zmiana wyglądu statystyk dzienników

This commit is contained in:
2023-12-14 18:42:13 +01:00
parent 5a651aedf8
commit e0d3d2585d
15 changed files with 306 additions and 229 deletions
+115 -104
View File
@@ -1,128 +1,138 @@
<template> <template>
<section class="daily-stats"> <section class="daily-stats">
<span :data-active="statsStatus"> <span :data-active="statsStatus">
<b v-if="statsStatus == Status.Data.Loading"> <span class="stats-list">
{{ $t('app.loading') }}
</b>
<span class="stats-list" v-else>
<h3> <h3>
{{ $t('journal.daily-stats-title') }} {{ $t('journal.daily-stats-title') }}
<b class="text--primary">{{ new Date().toLocaleDateString($i18n.locale) }}</b> <b class="text--primary">{{ new Date().toLocaleDateString($i18n.locale) }}</b>
</h3> </h3>
<hr style="margin-bottom: 0.5em" /> <hr class="header-separator" />
<div v-if="stats.totalTimetables"> <b v-if="statsStatus == Status.Data.Loading">
&bull; {{ $t('app.loading') }}
<i18n-t keypath="journal.timetable-stats-total"> </b>
<template #count>
<b class="text--primary">
{{ stats.totalTimetables }}
{{ $t('journal.timetable-count', stats.totalTimetables) }}
</b>
</template>
<template #distance> <b class="text--error" v-else-if="statsStatus == Status.Data.Error">
<b class="text--primary"> {{ stats.distanceSum?.toFixed(2) }} km</b> {{ $t('journal.stats-error') }}
</template> </b>
</i18n-t>
</div>
<div v-if="stats.maxTimetable"> <b v-else-if="topDispatchers.length == 0">
&bull; {{ $t('journal.daily-stats-info') }}
<i18n-t keypath="journal.timetable-stats-longest"> </b>
<template #id>
<router-link :to="`/journal/timetables?timetableId=${stats.maxTimetable.id}`">
<b>{{ stats.maxTimetable.id }}</b>
</router-link>
</template>
<template #author>
<router-link
:to="`/journal/dispatchers?dispatcherName=${stats.maxTimetable.authorName}`"
>
<b>{{ stats.maxTimetable.authorName }}</b>
</router-link>
</template>
<template #driver>
<b class="text--primary">{{ stats.maxTimetable.driverName }}</b>
</template>
<template #distance>
<b class="text--primary">{{ stats.maxTimetable.routeDistance }} km</b>
</template>
</i18n-t>
</div>
<div v-if="topDispatchers.length == 1"> <div v-else>
&bull; <div v-if="stats.totalTimetables">
<i18n-t keypath="journal.timetable-stats-most-active-dr"> &bull;
<template #dispatcher> <i18n-t keypath="journal.timetable-stats-total">
<router-link :to="`/journal/dispatchers?dispatcherName=${topDispatchers[0].name}`"> <template #count>
<b>{{ topDispatchers[0].name }}</b> <b class="text--primary">
</router-link> {{ stats.totalTimetables }}
</template> {{ $t('journal.timetable-count', stats.totalTimetables) }}
<template #count> </b>
<b class="text--primary"> </template>
{{ topDispatchers[0].count }}
{{ $t('journal.timetable-count', topDispatchers[0].count) }}
</b>
</template>
</i18n-t>
</div>
<div v-if="topDispatchers.length > 1"> <template #distance>
&bull; <b class="text--primary"> {{ stats.distanceSum?.toFixed(2) }} km</b>
<i18n-t keypath="journal.timetable-stats-most-active-dr-many"> </template>
<template #dispatchers> </i18n-t>
<span v-for="(disp, i) in topDispatchers" :key="i"> </div>
<span v-if="i == topDispatchers.length - 1"> {{ $t('general.and') }} </span>
<router-link :to="`/journal/dispatchers?dispatcherName=${disp.name}`"> <div v-if="stats.maxTimetable">
<b>{{ disp.name }}</b> &bull;
<i18n-t keypath="journal.timetable-stats-longest">
<template #id>
<router-link :to="`/journal/timetables?timetableId=${stats.maxTimetable.id}`">
<b>{{ stats.maxTimetable.id }}</b>
</router-link> </router-link>
</template>
<template #author>
<router-link
:to="`/journal/dispatchers?dispatcherName=${stats.maxTimetable.authorName}`"
>
<b>{{ stats.maxTimetable.authorName }}</b>
</router-link>
</template>
<template #driver>
<b class="text--primary">{{ stats.maxTimetable.driverName }}</b>
</template>
<template #distance>
<b class="text--primary">{{ stats.maxTimetable.routeDistance }} km</b>
</template>
</i18n-t>
</div>
<span v-if="i < topDispatchers.length - 2">, </span> <div v-if="topDispatchers.length == 1">
</span> &bull;
</template> <i18n-t keypath="journal.timetable-stats-most-active-dr">
<template #dispatcher>
<router-link :to="`/journal/dispatchers?dispatcherName=${topDispatchers[0].name}`">
<b>{{ topDispatchers[0].name }}</b>
</router-link>
</template>
<template #count>
<b class="text--primary">
{{ topDispatchers[0].count }}
{{ $t('journal.timetable-count', topDispatchers[0].count) }}
</b>
</template>
</i18n-t>
</div>
<template #count> <div v-if="topDispatchers.length > 1">
<b class="text--primary"> &bull;
{{ topDispatchers[0].count }} <i18n-t keypath="journal.timetable-stats-most-active-dr-many">
{{ $t('journal.timetable-count', topDispatchers[0].count) }} <template #dispatchers>
</b> <span v-for="(disp, i) in topDispatchers" :key="i">
</template> <span v-if="i == topDispatchers.length - 1"> {{ $t('general.and') }} </span>
</i18n-t>
</div>
<div v-if="stats.longestDuties.length > 0"> <router-link :to="`/journal/dispatchers?dispatcherName=${disp.name}`">
&bull; <b>{{ disp.name }}</b>
<i18n-t keypath="journal.timetable-stats-longest-duties"> </router-link>
<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> <span v-if="i < topDispatchers.length - 2">, </span>
</span>
</template>
<template #duration> <template #count>
{{ calculateDuration(stats.longestDuties[0].duration) }} <b class="text--primary">
</template> {{ topDispatchers[0].count }}
</i18n-t> {{ $t('journal.timetable-count', topDispatchers[0].count) }}
</div> </b>
</template>
</i18n-t>
</div>
<div v-if="stats.mostActiveDrivers.length > 0"> <div v-if="stats.longestDuties.length > 0">
&bull; &bull;
<i18n-t keypath="journal.timetable-stats-most-active-driver"> <i18n-t keypath="journal.timetable-stats-longest-duties">
<template #driver> <template #dispatcher>
<b class="text--primary">{{ stats.mostActiveDrivers[0].name }}</b> <router-link
</template> :to="`/journal/dispatchers?dispatcherName=${stats.longestDuties[0].name}`"
<template #distance> >
<b class="text--primary">{{ stats.mostActiveDrivers[0].distance.toFixed(2) }} km</b> <b>{{ stats.longestDuties[0].name }}</b>
</template> </router-link>
</i18n-t> </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">
&bull;
<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.toFixed(2) }} km</b>
</template>
</i18n-t>
</div>
</div> </div>
</span> </span>
</span> </span>
@@ -203,6 +213,7 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
@import '../../styles/responsive.scss'; @import '../../styles/responsive.scss';
@import '../../styles/JournalStats.scss';
.daily-stats { .daily-stats {
text-align: left; text-align: left;
@@ -57,6 +57,7 @@ import { API } from '../../typings/api';
import http from '../../http'; import http from '../../http';
export default defineComponent({ export default defineComponent({
name: 'journal-dispatcher-stats',
components: { Loading }, components: { Loading },
setup() { setup() {
@@ -1,11 +1,13 @@
<template> <template>
<div class="journal-stats"> <div class="journal-stats" v-if="store.driverStatsData">
<span v-if="store.driverStatsData"> <span>
<h3> <h3>
{{ $t('journal.stats-title') }} {{ $t('journal.stats-title') }}
<span class="text--primary">{{ store.driverStatsName.toUpperCase() }}</span> <span class="text--primary">{{ store.driverStatsName.toUpperCase() }}</span>
</h3> </h3>
<hr class="header-separator" />
<div class="info-stats"> <div class="info-stats">
<span class="stat-badge"> <span class="stat-badge">
<span>{{ $t('journal.stats-timetables') }}</span> <span>{{ $t('journal.stats-timetables') }}</span>
@@ -43,13 +45,13 @@
</div> </div>
</span> </span>
<b v-else-if="store.driverStatsStatus == Status.Data.Loading">{{ <!-- <b v-else-if="store.driverStatsStatus == Status.Data.Loading">{{
$t('journal.stats-loading') $t('journal.stats-loading')
}}</b> }}</b>
<b v-else-if="store.driverStatsStatus == Status.Data.Error"> <b v-else-if="store.driverStatsStatus == Status.Data.Error">
{{ $t('journal.stats-error ') }} {{ $t('journal.stats-error ') }}
</b> </b>
<b v-else>{{ $t('journal.driver-stats-info') }}</b> <b v-else>{{ $t('journal.driver-stats-info') }}</b> -->
</div> </div>
</template> </template>
+67 -73
View File
@@ -1,12 +1,24 @@
<template> <template>
<div class="journal-stats" v-if="!store.isOffline"> <div
<div class="stats-buttons"> class="journal-stats dropdown"
v-if="!mainStore.isOffline"
@keydown.esc="currentStatsTab = null"
>
<div
class="dropdown_background"
v-if="currentStatsTab !== null"
@click="currentStatsTab = null"
></div>
<div class="actions-bar">
<button <button
v-for="button in data.statsButtons" v-for="button in statsButtons"
:key="button.name" :key="button.tab"
class="btn--filled btn--image" class="btn--filled btn--image"
:data-selected="button.name == currentStatsTab" :data-selected="button.tab == currentStatsTab"
@click="onTabButtonClick(button.name)" :data-disabled="button.disabled"
:disabled="button.disabled"
@click="onTabButtonClick(button.tab)"
> >
<img <img
v-if="button.iconName" v-if="button.iconName"
@@ -17,87 +29,69 @@
</button> </button>
</div> </div>
<div class="stats-tab" v-show="currentStatsTab !== null"> <transition name="dropdown-anim">
<keep-alive> <div class="dropdown_wrapper" v-if="currentStatsTab !== null">
<JournalDailyStats v-if="currentStatsTab == 'journal-daily-stats'" /> <keep-alive>
<JournalDriverStats v-else-if="currentStatsTab == 'journal-driver-stats'" /> <component :is="currentStatsTab" :key="currentStatsTab"></component>
</keep-alive> </keep-alive>
</div> </div>
</transition>
</div> </div>
</template> </template>
<script setup lang="ts"> <script lang="ts">
import { computed, onMounted, reactive, Ref, ref, watch } from 'vue'; import { defineComponent, PropType } from 'vue';
import { useMainStore } from '../../store/mainStore'; import { useMainStore } from '../../store/mainStore';
import JournalDailyStats from './JournalDailyStats.vue';
import JournalDriverStats from './JournalDriverStats.vue';
import StorageManager from '../../managers/storageManager'; import StorageManager from '../../managers/storageManager';
import { Journal } from './typings';
import JournalDailyStats from './JournalDailyStats.vue';
import JournalDispatcherStats from './JournalDispatcherStats.vue';
import JournalDriverStats from './JournalDriverStats.vue';
export type JournalStatsTab = 'journal-driver-stats' | 'journal-daily-stats'; export default defineComponent({
components: { JournalDailyStats, JournalDriverStats, JournalDispatcherStats },
const store = useMainStore(); props: {
const currentStatsTab: Ref<JournalStatsTab | null> = ref(null); statsButtons: {
type: Array as PropType<Journal.StatsButton[]>,
let data = reactive({ required: true
statsButtons: [
{
name: 'journal-daily-stats',
localeKey: 'journal.daily-stats-title',
iconName: 'stats'
},
{
name: 'journal-driver-stats',
localeKey: 'journal.driver-stats-title',
iconName: 'user'
} }
] as { name: JournalStatsTab; localeKey: string; iconName?: string }[] },
}); data() {
return {
Journal,
mainStore: useMainStore(),
currentStatsTab: null as Journal.StatsTab | null
};
},
mounted() {
// const storedTab = StorageManager.getStringValue('journalStatsTab');
// if (storedTab && storedTab !== '' && this.statsButtons.some((b) => b.tab == storedTab))
// this.currentStatsTab = storedTab as Journal.StatsTab;
},
// watch: {
// 'mainStore.driverStatsData'(newData, prevData) {
// this.currentStatsTab =
// JSON.stringify(prevData) !== JSON.stringify(newData) && newData !== undefined
// ? Journal.StatsTab.DRIVER_STATS
// : this.currentStatsTab;
// }
// },
methods: {
onTabButtonClick(tab: Journal.StatsTab) {
this.currentStatsTab = tab == this.currentStatsTab ? null : tab;
function onTabButtonClick(tab: JournalStatsTab) { StorageManager.setStringValue('journalStatsTab', this.currentStatsTab ?? '');
currentStatsTab.value = tab == currentStatsTab.value ? null : tab; }
StorageManager.setStringValue('journalStatsTab', currentStatsTab.value ?? '');
}
watch(
computed(() => store.driverStatsData),
(newData, prevData) => {
currentStatsTab.value =
JSON.stringify(prevData) !== JSON.stringify(newData) && newData !== undefined
? 'journal-driver-stats'
: currentStatsTab.value;
} }
);
onMounted(() => {
const storedTab = StorageManager.getStringValue('journalStatsTab');
if (storedTab && storedTab !== '') currentStatsTab.value = storedTab as JournalStatsTab;
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '../../styles/JournalStats.scss'; @import '../../styles/dropdown.scss';
@import '../../styles/dropdown_filters.scss';
@import '../../styles/variables.scss'; @import '../../styles/variables.scss';
.stats-buttons { .dropdown_wrapper {
position: relative; max-width: 100%;
display: flex;
gap: 0.5em;
margin-bottom: 0.5em;
button {
font-weight: bold;
padding: 0.5em 0.75em;
&[data-inactive='true'] {
color: gray;
}
&[data-selected='true'] {
color: $accentCol;
}
}
} }
</style> </style>
+13
View File
@@ -46,4 +46,17 @@ export namespace Journal {
id: TimetableSorterKey; id: TimetableSorterKey;
dir: 'asc' | 'desc'; dir: 'asc' | 'desc';
} }
export enum StatsTab {
DRIVER_STATS = 'journal-driver-stats',
DISPATCHER_STATS = 'journal-dispatcher-stats',
DAILY_STATS = 'journal-daily-stats'
}
export interface StatsButton {
tab: StatsTab;
localeKey: string;
iconName: string;
disabled: boolean;
}
} }
+3
View File
@@ -371,6 +371,9 @@
"driver-stats-title": "DRIVER STATS", "driver-stats-title": "DRIVER STATS",
"driver-stats-info": "Enter a proper nickname into filters [F] to see user's driving statistics!", "driver-stats-info": "Enter a proper nickname into filters [F] to see user's driving statistics!",
"dispatcher-stats-title": "DISPATCHER STATS",
"dispatcher-stats-info": "Enter a proper nickname into filters [F] to see user's dispatcher statistics!",
"stats-loading": "Fetching statistics...", "stats-loading": "Fetching statistics...",
"stats-error": "Oops! An unexpected error occurred while trying to fetch statistics! :/", "stats-error": "Oops! An unexpected error occurred while trying to fetch statistics! :/",
+4 -1
View File
@@ -349,9 +349,12 @@
"daily-stats-title": "STATYSTYKI DNIA", "daily-stats-title": "STATYSTYKI DNIA",
"daily-stats-info": "Dzisiejsze statystyki nie są jeszcze dostępne!", "daily-stats-info": "Dzisiejsze statystyki nie są jeszcze dostępne!",
"driver-stats-title": "STATYSTYKI GRACZA", "driver-stats-title": "STAT. MASZYNISTY",
"driver-stats-info": "Wpisz nazwę użytkownika w filtrach [F], aby zobaczyć jego statystyki maszynisty!", "driver-stats-info": "Wpisz nazwę użytkownika w filtrach [F], aby zobaczyć jego statystyki maszynisty!",
"dispatcher-stats-title": "STATYSTYKI DYŻURNEGO",
"dispatcher-stats-info": "Wpisz nazwę użytkownika w filtrach [F], aby zobaczyć jego statystyki dyżurnego!",
"stats-loading": "Pobieranie statystyk...", "stats-loading": "Pobieranie statystyk...",
"stats-error": "Ups! Wystąpił błąd podczas próby pobrania statystyk!", "stats-error": "Ups! Wystąpił błąd podczas próby pobrania statystyk!",
+1
View File
@@ -19,6 +19,7 @@ export const useMainStore = defineStore('store', {
dispatcherStatsName: '', dispatcherStatsName: '',
dispatcherStatsData: undefined, dispatcherStatsData: undefined,
dispatcherStatsStatus: Status.Data.Initialized,
driverStatsName: '', driverStatsName: '',
driverStatsData: undefined, driverStatsData: undefined,
-2
View File
@@ -53,9 +53,7 @@
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
gap: 0.5em; gap: 0.5em;
position: relative; position: relative;
margin-bottom: 0.5em;
} }
.btn--load-data { .btn--load-data {
+11 -5
View File
@@ -2,24 +2,30 @@
@import 'responsive.scss'; @import 'responsive.scss';
.stats-tab { .stats-tab {
position: absolute;
right: 0;
z-index: 99;
transform: translateY(1em);
width: 100%;
background-color: #1a1a1a; background-color: #1a1a1a;
box-shadow: 0 0 5px 1px $accentCol; box-shadow: 0 0 5px 1px $accentCol;
padding: 1em; padding: 1em;
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
}
margin-bottom: 0.5em; hr.header-separator {
margin-bottom: 1em;
width: 100%;
} }
.info-stats { .info-stats {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 0.5em; gap: 0.5em;
margin-top: 1em;
} }
.stat-badge { .stat-badge {
+2 -1
View File
@@ -30,7 +30,8 @@
top: calc(100% + 0.5em); top: calc(100% + 0.5em);
background-color: $bgCol; background-color: $bgCol;
box-shadow: 0 5px 10px 2px #0f0f0f; // box-shadow: 0 5px 10px 2px #0f0f0f;
box-shadow: 0 0 5px 1px $accentCol;
width: 100%; width: 100%;
max-width: 550px; max-width: 550px;
-5
View File
@@ -5,11 +5,6 @@
.actions-bar { .actions-bar {
display: flex; display: flex;
gap: 0.5em; gap: 0.5em;
margin-bottom: 0.5em;
}
.filters-options {
position: relative;
} }
h1.option-title { h1.option-title {
+6 -2
View File
@@ -11,7 +11,7 @@
--clr-skr: #ff5100; --clr-skr: #ff5100;
--clr-twr: #ffbb00; --clr-twr: #ffbb00;
--clr-error: #df3e3e; --clr-error: #fa3636;
--clr-warning: #c59429; --clr-warning: #c59429;
--clr-donator: #f7a4ff; --clr-donator: #f7a4ff;
@@ -158,6 +158,10 @@ ul {
color: #ccc; color: #ccc;
} }
&--error {
color: var(--clr-error);
}
&--donator { &--donator {
color: var(--clr-donator); color: var(--clr-donator);
text-shadow: var(--clr-donator) 0 0 10px; text-shadow: var(--clr-donator) 0 0 10px;
@@ -183,7 +187,7 @@ a.a-button {
&[data-disabled='true'] { &[data-disabled='true'] {
user-select: none; user-select: none;
pointer-events: none; pointer-events: none;
opacity: 0.85; opacity: 0.7;
} }
&.btn--filled { &.btn--filled {
+40 -17
View File
@@ -3,15 +3,19 @@
<JournalHeader /> <JournalHeader />
<div class="journal_wrapper"> <div class="journal_wrapper">
<JournalOptions <div class="journal_top-bar">
@on-search-confirm="fetchHistoryData" <JournalOptions
@on-options-reset="resetOptions" @on-search-confirm="fetchHistoryData"
@on-refresh-data="fetchHistoryData(true)" @on-options-reset="resetOptions"
:sorter-option-ids="['timestampFrom', 'duration']" @on-refresh-data="fetchHistoryData(true)"
:data-status="dataStatus" :sorter-option-ids="['timestampFrom', 'duration']"
:current-options-active="currentOptionsActive" :data-status="dataStatus"
optionsType="dispatchers" :current-options-active="currentOptionsActive"
/> optionsType="dispatchers"
/>
<JournalStats :statsButtons="statsButtons" />
</div>
<div class="journal_refreshed-date" v-if="dataRefreshedAt"> <div class="journal_refreshed-date" v-if="dataRefreshedAt">
{{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }} {{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }}
@@ -33,22 +37,33 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, provide, reactive, Ref, ref } from 'vue'; import { defineComponent, provide, reactive, Ref, ref } from 'vue';
import JournalOptions from '../components/JournalView/JournalOptions.vue'; import http from '../http';
import { useMainStore } from '../store/mainStore'; import { useMainStore } from '../store/mainStore';
import JournalDispatchersList from '../components/JournalView/JournalDispatchersList.vue';
import JournalHeader from '../components/JournalView/JournalHeader.vue';
import { LocationQuery } from 'vue-router'; import { LocationQuery } from 'vue-router';
import { Journal } from '../components/JournalView/typings'; import { Journal } from '../components/JournalView/typings';
import { API } from '../typings/api'; import { API } from '../typings/api';
import { Status } from '../typings/common'; import { Status } from '../typings/common';
import http from '../http';
import JournalOptions from '../components/JournalView/JournalOptions.vue';
import JournalDispatchersList from '../components/JournalView/JournalDispatchersList.vue';
import JournalHeader from '../components/JournalView/JournalHeader.vue';
import JournalStats from '../components/JournalView/JournalStats.vue';
const statsButtons: Journal.StatsButton[] = [
{
tab: Journal.StatsTab.DISPATCHER_STATS,
localeKey: 'journal.dispatcher-stats-title',
iconName: 'user',
disabled: false
}
];
export default defineComponent({ export default defineComponent({
components: { components: {
JournalOptions, JournalOptions,
JournalDispatchersList, JournalDispatchersList,
JournalHeader JournalHeader,
JournalStats
}, },
name: 'JournalDispatchers', name: 'JournalDispatchers',
@@ -65,6 +80,8 @@ export default defineComponent({
}, },
data: () => ({ data: () => ({
statsButtons,
currentQuery: '', currentQuery: '',
currentQueryArray: [] as string[], currentQueryArray: [] as string[],
dataRefreshedAt: null as Date | null, dataRefreshedAt: null as Date | null,
@@ -102,7 +119,7 @@ export default defineComponent({
const scrollElement: Ref<HTMLElement | null> = ref(null); const scrollElement: Ref<HTMLElement | null> = ref(null);
return { return {
store: useMainStore(), mainStore: useMainStore(),
sorterActive, sorterActive,
searchersValues, searchersValues,
@@ -120,6 +137,12 @@ export default defineComponent({
this.currentOptionsActive = this.currentOptionsActive =
q.length > 2 || q.length > 2 ||
q.some((qv) => qv.startsWith('sortBy=') && qv.split('=')[1] != 'timestampFrom'); q.some((qv) => qv.startsWith('sortBy=') && qv.split('=')[1] != 'timestampFrom');
},
'mainStore.dispatcherStatsData'(stats) {
// console.log(stats);
// this.statsButtons.find((sb) => sb.tab == Journal.StatsTab.DRIVER_STATS)!.disabled =
// driverStats === undefined;
} }
}, },
@@ -241,7 +264,7 @@ export default defineComponent({
this.historyList = responseData; this.historyList = responseData;
// Stats display // Stats display
this.store.dispatcherStatsName = this.mainStore.dispatcherStatsName =
this.historyList.length > 0 && this.searchersValues['search-dispatcher'].trim() this.historyList.length > 0 && this.searchersValues['search-dispatcher'].trim()
? this.historyList[0].dispatcherName ? this.historyList[0].dispatcherName
: ''; : '';
+37 -15
View File
@@ -3,18 +3,20 @@
<JournalHeader /> <JournalHeader />
<div class="journal_wrapper"> <div class="journal_wrapper">
<JournalOptions <div class="journal_top-bar">
@on-search-confirm="fetchHistoryData" <JournalOptions
@on-options-reset="resetOptions" @on-search-confirm="fetchHistoryData"
@on-refresh-data="fetchHistoryData" @on-options-reset="resetOptions"
:sorter-option-ids="['timetableId', 'beginDate', 'routeDistance', 'allStopsCount']" @on-refresh-data="fetchHistoryData"
:filters="journalTimetableFilters" :sorter-option-ids="['timetableId', 'beginDate', 'routeDistance', 'allStopsCount']"
:currentOptionsActive="currentOptionsActive" :filters="journalTimetableFilters"
:data-status="dataStatus" :currentOptionsActive="currentOptionsActive"
optionsType="timetables" :data-status="dataStatus"
/> optionsType="timetables"
/>
<JournalStats /> <JournalStats :statsButtons="statsButtons" />
</div>
<div class="journal_refreshed-date" v-if="dataRefreshedAt"> <div class="journal_refreshed-date" v-if="dataRefreshedAt">
{{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }} {{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }}
@@ -138,6 +140,24 @@ export default defineComponent({
}, },
data: () => ({ data: () => ({
journalTimetableFilters,
mainStore: useMainStore(),
statsButtons: [
{
tab: Journal.StatsTab.DAILY_STATS,
localeKey: 'journal.daily-stats-title',
iconName: 'stats',
disabled: false
},
{
tab: Journal.StatsTab.DRIVER_STATS,
localeKey: 'journal.driver-stats-title',
iconName: 'user',
disabled: true
}
],
currentQueryParams: {} as TimetablesQueryParams, currentQueryParams: {} as TimetablesQueryParams,
dataRefreshedAt: null as Date | null, dataRefreshedAt: null as Date | null,
@@ -149,7 +169,6 @@ export default defineComponent({
currentOptionsActive: false, currentOptionsActive: false,
timetableHistory: [] as API.TimetableHistory.Response, timetableHistory: [] as API.TimetableHistory.Response,
journalTimetableFilters,
dataStatus: Status.Data.Loading, dataStatus: Status.Data.Loading,
dataErrorMessage: '' dataErrorMessage: ''
@@ -189,15 +208,18 @@ export default defineComponent({
countFromIndex, countFromIndex,
countLimit, countLimit,
scrollElement, scrollElement
store: useMainStore()
}; };
}, },
watch: { watch: {
currentQueryParams(q: TimetablesQueryParams) { currentQueryParams(q: TimetablesQueryParams) {
this.currentOptionsActive = Object.values(q).some((v) => v !== undefined); this.currentOptionsActive = Object.values(q).some((v) => v !== undefined);
},
'mainStore.driverStatsData'(driverStats) {
this.statsButtons.find((sb) => sb.tab == Journal.StatsTab.DRIVER_STATS)!.disabled =
driverStats === undefined;
} }
}, },