mirror of
https://github.com/Spythere/srjp-td2.git
synced 2026-05-04 22:18:12 +00:00
chore: added storage timetables filtering, deleting and information
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
class="p-1 rounded-md"
|
class="p-1 rounded-md"
|
||||||
:class="{
|
:class="{
|
||||||
'bg-zinc-800 hover:bg-zinc-700': globalStore.viewMode == 'active',
|
'bg-zinc-800 hover:bg-zinc-700': globalStore.viewMode == 'active',
|
||||||
'bg-green-500 hover:bg-green-400': globalStore.viewMode == 'storage',
|
'bg-green-600 hover:bg-green-500': globalStore.viewMode == 'storage',
|
||||||
}"
|
}"
|
||||||
@click="toggleViewMode"
|
@click="toggleViewMode"
|
||||||
>
|
>
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
v-if="globalStore.viewMode == 'storage'"
|
v-if="globalStore.viewMode == 'storage'"
|
||||||
|
v-model="globalStore.timetableSearch"
|
||||||
class="bg-zinc-800 p-1 rounded-md print:hidden w-full"
|
class="bg-zinc-800 p-1 rounded-md print:hidden w-full"
|
||||||
:placeholder="$t('train-search-placeholder')"
|
:placeholder="$t('train-search-placeholder')"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,15 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="text-white">
|
||||||
<div v-if="globalStore.selectedStorageTimetable == null && Object.keys(globalStore.storageTimetables).length == 0">
|
<div v-if="globalStore.selectedStorageTimetable == null && Object.keys(globalStore.storageTimetables).length == 0">
|
||||||
<div class="font-bold text-xl">{{ $t('storage-empty-header') }}</div>
|
<div class="font-bold text-xl">{{ $t('storage-empty-header') }}</div>
|
||||||
<div>{{ $t('storage-empty-info') }}</div>
|
<div>{{ $t('storage-empty-info') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
|
<div class="font-bold text-xl p-2 bg-zinc-700 mb-3">{{ $t('storage-preview-title') }}</div>
|
||||||
|
<div class="font-bold p-2 bg-zinc-800 mb-3" v-if="filteredTimetables.length == 0">{{ $t('storage-preview-empty') }}</div>
|
||||||
|
|
||||||
<ul class="flex flex-col gap-3">
|
<ul class="flex flex-col gap-3">
|
||||||
<li v-for="timetable in globalStore.storageTimetables" class="text-left">
|
<li v-for="timetable in filteredTimetables" class="flex gap-1">
|
||||||
<button class="bg-zinc-900 p-2 w-full text-zinc-300 cursor-pointer hover:bg-zinc-800" @click="selectTimetable(timetable)">
|
<button class="bg-zinc-900 p-2 w-full cursor-pointer hover:bg-zinc-800 text-left" @click="selectTimetable(timetable)">
|
||||||
<b>{{ timetable.driverName }} {{ timetable.category }} {{ timetable.trainNo }}</b> {{ timetable.route.replace('|', ' - ') }}
|
<div class="text-zinc-300">#{{ timetable.timetableId }} • {{ new Date(timetable.savedTimestamp!).toLocaleString() }}</div>
|
||||||
|
<b>{{ timetable.driverName }} | {{ timetable.category }} {{ timetable.trainNo }}</b> {{ timetable.route.replace('|', ' > ') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="bg-zinc-900 p-2 hover:bg-zinc-800" @click="removeTimetable(timetable.timetableId)">
|
||||||
|
<TrashIcon class="size-5 text-white" />
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -18,14 +26,50 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { TrashIcon } from '@heroicons/vue/16/solid';
|
||||||
import { useGlobalStore } from '../../stores/global.store';
|
import { useGlobalStore } from '../../stores/global.store';
|
||||||
import type { TimetableData } from '../../types/common.types';
|
import type { TimetableData } from '../../types/common.types';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
const globalStore = useGlobalStore();
|
const globalStore = useGlobalStore();
|
||||||
|
const i18n = useI18n();
|
||||||
|
|
||||||
|
const filteredTimetables = computed(() => {
|
||||||
|
const timetables = Object.values(globalStore.storageTimetables);
|
||||||
|
|
||||||
|
if (globalStore.timetableSearch.length != 0)
|
||||||
|
timetables.filter((st) =>
|
||||||
|
`${st.timetableId} ${st.driverName} ${st.route} ${st.category} ${st.trainNo}`
|
||||||
|
.toLocaleLowerCase()
|
||||||
|
.includes(globalStore.timetableSearch.toLocaleLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
timetables.sort((a, b) => {
|
||||||
|
return (b.savedTimestamp ?? 0) - (a.savedTimestamp ?? 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
return timetables;
|
||||||
|
});
|
||||||
|
|
||||||
function selectTimetable(timetable: TimetableData) {
|
function selectTimetable(timetable: TimetableData) {
|
||||||
globalStore.selectedStorageTimetable = timetable;
|
globalStore.selectedStorageTimetable = timetable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeTimetable(timetableId: number) {
|
||||||
|
const isConfirmed = confirm(i18n.t('delete-timetable-confirm'));
|
||||||
|
|
||||||
|
if (!isConfirmed) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const savedTimetablesStorage = localStorage.getItem('savedTimetables');
|
||||||
|
let savedTimetablesJSON: Record<number, TimetableData> = savedTimetablesStorage ? JSON.parse(savedTimetablesStorage) : {};
|
||||||
|
delete savedTimetablesJSON[timetableId];
|
||||||
|
|
||||||
|
localStorage.setItem('savedTimetables', JSON.stringify(savedTimetablesJSON));
|
||||||
|
globalStore.storageTimetables = savedTimetablesJSON;
|
||||||
|
} catch (error) {}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -1,15 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div class="my-2 print:hidden" v-if="globalStore.currentTimetableData?.savedTimestamp">
|
||||||
class="my-2 print:hidden"
|
<div class="flex gap-2">
|
||||||
v-if="globalStore.currentTimetableData && (globalStore.timetableWarnings || globalStore.currentTimetableData.savedTimestamp)"
|
<div class="flex items-center gap-2 bg-zinc-900 p-1 w-full">
|
||||||
>
|
|
||||||
<div v-if="globalStore.currentTimetableData?.savedTimestamp" class="flex justify-between p-1 bg-zinc-900">
|
|
||||||
<div>
|
<div>
|
||||||
{{ $t('storage-preview-text') }}
|
<InformationCircleIcon class="size-5" />
|
||||||
|
</div>
|
||||||
|
<i18n-t keypath="storage-preview-info" tag="span">
|
||||||
|
<template v-slot:id>
|
||||||
<b>#{{ globalStore.currentTimetableData.timetableId }}</b>
|
<b>#{{ globalStore.currentTimetableData.timetableId }}</b>
|
||||||
|
</template>
|
||||||
|
<template v-slot:driverName>
|
||||||
|
<b>{{ globalStore.currentTimetableData.driverName }}</b>
|
||||||
|
</template>
|
||||||
|
<template v-slot:date>
|
||||||
|
<b>{{ new Date(globalStore.currentTimetableData.savedTimestamp).toLocaleString() }}</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="font-bold" @click="globalStore.selectedStorageTimetable = null">
|
<button class="font-bold bg-zinc-900 p-1 hover:bg-zinc-800" @click="globalStore.selectedStorageTimetable = null">
|
||||||
<ArrowUturnLeftIcon class="text-white size-6" />
|
<ArrowUturnLeftIcon class="text-white size-6" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -17,7 +26,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ArrowUturnLeftIcon } from '@heroicons/vue/16/solid';
|
import { ArrowUturnLeftIcon, InformationCircleIcon } from '@heroicons/vue/16/solid';
|
||||||
import { useGlobalStore } from '../../stores/global.store';
|
import { useGlobalStore } from '../../stores/global.store';
|
||||||
|
|
||||||
const globalStore = useGlobalStore();
|
const globalStore = useGlobalStore();
|
||||||
|
|||||||
+6
-6
@@ -3,7 +3,6 @@
|
|||||||
"train-select-placeholder": "Choose active train from the list",
|
"train-select-placeholder": "Choose active train from the list",
|
||||||
"train-select-info": "Choose active train to generate SRJP timetable",
|
"train-select-info": "Choose active train to generate SRJP timetable",
|
||||||
"train-search-placeholder": "Enter TT details (number, route, user)",
|
"train-search-placeholder": "Enter TT details (number, route, user)",
|
||||||
|
|
||||||
"headers": {
|
"headers": {
|
||||||
"line_no": "Line\nno.",
|
"line_no": "Line\nno.",
|
||||||
"line_km": "Km",
|
"line_km": "Km",
|
||||||
@@ -17,10 +16,11 @@
|
|||||||
"vmax": "Vmax",
|
"vmax": "Vmax",
|
||||||
"relation": "Route"
|
"relation": "Route"
|
||||||
},
|
},
|
||||||
|
"storage-empty-header": "ARCHIVED TIMETABLES SEARCH MODE",
|
||||||
"storage-empty-header": "SAVED TIMETABLES SEARCH MODE",
|
|
||||||
"storage-empty-info": "Timetables will be shown here after their archiving.",
|
"storage-empty-info": "Timetables will be shown here after their archiving.",
|
||||||
|
"storage-preview-title": "ARCHIVED TIMETABLES",
|
||||||
"storage-preview-text": "You're browsing now saved timetable with ID:",
|
"storage-preview-empty": "No entries found for given parameters",
|
||||||
"storage-preview-button-text": "Return"
|
"storage-preview-info": "Archived timetable {id} for user {driverName} from: {date}",
|
||||||
|
"storage-preview-button-text": "Return",
|
||||||
|
"delete-timetable-confirm": "Are you sure that you want to delete this timetable?"
|
||||||
}
|
}
|
||||||
+5
-5
@@ -3,7 +3,6 @@
|
|||||||
"train-select-placeholder": "Wybierz pociąg z listy",
|
"train-select-placeholder": "Wybierz pociąg z listy",
|
||||||
"train-select-info": "Wybierz aktywny pociąg, aby wygenerować SRJP",
|
"train-select-info": "Wybierz aktywny pociąg, aby wygenerować SRJP",
|
||||||
"train-search-placeholder": "Wpisz szczegóły RJ (nr, relacja, gracz)",
|
"train-search-placeholder": "Wpisz szczegóły RJ (nr, relacja, gracz)",
|
||||||
|
|
||||||
"headers": {
|
"headers": {
|
||||||
"line_no": "Nr\nlinii",
|
"line_no": "Nr\nlinii",
|
||||||
"line_km": "Km",
|
"line_km": "Km",
|
||||||
@@ -17,10 +16,11 @@
|
|||||||
"vmax": "Vmax",
|
"vmax": "Vmax",
|
||||||
"relation": "Relacja"
|
"relation": "Relacja"
|
||||||
},
|
},
|
||||||
|
|
||||||
"storage-empty-header": "TRYB WYSZUKIWANA ZAPISANYCH ROZKŁADÓW JAZDY",
|
"storage-empty-header": "TRYB WYSZUKIWANA ZAPISANYCH ROZKŁADÓW JAZDY",
|
||||||
"storage-empty-info": "Użyj funkcji zapisu rozkładu jazdy, aby go tutaj wyświetlić.",
|
"storage-empty-info": "Użyj funkcji zapisu rozkładu jazdy, aby go tutaj wyświetlić.",
|
||||||
|
"storage-preview-title": "ZAPISANE ROZKŁADY JAZDY",
|
||||||
"storage-preview-text": "Przeglądasz teraz zapisany rozkład jazdy o ID:",
|
"storage-preview-empty": "Nie znaleziono żadnych wpisów dla podanych parametrów",
|
||||||
"storage-preview-button-text": "Powróć"
|
"storage-preview-info": "Rozkład archiwalny {id} maszynisty {driverName} z dnia {date}",
|
||||||
|
"storage-preview-button-text": "Powróć",
|
||||||
|
"delete-timetable-confirm": "Czy na pewno chcesz usunąć ten rozkład jazdy z archiwum?"
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,8 @@ export const useGlobalStore = defineStore('global', {
|
|||||||
generatedDate: null as Date | null,
|
generatedDate: null as Date | null,
|
||||||
generatedMs: 0,
|
generatedMs: 0,
|
||||||
|
|
||||||
|
timetableSearch: '',
|
||||||
|
|
||||||
showSettings: false,
|
showSettings: false,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
|
|||||||
Reference in New Issue
Block a user