mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 13:28:11 +00:00
rework reaktywności danych z API i WS
This commit is contained in:
+6
-32
@@ -32,20 +32,19 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, provide, ref, watch } from 'vue';
|
||||
import { defineComponent, watch } from 'vue';
|
||||
|
||||
import Clock from './components/App/Clock.vue';
|
||||
|
||||
import packageInfo from '.././package.json';
|
||||
|
||||
import { useStore } from './store/store';
|
||||
import StatusIndicator from './components/App/StatusIndicator.vue';
|
||||
import SelectBox from './components/Global/SelectBox.vue';
|
||||
import { useStore } from './store/store';
|
||||
import TrainModal from './components/Global/TrainModal.vue';
|
||||
import StorageManager from './scripts/managers/storageManager';
|
||||
import AppHeader from './components/App/AppHeader.vue';
|
||||
import axios from 'axios';
|
||||
import useCustomSW from './mixins/useCustomSW';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@@ -56,31 +55,9 @@ export default defineComponent({
|
||||
AppHeader
|
||||
},
|
||||
|
||||
setup() {
|
||||
const store = useStore();
|
||||
store.connectToAPI();
|
||||
|
||||
useCustomSW();
|
||||
|
||||
const isFilterCardVisible = ref(false);
|
||||
|
||||
provide('isFilterCardVisible', isFilterCardVisible);
|
||||
|
||||
return {
|
||||
store,
|
||||
isFilterCardVisible,
|
||||
onlineDispatchers: computed(() =>
|
||||
store.stationList.filter(
|
||||
(station) => station.onlineInfo && station.onlineInfo.region == store.region.id
|
||||
)
|
||||
),
|
||||
|
||||
dispatcherDataStatus: store.dataStatuses.dispatchers
|
||||
};
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
VERSION: packageInfo.version,
|
||||
store: useStore(),
|
||||
|
||||
currentLang: 'pl',
|
||||
releaseURL: '',
|
||||
@@ -89,6 +66,7 @@ export default defineComponent({
|
||||
|
||||
created() {
|
||||
this.loadLang();
|
||||
this.store.connectToAPI();
|
||||
|
||||
this.store.isOffline = !window.navigator.onLine;
|
||||
|
||||
@@ -116,12 +94,8 @@ export default defineComponent({
|
||||
watch(
|
||||
() => this.store.blockScroll,
|
||||
(value) => {
|
||||
if (value) {
|
||||
document.body.classList.add('no-scroll');
|
||||
return;
|
||||
}
|
||||
|
||||
document.body.classList.remove('no-scroll');
|
||||
if (value) document.body.classList.add('no-scroll');
|
||||
else document.body.classList.remove('no-scroll');
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
@@ -82,28 +82,30 @@ export default defineComponent({
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
setup() {
|
||||
return {
|
||||
store: useStore()
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
changeRegion(region: { id: string; value: string }) {
|
||||
this.store.changeRegion(region);
|
||||
},
|
||||
|
||||
changeLang(lang: string) {
|
||||
this.$emit('changeLang', lang);
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
onlineTrainsCount() {
|
||||
return this.store.trainList.filter((train) => train.online).length;
|
||||
},
|
||||
|
||||
onlineDispatchersCount() {
|
||||
return this.store.stationList.filter(
|
||||
(station) => station.onlineInfo && station.onlineInfo.region == this.store.region.id
|
||||
).length;
|
||||
return this.store.onlineSceneryList.length;
|
||||
},
|
||||
|
||||
factorU() {
|
||||
|
||||
@@ -87,6 +87,19 @@ export default defineComponent({
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$route.query': {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (newVal.region) {
|
||||
const item = this.itemList.find((it) => it.id == newVal.region);
|
||||
|
||||
if (item) this.selectedItem = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
selectOption(item: Item) {
|
||||
this.selectedItem = item;
|
||||
|
||||
@@ -76,6 +76,7 @@ import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import styleMixin from '../../mixins/styleMixin';
|
||||
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||
import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryDispatchersHistory',
|
||||
@@ -85,6 +86,10 @@ export default defineComponent({
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
},
|
||||
onlineScenery: {
|
||||
type: Object as PropType<OnlineScenery>,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -8,19 +8,25 @@
|
||||
{{ $t('scenery.abbrev') }} <b>{{ station.generalInfo?.abbr }}</b>
|
||||
</div>
|
||||
|
||||
<div class="scenery-hash" v-if="station.onlineInfo?.hash">#{{ station.onlineInfo.hash }}</div>
|
||||
<div class="scenery-hash" v-if="onlineScenery?.hash">#{{ onlineScenery.hash }}</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
},
|
||||
|
||||
onlineScenery: {
|
||||
type: Object as PropType<OnlineScenery>,
|
||||
required: false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="scenery-info">
|
||||
<section v-if="!timetableOnly">
|
||||
<section>
|
||||
<div class="scenery-info-general" v-if="station.generalInfo">
|
||||
<SceneryInfoIcons :station="station" />
|
||||
|
||||
@@ -68,14 +68,14 @@
|
||||
<div style="margin: 2em 0; height: 2px; background-color: white"></div>
|
||||
|
||||
<!-- info dispatcher -->
|
||||
<SceneryInfoDispatcher :station="station" :onlineFrom="onlineFrom" />
|
||||
<SceneryInfoDispatcher :onlineScenery="onlineScenery" />
|
||||
|
||||
<div class="info-lists">
|
||||
<!-- user list -->
|
||||
<SceneryInfoUserList :station="station" />
|
||||
<SceneryInfoUserList :onlineScenery="onlineScenery" />
|
||||
|
||||
<!-- spawn list -->
|
||||
<SceneryInfoSpawnList :station="station" />
|
||||
<SceneryInfoSpawnList :onlineScenery="onlineScenery" />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
@@ -90,6 +90,7 @@ import SceneryInfoUserList from './SceneryInfo/SceneryInfoUserList.vue';
|
||||
import SceneryInfoSpawnList from './SceneryInfo/SceneryInfoSpawnList.vue';
|
||||
import SceneryInfoRoutes from './SceneryInfo/SceneryInfoRoutes.vue';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@@ -105,12 +106,11 @@ export default defineComponent({
|
||||
required: true
|
||||
},
|
||||
|
||||
timetableOnly: Boolean
|
||||
onlineScenery: {
|
||||
type: Object as PropType<OnlineScenery>,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
onlineFrom: -1
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,35 +1,30 @@
|
||||
<template>
|
||||
<section class="info-dispatcher">
|
||||
<div class="dispatcher" v-if="station.onlineInfo">
|
||||
<div class="dispatcher" v-if="onlineScenery">
|
||||
<span
|
||||
class="dispatcher_level"
|
||||
:style="
|
||||
calculateExpStyle(
|
||||
station.onlineInfo.dispatcherExp,
|
||||
station.onlineInfo.dispatcherIsSupporter
|
||||
)
|
||||
"
|
||||
:style="calculateExpStyle(onlineScenery.dispatcherExp, onlineScenery.dispatcherIsSupporter)"
|
||||
>
|
||||
{{ station.onlineInfo.dispatcherExp > 1 ? station.onlineInfo.dispatcherExp : 'L' }}
|
||||
{{ onlineScenery.dispatcherExp > 1 ? onlineScenery.dispatcherExp : 'L' }}
|
||||
</span>
|
||||
|
||||
<router-link
|
||||
class="dispatcher_name"
|
||||
:to="`/journal/dispatchers?dispatcherName=${station.onlineInfo.dispatcherName}`"
|
||||
:to="`/journal/dispatchers?dispatcherName=${onlineScenery.dispatcherName}`"
|
||||
>
|
||||
{{ station.onlineInfo.dispatcherName }}
|
||||
{{ onlineScenery.dispatcherName }}
|
||||
</router-link>
|
||||
|
||||
<span class="dispatcher_likes text--primary">
|
||||
<img src="/images/icon-like.svg" alt="Likes count icon" />
|
||||
<span>{{ station.onlineInfo?.dispatcherRate || '0' }}</span>
|
||||
<span>{{ onlineScenery?.dispatcherRate || '0' }}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<StationStatusBadge
|
||||
:statusID="station.onlineInfo?.statusID"
|
||||
:isOnline="station.onlineInfo ? true : false"
|
||||
:statusTimestamp="station.onlineInfo?.statusTimestamp"
|
||||
:statusID="onlineScenery?.statusID"
|
||||
:isOnline="onlineScenery ? true : false"
|
||||
:statusTimestamp="onlineScenery?.statusTimestamp"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
@@ -39,19 +34,15 @@ import { PropType, defineComponent } from 'vue';
|
||||
import dateMixin from '../../../mixins/dateMixin';
|
||||
import routerMixin from '../../../mixins/routerMixin';
|
||||
import styleMixin from '../../../mixins/styleMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
import StationStatusBadge from '../../Global/StationStatusBadge.vue';
|
||||
import { OnlineScenery } from '../../../scripts/interfaces/store/storeTypes';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [styleMixin, dateMixin, routerMixin],
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
},
|
||||
onlineFrom: {
|
||||
type: Number,
|
||||
default: -1
|
||||
onlineScenery: {
|
||||
type: Object as PropType<OnlineScenery>,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
components: { StationStatusBadge }
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
<h3 class="spawn-header section-header">
|
||||
<img src="/images/icon-spawn.svg" alt="Open spawns icon" />
|
||||
{{ $t('scenery.spawns') }}
|
||||
<span class="text--primary">{{ station.onlineInfo?.spawns.length || '0' }}</span>
|
||||
<span class="text--primary">{{ onlineScenery?.spawns.length || '0' }}</span>
|
||||
</h3>
|
||||
|
||||
<span v-if="station.onlineInfo">
|
||||
<span v-if="onlineScenery">
|
||||
<span
|
||||
class="badge spawn"
|
||||
v-for="(spawn, i) in sortedSpawns"
|
||||
:key="spawn.spawnName + station.onlineInfo?.dispatcherName + i"
|
||||
:key="spawn.spawnName + onlineScenery?.dispatcherName + i"
|
||||
:data-electrified="spawn.isElectrified"
|
||||
>
|
||||
<span class="spawn_name">{{ spawn.spawnName }}</span>
|
||||
@@ -18,9 +18,7 @@
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="badge spawn badge-none"
|
||||
v-if="!station.onlineInfo || station.onlineInfo.spawns.length == 0"
|
||||
<span class="badge spawn badge-none" v-if="!onlineScenery || onlineScenery.spawns.length == 0"
|
||||
>{{ $t('scenery.no-spawns') }}
|
||||
</span>
|
||||
</section>
|
||||
@@ -28,21 +26,21 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
import { OnlineScenery } from '../../../scripts/interfaces/store/storeTypes';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
onlineScenery: {
|
||||
type: Object as PropType<OnlineScenery>,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
sortedSpawns() {
|
||||
if (!this.station.onlineInfo) return [];
|
||||
if (!this.onlineScenery) return [];
|
||||
|
||||
return [...this.station.onlineInfo.spawns].sort((s1, s2) =>
|
||||
return [...this.onlineScenery.spawns].sort((s1, s2) =>
|
||||
s1.spawnLength < s2.spawnLength ? 1 : -1
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
<h3 class="user-header section-header">
|
||||
<img src="/images/icon-user.svg" alt="Users icon" />
|
||||
{{ $t('scenery.users') }}
|
||||
<span class="text--primary">{{ station.onlineInfo?.currentUsers || '0' }}</span
|
||||
> / <span class="text--primary">{{ station.onlineInfo?.maxUsers || '0' }}</span>
|
||||
<span class="text--primary">{{ onlineScenery?.currentUsers || 0 }}</span
|
||||
> / <span class="text--primary">{{ onlineScenery?.maxUsers || 0 }}</span>
|
||||
</h3>
|
||||
|
||||
<div
|
||||
v-for="train in computedStationTrains"
|
||||
v-for="train in onlineScenery?.stationTrains"
|
||||
class="badge user"
|
||||
:class="train.stopStatus"
|
||||
:key="train.trainId"
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<div
|
||||
class="badge user badge-none"
|
||||
v-if="!computedStationTrains || computedStationTrains.length == 0"
|
||||
v-if="!onlineScenery?.scheduledTrains || onlineScenery.scheduledTrains.length == 0"
|
||||
>
|
||||
{{ $t('scenery.no-users') }}
|
||||
</div>
|
||||
@@ -30,45 +30,19 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, computed, defineComponent } from 'vue';
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
||||
import routerMixin from '../../../mixins/routerMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
import { useStore } from '../../../store/store';
|
||||
import { OnlineScenery } from '../../../scripts/interfaces/store/storeTypes';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [routerMixin, modalTrainMixin],
|
||||
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
onlineScenery: {
|
||||
type: Object as PropType<OnlineScenery>,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
|
||||
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>
|
||||
|
||||
@@ -6,14 +6,12 @@
|
||||
<span>{{ $t('scenery.timetables') }}</span>
|
||||
|
||||
<span>
|
||||
<span class="text--primary">{{
|
||||
station.onlineInfo?.scheduledTrains?.length || '0'
|
||||
}}</span>
|
||||
<span class="text--primary">{{ onlineScenery?.scheduledTrains?.length || '0' }}</span>
|
||||
<span> / </span>
|
||||
<span class="text--grayed">
|
||||
{{
|
||||
station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed)
|
||||
.length || '0'
|
||||
onlineScenery?.scheduledTrains?.filter((train) => train.stopInfo.confirmed).length ||
|
||||
'0'
|
||||
}}
|
||||
</span>
|
||||
</span>
|
||||
@@ -59,7 +57,7 @@
|
||||
|
||||
<span
|
||||
class="timetable-item empty"
|
||||
v-else-if="computedScheduledTrains.length == 0 && !station.onlineInfo"
|
||||
v-else-if="computedScheduledTrains.length == 0 && !onlineScenery"
|
||||
>
|
||||
{{ $t('scenery.offline') }}
|
||||
</span>
|
||||
@@ -186,6 +184,7 @@ import Station from '../../scripts/interfaces/Station';
|
||||
import { useStore } from '../../store/store';
|
||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||
import ScheduledTrainStatus from './ScheduledTrainStatus.vue';
|
||||
import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryTimetable',
|
||||
@@ -199,9 +198,9 @@ export default defineComponent({
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
},
|
||||
|
||||
timetableOnly: {
|
||||
type: Boolean
|
||||
onlineScenery: {
|
||||
type: Object as PropType<OnlineScenery>,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
|
||||
@@ -229,36 +228,9 @@ export default defineComponent({
|
||||
: 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
|
||||
};
|
||||
},
|
||||
@@ -269,27 +241,37 @@ export default defineComponent({
|
||||
if (this.chosenCheckpoint) url += `&checkpoint=${this.chosenCheckpoint}`;
|
||||
|
||||
return url;
|
||||
},
|
||||
|
||||
computedScheduledTrains() {
|
||||
return (
|
||||
this.onlineScenery?.scheduledTrains
|
||||
?.filter(
|
||||
(train) =>
|
||||
train.checkpointName.toLocaleLowerCase() ==
|
||||
(this.chosenCheckpoint || this.station.name).toLocaleLowerCase()
|
||||
)
|
||||
.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;
|
||||
}) || []
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
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;
|
||||
this.chosenCheckpoint =
|
||||
this.station.generalInfo?.checkpoints[0]?.checkpointName || this.station.name;
|
||||
},
|
||||
|
||||
setCheckpoint(cp: { checkpointName: string }) {
|
||||
this.chosenCheckpoint = cp.checkpointName;
|
||||
},
|
||||
|
||||
showTimetableOnlyView() {
|
||||
this.$router.push(`${this.$route.fullPath}&timetableOnly=1`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -65,6 +65,7 @@ import Station from '../../scripts/interfaces/Station';
|
||||
import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||
import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryTimetablesHistory',
|
||||
@@ -73,6 +74,10 @@ export default defineComponent({
|
||||
station: {
|
||||
type: Object as PropType<Station>,
|
||||
required: true
|
||||
},
|
||||
onlineScenery: {
|
||||
type: Object as PropType<OnlineScenery>,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<label @dblclick="handleDbClick">
|
||||
<input
|
||||
:value="optionValue"
|
||||
@input="$emit('update:optionValue', ($event.target as HTMLInputElement).value)"
|
||||
:checked="optionValue"
|
||||
@input="$emit('update:optionValue', ($event.target as HTMLInputElement).checked)"
|
||||
type="checkbox"
|
||||
:class="option.section"
|
||||
:name="option.id"
|
||||
|
||||
@@ -79,11 +79,19 @@
|
||||
</span>
|
||||
|
||||
<span v-else-if="station.generalInfo.availability == 'abandoned'">
|
||||
<img src="/images/icon-abandoned.svg" alt="non-public" :title="$t('desc.abandoned')" />
|
||||
<img
|
||||
src="/images/icon-abandoned.svg"
|
||||
alt="non-public"
|
||||
:title="$t('desc.abandoned')"
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span v-else-if="station.generalInfo.availability == 'nonPublic'">
|
||||
<img src="/images/icon-lock.svg" alt="non-public" :title="$t('desc.non-public')" />
|
||||
<img
|
||||
src="/images/icon-lock.svg"
|
||||
alt="non-public"
|
||||
:title="$t('desc.non-public')"
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span v-else>
|
||||
@@ -234,7 +242,7 @@
|
||||
</td>
|
||||
|
||||
<td
|
||||
class="station_schedules"
|
||||
class="station_schedules all"
|
||||
style="width: 30px"
|
||||
:class="{ inactive: !station.onlineInfo }"
|
||||
>
|
||||
@@ -244,20 +252,23 @@
|
||||
</td>
|
||||
|
||||
<td
|
||||
class="station_schedules"
|
||||
class="station_schedules unconfirmed"
|
||||
style="width: 30px"
|
||||
:class="{ inactive: !station.onlineInfo }"
|
||||
>
|
||||
<span style="color: #ccc">
|
||||
{{
|
||||
station.onlineInfo?.scheduledTrains?.filter((train) => !train.stopInfo.confirmed)
|
||||
.length || 0
|
||||
new Set([
|
||||
...(station.onlineInfo?.scheduledTrains
|
||||
?.filter((train) => !train.stopInfo.confirmed)
|
||||
.map((train) => train.checkpointName) || [])
|
||||
]).size || 0
|
||||
}}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td
|
||||
class="station_schedules"
|
||||
class="station_schedules confirmed"
|
||||
style="width: 30px"
|
||||
:class="{ inactive: !station.onlineInfo }"
|
||||
>
|
||||
@@ -336,9 +347,13 @@ export default defineComponent({
|
||||
if (!station) return;
|
||||
|
||||
this.lastSelectedStationName = station.name;
|
||||
|
||||
this.$router.push({
|
||||
name: 'SceneryView',
|
||||
query: { station: station.name.replaceAll(' ', '_') }
|
||||
query: {
|
||||
station: station.name.replaceAll(' ', '_'),
|
||||
region: this.$route.query.region || undefined
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import plLang from './locales/pl.json';
|
||||
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import { createPinia } from 'pinia';
|
||||
import useCustomSW from './mixins/useCustomSW';
|
||||
|
||||
const i18n = createI18n({
|
||||
locale: 'pl',
|
||||
@@ -20,6 +21,9 @@ const i18n = createI18n({
|
||||
enableLegacy: false
|
||||
});
|
||||
|
||||
// SW
|
||||
useCustomSW();
|
||||
|
||||
const clickOutsideDirective: Directive = {
|
||||
mounted(el, binding) {
|
||||
el.clickOutsideEvent = (event: Event) => {
|
||||
|
||||
+12
-3
@@ -6,7 +6,10 @@ const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'StationsView',
|
||||
component: () => import('../views/StationsView.vue')
|
||||
component: () => import('../views/StationsView.vue'),
|
||||
props: (route) => ({
|
||||
region: route.query.region
|
||||
})
|
||||
},
|
||||
{
|
||||
path: '/trains',
|
||||
@@ -21,7 +24,11 @@ const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/scenery',
|
||||
name: 'SceneryView',
|
||||
component: () => import('../views/SceneryView.vue')
|
||||
component: () => import('../views/SceneryView.vue'),
|
||||
props: (route) => ({
|
||||
region: route.query.region,
|
||||
station: route.query.station
|
||||
})
|
||||
},
|
||||
{
|
||||
path: '/journal',
|
||||
@@ -53,9 +60,11 @@ const routes: Array<RouteRecordRaw> = [
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
scrollBehavior(to, from) {
|
||||
scrollBehavior(to, from, savedPosition) {
|
||||
if (to.name == 'SceneryView' && from.name) return { el: `.app_main` };
|
||||
|
||||
if (savedPosition) return savedPosition;
|
||||
|
||||
// if (from.name == 'SceneryView' && to.name == 'StationsView') return { el: `.last-selected`, top: 20 };
|
||||
},
|
||||
history: createWebHistory(),
|
||||
|
||||
@@ -10,6 +10,8 @@ export enum StopStatus {
|
||||
}
|
||||
|
||||
export interface ScheduledTrain {
|
||||
checkpointName: string;
|
||||
|
||||
trainId: string;
|
||||
trainNo: number;
|
||||
|
||||
|
||||
@@ -2,17 +2,16 @@ import { Socket } from 'socket.io-client';
|
||||
import { DataStatus } from '../../enums/DataStatus';
|
||||
import StationAPIData from '../api/StationAPIData';
|
||||
import { TrainAPIData } from '../api/TrainAPIData';
|
||||
import Station from '../Station';
|
||||
import Train from '../Train';
|
||||
import { DispatcherStatsAPIData } from '../api/DispatcherStatsAPIData';
|
||||
import { DriverStatsAPIData } from '../api/DriverStatsAPIData';
|
||||
import { RollingStockGithubData } from '../github_api/StockInfoGithubData';
|
||||
import Station from '../Station';
|
||||
import { ScheduledTrain } from '../ScheduledTrain';
|
||||
|
||||
export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault';
|
||||
|
||||
export interface StoreState {
|
||||
stationList: Station[];
|
||||
trainList: Train[];
|
||||
apiData: APIData;
|
||||
rollingStockData?: RollingStockGithubData;
|
||||
|
||||
@@ -91,3 +90,31 @@ export interface StationJSONData {
|
||||
|
||||
availability: Availability;
|
||||
}
|
||||
|
||||
export interface StationTrain {
|
||||
driverName: string;
|
||||
driverId: number;
|
||||
trainNo: number;
|
||||
trainId: string;
|
||||
stopStatus: string;
|
||||
}
|
||||
|
||||
export interface OnlineScenery {
|
||||
name: string;
|
||||
hash: string;
|
||||
region: string;
|
||||
maxUsers: number;
|
||||
currentUsers: number;
|
||||
spawns: { spawnName: string; spawnLength: number; isElectrified: boolean }[];
|
||||
dispatcherName: string;
|
||||
dispatcherRate: number;
|
||||
dispatcherId: number;
|
||||
dispatcherExp: number;
|
||||
dispatcherIsSupporter: boolean;
|
||||
|
||||
statusTimestamp: number;
|
||||
statusID: string;
|
||||
|
||||
stationTrains?: StationTrain[];
|
||||
scheduledTrains?: ScheduledTrain[];
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { ScheduledTrain, StopStatus } from '../interfaces/ScheduledTrain';
|
||||
import Station from '../interfaces/Station';
|
||||
import Train from '../interfaces/Train';
|
||||
import TrainStop from '../interfaces/TrainStop';
|
||||
import StationAPIData from '../interfaces/api/StationAPIData';
|
||||
import { StationTrain, StoreState } from '../interfaces/store/storeTypes';
|
||||
|
||||
export const getLocoURL = (locoType: string): string =>
|
||||
`https://rj.td2.info.pl/dist/img/thumbnails/${
|
||||
@@ -79,7 +82,7 @@ export const getTimestamp = (date: string | null): number => (date ? new Date(da
|
||||
export const getTrainStopStatus = (
|
||||
stopInfo: TrainStop,
|
||||
currentStationName: string,
|
||||
stationName: string
|
||||
sceneryName: string
|
||||
) => {
|
||||
let stopStatus = StopStatus['arriving'],
|
||||
stopLabel = '',
|
||||
@@ -89,23 +92,23 @@ export const getTrainStopStatus = (
|
||||
stopStatus = StopStatus['terminated'];
|
||||
stopLabel = 'Skończył bieg';
|
||||
stopStatusID = 5;
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == stationName) {
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == sceneryName) {
|
||||
stopStatus = StopStatus['departed'];
|
||||
stopLabel = 'Odprawiony';
|
||||
stopStatusID = 2;
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != stationName) {
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != sceneryName) {
|
||||
stopStatus = StopStatus['departed-away'];
|
||||
stopLabel = 'Odjechał';
|
||||
stopStatusID = 4;
|
||||
} else if (currentStationName == stationName && !stopInfo.stopped) {
|
||||
} else if (currentStationName == sceneryName && !stopInfo.stopped) {
|
||||
stopStatus = StopStatus['online'];
|
||||
stopLabel = 'Na stacji';
|
||||
stopStatusID = 0;
|
||||
} else if (currentStationName == stationName && stopInfo.stopped) {
|
||||
} else if (currentStationName == sceneryName && stopInfo.stopped) {
|
||||
stopStatus = StopStatus['stopped'];
|
||||
stopLabel = 'Postój';
|
||||
stopStatusID = 1;
|
||||
} else if (currentStationName != stationName) {
|
||||
} else if (currentStationName != sceneryName) {
|
||||
stopStatus = StopStatus['arriving'];
|
||||
stopLabel = 'W drodze';
|
||||
stopStatusID = 3;
|
||||
@@ -114,16 +117,16 @@ export const getTrainStopStatus = (
|
||||
return { stopStatus, stopLabel, stopStatusID };
|
||||
};
|
||||
|
||||
export function getScheduledTrain(
|
||||
export function getCheckpointTrain(
|
||||
train: Train,
|
||||
trainStopIndex: number,
|
||||
stationName: string
|
||||
sceneryName: string
|
||||
): ScheduledTrain {
|
||||
const timetable = train.timetableData!;
|
||||
const followingStops = timetable.followingStops;
|
||||
const trainStop = followingStops[trainStopIndex];
|
||||
|
||||
const trainStopStatus = getTrainStopStatus(trainStop, train.currentStationName, stationName);
|
||||
const trainStopStatus = getTrainStopStatus(trainStop, train.currentStationName, sceneryName);
|
||||
|
||||
let prevStationName = '',
|
||||
nextStationName = '';
|
||||
@@ -177,6 +180,8 @@ export function getScheduledTrain(
|
||||
}
|
||||
|
||||
return {
|
||||
checkpointName: trainStop.stopNameRAW,
|
||||
|
||||
trainNo: train.trainNo,
|
||||
trainId: train.trainId,
|
||||
|
||||
@@ -206,3 +211,119 @@ export function getScheduledTrain(
|
||||
prevDepartureLine
|
||||
};
|
||||
}
|
||||
|
||||
export function getDispatcherStatus(state: StoreState, onlineStationData: StationAPIData) {
|
||||
const { dispatchers } = state.apiData;
|
||||
|
||||
const prevDispatcherStatus = state.lastDispatcherStatuses.find(
|
||||
(dispatcher) => dispatcher.hash === onlineStationData.stationHash
|
||||
);
|
||||
|
||||
const stationStatus = !dispatchers
|
||||
? undefined
|
||||
: dispatchers.find(
|
||||
(status: string[]) =>
|
||||
status[0] == onlineStationData.stationHash && status[1] == state.region.id
|
||||
) || -1;
|
||||
|
||||
const statusTimestamp =
|
||||
prevDispatcherStatus && !dispatchers
|
||||
? prevDispatcherStatus.statusTimestamp
|
||||
: getStatusTimestamp(stationStatus);
|
||||
|
||||
const statusID =
|
||||
prevDispatcherStatus && !dispatchers
|
||||
? prevDispatcherStatus.statusID
|
||||
: getStatusID(stationStatus);
|
||||
|
||||
return {
|
||||
hash: onlineStationData.stationHash,
|
||||
statusID,
|
||||
statusTimestamp
|
||||
};
|
||||
}
|
||||
|
||||
export function getScheduledTrains(
|
||||
trainList: Train[],
|
||||
stationAPIData: StationAPIData,
|
||||
stationGeneralInfo: Station['generalInfo']
|
||||
): ScheduledTrain[] {
|
||||
const stationName = stationAPIData.stationName.toLocaleLowerCase();
|
||||
|
||||
stationGeneralInfo?.checkpoints.forEach((cp) => (cp.scheduledTrains.length = 0));
|
||||
|
||||
return trainList.reduce((acc: ScheduledTrain[], train) => {
|
||||
if (!train.timetableData) return acc;
|
||||
|
||||
const timetable = train.timetableData;
|
||||
if (!timetable.sceneries.includes(stationAPIData.stationHash)) return acc;
|
||||
|
||||
const stopInfoIndex = timetable.followingStops.findIndex((stop) => {
|
||||
const stopName = stop.stopNameRAW.toLowerCase();
|
||||
|
||||
return (
|
||||
stationName == stopName ||
|
||||
(!/(po\.|podg\.)/.test(stationName) && stopName.includes(stationName)) ||
|
||||
(!/(po\.|podg\.)/.test(stopName) && stationName.includes(stopName)) ||
|
||||
(stopName.split(', podg.')[0] !== undefined &&
|
||||
stationName.startsWith(stopName.split(', podg.')[0]))
|
||||
);
|
||||
});
|
||||
|
||||
const checkpointScheduledTrains: ScheduledTrain[] = [];
|
||||
|
||||
if (stopInfoIndex != -1) {
|
||||
checkpointScheduledTrains.push(
|
||||
getCheckpointTrain(train, stopInfoIndex, stationAPIData.stationName)
|
||||
);
|
||||
}
|
||||
|
||||
stationGeneralInfo?.checkpoints?.forEach((checkpoint) => {
|
||||
if (checkpoint.checkpointName.toLocaleLowerCase() == stationName) return;
|
||||
|
||||
if (
|
||||
checkpointScheduledTrains.findIndex(
|
||||
(cpTrain) =>
|
||||
cpTrain.checkpointName.toLocaleLowerCase() ==
|
||||
checkpoint.checkpointName.toLocaleLowerCase()
|
||||
) != -1
|
||||
)
|
||||
return;
|
||||
|
||||
const index = timetable.followingStops.findIndex(
|
||||
(stop) => stop.stopNameRAW.toLowerCase() == checkpoint.checkpointName.toLowerCase()
|
||||
);
|
||||
|
||||
if (index > -1)
|
||||
checkpointScheduledTrains.push(
|
||||
getCheckpointTrain(train, index, stationAPIData.stationName)
|
||||
);
|
||||
});
|
||||
|
||||
acc.push(...checkpointScheduledTrains);
|
||||
return acc;
|
||||
}, []) as ScheduledTrain[];
|
||||
}
|
||||
|
||||
export function getStationTrains(
|
||||
trainList: Train[],
|
||||
scheduledTrainList: ScheduledTrain[],
|
||||
region: string,
|
||||
apiStation: StationAPIData
|
||||
): StationTrain[] {
|
||||
return trainList
|
||||
.filter(
|
||||
(train) =>
|
||||
train?.region === region &&
|
||||
train.online &&
|
||||
train.currentStationName === apiStation.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'
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import inputData from '../data/options.json';
|
||||
import Station from '../scripts/interfaces/Station';
|
||||
import StorageManager from '../scripts/managers/storageManager';
|
||||
import { useStore } from './store';
|
||||
import { filterInitStates } from '../scripts/constants/stores/initFilterStates';
|
||||
@@ -13,31 +12,28 @@ export const useStationFiltersStore = defineStore('stationFiltersStore', {
|
||||
inputs: inputData,
|
||||
filters: { ...filterInitStates },
|
||||
sorterActive: { headerName: 'station' as HeadIdsTypes, dir: 1 },
|
||||
store: useStore(),
|
||||
lastClickedFilterId: ''
|
||||
};
|
||||
},
|
||||
|
||||
getters: {
|
||||
areFiltersAtDefault(state) {
|
||||
areFiltersAtDefault: (state) => {
|
||||
return Object.keys(state.filters).every((f) => state.filters[f] === filterInitStates[f]);
|
||||
},
|
||||
|
||||
filteredStationList: (state) => {
|
||||
const store = useStore();
|
||||
return store.stationList
|
||||
.map((station) => ({
|
||||
...station,
|
||||
onlineInfo: store.onlineSceneryList.find((os) => os.name == station.name)
|
||||
}))
|
||||
.filter((station) => filterStations(station, state.filters))
|
||||
.sort((a, b) => sortStations(a, b, state.sorterActive));
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
getFilteredStationList(stationList: Station[], region: string): Station[] {
|
||||
return stationList
|
||||
.map((station) => {
|
||||
if (station.onlineInfo && station.onlineInfo.region != region) {
|
||||
delete station.onlineInfo;
|
||||
}
|
||||
|
||||
return station;
|
||||
})
|
||||
.filter((station) => filterStations(station, this.filters))
|
||||
.sort((a, b) => sortStations(a, b, this.sorterActive));
|
||||
},
|
||||
|
||||
setupFilters() {
|
||||
if (!StorageManager.isRegistered('options_saved')) return;
|
||||
|
||||
|
||||
+108
-189
@@ -9,12 +9,18 @@ import StationRoutes from '../scripts/interfaces/StationRoutes';
|
||||
import Train from '../scripts/interfaces/Train';
|
||||
import { URLs } from '../scripts/utils/apiURLs';
|
||||
import {
|
||||
getStatusTimestamp,
|
||||
getStatusID,
|
||||
getScheduledTrain,
|
||||
parseSpawns
|
||||
getDispatcherStatus,
|
||||
getCheckpointTrain,
|
||||
parseSpawns,
|
||||
getScheduledTrains,
|
||||
getStationTrains
|
||||
} from '../scripts/utils/storeUtils';
|
||||
import { APIData, StationJSONData, StoreState } from '../scripts/interfaces/store/storeTypes';
|
||||
import {
|
||||
APIData,
|
||||
OnlineScenery,
|
||||
StationJSONData,
|
||||
StoreState
|
||||
} from '../scripts/interfaces/store/storeTypes';
|
||||
import packageInfo from '../../package.json';
|
||||
import { RollingStockGithubData } from '../scripts/interfaces/github_api/StockInfoGithubData';
|
||||
|
||||
@@ -25,7 +31,7 @@ export const useStore = defineStore('store', {
|
||||
rollingStockData: undefined,
|
||||
|
||||
stationList: [],
|
||||
trainList: [],
|
||||
|
||||
routesList: [],
|
||||
|
||||
sceneryData: [],
|
||||
@@ -63,13 +69,9 @@ export const useStore = defineStore('store', {
|
||||
modalLastClickedTarget: null
|
||||
}) as StoreState,
|
||||
|
||||
actions: {
|
||||
setTrainsOnlineData() {
|
||||
const { trains } = this.apiData;
|
||||
|
||||
if (!trains) return [];
|
||||
|
||||
this.trainList = trains
|
||||
getters: {
|
||||
trainList(): Train[] {
|
||||
return (this.apiData?.trains ?? [])
|
||||
.filter(
|
||||
(train) =>
|
||||
train.region === this.region.id &&
|
||||
@@ -123,193 +125,113 @@ export const useStore = defineStore('store', {
|
||||
});
|
||||
},
|
||||
|
||||
getDispatcherStatus(onlineStationData: StationAPIData) {
|
||||
const { dispatchers } = this.apiData;
|
||||
onlineSceneryList(state): OnlineScenery[] {
|
||||
if (state.isOffline) return [];
|
||||
if (!state.apiData?.stations) return [];
|
||||
|
||||
const prevDispatcherStatus = this.lastDispatcherStatuses.find(
|
||||
(dispatcher) => dispatcher.hash === onlineStationData.stationHash
|
||||
);
|
||||
return state.apiData?.stations
|
||||
?.filter((apiStation) => apiStation.region == state.region.id && apiStation.isOnline)
|
||||
.map((apiStation) => {
|
||||
const dispatcherStatus = getDispatcherStatus(state as StoreState, apiStation);
|
||||
const station = this.stationList.find((s) => s.name === apiStation.stationName);
|
||||
|
||||
const stationStatus = !dispatchers
|
||||
? undefined
|
||||
: dispatchers.find(
|
||||
(status: string[]) =>
|
||||
status[0] == onlineStationData.stationHash && status[1] == this.region.id
|
||||
) || -1;
|
||||
const scheduledTrains = getScheduledTrains(
|
||||
this.trainList,
|
||||
apiStation,
|
||||
station?.generalInfo
|
||||
);
|
||||
|
||||
const statusTimestamp =
|
||||
prevDispatcherStatus && !dispatchers
|
||||
? prevDispatcherStatus.statusTimestamp
|
||||
: getStatusTimestamp(stationStatus);
|
||||
const statusID =
|
||||
prevDispatcherStatus && !dispatchers
|
||||
? prevDispatcherStatus.statusID
|
||||
: getStatusID(stationStatus);
|
||||
const stationTrains = getStationTrains(
|
||||
this.trainList,
|
||||
scheduledTrains,
|
||||
this.region.id,
|
||||
apiStation
|
||||
);
|
||||
|
||||
return {
|
||||
hash: onlineStationData.stationHash,
|
||||
statusID,
|
||||
statusTimestamp
|
||||
};
|
||||
},
|
||||
|
||||
getScheduledTrains(stationGeneralInfo: Station['generalInfo'], stationAPIData: StationAPIData) {
|
||||
const stationName = stationAPIData.stationName.toLowerCase();
|
||||
|
||||
stationGeneralInfo?.checkpoints.forEach((cp) => (cp.scheduledTrains.length = 0));
|
||||
|
||||
return this.trainList.reduce((acc: ScheduledTrain[], train) => {
|
||||
if (!train.timetableData) return acc;
|
||||
|
||||
const timetable = train.timetableData;
|
||||
if (!timetable.sceneries.includes(stationAPIData.stationHash)) return acc;
|
||||
|
||||
const stopInfoIndex = timetable.followingStops.findIndex((stop) => {
|
||||
const stopName = stop.stopNameRAW.toLowerCase();
|
||||
|
||||
if (stationName === stopName) return true;
|
||||
if (
|
||||
stopName.includes(stationName) &&
|
||||
!stop.stopName.includes('po.') &&
|
||||
!stop.stopName.includes('podg.')
|
||||
)
|
||||
return true;
|
||||
|
||||
if (
|
||||
stationName.includes(stopName) &&
|
||||
!stop.stopName.includes('po.') &&
|
||||
!stop.stopName.includes('podg.')
|
||||
)
|
||||
return true;
|
||||
|
||||
if (
|
||||
stopName.includes('podg.') &&
|
||||
stopName.split(', podg.')[0] &&
|
||||
stationName.includes(stopName.split(', podg.')[0])
|
||||
)
|
||||
return true;
|
||||
|
||||
if (
|
||||
stationGeneralInfo &&
|
||||
stationGeneralInfo.checkpoints &&
|
||||
stationGeneralInfo.checkpoints.length > 0 &&
|
||||
stationGeneralInfo.checkpoints.some((cp) =>
|
||||
cp.checkpointName.toLowerCase().includes(stop.stopNameRAW.toLowerCase())
|
||||
)
|
||||
)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return {
|
||||
name: apiStation.stationName,
|
||||
hash: apiStation.stationHash,
|
||||
region: apiStation.region,
|
||||
maxUsers: apiStation.maxUsers,
|
||||
currentUsers: apiStation.currentUsers,
|
||||
spawns: parseSpawns(apiStation.spawnString),
|
||||
dispatcherName: apiStation.dispatcherName,
|
||||
dispatcherRate: apiStation.dispatcherRate,
|
||||
dispatcherId: apiStation.dispatcherId,
|
||||
dispatcherExp: apiStation.dispatcherExp,
|
||||
dispatcherIsSupporter: apiStation.dispatcherIsSupporter,
|
||||
scheduledTrains: scheduledTrains,
|
||||
stationTrains: stationTrains,
|
||||
statusTimestamp: dispatcherStatus.statusTimestamp,
|
||||
statusID: dispatcherStatus.statusID
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
// setStationsOnlineInfo() {
|
||||
// const onlineStationNames: string[] = [];
|
||||
// const prevDispatcherStatuses: StoreState['lastDispatcherStatuses'] = [];
|
||||
|
||||
if (stopInfoIndex == -1) return acc;
|
||||
// if (this.isOffline) {
|
||||
// this.stationList.forEach((station) => {
|
||||
// station.onlineInfo = undefined;
|
||||
// });
|
||||
|
||||
const scheduledStopTrain = getScheduledTrain(
|
||||
train,
|
||||
stopInfoIndex,
|
||||
stationAPIData.stationName
|
||||
);
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (stationGeneralInfo?.checkpoints) {
|
||||
for (const checkpoint of stationGeneralInfo.checkpoints) {
|
||||
const index = timetable.followingStops.findIndex(
|
||||
(stop) => stop.stopNameRAW.toLowerCase() == checkpoint.checkpointName.toLowerCase()
|
||||
);
|
||||
// this.apiData.stations?.forEach((stationAPIData) => {
|
||||
// if (stationAPIData.region !== this.region.id || !stationAPIData.isOnline) return;
|
||||
|
||||
if (index == -1) continue;
|
||||
// const station = this.stationList.find((s) => s.name === stationAPIData.stationName);
|
||||
|
||||
const scheduledCheckpointTrain = getScheduledTrain(
|
||||
train,
|
||||
index,
|
||||
stationAPIData.stationName
|
||||
);
|
||||
checkpoint.scheduledTrains.push(scheduledCheckpointTrain);
|
||||
}
|
||||
}
|
||||
// onlineStationNames.push(stationAPIData.stationName);
|
||||
|
||||
acc.push(scheduledStopTrain);
|
||||
return acc;
|
||||
}, []) as ScheduledTrain[];
|
||||
},
|
||||
// const dispatcherStatus = this.getDispatcherStatus(stationAPIData);
|
||||
// prevDispatcherStatuses.push(dispatcherStatus);
|
||||
|
||||
getStationTrains(stationAPIData: StationAPIData) {
|
||||
return this.trainList
|
||||
.filter(
|
||||
(train) =>
|
||||
train?.region === this.region.id &&
|
||||
train.online &&
|
||||
train.currentStationName === stationAPIData.stationName
|
||||
)
|
||||
.map((train) => ({
|
||||
driverName: train.driverName,
|
||||
driverId: train.driverId,
|
||||
trainNo: train.trainNo,
|
||||
trainId: train.trainId
|
||||
}));
|
||||
},
|
||||
// const stationTrains = this.getStationTrains(stationAPIData);
|
||||
// const scheduledTrains = this.getScheduledTrains(station?.generalInfo, stationAPIData);
|
||||
|
||||
setStationsOnlineInfo() {
|
||||
const onlineStationNames: string[] = [];
|
||||
const prevDispatcherStatuses: StoreState['lastDispatcherStatuses'] = [];
|
||||
// const onlineInfo = {
|
||||
// name: stationAPIData.stationName,
|
||||
// hash: stationAPIData.stationHash,
|
||||
// region: stationAPIData.region,
|
||||
// maxUsers: stationAPIData.maxUsers,
|
||||
// currentUsers: stationAPIData.currentUsers,
|
||||
// spawns: parseSpawns(stationAPIData.spawnString),
|
||||
// dispatcherName: stationAPIData.dispatcherName,
|
||||
// dispatcherRate: stationAPIData.dispatcherRate,
|
||||
// dispatcherId: stationAPIData.dispatcherId,
|
||||
// dispatcherExp: stationAPIData.dispatcherExp,
|
||||
// dispatcherIsSupporter: stationAPIData.dispatcherIsSupporter,
|
||||
// stationTrains,
|
||||
// statusTimestamp: dispatcherStatus.statusTimestamp,
|
||||
// statusID: dispatcherStatus.statusID,
|
||||
// scheduledTrains
|
||||
// };
|
||||
|
||||
if (this.isOffline) {
|
||||
this.stationList.forEach((station) => {
|
||||
station.onlineInfo = undefined;
|
||||
});
|
||||
// if (!station) {
|
||||
// this.stationList.push({
|
||||
// name: stationAPIData.stationName,
|
||||
// onlineInfo
|
||||
// });
|
||||
|
||||
return;
|
||||
}
|
||||
// return;
|
||||
// }
|
||||
|
||||
this.apiData.stations?.forEach((stationAPIData) => {
|
||||
if (stationAPIData.region !== this.region.id || !stationAPIData.isOnline) return;
|
||||
const station = this.stationList.find((s) => s.name === stationAPIData.stationName);
|
||||
// station.onlineInfo = { ...onlineInfo };
|
||||
// });
|
||||
|
||||
onlineStationNames.push(stationAPIData.stationName);
|
||||
// this.stationList
|
||||
// .filter((station) => !onlineStationNames.includes(station.name) && station.onlineInfo)
|
||||
// .forEach((offlineStation) => {
|
||||
// offlineStation.onlineInfo = undefined;
|
||||
// });
|
||||
|
||||
const dispatcherStatus = this.getDispatcherStatus(stationAPIData);
|
||||
prevDispatcherStatuses.push(dispatcherStatus);
|
||||
|
||||
const stationTrains = this.getStationTrains(stationAPIData);
|
||||
const scheduledTrains = this.getScheduledTrains(station?.generalInfo, stationAPIData);
|
||||
|
||||
const onlineInfo = {
|
||||
name: stationAPIData.stationName,
|
||||
hash: stationAPIData.stationHash,
|
||||
region: stationAPIData.region,
|
||||
maxUsers: stationAPIData.maxUsers,
|
||||
currentUsers: stationAPIData.currentUsers,
|
||||
spawns: parseSpawns(stationAPIData.spawnString),
|
||||
dispatcherName: stationAPIData.dispatcherName,
|
||||
dispatcherRate: stationAPIData.dispatcherRate,
|
||||
dispatcherId: stationAPIData.dispatcherId,
|
||||
dispatcherExp: stationAPIData.dispatcherExp,
|
||||
dispatcherIsSupporter: stationAPIData.dispatcherIsSupporter,
|
||||
stationTrains,
|
||||
statusTimestamp: dispatcherStatus.statusTimestamp,
|
||||
statusID: dispatcherStatus.statusID,
|
||||
scheduledTrains
|
||||
};
|
||||
|
||||
if (!station) {
|
||||
this.stationList.push({
|
||||
name: stationAPIData.stationName,
|
||||
onlineInfo
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
station.onlineInfo = { ...onlineInfo };
|
||||
|
||||
this.stationList
|
||||
.filter((station) => !onlineStationNames.includes(station.name) && station.onlineInfo)
|
||||
.forEach((offlineStation) => {
|
||||
offlineStation.onlineInfo = undefined;
|
||||
});
|
||||
});
|
||||
|
||||
if (this.apiData.dispatchers != null) this.lastDispatcherStatuses = prevDispatcherStatuses;
|
||||
},
|
||||
// if (this.apiData.dispatchers != null) this.lastDispatcherStatuses = prevDispatcherStatuses;
|
||||
// },
|
||||
|
||||
async fetchStationsGeneralInfo() {
|
||||
const sceneryData: StationJSONData[] = await (
|
||||
@@ -385,7 +307,7 @@ export const useStore = defineStore('store', {
|
||||
}
|
||||
|
||||
const socket = io(URLs.stacjownikAPI, {
|
||||
// transports: ['websocket', 'polling'],
|
||||
transports: ['websocket', 'polling'],
|
||||
rememberUpgrade: true,
|
||||
reconnection: true,
|
||||
extraHeaders: {
|
||||
@@ -405,7 +327,6 @@ export const useStore = defineStore('store', {
|
||||
|
||||
socket.emit('FETCH_DATA', { version: packageInfo.version }, (data: APIData) => {
|
||||
this.dataStatuses.connection = DataStatus.Loaded;
|
||||
|
||||
this.apiData = data;
|
||||
this.setOnlineData();
|
||||
});
|
||||
@@ -414,10 +335,9 @@ export const useStore = defineStore('store', {
|
||||
},
|
||||
|
||||
async connectToAPI() {
|
||||
await this.fetchStationsGeneralInfo();
|
||||
await this.fetchStockInfoData();
|
||||
|
||||
this.connectToWebsocket();
|
||||
this.fetchStockInfoData();
|
||||
this.fetchStationsGeneralInfo();
|
||||
},
|
||||
|
||||
async changeRegion(region: StoreState['region']) {
|
||||
@@ -453,8 +373,7 @@ export const useStore = defineStore('store', {
|
||||
? DataStatus.Warning
|
||||
: DataStatus.Loaded;
|
||||
|
||||
this.setTrainsOnlineData();
|
||||
this.setStationsOnlineInfo();
|
||||
// this.setStationsOnlineInfo();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -35,10 +35,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--clr-bg);
|
||||
|
||||
|
||||
+35
-25
@@ -1,9 +1,6 @@
|
||||
<template>
|
||||
<div class="scenery-view">
|
||||
<div
|
||||
class="scenery-offline"
|
||||
v-if="!stationInfo && isComponentVisible && store.dataStatuses.sceneries == 2"
|
||||
>
|
||||
<div class="scenery-offline" v-if="!stationInfo && store.dataStatuses.sceneries == 2">
|
||||
<div>{{ $t('scenery.no-scenery') }}</div>
|
||||
|
||||
<action-button>
|
||||
@@ -11,21 +8,16 @@
|
||||
</action-button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="scenery-wrapper"
|
||||
v-if="stationInfo"
|
||||
ref="card-wrapper"
|
||||
:data-timetable-only="timetableOnly"
|
||||
>
|
||||
<div class="scenery-left" v-if="!timetableOnly">
|
||||
<div class="scenery-wrapper" v-if="stationInfo" ref="card-wrapper">
|
||||
<div class="scenery-left">
|
||||
<div class="scenery-actions">
|
||||
<button class="back-btn btn" :title="$t('scenery.return-btn')" @click="navigateTo('/')">
|
||||
<img src="/images/icon-back.svg" alt="Back to scenery" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<SceneryHeader :station="stationInfo" />
|
||||
<SceneryInfo :station="stationInfo" />
|
||||
<SceneryHeader :station="stationInfo" :onlineScenery="onlineSceneryInfo" />
|
||||
<SceneryInfo :station="stationInfo" :onlineScenery="onlineSceneryInfo" />
|
||||
</div>
|
||||
|
||||
<div class="scenery-right">
|
||||
@@ -44,6 +36,7 @@
|
||||
<keep-alive>
|
||||
<component
|
||||
:is="currentViewCompontent"
|
||||
:onlineScenery="onlineSceneryInfo"
|
||||
:station="stationInfo"
|
||||
:key="currentViewCompontent"
|
||||
></component>
|
||||
@@ -82,9 +75,22 @@ export default defineComponent({
|
||||
SceneryDispatchersHistory
|
||||
},
|
||||
|
||||
props: {
|
||||
region: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
|
||||
station: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
mixins: [routerMixin],
|
||||
|
||||
data: () => ({
|
||||
store: useStore(),
|
||||
viewModes: [
|
||||
{
|
||||
id: 'scenery.option-active-timetables',
|
||||
@@ -111,24 +117,28 @@ export default defineComponent({
|
||||
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const store = useStore();
|
||||
|
||||
const timetableOnly = computed(() => (route.query['timetableOnly'] == '1' ? true : false));
|
||||
const isComponentVisible = computed(() => route.path === '/scenery');
|
||||
|
||||
const stationInfo = computed(() => {
|
||||
return store.stationList.find(
|
||||
(station) => station.name === route.query.station?.toString().replace(/_/g, ' ')
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
timetableOnly,
|
||||
isComponentVisible,
|
||||
stationInfo,
|
||||
store
|
||||
isComponentVisible
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
stationInfo() {
|
||||
return this.store.stationList.find(
|
||||
(station) => station.name === this.station?.toString().replace(/_/g, ' ')
|
||||
);
|
||||
},
|
||||
|
||||
onlineSceneryInfo() {
|
||||
return this.store.onlineSceneryList.find(
|
||||
(scenery) => scenery.name === this.station?.toString().replace(/_/g, ' ')
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setViewMode(componentName: string) {
|
||||
this.currentViewCompontent = componentName;
|
||||
|
||||
@@ -33,19 +33,15 @@ export default defineComponent({
|
||||
filterCardOpen: false,
|
||||
modalHidden: true,
|
||||
STORAGE_KEY: 'options_saved',
|
||||
focusedStationName: ''
|
||||
focusedStationName: '',
|
||||
filterStore: useStationFiltersStore(),
|
||||
store: useStore()
|
||||
}),
|
||||
|
||||
setup() {
|
||||
return {
|
||||
filterStore: useStationFiltersStore(),
|
||||
store: useStore()
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
computedStationList() {
|
||||
return this.filterStore.getFilteredStationList(this.store.stationList, this.store.region.id);
|
||||
return this.filterStore.filteredStationList;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user