mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 05:18:11 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b7f3761940 | |||
| ea7c49dfb3 | |||
| 5d6785813a | |||
| a0054aed14 | |||
| 471e6f5216 | |||
| a617eef00e | |||
| 38e700ecd6 | |||
| da1be0e10a | |||
| f49bb12948 | |||
| 02673a3d70 | |||
| 4ddc7345df | |||
| 5d822684c0 | |||
| 69fa15c70a | |||
| 9192067388 | |||
| 2b41e5b857 | |||
| 674680ff14 | |||
| 475bd2ff10 | |||
| 074d1eb155 | |||
| 378393de89 | |||
| 03e61083a7 | |||
| 0b746fce8c | |||
| 5883e710be | |||
| 3d0695a17b | |||
| 4adb76eeb0 | |||
| 4c41076519 | |||
| 77f61d17fd | |||
| 032a84cbcf |
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "stacjownik",
|
||||
"version": "1.13.0",
|
||||
"version": "1.15.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -91,6 +91,11 @@ footer.app_footer {
|
||||
max-width: 100%;
|
||||
padding: 0.5em;
|
||||
|
||||
img {
|
||||
width: 1.1em;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
z-index: 10;
|
||||
|
||||
background: #111;
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
||||
{{ new Date().getUTCFullYear() }} |
|
||||
<a :href="releaseURL" target="_blank">v{{ VERSION }}{{ isOnProductionHost ? '' : 'dev' }}</a>
|
||||
<br />
|
||||
<a href="https://discord.gg/x2mpNN3svk"><img :src="getIcon('discord', 'png')" alt=""> <b>{{ $t('footer.discord') }}</b></a>
|
||||
|
||||
<div style="display: none">∫ ukryta taktyczna całka do programowania w HTMLu</div>
|
||||
</footer>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M23.75 3.75H22.5V1.25H20V3.75H10V1.25H7.5V3.75H6.25C4.875 3.75 3.75 4.875 3.75 6.25V23.75C3.75 25.125 4.875 26.25 6.25 26.25H23.75C25.125 26.25 26.25 25.125 26.25 23.75V6.25C26.25 4.875 25.125 3.75 23.75 3.75ZM23.75 23.75H6.25V11.25H23.75V23.75ZM6.25 8.75V6.25H23.75V8.75H6.25ZM8.75 13.75H21.25V16.25H8.75V13.75ZM8.75 18.75H17.5V21.25H8.75V18.75Z" fill="#F2E147"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 477 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M23.75 3.75H22.5V1.25H20V3.75H10V1.25H7.5V3.75H6.25C4.875 3.75 3.75 4.875 3.75 6.25V23.75C3.75 25.125 4.875 26.25 6.25 26.25H23.75C25.125 26.25 26.25 25.125 26.25 23.75V6.25C26.25 4.875 25.125 3.75 23.75 3.75ZM23.75 23.75H6.25V11.25H23.75V23.75ZM6.25 8.75V6.25H23.75V8.75H6.25ZM8.75 13.75H21.25V16.25H8.75V13.75ZM8.75 18.75H17.5V21.25H8.75V18.75Z" fill="#66FF6C"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 477 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M23.75 3.75H22.5V1.25H20V3.75H10V1.25H7.5V3.75H6.25C4.875 3.75 3.75 4.875 3.75 6.25V23.75C3.75 25.125 4.875 26.25 6.25 26.25H23.75C25.125 26.25 26.25 25.125 26.25 23.75V6.25C26.25 4.875 25.125 3.75 23.75 3.75ZM23.75 23.75H6.25V11.25H23.75V23.75ZM6.25 8.75V6.25H23.75V8.75H6.25ZM8.75 13.75H21.25V16.25H8.75V13.75ZM8.75 18.75H17.5V21.25H8.75V18.75Z" fill="#898989"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 477 B |
@@ -6,16 +6,6 @@
|
||||
<img :src="getIcon('pl')" alt="icon-pl" @click="changeLang('en')" v-if="currentLang == 'pl'" />
|
||||
<img :src="getIcon('en', 'jpg')" alt="icon-en" @click="changeLang('pl')" v-else />
|
||||
</span>
|
||||
|
||||
<span class="icons-bottom">
|
||||
<a href="https://www.paypal.com/paypalme/spythere" target="_blank">
|
||||
<img :src="getIcon('dollar')" alt="icon paypal" />
|
||||
</a>
|
||||
|
||||
<a href="https://discord.gg/x2mpNN3svk" target="_blank">
|
||||
<img :src="getIcon('discord', 'png')" alt="icon discord" />
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="header_body">
|
||||
@@ -33,6 +23,12 @@
|
||||
<div class="info_counter">
|
||||
<img :src="getIcon('dispatcher')" alt="icon dispatcher" />
|
||||
<span class="text--primary">{{ onlineDispatchersCount }}</span>
|
||||
|
||||
<!-- <span class="g-tooltip">
|
||||
<b class="text--primary">{{ factorU }}U</b>
|
||||
<div class="content">Test</div>
|
||||
</span> -->
|
||||
|
||||
<span class="text--grayed"> / </span>
|
||||
<span class="text--primary">{{ onlineTrainsCount }}</span>
|
||||
<img :src="getIcon('train')" alt="icon train" />
|
||||
@@ -98,11 +94,17 @@ export default defineComponent({
|
||||
onlineTrainsCount() {
|
||||
return this.store.trainList.filter((train) => train.online).length;
|
||||
},
|
||||
|
||||
onlineDispatchersCount() {
|
||||
return this.store.stationList.filter(
|
||||
(station) => station.onlineInfo && station.onlineInfo.region == this.store.region.id
|
||||
).length;
|
||||
},
|
||||
|
||||
factorU() {
|
||||
return this.onlineDispatchersCount == 0 ? '-' : (this.onlineTrainsCount / this.onlineDispatchersCount).toFixed(2);
|
||||
},
|
||||
|
||||
computedRegions() {
|
||||
return options.regions.map((region) => {
|
||||
const regionStationCount =
|
||||
@@ -135,22 +137,20 @@ export default defineComponent({
|
||||
|
||||
.header {
|
||||
&_body {
|
||||
max-width: 21em;
|
||||
position: relative;
|
||||
|
||||
@include smallScreen {
|
||||
max-width: 18em;
|
||||
}
|
||||
max-width: 20em;
|
||||
}
|
||||
|
||||
&_container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
width: 1350px;
|
||||
padding: 0.5em 0.3em 0 0.3em;
|
||||
border-radius: 0 0 1em 1em;
|
||||
|
||||
@include smallScreen {
|
||||
position: relative;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
&_brand {
|
||||
@@ -158,6 +158,7 @@ export default defineComponent({
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
@@ -165,9 +166,7 @@ export default defineComponent({
|
||||
&_info {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
max-width: 100%;
|
||||
|
||||
font-size: 1.2em;
|
||||
font-size: 1.15em;
|
||||
}
|
||||
|
||||
&_links {
|
||||
@@ -184,57 +183,20 @@ export default defineComponent({
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-end;
|
||||
padding: 0.5em 0.5em;
|
||||
padding: 0.5em;
|
||||
|
||||
@include smallScreen() {
|
||||
right: auto;
|
||||
left: 0.75em;
|
||||
padding: 0;
|
||||
|
||||
align-items: center;
|
||||
@include smallScreen {
|
||||
transform: translateX(85%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ICONS
|
||||
.icons {
|
||||
position: relative;
|
||||
|
||||
&-top {
|
||||
img {
|
||||
width: 2.5em;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
&-bottom {
|
||||
display: flex;
|
||||
|
||||
a {
|
||||
margin-left: 0.6em;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 1.9em;
|
||||
}
|
||||
|
||||
@include smallScreen() {
|
||||
flex-direction: column;
|
||||
|
||||
a {
|
||||
margin: 0.25em 0;
|
||||
}
|
||||
}
|
||||
.icons-top {
|
||||
img {
|
||||
width: 2.5em;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||
import { useStore } from '../../store/store';
|
||||
import { StoreState } from '../../store/storeTypes';
|
||||
import { StoreState } from '../../scripts/interfaces/store/storeTypes';
|
||||
|
||||
export default defineComponent({
|
||||
data() {
|
||||
@@ -303,9 +303,11 @@ export default defineComponent({
|
||||
|
||||
.status-indicator {
|
||||
position: absolute;
|
||||
left: 110%;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
|
||||
transform: translateX(1.5em);
|
||||
}
|
||||
|
||||
.indicator {
|
||||
@@ -330,7 +332,7 @@ export default defineComponent({
|
||||
background-color: #171717;
|
||||
border-radius: 0.75em;
|
||||
|
||||
min-width: 13em;
|
||||
width: 13em;
|
||||
text-align: center;
|
||||
overflow: none;
|
||||
|
||||
@@ -354,22 +356,16 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
@include midScreen() {
|
||||
left: 50%;
|
||||
top: 100%;
|
||||
|
||||
transform: translate(-50%, 0);
|
||||
margin-left: 0;
|
||||
margin-top: 0.75em;
|
||||
left: auto;
|
||||
right: 200%;
|
||||
|
||||
&::before {
|
||||
border-left: 10px solid transparent;
|
||||
border-right: 10px solid transparent;
|
||||
border-bottom: 10px solid #171717;
|
||||
border-left: 12px solid #171717;
|
||||
right: 0;
|
||||
left: auto;
|
||||
|
||||
top: 0;
|
||||
left: 50%;
|
||||
|
||||
transform: translate(-50%, -100%);
|
||||
transform: translate(100%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,3 +375,4 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
<div class="select-box_content">
|
||||
<button class="selected" @click="toggleBox">
|
||||
<span>{{ computedSelectedItem.selectedValue || computedSelectedItem.value }}</span>
|
||||
|
||||
<div class="arrow">
|
||||
<img :src="listOpen ? getIcon('arrow-asc') : getIcon('arrow-desc')" alt="arrow-icon" />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<ul class="options" :ref="(el) => (listRef = el as Element)">
|
||||
@@ -21,10 +25,6 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="arrow">
|
||||
<img :src="listOpen ? getIcon('arrow-asc') : getIcon('arrow-desc')" alt="arrow-icon" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -129,46 +129,22 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
.select-box {
|
||||
position: relative;
|
||||
width: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
padding: 0;
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
width: 1.35em;
|
||||
}
|
||||
|
||||
transform: translateY(-50%);
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
button.selected {
|
||||
background-color: transparent;
|
||||
color: paleturquoise;
|
||||
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
|
||||
padding: 0.1em 0.5em;
|
||||
margin-right: 2em;
|
||||
|
||||
display: flex;
|
||||
|
||||
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
text-align: left;
|
||||
|
||||
&:focus {
|
||||
background-color: #262626;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<transition-group class="journal-list" tag="ul" name="list-anim">
|
||||
<li
|
||||
v-for="{ timetable, sceneryList, ...item } in computedTimetableHistory"
|
||||
v-for="{ timetable, sceneryList, stockHistoryComp, ...item } in computedTimetableHistory"
|
||||
class="journal_item"
|
||||
:key="timetable.id"
|
||||
@click="item.showExtra.value = !item.showExtra.value"
|
||||
@@ -16,6 +16,12 @@
|
||||
style="cursor: pointer"
|
||||
>
|
||||
<span class="text--grayed">#{{ timetable.id }}</span>
|
||||
|
||||
<span class="badges" v-if="timetable.skr || timetable.twr">
|
||||
<span class="train-badge twr" v-if="timetable.twr" :title="$t('general.TWR')">TWR</span>
|
||||
<span class="train-badge skr" v-if="timetable.skr" :title="$t('general.SKR')">SKR</span>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
<strong class="text--primary">
|
||||
{{ timetable.trainCategoryCode }}
|
||||
@@ -129,24 +135,58 @@
|
||||
<img :src="getIcon(`arrow-${item.showExtra.value ? 'asc' : 'desc'}`)" alt="Arrow" />
|
||||
</button>
|
||||
|
||||
<div class="info-extended" v-if="timetable.stockString && item.showExtra.value">
|
||||
<!-- Dodatkowe informacje -->
|
||||
<div class="info-extended" v-if="timetable.stockString && timetable.stockMass && item.showExtra.value">
|
||||
<hr />
|
||||
<div>
|
||||
<span class="badge info-badge">
|
||||
|
||||
<div class="stock-specs">
|
||||
<span class="badge specs-badge">
|
||||
<span>{{ $t('journal.stock-max-speed') }}</span>
|
||||
<span>{{ timetable.maxSpeed }}km/h</span>
|
||||
</span>
|
||||
<span class="badge info-badge">
|
||||
<span class="badge specs-badge">
|
||||
<span>{{ $t('journal.stock-length') }}</span>
|
||||
<span>{{ timetable.stockLength }}m</span>
|
||||
<span>
|
||||
{{
|
||||
item.currentHistoryIndex.value == 0
|
||||
? timetable.stockLength
|
||||
: stockHistoryComp[item.currentHistoryIndex.value].stockLength || timetable.stockLength
|
||||
}}m
|
||||
</span>
|
||||
</span>
|
||||
<span class="badge info-badge">
|
||||
<span class="badge specs-badge">
|
||||
<span>{{ $t('journal.stock-mass') }}</span>
|
||||
<span>{{ Math.floor(timetable.stockMass! / 1000) }}t</span>
|
||||
<span>
|
||||
{{
|
||||
Math.floor(
|
||||
(item.currentHistoryIndex.value == 0
|
||||
? timetable.stockMass!
|
||||
: stockHistoryComp[item.currentHistoryIndex.value].stockMass || timetable.stockMass) / 1000
|
||||
)
|
||||
}}t
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="stock-history" v-if="stockHistoryComp.length > 1">
|
||||
<button
|
||||
class="btn--action"
|
||||
v-for="(sh, i) in stockHistoryComp"
|
||||
:data-checked="i == item.currentHistoryIndex.value"
|
||||
@click.stop="item.currentHistoryIndex.value = i"
|
||||
>
|
||||
{{ sh.updatedAt }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ul class="stock-list">
|
||||
<li v-for="(car, i) in timetable.stockString.split(';')" :key="i">
|
||||
<li
|
||||
v-for="(car, i) in (item.currentHistoryIndex.value == 0
|
||||
? timetable.stockString
|
||||
: stockHistoryComp[item.currentHistoryIndex.value].stockString
|
||||
).split(';')"
|
||||
:key="i"
|
||||
>
|
||||
<img
|
||||
@error="onImageError"
|
||||
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${car.split(':')[0]}.png`"
|
||||
@@ -168,7 +208,6 @@ import imageMixin from '../../mixins/imageMixin';
|
||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||
import styleMixin from '../../mixins/styleMixin';
|
||||
import { TimetableHistory } from '../../scripts/interfaces/api/TimetablesAPIData';
|
||||
import { TimetableStop } from '../../scripts/interfaces/api/TrainAPIData';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -185,7 +224,24 @@ export default defineComponent({
|
||||
return this.timetableHistory.map((timetable) => ({
|
||||
timetable,
|
||||
sceneryList: this.getSceneryList(timetable),
|
||||
stockHistoryComp: timetable.stockHistory
|
||||
.slice()
|
||||
.reverse()
|
||||
.map((h) => {
|
||||
const historyData = h.split('@');
|
||||
|
||||
return {
|
||||
updatedAt: new Date(Number(historyData[0])).toLocaleTimeString(this.$i18n.locale, {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
}),
|
||||
stockString: historyData[1],
|
||||
stockMass: Number(historyData[2]) || undefined,
|
||||
stockLength: Number(historyData[3]) || undefined,
|
||||
};
|
||||
}),
|
||||
showExtra: ref(false),
|
||||
currentHistoryIndex: ref(0),
|
||||
}));
|
||||
},
|
||||
},
|
||||
@@ -292,6 +348,7 @@ hr {
|
||||
|
||||
.general-train {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
}
|
||||
@@ -308,6 +365,45 @@ ul.stock-list {
|
||||
color: #aaa;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
li > img {
|
||||
vertical-align: text-bottom;
|
||||
max-height: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.stock-specs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em;
|
||||
margin-top: 0.5em;
|
||||
|
||||
.specs-badge {
|
||||
margin: 0;
|
||||
|
||||
span:last-child {
|
||||
color: black;
|
||||
background-color: $accentCol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.badges {
|
||||
display: flex;
|
||||
gap: 0.25em;
|
||||
|
||||
// badge.scss
|
||||
}
|
||||
|
||||
.stock-history {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5em;
|
||||
margin-top: 1em;
|
||||
|
||||
button[data-checked='true'] {
|
||||
color: $accentCol;
|
||||
}
|
||||
}
|
||||
|
||||
.scenery-list {
|
||||
@@ -328,13 +424,6 @@ ul.stock-list {
|
||||
}
|
||||
}
|
||||
|
||||
.info-badge {
|
||||
span:last-child {
|
||||
color: black;
|
||||
background-color: $accentCol;
|
||||
}
|
||||
}
|
||||
|
||||
@include smallScreen {
|
||||
.info-general {
|
||||
flex-direction: column;
|
||||
@@ -343,6 +432,10 @@ ul.stock-list {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.general-train {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.info-route {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -351,5 +444,13 @@ ul.stock-list {
|
||||
.btn--show {
|
||||
margin: 1em auto 0 auto;
|
||||
}
|
||||
|
||||
.stock-specs {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.stock-history {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
{{ station.name }}
|
||||
</a>
|
||||
|
||||
<div class="scenery-abbrev">{{ $t('scenery.abbrev') }} <b>{{ station.generalInfo?.abbr }}</b></div>
|
||||
|
||||
<div class="scenery-hash" v-if="station.onlineInfo?.hash">#{{ station.onlineInfo.hash }}</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -28,16 +30,20 @@ export default defineComponent({
|
||||
|
||||
.scenery-name {
|
||||
font-weight: bold;
|
||||
|
||||
position: relative;
|
||||
|
||||
font-size: 3em;
|
||||
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.scenery-abbrev {
|
||||
font-size: 1.3em;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.scenery-hash {
|
||||
margin-top: 0.5em;
|
||||
color: #aaa;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -30,8 +30,9 @@
|
||||
style="color: salmon; text-decoration: underline; font-weight: bold"
|
||||
:href="station.generalInfo.projectUrl"
|
||||
target="_blank"
|
||||
>{{ station.generalInfo.project }}</a
|
||||
>
|
||||
{{ station.generalInfo.project }}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
|
||||
<table v-else-if="sceneryHistoryList.length">
|
||||
<thead>
|
||||
<th>{{ $t('scenery.timetables-history-id') }}</th>
|
||||
<th>{{ $t('scenery.timetables-history-number')}}</th>
|
||||
<th>{{ $t('scenery.timetables-history-route')}}</th>
|
||||
<th>{{ $t('scenery.timetables-history-driver')}}</th>
|
||||
<th>{{ $t('scenery.timetables-history-author')}}</th>
|
||||
<th>{{ $t('scenery.timetables-history-date')}}</th>
|
||||
<th>{{ $t('scenery.timetables-history-id') }}</th>
|
||||
<th>{{ $t('scenery.timetables-history-number') }}</th>
|
||||
<th>{{ $t('scenery.timetables-history-route') }}</th>
|
||||
<th>{{ $t('scenery.timetables-history-driver') }}</th>
|
||||
<th>{{ $t('scenery.timetables-history-author') }}</th>
|
||||
<th>{{ $t('scenery.timetables-history-date') }}</th>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr v-for="historyItem in sceneryHistoryList" @click="test">
|
||||
<tr v-for="historyItem in sceneryHistoryList">
|
||||
<td>
|
||||
<router-link :to="`/journal/timetables?timetableId=${historyItem.id}`">#{{ historyItem.id }}</router-link>
|
||||
</td>
|
||||
@@ -40,31 +40,6 @@
|
||||
</table>
|
||||
|
||||
<div class="list-warning" v-else>{{ $t('scenery.history-list-empty') }}</div>
|
||||
|
||||
<!-- <ul class="history-list" v-else>
|
||||
<li class="list-item" v-for="historyItem in sceneryHistoryList">
|
||||
<div>
|
||||
<b>{{ localeDay(historyItem.beginDate, $i18n.locale) }}</b>
|
||||
{{ localeTime(historyItem.beginDate, $i18n.locale) }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<router-link :to="`/journal/timetables?timetableId=${historyItem.id}`">
|
||||
<span class="text--grayed"> #{{ historyItem.id }} </span>
|
||||
<b class="text--primary"> {{ historyItem.trainCategoryCode }} {{ historyItem.trainNo }}</b>
|
||||
<div>{{ historyItem.driverName }}</div>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<div>{{ historyItem.route.replace('|', ' -> ') }}</div>
|
||||
<div>
|
||||
{{ $t('scenery.timetable-author-title') }}:
|
||||
<b v-if="historyItem.authorName">{{ historyItem.authorName }}</b>
|
||||
<i v-else>{{ $t('scenery.timetable-author-unknown') }}</i>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
</ul> -->
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -99,19 +74,15 @@ export default defineComponent({
|
||||
methods: {
|
||||
async fetchAPIData(countFrom = 0, countLimit = 15) {
|
||||
try {
|
||||
const requestString = `${URLs.stacjownikAPI}/api/getSceneryTimetables?name=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||
const requestString = `${URLs.stacjownikAPI}/api/getIssuedTimetables?name=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||
const historyAPIData: SceneryTimetableHistory = await (await axios.get(requestString)).data;
|
||||
|
||||
this.sceneryHistoryList = historyAPIData.sceneryTimetables;
|
||||
this.sceneryHistoryList = historyAPIData.timetables;
|
||||
this.dataStatus = DataStatus.Loaded;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
|
||||
test() {
|
||||
console.log('test');
|
||||
},
|
||||
},
|
||||
components: { Loading },
|
||||
});
|
||||
|
||||
@@ -1,47 +1,19 @@
|
||||
<template>
|
||||
<div class="general-status">
|
||||
<span :class="scheduledTrain.stopStatus">
|
||||
<span v-if="scheduledTrain.stopStatus == 'arriving'">
|
||||
<span v-if="scheduledTrain.prevDepartureLine">({{ scheduledTrain.prevDepartureLine }})</span>
|
||||
{{ scheduledTrain.prevStationName }}
|
||||
><span v-if="scheduledTrain.nextArrivalLine"> ({{ scheduledTrain.nextArrivalLine }}) </span>
|
||||
{{ scheduledTrain.nextStationName || '---' }}
|
||||
</span>
|
||||
|
||||
<span v-else-if="scheduledTrain.stopStatus == 'departed'">
|
||||
>> <span v-if="scheduledTrain.nextArrivalLine"> ({{ scheduledTrain.nextArrivalLine }}) </span>
|
||||
{{ scheduledTrain.nextStationName }}
|
||||
</span>
|
||||
|
||||
<span v-else-if="scheduledTrain.stopStatus == 'departed-away'">
|
||||
>>>
|
||||
<span v-if="scheduledTrain.nextArrivalLine"> ({{ scheduledTrain.nextArrivalLine }}) </span>
|
||||
{{ scheduledTrain.nextStationName }}
|
||||
</span>
|
||||
|
||||
<span v-else-if="scheduledTrain.stopStatus == 'online'">
|
||||
>
|
||||
<span v-if="scheduledTrain.nextArrivalLine">
|
||||
({{ scheduledTrain.nextArrivalLine }}) {{ scheduledTrain.nextStationName }}
|
||||
</span>
|
||||
<span v-else-if="!scheduledTrain.nextStationName">{{ $t('timetables.end') }}</span>
|
||||
<span v-else>{{ scheduledTrain.nextStationName }}</span>
|
||||
</span>
|
||||
|
||||
<span v-else-if="scheduledTrain.stopStatus == 'stopped'">
|
||||
>
|
||||
<span v-if="scheduledTrain.nextArrivalLine"> ({{ scheduledTrain.nextArrivalLine }}) </span>
|
||||
{{ scheduledTrain.nextStationName }}
|
||||
</span>
|
||||
|
||||
<span v-else-if="scheduledTrain.stopStatus == 'terminated'">X {{ $t('timetables.terminated') }}</span>
|
||||
<span :class="computedScheduledTrain.stopStatus" :title="computedScheduledTrain.stopStatusDescription">
|
||||
{{ computedScheduledTrain.stopStatusIndicator }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import ScheduledTrain from '../../scripts/interfaces/ScheduledTrain';
|
||||
import { ScheduledTrain, StopStatus } from '../../scripts/interfaces/ScheduledTrain';
|
||||
|
||||
interface ScheduledTrainComp extends ScheduledTrain {
|
||||
stopStatusIndicator: string;
|
||||
stopStatusDescription: string;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -50,6 +22,58 @@ export default defineComponent({
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
computedScheduledTrain(): ScheduledTrainComp {
|
||||
const { prevDepartureLine, prevStationName, stopStatus, nextArrivalLine, nextStationName } = this.scheduledTrain;
|
||||
|
||||
const prevDepartureIndicator = prevDepartureLine ? `(${prevDepartureLine}) ${prevStationName}` : '---';
|
||||
const nextArrivalIndicator = nextArrivalLine ? `(${nextArrivalLine}) ${nextStationName}` : '---';
|
||||
|
||||
let stopStatusDescription = '',
|
||||
stopStatusIndicator = '';
|
||||
|
||||
switch (stopStatus) {
|
||||
case StopStatus.arriving:
|
||||
stopStatusIndicator = `${this.$t('timetables.from')}: ${prevDepartureIndicator}`;
|
||||
stopStatusDescription = this.$t('timetables.desc-arriving', { prevStationName, prevDepartureLine });
|
||||
break;
|
||||
|
||||
case StopStatus.online:
|
||||
case StopStatus.stopped:
|
||||
stopStatusIndicator = nextArrivalLine
|
||||
? `${this.$t('timetables.to')}: ${nextArrivalIndicator}`
|
||||
: `${this.$t('timetables.desc-end')}`;
|
||||
stopStatusDescription = nextArrivalLine
|
||||
? this.$t(`timetables.desc-${stopStatus}`, { nextStationName, nextArrivalLine })
|
||||
: '';
|
||||
break;
|
||||
|
||||
case StopStatus.departed:
|
||||
stopStatusIndicator = `${this.$t('timetables.to')}: ${nextArrivalIndicator}`;
|
||||
stopStatusDescription = this.$t('timetables.desc-departed', { nextStationName, nextArrivalLine });
|
||||
break;
|
||||
|
||||
case StopStatus['departed-away']:
|
||||
stopStatusIndicator = `${this.$t('timetables.to')}: ${nextArrivalIndicator}`;
|
||||
stopStatusDescription = this.$t('timetables.desc-departed-away', { nextStationName, nextArrivalLine });
|
||||
break;
|
||||
|
||||
case StopStatus.terminated:
|
||||
stopStatusIndicator = `X ${this.$t('timetables.desc-terminated')}`;
|
||||
stopStatusDescription = this.$t('timetables.desc-terminated');
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return {
|
||||
...this.scheduledTrain,
|
||||
stopStatusDescription,
|
||||
stopStatusIndicator,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -86,3 +110,4 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -50,9 +50,6 @@ export default defineComponent({
|
||||
handleDbClick(e: Event) {
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
const lastClicked = this.filterStore.lastClickedFilterId == this.option.id;
|
||||
console.log(this.filterStore.lastClickedFilterId);
|
||||
this.filterStore.lastClickedFilterId = this.option.id;
|
||||
this.option.value = true;
|
||||
|
||||
@@ -96,51 +93,8 @@ button {
|
||||
}
|
||||
|
||||
&[data-selected='true'] {
|
||||
// &.reality {
|
||||
// background-color: $realityCol;
|
||||
// box-shadow: 0 0 6px 1px $realityCol;
|
||||
// }
|
||||
|
||||
// &.access {
|
||||
// background-color: $accessCol;
|
||||
// box-shadow: 0 0 6px 1px $accessCol;
|
||||
// }
|
||||
|
||||
// &.control {
|
||||
// background-color: $controlCol;
|
||||
// box-shadow: 0 0 6px 1px $controlCol;
|
||||
// }
|
||||
|
||||
// &.signals {
|
||||
// background-color: $signalCol;
|
||||
// box-shadow: 0 0 6px 1px $signalCol;
|
||||
// }
|
||||
|
||||
// &.routes {
|
||||
// background-color: $routesCol;
|
||||
// box-shadow: 0 0 6px 1px $routesCol;
|
||||
// }
|
||||
|
||||
// &.status {
|
||||
// background-color: $statusCol;
|
||||
// box-shadow: 0 0 6px 1px $statusCol;
|
||||
// }
|
||||
|
||||
// &.save {
|
||||
// background-color: $saveCol;
|
||||
// box-shadow: 0 0 6px 1px $saveCol;
|
||||
// }
|
||||
|
||||
// &.troll {
|
||||
// background-color: firebrick;
|
||||
// box-shadow: 0 0 6px 1px firebrick;
|
||||
// }
|
||||
|
||||
// & {
|
||||
background-color: forestgreen;
|
||||
|
||||
font-weight: bold;
|
||||
// }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -128,7 +128,6 @@ import { useStore } from '../../store/store';
|
||||
|
||||
import ActionButton from '../Global/ActionButton.vue';
|
||||
import FilterOption from './FilterOption.vue';
|
||||
import { filterInitStates } from '../../store/constants/initFilterStates';
|
||||
|
||||
export default defineComponent({
|
||||
components: { ActionButton, FilterOption },
|
||||
|
||||
@@ -8,26 +8,36 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="(id, i) in headIds" :key="id" @click="() => changeSorter(i)">
|
||||
<th
|
||||
v-for="(headerName, i) in headIds"
|
||||
:key="headerName"
|
||||
@click="changeSorter(headerName)"
|
||||
class="header-text"
|
||||
>
|
||||
<span class="header_wrapper">
|
||||
<div v-html="$t(`sceneries.${id}`)"></div>
|
||||
<div v-html="$t(`sceneries.${headerName}`)"></div>
|
||||
|
||||
<img
|
||||
class="sort-icon"
|
||||
v-if="sorterActive.index == i"
|
||||
v-if="sorterActive.headerName == headerName"
|
||||
:src="sorterActive.dir == 1 ? getIcon('arrow-asc') : getIcon('arrow-desc')"
|
||||
alt="sort icon"
|
||||
/>
|
||||
</span>
|
||||
</th>
|
||||
|
||||
<th v-for="(id, i) in headIconsIds" :key="id" @click="() => changeSorter(i + 7)">
|
||||
<th
|
||||
v-for="(headerName, i) in headIconsIds"
|
||||
:key="headerName"
|
||||
@click="changeSorter(headerName)"
|
||||
class="header-image"
|
||||
>
|
||||
<span class="header_wrapper">
|
||||
<img :src="getIcon(id)" :alt="id" :title="$t(`sceneries.${id}s`)" />
|
||||
<img :src="getIcon(headerName)" :alt="headerName" :title="$t(`sceneries.${headerName}`)" />
|
||||
|
||||
<img
|
||||
class="sort-icon"
|
||||
v-if="sorterActive.index == i + 7"
|
||||
v-if="sorterActive.headerName == headerName"
|
||||
:src="sorterActive.dir == 1 ? getIcon('arrow-asc') : getIcon('arrow-desc')"
|
||||
alt="sort icon"
|
||||
/>
|
||||
@@ -190,25 +200,31 @@
|
||||
|
||||
<td class="station_users" :class="{ inactive: !station.onlineInfo }">
|
||||
<span>
|
||||
<span class="highlight">{{ station.onlineInfo?.currentUsers || '0' }}</span>
|
||||
<span class="highlight">{{ station.onlineInfo?.currentUsers || 0 }}</span>
|
||||
/
|
||||
<span>{{ station.onlineInfo?.maxUsers || '0' }}</span>
|
||||
<span class="highlight">{{ station.onlineInfo?.maxUsers || 0 }}</span>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="station_spawns" :class="{ inactive: !station.onlineInfo }">
|
||||
<span class="highlight">{{ station.onlineInfo?.spawns.length || '0' }}</span>
|
||||
<span>{{ station.onlineInfo?.spawns.length || 0 }}</span>
|
||||
</td>
|
||||
|
||||
<td class="station_schedules" :class="{ inactive: !station.onlineInfo }">
|
||||
<span>
|
||||
<span class="highlight">
|
||||
{{ station.onlineInfo?.scheduledTrains?.length || '0' }}
|
||||
</span>
|
||||
/
|
||||
<span style="color: #bbb">
|
||||
{{ station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed).length || '0' }}
|
||||
</span>
|
||||
<td class="station_schedules" style="width: 30px" :class="{ inactive: !station.onlineInfo }">
|
||||
<span class="highlight">
|
||||
{{ station.onlineInfo?.scheduledTrains?.length || 0 }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="station_schedules" style="width: 30px" :class="{ inactive: !station.onlineInfo }">
|
||||
<span style="color: #ccc">
|
||||
{{ station.onlineInfo?.scheduledTrains?.filter((train) => !train.stopInfo.confirmed).length || 0 }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="station_schedules" style="width: 30px" :class="{ inactive: !station.onlineInfo }">
|
||||
<span style="color: #66ff6c">
|
||||
{{ station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed).length || 0 }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -236,6 +252,7 @@ import Station from '../../scripts/interfaces/Station';
|
||||
import { useStationFiltersStore } from '../../store/stationFiltersStore';
|
||||
import { useStore } from '../../store/store';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import { HeadIdsTypes, headIconsIds, headIds } from '../../scripts/data/stationHeaderNames';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -249,8 +266,8 @@ export default defineComponent({
|
||||
mixins: [styleMixin, dateMixin, stationInfoMixin, returnBtnMixin, imageMixin],
|
||||
|
||||
data: () => ({
|
||||
headIds: ['station', 'min-lvl', 'status', 'dispatcher', 'dispatcher-lvl', 'routes', 'general'],
|
||||
headIconsIds: ['user', 'spawn', 'timetable'],
|
||||
headIconsIds,
|
||||
headIds,
|
||||
lastSelectedStationName: '',
|
||||
}),
|
||||
|
||||
@@ -291,8 +308,10 @@ export default defineComponent({
|
||||
window.open(url, '_blank');
|
||||
},
|
||||
|
||||
changeSorter(i: number) {
|
||||
this.stationFiltersStore.changeSorter(i);
|
||||
changeSorter(headerName: HeadIdsTypes) {
|
||||
if (headerName == 'general' || headerName == 'routes') return;
|
||||
|
||||
this.stationFiltersStore.changeSorter(headerName);
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -349,9 +368,15 @@ table {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
min-width: 75px;
|
||||
&.header-text {
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
padding: 0.5em;
|
||||
&.header-image {
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
padding: 0.5em 0.25em;
|
||||
background-color: $bgCol;
|
||||
white-space: pre-wrap;
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<span class="timetable-id" v-if="train.timetableData">#{{ train.timetableData.timetableId }}</span>
|
||||
|
||||
<span class="timetable_warnings" v-if="train.timetableData?.TWR || train.timetableData?.SKR">
|
||||
<span class="train-badge twr" v-if="train.timetableData?.TWR">TWR</span>
|
||||
<span class="train-badge skr" v-if="train.timetableData?.SKR">SKR</span>
|
||||
<span class="train-badge twr" v-if="train.timetableData?.TWR" :title="$t('general.TWR')">TWR</span>
|
||||
<span class="train-badge skr" v-if="train.timetableData?.SKR" :title="$t('general.SKR')">SKR</span>
|
||||
</span>
|
||||
|
||||
<strong>
|
||||
@@ -118,7 +118,6 @@ export default defineComponent({
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/badge.scss';
|
||||
|
||||
|
||||
.image-warning {
|
||||
height: 1em;
|
||||
|
||||
@@ -182,26 +181,6 @@ export default defineComponent({
|
||||
gap: 0.25em;
|
||||
}
|
||||
|
||||
.train-badge {
|
||||
padding: 0.1em 0.2em;
|
||||
border-radius: 0.2em;
|
||||
font-weight: bold;
|
||||
|
||||
font-size: 0.9em;
|
||||
|
||||
&.twr {
|
||||
background-color: var(--clr-twr);
|
||||
}
|
||||
|
||||
&.skr {
|
||||
background-color: var(--clr-skr);
|
||||
}
|
||||
|
||||
&.offline {
|
||||
background-color: #9c362b;
|
||||
}
|
||||
}
|
||||
|
||||
.train-driver {
|
||||
&.supporter {
|
||||
color: orange;
|
||||
@@ -218,9 +197,7 @@ export default defineComponent({
|
||||
|
||||
.timetable_warnings {
|
||||
display: flex;
|
||||
gap: 0.2em;
|
||||
|
||||
color: black;
|
||||
gap: 0.25em;
|
||||
}
|
||||
|
||||
.timetable_progress {
|
||||
|
||||
@@ -202,7 +202,6 @@ ul.stock-list {
|
||||
|
||||
img {
|
||||
max-height: 60px;
|
||||
max-width: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
-7
@@ -1,7 +1,9 @@
|
||||
{
|
||||
"general": {
|
||||
"and": " and ",
|
||||
"refresh": "REFRESH"
|
||||
"refresh": "REFRESH",
|
||||
"TWR": "High risk freight train",
|
||||
"SKR": "Train with exceeded gauge"
|
||||
},
|
||||
"app": {
|
||||
"sceneries": "SCENERIES",
|
||||
@@ -15,6 +17,9 @@
|
||||
"migration-confirm": "Roger that!",
|
||||
"offline": "App is in the offline mode!"
|
||||
},
|
||||
"footer": {
|
||||
"discord": "Stacjownik Discord server"
|
||||
},
|
||||
"update": {
|
||||
"title": "New version of the app is available!",
|
||||
"paragraph1": "Enjoy the application and may the green signal be with you!",
|
||||
@@ -208,13 +213,15 @@
|
||||
"dispatcher-lvl": "Dispatcher\nlevel",
|
||||
"routes": "Routes\ndouble / single",
|
||||
"general": "General info",
|
||||
"users": "Drivers online",
|
||||
"spawns": "Spawns online",
|
||||
"timetables": "Active timetables",
|
||||
"user": "Drivers online",
|
||||
"spawn": "Spawns online",
|
||||
"timetableAll": "Active timetables",
|
||||
"timetableConfirmed": "Confirmed timetables",
|
||||
"timetableUnconfirmed": "Unconfirmed timetables",
|
||||
"no-stations": "No stations to show here!",
|
||||
"scenery-search": "Search for scenery..."
|
||||
},
|
||||
"trains": {
|
||||
"trains": {
|
||||
"no-trains": "No trains to show here!",
|
||||
"loading": "Loading train data...",
|
||||
"offline": "Offline ride",
|
||||
@@ -284,7 +291,7 @@
|
||||
"stock-info": "EXTRA INFO",
|
||||
"stock-length": "Length",
|
||||
"stock-mass": "Mass",
|
||||
"stock-max-speed": "Maximum registered speed",
|
||||
"stock-max-speed": "Max. speed",
|
||||
|
||||
"load-data": "Load further data...",
|
||||
|
||||
@@ -328,6 +335,7 @@
|
||||
"history-btn": "View the dispatcher history",
|
||||
"info-btn": "Return to the scenery view",
|
||||
"authors-title": "Scenery author | Scenery authors",
|
||||
"abbrev": "Station symbol:",
|
||||
"lines-title": "Real lines",
|
||||
"project-title": "Project name",
|
||||
"one-way-routes": "One way routes",
|
||||
@@ -368,7 +376,19 @@
|
||||
"end": "Timetable terminates here",
|
||||
"terminated": "Timetable terminated",
|
||||
"begins": "BEGINS HERE",
|
||||
"terminates": "TERMINATES\nHERE"
|
||||
"terminates": "TERMINATES\nHERE",
|
||||
|
||||
"from": "FROM",
|
||||
"to": "TO",
|
||||
|
||||
"desc-arriving": "The train is not here yet. It's going to come from: {prevStationName} (szlak {prevDepartureLine})",
|
||||
"desc-online": "The train is at the station. It's going to leave to: {nextStationName} (szlak {nextArrivalLine})",
|
||||
"desc-stopped": "The train is at the station and is stopped. It's going to leave towards: {nextStationName} (szlak {nextArrivalLine})",
|
||||
"desc-next-arrival": "Leaves towards: {nextStationName} (szlak {nextArrivalLine})",
|
||||
"desc-departed": "The train is at the station and it's been departed. Leaves towards: {nextStationName} (szlak {nextArrivalLine})",
|
||||
"desc-departed-away": "The train has been departed to: {nextStationName} (szlak {nextArrivalLine})",
|
||||
"desc-end": "The train terminates here",
|
||||
"desc-terminated": "The train has been terminated"
|
||||
},
|
||||
"history": {
|
||||
"title": "TIMETABLE JOURNAL",
|
||||
|
||||
+28
-9
@@ -1,7 +1,9 @@
|
||||
{
|
||||
"general": {
|
||||
"and": " oraz ",
|
||||
"refresh": "ODŚWIEŻ"
|
||||
"refresh": "ODŚWIEŻ",
|
||||
"TWR": "Towar niebezpieczny wysokiego ryzyka",
|
||||
"SKR": "Przekroczona skrajnia"
|
||||
},
|
||||
"app": {
|
||||
"sceneries": "SCENERIE",
|
||||
@@ -15,7 +17,9 @@
|
||||
"migration-confirm": "Przyjąłem!",
|
||||
"offline": "Aplikacja w trybie offline!"
|
||||
},
|
||||
|
||||
"footer": {
|
||||
"discord": "Serwer Discord Stacjownika"
|
||||
},
|
||||
"update": {
|
||||
"title": "Nowa wersja Stacjownika jest dostępna!",
|
||||
"paragraph1": "Miłego korzystania z aplikacji i niech S2 będzie z wami!",
|
||||
@@ -23,7 +27,6 @@
|
||||
"confirm-button": "ZAKTUALIZUJ",
|
||||
"later-button": "PÓŹNIEJ"
|
||||
},
|
||||
|
||||
"data-status": {
|
||||
"S1-offline": "<b>Sygnał S1</b> <br> Aplikacja działa w trybie offline!",
|
||||
"S1a-connection": "<b>Sygnał S1a</b> <br> Błąd podczas próby połączenia się z API Stacjownika!",
|
||||
@@ -136,7 +139,7 @@
|
||||
},
|
||||
"filters": {
|
||||
"desc": " • Kliknięcie: zaznaczenie / odznaczenie filtru <br /> • Podwójne kliknięcie: odznaczenie reszty filtrów z <b class='text--primary'>grupy</b> <br /> • <span style='color: coral'>RESET</span>: zresetowanie filtrów z <b class='text--primary'>grupy</b>",
|
||||
|
||||
|
||||
"sections": {
|
||||
"reality": "FIKCYJNOŚĆ SCENERII",
|
||||
"package-access": "DOSTĘPNOŚĆ W PACZCE",
|
||||
@@ -207,15 +210,18 @@
|
||||
},
|
||||
"sceneries": {
|
||||
"station": "Stacja",
|
||||
"abbr": "Skrót\nposterunku",
|
||||
"min-lvl": "Min. poziom\ndyżurnego",
|
||||
"status": "Status",
|
||||
"dispatcher": "Dyżurny",
|
||||
"dispatcher-lvl": "Poziom\ndyżurnego",
|
||||
"routes": "Szlaki\n2tor / 1tor",
|
||||
"general": "Informacje\nogólne",
|
||||
"users": "Maszyniści online",
|
||||
"spawns": "Otwarte spawny",
|
||||
"timetables": "Aktywne rozkłady jazdy",
|
||||
"user": "Maszyniści online",
|
||||
"spawn": "Otwarte spawny",
|
||||
"timetableAll": "Aktywne rozkłady jazdy",
|
||||
"timetableConfirmed": "Zatwierdzone rozkłady jazdy",
|
||||
"timetableUnconfirmed": "Niezatwierdzone rozkłady jazdy",
|
||||
"no-stations": "Brak stacji do wyświetlenia!",
|
||||
"scenery-search": "Wyszukaj scenerię..."
|
||||
},
|
||||
@@ -290,7 +296,7 @@
|
||||
"stock-info": "DODATKOWE INFORMACJE",
|
||||
"stock-length": "Długość",
|
||||
"stock-mass": "Masa",
|
||||
"stock-max-speed": "Maks. zarejestrowana prędkość",
|
||||
"stock-max-speed": "Prędkość maks.",
|
||||
|
||||
"load-data": "Pobierz dalszą historię...",
|
||||
|
||||
@@ -334,6 +340,7 @@
|
||||
"history-btn": "Przejdź do widoku historii dyżurnych ruchu",
|
||||
"info-btn": "Wróć do widoku scenerii",
|
||||
"authors-title": "Autor scenerii | Autorzy scenerii",
|
||||
"abbrev": "Skrót posterunku:",
|
||||
"lines-title": "Rzeczywiste linie",
|
||||
"project-title": "Projekt",
|
||||
"one-way-routes": "Szlaki jednotorowe",
|
||||
@@ -374,7 +381,19 @@
|
||||
"end": "Koniec rozkładu jazdy",
|
||||
"terminated": "Rozkład jazdy zakończony",
|
||||
"begins": "ROZPOCZYNA\nBIEG",
|
||||
"terminates": "KOŃCZY BIEG"
|
||||
"terminates": "KOŃCZY BIEG",
|
||||
|
||||
"from": "Z",
|
||||
"to": "DO",
|
||||
|
||||
"desc-arriving": "Pociągu nie ma jeszcze na tej scenerii. Przyjedzie z: {prevStationName} (szlak {prevDepartureLine})",
|
||||
"desc-online": "Pociąg jest na tej scenerii. Odjedzie do: {nextStationName} (szlak {nextArrivalLine})",
|
||||
"desc-stopped": "Pociąg jest na tej scenerii i odbywa postój. Odjedzie do: {nextStationName} (szlak {nextArrivalLine})",
|
||||
"desc-next-arrival": "Odjeżdża do: {nextStationName} (szlak {nextArrivalLine})",
|
||||
"desc-departed": "Pociąg jest na tej scenerii i został odprawiony. Odjeżdża do: {nextStationName} (szlak {nextArrivalLine})",
|
||||
"desc-departed-away": "Pociąg został odprawiony i odjechał do: {nextStationName} (szlak {nextArrivalLine})",
|
||||
"desc-end": "Pociąg kończy bieg",
|
||||
"desc-terminated": "Pociąg skończył bieg"
|
||||
},
|
||||
"history": {
|
||||
"title": "DZIENNIK ROZKŁADÓW JAZDY"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export const headIds = ['station', 'min-lvl', 'status', 'dispatcher', 'dispatcher-lvl', 'routes', 'general'] as const;
|
||||
|
||||
export const headIconsIds = ['user', 'spawn', 'timetableAll', 'timetableUnconfirmed', 'timetableConfirmed'] as const;
|
||||
|
||||
export type HeadIdsTypes = typeof headIds[number] | typeof headIconsIds[number];
|
||||
@@ -1,32 +1,41 @@
|
||||
import TrainStop from "./TrainStop";
|
||||
import TrainStop from './TrainStop';
|
||||
|
||||
export default interface ScheduledTrain {
|
||||
trainId: string;
|
||||
trainNo: number;
|
||||
|
||||
driverName: string;
|
||||
driverId: number;
|
||||
currentStationName: string;
|
||||
currentStationHash: string;
|
||||
category: string;
|
||||
stopInfo: TrainStop;
|
||||
export enum StopStatus {
|
||||
'arriving' = 'arriving',
|
||||
'departed' = 'departed',
|
||||
'departed-away' = 'departed-away',
|
||||
'online' = 'online',
|
||||
'stopped' = 'stopped',
|
||||
'terminated' = 'terminated',
|
||||
}
|
||||
|
||||
terminatesAt: string;
|
||||
beginsAt: string;
|
||||
export interface ScheduledTrain {
|
||||
trainId: string;
|
||||
trainNo: number;
|
||||
|
||||
prevStationName: string;
|
||||
nextStationName: string;
|
||||
driverName: string;
|
||||
driverId: number;
|
||||
currentStationName: string;
|
||||
currentStationHash: string;
|
||||
category: string;
|
||||
stopInfo: TrainStop;
|
||||
|
||||
arrivingLine: string | null;
|
||||
departureLine: string | null;
|
||||
terminatesAt: string;
|
||||
beginsAt: string;
|
||||
|
||||
prevDepartureLine: string | null;
|
||||
nextArrivalLine: string | null;
|
||||
prevStationName: string;
|
||||
nextStationName: string;
|
||||
|
||||
signal: string;
|
||||
connectedTrack: string;
|
||||
arrivingLine: string | null;
|
||||
departureLine: string | null;
|
||||
|
||||
stopLabel: string;
|
||||
stopStatus: string;
|
||||
stopStatusID: number;
|
||||
}
|
||||
prevDepartureLine: string | null;
|
||||
nextArrivalLine: string | null;
|
||||
|
||||
signal: string;
|
||||
connectedTrack: string;
|
||||
|
||||
stopLabel: string;
|
||||
stopStatus: StopStatus;
|
||||
stopStatusID: number;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Availability } from '../../store/storeTypes';
|
||||
import ScheduledTrain from './ScheduledTrain';
|
||||
import { Availability } from './store/storeTypes';
|
||||
import {ScheduledTrain} from './ScheduledTrain';
|
||||
import StationRoutes from './StationRoutes';
|
||||
|
||||
export default interface Station {
|
||||
@@ -8,9 +8,11 @@ export default interface Station {
|
||||
generalInfo?: {
|
||||
name: string;
|
||||
url: string;
|
||||
|
||||
abbr: string;
|
||||
|
||||
reqLevel: number;
|
||||
// supportersOnly: boolean;
|
||||
|
||||
|
||||
lines: string;
|
||||
project: string;
|
||||
|
||||
@@ -38,6 +38,8 @@ export interface TimetableHistory {
|
||||
stopsString?: string;
|
||||
|
||||
stockString?: string;
|
||||
stockHistory: string[];
|
||||
|
||||
stockMass?: number;
|
||||
stockLength?: number;
|
||||
maxSpeed?: number;
|
||||
@@ -45,10 +47,12 @@ export interface TimetableHistory {
|
||||
hashesString?: string;
|
||||
currentSceneryName?: string;
|
||||
currentSceneryHash?: string;
|
||||
|
||||
routeSceneries?: string;
|
||||
}
|
||||
|
||||
export interface SceneryTimetableHistory {
|
||||
sceneryTimetables: TimetableHistory[];
|
||||
totalCount: number;
|
||||
sceneryName: string;
|
||||
timetables: TimetableHistory[];
|
||||
// totalCount: number;
|
||||
// sceneryName: string;
|
||||
}
|
||||
|
||||
@@ -1,78 +1,90 @@
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { DataStatus } from '../scripts/enums/DataStatus';
|
||||
import StationAPIData from '../scripts/interfaces/api/StationAPIData';
|
||||
import { TrainAPIData } from '../scripts/interfaces/api/TrainAPIData';
|
||||
import Station from '../scripts/interfaces/Station';
|
||||
import Train from '../scripts/interfaces/Train';
|
||||
import { DispatcherStatsAPIData } from '../scripts/interfaces/api/DispatcherStatsAPIData';
|
||||
import { DriverStatsAPIData } from '../scripts/interfaces/api/DriverStatsAPIData';
|
||||
|
||||
export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault';
|
||||
|
||||
export interface StoreState {
|
||||
stationList: Station[];
|
||||
trainList: Train[];
|
||||
apiData: APIData;
|
||||
|
||||
lastDispatcherStatuses: { hash: string; statusTimestamp: number; statusID: string }[];
|
||||
|
||||
sceneryData: any[][];
|
||||
|
||||
region: { id: string; value: string };
|
||||
trainCount: number;
|
||||
stationCount: number;
|
||||
|
||||
webSocket?: Socket;
|
||||
isOffline: boolean;
|
||||
|
||||
dispatcherStatsName: string;
|
||||
dispatcherStatsData?: DispatcherStatsAPIData;
|
||||
|
||||
driverStatsName: string;
|
||||
driverStatsData?: DriverStatsAPIData;
|
||||
driverStatsStatus: DataStatus;
|
||||
|
||||
chosenModalTrainId?: string;
|
||||
|
||||
currentStatsTab: 'daily' | 'driver';
|
||||
|
||||
dataStatuses: {
|
||||
connection: DataStatus;
|
||||
sceneries: DataStatus;
|
||||
timetables: DataStatus;
|
||||
dispatchers: DataStatus;
|
||||
trains: DataStatus;
|
||||
};
|
||||
|
||||
listenerLaunched: boolean;
|
||||
blockScroll: boolean;
|
||||
}
|
||||
|
||||
export interface APIData {
|
||||
stations?: StationAPIData[];
|
||||
dispatchers?: string[][];
|
||||
trains?: TrainAPIData[];
|
||||
connectedSocketCount: number;
|
||||
}
|
||||
|
||||
export interface StationJSONData {
|
||||
name: string;
|
||||
url: string;
|
||||
lines: string;
|
||||
project: string;
|
||||
projectUrl: string;
|
||||
|
||||
reqLevel: number;
|
||||
|
||||
signalType: string;
|
||||
controlType: string;
|
||||
|
||||
SUP: boolean;
|
||||
|
||||
routes: string;
|
||||
|
||||
checkpoints: string | null;
|
||||
authors?: string;
|
||||
|
||||
availability: Availability;
|
||||
}
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { DataStatus } from '../../enums/DataStatus';
|
||||
import StationAPIData from '../api/StationAPIData';
|
||||
import { TrainAPIData } from '../api/TrainAPIData';
|
||||
import Station from '../Station';
|
||||
import Train from '../Train';
|
||||
import { DispatcherStatsAPIData } from '../api/DispatcherStatsAPIData';
|
||||
import { DriverStatsAPIData } from '../api/DriverStatsAPIData';
|
||||
|
||||
export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault';
|
||||
|
||||
export interface StoreState {
|
||||
stationList: Station[];
|
||||
trainList: Train[];
|
||||
apiData: APIData;
|
||||
|
||||
lastDispatcherStatuses: { hash: string; statusTimestamp: number; statusID: string }[];
|
||||
|
||||
sceneryData: any[][];
|
||||
|
||||
region: { id: string; value: string };
|
||||
trainCount: number;
|
||||
stationCount: number;
|
||||
|
||||
webSocket?: Socket;
|
||||
isOffline: boolean;
|
||||
|
||||
dispatcherStatsName: string;
|
||||
dispatcherStatsData?: DispatcherStatsAPIData;
|
||||
|
||||
driverStatsName: string;
|
||||
driverStatsData?: DriverStatsAPIData;
|
||||
driverStatsStatus: DataStatus;
|
||||
|
||||
chosenModalTrainId?: string;
|
||||
|
||||
currentStatsTab: 'daily' | 'driver';
|
||||
|
||||
dataStatuses: {
|
||||
connection: DataStatus;
|
||||
sceneries: DataStatus;
|
||||
timetables: DataStatus;
|
||||
dispatchers: DataStatus;
|
||||
trains: DataStatus;
|
||||
};
|
||||
|
||||
listenerLaunched: boolean;
|
||||
blockScroll: boolean;
|
||||
}
|
||||
|
||||
export interface APIData {
|
||||
stations?: StationAPIData[];
|
||||
dispatchers?: string[][];
|
||||
trains?: TrainAPIData[];
|
||||
connectedSocketCount: number;
|
||||
}
|
||||
|
||||
export interface StationRoutesInfo {
|
||||
routeName: string;
|
||||
isElectric: boolean;
|
||||
isInternal: boolean;
|
||||
isRouteSBL: boolean;
|
||||
routeLength: number;
|
||||
routeSpeed: number;
|
||||
routeTracks: number;
|
||||
}
|
||||
|
||||
export interface StationJSONData {
|
||||
name: string;
|
||||
abbr: string;
|
||||
url: string;
|
||||
lines: string;
|
||||
project: string;
|
||||
projectUrl: string;
|
||||
|
||||
reqLevel: number;
|
||||
|
||||
signalType: string;
|
||||
controlType: string;
|
||||
|
||||
SUP: boolean;
|
||||
|
||||
// routes: string;
|
||||
routesInfo: StationRoutesInfo[];
|
||||
|
||||
checkpoints: string | null;
|
||||
authors?: string;
|
||||
|
||||
availability: Availability;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
export const URLs = {
|
||||
stacjownikAPI:
|
||||
import.meta.env.VITE_APP_API_DEV == 1 && !import.meta.env.PROD
|
||||
? 'http://localhost:3000'
|
||||
? 'http://localhost:3001'
|
||||
: 'https://spythere.pl',
|
||||
stacjownikAPIDev: 'localhost:3000',
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import ScheduledTrain from '../interfaces/ScheduledTrain';
|
||||
import { ScheduledTrain, StopStatus } from '../interfaces/ScheduledTrain';
|
||||
import Train from '../interfaces/Train';
|
||||
import TrainStop from '../interfaces/TrainStop';
|
||||
|
||||
@@ -74,32 +74,32 @@ export const parseSpawns = (spawnString: string) => {
|
||||
export const getTimestamp = (date: string | null): number => (date ? new Date(date).getTime() : 0);
|
||||
|
||||
export const getTrainStopStatus = (stopInfo: TrainStop, currentStationName: string, stationName: string) => {
|
||||
let stopStatus = '',
|
||||
let stopStatus = StopStatus['arriving'],
|
||||
stopLabel = '',
|
||||
stopStatusID = -1;
|
||||
|
||||
if (stopInfo.terminatesHere && stopInfo.confirmed) {
|
||||
stopStatus = 'terminated';
|
||||
stopStatus = StopStatus['terminated'];
|
||||
stopLabel = 'Skończył bieg';
|
||||
stopStatusID = 5;
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == stationName) {
|
||||
stopStatus = 'departed';
|
||||
stopStatus = StopStatus['departed'];
|
||||
stopLabel = 'Odprawiony';
|
||||
stopStatusID = 2;
|
||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != stationName) {
|
||||
stopStatus = 'departed-away';
|
||||
stopStatus = StopStatus['departed-away'];
|
||||
stopLabel = 'Odjechał';
|
||||
stopStatusID = 4;
|
||||
} else if (currentStationName == stationName && !stopInfo.stopped) {
|
||||
stopStatus = 'online';
|
||||
stopStatus = StopStatus['online'];
|
||||
stopLabel = 'Na stacji';
|
||||
stopStatusID = 0;
|
||||
} else if (currentStationName == stationName && stopInfo.stopped) {
|
||||
stopStatus = 'stopped';
|
||||
stopStatus = StopStatus['stopped'];
|
||||
stopLabel = 'Postój';
|
||||
stopStatusID = 1;
|
||||
} else if (currentStationName != stationName) {
|
||||
stopStatus = 'arriving';
|
||||
stopStatus = StopStatus['arriving'];
|
||||
stopLabel = 'W drodze';
|
||||
stopStatusID = 3;
|
||||
}
|
||||
@@ -122,7 +122,7 @@ export function getScheduledTrain(train: Train, trainStopIndex: number, stationN
|
||||
|
||||
for (let i = trainStopIndex - 1; i >= 0; i--) {
|
||||
if (/strong|podg/g.test(followingStops[i].stopName)) {
|
||||
prevStationName = followingStops[i].stopNameRAW.replace(/,.*/g,"");
|
||||
prevStationName = followingStops[i].stopNameRAW.replace(/,.*/g, '');
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -130,7 +130,7 @@ export function getScheduledTrain(train: Train, trainStopIndex: number, stationN
|
||||
|
||||
for (let i = trainStopIndex + 1; i < followingStops.length; i++) {
|
||||
if (/strong|podg/g.test(followingStops[i].stopName)) {
|
||||
nextStationName = followingStops[i].stopNameRAW.replace(/,.*/g,"");
|
||||
nextStationName = followingStops[i].stopNameRAW.replace(/,.*/g, '');
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -172,7 +172,6 @@ export function getScheduledTrain(train: Train, trainStopIndex: number, stationN
|
||||
signal: train.signal,
|
||||
connectedTrack: train.connectedTrack,
|
||||
|
||||
|
||||
driverName: train.driverName,
|
||||
driverId: train.driverId,
|
||||
currentStationName: train.currentStationName,
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import inputData from '../data/options.json';
|
||||
import Filter from '../scripts/interfaces/Filter';
|
||||
import Station from '../scripts/interfaces/Station';
|
||||
import StorageManager from '../scripts/managers/storageManager';
|
||||
import { useStore } from './store';
|
||||
import { filterInitStates } from './constants/initFilterStates';
|
||||
import { filterStations, sortStations } from './utils/filterUtils';
|
||||
import { HeadIdsTypes } from '../scripts/data/stationHeaderNames';
|
||||
|
||||
export const useStationFiltersStore = defineStore('stationFiltersStore', {
|
||||
state() {
|
||||
return {
|
||||
inputs: inputData,
|
||||
filters: { ...filterInitStates },
|
||||
sorterActive: { index: 0, dir: 1 },
|
||||
sorterActive: { headerName: 'station' as HeadIdsTypes, dir: 1 },
|
||||
store: useStore(),
|
||||
lastClickedFilterId: '',
|
||||
};
|
||||
@@ -89,13 +89,11 @@ export const useStationFiltersStore = defineStore('stationFiltersStore', {
|
||||
});
|
||||
},
|
||||
|
||||
changeSorter(index: number) {
|
||||
if (index > 4 && index < 7) return;
|
||||
|
||||
if (index == this.sorterActive.index) this.sorterActive.dir = -1 * this.sorterActive.dir;
|
||||
changeSorter(headerName: HeadIdsTypes) {
|
||||
if (headerName == this.sorterActive.headerName) this.sorterActive.dir = -1 * this.sorterActive.dir;
|
||||
else this.sorterActive.dir = 1;
|
||||
|
||||
this.sorterActive.index = index;
|
||||
this.sorterActive.headerName = headerName;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
+31
-49
@@ -3,7 +3,7 @@ import { defineStore } from 'pinia';
|
||||
import { io } from 'socket.io-client';
|
||||
import { DataStatus } from '../scripts/enums/DataStatus';
|
||||
import StationAPIData from '../scripts/interfaces/api/StationAPIData';
|
||||
import ScheduledTrain from '../scripts/interfaces/ScheduledTrain';
|
||||
import { ScheduledTrain } from '../scripts/interfaces/ScheduledTrain';
|
||||
import Station from '../scripts/interfaces/Station';
|
||||
import StationRoutes from '../scripts/interfaces/StationRoutes';
|
||||
import Train from '../scripts/interfaces/Train';
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
getScheduledTrain,
|
||||
parseSpawns,
|
||||
} from '../scripts/utils/storeUtils';
|
||||
import { APIData, StationJSONData, StoreState } from './storeTypes';
|
||||
import { APIData, StationJSONData, StoreState } from '../scripts/interfaces/store/storeTypes';
|
||||
|
||||
export const useStore = defineStore('store', {
|
||||
state: () =>
|
||||
@@ -303,57 +303,39 @@ export const useStore = defineStore('store', {
|
||||
...scenery,
|
||||
authors: scenery.authors?.split(',').map((a) => a.trim()),
|
||||
routes:
|
||||
scenery.routes
|
||||
?.split(';')
|
||||
.filter((routeString) => routeString)
|
||||
.reduce(
|
||||
(acc, routeString) => {
|
||||
const specs1 = routeString.split('_')[0];
|
||||
const isInternal = specs1.startsWith('!');
|
||||
const name = isInternal ? specs1.replace('!', '') : specs1;
|
||||
scenery.routesInfo.reduce(
|
||||
(acc, route) => {
|
||||
const propName: keyof StationRoutes = `${route.routeTracks == 2 ? 'twoWay' : 'oneWay'}${
|
||||
route.isElectric ? '' : 'No'
|
||||
}CatenaryRouteNames`;
|
||||
|
||||
const specs2 = routeString.split('_')[1].split('');
|
||||
const twoWay = specs2[0] == '2';
|
||||
const catenary = specs2[1] == 'E';
|
||||
const SBL = specs2[2] == 'S';
|
||||
const TWB = specs2[3] ? true : false;
|
||||
const speed = Number(routeString.split(':')[1]) || 0;
|
||||
const length = Number(routeString.split(':')[2]) || 0;
|
||||
acc[route.routeTracks == 2 ? 'twoWay' : 'oneWay'].push({
|
||||
name: route.routeName,
|
||||
SBL: route.isRouteSBL,
|
||||
TWB: false,
|
||||
catenary: route.isElectric,
|
||||
isInternal: route.isInternal,
|
||||
tracks: route.routeTracks,
|
||||
length: route.routeLength,
|
||||
speed: route.routeSpeed,
|
||||
});
|
||||
|
||||
const propName = twoWay
|
||||
? catenary
|
||||
? 'twoWayCatenaryRouteNames'
|
||||
: 'twoWayNoCatenaryRouteNames'
|
||||
: catenary
|
||||
? 'oneWayCatenaryRouteNames'
|
||||
: 'oneWayNoCatenaryRouteNames';
|
||||
if (!route.isInternal) acc[propName].push(route.routeName);
|
||||
|
||||
acc[twoWay ? 'twoWay' : 'oneWay'].push({
|
||||
name,
|
||||
SBL,
|
||||
TWB,
|
||||
catenary,
|
||||
isInternal,
|
||||
tracks: twoWay ? 2 : 1,
|
||||
length,
|
||||
speed,
|
||||
});
|
||||
if (!isInternal) acc[propName].push(name);
|
||||
if (route.isRouteSBL) acc['sblRouteNames'].push(route.routeName);
|
||||
|
||||
if (SBL) acc['sblRouteNames'].push(name);
|
||||
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
oneWay: [],
|
||||
twoWay: [],
|
||||
sblRouteNames: [],
|
||||
oneWayCatenaryRouteNames: [],
|
||||
oneWayNoCatenaryRouteNames: [],
|
||||
twoWayCatenaryRouteNames: [],
|
||||
twoWayNoCatenaryRouteNames: [],
|
||||
} as StationRoutes
|
||||
) || {},
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
oneWay: [],
|
||||
twoWay: [],
|
||||
sblRouteNames: [],
|
||||
oneWayCatenaryRouteNames: [],
|
||||
oneWayNoCatenaryRouteNames: [],
|
||||
twoWayCatenaryRouteNames: [],
|
||||
twoWayNoCatenaryRouteNames: [],
|
||||
} as StationRoutes
|
||||
) || {},
|
||||
checkpoints: scenery.checkpoints
|
||||
? scenery.checkpoints.split(';').map((sub) => ({ checkpointName: sub, scheduledTrains: [] }))
|
||||
: [],
|
||||
|
||||
@@ -1,57 +1,72 @@
|
||||
import { HeadIdsTypes } from '../../scripts/data/stationHeaderNames';
|
||||
import Filter from '../../scripts/interfaces/Filter';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
|
||||
export const sortStations = (a: Station, b: Station, sorter: { index: number; dir: number }) => {
|
||||
switch (sorter.index) {
|
||||
case 0:
|
||||
export const sortStations = (a: Station, b: Station, sorter: { headerName: HeadIdsTypes; dir: number }) => {
|
||||
let diff = 0;
|
||||
|
||||
switch (sorter.headerName) {
|
||||
case 'station':
|
||||
return sorter.dir == 1 ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name);
|
||||
|
||||
case 1:
|
||||
if ((a.generalInfo?.reqLevel || 0) > (b.generalInfo?.reqLevel || 0)) return sorter.dir;
|
||||
if ((a.generalInfo?.reqLevel || 0) < (b.generalInfo?.reqLevel || 0)) return -sorter.dir;
|
||||
case 'min-lvl':
|
||||
diff = (a.generalInfo?.reqLevel || 0) - (b.generalInfo?.reqLevel || 0);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if ((a.onlineInfo?.statusTimestamp || 0) > (b.onlineInfo?.statusTimestamp || 0)) return sorter.dir;
|
||||
if ((a.onlineInfo?.statusTimestamp || 0) < (b.onlineInfo?.statusTimestamp || 0)) return -sorter.dir;
|
||||
case 'status':
|
||||
diff = (a.onlineInfo?.statusTimestamp || 0) - (b.onlineInfo?.statusTimestamp || 0);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
case 'dispatcher':
|
||||
if ((a.onlineInfo?.dispatcherName.toLowerCase() || '') > (b.onlineInfo?.dispatcherName.toLowerCase() || ''))
|
||||
return sorter.dir;
|
||||
if ((a.onlineInfo?.dispatcherName.toLowerCase() || '') < (b.onlineInfo?.dispatcherName.toLowerCase() || ''))
|
||||
return -sorter.dir;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ((a.onlineInfo?.dispatcherExp || 0) > (b.onlineInfo?.dispatcherExp || 0)) return sorter.dir;
|
||||
if ((a.onlineInfo?.dispatcherExp || 0) < (b.onlineInfo?.dispatcherExp || 0)) return -sorter.dir;
|
||||
case 'dispatcher-lvl':
|
||||
diff = (a.onlineInfo?.dispatcherExp || 0) - (b.onlineInfo?.dispatcherExp || 0);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
if ((a.onlineInfo?.currentUsers || 0) > (b.onlineInfo?.currentUsers || 0)) return sorter.dir;
|
||||
if ((a.onlineInfo?.currentUsers || 0) < (b.onlineInfo?.currentUsers || 0)) return -sorter.dir;
|
||||
|
||||
if ((a.onlineInfo?.maxUsers || 0) > (b.onlineInfo?.maxUsers || 0)) return sorter.dir;
|
||||
if ((a.onlineInfo?.maxUsers || 0) < (b.onlineInfo?.maxUsers || 0)) return -sorter.dir;
|
||||
case 'user':
|
||||
diff = (b.onlineInfo ? b.onlineInfo.currentUsers : -1) - (a.onlineInfo ? a.onlineInfo.currentUsers : -1);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
if ((a.onlineInfo?.spawns.length || 0) > (b.onlineInfo?.spawns.length || 0)) return sorter.dir;
|
||||
if ((a.onlineInfo?.spawns.length || 0) < (b.onlineInfo?.spawns.length || 0)) return -sorter.dir;
|
||||
|
||||
case 'spawn':
|
||||
diff = (a.onlineInfo ? a.onlineInfo.spawns.length : -1) - (b.onlineInfo ? b.onlineInfo.spawns.length : -1);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
if ((a.onlineInfo?.scheduledTrains?.length || 0) > (b.onlineInfo?.scheduledTrains?.length || 0))
|
||||
return sorter.dir;
|
||||
if ((a.onlineInfo?.scheduledTrains?.length || 0) < (b.onlineInfo?.scheduledTrains?.length || 0))
|
||||
return -sorter.dir;
|
||||
case 'timetableConfirmed':
|
||||
diff =
|
||||
(a.onlineInfo?.scheduledTrains
|
||||
? a.onlineInfo.scheduledTrains.filter((train) => train.stopInfo.confirmed).length
|
||||
: -1) -
|
||||
(b.onlineInfo?.scheduledTrains
|
||||
? b.onlineInfo.scheduledTrains.filter((train) => train.stopInfo.confirmed).length
|
||||
: -1);
|
||||
break;
|
||||
|
||||
case 'timetableUnconfirmed':
|
||||
diff =
|
||||
(a.onlineInfo?.scheduledTrains
|
||||
? a.onlineInfo.scheduledTrains.filter((train) => !train.stopInfo.confirmed).length
|
||||
: -1) -
|
||||
(b.onlineInfo?.scheduledTrains
|
||||
? b.onlineInfo.scheduledTrains.filter((train) => !train.stopInfo.confirmed).length
|
||||
: -1);
|
||||
break;
|
||||
|
||||
case 'timetableAll':
|
||||
diff =
|
||||
(a.onlineInfo?.scheduledTrains ? a.onlineInfo.scheduledTrains.length : -1) -
|
||||
(b.onlineInfo?.scheduledTrains ? b.onlineInfo.scheduledTrains.length : -1);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (diff != 0) return Math.sign(diff) * sorter.dir;
|
||||
return a.name.localeCompare(b.name);
|
||||
};
|
||||
|
||||
|
||||
+20
-2
@@ -4,12 +4,11 @@
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
|
||||
background: #585858;
|
||||
|
||||
margin: 0.25em;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
background: #585858;
|
||||
padding: 0.2em 0.4em;
|
||||
}
|
||||
|
||||
@@ -56,3 +55,22 @@
|
||||
background-color: forestgreen;
|
||||
}
|
||||
}
|
||||
|
||||
.train-badge {
|
||||
padding: 0.1em 0.2em;
|
||||
border-radius: 0.2em;
|
||||
font-weight: bold;
|
||||
|
||||
font-size: 0.9em;
|
||||
|
||||
&.twr {
|
||||
background-color: var(--clr-twr);
|
||||
box-shadow: 0 0 5px 1px var(--clr-twr);
|
||||
color: black;
|
||||
}
|
||||
|
||||
&.skr {
|
||||
background-color: var(--clr-skr);
|
||||
box-shadow: 0 0 5px 1px var(--clr-skr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,17 +52,6 @@ export default defineComponent({
|
||||
|
||||
mounted() {
|
||||
this.filterStore.setupFilters();
|
||||
// this.filterStore.inputs.options.forEach((option) => {
|
||||
// const value = StorageManager.getBooleanValue(option.name);
|
||||
// option.value = value;
|
||||
// this.filterStore.changeFilterValue({ name: option.name, value: value });
|
||||
// });
|
||||
|
||||
// this.filterStore.inputs.sliders.forEach((slider) => {
|
||||
// const value = StorageManager.getNumericValue(slider.name);
|
||||
// slider.value = value;
|
||||
// this.filterStore.changeFilterValue({ name: slider.name, value: value });
|
||||
// });
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user