mirror of
https://github.com/Spythere/srjp-td2.git
synced 2026-05-03 13:38:12 +00:00
feat/restruct: saving timetables to local storage
This commit is contained in:
+20
-4
@@ -20,13 +20,29 @@ const globalStore = useGlobalStore();
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
apiStore.setupAPIData();
|
apiStore.setupAPIData();
|
||||||
|
|
||||||
// Setup dark mode
|
setupDarkMode();
|
||||||
globalStore.darkMode =
|
loadStorageTimetables();
|
||||||
localStorage.currentTheme === 'dark' || (!('currentTheme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
setupAfterPrintClose();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Resetting after print dialog is closed
|
function loadStorageTimetables() {
|
||||||
|
if (!window.localStorage.getItem('savedTimetables')) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
globalStore.storageTimetables = JSON.parse(window.localStorage.getItem('savedTimetables')!);
|
||||||
|
} catch (error) {
|
||||||
|
alert('Ups! Coś poszło nie tak podczas pobierania zapisanych RJ!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupDarkMode() {
|
||||||
|
globalStore.darkMode =
|
||||||
|
localStorage.currentTheme === 'dark' || (!('currentTheme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupAfterPrintClose() {
|
||||||
window.addEventListener('afterprint', () => {
|
window.addEventListener('afterprint', () => {
|
||||||
document.title = originalDocumentTitle;
|
document.title = originalDocumentTitle;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -121,13 +121,13 @@
|
|||||||
<table class="h-full w-full border-collapse">
|
<table class="h-full w-full border-collapse">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="border-b-[1px] border-b-black dark:border-b-white">
|
<tr class="border-b-[1px] border-b-black dark:border-b-white">
|
||||||
<td>{{ row.headLocos[0] }}</td>
|
<td>{{ row.headUnits[0] }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="border-b-[1px] border-b-black dark:border-b-white">
|
<tr class="border-b-[1px] border-b-black dark:border-b-white">
|
||||||
<td>{{ row.headLocos[1] ?? ' ' }}</td>
|
<td>{{ row.headUnits[1] ?? ' ' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ row.headLocos[2] ?? ' ' }}</td>
|
<td>{{ row.headUnits[2] ?? ' ' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex gap-2 mb-2">
|
<div class="flex gap-2 mb-2">
|
||||||
|
<button
|
||||||
|
class="p-1 rounded-md"
|
||||||
|
:class="{
|
||||||
|
'bg-zinc-800 hover:bg-zinc-700': globalStore.viewMode == 'active',
|
||||||
|
'bg-green-500 hover:bg-green-400': globalStore.viewMode == 'storage',
|
||||||
|
}"
|
||||||
|
@click="toggleViewMode"
|
||||||
|
>
|
||||||
|
<ArchiveBoxArrowDownIcon class="size-6" />
|
||||||
|
</button>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
name="trains"
|
name="trains"
|
||||||
id="trains-select"
|
id="trains-select"
|
||||||
class="bg-zinc-800 p-1 rounded-md print:hidden w-full"
|
class="bg-zinc-800 p-1 rounded-md print:hidden w-full"
|
||||||
:disabled="apiStore.activeDataStatus != DataStatus.SUCCESS"
|
:disabled="apiStore.activeDataStatus != DataStatus.SUCCESS"
|
||||||
v-model="selectedTrainId"
|
v-model="selectedTrainId"
|
||||||
|
v-if="globalStore.viewMode == 'active'"
|
||||||
@change="selectTrain"
|
@change="selectTrain"
|
||||||
>
|
>
|
||||||
<option :value="null" 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>
|
||||||
@@ -14,29 +26,42 @@
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
v-if="globalStore.viewMode == 'storage'"
|
||||||
|
class="bg-zinc-800 p-1 rounded-md print:hidden w-full"
|
||||||
|
placeholder="Wpisz szczegóły RJ, który chcesz znaleźć (np. numer, relacja)"
|
||||||
|
/>
|
||||||
|
|
||||||
<button class="bg-zinc-800 p-1 rounded-md hover:bg-zinc-700" @click="toggleDarkMode">
|
<button class="bg-zinc-800 p-1 rounded-md hover:bg-zinc-700" @click="toggleDarkMode">
|
||||||
<SunIcon v-if="globalStore.darkMode" class="text-white size-6" />
|
<MoonIcon v-if="globalStore.darkMode" class="text-white size-6" />
|
||||||
<MoonIcon v-else class="text-white size-6" />
|
<SunIcon v-else class="text-white size-6" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="bg-zinc-800 p-1 rounded-md hover:bg-zinc-700" @click="openPrintingWindow">
|
<button class="bg-zinc-800 p-1 rounded-md hover:bg-zinc-700" @click="openPrintingWindow">
|
||||||
<PrinterIcon class="text-white size-6" />
|
<PrinterIcon class="text-white size-6" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="bg-zinc-800 p-1 rounded-md hover:bg-zinc-700 relative" @click="refreshData">
|
<button
|
||||||
<ArrowPathIcon class="text-white size-6" />
|
class="bg-zinc-800 p-1 rounded-md hover:bg-zinc-700"
|
||||||
<div v-if="apiStore.isActiveDataOutdated" class="size-3 bg-green-300 rounded-full absolute -top-1 -right-1"></div>
|
:class="{
|
||||||
|
'bg-green-600': isTimetableSaved,
|
||||||
|
}"
|
||||||
|
@click="saveToStorage"
|
||||||
|
>
|
||||||
|
<ArrowDownTrayIcon class="text-white size-6" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, type Ref } from 'vue';
|
import { computed, ref, type Ref } from 'vue';
|
||||||
import { useApiStore } from '../../stores/api.store';
|
import { useApiStore } from '../../stores/api.store';
|
||||||
import { DataStatus } from '../../types/api.types';
|
import { DataStatus } from '../../types/api.types';
|
||||||
import { useGlobalStore } from '../../stores/global.store';
|
import { useGlobalStore } from '../../stores/global.store';
|
||||||
import { PrinterIcon, ArrowPathIcon, MoonIcon, SunIcon } from '@heroicons/vue/16/solid';
|
import { PrinterIcon, MoonIcon, SunIcon, ArchiveBoxArrowDownIcon, ArrowDownTrayIcon } from '@heroicons/vue/16/solid';
|
||||||
import { getRegionNameById } from '../../utils/trainUtils';
|
import { getRegionNameById } from '../../utils/trainUtils';
|
||||||
|
import type { TimetableData } from '../../types/common.types';
|
||||||
|
|
||||||
// Stores
|
// Stores
|
||||||
const apiStore = useApiStore();
|
const apiStore = useApiStore();
|
||||||
@@ -45,38 +70,64 @@ const globalStore = useGlobalStore();
|
|||||||
// Variables & refs
|
// Variables & refs
|
||||||
let selectedTrainId = ref(null) as Ref<string | null>;
|
let selectedTrainId = ref(null) as Ref<string | null>;
|
||||||
|
|
||||||
|
// Computed
|
||||||
|
const isTimetableSaved = computed(() => {
|
||||||
|
if (!globalStore.currentTimetableData) return false;
|
||||||
|
|
||||||
|
return Object.keys(globalStore.storageTimetables).includes(`${globalStore.currentTimetableData.timetableId}`);
|
||||||
|
});
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
function selectTrain() {
|
function selectTrain() {
|
||||||
if (!apiStore.activeData) return;
|
if (!apiStore.activeData) return;
|
||||||
|
|
||||||
globalStore.selectedTrain = globalStore.activeTimetableTrains.find((train) => train.id == selectedTrainId.value) ?? null;
|
globalStore.selectedActiveTrain = globalStore.activeTimetableTrains.find((train) => train.id == selectedTrainId.value) ?? null;
|
||||||
|
|
||||||
if (globalStore.selectedTrain != null) {
|
if (globalStore.selectedActiveTrain != null) {
|
||||||
globalStore.generatedDate = new Date();
|
globalStore.generatedDate = new Date();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleViewMode() {
|
||||||
|
globalStore.viewMode = globalStore.viewMode == 'active' ? 'storage' : 'active';
|
||||||
|
}
|
||||||
|
|
||||||
function toggleDarkMode() {
|
function toggleDarkMode() {
|
||||||
globalStore.darkMode = !globalStore.darkMode;
|
globalStore.darkMode = !globalStore.darkMode;
|
||||||
|
|
||||||
window.localStorage.setItem('currentTheme', globalStore.darkMode ? 'dark' : 'light');
|
window.localStorage.setItem('currentTheme', globalStore.darkMode ? 'dark' : 'light');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveToStorage() {
|
||||||
|
if (globalStore.currentTimetableData == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const savedTimetablesStorage = localStorage.getItem('savedTimetables');
|
||||||
|
let savedTimetablesJSON: Record<number, TimetableData> = savedTimetablesStorage ? JSON.parse(savedTimetablesStorage) : {};
|
||||||
|
savedTimetablesJSON[globalStore.currentTimetableData.timetableId] = { ...globalStore.currentTimetableData, savedTimestamp: Date.now() };
|
||||||
|
|
||||||
|
localStorage.setItem('savedTimetables', JSON.stringify(savedTimetablesJSON));
|
||||||
|
globalStore.storageTimetables = savedTimetablesJSON;
|
||||||
|
} catch (error) {}
|
||||||
|
}
|
||||||
|
|
||||||
function openPrintingWindow() {
|
function openPrintingWindow() {
|
||||||
if (globalStore.selectedTrain != null) {
|
if (globalStore.selectedActiveTrain != null) {
|
||||||
const date = `${globalStore.generatedDate!.toLocaleDateString('pl-PL').replace(/\./g, '-')}--${globalStore
|
const date = `${globalStore.generatedDate!.toLocaleDateString('pl-PL').replace(/\./g, '-')}--${globalStore
|
||||||
.generatedDate!.toLocaleTimeString('pl-PL')
|
.generatedDate!.toLocaleTimeString('pl-PL')
|
||||||
.replace(/:/g, '-')}`;
|
.replace(/:/g, '-')}`;
|
||||||
|
|
||||||
document.title = `${globalStore.selectedTrain.driverName} ; ${globalStore.selectedTrain.timetable!.category} ${globalStore.selectedTrain.trainNo}
|
document.title = `${globalStore.selectedActiveTrain.driverName} ; ${globalStore.selectedActiveTrain.timetable!.category} ${
|
||||||
${globalStore.selectedTrain.timetable?.route.replace('|', ' - ')} ; ${date}`;
|
globalStore.selectedActiveTrain.trainNo
|
||||||
|
}
|
||||||
|
${globalStore.selectedActiveTrain.timetable?.route.replace('|', ' - ')} ; ${date}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.print();
|
window.print();
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshData() {
|
// function refreshData() {
|
||||||
apiStore.fetchActiveData();
|
// apiStore.fetchActiveData();
|
||||||
selectTrain();
|
// selectTrain();
|
||||||
}
|
// }
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div v-if="globalStore.selectedStorageTimetable == null && Object.keys(globalStore.storageTimetables).length == 0">
|
||||||
|
<div class="font-bold text-xl">TRYB WYSZUKIWANA ZAPISANYCH ROZKŁADÓW JAZDY</div>
|
||||||
|
<div>Użyj funkcji zapisu rozkładu jazdy, aby go tutaj wyświetlić.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<ul class="flex flex-col gap-3">
|
||||||
|
<li v-for="timetable in globalStore.storageTimetables" class="text-left">
|
||||||
|
<button class="bg-zinc-900 p-2 w-full text-zinc-300 cursor-pointer hover:bg-zinc-800" @click="selectTimetable(timetable)">
|
||||||
|
<b>{{ timetable.category }} {{ timetable.trainNo }}</b> {{ timetable.route.replace('|', ' - ') }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useGlobalStore } from '../../stores/global.store';
|
||||||
|
import type { TimetableData } from '../../types/common.types';
|
||||||
|
|
||||||
|
const globalStore = useGlobalStore();
|
||||||
|
|
||||||
|
function selectTimetable(timetable: TimetableData) {
|
||||||
|
globalStore.selectedStorageTimetable = timetable;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -1,70 +1,68 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="{ dark: globalStore.darkMode }"
|
:class="{ dark: globalStore.darkMode }"
|
||||||
v-if="globalStore.selectedTrain"
|
v-if="globalStore.currentTimetableData != null"
|
||||||
class="overflow-auto p-1 bg-white print:bg-white dark:bg-zinc-950 print:text-black text-black dark:text-white min-h-full"
|
class="overflow-auto p-1 bg-white print:bg-white dark:bg-zinc-950 print:text-black text-black dark:text-white min-h-full"
|
||||||
>
|
>
|
||||||
|
<div class="p-1 bg-zinc-900 my-2 print:hidden flex justify-between" v-if="globalStore.currentTimetableData.savedTimestamp">
|
||||||
<div>
|
<div>
|
||||||
<div class="p-1 font-bold w-max">
|
Przeglądasz teraz zapisany rozkład jazdy o ID: <b>#{{ globalStore.currentTimetableData.timetableId }}</b>
|
||||||
{{ globalStore.selectedTrain.timetable!.category }} {{ globalStore.selectedTrain.trainNo }} Relacja
|
|
||||||
{{ globalStore.selectedTrain.timetable?.route.replace('|', ' - ') }}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="table-fixed mt-2 w-full border-collapse" v-if="computedTimetable.length > 0">
|
<button class="font-bold" @click="globalStore.selectedStorageTimetable = null">Powróć do listy</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="p-1 font-bold w-max">
|
||||||
|
{{ globalStore.currentTimetableData.category }} {{ globalStore.currentTimetableData.trainNo }} Relacja
|
||||||
|
{{ globalStore.currentTimetableData.route.replace('|', ' - ') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table-fixed mt-2 w-full border-collapse" v-if="computedTimetableRows.length > 0">
|
||||||
<TimetableHeader />
|
<TimetableHeader />
|
||||||
<TimetableBody :computed-timetable="computedTimetable" />
|
<TimetableBody :computed-timetable="computedTimetableRows" />
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overflow-auto text-center font-bold text-zinc-400 p-1 min-h-full" v-else>Wybierz aktywny pociąg, aby wygenerować SRJP</div>
|
<div class="overflow-auto text-center font-bold text-zinc-400 p-1 min-h-full" v-else>
|
||||||
|
<div v-if="globalStore.viewMode == 'active'">
|
||||||
|
<div>Wybierz aktywny pociąg, aby wygenerować SRJP</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<TimetableStorage />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';``
|
||||||
import { useApiStore } from '../../stores/api.store';
|
import { useApiStore } from '../../stores/api.store';
|
||||||
import { useGlobalStore } from '../../stores/global.store';
|
import { useGlobalStore } from '../../stores/global.store';
|
||||||
import TimetableBody from './TimetableBody.vue';
|
import TimetableBody from './TimetableBody.vue';
|
||||||
import TimetableHeader from './TimetableHeader.vue';
|
import TimetableHeader from './TimetableHeader.vue';
|
||||||
import type { SceneryRoute, StopRow } from '../../types/common.types';
|
import type { SceneryRoute, StopRow, TimetablePathData } from '../../types/common.types';
|
||||||
|
import TimetableStorage from './TimetableStorage.vue';
|
||||||
|
|
||||||
const globalStore = useGlobalStore();
|
const globalStore = useGlobalStore();
|
||||||
const apiStore = useApiStore();
|
const apiStore = useApiStore();
|
||||||
|
|
||||||
const computedTimetable = computed(() => {
|
// Tymczasowa tabelka z posterunkami APO
|
||||||
if (!globalStore.selectedTrain || !globalStore.selectedTrain.timetable) return [];
|
// const apoNames = ['Stary Kisielin, pe', 'Czerwony Dwór, pe', 'Szczejkowice, pe'];
|
||||||
|
|
||||||
const { timetable, stockString, mass, length } = globalStore.selectedTrain;
|
const computedTimetableRows = computed(() => {
|
||||||
|
const timetableData = globalStore.currentTimetableData;
|
||||||
|
|
||||||
|
if (!timetableData) return [];
|
||||||
|
|
||||||
let timeFrom = Date.now();
|
let timeFrom = Date.now();
|
||||||
|
|
||||||
const headLocos = stockString
|
const stockVmax = timetableData.trainMaxSpeed,
|
||||||
.split(';')
|
stockMass = Math.floor(timetableData.mass / 1000),
|
||||||
.slice(0, 3)
|
|
||||||
.filter((s, i) => i == 0 || /-\d+$/.test(s))
|
|
||||||
.map((s) => s.slice(0, s.indexOf('-')));
|
|
||||||
|
|
||||||
const stockVmax = timetable.trainMaxSpeed,
|
|
||||||
stockMass = Math.floor(mass / 1000),
|
|
||||||
stockLength = length;
|
stockLength = length;
|
||||||
|
|
||||||
const timetablePath = timetable.path.split(';').map((pathEl) => {
|
const timetablePath = parseTimetablePath(timetableData.path);
|
||||||
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[] = [];
|
const stopRows: StopRow[] = [];
|
||||||
|
|
||||||
@@ -94,7 +92,9 @@ const computedTimetable = computed(() => {
|
|||||||
|
|
||||||
// console.debug('=========== ' + this.selectedTrain.trainNo + ' ===========');
|
// console.debug('=========== ' + this.selectedTrain.trainNo + ' ===========');
|
||||||
|
|
||||||
for (const stop of timetable.stopList) {
|
const stopList = parseStopListString(timetableData.stopListString);
|
||||||
|
|
||||||
|
for (const stop of stopList) {
|
||||||
if (stop.arrivalLine && stop.arrivalLine == currentPath.arrivalLine) {
|
if (stop.arrivalLine && stop.arrivalLine == currentPath.arrivalLine) {
|
||||||
arrivalKm = stop.stopDistance;
|
arrivalKm = stop.stopDistance;
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ const computedTimetable = computed(() => {
|
|||||||
departureTracks = arrivalTracks;
|
departureTracks = arrivalTracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/^<strong>|, (podg|po)$|^(!_, pe)$/.test(stop.stopName)) {
|
if (stop.mainStop || (/^podg|po|pe$/.test(stop.stopNameRAW) && !/^sbl/i.test(stop.stopNameRAW))) {
|
||||||
let correctedDepartureSpeed = 0,
|
let correctedDepartureSpeed = 0,
|
||||||
correctedDepartureTracks = 0;
|
correctedDepartureTracks = 0;
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ const computedTimetable = computed(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let rowData: StopRow = {
|
let rowData: StopRow = {
|
||||||
isMain: /^<strong>/.test(stop.stopName),
|
isMain: stop.mainStop,
|
||||||
pointKm: stop.stopDistance.toFixed(3),
|
pointKm: stop.stopDistance.toFixed(3),
|
||||||
pointName: stop.stopNameRAW,
|
pointName: stop.stopNameRAW,
|
||||||
scheduledArrivalDate: stop.arrivalTimestamp ? new Date(stop.arrivalTimestamp) : null,
|
scheduledArrivalDate: stop.arrivalTimestamp ? new Date(stop.arrivalTimestamp) : null,
|
||||||
@@ -150,12 +150,14 @@ const computedTimetable = computed(() => {
|
|||||||
departureSpeed: departureSpeed,
|
departureSpeed: departureSpeed,
|
||||||
departureTracks: departureTracks,
|
departureTracks: departureTracks,
|
||||||
|
|
||||||
headLocos,
|
headUnits: timetableData.headUnits,
|
||||||
stockVmax,
|
stockVmax,
|
||||||
stockLength,
|
stockLength,
|
||||||
stockMass,
|
stockMass,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// if (apoNames.includes(stop.stopNameRAW)) abbrevs.unshift(`APO ${currentPath.sceneryData?.abbr}`);
|
||||||
|
|
||||||
// console.debug(stop.stopNameRAW, stop.departureLine);
|
// console.debug(stop.stopNameRAW, stop.departureLine);
|
||||||
|
|
||||||
arrivalKm = stop.stopDistance;
|
arrivalKm = stop.stopDistance;
|
||||||
@@ -200,6 +202,46 @@ const computedTimetable = computed(() => {
|
|||||||
return stopRows;
|
return stopRows;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function parseTimetablePath(path: string): TimetablePathData[] {
|
||||||
|
return 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 ?? '',
|
||||||
|
departureLine: departureLine ?? '',
|
||||||
|
arrivalLineData,
|
||||||
|
departureLineData,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseStopListString(stopsString: string) {
|
||||||
|
//${stop.arrivalLine ?? ''};${stop.arrivalTimestamp};${stop.stopNameRAW};${stop.stopTime ? stop.stopTime + '_' + stop.stopType : ''};${stop.mainStop};${stop.stopDistance};${stop.departureTimestamp};${stop.departureLine ?? ''}
|
||||||
|
return stopsString.split('~~').map((stop) => {
|
||||||
|
const [arrivalLine, arrivalTimestamp, stopNameRAW, stopDetails, isMainStop, stopDistance, departureTimestamp, departureLine] = stop.split(';');
|
||||||
|
const [stopTime, stopType] = stopDetails.split('_');
|
||||||
|
|
||||||
|
return {
|
||||||
|
arrivalLine,
|
||||||
|
arrivalTimestamp: parseInt(arrivalTimestamp),
|
||||||
|
stopNameRAW,
|
||||||
|
stopTime: stopTime ?? 0,
|
||||||
|
stopType: stopType ?? null,
|
||||||
|
mainStop: isMainStop == 'true',
|
||||||
|
stopDistance: parseFloat(stopDistance),
|
||||||
|
departureTimestamp: parseInt(departureTimestamp),
|
||||||
|
departureLine,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getAbbrevs(routeData: SceneryRoute) {
|
function getAbbrevs(routeData: SceneryRoute) {
|
||||||
const abbrevs = [];
|
const abbrevs = [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { useApiStore } from './api.store';
|
import { useApiStore } from './api.store';
|
||||||
import type { ActiveTrain } from '../types/common.types';
|
import type { ActiveTrain, TimetableData, ViewMode } from '../types/common.types';
|
||||||
|
import { unitNameCorrections } from '../utils/trainUtils';
|
||||||
|
|
||||||
export const useGlobalStore = defineStore('global', {
|
export const useGlobalStore = defineStore('global', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
darkMode: false,
|
darkMode: false,
|
||||||
|
viewMode: 'active' as ViewMode,
|
||||||
|
|
||||||
|
selectedActiveTrain: null as ActiveTrain | null,
|
||||||
|
selectedStorageTimetable: null as TimetableData | null,
|
||||||
|
|
||||||
|
storageTimetables: {} as Record<number, TimetableData>,
|
||||||
|
|
||||||
selectedTrain: null as ActiveTrain | null,
|
|
||||||
generatedDate: null as Date | null,
|
generatedDate: null as Date | null,
|
||||||
generatedMs: 0,
|
generatedMs: 0,
|
||||||
}),
|
}),
|
||||||
@@ -18,6 +24,51 @@ export const useGlobalStore = defineStore('global', {
|
|||||||
|
|
||||||
return apiStore.activeData.trains.filter((train) => train.timetable).sort((t1, t2) => t1.driverName.localeCompare(t2.driverName, 'pl-PL'));
|
return apiStore.activeData.trains.filter((train) => train.timetable).sort((t1, t2) => t1.driverName.localeCompare(t2.driverName, 'pl-PL'));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
currentTimetableData(): TimetableData | null {
|
||||||
|
if (this.viewMode == 'active') {
|
||||||
|
const selectedTrain = this.selectedActiveTrain;
|
||||||
|
|
||||||
|
if (!selectedTrain || !selectedTrain.timetable) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
trainNo: selectedTrain.trainNo,
|
||||||
|
mass: selectedTrain.mass,
|
||||||
|
length: selectedTrain.length,
|
||||||
|
driverId: selectedTrain.driverId,
|
||||||
|
driverName: selectedTrain.driverName,
|
||||||
|
category: selectedTrain.timetable.category,
|
||||||
|
hasDangerousCargo: selectedTrain.timetable.hasDangerousCargo,
|
||||||
|
hasExtraDeliveries: selectedTrain.timetable.hasExtraDeliveries,
|
||||||
|
warningNotes: selectedTrain.timetable.warningNotes,
|
||||||
|
path: selectedTrain.timetable.path,
|
||||||
|
route: selectedTrain.timetable.route,
|
||||||
|
trainMaxSpeed: selectedTrain.timetable.trainMaxSpeed,
|
||||||
|
timetableId: selectedTrain.timetable.timetableId,
|
||||||
|
stopListString: selectedTrain.timetable.stopList
|
||||||
|
.filter((stop) => stop.mainStop || (/^podg|po|pe$/.test(stop.stopNameRAW) && !/^sbl/i.test(stop.stopNameRAW)))
|
||||||
|
.map(
|
||||||
|
(stop) =>
|
||||||
|
`${stop.arrivalLine ?? ''};${stop.arrivalTimestamp};${stop.stopNameRAW};${stop.stopTime ? stop.stopTime + '_' + stop.stopType : ''};${
|
||||||
|
stop.mainStop
|
||||||
|
};${stop.stopDistance};${stop.departureTimestamp};${stop.departureLine ?? ''}`
|
||||||
|
)
|
||||||
|
.join('~~'),
|
||||||
|
headUnits: selectedTrain.stockString
|
||||||
|
.split(';')
|
||||||
|
.slice(0, 3)
|
||||||
|
.filter((s, i) => i == 0 || /-\d+$/.test(s))
|
||||||
|
.map((s) => {
|
||||||
|
const unitName = s.slice(0, s.indexOf('-'));
|
||||||
|
|
||||||
|
return unitNameCorrections[unitName] ?? unitName;
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const selectedStorageTimetable = this.selectedStorageTimetable;
|
||||||
|
return selectedStorageTimetable;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {},
|
actions: {},
|
||||||
});
|
});
|
||||||
|
|||||||
+116
-1
@@ -1,3 +1,5 @@
|
|||||||
|
export type ViewMode = 'active' | 'storage';
|
||||||
|
|
||||||
export interface ActiveData {
|
export interface ActiveData {
|
||||||
trains: ActiveTrain[];
|
trains: ActiveTrain[];
|
||||||
activeSceneries: ActiveScenery[];
|
activeSceneries: ActiveScenery[];
|
||||||
@@ -141,8 +143,121 @@ export interface StopRow {
|
|||||||
departureKm: string;
|
departureKm: string;
|
||||||
departureSpeed: number;
|
departureSpeed: number;
|
||||||
departureTracks: number;
|
departureTracks: number;
|
||||||
headLocos: string[];
|
headUnits: string[];
|
||||||
stockVmax: number;
|
stockVmax: number;
|
||||||
stockLength: number;
|
stockLength: number;
|
||||||
stockMass: number;
|
stockMass: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TimetablePathData {
|
||||||
|
sceneryName: string;
|
||||||
|
sceneryData: SceneryData | null;
|
||||||
|
arrivalLine: string;
|
||||||
|
departureLine: string;
|
||||||
|
arrivalLineData: SceneryRoute | null;
|
||||||
|
departureLineData: SceneryRoute | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JournalTimetableShort {
|
||||||
|
id: number;
|
||||||
|
allStopsCount: number;
|
||||||
|
confirmedStopsCount: number;
|
||||||
|
createdAt: string;
|
||||||
|
beginDate: string;
|
||||||
|
driverId: number;
|
||||||
|
driverName: string;
|
||||||
|
route: string;
|
||||||
|
routeDistance: number;
|
||||||
|
currentDistance: number;
|
||||||
|
currentLocation: string[];
|
||||||
|
currentSceneryName: string;
|
||||||
|
currentSceneryHash: string;
|
||||||
|
driverLevel: number;
|
||||||
|
fulfilled: boolean;
|
||||||
|
terminated: boolean;
|
||||||
|
driverIsSupporter: boolean;
|
||||||
|
trainCategoryCode: string;
|
||||||
|
trainNo: number;
|
||||||
|
region: string;
|
||||||
|
hasDangerousCargo: boolean;
|
||||||
|
hasExtraDeliveries: boolean;
|
||||||
|
twr: boolean;
|
||||||
|
skr: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JournalTimetableDetailed extends JournalTimetableShort {
|
||||||
|
id: number;
|
||||||
|
schemaVersion: string;
|
||||||
|
allStopsCount: number;
|
||||||
|
authorId: number;
|
||||||
|
authorName: string;
|
||||||
|
beginDate: string;
|
||||||
|
confirmedStopsCount: number;
|
||||||
|
currentDistance: number;
|
||||||
|
driverId: number;
|
||||||
|
driverName: string;
|
||||||
|
endDate: string;
|
||||||
|
fulfilled: boolean;
|
||||||
|
route: string;
|
||||||
|
routeDistance: number;
|
||||||
|
region: string;
|
||||||
|
sceneriesString: string;
|
||||||
|
scheduledBeginDate: string;
|
||||||
|
scheduledEndDate: string;
|
||||||
|
terminated: boolean;
|
||||||
|
timetableId: number;
|
||||||
|
trainCategoryCode: string;
|
||||||
|
trainNo: number;
|
||||||
|
twr: boolean;
|
||||||
|
skr: boolean;
|
||||||
|
stockString: string;
|
||||||
|
stockMass: number;
|
||||||
|
stockLength: number;
|
||||||
|
maxSpeed: number;
|
||||||
|
trainMaxSpeed: number;
|
||||||
|
hashesString: string;
|
||||||
|
currentSceneryName: string;
|
||||||
|
currentSceneryHash: any;
|
||||||
|
driverIsSupporter: boolean;
|
||||||
|
driverLevel: number;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
stockHistory: string[];
|
||||||
|
hidden: boolean;
|
||||||
|
routeSceneries: string;
|
||||||
|
checkpointArrivals: any[];
|
||||||
|
checkpointDepartures: any[];
|
||||||
|
checkpointArrivalsScheduled: string[];
|
||||||
|
checkpointDeparturesScheduled: string[];
|
||||||
|
checkpointStopTypes: string[];
|
||||||
|
currentLocation: string[];
|
||||||
|
visitedSceneries: string[];
|
||||||
|
sceneryHashes: string[];
|
||||||
|
sceneryNames: string[];
|
||||||
|
checkpointComments: string[];
|
||||||
|
checkpointNames: string[];
|
||||||
|
path: string;
|
||||||
|
warningNotes: string;
|
||||||
|
hasDangerousCargo: boolean;
|
||||||
|
hasExtraDeliveries: boolean;
|
||||||
|
stopListString: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimetableData {
|
||||||
|
trainNo: number;
|
||||||
|
mass: number;
|
||||||
|
length: number;
|
||||||
|
driverName: string;
|
||||||
|
driverId: number;
|
||||||
|
hasDangerousCargo: boolean;
|
||||||
|
hasExtraDeliveries: boolean;
|
||||||
|
warningNotes: string;
|
||||||
|
category: string;
|
||||||
|
route: string;
|
||||||
|
timetableId: number;
|
||||||
|
path: string;
|
||||||
|
trainMaxSpeed: number;
|
||||||
|
stopListString: string;
|
||||||
|
headUnits: string[];
|
||||||
|
savedTimestamp?: number;
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,3 +19,11 @@ export const getRegionNameById = (id: string) => {
|
|||||||
return 'PL1';
|
return 'PL1';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const unitNameCorrections: Record<string, string> = {
|
||||||
|
'2EN57': 'EN57',
|
||||||
|
'201E': 'ET22',
|
||||||
|
'4E': 'EU07',
|
||||||
|
M62: 'ST44',
|
||||||
|
CTLR4C: 'ST44',
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user