mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 21:38:13 +00:00
format & lint
This commit is contained in:
@@ -1,143 +1,150 @@
|
||||
<template>
|
||||
<section class="scenery-table-section">
|
||||
<Loading v-if="dataStatus != DataStatus.Loaded && historyList.length == 0" />
|
||||
<div class="no-history" v-else-if="historyList.length == 0">{{ $t('scenery.history-list-empty') }}</div>
|
||||
|
||||
<table class="scenery-history-table" v-else="historyList.length">
|
||||
<thead>
|
||||
<th>{{ $t('scenery.dispatchers-history-hash') }}</th>
|
||||
<th>{{ $t('scenery.dispatchers-history-dispatcher') }}</th>
|
||||
<th>{{ $t('scenery.dispatchers-history-level') }}</th>
|
||||
<th>{{ $t('scenery.dispatchers-history-rate') }}</th>
|
||||
<th>{{ $t('scenery.dispatchers-history-date') }}</th>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<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>
|
||||
|
||||
{{ timestampToString(historyItem.timestampFrom) }}
|
||||
- {{ timestampToString(historyItem.timestampTo) }} ({{ calculateDuration(historyItem.currentDuration) }})
|
||||
</div>
|
||||
|
||||
<div class="dispatcher-online" v-else>
|
||||
{{ $t('journal.online-since') }}
|
||||
<b>{{ timestampToString(historyItem.timestampFrom) }}</b>
|
||||
({{ calculateDuration(historyItem.currentDuration) }})
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<div class="bottom-info">
|
||||
<button class="btn btn--option" v-if="historyList.length > 0" @click="navigateToHistory">
|
||||
{{ $t('scenery.bottom-info') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import axios from 'axios';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||
import { DispatcherHistory } from '../../scripts/interfaces/api/DispatchersAPIData';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import styleMixin from '../../mixins/styleMixin';
|
||||
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryDispatchersHistory',
|
||||
mixins: [dateMixin, styleMixin, listObserverMixin],
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
historyList: [] as DispatcherHistory[],
|
||||
dataStatus: DataStatus.Loading,
|
||||
DataStatus,
|
||||
};
|
||||
},
|
||||
|
||||
async activated() {
|
||||
// if (this.historyList.length == 0) {
|
||||
const fetchedHistory = await this.fetchAPIData();
|
||||
if (fetchedHistory) this.historyList = fetchedHistory;
|
||||
// }
|
||||
},
|
||||
|
||||
methods: {
|
||||
async fetchAPIData(countFrom = 0, countLimit = 30): Promise<DispatcherHistory[] | null> {
|
||||
try {
|
||||
this.dataStatus = DataStatus.Loading;
|
||||
|
||||
const requestString = `${URLs.stacjownikAPI}/api/getDispatchers?stationName=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||
const historyAPIData: DispatcherHistory[] = await (await axios.get(requestString)).data;
|
||||
|
||||
this.dataStatus = DataStatus.Loaded;
|
||||
return historyAPIData;
|
||||
} catch (error) {
|
||||
this.dataStatus = DataStatus.Error;
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
navigateToHistory() {
|
||||
this.$router.push(`/journal/dispatchers?sceneryName=${this.station.name}`);
|
||||
},
|
||||
},
|
||||
components: { Loading },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/sceneryViewTables.scss';
|
||||
|
||||
.level-badge {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.dispatcher-online {
|
||||
color: springgreen;
|
||||
}
|
||||
|
||||
@include smallScreen {
|
||||
.history-list {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.list-item {
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<section class="scenery-table-section">
|
||||
<Loading v-if="dataStatus != DataStatus.Loaded && historyList.length == 0" />
|
||||
|
||||
<div class="no-history" v-else-if="historyList.length == 0">
|
||||
{{ $t('scenery.history-list-empty') }}
|
||||
</div>
|
||||
|
||||
<table class="scenery-history-table" v-else>
|
||||
<thead>
|
||||
<th>{{ $t('scenery.dispatchers-history-hash') }}</th>
|
||||
<th>{{ $t('scenery.dispatchers-history-dispatcher') }}</th>
|
||||
<th>{{ $t('scenery.dispatchers-history-level') }}</th>
|
||||
<th>{{ $t('scenery.dispatchers-history-rate') }}</th>
|
||||
<th>{{ $t('scenery.dispatchers-history-date') }}</th>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr v-for="historyItem in historyList" :key="historyItem.id">
|
||||
<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>
|
||||
|
||||
{{ timestampToString(historyItem.timestampFrom) }}
|
||||
- {{ timestampToString(historyItem.timestampTo) }} ({{
|
||||
calculateDuration(historyItem.currentDuration)
|
||||
}})
|
||||
</div>
|
||||
|
||||
<div class="dispatcher-online" v-else>
|
||||
{{ $t('journal.online-since') }}
|
||||
<b>{{ timestampToString(historyItem.timestampFrom) }}</b>
|
||||
({{ calculateDuration(historyItem.currentDuration) }})
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<div class="bottom-info">
|
||||
<button class="btn btn--option" v-if="historyList.length > 0" @click="navigateToHistory">
|
||||
{{ $t('scenery.bottom-info') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import axios from 'axios';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||
import { DispatcherHistory } from '../../scripts/interfaces/api/DispatchersAPIData';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import styleMixin from '../../mixins/styleMixin';
|
||||
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryDispatchersHistory',
|
||||
mixins: [dateMixin, styleMixin, listObserverMixin],
|
||||
components: { Loading },
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
historyList: [] as DispatcherHistory[],
|
||||
dataStatus: DataStatus.Loading,
|
||||
DataStatus
|
||||
};
|
||||
},
|
||||
|
||||
async activated() {
|
||||
// if (this.historyList.length == 0) {
|
||||
const fetchedHistory = await this.fetchAPIData();
|
||||
if (fetchedHistory) this.historyList = fetchedHistory;
|
||||
// }
|
||||
},
|
||||
|
||||
methods: {
|
||||
async fetchAPIData(countFrom = 0, countLimit = 30): Promise<DispatcherHistory[] | null> {
|
||||
try {
|
||||
this.dataStatus = DataStatus.Loading;
|
||||
|
||||
const requestString = `${URLs.stacjownikAPI}/api/getDispatchers?stationName=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||
const historyAPIData: DispatcherHistory[] = await (await axios.get(requestString)).data;
|
||||
|
||||
this.dataStatus = DataStatus.Loaded;
|
||||
return historyAPIData;
|
||||
} catch (error) {
|
||||
this.dataStatus = DataStatus.Error;
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
navigateToHistory() {
|
||||
this.$router.push(`/journal/dispatchers?sceneryName=${this.station.name}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/sceneryViewTables.scss';
|
||||
|
||||
.level-badge {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.dispatcher-online {
|
||||
color: springgreen;
|
||||
}
|
||||
|
||||
@include smallScreen {
|
||||
.history-list {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.list-item {
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -52,4 +52,3 @@ export default defineComponent({
|
||||
font-size: 1.2em;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,139 +1,162 @@
|
||||
<template>
|
||||
<div class="scenery-info">
|
||||
<section v-if="!timetableOnly">
|
||||
<div class="scenery-info-general" v-if="station.generalInfo">
|
||||
<SceneryInfoIcons :station="station" />
|
||||
|
||||
<div class="scenery-general-list">
|
||||
<span>
|
||||
<b>{{ $t('availability.title') }}:</b> {{ $t(`availability.${station.generalInfo.availability}`) }}
|
||||
|
||||
<span v-if="station.generalInfo.reqLevel > -1">
|
||||
- {{ $t('scenery.req-level', { lvl: station.generalInfo.reqLevel }, station.generalInfo.reqLevel) }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
• <b>{{ $t('controls.title') }}:</b> {{ $t(`controls.${station.generalInfo.controlType}`) }}
|
||||
</span>
|
||||
|
||||
<span>
|
||||
• <b>{{ $t('signals.title') }}:</b> {{ $t(`signals.${station.generalInfo.signalType}`) }}
|
||||
</span>
|
||||
|
||||
<span v-if="station.generalInfo.lines">
|
||||
• <b>{{ $t('scenery.lines-title') }}:</b> {{ station.generalInfo.lines }}
|
||||
</span>
|
||||
<span v-if="station.generalInfo.project">
|
||||
• <b>{{ $t('scenery.project-title') }}: </b>
|
||||
<a style="color: salmon; text-decoration: underline; font-weight: bold" :href="station.generalInfo.projectUrl" target="_blank">
|
||||
{{ station.generalInfo.project }}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<SceneryInfoRoutes :station="station" />
|
||||
|
||||
<div class="scenery-authors" v-if="station.generalInfo.authors && station.generalInfo.authors.length > 0">
|
||||
<b> {{ $t('scenery.authors-title', { authors: station.generalInfo.authors.length }, station.generalInfo.authors.length) }}: </b>
|
||||
{{ station.generalInfo.authors.join(', ') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin: 2em 0; height: 2px; background-color: white"></div>
|
||||
|
||||
<!-- info dispatcher -->
|
||||
<SceneryInfoDispatcher :station="station" :onlineFrom="onlineFrom" />
|
||||
|
||||
<div class="info-lists">
|
||||
<!-- user list -->
|
||||
<SceneryInfoUserList :station="station" />
|
||||
|
||||
<!-- spawn list -->
|
||||
<SceneryInfoSpawnList :station="station" />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '@vue/runtime-core';
|
||||
|
||||
import SceneryInfoDispatcher from './SceneryInfo/SceneryInfoDispatcher.vue';
|
||||
import SceneryInfoIcons from './SceneryInfo/SceneryInfoIcons.vue';
|
||||
import SceneryInfoStats from './SceneryInfo/SceneryInfoStats.vue';
|
||||
import SceneryInfoUserList from './SceneryInfo/SceneryInfoUserList.vue';
|
||||
import SceneryInfoSpawnList from './SceneryInfo/SceneryInfoSpawnList.vue';
|
||||
import SceneryInfoRoutes from './SceneryInfo/SceneryInfoRoutes.vue';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
SceneryInfoDispatcher,
|
||||
SceneryInfoIcons,
|
||||
SceneryInfoStats,
|
||||
SceneryInfoUserList,
|
||||
SceneryInfoSpawnList,
|
||||
SceneryInfoRoutes,
|
||||
},
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
default: {},
|
||||
},
|
||||
|
||||
timetableOnly: Boolean,
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
onlineFrom: -1,
|
||||
}),
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/badge.scss';
|
||||
|
||||
h3.section-header {
|
||||
margin: 0.5em 0;
|
||||
padding: 0.3em;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
font-size: 1.2em;
|
||||
|
||||
img {
|
||||
width: 1.1em;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.info-lists {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.scenery-info-general {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.scenery-general-list {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
span {
|
||||
margin: 0 0.15em;
|
||||
}
|
||||
}
|
||||
|
||||
.scenery-topic a {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div class="scenery-info">
|
||||
<section v-if="!timetableOnly">
|
||||
<div class="scenery-info-general" v-if="station.generalInfo">
|
||||
<SceneryInfoIcons :station="station" />
|
||||
|
||||
<div class="scenery-general-list">
|
||||
<span>
|
||||
<b>{{ $t('availability.title') }}:</b>
|
||||
{{ $t(`availability.${station.generalInfo.availability}`) }}
|
||||
|
||||
<span v-if="station.generalInfo.reqLevel > -1">
|
||||
-
|
||||
{{
|
||||
$t(
|
||||
'scenery.req-level',
|
||||
{ lvl: station.generalInfo.reqLevel },
|
||||
station.generalInfo.reqLevel
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
• <b>{{ $t('controls.title') }}:</b>
|
||||
{{ $t(`controls.${station.generalInfo.controlType}`) }}
|
||||
</span>
|
||||
|
||||
<span>
|
||||
• <b>{{ $t('signals.title') }}:</b>
|
||||
{{ $t(`signals.${station.generalInfo.signalType}`) }}
|
||||
</span>
|
||||
|
||||
<span v-if="station.generalInfo.lines">
|
||||
• <b>{{ $t('scenery.lines-title') }}:</b> {{ station.generalInfo.lines }}
|
||||
</span>
|
||||
<span v-if="station.generalInfo.project">
|
||||
• <b>{{ $t('scenery.project-title') }}: </b>
|
||||
<a
|
||||
style="color: salmon; text-decoration: underline; font-weight: bold"
|
||||
:href="station.generalInfo.projectUrl"
|
||||
target="_blank"
|
||||
>
|
||||
{{ station.generalInfo.project }}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<SceneryInfoRoutes :station="station" />
|
||||
|
||||
<div
|
||||
class="scenery-authors"
|
||||
v-if="station.generalInfo.authors && station.generalInfo.authors.length > 0"
|
||||
>
|
||||
<b>
|
||||
{{
|
||||
$t(
|
||||
'scenery.authors-title',
|
||||
{ authors: station.generalInfo.authors.length },
|
||||
station.generalInfo.authors.length
|
||||
)
|
||||
}}:
|
||||
</b>
|
||||
{{ station.generalInfo.authors.join(', ') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin: 2em 0; height: 2px; background-color: white"></div>
|
||||
|
||||
<!-- info dispatcher -->
|
||||
<SceneryInfoDispatcher :station="station" :onlineFrom="onlineFrom" />
|
||||
|
||||
<div class="info-lists">
|
||||
<!-- user list -->
|
||||
<SceneryInfoUserList :station="station" />
|
||||
|
||||
<!-- spawn list -->
|
||||
<SceneryInfoSpawnList :station="station" />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
|
||||
import SceneryInfoDispatcher from './SceneryInfo/SceneryInfoDispatcher.vue';
|
||||
import SceneryInfoIcons from './SceneryInfo/SceneryInfoIcons.vue';
|
||||
import SceneryInfoUserList from './SceneryInfo/SceneryInfoUserList.vue';
|
||||
import SceneryInfoSpawnList from './SceneryInfo/SceneryInfoSpawnList.vue';
|
||||
import SceneryInfoRoutes from './SceneryInfo/SceneryInfoRoutes.vue';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
SceneryInfoDispatcher,
|
||||
SceneryInfoIcons,
|
||||
SceneryInfoUserList,
|
||||
SceneryInfoSpawnList,
|
||||
SceneryInfoRoutes
|
||||
},
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
},
|
||||
|
||||
timetableOnly: Boolean
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
onlineFrom: -1
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/badge.scss';
|
||||
|
||||
h3.section-header {
|
||||
margin: 0.5em 0;
|
||||
padding: 0.3em;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
font-size: 1.2em;
|
||||
|
||||
img {
|
||||
width: 1.1em;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.info-lists {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.scenery-info-general {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.scenery-general-list {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
span {
|
||||
margin: 0 0.15em;
|
||||
}
|
||||
}
|
||||
|
||||
.scenery-topic a {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
<div class="dispatcher" v-if="station.onlineInfo">
|
||||
<span
|
||||
class="dispatcher_level"
|
||||
:style="calculateExpStyle(station.onlineInfo.dispatcherExp, station.onlineInfo.dispatcherIsSupporter)"
|
||||
:style="
|
||||
calculateExpStyle(
|
||||
station.onlineInfo.dispatcherExp,
|
||||
station.onlineInfo.dispatcherIsSupporter
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ station.onlineInfo.dispatcherExp > 1 ? station.onlineInfo.dispatcherExp : 'L' }}
|
||||
</span>
|
||||
@@ -30,7 +35,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
import dateMixin from '../../../mixins/dateMixin';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import routerMixin from '../../../mixins/routerMixin';
|
||||
@@ -39,18 +44,18 @@ import Station from '../../../scripts/interfaces/Station';
|
||||
import StationStatusBadge from '../../Global/StationStatusBadge.vue';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [styleMixin, dateMixin, routerMixin, imageMixin],
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
default: {},
|
||||
},
|
||||
onlineFrom: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
},
|
||||
mixins: [styleMixin, dateMixin, routerMixin, imageMixin],
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
},
|
||||
components: { StationStatusBadge }
|
||||
onlineFrom: {
|
||||
type: Number,
|
||||
default: -1
|
||||
}
|
||||
},
|
||||
components: { StationStatusBadge }
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -98,4 +103,3 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import stationInfoMixin from '../../../mixins/stationInfoMixin';
|
||||
import styleMixin from '../../../mixins/styleMixin';
|
||||
@@ -86,10 +86,10 @@ export default defineComponent({
|
||||
mixins: [stationInfoMixin, styleMixin, imageMixin],
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -118,4 +118,3 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,129 +1,142 @@
|
||||
<template>
|
||||
<section class="info-routes" v-if="station.generalInfo">
|
||||
<div class="routes one-way" v-if="station.generalInfo.routes.oneWay.length > 0">
|
||||
<b>{{ $t('scenery.one-way-routes') }}</b>
|
||||
|
||||
<ul class="routes-list">
|
||||
<li v-for="route in station.generalInfo.routes.oneWay" @click="setActiveShowLength(route.name)">
|
||||
<span :class="{ 'no-catenary': !route.catenary, internal: route.isInternal }"> {{ route.name }}</span>
|
||||
<span v-if="route.speed" class="speed">
|
||||
{{ activeShowLength.includes(route.name) ? route.length + 'm' : route.speed }}
|
||||
</span>
|
||||
<span v-if="route.SBL" class="sbl">SBL</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="routes two-way" v-if="station.generalInfo.routes.twoWay.length > 0">
|
||||
<b>{{ $t('scenery.two-way-routes') }}</b>
|
||||
|
||||
<ul class="routes-list">
|
||||
<li v-for="(route, i) in station.generalInfo.routes.twoWay" @click="setActiveShowLength(route.name)">
|
||||
<span :class="{ 'no-catenary': !route.catenary, internal: route.isInternal }">{{ route.name }}</span>
|
||||
<span v-if="route.speed" class="speed">
|
||||
{{ activeShowLength.includes(route.name) ? route.length + 'm' : route.speed }}
|
||||
</span>
|
||||
<span v-if="route.SBL" class="sbl">SBL</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
setActiveShowLength(name: string) {
|
||||
if (this.activeShowLength.includes(name)) this.activeShowLength.splice(this.activeShowLength.indexOf(name), 1);
|
||||
else this.activeShowLength.push(name);
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
activeShowLength: [] as string[],
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.info-routes {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.routes {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
ul.routes-list {
|
||||
margin: 0.45em 0.25em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
li {
|
||||
margin: 0.5em 0.25em;
|
||||
cursor: pointer;
|
||||
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
|
||||
span {
|
||||
padding: 0.2em 0.25em;
|
||||
background-color: #007599;
|
||||
font-weight: bold;
|
||||
|
||||
&.no-catenary {
|
||||
background-color: #686868;
|
||||
}
|
||||
|
||||
&.internal {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&.speed {
|
||||
background-color: #404040;
|
||||
color: #cfcfcf;
|
||||
}
|
||||
|
||||
&.sbl {
|
||||
color: var(--clr-primary);
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-radius: 0 0.5em 0.5em 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-radius: 0.5em 0 0 0.5em;
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
border-radius: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<section class="info-routes" v-if="station.generalInfo">
|
||||
<div class="routes one-way" v-if="station.generalInfo.routes.oneWay.length > 0">
|
||||
<b>{{ $t('scenery.one-way-routes') }}</b>
|
||||
|
||||
<ul class="routes-list">
|
||||
<li
|
||||
v-for="route in station.generalInfo.routes.oneWay"
|
||||
:key="route.name"
|
||||
@click="setActiveShowLength(route.name)"
|
||||
>
|
||||
<span :class="{ 'no-catenary': !route.catenary, internal: route.isInternal }">
|
||||
{{ route.name }}</span
|
||||
>
|
||||
<span v-if="route.speed" class="speed">
|
||||
{{ activeShowLength.includes(route.name) ? route.length + 'm' : route.speed }}
|
||||
</span>
|
||||
<span v-if="route.SBL" class="sbl">SBL</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="routes two-way" v-if="station.generalInfo.routes.twoWay.length > 0">
|
||||
<b>{{ $t('scenery.two-way-routes') }}</b>
|
||||
|
||||
<ul class="routes-list">
|
||||
<li
|
||||
v-for="route in station.generalInfo.routes.twoWay"
|
||||
:key="route.name"
|
||||
@click="setActiveShowLength(route.name)"
|
||||
>
|
||||
<span :class="{ 'no-catenary': !route.catenary, internal: route.isInternal }">{{
|
||||
route.name
|
||||
}}</span>
|
||||
<span v-if="route.speed" class="speed">
|
||||
{{ activeShowLength.includes(route.name) ? route.length + 'm' : route.speed }}
|
||||
</span>
|
||||
<span v-if="route.SBL" class="sbl">SBL</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setActiveShowLength(name: string) {
|
||||
if (this.activeShowLength.includes(name))
|
||||
this.activeShowLength.splice(this.activeShowLength.indexOf(name), 1);
|
||||
else this.activeShowLength.push(name);
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
activeShowLength: [] as string[]
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.info-routes {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.routes {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
padding: 0.25em;
|
||||
}
|
||||
|
||||
ul.routes-list {
|
||||
margin: 0.45em 0.25em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
li {
|
||||
margin: 0.5em 0.25em;
|
||||
cursor: pointer;
|
||||
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
|
||||
span {
|
||||
padding: 0.2em 0.25em;
|
||||
background-color: #007599;
|
||||
font-weight: bold;
|
||||
|
||||
&.no-catenary {
|
||||
background-color: #686868;
|
||||
}
|
||||
|
||||
&.internal {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&.speed {
|
||||
background-color: #404040;
|
||||
color: #cfcfcf;
|
||||
}
|
||||
|
||||
&.sbl {
|
||||
color: var(--clr-primary);
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-radius: 0 0.5em 0.5em 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-radius: 0.5em 0 0 0.5em;
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
border-radius: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,65 +1,71 @@
|
||||
<template>
|
||||
<section class="info-spawn-list">
|
||||
<h3 class="spawn-header section-header">
|
||||
<img :src="getIcon('spawn')" alt="icon-spawn" />
|
||||
{{ $t('scenery.spawns') }}
|
||||
<span class="text--primary">{{ station.onlineInfo?.spawns.length || '0' }}</span>
|
||||
</h3>
|
||||
|
||||
<span v-if="station.onlineInfo">
|
||||
<span
|
||||
class="badge spawn"
|
||||
v-for="(spawn, i) in sortedSpawns"
|
||||
:key="spawn.spawnName + station.onlineInfo?.dispatcherName + i"
|
||||
:data-electrified="spawn.isElectrified"
|
||||
>
|
||||
<span class="spawn_name">{{ spawn.spawnName }}</span>
|
||||
<span class="spawn_length">{{ spawn.spawnLength }}m</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="badge spawn badge-none" v-if="!station.onlineInfo || station.onlineInfo.spawns.length == 0"
|
||||
>{{ $t('scenery.no-spawns') }}
|
||||
</span>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [imageMixin],
|
||||
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
sortedSpawns() {
|
||||
return this.station.onlineInfo?.spawns.sort((s1, s2) => (s1.spawnLength < s2.spawnLength ? 1 : -1));
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../../styles/variables.scss';
|
||||
|
||||
.spawn {
|
||||
color: white;
|
||||
|
||||
&_length {
|
||||
background-color: #404040;
|
||||
color: #cfcfcf;
|
||||
}
|
||||
|
||||
&[data-electrified='true'] > &_name {
|
||||
background-color: #007599;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<section class="info-spawn-list">
|
||||
<h3 class="spawn-header section-header">
|
||||
<img :src="getIcon('spawn')" alt="icon-spawn" />
|
||||
{{ $t('scenery.spawns') }}
|
||||
<span class="text--primary">{{ station.onlineInfo?.spawns.length || '0' }}</span>
|
||||
</h3>
|
||||
|
||||
<span v-if="station.onlineInfo">
|
||||
<span
|
||||
class="badge spawn"
|
||||
v-for="(spawn, i) in sortedSpawns"
|
||||
:key="spawn.spawnName + station.onlineInfo?.dispatcherName + i"
|
||||
:data-electrified="spawn.isElectrified"
|
||||
>
|
||||
<span class="spawn_name">{{ spawn.spawnName }}</span>
|
||||
<span class="spawn_length">{{ spawn.spawnLength }}m</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="badge spawn badge-none"
|
||||
v-if="!station.onlineInfo || station.onlineInfo.spawns.length == 0"
|
||||
>{{ $t('scenery.no-spawns') }}
|
||||
</span>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [imageMixin],
|
||||
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
sortedSpawns() {
|
||||
if (!this.station.onlineInfo) return [];
|
||||
|
||||
return [...this.station.onlineInfo.spawns].sort((s1, s2) =>
|
||||
s1.spawnLength < s2.spawnLength ? 1 : -1
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../../styles/variables.scss';
|
||||
|
||||
.spawn {
|
||||
color: white;
|
||||
|
||||
&_length {
|
||||
background-color: #404040;
|
||||
color: #cfcfcf;
|
||||
}
|
||||
|
||||
&[data-electrified='true'] > &_name {
|
||||
background-color: #007599;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -23,7 +23,10 @@
|
||||
<span style="color: #eee">{{ station.onlineInfo?.scheduledTrains?.length || '0' }}</span>
|
||||
/
|
||||
<span style="color: #bbb"
|
||||
>{{ station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed).length || '0' }}
|
||||
>{{
|
||||
station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed)
|
||||
.length || '0'
|
||||
}}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
@@ -31,7 +34,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
|
||||
@@ -39,10 +42,10 @@ export default defineComponent({
|
||||
mixins: [imageMixin],
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,131 +1,136 @@
|
||||
<template>
|
||||
<section class="info-user-list">
|
||||
<h3 class="user-header section-header">
|
||||
<img :src="getIcon('user')" alt="icon-user" />
|
||||
{{ $t('scenery.users') }}
|
||||
<span class="text--primary">{{ station.onlineInfo?.currentUsers || '0' }}</span
|
||||
> / <span class="text--primary">{{ station.onlineInfo?.maxUsers || '0' }}</span>
|
||||
</h3>
|
||||
|
||||
<div
|
||||
v-for="(train, i) in computedStationTrains"
|
||||
class="badge user"
|
||||
:class="train.stopStatus"
|
||||
:key="train.trainId"
|
||||
tabindex="0"
|
||||
@click.prevent="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||
@keydown.enter="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||
>
|
||||
<span class="user_train">{{ train.trainNo }}</span>
|
||||
<span class="user_name">{{ train.driverName }}</span>
|
||||
</div>
|
||||
|
||||
<div class="badge user badge-none" v-if="!computedStationTrains || computedStationTrains.length == 0">
|
||||
{{ $t('scenery.no-users') }}
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
||||
import routerMixin from '../../../mixins/routerMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
import { useStore } from '../../../store/store';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [routerMixin, imageMixin, modalTrainMixin],
|
||||
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const store = useStore();
|
||||
|
||||
const computedStationTrains = computed(() => {
|
||||
if (!props.station) return [];
|
||||
|
||||
const station = props.station as Station;
|
||||
if (!station.onlineInfo) return [];
|
||||
if (!station.onlineInfo.stationTrains) return [];
|
||||
|
||||
return station.onlineInfo.stationTrains.map((train) => {
|
||||
const scheduledTrainStatus = station.onlineInfo?.scheduledTrains?.find((st) => st.trainNo === train.trainNo);
|
||||
|
||||
return {
|
||||
...train,
|
||||
stopStatus: scheduledTrainStatus?.stopStatus || 'no-timetable',
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
return { computedStationTrains, store };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$no-timetable: #aaa;
|
||||
$departed: springgreen;
|
||||
$stopped: #ffa600;
|
||||
$online: gold;
|
||||
$terminated: salmon;
|
||||
$disconnected: slategray;
|
||||
|
||||
.info-user-list {
|
||||
width: 100%;
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.user {
|
||||
cursor: pointer;
|
||||
|
||||
&_train {
|
||||
color: black;
|
||||
background-color: $no-timetable;
|
||||
|
||||
transition: background-color 200ms;
|
||||
-ms-transition: background-color 200ms;
|
||||
-webkit-transition: background-color 200ms;
|
||||
}
|
||||
|
||||
&.no-timetable .user_train {
|
||||
background-color: $no-timetable;
|
||||
}
|
||||
|
||||
&.departed > &_train {
|
||||
background-color: $departed;
|
||||
}
|
||||
|
||||
&.stopped > &_train {
|
||||
background-color: $stopped;
|
||||
}
|
||||
|
||||
&.online > &_train {
|
||||
background-color: $online;
|
||||
}
|
||||
|
||||
&.terminated > &_train {
|
||||
background-color: $terminated;
|
||||
}
|
||||
|
||||
&.disconnected > &_train {
|
||||
background-color: $disconnected;
|
||||
}
|
||||
|
||||
&.offline {
|
||||
background: firebrick;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<section class="info-user-list">
|
||||
<h3 class="user-header section-header">
|
||||
<img :src="getIcon('user')" alt="icon-user" />
|
||||
{{ $t('scenery.users') }}
|
||||
<span class="text--primary">{{ station.onlineInfo?.currentUsers || '0' }}</span
|
||||
> / <span class="text--primary">{{ station.onlineInfo?.maxUsers || '0' }}</span>
|
||||
</h3>
|
||||
|
||||
<div
|
||||
v-for="train in computedStationTrains"
|
||||
class="badge user"
|
||||
:class="train.stopStatus"
|
||||
:key="train.trainId"
|
||||
tabindex="0"
|
||||
@click.prevent="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||
@keydown.enter="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||
>
|
||||
<span class="user_train">{{ train.trainNo }}</span>
|
||||
<span class="user_name">{{ train.driverName }}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="badge user badge-none"
|
||||
v-if="!computedStationTrains || computedStationTrains.length == 0"
|
||||
>
|
||||
{{ $t('scenery.no-users') }}
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent } from 'vue';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
||||
import routerMixin from '../../../mixins/routerMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
import { useStore } from '../../../store/store';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [routerMixin, imageMixin, modalTrainMixin],
|
||||
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const store = useStore();
|
||||
|
||||
const computedStationTrains = computed(() => {
|
||||
if (!props.station) return [];
|
||||
|
||||
const station = props.station as Station;
|
||||
if (!station.onlineInfo) return [];
|
||||
if (!station.onlineInfo.stationTrains) return [];
|
||||
|
||||
return station.onlineInfo.stationTrains.map((train) => {
|
||||
const scheduledTrainStatus = station.onlineInfo?.scheduledTrains?.find(
|
||||
(st) => st.trainNo === train.trainNo
|
||||
);
|
||||
|
||||
return {
|
||||
...train,
|
||||
stopStatus: scheduledTrainStatus?.stopStatus || 'no-timetable'
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
return { computedStationTrains, store };
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$no-timetable: #aaa;
|
||||
$departed: springgreen;
|
||||
$stopped: #ffa600;
|
||||
$online: gold;
|
||||
$terminated: salmon;
|
||||
$disconnected: slategray;
|
||||
|
||||
.info-user-list {
|
||||
width: 100%;
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.user {
|
||||
cursor: pointer;
|
||||
|
||||
&_train {
|
||||
color: black;
|
||||
background-color: $no-timetable;
|
||||
|
||||
transition: background-color 200ms;
|
||||
-ms-transition: background-color 200ms;
|
||||
-webkit-transition: background-color 200ms;
|
||||
}
|
||||
|
||||
&.no-timetable .user_train {
|
||||
background-color: $no-timetable;
|
||||
}
|
||||
|
||||
&.departed > &_train {
|
||||
background-color: $departed;
|
||||
}
|
||||
|
||||
&.stopped > &_train {
|
||||
background-color: $stopped;
|
||||
}
|
||||
|
||||
&.online > &_train {
|
||||
background-color: $online;
|
||||
}
|
||||
|
||||
&.terminated > &_train {
|
||||
background-color: $terminated;
|
||||
}
|
||||
|
||||
&.disconnected > &_train {
|
||||
background-color: $disconnected;
|
||||
}
|
||||
|
||||
&.offline {
|
||||
background: firebrick;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,457 +1,481 @@
|
||||
<template>
|
||||
<section class="scenery-timetable">
|
||||
<div class="timetable-header">
|
||||
<h3>
|
||||
<img :src="getIcon('timetable')" alt="icon-timetable" />
|
||||
<span>{{ $t('scenery.timetables') }}</span>
|
||||
|
||||
<span>
|
||||
<span class="text--primary">{{ station.onlineInfo?.scheduledTrains?.length || '0' }}</span>
|
||||
<span> / </span>
|
||||
<span class="text--grayed">
|
||||
{{ station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed).length || '0' }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="header_links">
|
||||
<a :href="`https://pragotron-td2.web.app/board?name=${station.name}`" target="_blank" :title="$t('scenery.pragotron-link')">
|
||||
<img :src="getIcon('pragotron')" alt="icon-pragotron" />
|
||||
</a>
|
||||
|
||||
<a :href="tabliceZbiorczeHref" target="_blank" :title="$t('scenery.tablice-link')">
|
||||
<img :src="getIcon('tablice', 'ico')" alt="icon-tablice" />
|
||||
</a>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<div class="timetable-checkpoints" v-if="station?.generalInfo?.checkpoints">
|
||||
<span v-for="(cp, i) in station.generalInfo.checkpoints" :key="i">
|
||||
{{ (i > 0 && '•') || '' }}
|
||||
|
||||
<button
|
||||
:key="cp.checkpointName"
|
||||
class="checkpoint_item"
|
||||
:class="{ current: chosenCheckpoint === cp.checkpointName }"
|
||||
@click="setCheckpoint(cp)"
|
||||
>
|
||||
{{ cp.checkpointName }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timetable-list">
|
||||
<div style="padding-bottom: 5em" v-if="store.dataStatuses.trains == 0 && computedScheduledTrains.length == 0">
|
||||
<Loading />
|
||||
</div>
|
||||
|
||||
<span class="timetable-item empty" v-else-if="computedScheduledTrains.length == 0 && !station.onlineInfo">
|
||||
{{ $t('scenery.offline') }}
|
||||
</span>
|
||||
|
||||
<span class="timetable-item empty" v-else-if="computedScheduledTrains.length == 0">
|
||||
{{ $t('scenery.no-timetables') }}
|
||||
</span>
|
||||
|
||||
<transition-group name="list-anim">
|
||||
<div
|
||||
class="timetable-item"
|
||||
v-for="(scheduledTrain, i) in computedScheduledTrains"
|
||||
:key="scheduledTrain.trainId"
|
||||
tabindex="0"
|
||||
@click.prevent.stop="selectModalTrain(scheduledTrain.trainId, $event.currentTarget)"
|
||||
@keydown.enter.prevent="selectModalTrain(scheduledTrain.trainId, $event.currentTarget)"
|
||||
>
|
||||
<span class="timetable-general">
|
||||
<span class="general-info">
|
||||
<span class="info-number">
|
||||
<strong>{{ scheduledTrain.category }}</strong>
|
||||
{{ scheduledTrain.trainNo }}
|
||||
|
||||
<span class="g-tooltip" v-if="scheduledTrain.stopInfo.comments">
|
||||
<img :src="getIcon('warning')" />
|
||||
<span class="content" v-html="scheduledTrain.stopInfo.comments"> </span>
|
||||
</span>
|
||||
</span>
|
||||
|
|
||||
<span>
|
||||
{{ scheduledTrain.driverName }}
|
||||
</span>
|
||||
|
||||
<div class="info-route">
|
||||
<strong>{{ scheduledTrain.beginsAt }} - {{ scheduledTrain.terminatesAt }}</strong>
|
||||
</div>
|
||||
|
||||
<ScheduledTrainStatus :scheduledTrain="scheduledTrain" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="timetable-schedule">
|
||||
<span class="schedule-arrival">
|
||||
<span class="arrival-time begins" v-if="scheduledTrain.stopInfo.beginsHere">
|
||||
{{ $t('timetables.begins') }}
|
||||
</span>
|
||||
|
||||
<span class="arrival-time" v-else>
|
||||
<div v-if="scheduledTrain.stopInfo.arrivalDelay == 0">
|
||||
<span>{{ timestampToString(scheduledTrain.stopInfo.arrivalTimestamp) }}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div>
|
||||
<s style="margin-right: 0.2em" class="text--grayed">{{ timestampToString(scheduledTrain.stopInfo.arrivalTimestamp) }}</s>
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{{ timestampToString(scheduledTrain.stopInfo.arrivalRealTimestamp) }}
|
||||
({{ scheduledTrain.stopInfo.arrivalDelay > 0 ? '+' : '' }}{{ scheduledTrain.stopInfo.arrivalDelay }})
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="schedule-stop">
|
||||
<span class="stop-connection">
|
||||
{{ scheduledTrain.arrivingLine }}
|
||||
</span>
|
||||
|
||||
<span class="stop-time">
|
||||
{{ scheduledTrain.stopInfo.stopTime || '' }}
|
||||
{{ scheduledTrain.stopInfo.stopTime ? scheduledTrain.stopInfo.stopType || 'pt' : '' }}
|
||||
</span>
|
||||
|
||||
<span class="stop-connection">
|
||||
{{ scheduledTrain.departureLine }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="schedule-departure">
|
||||
<span class="departure-time terminates" v-if="scheduledTrain.stopInfo.terminatesHere">
|
||||
{{ $t('timetables.terminates') }}
|
||||
</span>
|
||||
|
||||
<span class="departure-time" v-else>
|
||||
<div v-if="scheduledTrain.stopInfo.departureDelay == 0">
|
||||
<span>{{ timestampToString(scheduledTrain.stopInfo.departureTimestamp) }}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div>
|
||||
<s style="margin-right: 0.2em" class="text--grayed">{{ timestampToString(scheduledTrain.stopInfo.departureTimestamp) }}</s>
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{{ timestampToString(scheduledTrain.stopInfo.departureRealTimestamp) }}
|
||||
({{ scheduledTrain.stopInfo.departureDelay > 0 ? '+' : '' }}{{ scheduledTrain.stopInfo.departureDelay }})
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import SelectBox from '../Global/SelectBox.vue';
|
||||
import { computed, defineComponent, PropType, ref } from '@vue/runtime-core';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import TrainModal from '../Global/TrainModal.vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import routerMixin from '../../mixins/routerMixin';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { useStore } from '../../store/store';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||
import ScheduledTrainStatus from './ScheduledTrainStatus.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryTimetable',
|
||||
|
||||
components: { SelectBox, Loading, TrainModal, ScheduledTrainStatus },
|
||||
|
||||
mixins: [dateMixin, routerMixin, imageMixin, modalTrainMixin],
|
||||
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true,
|
||||
},
|
||||
|
||||
timetableOnly: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
listOpen: false,
|
||||
}),
|
||||
|
||||
mounted() {
|
||||
this.loadSelectedOption();
|
||||
},
|
||||
|
||||
activated() {
|
||||
this.loadSelectedOption();
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const route = useRoute();
|
||||
const currentURL = computed(() => `${location.origin}${route.fullPath}`);
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const chosenCheckpoint = ref(
|
||||
props.station?.generalInfo?.checkpoints?.length == 0 ? '' : props.station?.generalInfo?.checkpoints[0].checkpointName || null
|
||||
);
|
||||
|
||||
const computedScheduledTrains = computed(() => {
|
||||
if (!props.station) return [];
|
||||
|
||||
const station = props.station as Station;
|
||||
|
||||
let scheduledTrains =
|
||||
station.generalInfo?.checkpoints.find((cp) => cp.checkpointName === chosenCheckpoint.value)?.scheduledTrains ||
|
||||
station.onlineInfo?.scheduledTrains ||
|
||||
[];
|
||||
|
||||
if (!scheduledTrains) return [];
|
||||
|
||||
return (
|
||||
scheduledTrains.sort((a, b) => {
|
||||
if (a.stopStatusID > b.stopStatusID) return 1;
|
||||
if (a.stopStatusID < b.stopStatusID) return -1;
|
||||
|
||||
if (a.stopInfo.arrivalTimestamp > b.stopInfo.arrivalTimestamp) return 1;
|
||||
if (a.stopInfo.arrivalTimestamp < b.stopInfo.arrivalTimestamp) return -1;
|
||||
|
||||
return a.stopInfo.departureTimestamp > b.stopInfo.departureTimestamp ? 1 : -1;
|
||||
}) || []
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
currentURL,
|
||||
chosenCheckpoint,
|
||||
computedScheduledTrains,
|
||||
store,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
tabliceZbiorczeHref() {
|
||||
let url = `https://tablice-td2.web.app/?station=${this.station.name}`;
|
||||
if (this.chosenCheckpoint) url += `&checkpoint=${this.chosenCheckpoint}`;
|
||||
|
||||
return url;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadSelectedOption() {
|
||||
if (!this.station) return;
|
||||
if (!this.station.generalInfo) return;
|
||||
if (!this.station.generalInfo.checkpoints) return;
|
||||
if (this.station.generalInfo.checkpoints.length == 0) return;
|
||||
|
||||
if (this.chosenCheckpoint != '') return;
|
||||
|
||||
this.chosenCheckpoint = this.station.generalInfo.checkpoints[0].checkpointName;
|
||||
},
|
||||
|
||||
setCheckpoint(cp: { checkpointName: string }) {
|
||||
this.chosenCheckpoint = cp.checkpointName;
|
||||
},
|
||||
|
||||
showTimetableOnlyView() {
|
||||
this.$router.push(`${this.$route.fullPath}&timetableOnly=1`);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/variables.scss';
|
||||
@import '../../styles/animations.scss';
|
||||
|
||||
.scenery-timetable {
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
|
||||
.timetable-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 99;
|
||||
|
||||
background-color: #181818;
|
||||
|
||||
padding: 0.5em;
|
||||
|
||||
img {
|
||||
width: 25px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
h3 {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
|
||||
gap: 0.5em;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
}
|
||||
|
||||
.header_links {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.timetable {
|
||||
&-count {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
&-item {
|
||||
margin: 0.5em auto;
|
||||
padding: 0.5em;
|
||||
max-width: 1100px;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.2em 0.5em;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
background: #353535;
|
||||
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
|
||||
&.empty {
|
||||
padding: 1rem;
|
||||
font-size: 1.2em;
|
||||
color: #bbb;
|
||||
}
|
||||
}
|
||||
|
||||
&-general {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&-schedule {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.2em;
|
||||
align-items: center;
|
||||
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.timetable-list {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.timetable-checkpoints {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
flex-wrap: wrap;
|
||||
font-size: 1.1em;
|
||||
|
||||
margin-top: 0.5em;
|
||||
|
||||
button.checkpoint_item {
|
||||
color: #aaa;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.checkpoint_item.current {
|
||||
font-weight: bold;
|
||||
color: $accentCol;
|
||||
}
|
||||
}
|
||||
|
||||
.general-info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.info-number {
|
||||
color: $accentCol;
|
||||
}
|
||||
|
||||
.info-route {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.g-tooltip > .content {
|
||||
z-index: 100;
|
||||
color: white;
|
||||
|
||||
left: 110%;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 1.1em;
|
||||
}
|
||||
}
|
||||
|
||||
.schedule {
|
||||
&-arrival,
|
||||
&-departure {
|
||||
font-size: 1.15em;
|
||||
}
|
||||
|
||||
&-stop {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.5em;
|
||||
align-items: end;
|
||||
|
||||
.stop-connection {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.stop-time {
|
||||
position: relative;
|
||||
inline-size: max-content;
|
||||
align-self: center;
|
||||
font-size: 0.9em;
|
||||
|
||||
color: $accentCol;
|
||||
|
||||
&::after {
|
||||
content: '\027F6';
|
||||
display: block;
|
||||
font-size: 2.2em;
|
||||
line-height: 0.65em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.arrival-time.begins,
|
||||
.departure-time.terminates {
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
@include smallScreen {
|
||||
.timetable-item {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<section class="scenery-timetable">
|
||||
<div class="timetable-header">
|
||||
<h3>
|
||||
<img :src="getIcon('timetable')" alt="icon-timetable" />
|
||||
<span>{{ $t('scenery.timetables') }}</span>
|
||||
|
||||
<span>
|
||||
<span class="text--primary">{{
|
||||
station.onlineInfo?.scheduledTrains?.length || '0'
|
||||
}}</span>
|
||||
<span> / </span>
|
||||
<span class="text--grayed">
|
||||
{{
|
||||
station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed)
|
||||
.length || '0'
|
||||
}}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="header_links">
|
||||
<a
|
||||
:href="`https://pragotron-td2.web.app/board?name=${station.name}`"
|
||||
target="_blank"
|
||||
:title="$t('scenery.pragotron-link')"
|
||||
>
|
||||
<img :src="getIcon('pragotron')" alt="icon-pragotron" />
|
||||
</a>
|
||||
|
||||
<a :href="tabliceZbiorczeHref" target="_blank" :title="$t('scenery.tablice-link')">
|
||||
<img :src="getIcon('tablice', 'ico')" alt="icon-tablice" />
|
||||
</a>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<div class="timetable-checkpoints" v-if="station?.generalInfo?.checkpoints">
|
||||
<span v-for="(cp, i) in station.generalInfo.checkpoints" :key="i">
|
||||
{{ (i > 0 && '•') || '' }}
|
||||
|
||||
<button
|
||||
:key="cp.checkpointName"
|
||||
class="checkpoint_item"
|
||||
:class="{ current: chosenCheckpoint === cp.checkpointName }"
|
||||
@click="setCheckpoint(cp)"
|
||||
>
|
||||
{{ cp.checkpointName }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timetable-list">
|
||||
<div
|
||||
style="padding-bottom: 5em"
|
||||
v-if="store.dataStatuses.trains == 0 && computedScheduledTrains.length == 0"
|
||||
>
|
||||
<Loading />
|
||||
</div>
|
||||
|
||||
<span
|
||||
class="timetable-item empty"
|
||||
v-else-if="computedScheduledTrains.length == 0 && !station.onlineInfo"
|
||||
>
|
||||
{{ $t('scenery.offline') }}
|
||||
</span>
|
||||
|
||||
<span class="timetable-item empty" v-else-if="computedScheduledTrains.length == 0">
|
||||
{{ $t('scenery.no-timetables') }}
|
||||
</span>
|
||||
|
||||
<transition-group name="list-anim">
|
||||
<div
|
||||
class="timetable-item"
|
||||
v-for="scheduledTrain in computedScheduledTrains"
|
||||
:key="scheduledTrain.trainId"
|
||||
tabindex="0"
|
||||
@click.prevent.stop="selectModalTrain(scheduledTrain.trainId, $event.currentTarget)"
|
||||
@keydown.enter.prevent="selectModalTrain(scheduledTrain.trainId, $event.currentTarget)"
|
||||
>
|
||||
<span class="timetable-general">
|
||||
<span class="general-info">
|
||||
<span class="info-number">
|
||||
<strong>{{ scheduledTrain.category }}</strong>
|
||||
{{ scheduledTrain.trainNo }}
|
||||
|
||||
<span class="g-tooltip" v-if="scheduledTrain.stopInfo.comments">
|
||||
<img :src="getIcon('warning')" />
|
||||
<span class="content" v-html="scheduledTrain.stopInfo.comments"> </span>
|
||||
</span>
|
||||
</span>
|
||||
|
|
||||
<span>
|
||||
{{ scheduledTrain.driverName }}
|
||||
</span>
|
||||
|
||||
<div class="info-route">
|
||||
<strong>{{ scheduledTrain.beginsAt }} - {{ scheduledTrain.terminatesAt }}</strong>
|
||||
</div>
|
||||
|
||||
<ScheduledTrainStatus :scheduledTrain="scheduledTrain" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="timetable-schedule">
|
||||
<span class="schedule-arrival">
|
||||
<span class="arrival-time begins" v-if="scheduledTrain.stopInfo.beginsHere">
|
||||
{{ $t('timetables.begins') }}
|
||||
</span>
|
||||
|
||||
<span class="arrival-time" v-else>
|
||||
<div v-if="scheduledTrain.stopInfo.arrivalDelay == 0">
|
||||
<span>{{ timestampToString(scheduledTrain.stopInfo.arrivalTimestamp) }}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div>
|
||||
<s style="margin-right: 0.2em" class="text--grayed">{{
|
||||
timestampToString(scheduledTrain.stopInfo.arrivalTimestamp)
|
||||
}}</s>
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{{ timestampToString(scheduledTrain.stopInfo.arrivalRealTimestamp) }}
|
||||
({{ scheduledTrain.stopInfo.arrivalDelay > 0 ? '+' : ''
|
||||
}}{{ scheduledTrain.stopInfo.arrivalDelay }})
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="schedule-stop">
|
||||
<span class="stop-connection">
|
||||
{{ scheduledTrain.arrivingLine }}
|
||||
</span>
|
||||
|
||||
<span class="stop-time">
|
||||
{{ scheduledTrain.stopInfo.stopTime || '' }}
|
||||
{{
|
||||
scheduledTrain.stopInfo.stopTime ? scheduledTrain.stopInfo.stopType || 'pt' : ''
|
||||
}}
|
||||
</span>
|
||||
|
||||
<span class="stop-connection">
|
||||
{{ scheduledTrain.departureLine }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="schedule-departure">
|
||||
<span class="departure-time terminates" v-if="scheduledTrain.stopInfo.terminatesHere">
|
||||
{{ $t('timetables.terminates') }}
|
||||
</span>
|
||||
|
||||
<span class="departure-time" v-else>
|
||||
<div v-if="scheduledTrain.stopInfo.departureDelay == 0">
|
||||
<span>{{ timestampToString(scheduledTrain.stopInfo.departureTimestamp) }}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div>
|
||||
<s style="margin-right: 0.2em" class="text--grayed">{{
|
||||
timestampToString(scheduledTrain.stopInfo.departureTimestamp)
|
||||
}}</s>
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{{ timestampToString(scheduledTrain.stopInfo.departureRealTimestamp) }}
|
||||
({{ scheduledTrain.stopInfo.departureDelay > 0 ? '+' : ''
|
||||
}}{{ scheduledTrain.stopInfo.departureDelay }})
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import routerMixin from '../../mixins/routerMixin';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { useStore } from '../../store/store';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||
import ScheduledTrainStatus from './ScheduledTrainStatus.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryTimetable',
|
||||
|
||||
components: { Loading, ScheduledTrainStatus },
|
||||
|
||||
mixins: [dateMixin, routerMixin, imageMixin, modalTrainMixin],
|
||||
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
},
|
||||
|
||||
timetableOnly: {
|
||||
type: Boolean
|
||||
}
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
listOpen: false
|
||||
}),
|
||||
|
||||
mounted() {
|
||||
this.loadSelectedOption();
|
||||
},
|
||||
|
||||
activated() {
|
||||
this.loadSelectedOption();
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const route = useRoute();
|
||||
const currentURL = computed(() => `${location.origin}${route.fullPath}`);
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const chosenCheckpoint = ref(
|
||||
props.station?.generalInfo?.checkpoints?.length == 0
|
||||
? ''
|
||||
: props.station?.generalInfo?.checkpoints[0].checkpointName || null
|
||||
);
|
||||
|
||||
const computedScheduledTrains = computed(() => {
|
||||
if (!props.station) return [];
|
||||
|
||||
const station = props.station as Station;
|
||||
|
||||
let scheduledTrains =
|
||||
station.generalInfo?.checkpoints.find((cp) => cp.checkpointName === chosenCheckpoint.value)
|
||||
?.scheduledTrains ||
|
||||
station.onlineInfo?.scheduledTrains ||
|
||||
[];
|
||||
|
||||
if (!scheduledTrains) return [];
|
||||
|
||||
return (
|
||||
scheduledTrains.sort((a, b) => {
|
||||
if (a.stopStatusID > b.stopStatusID) return 1;
|
||||
if (a.stopStatusID < b.stopStatusID) return -1;
|
||||
|
||||
if (a.stopInfo.arrivalTimestamp > b.stopInfo.arrivalTimestamp) return 1;
|
||||
if (a.stopInfo.arrivalTimestamp < b.stopInfo.arrivalTimestamp) return -1;
|
||||
|
||||
return a.stopInfo.departureTimestamp > b.stopInfo.departureTimestamp ? 1 : -1;
|
||||
}) || []
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
currentURL,
|
||||
chosenCheckpoint,
|
||||
computedScheduledTrains,
|
||||
store
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
tabliceZbiorczeHref() {
|
||||
let url = `https://tablice-td2.web.app/?station=${this.station.name}`;
|
||||
if (this.chosenCheckpoint) url += `&checkpoint=${this.chosenCheckpoint}`;
|
||||
|
||||
return url;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadSelectedOption() {
|
||||
if (!this.station) return;
|
||||
if (!this.station.generalInfo) return;
|
||||
if (!this.station.generalInfo.checkpoints) return;
|
||||
if (this.station.generalInfo.checkpoints.length == 0) return;
|
||||
|
||||
if (this.chosenCheckpoint != '') return;
|
||||
|
||||
this.chosenCheckpoint = this.station.generalInfo.checkpoints[0].checkpointName;
|
||||
},
|
||||
|
||||
setCheckpoint(cp: { checkpointName: string }) {
|
||||
this.chosenCheckpoint = cp.checkpointName;
|
||||
},
|
||||
|
||||
showTimetableOnlyView() {
|
||||
this.$router.push(`${this.$route.fullPath}&timetableOnly=1`);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/variables.scss';
|
||||
@import '../../styles/animations.scss';
|
||||
|
||||
.scenery-timetable {
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
|
||||
.timetable-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 99;
|
||||
|
||||
background-color: #181818;
|
||||
|
||||
padding: 0.5em;
|
||||
|
||||
img {
|
||||
width: 25px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
h3 {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
|
||||
gap: 0.5em;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
}
|
||||
|
||||
.header_links {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.timetable {
|
||||
&-count {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
&-item {
|
||||
margin: 0.5em auto;
|
||||
padding: 0.5em;
|
||||
max-width: 1100px;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.2em 0.5em;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
background: #353535;
|
||||
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
|
||||
&.empty {
|
||||
padding: 1rem;
|
||||
font-size: 1.2em;
|
||||
color: #bbb;
|
||||
}
|
||||
}
|
||||
|
||||
&-general {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&-schedule {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.2em;
|
||||
align-items: center;
|
||||
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.timetable-list {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.timetable-checkpoints {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
flex-wrap: wrap;
|
||||
font-size: 1.1em;
|
||||
|
||||
margin-top: 0.5em;
|
||||
|
||||
button.checkpoint_item {
|
||||
color: #aaa;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.checkpoint_item.current {
|
||||
font-weight: bold;
|
||||
color: $accentCol;
|
||||
}
|
||||
}
|
||||
|
||||
.general-info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.info-number {
|
||||
color: $accentCol;
|
||||
}
|
||||
|
||||
.info-route {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.g-tooltip > .content {
|
||||
z-index: 100;
|
||||
color: white;
|
||||
|
||||
left: 110%;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 1.1em;
|
||||
}
|
||||
}
|
||||
|
||||
.schedule {
|
||||
&-arrival,
|
||||
&-departure {
|
||||
font-size: 1.15em;
|
||||
}
|
||||
|
||||
&-stop {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.5em;
|
||||
align-items: end;
|
||||
|
||||
.stop-connection {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.stop-time {
|
||||
position: relative;
|
||||
inline-size: max-content;
|
||||
align-self: center;
|
||||
font-size: 0.9em;
|
||||
|
||||
color: $accentCol;
|
||||
|
||||
&::after {
|
||||
content: '\027F6';
|
||||
display: block;
|
||||
font-size: 2.2em;
|
||||
line-height: 0.65em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.arrival-time.begins,
|
||||
.departure-time.terminates {
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
@include smallScreen {
|
||||
.timetable-item {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,110 +1,117 @@
|
||||
<template>
|
||||
<section class="scenery-table-section">
|
||||
<Loading v-if="dataStatus != DataStatus.Loaded" />
|
||||
<div class="no-history" v-else-if="historyList.length == 0">{{ $t('scenery.history-list-empty') }}</div>
|
||||
|
||||
<table class="scenery-history-table" v-else>
|
||||
<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>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr v-for="historyItem in historyList">
|
||||
<td>
|
||||
<router-link :to="`/journal/timetables?timetableId=${historyItem.id}`">#{{ historyItem.id }}</router-link>
|
||||
</td>
|
||||
<td>
|
||||
<b class="text--primary">{{ historyItem.trainCategoryCode }}</b> <br />
|
||||
{{ historyItem.trainNo }}
|
||||
</td>
|
||||
<td>{{ historyItem.route.replace('|', ' -> ') }}</td>
|
||||
<td>{{ historyItem.driverName }}</td>
|
||||
<td>
|
||||
<router-link
|
||||
v-if="historyItem.authorName"
|
||||
:to="`/journal/timetables?authorName=${historyItem.authorName}`"
|
||||
>{{ historyItem.authorName }}
|
||||
</router-link>
|
||||
<i v-else>{{ $t('scenery.timetable-author-unknown') }}</i>
|
||||
</td>
|
||||
<td>
|
||||
<b>{{ localeDay(historyItem.beginDate, $i18n.locale) }}</b>
|
||||
{{ localeTime(historyItem.beginDate, $i18n.locale) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<div class="bottom-info">
|
||||
<button class="btn btn--option" v-if="historyList.length > 0" @click="navigateToHistory()">
|
||||
{{ $t('scenery.bottom-info') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import axios from 'axios';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||
import { TimetableHistory, SceneryTimetableHistory } from '../../scripts/interfaces/api/TimetablesAPIData';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryTimetablesHistory',
|
||||
mixins: [dateMixin, listObserverMixin],
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
historyList: [] as TimetableHistory[],
|
||||
dataStatus: DataStatus.Loading,
|
||||
DataStatus,
|
||||
};
|
||||
},
|
||||
|
||||
async activated() {
|
||||
const fetchedHistory = await this.fetchAPIData();
|
||||
if (fetchedHistory) this.historyList = fetchedHistory.timetables;
|
||||
},
|
||||
|
||||
methods: {
|
||||
async fetchAPIData(countFrom = 0, countLimit = 15): Promise<SceneryTimetableHistory | null> {
|
||||
try {
|
||||
const requestString = `${URLs.stacjownikAPI}/api/getIssuedTimetables?name=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||
const historyAPIData: SceneryTimetableHistory = await (await axios.get(requestString)).data;
|
||||
|
||||
this.dataStatus = DataStatus.Loaded;
|
||||
return historyAPIData;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
navigateToHistory() {
|
||||
this.$router.push(`/journal/timetables?issuedFrom=${this.station.name}`);
|
||||
},
|
||||
},
|
||||
components: { Loading },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/sceneryViewTables.scss';
|
||||
</style>
|
||||
<template>
|
||||
<section class="scenery-table-section">
|
||||
<Loading v-if="dataStatus != DataStatus.Loaded" />
|
||||
<div class="no-history" v-else-if="historyList.length == 0">
|
||||
{{ $t('scenery.history-list-empty') }}
|
||||
</div>
|
||||
|
||||
<table class="scenery-history-table" v-else>
|
||||
<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>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr v-for="historyItem in historyList" :key="historyItem.id">
|
||||
<td>
|
||||
<router-link :to="`/journal/timetables?timetableId=${historyItem.id}`"
|
||||
>#{{ historyItem.id }}</router-link
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<b class="text--primary">{{ historyItem.trainCategoryCode }}</b> <br />
|
||||
{{ historyItem.trainNo }}
|
||||
</td>
|
||||
<td>{{ historyItem.route.replace('|', ' -> ') }}</td>
|
||||
<td>{{ historyItem.driverName }}</td>
|
||||
<td>
|
||||
<router-link
|
||||
v-if="historyItem.authorName"
|
||||
:to="`/journal/timetables?authorName=${historyItem.authorName}`"
|
||||
>{{ historyItem.authorName }}
|
||||
</router-link>
|
||||
<i v-else>{{ $t('scenery.timetable-author-unknown') }}</i>
|
||||
</td>
|
||||
<td>
|
||||
<b>{{ localeDay(historyItem.beginDate, $i18n.locale) }}</b>
|
||||
{{ localeTime(historyItem.beginDate, $i18n.locale) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<div class="bottom-info">
|
||||
<button class="btn btn--option" v-if="historyList.length > 0" @click="navigateToHistory()">
|
||||
{{ $t('scenery.bottom-info') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import axios from 'axios';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||
import {
|
||||
TimetableHistory,
|
||||
SceneryTimetableHistory
|
||||
} from '../../scripts/interfaces/api/TimetablesAPIData';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryTimetablesHistory',
|
||||
mixins: [dateMixin, listObserverMixin],
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
historyList: [] as TimetableHistory[],
|
||||
dataStatus: DataStatus.Loading,
|
||||
DataStatus
|
||||
};
|
||||
},
|
||||
|
||||
async activated() {
|
||||
const fetchedHistory = await this.fetchAPIData();
|
||||
if (fetchedHistory) this.historyList = fetchedHistory.timetables;
|
||||
},
|
||||
|
||||
methods: {
|
||||
async fetchAPIData(countFrom = 0, countLimit = 15): Promise<SceneryTimetableHistory | null> {
|
||||
try {
|
||||
const requestString = `${URLs.stacjownikAPI}/api/getIssuedTimetables?name=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||
const historyAPIData: SceneryTimetableHistory = await (await axios.get(requestString)).data;
|
||||
|
||||
this.dataStatus = DataStatus.Loaded;
|
||||
return historyAPIData;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
navigateToHistory() {
|
||||
this.$router.push(`/journal/timetables?issuedFrom=${this.station.name}`);
|
||||
}
|
||||
},
|
||||
components: { Loading }
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/sceneryViewTables.scss';
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<div class="general-status">
|
||||
<span :class="computedScheduledTrain.stopStatus" :title="computedScheduledTrain.stopStatusDescription">
|
||||
<span
|
||||
:class="computedScheduledTrain.stopStatus"
|
||||
:title="computedScheduledTrain.stopStatusDescription"
|
||||
>
|
||||
{{ computedScheduledTrain.stopStatusIndicator }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -19,16 +22,21 @@ export default defineComponent({
|
||||
props: {
|
||||
scheduledTrain: {
|
||||
type: Object as PropType<ScheduledTrain>,
|
||||
required: true,
|
||||
},
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
computedScheduledTrain(): ScheduledTrainComp {
|
||||
const { prevDepartureLine, prevStationName, stopStatus, nextArrivalLine, nextStationName } = this.scheduledTrain;
|
||||
const { prevDepartureLine, prevStationName, stopStatus, nextArrivalLine, nextStationName } =
|
||||
this.scheduledTrain;
|
||||
|
||||
const prevDepartureIndicator = prevDepartureLine ? `(${prevDepartureLine}) ${prevStationName}` : '---';
|
||||
const nextArrivalIndicator = nextArrivalLine ? `(${nextArrivalLine}) ${nextStationName}` : '---';
|
||||
const prevDepartureIndicator = prevDepartureLine
|
||||
? `(${prevDepartureLine}) ${prevStationName}`
|
||||
: '---';
|
||||
const nextArrivalIndicator = nextArrivalLine
|
||||
? `(${nextArrivalLine}) ${nextStationName}`
|
||||
: '---';
|
||||
|
||||
let stopStatusDescription = '',
|
||||
stopStatusIndicator = '';
|
||||
@@ -36,7 +44,10 @@ export default defineComponent({
|
||||
switch (stopStatus) {
|
||||
case StopStatus.arriving:
|
||||
stopStatusIndicator = `${this.$t('timetables.from')}: ${prevDepartureIndicator}`;
|
||||
stopStatusDescription = this.$t('timetables.desc-arriving', { prevStationName, prevDepartureLine });
|
||||
stopStatusDescription = this.$t('timetables.desc-arriving', {
|
||||
prevStationName,
|
||||
prevDepartureLine
|
||||
});
|
||||
break;
|
||||
|
||||
case StopStatus.online:
|
||||
@@ -51,12 +62,18 @@ export default defineComponent({
|
||||
|
||||
case StopStatus.departed:
|
||||
stopStatusIndicator = `${this.$t('timetables.to')}: ${nextArrivalIndicator}`;
|
||||
stopStatusDescription = this.$t('timetables.desc-departed', { nextStationName, nextArrivalLine });
|
||||
stopStatusDescription = this.$t('timetables.desc-departed', {
|
||||
nextStationName,
|
||||
nextArrivalLine
|
||||
});
|
||||
break;
|
||||
|
||||
case StopStatus['departed-away']:
|
||||
stopStatusIndicator = `${this.$t('timetables.to')}: ${nextArrivalIndicator}`;
|
||||
stopStatusDescription = this.$t('timetables.desc-departed-away', { nextStationName, nextArrivalLine });
|
||||
stopStatusDescription = this.$t('timetables.desc-departed-away', {
|
||||
nextStationName,
|
||||
nextArrivalLine
|
||||
});
|
||||
break;
|
||||
|
||||
case StopStatus.terminated:
|
||||
@@ -70,10 +87,10 @@ export default defineComponent({
|
||||
return {
|
||||
...this.scheduledTrain,
|
||||
stopStatusDescription,
|
||||
stopStatusIndicator,
|
||||
stopStatusIndicator
|
||||
};
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -110,4 +127,3 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user