203 lines
6.2 KiB
Vue
203 lines
6.2 KiB
Vue
<script setup lang="ts">
|
|
import QuickStats from '@/components/QuickStats.vue';
|
|
import StatsBlock from '@/components/StatsBlock.vue';
|
|
import { specialCars } from '@/data/specials.ts';
|
|
import { type, useTramStore } from '@/stores/tram.ts';
|
|
import { groupBy } from '@/utils/array.ts';
|
|
import { idsOf, missingOf } from '@/utils/typeGroup.ts';
|
|
import { ref } from 'vue';
|
|
import {
|
|
useModal,
|
|
useToast,
|
|
VaButton,
|
|
VaCard,
|
|
VaCardContent,
|
|
VaCardTitle,
|
|
VaCheckbox,
|
|
type VaFile,
|
|
VaFileUpload
|
|
} from 'vuestic-ui';
|
|
import { z } from 'zod';
|
|
|
|
const { init } = useToast();
|
|
const { confirm } = useModal();
|
|
const tramStore = useTramStore();
|
|
|
|
const showMissing = ref(false);
|
|
|
|
function download() {
|
|
const fileType = 'application/json';
|
|
const blob = new Blob([tramStore.exportData()], { type: fileType });
|
|
|
|
const a = document.createElement('a');
|
|
a.download = `tramtrack-export-${Date.now()}.json`;
|
|
a.href = URL.createObjectURL(blob);
|
|
a.dataset.downloadurl = [fileType, a.download, a.href].join(':');
|
|
a.style.display = 'none';
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
setTimeout(() => URL.revokeObjectURL(a.href), 1500);
|
|
|
|
init({
|
|
title: 'Export erfolgreich',
|
|
message: 'Datenbestand wurde erfolgreich exportiert!',
|
|
color: 'success'
|
|
});
|
|
}
|
|
|
|
async function upload(file: VaFile) {
|
|
const data = (await file?.text?.()?.catch(() => '')) || '';
|
|
|
|
const error = tramStore.importData(data);
|
|
if (error) {
|
|
console.error(error);
|
|
console.warn(z.prettifyError(error));
|
|
init({
|
|
title: 'Import fehlgeschlagen',
|
|
message: `Die hochgeladene Datei ist im falschen Format!`,
|
|
color: 'danger'
|
|
});
|
|
return;
|
|
}
|
|
init({
|
|
title: 'Import erfolgreich',
|
|
message: 'Datenbestand wurde erfolgreich importiert!',
|
|
color: 'success'
|
|
});
|
|
}
|
|
|
|
async function reset() {
|
|
const yes = await confirm({
|
|
title: 'Bist du dir sicher?',
|
|
message:
|
|
'Willst du wirklich deinen Fortschritt zurücksetzen? Dies ist nicht rückgängig zu machen!',
|
|
okText: 'Ja zurücksetzen!',
|
|
cancelText: 'Abbrechen',
|
|
'child:okButton': {
|
|
color: 'danger'
|
|
}
|
|
});
|
|
|
|
if (!yes) {
|
|
return;
|
|
}
|
|
|
|
tramStore.$reset();
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<article class="p-4">
|
|
<div class="mb-4 flex flex-row items-center">
|
|
<h1 class="text-3xl">Statistiken</h1>
|
|
<VaCheckbox v-model="showMissing" label="Fehlende anzeigen?" left-label class="ml-auto" />
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
|
<VaCard stripe-color="success" stripe>
|
|
<VaCardTitle>Nach Typ</VaCardTitle>
|
|
<VaCardContent>
|
|
<div class="flex flex-col justify-around gap-4">
|
|
<div v-for="(group, i) in groupBy(type, (t) => t[3])" :key="i">
|
|
<p>
|
|
{{
|
|
showMissing
|
|
? missingOf(group.elements, tramStore.trams.bsag)
|
|
: idsOf(group.elements)
|
|
}}:
|
|
</p>
|
|
<StatsBlock
|
|
:total="group.elements.reduce((acc, t) => acc + (t[1] - t[0]) + 1, 0)"
|
|
:found="
|
|
tramStore.trams.bsag.filter((id) =>
|
|
group.elements.some((t) => id >= t[0] && id <= t[1])
|
|
).length
|
|
"
|
|
:icon="group.elements[0][2] ? 'tram' : 'directions_bus'"
|
|
:color="group.elements[0][2] ? 'danger' : 'warning'"
|
|
:name="group.key"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</VaCardContent>
|
|
</VaCard>
|
|
<VaCard stripe-color="success" stripe>
|
|
<VaCardTitle>Besondere Fahrzeuge</VaCardTitle>
|
|
<VaCardContent>
|
|
<div class="flex flex-col justify-around gap-4">
|
|
<StatsBlock
|
|
:total="specialCars.crash.length"
|
|
:found="
|
|
tramStore.specials.bsag.filter((id) => specialCars.crash.some((t) => id === t[0]))
|
|
.length
|
|
"
|
|
icon="car_crash"
|
|
color="info"
|
|
name="Betriebsaufsicht/Unfallhilfe"
|
|
/>
|
|
<StatsBlock
|
|
:total="specialCars.work.length"
|
|
:found="
|
|
tramStore.specials.bsag.filter((id) => specialCars.work.some((t) => id === t[0]))
|
|
.length
|
|
"
|
|
icon="edit_road"
|
|
color="info"
|
|
name="Fahrzeuge Instandhaltung Bahn-Infrastruktur"
|
|
/>
|
|
<StatsBlock
|
|
:total="specialCars.help.length"
|
|
:found="
|
|
tramStore.specials.bsag.filter((id) => specialCars.help.some((t) => id === t[0]))
|
|
.length
|
|
"
|
|
icon="handyman"
|
|
color="info"
|
|
name="Hilfsfahrzeuge in und für Werkstätten"
|
|
/>
|
|
<StatsBlock
|
|
:total="specialCars.historic.length"
|
|
:found="
|
|
tramStore.specials.bsag.filter((id) =>
|
|
specialCars.historic.some((t) => id === t[0])
|
|
).length
|
|
"
|
|
icon="museum"
|
|
color="info"
|
|
name="Freunde der Bremer Straßenbahn e.V."
|
|
/>
|
|
</div>
|
|
</VaCardContent>
|
|
</VaCard>
|
|
<VaCard class="mb-auto" stripe-color="success" stripe>
|
|
<VaCardTitle>Quick stats</VaCardTitle>
|
|
<VaCardContent>
|
|
<QuickStats />
|
|
</VaCardContent>
|
|
</VaCard>
|
|
<VaCard stripe-color="warning" stripe>
|
|
<VaCardTitle>Export/Import</VaCardTitle>
|
|
<VaCardContent>
|
|
<div class="flex flex-row items-center justify-center gap-2 md:justify-start">
|
|
<VaButton color="success" icon="file_upload" @click="download">Export</VaButton>
|
|
<VaFileUpload
|
|
color="warning"
|
|
fileTypes="json"
|
|
type="single"
|
|
file-incorrect-message="Falscher Datentyp, .json erforderlich!"
|
|
upload-button-text="Import"
|
|
hideFileList
|
|
@update:model-value="upload"
|
|
><VaButton color="warning" icon="file_download">Import</VaButton></VaFileUpload
|
|
>
|
|
<VaButton color="danger" icon="delete_forever" @click="reset">Reset</VaButton>
|
|
</div>
|
|
</VaCardContent>
|
|
</VaCard>
|
|
</div>
|
|
</article>
|
|
</template>
|
|
|
|
<style scoped></style>
|