Dodano szczegółowy rozkład pociągów

This commit is contained in:
2020-09-19 19:34:47 +02:00
parent e71a9e01f2
commit 0b4a32eeb2
14 changed files with 1064 additions and 683 deletions
+8 -10
View File
@@ -186,10 +186,10 @@ export default class StationCard extends styleMixin {
let stopStatus = "";
let stopLabel = "";
if (scheduledTrain.terminatesHere && scheduledTrain.confirmed) { stopStatus = "terminated"; stopLabel = "Skończył bieg" }
else if (!scheduledTrain.terminatesHere && scheduledTrain.confirmed) { stopStatus = "departed"; stopLabel = "Odprawiony" }
else if (scheduledTrain.currentStationName == this.stationInfo.stationName && !scheduledTrain.stopped) { stopStatus = "online"; stopLabel = "Na stacji" }
else if (scheduledTrain.currentStationName == this.stationInfo.stationName && scheduledTrain.stopped) { stopStatus = "stopped"; stopLabel = "Postój" }
if (scheduledTrain.stopInfo.terminatesHere && scheduledTrain.stopInfo.confirmed) { stopStatus = "terminated"; stopLabel = "Skończył bieg" }
else if (!scheduledTrain.stopInfo.terminatesHere && scheduledTrain.stopInfo.confirmed) { stopStatus = "departed"; stopLabel = "Odprawiony" }
else if (scheduledTrain.currentStationName == this.stationInfo.stationName && !scheduledTrain.stopInfo.stopped) { stopStatus = "online"; stopLabel = "Na stacji" }
else if (scheduledTrain.currentStationName == this.stationInfo.stationName && scheduledTrain.stopInfo.stopped) { stopStatus = "stopped"; stopLabel = "Postój" }
else if (scheduledTrain.currentStationName != this.stationInfo.stationName) { stopStatus = "arriving"; stopLabel = "W drodze" }
return {
@@ -223,13 +223,11 @@ export default class StationCard extends styleMixin {
}
.station-card {
scroll-behavior: smooth;
font-size: calc(0.5rem + 0.4vw);
max-width: 850px;
font-size: calc(0.5rem + 0.35vw);
max-width: 800px;
@include bigScreen {
font-size: 1.1rem;
font-size: 1rem;
}
@include smallScreen {
@@ -269,7 +267,7 @@ export default class StationCard extends styleMixin {
grid-template-areas: "main main" "icons icons" "dispatcher hours" "users spawns";
grid-template-columns: repeat(2, minmax(0, 1fr));
min-width: 200px;
max-height: 500px;
max-height: 600px;
transform: translateY(0%);
+1 -1
View File
@@ -126,7 +126,7 @@
/
<span
style="color:#bbb"
>{{ station.scheduledTrains.filter(train => train.confirmed).length }}</span>
>{{ station.scheduledTrains.filter(train => train.stopInfo.confirmed).length }}</span>
</span>
<span v-else>...</span>
@@ -33,29 +33,32 @@
<span class="timetable-schedule">
<span class="schedule-arrival">
<span class="arrival-time begins" v-if="scheduledTrain.beginsHere">ROZPOCZYNA BIEG</span>
<span
class="arrival-time begins"
v-if="scheduledTrain.stopInfo.beginsHere"
>ROZPOCZYNA BIEG</span>
<span
class="arrival-time"
v-else
>{{timestampToTime(scheduledTrain.arrivalTime)}} ({{scheduledTrain.arrivalDelay}})</span>
>{{scheduledTrain.stopInfo.arrivalTimeString}} ({{scheduledTrain.stopInfo.arrivalDelay}})</span>
</span>
<span class="schedule-stop">
<span
class="stop-time"
v-if="scheduledTrain.stopTime"
>{{scheduledTrain.stopTime}} {{scheduledTrain.stopType}}</span>
v-if="scheduledTrain.stopInfo.stopTime"
>{{scheduledTrain.stopInfo.stopTime}} {{scheduledTrain.stopInfo.stopType}}</span>
<span class="stop-arrow arrow"></span>
</span>
<span class="schedule-departure">
<span
class="departure-time terminates"
v-if="scheduledTrain.terminatesHere"
v-if="scheduledTrain.stopInfo.terminatesHere"
>KOŃCZY BIEG</span>
<span
class="departure-time"
v-else
>{{timestampToTime(scheduledTrain.departureTime)}} ({{scheduledTrain.departureDelay}})</span>
>{{scheduledTrain.stopInfo.departureTimeString}} ({{scheduledTrain.stopInfo.departureDelay}})</span>
</span>
</span>
</div>
@@ -67,6 +70,8 @@
<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator';
import Station from "@/scripts/interfaces/Station";
@Component
export default class StationTimetable extends Vue {
@Prop() readonly scheduledTrains;
@@ -74,17 +79,10 @@ export default class StationTimetable extends Vue {
get computedScheduledTrains() {
return this.scheduledTrains.sort((a, b) => {
if (a.arrivalTime > b.arrivalTime) return 1;
else if ((a.arrivalTime < b.arrivalTime)) return -1;
if (a.stopInfo.arrivalTimestamp > b.stopInfo.arrivalTimestamp) return 1;
else if ((a.stopInfo.arrivalTimestamp < b.stopInfo.arrivalTimestamp)) 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',
return a.stopInfo.departureTimestamp > b.stopInfo.departureTimestamp ? 1 : -1;
})
}
}
+210
View File
@@ -0,0 +1,210 @@
<template>
<div class="train-schedule">
<div class="schedule-wrapper">
<div class="schedule-bar"></div>
<ul class="schedule-list">
<li
class="schedule-item"
v-for="(stop, i) in followingStops"
:key="i"
:class="{ confirmed: stop.confirmed, stopped: stop.stopped }"
>
<div class="progress-bar"></div>
<div
class="stop-line arrival"
v-if="i > 0 && followingStops[i - 1].departureLine != stop.arrivalLine"
>{{ stop.arrivalLine }}</div>
<span class="stop-info">
<div class="info-indicator"></div>
<span class="info-name" v-html="stop.stopName"></span>
<span class="info-date">
<span
class="date-arrival"
v-if="!stop.beginsHere"
:class="{delayed: stop.arrivalDelay > 0, preponed: stop.arrivalDelay < 0}"
>p. {{stylizeTime(stop.arrivalRealTimeString, stop.arrivalDelay)}}</span>
<span
class="date-stop"
v-if="stop.stopTime"
:class="stop.stopType.replace(', ', '-')"
>{{ stop.stopTime }} {{ stop.stopType }}</span>
<span
class="date-departure"
v-if="!stop.terminatesHere && stop.stopTime != 0"
:class="{delayed: stop.departureDelay > 0, preponed: stop.departureDelay < 0}"
>o. {{ stylizeTime(stop.departureRealTimeString, stop.departureDelay) }}</span>
</span>
</span>
<div class="stop-line departure">{{ stop.departureLine }}</div>
</li>
</ul>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";
import TrainStop from "@/scripts/interfaces/TrainStop";
@Component
export default class TrainSchedule extends Vue {
@Prop() readonly followingStops!: TrainStop[];
@Prop() readonly currentStationName!: string;
stylizeTime(timeString: string, delay: number) {
return timeString + (delay != 0 ? " (" + (delay > 0 ? "+" : "") + delay.toString() + ")" : "");
}
}
</script>
<style lang="scss" scoped>
@import "../../styles/responsive.scss";
.train-schedule {
max-height: 600px;
overflow: auto;
margin-top: 1rem;
font-size: 1em;
@include smallScreen() {
font-size: 0.8em;
}
}
.schedule-bar,
.progress-bar {
position: absolute;
z-index: 1;
width: 2px;
height: 100%;
top: 0;
left: 0;
background: white;
}
.progress-bar {
height: 100%;
top: 0;
left: calc(-0.5rem - 2px);
width: 2px;
}
.schedule-wrapper {
position: relative;
margin-top: 1rem;
margin-left: 0.5rem;
}
ul.schedule-list {
margin-left: 10px;
}
ul.schedule-list > li.schedule-item {
position: relative;
display: flex;
flex-direction: column;
padding: 0 0.5rem;
&.confirmed {
& > .progress-bar,
& > .stop-info > .info-indicator {
background: lime;
}
}
&.stopped {
& > .progress-bar {
background: lime;
height: 50%;
}
& > .stop-info > .info-indicator {
background: orangered;
}
}
}
li.schedule-item > .stop-info {
display: flex;
position: relative;
& > .info-indicator {
position: absolute;
z-index: 1;
top: 50%;
left: -1.5rem;
transform: translateY(-50%);
width: 15px;
height: 2px;
background: white;
}
& > .info-name {
background: rgb(0, 81, 187);
padding: 0.3rem 0.5rem;
}
& > .info-date {
display: flex;
align-items: center;
& > span {
background: #5c5c5c;
padding: 0.3rem 0.5rem;
}
& > .date-stop {
&.ph,
&.ph-pm {
background: #ce8d00;
}
&.pt,
&.pm {
background: #252525;
}
}
& > .date-arrival,
& > .date-departure {
&.delayed {
background: rgb(250, 0, 0);
}
&.preponed {
background: rgb(0, 139, 0);
}
}
}
}
li.schedule-item > .stop-line {
font-size: 0.8em;
color: #bbb;
padding: 0.3em 0;
margin: 0.2em 0;
transform: translateX(-0.8rem);
}
</style>
+1
View File
@@ -185,6 +185,7 @@ export default class TrainStats extends Vue {
.train-stats {
padding: 0.3em 0;
font-size: 1.1em;
z-index: 2;
position: relative;
}
+157 -114
View File
@@ -2,129 +2,152 @@
<div class="train-table">
<div class="no-trains" v-if="computedTrains.length == 0">Ups! Brak pociągów do wyświetlenia :/</div>
<ul class="list">
<li class="item" v-for="(train, i) in computedTrains" :key="i">
<span class="info">
<div class="info-top">
<div class="info-category">
<span>
<strong>{{ train.timetableData.category }}</strong>
{{ train.trainNo }} |
<span
style=" color: gold;"
>{{ train.timetableData.routeDistance }} km</span>
</span>
<ul class="train-list">
<li
class="train-item"
v-for="(train, i) in computedTrains"
:key="i"
:id="train.timetableData.timetableId"
>
<span class="train-info">
<span class="info">
<div class="info-top">
<div class="info-category">
<span>
<strong>{{ train.timetableData.category }}</strong>
{{ train.trainNo }} |
<span
style=" color: gold;"
>{{ train.timetableData.routeDistance }} km</span>
</span>
<span>
<span class="warning twr" v-if="train.timetableData.TWR">TWR</span>
<span class="warning skr" v-if="train.timetableData.SKR">SKR</span>
</span>
</div>
<span>
<span class="warning twr" v-if="train.timetableData.TWR">TWR</span>
<span class="warning skr" v-if="train.timetableData.SKR">SKR</span>
</span>
</div>
<div class="info-route">
<a :href="'https://rj.td2.info.pl/train#' + train.trainNo + ';eu'" target="_blank">
<div class="info-route">
<strong>
{{
train.timetableData.route.replace("|", " - ")
}}
</strong>
</a>
</div>
<div class="info-stations">
<span v-if="train.timetableData.followingStops.length > 2">
Przez:
<span v-html="generateStopList(train.timetableData.followingStops)"></span>
</span>
</div>
</div>
<div class="info-stations">
<span v-if="train.timetableData.followingStops.length > 2">
Przez:
<span v-html="generateStopList(train.timetableData.followingStops)"></span>
<div class="info-bottom">
<span
class="info-online"
:class="{'online': train.online}"
>{{train.online ? "ONLINE" : "OFFLINE"}}</span>
<button
class="button"
@click="changeScheduleShowState(train.timetableData.timetableId)"
>SZCZEGÓŁOWY ROZKŁAD</button>
</div>
</span>
<span class="driver">
<span class="driver-name">
<a
:href="'https://td2.info.pl/profile/?u=' + train.driverId"
target="_blank"
>{{ train.driverName }}</a>
<span style="color: #bbb; margin-left: 1em;">
{{
train.locoType
}}
</span>
</span>
<span class="driver-loco">
<img :src="train.locoURL" @error="onImageError" />
</span>
</span>
<span class="stats">
<div class="stats-general">
<span class="stat mass">
<img :src="massIcon" alt="icon-mass" />
{{ train.mass / 1000 }}t
</span>
<span class="stat speed">
<img :src="speedIcon" alt="icon-speed" />
{{ train.speed }} km/h
</span>
<span class="stat length">
<img :src="lengthIcon" alt="icon-length" />
{{ train.length }}m
</span>
</div>
</div>
<div class="info-bottom">
<span
class="info-online"
:class="{'online': train.online}"
>{{train.online ? "ONLINE" : "OFFLINE"}}</span>
</div>
</span>
<span class="driver">
<span class="driver-name">
<a
:href="'https://td2.info.pl/profile/?u=' + train.driverId"
target="_blank"
>{{ train.driverName }}</a>
<span style="color: #bbb; margin-left: 1em;">
{{
train.locoType
}}
</span>
</span>
<span class="driver-loco">
<img :src="train.locoURL" @error="onImageError" />
<div class="stats-position">
<span class="stat station">
<div class="stat-icon">
<img :src="sceneryIcon" alt="icon-scenery" />
</div>
{{ train.currentStationName || "---" }}
</span>
<span class="stat track">
<div class="stat-icon">
<img :src="routeIcon" alt="icon-scenery" />
</div>
{{ train.connectedTrack || "---" }}
</span>
<span class="stat signal">
<div class="stat-icon">
<img :src="signalIcon" alt="icon-scenery" />
</div>
{{ train.signal || "---" }}
</span>
<span class="stat distance">
<div class="stat-icon">
<img :src="distanceIcon" alt="icon-scenery" />
</div>
{{ train.distance || "0" }}m
</span>
</div>
</span>
</span>
<span class="stats">
<div class="stats-general">
<span class="stat mass">
<img :src="massIcon" alt="icon-mass" />
{{ train.mass / 1000 }}t
</span>
<span class="stat speed">
<img :src="speedIcon" alt="icon-speed" />
{{ train.speed }} km/h
</span>
<span class="stat length">
<img :src="lengthIcon" alt="icon-length" />
{{ train.length }}m
</span>
</div>
<div class="stats-position">
<span class="stat station">
<div class="stat-icon">
<img :src="sceneryIcon" alt="icon-scenery" />
</div>
{{ train.currentStationName || "---" }}
</span>
<span class="stat track">
<div class="stat-icon">
<img :src="routeIcon" alt="icon-scenery" />
</div>
{{ train.connectedTrack || "---" }}
</span>
<span class="stat signal">
<div class="stat-icon">
<img :src="signalIcon" alt="icon-scenery" />
</div>
{{ train.signal || "---" }}
</span>
<span class="stat distance">
<div class="stat-icon">
<img :src="distanceIcon" alt="icon-scenery" />
</div>
{{ train.distance || "0" }}m
</span>
</div>
</span>
<TrainSchedule
:followingStops="train.timetableData.followingStops"
:currentStationName="train.currentStationName"
@click="changeScheduleShowState(train.timetableData.timetableId)"
v-if="showSchedules.includes(train.timetableData.timetableId)"
/>
</li>
</ul>
</div>
</template>
<script lang="ts">
import { Vue, Component, Prop } from "vue-property-decorator";
import { Vue, Component, Prop, Watch } from "vue-property-decorator";
const unknownTrainImage = require("@/assets/unknown.png");
import Train from "@/scripts/interfaces/Train";
import Station from "@/scripts/interfaces/Station";
@Component
import TrainSchedule from "@/components/TrainsView/TrainSchedule.vue";
@Component({
components: { TrainSchedule }
})
export default class TrainTable extends Vue {
@Prop() readonly computedTrains!: Train[];
@Prop() computedTrains!: Train[];
showSchedules: number[] = [];
speedIcon: string = require("@/assets/icon-speed.svg");
massIcon: string = require("@/assets/icon-mass.svg");
@@ -135,6 +158,11 @@ export default class TrainTable extends Vue {
signalIcon: string = require("@/assets/icon-signal.svg");
routeIcon: string = require("@/assets/icon-route.svg");
changeScheduleShowState(timetableId: number) {
if (this.showSchedules.includes(timetableId)) this.showSchedules.splice(this.showSchedules.indexOf(timetableId), 1)
else this.showSchedules.push(timetableId);
}
onImageError(e: Event) {
(e.target as HTMLImageElement).src = unknownTrainImage;
}
@@ -156,10 +184,6 @@ export default class TrainTable extends Vue {
@import "../../styles/responsive.scss";
@import "../../styles/variables.scss";
.train-table {
font-size: calc(0.4rem + 0.5vw);
}
.no-trains {
text-align: center;
font-size: 1.5em;
@@ -170,26 +194,29 @@ export default class TrainTable extends Vue {
background: #333;
}
.list {
overflow: auto;
.train {
&-list {
overflow: auto;
@include smallScreen() {
width: 100%;
@include smallScreen() {
width: 100%;
}
}
&-item {
padding: 1rem;
margin-bottom: 1rem;
background-color: #383838;
cursor: pointer;
}
}
.item {
.train-info {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
background-color: #444;
padding: 1rem;
margin-bottom: 1em;
&:nth-child(even) {
background-color: #666;
}
font-size: calc(0.4rem + 0.5vw);
@include smallScreen() {
grid-template-columns: 1fr;
@@ -197,7 +224,10 @@ export default class TrainTable extends Vue {
font-size: 0.8rem;
gap: 0.4em 0;
// grid-template-columns: repeat(3, 1fr);
}
@include bigScreen() {
font-size: 1.1rem;
}
}
@@ -238,6 +268,19 @@ export default class TrainTable extends Vue {
background-color: #009700;
}
}
&-bottom {
display: flex;
align-items: center;
button {
margin-left: 10px;
background: #144e75;
border-radius: 1em;
padding: 0.2em 0.5em;
font-size: 0.85em;
}
}
}
.driver {
+3 -13
View File
@@ -1,4 +1,5 @@
import Train from '@/scripts/interfaces/Train';
import TrainStop from '@/scripts/interfaces/TrainStop';
export default interface Station {
stationName: string;
@@ -32,18 +33,7 @@ export default interface Station {
driverName: string;
driverId: number;
currentStationName: string;
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;
category: string;
stopInfo: TrainStop;
}[];
}
+3 -17
View File
@@ -1,3 +1,5 @@
import TrainStop from '@/scripts/interfaces/TrainStop';
export default interface Train {
mass: number;
length: number;
@@ -17,23 +19,7 @@ export default interface Train {
timetableId: number;
category: string;
route: string;
followingStops: {
stopName: string;
stopNameRAW: string;
stopType: string;
mainStop: boolean;
arrivalLine?: string;
arrivalTime: number;
arrivalDelay: number;
departureLine?: string;
departureTime: number;
beginsHere: boolean;
terminatesHere: boolean;
departureDelay: number;
confirmed: boolean;
stopped: boolean;
stopTime: number;
}[];
followingStops: TrainStop[];
TWR: boolean;
SKR: boolean;
routeDistance: number;
+28
View File
@@ -0,0 +1,28 @@
export default interface {
stopName: string;
stopNameRAW: string;
stopType: string;
mainStop: boolean;
arrivalLine: string;
arrivalTimeString: string;
arrivalTimestamp: number;
arrivalRealTimeString: string;
arrivalRealTimestamp: number;
arrivalDelay: number;
departureLine: string;
departureTimeString: string;
departureTimestamp: number;
departureRealTimeString: string;
departureRealTimestamp: number;
departureDelay: number;
comments?: any;
beginsHere: boolean;
terminatesHere: boolean;
confirmed: boolean;
stopped: boolean;
stopTime: number;
}
+35 -31
View File
@@ -5,7 +5,7 @@ import JSONStationData from '@/data/stations.json';
import Station from '@/scripts/interfaces/Station';
import Train from '@/scripts/interfaces/Train';
import Timetable from '@/scripts/interfaces/Timetable';
import TrainStop from '@/scripts/interfaces/TrainStop';
enum Status {
Loading = 0,
@@ -80,6 +80,11 @@ const getStatusTimestamp = (stationStatus: any) => {
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);
const timestampToTime = (timestamp: number) =>
new Date(timestamp).toLocaleTimeString('pl-PL', {
hour: '2-digit',
minute: '2-digit',
});
@Module
export default class Store extends VuexModule {
@@ -135,41 +140,40 @@ export default class Store extends VuexModule {
if (timetable && trainInfo) {
timetableData = {};
const followingStops = timetable.stopPoints.reduce((acc, point) => {
const stopObj: any = {};
const followingStops: TrainStop[] = timetable.stopPoints.reduce((acc: TrainStop[], point) => {
const arrivalTimestamp = getTimestamp(point.arrivalTime);
const arrivalRealTimestamp = getTimestamp(point.arrivalRealTime);
// if (point.pointName.includes('strong') && !point.pointName.includes('Południowy')) {
// stopObj.stopName = point.pointNameRAW;
// stopObj.stopType = point.pointStopType;
// }
const departureTimestamp = getTimestamp(point.departureTime);
const departureRealTimestamp = getTimestamp(point.departureRealTime);
// if (point.pointNameRAW.includes('Południowy')) return acc;
// if (
// !point.pointName.includes('strong') ||
// !(point.pointNameRAW.includes('podg.') || JSONStationData.some(data => data.stationName.toLowerCase().includes(point.pointNameRAW.split(',')[0].toLowerCase())))
// )
// return acc;
acc.push({
stopName: point.pointName,
stopNameRAW: point.pointNameRAW,
stopType: point.pointStopType,
mainStop: point.pointName.includes('strong'),
// stopObj.stopName = point.pointName.includes('strong') ? point.pointNameRAW : point.pointNameRAW.split(',')[0];
// stopObj.stopType = point.pointName.includes('strong') ? point.pointStopType : 'pt podg.';
arrivalLine: point.arrivalLine,
arrivalTimeString: timestampToTime(point.arrivalTime),
arrivalTimestamp: arrivalTimestamp,
arrivalRealTimeString: timestampToTime(point.arrivalRealTime),
arrivalRealTimestamp: arrivalRealTimestamp,
arrivalDelay: point.arrivalDelay,
stopObj.stopName = point.pointName;
stopObj.stopNameRAW = point.pointNameRAW;
stopObj.stopType = point.pointStopType;
departureLine: point.departureLine,
departureTimeString: timestampToTime(point.departureTime),
departureTimestamp: departureTimestamp,
departureRealTimeString: timestampToTime(point.departureRealTime),
departureRealTimestamp: departureRealTimestamp,
departureDelay: point.departureDelay,
stopObj.mainStop = point.pointName.includes('strong');
beginsHere: arrivalTimestamp == 0,
terminatesHere: departureTimestamp == 0,
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.isStopped;
stopObj.stopTime = point.pointStopTime;
acc.push(stopObj);
confirmed: point.confirmed,
stopped: point.isStopped,
stopTime: point.pointStopTime,
});
return acc;
}, []);
@@ -384,12 +388,12 @@ export default class Store extends VuexModule {
const scheduledData = timetableData.followingStops[scheduledIndex];
acc.push({
...scheduledData,
trainNo: timetableData.trainNo,
driverName: timetableData.driverName,
driverId: timetableData.driverId,
currentStationName: timetableData.currentStationName,
category: timetableData.category,
stopInfo: scheduledData,
});
}
+279 -306
View File
@@ -4,11 +4,7 @@
<div class="stations-body">
<div class="options">
<div class="options-actions">
<button
class="action-btn"
:class="{'open': filterCardOpen}"
@click="() => toggleCardsState('filter')"
>
<button class="action-btn" :class="{ open: filterCardOpen }" @click="() => toggleCardsState('filter')">
<img :src="require('@/assets/icon-filter2.svg')" alt="icon-filter" />
<p>FILTRY</p>
</button>
@@ -40,333 +36,310 @@
</template>
<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
import { Getter } from "vuex-class";
import { Vue, Component } from "vue-property-decorator";
import { Getter } from "vuex-class";
import Station from "@/scripts/interfaces/Station";
import Train from "@/scripts/interfaces/Train";
import Station from "@/scripts/interfaces/Station";
import Train from "@/scripts/interfaces/Train";
import inputData from "@/data/options.json";
import inputData from "@/data/options.json";
import StationTable from "@/components/StationsView/StationTable.vue";
import StationCard from "@/components/StationsView/StationCard.vue";
import FilterCard from "@/components/StationsView/FilterCard.vue";
import StationTable from "@/components/StationsView/StationTable.vue";
import StationCard from "@/components/StationsView/StationCard.vue";
import FilterCard from "@/components/StationsView/FilterCard.vue";
const filterInitStates = {
default: false,
notDefault: false,
nonPublic: false,
SPK: false,
SCS: false,
ręczne: false,
mechaniczne: false,
współczesna: false,
kształtowa: false,
historyczna: false,
mieszana: false,
minLevel: 0,
minOneWayCatenary: 0,
minOneWay: 0,
minTwoWayCatenary: 0,
minTwoWay: 0,
"no-1track": false,
"no-2track": false,
free: true,
occupied: false,
ending: false,
};
const filterInitStates = {
default: false,
notDefault: false,
nonPublic: false,
SPK: false,
SCS: false,
ręczne: false,
mechaniczne: false,
współczesna: false,
kształtowa: false,
historyczna: false,
mieszana: false,
minLevel: 0,
minOneWayCatenary: 0,
minOneWay: 0,
minTwoWayCatenary: 0,
minTwoWay: 0,
"no-1track": false,
"no-2track": false,
free: true,
occupied: false,
ending: false,
};
@Component({
components: {
StationCard,
StationTable,
FilterCard,
},
})
export default class StationsView extends Vue {
STORAGE_KEY: string = "options_saved";
@Component({
components: {
StationCard,
StationTable,
FilterCard,
},
})
export default class StationsView extends Vue {
STORAGE_KEY: string = "options_saved";
sorterActive: { index: number; dir: number } = { index: 0, dir: 1 };
focusedStationName: string = "";
filterCardOpen: boolean = false;
filters = { ...filterInitStates };
sorterActive: { index: number; dir: number } = { index: 0, dir: 1 };
focusedStationName: string = "";
filterCardOpen: boolean = false;
filters = { ...filterInitStates };
inputs = inputData;
inputs = inputData;
@Getter("getStationList") stationList!: Station[];
@Getter("getStationList") stationList!: Station[];
toggleCardsState(name: string): void {
if (name == "filter") {
this.filterCardOpen = !this.filterCardOpen;
toggleCardsState(name: string): void {
if (name == "filter") {
this.filterCardOpen = !this.filterCardOpen;
}
}
changeSorter(index: number) {
if (index > 5) return;
if (index == this.sorterActive.index) this.sorterActive.dir = -1 * this.sorterActive.dir;
else this.sorterActive.dir = 1;
this.sorterActive.index = index;
}
changeFilterValue(filter: { name: string; value: number }) {
this.filters[filter.name] = filter.value;
}
resetFilters() {
this.filters = { ...filterInitStates };
}
get computedStations() {
const dir: number = this.sorterActive.dir;
// const scheduledTrainList = this.scheduledTrains;
return this.stationList
.filter((station) => {
if (!station.reqLevel || station.reqLevel == "-1") return true;
if ((station.nonPublic || !station.reqLevel) && this.filters["nonPublic"]) return false;
if (station.online && station.occupiedTo == "KOŃCZY" && this.filters["ending"]) return false;
if (station.online && this.filters["occupied"]) return false;
if (!station.online && this.filters["free"]) return false;
if (station.default && this.filters["default"]) return false;
if (!station.default && this.filters["notDefault"]) return false;
if (parseInt(station.reqLevel) < this.filters["minLevel"]) return false;
if (
this.filters["no-1track"] &&
(station.routes.oneWay.catenary != 0 || station.routes.oneWay.noCatenary != 0)
)
return false;
if (
this.filters["no-2track"] &&
(station.routes.twoWay.catenary != 0 || station.routes.twoWay.noCatenary != 0)
)
return false;
if (station.routes.oneWay.catenary < this.filters["minOneWayCatenary"]) return false;
if (station.routes.oneWay.noCatenary < this.filters["minOneWay"]) return false;
if (station.routes.twoWay.catenary < this.filters["minTwoWayCatenary"]) return false;
if (station.routes.twoWay.noCatenary < this.filters["minTwoWay"]) return false;
if (this.filters[station.controlType]) return false;
if (this.filters[station.signalType]) return false;
if (this.filters["SPK"] && (station.controlType === "SPK" || station.controlType.includes("+SPK")))
return false;
if (this.filters["SCS"] && (station.controlType === "SCS" || station.controlType.includes("+SCS")))
return false;
if (
this.filters["SCS"] &&
this.filters["SPK"] &&
(station.controlType.includes("SPK") || station.controlType.includes("SCS"))
)
return false;
if (this.filters["mechaniczne"] && station.controlType.includes("mechaniczne")) return false;
if (this.filters["ręczne"] && station.controlType.includes("ręczne")) return false;
return true;
})
.sort((a, b) => {
switch (this.sorterActive.index) {
case 1:
if (parseInt(a.reqLevel) > parseInt(b.reqLevel)) return dir;
if (parseInt(a.reqLevel) < parseInt(b.reqLevel)) return -dir;
break;
case 2:
if (a.statusTimestamp > b.statusTimestamp) return dir;
if (a.statusTimestamp < b.statusTimestamp) return -dir;
break;
case 3:
if (a.dispatcherName.toLowerCase() > b.dispatcherName.toLowerCase()) return dir;
if (a.dispatcherName.toLowerCase() < b.dispatcherName.toLowerCase()) return -dir;
break;
case 4:
if (a.dispatcherExp > b.dispatcherExp) return dir;
if (a.dispatcherExp < b.dispatcherExp) return -dir;
break;
case 5:
if (a.currentUsers > b.currentUsers) return dir;
if (a.currentUsers < b.currentUsers) return -dir;
if (a.maxUsers > b.maxUsers) return dir;
if (a.maxUsers < b.maxUsers) return -dir;
break;
default:
break;
}
if (a.stationName.toLowerCase() >= b.stationName.toLowerCase()) return dir;
return -dir;
});
}
mounted() {
const storage = window.localStorage;
if (storage.getItem(this.STORAGE_KEY) !== "true") return;
this.inputs.options.forEach((option) => {
const value = storage.getItem(option.name) === "true" ? true : false;
this.changeFilterValue({ name: option.name, value: value ? 0 : 1 });
option.value = value;
});
this.inputs.sliders.forEach((slider) => {
const value = parseInt(storage.getItem(slider.name) || "0");
this.changeFilterValue({ name: slider.name, value });
slider.value = value;
});
window.addEventListener("keydown", (e: KeyboardEvent) => {
if (e.keyCode == 27 && this.focusedStationName != "") {
this.focusedStationName = "";
}
});
}
closeCard() {
this.focusedStationName = "";
}
setFocusedStation(name: string) {
if (this.focusedStationName == name) this.focusedStationName = "";
else this.focusedStationName = name;
}
get focusedStationInfo() {
return this.computedStations.find((station) => station.stationName === this.focusedStationName);
}
}
changeSorter(index: number) {
if (index > 5) return;
if (index == this.sorterActive.index)
this.sorterActive.dir = -1 * this.sorterActive.dir;
else this.sorterActive.dir = 1;
this.sorterActive.index = index;
}
changeFilterValue(filter: { name: string; value: number }) {
this.filters[filter.name] = filter.value;
}
resetFilters() {
this.filters = { ...filterInitStates };
}
get computedStations() {
const dir: number = this.sorterActive.dir;
// const scheduledTrainList = this.scheduledTrains;
return this.stationList
.filter((station) => {
if (!station.reqLevel || station.reqLevel == "-1") return true;
if (
(station.nonPublic || !station.reqLevel) &&
this.filters["nonPublic"]
)
return false;
if (
station.online &&
station.occupiedTo == "KOŃCZY" &&
this.filters["ending"]
)
return false;
if (station.online && this.filters["occupied"]) return false;
if (!station.online && this.filters["free"]) return false;
if (station.default && this.filters["default"]) return false;
if (!station.default && this.filters["notDefault"]) return false;
if (parseInt(station.reqLevel) < this.filters["minLevel"]) return false;
if (
this.filters["no-1track"] &&
(station.routes.oneWay.catenary != 0 ||
station.routes.oneWay.noCatenary != 0)
)
return false;
if (
this.filters["no-2track"] &&
(station.routes.twoWay.catenary != 0 ||
station.routes.twoWay.noCatenary != 0)
)
return false;
if (station.routes.oneWay.catenary < this.filters["minOneWayCatenary"])
return false;
if (station.routes.oneWay.noCatenary < this.filters["minOneWay"])
return false;
if (station.routes.twoWay.catenary < this.filters["minTwoWayCatenary"])
return false;
if (station.routes.twoWay.noCatenary < this.filters["minTwoWay"])
return false;
if (this.filters[station.controlType]) return false;
if (this.filters[station.signalType]) return false;
if (this.filters["SPK"] && (station.controlType === "SPK" || station.controlType.includes("+SPK")))
return false;
if (this.filters["SCS"] && (station.controlType === "SCS" || station.controlType.includes("+SCS")))
return false;
if (this.filters["SCS"] && this.filters["SPK"] && (station.controlType.includes("SPK") || station.controlType.includes("SCS")))
return false;
if (
this.filters["mechaniczne"] &&
station.controlType.includes("mechaniczne")
)
return false;
if (this.filters["ręczne"] && station.controlType.includes("ręczne"))
return false;
return true;
})
.sort((a, b) => {
switch (this.sorterActive.index) {
case 1:
if (parseInt(a.reqLevel) > parseInt(b.reqLevel)) return dir;
if (parseInt(a.reqLevel) < parseInt(b.reqLevel)) return -dir;
break;
case 2:
if (a.statusTimestamp > b.statusTimestamp) return dir;
if (a.statusTimestamp < b.statusTimestamp) return -dir;
break;
case 3:
if (a.dispatcherName.toLowerCase() > b.dispatcherName.toLowerCase()) return dir;
if (a.dispatcherName.toLowerCase() < b.dispatcherName.toLowerCase()) return -dir;
break;
case 4:
if (a.dispatcherExp > b.dispatcherExp) return dir;
if (a.dispatcherExp < b.dispatcherExp) return -dir;
break;
case 5:
if (a.currentUsers > b.currentUsers) return dir;
if (a.currentUsers < b.currentUsers) return -dir;
if (a.maxUsers > b.maxUsers) return dir;
if (a.maxUsers < b.maxUsers) return -dir;
break;
default:
break;
}
if (a.stationName.toLowerCase() >= b.stationName.toLowerCase()) return dir;
return -dir;
})
}
mounted() {
const storage = window.localStorage;
if (storage.getItem(this.STORAGE_KEY) !== "true") return;
this.inputs.options.forEach(option => {
const value = storage.getItem(option.name) === "true" ? true : false;
this.changeFilterValue({ name: option.name, value: value ? 0 : 1 });
option.value = value;
})
this.inputs.sliders.forEach(slider => {
const value = parseInt(storage.getItem(slider.name) || "0");
this.changeFilterValue({ name: slider.name, value });
slider.value = value;
})
window.addEventListener('keydown', (e: KeyboardEvent) => {
if (e.keyCode == 27 && this.focusedStationName != "") {
this.focusedStationName = "";
}
})
}
closeCard() {
this.focusedStationName = "";
}
setFocusedStation(name: string) {
if (this.focusedStationName == name) this.focusedStationName = "";
else this.focusedStationName = name;
}
get focusedStationInfo() {
return this.computedStations.find(
(station) => station.stationName === this.focusedStationName
);
}
}
</script>
<style lang="scss" scoped>
.stations-view {
padding: 1rem 0;
min-height: 100%;
.stations-view {
padding: 1rem 0;
min-height: 100%;
font-size: calc(0.6rem + 0.9vw);
font-size: calc(0.6rem + 0.9vw);
position: relative;
}
@import "../styles/variables.scss";
@import "../styles/responsive.scss";
.card-anim {
&-enter-active,
&-leave-active {
transition: all 0.25s ease-in-out;
position: relative;
}
&-enter,
&-leave-to {
transform: translate(-45%, -50%);
opacity: 0;
}
}
@import "../styles/variables.scss";
@import "../styles/responsive.scss";
.options {
&-actions {
display: flex;
}
}
.card-anim {
&-enter-active,
&-leave-active {
transition: all 0.25s ease-in-out;
}
.action-btn {
display: flex;
align-items: center;
background: #333;
border: none;
color: #e0e0e0;
font-size: 0.65em;
padding: 0.3em;
outline: none;
cursor: pointer;
transition: all 0.3s;
img {
width: 1.3em;
margin-right: 0.2em;
&-enter,
&-leave-to {
transform: translate(-45%, -50%);
opacity: 0;
}
}
p {
font-size: 1em;
overflow: hidden;
transition: max-width 0.35s ease-in-out;
}
&:hover {
color: $accentCol;
background: rgba(#e0e0e0, 0.4);
}
&.open {
color: $accentCol;
}
}
@include smallScreen {
.options {
&-actions {
display: flex;
}
}
.action-btn {
display: flex;
align-items: center;
background: #333;
border: none;
color: #e0e0e0;
font-size: 0.65em;
padding: 0.3em;
outline: none;
cursor: pointer;
transition: all 0.3s;
img {
width: 1.3em;
margin-right: 0.2em;
}
p {
font-size: 1em;
overflow: hidden;
transition: max-width 0.35s ease-in-out;
}
&:hover {
color: $accentCol;
background: rgba(#e0e0e0, 0.4);
}
&.open {
color: $accentCol;
}
}
@include smallScreen {
.options {
display: flex;
justify-content: center;
}
.action-btn {
font-size: 0.75rem;
}
}
.stations-wrapper {
display: flex;
justify-content: center;
}
.action-btn {
font-size: 0.75rem;
.stations-body {
margin: 0 auto;
overflow: auto;
}
}
.stations-wrapper {
display: flex;
justify-content: center;
}
.stations-body {
margin: 0 auto;
overflow: auto;
}
</style>
+1 -1
View File
@@ -122,7 +122,7 @@ export default class TrainsView extends Vue {
.body-wrapper {
margin: 1rem auto;
max-width: 1200px;
max-width: 1300px;
padding: 0 0.5rem;