diff --git a/src/App.scss b/src/App.scss index 267ed5e..e47fae8 100644 --- a/src/App.scss +++ b/src/App.scss @@ -43,9 +43,10 @@ #app { color: white; font-size: 1rem; + overflow-x: hidden; @include smallScreen() { - font-size: calc(0.55rem + 1.1vw); + font-size: calc(0.65rem + 0.8vw); } @include screenLandscape() { diff --git a/src/App.vue b/src/App.vue index d10a715..293ff13 100644 --- a/src/App.vue +++ b/src/App.vue @@ -80,7 +80,7 @@ export default defineComponent({ connectedSocketCount: 0 }; - this.store.setOnlineData(); + this.store.setStatuses(); }); window.addEventListener('online', () => { diff --git a/src/components/JournalView/DailyStats.vue b/src/components/JournalView/DailyStats.vue index 04fa250..6251c95 100644 --- a/src/components/JournalView/DailyStats.vue +++ b/src/components/JournalView/DailyStats.vue @@ -243,10 +243,6 @@ export default defineComponent({ } @include smallScreen { - .daily-stats { - text-align: justify; - } - h3 { text-align: center; } diff --git a/src/components/JournalView/JournalOptions.vue b/src/components/JournalView/JournalOptions.vue index e1a0bd0..5274033 100644 --- a/src/components/JournalView/JournalOptions.vue +++ b/src/components/JournalView/JournalOptions.vue @@ -51,7 +51,11 @@ /> @@ -180,7 +184,7 @@ export default defineComponent({ }, watch: { - async driverStatsName() { + async 'store.driverStatsName'() { await this.fetchDriverStats(); // if (value) this.store.currentStatsTab = 'driver'; diff --git a/src/components/JournalView/JournalStats.vue b/src/components/JournalView/JournalStats.vue index f157695..47e3449 100644 --- a/src/components/JournalView/JournalStats.vue +++ b/src/components/JournalView/JournalStats.vue @@ -86,8 +86,6 @@ watch( ); onMounted(() => { - console.log(StorageManager.getBooleanValue('dailyStatsOpen')); - if (StorageManager.getBooleanValue('dailyStatsOpen')) { areStatsOpen.value = true; store.currentStatsTab = 'daily'; diff --git a/src/components/SceneryView/SceneryInfo/SceneryInfoUserList.vue b/src/components/SceneryView/SceneryInfo/SceneryInfoUserList.vue index 7372f5a..7e950e3 100644 --- a/src/components/SceneryView/SceneryInfo/SceneryInfoUserList.vue +++ b/src/components/SceneryView/SceneryInfo/SceneryInfoUserList.vue @@ -3,7 +3,7 @@

Users icon  {{ $t('scenery.users') }}   - {{ onlineScenery?.currentUsers || 0 }}{{ onlineScenery?.stationTrains?.length || 0 }} / {{ onlineScenery?.maxUsers || 0 }}

