diff --git a/src/components/SceneryView/SceneryInfo.vue b/src/components/SceneryView/SceneryInfo.vue
index 4f9e1ab..9e9c5f1 100644
--- a/src/components/SceneryView/SceneryInfo.vue
+++ b/src/components/SceneryView/SceneryInfo.vue
@@ -391,12 +391,8 @@ h3 {
-webkit-transition: background-color 200ms;
}
- &.no-timetable {
- pointer-events: none;
-
- & > .user_train {
- background-color: $no-timetable;
- }
+ &.no-timetable .user_train {
+ background-color: $no-timetable;
}
&.departed > &_train {
diff --git a/src/components/SceneryView/SceneryTimetable.vue b/src/components/SceneryView/SceneryTimetable.vue
index bd2b86b..fcd9696 100644
--- a/src/components/SceneryView/SceneryTimetable.vue
+++ b/src/components/SceneryView/SceneryTimetable.vue
@@ -347,7 +347,7 @@ h3 {
}
&.empty {
- color: $accentCol;
+ color: #bbb;
}
}
diff --git a/src/components/StationsView/StationTable.vue b/src/components/StationsView/StationTable.vue
index ce969fc..3c180f8 100644
--- a/src/components/StationsView/StationTable.vue
+++ b/src/components/StationsView/StationTable.vue
@@ -207,18 +207,18 @@
).length
}}
-
-
+
{{ $t("sceneries.no-stations") }}
+
+
+ {{ $t("app.loading") }}
+
@@ -228,7 +228,11 @@ import { Component, Prop } from "vue-property-decorator";
import Station from "@/scripts/interfaces/Station";
import styleMixin from "@/mixins/styleMixin";
+import { Getter } from "vuex-class";
+
import Options from "@/components/StationsView/Options.vue";
+import { StoreData } from "@/scripts/interfaces/StoreData";
+import { DataStatus } from "@/scripts/enums/DataStatus";
@Component({
components: { Options },
@@ -240,6 +244,8 @@ export default class StationTable extends styleMixin {
@Prop() readonly setFocusedStation!: () => void;
@Prop() readonly changeSorter!: () => void;
+ @Getter("getAllData") storeAPIData!: StoreData;
+
likeIcon: string = require("@/assets/icon-like.svg");
spawnIcon: string = require("@/assets/icon-spawn.svg");
timetableIcon: string = require("@/assets/icon-timetable.svg");
@@ -286,6 +292,10 @@ export default class StationTable extends styleMixin {
query: { station: station.stationName.replaceAll(" ", "_") },
});
}
+
+ get isDataLoaded() {
+ return this.storeAPIData.dataConnectionStatus == DataStatus.Loaded;
+ }
}
diff --git a/src/scripts/interfaces/Station.ts b/src/scripts/interfaces/Station.ts
index e92d245..f654139 100644
--- a/src/scripts/interfaces/Station.ts
+++ b/src/scripts/interfaces/Station.ts
@@ -1,5 +1,5 @@
-import Train from './Train';
-import ScheduledTrain from './ScheduledTrain';
+import Train from "./Train";
+import ScheduledTrain from "./ScheduledTrain";
export default interface Station {
stationName: string;
@@ -52,6 +52,9 @@ export default interface Station {
statusTimeString: string;
statusID: string;
- stationTrains: Train[];
+ stationTrains: {
+ driverName: number;
+ trainNo: number;
+ }[];
scheduledTrains: ScheduledTrain[];
}
diff --git a/src/scripts/interfaces/Train.ts b/src/scripts/interfaces/Train.ts
index 0363502..6308bd3 100644
--- a/src/scripts/interfaces/Train.ts
+++ b/src/scripts/interfaces/Train.ts
@@ -1,4 +1,4 @@
-import TrainStop from '@/scripts/interfaces/TrainStop';
+import TrainStop from "@/scripts/interfaces/TrainStop";
export default interface Train {
mass: number;
@@ -16,6 +16,8 @@ export default interface Train {
locoType: string;
online: boolean;
+ cars: string[];
+
timetableData?: {
timetableId: number;
category: string;
diff --git a/src/scripts/interfaces/TrainStop.ts b/src/scripts/interfaces/TrainStop.ts
index 3bfbcb2..df2ad9a 100644
--- a/src/scripts/interfaces/TrainStop.ts
+++ b/src/scripts/interfaces/TrainStop.ts
@@ -5,17 +5,17 @@ export default interface TrainStop {
stopDistance: number;
mainStop: boolean;
- arrivalLine: string;
- arrivalTimeString: string;
+ arrivalLine: string | null;
+ arrivalTimeString: string | null;
arrivalTimestamp: number;
- arrivalRealTimeString: string;
+ arrivalRealTimeString: string | null;
arrivalRealTimestamp: number;
arrivalDelay: number;
- departureLine: string;
- departureTimeString: string;
+ departureLine: string | null;
+ departureTimeString: string | null;
departureTimestamp: number;
- departureRealTimeString: string;
+ departureRealTimeString: string | null;
departureRealTimestamp: number;
departureDelay: number;
@@ -25,5 +25,5 @@ export default interface TrainStop {
terminatesHere: boolean;
confirmed: boolean;
stopped: boolean;
- stopTime: number;
+ stopTime: number | null;
}
diff --git a/src/scripts/utils/storeUtils.ts b/src/scripts/utils/storeUtils.ts
index 7c84781..3939bc0 100644
--- a/src/scripts/utils/storeUtils.ts
+++ b/src/scripts/utils/storeUtils.ts
@@ -69,7 +69,7 @@ const parseSpawns = (spawnString: string) => {
});
};
-const getTimestamp = (date: string) => (date ? new Date(date).getTime() : 0);
+const getTimestamp = (date: string | null) => (date ? new Date(date).getTime() : 0);
const timestampToString = (timestamp: number) =>
new Date(timestamp).toLocaleTimeString("pl-PL", {
diff --git a/src/store/store.ts b/src/store/store.ts
index bbad70a..bc458ce 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -11,23 +11,42 @@ import utils from "@/scripts/utils/storeUtils";
import { DataStatus } from "@/scripts/enums/DataStatus";
import { StoreData } from "@/scripts/interfaces/StoreData";
-interface TimetableData {
- trainNo: number;
- driverName: string;
- driverId: number;
- currentStationName: string;
- currentStationHash: string;
- timetableId: number;
- category: string;
- route: string;
- TWR: boolean;
- SKR: boolean;
- routeDistance: number;
- followingStops: TrainStop[];
- followingSceneries: string[];
+interface TimetableAPIData {
+ trainInfo: {
+ timetableId: number;
+ trainNo: number;
+ trainCategoryCode: string;
+ driverId: number;
+ driverName: string;
+ route: string;
+ twr: boolean;
+ skr: boolean;
+ sceneries: string[];
+ };
+
+ stopPoints: {
+ arrivalLine: string | null;
+ arrivalTime: string | null;
+ arrivalDelay: number;
+ arrivalRealTime: string | null;
+ pointDistance: number;
+ pointName: string;
+ pointNameRAW: string;
+ entryId: number;
+ pointId: number;
+ comments: string | null;
+ confirmed: boolean;
+ isStopped: boolean;
+ pointStopTime: number | null;
+ pointStopType: string;
+ departureLine: string | null;
+ departureTime: string | null;
+ departureDelay: number;
+ departureRealTime: string | null;
+ }[];
}
-interface IOnlineStationData {
+interface StationAPIData {
dispatcherId: number;
dispatcherName: string;
dispatcherIsSupporter: boolean;
@@ -46,6 +65,77 @@ interface IOnlineStationData {
dispatcherRate: number;
}
+interface TrainAPIData {
+ trainNo: number;
+ driverId: number;
+ driverName: string;
+ driverIsSupporter: boolean;
+ station: StationAPIData;
+ dataSignal: string;
+ dataSceneryConnection: string;
+ dataDistance: number;
+ dataCon: string;
+ dataSpeed: number;
+ dataMass: number;
+ dataLength: number;
+ region: string;
+ isOnline: boolean;
+ lastSeen: number;
+}
+
+interface Timetable {
+ trainNo: number;
+ driverName: string;
+ driverId: number;
+ currentStationName: string;
+ currentStationHash: string;
+ timetableId: number;
+ category: string;
+ route: string;
+ TWR: boolean;
+ SKR: boolean;
+ routeDistance: number;
+ followingStops: TrainStop[];
+ followingSceneries: string[];
+}
+
+// interface OnlineStationData {
+// dispatcherId: number;
+// dispatcherName: string;
+// dispatcherIsSupporter: boolean;
+// stationName: string;
+// stationHash: string;
+// region: string;
+// maxUsers: number;
+// currentUsers: number;
+// spawn: number;
+// lastSeen: number;
+// dispatcherExp: number;
+// nameFromHeader: string;
+// spawnString: string;
+// networkConnectionString: string;
+// isOnline: number;
+// dispatcherRate: number;
+// }
+
+// interface TrainData {
+// trainNo: number;
+// driverId: number;
+// driverName: string;
+// driverIsSupporter: boolean;
+// dataSignal: string;
+// dataSceneryConnection: string;
+// dataDistance: number;
+// dataCon: string;
+// dataSpeed: number;
+// dataMass: number;
+// dataLength: number;
+// station: OnlineStationData;
+// region: string;
+// isOnline: number;
+// lastSeen: number;
+// }
+
const URLs = {
stations: "https://api.td2.info.pl:9640/?method=getStationsOnline",
trains: "https://api.td2.info.pl:9640/?method=getTrainsOnline",
@@ -108,15 +198,95 @@ export default class Store extends VuexModule {
setInterval(() => this.context.dispatch("fetchOnlineData"), 20000);
}
+ // Fetching all station and train data from API
+ @Action
+ async fetchOnlineData() {
+ 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 updatedStationList = onlineStationsData.reduce((acc, station) => {
+ if (station.region !== "eu" || !station.isOnline) return acc;
+
+ const stationStatus = onlineDispatchersData.find((status: string[]) => status[0] == station.stationHash && status[1] == "eu");
+
+ const statusTimestamp = utils.getStatusTimestamp(stationStatus);
+ const statusID = utils.getStatusID(stationStatus);
+
+ const stationTrains = onlineTrainsData
+ .filter(train => train.region === "eu" && train.isOnline && train.station.stationName === station.stationName)
+ .map(train => ({ driverName: train.driverName, trainNo: train.trainNo }));
+
+ acc.push({
+ stationName: station.stationName,
+ stationHash: station.stationHash,
+ maxUsers: station.maxUsers,
+ currentUsers: station.currentUsers,
+ spawns: utils.parseSpawns(station.spawnString),
+ dispatcherName: station.dispatcherName,
+ dispatcherRate: station.dispatcherRate,
+ dispatcherId: station.dispatcherId,
+ dispatcherExp: station.dispatcherExp,
+ dispatcherIsSupporter: station.dispatcherIsSupporter,
+ stationTrains,
+ statusTimestamp,
+ statusID,
+ statusTimeString: utils.timestampToString(statusTimestamp)
+ });
+
+ return acc;
+ }, [] as any);
+
+ const updatedTrainList = await Promise.all(
+ onlineTrainsData
+ .filter(train => train.region === "eu")
+ .map(async train => {
+ const locoType = train.dataCon.split(";") ? train.dataCon.split(";")[0] : train.dataCon;
+
+ return {
+ trainNo: train.trainNo,
+ mass: train.dataMass,
+ length: train.dataLength,
+ speed: train.dataSpeed,
+ distance: train.dataDistance,
+ signal: train.dataSignal,
+ online: train.isOnline,
+ driverId: train.driverId,
+ driverName: train.driverName,
+ currentStationName: train.station.stationName,
+ currentStationHash: train.station.stationHash,
+ connectedTrack: train.dataSceneryConnection,
+ locoType,
+ locoURL: utils.getLocoURL(locoType),
+ cars: train.dataCon.split(";").filter((train, i) => i > 0) || []
+ };
+ })
+ );
+
+ this.context.commit("updateOnlineStations", updatedStationList);
+ this.context.commit("updateOnlineTrains", updatedTrainList);
+
+ this.context.dispatch("fetchTimetableData");
+ })
+ .catch(() => {
+ this.context.commit("setDataConnectionStatus", DataStatus.Error);
+ });
+ }
+
+ // Fetching timetable data from API basing on online trains
@Action({ commit: "updateTimetableData" })
async fetchTimetableData() {
- return this.trainList.reduce(async (acc: Promise
, train) => {
- const timetable = await (await axios.get(utils.timetableURL(train.trainNo))).data.message;
+ return this.trainList.reduce(async (acc: Promise, train: Train) => {
+ const timetable: TimetableAPIData = await (await axios.get(utils.timetableURL(train.trainNo))).data.message;
const trainInfo = timetable.trainInfo;
if (!timetable || !trainInfo) return acc;
const followingStops: TrainStop[] = timetable.stopPoints.reduce((stopsAcc: TrainStop[], point) => {
+ if (point.pointNameRAW.toLowerCase().includes("sbl")) return stopsAcc;
+
const arrivalTimestamp = utils.getTimestamp(point.arrivalTime);
const arrivalRealTimestamp = utils.getTimestamp(point.arrivalRealTime);
@@ -132,16 +302,16 @@ export default class Store extends VuexModule {
mainStop: point.pointName.includes("strong"),
arrivalLine: point.arrivalLine,
- arrivalTimeString: utils.timestampToString(point.arrivalTime),
+ arrivalTimeString: point.arrivalTime,
arrivalTimestamp: arrivalTimestamp,
- arrivalRealTimeString: utils.timestampToString(point.arrivalRealTime),
+ arrivalRealTimeString: point.arrivalRealTime,
arrivalRealTimestamp: arrivalRealTimestamp,
arrivalDelay: point.arrivalDelay,
departureLine: point.departureLine,
- departureTimeString: utils.timestampToString(point.departureTime),
+ departureTimeString: point.departureTime,
departureTimestamp: departureTimestamp,
- departureRealTimeString: utils.timestampToString(point.departureRealTime),
+ departureRealTimeString: point.departureRealTime,
departureRealTimestamp: departureRealTimestamp,
departureDelay: point.departureDelay,
@@ -176,81 +346,6 @@ export default class Store extends VuexModule {
}, Promise.resolve([]));
}
- @Action
- async fetchOnlineData() {
- Promise.all([axios.get(URLs.stations), axios.get(URLs.trains), axios.get(URLs.dispatchers)])
- .then(async response => {
- const onlineStationsData: IOnlineStationData[] = response[0].data.message;
- const onlineTrainsData = await response[1].data.message;
- const onlineDispatchersData = await response[2].data.message;
-
- let updatedStationList = onlineStationsData.reduce((acc, station) => {
- if (station.region !== "eu" || !station.isOnline) return acc;
-
- const stationStatus = onlineDispatchersData.find(status => status[0] == station.stationHash && status[1] == "eu");
-
- const statusTimestamp = utils.getStatusTimestamp(stationStatus);
- const statusID = utils.getStatusID(stationStatus);
-
- const stationTrains = onlineTrainsData.filter(
- train => train.region === "eu" && train.isOnline && train.station.stationName === station.stationName
- );
-
- acc.push({
- stationName: station.stationName,
- stationHash: station.stationHash,
- maxUsers: station.maxUsers,
- currentUsers: station.currentUsers,
- spawns: utils.parseSpawns(station.spawnString),
- dispatcherName: station.dispatcherName,
- dispatcherRate: station.dispatcherRate,
- dispatcherId: station.dispatcherId,
- dispatcherExp: station.dispatcherExp,
- dispatcherIsSupporter: station.dispatcherIsSupporter,
- stationTrains,
- statusTimestamp,
- statusID,
- statusTimeString: utils.timestampToString(statusTimestamp)
- });
-
- return acc;
- }, [] as any);
-
- let updatedTrainList = await Promise.all(
- onlineTrainsData
- .filter(train => train.region === "eu")
- .map(async train => {
- const locoType = train.dataCon.split(";") ? train.dataCon.split(";")[0] : train.dataCon;
-
- return {
- trainNo: train.trainNo,
- mass: train.dataMass,
- length: train.dataLength,
- speed: train.dataSpeed,
- distance: train.dataDistance,
- signal: train.dataSignal,
- online: train.isOnline,
- driverId: train.driverId,
- driverName: train.driverName,
- currentStationName: train.station.stationName,
- currentStationHash: train.station.stationHash,
- connectedTrack: train.dataSceneryConnection,
- locoType,
- locoURL: utils.getLocoURL(locoType)
- };
- })
- );
-
- this.context.commit("updateOnlineStations", updatedStationList);
- this.context.commit("updateOnlineTrains", updatedTrainList);
-
- this.context.dispatch("fetchTimetableData");
- })
- .catch(err => {
- this.context.commit("setDataConnectionStatus", DataStatus.Error);
- });
- }
-
//MUTATIONS
@Mutation
private setDataConnectionStatus(status: DataStatus) {
@@ -336,7 +431,7 @@ export default class Store extends VuexModule {
private updateOnlineStations(updatedStationList: any[]) {
this.stationList = this.stationList.reduce((acc: Station[], station) => {
const onlineStationData = updatedStationList.find(updatedStation => updatedStation.stationName === station.stationName);
- const registeredStation = JSONStationData.find(data => data[0] === station.stationName);
+ const listedStationData = JSONStationData.find(data => data[0] === station.stationName);
if (onlineStationData)
acc.push({
@@ -344,7 +439,7 @@ export default class Store extends VuexModule {
...onlineStationData,
online: true
});
- else if (registeredStation)
+ else if (listedStationData)
acc.push({
...station,
stationProject: "",
@@ -374,7 +469,7 @@ export default class Store extends VuexModule {
this.stationList.push({
...uStation,
scheduledTrains: [],
- stationTrains: [],
+ stationTrains: uStation.stationTrains || [],
subStations: [],
online: true,
reqLevel: "-1",
@@ -402,11 +497,11 @@ export default class Store extends VuexModule {
}
@Mutation
- private updateTimetableData(timetableList: TimetableData[]) {
+ private updateTimetableData(timetableList: Timetable[]) {
this.stationList = this.stationList.map(station => {
const stationName = station.stationName.toLowerCase();
- const scheduledTrains: Station["scheduledTrains"] = timetableList.reduce((acc: Station["scheduledTrains"], timetable: TimetableData, index) => {
+ const scheduledTrains: Station["scheduledTrains"] = timetableList.reduce((acc: Station["scheduledTrains"], timetable: Timetable, index) => {
if (!timetable.followingSceneries.includes(station.stationHash)) return acc;
const stopInfoIndex = timetable.followingStops.findIndex(stop => {