mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 05:18:11 +00:00
dodatkowe statystyki dnia
This commit is contained in:
@@ -1,56 +1,59 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="daily-stats">
|
<section class="daily-stats">
|
||||||
<span :data-active="data.statsStatus">
|
<span :data-active="statsStatus">
|
||||||
<b v-if="data.statsStatus == DataStatus.Loading">
|
<b v-if="statsStatus == DataStatus.Loading">
|
||||||
{{ $t('app.loading') }}
|
{{ $t('app.loading') }}
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
<b v-else-if="data.stats.distanceSum == null">
|
<b v-else-if="stats.distanceSum == null">
|
||||||
{{ $t('journal.daily-stats-info') }}
|
{{ $t('journal.daily-stats-info') }}
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
<span>
|
<h3>{{ $t('journal.daily-stats-title') }} {{ new Date().toLocaleDateString($i18n.locale) }}</h3>
|
||||||
<div v-if="data.stats.totalTimetables">
|
<hr style="margin-bottom: 0.5em" />
|
||||||
|
|
||||||
|
<span class="stats-list">
|
||||||
|
<div v-if="stats.totalTimetables">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-total">
|
<i18n-t keypath="journal.timetable-stats-total">
|
||||||
<template #count>
|
<template #count>
|
||||||
<b class="text--primary">
|
<b class="text--primary">
|
||||||
{{ data.stats.totalTimetables }}
|
{{ stats.totalTimetables }}
|
||||||
{{ $t('journal.timetable-count', data.stats.totalTimetables) }}
|
{{ $t('journal.timetable-count', stats.totalTimetables) }}
|
||||||
</b>
|
</b>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #distance>
|
<template #distance>
|
||||||
<b class="text--primary"> {{ data.stats.distanceSum?.toFixed(2) }} km </b>
|
<b class="text--primary"> {{ stats.distanceSum?.toFixed(2) }} km</b>
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="data.stats.timetableId">
|
<div v-if="stats.timetableId">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-longest">
|
<i18n-t keypath="journal.timetable-stats-longest">
|
||||||
<template #id>
|
<template #id>
|
||||||
<router-link :to="`/journal/timetables?timetableId=${data.stats.timetableId}`">
|
<router-link :to="`/journal/timetables?timetableId=${stats.timetableId}`">
|
||||||
<b>{{ data.stats.timetableId }}</b>
|
<b>{{ stats.timetableId }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template #author>
|
<template #author>
|
||||||
<router-link :to="`/journal/dispatchers?dispatcherName=${data.stats.timetableAuthor}`">
|
<router-link :to="`/journal/dispatchers?dispatcherName=${stats.timetableAuthor}`">
|
||||||
<b>{{ data.stats.timetableAuthor }}</b>
|
<b>{{ stats.timetableAuthor }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template #driver>
|
<template #driver>
|
||||||
<b>{{ data.stats.timetableDriver }}</b>
|
<b class="text--primary">{{ stats.timetableDriver }}</b>
|
||||||
</template>
|
</template>
|
||||||
<template #distance>
|
<template #distance>
|
||||||
<b class="text--primary">{{ data.stats.timetableRouteDistance }} km</b>
|
<b class="text--primary">{{ stats.timetableRouteDistance }} km</b>
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="firstPlaceDispatchers.length == 1">
|
<div v-if="firstPlaceDispatchers.length == 1">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-most-active">
|
<i18n-t keypath="journal.timetable-stats-most-active-dr">
|
||||||
<template #dispatcher>
|
<template #dispatcher>
|
||||||
<router-link :to="`/journal/dispatchers?dispatcherName=${firstPlaceDispatchers[0].name}`">
|
<router-link :to="`/journal/dispatchers?dispatcherName=${firstPlaceDispatchers[0].name}`">
|
||||||
<b>{{ firstPlaceDispatchers[0].name }}</b>
|
<b>{{ firstPlaceDispatchers[0].name }}</b>
|
||||||
@@ -67,7 +70,7 @@
|
|||||||
|
|
||||||
<div v-if="firstPlaceDispatchers.length > 1">
|
<div v-if="firstPlaceDispatchers.length > 1">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-most-active-many">
|
<i18n-t keypath="journal.timetable-stats-most-active-dr-many">
|
||||||
<template #dispatchers>
|
<template #dispatchers>
|
||||||
<span v-for="(disp, i) in firstPlaceDispatchers">
|
<span v-for="(disp, i) in firstPlaceDispatchers">
|
||||||
<span v-if="i == firstPlaceDispatchers.length - 1"> {{ $t('general.and') }} </span>
|
<span v-if="i == firstPlaceDispatchers.length - 1"> {{ $t('general.and') }} </span>
|
||||||
@@ -88,101 +91,133 @@
|
|||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="stats.longestDuties.length > 0">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.timetable-stats-longest-duties">
|
||||||
|
<template #dispatcher>
|
||||||
|
<router-link :to="`/journal/dispatchers?dispatcherName=${stats.longestDuties[0].name}`">
|
||||||
|
<b>{{ stats.longestDuties[0].name }}</b>
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #station>{{ stats.longestDuties[0].station }}</template>
|
||||||
|
|
||||||
|
<template #duration>
|
||||||
|
{{ calculateDuration(stats.longestDuties[0].duration) }}
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="stats.mostActiveDrivers.length > 0">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.timetable-stats-most-active-driver">
|
||||||
|
<template #driver>
|
||||||
|
<b class="text--primary">{{ stats.mostActiveDrivers[0].name }}</b>
|
||||||
|
</template>
|
||||||
|
<template #distance>
|
||||||
|
<b class="text--primary">{{ stats.mostActiveDrivers[0].distance }} km</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { computed, onActivated, onDeactivated, onMounted, reactive, ref } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||||
import { ITimetablesDailyStats, ITimetablesDailyStatsResponse } from '../../scripts/interfaces/api/StatsAPIData';
|
import { ITimetablesDailyStats, ITimetablesDailyStatsResponse } from '../../scripts/interfaces/api/StatsAPIData';
|
||||||
import { URLs } from '../../scripts/utils/apiURLs';
|
import { URLs } from '../../scripts/utils/apiURLs';
|
||||||
import StorageManager from '../../scripts/managers/storageManager';
|
|
||||||
|
|
||||||
const intervalId = ref(-1);
|
export default defineComponent({
|
||||||
|
mixins: [dateMixin],
|
||||||
|
emits: ['toggleStatsOpen'],
|
||||||
|
|
||||||
const emit = defineEmits<{
|
data() {
|
||||||
(e: 'toggleStatsOpen', value: boolean): void;
|
return {
|
||||||
}>();
|
DataStatus,
|
||||||
|
statsStatus: DataStatus.Loading,
|
||||||
|
intervalId: -1,
|
||||||
|
|
||||||
const data = reactive({
|
stats: {
|
||||||
statsStatus: DataStatus.Loading,
|
totalTimetables: 0,
|
||||||
|
distanceSum: 0,
|
||||||
stats: {
|
distanceAvg: 0,
|
||||||
totalTimetables: 0,
|
timetableAuthor: '',
|
||||||
distanceSum: 0,
|
timetableDriver: '',
|
||||||
distanceAvg: 0,
|
timetableId: 0,
|
||||||
timetableAuthor: '',
|
timetableRouteDistance: 0,
|
||||||
timetableDriver: '',
|
longestDuties: [],
|
||||||
timetableId: 0,
|
mostActiveDrivers: [],
|
||||||
timetableRouteDistance: 0,
|
mostActiveDispatchers: [],
|
||||||
|
} as ITimetablesDailyStats,
|
||||||
mostActiveDispatchers: [],
|
|
||||||
} as ITimetablesDailyStats,
|
|
||||||
});
|
|
||||||
|
|
||||||
const firstPlaceDispatchers = computed(() => {
|
|
||||||
if (data.stats.mostActiveDispatchers.length == 0) return [];
|
|
||||||
const maxCount = data.stats.mostActiveDispatchers[0].count;
|
|
||||||
|
|
||||||
return data.stats.mostActiveDispatchers.filter((disp) => disp.count === maxCount);
|
|
||||||
});
|
|
||||||
|
|
||||||
async function fetchDailyTimetableStats() {
|
|
||||||
try {
|
|
||||||
const {
|
|
||||||
distanceAvg,
|
|
||||||
distanceSum,
|
|
||||||
maxTimetable,
|
|
||||||
totalTimetables,
|
|
||||||
mostActiveDispatchers,
|
|
||||||
}: ITimetablesDailyStatsResponse = await (
|
|
||||||
await axios.get(`${URLs.stacjownikAPI}/api/getDailyTimetableStats`)
|
|
||||||
).data;
|
|
||||||
|
|
||||||
data.stats = {
|
|
||||||
totalTimetables,
|
|
||||||
distanceSum,
|
|
||||||
distanceAvg,
|
|
||||||
timetableAuthor: maxTimetable?.authorName || '',
|
|
||||||
timetableDriver: maxTimetable?.driverName || '',
|
|
||||||
timetableId: maxTimetable?.id || 0,
|
|
||||||
timetableRouteDistance: maxTimetable?.routeDistance || 0,
|
|
||||||
|
|
||||||
mostActiveDispatchers,
|
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
data.statsStatus = DataStatus.Loaded;
|
activated() {
|
||||||
} catch (error) {
|
this.startFetchingDailyStats();
|
||||||
console.error('Ups! Wystąpił błąd podczas pobierania statystyk rozkładów jazdy...');
|
this.$emit('toggleStatsOpen', true);
|
||||||
data.statsStatus = DataStatus.Error;
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function startFetchingDailyStats() {
|
deactivated() {
|
||||||
fetchDailyTimetableStats();
|
this.stopFetchingDailyStats();
|
||||||
|
},
|
||||||
|
|
||||||
if (intervalId.value != -1) return;
|
computed: {
|
||||||
|
firstPlaceDispatchers() {
|
||||||
|
if (this.stats.mostActiveDispatchers.length == 0) return [];
|
||||||
|
const maxCount = this.stats.mostActiveDispatchers[0].count;
|
||||||
|
|
||||||
intervalId.value = setInterval(fetchDailyTimetableStats, 60000);
|
return this.stats.mostActiveDispatchers.filter((disp) => disp.count === maxCount);
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
|
||||||
function stopFetchingDailyStats() {
|
methods: {
|
||||||
clearInterval(intervalId.value);
|
async fetchDailyTimetableStats() {
|
||||||
intervalId.value = -1;
|
try {
|
||||||
}
|
const res: ITimetablesDailyStatsResponse = await (
|
||||||
|
await axios.get(`${URLs.stacjownikAPI}/api/getDailyTimetableStats`)
|
||||||
|
).data;
|
||||||
|
|
||||||
onActivated(() => {
|
this.stats = {
|
||||||
startFetchingDailyStats();
|
totalTimetables: res.totalTimetables,
|
||||||
emit('toggleStatsOpen', true);
|
distanceSum: res.distanceSum,
|
||||||
|
distanceAvg: res.distanceAvg,
|
||||||
|
timetableAuthor: res.maxTimetable?.authorName || '',
|
||||||
|
timetableDriver: res.maxTimetable?.driverName || '',
|
||||||
|
timetableId: res.maxTimetable?.id || 0,
|
||||||
|
timetableRouteDistance: res.maxTimetable?.routeDistance || 0,
|
||||||
|
|
||||||
|
mostActiveDispatchers: res.mostActiveDispatchers,
|
||||||
|
mostActiveDrivers: res.mostActiveDrivers,
|
||||||
|
longestDuties: res.longestDuties,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.statsStatus = DataStatus.Loaded;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ups! Wystąpił błąd podczas pobierania statystyk rozkładów jazdy...');
|
||||||
|
this.statsStatus = DataStatus.Error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
startFetchingDailyStats() {
|
||||||
|
this.fetchDailyTimetableStats();
|
||||||
|
|
||||||
|
if (this.intervalId != -1) return;
|
||||||
|
|
||||||
|
this.intervalId = setInterval(this.fetchDailyTimetableStats, 60000);
|
||||||
|
},
|
||||||
|
|
||||||
|
stopFetchingDailyStats() {
|
||||||
|
clearInterval(this.intervalId);
|
||||||
|
this.intervalId = -1;
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
onDeactivated(() => {
|
|
||||||
stopFetchingDailyStats();
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -192,5 +227,9 @@ onDeactivated(() => {
|
|||||||
.daily-stats > span[data-active='0'] {
|
.daily-stats > span[data-active='0'] {
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stats-list a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
+7
-4
@@ -312,10 +312,13 @@
|
|||||||
"stats-distance": "DISTANCE",
|
"stats-distance": "DISTANCE",
|
||||||
"stats-stations": "STATIONS",
|
"stats-stations": "STATIONS",
|
||||||
|
|
||||||
"timetable-stats-total": "Today, dispatchers made so far {count} with total distance of {distance}",
|
"timetable-stats-title": "Daily stats on {date}",
|
||||||
"timetable-stats-longest": "The longest timetable today is #{id} made by {author} for {driver} - {distance}",
|
"timetable-stats-total": "Issued timetables: {count} (total distance: {distance})",
|
||||||
"timetable-stats-most-active": "The most active dispatcher today is {dispatcher} who created {count}",
|
"timetable-stats-longest": "The longest timetable: #{id} (made by {author} for {driver}, distance: {distance})",
|
||||||
"timetable-stats-most-active-many": "The most active dispatchers today are {dispatchers} who created {count} each",
|
"timetable-stats-most-active-dr": "The most active dispatcher: {dispatcher} (created {count})",
|
||||||
|
"timetable-stats-most-active-dr-many": "The most active dispatchers: {dispatchers} (created {count} each)",
|
||||||
|
"timetable-stats-most-active-driver": "The most active driver: {driver} (has driven {distance})",
|
||||||
|
"timetable-stats-longest-duties": "The longest service: {dispatcher} at {station} (duration: {duration})",
|
||||||
|
|
||||||
"timetable-count": "timetable | timetables",
|
"timetable-count": "timetable | timetables",
|
||||||
|
|
||||||
|
|||||||
+6
-4
@@ -317,10 +317,12 @@
|
|||||||
"stats-distance": "DYSTANS",
|
"stats-distance": "DYSTANS",
|
||||||
"stats-stations": "STACJE",
|
"stats-stations": "STACJE",
|
||||||
|
|
||||||
"timetable-stats-total": "Dyżurni stworzyli dziś {count} o łącznym dystansie {distance}",
|
"timetable-stats-total": "Stworzone rozkłady jazdy: {count} (łączny dystans: {distance})",
|
||||||
"timetable-stats-longest": "Najdłuższym rozkładem jazdy jest dzisiaj #{id} stworzony przez dyżurnego {author} dla maszynisty {driver} - {distance}",
|
"timetable-stats-longest": "Najdłuższy rozkład jazdy: #{id} (stworzony przez dyżurnego {author} dla maszynisty {driver} o dystansie {distance})",
|
||||||
"timetable-stats-most-active": "Dzisiejszym najaktywniejszym dyżurnym jest {dispatcher}, który stworzył {count}",
|
"timetable-stats-most-active-dr": "Najaktywniejszy dyżurny: {dispatcher} (stworzył {count})",
|
||||||
"timetable-stats-most-active-many": "Dzisiejszymi najaktywniejszymi dyżurnymi są {dispatchers}, którzy stworzyli po {count}",
|
"timetable-stats-most-active-dr-many": "Najaktywniejsi dyżurni: {dispatchers} (stworzyli po {count})",
|
||||||
|
"timetable-stats-most-active-driver": "Najaktywniejszy maszynista: {driver} (przejechał łącznie {distance})",
|
||||||
|
"timetable-stats-longest-duties": "Najdłuższa służba: {dispatcher} na scenerii {station} (czas trwania: {duration})",
|
||||||
|
|
||||||
"timetable-count": "rozkład jazdy | rozkładów jazdy",
|
"timetable-count": "rozkład jazdy | rozkładów jazdy",
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,17 @@ export interface ITimetablesDailyStats {
|
|||||||
name: string;
|
name: string;
|
||||||
count: number;
|
count: number;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
|
mostActiveDrivers: {
|
||||||
|
name: string;
|
||||||
|
distance: number;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
longestDuties: {
|
||||||
|
name: string;
|
||||||
|
duration: number;
|
||||||
|
station: string;
|
||||||
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITimetablesDailyStatsResponse {
|
export interface ITimetablesDailyStatsResponse {
|
||||||
@@ -26,5 +37,16 @@ export interface ITimetablesDailyStatsResponse {
|
|||||||
name: string;
|
name: string;
|
||||||
count: number;
|
count: number;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
|
mostActiveDrivers: {
|
||||||
|
name: string;
|
||||||
|
distance: number;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
longestDuties: {
|
||||||
|
name: string;
|
||||||
|
duration: number;
|
||||||
|
station: string;
|
||||||
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user