From c0e37310eee96b32e77882e81d0e357b45aa64e9 Mon Sep 17 00:00:00 2001 From: Spythere Date: Wed, 9 Feb 2022 15:41:00 +0100 Subject: [PATCH] Dodano sygnalizator do pokazywania statusu danych --- src/App.scss | 17 ++- src/App.vue | 151 +++++++++++++++++++++++-- src/assets/signal-status-indicator.svg | 87 ++++++++++++++ src/constants/storeConstants.ts | 10 +- src/scripts/enums/DataStatus.ts | 3 +- src/scripts/interfaces/StoreData.ts | 4 + src/store/index.ts | 75 ++++++++---- 7 files changed, 315 insertions(+), 32 deletions(-) create mode 100644 src/assets/signal-status-indicator.svg diff --git a/src/App.scss b/src/App.scss index 9bbaf37..9dc5726 100644 --- a/src/App.scss +++ b/src/App.scss @@ -75,21 +75,34 @@ // HEADER .app_header { + display: flex; + justify-content: center; + + position: relative; background: $primaryCol; padding: 0.5em 0.3em 0 0.3em; border-radius: 0 0 1em 1em; - display: flex; - justify-content: center; + .signal-status-indicator { + position: absolute; + left: 50%; + bottom: 0; + + transform: translateX(11.6em); + width: 1.2em; + } } .train-logo { position: relative; } + + .header { + &_brand { position: relative; width: 100%; diff --git a/src/App.vue b/src/App.vue index cc43bca..408a27e 100644 --- a/src/App.vue +++ b/src/App.vue @@ -8,6 +8,14 @@ -->
+ + + S @@ -25,7 +33,7 @@ :class="{ current: currentLang == 'pl' }" v-if="currentLang == 'pl'" > - icon-pl + icon-pl - icon-en + icon-en @@ -89,12 +97,13 @@ import Clock from '@/components/App/Clock.vue'; import StorageManager from '@/scripts/managers/storageManager'; -import { computed, ComputedRef, defineComponent, provide, ref } from 'vue'; +import { computed, ComputedRef, defineComponent, provide, ref, watch } from 'vue'; import { GETTERS } from './constants/storeConstants'; import { StoreData } from './scripts/interfaces/StoreData'; import { useStore } from './store'; import packageInfo from '.././package.json'; +import { DataStatus } from './scripts/enums/DataStatus'; export default defineComponent({ components: { @@ -111,6 +120,9 @@ export default defineComponent({ () => store.getters[GETTERS.currentRegion] ); + const dataStatus = computed(() => data.value); + const sceneryDataStatus = computed(() => data.value.sceneryDataStatus); + const isFilterCardVisible = ref(false); provide('isFilterCardVisible', isFilterCardVisible); @@ -120,6 +132,10 @@ export default defineComponent({ currentRegion, isFilterCardVisible, + dataStatus, + sceneryDataStatus, + dispatcherDataStatus: computed(() => data.value.dispatcherDataStatus), + openFilterCard() { isFilterCardVisible.value = true; }, @@ -132,16 +148,85 @@ export default defineComponent({ hasReleaseNotes: false, currentLang: 'pl', - iconEN: require('@/assets/icon-en.jpg'), - iconPL: require('@/assets/icon-pl.svg'), - iconError: require('@/assets/icon-error.svg'), - svgChristmasCap: require('@/assets/christmas-cap.svg'), + icons: { + statusIndicator: require('@/assets/signal-status-indicator.svg'), + en: require('@/assets/icon-en.jpg'), + pl: require('@/assets/icon-pl.svg'), + error: require('@/assets/icon-error.svg'), + }, + + indicator: {} as { + status: DataStatus; + message: string; + }, }), created() { this.loadLang(); }, + watch: { + dataStatus(storeData: StoreData) { + // if(val == DataStatus.Loaded) + // this.setSignalStatus(DataStatus.Loaded) + + const dataConnectionStatus = storeData.dataConnectionStatus; + const sceneryDataStatus = storeData.sceneryDataStatus; + const trainsDataStatus = storeData.trainsDataStatus; + const dispatcherDataStatus = storeData.dispatcherDataStatus; + const timetableDataStatus = storeData.timetableDataStatus; + + if (dataConnectionStatus == DataStatus.Error) { + this.indicator.status = DataStatus.Error; + this.indicator.message = "Błąd podczas łączenia z serwisem SWDR!"; + this.setSignalStatus(DataStatus.Error); + return; + } + + if (sceneryDataStatus == DataStatus.Error) { + this.indicator.status = DataStatus.Error; + this.indicator.message = "Nie można pobrać danych o sceneriach!"; + this.setSignalStatus(DataStatus.Error); + return; + } + + if (trainsDataStatus == DataStatus.Warning) { + this.indicator.status = DataStatus.Warning; + this.indicator.message = "Nie można pobrać danych o pociągach!"; + this.setSignalStatus(DataStatus.Warning); + return; + } + + if (dispatcherDataStatus == DataStatus.Warning) { + this.indicator.status = DataStatus.Warning; + this.indicator.message = "Nie można pobrać danych o statusach dyżurnych ruchu!"; + this.setSignalStatus(DataStatus.Warning); + return; + } + + if (timetableDataStatus == DataStatus.Warning) { + this.indicator.status = DataStatus.Warning; + this.indicator.message = "Rozkłady jazdy mogą być niekompletne!"; + this.setSignalStatus(DataStatus.Warning); + return; + } + + this.indicator.status = DataStatus.Loaded; + this.indicator.message = ""; + + this.setSignalStatus(DataStatus.Loaded); + }, + + sceneryDataStatus(val: DataStatus) { + if (val == DataStatus.Error) this.setSignalStatus(DataStatus.Error); + }, + + dispatcherDataStatus(val: DataStatus) { + if (val == DataStatus.Warning && this.sceneryDataStatus != DataStatus.Error) + this.setSignalStatus(DataStatus.Warning); + }, + }, + async mounted() { if (StorageManager.getStringValue('version') != this.VERSION) { StorageManager.setStringValue('version', this.VERSION); @@ -152,6 +237,12 @@ export default defineComponent({ this.updateModalVisible = this.hasReleaseNotes && !StorageManager.getBooleanValue('version_notes_read'); this.updateToNewestVersion(); + + const obj = this.$refs['status-indicator'] as HTMLObjectElement; + + obj.addEventListener('load', () => { + this.setSignalStatus(DataStatus.Loading); + }); }, methods: { @@ -160,6 +251,52 @@ export default defineComponent({ StorageManager.setBooleanValue('version_notes_read', true); }, + setSignalStatus(status: DataStatus) { + const obj = this.$refs['status-indicator'] as HTMLObjectElement; + + const green = obj.contentDocument?.querySelector('#green') as SVGElement; + const greenBlink = obj.contentDocument?.querySelector('#green-blink') as SVGElement; + const redTop = obj.contentDocument?.querySelector('#red-top') as SVGElement; + const orange = obj.contentDocument?.querySelector('#orange') as SVGElement; + const redBottom = obj.contentDocument?.querySelector('#red-bottom') as SVGElement; + + if (status == DataStatus.Loaded) { + green.style.visibility = 'visible'; + greenBlink.style.visibility = 'hidden'; + redTop.style.visibility = 'hidden'; + orange.style.visibility = 'hidden'; + redBottom.style.visibility = 'hidden'; + } + + if (status == DataStatus.Warning) { + green.style.visibility = 'hidden'; + greenBlink.style.visibility = 'hidden'; + redTop.style.visibility = 'hidden'; + orange.style.visibility = 'visible'; + redBottom.style.visibility = 'hidden'; + } + + if (status == DataStatus.Error) { + green.style.visibility = 'hidden'; + greenBlink.style.visibility = 'hidden'; + redTop.style.visibility = 'visible'; + orange.style.visibility = 'hidden'; + redBottom.style.visibility = 'visible'; + } + + if (status == DataStatus.Loading) { + green.style.visibility = 'hidden'; + greenBlink.style.visibility = 'visible'; + redTop.style.visibility = 'hidden'; + orange.style.visibility = 'hidden'; + redBottom.style.visibility = 'hidden'; + } + + // (this.$refs['redTop'] as SVGElement).style.display = "none"; + // (this.$refs['orangeBottom'] as SVGElement).style.display = "block"; + // (this.$refs['redBottom'] as SVGElement).style.display = "none"; + }, + changeLang(lang: string) { this.$i18n.locale = lang; this.currentLang = lang; diff --git a/src/assets/signal-status-indicator.svg b/src/assets/signal-status-indicator.svg new file mode 100644 index 0000000..2417d66 --- /dev/null +++ b/src/assets/signal-status-indicator.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/constants/storeConstants.ts b/src/constants/storeConstants.ts index 19f0c04..b1e392a 100644 --- a/src/constants/storeConstants.ts +++ b/src/constants/storeConstants.ts @@ -6,9 +6,13 @@ export const ACTIONS = { export const MUTATIONS = { SET_SCENERY_DATA: "SET_SCENERY_DATA", + SET_DATA_CONNECTION_STATUS: "SET_DATA_CONNECTION_STATUS", + SET_SCENERY_DATA_STATUS: "SET_SCENERY_DATA_STATUS", SET_TIMETABLE_DATA_STATUS: "SET_TIMETABLE_DATA_STATUS", - SET_DATA_CONNECTION_STATUS: "SET_DATA_CONNECTION_STATUS", + SET_DISPATCHER_DATA_STATUS: "SET_DISPATCHER_DATA_STATUS", + SET_TRAINS_DATA_STATUS: "SET_TRAINS_DATA_STATUS", + SET_REGION: "SET_REGION", UPDATE_STATIONS: "UPDATE_STATIONS", UPDATE_TRAINS: "UPDATE_TRAINS", @@ -19,8 +23,12 @@ export const GETTERS = { stationList: "stationList", trainList: "trainList", allData: "allData", + timetableDataStatus: "timetableDataStatus", sceneryDataStatus: "sceneryDataStatus", + dispatcherDataStatus: "dispatcherDataStatus", + trainsDataStatus: "trainDataStatus", + dataStatus: "dataStatus", currentRegion: "currentRegion" } \ No newline at end of file diff --git a/src/scripts/enums/DataStatus.ts b/src/scripts/enums/DataStatus.ts index 2de3f5a..0b37532 100644 --- a/src/scripts/enums/DataStatus.ts +++ b/src/scripts/enums/DataStatus.ts @@ -2,5 +2,6 @@ export const enum DataStatus { Initialized = -1, Loading = 0, Error = 1, - Loaded = 2 + Loaded = 2, + Warning = 3 } diff --git a/src/scripts/interfaces/StoreData.ts b/src/scripts/interfaces/StoreData.ts index 55d87e4..b912c70 100644 --- a/src/scripts/interfaces/StoreData.ts +++ b/src/scripts/interfaces/StoreData.ts @@ -10,5 +10,9 @@ export interface StoreData { activeStationCount: number; dataConnectionStatus: DataStatus; + timetableDataStatus: DataStatus; + sceneryDataStatus: DataStatus; + dispatcherDataStatus: DataStatus; + trainsDataStatus: DataStatus; } diff --git a/src/store/index.ts b/src/store/index.ts index 6b45236..5ca9b3c 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -36,8 +36,11 @@ export interface State { stationCount: number; dataConnectionStatus: DataStatus; + sceneryDataStatus: DataStatus; timetableDataStatus: DataStatus; + dispatcherDataStatus: DataStatus; + trainsDataStatus: DataStatus; listenerLaunched: boolean; } @@ -59,8 +62,11 @@ export const store = createStore({ stationCount: 0, dataConnectionStatus: DataStatus.Loading, + sceneryDataStatus: DataStatus.Loading, timetableDataStatus: DataStatus.Loading, + dispatcherDataStatus: DataStatus.Loading, + trainsDataStatus: DataStatus.Loading, listenerLaunched: false }), @@ -76,7 +82,11 @@ export const store = createStore({ activeStationCount: state.stationCount, dataConnectionStatus: state.dataConnectionStatus, - timetableDataStatus: state.timetableDataStatus + timetableDataStatus: state.timetableDataStatus, + sceneryDataStatus: state.sceneryDataStatus, + + dispatcherDataStatus: state.dispatcherDataStatus, + trainsDataStatus: state.trainsDataStatus }), timetableDataStatus: (state): DataStatus => state.timetableDataStatus, sceneryDataStatus: (state): DataStatus => state.sceneryDataStatus, @@ -104,22 +114,31 @@ export const store = createStore({ Promise.all([axios.get(URLs.stations), axios.get(URLs.trains), axios.get(URLs.dispatchers)]) .then(async response => { - const onlineStationsData: StationAPIData[] = response[0].data.message; - const onlineTrainsData: TrainAPIData[] = await response[1].data.message; - const onlineDispatchersData: string[][] = await response[2].data.message; + const onlineStationsData: { success: boolean, message: StationAPIData[] } = response[0].data; + const onlineTrainsData: { success: boolean, message: TrainAPIData[] } = await response[1].data; + const onlineDispatchersData: { success: boolean, message: string[][] } = await response[2].data; - - const updatedStationList: Station['onlineInfo'][] = onlineStationsData.reduce((acc, station) => { + if (!onlineStationsData.success) { + commit(MUTATIONS.SET_DATA_CONNECTION_STATUS, DataStatus.Error); + commit(MUTATIONS.SET_SCENERY_DATA_STATUS, DataStatus.Error); + return; + } + + commit(MUTATIONS.SET_SCENERY_DATA_STATUS, DataStatus.Loaded); + commit(MUTATIONS.SET_DISPATCHER_DATA_STATUS, onlineDispatchersData.success ? DataStatus.Loaded : DataStatus.Warning); + commit(MUTATIONS.SET_TRAINS_DATA_STATUS, onlineTrainsData.success ? DataStatus.Loaded : DataStatus.Warning); + + const updatedStationList: Station['onlineInfo'][] = onlineStationsData.message.reduce((acc, station) => { if (station.region !== this.state.region.id || !station.isOnline) return acc; - const stationStatus = onlineDispatchersData.find((status: string[]) => status[0] == station.stationHash && status[1] == this.state.region.id); + const stationStatus = onlineDispatchersData.success ? onlineDispatchersData.message.find((status: string[]) => status[0] == station.stationHash && status[1] == this.state.region.id) : undefined; const statusTimestamp = getStatusTimestamp(stationStatus); const statusID = getStatusID(stationStatus); - const stationTrains = onlineTrainsData + const stationTrains = onlineTrainsData.success ? onlineTrainsData.message .filter(train => train.region === this.state.region.id && train.isOnline && train.station.stationName === station.stationName) - .map(train => ({ driverName: train.driverName, trainNo: train.trainNo })); + .map(train => ({ driverName: train.driverName, trainNo: train.trainNo })) : []; acc.push({ name: station.stationName, @@ -141,8 +160,8 @@ export const store = createStore({ return acc; }, [] as Station['onlineInfo'][]); - const updatedTrainList = await Promise.all( - onlineTrainsData + const updatedTrainList = onlineTrainsData.success ? await Promise.all( + onlineTrainsData.message .filter(train => train.region === this.state.region.id) .map(async train => { const locoType = train.dataCon.split(";") ? train.dataCon.split(";")[0] : train.dataCon; @@ -165,11 +184,13 @@ export const store = createStore({ cars: train.dataCon.split(";").filter((train, i) => i > 0) || [] }; }) - ); + ) : []; // Pass reduced lists to mutations commit(MUTATIONS.UPDATE_STATIONS, updatedStationList); commit(MUTATIONS.UPDATE_TRAINS, updatedTrainList); + + // Statuses commit(MUTATIONS.SET_DATA_CONNECTION_STATUS, DataStatus.Loaded); dispatch(ACTIONS.fetchTimetableData); @@ -180,14 +201,16 @@ export const store = createStore({ }, async fetchTimetableData({ commit }) { + let warnings = 0; const reducedList = this.state.trainList.reduce(async (acc: Promise, train: Train) => { const data: { success: boolean; message: TimetableAPIData } = await (await axios.get(URLs.getTimetableURL(train.trainNo, this.state.region.id))).data; if (!data.success) { + warnings++; return acc; } - + const timetable = data.message; const trainInfo = timetable.trainInfo; @@ -274,7 +297,7 @@ export const store = createStore({ }, Promise.resolve([])); commit(MUTATIONS.UPDATE_TIMETABLES, (await reducedList)); - commit(MUTATIONS.SET_TIMETABLE_DATA_STATUS, DataStatus.Loaded); + commit(MUTATIONS.SET_TIMETABLE_DATA_STATUS, warnings == 0 ? DataStatus.Loaded : DataStatus.Warning); } }, @@ -293,7 +316,7 @@ export const store = createStore({ supportersOnly: station[5] == "TAK", signalType: station[6], controlType: station[7], - + SUP: station[8], SBL: station[9], @@ -319,18 +342,28 @@ export const store = createStore({ }, - SET_SCENERY_DATA_STATUS(state, status: DataStatus) { - state.sceneryDataStatus = status; - }, - + SET_DATA_CONNECTION_STATUS(state, status: DataStatus) { state.dataConnectionStatus = status; }, + + SET_SCENERY_DATA_STATUS(state, status: DataStatus) { + state.sceneryDataStatus = status; + }, SET_TIMETABLE_DATA_STATUS(state, status: DataStatus) { state.timetableDataStatus = status; }, + SET_DISPATCHER_DATA_STATUS(state, status: DataStatus) { + state.dispatcherDataStatus = status; + }, + + SET_TRAINS_DATA_STATUS(state, status: DataStatus) { + state.trainsDataStatus = status; + }, + + SET_REGION(state, region: { id: string; value: string }) { state.region = region; }, @@ -398,7 +431,7 @@ export const store = createStore({ state.stationList = state.stationList.map(station => { const stationName = station.name.toLowerCase(); - const scheduledTrains: ScheduledTrain[] = timetableList.reduce((acc: ScheduledTrain[], timetable: Timetable) => { + const scheduledTrains: ScheduledTrain[] = timetableList.reduce((acc: ScheduledTrain[], timetable: Timetable) => { if (!timetable.followingSceneries.includes(station.onlineInfo?.hash || "")) return acc; const stopInfoIndex = timetable.followingStops.findIndex(stop => { @@ -406,7 +439,7 @@ export const store = createStore({ // if (stop.stopName == "ARKADIA ZDRÓJ" && station.name == "Arkadia Zdrój 2019" && stop.pointId != "1583014379097") return false; // if (stop.stopName == "ARKADIA ZDRÓJ" && station.name == "Arkadia Zdrój 2012" && stop.pointId != "1519258642187") return false; - + if (stationName === stopName) return true; if (stopName.includes(stationName) && !stop.stopName.includes("po.") && !stop.stopName.includes("podg.")) return true; if (stationName.includes(stopName) && !stop.stopName.includes("po.") && !stop.stopName.includes("podg.")) return true;