@@ -22,7 +22,7 @@
{{ $t('scenery.no-users') }}
diff --git a/src/components/SceneryView/SceneryTimetable.vue b/src/components/SceneryView/SceneryTimetable.vue index 4894c79..6467354 100644 --- a/src/components/SceneryView/SceneryTimetable.vue +++ b/src/components/SceneryView/SceneryTimetable.vue @@ -6,13 +6,10 @@ {{ $t('scenery.timetables') }} - {{ onlineScenery?.scheduledTrains?.length || '0' }} + {{ onlineScenery?.scheduledTrainCount.all || 0 }} / - {{ - onlineScenery?.scheduledTrains?.filter((train) => train.stopInfo.confirmed).length || - '0' - }} + {{ onlineScenery?.scheduledTrainCount.confirmed || '0' }} @@ -48,27 +45,34 @@
-
- -
- - - {{ $t('scenery.offline') }} - - - - {{ $t('scenery.no-timetables') }} - - +
+ +
+ + + {{ $t('scenery.offline') }} + + +
+ {{ $t('scenery.no-timetables') }} +
+
- - {{ station.onlineInfo?.currentUsers || 0 }} - / - {{ station.onlineInfo?.maxUsers || 0 }} - + {{ station.onlineInfo?.currentUsers || 0 }} + / + {{ station.onlineInfo?.maxUsers || 0 }} @@ -246,9 +244,7 @@ style="width: 30px" :class="{ inactive: !station.onlineInfo }" > - - {{ station.onlineInfo?.scheduledTrains?.length || 0 }} - + {{ station.onlineInfo?.scheduledTrainCount.all }} - - {{ - new Set([ - ...(station.onlineInfo?.scheduledTrains - ?.filter((train) => !train.stopInfo.confirmed) - .map((train) => train.checkpointName) || []) - ]).size || 0 - }} - + {{ station.onlineInfo?.scheduledTrainCount.unconfirmed }} - - {{ - station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed) - .length || 0 - }} - + {{ station.onlineInfo?.scheduledTrainCount.confirmed }} @@ -391,10 +374,6 @@ $rowCol: #424242; } } -.highlight { - color: gold; -} - section.station_table { overflow: auto; overflow-y: hidden; @@ -576,6 +555,26 @@ td.station { } } +.station_users { + span { + color: gold; + } +} + +.station_schedules { + &.all { + color: gold; + } + + &.unconfirmed { + color: #ccc; + } + + &.confirmed { + color: lime; + } +} + .separator { border-left: 3px solid #b3b3b3; } diff --git a/src/scripts/enums/DispatcherStatus.ts b/src/scripts/enums/DispatcherStatus.ts new file mode 100644 index 0000000..cc533bb --- /dev/null +++ b/src/scripts/enums/DispatcherStatus.ts @@ -0,0 +1,11 @@ +export enum DispatcherStatusID { + Unknown = 'unknown', + Outdated = 'outdated', + Unauthorized = 'not-signed', + OnlineNoLimit = 'no-limit', + Afk = 'brb', + Ending = 'ending', + NoSpace = 'no-space', + Unavailable = 'unavailable', + OnlineWithHours = 'online' +} \ No newline at end of file diff --git a/src/scripts/interfaces/Station.ts b/src/scripts/interfaces/Station.ts index 1173ee8..8dfa96d 100644 --- a/src/scripts/interfaces/Station.ts +++ b/src/scripts/interfaces/Station.ts @@ -1,4 +1,4 @@ -import { Availability } from './store/storeTypes'; +import { Availability, OnlineScenery } from './store/storeTypes'; import { ScheduledTrain } from './ScheduledTrain'; import StationRoutes from './StationRoutes'; @@ -32,33 +32,5 @@ export default interface Station { }[]; }; - onlineInfo?: { - hash: string; - name: string; - region: string; - - maxUsers: number; - currentUsers: number; - - spawns: { spawnName: string; spawnLength: number; isElectrified: boolean }[]; - dispatcherRate: number; - dispatcherName: string; - dispatcherExp: number; - dispatcherId: number; - dispatcherIsSupporter: boolean; - - statusTimestamp: number; - // statusTimeString: string; - statusID: string; - - stationTrains?: { - driverName: string; - driverId: number; - trainNo: number; - trainId: string; - stopStatus?: string; - }[]; - - scheduledTrains?: ScheduledTrain[]; - }; + onlineInfo?: OnlineScenery; } diff --git a/src/scripts/interfaces/store/storeTypes.ts b/src/scripts/interfaces/store/storeTypes.ts index 6a58609..7b6ea1b 100644 --- a/src/scripts/interfaces/store/storeTypes.ts +++ b/src/scripts/interfaces/store/storeTypes.ts @@ -7,6 +7,7 @@ import { DriverStatsAPIData } from '../api/DriverStatsAPIData'; import { RollingStockGithubData } from '../github_api/StockInfoGithubData'; import Station from '../Station'; import { ScheduledTrain } from '../ScheduledTrain'; +import { DispatcherStatusID } from '../../enums/DispatcherStatus'; export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault'; @@ -15,7 +16,7 @@ export interface StoreState { apiData: APIData; rollingStockData?: RollingStockGithubData; - lastDispatcherStatuses: { hash: string; statusTimestamp: number; statusID: string }[]; + lastDispatcherStatuses: { hash: string; statusTimestamp: number; statusID: DispatcherStatusID }[]; sceneryData: any[][]; @@ -113,8 +114,16 @@ export interface OnlineScenery { dispatcherIsSupporter: boolean; statusTimestamp: number; - statusID: string; + statusID: DispatcherStatusID; + + isOnline: boolean; stationTrains?: StationTrain[]; scheduledTrains?: ScheduledTrain[]; + + scheduledTrainCount: { + all: number; + confirmed: number; + unconfirmed: number; + } } diff --git a/src/scripts/utils/filterUtils.ts b/src/scripts/utils/filterUtils.ts index 6206d2c..c55c3ae 100644 --- a/src/scripts/utils/filterUtils.ts +++ b/src/scripts/utils/filterUtils.ts @@ -1,4 +1,5 @@ import { HeadIdsTypes } from '../data/stationHeaderNames'; +import { DispatcherStatusID } from '../enums/DispatcherStatus'; import Filter from '../interfaces/Filter'; import Station from '../interfaces/Station'; @@ -90,11 +91,15 @@ export const filterStations = (station: Station, filters: Filter) => { if (station.onlineInfo) { const { statusID, statusTimestamp } = station.onlineInfo; - const isEnding = statusID == 'ending' && filters['endingStatus']; + const isEnding = statusID == DispatcherStatusID.Ending && filters['endingStatus']; + const isNotSigned = (statusID == 'not-signed' || statusID == 'unavailable') && filters['unavailableStatus']; + const isAFK = statusID == 'brb' && filters['afkStatus']; + const isNoSpace = statusID == 'no-space' && filters['noSpaceStatus']; + const isOccupied = station.onlineInfo && filters['occupied']; const isOnlineInBounds = diff --git a/src/scripts/utils/storeUtils.ts b/src/scripts/utils/storeUtils.ts index e1d09c2..38520f7 100644 --- a/src/scripts/utils/storeUtils.ts +++ b/src/scripts/utils/storeUtils.ts @@ -1,3 +1,4 @@ +import { DispatcherStatusID } from '../enums/DispatcherStatus'; import { ScheduledTrain, StopStatus } from '../interfaces/ScheduledTrain'; import Station from '../interfaces/Station'; import Train from '../interfaces/Train'; @@ -10,34 +11,39 @@ export const getLocoURL = (locoType: string): string => locoType.includes('EN') ? locoType + 'rb' : locoType }.png`; -export const getStatusID = (stationStatus: any): string => { - if (!stationStatus) return 'unknown'; - if (stationStatus == -1) return 'not-signed'; +export const getStatusID = ( + stationStatus: any[] | undefined, + isSWDROnline: boolean +): DispatcherStatusID => { + if (isSWDROnline && !stationStatus) return DispatcherStatusID.Unauthorized; + if (!stationStatus) return DispatcherStatusID.Unknown; + + // if (stationStatus == -1) return DispatcherStatusID.Unauthorized; const statusCode = stationStatus[2]; const statusTimestamp = stationStatus[3]; switch (statusCode) { case 0: - if (statusTimestamp - Date.now() > 21000000) return 'no-limit'; + if (statusTimestamp - Date.now() > 21000000) return DispatcherStatusID.OnlineNoLimit; - return 'online'; + return DispatcherStatusID.OnlineWithHours; case 1: - return 'brb'; + return DispatcherStatusID.Afk; case 2: - if (statusTimestamp == 0) return 'ending'; + if (statusTimestamp == 0) return DispatcherStatusID.Ending; break; case 3: - return 'no-space'; + return DispatcherStatusID.NoSpace; default: break; } - return 'unavailable'; + return DispatcherStatusID.Unavailable; }; export const getStatusTimestamp = (stationStatus: any): number => { @@ -219,12 +225,9 @@ export function getDispatcherStatus(state: StoreState, onlineStationData: Statio (dispatcher) => dispatcher.hash === onlineStationData.stationHash ); - const stationStatus = !dispatchers - ? undefined - : dispatchers.find( - (status: string[]) => - status[0] == onlineStationData.stationHash && status[1] == state.region.id - ) || -1; + const stationStatus = dispatchers?.find( + (status: string[]) => status[0] == onlineStationData.stationHash && status[1] == state.region.id + ); const statusTimestamp = prevDispatcherStatus && !dispatchers @@ -234,7 +237,7 @@ export function getDispatcherStatus(state: StoreState, onlineStationData: Statio const statusID = prevDispatcherStatus && !dispatchers ? prevDispatcherStatus.statusID - : getStatusID(stationStatus); + : getStatusID(stationStatus, onlineStationData.isOnline === 1); return { hash: onlineStationData.stationHash, @@ -263,8 +266,8 @@ export function getScheduledTrains( return ( stationName == stopName || - (!/(po\.|podg\.)/.test(stationName) && stopName.includes(stationName)) || - (!/(po\.|podg\.)/.test(stopName) && stationName.includes(stopName)) || + (!/(po\.|podg\.)/.test(stopName) && stopName.includes(stationName)) || + (!/(po\.|podg\.)/.test(stationName) && stationName.includes(stopName)) || (stopName.split(', podg.')[0] !== undefined && stationName.startsWith(stopName.split(', podg.')[0])) ); diff --git a/src/store/store.ts b/src/store/store.ts index 02ce13c..cb5434f 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -21,6 +21,8 @@ import { import packageInfo from '../../package.json'; import { RollingStockGithubData } from '../scripts/interfaces/github_api/StockInfoGithubData'; +import { ScheduledTrain } from '../scripts/interfaces/ScheduledTrain'; +import { DispatcherStatusID } from '../scripts/enums/DispatcherStatus'; export const useStore = defineStore('store', { state: () => @@ -127,110 +129,72 @@ export const useStore = defineStore('store', { if (state.isOffline) return []; if (!state.apiData?.stations) return []; - return state.apiData?.stations - ?.filter((apiStation) => apiStation.region == state.region.id && apiStation.isOnline) - .map((apiStation) => { - const dispatcherStatus = getDispatcherStatus(state as StoreState, apiStation); - const station = this.stationList.find((s) => s.name === apiStation.stationName); + return ( + state.apiData?.stations + // ?.filter((apiStation) => apiStation.region == state.region.id) + .reduce((list, apiStation) => { + if (apiStation.region != state.region.id) return list; - const scheduledTrains = getScheduledTrains( - this.trainList, - apiStation, - station?.generalInfo - ); + const dispatcherStatus = getDispatcherStatus(state as StoreState, apiStation); - const stationTrains = getStationTrains( - this.trainList, - scheduledTrains, - this.region.id, - apiStation - ); + if (dispatcherStatus.statusID == DispatcherStatusID.Unknown) return list; - return { - name: apiStation.stationName, - hash: apiStation.stationHash, - region: apiStation.region, - maxUsers: apiStation.maxUsers, - currentUsers: apiStation.currentUsers, - spawns: parseSpawns(apiStation.spawnString), - dispatcherName: apiStation.dispatcherName, - dispatcherRate: apiStation.dispatcherRate, - dispatcherId: apiStation.dispatcherId, - dispatcherExp: apiStation.dispatcherExp, - dispatcherIsSupporter: apiStation.dispatcherIsSupporter, - scheduledTrains: scheduledTrains, - stationTrains: stationTrains, - statusTimestamp: dispatcherStatus.statusTimestamp, - statusID: dispatcherStatus.statusID - }; - }); + const station = this.stationList.find((s) => s.name === apiStation.stationName); + + const scheduledTrains = getScheduledTrains( + this.trainList, + apiStation, + station?.generalInfo + ); + + const stationTrains = getStationTrains( + this.trainList, + scheduledTrains, + this.region.id, + apiStation + ); + + // Remove checkpoint duplicates + const uniqueScheduledTrains = scheduledTrains.reduce( + (uniqueList, sTrain) => + uniqueList.find((v) => v.trainId === sTrain.trainId) + ? uniqueList + : [...uniqueList, sTrain], + [] as ScheduledTrain[] + ); + + list.push({ + name: apiStation.stationName, + hash: apiStation.stationHash, + region: apiStation.region, + maxUsers: apiStation.maxUsers, + currentUsers: apiStation.currentUsers, + spawns: parseSpawns(apiStation.spawnString), + dispatcherName: apiStation.dispatcherName, + dispatcherRate: apiStation.dispatcherRate, + dispatcherId: apiStation.dispatcherId, + dispatcherExp: apiStation.dispatcherExp, + dispatcherIsSupporter: apiStation.dispatcherIsSupporter, + scheduledTrains: scheduledTrains, + stationTrains: stationTrains, + statusTimestamp: dispatcherStatus.statusTimestamp, + statusID: dispatcherStatus.statusID, + + isOnline: apiStation.isOnline == 1, + + scheduledTrainCount: { + all: uniqueScheduledTrains.length, + confirmed: uniqueScheduledTrains.filter((train) => train.stopInfo.confirmed).length, + unconfirmed: uniqueScheduledTrains.filter((train) => !train.stopInfo.confirmed).length + } + }); + + return list; + }, [] as OnlineScenery[]) + ); } }, actions: { - // setStationsOnlineInfo() { - // const onlineStationNames: string[] = []; - // const prevDispatcherStatuses: StoreState['lastDispatcherStatuses'] = []; - - // if (this.isOffline) { - // this.stationList.forEach((station) => { - // station.onlineInfo = undefined; - // }); - - // return; - // } - - // this.apiData.stations?.forEach((stationAPIData) => { - // if (stationAPIData.region !== this.region.id || !stationAPIData.isOnline) return; - - // const station = this.stationList.find((s) => s.name === stationAPIData.stationName); - - // onlineStationNames.push(stationAPIData.stationName); - - // const dispatcherStatus = this.getDispatcherStatus(stationAPIData); - // prevDispatcherStatuses.push(dispatcherStatus); - - // const stationTrains = this.getStationTrains(stationAPIData); - // const scheduledTrains = this.getScheduledTrains(station?.generalInfo, stationAPIData); - - // const onlineInfo = { - // name: stationAPIData.stationName, - // hash: stationAPIData.stationHash, - // region: stationAPIData.region, - // maxUsers: stationAPIData.maxUsers, - // currentUsers: stationAPIData.currentUsers, - // spawns: parseSpawns(stationAPIData.spawnString), - // dispatcherName: stationAPIData.dispatcherName, - // dispatcherRate: stationAPIData.dispatcherRate, - // dispatcherId: stationAPIData.dispatcherId, - // dispatcherExp: stationAPIData.dispatcherExp, - // dispatcherIsSupporter: stationAPIData.dispatcherIsSupporter, - // stationTrains, - // statusTimestamp: dispatcherStatus.statusTimestamp, - // statusID: dispatcherStatus.statusID, - // scheduledTrains - // }; - - // if (!station) { - // this.stationList.push({ - // name: stationAPIData.stationName, - // onlineInfo - // }); - - // return; - // } - - // station.onlineInfo = { ...onlineInfo }; - // }); - - // this.stationList - // .filter((station) => !onlineStationNames.includes(station.name) && station.onlineInfo) - // .forEach((offlineStation) => { - // offlineStation.onlineInfo = undefined; - // }); - - // if (this.apiData.dispatchers != null) this.lastDispatcherStatuses = prevDispatcherStatuses; - // }, - async fetchStationsGeneralInfo() { const sceneryData: StationJSONData[] = await ( await axios.get(`${URLs.stacjownikAPI}/api/getSceneries`) @@ -297,7 +261,7 @@ export const useStore = defineStore('store', { const mockWebsocketData = await import('../data/mockWebsocketData.json'); this.dataStatuses.connection = DataStatus.Loaded; this.apiData = mockWebsocketData as any; - this.setOnlineData(); + this.setStatuses(); console.warn('Stacjownik dziaƂa w trybie mockowania danych z WS'); @@ -320,13 +284,13 @@ export const useStore = defineStore('store', { socket.on('UPDATE', (data: APIData) => { this.apiData = data; this.dataStatuses.connection = DataStatus.Loaded; - this.setOnlineData(); + this.setStatuses(); }); socket.emit('FETCH_DATA', { version: packageInfo.version }, (data: APIData) => { this.dataStatuses.connection = DataStatus.Loaded; this.apiData = data; - this.setOnlineData(); + this.setStatuses(); }); this.webSocket = socket; @@ -354,7 +318,7 @@ export const useStore = defineStore('store', { } }, - async setOnlineData() { + async setStatuses() { if (!this.apiData.stations) { this.dataStatuses.sceneries = DataStatus.Error; this.dataStatuses.trains = DataStatus.Error; @@ -368,6 +332,8 @@ export const useStore = defineStore('store', { this.dataStatuses.dispatchers = !this.apiData.dispatchers ? DataStatus.Warning : DataStatus.Loaded; + + // if (this.apiData.dispatchers != null) this.lastDispatcherStatuses = prevDispatcherStatuses; } } });