mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 05:18:11 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 91f4c6bc57 | |||
| c133eb060b | |||
| 7ffc169d8a | |||
| 1b85cc5f58 | |||
| 72ff857fff | |||
| 96d64e77fc | |||
| 6ceae3f161 |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.16.1",
|
"version": "1.16.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ let data = reactive({
|
|||||||
{
|
{
|
||||||
name: 'driver',
|
name: 'driver',
|
||||||
titlePath: 'journal.driver-stats-title',
|
titlePath: 'journal.driver-stats-title',
|
||||||
inactive: true,
|
// inactive: true,
|
||||||
},
|
},
|
||||||
] as { name: TStatTab; titlePath: string; inactive?: boolean }[],
|
] as { name: TStatTab; titlePath: string; inactive?: boolean }[],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition-group class="journal-list" tag="ul" name="list-anim">
|
<transition-group class="journal-list" tag="ul" name="list-anim">
|
||||||
<li
|
<li
|
||||||
v-for="{ timetable, sceneryList, stockHistoryComp, ...item } in computedTimetableHistory"
|
v-for="{ timetable, stockHistoryComp, stops, showExtraInfo, ...item } in computedTimetableHistory"
|
||||||
class="journal_item"
|
class="journal_item"
|
||||||
:key="timetable.id"
|
:key="timetable.id"
|
||||||
@click="item.showExtra.value = !item.showExtra.value"
|
@click="showExtraInfo.value = !showExtraInfo.value"
|
||||||
>
|
>
|
||||||
<div class="journal_item-info">
|
<div class="journal_item-info">
|
||||||
<div class="info-general">
|
<div class="info-general">
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
<span class="general-time">
|
<span class="general-time">
|
||||||
<b class="info-date">{{ localeDay(timetable.beginDate, $i18n.locale) }}</b>
|
<b class="info-date">{{ localeDay(timetable.beginDate, $i18n.locale) }}</b>
|
||||||
<b
|
<b
|
||||||
class="info-status"
|
class="info-badge"
|
||||||
:class="{
|
:class="{
|
||||||
fulfilled: timetable.fulfilled,
|
fulfilled: timetable.fulfilled,
|
||||||
terminated: timetable.terminated && !timetable.fulfilled,
|
terminated: timetable.terminated && !timetable.fulfilled,
|
||||||
@@ -67,45 +67,28 @@
|
|||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<div class="scenery-list">
|
<!-- Spis postojów -->
|
||||||
|
<div class="stop-list">
|
||||||
<span
|
<span
|
||||||
v-for="(scenery, i) in sceneryList.filter((_, i) =>
|
v-for="(stop, i) in stops.filter((_, i) => (!showExtraInfo.value ? i == 0 || i == stops.length - 1 : true))"
|
||||||
!item.showExtra.value ? i == 0 || i == sceneryList.length - 1 : true
|
class="stop-list-item"
|
||||||
)"
|
:key="stop.stopName"
|
||||||
:key="scenery.name"
|
:data-confirmed="stop.confirmed"
|
||||||
:class="{ confirmed: scenery.confirmed }"
|
|
||||||
>
|
>
|
||||||
<span v-if="i > 0">
|
<span v-if="i > 0">
|
||||||
>
|
>
|
||||||
<span v-if="!item.showExtra.value && i == 1 && sceneryList.length > 2">
|
<span v-if="!showExtraInfo.value && i == 1 && stops.length > 2">
|
||||||
... (+{{ sceneryList.length - 2 }}) >
|
... (+{{ stops.length - 2 }}) >
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{{ scenery.name }}
|
|
||||||
|
|
||||||
<!-- Data odjazdu ze stacji początkowej -->
|
<span class="stop-name">{{ stop.stopName }}</span>
|
||||||
<span v-if="i == 0" v-html="scenery.beginDateHTML"></span>
|
<span v-html="stop.html"></span>
|
||||||
|
|
||||||
<!-- Data przyjazdu do stacji końcowej -->
|
|
||||||
<span
|
|
||||||
v-else-if="i == sceneryList.length - 1 || (i == 1 && !item.showExtra.value)"
|
|
||||||
v-html="scenery.endDateHTML"
|
|
||||||
></span>
|
|
||||||
|
|
||||||
<!-- Data przyjazdu i odjazdu ze stacji pośredniej -->
|
|
||||||
<span v-if="item.showExtra.value && i > 0 && i < sceneryList.length - 1">
|
|
||||||
<span v-if="timetable.checkpointArrivals && i < timetable.checkpointArrivals.length">
|
|
||||||
(p. {{ localeTime(timetable.checkpointArrivals[i], $i18n.locale)
|
|
||||||
}}<span v-if="timetable.checkpointDepartures && i < timetable.checkpointDepartures.length">
|
|
||||||
/ o. {{ localeTime(timetable.checkpointDepartures[i], $i18n.locale) }}</span
|
|
||||||
>)
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Status RJ -->
|
<!-- Status RJ -->
|
||||||
<div style="margin: 0.5em 0">
|
<div class="info-status" style="margin: 0.5em 0">
|
||||||
<span>
|
<span>
|
||||||
<b>{{ $t('journal.route-length') }}</b>
|
<b>{{ $t('journal.route-length') }}</b>
|
||||||
{{ !timetable.fulfilled ? timetable.currentDistance + ' /' : '' }}
|
{{ !timetable.fulfilled ? timetable.currentDistance + ' /' : '' }}
|
||||||
@@ -122,12 +105,24 @@
|
|||||||
<b>
|
<b>
|
||||||
{{ $t(`journal.${timetable.terminated ? 'last-seen-at' : 'currently-at'}`) }}
|
{{ $t(`journal.${timetable.terminated ? 'last-seen-at' : 'currently-at'}`) }}
|
||||||
{{ timetable.currentSceneryName.replace(/.[a-zA-Z0-9]+.sc/, '') }}
|
{{ timetable.currentSceneryName.replace(/.[a-zA-Z0-9]+.sc/, '') }}
|
||||||
|
|
||||||
|
<span v-if="timetable.currentLocation[0] || timetable.currentLocation[1]">(</span>
|
||||||
|
|
||||||
|
<span v-if="timetable.currentLocation[1]">
|
||||||
|
{{ $t('journal.timetable-location-route') }} {{ timetable.currentLocation[1] }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-else-if="timetable.currentLocation[0]">
|
||||||
|
{{ $t('journal.timetable-location-signal') }} {{ timetable.currentLocation[0] }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-if="timetable.currentLocation[0] || timetable.currentLocation[1]">)</span>
|
||||||
</b>
|
</b>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Nick dyżurnego -->
|
<!-- Info o autorze RJ -->
|
||||||
<div v-if="timetable.authorName">
|
<div class="info-author" v-if="timetable.authorName">
|
||||||
<b class="text--grayed">{{ $t('journal.dispatcher-name') }} </b>
|
<b class="text--grayed">{{ $t('journal.dispatcher-name') }} </b>
|
||||||
<router-link class="dispatcher-link" :to="`/journal/dispatchers?dispatcherName=${timetable.authorName}`">
|
<router-link class="dispatcher-link" :to="`/journal/dispatchers?dispatcherName=${timetable.authorName}`">
|
||||||
<b>{{ timetable.authorName }}</b>
|
<b>{{ timetable.authorName }}</b>
|
||||||
@@ -144,11 +139,11 @@
|
|||||||
|
|
||||||
<button class="btn--option btn--show">
|
<button class="btn--option btn--show">
|
||||||
{{ $t('journal.stock-info') }}
|
{{ $t('journal.stock-info') }}
|
||||||
<img :src="getIcon(`arrow-${item.showExtra.value ? 'asc' : 'desc'}`)" alt="Arrow" />
|
<img :src="getIcon(`arrow-${showExtraInfo.value ? 'asc' : 'desc'}`)" alt="Arrow" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Dodatkowe informacje -->
|
<!-- Dodatkowe informacje -->
|
||||||
<div class="info-extended" v-if="timetable.stockString && timetable.stockMass && item.showExtra.value">
|
<div class="info-extended" v-if="timetable.stockString && timetable.stockMass && showExtraInfo.value">
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<div class="stock-specs">
|
<div class="stock-specs">
|
||||||
@@ -180,6 +175,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Historia zmian w składzie -->
|
||||||
<div class="stock-history" v-if="stockHistoryComp.length > 1">
|
<div class="stock-history" v-if="stockHistoryComp.length > 1">
|
||||||
<button
|
<button
|
||||||
class="btn--action"
|
class="btn--action"
|
||||||
@@ -235,7 +231,6 @@ export default defineComponent({
|
|||||||
computedTimetableHistory() {
|
computedTimetableHistory() {
|
||||||
return this.timetableHistory.map((timetable) => ({
|
return this.timetableHistory.map((timetable) => ({
|
||||||
timetable,
|
timetable,
|
||||||
sceneryList: this.getSceneryList(timetable),
|
|
||||||
stockHistoryComp: timetable.stockHistory
|
stockHistoryComp: timetable.stockHistory
|
||||||
.slice()
|
.slice()
|
||||||
.reverse()
|
.reverse()
|
||||||
@@ -252,38 +247,64 @@ export default defineComponent({
|
|||||||
stockLength: Number(historyData[3]) || undefined,
|
stockLength: Number(historyData[3]) || undefined,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
showExtra: ref(false),
|
|
||||||
|
showExtraInfo: ref(false),
|
||||||
|
stops: this.getTimetableStops(timetable),
|
||||||
currentHistoryIndex: ref(0),
|
currentHistoryIndex: ref(0),
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
getSceneryList(timetable: TimetableHistory) {
|
getTimetableStops(timetable: TimetableHistory) {
|
||||||
return timetable.sceneriesString.split('%').map((name, i) => {
|
const stopNames = timetable.sceneriesString.split('%');
|
||||||
const beginDateHTML =
|
|
||||||
' (o. ' +
|
|
||||||
(timetable.beginDate != timetable.scheduledBeginDate
|
|
||||||
? `<s class='text--grayed'>${this.localeTime(timetable.beginDate, this.$i18n.locale)}</s> `
|
|
||||||
: '') +
|
|
||||||
`<span>${this.localeTime(timetable.scheduledBeginDate, this.$i18n.locale)}</span>)`;
|
|
||||||
|
|
||||||
const endDateHTML =
|
const beginDateHTML = ` (o. ${
|
||||||
' (p. ' +
|
timetable.beginDate != timetable.scheduledBeginDate
|
||||||
(timetable.endDate != timetable.scheduledEndDate && timetable.fulfilled
|
? `<s class="text--grayed">${this.localeTime(timetable.beginDate, this.$i18n.locale)}</s>`
|
||||||
? `<s class='text--grayed'>${this.localeTime(
|
: ''
|
||||||
timetable.fulfilled ? timetable.endDate : timetable.scheduledEndDate,
|
} <span>${this.localeTime(timetable.scheduledBeginDate, this.$i18n.locale)}</span>)`;
|
||||||
this.$i18n.locale
|
|
||||||
)}</s> `
|
|
||||||
: '') +
|
|
||||||
`<span>${this.localeTime(
|
|
||||||
timetable.fulfilled || (timetable.terminated && !timetable.fulfilled)
|
|
||||||
? timetable.scheduledEndDate
|
|
||||||
: timetable.endDate,
|
|
||||||
this.$i18n.locale
|
|
||||||
)}</span>)`;
|
|
||||||
|
|
||||||
return { name, confirmed: i < timetable.confirmedStopsCount, beginDateHTML, endDateHTML };
|
const endDateHTML = ` (p. ${
|
||||||
|
timetable.endDate != timetable.scheduledEndDate && timetable.fulfilled
|
||||||
|
? `<s class="text--grayed">${this.localeTime(timetable.endDate, this.$i18n.locale)}</s>`
|
||||||
|
: ''
|
||||||
|
} <span>${this.localeTime(timetable.scheduledEndDate, this.$i18n.locale)}</span>)`;
|
||||||
|
|
||||||
|
return stopNames.map((stopName, i) => {
|
||||||
|
const confirmed = i < timetable.confirmedStopsCount;
|
||||||
|
if (i == 0) return { stopName, html: beginDateHTML, confirmed };
|
||||||
|
if (i == stopNames.length - 1) return { stopName, html: endDateHTML, confirmed };
|
||||||
|
|
||||||
|
const departureDateScheduled = this.stringToDate(timetable.checkpointDeparturesScheduled?.at(i));
|
||||||
|
const departureDateReal = this.stringToDate(timetable.checkpointDepartures?.at(i));
|
||||||
|
const arrivalDateScheduled = this.stringToDate(timetable.checkpointArrivalsScheduled?.at(i));
|
||||||
|
const arrivalDateReal = this.stringToDate(timetable.checkpointArrivals?.at(i));
|
||||||
|
|
||||||
|
// const arrivalDelay =
|
||||||
|
// arrivalDateReal && arrivalDateScheduled ? arrivalDateReal.getTime() - arrivalDateScheduled.getTime() : 0;
|
||||||
|
|
||||||
|
// const departureDelay =
|
||||||
|
// departureDateReal && departureDateScheduled
|
||||||
|
// ? departureDateReal.getTime() - departureDateScheduled.getTime()
|
||||||
|
// : 0;
|
||||||
|
|
||||||
|
const arrivalHTML =
|
||||||
|
(arrivalDateReal && arrivalDateScheduled && arrivalDateReal?.getTime() != arrivalDateScheduled?.getTime()
|
||||||
|
? `<s class="text--grayed">${this.parseDateToTimeString(arrivalDateScheduled)}</s> `
|
||||||
|
: '') + this.parseDateToTimeString(arrivalDateReal || arrivalDateScheduled);
|
||||||
|
|
||||||
|
const departureHTML =
|
||||||
|
(departureDateReal &&
|
||||||
|
departureDateScheduled &&
|
||||||
|
departureDateReal?.getTime() != departureDateScheduled?.getTime()
|
||||||
|
? `<s class="text--grayed">${this.parseDateToTimeString(departureDateScheduled)}</s> `
|
||||||
|
: '') + this.parseDateToTimeString(departureDateReal || departureDateScheduled);
|
||||||
|
|
||||||
|
let html = `${arrivalHTML}${departureHTML ? ` / ${departureHTML}` : ''}`;
|
||||||
|
if (html) html = ` (${html})`;
|
||||||
|
|
||||||
|
return { stopName, html, confirmed };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -322,7 +343,7 @@ hr {
|
|||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-status {
|
&-badge {
|
||||||
padding: 0.05em 0.35em;
|
padding: 0.05em 0.35em;
|
||||||
color: black;
|
color: black;
|
||||||
|
|
||||||
@@ -418,10 +439,19 @@ ul.stock-list {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.scenery-list {
|
.stop-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.25em;
|
||||||
|
|
||||||
color: #adadad;
|
color: #adadad;
|
||||||
span.confirmed {
|
|
||||||
|
&-item[data-confirmed='true'] {
|
||||||
color: #a3eba3;
|
color: #a3eba3;
|
||||||
|
|
||||||
|
.stop-name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,17 +467,10 @@ ul.stock-list {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@include smallScreen {
|
@include smallScreen {
|
||||||
.info-general {
|
.journal_item-info {
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.info-extended {
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.general-train {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-route {
|
.info-route {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -457,10 +480,9 @@ ul.stock-list {
|
|||||||
margin: 1em auto 0 auto;
|
margin: 1em auto 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stock-specs {
|
.info-general,
|
||||||
justify-content: center;
|
.general-train,
|
||||||
}
|
.stock-specs,
|
||||||
|
|
||||||
.stock-history {
|
.stock-history {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,37 +2,62 @@
|
|||||||
<section class="scenery-dispatchers-history scenery-section">
|
<section class="scenery-dispatchers-history scenery-section">
|
||||||
<Loading v-if="dataStatus != 2" />
|
<Loading v-if="dataStatus != 2" />
|
||||||
|
|
||||||
<div class="list-warning" v-else-if="dispatcherHistoryList.length == 0">{{ $t('scenery.history-list-empty') }}</div>
|
<table class="scenery-history-table" v-else-if="historyList.length">
|
||||||
|
<thead>
|
||||||
|
<!-- <th>{{ $t('scenery.timetables-history-id') }}</th>
|
||||||
|
<th>{{ $t('scenery.timetables-history-number') }}</th>
|
||||||
|
<th>{{ $t('scenery.timetables-history-route') }}</th>
|
||||||
|
<th>{{ $t('scenery.timetables-history-driver') }}</th>
|
||||||
|
<th>{{ $t('scenery.timetables-history-author') }}</th>
|
||||||
|
<th>{{ $t('scenery.timetables-history-date') }}</th> -->
|
||||||
|
|
||||||
<ul class="history-list" v-else>
|
<th>Hash</th>
|
||||||
<li class="list-item" v-for="item in dispatcherHistoryList">
|
<th>Dyżurny</th>
|
||||||
<router-link class="item-general" :to="`/journal/dispatchers?dispatcherName=${item.dispatcherName}`">
|
<th>Poziom</th>
|
||||||
<span class="text--grayed">#{{ item.stationHash }} </span>
|
<th>Ocena</th>
|
||||||
<b
|
<th>Data</th>
|
||||||
v-if="item.dispatcherLevel !== null"
|
</thead>
|
||||||
class="level-badge dispatcher"
|
|
||||||
:style="calculateExpStyle(item.dispatcherLevel, item.dispatcherIsSupporter)"
|
|
||||||
>
|
|
||||||
{{ item.dispatcherLevel >= 2 ? item.dispatcherLevel : 'L' }}
|
|
||||||
</b>
|
|
||||||
|
|
||||||
<b>{{ item.dispatcherName }}</b>
|
<tbody>
|
||||||
</router-link>
|
<tr v-for="historyItem in historyList">
|
||||||
|
<td>#{{ historyItem.stationHash }}</td>
|
||||||
|
<td>
|
||||||
|
<router-link :to="`/journal/dispatchers?dispatcherName=${historyItem.dispatcherName}`">
|
||||||
|
<b>{{ 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 style="min-width: 300px">
|
||||||
|
<div v-if="historyItem.timestampTo">
|
||||||
|
<b>{{ $d(historyItem.timestampFrom) }}</b>
|
||||||
|
|
||||||
<div v-if="item.timestampTo">
|
{{ timestampToString(historyItem.timestampFrom) }}
|
||||||
<b>{{ $d(item.timestampFrom) }}</b>
|
- {{ timestampToString(historyItem.timestampTo) }} ({{ calculateDuration(historyItem.currentDuration) }})
|
||||||
|
</div>
|
||||||
|
|
||||||
{{ timestampToString(item.timestampFrom) }}
|
<div class="dispatcher-online" v-else>
|
||||||
- {{ timestampToString(item.timestampTo) }} ({{ calculateDuration(item.currentDuration) }})
|
{{ $t('journal.online-since') }}
|
||||||
</div>
|
<b>{{ timestampToString(historyItem.timestampFrom) }}</b>
|
||||||
|
({{ calculateDuration(historyItem.currentDuration) }})
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
<div class="dispatcher-online" v-else>
|
<div class="no-history" v-else>{{ $t('scenery.history-list-empty') }}</div>
|
||||||
{{ $t('journal.online-since') }}
|
<div ref="bottomDiv"></div>
|
||||||
<b>{{ timestampToString(item.timestampFrom) }}</b>
|
|
||||||
({{ calculateDuration(item.currentDuration) }})
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -46,24 +71,35 @@ import Station from '../../scripts/interfaces/Station';
|
|||||||
import { URLs } from '../../scripts/utils/apiURLs';
|
import { URLs } from '../../scripts/utils/apiURLs';
|
||||||
import Loading from '../Global/Loading.vue';
|
import Loading from '../Global/Loading.vue';
|
||||||
import styleMixin from '../../mixins/styleMixin';
|
import styleMixin from '../../mixins/styleMixin';
|
||||||
|
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SceneryDispatchersHistory',
|
name: 'SceneryDispatchersHistory',
|
||||||
mixins: [dateMixin, styleMixin],
|
mixins: [dateMixin, styleMixin, listObserverMixin],
|
||||||
props: {
|
props: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as PropType<Station>,
|
type: Object as PropType<Station>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dispatcherHistoryList: [] as DispatcherHistory[],
|
historyList: [] as DispatcherHistory[],
|
||||||
dataStatus: DataStatus.Loading,
|
dataStatus: DataStatus.Loading,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.mountObserver(this.fireObserverAction, this.$refs['bottomDiv'] as Element);
|
||||||
|
},
|
||||||
|
|
||||||
|
unmounted() {
|
||||||
|
this.unmountObserver();
|
||||||
|
},
|
||||||
|
|
||||||
activated() {
|
activated() {
|
||||||
this.fetchAPIData();
|
if (this.historyList.length == 0) this.fetchAPIData();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchAPIData(countFrom = 0, countLimit = 30) {
|
async fetchAPIData(countFrom = 0, countLimit = 30) {
|
||||||
@@ -71,12 +107,17 @@ export default defineComponent({
|
|||||||
const requestString = `${URLs.stacjownikAPI}/api/getDispatchers?stationName=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
const requestString = `${URLs.stacjownikAPI}/api/getDispatchers?stationName=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||||
const historyAPIData: DispatcherHistory[] = await (await axios.get(requestString)).data;
|
const historyAPIData: DispatcherHistory[] = await (await axios.get(requestString)).data;
|
||||||
|
|
||||||
this.dispatcherHistoryList = historyAPIData;
|
this.historyList.push(...historyAPIData);
|
||||||
this.dataStatus = DataStatus.Loaded;
|
this.dataStatus = DataStatus.Loaded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
fireObserverAction() {
|
||||||
|
if (this.historyList.length > 0 && this.dataStatus == DataStatus.Loaded)
|
||||||
|
this.fetchAPIData(this.historyList.length);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: { Loading },
|
components: { Loading },
|
||||||
});
|
});
|
||||||
@@ -84,30 +125,10 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
@import '../../styles/SceneryView/styles.scss';
|
@import '../../styles/sceneryViewTables.scss';
|
||||||
|
|
||||||
.history-list {
|
.level-badge {
|
||||||
padding: 0 0.5em;
|
margin: 0 auto;
|
||||||
}
|
|
||||||
|
|
||||||
.list-item {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
text-align: left;
|
|
||||||
background-color: #353535;
|
|
||||||
padding: 0.5em;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
|
|
||||||
line-height: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-general {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.25em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dispatcher-online {
|
.dispatcher-online {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<section class="scenery-timetables-history scenery-section">
|
<section class="scenery-timetables-history scenery-section">
|
||||||
<Loading v-if="dataStatus != 2" />
|
<Loading v-if="dataStatus != 2" />
|
||||||
|
|
||||||
<table v-else-if="sceneryHistoryList.length">
|
<table class="scenery-history-table" v-else-if="historyList.length">
|
||||||
<thead>
|
<thead>
|
||||||
<th>{{ $t('scenery.timetables-history-id') }}</th>
|
<th>{{ $t('scenery.timetables-history-id') }}</th>
|
||||||
<th>{{ $t('scenery.timetables-history-number') }}</th>
|
<th>{{ $t('scenery.timetables-history-number') }}</th>
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="historyItem in sceneryHistoryList">
|
<tr v-for="historyItem in historyList">
|
||||||
<td>
|
<td>
|
||||||
<router-link :to="`/journal/timetables?timetableId=${historyItem.id}`">#{{ historyItem.id }}</router-link>
|
<router-link :to="`/journal/timetables?timetableId=${historyItem.id}`">#{{ historyItem.id }}</router-link>
|
||||||
</td>
|
</td>
|
||||||
@@ -39,7 +39,8 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="list-warning" v-else>{{ $t('scenery.history-list-empty') }}</div>
|
<div class="no-history" v-else>{{ $t('scenery.history-list-empty') }}</div>
|
||||||
|
<div ref="bottomDiv"></div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -52,37 +53,54 @@ import { TimetableHistory, SceneryTimetableHistory } from '../../scripts/interfa
|
|||||||
import Station from '../../scripts/interfaces/Station';
|
import Station from '../../scripts/interfaces/Station';
|
||||||
import { URLs } from '../../scripts/utils/apiURLs';
|
import { URLs } from '../../scripts/utils/apiURLs';
|
||||||
import Loading from '../Global/Loading.vue';
|
import Loading from '../Global/Loading.vue';
|
||||||
|
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SceneryTimetablesHistory',
|
name: 'SceneryTimetablesHistory',
|
||||||
mixins: [dateMixin],
|
mixins: [dateMixin, listObserverMixin],
|
||||||
props: {
|
props: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as PropType<Station>,
|
type: Object as PropType<Station>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
sceneryHistoryList: [] as TimetableHistory[],
|
historyList: [] as TimetableHistory[],
|
||||||
dataStatus: DataStatus.Loading,
|
dataStatus: DataStatus.Loading,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
activated() {
|
|
||||||
this.fetchAPIData();
|
mounted() {
|
||||||
|
this.mountObserver(this.fireObserverAction, this.$refs['bottomDiv'] as Element);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
unmounted() {
|
||||||
|
this.unmountObserver();
|
||||||
|
},
|
||||||
|
|
||||||
|
activated() {
|
||||||
|
if (this.historyList.length == 0) this.fetchAPIData();
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async fetchAPIData(countFrom = 0, countLimit = 15) {
|
async fetchAPIData(countFrom = 0, countLimit = 15) {
|
||||||
try {
|
try {
|
||||||
const requestString = `${URLs.stacjownikAPI}/api/getIssuedTimetables?name=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
const requestString = `${URLs.stacjownikAPI}/api/getIssuedTimetables?name=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||||
const historyAPIData: SceneryTimetableHistory = await (await axios.get(requestString)).data;
|
const historyAPIData: SceneryTimetableHistory = await (await axios.get(requestString)).data;
|
||||||
|
|
||||||
this.sceneryHistoryList = historyAPIData.timetables;
|
this.historyList.push(...historyAPIData.timetables);
|
||||||
this.dataStatus = DataStatus.Loaded;
|
this.dataStatus = DataStatus.Loaded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
fireObserverAction() {
|
||||||
|
if (this.historyList.length > 0 && this.dataStatus == DataStatus.Loaded)
|
||||||
|
this.fetchAPIData(this.historyList.length);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: { Loading },
|
components: { Loading },
|
||||||
});
|
});
|
||||||
@@ -90,46 +108,5 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
@import '../../styles/SceneryView/styles.scss';
|
@import '../../styles/sceneryViewTables.scss';
|
||||||
|
|
||||||
.list-warning {
|
|
||||||
padding: 1em 0.5em;
|
|
||||||
background-color: #444;
|
|
||||||
font-size: 1.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-list {
|
|
||||||
padding: 0 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
|
|
||||||
thead {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
background-color: #222222;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr {
|
|
||||||
background-color: #353535;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
padding: 0.75em;
|
|
||||||
border-bottom: solid 5px #111;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include smallScreen {
|
|
||||||
.list-item {
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+9
-3
@@ -274,6 +274,7 @@
|
|||||||
"title": "DISPATCHER HISTORY",
|
"title": "DISPATCHER HISTORY",
|
||||||
"loading": "Loading dispatcher history data...",
|
"loading": "Loading dispatcher history data...",
|
||||||
"no-history": "No dispatcher history found!",
|
"no-history": "No dispatcher history found!",
|
||||||
|
"data-refreshed-at": "Data refreshed at",
|
||||||
|
|
||||||
"section-timetables": "TIMETABLES",
|
"section-timetables": "TIMETABLES",
|
||||||
"section-dispatchers": "DISPATCHERS",
|
"section-dispatchers": "DISPATCHERS",
|
||||||
@@ -291,8 +292,10 @@
|
|||||||
|
|
||||||
"online-since": "ONLINE SINCE",
|
"online-since": "ONLINE SINCE",
|
||||||
"duty-lasted": "The duty lasted",
|
"duty-lasted": "The duty lasted",
|
||||||
"minutes": "{minutes} mins",
|
|
||||||
"hours": "{hours}h {minutes} mins",
|
"hours": "{value} hour | {value} hours",
|
||||||
|
"minutes": "{value} min | {value} mins",
|
||||||
|
"seconds": "{value} s",
|
||||||
|
|
||||||
"stock-info": "EXTRA INFO",
|
"stock-info": "EXTRA INFO",
|
||||||
"stock-length": "Length",
|
"stock-length": "Length",
|
||||||
@@ -329,7 +332,10 @@
|
|||||||
"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!",
|
||||||
|
|
||||||
"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! :/",
|
||||||
|
|
||||||
|
"timetable-location-signal": "signal:",
|
||||||
|
"timetable-location-route": "route:"
|
||||||
},
|
},
|
||||||
"scenery": {
|
"scenery": {
|
||||||
"users": "PLAYERS ONLINE",
|
"users": "PLAYERS ONLINE",
|
||||||
|
|||||||
+8
-3
@@ -279,6 +279,7 @@
|
|||||||
"title": "HISTORIA DYŻURÓW",
|
"title": "HISTORIA DYŻURÓW",
|
||||||
"loading": "Ładowanie historii dyżurów...",
|
"loading": "Ładowanie historii dyżurów...",
|
||||||
"no-history": "Brak historii dyżurów dla tej scenerii!",
|
"no-history": "Brak historii dyżurów dla tej scenerii!",
|
||||||
|
"data-refreshed-at": "Dane odświeżone o",
|
||||||
|
|
||||||
"section-timetables": "ROZKŁADY JAZDY",
|
"section-timetables": "ROZKŁADY JAZDY",
|
||||||
"section-dispatchers": "DYŻURNI",
|
"section-dispatchers": "DYŻURNI",
|
||||||
@@ -288,8 +289,9 @@
|
|||||||
|
|
||||||
"online-since": "ONLINE OD",
|
"online-since": "ONLINE OD",
|
||||||
"duty-lasted": "Dyżur trwał",
|
"duty-lasted": "Dyżur trwał",
|
||||||
"minutes": "{minutes} min.",
|
"hours": "{value} godz.",
|
||||||
"hours": "{hours} godz. {minutes} min.",
|
"minutes": "{value} min.",
|
||||||
|
"seconds": "{value} sek.",
|
||||||
|
|
||||||
"route-length": "Kilometraż:",
|
"route-length": "Kilometraż:",
|
||||||
"station-count": "Stacje:",
|
"station-count": "Stacje:",
|
||||||
@@ -333,7 +335,10 @@
|
|||||||
"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!",
|
||||||
|
|
||||||
"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! :/",
|
||||||
|
|
||||||
|
"timetable-location-signal": "semafor:",
|
||||||
|
"timetable-location-route": "szlak:"
|
||||||
},
|
},
|
||||||
"scenery": {
|
"scenery": {
|
||||||
"users": "GRACZE ONLINE",
|
"users": "GRACZE ONLINE",
|
||||||
|
|||||||
+70
-50
@@ -1,50 +1,70 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
methods: {
|
methods: {
|
||||||
localeDate(dateString: string, locale: string) {
|
localeDate(dateString: string, locale: string) {
|
||||||
return new Date(dateString).toLocaleDateString(locale == 'pl' ? 'pl-PL' : 'en-GB', {
|
return new Date(dateString).toLocaleDateString(locale == 'pl' ? 'pl-PL' : 'en-GB', {
|
||||||
weekday: 'long',
|
weekday: 'long',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: '2-digit',
|
month: '2-digit',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
localeDay(dateString: string, locale: string) {
|
localeDay(dateString: string, locale: string) {
|
||||||
return new Date(dateString).toLocaleDateString(locale == 'pl' ? 'pl-PL' : 'en-GB', {
|
return new Date(dateString).toLocaleDateString(locale == 'pl' ? 'pl-PL' : 'en-GB', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: '2-digit',
|
month: '2-digit',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
localeTime(dateString: string, locale: string) {
|
localeTime(dateString: string, locale: string) {
|
||||||
return new Date(dateString).toLocaleTimeString(locale == 'pl' ? 'pl-PL' : 'en-GB', {
|
return new Date(dateString).toLocaleTimeString(locale == 'pl' ? 'pl-PL' : 'en-GB', {
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
timestampToString(timestamp: number | null) {
|
stringToDate(dateString?: string) {
|
||||||
return timestamp
|
return dateString ? new Date(dateString) : null;
|
||||||
? new Date(timestamp).toLocaleTimeString('pl-PL', {
|
},
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit',
|
parseDateToTimeString(date: Date | null) {
|
||||||
})
|
return (
|
||||||
: '';
|
date?.toLocaleTimeString('pl-PL', {
|
||||||
},
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
calculateDuration(timestampMs: number) {
|
}) || ''
|
||||||
const minsTotal = Math.round(timestampMs / 60000);
|
);
|
||||||
const hoursTotal = Math.floor(minsTotal / 60);
|
},
|
||||||
const minsInHour = minsTotal % 60;
|
|
||||||
|
timestampToString(timestamp: number | null) {
|
||||||
return minsTotal > 60
|
return timestamp
|
||||||
? this.$t('journal.hours', { hours: hoursTotal, minutes: minsInHour })
|
? new Date(timestamp).toLocaleTimeString('pl-PL', {
|
||||||
: this.$t('journal.minutes', { minutes: minsTotal });
|
hour: '2-digit',
|
||||||
},
|
minute: '2-digit',
|
||||||
},
|
})
|
||||||
});
|
: '';
|
||||||
|
},
|
||||||
|
|
||||||
|
calculateDuration(timestampMs: number, showSeconds = false) {
|
||||||
|
const secondsTotal = Math.floor(timestampMs / 1000);
|
||||||
|
const minsTotal = Math.round(timestampMs / 60000);
|
||||||
|
const hoursTotal = Math.floor(minsTotal / 60);
|
||||||
|
const minsInHour = minsTotal % 60;
|
||||||
|
|
||||||
|
return minsTotal >= 60
|
||||||
|
? `${this.$t('journal.hours', { value: hoursTotal }, hoursTotal)} ${this.$t(
|
||||||
|
'journal.minutes',
|
||||||
|
{ value: minsInHour },
|
||||||
|
minsInHour
|
||||||
|
)}`
|
||||||
|
: showSeconds && secondsTotal <= 60
|
||||||
|
? this.$t('journal.seconds', { value: secondsTotal }, secondsTotal)
|
||||||
|
: this.$t('journal.minutes', { value: minsTotal }, minsTotal);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
data: () => ({
|
||||||
|
observer: null as IntersectionObserver | null,
|
||||||
|
observerTarget: null as Element | null,
|
||||||
|
}),
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
mountObserver(actionFunction: () => void, target: Element) {
|
||||||
|
this.observer = new IntersectionObserver((entries) => {
|
||||||
|
if (entries[0].intersectionRatio > 0) actionFunction();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.observer.observe(target);
|
||||||
|
},
|
||||||
|
|
||||||
|
unmountObserver() {
|
||||||
|
if (!this.observerTarget) return;
|
||||||
|
|
||||||
|
this.observer?.unobserve(this.observerTarget);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -16,6 +16,7 @@ export interface TimetableHistory {
|
|||||||
twr: number;
|
twr: number;
|
||||||
skr: number;
|
skr: number;
|
||||||
sceneriesString: string;
|
sceneriesString: string;
|
||||||
|
currentLocation: string[];
|
||||||
|
|
||||||
routeDistance: number;
|
routeDistance: number;
|
||||||
currentDistance: number;
|
currentDistance: number;
|
||||||
@@ -52,6 +53,11 @@ export interface TimetableHistory {
|
|||||||
|
|
||||||
checkpointArrivals?: string[];
|
checkpointArrivals?: string[];
|
||||||
checkpointDepartures?: string[];
|
checkpointDepartures?: string[];
|
||||||
|
|
||||||
|
checkpointArrivalsScheduled?: string[];
|
||||||
|
checkpointDeparturesScheduled?: string[];
|
||||||
|
|
||||||
|
checkpointStopTypes?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SceneryTimetableHistory {
|
export interface SceneryTimetableHistory {
|
||||||
|
|||||||
@@ -23,6 +23,15 @@
|
|||||||
padding: 1em 0;
|
padding: 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.journal_refreshed-date {
|
||||||
|
background-color: #333;
|
||||||
|
color: #ddd;
|
||||||
|
text-align: end;
|
||||||
|
|
||||||
|
padding: 0.25em;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
.journal_warning {
|
.journal_warning {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
@@ -71,6 +80,10 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.journal_refreshed-date {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (orientation: landscape) {
|
@media (orientation: landscape) {
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
.scenery-section {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-warning {
|
|
||||||
padding: 1em 0.5em;
|
|
||||||
background-color: #444;
|
|
||||||
font-size: 1.2em;
|
|
||||||
}
|
|
||||||
@@ -30,7 +30,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 0.9em;
|
|
||||||
|
|
||||||
&.driver {
|
&.driver {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
table.scenery-history-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
thead {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
background-color: #222222;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
background-color: #353535;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0.75em;
|
||||||
|
border-bottom: solid 5px #111;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-history {
|
||||||
|
padding: 1em 0.5em;
|
||||||
|
background-color: #444;
|
||||||
|
font-size: 1.2em;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
@@ -13,6 +13,10 @@
|
|||||||
optionsType="dispatchers"
|
optionsType="dispatchers"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div class="journal_refreshed-date" v-if="dataRefreshedAt">
|
||||||
|
{{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="list_wrapper" @scroll="handleScroll">
|
<div class="list_wrapper" @scroll="handleScroll">
|
||||||
<transition name="status-anim" mode="out-in">
|
<transition name="status-anim" mode="out-in">
|
||||||
<div :key="dataStatus">
|
<div :key="dataStatus">
|
||||||
@@ -104,6 +108,7 @@ export default defineComponent({
|
|||||||
data: () => ({
|
data: () => ({
|
||||||
currentQuery: '',
|
currentQuery: '',
|
||||||
currentQueryArray: [] as string[],
|
currentQueryArray: [] as string[],
|
||||||
|
dataRefreshedAt: null as Date | null,
|
||||||
|
|
||||||
scrollDataLoaded: true,
|
scrollDataLoaded: true,
|
||||||
scrollNoMoreData: false,
|
scrollNoMoreData: false,
|
||||||
@@ -273,6 +278,7 @@ export default defineComponent({
|
|||||||
? this.historyList[0].dispatcherName
|
? this.historyList[0].dispatcherName
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
|
this.dataRefreshedAt = new Date();
|
||||||
this.dataStatus = DataStatus.Loaded;
|
this.dataStatus = DataStatus.Loaded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.dataStatus = DataStatus.Error;
|
this.dataStatus = DataStatus.Error;
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
<JournalStats />
|
<JournalStats />
|
||||||
|
|
||||||
|
<div class="journal_refreshed-date" v-if="dataRefreshedAt">
|
||||||
|
{{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="list_wrapper" @scroll="handleScroll">
|
<div class="list_wrapper" @scroll="handleScroll">
|
||||||
<transition name="status-anim" mode="out-in">
|
<transition name="status-anim" mode="out-in">
|
||||||
<div :key="dataStatus">
|
<div :key="dataStatus">
|
||||||
@@ -101,6 +105,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
currentQueryParams: {} as TimetablesQueryParams,
|
currentQueryParams: {} as TimetablesQueryParams,
|
||||||
|
dataRefreshedAt: null as Date | null,
|
||||||
|
|
||||||
scrollDataLoaded: true,
|
scrollDataLoaded: true,
|
||||||
scrollNoMoreData: false,
|
scrollNoMoreData: false,
|
||||||
@@ -326,6 +331,7 @@ export default defineComponent({
|
|||||||
: '';
|
: '';
|
||||||
|
|
||||||
this.dataStatus = DataStatus.Loaded;
|
this.dataStatus = DataStatus.Loaded;
|
||||||
|
this.dataRefreshedAt = new Date();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.dataStatus = DataStatus.Error;
|
this.dataStatus = DataStatus.Error;
|
||||||
this.dataErrorMessage = 'Ups! Coś poszło nie tak!';
|
this.dataErrorMessage = 'Ups! Coś poszło nie tak!';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scenery-view">
|
<div class="scenery-view">
|
||||||
<div class="scenery-offline" v-if="!stationInfo && isComponentVisible && store.dataStatuses.sceneries == 2">
|
<div class="scenery-offline" v-if="!stationInfo && isComponentVisible && store.dataStatuses.sceneries == 2">
|
||||||
<div>{{ $t('scenery.no-scenery') }}</div>
|
<div>{{ $t('scenery.no-scenery') }}</div>
|
||||||
@@ -172,6 +172,12 @@ button.back-btn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scenery-section {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
.scenery-wrapper {
|
.scenery-wrapper {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 4fr 5fr;
|
grid-template-columns: 4fr 5fr;
|
||||||
|
|||||||
Reference in New Issue
Block a user