mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 05:18:11 +00:00
refactor: optimization of train schedules
This commit is contained in:
@@ -60,10 +60,7 @@ export default defineComponent({
|
||||
htmlChangelog() {
|
||||
if (this.mainStore.appUpdate == null) return '';
|
||||
|
||||
const x = converter.makeHtml(this.mainStore.appUpdate.changelog);
|
||||
console.log(x);
|
||||
|
||||
return x;
|
||||
return converter.makeHtml(this.mainStore.appUpdate.changelog);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
<div class="info-lists">
|
||||
<!-- user list -->
|
||||
<SceneryInfoUserList :onlineScenery="onlineScenery" />
|
||||
<SceneryInfoUserList :onlineScenery="onlineScenery" :station="station" />
|
||||
|
||||
<!-- spawn list -->
|
||||
<SceneryInfoSpawnList :onlineScenery="onlineScenery" />
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
</li>
|
||||
|
||||
<li
|
||||
v-for="train in onlineScenery?.stationTrains"
|
||||
v-for="{ train, status } in stationTrains"
|
||||
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)"
|
||||
:key="train.id"
|
||||
:data-status="status"
|
||||
@click.prevent="selectModalTrain(train.id, $event.currentTarget)"
|
||||
@keydown.enter="selectModalTrain(train.id, $event.currentTarget)"
|
||||
>
|
||||
<span class="user_train">{{ train.trainNo }}</span>
|
||||
<span class="user_name">{{ train.driverName }}</span>
|
||||
@@ -32,7 +32,9 @@
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
||||
import routerMixin from '../../../mixins/routerMixin';
|
||||
import { ActiveScenery } from '../../../typings/common';
|
||||
import { ActiveScenery, Station, StopStatus } from '../../../typings/common';
|
||||
import { getTrainStopStatus } from '../utils';
|
||||
import { useMainStore } from '../../../store/mainStore';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [routerMixin, modalTrainMixin],
|
||||
@@ -41,6 +43,38 @@ export default defineComponent({
|
||||
onlineScenery: {
|
||||
type: Object as PropType<ActiveScenery>,
|
||||
required: false
|
||||
},
|
||||
station: {
|
||||
type: Object as PropType<Station>
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
mainStore: useMainStore()
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
stationTrains() {
|
||||
if (!this.onlineScenery) return;
|
||||
|
||||
const name = this.station?.generalInfo?.checkpoints[0] ?? this.onlineScenery.name;
|
||||
|
||||
return this.onlineScenery.stationTrains.map((train) => {
|
||||
const stop = train.timetableData?.followingStops.find(
|
||||
(stop) => stop.stopNameRAW.toLowerCase() == name.toLowerCase()
|
||||
);
|
||||
|
||||
const status = stop
|
||||
? getTrainStopStatus(stop, train.currentStationName, this.onlineScenery!.name)
|
||||
: 'no-timetable';
|
||||
|
||||
return {
|
||||
train,
|
||||
status
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -74,31 +108,31 @@ ul {
|
||||
-webkit-transition: background-color 200ms;
|
||||
}
|
||||
|
||||
&.no-timetable .user_train {
|
||||
&[data-status='no-timetable'] .user_train {
|
||||
background-color: $no-timetable;
|
||||
}
|
||||
|
||||
&.departed > &_train {
|
||||
&[data-status='departed'] > &_train {
|
||||
background-color: $departed;
|
||||
}
|
||||
|
||||
&.stopped > &_train {
|
||||
&[data-status='stopped'] > &_train {
|
||||
background-color: $stopped;
|
||||
}
|
||||
|
||||
&.online > &_train {
|
||||
&[data-status='online'] > &_train {
|
||||
background-color: $online;
|
||||
}
|
||||
|
||||
&.terminated > &_train {
|
||||
&[data-status='terminated'] > &_train {
|
||||
background-color: $terminated;
|
||||
}
|
||||
|
||||
&.disconnected > &_train {
|
||||
&[data-status='disconnected'] > &_train {
|
||||
background-color: $disconnected;
|
||||
}
|
||||
|
||||
&.offline {
|
||||
&[data-status='offline'] {
|
||||
background: firebrick;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<transition-group name="list-anim">
|
||||
<div
|
||||
style="padding-bottom: 5em"
|
||||
v-if="apiStore.dataStatuses.connection == 0 && computedScheduledTrains.length == 0"
|
||||
v-if="apiStore.dataStatuses.connection == 0 && sceneryTimetables.length == 0"
|
||||
key="list-loading"
|
||||
>
|
||||
<Loading />
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
<span
|
||||
class="timetable-item empty"
|
||||
v-else-if="computedScheduledTrains.length == 0 && !onlineScenery"
|
||||
v-else-if="sceneryTimetables.length == 0 && !onlineScenery"
|
||||
key="list-offline"
|
||||
>
|
||||
{{ $t('scenery.offline') }}
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
<div
|
||||
class="timetable-item empty"
|
||||
v-else-if="computedScheduledTrains.length == 0"
|
||||
v-else-if="sceneryTimetables.length == 0"
|
||||
key="list-no-timetables"
|
||||
>
|
||||
{{ $t('scenery.no-timetables') }}
|
||||
@@ -65,59 +65,56 @@
|
||||
<div
|
||||
class="timetable-item"
|
||||
v-else
|
||||
v-for="scheduledTrain in computedScheduledTrains"
|
||||
:key="scheduledTrain.trainId + scheduledTrain.stopInfo.arrivalTimestamp"
|
||||
v-for="row in sceneryTimetables"
|
||||
:key="row.train.id + row.checkpointStop.arrivalTimestamp"
|
||||
tabindex="0"
|
||||
@click.prevent.stop="selectModalTrain(scheduledTrain.trainId, $event.currentTarget)"
|
||||
@keydown.enter.prevent="selectModalTrain(scheduledTrain.trainId, $event.currentTarget)"
|
||||
@click.prevent.stop="selectModalTrain(row.train.id, $event.currentTarget)"
|
||||
@keydown.enter.prevent="selectModalTrain(row.train.id, $event.currentTarget)"
|
||||
>
|
||||
<span class="timetable-general">
|
||||
<span class="general-info">
|
||||
<span class="info-number">
|
||||
<strong>{{ scheduledTrain.category }}</strong>
|
||||
{{ scheduledTrain.trainNo }}
|
||||
<strong>{{ row.train.timetableData!.category }}</strong>
|
||||
{{ row.train.trainNo }}
|
||||
|
||||
<span
|
||||
v-if="scheduledTrain.stopInfo.comments"
|
||||
:title="scheduledTrain.stopInfo.comments"
|
||||
>
|
||||
<span v-if="row.checkpointStop.comments" :title="row.checkpointStop.comments">
|
||||
<img src="/images/icon-warning.svg" />
|
||||
</span>
|
||||
</span>
|
||||
|
|
||||
<span>
|
||||
{{ scheduledTrain.driverName }}
|
||||
{{ row.train.driverName }}
|
||||
</span>
|
||||
|
||||
<div class="info-route">
|
||||
<strong>{{ scheduledTrain.beginsAt }} - {{ scheduledTrain.terminatesAt }}</strong>
|
||||
<strong>{{ row.train.timetableData!.route.replace('|', ' - ') }}</strong>
|
||||
</div>
|
||||
|
||||
<ScheduledTrainStatus :scheduledTrain="scheduledTrain" />
|
||||
<ScheduledTrainStatus :sceneryTimetableRow="row" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="timetable-schedule">
|
||||
<span class="schedule-arrival">
|
||||
<span class="arrival-time begins" v-if="scheduledTrain.stopInfo.beginsHere">
|
||||
<span class="arrival-time begins" v-if="row.checkpointStop.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 v-if="row.checkpointStop.arrivalDelay == 0">
|
||||
<span>{{ timestampToString(row.checkpointStop.arrivalTimestamp) }}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div>
|
||||
<s style="margin-right: 0.2em" class="text--grayed">{{
|
||||
timestampToString(scheduledTrain.stopInfo.arrivalTimestamp)
|
||||
timestampToString(row.checkpointStop.arrivalTimestamp)
|
||||
}}</s>
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{{ timestampToString(scheduledTrain.stopInfo.arrivalRealTimestamp) }}
|
||||
({{ scheduledTrain.stopInfo.arrivalDelay > 0 ? '+' : ''
|
||||
}}{{ scheduledTrain.stopInfo.arrivalDelay }})
|
||||
{{ timestampToString(row.checkpointStop.arrivalRealTimestamp) }}
|
||||
({{ row.checkpointStop.arrivalDelay > 0 ? '+' : ''
|
||||
}}{{ row.checkpointStop.arrivalDelay }})
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
@@ -125,41 +122,39 @@
|
||||
|
||||
<span class="schedule-stop">
|
||||
<span class="stop-connection">
|
||||
{{ scheduledTrain.arrivingLine }}
|
||||
{{ row.arrivingLine }}
|
||||
</span>
|
||||
|
||||
<span class="stop-time">
|
||||
{{ scheduledTrain.stopInfo.stopTime || '' }}
|
||||
{{
|
||||
scheduledTrain.stopInfo.stopTime ? scheduledTrain.stopInfo.stopType || 'pt' : ''
|
||||
}}
|
||||
{{ row.checkpointStop.stopTime || '' }}
|
||||
{{ row.checkpointStop.stopTime ? row.checkpointStop.stopType || 'pt' : '' }}
|
||||
</span>
|
||||
|
||||
<span class="stop-connection">
|
||||
{{ scheduledTrain.departureLine }}
|
||||
{{ row.departureLine }}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="schedule-departure">
|
||||
<span class="departure-time terminates" v-if="scheduledTrain.stopInfo.terminatesHere">
|
||||
<span class="departure-time terminates" v-if="row.checkpointStop.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 v-if="row.checkpointStop.departureDelay == 0">
|
||||
<span>{{ timestampToString(row.checkpointStop.departureTimestamp) }}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div>
|
||||
<s style="margin-right: 0.2em" class="text--grayed">{{
|
||||
timestampToString(scheduledTrain.stopInfo.departureTimestamp)
|
||||
timestampToString(row.checkpointStop.departureTimestamp)
|
||||
}}</s>
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{{ timestampToString(scheduledTrain.stopInfo.departureRealTimestamp) }}
|
||||
({{ scheduledTrain.stopInfo.departureDelay > 0 ? '+' : ''
|
||||
}}{{ scheduledTrain.stopInfo.departureDelay }})
|
||||
{{ timestampToString(row.checkpointStop.departureRealTimestamp) }}
|
||||
({{ row.checkpointStop.departureDelay > 0 ? '+' : ''
|
||||
}}{{ row.checkpointStop.departureDelay }})
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
@@ -183,6 +178,8 @@ import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||
import ScheduledTrainStatus from './ScheduledTrainStatus.vue';
|
||||
import { useApiStore } from '../../store/apiStore';
|
||||
import { ActiveScenery, Station } from '../../typings/common';
|
||||
import { SceneryTimetableRow } from './typings';
|
||||
import { getTrainStopStatus, stopStatusPriority } from './utils';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryTimetable',
|
||||
@@ -204,10 +201,6 @@ export default defineComponent({
|
||||
listOpen: false
|
||||
}),
|
||||
|
||||
mounted() {
|
||||
this.loadSelectedOption();
|
||||
},
|
||||
|
||||
activated() {
|
||||
this.loadSelectedOption();
|
||||
},
|
||||
@@ -241,27 +234,105 @@ export default defineComponent({
|
||||
return url;
|
||||
},
|
||||
|
||||
computedScheduledTrains() {
|
||||
sceneryTimetables(): SceneryTimetableRow[] {
|
||||
if (!this.station) return [];
|
||||
if (!this.onlineScenery) return [];
|
||||
|
||||
return (
|
||||
this.onlineScenery?.scheduledTrains
|
||||
?.filter(
|
||||
(train) =>
|
||||
train.checkpointName.toLocaleLowerCase() ==
|
||||
(this.chosenCheckpoint || this.station!.name).toLocaleLowerCase() &&
|
||||
train.region == this.mainStore.region.id
|
||||
)
|
||||
.sort((a, b) => {
|
||||
if (a.stopStatusID > b.stopStatusID) return 1;
|
||||
if (a.stopStatusID < b.stopStatusID) return -1;
|
||||
return this.onlineScenery.scheduledTrains
|
||||
.filter(
|
||||
(ct) =>
|
||||
ct.train.region == this.mainStore.region.id &&
|
||||
this.chosenCheckpoint &&
|
||||
ct.checkpointStop.stopNameRAW.toLowerCase() == this.chosenCheckpoint.toLowerCase()
|
||||
)
|
||||
.map((ct) => {
|
||||
const trainStopStatus = getTrainStopStatus(
|
||||
ct.checkpointStop,
|
||||
ct.train.currentStationName,
|
||||
this.station!.name
|
||||
);
|
||||
|
||||
if (a.stopInfo.arrivalTimestamp > b.stopInfo.arrivalTimestamp) return 1;
|
||||
if (a.stopInfo.arrivalTimestamp < b.stopInfo.arrivalTimestamp) return -1;
|
||||
const trainStopIndex =
|
||||
ct.train.timetableData?.followingStops.findIndex(
|
||||
(stop) => stop.stopName == ct.checkpointStop.stopName
|
||||
) ?? -1;
|
||||
|
||||
return a.stopInfo.departureTimestamp > b.stopInfo.departureTimestamp ? 1 : -1;
|
||||
}) || []
|
||||
);
|
||||
let prevStationName = '',
|
||||
nextStationName = '';
|
||||
|
||||
let departureLine: string | null = null;
|
||||
let arrivingLine: string | null = null;
|
||||
|
||||
let prevDepartureLine: string | null = null,
|
||||
nextArrivalLine: string | null = null;
|
||||
|
||||
if (trainStopIndex > -1 && ct.train.timetableData?.followingStops !== undefined) {
|
||||
for (let i = trainStopIndex; i >= 0; i--) {
|
||||
const stop = ct.train.timetableData.followingStops[i];
|
||||
|
||||
if (
|
||||
/strong|podg\.|pe\./g.test(stop.stopName) &&
|
||||
!prevStationName &&
|
||||
i <= trainStopIndex - 1
|
||||
)
|
||||
prevStationName = stop.stopNameRAW.replace(/,.*/g, '');
|
||||
|
||||
if (
|
||||
stop.arrivalLine != null &&
|
||||
!arrivingLine &&
|
||||
!/-|_|it|sbl/gi.test(stop.arrivalLine)
|
||||
) {
|
||||
arrivingLine = stop.arrivalLine;
|
||||
prevDepartureLine =
|
||||
ct.train.timetableData.followingStops[i - 1]?.departureLine || null;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = trainStopIndex; i < ct.train.timetableData.followingStops.length; i++) {
|
||||
const stop = ct.train.timetableData.followingStops[i];
|
||||
|
||||
if (
|
||||
/strong|podg\.|pe\./g.test(stop.stopName) &&
|
||||
!nextStationName &&
|
||||
i > trainStopIndex
|
||||
)
|
||||
nextStationName = stop.stopNameRAW.replace(/,.*/g, '');
|
||||
|
||||
if (
|
||||
stop.departureLine &&
|
||||
!departureLine &&
|
||||
!/-|_|it|sbl/gi.test(stop.departureLine)
|
||||
) {
|
||||
departureLine = stop.departureLine;
|
||||
nextArrivalLine = ct.train.timetableData.followingStops[i + 1]?.arrivalLine || null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
checkpointStop: ct.checkpointStop,
|
||||
train: ct.train,
|
||||
prevDepartureLine,
|
||||
nextArrivalLine,
|
||||
departureLine,
|
||||
arrivingLine,
|
||||
prevStationName,
|
||||
nextStationName,
|
||||
status: trainStopStatus
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
if (stopStatusPriority.indexOf(a.status) - stopStatusPriority.indexOf(b.status) < 0)
|
||||
return -1;
|
||||
|
||||
if (stopStatusPriority.indexOf(a.status) - stopStatusPriority.indexOf(b.status) > 0)
|
||||
return 1;
|
||||
|
||||
if (a.checkpointStop.arrivalTimestamp > b.checkpointStop.arrivalTimestamp) return 1;
|
||||
if (a.checkpointStop.arrivalTimestamp < b.checkpointStop.arrivalTimestamp) return -1;
|
||||
|
||||
return a.checkpointStop.departureTimestamp > b.checkpointStop.departureTimestamp ? 1 : -1;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="general-status">
|
||||
<span
|
||||
:class="computedScheduledTrain.stopStatus"
|
||||
:class="computedScheduledTrain.status"
|
||||
:title="computedScheduledTrain.stopStatusDescription"
|
||||
>
|
||||
{{ computedScheduledTrain.stopStatusIndicator }}
|
||||
@@ -11,25 +11,21 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import { ScheduledTrain, StopStatus } from '../../typings/common';
|
||||
|
||||
interface ScheduledTrainComp extends ScheduledTrain {
|
||||
stopStatusIndicator: string;
|
||||
stopStatusDescription: string;
|
||||
}
|
||||
import { StopStatus } from '../../typings/common';
|
||||
import { SceneryTimetableRow } from './typings';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
scheduledTrain: {
|
||||
type: Object as PropType<ScheduledTrain>,
|
||||
sceneryTimetableRow: {
|
||||
type: Object as PropType<SceneryTimetableRow>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
computedScheduledTrain(): ScheduledTrainComp {
|
||||
const { prevDepartureLine, prevStationName, stopStatus, nextArrivalLine, nextStationName } =
|
||||
this.scheduledTrain;
|
||||
computedScheduledTrain() {
|
||||
const { prevDepartureLine, prevStationName, nextArrivalLine, nextStationName, status } =
|
||||
this.sceneryTimetableRow;
|
||||
|
||||
const prevDepartureIndicator = prevDepartureLine
|
||||
? `(${prevDepartureLine}) ${prevStationName}`
|
||||
@@ -41,7 +37,7 @@ export default defineComponent({
|
||||
let stopStatusDescription = '',
|
||||
stopStatusIndicator = '';
|
||||
|
||||
switch (stopStatus) {
|
||||
switch (status) {
|
||||
case StopStatus.ARRIVING:
|
||||
stopStatusIndicator = `${this.$t('timetables.from')}: ${prevDepartureIndicator}`;
|
||||
stopStatusDescription = this.$t('timetables.desc-arriving', {
|
||||
@@ -56,7 +52,7 @@ export default defineComponent({
|
||||
? `${this.$t('timetables.to')}: ${nextArrivalIndicator}`
|
||||
: `${this.$t('timetables.desc-end')}`;
|
||||
stopStatusDescription = nextArrivalLine
|
||||
? this.$t(`timetables.desc-${stopStatus}`, { nextStationName, nextArrivalLine })
|
||||
? this.$t(`timetables.desc-${status}`, { nextStationName, nextArrivalLine })
|
||||
: '';
|
||||
break;
|
||||
|
||||
@@ -85,7 +81,7 @@ export default defineComponent({
|
||||
break;
|
||||
}
|
||||
return {
|
||||
...this.scheduledTrain,
|
||||
...this.sceneryTimetableRow,
|
||||
stopStatusDescription,
|
||||
stopStatusIndicator
|
||||
};
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { StopStatus, Train, TrainStop } from '../../typings/common';
|
||||
|
||||
export interface SceneryTimetableRow {
|
||||
checkpointStop: TrainStop;
|
||||
train: Train;
|
||||
prevDepartureLine: string | null;
|
||||
nextArrivalLine: string | null;
|
||||
departureLine: string | null;
|
||||
arrivingLine: string | null;
|
||||
prevStationName: string | null;
|
||||
nextStationName: string | null;
|
||||
status: StopStatus;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { StopStatus, TrainStop } from '../../typings/common';
|
||||
|
||||
export const stopStatusPriority = [
|
||||
StopStatus.ONLINE,
|
||||
StopStatus.STOPPED,
|
||||
StopStatus.DEPARTED,
|
||||
StopStatus.ARRIVING,
|
||||
StopStatus.DEPARTED_AWAY,
|
||||
StopStatus.TERMINATED
|
||||
];
|
||||
|
||||
export function getTrainStopStatus(
|
||||
stopInfo: TrainStop,
|
||||
currentStationName: string,
|
||||
sceneryName: string
|
||||
) {
|
||||
if (stopInfo.terminatesHere && stopInfo.confirmed) {
|
||||
return StopStatus.TERMINATED;
|
||||
}
|
||||
|
||||
if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == sceneryName) {
|
||||
return StopStatus.DEPARTED;
|
||||
}
|
||||
|
||||
if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != sceneryName) {
|
||||
return StopStatus.DEPARTED_AWAY;
|
||||
}
|
||||
|
||||
if (currentStationName == sceneryName && !stopInfo.stopped) {
|
||||
return StopStatus.ONLINE;
|
||||
}
|
||||
|
||||
if (currentStationName == sceneryName && stopInfo.stopped) {
|
||||
return StopStatus.STOPPED;
|
||||
}
|
||||
|
||||
if (currentStationName != sceneryName) {
|
||||
return StopStatus.ARRIVING;
|
||||
}
|
||||
|
||||
return StopStatus.ONLINE;
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { useTooltipStore } from '../../store/tooltipStore';
|
||||
import { StationTrain } from '../../typings/common';
|
||||
import { Train } from '../../typings/common';
|
||||
|
||||
export default defineComponent({
|
||||
data() {
|
||||
@@ -23,7 +23,7 @@ export default defineComponent({
|
||||
trains() {
|
||||
if (this.tooltipStore.content == '') return [];
|
||||
|
||||
const parsedTrains = JSON.parse(this.tooltipStore.content) as StationTrain[];
|
||||
const parsedTrains = JSON.parse(this.tooltipStore.content) as Train[];
|
||||
return (parsedTrains ?? []).sort((a, b) => a.trainNo - b.trainNo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export default defineComponent({
|
||||
|
||||
computed: {
|
||||
chosenTrain() {
|
||||
return this.store.trainList.find((train) => train.trainId == this.store.chosenModalTrainId);
|
||||
return this.store.trainList.find((train) => train.id == this.store.chosenModalTrainId);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
<li
|
||||
class="train-row"
|
||||
v-for="train in trains"
|
||||
:key="train.trainId"
|
||||
:key="train.id"
|
||||
tabindex="0"
|
||||
@click.stop="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||
@keydown.enter="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||
@click.stop="selectModalTrain(train.id, $event.currentTarget)"
|
||||
@keydown.enter="selectModalTrain(train.id, $event.currentTarget)"
|
||||
>
|
||||
<TrainInfo :train="train" :extended="false" />
|
||||
</li>
|
||||
|
||||
+72
-35
@@ -1,9 +1,9 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { parseSpawns, getScheduledTrains, getStationTrains } from './utils';
|
||||
import { parseSpawns } from './utils';
|
||||
|
||||
import {
|
||||
ActiveScenery,
|
||||
ScheduledTrain,
|
||||
CheckpointTrain,
|
||||
Station,
|
||||
StationRoutes,
|
||||
Status,
|
||||
@@ -12,6 +12,9 @@ import {
|
||||
import { useApiStore } from './apiStore';
|
||||
import { MainStoreState } from './typings';
|
||||
|
||||
const checkpointsTrains: Map<string, CheckpointTrain[]> = new Map();
|
||||
const sceneriesTrains: Map<string, Train[]> = new Map();
|
||||
|
||||
export const useMainStore = defineStore('mainStore', {
|
||||
state: () =>
|
||||
({
|
||||
@@ -33,10 +36,17 @@ export const useMainStore = defineStore('mainStore', {
|
||||
}) as MainStoreState,
|
||||
|
||||
getters: {
|
||||
checkpointsTrains() {
|
||||
return checkpointsTrains;
|
||||
},
|
||||
|
||||
trainList(): Train[] {
|
||||
const apiStore = useApiStore();
|
||||
|
||||
return (apiStore.activeData?.trains ?? [])
|
||||
checkpointsTrains.clear();
|
||||
sceneriesTrains.clear();
|
||||
|
||||
const x = (apiStore.activeData?.trains ?? [])
|
||||
.filter((train) => train.timetable || train.online)
|
||||
.map((train) => {
|
||||
const stock = train.stockString.split(';');
|
||||
@@ -53,8 +63,8 @@ export const useMainStore = defineStore('mainStore', {
|
||||
sceneryHash
|
||||
) ?? [];
|
||||
|
||||
return {
|
||||
trainId: train.driverName + train.trainNo.toString(),
|
||||
const trainObj = {
|
||||
id: train.id,
|
||||
|
||||
trainNo: train.trainNo,
|
||||
mass: train.mass,
|
||||
@@ -93,7 +103,36 @@ export const useMainStore = defineStore('mainStore', {
|
||||
}
|
||||
: undefined
|
||||
} as Train;
|
||||
|
||||
// Sceneries trains map
|
||||
if (sceneriesTrains.has(train.currentStationName)) {
|
||||
sceneriesTrains.set(train.currentStationName, [
|
||||
...sceneriesTrains.get(train.currentStationName)!,
|
||||
trainObj
|
||||
]);
|
||||
} else sceneriesTrains.set(train.currentStationName, [trainObj]);
|
||||
|
||||
// Checkpoints trains map
|
||||
timetable?.stopList.forEach((stop, i) => {
|
||||
if (/strong|podg\.|pe\./.test(stop.stopName)) {
|
||||
const checkpointTrain: CheckpointTrain = {
|
||||
train: trainObj,
|
||||
checkpointStop: stop
|
||||
};
|
||||
|
||||
if (checkpointsTrains.has(stop.stopNameRAW.toLowerCase())) {
|
||||
checkpointsTrains.set(stop.stopNameRAW.toLowerCase(), [
|
||||
...checkpointsTrains.get(stop.stopNameRAW.toLowerCase())!,
|
||||
checkpointTrain
|
||||
]);
|
||||
} else checkpointsTrains.set(stop.stopNameRAW.toLowerCase(), [checkpointTrain]);
|
||||
}
|
||||
});
|
||||
|
||||
return trainObj;
|
||||
});
|
||||
|
||||
return x;
|
||||
},
|
||||
|
||||
// computed active sceneries
|
||||
@@ -104,6 +143,7 @@ export const useMainStore = defineStore('mainStore', {
|
||||
|
||||
if (!apiStore.activeData?.activeSceneries) return [];
|
||||
|
||||
console.time('activeSceneryList');
|
||||
const offlineActiveSceneries = this.trainList.reduce((acc, train) => {
|
||||
if (!train.timetableData) return acc;
|
||||
|
||||
@@ -131,13 +171,14 @@ export const useMainStore = defineStore('mainStore', {
|
||||
dispatcherId: -1,
|
||||
dispatcherExp: -1,
|
||||
dispatcherIsSupporter: false,
|
||||
scheduledTrains: [],
|
||||
stationTrains: [],
|
||||
dispatcherStatus: Status.ActiveDispatcher.FREE,
|
||||
dispatcherTimestamp: -1,
|
||||
|
||||
isOnline: false,
|
||||
|
||||
stationTrains: [],
|
||||
scheduledTrains: [],
|
||||
|
||||
scheduledTrainCount: {
|
||||
all: 0,
|
||||
confirmed: 0,
|
||||
@@ -177,8 +218,9 @@ export const useMainStore = defineStore('mainStore', {
|
||||
|
||||
isOnline: scenery.isOnline == 1,
|
||||
|
||||
scheduledTrains: [],
|
||||
stationTrains: [],
|
||||
scheduledTrains: [],
|
||||
|
||||
scheduledTrainCount: {
|
||||
all: 0,
|
||||
confirmed: 0,
|
||||
@@ -196,39 +238,34 @@ export const useMainStore = defineStore('mainStore', {
|
||||
|
||||
const station = this.stationList.find((s) => s.name === scenery.name);
|
||||
|
||||
const scheduledTrains = getScheduledTrains(
|
||||
this.trainList,
|
||||
station?.generalInfo,
|
||||
scenery.name,
|
||||
scenery.region
|
||||
);
|
||||
const checkpoints = [scenery.name];
|
||||
if (station?.generalInfo?.checkpoints) checkpoints.push(...station.generalInfo.checkpoints);
|
||||
|
||||
const stationTrains = getStationTrains(
|
||||
this.trainList,
|
||||
scheduledTrains,
|
||||
this.region.id,
|
||||
scenery.name
|
||||
);
|
||||
scenery.stationTrains =
|
||||
sceneriesTrains.get(scenery.name)?.filter((sc) => sc.region == this.region.id) ?? [];
|
||||
|
||||
// Remove checkpoint duplicates
|
||||
const uniqueScheduledTrains = scheduledTrains.reduce(
|
||||
(uniqueList, sTrain) =>
|
||||
uniqueList.find((v) => v.trainId === sTrain.trainId)
|
||||
? uniqueList
|
||||
: [...uniqueList, sTrain],
|
||||
[] as ScheduledTrain[]
|
||||
);
|
||||
const uniqueTrainIds: string[] = [];
|
||||
checkpoints.forEach((cp) => {
|
||||
const scheduledTrains = checkpointsTrains.get(cp.toLowerCase());
|
||||
|
||||
scenery.scheduledTrains = scheduledTrains;
|
||||
scenery.stationTrains = stationTrains;
|
||||
if (!scheduledTrains) return;
|
||||
|
||||
scenery.scheduledTrainCount = {
|
||||
all: uniqueScheduledTrains.length,
|
||||
confirmed: uniqueScheduledTrains.filter((train) => train.stopInfo.confirmed).length,
|
||||
unconfirmed: uniqueScheduledTrains.filter((train) => !train.stopInfo.confirmed).length
|
||||
};
|
||||
scheduledTrains.forEach(({ train, checkpointStop }) => {
|
||||
if (uniqueTrainIds.includes(train.id) || train.region != this.region.id) return;
|
||||
|
||||
scenery.scheduledTrainCount.all += 1;
|
||||
scenery.scheduledTrains.push({ train, checkpointStop });
|
||||
|
||||
if (checkpointStop.confirmed) scenery.scheduledTrainCount.confirmed++;
|
||||
else scenery.scheduledTrainCount.unconfirmed++;
|
||||
|
||||
uniqueTrainIds.push(train.id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
console.timeEnd('activeSceneryList');
|
||||
|
||||
return allActiveSceneries;
|
||||
},
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { API } from '../typings/api';
|
||||
import { Availability, StationRoutesInfo, Status } from '../typings/common';
|
||||
import { Availability, CheckpointTrain, StationRoutesInfo, Status } from '../typings/common';
|
||||
|
||||
export interface MainStoreState {
|
||||
region: { id: string; value: string; name: string };
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
TrainStop,
|
||||
StopStatus,
|
||||
Train,
|
||||
ScheduledTrain,
|
||||
Station,
|
||||
StationTrain,
|
||||
ScenerySpawn,
|
||||
@@ -57,176 +56,3 @@ export function parseSpawns(spawnString: string | null): ScenerySpawn[] {
|
||||
export function getTimestamp(date: string | null): number {
|
||||
return date ? new Date(date).getTime() : 0;
|
||||
}
|
||||
|
||||
export function getTrainStopStatus(
|
||||
stopInfo: TrainStop,
|
||||
currentStationName: string,
|
||||
sceneryName: string
|
||||
) {
|
||||
let stopStatus = StopStatus.ARRIVING,
|
||||
stopLabel = '',
|
||||
stopStatusID = -1;
|
||||
|
||||
if (stopInfo.terminatesHere && stopInfo.confirmed) {
|
||||
stopStatus = StopStatus.TERMINATED;
|
||||
stopLabel = 'Skończył bieg';
|
||||
stopStatusID = 5;
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == sceneryName) {
|
||||
stopStatus = StopStatus.DEPARTED;
|
||||
stopLabel = 'Odprawiony';
|
||||
stopStatusID = 2;
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != sceneryName) {
|
||||
stopStatus = StopStatus.DEPARTED_AWAY;
|
||||
stopLabel = 'Odjechał';
|
||||
stopStatusID = 4;
|
||||
} else if (currentStationName == sceneryName && !stopInfo.stopped) {
|
||||
stopStatus = StopStatus.ONLINE;
|
||||
stopLabel = 'Na stacji';
|
||||
stopStatusID = 0;
|
||||
} else if (currentStationName == sceneryName && stopInfo.stopped) {
|
||||
stopStatus = StopStatus.STOPPED;
|
||||
stopLabel = 'Postój';
|
||||
stopStatusID = 1;
|
||||
} else if (currentStationName != sceneryName) {
|
||||
stopStatus = StopStatus.ARRIVING;
|
||||
stopLabel = 'W drodze';
|
||||
stopStatusID = 3;
|
||||
}
|
||||
|
||||
return { stopStatus, stopLabel, stopStatusID };
|
||||
}
|
||||
|
||||
export function getCheckpointTrain(
|
||||
train: Train,
|
||||
trainStopIndex: number,
|
||||
sceneryName: string
|
||||
): ScheduledTrain {
|
||||
const timetable = train.timetableData!;
|
||||
const followingStops = timetable.followingStops;
|
||||
const trainStop = followingStops[trainStopIndex];
|
||||
|
||||
const trainStopStatus = getTrainStopStatus(trainStop, train.currentStationName, sceneryName);
|
||||
|
||||
let prevStationName = '',
|
||||
nextStationName = '';
|
||||
|
||||
let departureLine: string | null = null;
|
||||
let arrivingLine: string | null = null;
|
||||
|
||||
let prevDepartureLine: string | null = null,
|
||||
nextArrivalLine: string | null = null;
|
||||
|
||||
for (let i = trainStopIndex; i >= 0; i--) {
|
||||
const stop = followingStops[i];
|
||||
|
||||
if (/strong|podg\.|pe\./g.test(stop.stopName) && !prevStationName && i <= trainStopIndex - 1)
|
||||
prevStationName = stop.stopNameRAW.replace(/,.*/g, '');
|
||||
|
||||
if (stop.arrivalLine != null && !arrivingLine && !/-|_|it|sbl/gi.test(stop.arrivalLine)) {
|
||||
arrivingLine = stop.arrivalLine;
|
||||
prevDepartureLine = followingStops[i - 1]?.departureLine || null;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = trainStopIndex; i < followingStops.length; i++) {
|
||||
const stop = followingStops[i];
|
||||
|
||||
if (/strong|podg\.|pe\./g.test(stop.stopName) && !nextStationName && i > trainStopIndex)
|
||||
nextStationName = stop.stopNameRAW.replace(/,.*/g, '');
|
||||
|
||||
if (stop.departureLine && !departureLine && !/-|_|it|sbl/gi.test(stop.departureLine)) {
|
||||
departureLine = stop.departureLine;
|
||||
nextArrivalLine = followingStops[i + 1]?.arrivalLine || null;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
checkpointName: trainStop.stopNameRAW,
|
||||
|
||||
trainNo: train.trainNo,
|
||||
trainId: train.trainId,
|
||||
|
||||
signal: train.signal,
|
||||
connectedTrack: train.connectedTrack,
|
||||
|
||||
driverName: train.driverName,
|
||||
driverId: train.driverId,
|
||||
currentStationName: train.currentStationName,
|
||||
currentStationHash: train.currentStationHash,
|
||||
category: timetable.category,
|
||||
beginsAt: timetable.followingStops[0].stopNameRAW,
|
||||
terminatesAt: timetable.followingStops[timetable.followingStops.length - 1].stopNameRAW,
|
||||
|
||||
nextStationName,
|
||||
prevStationName,
|
||||
|
||||
stopInfo: trainStop,
|
||||
stopLabel: trainStopStatus.stopLabel,
|
||||
stopStatus: trainStopStatus.stopStatus,
|
||||
stopStatusID: trainStopStatus.stopStatusID,
|
||||
|
||||
region: train.region,
|
||||
|
||||
arrivingLine: arrivingLine,
|
||||
departureLine: departureLine,
|
||||
|
||||
nextArrivalLine,
|
||||
prevDepartureLine
|
||||
};
|
||||
}
|
||||
|
||||
export function getScheduledTrains(
|
||||
trainList: Train[],
|
||||
stationGeneralInfo: Station['generalInfo'],
|
||||
stationName: string,
|
||||
region: string
|
||||
// sceneryData: API.ActiveSceneries.Data,
|
||||
): ScheduledTrain[] {
|
||||
// stationGeneralInfo?.checkpoints.forEach((cp) => (cp.scheduledTrains.length = 0));
|
||||
|
||||
return trainList.reduce((acc: ScheduledTrain[], train) => {
|
||||
if (!train.timetableData) return acc;
|
||||
if (train.region != region) return acc;
|
||||
|
||||
const timetable = train.timetableData;
|
||||
if (!timetable.sceneryNames.includes(stationName)) return acc;
|
||||
|
||||
const checkpoints = [stationName];
|
||||
if (stationGeneralInfo?.checkpoints) checkpoints.push(...stationGeneralInfo.checkpoints);
|
||||
|
||||
const checkpointScheduledTrains: ScheduledTrain[] = [];
|
||||
for (let i = 0; i < timetable.followingStops.length; i++) {
|
||||
if (
|
||||
new RegExp(`^(${checkpoints.join('|')})$`, 'i').test(
|
||||
timetable.followingStops[i].stopNameRAW
|
||||
)
|
||||
) {
|
||||
checkpointScheduledTrains.push(getCheckpointTrain(train, i, stationName));
|
||||
}
|
||||
}
|
||||
|
||||
acc.push(...checkpointScheduledTrains);
|
||||
return acc;
|
||||
}, []) as ScheduledTrain[];
|
||||
}
|
||||
|
||||
export function getStationTrains(
|
||||
trainList: Train[],
|
||||
scheduledTrainList: ScheduledTrain[],
|
||||
region: string,
|
||||
stationName: string
|
||||
): StationTrain[] {
|
||||
return trainList
|
||||
.filter(
|
||||
(train) =>
|
||||
train?.region === region && train.online && train.currentStationName === stationName
|
||||
)
|
||||
.map((train) => ({
|
||||
driverName: train.driverName,
|
||||
driverId: train.driverId,
|
||||
trainNo: train.trainNo,
|
||||
trainId: train.trainId,
|
||||
stopStatus:
|
||||
scheduledTrainList.find((st) => st.trainNo === train.trainNo)?.stopStatus || 'no-timetable'
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -161,7 +161,6 @@ export namespace API {
|
||||
stopNameRAW: string;
|
||||
stopType: string;
|
||||
stopDistance: number;
|
||||
pointId: string;
|
||||
|
||||
mainStop: boolean;
|
||||
|
||||
|
||||
+9
-49
@@ -41,7 +41,6 @@ export interface RegionCounters {
|
||||
|
||||
export interface Train {
|
||||
id: string;
|
||||
trainId: string;
|
||||
mass: number;
|
||||
length: number;
|
||||
speed: number;
|
||||
@@ -148,8 +147,8 @@ export interface ActiveScenery {
|
||||
dispatcherStatus: Status.ActiveDispatcher | number;
|
||||
dispatcherTimestamp: number | null;
|
||||
isOnline: boolean;
|
||||
stationTrains?: StationTrain[];
|
||||
scheduledTrains?: ScheduledTrain[];
|
||||
stationTrains: Train[];
|
||||
scheduledTrains: CheckpointTrain[];
|
||||
scheduledTrainCount: {
|
||||
all: number;
|
||||
confirmed: number;
|
||||
@@ -164,49 +163,6 @@ export interface ScenerySpawn {
|
||||
spawnType: ScenerySpawnType;
|
||||
}
|
||||
|
||||
export interface StationTrain {
|
||||
driverName: string;
|
||||
driverId: number;
|
||||
trainNo: number;
|
||||
trainId: string;
|
||||
stopStatus: string;
|
||||
}
|
||||
|
||||
export interface ScheduledTrain {
|
||||
checkpointName: string;
|
||||
|
||||
trainId: string;
|
||||
trainNo: number;
|
||||
|
||||
driverName: string;
|
||||
driverId: number;
|
||||
currentStationName: string;
|
||||
currentStationHash: string;
|
||||
category: string;
|
||||
stopInfo: TrainStop;
|
||||
|
||||
terminatesAt: string;
|
||||
beginsAt: string;
|
||||
|
||||
prevStationName: string;
|
||||
nextStationName: string;
|
||||
|
||||
arrivingLine: string | null;
|
||||
departureLine: string | null;
|
||||
|
||||
prevDepartureLine: string | null;
|
||||
nextArrivalLine: string | null;
|
||||
|
||||
signal: string;
|
||||
connectedTrack: string;
|
||||
|
||||
stopLabel: string;
|
||||
stopStatus: StopStatus;
|
||||
stopStatusID: number;
|
||||
|
||||
region: string;
|
||||
}
|
||||
|
||||
export interface TrainStop {
|
||||
stopName: string;
|
||||
stopNameRAW: string;
|
||||
@@ -223,13 +179,17 @@ export interface TrainStop {
|
||||
departureTimestamp: number;
|
||||
departureRealTimestamp: number;
|
||||
departureDelay: number;
|
||||
pointId: number;
|
||||
|
||||
comments?: string;
|
||||
|
||||
beginsHere: boolean;
|
||||
terminatesHere: boolean;
|
||||
confirmed: boolean;
|
||||
stopped: boolean;
|
||||
confirmed: number;
|
||||
stopped: number;
|
||||
stopTime: number | null;
|
||||
}
|
||||
|
||||
export interface CheckpointTrain {
|
||||
checkpointStop: TrainStop;
|
||||
train: Train;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user