mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 05:18:11 +00:00
Zmiana w funkcjonowaniu filtrów, zmiany estetyczne
This commit is contained in:
+57
-4
@@ -38,6 +38,17 @@
|
||||
<footer class="app-footer flex">
|
||||
<span>© Spythere 2020</span>
|
||||
</footer>
|
||||
|
||||
<transition name="message-anim" mode="out-in">
|
||||
<span :key="connState">
|
||||
<div class="message loading" v-if="connState == 0">Pobieranie danych...</div>
|
||||
|
||||
<div class="message error" v-if="connState == 1">
|
||||
<img :src="ErrorIcon" alt="Error" />
|
||||
Brak odpowiedzi ze strony serwera!
|
||||
</div>
|
||||
</span>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -48,16 +59,16 @@ import { Action, Getter } from "vuex-class";
|
||||
|
||||
import { mapGetters, mapActions } from "vuex";
|
||||
|
||||
import Error from "@/components/App/Error.vue";
|
||||
import Loading from "@/components/App/Loading.vue";
|
||||
|
||||
import Clock from "@/components/App/Clock.vue";
|
||||
|
||||
@Component({
|
||||
components: { Error, Loading, Clock },
|
||||
components: { Clock },
|
||||
})
|
||||
export default class App extends Vue {
|
||||
ErrorIcon = require("@/assets/icon-error.svg");
|
||||
|
||||
@Getter("getOnlineInfo") onlineInfo;
|
||||
@Getter("getConnectionState") connState;
|
||||
|
||||
@Action("initStations") initStations;
|
||||
|
||||
@@ -95,6 +106,48 @@ export default class App extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
&-anim {
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all $animDuration $animType;
|
||||
}
|
||||
|
||||
&-enter {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
&-leave-to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
|
||||
width: 100%;
|
||||
|
||||
font-size: calc(0.5rem + 0.5vw);
|
||||
padding: 0.5rem;
|
||||
|
||||
img {
|
||||
width: 1.5em;
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
|
||||
&.loading {
|
||||
background: #cc8b21;
|
||||
}
|
||||
|
||||
&.error {
|
||||
background: firebrick;
|
||||
}
|
||||
}
|
||||
|
||||
.route {
|
||||
margin: 0 0.2em;
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
|
||||
<template>
|
||||
<div class="error">
|
||||
<img src="@/assets/icon-error.svg" alt="Error" />
|
||||
<div>Mechaniku, brak przejazdu!</div>
|
||||
<div class="error-message">{{ error }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ["error"],
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.error {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
flex-direction: column;
|
||||
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
text-align: center;
|
||||
|
||||
font-size: calc(1rem + 1.5vw);
|
||||
font-weight: 550;
|
||||
|
||||
color: #ff1919;
|
||||
|
||||
img {
|
||||
margin-bottom: 1rem;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
&-message {
|
||||
font-size: 0.6em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+68
-74
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<section class="option-card">
|
||||
<section class="filter-card">
|
||||
<div class="card-exit" @click="exit">
|
||||
<img :src="require('@/assets/icon-exit.svg')" alt="exit icon" />
|
||||
</div>
|
||||
@@ -18,7 +18,10 @@
|
||||
v-model="option.value"
|
||||
@change="handleChange"
|
||||
/>
|
||||
<span class="option-content" :class="option.section">{{option.content}}</span>
|
||||
<span
|
||||
class="option-content"
|
||||
:class="option.section + (option.value ? ' checked' : '')"
|
||||
>{{option.content}}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -45,13 +48,8 @@
|
||||
<div class="card-save">
|
||||
<div class="option">
|
||||
<label class="option-label">
|
||||
<input
|
||||
class="option-input"
|
||||
type="checkbox"
|
||||
v-model="saveOptions"
|
||||
@change="changeSaveState"
|
||||
/>
|
||||
<span class="option-content save">ZAPISZ FILTRY</span>
|
||||
<input class="option-input" type="checkbox" v-model="saveOptions" @change="saveFilters" />
|
||||
<span class="option-content save" :class="{'checked': saveOptions}">ZAPISZ FILTRY</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,22 +63,17 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component, Prop } from "vue-property-decorator";
|
||||
import { Action } from "vuex-class";
|
||||
|
||||
import inputData from "@/data/options.json";
|
||||
|
||||
@Component
|
||||
export default class OptionCard extends Vue {
|
||||
export default class FilterCard extends Vue {
|
||||
inputs = { ...inputData };
|
||||
saveOptions: boolean = false;
|
||||
|
||||
STORAGE_KEY: string = "options_saved";
|
||||
|
||||
@Prop() exit!: () => void;
|
||||
|
||||
@Action("setFilter") setFilter;
|
||||
@Action("resetFilters") resetFilters;
|
||||
|
||||
mounted() {
|
||||
const storage = window.localStorage;
|
||||
|
||||
@@ -91,8 +84,8 @@ export default class OptionCard extends Vue {
|
||||
handleChange(e: Event): void {
|
||||
const target = <HTMLInputElement>e.target;
|
||||
|
||||
this.setFilter({
|
||||
filterName: target.name,
|
||||
this.$emit("changeFilterValue", {
|
||||
name: target.name,
|
||||
value: !target.checked,
|
||||
});
|
||||
|
||||
@@ -102,17 +95,16 @@ export default class OptionCard extends Vue {
|
||||
|
||||
handleInput(e: Event): void {
|
||||
const target = <HTMLInputElement>e.target;
|
||||
|
||||
this.setFilter({
|
||||
filterName: target.name,
|
||||
value: parseInt(target.value),
|
||||
this.$emit("changeFilterValue", {
|
||||
name: target.name,
|
||||
value: target.value,
|
||||
});
|
||||
|
||||
if (this.saveOptions)
|
||||
window.localStorage.setItem(target.name, target.value + "");
|
||||
}
|
||||
|
||||
changeSaveState(): void {
|
||||
saveFilters(): void {
|
||||
const storage = window.localStorage;
|
||||
|
||||
if (this.saveOptions) {
|
||||
@@ -139,7 +131,7 @@ export default class OptionCard extends Vue {
|
||||
window.localStorage.setItem(slider.name, slider.value + "");
|
||||
});
|
||||
|
||||
this.resetFilters();
|
||||
this.$emit('resetFilters');
|
||||
}
|
||||
|
||||
closeCard(): void {
|
||||
@@ -152,7 +144,7 @@ export default class OptionCard extends Vue {
|
||||
@import "../../styles/responsive";
|
||||
@import "../../styles/variables";
|
||||
|
||||
.option-card {
|
||||
.filter-card {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
@@ -235,14 +227,6 @@ export default class OptionCard extends Vue {
|
||||
|
||||
&-input {
|
||||
display: none;
|
||||
|
||||
&:not(:checked) + span {
|
||||
background-color: #585858;
|
||||
|
||||
&::before {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
@@ -267,57 +251,67 @@ export default class OptionCard extends Vue {
|
||||
|
||||
transition: all 0.2s;
|
||||
|
||||
&.access {
|
||||
background-color: #e03b07;
|
||||
&:not(.checked) {
|
||||
background-color: #585858;
|
||||
|
||||
&::before {
|
||||
box-shadow: 0 0 6px 1px #e03b07;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.control {
|
||||
background-color: #0085ff;
|
||||
&.checked {
|
||||
&.access {
|
||||
background-color: #e03b07;
|
||||
|
||||
&::before {
|
||||
box-shadow: 0 0 6px 1px #e03b07;
|
||||
}
|
||||
}
|
||||
|
||||
&.control {
|
||||
background-color: #0085ff;
|
||||
|
||||
&::before {
|
||||
box-shadow: 0 0 6px 1px #0085ff;
|
||||
}
|
||||
}
|
||||
|
||||
&.signals {
|
||||
background-color: #b000bf;
|
||||
|
||||
&::before {
|
||||
box-shadow: 0 0 6px 1px #b000bf;
|
||||
}
|
||||
}
|
||||
|
||||
&.status {
|
||||
background-color: #05b702;
|
||||
|
||||
&::before {
|
||||
box-shadow: 0 0 6px 1px #05b702;
|
||||
}
|
||||
}
|
||||
|
||||
&.save {
|
||||
background-color: #05b702;
|
||||
|
||||
&::before {
|
||||
box-shadow: 0 0 6px 1px #05b702;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
box-shadow: 0 0 6px 1px #0085ff;
|
||||
position: absolute;
|
||||
content: "";
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
border-radius: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
&.signals {
|
||||
background-color: #b000bf;
|
||||
|
||||
&::before {
|
||||
box-shadow: 0 0 6px 1px #b000bf;
|
||||
}
|
||||
}
|
||||
|
||||
&.status {
|
||||
background-color: #05b702;
|
||||
|
||||
&::before {
|
||||
box-shadow: 0 0 6px 1px #05b702;
|
||||
}
|
||||
}
|
||||
|
||||
&.save {
|
||||
background-color: #05b702;
|
||||
|
||||
&::before {
|
||||
box-shadow: 0 0 6px 1px #05b702;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
border-radius: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
<template>
|
||||
<section class="legend-card card">
|
||||
<div class="card-exit" @click="exit">
|
||||
<img :src="require('@/assets/icon-exit.svg')" alt="exit icon" />
|
||||
</div>
|
||||
|
||||
<div class="card-title flex">LEGENDA</div>
|
||||
|
||||
<div class="card-icons">
|
||||
<div class="legend-icon" v-for="(icon, i) in icons" :key="i">
|
||||
<img :src="require(`@/assets/icon-${icon.name}.svg`)" :alt="icon.name" />
|
||||
<span>{{icon.desc}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component, Prop } from "vue-property-decorator";
|
||||
|
||||
@Component
|
||||
export default class LegendCard extends Vue {
|
||||
@Prop() exit!: void;
|
||||
|
||||
icons: { name: string; desc: string }[] = [
|
||||
{ name: "SPK", desc: "Sceneria sterowana za pomocą programu SPK" },
|
||||
{ name: "SCS", desc: "Sceneria sterowana za pomocą programu SCS" },
|
||||
{
|
||||
name: "SCS-SPK",
|
||||
desc: "Sceneria sterowana za pomocą programu SCS lub SPK"
|
||||
},
|
||||
{
|
||||
name: "mechaniczne",
|
||||
desc: "Sceneria posiadająca urządzenia sterowane mechanicznie"
|
||||
},
|
||||
{
|
||||
name: "mechaniczne+SPK",
|
||||
desc:
|
||||
"Sceneria posiadająca urządzenia sterowane mechanicznie zintegrowane z SPK"
|
||||
},
|
||||
{
|
||||
name: "mechaniczne+SCS",
|
||||
desc:
|
||||
"Sceneria posiadająca urządzenia sterowane mechanicznie zintegrowane z SCS"
|
||||
},
|
||||
{ name: "ręczne", desc: "Sceneria z ręcznie sterowanymi zwrotnicami" },
|
||||
{
|
||||
name: "ręczne+SPK",
|
||||
desc: "Sceneria z ręcznie sterowanymi zwrotnicami zintegrowana z SPK"
|
||||
},
|
||||
{
|
||||
name: "współczesna",
|
||||
desc: "Sceneria ze współczesną sygnalizacją świetlną"
|
||||
},
|
||||
{ name: "kształtowa", desc: "Sceneria ze sygnalizacją kształtową" },
|
||||
{ name: "historyczna", desc: "Sceneria ze sygnalizacją historyczną" },
|
||||
{
|
||||
name: "mieszana",
|
||||
desc:
|
||||
"Sceneria ze sygnalizacją mieszaną (kształtowe, historyczne lub/i współczesne)"
|
||||
},
|
||||
{
|
||||
name: "SBL",
|
||||
desc:
|
||||
"Sceneria posiadająca samoczynną blokadę liniową na co najmniej jednym z jej szlaków"
|
||||
}
|
||||
];
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../styles/variables.scss";
|
||||
@import "../../styles/responsive.scss";
|
||||
|
||||
.card {
|
||||
&-exit {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
margin: 0.8em;
|
||||
|
||||
img {
|
||||
width: 1.1em;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&-title {
|
||||
font-size: 3em;
|
||||
font-weight: 700;
|
||||
color: $accentCol;
|
||||
|
||||
margin: 0.3em 0;
|
||||
}
|
||||
}
|
||||
|
||||
.legend-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
padding: 0.5em;
|
||||
|
||||
img {
|
||||
width: 2.5em;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 1.1em;
|
||||
text-align: start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -21,25 +21,15 @@
|
||||
</div>
|
||||
|
||||
<div class="options-content">
|
||||
<transition name="card-anim">
|
||||
<OptionCard v-if="filterCardOpen" :exit="() => toggleCardsState('filter')" />
|
||||
</transition>
|
||||
|
||||
<transition name="card-anim">
|
||||
<LegendCard v-if="legendCardOpen" :exit="() => toggleCardsState('legend')" />
|
||||
</transition>
|
||||
<transition name="card-anim"></transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from "vue-property-decorator";
|
||||
import OptionCard from "@/components/StationsView/OptionCard.vue";
|
||||
import LegendCard from "@/components/StationsView/LegendCard.vue";
|
||||
|
||||
@Component({
|
||||
components: { OptionCard, LegendCard },
|
||||
})
|
||||
@Component({})
|
||||
export default class Options extends Vue {
|
||||
filterCardOpen: boolean = false;
|
||||
legendCardOpen: boolean = false;
|
||||
|
||||
@@ -1,140 +1,142 @@
|
||||
<template>
|
||||
<section class="station-table">
|
||||
<table class="table" v-if="stations.length != 0">
|
||||
<thead class="table-head">
|
||||
<tr>
|
||||
<th v-for="(head, i) in headTitles" :key="i" @click="() => changeSorter(i)">
|
||||
<span>
|
||||
<div>
|
||||
<div>{{head[0]}}</div>
|
||||
<div v-if="head.length > 1">{{head[1]}}</div>
|
||||
</div>
|
||||
<div class="table-wrapper">
|
||||
<table class="table">
|
||||
<thead class="table-head">
|
||||
<tr>
|
||||
<th v-for="(head, i) in headTitles" :key="i" @click="() => changeSorter(i)">
|
||||
<span>
|
||||
<div>
|
||||
<div>{{head[0]}}</div>
|
||||
<div v-if="head.length > 1">{{head[1]}}</div>
|
||||
</div>
|
||||
|
||||
<img
|
||||
class="sort-icon"
|
||||
v-if="sorterActive.index == i"
|
||||
:src="sorterActive.dir == 1 ? icons.ascSVG : icons.descSVG"
|
||||
alt
|
||||
/>
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tr
|
||||
class="table-item"
|
||||
v-for="(station, i) in stations"
|
||||
:key="i + station.stationHash"
|
||||
@click="() => { setFocusedStation(station.stationName) }"
|
||||
>
|
||||
<td
|
||||
class="item-station-name"
|
||||
:class="{'default-station': station.default, 'online': station.online}"
|
||||
>{{station.stationName}}</td>
|
||||
|
||||
<td class="item-station-level">
|
||||
<span
|
||||
v-if="station.reqLevel"
|
||||
:style="calculateExpStyle(station.reqLevel)"
|
||||
>{{ (station.reqLevel && station.reqLevel > -1) ? (parseInt(station.reqLevel) >= 2 ? station.reqLevel : "L") : "?" }}</span>
|
||||
|
||||
<span v-else>?</span>
|
||||
</td>
|
||||
|
||||
<td class="item-station-status">
|
||||
<span class="status" :class="statusClasses(station.occupiedTo)">{{station.occupiedTo}}</span>
|
||||
</td>
|
||||
|
||||
<td class="item-dispatcher-name">{{station.online ? station.dispatcherName : ""}}</td>
|
||||
<td class="item-dispatcher-exp">
|
||||
<span
|
||||
v-if="station.online"
|
||||
:style="calculateExpStyle(station.dispatcherExp)"
|
||||
>{{2 > station.dispatcherExp ? 'L' : station.dispatcherExp}}</span>
|
||||
</td>
|
||||
<td
|
||||
class="item-users"
|
||||
>{{station.online ? (station.currentUsers + "/" + station.maxUsers) : ""}}</td>
|
||||
<td class="item-info">
|
||||
<img
|
||||
class="icon-info"
|
||||
v-if="station.controlType"
|
||||
:src="require(`@/assets/icon-${station.controlType}.svg`)"
|
||||
:alt="station.controlType"
|
||||
:title="'Sterowanie ' + station.controlType"
|
||||
/>
|
||||
|
||||
<img
|
||||
class="icon-info"
|
||||
v-if="station.signalType"
|
||||
:src="require(`@/assets/icon-${station.signalType}.svg`)"
|
||||
:alt="station.signalType"
|
||||
:title="'Sygnalizacja ' + station.signalType"
|
||||
/>
|
||||
|
||||
<img
|
||||
class="icon-info"
|
||||
v-if="station.SBL && station.SBL !== ''"
|
||||
:src="require(`@/assets/icon-SBL.svg`)"
|
||||
alt="SBL"
|
||||
title="Sceneria posiada SBL na przynajmniej jednym ze szlaków"
|
||||
/>
|
||||
|
||||
<img
|
||||
class="icon-info"
|
||||
v-if="!station.reqLevel || station.nonPublic"
|
||||
:src="require(`@/assets/icon-lock.svg`)"
|
||||
alt="non-public"
|
||||
title="Sceneria niepubliczna"
|
||||
/>
|
||||
</td>
|
||||
|
||||
<td class="item-tracks twoway">
|
||||
<span
|
||||
v-if="station.routes && station.routes.twoWay.catenary > 0"
|
||||
class="track catenary"
|
||||
:title="'Liczba zelektryfikowanych szlaków dwutorowych: ' + station.routes.twoWay.catenary"
|
||||
>{{station.routes.twoWay.catenary}}</span>
|
||||
|
||||
<span
|
||||
v-if="station.routes && station.routes.twoWay.noCatenary > 0"
|
||||
class="track no-catenary"
|
||||
:title="'Liczba niezelektryfikowanych szlaków dwutorowych: ' + station.routes.twoWay.noCatenary"
|
||||
>{{station.routes.twoWay.noCatenary}}</span>
|
||||
|
||||
<span class="separator"></span>
|
||||
|
||||
<span
|
||||
v-if="station.routes && station.routes.oneWay.catenary > 0"
|
||||
class="track catenary"
|
||||
:title="'Liczba zelektryfikowanych szlaków jednotorowych: ' + station.routes.oneWay.catenary"
|
||||
>{{station.routes.oneWay.catenary}}</span>
|
||||
|
||||
<span
|
||||
v-if="station.routes && station.routes.oneWay.noCatenary > 0"
|
||||
class="track no-catenary"
|
||||
:title="'Liczba niezelektryfikowanych szlaków jednotorowych: ' + station.routes.oneWay.noCatenary"
|
||||
>{{station.routes.oneWay.noCatenary}}</span>
|
||||
</td>
|
||||
|
||||
<td class="active-timetables">
|
||||
<transition name="change-anim" mode="out-in">
|
||||
<span :key="station.scheduledTrains.length">
|
||||
<span v-if="station.scheduledTrains">
|
||||
<span style="color:#eee">{{ station.scheduledTrains.length}}</span>
|
||||
/
|
||||
<span
|
||||
style="color:#bbb"
|
||||
>{{ station.scheduledTrains.filter(train => train.confirmed).length }}</span>
|
||||
<img
|
||||
class="sort-icon"
|
||||
v-if="sorterActive.index == i"
|
||||
:src="sorterActive.dir == 1 ? icons.ascSVG : icons.descSVG"
|
||||
alt
|
||||
/>
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<span v-else>...</span>
|
||||
</span>
|
||||
</transition>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="no-stations" v-else>Ups! Brak stacji do wyświetlenia!</div>
|
||||
<tr
|
||||
class="table-item"
|
||||
v-for="(station, i) in stations"
|
||||
:key="i + station.stationHash"
|
||||
@click="() => { setFocusedStation(station.stationName) }"
|
||||
>
|
||||
<td
|
||||
class="item-station-name"
|
||||
:class="{'default-station': station.default, 'online': station.online}"
|
||||
>{{station.stationName}}</td>
|
||||
|
||||
<td class="item-station-level">
|
||||
<span
|
||||
v-if="station.reqLevel"
|
||||
:style="calculateExpStyle(station.reqLevel)"
|
||||
>{{ (station.reqLevel && station.reqLevel > -1) ? (parseInt(station.reqLevel) >= 2 ? station.reqLevel : "L") : "?" }}</span>
|
||||
|
||||
<span v-else>?</span>
|
||||
</td>
|
||||
|
||||
<td class="item-station-status">
|
||||
<span class="status" :class="statusClasses(station.occupiedTo)">{{station.occupiedTo}}</span>
|
||||
</td>
|
||||
|
||||
<td class="item-dispatcher-name">{{station.online ? station.dispatcherName : ""}}</td>
|
||||
<td class="item-dispatcher-exp">
|
||||
<span
|
||||
v-if="station.online"
|
||||
:style="calculateExpStyle(station.dispatcherExp)"
|
||||
>{{2 > station.dispatcherExp ? 'L' : station.dispatcherExp}}</span>
|
||||
</td>
|
||||
<td
|
||||
class="item-users"
|
||||
>{{station.online ? (station.currentUsers + "/" + station.maxUsers) : ""}}</td>
|
||||
<td class="item-info">
|
||||
<img
|
||||
class="icon-info"
|
||||
v-if="station.controlType"
|
||||
:src="require(`@/assets/icon-${station.controlType}.svg`)"
|
||||
:alt="station.controlType"
|
||||
:title="'Sterowanie ' + station.controlType"
|
||||
/>
|
||||
|
||||
<img
|
||||
class="icon-info"
|
||||
v-if="station.signalType"
|
||||
:src="require(`@/assets/icon-${station.signalType}.svg`)"
|
||||
:alt="station.signalType"
|
||||
:title="'Sygnalizacja ' + station.signalType"
|
||||
/>
|
||||
|
||||
<img
|
||||
class="icon-info"
|
||||
v-if="station.SBL && station.SBL !== ''"
|
||||
:src="require(`@/assets/icon-SBL.svg`)"
|
||||
alt="SBL"
|
||||
title="Sceneria posiada SBL na przynajmniej jednym ze szlaków"
|
||||
/>
|
||||
|
||||
<img
|
||||
class="icon-info"
|
||||
v-if="!station.reqLevel || station.nonPublic"
|
||||
:src="require(`@/assets/icon-lock.svg`)"
|
||||
alt="non-public"
|
||||
title="Sceneria niepubliczna"
|
||||
/>
|
||||
</td>
|
||||
|
||||
<td class="item-tracks twoway">
|
||||
<span
|
||||
v-if="station.routes && station.routes.twoWay.catenary > 0"
|
||||
class="track catenary"
|
||||
:title="'Liczba zelektryfikowanych szlaków dwutorowych: ' + station.routes.twoWay.catenary"
|
||||
>{{station.routes.twoWay.catenary}}</span>
|
||||
|
||||
<span
|
||||
v-if="station.routes && station.routes.twoWay.noCatenary > 0"
|
||||
class="track no-catenary"
|
||||
:title="'Liczba niezelektryfikowanych szlaków dwutorowych: ' + station.routes.twoWay.noCatenary"
|
||||
>{{station.routes.twoWay.noCatenary}}</span>
|
||||
|
||||
<span class="separator"></span>
|
||||
|
||||
<span
|
||||
v-if="station.routes && station.routes.oneWay.catenary > 0"
|
||||
class="track catenary"
|
||||
:title="'Liczba zelektryfikowanych szlaków jednotorowych: ' + station.routes.oneWay.catenary"
|
||||
>{{station.routes.oneWay.catenary}}</span>
|
||||
|
||||
<span
|
||||
v-if="station.routes && station.routes.oneWay.noCatenary > 0"
|
||||
class="track no-catenary"
|
||||
:title="'Liczba niezelektryfikowanych szlaków jednotorowych: ' + station.routes.oneWay.noCatenary"
|
||||
>{{station.routes.oneWay.noCatenary}}</span>
|
||||
</td>
|
||||
|
||||
<td class="active-timetables">
|
||||
<transition name="change-anim" mode="out-in">
|
||||
<span :key="station.scheduledTrains.length">
|
||||
<span v-if="station.scheduledTrains">
|
||||
<span style="color:#eee">{{ station.scheduledTrains.length}}</span>
|
||||
/
|
||||
<span
|
||||
style="color:#bbb"
|
||||
>{{ station.scheduledTrains.filter(train => train.confirmed).length }}</span>
|
||||
</span>
|
||||
|
||||
<span v-else>...</span>
|
||||
</span>
|
||||
</transition>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="no-stations" v-if="stations.length == 0">Ups! Brak stacji do wyświetlenia!</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -218,6 +220,9 @@ export default class StationTable extends styleMixin {
|
||||
}
|
||||
|
||||
.table {
|
||||
&-wrapper {
|
||||
overflow: auto;
|
||||
}
|
||||
white-space: nowrap;
|
||||
border-collapse: collapse;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"options": [
|
||||
{
|
||||
"options": [{
|
||||
"id": "is-default",
|
||||
"name": "default",
|
||||
"section": "access",
|
||||
@@ -113,8 +112,7 @@
|
||||
"content": "KOŃCZY"
|
||||
}
|
||||
],
|
||||
"sliders": [
|
||||
{
|
||||
"sliders": [{
|
||||
"id": "min-level",
|
||||
"name": "minLevel",
|
||||
"minRange": 0,
|
||||
@@ -160,4 +158,4 @@
|
||||
"content": "SZLAKI DWUTOROWE NIEZELEKTR. (MINIMUM)"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Module, VuexModule, Mutation, Action } from "vuex-module-decorators";
|
||||
import axios from "axios";
|
||||
import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators';
|
||||
import axios from 'axios';
|
||||
|
||||
import data from "@/data/stations.json";
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import data from '@/data/stations.json';
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
|
||||
const stationsOnlineURL =
|
||||
"https://api.td2.info.pl:9640/?method=getStationsOnline";
|
||||
const trainsOnlineURL = "https://api.td2.info.pl:9640/?method=getTrainsOnline";
|
||||
'https://api.td2.info.pl:9640/?method=getStationsOnline';
|
||||
const trainsOnlineURL = 'https://api.td2.info.pl:9640/?method=getTrainsOnline';
|
||||
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 {
|
||||
Loading = 0,
|
||||
@@ -18,14 +18,13 @@ enum ConnState {
|
||||
|
||||
interface TimetableResponseData {
|
||||
stopPoints:
|
||||
| {
|
||||
arrivalTime: string;
|
||||
arrivalDelay: number;
|
||||
departureTime: string;
|
||||
departureDelay: number;
|
||||
pointNameRAW: string;
|
||||
}[]
|
||||
| [];
|
||||
{
|
||||
arrivalTime: string;
|
||||
arrivalDelay: number;
|
||||
departureTime: string;
|
||||
departureDelay: number;
|
||||
pointNameRAW: string;
|
||||
}[];
|
||||
trainInfo: {
|
||||
timetableId: number;
|
||||
trainCategoryCode: string;
|
||||
@@ -53,127 +52,54 @@ let onlineTrainsData: {
|
||||
isOnline: number;
|
||||
region: string;
|
||||
trainNo: number;
|
||||
station: { stationName: string };
|
||||
station: {
|
||||
stationName: string;
|
||||
};
|
||||
}[];
|
||||
|
||||
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 queryStations = axios.get(stationsOnlineURL);
|
||||
const queryTrains = axios.get(trainsOnlineURL);
|
||||
const queryDispatchers = axios.get(dispatchersOnlineURL);
|
||||
|
||||
const getStationLabel = (stationStatus: any) => {
|
||||
if (!stationStatus) return "NIEZALOGOWANY";
|
||||
if (!stationStatus) return 'NIEZALOGOWANY';
|
||||
|
||||
const statusCode = stationStatus[2];
|
||||
const statusTimestamp = stationStatus[3];
|
||||
|
||||
switch (statusCode) {
|
||||
case 0:
|
||||
if (statusTimestamp - Date.now() > 21000000) return "BEZ LIMITU";
|
||||
if (statusTimestamp - Date.now() > 21000000) return 'BEZ LIMITU';
|
||||
|
||||
return `DO ${new Date(statusTimestamp).toLocaleTimeString("en-US", {
|
||||
return `DO ${new Date(statusTimestamp).toLocaleTimeString('en-US', {
|
||||
hour12: false,
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})}`;
|
||||
|
||||
case 1:
|
||||
return "Z/W";
|
||||
return 'Z/W';
|
||||
|
||||
case 2:
|
||||
if (statusTimestamp == 0) return "KOŃCZY";
|
||||
if (statusTimestamp == 0) return 'KOŃCZY';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
return "BRAK MIEJSCA";
|
||||
return 'BRAK MIEJSCA';
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "NIEDOSTĘPNY";
|
||||
return 'NIEDOSTĘPNY';
|
||||
};
|
||||
|
||||
const getOpenSpawns = (spawnString: string) => {
|
||||
if (!spawnString) return "";
|
||||
if (!spawnString) return '';
|
||||
|
||||
return spawnString
|
||||
.split(";")
|
||||
.map((v) => (v.split(",")[6] ? v.split(",")[6] : v.split(",")[0]));
|
||||
};
|
||||
|
||||
const filterStations = (stations, filters) => {
|
||||
return stations.filter((station) => {
|
||||
if ((station.nonPublic || !station.reqLevel) && filters["nonPublic"])
|
||||
return false;
|
||||
if (!station.reqLevel || station.reqLevel == "-1") return true;
|
||||
|
||||
if (station.online && station.occupiedTo == "KOŃCZY" && filters["ending"])
|
||||
return false;
|
||||
if (station.online && filters["occupied"]) return false;
|
||||
if (!station.online && filters["free"]) return false;
|
||||
|
||||
if (station.default && filters["default"]) return false;
|
||||
if (!station.default && filters["notDefault"]) return false;
|
||||
|
||||
if (station.reqLevel < filters["minLevel"]) return false;
|
||||
|
||||
if (
|
||||
filters["no-1track"] &&
|
||||
(station.routes.oneWay.catenary != 0 ||
|
||||
station.routes.oneWay.noCatenary != 0)
|
||||
)
|
||||
return false;
|
||||
if (
|
||||
filters["no-2track"] &&
|
||||
(station.routes.twoWay.catenary != 0 ||
|
||||
station.routes.twoWay.noCatenary != 0)
|
||||
)
|
||||
return false;
|
||||
|
||||
if (station.routes.oneWay.catenary < filters["minOneWayCatenary"])
|
||||
return false;
|
||||
if (station.routes.oneWay.noCatenary < filters["minOneWay"]) return false;
|
||||
|
||||
if (station.routes.twoWay.catenary < filters["minTwoWayCatenary"])
|
||||
return false;
|
||||
if (station.routes.twoWay.noCatenary < filters["minTwoWay"]) return false;
|
||||
|
||||
if (filters[station.controlType]) return false;
|
||||
if (filters[station.signalType]) return false;
|
||||
|
||||
if (filters["SPK"] && station.controlType.includes("SPK")) return false;
|
||||
if (filters["SCS"] && station.controlType.includes("SCS")) return false;
|
||||
if (filters["mechaniczne"] && station.controlType.includes("mechaniczne"))
|
||||
return false;
|
||||
if (filters["ręczne"] && station.controlType.includes("ręczne"))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
.split(';')
|
||||
.map(v => (v.split(',')[6] ? v.split(',')[6] : v.split(',')[0]));
|
||||
};
|
||||
|
||||
@Module
|
||||
@@ -184,24 +110,20 @@ export default class StationsModule extends VuexModule {
|
||||
private stationsConnectionState: ConnState = ConnState.Loading;
|
||||
|
||||
private stations: Station[] = [];
|
||||
private filteredStations: {}[] = [];
|
||||
|
||||
private filters: any = { ...filterInitStates };
|
||||
|
||||
get getConnectionState() {
|
||||
return this.stationsConnectionState;
|
||||
}
|
||||
|
||||
get getOnlineInfo() {
|
||||
return { trainCount: this.trainCount, stationCount: this.stationCount };
|
||||
return {
|
||||
trainCount: this.trainCount,
|
||||
stationCount: this.stationCount,
|
||||
};
|
||||
}
|
||||
|
||||
get getStationList() {
|
||||
return this.filteredStations;
|
||||
}
|
||||
|
||||
get getFilters() {
|
||||
return this.filters;
|
||||
return this.stations;
|
||||
}
|
||||
|
||||
@Mutation
|
||||
@@ -213,22 +135,22 @@ export default class StationsModule extends VuexModule {
|
||||
private updateStations(updatedStations) {
|
||||
this.stations = this.stations.reduce((acc, station) => {
|
||||
const onlineStationData = updatedStations.find(
|
||||
(uStation) => uStation.stationName === station.stationName
|
||||
uStation => uStation.stationName === station.stationName
|
||||
);
|
||||
|
||||
if (!onlineStationData) {
|
||||
acc.push({
|
||||
...station,
|
||||
stationProject: "",
|
||||
spawnString: "",
|
||||
stationHash: "",
|
||||
stationProject: '',
|
||||
spawnString: '',
|
||||
stationHash: '',
|
||||
maxUsers: 0,
|
||||
currentUsers: 0,
|
||||
dispatcherName: "",
|
||||
dispatcherName: '',
|
||||
dispatcherRate: 0,
|
||||
dispatcherExp: -1,
|
||||
dispatcherId: 0,
|
||||
occupiedTo: "WOLNA",
|
||||
occupiedTo: 'WOLNA',
|
||||
statusTimestamp: 0,
|
||||
scheduledTrains: [],
|
||||
online: false,
|
||||
@@ -237,7 +159,11 @@ export default class StationsModule extends VuexModule {
|
||||
return acc;
|
||||
}
|
||||
|
||||
acc.push({ ...station, ...onlineStationData, online: true });
|
||||
acc.push({
|
||||
...station,
|
||||
...onlineStationData,
|
||||
online: true,
|
||||
});
|
||||
|
||||
// updatedStations = updatedStations.filter(
|
||||
// (updated: any) => updated.stationName !== station.stationName
|
||||
@@ -249,66 +175,48 @@ export default class StationsModule extends VuexModule {
|
||||
// Dodawanie do listy online potencjalnych scenerii niewpisanych do bazy
|
||||
updatedStations.forEach((updated: any) => {
|
||||
const alreadyInList: any = this.stations.find(
|
||||
(station) => station.stationName === updated.stationName
|
||||
station => station.stationName === updated.stationName
|
||||
);
|
||||
|
||||
if (!alreadyInList) {
|
||||
this.stations.push({ ...updated, online: true, reqLevel: "-1" });
|
||||
this.stations.push({
|
||||
...updated,
|
||||
online: true,
|
||||
reqLevel: '-1',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.filteredStations = filterStations(this.stations, this.filters);
|
||||
|
||||
this.stationCount = this.stations.filter(
|
||||
(station) => station.online
|
||||
).length;
|
||||
this.stationCount = this.stations.filter(station => station.online).length;
|
||||
|
||||
this.trainCount = onlineTrainsData.filter(
|
||||
(train) => train.isOnline && train.region === "eu"
|
||||
train => train.isOnline && train.region === 'eu'
|
||||
).length;
|
||||
|
||||
this.stationsConnectionState = ConnState.Connected;
|
||||
}
|
||||
|
||||
@Mutation
|
||||
private resetFilterList() {
|
||||
this.filters = { ...filterInitStates };
|
||||
this.filteredStations = filterStations(this.stations, this.filters);
|
||||
}
|
||||
|
||||
@Mutation
|
||||
private changeFilter({ filterName, value }) {
|
||||
this.filters[filterName] = value;
|
||||
this.filteredStations = filterStations(this.stations, this.filters);
|
||||
}
|
||||
|
||||
@Mutation
|
||||
private mutateStations(stations) {
|
||||
this.stations = stations;
|
||||
}
|
||||
|
||||
@Action({ commit: "changeFilter" })
|
||||
setFilter(payload: { filterName: string; value: number | boolean }) {
|
||||
return payload;
|
||||
}
|
||||
|
||||
@Action({ commit: "resetFilterList" })
|
||||
resetFilters() {}
|
||||
|
||||
@Action({ commit: "mutateStations" })
|
||||
@Action({
|
||||
commit: 'mutateStations',
|
||||
})
|
||||
async loadStations() {
|
||||
return await data.map((stationData) => ({
|
||||
stationProject: "",
|
||||
spawnString: "",
|
||||
stationHash: "",
|
||||
return await data.map(stationData => ({
|
||||
stationProject: '',
|
||||
spawnString: '',
|
||||
stationHash: '',
|
||||
maxUsers: 0,
|
||||
currentUsers: 0,
|
||||
dispatcherName: "",
|
||||
dispatcherName: '',
|
||||
dispatcherRate: 0,
|
||||
dispatcherExp: -1,
|
||||
dispatcherId: 0,
|
||||
online: false,
|
||||
occupiedTo: "WOLNA",
|
||||
occupiedTo: 'WOLNA',
|
||||
statusTimestamp: 0,
|
||||
scheduledTrains: [],
|
||||
...stationData,
|
||||
@@ -317,43 +225,47 @@ export default class StationsModule extends VuexModule {
|
||||
|
||||
@Action
|
||||
async initStations() {
|
||||
this.context.dispatch("loadStations");
|
||||
this.context.dispatch("fetchOnlineStations");
|
||||
this.context.dispatch('loadStations');
|
||||
this.context.dispatch('fetchOnlineStations');
|
||||
}
|
||||
|
||||
@Action({ commit: "updateStations" })
|
||||
@Action({
|
||||
commit: 'updateStations',
|
||||
})
|
||||
async fetchOnlineStations() {
|
||||
return await Promise.all([
|
||||
axios.get(stationsOnlineURL),
|
||||
axios.get(trainsOnlineURL),
|
||||
axios.get(dispatchersOnlineURL),
|
||||
])
|
||||
.then(async (response) => {
|
||||
.then(async response => {
|
||||
onlineStationsData = response[0].data.message;
|
||||
onlineTrainsData = await response[1].data.message;
|
||||
onlineDispatchersData = await response[2].data.message;
|
||||
|
||||
const updatedStations = await Promise.all(
|
||||
onlineStationsData
|
||||
.filter((station) => station.region === "eu" && station.isOnline)
|
||||
.map(async (station) => {
|
||||
.filter(station => station.region === 'eu' && station.isOnline)
|
||||
.map(async station => {
|
||||
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 statusTimestamp = stationStatus ? stationStatus[3] : -1;
|
||||
const trains = onlineTrainsData.filter(
|
||||
(train) =>
|
||||
train.region === "eu" &&
|
||||
train =>
|
||||
train.region === 'eu' &&
|
||||
train.isOnline &&
|
||||
train.station.stationName === station.stationName
|
||||
);
|
||||
|
||||
const stationData = data.find(
|
||||
(s) => s.stationName === station.stationName
|
||||
) || { stationName: station.stationName, stationURL: "" };
|
||||
s => s.stationName === station.stationName
|
||||
) || {
|
||||
stationName: station.stationName,
|
||||
stationURL: '',
|
||||
};
|
||||
|
||||
return {
|
||||
...stationData,
|
||||
@@ -374,7 +286,7 @@ export default class StationsModule extends VuexModule {
|
||||
return updatedStations;
|
||||
})
|
||||
.catch(() => {
|
||||
this.context.commit("setConnectionState", ConnState.Error);
|
||||
this.context.commit('setConnectionState', ConnState.Error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+214
-56
@@ -1,15 +1,20 @@
|
||||
<template>
|
||||
<div class="stations-view">
|
||||
<Loading v-if="connectionState == 0" message="Ładowanie scenerii..." />
|
||||
<Error v-if="connectionState == 1" />
|
||||
|
||||
<transition name="card-anim">
|
||||
<StationCard v-if="focusedStationInfo" :stationInfo="focusedStationInfo" :exit="closeCard" />
|
||||
</transition>
|
||||
|
||||
<div class="stations-wrapper" v-if="connectionState == 2">
|
||||
<div class="stations-wrapper">
|
||||
<div class="stations-body">
|
||||
<Options />
|
||||
<div class="options">
|
||||
<div class="options-actions">
|
||||
<button
|
||||
class="action-btn"
|
||||
:class="{'open': filterCardOpen}"
|
||||
@click="() => toggleCardsState('filter')"
|
||||
>
|
||||
<img :src="require('@/assets/icon-filter2.svg')" alt="icon-filter" />
|
||||
<p>FILTRY</p>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<StationTable
|
||||
:stations="computedStations"
|
||||
:sorterActive="sorterActive"
|
||||
@@ -18,54 +23,84 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<transition name="card-anim">
|
||||
<StationCard v-if="focusedStationInfo" :stationInfo="focusedStationInfo" :exit="closeCard" />
|
||||
</transition>
|
||||
|
||||
<transition name="card-anim">
|
||||
<FilterCard
|
||||
v-if="filterCardOpen"
|
||||
:exit="() => toggleCardsState('filter')"
|
||||
@changeFilterValue="changeFilterValue"
|
||||
@resetFilters="resetFilters"
|
||||
/>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from "vue-property-decorator";
|
||||
import { Getter, Action } from "vuex-class";
|
||||
import { Getter } from "vuex-class";
|
||||
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import Train from "@/scripts/interfaces/Train";
|
||||
|
||||
import inputData from "@/data/options.json";
|
||||
|
||||
import Loading from "@/components/App/Loading.vue";
|
||||
import Error from "@/components/App/Error.vue";
|
||||
|
||||
import StationTable from "@/components/StationsView/StationTable.vue";
|
||||
import StationCard from "@/components/StationsView/StationCard.vue";
|
||||
import Options from "@/components/StationsView/Options.vue";
|
||||
import FilterCard from "@/components/StationsView/FilterCard.vue";
|
||||
|
||||
enum ConnState {
|
||||
Loading = 0,
|
||||
Error = 1,
|
||||
Connected = 2,
|
||||
}
|
||||
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,
|
||||
Loading,
|
||||
Error,
|
||||
Options,
|
||||
FilterCard,
|
||||
},
|
||||
})
|
||||
export default class StationsView extends Vue {
|
||||
focusedStationName: string = "";
|
||||
inputs = { ...inputData };
|
||||
STORAGE_KEY: string = "options_saved";
|
||||
|
||||
@Getter("getStationList") stations!: Station[];
|
||||
@Getter("getConnectionState") connectionState!: ConnState;
|
||||
|
||||
@Getter("trainsDataList") trains!: Train[];
|
||||
@Getter("trainsDataState") trainsDataState!: number;
|
||||
|
||||
@Action("setFilter") setFilter;
|
||||
|
||||
sorterActive: { index: number; dir: number } = { index: 0, dir: 1 };
|
||||
focusedStationName: string = "";
|
||||
filterCardOpen: boolean = false;
|
||||
filters = { ...filterInitStates };
|
||||
|
||||
inputs = inputData;
|
||||
|
||||
@Getter("getStationList") stations!: Station[];
|
||||
@Getter("trainsDataList") trains!: Train[];
|
||||
|
||||
toggleCardsState(name: string): void {
|
||||
if (name == "filter") {
|
||||
this.filterCardOpen = !this.filterCardOpen;
|
||||
}
|
||||
}
|
||||
|
||||
changeSorter(index: number) {
|
||||
if (index > 5) return;
|
||||
@@ -77,6 +112,14 @@ export default class StationsView extends Vue {
|
||||
this.sorterActive.index = index;
|
||||
}
|
||||
|
||||
changeFilterValue(filter: { name: string; value: number }) {
|
||||
this.filters[filter.name] = filter.value;
|
||||
}
|
||||
|
||||
resetFilters() {
|
||||
this.filters = { ...filterInitStates };
|
||||
}
|
||||
|
||||
get scheduledTrains() {
|
||||
const reducedList = this.stations.reduce((acc, station) => {
|
||||
if (!acc[station.stationName]) acc[station.stationName] = [];
|
||||
@@ -120,6 +163,74 @@ export default class StationsView extends Vue {
|
||||
const scheduledTrainList = this.scheduledTrains;
|
||||
|
||||
return this.stations
|
||||
.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:
|
||||
@@ -164,39 +275,26 @@ export default class StationsView extends Vue {
|
||||
|
||||
mounted() {
|
||||
const storage = window.localStorage;
|
||||
console.log(storage.getItem(this.STORAGE_KEY));
|
||||
|
||||
if (storage.getItem(this.STORAGE_KEY) !== "true") return;
|
||||
|
||||
this.inputs.options.forEach((input) => {
|
||||
if (storage.getItem(input.name) === "true") {
|
||||
this.setFilter({
|
||||
filterName: input.name,
|
||||
value: false,
|
||||
});
|
||||
this.inputs.options.forEach(option => {
|
||||
const value = storage.getItem(option.name) === "true" ? true : false;
|
||||
console.log(option.name, value);
|
||||
|
||||
input.value = true;
|
||||
} else if (storage.getItem(input.name) === "false") {
|
||||
this.setFilter({
|
||||
filterName: input.name,
|
||||
value: true,
|
||||
});
|
||||
|
||||
input.value = false;
|
||||
}
|
||||
});
|
||||
this.changeFilterValue({ name: option.name, value: value ? 0 : 1 });
|
||||
option.value = value;
|
||||
})
|
||||
|
||||
this.inputs.sliders.forEach((slider) => {
|
||||
const value = parseInt(
|
||||
window.localStorage.getItem(slider.name) as string
|
||||
);
|
||||
this.inputs.sliders.forEach(slider => {
|
||||
const value = parseInt(storage.getItem(slider.name) || "0");
|
||||
|
||||
this.setFilter({
|
||||
filterName: slider.name,
|
||||
value,
|
||||
});
|
||||
|
||||
this.changeFilterValue({ name: slider.name, value });
|
||||
slider.value = value;
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
closeCard() {
|
||||
@@ -220,6 +318,8 @@ export default class StationsView extends Vue {
|
||||
.stations-view {
|
||||
padding: 1rem 0;
|
||||
min-height: 100%;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@import "../styles/variables.scss";
|
||||
@@ -238,6 +338,64 @@ export default class StationsView extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
font-size: calc(0.6rem + 0.9vw);
|
||||
|
||||
&-actions {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
background: #333;
|
||||
border: none;
|
||||
|
||||
color: #e0e0e0;
|
||||
font-size: 0.75em;
|
||||
|
||||
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.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
.stations-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<template>
|
||||
<section class="trains-view">
|
||||
<Loading v-if="connectionState == 0" message="Liczenie pociągów..." />
|
||||
|
||||
<div class="body-wrapper" v-else>
|
||||
<div class="body-wrapper">
|
||||
<div class="options-wrapper">
|
||||
<TrainSorter :trainList="computedTrains" @changeSorter="changeSorter" />
|
||||
<TrainSearch
|
||||
@@ -25,8 +23,6 @@ import { Getter, Action } from "vuex-class";
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import Train from "@/scripts/interfaces/Train";
|
||||
|
||||
import Loading from "@/components/App/Loading.vue";
|
||||
|
||||
import TrainSorter from "@/components/TrainsView/TrainSorter.vue";
|
||||
import TrainSearch from "@/components/TrainsView/TrainSearch.vue";
|
||||
import TrainTable from "@/components/TrainsView/TrainTable.vue";
|
||||
@@ -36,7 +32,6 @@ import axios from "axios";
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
Loading,
|
||||
TrainSorter,
|
||||
TrainTable,
|
||||
TrainStats,
|
||||
@@ -46,8 +41,6 @@ import axios from "axios";
|
||||
export default class TrainsView extends Vue {
|
||||
@Getter("trainsDataList") trains!: Train[];
|
||||
|
||||
@Getter("trainsDataState") connectionState;
|
||||
|
||||
@Action("fetchTrainsData") fetchTrainsData;
|
||||
|
||||
sorterActive: { id: string; dir: number } = { id: "timetable", dir: 1 };
|
||||
@@ -121,8 +114,8 @@ export default class TrainsView extends Vue {
|
||||
@import "../styles/responsive.scss";
|
||||
|
||||
.trains-view {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.body-wrapper {
|
||||
|
||||
Reference in New Issue
Block a user