Poprawki kod

u. Dodano widok z rozkładami w karcie stacji
This commit is contained in:
2020-09-06 02:29:37 +02:00
parent 3febe562bf
commit 33b3837bd8
11 changed files with 358 additions and 88 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" /> <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&display=swap" rel="stylesheet">
<title>Stacjownik</title> <title>Stacjownik</title>
</head> </head>
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="18px" height="18px"><path d="M0 0h24v24H0z" fill="none"/><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/><path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"/></svg>

After

Width:  |  Height:  |  Size: 350 B

+1 -3
View File
@@ -1,3 +1 @@
<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="18px" height="18px"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
<path d="M2 2L32 32M32 2L2 32" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="bevel"/>
</svg>

Before

Width:  |  Height:  |  Size: 215 B

After

Width:  |  Height:  |  Size: 256 B

+1 -1
View File
@@ -166,7 +166,7 @@ export default class FilterCard extends Vue {
@include smallScreen() { @include smallScreen() {
width: 85vw; width: 85vw;
font-size: 1em; font-size: 0.45em;
} }
} }
+228 -24
View File
@@ -1,7 +1,13 @@
<template> <template>
<section class="card station-card"> <section class="card station-card">
<div class="card-exit" @click="exit"> <div class="card-exit">
<img :src="require('@/assets/icon-exit.svg')" alt="exit icon" /> <img
class="schedule-icon"
:src="require('@/assets/icon-clock.svg')"
alt="schedule-icon"
@click="() => cardMode = cardMode == 0 ? 1 : 0"
/>
<img :src="require('@/assets/icon-exit.svg')" alt="exit-icon" @click="exit" />
</div> </div>
<div class="card-content" :class="{'offline': !stationInfo.online}"> <div class="card-content" :class="{'offline': !stationInfo.online}">
@@ -133,13 +139,63 @@
</div> </div>
</div> </div>
<!-- <div class="card-timetables"> <div class="card-timetables" id="card-timetables" :class="{show: cardMode == 1}">
<div class="title">AKTYWNE ROZKŁADY JAZDY</div> <div class="timetables-wrapper">
<div class="content"> <div class="timetables-title title">
<ul> <div style="font-size: 1.2em;">{{stationInfo.stationName.toUpperCase()}}</div>
</ul> <div>AKTYWNE ROZKŁADY JAZDY</div>
</div>
<div class="timetables-content">
<div class="timetable" v-for="(timetable, i) in computedScheduledTrains" :key="i">
<span class="timetable-general">
<span class="general-category">
<span>{{timetable.category}}</span>
{{timetable.trainNo}}
</span>
<span class="general-driver">{{timetable.driverName}}</span>
<span class="general-confirmed">
<span
style="color: gold"
v-if="timetable.stopped || (timetable.beginsHere && !timetable.confirmed)"
>Na stacji</span>
<span style="color: #aaa" v-else-if="!timetable.confirmed">W drodze</span>
<span
style="color: red"
v-else-if="(timetable.terminatesHere && timetable.confirmed)"
>Skończył bieg</span>
<span style="color: lime" v-else>Odprawiony</span>
</span>
</span>
<span class="timetable-schedule">
<span class="schedule-arrival">
<span class="arrival-time begins" v-if="timetable.beginsHere">ROZPOCZYNA BIEG</span>
<span
class="arrival-time"
v-else
>{{timestampToTime(timetable.arrivalTime)}} ({{timetable.arrivalDelay}})</span>
</span>
<span class="schedule-stop">
<span
class="stop-time"
v-if="timetable.stopTime"
>{{timetable.stopTime}} {{timetable.stopType}}</span>
<span class="stop-arrow arrow"></span>
</span>
<span class="schedule-departure">
<span class="departure-time terminates" v-if="timetable.terminatesHere">KOŃCZY BIEG</span>
<span
class="departure-time"
v-else
>{{timestampToTime(timetable.departureTime)}} ({{timetable.departureDelay}})</span>
</span>
</span>
</div>
</div>
</div>
</div> </div>
</div>-->
</section> </section>
</template> </template>
@@ -147,32 +203,55 @@
import { Component, Prop, Watch } from "vue-property-decorator"; import { Component, Prop, Watch } from "vue-property-decorator";
import styleMixin from "@/mixins/styleMixin"; import styleMixin from "@/mixins/styleMixin";
import Station from "@/scripts/interfaces/Station";
@Component @Component
export default class StationCard extends styleMixin { export default class StationCard extends styleMixin {
@Prop() stationInfo; @Prop() stationInfo!: Station;
@Prop() dispatcherHistory;
@Prop() exit!: void; @Prop() exit!: void;
history: any[] = []; history: any[] = [];
cardMode: number = 0;
get computedExp(): string { get computedExp(): string {
console.log(this.stationInfo.scheduledTrains);
return this.stationInfo.dispatcherExp < 2 return this.stationInfo.dispatcherExp < 2
? "L" ? "L"
: `${this.stationInfo.dispatcherExp}`; : `${this.stationInfo.dispatcherExp}`;
} }
get computedScheduledTrains() {
return this.stationInfo.scheduledTrains.sort((a, b) => {
if (a.arrivalTime > b.arrivalTime) return 1;
else if ((a.arrivalTime < b.arrivalTime)) return -1;
return a.departureTime > b.departureTime ? 1 : -1;
})
}
timestampToTime(timestamp: number) {
return new Date(timestamp).toLocaleTimeString('pl-PL', {
hour: '2-digit',
minute: '2-digit',
})
}
} }
</script> </script>
<style lang="scss"> <style lang="scss">
@import "../../styles/variables.scss"; @import "../../styles/variables.scss";
@import "../../styles/responsive.scss"; @import "../../styles/responsive.scss";
.title { .title {
color: $accentCol; color: $accentCol;
font-weight: 600; font-weight: 600;
margin: 0.5em 0; margin: 0.5em 0;
} }
.station-card {
scroll-behavior: smooth;
}
.card { .card {
padding: 2em; padding: 2em;
text-align: center; text-align: center;
@@ -182,18 +261,26 @@ export default class StationCard extends styleMixin {
-webkit-user-select: none; -webkit-user-select: none;
&-exit { &-exit {
z-index: 3;
img { img {
width: 1.5em; margin: 0 0.3em;
font-size: 1.6em;
} }
cursor: pointer; cursor: pointer;
} }
&-content { &-content {
position: relative;
display: grid; display: grid;
grid-template-areas: "main main" "icons icons" "dispatcher hours" "users spawns" "history history"; grid-template-areas: "main main" "icons icons" "dispatcher hours" "users spawns" "history history";
grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-columns: repeat(2, minmax(0, 1fr));
min-width: 200px; min-width: 200px;
max-height: 500px;
transform: translateY(0%);
gap: 1.5em; gap: 1.5em;
@@ -367,21 +454,138 @@ export default class StationCard extends styleMixin {
.card-timetables { .card-timetables {
position: absolute; position: absolute;
width: 100%;
height: 90%;
background: #333;
overflow: hidden;
bottom: 0;
left: 0; left: 0;
top: 0;
width: 100%;
min-height: 100%;
.content { transform: translateY(-100%);
position: absolute; -webikit-transform: translateY(-100%);
&.show {
transform: translateY(0);
-webkit-transform: translateY(0);
} }
// transform: translateY(80%); transition: transform 150ms ease-out;
overflow: auto;
background: #333;
}
.timetables {
&-content {
width: 100%;
height: 100%;
padding: 25px 0;
}
&-title {
padding-top: 1rem;
font-size: 1.3em;
}
}
.timetable {
position: relative;
// margin: 0.rem auto;
margin: 1em auto;
max-width: 600px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
gap: 0 1rem;
@include smallScreen() {
display: flex;
flex-direction: column;
align-items: center;
}
&-general {
padding: 0.3rem 0.5rem;
border: 1px solid white;
display: flex;
justify-content: space-between;
@include smallScreen() {
width: 75%;
}
}
&-schedule {
@include smallScreen() {
width: 70%;
margin: 0.7em 0;
}
display: grid;
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
font-size: 1.2em;
}
}
.arrow {
border: solid white;
border-width: 0 2px 2px 0;
display: inline-block;
padding: 2px;
margin-left: 50px;
position: relative;
transform: rotate(-45deg);
&::before {
content: "";
position: absolute;
display: block;
width: 55px;
height: 3px;
top: 4px;
left: 4px;
transform: translate(-100%, -1px) rotate(45deg);
transform-origin: right bottom;
background: white;
}
}
.general-category {
span {
color: $accentCol;
}
}
.schedule {
&-arrival,
&-stop,
&-departure {
display: flex;
justify-content: center;
align-items: center;
margin: 0 0.3rem;
}
&-stop {
display: flex;
flex-direction: column;
.stop-time {
font-size: 0.7em;
}
}
}
.arrival-time.begins,
.departure-time.terminates {
font-size: 0.75em;
} }
</style> </style>
+13 -7
View File
@@ -30,9 +30,9 @@
</div> </div>
<div class="info-stations"> <div class="info-stations">
<span v-if="train.sceneries.length > 2"> <span v-if="train.followingStops.length > 2">
Przez: Przez:
<span v-html="mapTimetableSceneries(train.sceneries)"></span> <span v-html="generateStopList(train.followingStops)"></span>
</span> </span>
</div> </div>
</div> </div>
@@ -140,12 +140,18 @@ export default class TrainTable extends Vue {
(e.target as HTMLImageElement).src = unknownTrainImage; (e.target as HTMLImageElement).src = unknownTrainImage;
} }
mapTimetableSceneries(sceneries: string[]): string { generateStopList(stops: any): string | undefined {
if (sceneries.length < 1) return ""; if (!stops) return "";
return stops.reduce((acc, stop, i) => {
if (i < 2 || i > stops.length - 2) return acc;
return sceneries if (stop.stopType.includes("ph")) acc.push(`<strong>${stop.stopName}</strong>`);
.filter((scenery, i) => i > 0 && i < sceneries.length - 1) if (stop.stopType == "") acc.push(`<span style='color: #ccc;'>${stop.stopName}</span>`);
.join(" * "); if (stop.stopType == "podg.") acc.push(`<span style='color: #ccc;'>${stop.stopName
}</span>`);
return acc;
}, []).join(" * ");
} }
} }
</script> </script>
+13 -3
View File
@@ -25,8 +25,18 @@ export default interface Station {
statusTimestamp: number; statusTimestamp: number;
scheduledTrains: { scheduledTrains: {
trainNo: number; trainNo: number;
trainCategory: string; driverName: string;
arrivalTime: string; category: string;
departureTime: string; stopName: string;
stopType: string;
arrivalTime: number;
arrivalDelay: number;
departureTime: number;
departureDelay: number;
confirmed: boolean;
stopped: boolean;
stopTime: number;
beginsHere: boolean;
terminatesHere: boolean;
}[]; }[];
} }
+19 -10
View File
@@ -12,7 +12,25 @@ export default interface Train {
route: string | null; route: string | null;
timetableId: number | null; timetableId: number | null;
category: string | null; category: string | null;
sceneries: 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; TWR: boolean | null;
SKR: boolean | null; SKR: boolean | null;
noTimetable: boolean; noTimetable: boolean;
@@ -20,13 +38,4 @@ export default interface Train {
locoType: string; locoType: string;
routeDistance: number; routeDistance: number;
online: boolean; online: boolean;
stopPoints: {
arrivalTime: string;
arrivalDelay: number;
departureTime: string;
departureDelay: number;
pointNameRAW: string;
pointStopType: string;
confirmed: boolean;
}[];
} }
+64 -26
View File
@@ -1,9 +1,9 @@
import { Module, VuexModule, Mutation, Action } from "vuex-module-decorators"; import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators';
import Train from "@/scripts/interfaces/Train"; import Train from '@/scripts/interfaces/Train';
import axios from "axios"; import axios from 'axios';
const API_URL = "https://api.td2.info.pl:9640/?method=getTrainsOnline"; const API_URL = 'https://api.td2.info.pl:9640/?method=getTrainsOnline';
enum ConnState { enum ConnState {
Loading = 0, Loading = 0,
@@ -32,6 +32,15 @@ interface TimetableResponseData {
pointNameRAW: string; pointNameRAW: string;
pointName: string; pointName: string;
pointStopType: string; pointStopType: string;
arrivalLine: string;
departureLine: string;
arrivalTime: string;
arrivalDelay: number;
departureTime: string;
departureDelay: number;
confirmed: boolean;
stopped: boolean;
pointStopTime: number;
}[]; }[];
trainInfo: { trainInfo: {
timetableId: number; timetableId: number;
@@ -54,12 +63,14 @@ interface TimetableData {
stopPoints?: {}[]; stopPoints?: {}[];
} }
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/${ `https://rj.td2.info.pl/dist/img/thumbnails/${
locoType.includes("EN") ? locoType + "rb" : locoType locoType.includes('EN') ? locoType + 'rb' : locoType
}.png`; }.png`;
@Module @Module
@@ -67,21 +78,21 @@ export default class TrainsModule extends VuexModule {
onlineTrainsData: Train[] = []; onlineTrainsData: Train[] = [];
onlineTrainsState: ConnState = ConnState.Loading; onlineTrainsState: ConnState = ConnState.Loading;
@Action({ commit: "loadTrainsData" }) @Action({ commit: 'loadTrainsData' })
async fetchTrainsData() { async fetchTrainsData() {
let trainDataResponse; let trainDataResponse;
try { try {
trainDataResponse = await axios.get(API_URL); trainDataResponse = await axios.get(API_URL);
} catch (error) { } catch (error) {
this.context.commit("setConnectionState", ConnState.Error); this.context.commit('setConnectionState', ConnState.Error);
return null; return null;
} }
let onlineTrainsData: TrainData[] = trainDataResponse.data.message; let onlineTrainsData: TrainData[] = trainDataResponse.data.message;
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)) await axios.get(getTimetableURL(train.trainNo))
).data.message; ).data.message;
@@ -101,29 +112,57 @@ export default class TrainsModule extends VuexModule {
}; };
} }
const locoType = train.dataCon.split(";") const locoType = train.dataCon.split(';')
? train.dataCon.split(";")[0] ? train.dataCon.split(';')[0]
: train.dataCon; : train.dataCon;
const stopPoints = timetableResponseData?.stopPoints.reduce( const followingStops = timetableResponseData?.stopPoints.reduce(
(acc, point) => { (acc, point) => {
if (point.pointName.includes("strong")) const stopObj: any = {};
acc.push( if (
point.pointStopType.includes("ph") !point.pointName.includes('Południowy') &&
? `<strong>${point.pointNameRAW}</strong>` (point.pointName.includes('strong') ||
: `<span style='color: #ccc;'>${point.pointNameRAW}</span>` point.pointName.includes('podg.'))
); ) {
if (point.pointName.includes('strong')) {
stopObj.stopName = point.pointNameRAW;
if (point.pointName.includes("podg.")) stopObj.stopType = point.pointStopType;
acc.push( } else {
`<span style='color: #ccc;'>${ stopObj.stopName = point.pointNameRAW.split(',')[0];
point.pointNameRAW.split(",")[0] stopObj.stopType = 'podg.';
}</span>` }
);
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;
stopObj.stopTime = point.pointStopTime;
acc.push(stopObj);
}
return acc; return acc;
}, },
[] as string[] [] as {
stopName: string;
stopType: string;
arrivalTime: number;
arrivalDelay: number;
departureTime: number;
departureDelay: number;
confirmed: boolean;
stopped: boolean;
stopTime: number;
beginsHere: boolean;
terminatesHere: boolean;
}[]
); );
return { return {
@@ -145,8 +184,7 @@ export default class TrainsModule extends VuexModule {
timetableId: timetableData?.timetableId, timetableId: timetableData?.timetableId,
category: timetableData?.trainCategoryCode, category: timetableData?.trainCategoryCode,
routeDistance: timetableData?.routeDistance || 0, routeDistance: timetableData?.routeDistance || 0,
sceneries: stopPoints, followingStops,
stopPoints: timetableData?.stopPoints,
TWR: timetableData?.twr, TWR: timetableData?.twr,
SKR: timetableData?.skr, SKR: timetableData?.skr,
}; };
+4 -2
View File
@@ -23,7 +23,8 @@ html {
body { body {
width: 100%; width: 100%;
margin: 0; margin: 0;
font-family: "Open Sans", sans-serif; // font-family: "Open Sans", sans-serif;
font-family: "Quicksand", sans-serif;
overflow-x: hidden; overflow-x: hidden;
} }
@@ -31,7 +32,8 @@ body {
button, button,
input, input,
select { select {
font-family: "Open Sans", sans-serif; // font-family: "Open Sans", sans-serif;
font-family: "Quicksand", sans-serif;
} }
input { input {
+13 -11
View File
@@ -127,28 +127,30 @@ export default class StationsView extends Vue {
this.trains this.trains
.filter((train) => !train.noTimetable) .filter((train) => !train.noTimetable)
.forEach((train) => { .forEach((train) => {
const found = train.stopPoints!.find( const foundIndex = train.followingStops.findIndex(
(sp) => (stop) =>
(station.stationName (station.stationName
.toLowerCase() .toLowerCase()
.includes(sp.pointNameRAW.toLowerCase()) || .includes(stop.stopName) ||
station.stationName station.stationName
.toLowerCase() .toLowerCase()
.includes(sp.pointNameRAW.toLowerCase().split(",")[0]) || .includes(stop.stopName.toLowerCase().split(",")[0]) ||
(station.stationName (station.stationName
.toLowerCase() .toLowerCase()
.includes(sp.pointNameRAW.toLowerCase().split(" ")[0]) && .includes(stop.stopName.toLowerCase().split(" ")[0]) &&
station.stationName.toLowerCase().includes("lcs"))) && station.stationName.toLowerCase().includes("lcs"))) &&
!acc[station.stationName].find((t) => t.trainNo === train.trainNo) !acc[station.stationName].find((t) => t.trainNo === train.trainNo)
); );
if (!found) return acc; if (foundIndex < 0) return acc;
const foundStop = train.followingStops[foundIndex];
acc[station.stationName].push({ acc[station.stationName].push({
trainNo: train.trainNo, trainNo: train.trainNo,
driverName: train.driverName, driverName: train.driverName,
category: train.category, category: train.category,
...found, ...foundStop
}); });
}); });
@@ -244,8 +246,8 @@ export default class StationsView extends Vue {
break; break;
case 3: case 3:
if (a.dispatcherName > b.dispatcherName) return dir; if (a.dispatcherName.toLowerCase() > b.dispatcherName.toLowerCase()) return dir;
if (a.dispatcherName < b.dispatcherName) return -dir; if (a.dispatcherName.toLowerCase() < b.dispatcherName.toLowerCase()) return -dir;
break; break;
case 4: case 4:
@@ -264,7 +266,7 @@ export default class StationsView extends Vue {
break; break;
} }
if (a.stationName >= b.stationName) return dir; if (a.stationName.toLowerCase() >= b.stationName.toLowerCase()) return dir;
return -dir; return -dir;
}) })
.map((station) => ({ .map((station) => ({
@@ -307,7 +309,7 @@ export default class StationsView extends Vue {
} }
get focusedStationInfo() { get focusedStationInfo() {
return this.stations.find( return this.computedStations.find(
(station) => station.stationName === this.focusedStationName (station) => station.stationName === this.focusedStationName
); );
} }