dodane nowe statystyki dnia; poprawki bugów

This commit is contained in:
2023-12-22 15:46:47 +01:00
parent 514723cf74
commit 2f8376c996
9 changed files with 215 additions and 141 deletions
@@ -42,13 +42,13 @@
• •
<i18n-t keypath="journal.daily-stats.longest"> <i18n-t keypath="journal.daily-stats.longest">
<template #id> <template #id>
<router-link :to="`/journal/timetables?timetableId=${stats.maxTimetable.id}`"> <router-link :to="`/journal/timetables?search-train=%23${stats.maxTimetable.id}`">
<b>{{ stats.maxTimetable.id }}</b> <b>{{ stats.maxTimetable.id }}</b>
</router-link> </router-link>
</template> </template>
<template #author> <template #author>
<router-link <router-link
:to="`/journal/dispatchers?dispatcherName=${stats.maxTimetable.authorName}`" :to="`/journal/timetables?search-dispatcher=${stats.maxTimetable.authorName}`"
> >
<b>{{ stats.maxTimetable.authorName }}</b> <b>{{ stats.maxTimetable.authorName }}</b>
</router-link> </router-link>
@@ -66,7 +66,9 @@
&bull; &bull;
<i18n-t keypath="journal.daily-stats.most-active-dr"> <i18n-t keypath="journal.daily-stats.most-active-dr">
<template #dispatcher> <template #dispatcher>
<router-link :to="`/journal/dispatchers?dispatcherName=${topDispatchers[0].name}`"> <router-link
:to="`/journal/dispatchers?search-dispatcher=${topDispatchers[0].name}`"
>
<b>{{ topDispatchers[0].name }}</b> <b>{{ topDispatchers[0].name }}</b>
</router-link> </router-link>
</template> </template>
@@ -86,7 +88,7 @@
<span v-for="(disp, i) in topDispatchers" :key="i"> <span v-for="(disp, i) in topDispatchers" :key="i">
<span v-if="i == topDispatchers.length - 1"> {{ $t('general.and') }} </span> <span v-if="i == topDispatchers.length - 1"> {{ $t('general.and') }} </span>
<router-link :to="`/journal/dispatchers?dispatcherName=${disp.name}`"> <router-link :to="`/journal/dispatchers?search-dispatcher=${disp.name}`">
<b>{{ disp.name }}</b> <b>{{ disp.name }}</b>
</router-link> </router-link>
@@ -108,7 +110,7 @@
<i18n-t keypath="journal.daily-stats.longest-duties"> <i18n-t keypath="journal.daily-stats.longest-duties">
<template #dispatcher> <template #dispatcher>
<router-link <router-link
:to="`/journal/dispatchers?dispatcherName=${stats.longestDuties[0].name}`" :to="`/journal/dispatchers?search-dispatcher=${stats.longestDuties[0].name}`"
> >
<b>{{ stats.longestDuties[0].name }}</b> <b>{{ stats.longestDuties[0].name }}</b>
</router-link> </router-link>
@@ -126,13 +128,38 @@
&bull; &bull;
<i18n-t keypath="journal.daily-stats.most-active-driver"> <i18n-t keypath="journal.daily-stats.most-active-driver">
<template #driver> <template #driver>
<b class="text--primary">{{ stats.mostActiveDrivers[0].name }}</b> <router-link
:to="`/journal/timetables?search-driver=${stats.mostActiveDrivers[0].name}`"
>
<b>{{ stats.mostActiveDrivers[0].name }}</b>
</router-link>
</template> </template>
<template #distance> <template #distance>
<b class="text--primary">{{ stats.mostActiveDrivers[0].distance.toFixed(2) }} km</b> <b class="text--primary">{{ stats.mostActiveDrivers[0].distance.toFixed(2) }} km</b>
</template> </template>
</i18n-t> </i18n-t>
</div> </div>
<hr class="section-separator" />
<div class="stats-badges">
<span
class="stat-badge"
v-for="key in [
'rippedSwitches',
'derailments',
'skippedStopSignals',
'radioStops',
'kills'
]"
:key="key"
>
<span>{{ $t(`journal.daily-stats.${key}`) }}</span>
<span>{{
Object.entries(stats.globalDiff).find(([k, v]) => k == key)?.[1] || '--'
}}</span>
</span>
</div>
</div> </div>
</span> </span>
</span> </span>
@@ -214,6 +241,7 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
@import '../../styles/responsive.scss'; @import '../../styles/responsive.scss';
@import '../../styles/JournalStats.scss'; @import '../../styles/JournalStats.scss';
@import '../../styles/badge.scss';
.daily-stats { .daily-stats {
text-align: left; text-align: left;
@@ -226,6 +254,12 @@ export default defineComponent({
text-decoration: underline; text-decoration: underline;
} }
.stats-badges {
display: flex;
flex-wrap: wrap;
gap: 0.5em;
}
@include smallScreen { @include smallScreen {
h3 { h3 {
text-align: center; text-align: center;
@@ -32,7 +32,7 @@
</span> </span>
</div> </div>
<hr style="margin: 1em 0" /> <hr class="section-separator" />
<div class="info-stats"> <div class="info-stats">
<span class="stat-badge" v-if="stats.issuedTimetables"> <span class="stat-badge" v-if="stats.issuedTimetables">
@@ -1,124 +1,122 @@
<template> <template>
<div> <transition name="status-anim" mode="out-in">
<transition name="status-anim" mode="out-in"> <div :key="dataStatus">
<div :key="dataStatus"> <div class="journal_warning" v-if="store.isOffline">
<div class="journal_warning" v-if="store.isOffline"> {{ $t('app.offline') }}
{{ $t('app.offline') }}
</div>
<Loading v-else-if="dataStatus == Status.Data.Loading" />
<div v-else-if="dataStatus == Status.Data.Error" class="journal_warning error">
{{ $t('app.error') }}
</div>
<div class="journal_warning" v-else-if="dispatcherHistory.length == 0">
{{ $t('app.no-result') }}
</div>
<div v-else>
<table class="scenery-history-table">
<thead>
<th>{{ $t('journal.history-name') }}</th>
<th>{{ $t('journal.history-hash') }}</th>
<th>{{ $t('journal.history-dispatcher') }}</th>
<th>{{ $t('journal.history-level') }}</th>
<th>{{ $t('journal.history-rate') }}</th>
<th>{{ $t('journal.history-region') }}</th>
<th>{{ $t('journal.history-date') }}</th>
</thead>
<tbody>
<transition-group name="list-anim">
<tr v-for="historyItem in dispatcherHistory" :key="historyItem.id">
<td>
<router-link
:to="`/journal/dispatchers?search-station=${historyItem.stationName}`"
>
<b>{{ historyItem.stationName }}</b>
</router-link>
</td>
<td>#{{ historyItem.stationHash }}</td>
<td>
<router-link
:to="`/journal/dispatchers?search-dispatcher=${historyItem.dispatcherName}`"
>
<b
v-if="isDonator(historyItem.dispatcherName)"
class="text--donator"
:title="$t('donations.dispatcher-message')"
>
{{ historyItem.dispatcherName }}
</b>
<b v-else>
{{ historyItem.dispatcherName }}
</b>
</router-link>
</td>
<td>
<b
v-if="historyItem.dispatcherLevel !== null"
class="level-badge dispatcher"
:style="
calculateExpStyle(
historyItem.dispatcherLevel,
historyItem.dispatcherIsSupporter
)
"
>
{{ historyItem.dispatcherLevel >= 2 ? historyItem.dispatcherLevel : 'L' }}
</b>
</td>
<td class="text--primary">
<b>{{ historyItem.dispatcherRate }}</b>
</td>
<td>
<b class="region-badge" :aria-describedby="historyItem.region">{{
regions.find((r) => r.id == historyItem.region)?.value || '???'
}}</b>
</td>
<td style="min-width: 200px" class="time">
<span v-if="historyItem.timestampTo" class="text--offline">
<b>{{ $d(historyItem.timestampFrom) }}</b>
{{ timestampToString(historyItem.timestampFrom) }}
- {{ timestampToString(historyItem.timestampTo) }} ({{
calculateDuration(historyItem.currentDuration)
}})
</span>
<span class="dispatcher-online" v-else>
<b class="text--online">
<router-link :to="`/scenery?station=${historyItem.stationName}`">{{
$t('journal.online-since')
}}</router-link>
{{ timestampToString(historyItem.timestampFrom) }}
</b>
({{ calculateDuration(historyItem.currentDuration) }})
</span>
</td>
</tr>
</transition-group>
</tbody>
</table>
<AddDataButton
:list="dispatcherHistory"
:scrollDataLoaded="scrollDataLoaded"
:scrollNoMoreData="scrollNoMoreData"
@addHistoryData="addHistoryData"
/>
</div>
</div> </div>
</transition>
<div class="journal_warning" v-if="scrollNoMoreData"> <Loading v-else-if="dataStatus == Status.Data.Loading" />
{{ $t('journal.no-further-data') }}
</div>
<div class="journal_warning" v-else-if="!scrollDataLoaded"> <div v-else-if="dataStatus == Status.Data.Error" class="journal_warning error">
{{ $t('journal.loading-further-data') }} {{ $t('app.error') }}
</div>
<div class="journal_warning" v-else-if="dispatcherHistory.length == 0">
{{ $t('app.no-result') }}
</div>
<div v-else>
<table class="dispatchers-table">
<thead>
<th>{{ $t('journal.history-name') }}</th>
<th>{{ $t('journal.history-hash') }}</th>
<th>{{ $t('journal.history-dispatcher') }}</th>
<th>{{ $t('journal.history-level') }}</th>
<th>{{ $t('journal.history-rate') }}</th>
<th>{{ $t('journal.history-region') }}</th>
<th>{{ $t('journal.history-date') }}</th>
</thead>
<tbody>
<transition-group name="list-anim">
<tr v-for="historyItem in dispatcherHistory" :key="historyItem.id">
<td>
<router-link
:to="`/journal/dispatchers?search-station=${historyItem.stationName}`"
>
<b>{{ historyItem.stationName }}</b>
</router-link>
</td>
<td>#{{ historyItem.stationHash }}</td>
<td>
<router-link
:to="`/journal/dispatchers?search-dispatcher=${historyItem.dispatcherName}`"
>
<b
v-if="isDonator(historyItem.dispatcherName)"
class="text--donator"
:title="$t('donations.dispatcher-message')"
>
{{ historyItem.dispatcherName }}
</b>
<b v-else>
{{ historyItem.dispatcherName }}
</b>
</router-link>
</td>
<td>
<b
v-if="historyItem.dispatcherLevel !== null"
class="level-badge dispatcher"
:style="
calculateExpStyle(
historyItem.dispatcherLevel,
historyItem.dispatcherIsSupporter
)
"
>
{{ historyItem.dispatcherLevel >= 2 ? historyItem.dispatcherLevel : 'L' }}
</b>
</td>
<td class="text--primary">
<b>{{ historyItem.dispatcherRate }}</b>
</td>
<td>
<b class="region-badge" :aria-describedby="historyItem.region">{{
regions.find((r) => r.id == historyItem.region)?.value || '???'
}}</b>
</td>
<td style="min-width: 200px" class="time">
<span v-if="historyItem.timestampTo" class="text--offline">
<b>{{ $d(historyItem.timestampFrom) }}</b>
{{ timestampToString(historyItem.timestampFrom) }}
- {{ timestampToString(historyItem.timestampTo) }} ({{
calculateDuration(historyItem.currentDuration)
}})
</span>
<span class="dispatcher-online" v-else>
<b class="text--online">
<router-link :to="`/scenery?station=${historyItem.stationName}`">{{
$t('journal.online-since')
}}</router-link>
{{ timestampToString(historyItem.timestampFrom) }}
</b>
({{ calculateDuration(historyItem.currentDuration) }})
</span>
</td>
</tr>
</transition-group>
</tbody>
</table>
<AddDataButton
:list="dispatcherHistory"
:scrollDataLoaded="scrollDataLoaded"
:scrollNoMoreData="scrollNoMoreData"
@addHistoryData="addHistoryData"
/>
</div>
<div class="journal_warning" v-if="scrollNoMoreData">
{{ $t('journal.no-further-data') }}
</div>
<div class="journal_warning" v-else-if="!scrollDataLoaded">
{{ $t('journal.loading-further-data') }}
</div>
</div> </div>
</div> </transition>
</template> </template>
<script lang="ts"> <script lang="ts">
@@ -206,7 +204,7 @@ export default defineComponent({
@import '../../../styles/variables.scss'; @import '../../../styles/variables.scss';
@import '../../../styles/JournalSection.scss'; @import '../../../styles/JournalSection.scss';
table.scenery-history-table { table.dispatchers-table {
--_bg-table: #111; --_bg-table: #111;
--_bg-head: #101010; --_bg-head: #101010;
--_bg-row: #2f2f2f; --_bg-row: #2f2f2f;
+1 -1
View File
@@ -17,7 +17,7 @@ export namespace Journal {
}; };
export type TimetableSorterKey = 'timetableId' | 'beginDate' | 'distance' | 'total-stops'; export type TimetableSorterKey = 'timetableId' | 'beginDate' | 'distance' | 'total-stops';
export type DispatcherSorterKey = 'timestampFrom' | 'duration' | ''; export type DispatcherSorterKey = 'timestampFrom' | 'duration';
export interface DispatcherSorter { export interface DispatcherSorter {
id: DispatcherSorterKey; id: DispatcherSorterKey;
+7 -1
View File
@@ -369,7 +369,13 @@
"most-active-dr-many": "The most active dispatchers: {dispatchers} (created {count} each)", "most-active-dr-many": "The most active dispatchers: {dispatchers} (created {count} each)",
"most-active-driver": "The most active driver: {driver} (total driven distance: {distance})", "most-active-driver": "The most active driver: {driver} (total driven distance: {distance})",
"longest-duties": "The longest service: {dispatcher} at {station} (duration: {duration})", "longest-duties": "The longest service: {dispatcher} at {station} (duration: {duration})",
"count": "timetable | timetables" "count": "timetable | timetables",
"rippedSwitches": "RIPPED SWITCHES",
"derailments": "DERAILMENTS",
"skippedStopSignals": "SKIPPED STOP SIGNALS",
"radioStops": "RADIOSTOPS",
"kills": "KILLS"
}, },
"dispatcher-stats": { "dispatcher-stats": {
+7 -1
View File
@@ -351,7 +351,13 @@
"most-active-dr-many": "Najaktywniejsi dyżurni: {dispatchers} (stworzyli po {count})", "most-active-dr-many": "Najaktywniejsi dyżurni: {dispatchers} (stworzyli po {count})",
"most-active-driver": "Najaktywniejszy maszynista: {driver} (łączny przejechany dystans: {distance})", "most-active-driver": "Najaktywniejszy maszynista: {driver} (łączny przejechany dystans: {distance})",
"longest-duties": "Najdłuższa służba: {dispatcher} na scenerii {station} (czas trwania: {duration})", "longest-duties": "Najdłuższa służba: {dispatcher} na scenerii {station} (czas trwania: {duration})",
"count": "rozkład jazdy | rozkładów jazdy" "count": "rozkład jazdy | rozkładów jazdy",
"rippedSwitches": "ROZPRUTE ZWROTNICE",
"derailments": "WYKOLEJENIA",
"skippedStopSignals": "POMINIĘTE S1",
"radioStops": "RADIOSTOPY",
"kills": "POTRĄCENIA"
}, },
"dispatcher-stats": { "dispatcher-stats": {
+4
View File
@@ -22,6 +22,10 @@ hr.header-separator {
margin-bottom: 1em; margin-bottom: 1em;
} }
hr.section-separator {
margin: 1em 0;
}
.info-stats { .info-stats {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
+39 -13
View File
@@ -274,21 +274,47 @@ export namespace API {
distanceAvg: number; distanceAvg: number;
maxTimetable: API.TimetableHistory.Data | null; maxTimetable: API.TimetableHistory.Data | null;
mostActiveDispatchers: { globalDiff: GlobalDiff;
name: string; globalMax: GlobalMax;
count: number;
}[];
mostActiveDrivers: { mostActiveDispatchers: MostActiveDispatcher[];
name: string; mostActiveDrivers: MostActiveDriver[];
distance: number;
}[];
longestDuties: { longestDuties: LongestDuty[];
name: string; }
duration: number;
station: string; export interface MostActiveDispatcher {
}[]; name: string;
count: number;
}
export interface MostActiveDriver {
name: string;
distance: number;
}
export interface LongestDuty {
name: string;
duration: number;
station: string;
}
export interface GlobalDiff {
rippedSwitches: number;
derailments: number;
skippedStopSignals: number;
radioStops: number;
kills: number;
drivenKilometers: number;
routedTrains: number;
}
export interface GlobalMax {
_max: {
drivers: number;
dispatchers: number;
timetables: number;
};
} }
} }
+1 -1
View File
@@ -169,7 +169,7 @@ export default defineComponent({
{ {
tab: Journal.StatsTab.DRIVER_STATS, tab: Journal.StatsTab.DRIVER_STATS,
localeKey: 'journal.driver-stats.button', localeKey: 'journal.driver-stats.button',
iconName: 'user', iconName: 'train',
disabled: true disabled: true
} }
], ],