From 5f48c4688f6705d1a3ffac7542d1e1a5e002fee7 Mon Sep 17 00:00:00 2001 From: Spythere Date: Sat, 29 Aug 2020 02:11:01 +0200 Subject: [PATCH] Kolumna z aktywnymi RJ dla scenerii - W.I.P. --- src/App.vue | 9 +- src/components/StationsView/StationTable.vue | 51 +- src/components/TrainsView/TrainSorter.vue | 4 +- src/scripts/interfaces/Train.ts | 1 + src/store/modules/store.ts | 474 ------------------- src/store/modules/trainsModule.ts | 111 ++--- src/views/StationsView.vue | 6 +- src/views/TrainsView.vue | 56 ++- 8 files changed, 149 insertions(+), 563 deletions(-) delete mode 100644 src/store/modules/store.ts diff --git a/src/App.vue b/src/App.vue index 59c03d1..d3b49f8 100644 --- a/src/App.vue +++ b/src/App.vue @@ -57,18 +57,19 @@ import Clock from "@/components/App/Clock.vue"; components: { Error, Loading, Clock }, }) export default class App extends Vue { - @Getter("getStationList") stations; @Getter("getOnlineInfo") onlineInfo; @Action("initStations") initStations; - @Action("fetchOnlineStations") fetchStations; - errorMessage: string = ""; + @Action("fetchOnlineStations") fetchStations; + @Action("fetchTrainsData") fetchTrainsData; async mounted() { this.initStations(); + this.fetchTrainsData(); - setInterval(this.fetchStations, 5000); + setInterval(this.fetchStations, 15000); + setInterval(this.fetchTrainsData, 10000); } } diff --git a/src/components/StationsView/StationTable.vue b/src/components/StationsView/StationTable.vue index 494a1db..068ad7c 100644 --- a/src/components/StationsView/StationTable.vue +++ b/src/components/StationsView/StationTable.vue @@ -118,12 +118,10 @@ >{{station.routes.oneWay.noCatenary}} - + 0 +
Ups! Brak stacji do wyświetlenia!
@@ -152,7 +150,6 @@ export default class StationTable extends styleMixin { @Prop() readonly setFocusedStation!: () => void; @Getter("trainsDataList") trains!: Train[]; - @Getter("trainsDataState") state!: number; icons: { ascSVG; descSVG } = { ascSVG, descSVG }; sorterActive: { index: number; dir: number } = { index: 0, dir: 1 }; @@ -166,7 +163,7 @@ export default class StationTable extends styleMixin { ["Maszyniści"], ["Informacje", "ogólne"], ["Szlaki", "2tor | 1tor"], - // ["Aktywne RJ"], + ["Aktywne RJ"], ]; changeSorter(index: number) { @@ -179,12 +176,28 @@ export default class StationTable extends styleMixin { this.sorterActive.index = index; } - get test() { - return this.trains; - } + get scheduledTrains() { + return this.stations.reduce((acc, station) => { + if (!acc[station.stationName]) acc[station.stationName] = []; - showScheduledTrains(station) { - console.log(station.scheduledTrains); + this.trains + .filter((train) => !train.noTimetable) + .forEach((train) => { + const found = train.stopPoints!.find( + (sp: any) => + (station.stationName.includes(sp.pointNameRAW) || + station.stationName.includes(sp.pointNameRAW.split(" ")[0])) && + !acc[station.stationName].find((t) => t === train.trainNo) + // !acc[station.stationName].find((t) => t.trainNo === train.trainNo) + ); + + if (!found) return acc; + + acc[station.stationName].push(train.trainNo); + }); + + return acc; + }, {}); } get computedStations() { @@ -235,10 +248,24 @@ export default class StationTable extends styleMixin { @import "../../styles/variables.scss"; @import "../../styles/global.scss"; +.station-table { + font-size: calc(0.6rem + 0.3vw); +} + .separator { border-left: 3px solid #b3b3b3; } +.no-stations { + text-align: center; + font-size: 1.5em; + + padding: 1rem; + margin: 1rem 0; + + background: #333; +} + .table { &-wrapper { overflow: auto; @@ -247,8 +274,6 @@ export default class StationTable extends styleMixin { white-space: nowrap; border-collapse: collapse; - font-size: calc(0.6rem + 0.3vw); - @include smallScreen() { font-size: 0.6rem; } diff --git a/src/components/TrainsView/TrainSorter.vue b/src/components/TrainsView/TrainSorter.vue index aca3639..39a31dd 100644 --- a/src/components/TrainsView/TrainSorter.vue +++ b/src/components/TrainsView/TrainSorter.vue @@ -140,7 +140,7 @@ export default class TrainSorter extends Vue { z-index: 5; width: 100%; - background-color: rgba(#333, 0.85); + background-color: rgba(#222, 0.95); overflow: hidden; max-height: 0; @@ -150,7 +150,7 @@ export default class TrainSorter extends Vue { opacity: 1; } - transition: all 250ms ease-in; + transition: all 150ms ease-in; } .option { diff --git a/src/scripts/interfaces/Train.ts b/src/scripts/interfaces/Train.ts index 79b934c..22bdf8d 100644 --- a/src/scripts/interfaces/Train.ts +++ b/src/scripts/interfaces/Train.ts @@ -19,4 +19,5 @@ export default interface Train { locoURL: string; locoType: string; routeDistance: number; + stopPoints?: []; } diff --git a/src/store/modules/store.ts b/src/store/modules/store.ts deleted file mode 100644 index 4ed0aa2..0000000 --- a/src/store/modules/store.ts +++ /dev/null @@ -1,474 +0,0 @@ -import { VuexModule, Module, Mutation, Action } from "vuex-module-decorators"; -import axios from "axios"; -import data from "@/data/stations.json"; - -import Station from "@/scripts/interfaces/Station"; - -enum ConnState { - Loading = 0, - Error = 1, - Connected = 2, -} - -const apiURLS = { - stationDataURL: "https://api.td2.info.pl:9640/?method=getStationsOnline", - trainDataURL: "https://api.td2.info.pl:9640/?method=getTrainsOnline", - dispatcherDataURL: - "https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1", -}; - -interface TimetableResponseData { - stopPoints: - | { - arrivalTime: string; - arrivalDelay: number; - departureTime: string; - departureDelay: number; - pointNameRAW: string; - }[] - | []; - trainInfo: { - timetableId: number; - trainCategoryCode: string; - }; -} - -interface OnlineStationsResponseData { - stationName: string; - stationHash: string; - maxUsers: number; - currentUsers: number; - spawnString: string; - dispatcherRate: number; - dispatcherName: string; - dispatcherExp: number; - dispatcherId: number; - region: string; - isOnline: number; -} - -let onlineStationsData: OnlineStationsResponseData[]; - -let onlineDispatchersData: [string, string, number, number][]; - -let onlineTrainsData: { - isOnline: number; - region: string; - trainNo: number; - station: { stationName: string }; -}[]; - -const queryStations = (async () => { - return (await axios.get(apiURLS.stationDataURL)).data.message; -})(); - -const queryTrains = (async () => { - return await (await axios.get(apiURLS.trainDataURL)).data.message; -})(); - -const queryDisptachers = (async () => { - return await (await axios.get(apiURLS.dispatcherDataURL)).data.message; -})(); - -const queryTimetableData = async ( - trainNo: number -): Promise => - ( - await axios.get( - `https://api.td2.info.pl:9640/?method=readFromSWDR&value=getTimetable%3B${trainNo}%3Beu` - ) - ).data.message; - -async function getScheduledTrains(stationName: string) { - let scheduledTrains: any[] = []; - - for (let train of onlineTrainsData) { - if (train.region !== "eu" || !train.isOnline) continue; - - const timetable = await queryTimetableData(train.trainNo); - - if (!timetable.trainInfo) continue; - - const stop = timetable.stopPoints.find((point) => { - return ( - stationName.toLowerCase().includes(point.pointNameRAW.toLowerCase()) || - stationName - .toLowerCase() - .includes(point.pointNameRAW.toLowerCase().split(" ")[0]) || - stationName - .toLowerCase() - .includes(point.pointNameRAW.toLowerCase().split(",")[0]) - ); - }); - - if (!stop) continue; - - scheduledTrains.push({ - arrivalTime: stop?.arrivalTime, - departureTime: stop?.departureTime, - trainCategory: timetable.trainInfo?.trainCategoryCode, - trainNo: train.trainNo, - }); - } - - return scheduledTrains; -} - -@Module -class Store extends VuexModule { - private trainCount: number = 0; - private stationCount: number = 0; - - private connectionState: ConnState = ConnState.Loading; - - private stations: Station[] = []; - - // private scheduledTrains: { - // trainNo: number; - // trainCategory: string; - // arrivalTime: string; - // departureTime: string; - // }[] = []; - - private filteredStations: {}[] = []; - - private filterInitStates = { - default: false, - notDefault: false, - nonPublic: false, - SPK: false, - SCS: false, - ręczne: false, - mechaniczne: false, - współczesna: false, - kształtowa: false, - historyczna: false, - mieszana: false, - minLevel: 0, - minOneWayCatenary: 0, - minOneWay: 0, - minTwoWayCatenary: 0, - minTwoWay: 0, - "no-1track": false, - "no-2track": false, - free: true, - occupied: false, - ending: false, - } as const; - - private filters: any = { ...this.filterInitStates }; - - get getStationCount(): number { - return this.stationCount; - } - - get getTrainCount(): number { - return this.trainCount; - } - - get getStations() { - return this.filteredStations; - } - - get getAllStations() { - return this.stations; - } - - get getFilters() { - return this.filters; - } - - get getConnectionState() { - return this.connectionState; - } - - @Action - public setFilter(payload: { filterName: string; value: number | boolean }) { - this.context.commit("mutateFilter", payload); - this.context.commit("filterStations"); - } - - @Action - public resetFilters() { - this.context.commit("resetFilterList"); - this.context.commit("filterStations"); - } - - @Action - public initStations() { - this.context.commit("loadAllStations"); - this.context.dispatch("fetchStations"); - - setInterval(() => this.context.dispatch("fetchStations"), 10000); - } - - @Action - private fetchStations() { - Promise.all([queryStations, queryTrains, queryDisptachers]) - .then(async (response) => { - onlineStationsData = response[0]; - onlineTrainsData = response[1]; - onlineDispatchersData = response[2]; - - const updatedStations = await Promise.all( - onlineStationsData - .filter((station) => station.region === "eu" && station.isOnline) - .map(async (station) => { - const stationStatus = onlineDispatchersData.find( - (status) => - status[0] == station.stationHash && status[1] == "eu" - ); - - let statusLabel = ""; - let statusTimestamp = -1; - - if (!stationStatus) statusLabel = "NIEZALOGOWANY"; - else { - let statusCode = stationStatus[2]; - statusTimestamp = stationStatus[3]; - - statusLabel = "NIEDOSTĘPNY"; - - switch (statusCode) { - case 0: - if (statusTimestamp - Date.now() > 21000000) - statusLabel = "BEZ LIMITU"; - else - statusLabel = - "DO " + - new Date(statusTimestamp).toLocaleTimeString("en-US", { - hour12: false, - hour: "2-digit", - minute: "2-digit", - }); - break; - - case 1: - statusLabel = "Z/W"; - break; - - case 2: - if (statusTimestamp == 0) statusLabel = "KOŃCZY"; - break; - - case 3: - statusLabel = "BRAK MIEJSCA"; - break; - - default: - break; - } - } - - const trains = onlineTrainsData.filter( - (train) => - train.region === "eu" && - train.isOnline && - train.station.stationName === station.stationName - ); - - const stationData = data.find( - (s) => s.stationName === station.stationName - ) || { stationName: station.stationName, stationURL: "" }; - - // let scheduledTrains = await getScheduledTrains( - // station.stationName - // ); - - let scheduledTrains: any[] = []; - - return { - ...stationData, - stationHash: station.stationHash, - maxUsers: station.maxUsers, - currentUsers: station.currentUsers, - spawnString: - station.spawnString && - station.spawnString - .split(";") - .map((v) => - v.split(",")[6] ? v.split(",")[6] : v.split(",")[0] - ), - dispatcherName: station.dispatcherName, - dispatcherRate: station.dispatcherRate, - dispatcherId: station.dispatcherId, - dispatcherExp: station.dispatcherExp, - occupiedTo: statusLabel, - statusTimestamp, - trains, - scheduledTrains, - }; - }) - ); - - // const scheduled = await testLoad(); - - // for (let stationName in scheduled) { - // let t = updatedStations.find( - // (updated) => updated.stationName === stationName - // ); - - // if (!t) continue; - - // t.scheduledTrains = scheduled[stationName]; - // } - - this.context.commit("updateStations", { - updatedStations, - trainCount: onlineTrainsData.filter( - (train) => train.isOnline && train.region === "eu" - ).length, - }); - - this.context.commit("filterStations"); - this.context.commit("setConnState", ConnState.Connected); - }) - .catch((err) => { - this.context.commit("setConnState", ConnState.Error); - }); - } - - @Mutation - private filterStations() { - this.filteredStations = this.stations.filter((station) => { - if ((station.nonPublic || !station.reqLevel) && this.filters["nonPublic"]) - return false; - if (!station.reqLevel || station.reqLevel == "-1") return true; - - if ( - station.online && - station.occupiedTo == "KOŃCZY" && - this.filters["ending"] - ) - return false; - if (station.online && this.filters["occupied"]) return false; - if (!station.online && this.filters["free"]) return false; - - if (station.default && this.filters["default"]) return false; - if (!station.default && this.filters["notDefault"]) return false; - - if (station.reqLevel < this.filters["minLevel"]) return false; - - if ( - this.filters["no-1track"] && - (station.routes.oneWay.catenary != 0 || - station.routes.oneWay.noCatenary != 0) - ) - return false; - if ( - this.filters["no-2track"] && - (station.routes.twoWay.catenary != 0 || - station.routes.twoWay.noCatenary != 0) - ) - return false; - - if (station.routes.oneWay.catenary < this.filters["minOneWayCatenary"]) - return false; - if (station.routes.oneWay.noCatenary < this.filters["minOneWay"]) - return false; - - if (station.routes.twoWay.catenary < this.filters["minTwoWayCatenary"]) - return false; - if (station.routes.twoWay.noCatenary < this.filters["minTwoWay"]) - return false; - - if (this.filters[station.controlType]) return false; - if (this.filters[station.signalType]) return false; - - if (this.filters["SPK"] && station.controlType.includes("SPK")) - return false; - if (this.filters["SCS"] && station.controlType.includes("SCS")) - return false; - if ( - this.filters["mechaniczne"] && - station.controlType.includes("mechaniczne") - ) - return false; - if (this.filters["ręczne"] && station.controlType.includes("ręczne")) - return false; - - return true; - }); - } - - @Mutation - private loadAllStations() { - this.stations = data.map((stationData) => ({ - stationProject: "", - spawnString: "", - stationHash: "", - maxUsers: 0, - currentUsers: 0, - dispatcherName: "", - dispatcherRate: 0, - dispatcherExp: -1, - dispatcherId: 0, - online: false, - occupiedTo: "WOLNA", - statusTimestamp: 0, - scheduledTrains: [], - ...stationData, - })); - } - - @Mutation - private updateStations({ updatedStations, trainCount }) { - for (let i = 0; i < this.stations.length; i++) { - const toUpdate: any = updatedStations.find( - (updated: any) => updated.stationName === this.stations[i].stationName - ); - - if (!toUpdate) { - this.stations[i].online = false; - this.stations[i].occupiedTo = "WOLNA"; - this.stations[i].statusTimestamp = -1; - this.stations[i].dispatcherExp = -1; - continue; - } - - this.stations[i] = { ...this.stations[i], ...toUpdate }; - this.stations[i].online = true; - - updatedStations = updatedStations.filter( - (updated: any) => updated.stationName !== this.stations[i].stationName - ); - } - - // Dodawanie do listy online potencjalnych scenerii niewpisanych do bazy - updatedStations.forEach((updated: any) => { - const toUpdate: any = this.stations.find( - (station) => station.stationName === updated.stationName - ); - - if (!toUpdate) { - this.stations.push({ ...updated, online: true, reqLevel: "-1" }); - } - }); - - // Aktualizacja liczników - this.stationCount = this.stations.filter( - (station) => station.online - ).length; - this.trainCount = trainCount; - } - - @Mutation - private mutateFilter(payload: { - filterName: string; - value: number | boolean; - }) { - this.filters[payload.filterName] = payload.value; - } - - @Mutation - private resetFilterList() { - this.filters = { ...this.filterInitStates }; - } - - @Mutation - private setConnState(state: ConnState) { - this.connectionState = state; - } -} - -export default Store; diff --git a/src/store/modules/trainsModule.ts b/src/store/modules/trainsModule.ts index 5586e2f..1cdbc52 100644 --- a/src/store/modules/trainsModule.ts +++ b/src/store/modules/trainsModule.ts @@ -50,6 +50,7 @@ interface TimetableData { skr: boolean; sceneries: string[]; routeDistance: number; + stopPoints?: {}[]; } const getTimetableURL = (trainNo: number) => @@ -79,65 +80,65 @@ export default class TrainsModule extends VuexModule { let onlineTrainsData: TrainData[] = trainDataResponse.data.message; return await Promise.all( - onlineTrainsData - .filter((train) => train.isOnline) - .map(async (train) => { - const timetableResponseData: TimetableResponseData | null = ( - await axios.get(getTimetableURL(train.trainNo)) - ).data.message; + onlineTrainsData.map(async (train) => { + const timetableResponseData: TimetableResponseData | null = ( + await axios.get(getTimetableURL(train.trainNo)) + ).data.message; - let timetableData: TimetableData | null = null; + let timetableData: TimetableData | null = null; - if (timetableResponseData && timetableResponseData.trainInfo) { - const routeDistance: number = - timetableResponseData.stopPoints[ - timetableResponseData.stopPoints.length - 1 - ].pointDistance; + if (timetableResponseData && timetableResponseData.trainInfo) { + const routeDistance: number = + timetableResponseData.stopPoints[ + timetableResponseData.stopPoints.length - 1 + ].pointDistance; - timetableData = { - ...timetableResponseData.trainInfo, - routeDistance, - }; - } - - const locoType = train.dataCon.split(";") - ? train.dataCon.split(";")[0] - : train.dataCon; - - const stopPoints = timetableResponseData?.stopPoints.reduce( - (acc, point) => { - if (point.pointName.includes("strong")) { - acc.push(point.pointNameRAW); - } - - return acc; - }, - [] as string[] - ); - - return { - driverId: train.driverId, - driverName: train.driverName, - trainNo: train.trainNo, - currentStationName: train.station.stationName, - mass: train.dataMass, - length: train.dataLength, - speed: train.dataSpeed, - distance: train.dataDistance, - signal: train.dataSignal, - connectedTrack: train.dataSceneryConnection, - locoType, - locoURL: getLocoURL(locoType), - noTimetable: timetableData == null, - route: timetableData && timetableData.route, - timetableId: timetableData && timetableData.timetableId, - category: timetableData && timetableData.trainCategoryCode, - routeDistance: (timetableData && timetableData.routeDistance) || 0, - sceneries: stopPoints, - TWR: timetableData && timetableData.twr, - SKR: timetableData && timetableData.skr, + timetableData = { + ...timetableResponseData.trainInfo, + routeDistance, + stopPoints: timetableResponseData.stopPoints, }; - }) + } + + const locoType = train.dataCon.split(";") + ? train.dataCon.split(";")[0] + : train.dataCon; + + const stopPoints = timetableResponseData?.stopPoints.reduce( + (acc, point) => { + if (point.pointName.includes("strong")) { + acc.push(point.pointNameRAW); + } + + return acc; + }, + [] as string[] + ); + + return { + driverId: train.driverId, + driverName: train.driverName, + trainNo: train.trainNo, + currentStationName: train.station.stationName, + mass: train.dataMass, + length: train.dataLength, + speed: train.dataSpeed, + distance: train.dataDistance, + signal: train.dataSignal, + connectedTrack: train.dataSceneryConnection, + locoType, + locoURL: getLocoURL(locoType), + noTimetable: timetableData == null, + route: timetableData?.route, + timetableId: timetableData?.timetableId, + category: timetableData?.trainCategoryCode, + routeDistance: timetableData?.routeDistance || 0, + sceneries: stopPoints, + stopPoints: timetableData?.stopPoints, + TWR: timetableData?.twr, + SKR: timetableData?.skr, + }; + }) ); } diff --git a/src/views/StationsView.vue b/src/views/StationsView.vue index ccb25c6..ba40faf 100644 --- a/src/views/StationsView.vue +++ b/src/views/StationsView.vue @@ -6,7 +6,6 @@ -
@@ -22,6 +21,9 @@ import { Vue, Component } from "vue-property-decorator"; import { Getter, Action } from "vuex-class"; import Station from "@/scripts/interfaces/Station"; +import Train from "@/scripts/interfaces/Train"; + +import inputData from "@/data/options.json"; import Loading from "@/components/App/Loading.vue"; import Error from "@/components/App/Error.vue"; @@ -30,8 +32,6 @@ import StationTable from "@/components/StationsView/StationTable.vue"; import StationCard from "@/components/StationsView/StationCard.vue"; import Options from "@/components/StationsView/Options.vue"; -import inputData from "@/data/options.json"; - enum ConnState { Loading = 0, Error = 1, diff --git a/src/views/TrainsView.vue b/src/views/TrainsView.vue index c4b0001..04707ac 100644 --- a/src/views/TrainsView.vue +++ b/src/views/TrainsView.vue @@ -7,12 +7,28 @@
@@ -48,7 +64,10 @@ import axios from "axios"; }, }) export default class TrainsView extends Vue { + exitIcon = require("@/assets/icon-exit.svg"); + @Getter("trainsDataList") trains!: Train[]; + @Getter("trainsDataState") connectionState; @Action("fetchTrainsData") fetchTrainsData; @@ -70,7 +89,9 @@ export default class TrainsView extends Vue { ? train.trainNo.toString().includes(this.searchedTrain) : true) && (this.searchedDriver.length > 0 - ? train.driverName.includes(this.searchedDriver) + ? train.driverName + .toLowerCase() + .includes(this.searchedDriver.toLowerCase()) : true) ) .sort((a, b) => { @@ -107,12 +128,6 @@ export default class TrainsView extends Vue { return 0; }); } - - mounted() { - this.fetchTrainsData(); - - setInterval(this.fetchTrainsData, 5000); - } } @@ -142,17 +157,34 @@ export default class TrainsView extends Vue { } .search { - &-input { + &-box { + position: relative; + background: #333; - border: none; border-radius: 0.5em; + min-width: 150px; + } + + &-input { + border: none; padding: 0.5rem 1rem; margin: 0; font-size: 1em; - min-width: 150px; + min-width: 85%; + } + + &-exit { + position: absolute; + cursor: pointer; + + top: 50%; + right: 10px; + transform: translateY(-50%); + + width: 1em; } } }