Add special cars

This commit is contained in:
2025-09-08 00:03:18 +02:00
parent f02c39807e
commit fdc84e8597
10 changed files with 217 additions and 49 deletions
+3
View File
@@ -15,6 +15,9 @@ usePWAReload();
<template #right> <template #right>
<VaButton to="/stats" icon="leaderboard" title="Statistiken" /> <VaButton to="/stats" icon="leaderboard" title="Statistiken" />
</template> </template>
<template #left>
<VaButton to="/special" icon="star" title="Besondere Fahrzeuge" />
</template>
</VaNavbar> </VaNavbar>
</template> </template>
+41
View File
@@ -0,0 +1,41 @@
<script setup lang="ts">
import StatsBlock from '@/components/StatsBlock.vue';
import { useTramStore } from '@/stores/tram.ts';
const tramStore = useTramStore();
</script>
<template>
<div class="flex flex-col justify-around sm:flex-row">
<StatsBlock
:total="tramStore.shortStats.totalCount"
:found="tramStore.shortStats.found"
name="Fahrzeuge"
color="success"
icon="train"
/>
<StatsBlock
:total="tramStore.shortStats.tramCount"
:found="tramStore.shortStats.trams"
name="Trams"
color="danger"
icon="tram"
/>
<StatsBlock
:total="tramStore.shortStats.busCount"
:found="tramStore.shortStats.busses"
name="Busse"
color="warning"
icon="directions_bus"
/>
<StatsBlock
:total="tramStore.shortStats.specialsTotal"
:found="tramStore.shortStats.specials"
name="Besondere Fahrzeuge"
color="info"
icon="star"
/>
</div>
</template>
<style scoped></style>
+29
View File
@@ -0,0 +1,29 @@
<script setup lang="ts">
import type { SpecialCar } from '@/data/specials.ts';
import { useTramStore } from '@/stores/tram.ts';
import { VaCheckbox } from 'vuestic-ui';
defineProps<{
car: SpecialCar;
}>();
const tramStore = useTramStore();
</script>
<template>
<div
class="grid grid-cols-2 justify-between rounded-2xl px-4 py-2 text-center transition-colors sm:grid-cols-4"
:class="
tramStore.specials.bsag.includes(car[0])
? 'bg-green-100 hover:bg-green-200'
: 'bg-gray-100 hover:bg-gray-200'
"
>
<p class="text-left">{{ car.length > 3 ? car[3] : car[0] }}</p>
<p>{{ car[1] }}</p>
<p>{{ car[2] }}</p>
<VaCheckbox class="ms-auto mr-2" :array-value="car[0]" v-model="tramStore.specials.bsag" />
</div>
</template>
<style scoped></style>
+12
View File
@@ -0,0 +1,12 @@
<script setup lang="ts"></script>
<template>
<div class="grid grid-cols-2 justify-between px-4 py-2 text-center sm:grid-cols-4">
<p class="text-left">Name</p>
<p>Typ</p>
<p>Baujahr</p>
<p class="text-right">Gesehen</p>
</div>
</template>
<style scoped></style>
+32
View File
@@ -0,0 +1,32 @@
export type SpecialCar = [string, string, number] | [string, string, number, string];
export const specialCars = {
crash: [
['E10', 'Sprinter 316 BlueTec', 2017, 'Emil 10'],
['E11', 'Sprinter 316 CDI', 2019, 'Emil 11'],
['E12', 'Sprinter 316 CDI', 2023, 'Emil 12'],
['E13', 'Sprinter 317 CDI', 2024, 'Emil 13']
] as SpecialCar[],
work: [
['TW1', 'Zweiwege-Turmwagen', 2021],
['TW2', 'Zweiwege-Hubsteiger', 2014],
['TW3', 'Zweiwege-Turmwagen', 2003],
['TW4', 'Zweiwege-Turmwagen', 1997],
['0321', 'Hubsteiger', 2021],
['B12', 'Zweiwege-Bagger', 2000],
['B13', 'Zweiwege-Bagger', 2016],
['0264', 'Hochdruck-Spülwagen (für Weichen)', 2013],
['0291', 'Zweiwege-Schienenreinigungswagen', 2015],
['0292', 'Reinigungsfahrzeug', 2016],
['0293', 'Reinigungsfahrzeug', 2016]
] as SpecialCar[],
help: [
['ZM1', 'Zugmaschine Servicewerkstatt', 1993],
['ZM3', 'Diesel-Zweiwege-Unimog', 1993],
['ZM4', 'Zugmaschine Servicewerkstatt', 1990],
['0028', 'Diesel-Unimog', 1999],
['0266', 'Diesel-Zugmaschine', 2009],
['SF1', 'Sandbefüllfahrzeug', 2019]
] as SpecialCar[]
} as const;
export const allSpecials = [...specialCars.crash, ...specialCars.work, ...specialCars.help];
+2 -24
View File
@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import CarDetail from '@/components/CarDetail.vue'; import CarDetail from '@/components/CarDetail.vue';
import StatsBlock from '@/components/StatsBlock.vue'; import QuickStats from '@/components/QuickStats.vue';
import { getType, useTramStore } from '@/stores/tram.ts'; import { getType, useTramStore } from '@/stores/tram.ts';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { import {
@@ -97,29 +97,7 @@ function add() {
<VaCard class="md:col-2" stripe-color="success" stripe> <VaCard class="md:col-2" stripe-color="success" stripe>
<VaCardTitle>Quick stats</VaCardTitle> <VaCardTitle>Quick stats</VaCardTitle>
<VaCardContent> <VaCardContent>
<div class="flex flex-col justify-around sm:flex-row"> <QuickStats />
<StatsBlock
:total="tramStore.shortStats.totalCount"
:found="tramStore.shortStats.found"
name="Fahrzeuge"
color="success"
icon="train"
/>
<StatsBlock
:total="tramStore.shortStats.tramCount"
:found="tramStore.shortStats.trams"
name="Trams"
color="danger"
icon="tram"
/>
<StatsBlock
:total="tramStore.shortStats.busCount"
:found="tramStore.shortStats.busses"
name="Busse"
color="warning"
icon="directions_bus"
/>
</div>
</VaCardContent> </VaCardContent>
<VaCardActions> <VaCardActions>
<VaButton to="/stats" icon="arrow_outward">Mehr Statistiken</VaButton> <VaButton to="/stats" icon="arrow_outward">Mehr Statistiken</VaButton>
+44
View File
@@ -0,0 +1,44 @@
<script setup lang="ts">
import SpecialCar from '@/components/SpecialCar.vue';
import SpecialCarHead from '@/components/SpecialCarHead.vue';
import { specialCars } from '@/data/specials.ts';
import { VaCard, VaCardContent, VaCardTitle } from 'vuestic-ui';
</script>
<template>
<article>
<h1 class="m-4 mb-6 text-3xl">Besondere Fahrzeuge</h1>
<div class="grid grid-cols-1 gap-4 p-4 pt-0 md:grid-cols-2">
<VaCard>
<VaCardTitle>Betriebsaufsicht/Unfallhilfe</VaCardTitle>
<VaCardContent>
<div class="flex flex-col gap-2">
<SpecialCarHead />
<SpecialCar v-for="car in specialCars.crash" :key="car[0]" :car="car" />
</div>
</VaCardContent>
</VaCard>
<VaCard>
<VaCardTitle>Fahrzeuge Instandhaltung Bahn-Infrastruktur</VaCardTitle>
<VaCardContent>
<div class="flex flex-col gap-2">
<SpecialCarHead />
<SpecialCar v-for="car in specialCars.work" :key="car[0]" :car="car" />
</div>
</VaCardContent>
</VaCard>
<VaCard>
<VaCardTitle>Hilfsfahrzeuge in und für Werkstätten</VaCardTitle>
<VaCardContent>
<div class="flex flex-col gap-2">
<SpecialCarHead />
<SpecialCar v-for="car in specialCars.help" :key="car[0]" :car="car" />
</div>
</VaCardContent>
</VaCard>
</div>
</article>
</template>
<style scoped></style>
+40 -23
View File
@@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import QuickStats from '@/components/QuickStats.vue';
import StatsBlock from '@/components/StatsBlock.vue'; import StatsBlock from '@/components/StatsBlock.vue';
import { specialCars } from '@/data/specials.ts';
import { type, useTramStore } from '@/stores/tram.ts'; import { type, useTramStore } from '@/stores/tram.ts';
import { groupBy } from '@/utils/array.ts'; import { groupBy } from '@/utils/array.ts';
import { idsOf } from '@/utils/typeGroup.ts'; import { idsOf } from '@/utils/typeGroup.ts';
@@ -34,32 +36,47 @@ const tramStore = useTramStore();
</div> </div>
</VaCardContent> </VaCardContent>
</VaCard> </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"
/>
</div>
</VaCardContent>
</VaCard>
<VaCard class="mb-auto" stripe-color="success" stripe> <VaCard class="mb-auto" stripe-color="success" stripe>
<VaCardTitle>Quick stats</VaCardTitle> <VaCardTitle>Quick stats</VaCardTitle>
<VaCardContent> <VaCardContent>
<div class="flex flex-col justify-around sm:flex-row"> <QuickStats />
<StatsBlock
:total="tramStore.shortStats.totalCount"
:found="tramStore.shortStats.found"
name="Fahrzeuge"
color="success"
icon="train"
/>
<StatsBlock
:total="tramStore.shortStats.tramCount"
:found="tramStore.shortStats.trams"
name="Trams"
color="danger"
icon="tram"
/>
<StatsBlock
:total="tramStore.shortStats.busCount"
:found="tramStore.shortStats.busses"
name="Busse"
color="warning"
icon="directions_bus"
/>
</div>
</VaCardContent> </VaCardContent>
</VaCard> </VaCard>
</div> </div>
+4
View File
@@ -27,6 +27,10 @@ const router = createRouter({
{ {
path: '/imprint', path: '/imprint',
component: () => import('../pages/ImprintView.vue') component: () => import('../pages/ImprintView.vue')
},
{
path: '/special',
component: () => import('../pages/SpecialView.vue')
} }
] ]
}); });
+10 -2
View File
@@ -1,3 +1,4 @@
import { allSpecials } from '@/data/specials.ts';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { computed, reactive } from 'vue'; import { computed, reactive } from 'vue';
@@ -53,6 +54,11 @@ export const useTramStore = defineStore(
}>({ }>({
bsag: [] bsag: []
}); });
const specials = reactive<{
bsag: string[];
}>({
bsag: []
});
function addNumber(id: number | string) { function addNumber(id: number | string) {
const foundType = getType(id); const foundType = getType(id);
@@ -77,11 +83,13 @@ export const useTramStore = defineStore(
tramCount, tramCount,
found, found,
busses, busses,
trams: found - busses trams: found - busses,
specials: specials.bsag.length,
specialsTotal: allSpecials.length
}; };
}); });
return { trams, addNumber, shortStats }; return { trams, addNumber, shortStats, specials };
}, },
{ {
persist: true persist: true