Restrukturyzacja pobierania danych, zmiany w wyglądzie

This commit is contained in:
2020-09-10 21:25:10 +02:00
parent 5adb990361
commit 4ef90e655d
17 changed files with 553 additions and 225 deletions
+22 -17
View File
@@ -13,9 +13,9 @@
<Clock /> <Clock />
<div class="counter"> <div class="counter">
<img src="@/assets/icon-dispatcher.svg" alt="icon dispatcher" /> <img src="@/assets/icon-dispatcher.svg" alt="icon dispatcher" />
<span>{{onlineInfo.stationCount}}</span> <span>{{data.stationCount}}</span>
<span>{{onlineInfo.trainCount}}</span> <span>{{data.trainCount}}</span>
<img src="@/assets/icon-train.svg" alt="icon train" /> <img src="@/assets/icon-train.svg" alt="icon train" />
</div> </div>
</span> </span>
@@ -40,10 +40,10 @@
</footer> </footer>
<transition name="message-anim" mode="out-in"> <transition name="message-anim" mode="out-in">
<span :key="connState"> <span :key="data.dataConnectionStatus">
<div class="message loading" v-if="connState == 0">Pobieranie danych...</div> <div class="message loading" v-if="data.dataConnectionStatus == 0">Pobieranie danych...</div>
<div class="message error" v-if="connState == 1"> <div class="message error" v-if="data.dataConnectionStatus == 1">
<img :src="ErrorIcon" alt="Error" /> <img :src="ErrorIcon" alt="Error" />
Brak odpowiedzi ze strony serwera! Brak odpowiedzi ze strony serwera!
</div> </div>
@@ -67,20 +67,25 @@ import Clock from "@/components/App/Clock.vue";
export default class App extends Vue { export default class App extends Vue {
ErrorIcon = require("@/assets/icon-error.svg"); ErrorIcon = require("@/assets/icon-error.svg");
@Getter("getOnlineInfo") onlineInfo; @Action("synchronizeData") synchronizeData;
@Getter("getConnectionState") connState;
@Action("initStations") initStations; @Getter("getAllData") data;
@Action("fetchOnlineStations") fetchStations; // @Getter("getOnlineInfo") onlineInfo;
@Action("fetchTrainsData") fetchTrainsData; // @Getter("getConnectionState") connState;
async mounted() { // @Action("initStations") initStations;
this.initStations();
this.fetchTrainsData();
setInterval(this.fetchStations, 15000); // @Action("fetchOnlineStations") fetchStations;
setInterval(this.fetchTrainsData, 10000); // @Action("fetchTrainsData") fetchTrainsData;
mounted() {
this.synchronizeData();
// this.initStations();
// this.fetchTrainsData();
// setInterval(this.fetchStations, 15000);
// setInterval(this.fetchTrainsData, 45000);
} }
} }
</script> </script>
@@ -161,10 +166,10 @@ export default class App extends Vue {
background: $bgCol; background: $bgCol;
color: white; color: white;
font-size: calc(1rem + 2.1vw); font-size: calc(1.1rem + 2.1vw);
@include smallScreen() { @include smallScreen() {
font-size: 2rem; font-size: 2.5rem;
} }
} }
+1 -1
View File
@@ -34,7 +34,7 @@ export default Vue.extend({
align-items: center; align-items: center;
@include smallScreen() { @include smallScreen() {
font-size: 0.65rem; font-size: 0.95rem;
} }
} }
</style> </style>
+2 -2
View File
@@ -165,8 +165,8 @@ export default class FilterCard extends Vue {
box-shadow: 0 0 15px 5px #474747; box-shadow: 0 0 15px 5px #474747;
@include smallScreen() { @include smallScreen() {
width: 85vw; width: 100%;
font-size: calc(0.3em + 1vw); font-size: calc(0.7em + 1.1vw);
} }
@include bigScreen { @include bigScreen {
+34 -8
View File
@@ -124,11 +124,12 @@
<div class="users-content"> <div class="users-content">
<div <div
class="user" class="user"
v-for="train in stationInfo.trains" v-for="train in stationInfo.stationTrains"
:key="train.trainNo + train.driverName" :key="train.trainNo + train.driverName"
:class="{'no-timetable': !hasTimetable(train.trainNo)}"
> >
<a <a
:href="'https://rj.td2.info.pl/train#' + train.trainNo + ';eu'" :href="`https://rj.td2.info.pl/train#${train.trainNo};eu`"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
@@ -140,7 +141,7 @@
<span <span
class="user borderless" class="user borderless"
v-if="!stationInfo.trains || stationInfo.trains.length == 0" v-if="!stationInfo.stationTrains || stationInfo.stationTrains.length == 0"
>BRAK</span> >BRAK</span>
</div> </div>
</div> </div>
@@ -174,16 +175,19 @@
</span> </span>
<span class="general-confirmed"> <span class="general-confirmed">
<span style="color: lime" v-if="timetable.confirmed">Odprawiony</span>
<span <span
style="color: gold" style="color: gold"
v-if="timetable.stopped || (timetable.beginsHere && !timetable.confirmed)" v-else-if="timetable.currentStationName == stationInfo.stationName"
>Na stacji</span> >Na stacji</span>
<span style="color: #FF4646" v-else-if="timetable.stopped">Postój</span>
<span style="color: #aaa" v-else-if="!timetable.confirmed">W drodze</span> <span style="color: #aaa" v-else-if="!timetable.confirmed">W drodze</span>
<span <span
style="color: red" style="color: red"
v-else-if="(timetable.terminatesHere && timetable.confirmed)" v-else-if="(timetable.terminatesHere && timetable.confimed)"
>Skończył bieg</span> >Skończył bieg</span>
<span style="color: lime" v-else>Odprawiony</span>
</span> </span>
</span> </span>
@@ -220,6 +224,8 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Watch } from "vue-property-decorator"; import { Component, Prop, Watch } from "vue-property-decorator";
import { Getter } from "vuex-class";
import styleMixin from "@/mixins/styleMixin"; import styleMixin from "@/mixins/styleMixin";
import Station from "@/scripts/interfaces/Station"; import Station from "@/scripts/interfaces/Station";
@@ -228,8 +234,8 @@ import Station from "@/scripts/interfaces/Station";
export default class StationCard extends styleMixin { export default class StationCard extends styleMixin {
@Prop() stationInfo!: Station; @Prop() stationInfo!: Station;
@Prop() exit!: void; @Prop() exit!: void;
@Getter('getTrainList') trains;
history: any[] = [];
cardMode: number = 0; cardMode: number = 0;
get computedExp(): string { get computedExp(): string {
@@ -239,6 +245,7 @@ export default class StationCard extends styleMixin {
: `${this.stationInfo.dispatcherExp}`; : `${this.stationInfo.dispatcherExp}`;
} }
get computedScheduledTrains() { get computedScheduledTrains() {
return this.stationInfo.scheduledTrains.sort((a, b) => { return this.stationInfo.scheduledTrains.sort((a, b) => {
if (a.arrivalTime > b.arrivalTime) return 1; if (a.arrivalTime > b.arrivalTime) return 1;
@@ -248,6 +255,10 @@ export default class StationCard extends styleMixin {
}) })
} }
hasTimetable(trainNo: number) {
return this.trains.find(train => train.timetableData && train.trainNo === trainNo);
}
timestampToTime(timestamp: number) { timestampToTime(timestamp: number) {
return new Date(timestamp).toLocaleTimeString('pl-PL', { return new Date(timestamp).toLocaleTimeString('pl-PL', {
hour: '2-digit', hour: '2-digit',
@@ -286,10 +297,16 @@ export default class StationCard extends styleMixin {
&-exit { &-exit {
z-index: 3; z-index: 3;
display: flex;
align-items: center;
img { img {
margin: 0.1em 0.3em;
font-size: 1.6em; font-size: 1.6em;
margin: 0.1em 0.1em;
}
.schedule-icon {
font-size: 1.4em;
} }
} }
@@ -451,6 +468,15 @@ export default class StationCard extends styleMixin {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
&.no-timetable {
border: 1px solid #aaa;
a {
color: #aaa;
pointer-events: none;
}
}
} }
} }
} }
@@ -144,8 +144,6 @@
import Vue from "vue"; import Vue from "vue";
import { Component, Prop } from "vue-property-decorator"; import { Component, Prop } from "vue-property-decorator";
import { Getter } from "vuex-class";
import Station from "@/scripts/interfaces/Station"; import Station from "@/scripts/interfaces/Station";
import Train from "@/scripts/interfaces/Train"; import Train from "@/scripts/interfaces/Train";
+26 -18
View File
@@ -77,7 +77,7 @@ export default class TrainStats extends Vue {
).toFixed(2); ).toFixed(2);
const minMax = this.trains.reduce((acc, train) => { const minMax = this.trains.reduce((acc, train) => {
if (train.noTimetable) return acc; if (!train.timetableData) return acc;
acc[0] = acc[0] =
acc[0] === undefined || train.speed < acc[0] ? train.speed : acc[0]; acc[0] === undefined || train.speed < acc[0] ? train.speed : acc[0];
@@ -94,21 +94,21 @@ export default class TrainStats extends Vue {
if (this.trains.length == 0) return { avg: "0", min: "0", max: "0" }; if (this.trains.length == 0) return { avg: "0", min: "0", max: "0" };
const avg = ( const avg = (
this.trains.reduce((acc, train) => acc + train.routeDistance, 0) / this.trains.reduce((acc, train) => train.timetableData ? acc + train.timetableData.routeDistance : acc, 0) /
this.trains.length this.trains.length
).toFixed(2); ).toFixed(2);
const minMax = this.trains.reduce((acc, train) => { const minMax = this.trains.reduce((acc, train) => {
if (train.noTimetable) return acc; if (!train.timetableData) return acc;
acc[0] = acc[0] =
acc[0] === undefined || train.routeDistance < acc[0] acc[0] === undefined || train.timetableData.routeDistance < acc[0]
? train.routeDistance ? train.timetableData.routeDistance
: acc[0]; : acc[0];
acc[1] = acc[1] =
acc[1] === undefined || train.routeDistance > acc[1] acc[1] === undefined || train.timetableData.routeDistance > acc[1]
? train.routeDistance ? train.timetableData.routeDistance
: acc[1]; : acc[1];
return acc; return acc;
}, [] as any); }, [] as any);
@@ -118,11 +118,11 @@ export default class TrainStats extends Vue {
get categoryList(): Map<string, number> { get categoryList(): Map<string, number> {
const map = this.trains.reduce((acc, train) => { const map = this.trains.reduce((acc, train) => {
if (train.noTimetable || !train.category) return acc; if (!train.timetableData || !train.timetableData.category) return acc;
acc.set( acc.set(
train.category, train.timetableData.category,
acc.get(train.category) ? acc.get(train.category) + 1 : 1 acc.get(train.timetableData.category) ? acc.get(train.timetableData.category) + 1 : 1
); );
return acc; return acc;
@@ -133,7 +133,7 @@ export default class TrainStats extends Vue {
get locoList(): any[] { get locoList(): any[] {
const map = this.trains.reduce((acc, train) => { const map = this.trains.reduce((acc, train) => {
if (train.noTimetable || !train.locoType) return acc; if (!train.timetableData || !train.locoType) return acc;
acc.set( acc.set(
train.locoType, train.locoType,
@@ -151,8 +151,8 @@ export default class TrainStats extends Vue {
} }
get specialTrainCount(): [number, number] { get specialTrainCount(): [number, number] {
const twrList = this.trains.filter((train) => train.TWR); const twrList = this.trains.filter((train) => train.timetableData && train.timetableData.TWR);
const skrList = this.trains.filter((train) => train.SKR); const skrList = this.trains.filter((train) => train.timetableData && train.timetableData.SKR);
return [twrList.length, skrList.length]; return [twrList.length, skrList.length];
} }
@@ -177,18 +177,18 @@ export default class TrainStats extends Vue {
.train-stats { .train-stats {
padding: 0.3em 0; padding: 0.3em 0;
font-size: 0.9em; font-size: 1.1em;
position: relative; position: relative;
} }
.button { .button {
font-size: 1.1em; font-size: 1em;
padding: 0.5em; padding: 0.5em;
} }
.content { .content {
font-size: 1.2em; font-size: 1.1em;
color: #ddd; color: #ddd;
} }
@@ -199,7 +199,7 @@ export default class TrainStats extends Vue {
.stats-body { .stats-body {
position: absolute; position: absolute;
display: inline-block; display: inline-block;
max-width: 800px; max-width: 700px;
background: rgba(black, 0.85); background: rgba(black, 0.85);
border-radius: 0 1em 1em 1em; border-radius: 0 1em 1em 1em;
@@ -213,6 +213,8 @@ export default class TrainStats extends Vue {
} }
.category { .category {
font-size: 0.9em;
margin-right: 0.4em; margin-right: 0.4em;
margin-bottom: 0.4em; margin-bottom: 0.4em;
@@ -256,11 +258,17 @@ export default class TrainStats extends Vue {
@include smallScreen { @include smallScreen {
.button { .button {
font-size: 0.9rem; font-size: 0.85rem;
} }
.stats-body { .stats-body {
display: block; display: block;
font-size: 0.9em;
// position: fixed;
// top: 0;
// left: 0;
width: 100%; width: 100%;
// height: 100%;
border-radius: 0 0 1em 1em; border-radius: 0 0 1em 1em;
} }
+7 -10
View File
@@ -8,31 +8,31 @@
<div class="info-top"> <div class="info-top">
<div class="info-category"> <div class="info-category">
<span> <span>
<strong>{{ train.category }}</strong> <strong>{{ train.timetableData.category }}</strong>
{{ train.trainNo }} | {{ train.trainNo }} |
</span> </span>
<span style=" color: gold;">{{ train.routeDistance }} km</span> <span style=" color: gold;">{{ train.timetableData.routeDistance }} km</span>
</div> </div>
<div class="info-warnings"> <div class="info-warnings">
<span class="warning twr" v-if="train.TWR">TWR</span> <span class="warning twr" v-if="train.timetableData.TWR">TWR</span>
<span class="warning skr" v-if="train.SKR">SKR</span> <span class="warning skr" v-if="train.timetableData.SKR">SKR</span>
</div> </div>
<div class="info-route"> <div class="info-route">
<a :href="'https://rj.td2.info.pl/train#' + train.trainNo + ';eu'" target="_blank"> <a :href="'https://rj.td2.info.pl/train#' + train.trainNo + ';eu'" target="_blank">
<strong> <strong>
{{ {{
train.route && train.route.replace("|", " - ") train.timetableData.route.replace("|", " - ")
}} }}
</strong> </strong>
</a> </a>
</div> </div>
<div class="info-stations"> <div class="info-stations">
<span v-if="train.followingStops.length > 2"> <span v-if="train.timetableData.followingStops.length > 2">
Przez: Przez:
<span v-html="generateStopList(train.followingStops)"></span> <span v-html="generateStopList(train.timetableData.followingStops)"></span>
</span> </span>
</div> </div>
</div> </div>
@@ -114,7 +114,6 @@
<script lang="ts"> <script lang="ts">
import { Vue, Component, Prop } from "vue-property-decorator"; import { Vue, Component, Prop } from "vue-property-decorator";
import { Getter } from "vuex-class";
const unknownTrainImage = require("@/assets/unknown.png"); const unknownTrainImage = require("@/assets/unknown.png");
@@ -125,8 +124,6 @@ import Station from "@/scripts/interfaces/Station";
export default class TrainTable extends Vue { export default class TrainTable extends Vue {
@Prop() readonly computedTrains!: Train[]; @Prop() readonly computedTrains!: Train[];
@Getter("getAllStations") stations!: Station[];
speedIcon: string = require("@/assets/icon-speed.svg"); speedIcon: string = require("@/assets/icon-speed.svg");
massIcon: string = require("@/assets/icon-mass.svg"); massIcon: string = require("@/assets/icon-mass.svg");
lengthIcon: string = require("@/assets/icon-length.svg"); lengthIcon: string = require("@/assets/icon-length.svg");
+2 -3
View File
@@ -1720,7 +1720,7 @@
"stationName": "Sól", "stationName": "Sól",
"stationURL": "https://td2.info.pl/scenerie/sol/", "stationURL": "https://td2.info.pl/scenerie/sol/",
"stationLines": "139", "stationLines": "139",
"reqLevel": "0", "reqLevel": "2",
"supportersOnly": "NIE", "supportersOnly": "NIE",
"signalType": "współczesna", "signalType": "współczesna",
"controlType": "SPK", "controlType": "SPK",
@@ -1784,8 +1784,7 @@
} }
}, },
"default": false, "default": false,
"nonPublic": false, "nonPublic": false
"unavailable": true
}, },
{ {
"stationName": "Głęboszów", "stationName": "Głęboszów",
+9 -3
View File
@@ -1,3 +1,5 @@
import Train from '@/scripts/interfaces/Train';
export default interface Station { export default interface Station {
stationName: string; stationName: string;
stationHash: string; stationHash: string;
@@ -23,20 +25,24 @@ export default interface Station {
online: boolean; online: boolean;
occupiedTo: string; occupiedTo: string;
statusTimestamp: number; statusTimestamp: number;
stationTrains: Train[];
scheduledTrains: { scheduledTrains: {
trainNo: number; trainNo: number;
driverName: string; driverName: string;
category: string; driverId: number;
currentStationName: string;
stopName: string; stopName: string;
stopType: string; stopType: string;
arrivalLine?: string;
arrivalTime: number; arrivalTime: number;
arrivalDelay: number; arrivalDelay: number;
departureLine?: string;
departureTime: number; departureTime: number;
beginsHere: boolean;
terminatesHere: boolean;
departureDelay: number; departureDelay: number;
confirmed: boolean; confirmed: boolean;
stopped: boolean; stopped: boolean;
stopTime: number; stopTime: number;
beginsHere: boolean;
terminatesHere: boolean;
}[]; }[];
} }
+16
View File
@@ -0,0 +1,16 @@
export default interface Timetable {
trainNo: number;
driverName: string;
category: string;
stopName: string;
stopType: string;
arrivalTime: number;
arrivalDelay: number;
departureTime: number;
departureDelay: number;
confirmed: boolean;
stopped: boolean;
stopTime: number;
beginsHere: boolean;
terminatesHere: boolean;
}
+24 -26
View File
@@ -9,33 +9,31 @@ export default interface Train {
trainNo: number; trainNo: number;
driverName: string; driverName: string;
currentStationName: string; currentStationName: string;
route: string | null;
timetableId: number | null;
category: string | null;
followingStops: {
stopName: string;
stopType: string;
arrivalLine?: string;
arrivalTime: number;
arrivalDelay: number;
departureLine?: string;
departureTime: number;
beginsHere: boolean;
terminatesHere: boolean;
departureDelay: number;
confirmed: boolean;
stopped: boolean;
stopTime: number;
arrivalScenery?: string;
departureScenery?: string;
}[];
TWR: boolean | null;
SKR: boolean | null;
noTimetable: boolean;
locoURL: string; locoURL: string;
locoType: string; locoType: string;
routeDistance: number;
online: boolean; online: boolean;
timetableData?: {
timetableId: number;
category: string;
route: string;
followingStops: {
stopName: string;
stopType: string;
arrivalLine?: string;
arrivalTime: number;
arrivalDelay: number;
departureLine?: string;
departureTime: number;
beginsHere: boolean;
terminatesHere: boolean;
departureDelay: number;
confirmed: boolean;
stopped: boolean;
stopTime: number;
}[];
TWR: boolean;
SKR: boolean;
routeDistance: number;
};
} }
+5 -6
View File
@@ -1,13 +1,12 @@
import Vue from "vue"; import Vue from 'vue';
import Vuex from "vuex"; import Vuex from 'vuex';
import Store from '@/store/store';
import StationsModule from "@/store/modules/stationsModule";
import TrainsModule from "@/store/modules/trainsModule";
Vue.use(Vuex); Vue.use(Vuex);
const store = new Vuex.Store({ const store = new Vuex.Store({
modules: { modules: {
StationsModule, Store,
TrainsModule,
}, },
}); });
export default store; export default store;
+13 -41
View File
@@ -4,11 +4,9 @@ import axios from 'axios';
import data from '@/data/stations.json'; import data from '@/data/stations.json';
import Station from '@/scripts/interfaces/Station'; import Station from '@/scripts/interfaces/Station';
const stationsOnlineURL = const stationsOnlineURL = 'https://api.td2.info.pl:9640/?method=getStationsOnline';
'https://api.td2.info.pl:9640/?method=getStationsOnline';
const trainsOnlineURL = 'https://api.td2.info.pl:9640/?method=getTrainsOnline'; const trainsOnlineURL = 'https://api.td2.info.pl:9640/?method=getTrainsOnline';
const dispatchersOnlineURL = const dispatchersOnlineURL = 'https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1';
'https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1';
enum ConnState { enum ConnState {
Loading = 0, Loading = 0,
@@ -17,8 +15,7 @@ enum ConnState {
} }
interface TimetableResponseData { interface TimetableResponseData {
stopPoints: stopPoints: {
{
arrivalTime: string; arrivalTime: string;
arrivalDelay: number; arrivalDelay: number;
departureTime: string; departureTime: string;
@@ -57,10 +54,6 @@ let onlineTrainsData: {
}; };
}[]; }[];
const queryStations = axios.get(stationsOnlineURL);
const queryTrains = axios.get(trainsOnlineURL);
const queryDispatchers = axios.get(dispatchersOnlineURL);
const getStationLabel = (stationStatus: any) => { const getStationLabel = (stationStatus: any) => {
if (!stationStatus) return 'NIEZALOGOWANY'; if (!stationStatus) return 'NIEZALOGOWANY';
@@ -97,9 +90,7 @@ const getStationLabel = (stationStatus: any) => {
const getOpenSpawns = (spawnString: string) => { const getOpenSpawns = (spawnString: string) => {
if (!spawnString) return ''; if (!spawnString) return '';
return spawnString return spawnString.split(';').map(v => (v.split(',')[6] ? v.split(',')[6] : v.split(',')[0]));
.split(';')
.map(v => (v.split(',')[6] ? v.split(',')[6] : v.split(',')[0]));
}; };
@Module @Module
@@ -134,9 +125,7 @@ export default class StationsModule extends VuexModule {
@Mutation @Mutation
private updateStations(updatedStations) { private updateStations(updatedStations) {
this.stations = this.stations.reduce((acc, station) => { this.stations = this.stations.reduce((acc, station) => {
const onlineStationData = updatedStations.find( const onlineStationData = updatedStations.find(uStation => uStation.stationName === station.stationName);
uStation => uStation.stationName === station.stationName
);
if (!onlineStationData) { if (!onlineStationData) {
acc.push({ acc.push({
@@ -152,7 +141,6 @@ export default class StationsModule extends VuexModule {
dispatcherId: 0, dispatcherId: 0,
occupiedTo: 'WOLNA', occupiedTo: 'WOLNA',
statusTimestamp: 0, statusTimestamp: 0,
scheduledTrains: [],
online: false, online: false,
}); });
@@ -174,9 +162,7 @@ export default class StationsModule extends VuexModule {
// Dodawanie do listy online potencjalnych scenerii niewpisanych do bazy // Dodawanie do listy online potencjalnych scenerii niewpisanych do bazy
updatedStations.forEach((updated: any) => { updatedStations.forEach((updated: any) => {
const alreadyInList: any = this.stations.find( const alreadyInList: any = this.stations.find(station => station.stationName === updated.stationName);
station => station.stationName === updated.stationName
);
if (!alreadyInList) { if (!alreadyInList) {
this.stations.push({ this.stations.push({
@@ -189,9 +175,7 @@ export default class StationsModule extends VuexModule {
this.stationCount = this.stations.filter(station => station.online).length; this.stationCount = this.stations.filter(station => station.online).length;
this.trainCount = onlineTrainsData.filter( this.trainCount = onlineTrainsData.filter(train => train.isOnline && train.region === 'eu').length;
train => train.isOnline && train.region === 'eu'
).length;
this.stationsConnectionState = ConnState.Connected; this.stationsConnectionState = ConnState.Connected;
} }
@@ -233,11 +217,7 @@ export default class StationsModule extends VuexModule {
commit: 'updateStations', commit: 'updateStations',
}) })
async fetchOnlineStations() { async fetchOnlineStations() {
return await Promise.all([ return await Promise.all([axios.get(stationsOnlineURL), axios.get(trainsOnlineURL), axios.get(dispatchersOnlineURL)])
axios.get(stationsOnlineURL),
axios.get(trainsOnlineURL),
axios.get(dispatchersOnlineURL),
])
.then(async response => { .then(async response => {
onlineStationsData = response[0].data.message; onlineStationsData = response[0].data.message;
onlineTrainsData = await response[1].data.message; onlineTrainsData = await response[1].data.message;
@@ -247,22 +227,13 @@ export default class StationsModule extends VuexModule {
onlineStationsData onlineStationsData
.filter(station => station.region === 'eu' && station.isOnline) .filter(station => station.region === 'eu' && station.isOnline)
.map(async station => { .map(async station => {
const stationStatus = onlineDispatchersData.find( const stationStatus = onlineDispatchersData.find(status => status[0] == station.stationHash && status[1] == 'eu');
status => status[0] == station.stationHash && status[1] == 'eu'
);
const statusLabel = getStationLabel(stationStatus); const statusLabel = getStationLabel(stationStatus);
const statusTimestamp = stationStatus ? stationStatus[3] : -1; const statusTimestamp = stationStatus ? stationStatus[3] : -1;
const trains = onlineTrainsData.filter( const trains = onlineTrainsData.filter(train => train.region === 'eu' && train.isOnline && train.station.stationName === station.stationName);
train =>
train.region === 'eu' &&
train.isOnline &&
train.station.stationName === station.stationName
);
const stationData = data.find( const stationData = data.find(s => s.stationName === station.stationName) || {
s => s.stationName === station.stationName
) || {
stationName: station.stationName, stationName: station.stationName,
stationURL: '', stationURL: '',
}; };
@@ -285,8 +256,9 @@ export default class StationsModule extends VuexModule {
); );
return updatedStations; return updatedStations;
}) })
.catch(() => { .catch(err => {
this.context.commit('setConnectionState', ConnState.Error); this.context.commit('setConnectionState', ConnState.Error);
console.log(err);
}); });
} }
} }
+9 -26
View File
@@ -65,13 +65,9 @@ interface TimetableData {
const getTimestamp = (date: string) => (date ? new Date(date).getTime() : 0); const getTimestamp = (date: string) => (date ? new Date(date).getTime() : 0);
const getTimetableURL = (trainNo: number) => const getTimetableURL = (trainNo: number) => `https://api.td2.info.pl:9640/?method=readFromSWDR&value=getTimetable%3B${trainNo}%3Beu`;
`https://api.td2.info.pl:9640/?method=readFromSWDR&value=getTimetable%3B${trainNo}%3Beu`;
const getLocoURL = (locoType: string) => const getLocoURL = (locoType: string) => `https://rj.td2.info.pl/dist/img/thumbnails/${locoType.includes('EN') ? locoType + 'rb' : locoType}.png`;
`https://rj.td2.info.pl/dist/img/thumbnails/${
locoType.includes('EN') ? locoType + 'rb' : locoType
}.png`;
@Module @Module
export default class TrainsModule extends VuexModule { export default class TrainsModule extends VuexModule {
@@ -93,17 +89,12 @@ export default class TrainsModule extends VuexModule {
return await Promise.all( return await Promise.all(
onlineTrainsData.map(async train => { onlineTrainsData.map(async train => {
const timetableResponseData: TimetableResponseData | null = ( const timetableResponseData: TimetableResponseData | null = (await axios.get(getTimetableURL(train.trainNo))).data.message;
await axios.get(getTimetableURL(train.trainNo))
).data.message;
let timetableData: TimetableData | null = null; let timetableData: TimetableData | null = null;
if (timetableResponseData && timetableResponseData.trainInfo) { if (timetableResponseData && timetableResponseData.trainInfo) {
const routeDistance: number = const routeDistance: number = timetableResponseData.stopPoints[timetableResponseData.stopPoints.length - 1].pointDistance;
timetableResponseData.stopPoints[
timetableResponseData.stopPoints.length - 1
].pointDistance;
timetableData = { timetableData = {
...timetableResponseData.trainInfo, ...timetableResponseData.trainInfo,
@@ -112,18 +103,12 @@ export default class TrainsModule extends VuexModule {
}; };
} }
const locoType = train.dataCon.split(';') const locoType = train.dataCon.split(';') ? train.dataCon.split(';')[0] : train.dataCon;
? train.dataCon.split(';')[0]
: train.dataCon;
const followingStops = timetableResponseData?.stopPoints.reduce( const followingStops = timetableResponseData?.stopPoints.reduce(
(acc, point) => { (acc, point) => {
const stopObj: any = {}; const stopObj: any = {};
if ( if (!point.pointName.includes('Południowy') && (point.pointName.includes('strong') || point.pointName.includes('podg.'))) {
!point.pointName.includes('Południowy') &&
(point.pointName.includes('strong') ||
point.pointName.includes('podg.'))
) {
if (point.pointName.includes('strong')) { if (point.pointName.includes('strong')) {
stopObj.stopName = point.pointNameRAW; stopObj.stopName = point.pointNameRAW;
@@ -137,13 +122,11 @@ export default class TrainsModule extends VuexModule {
stopObj.departureTime = getTimestamp(point.departureTime); stopObj.departureTime = getTimestamp(point.departureTime);
stopObj.arrivalDelay = point.arrivalDelay; stopObj.arrivalDelay = point.arrivalDelay;
stopObj.departureDelay = point.departureDelay; stopObj.departureDelay = point.departureDelay;
stopObj.beginsHere = stopObj.beginsHere = getTimestamp(point.arrivalTime) == 0 ? true : false;
getTimestamp(point.arrivalTime) == 0 ? true : false; stopObj.terminatesHere = getTimestamp(point.departureTime) == 0 ? true : false;
stopObj.terminatesHere =
getTimestamp(point.departureTime) == 0 ? true : false;
stopObj.confirmed = point.confirmed; stopObj.confirmed = point.confirmed;
stopObj.stopped = point.stopped; stopObj.stopped = point.stopped;
stopObj.stopTime = point.pointStopTime; stopObj.currentStationName = train.station.stationName;
acc.push(stopObj); acc.push(stopObj);
} }
+361
View File
@@ -0,0 +1,361 @@
import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators';
import axios from 'axios';
import JSONStationData from '@/data/stations.json';
import Station from '@/scripts/interfaces/Station';
import Train from '@/scripts/interfaces/Train';
import Timetable from '@/scripts/interfaces/Timetable';
enum Status {
Loading = 0,
Error = 1,
Loaded = 2,
}
const URLs = {
stations: 'https://api.td2.info.pl:9640/?method=getStationsOnline',
trains: 'https://api.td2.info.pl:9640/?method=getTrainsOnline',
dispatchers: 'https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1',
};
const timetableURL = (trainNo: number) => `https://api.td2.info.pl:9640/?method=readFromSWDR&value=getTimetable%3B${trainNo}%3Beu`;
const getLocoURL = (locoType: string) => `https://rj.td2.info.pl/dist/img/thumbnails/${locoType.includes('EN') ? locoType + 'rb' : locoType}.png`;
const getStationLabel = (stationStatus: any) => {
if (!stationStatus) return 'NIEZALOGOWANY';
const statusCode = stationStatus[2];
const statusTimestamp = stationStatus[3];
switch (statusCode) {
case 0:
if (statusTimestamp - Date.now() > 21000000) return 'BEZ LIMITU';
return `DO ${new Date(statusTimestamp).toLocaleTimeString('en-US', {
hour12: false,
hour: '2-digit',
minute: '2-digit',
})}`;
case 1:
return 'Z/W';
case 2:
if (statusTimestamp == 0) return 'KOŃCZY';
break;
case 3:
return 'BRAK MIEJSCA';
default:
break;
}
return 'NIEDOSTĘPNY';
};
const getOpenSpawns = (spawnString: string) => (spawnString ? spawnString.split(';').map(v => (v.split(',')[6] ? v.split(',')[6] : v.split(',')[0])) : '');
const getTimestamp = (date: string) => (date ? new Date(date).getTime() : 0);
@Module
export default class Store extends VuexModule {
private trainCount: number = 0;
private stationCount: number = 0;
// private stationsConnectionStatus: Status = Status.Loading;
// private trainsConnectionStatus: Status = Status.Loading;
// private dataConnectionStatus: Status = Status.Loading;
private dataConnectionStatus: Status = Status.Loading;
private stationList: Station[] = [];
private trainList: Train[] = [];
//GETTERS
get getAllData() {
return {
stationList: this.stationList,
trainList: this.trainList,
trainCount: this.trainCount,
stationCount: this.stationCount,
dataConnectionStatus: this.dataConnectionStatus,
};
}
get getStationList() {
return this.stationList;
}
get getTrainList() {
return this.trainList;
}
//ACTIONS
@Action
async synchronizeData() {
this.context.commit('setJSONData');
this.context.dispatch('fetchOnlineData');
setInterval(() => this.context.dispatch('fetchOnlineData'), 20000);
}
@Action({ commit: 'updateTimetableData' })
async fetchTimetableData() {
return await Promise.all(
this.trainList.map(async train => {
const timetable = await (await axios.get(timetableURL(train.trainNo))).data.message;
const trainInfo = timetable.trainInfo;
let timetableData;
if (timetable && trainInfo) {
timetableData = {};
const followingStops = timetable.stopPoints.reduce((acc, point) => {
const stopObj: any = {};
if (!point.pointName.includes('Południowy') && (point.pointName.includes('strong') || point.pointName.includes('podg.'))) {
if (point.pointName.includes('strong')) {
stopObj.stopName = point.pointNameRAW;
stopObj.stopType = point.pointStopType;
} else {
stopObj.stopName = point.pointNameRAW.split(',')[0];
stopObj.stopType = 'podg.';
}
stopObj.arrivalTime = getTimestamp(point.arrivalTime);
stopObj.departureTime = getTimestamp(point.departureTime);
stopObj.arrivalDelay = point.arrivalDelay;
stopObj.departureDelay = point.departureDelay;
stopObj.beginsHere = getTimestamp(point.arrivalTime) == 0 ? true : false;
stopObj.terminatesHere = getTimestamp(point.departureTime) == 0 ? true : false;
stopObj.confirmed = point.confirmed;
stopObj.stopped = point.stopped;
acc.push(stopObj);
}
return acc;
}, []);
timetableData = {
trainNo: train.trainNo,
driverName: train.driverName,
driverId: train.driverId,
currentStationName: train.currentStationName,
timetableId: trainInfo.timetableId,
category: trainInfo.trainCategoryCode,
route: trainInfo.route,
TWR: trainInfo.twr,
SKR: trainInfo.skr,
routeDistance: timetable.stopPoints[timetable.stopPoints.length - 1].pointDistance,
followingStops,
};
}
return timetableData;
})
);
}
@Action
async fetchOnlineData() {
Promise.all([axios.get(URLs.stations), axios.get(URLs.trains), axios.get(URLs.dispatchers)])
.then(async response => {
const onlineStationsData = response[0].data.message;
const onlineTrainsData = await response[1].data.message;
const onlineDispatchersData = await response[2].data.message;
let updatedStationList = onlineStationsData.reduce((acc, station) => {
if (station.region !== 'eu' || !station.isOnline) return acc;
const stationStatus = onlineDispatchersData.find(status => status[0] == station.stationHash && status[1] == 'eu');
const statusLabel = getStationLabel(stationStatus);
const statusTimestamp = stationStatus ? stationStatus[3] : -1;
const stationTrains = onlineTrainsData.filter(train => train.region === 'eu' && train.isOnline && train.station.stationName === station.stationName);
acc.push({
stationName: station.stationName,
stationHash: station.stationHash,
maxUsers: station.maxUsers,
currentUsers: station.currentUsers,
spawnString: getOpenSpawns(station.spawnString),
dispatcherName: station.dispatcherName,
dispatcherRate: station.dispatcherRate,
dispatcherId: station.dispatcherId,
dispatcherExp: station.dispatcherExp,
occupiedTo: statusLabel,
stationTrains,
statusTimestamp,
});
return acc;
}, []);
let updatedTrainList = await Promise.all(
onlineTrainsData
.filter(train => train.region === 'eu')
.map(async train => {
const locoType = train.dataCon.split(';') ? train.dataCon.split(';')[0] : train.dataCon;
return {
trainNo: train.trainNo,
mass: train.dataMass,
length: train.dataLength,
speed: train.dataSpeed,
distance: train.dataDistance,
signal: train.dataSignal,
online: train.isOnline,
driverId: train.driverId,
driverName: train.driverName,
currentStationName: train.station.stationName,
connectedTrack: train.dataSceneryConnection,
locoType,
locoURL: getLocoURL(locoType),
};
})
);
this.context.commit('updateOnlineStations', updatedStationList);
this.context.commit('updateOnlineTrains', updatedTrainList);
this.context.dispatch('fetchTimetableData');
})
.catch(err => {
this.context.commit('setDataConnectionStatus', Status.Error);
});
}
//MUTATIONS
@Mutation
private setDataConnectionStatus(status: Status) {
this.dataConnectionStatus = status;
}
@Mutation setJSONData() {
this.stationList = JSONStationData.map(stationData => ({
stationProject: '',
spawnString: '',
stationHash: '',
maxUsers: 0,
currentUsers: 0,
dispatcherName: '',
dispatcherRate: 0,
dispatcherExp: -1,
dispatcherId: 0,
online: false,
occupiedTo: 'WOLNA',
statusTimestamp: 0,
stationTrains: [],
scheduledTrains: [],
...stationData,
}));
}
@Mutation
private updateOnlineStations(updatedStationList: any[]) {
this.stationList = this.stationList.reduce((acc, station) => {
const onlineStationData = updatedStationList.find(updatedStation => updatedStation.stationName === station.stationName);
if (!onlineStationData) {
acc.push({
...station,
stationProject: '',
spawnString: '',
stationHash: '',
maxUsers: 0,
currentUsers: 0,
dispatcherName: '',
dispatcherRate: 0,
dispatcherExp: -1,
dispatcherId: 0,
occupiedTo: 'WOLNA',
statusTimestamp: 0,
online: false,
});
} else
acc.push({
...station,
...onlineStationData,
online: true,
});
return acc;
}, [] as Station[]);
// Dodawanie do listy online potencjalnych scenerii niewpisanych do bazy
updatedStationList.forEach(updatedStation => {
const alreadyInList: any = this.stationList.find(station => station.stationName === updatedStation.stationName);
if (!alreadyInList) {
this.stationList.push({
...updatedStation,
online: true,
reqLevel: '-1',
});
}
});
this.stationCount = this.stationList.filter(station => station.online).length;
this.dataConnectionStatus = Status.Loaded;
}
@Mutation
private updateOnlineTrains(updatedTrainList) {
this.trainList =
this.trainList.length == 0
? updatedTrainList
: this.trainList.reduce((acc, train) => {
const onlineTrainData = updatedTrainList.find(updatedTrain => train.trainNo === updatedTrain.trainNo);
if (onlineTrainData) acc.push({ ...train, ...onlineTrainData });
return acc;
}, [] as Train[]);
this.trainCount = this.trainList.filter(train => train.online).length;
this.dataConnectionStatus = Status.Loaded;
}
@Mutation
private updateTimetableData(timetableList: any[]) {
this.stationList = this.stationList.map(station => {
const scheduledTrains = timetableList.reduce((acc, timetableData: any) => {
const scheduledIndex = timetableData
? timetableData.followingStops.findIndex(
(stop: any) =>
station.stationName.toLowerCase().includes(stop.stopName) ||
station.stationName.toLowerCase().includes(stop.stopName.toLowerCase().split(',')[0]) ||
(station.stationName.toLowerCase().includes(stop.stopName.toLowerCase().split(' ')[0]) && station.stationName.toLowerCase().includes('lcs'))
)
: -1;
if (scheduledIndex >= 0) {
const scheduledData = timetableData.followingStops[scheduledIndex];
acc.push({
...scheduledData,
trainNo: timetableData.trainNo,
driverName: timetableData.driverName,
driverId: timetableData.driverId,
currentStationName: timetableData.currentStationName,
});
}
return acc;
}, []);
return { ...station, scheduledTrains };
});
this.trainList = this.trainList.reduce((acc, train) => {
const timetableData = timetableList.find(data => data && data.trainNo === train.trainNo);
if (timetableData) acc.push({ ...train, timetableData });
return acc;
}, [] as Train[]);
}
}
+16 -54
View File
@@ -93,8 +93,7 @@ export default class StationsView extends Vue {
inputs = inputData; inputs = inputData;
@Getter("getStationList") stations!: Station[]; @Getter("getStationList") stationList!: Station[];
@Getter("trainsDataList") trains!: Train[];
toggleCardsState(name: string): void { toggleCardsState(name: string): void {
if (name == "filter") { if (name == "filter") {
@@ -120,52 +119,14 @@ export default class StationsView extends Vue {
this.filters = { ...filterInitStates }; this.filters = { ...filterInitStates };
} }
get scheduledTrains() {
const reducedList = this.stations.reduce((acc, station) => {
if (!acc[station.stationName]) acc[station.stationName] = [];
this.trains
.filter((train) => !train.noTimetable)
.forEach((train) => {
const foundIndex = train.followingStops.findIndex(
(stop) =>
(station.stationName
.toLowerCase()
.includes(stop.stopName) ||
station.stationName
.toLowerCase()
.includes(stop.stopName.toLowerCase().split(",")[0]) ||
(station.stationName
.toLowerCase()
.includes(stop.stopName.toLowerCase().split(" ")[0]) &&
station.stationName.toLowerCase().includes("lcs"))) &&
!acc[station.stationName].find((t) => t.trainNo === train.trainNo)
);
if (foundIndex < 0) return acc;
const foundStop = train.followingStops[foundIndex];
acc[station.stationName].push({
trainNo: train.trainNo,
driverName: train.driverName,
driverId: train.driverId,
category: train.category,
...foundStop
});
});
return acc;
}, {});
return reducedList;
}
get computedStations() { get computedStations() {
const dir: number = this.sorterActive.dir; const dir: number = this.sorterActive.dir;
const scheduledTrainList = this.scheduledTrains; // const scheduledTrainList = this.scheduledTrains;
return this.stations
return this.stationList
.filter((station) => { .filter((station) => {
if (!station.reqLevel || station.reqLevel == "-1") return true; if (!station.reqLevel || station.reqLevel == "-1") return true;
@@ -270,21 +231,15 @@ export default class StationsView extends Vue {
if (a.stationName.toLowerCase() >= b.stationName.toLowerCase()) return dir; if (a.stationName.toLowerCase() >= b.stationName.toLowerCase()) return dir;
return -dir; return -dir;
}) })
.map((station) => ({
...station,
scheduledTrains: scheduledTrainList[station.stationName],
}));
} }
mounted() { mounted() {
const storage = window.localStorage; const storage = window.localStorage;
console.log(storage.getItem(this.STORAGE_KEY));
if (storage.getItem(this.STORAGE_KEY) !== "true") return; if (storage.getItem(this.STORAGE_KEY) !== "true") return;
this.inputs.options.forEach(option => { this.inputs.options.forEach(option => {
const value = storage.getItem(option.name) === "true" ? true : false; const value = storage.getItem(option.name) === "true" ? true : false;
console.log(option.name, value);
this.changeFilterValue({ name: option.name, value: value ? 0 : 1 }); this.changeFilterValue({ name: option.name, value: value ? 0 : 1 });
@@ -298,6 +253,13 @@ export default class StationsView extends Vue {
this.changeFilterValue({ name: slider.name, value }); this.changeFilterValue({ name: slider.name, value });
slider.value = value; slider.value = value;
}) })
window.addEventListener('keydown', (e: KeyboardEvent) => {
if (e.keyCode == 27 && this.focusedStationName != "") {
this.focusedStationName = "";
}
})
} }
closeCard() { closeCard() {
@@ -322,6 +284,8 @@ export default class StationsView extends Vue {
padding: 1rem 0; padding: 1rem 0;
min-height: 100%; min-height: 100%;
font-size: calc(0.6rem + 0.9vw);
position: relative; position: relative;
} }
@@ -342,8 +306,6 @@ export default class StationsView extends Vue {
} }
.options { .options {
font-size: calc(0.6rem + 0.9vw);
&-actions { &-actions {
display: flex; display: flex;
} }
@@ -357,7 +319,7 @@ export default class StationsView extends Vue {
border: none; border: none;
color: #e0e0e0; color: #e0e0e0;
font-size: 0.75em; font-size: 0.65em;
padding: 0.3em; padding: 0.3em;
@@ -395,7 +357,7 @@ export default class StationsView extends Vue {
} }
.action-btn { .action-btn {
font-size: 0.8rem; font-size: 0.75rem;
} }
} }
+6 -8
View File
@@ -40,10 +40,7 @@ import axios from "axios";
}, },
}) })
export default class TrainsView extends Vue { export default class TrainsView extends Vue {
@Getter("trainsDataList") trains!: Train[]; @Getter("getTrainList") trains!: Train[];
@Action("fetchTrainsData") fetchTrainsData;
@Prop() readonly passedSearchedTrain!: string; @Prop() readonly passedSearchedTrain!: string;
sorterActive: { id: string; dir: number } = { id: "timetable", dir: 1 }; sorterActive: { id: string; dir: number } = { id: "timetable", dir: 1 };
@@ -62,12 +59,11 @@ export default class TrainsView extends Vue {
this.sorterActive = sorter; this.sorterActive = sorter;
} }
get computedTrains() { get computedTrains() {
return this.trains return this.trains
.filter( .filter(
(train) => (train) =>
!train.noTimetable && train.timetableData &&
(this.searchedTrain.length > 0 (this.searchedTrain.length > 0
? train.trainNo.toString().includes(this.searchedTrain) ? train.trainNo.toString().includes(this.searchedTrain)
: true) && : true) &&
@@ -85,7 +81,9 @@ export default class TrainsView extends Vue {
break; break;
case "distance": case "distance":
if (a.routeDistance > b.routeDistance) return this.sorterActive.dir; if (!a.timetableData || !b.timetableData) return 0;
if (a.timetableData.routeDistance > b.timetableData.routeDistance) return this.sorterActive.dir;
else return -this.sorterActive.dir; else return -this.sorterActive.dir;
break; break;
@@ -128,7 +126,7 @@ export default class TrainsView extends Vue {
padding: 0 0.5rem; padding: 0 0.5rem;
font-size: calc(0.3rem + 0.4vw); font-size: calc(0.4rem + 0.4vw);
} }
.options-wrapper { .options-wrapper {