mirror of
https://github.com/Spythere/srjp-td2.git
synced 2026-05-03 13:38:12 +00:00
chore: added outdated data indicator
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<tbody v-if="computedTimetable">
|
||||
<tbody>
|
||||
<tr v-for="(row, i) in computedTimetable">
|
||||
<td class="text-center align-top border border-white print:border-black">{{ row.realLine }}</td>
|
||||
|
||||
@@ -150,166 +150,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
import { useApiStore } from '../../stores/api.store';
|
||||
import type { PropType } from 'vue';
|
||||
import type { StopRow } from '../../types/common.types';
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
const apiStore = useApiStore();
|
||||
|
||||
const computedTimetable = computed(() => {
|
||||
if (!globalStore.selectedTrain) return null;
|
||||
|
||||
const timetable = globalStore.selectedTrain.timetable;
|
||||
|
||||
if (!timetable) return null;
|
||||
|
||||
let timeFrom = Date.now();
|
||||
|
||||
const headLocos = globalStore.selectedTrain.stockString
|
||||
.split(';')
|
||||
.slice(0, 3)
|
||||
.filter((s, i) => i == 0 || /-\d+$/.test(s))
|
||||
.map((s) => s.slice(0, s.indexOf('-')));
|
||||
|
||||
const stockVmax = 70,
|
||||
stockMass = Math.floor(globalStore.selectedTrain.mass / 1000),
|
||||
stockLength = globalStore.selectedTrain.length;
|
||||
|
||||
const timetablePath = timetable.path.split(';').map((pathEl) => {
|
||||
const [arrivalLine, scenery, departureLine] = pathEl.split(',');
|
||||
const sceneryName = scenery.split(' ').slice(0, -1).join(' ');
|
||||
|
||||
const sceneryData = apiStore.sceneryData?.find((sc) => sc.name == sceneryName) ?? null;
|
||||
const arrivalLineData = arrivalLine ? sceneryData?.routesInfo.find((rt) => rt.routeName == arrivalLine) ?? null : null;
|
||||
const departureLineData = departureLine ? sceneryData?.routesInfo.find((rt) => rt.routeName == departureLine) ?? null : null;
|
||||
|
||||
return {
|
||||
sceneryName,
|
||||
sceneryData: sceneryData ?? null,
|
||||
arrivalLine: arrivalLine ?? '',
|
||||
arrivalLineData,
|
||||
departureLine: departureLine ?? '',
|
||||
departureLineData,
|
||||
};
|
||||
});
|
||||
|
||||
const stopRows: StopRow[] = [];
|
||||
|
||||
let currentPathIndex = 0;
|
||||
let currentPath = timetablePath[0];
|
||||
|
||||
let lastDepartureTimestamp = 0;
|
||||
|
||||
let arrivalKm = 0,
|
||||
arrivalSpeed = currentPath.departureLineData?.routeSpeed ?? 0,
|
||||
arrivalTracks = currentPath.departureLineData?.routeTracks ?? 0;
|
||||
|
||||
let departureSpeed = currentPath.departureLineData?.routeSpeed ?? 0,
|
||||
departureTracks = currentPath.departureLineData?.routeTracks ?? 2;
|
||||
|
||||
let realLineNo = 0;
|
||||
|
||||
// console.debug('=========== ' + this.selectedTrain.trainNo + ' ===========');
|
||||
|
||||
for (const stop of timetable.stopList) {
|
||||
if (stop.arrivalLine && stop.arrivalLine == currentPath.arrivalLine) {
|
||||
arrivalKm = stop.stopDistance;
|
||||
|
||||
if (currentPath.arrivalLineData) {
|
||||
arrivalSpeed = currentPath.arrivalLineData.routeSpeed;
|
||||
arrivalTracks = currentPath.arrivalLineData.routeTracks;
|
||||
}
|
||||
|
||||
departureSpeed = arrivalSpeed;
|
||||
departureTracks = arrivalTracks;
|
||||
}
|
||||
|
||||
if (/^<strong>|, (podg|po)$|^(!_, pe)$/.test(stop.stopName)) {
|
||||
let correctedDepartureSpeed = 0,
|
||||
correctedDepartureTracks = 0;
|
||||
|
||||
const internalRouteInfo = stop.departureLine
|
||||
? currentPath.sceneryData?.routesInfo.find((route) => route.isInternal && route.routeName == stop.departureLine)
|
||||
: undefined;
|
||||
|
||||
if (internalRouteInfo) {
|
||||
correctedDepartureSpeed = internalRouteInfo.routeSpeed;
|
||||
departureSpeed = internalRouteInfo.routeSpeed;
|
||||
|
||||
correctedDepartureTracks = internalRouteInfo.routeTracks;
|
||||
departureTracks = internalRouteInfo.routeTracks;
|
||||
}
|
||||
|
||||
let rowData: StopRow = {
|
||||
isMain: /^<strong>/.test(stop.stopName),
|
||||
pointKm: stop.stopDistance.toFixed(3),
|
||||
pointName: stop.stopNameRAW,
|
||||
scheduledArrivalDate: stop.arrivalTimestamp ? new Date(stop.arrivalTimestamp) : null,
|
||||
scheduledDepartureDate: stop.departureTimestamp ? new Date(stop.departureTimestamp) : null,
|
||||
stopTime: stop.stopTime ? (stop.departureTimestamp - stop.arrivalTimestamp) / 60000 : 0,
|
||||
stopType: stop.stopType,
|
||||
sceneryName: currentPath.sceneryName,
|
||||
realLine: realLineNo == 0 ? ' - ' : realLineNo.toString(),
|
||||
driveTime: lastDepartureTimestamp ? stop.arrivalTimestamp - lastDepartureTimestamp : 0,
|
||||
additionalAbbrevs: [],
|
||||
controlAbbrevs: [],
|
||||
|
||||
arrivalKm: arrivalKm.toFixed(3),
|
||||
departureKm: stop.stopDistance.toFixed(3),
|
||||
|
||||
arrivalSpeed: arrivalSpeed,
|
||||
arrivalTracks: arrivalTracks,
|
||||
|
||||
departureSpeed: departureSpeed,
|
||||
departureTracks: departureTracks,
|
||||
|
||||
headLocos,
|
||||
stockVmax,
|
||||
stockLength,
|
||||
stockMass,
|
||||
};
|
||||
|
||||
// console.debug(stop.stopNameRAW, stop.departureLine);
|
||||
|
||||
arrivalKm = stop.stopDistance;
|
||||
arrivalSpeed = correctedDepartureSpeed || arrivalSpeed;
|
||||
arrivalTracks = correctedDepartureTracks || arrivalTracks;
|
||||
|
||||
if (stop.departureTimestamp) lastDepartureTimestamp = stop.departureTimestamp;
|
||||
|
||||
stopRows.push(rowData);
|
||||
}
|
||||
|
||||
if (stop.departureLine && stop.departureLine == currentPath.departureLine) {
|
||||
// Reverse search for last scenery checkpoint
|
||||
for (let i = stopRows.length - 1; i > 0; i--) {
|
||||
if (currentPath.departureLineData) {
|
||||
stopRows[i].departureTracks = currentPath.departureLineData.routeTracks;
|
||||
stopRows[i].departureSpeed = currentPath.departureLineData.routeSpeed;
|
||||
stopRows[i].realLine = currentPath.departureLineData.realLineNo?.toString() ?? ' - ';
|
||||
|
||||
if (stopRows[i].isMain || stopRows[i].pointName.endsWith(', podg')) {
|
||||
stopRows[i].departureSpeed = currentPath.departureLineData.routeSpeed;
|
||||
stopRows[i].departureTracks = currentPath.departureLineData.routeTracks;
|
||||
break;
|
||||
}
|
||||
|
||||
stopRows[i].arrivalSpeed = currentPath.departureLineData.routeSpeed;
|
||||
stopRows[i].arrivalTracks = currentPath.departureLineData.routeTracks;
|
||||
}
|
||||
}
|
||||
|
||||
currentPath = timetablePath[++currentPathIndex];
|
||||
}
|
||||
}
|
||||
|
||||
let timeTo = Date.now();
|
||||
|
||||
globalStore.generatedMs = timeTo - timeFrom;
|
||||
|
||||
return stopRows;
|
||||
defineProps({
|
||||
computedTimetable: {
|
||||
type: Object as PropType<StopRow[]>,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
v-model="selectedTrainId"
|
||||
@change="selectTrain"
|
||||
>
|
||||
<option value="" disabled>{{ apiStore.activeDataStatus == DataStatus.LOADING ? 'Ładowanie danych...' : 'Wybierz pociąg z listy' }}</option>
|
||||
<option :value="null" disabled>{{ apiStore.activeDataStatus == DataStatus.LOADING ? 'Ładowanie danych...' : 'Wybierz pociąg z listy' }}</option>
|
||||
<option :value="train.id" v-for="train in globalStore.activeTimetableTrains">
|
||||
{{ train.driverName }} | {{ train.timetable?.category }} {{ train.trainNo }}
|
||||
{{ train.driverName }} | {{ train.timetable?.category }} {{ train.trainNo }} [{{ getRegionNameById(train.region) }}]
|
||||
</option>
|
||||
</select>
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
<PrinterIcon class="text-white size-6" />
|
||||
</button>
|
||||
|
||||
<button class="bg-zinc-800 p-1 rounded-md hover:bg-zinc-700" @click="refreshData">
|
||||
<button class="bg-zinc-800 p-1 rounded-md hover:bg-zinc-700 relative" @click="refreshData">
|
||||
<ArrowPathIcon class="text-white size-6" />
|
||||
<div v-if="apiStore.isActiveDataOutdated" class="size-3 bg-green-300 rounded-full absolute -top-1 -right-1"></div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -30,6 +31,7 @@ import { useApiStore } from '../../stores/api.store';
|
||||
import { DataStatus } from '../../types/api.types';
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
import { PrinterIcon, ArrowPathIcon } from '@heroicons/vue/16/solid';
|
||||
import { getRegionNameById } from '../../utils/trainUtils';
|
||||
|
||||
// Stores
|
||||
const apiStore = useApiStore();
|
||||
@@ -38,8 +40,6 @@ const globalStore = useGlobalStore();
|
||||
// Variables & refs
|
||||
let selectedTrainId = ref(null) as Ref<string | null>;
|
||||
|
||||
// Computed
|
||||
|
||||
// Methods
|
||||
function selectTrain() {
|
||||
if (!apiStore.activeData) return;
|
||||
|
||||
@@ -5,17 +5,177 @@
|
||||
{{ globalStore.selectedTrain.timetable?.route.replace('|', ' - ') }}
|
||||
</b>
|
||||
|
||||
<table class="table-fixed mt-2 w-full border-collapse">
|
||||
<table class="table-fixed mt-2 w-full border-collapse" v-if="computedTimetable.length > 0">
|
||||
<TimetableHeader />
|
||||
<TimetableBody />
|
||||
<TimetableBody :computed-timetable="computedTimetable" />
|
||||
</table>
|
||||
|
||||
<div class="text-center font-bold text-zinc-400 p-2" v-else>Wybierz aktywny pociąg, aby wygenerować SRJP</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useApiStore } from '../../stores/api.store';
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
import TimetableBody from './TimetableBody.vue';
|
||||
import TimetableHeader from './TimetableHeader.vue';
|
||||
import type { StopRow } from '../../types/common.types';
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
</script>
|
||||
const apiStore = useApiStore();
|
||||
|
||||
const computedTimetable = computed(() => {
|
||||
if (!globalStore.selectedTrain) return [];
|
||||
|
||||
const timetable = globalStore.selectedTrain.timetable;
|
||||
|
||||
if (!timetable) return [];
|
||||
|
||||
let timeFrom = Date.now();
|
||||
|
||||
const headLocos = globalStore.selectedTrain.stockString
|
||||
.split(';')
|
||||
.slice(0, 3)
|
||||
.filter((s, i) => i == 0 || /-\d+$/.test(s))
|
||||
.map((s) => s.slice(0, s.indexOf('-')));
|
||||
|
||||
const stockVmax = 70,
|
||||
stockMass = Math.floor(globalStore.selectedTrain.mass / 1000),
|
||||
stockLength = globalStore.selectedTrain.length;
|
||||
|
||||
const timetablePath = timetable.path.split(';').map((pathEl) => {
|
||||
const [arrivalLine, scenery, departureLine] = pathEl.split(',');
|
||||
const sceneryName = scenery.split(' ').slice(0, -1).join(' ');
|
||||
|
||||
const sceneryData = apiStore.sceneryData?.find((sc) => sc.name == sceneryName) ?? null;
|
||||
const arrivalLineData = arrivalLine ? sceneryData?.routesInfo.find((rt) => rt.routeName == arrivalLine) ?? null : null;
|
||||
const departureLineData = departureLine ? sceneryData?.routesInfo.find((rt) => rt.routeName == departureLine) ?? null : null;
|
||||
|
||||
return {
|
||||
sceneryName,
|
||||
sceneryData: sceneryData ?? null,
|
||||
arrivalLine: arrivalLine ?? '',
|
||||
arrivalLineData,
|
||||
departureLine: departureLine ?? '',
|
||||
departureLineData,
|
||||
};
|
||||
});
|
||||
|
||||
const stopRows: StopRow[] = [];
|
||||
|
||||
let currentPathIndex = 0;
|
||||
let currentPath = timetablePath[0];
|
||||
|
||||
let lastDepartureTimestamp = 0;
|
||||
|
||||
let arrivalKm = 0,
|
||||
arrivalSpeed = currentPath.departureLineData?.routeSpeed ?? 0,
|
||||
arrivalTracks = currentPath.departureLineData?.routeTracks ?? 0;
|
||||
|
||||
let departureSpeed = currentPath.departureLineData?.routeSpeed ?? 0,
|
||||
departureTracks = currentPath.departureLineData?.routeTracks ?? 2;
|
||||
|
||||
let realLineNo = 0;
|
||||
|
||||
// console.debug('=========== ' + this.selectedTrain.trainNo + ' ===========');
|
||||
|
||||
for (const stop of timetable.stopList) {
|
||||
if (stop.arrivalLine && stop.arrivalLine == currentPath.arrivalLine) {
|
||||
arrivalKm = stop.stopDistance;
|
||||
|
||||
if (currentPath.arrivalLineData) {
|
||||
arrivalSpeed = currentPath.arrivalLineData.routeSpeed;
|
||||
arrivalTracks = currentPath.arrivalLineData.routeTracks;
|
||||
}
|
||||
|
||||
departureSpeed = arrivalSpeed;
|
||||
departureTracks = arrivalTracks;
|
||||
}
|
||||
|
||||
if (/^<strong>|, (podg|po)$|^(!_, pe)$/.test(stop.stopName)) {
|
||||
let correctedDepartureSpeed = 0,
|
||||
correctedDepartureTracks = 0;
|
||||
|
||||
const internalRouteInfo = stop.departureLine
|
||||
? currentPath.sceneryData?.routesInfo.find((route) => route.isInternal && route.routeName == stop.departureLine)
|
||||
: undefined;
|
||||
|
||||
if (internalRouteInfo) {
|
||||
correctedDepartureSpeed = internalRouteInfo.routeSpeed;
|
||||
departureSpeed = internalRouteInfo.routeSpeed;
|
||||
|
||||
correctedDepartureTracks = internalRouteInfo.routeTracks;
|
||||
departureTracks = internalRouteInfo.routeTracks;
|
||||
}
|
||||
|
||||
let rowData: StopRow = {
|
||||
isMain: /^<strong>/.test(stop.stopName),
|
||||
pointKm: stop.stopDistance.toFixed(3),
|
||||
pointName: stop.stopNameRAW,
|
||||
scheduledArrivalDate: stop.arrivalTimestamp ? new Date(stop.arrivalTimestamp) : null,
|
||||
scheduledDepartureDate: stop.departureTimestamp ? new Date(stop.departureTimestamp) : null,
|
||||
stopTime: stop.stopTime ? (stop.departureTimestamp - stop.arrivalTimestamp) / 60000 : 0,
|
||||
stopType: stop.stopType,
|
||||
sceneryName: currentPath.sceneryName,
|
||||
realLine: realLineNo == 0 ? ' - ' : realLineNo.toString(),
|
||||
driveTime: lastDepartureTimestamp ? stop.arrivalTimestamp - lastDepartureTimestamp : 0,
|
||||
additionalAbbrevs: [],
|
||||
controlAbbrevs: [],
|
||||
|
||||
arrivalKm: arrivalKm.toFixed(3),
|
||||
departureKm: stop.stopDistance.toFixed(3),
|
||||
|
||||
arrivalSpeed: arrivalSpeed,
|
||||
arrivalTracks: arrivalTracks,
|
||||
|
||||
departureSpeed: departureSpeed,
|
||||
departureTracks: departureTracks,
|
||||
|
||||
headLocos,
|
||||
stockVmax,
|
||||
stockLength,
|
||||
stockMass,
|
||||
};
|
||||
|
||||
// console.debug(stop.stopNameRAW, stop.departureLine);
|
||||
|
||||
arrivalKm = stop.stopDistance;
|
||||
arrivalSpeed = correctedDepartureSpeed || arrivalSpeed;
|
||||
arrivalTracks = correctedDepartureTracks || arrivalTracks;
|
||||
|
||||
if (stop.departureTimestamp) lastDepartureTimestamp = stop.departureTimestamp;
|
||||
|
||||
stopRows.push(rowData);
|
||||
}
|
||||
|
||||
if (stop.departureLine && stop.departureLine == currentPath.departureLine) {
|
||||
// Reverse search for last scenery checkpoint
|
||||
for (let i = stopRows.length - 1; i > 0; i--) {
|
||||
if (currentPath.departureLineData) {
|
||||
stopRows[i].departureTracks = currentPath.departureLineData.routeTracks;
|
||||
stopRows[i].departureSpeed = currentPath.departureLineData.routeSpeed;
|
||||
stopRows[i].realLine = currentPath.departureLineData.realLineNo?.toString() ?? ' - ';
|
||||
|
||||
if (stopRows[i].isMain || stopRows[i].pointName.endsWith(', podg')) {
|
||||
stopRows[i].departureSpeed = currentPath.departureLineData.routeSpeed;
|
||||
stopRows[i].departureTracks = currentPath.departureLineData.routeTracks;
|
||||
break;
|
||||
}
|
||||
|
||||
stopRows[i].arrivalSpeed = currentPath.departureLineData.routeSpeed;
|
||||
stopRows[i].arrivalTracks = currentPath.departureLineData.routeTracks;
|
||||
}
|
||||
}
|
||||
|
||||
currentPath = timetablePath[++currentPathIndex];
|
||||
}
|
||||
}
|
||||
|
||||
let timeTo = Date.now();
|
||||
|
||||
globalStore.generatedMs = timeTo - timeFrom;
|
||||
|
||||
return stopRows;
|
||||
});
|
||||
</script>
|
||||
|
||||
+16
-6
@@ -8,11 +8,14 @@ export const useApiStore = defineStore('api', {
|
||||
state() {
|
||||
return {
|
||||
client: null as AxiosInstance | null,
|
||||
|
||||
|
||||
activeData: null as ActiveData | null,
|
||||
sceneryData: null as SceneryData[] | null,
|
||||
|
||||
activeDataStatus: DataStatus.LOADING
|
||||
outdatedTimerId: -1,
|
||||
isActiveDataOutdated: false,
|
||||
|
||||
activeDataStatus: DataStatus.LOADING,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -36,13 +39,13 @@ export const useApiStore = defineStore('api', {
|
||||
this.client = axios.create({
|
||||
baseURL,
|
||||
});
|
||||
|
||||
|
||||
this.fetchSceneriesData();
|
||||
this.fetchActiveData();
|
||||
|
||||
setInterval(() => {
|
||||
this.fetchActiveData();
|
||||
}, 20000);
|
||||
// setInterval(() => {
|
||||
// this.fetchActiveData();
|
||||
// }, 20000);
|
||||
},
|
||||
|
||||
async fetchActiveData() {
|
||||
@@ -51,6 +54,13 @@ export const useApiStore = defineStore('api', {
|
||||
|
||||
this.activeData = response;
|
||||
this.activeDataStatus = DataStatus.SUCCESS;
|
||||
this.isActiveDataOutdated = false;
|
||||
|
||||
if (this.outdatedTimerId != -1) clearTimeout(this.outdatedTimerId);
|
||||
|
||||
this.outdatedTimerId = setTimeout(() => {
|
||||
this.isActiveDataOutdated = true;
|
||||
}, 30000);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
export const getRegionNameById = (id: string) => {
|
||||
switch (id) {
|
||||
case 'eu':
|
||||
return 'PL1';
|
||||
|
||||
case 'cae':
|
||||
return 'PL2';
|
||||
|
||||
case 'us':
|
||||
return 'CZE';
|
||||
|
||||
case 'usw':
|
||||
return 'DE';
|
||||
|
||||
case 'ru':
|
||||
return 'ENG';
|
||||
|
||||
default:
|
||||
return 'PL1';
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user