mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 13:28:11 +00:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea5c9e0028 | |||
| eb7c2d7132 | |||
| ee7c50f59b | |||
| 439f59fedc | |||
| c47d839ce3 | |||
| f77c13cbcf | |||
| dbbbd33100 | |||
| 14d13360a8 | |||
| dc862252ba | |||
| e5fe727ccd | |||
| e836bbed0c | |||
| d4438fd215 | |||
| 1550849360 | |||
| 9d1dc4ffca | |||
| 0397fa788d | |||
| 6e5696b0a6 | |||
| 4537341a57 | |||
| c35c74bd4a | |||
| 25735c5e6e | |||
| 41e60bc69e | |||
| 933bdecb3c | |||
| 10e183d96b | |||
| 5429d39f5e | |||
| ff31e7f903 | |||
| 91f4c6bc57 | |||
| c133eb060b | |||
| 7ffc169d8a | |||
| 1b85cc5f58 | |||
| 72ff857fff | |||
| 96d64e77fc | |||
| 6ceae3f161 | |||
| 8e8e27658c | |||
| 9b6ace394a | |||
| 6cfeaa91bf | |||
| 08b208aeaa | |||
| a089b5275b | |||
| 8425cd4371 | |||
| dbdc517b87 | |||
| e271358a27 | |||
| 66262e3fcd | |||
| 5b2b6bdea2 | |||
| c8587de6d9 | |||
| 1f376085f2 | |||
| f28600a7fa | |||
| d59ead87e6 | |||
| 34d91bc800 | |||
| cf9991d8a0 | |||
| 4ffb79d62b | |||
| d9f5edb4fe | |||
| 1b2112430a | |||
| 0a972a23ef | |||
| 6d52724d06 | |||
| 99415c35d3 | |||
| c3f687d439 | |||
| 266edfd6e6 | |||
| d32d5ad91b | |||
| c3481470cb | |||
| 57e88b9abc | |||
| 44ebf53798 | |||
| 145dc72b6b | |||
| 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 |
Generated
+12
-8
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.11.0",
|
"version": "1.16.0.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.11.0",
|
"version": "1.16.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.12.1",
|
"core-js": "^3.12.1",
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
@@ -3465,9 +3465,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001441",
|
"version": "1.0.30001503",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001441.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz",
|
||||||
"integrity": "sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==",
|
"integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3477,6 +3477,10 @@
|
|||||||
{
|
{
|
||||||
"type": "tidelift",
|
"type": "tidelift",
|
||||||
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -9117,9 +9121,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"caniuse-lite": {
|
"caniuse-lite": {
|
||||||
"version": "1.0.30001441",
|
"version": "1.0.30001503",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001441.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz",
|
||||||
"integrity": "sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==",
|
"integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.13.0",
|
"version": "1.17.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
+5
-1
@@ -1,7 +1,6 @@
|
|||||||
@import './styles/responsive.scss';
|
@import './styles/responsive.scss';
|
||||||
@import './styles/variables.scss';
|
@import './styles/variables.scss';
|
||||||
@import './styles/global.scss';
|
@import './styles/global.scss';
|
||||||
@import './styles/scenery_status.scss';
|
|
||||||
|
|
||||||
// VUE ROUTE CHANGE ANIMATION
|
// VUE ROUTE CHANGE ANIMATION
|
||||||
.view-anim {
|
.view-anim {
|
||||||
@@ -91,6 +90,11 @@ footer.app_footer {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 1.1em;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
|
||||||
background: #111;
|
background: #111;
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
||||||
{{ new Date().getUTCFullYear() }} |
|
{{ new Date().getUTCFullYear() }} |
|
||||||
<a :href="releaseURL" target="_blank">v{{ VERSION }}{{ isOnProductionHost ? '' : 'dev' }}</a>
|
<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>
|
<div style="display: none">∫ ukryta taktyczna całka do programowania w HTMLu</div>
|
||||||
</footer>
|
</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('pl')" alt="icon-pl" @click="changeLang('en')" v-if="currentLang == 'pl'" />
|
||||||
<img :src="getIcon('en', 'jpg')" alt="icon-en" @click="changeLang('pl')" v-else />
|
<img :src="getIcon('en', 'jpg')" alt="icon-en" @click="changeLang('pl')" v-else />
|
||||||
</span>
|
</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>
|
||||||
|
|
||||||
<div class="header_body">
|
<div class="header_body">
|
||||||
@@ -33,6 +23,12 @@
|
|||||||
<div class="info_counter">
|
<div class="info_counter">
|
||||||
<img :src="getIcon('dispatcher')" alt="icon dispatcher" />
|
<img :src="getIcon('dispatcher')" alt="icon dispatcher" />
|
||||||
<span class="text--primary">{{ onlineDispatchersCount }}</span>
|
<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--grayed"> / </span>
|
||||||
<span class="text--primary">{{ onlineTrainsCount }}</span>
|
<span class="text--primary">{{ onlineTrainsCount }}</span>
|
||||||
<img :src="getIcon('train')" alt="icon train" />
|
<img :src="getIcon('train')" alt="icon train" />
|
||||||
@@ -98,11 +94,17 @@ export default defineComponent({
|
|||||||
onlineTrainsCount() {
|
onlineTrainsCount() {
|
||||||
return this.store.trainList.filter((train) => train.online).length;
|
return this.store.trainList.filter((train) => train.online).length;
|
||||||
},
|
},
|
||||||
|
|
||||||
onlineDispatchersCount() {
|
onlineDispatchersCount() {
|
||||||
return this.store.stationList.filter(
|
return this.store.stationList.filter(
|
||||||
(station) => station.onlineInfo && station.onlineInfo.region == this.store.region.id
|
(station) => station.onlineInfo && station.onlineInfo.region == this.store.region.id
|
||||||
).length;
|
).length;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
factorU() {
|
||||||
|
return this.onlineDispatchersCount == 0 ? '-' : (this.onlineTrainsCount / this.onlineDispatchersCount).toFixed(2);
|
||||||
|
},
|
||||||
|
|
||||||
computedRegions() {
|
computedRegions() {
|
||||||
return options.regions.map((region) => {
|
return options.regions.map((region) => {
|
||||||
const regionStationCount =
|
const regionStationCount =
|
||||||
@@ -135,22 +137,20 @@ export default defineComponent({
|
|||||||
|
|
||||||
.header {
|
.header {
|
||||||
&_body {
|
&_body {
|
||||||
max-width: 21em;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
max-width: 20em;
|
||||||
@include smallScreen {
|
|
||||||
max-width: 18em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&_container {
|
&_container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: relative;
|
|
||||||
|
|
||||||
width: 1350px;
|
|
||||||
padding: 0.5em 0.3em 0 0.3em;
|
|
||||||
border-radius: 0 0 1em 1em;
|
border-radius: 0 0 1em 1em;
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&_brand {
|
&_brand {
|
||||||
@@ -158,6 +158,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,9 +166,7 @@ export default defineComponent({
|
|||||||
&_info {
|
&_info {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
max-width: 100%;
|
font-size: 1.15em;
|
||||||
|
|
||||||
font-size: 1.2em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&_links {
|
&_links {
|
||||||
@@ -184,57 +183,20 @@ export default defineComponent({
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
display: flex;
|
padding: 0.5em;
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: flex-end;
|
|
||||||
padding: 0.5em 0.5em;
|
|
||||||
|
|
||||||
@include smallScreen() {
|
@include smallScreen {
|
||||||
right: auto;
|
transform: translateX(85%);
|
||||||
left: 0.75em;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ICONS
|
// ICONS
|
||||||
.icons {
|
.icons-top {
|
||||||
position: relative;
|
img {
|
||||||
|
width: 2.5em;
|
||||||
&-top {
|
cursor: pointer;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,7 +164,7 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/store';
|
||||||
import { StoreState } from '../../store/storeTypes';
|
import { StoreState } from '../../scripts/interfaces/store/storeTypes';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
data() {
|
data() {
|
||||||
@@ -303,9 +303,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
.status-indicator {
|
.status-indicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 110%;
|
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
|
||||||
|
transform: translateX(1.5em);
|
||||||
}
|
}
|
||||||
|
|
||||||
.indicator {
|
.indicator {
|
||||||
@@ -330,7 +332,7 @@ export default defineComponent({
|
|||||||
background-color: #171717;
|
background-color: #171717;
|
||||||
border-radius: 0.75em;
|
border-radius: 0.75em;
|
||||||
|
|
||||||
min-width: 13em;
|
width: 13em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: none;
|
overflow: none;
|
||||||
|
|
||||||
@@ -354,22 +356,16 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
@include midScreen() {
|
@include midScreen() {
|
||||||
left: 50%;
|
left: auto;
|
||||||
top: 100%;
|
right: 200%;
|
||||||
|
|
||||||
transform: translate(-50%, 0);
|
|
||||||
margin-left: 0;
|
|
||||||
margin-top: 0.75em;
|
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
border-left: 10px solid transparent;
|
|
||||||
border-right: 10px solid transparent;
|
border-right: 10px solid transparent;
|
||||||
border-bottom: 10px solid #171717;
|
border-left: 12px solid #171717;
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
|
||||||
top: 0;
|
transform: translate(100%, -50%);
|
||||||
left: 50%;
|
|
||||||
|
|
||||||
transform: translate(-50%, -100%);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,3 +375,4 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<template>
|
||||||
|
<div class="progress-bar">
|
||||||
|
<span class="bar-bg"></span>
|
||||||
|
<span class="bar-fg" :style="{ width: `${~~progressPercent}%`, backgroundColor: bgColor }"></span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
progressPercent: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
progressType: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
bgColor() {
|
||||||
|
switch (this.progressType) {
|
||||||
|
case 'abandoned':
|
||||||
|
return 'salmon';
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 'springgreen';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.progress-bar {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
width: 6em;
|
||||||
|
height: 1em;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
|
||||||
|
.bar-fg,
|
||||||
|
.bar-bg {
|
||||||
|
position: absolute;
|
||||||
|
height: 1em;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-fg {
|
||||||
|
background-color: springgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-bg {
|
||||||
|
background-color: #5b5b5b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -3,6 +3,10 @@
|
|||||||
<div class="select-box_content">
|
<div class="select-box_content">
|
||||||
<button class="selected" @click="toggleBox">
|
<button class="selected" @click="toggleBox">
|
||||||
<span>{{ computedSelectedItem.selectedValue || computedSelectedItem.value }}</span>
|
<span>{{ computedSelectedItem.selectedValue || computedSelectedItem.value }}</span>
|
||||||
|
|
||||||
|
<div class="arrow">
|
||||||
|
<img :src="listOpen ? getIcon('arrow-asc') : getIcon('arrow-desc')" alt="arrow-icon" />
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<ul class="options" :ref="(el) => (listRef = el as Element)">
|
<ul class="options" :ref="(el) => (listRef = el as Element)">
|
||||||
@@ -21,10 +25,6 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="arrow">
|
|
||||||
<img :src="listOpen ? getIcon('arrow-asc') : getIcon('arrow-desc')" alt="arrow-icon" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -129,46 +129,22 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.select-box {
|
.select-box {
|
||||||
position: relative;
|
display: flex;
|
||||||
width: auto;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.arrow {
|
.arrow {
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
img {
|
img {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
width: 1.35em;
|
width: 1.35em;
|
||||||
}
|
}
|
||||||
|
|
||||||
transform: translateY(-50%);
|
|
||||||
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button.selected {
|
button.selected {
|
||||||
background-color: transparent;
|
|
||||||
color: paleturquoise;
|
color: paleturquoise;
|
||||||
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
||||||
padding: 0.1em 0.5em;
|
padding: 0.1em 0.5em;
|
||||||
margin-right: 2em;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
background-color: #262626;
|
background-color: #262626;
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
<template>
|
||||||
|
<span class="status-badge" :class="statusID" v-if="isOnline">
|
||||||
|
{{ $t(`status.${statusID}`) }}
|
||||||
|
{{ statusID == 'online' ? timestampToString(statusTimestamp!) : '' }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="status-badge free" v-else>
|
||||||
|
{{ $t('status.free') }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
statusID: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
statusTimestamp: {
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
isOnline: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mixins: [dateMixin],
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
$free: #8a8a8a;
|
||||||
|
$ending: #e6c300;
|
||||||
|
$no-limit: #117fc9;
|
||||||
|
$unav: #ff3d5d;
|
||||||
|
$brb: #e6a100;
|
||||||
|
$no-space: #222;
|
||||||
|
$online: #09a116;
|
||||||
|
$unknown: rgb(185, 60, 60);
|
||||||
|
|
||||||
|
.status-badge {
|
||||||
|
border-radius: 1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
padding: 0.2em 0.55em;
|
||||||
|
|
||||||
|
background-color: $online;
|
||||||
|
|
||||||
|
&.free {
|
||||||
|
background-color: $free;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ending {
|
||||||
|
background-color: $ending;
|
||||||
|
color: black;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no-limit {
|
||||||
|
background-color: $no-limit;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.not-signed,
|
||||||
|
&.unavailable {
|
||||||
|
background-color: $unav;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.brb {
|
||||||
|
background-color: $brb;
|
||||||
|
color: black;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no-space {
|
||||||
|
background-color: $no-space;
|
||||||
|
border: 1px solid white;
|
||||||
|
color: white;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.unknown {
|
||||||
|
background-color: $unknown;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -4,12 +4,12 @@
|
|||||||
class="date arrival"
|
class="date arrival"
|
||||||
v-if="!stop.beginsHere"
|
v-if="!stop.beginsHere"
|
||||||
:class="{
|
:class="{
|
||||||
delayed: stop.arrivalDelay > 0 && stop.confirmed,
|
delayed: stop.arrivalDelay > 0 && (stop.confirmed || stop.stopped),
|
||||||
preponed: stop.arrivalDelay < 0 && stop.confirmed,
|
preponed: stop.arrivalDelay < 0 && (stop.confirmed || stop.stopped),
|
||||||
'on-time': stop.arrivalDelay == 0 && stop.confirmed,
|
'on-time': stop.arrivalDelay == 0 && stop.confirmed,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<span v-if="stop.arrivalDelay != 0 && stop.confirmed">
|
<span v-if="stop.arrivalDelay != 0 && (stop.confirmed || stop.stopped)">
|
||||||
<s>{{ timestampToString(stop.arrivalTimestamp) }}</s>
|
<s>{{ timestampToString(stop.arrivalTimestamp) }}</s>
|
||||||
{{ timestampToString(stop.arrivalRealTimestamp) }}
|
{{ timestampToString(stop.arrivalRealTimestamp) }}
|
||||||
({{ stop.arrivalDelay > 0 ? '+' : '' }}{{ stop.arrivalDelay }})
|
({{ stop.arrivalDelay > 0 ? '+' : '' }}{{ stop.arrivalDelay }})
|
||||||
@@ -20,13 +20,13 @@
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="date stop" v-if="stop.stopTime" :class="stop.stopType.replace(', ', '-')">
|
<span class="date stop" v-if="stop.stopTime || stop.stopped" :class="stop.stopType.replace(', ', '-')">
|
||||||
{{ stop.stopTime }} {{ stop.stopType == '' ? 'pt' : stop.stopType }}
|
{{ stop.stopTime }} {{ stop.stopType == '' ? 'pt' : stop.stopType }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
class="date departure"
|
class="date departure"
|
||||||
v-if="!stop.terminatesHere && stop.stopTime != 0"
|
v-if="!stop.terminatesHere && (stop.stopTime != 0 || stop.stopped)"
|
||||||
:class="{
|
:class="{
|
||||||
delayed: stop.departureDelay > 0 && stop.confirmed,
|
delayed: stop.departureDelay > 0 && stop.confirmed,
|
||||||
preponed: stop.departureDelay < 0 && stop.confirmed,
|
preponed: stop.departureDelay < 0 && stop.confirmed,
|
||||||
|
|||||||
@@ -1,56 +1,62 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="daily-stats">
|
<section class="daily-stats">
|
||||||
<span :data-active="data.statsStatus">
|
<span :data-active="statsStatus">
|
||||||
<b v-if="data.statsStatus == DataStatus.Loading">
|
<b v-if="statsStatus == DataStatus.Loading">
|
||||||
{{ $t('app.loading') }}
|
{{ $t('app.loading') }}
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
<b v-else-if="data.stats.distanceSum == null">
|
<b v-else-if="stats.distanceSum == null">
|
||||||
{{ $t('journal.daily-stats-info') }}
|
{{ $t('journal.daily-stats-info') }}
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
<span>
|
<span class="stats-list" v-else>
|
||||||
<div v-if="data.stats.totalTimetables">
|
<h3>
|
||||||
|
{{ $t('journal.daily-stats-title') }}
|
||||||
|
<b class="text--primary">{{ new Date().toLocaleDateString($i18n.locale) }}</b>
|
||||||
|
</h3>
|
||||||
|
<hr style="margin-bottom: 0.5em" />
|
||||||
|
|
||||||
|
<div v-if="stats.totalTimetables">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-total">
|
<i18n-t keypath="journal.timetable-stats-total">
|
||||||
<template #count>
|
<template #count>
|
||||||
<b class="text--primary">
|
<b class="text--primary">
|
||||||
{{ data.stats.totalTimetables }}
|
{{ stats.totalTimetables }}
|
||||||
{{ $t('journal.timetable-count', data.stats.totalTimetables) }}
|
{{ $t('journal.timetable-count', stats.totalTimetables) }}
|
||||||
</b>
|
</b>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #distance>
|
<template #distance>
|
||||||
<b class="text--primary"> {{ data.stats.distanceSum?.toFixed(2) }} km </b>
|
<b class="text--primary"> {{ stats.distanceSum?.toFixed(2) }} km</b>
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="data.stats.timetableId">
|
<div v-if="stats.timetableId">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-longest">
|
<i18n-t keypath="journal.timetable-stats-longest">
|
||||||
<template #id>
|
<template #id>
|
||||||
<router-link :to="`/journal/timetables?timetableId=${data.stats.timetableId}`">
|
<router-link :to="`/journal/timetables?timetableId=${stats.timetableId}`">
|
||||||
<b>{{ data.stats.timetableId }}</b>
|
<b>{{ stats.timetableId }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template #author>
|
<template #author>
|
||||||
<router-link :to="`/journal/dispatchers?dispatcherName=${data.stats.timetableAuthor}`">
|
<router-link :to="`/journal/dispatchers?dispatcherName=${stats.timetableAuthor}`">
|
||||||
<b>{{ data.stats.timetableAuthor }}</b>
|
<b>{{ stats.timetableAuthor }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template #driver>
|
<template #driver>
|
||||||
<b>{{ data.stats.timetableDriver }}</b>
|
<b class="text--primary">{{ stats.timetableDriver }}</b>
|
||||||
</template>
|
</template>
|
||||||
<template #distance>
|
<template #distance>
|
||||||
<b class="text--primary">{{ data.stats.timetableRouteDistance }} km</b>
|
<b class="text--primary">{{ stats.timetableRouteDistance }} km</b>
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="firstPlaceDispatchers.length == 1">
|
<div v-if="firstPlaceDispatchers.length == 1">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-most-active">
|
<i18n-t keypath="journal.timetable-stats-most-active-dr">
|
||||||
<template #dispatcher>
|
<template #dispatcher>
|
||||||
<router-link :to="`/journal/dispatchers?dispatcherName=${firstPlaceDispatchers[0].name}`">
|
<router-link :to="`/journal/dispatchers?dispatcherName=${firstPlaceDispatchers[0].name}`">
|
||||||
<b>{{ firstPlaceDispatchers[0].name }}</b>
|
<b>{{ firstPlaceDispatchers[0].name }}</b>
|
||||||
@@ -67,7 +73,7 @@
|
|||||||
|
|
||||||
<div v-if="firstPlaceDispatchers.length > 1">
|
<div v-if="firstPlaceDispatchers.length > 1">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-most-active-many">
|
<i18n-t keypath="journal.timetable-stats-most-active-dr-many">
|
||||||
<template #dispatchers>
|
<template #dispatchers>
|
||||||
<span v-for="(disp, i) in firstPlaceDispatchers">
|
<span v-for="(disp, i) in firstPlaceDispatchers">
|
||||||
<span v-if="i == firstPlaceDispatchers.length - 1"> {{ $t('general.and') }} </span>
|
<span v-if="i == firstPlaceDispatchers.length - 1"> {{ $t('general.and') }} </span>
|
||||||
@@ -88,95 +94,157 @@
|
|||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="stats.longestDuties.length > 0">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.timetable-stats-longest-duties">
|
||||||
|
<template #dispatcher>
|
||||||
|
<router-link :to="`/journal/dispatchers?dispatcherName=${stats.longestDuties[0].name}`">
|
||||||
|
<b>{{ stats.longestDuties[0].name }}</b>
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #station>{{ stats.longestDuties[0].station }}</template>
|
||||||
|
|
||||||
|
<template #duration>
|
||||||
|
{{ calculateDuration(stats.longestDuties[0].duration) }}
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="stats.mostActiveDrivers.length > 0">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.timetable-stats-most-active-driver">
|
||||||
|
<template #driver>
|
||||||
|
<b class="text--primary">{{ stats.mostActiveDrivers[0].name }}</b>
|
||||||
|
</template>
|
||||||
|
<template #distance>
|
||||||
|
<b class="text--primary">{{ stats.mostActiveDrivers[0].distance.toFixed(2) }} km</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { computed, reactive, ref } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||||
import { ITimetablesDailyStats, ITimetablesDailyStatsResponse } from '../../scripts/interfaces/api/StatsAPIData';
|
import { ITimetablesDailyStats, ITimetablesDailyStatsResponse } from '../../scripts/interfaces/api/StatsAPIData';
|
||||||
import { URLs } from '../../scripts/utils/apiURLs';
|
import { URLs } from '../../scripts/utils/apiURLs';
|
||||||
|
|
||||||
const intervalId = ref(-1);
|
export default defineComponent({
|
||||||
|
mixins: [dateMixin],
|
||||||
|
emits: ['toggleStatsOpen'],
|
||||||
|
|
||||||
const data = reactive({
|
data() {
|
||||||
statsStatus: DataStatus.Loading,
|
return {
|
||||||
|
DataStatus,
|
||||||
|
statsStatus: DataStatus.Loading,
|
||||||
|
intervalId: -1,
|
||||||
|
|
||||||
stats: {
|
stats: {
|
||||||
totalTimetables: 0,
|
totalTimetables: 0,
|
||||||
distanceSum: 0,
|
distanceSum: 0,
|
||||||
distanceAvg: 0,
|
distanceAvg: 0,
|
||||||
timetableAuthor: '',
|
timetableAuthor: '',
|
||||||
timetableDriver: '',
|
timetableDriver: '',
|
||||||
timetableId: 0,
|
timetableId: 0,
|
||||||
timetableRouteDistance: 0,
|
timetableRouteDistance: 0,
|
||||||
|
longestDuties: [],
|
||||||
mostActiveDispatchers: [],
|
mostActiveDrivers: [],
|
||||||
} as ITimetablesDailyStats,
|
mostActiveDispatchers: [],
|
||||||
});
|
} as ITimetablesDailyStats,
|
||||||
|
|
||||||
const firstPlaceDispatchers = computed(() => {
|
|
||||||
if (data.stats.mostActiveDispatchers.length == 0) return [];
|
|
||||||
const maxCount = data.stats.mostActiveDispatchers[0].count;
|
|
||||||
|
|
||||||
return data.stats.mostActiveDispatchers.filter((disp) => disp.count === maxCount);
|
|
||||||
});
|
|
||||||
|
|
||||||
async function fetchDailyTimetableStats() {
|
|
||||||
try {
|
|
||||||
const {
|
|
||||||
distanceAvg,
|
|
||||||
distanceSum,
|
|
||||||
maxTimetable,
|
|
||||||
totalTimetables,
|
|
||||||
mostActiveDispatchers,
|
|
||||||
}: ITimetablesDailyStatsResponse = await (
|
|
||||||
await axios.get(`${URLs.stacjownikAPI}/api/getDailyTimetableStats`)
|
|
||||||
).data;
|
|
||||||
|
|
||||||
data.stats = {
|
|
||||||
totalTimetables,
|
|
||||||
distanceSum,
|
|
||||||
distanceAvg,
|
|
||||||
timetableAuthor: maxTimetable?.authorName || '',
|
|
||||||
timetableDriver: maxTimetable?.driverName || '',
|
|
||||||
timetableId: maxTimetable?.id || 0,
|
|
||||||
timetableRouteDistance: maxTimetable?.routeDistance || 0,
|
|
||||||
|
|
||||||
mostActiveDispatchers,
|
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
data.statsStatus = DataStatus.Loaded;
|
activated() {
|
||||||
} catch (error) {
|
this.startFetchingDailyStats();
|
||||||
console.error('Ups! Wystąpił błąd podczas pobierania statystyk rozkładów jazdy...');
|
this.$emit('toggleStatsOpen', true);
|
||||||
data.statsStatus = DataStatus.Error;
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function startFetchingDailyStats() {
|
deactivated() {
|
||||||
fetchDailyTimetableStats();
|
this.stopFetchingDailyStats();
|
||||||
intervalId.value = setInterval(fetchDailyTimetableStats, 60000);
|
},
|
||||||
}
|
|
||||||
|
|
||||||
function stopFetchingDailyStats() {
|
computed: {
|
||||||
clearInterval(intervalId.value);
|
firstPlaceDispatchers() {
|
||||||
}
|
if (this.stats.mostActiveDispatchers.length == 0) return [];
|
||||||
|
const maxCount = this.stats.mostActiveDispatchers[0].count;
|
||||||
|
|
||||||
defineExpose({
|
return this.stats.mostActiveDispatchers.filter((disp) => disp.count === maxCount);
|
||||||
startFetchingDailyStats,
|
},
|
||||||
stopFetchingDailyStats,
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async fetchDailyTimetableStats() {
|
||||||
|
try {
|
||||||
|
const res: ITimetablesDailyStatsResponse = await (
|
||||||
|
await axios.get(`${URLs.stacjownikAPI}/api/getDailyTimetableStats`)
|
||||||
|
).data;
|
||||||
|
|
||||||
|
this.stats = {
|
||||||
|
totalTimetables: res.totalTimetables,
|
||||||
|
distanceSum: res.distanceSum,
|
||||||
|
distanceAvg: res.distanceAvg,
|
||||||
|
timetableAuthor: res.maxTimetable?.authorName || '',
|
||||||
|
timetableDriver: res.maxTimetable?.driverName || '',
|
||||||
|
timetableId: res.maxTimetable?.id || 0,
|
||||||
|
timetableRouteDistance: res.maxTimetable?.routeDistance || 0,
|
||||||
|
|
||||||
|
mostActiveDispatchers: res.mostActiveDispatchers,
|
||||||
|
mostActiveDrivers: res.mostActiveDrivers,
|
||||||
|
longestDuties: res.longestDuties,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.statsStatus = DataStatus.Loaded;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ups! Wystąpił błąd podczas pobierania statystyk rozkładów jazdy...');
|
||||||
|
this.statsStatus = DataStatus.Error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
startFetchingDailyStats() {
|
||||||
|
this.fetchDailyTimetableStats();
|
||||||
|
|
||||||
|
if (this.intervalId != -1) return;
|
||||||
|
|
||||||
|
this.intervalId = setInterval(this.fetchDailyTimetableStats, 60000);
|
||||||
|
},
|
||||||
|
|
||||||
|
stopFetchingDailyStats() {
|
||||||
|
clearInterval(this.intervalId);
|
||||||
|
this.intervalId = -1;
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/responsive.scss';
|
||||||
|
|
||||||
.daily-stats {
|
.daily-stats {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
.daily-stats > span[data-active='0'] {
|
.daily-stats > span[data-active='0'] {
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stats-list a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
.daily-stats {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -1,57 +1,106 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition-group class="journal-list" tag="ul" name="list-anim">
|
<div>
|
||||||
<li
|
<transition name="status-anim" mode="out-in">
|
||||||
v-for="item in computedDispatcherHistory"
|
<div :key="dataStatus">
|
||||||
:key="typeof item === 'string' ? item : item.timestampFrom + item.dispatcherId"
|
<div class="journal_warning" v-if="store.isOffline">
|
||||||
:class="{ sticky: typeof item == 'string' }"
|
{{ $t('app.offline') }}
|
||||||
>
|
</div>
|
||||||
<div v-if="typeof item == 'string'" class="journal_day">
|
|
||||||
{{ item }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<Loading v-else-if="dataStatus == DataStatus.Loading" />
|
||||||
v-else
|
|
||||||
class="journal_item"
|
<div v-else-if="dataStatus == DataStatus.Error" class="journal_warning error">
|
||||||
:class="{ online: item.isOnline }"
|
{{ $t('app.error') }}
|
||||||
@click="navigateToScenery(item.stationName, item.isOnline)"
|
</div>
|
||||||
@keydown.enter="navigateToScenery(item.stationName, item.isOnline)"
|
|
||||||
tabindex="0"
|
<div class="journal_warning" v-else-if="dispatcherHistory.length == 0">
|
||||||
>
|
{{ $t('app.no-result') }}
|
||||||
<span class="item-general">
|
</div>
|
||||||
<b
|
|
||||||
v-if="item.dispatcherLevel !== null"
|
<div v-else>
|
||||||
class="level-badge dispatcher"
|
<table class="scenery-history-table">
|
||||||
:style="calculateExpStyle(item.dispatcherLevel, item.dispatcherIsSupporter)"
|
<thead>
|
||||||
|
<th>{{ $t('journal.history-name') }}</th>
|
||||||
|
<th>{{ $t('journal.history-hash') }}</th>
|
||||||
|
<th>{{ $t('journal.history-dispatcher') }}</th>
|
||||||
|
<th>{{ $t('journal.history-level') }}</th>
|
||||||
|
<th>{{ $t('journal.history-rate') }}</th>
|
||||||
|
<th>{{ $t('journal.history-region') }}</th>
|
||||||
|
<th>{{ $t('journal.history-date') }}</th>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<transition-group name="list-anim">
|
||||||
|
<tr v-for="historyItem in dispatcherHistory" :key="historyItem.id">
|
||||||
|
<td>
|
||||||
|
<router-link :to="`/journal/dispatchers?sceneryName=${historyItem.stationName}`">
|
||||||
|
<b>{{ historyItem.stationName }}</b>
|
||||||
|
</router-link>
|
||||||
|
</td>
|
||||||
|
<td>#{{ historyItem.stationHash }}</td>
|
||||||
|
<td>
|
||||||
|
<router-link :to="`/journal/dispatchers?dispatcherName=${historyItem.dispatcherName}`">
|
||||||
|
<b>{{ historyItem.dispatcherName }}</b>
|
||||||
|
</router-link>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<b
|
||||||
|
v-if="historyItem.dispatcherLevel !== null"
|
||||||
|
class="level-badge dispatcher"
|
||||||
|
:style="calculateExpStyle(historyItem.dispatcherLevel, historyItem.dispatcherIsSupporter)"
|
||||||
|
>
|
||||||
|
{{ historyItem.dispatcherLevel >= 2 ? historyItem.dispatcherLevel : 'L' }}
|
||||||
|
</b>
|
||||||
|
</td>
|
||||||
|
<td class="text--primary">
|
||||||
|
<b>{{ historyItem.dispatcherRate }}</b>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<b class="region-badge" :aria-describedby="historyItem.region">{{
|
||||||
|
regions.find((r) => r.id == historyItem.region)?.value || '???'
|
||||||
|
}}</b>
|
||||||
|
</td>
|
||||||
|
<td style="min-width: 200px" class="time">
|
||||||
|
<span v-if="historyItem.timestampTo" class="text--offline">
|
||||||
|
<b>{{ $d(historyItem.timestampFrom) }}</b>
|
||||||
|
{{ timestampToString(historyItem.timestampFrom) }}
|
||||||
|
- {{ timestampToString(historyItem.timestampTo) }} ({{
|
||||||
|
calculateDuration(historyItem.currentDuration)
|
||||||
|
}})
|
||||||
|
</span>
|
||||||
|
<span class="dispatcher-online" v-else>
|
||||||
|
<b class="text--online">
|
||||||
|
<router-link :to="`/scenery?station=${historyItem.stationName}`">{{
|
||||||
|
$t('journal.online-since')
|
||||||
|
}}</router-link>
|
||||||
|
{{ timestampToString(historyItem.timestampFrom) }}
|
||||||
|
</b>
|
||||||
|
({{ calculateDuration(historyItem.currentDuration) }})
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</transition-group>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="btn btn--option btn--load-data"
|
||||||
|
v-if="!scrollNoMoreData && scrollDataLoaded && dispatcherHistory.length > 15"
|
||||||
|
@click="addHistoryData"
|
||||||
>
|
>
|
||||||
{{ item.dispatcherLevel >= 2 ? item.dispatcherLevel : 'L' }}
|
{{ $t('journal.load-data') }}
|
||||||
</b>
|
</button>
|
||||||
|
</div>
|
||||||
<b class="text--primary">{{ item.dispatcherName }}</b> • <b>{{ item.stationName }}</b>
|
|
||||||
<span class="text--grayed"> #{{ item.stationHash }} </span>
|
|
||||||
<span class="region-badge" :class="item.region">PL1</span>
|
|
||||||
<span class="like-count" v-if="item.dispatcherRate">
|
|
||||||
<img :src="getIcon('like')" alt="like icon" />
|
|
||||||
{{ item.dispatcherRate }}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="item-time">
|
|
||||||
<span :data-status="item.isOnline"> {{ item.isOnline ? $t('journal.online-since') : 'OFFLINE' }} </span>
|
|
||||||
<span>
|
|
||||||
{{ new Date(item.timestampFrom).toLocaleTimeString('pl-PL', { timeStyle: 'short' }) }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-if="item.currentDuration && item.isOnline"> ({{ calculateDuration(item.currentDuration) }}) </span>
|
|
||||||
|
|
||||||
<span v-if="item.timestampTo">
|
|
||||||
>
|
|
||||||
{{ new Date(item.timestampTo).toLocaleTimeString('pl-PL', { timeStyle: 'short' }) }}
|
|
||||||
({{ $t('journal.duty-lasted') }} {{ calculateDuration(item.currentDuration!) }})
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</transition>
|
||||||
</transition-group>
|
|
||||||
|
<div class="journal_warning" v-if="scrollNoMoreData">
|
||||||
|
{{ $t('journal.no-further-data') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="journal_warning" v-else-if="!scrollDataLoaded">
|
||||||
|
{{ $t('journal.loading-further-data') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -60,19 +109,47 @@ import dateMixin from '../../mixins/dateMixin';
|
|||||||
import { DispatcherHistory } from '../../scripts/interfaces/api/DispatchersAPIData';
|
import { DispatcherHistory } from '../../scripts/interfaces/api/DispatchersAPIData';
|
||||||
import styleMixin from '../../mixins/styleMixin';
|
import styleMixin from '../../mixins/styleMixin';
|
||||||
import imageMixin from '../../mixins/imageMixin';
|
import imageMixin from '../../mixins/imageMixin';
|
||||||
|
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
import Loading from '../Global/Loading.vue';
|
||||||
|
import { regions } from '../../data/options.json';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
components: { Loading },
|
||||||
|
|
||||||
|
mixins: [dateMixin, styleMixin, imageMixin],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
dispatcherHistory: {
|
dispatcherHistory: {
|
||||||
type: Array as PropType<DispatcherHistory[]>,
|
type: Array as PropType<DispatcherHistory[]>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
scrollNoMoreData: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
scrollDataLoaded: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
addHistoryData: {
|
||||||
|
type: Function as PropType<() => void>,
|
||||||
|
},
|
||||||
|
dataStatus: {
|
||||||
|
type: Number as PropType<DataStatus>,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [dateMixin, styleMixin, imageMixin],
|
data() {
|
||||||
|
return {
|
||||||
|
DataStatus,
|
||||||
|
store: useStore(),
|
||||||
|
regions,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
computedDispatcherHistory() {
|
computedDispatcherHistory() {
|
||||||
|
console.log(this.dispatcherHistory.length);
|
||||||
|
|
||||||
return this.dispatcherHistory.reduce((acc, historyItem, i) => {
|
return this.dispatcherHistory.reduce((acc, historyItem, i) => {
|
||||||
if (this.isAnotherDay(i - 1, i)) acc.push(new Date(historyItem.timestampFrom).toLocaleDateString('pl-PL'));
|
if (this.isAnotherDay(i - 1, i)) acc.push(new Date(historyItem.timestampFrom).toLocaleDateString('pl-PL'));
|
||||||
acc.push(historyItem);
|
acc.push(historyItem);
|
||||||
@@ -105,79 +182,58 @@ export default defineComponent({
|
|||||||
@import '../../styles/animations.scss';
|
@import '../../styles/animations.scss';
|
||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
@import '../../styles/badge.scss';
|
@import '../../styles/badge.scss';
|
||||||
@import '../../styles/JournalSection.scss';
|
|
||||||
@import '../../styles/variables.scss';
|
@import '../../styles/variables.scss';
|
||||||
|
@import '../../styles/JournalSection.scss';
|
||||||
|
|
||||||
li.sticky {
|
table.scenery-history-table {
|
||||||
position: sticky;
|
--_bg-table: #111;
|
||||||
top: 0;
|
--_bg-head: #101010;
|
||||||
}
|
--_bg-row: #2f2f2f;
|
||||||
|
|
||||||
.journal_item {
|
width: 100%;
|
||||||
display: flex;
|
border-collapse: collapse;
|
||||||
justify-content: space-between;
|
position: relative;
|
||||||
align-items: center;
|
text-align: center;
|
||||||
flex-wrap: wrap;
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
gap: 0.5em 1em;
|
thead {
|
||||||
|
position: sticky;
|
||||||
line-height: 1.7em;
|
top: 0;
|
||||||
padding: 0.75em;
|
background-color: var(--_bg-head);
|
||||||
|
|
||||||
&.online {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
span[data-status='true'] {
|
th {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
background-color: var(--_bg-row);
|
||||||
|
border-bottom: 2px solid black;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0.75em;
|
||||||
|
|
||||||
|
.level-badge {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 550px) {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
&--online {
|
||||||
color: springgreen;
|
color: springgreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
span[data-status='false'] {
|
&--offline {
|
||||||
color: salmon;
|
color: #ddd;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-general {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.25em;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
.level-badge {
|
|
||||||
margin-right: 0.25em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.journal_day {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
padding: 0.5em;
|
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
background-color: #333;
|
|
||||||
|
|
||||||
span {
|
|
||||||
position: relative;
|
|
||||||
background-color: inherit;
|
|
||||||
z-index: 10;
|
|
||||||
padding-right: 1em;
|
|
||||||
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.like-count {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.25em;
|
|
||||||
font-size: 1.2em;
|
|
||||||
color: $accentCol;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include smallScreen {
|
|
||||||
.journal_item {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -49,15 +49,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="search_actions">
|
|
||||||
<button class="btn--action" @click="onResetButtonClick">
|
|
||||||
{{ $t('options.reset-button') }}
|
|
||||||
</button>
|
|
||||||
<button class="btn--action" @click="onSearchButtonConfirm">
|
|
||||||
{{ $t('options.search-button') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 class="option-title">{{ $t('options.sort-title') }}</h1>
|
<h1 class="option-title">{{ $t('options.sort-title') }}</h1>
|
||||||
@@ -74,15 +65,31 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 class="option-title" v-if="filters.length != 0">{{ $t('options.filter-title') }}</h1>
|
<h1 class="option-title" v-if="filters.length != 0">{{ $t('options.filter-title') }}</h1>
|
||||||
<div class="options_filters">
|
|
||||||
<button
|
<div class="options_filter-sections" v-if="filters.length != 0 && filterList">
|
||||||
v-for="filter in filters"
|
<section class="filter-section" v-for="section in JournalFilterSection">
|
||||||
class="filter-option btn--option"
|
<p>{{ $t(`options.filter-section-${section}`) }}</p>
|
||||||
:class="{ checked: journalFilterActive.id === filter.id }"
|
|
||||||
:id="filter.id"
|
<div class="options_filters">
|
||||||
@click="onFilterChange(filter)"
|
<button
|
||||||
>
|
v-for="filter in filterList.filter((f) => f.filterSection == section)"
|
||||||
{{ $t(`options.filter-${filter.id}`) }}
|
class="filter-option btn--option"
|
||||||
|
:class="{ checked: filter.isActive }"
|
||||||
|
:id="filter.id"
|
||||||
|
@click="onFilterChange(filter)"
|
||||||
|
>
|
||||||
|
{{ $t(`options.filter-${filter.id}`) }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="options_actions">
|
||||||
|
<button class="btn--action" @click="onResetButtonClick">
|
||||||
|
{{ $t('options.reset-button') }}
|
||||||
|
</button>
|
||||||
|
<button class="btn--action" @click="onSearchButtonConfirm">
|
||||||
|
{{ $t('options.search-button') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -100,9 +107,10 @@ import { DataStatus } from '../../scripts/enums/DataStatus';
|
|||||||
import { DriverStatsAPIData } from '../../scripts/interfaces/api/DriverStatsAPIData';
|
import { DriverStatsAPIData } from '../../scripts/interfaces/api/DriverStatsAPIData';
|
||||||
import { URLs } from '../../scripts/utils/apiURLs';
|
import { URLs } from '../../scripts/utils/apiURLs';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/store';
|
||||||
import { JournalTimetableFilter } from '../../types/Journal/JournalTimetablesTypes';
|
|
||||||
import ActionButton from '../Global/ActionButton.vue';
|
import ActionButton from '../Global/ActionButton.vue';
|
||||||
import SelectBox from '../Global/SelectBox.vue';
|
import SelectBox from '../Global/SelectBox.vue';
|
||||||
|
import { JournalFilterSection } from '../../scripts/enums/JournalFilterType';
|
||||||
|
import { JournalFilter } from '../../scripts/types/JournalTimetablesTypes';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { SelectBox, ActionButton },
|
components: { SelectBox, ActionButton },
|
||||||
@@ -116,7 +124,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
filters: {
|
filters: {
|
||||||
type: Array as PropType<JournalTimetableFilter[]>,
|
type: Array as PropType<JournalFilter[]>,
|
||||||
default: [],
|
default: [],
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -132,13 +140,14 @@ export default defineComponent({
|
|||||||
|
|
||||||
optionsType: {
|
optionsType: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showOptions: false,
|
showOptions: false,
|
||||||
|
JournalFilterSection,
|
||||||
|
|
||||||
driverSuggestions: [] as string[],
|
driverSuggestions: [] as string[],
|
||||||
dispatcherSuggestions: [] as string[],
|
dispatcherSuggestions: [] as string[],
|
||||||
@@ -154,7 +163,8 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
searchersValues: inject('searchersValues') as { [key: string]: string },
|
searchersValues: inject('searchersValues') as { [key: string]: string },
|
||||||
sorterActive: inject('sorterActive') as { id: string | number; dir: number },
|
sorterActive: inject('sorterActive') as { id: string | number; dir: number },
|
||||||
journalFilterActive: inject('journalFilterActive') as JournalTimetableFilter,
|
// journalFilterActive: inject('journalFilterActive') as JournalFilter,
|
||||||
|
filterList: inject('filterList') as JournalFilter[] | undefined,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -174,7 +184,8 @@ export default defineComponent({
|
|||||||
watch: {
|
watch: {
|
||||||
async driverStatsName(value: string) {
|
async driverStatsName(value: string) {
|
||||||
await this.fetchDriverStats();
|
await this.fetchDriverStats();
|
||||||
this.store.currentStatsTab = value ? 'driver' : 'daily';
|
|
||||||
|
// if (value) this.store.currentStatsTab = 'driver';
|
||||||
},
|
},
|
||||||
|
|
||||||
async 'searchersValues.search-driver'(value: string | undefined) {
|
async 'searchersValues.search-driver'(value: string | undefined) {
|
||||||
@@ -249,18 +260,17 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
focusEnd() {
|
|
||||||
console.log('focus end');
|
|
||||||
},
|
|
||||||
|
|
||||||
onSorterChange(item: { id: string | number; value: string }) {
|
onSorterChange(item: { id: string | number; value: string }) {
|
||||||
this.sorterActive.id = item.id;
|
this.sorterActive.id = item.id;
|
||||||
this.sorterActive.dir = -1;
|
this.sorterActive.dir = -1;
|
||||||
this.$emit('onSearchConfirm');
|
this.$emit('onSearchConfirm');
|
||||||
},
|
},
|
||||||
|
|
||||||
onFilterChange(filter: JournalTimetableFilter) {
|
onFilterChange(filter: JournalFilter) {
|
||||||
this.journalFilterActive = filter;
|
// this.journalFilterActive = filter;
|
||||||
|
this.filterList?.filter((f) => f.filterSection === filter.filterSection).forEach((f) => (f.isActive = false));
|
||||||
|
filter.isActive = true;
|
||||||
|
|
||||||
this.$emit('onSearchConfirm');
|
this.$emit('onSearchConfirm');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="journal-stats" v-show="!store.isOffline">
|
<div class="journal-stats" v-if="!store.isOffline">
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<button
|
<button
|
||||||
v-for="tab in data.tabs"
|
v-for="tab in data.tabs"
|
||||||
class="btn--filled"
|
class="btn--filled"
|
||||||
:data-selected="tab.name == store.currentStatsTab && areStatsOpen"
|
:data-selected="tab.name == store.currentStatsTab && areStatsOpen"
|
||||||
:data-inactive="tab.inactive"
|
:data-inactive="tab.inactive"
|
||||||
|
:data-disabled="tab.inactive"
|
||||||
|
:disabled="tab.inactive"
|
||||||
@click="onTabButtonClick(tab.name)"
|
@click="onTabButtonClick(tab.name)"
|
||||||
>
|
>
|
||||||
{{ $t(tab.titlePath) }}
|
{{ $t(tab.titlePath) }}
|
||||||
@@ -14,7 +16,7 @@
|
|||||||
|
|
||||||
<div class="stats-tab" v-show="areStatsOpen">
|
<div class="stats-tab" v-show="areStatsOpen">
|
||||||
<keep-alive>
|
<keep-alive>
|
||||||
<JournalDailyStats v-if="store.currentStatsTab == 'daily'" ref="dailyStatsComp" />
|
<JournalDailyStats v-if="store.currentStatsTab == 'daily'" @toggleStatsOpen="toggleStatsOpen" />
|
||||||
<JournalDriverStats v-else-if="store.currentStatsTab == 'driver'" />
|
<JournalDriverStats v-else-if="store.currentStatsTab == 'driver'" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</div>
|
</div>
|
||||||
@@ -22,22 +24,21 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, KeepAlive, onActivated, onDeactivated, reactive, Ref, ref, watch } from 'vue';
|
import { computed, KeepAlive, onMounted, reactive, Ref, ref, watch } from 'vue';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/store';
|
||||||
import JournalDailyStats from './DailyStats.vue';
|
import JournalDailyStats from './DailyStats.vue';
|
||||||
import JournalDriverStats from './JournalDriverStats.vue';
|
import JournalDriverStats from './JournalDriverStats.vue';
|
||||||
|
import StorageManager from '../../scripts/managers/storageManager';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
type TStatTab = 'daily' | 'driver';
|
type TStatTab = 'daily' | 'driver';
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const dailyStatsComp: Ref<InstanceType<typeof JournalDailyStats> | null> = ref(null);
|
|
||||||
|
|
||||||
const lastDailyStatsOpen = ref(false);
|
const lastDailyStatsOpen = ref(false);
|
||||||
const areStatsOpen = ref(false);
|
const areStatsOpen = ref(false);
|
||||||
const lastClickedTab = ref('daily');
|
const lastClickedTab: Ref<'daily' | 'driver' | null> = ref(null);
|
||||||
|
|
||||||
let data = reactive({
|
let data = reactive({
|
||||||
tabs: [
|
tabs: [
|
||||||
@@ -48,7 +49,7 @@ let data = reactive({
|
|||||||
{
|
{
|
||||||
name: 'driver',
|
name: 'driver',
|
||||||
titlePath: 'journal.driver-stats-title',
|
titlePath: 'journal.driver-stats-title',
|
||||||
inactive: true,
|
// inactive: true,
|
||||||
},
|
},
|
||||||
] as { name: TStatTab; titlePath: string; inactive?: boolean }[],
|
] as { name: TStatTab; titlePath: string; inactive?: boolean }[],
|
||||||
});
|
});
|
||||||
@@ -57,30 +58,35 @@ let data = reactive({
|
|||||||
function onTabButtonClick(tab: TStatTab) {
|
function onTabButtonClick(tab: TStatTab) {
|
||||||
if (lastClickedTab.value == tab || !areStatsOpen.value) areStatsOpen.value = !areStatsOpen.value;
|
if (lastClickedTab.value == tab || !areStatsOpen.value) areStatsOpen.value = !areStatsOpen.value;
|
||||||
|
|
||||||
if (tab == 'daily') lastDailyStatsOpen.value = areStatsOpen.value;
|
if (tab == 'daily') {
|
||||||
|
StorageManager.setBooleanValue('dailyStatsOpen', areStatsOpen.value);
|
||||||
|
lastDailyStatsOpen.value = areStatsOpen.value;
|
||||||
|
}
|
||||||
|
|
||||||
store.currentStatsTab = tab;
|
store.currentStatsTab = tab;
|
||||||
lastClickedTab.value = tab;
|
lastClickedTab.value = tab;
|
||||||
|
|
||||||
|
if (areStatsOpen.value == false) store.currentStatsTab = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivated(() => {
|
function toggleStatsOpen(open: boolean) {
|
||||||
dailyStatsComp.value?.startFetchingDailyStats();
|
areStatsOpen.value = open;
|
||||||
});
|
}
|
||||||
|
|
||||||
onDeactivated(() => {
|
|
||||||
dailyStatsComp.value?.stopFetchingDailyStats();
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
computed(() => store.driverStatsData),
|
computed(() => store.driverStatsData),
|
||||||
(statsData) => {
|
(statsData) => {
|
||||||
data.tabs[1].inactive = statsData ? false : true;
|
store.currentStatsTab = statsData ? 'driver' : lastClickedTab.value;
|
||||||
|
areStatsOpen.value = statsData ? true : lastClickedTab.value !== null;
|
||||||
lastClickedTab.value = statsData ? 'driver' : 'daily';
|
|
||||||
if (statsData) areStatsOpen.value = true;
|
|
||||||
if (!statsData) areStatsOpen.value = lastDailyStatsOpen.value;
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (StorageManager.getBooleanValue('dailyStatsOpen')) {
|
||||||
|
areStatsOpen.value = true;
|
||||||
|
store.currentStatsTab = 'daily';
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -1,164 +1,250 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition-group class="journal-list" tag="ul" name="list-anim">
|
<div class="journal-list">
|
||||||
<li
|
<transition name="status-anim" mode="out-in">
|
||||||
v-for="{ timetable, sceneryList, ...item } in computedTimetableHistory"
|
<div :key="dataStatus">
|
||||||
class="journal_item"
|
<div class="journal_warning" v-if="store.isOffline">
|
||||||
:key="timetable.id"
|
{{ $t('app.offline') }}
|
||||||
@click="item.showExtra.value = !item.showExtra.value"
|
</div>
|
||||||
>
|
|
||||||
<div class="journal_item-info">
|
<Loading v-else-if="dataStatus == DataStatus.Loading" />
|
||||||
<div class="info-general">
|
|
||||||
<span
|
<div v-else-if="dataStatus == DataStatus.Error" class="journal_warning error">
|
||||||
class="general-train"
|
{{ $t('app.error') }}
|
||||||
tabindex="0"
|
</div>
|
||||||
@click.stop="showTimetable(timetable)"
|
|
||||||
@keydown.enter="showTimetable(timetable)"
|
<div v-else-if="timetableHistory.length == 0" class="journal_warning">
|
||||||
style="cursor: pointer"
|
{{ $t('app.no-result') }}
|
||||||
>
|
</div>
|
||||||
<span class="text--grayed">#{{ timetable.id }}</span>
|
|
||||||
<span>
|
<div v-else>
|
||||||
<strong class="text--primary">
|
<transition-group tag="ul" name="list-anim">
|
||||||
{{ timetable.trainCategoryCode }}
|
<li
|
||||||
</strong>
|
v-for="{ timetable, stockHistoryComp, stops, showExtraInfo, ...item } in computedTimetableHistory"
|
||||||
<strong> {{ timetable.trainNo }}</strong>
|
class="journal_item"
|
||||||
</span>
|
:key="timetable.id"
|
||||||
•
|
@click="showExtraInfo.value = !showExtraInfo.value"
|
||||||
<strong
|
|
||||||
v-if="timetable.driverLevel !== null"
|
|
||||||
class="level-badge driver"
|
|
||||||
:style="calculateExpStyle(timetable.driverLevel, timetable.driverIsSupporter)"
|
|
||||||
>
|
>
|
||||||
{{ timetable.driverLevel < 2 ? 'L' : `${timetable.driverLevel}` }}
|
<div class="journal_item-info">
|
||||||
</strong>
|
<div class="info-general">
|
||||||
|
<span
|
||||||
|
class="general-train"
|
||||||
|
tabindex="0"
|
||||||
|
@click.stop="showTimetable(timetable, $event.currentTarget)"
|
||||||
|
@keydown.enter="showTimetable(timetable, $event.currentTarget)"
|
||||||
|
>
|
||||||
|
<span class="text--grayed">#{{ timetable.id }}</span>
|
||||||
|
|
||||||
<strong>{{ timetable.driverName }}</strong>
|
<span class="badges" v-if="timetable.skr || timetable.twr">
|
||||||
</span>
|
<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 class="general-time">
|
<span>
|
||||||
<b class="info-date">{{ localeDay(timetable.beginDate, $i18n.locale) }}</b>
|
<strong class="text--primary">
|
||||||
<b
|
{{ timetable.trainCategoryCode }}
|
||||||
class="info-status"
|
</strong>
|
||||||
:class="{
|
<strong> {{ timetable.trainNo }}</strong>
|
||||||
fulfilled: timetable.fulfilled || timetable.currentDistance >= timetable.routeDistance * 0.9,
|
</span>
|
||||||
terminated: timetable.terminated && !timetable.fulfilled,
|
•
|
||||||
active: !timetable.terminated,
|
<strong
|
||||||
}"
|
v-if="timetable.driverLevel !== null"
|
||||||
>
|
class="level-badge driver"
|
||||||
{{
|
:style="calculateExpStyle(timetable.driverLevel, timetable.driverIsSupporter)"
|
||||||
!timetable.terminated
|
>
|
||||||
? $t('journal.timetable-active')
|
{{ timetable.driverLevel < 2 ? 'L' : `${timetable.driverLevel}` }}
|
||||||
: timetable.fulfilled || timetable.currentDistance >= timetable.routeDistance * 0.9
|
</strong>
|
||||||
? $t('journal.timetable-fulfilled')
|
|
||||||
: `${$t('journal.timetable-abandoned')} ${localeTime(timetable.endDate, $i18n.locale)}`
|
|
||||||
}}
|
|
||||||
</b>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info-route">
|
<strong>{{ timetable.driverName }}</strong>
|
||||||
<b>{{ timetable.route.replace('|', ' - ') }}</b>
|
</span>
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr />
|
<span class="general-time">
|
||||||
|
<b class="info-date"
|
||||||
|
>{{
|
||||||
|
new Date(timetable.createdAt).getTime() - new Date(timetable.beginDate).getTime() < 0
|
||||||
|
? localeDateTime(timetable.createdAt, $i18n.locale)
|
||||||
|
: localeDateTime(timetable.beginDate, $i18n.locale)
|
||||||
|
}}
|
||||||
|
</b>
|
||||||
|
|
||||||
<div class="scenery-list">
|
<b
|
||||||
<span
|
class="info-badge"
|
||||||
v-for="(scenery, i) in sceneryList.filter((_, i) =>
|
:class="{
|
||||||
!item.showExtra.value ? i == 0 || i == sceneryList.length - 1 : true
|
fulfilled: timetable.fulfilled,
|
||||||
)"
|
terminated: timetable.terminated && !timetable.fulfilled,
|
||||||
:key="scenery.name"
|
active: !timetable.terminated,
|
||||||
:class="{ confirmed: scenery.confirmed }"
|
}"
|
||||||
>
|
>
|
||||||
<span v-if="i > 0">
|
{{
|
||||||
>
|
!timetable.terminated
|
||||||
<span v-if="!item.showExtra.value && i == 1 && sceneryList.length > 2"
|
? $t('journal.timetable-active')
|
||||||
>... (+{{ sceneryList.length - 2 }}) ></span
|
: timetable.fulfilled
|
||||||
>
|
? $t('journal.timetable-fulfilled')
|
||||||
</span>
|
: `${$t('journal.timetable-abandoned')} ${localeTime(timetable.endDate, $i18n.locale)}`
|
||||||
{{ scenery.name }}
|
}}
|
||||||
<!-- Data odjazdu ze stacji początkowej -->
|
</b>
|
||||||
<span v-if="i == 0" v-html="scenery.beginDateHTML"></span>
|
</span>
|
||||||
<!-- Data przyjazdu do stacji końcowej -->
|
</div>
|
||||||
<span
|
|
||||||
v-if="i == sceneryList.length - 1 || (i == 1 && !item.showExtra.value)"
|
|
||||||
v-html="scenery.endDateHTML"
|
|
||||||
></span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Status RJ -->
|
<div class="info-route">
|
||||||
<div style="margin: 0.5em 0">
|
<b>{{ timetable.route.replace('|', ' - ') }}</b>
|
||||||
<span>
|
</div>
|
||||||
<b>{{ $t('journal.route-length') }}</b>
|
|
||||||
{{ !timetable.fulfilled ? timetable.currentDistance + ' /' : '' }}
|
|
||||||
{{ timetable.routeDistance }} km
|
|
||||||
</span>
|
|
||||||
•
|
|
||||||
<span>
|
|
||||||
<b>{{ $t('journal.station-count') }}</b>
|
|
||||||
{{ timetable.confirmedStopsCount }} /
|
|
||||||
{{ timetable.allStopsCount }}
|
|
||||||
</span>
|
|
||||||
<span class="text--grayed" v-if="!timetable.fulfilled && timetable.currentSceneryName">
|
|
||||||
•
|
|
||||||
<b>
|
|
||||||
{{ $t(`journal.${timetable.terminated ? 'last-seen-at' : 'currently-at'}`) }}
|
|
||||||
{{ timetable.currentSceneryName.replace(/.[a-zA-Z0-9]+.sc/, '') }}
|
|
||||||
</b>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Nick dyżurnego -->
|
<hr />
|
||||||
<div v-if="timetable.authorName">
|
|
||||||
<b class="text--grayed">{{ $t('journal.dispatcher-name') }} </b>
|
|
||||||
<router-link class="dispatcher-link" :to="`/journal/dispatchers?dispatcherName=${timetable.authorName}`">
|
|
||||||
<b>{{ timetable.authorName }}</b>
|
|
||||||
</router-link>
|
|
||||||
<span class="text--grayed">
|
|
||||||
({{
|
|
||||||
(new Date(timetable.createdAt).getTime() - new Date(timetable.beginDate).getTime() < 0
|
|
||||||
? new Date(timetable.createdAt)
|
|
||||||
: new Date(timetable.beginDate)
|
|
||||||
).toLocaleString($i18n.locale, { timeStyle: 'short', dateStyle: 'full' })
|
|
||||||
}})
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button class="btn--option btn--show">
|
<!-- Spis postojów -->
|
||||||
{{ $t('journal.stock-info') }}
|
<div class="stop-list" v-if="showExtraInfo.value == true">
|
||||||
<img :src="getIcon(`arrow-${item.showExtra.value ? 'asc' : 'desc'}`)" alt="Arrow" />
|
<span
|
||||||
</button>
|
v-for="(stop, i) in stops.filter((_, i) =>
|
||||||
|
!showExtraInfo.value ? i == 0 || i == stops.length - 1 : true
|
||||||
|
)"
|
||||||
|
class="stop-list-item"
|
||||||
|
:key="stop.stopName"
|
||||||
|
:data-confirmed="stop.confirmed"
|
||||||
|
>
|
||||||
|
<span v-if="i > 0">
|
||||||
|
>
|
||||||
|
<span v-if="!showExtraInfo.value && i == 1 && stops.length > 2">
|
||||||
|
... (+{{ stops.length - 2 }}) >
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
<div class="info-extended" v-if="timetable.stockString && item.showExtra.value">
|
<span class="stop-name">{{ stop.stopName }}</span>
|
||||||
<hr />
|
<span v-html="stop.html"></span>
|
||||||
<div>
|
</span>
|
||||||
<span class="badge info-badge">
|
</div>
|
||||||
<span>{{ $t('journal.stock-max-speed') }}</span>
|
|
||||||
<span>{{ timetable.maxSpeed }}km/h</span>
|
<!-- Status RJ -->
|
||||||
</span>
|
<div class="info-status" style="margin: 0.5em 0">
|
||||||
<span class="badge info-badge">
|
<ProgressBar
|
||||||
<span>{{ $t('journal.stock-length') }}</span>
|
:progressPercent="~~((timetable.currentDistance / timetable.routeDistance) * 100)"
|
||||||
<span>{{ timetable.stockLength }}m</span>
|
:progressType="!timetable.fulfilled && timetable.terminated ? 'abandoned' : ''"
|
||||||
</span>
|
/>
|
||||||
<span class="badge info-badge">
|
|
||||||
<span>{{ $t('journal.stock-mass') }}</span>
|
<span>
|
||||||
<span>{{ Math.floor(timetable.stockMass! / 1000) }}t</span>
|
<span :style="{ color: timetable.fulfilled ? 'lightgreen' : timetable.terminated ? 'salmon' : '' }">
|
||||||
</span>
|
{{ timetable.currentDistance + ' km' }}
|
||||||
</div>
|
</span>
|
||||||
<ul class="stock-list">
|
<span> / </span>
|
||||||
<li v-for="(car, i) in timetable.stockString.split(';')" :key="i">
|
<span class="text--primary">{{ timetable.routeDistance }} km</span>
|
||||||
<img
|
|
|
||||||
@error="onImageError"
|
<span class="text--grayed">{{ timetable.confirmedStopsCount }}/{{ timetable.allStopsCount }}</span>
|
||||||
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${car.split(':')[0]}.png`"
|
</span>
|
||||||
:alt="car"
|
|
||||||
/>
|
<span class="text--grayed" v-if="timetable.currentSceneryName">
|
||||||
<div>{{ car.replace(/_/g, ' ').split(':')[0] }}</div>
|
<b>
|
||||||
|
{{ $t(`journal.${timetable.terminated ? 'last-seen-at' : 'currently-at'}`) }}
|
||||||
|
{{ timetable.currentSceneryName.replace(/.[a-zA-Z0-9]+.sc/, '') }}
|
||||||
|
|
||||||
|
<span v-if="timetable.currentLocation[0] || timetable.currentLocation[1]">(</span>
|
||||||
|
|
||||||
|
<span v-if="timetable.currentLocation[1]">
|
||||||
|
{{ $t('journal.timetable-location-route') }} {{ timetable.currentLocation[1] }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-else-if="timetable.currentLocation[0]">
|
||||||
|
{{ $t('journal.timetable-location-signal') }} {{ timetable.currentLocation[0] }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-if="timetable.currentLocation[0] || timetable.currentLocation[1]">)</span>
|
||||||
|
</b>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn--option btn--show">
|
||||||
|
{{ $t('journal.stock-info') }}
|
||||||
|
<img :src="getIcon(`arrow-${showExtraInfo.value ? 'asc' : 'desc'}`)" alt="Arrow" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Dodatkowe informacje -->
|
||||||
|
<div class="info-extended" v-if="timetable.stockString && timetable.stockMass && showExtraInfo.value">
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="stock-specs">
|
||||||
|
<span class="badge specs-badge">
|
||||||
|
<span>{{ $t('journal.dispatcher-name') }}</span>
|
||||||
|
<span>{{ timetable.authorName }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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 specs-badge">
|
||||||
|
<span>{{ $t('journal.stock-length') }}</span>
|
||||||
|
<span>
|
||||||
|
{{
|
||||||
|
item.currentHistoryIndex.value == 0
|
||||||
|
? timetable.stockLength
|
||||||
|
: stockHistoryComp[item.currentHistoryIndex.value].stockLength || timetable.stockLength
|
||||||
|
}}m
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="badge specs-badge">
|
||||||
|
<span>{{ $t('journal.stock-mass') }}</span>
|
||||||
|
<span>
|
||||||
|
{{
|
||||||
|
Math.floor(
|
||||||
|
(item.currentHistoryIndex.value == 0
|
||||||
|
? timetable.stockMass!
|
||||||
|
: stockHistoryComp[item.currentHistoryIndex.value].stockMass || timetable.stockMass) /
|
||||||
|
1000
|
||||||
|
)
|
||||||
|
}}t
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Historia zmian w składzie -->
|
||||||
|
<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 (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`"
|
||||||
|
:alt="car"
|
||||||
|
/>
|
||||||
|
<div>{{ car.replace(/_/g, ' ').split(':')[0] }}</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</transition-group>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="btn btn--option btn--load-data"
|
||||||
|
v-if="!scrollNoMoreData && scrollDataLoaded && timetableHistory.length >= 15"
|
||||||
|
@click="addHistoryData"
|
||||||
|
>
|
||||||
|
{{ $t('journal.load-data') }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</transition>
|
||||||
</transition-group>
|
|
||||||
|
<div class="journal_warning" v-if="scrollNoMoreData">{{ $t('journal.no-further-data') }}</div>
|
||||||
|
<div class="journal_warning" v-else-if="!scrollDataLoaded">{{ $t('journal.loading-further-data') }}</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -167,65 +253,117 @@ import dateMixin from '../../mixins/dateMixin';
|
|||||||
import imageMixin from '../../mixins/imageMixin';
|
import imageMixin from '../../mixins/imageMixin';
|
||||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||||
import styleMixin from '../../mixins/styleMixin';
|
import styleMixin from '../../mixins/styleMixin';
|
||||||
|
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||||
import { TimetableHistory } from '../../scripts/interfaces/api/TimetablesAPIData';
|
import { TimetableHistory } from '../../scripts/interfaces/api/TimetablesAPIData';
|
||||||
import { TimetableStop } from '../../scripts/interfaces/api/TrainAPIData';
|
import { useStore } from '../../store/store';
|
||||||
|
import Loading from '../Global/Loading.vue';
|
||||||
|
import ProgressBar from '../Global/ProgressBar.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
components: { ProgressBar, Loading },
|
||||||
|
mixins: [dateMixin, imageMixin, modalTrainMixin, styleMixin],
|
||||||
props: {
|
props: {
|
||||||
timetableHistory: {
|
timetableHistory: {
|
||||||
type: Array as PropType<TimetableHistory[]>,
|
type: Array as PropType<TimetableHistory[]>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
scrollNoMoreData: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
scrollDataLoaded: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
addHistoryData: {
|
||||||
|
type: Function as PropType<() => void>,
|
||||||
|
},
|
||||||
|
dataStatus: {
|
||||||
|
type: Number as PropType<DataStatus>,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [dateMixin, imageMixin, modalTrainMixin, styleMixin],
|
data() {
|
||||||
|
return {
|
||||||
|
DataStatus,
|
||||||
|
store: useStore(),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
computedTimetableHistory() {
|
computedTimetableHistory() {
|
||||||
return this.timetableHistory.map((timetable) => ({
|
return this.timetableHistory.map((timetable) => ({
|
||||||
timetable,
|
timetable,
|
||||||
sceneryList: this.getSceneryList(timetable),
|
stockHistoryComp: timetable.stockHistory
|
||||||
showExtra: ref(false),
|
.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,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
showExtraInfo: ref(false),
|
||||||
|
stops: this.getTimetableStops(timetable),
|
||||||
|
currentHistoryIndex: ref(0),
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
getSceneryList(timetable: TimetableHistory) {
|
getTimetableStops(timetable: TimetableHistory) {
|
||||||
return timetable.sceneriesString.split('%').map((name, i) => {
|
const stopNames = timetable.sceneriesString.split('%');
|
||||||
const beginDateHTML =
|
|
||||||
' (o. ' +
|
|
||||||
(timetable.beginDate != timetable.scheduledBeginDate
|
|
||||||
? `<s class='text--grayed'>${this.localeTime(timetable.beginDate, this.$i18n.locale)}</s> `
|
|
||||||
: '') +
|
|
||||||
`<span>${this.localeTime(timetable.scheduledBeginDate, this.$i18n.locale)}</span>)`;
|
|
||||||
|
|
||||||
const endDateHTML =
|
const beginDateHTML = ` (o. ${
|
||||||
' (p. ' +
|
timetable.beginDate != timetable.scheduledBeginDate
|
||||||
(timetable.endDate != timetable.scheduledEndDate && timetable.fulfilled
|
? `<s class="text--grayed">${this.localeTime(timetable.beginDate, this.$i18n.locale)}</s>`
|
||||||
? `<s class='text--grayed'>${this.localeTime(
|
: ''
|
||||||
timetable.fulfilled ? timetable.endDate : timetable.scheduledEndDate,
|
} <span>${this.localeTime(timetable.scheduledBeginDate, this.$i18n.locale)}</span>)`;
|
||||||
this.$i18n.locale
|
|
||||||
)}</s> `
|
|
||||||
: '') +
|
|
||||||
`<span>${this.localeTime(
|
|
||||||
timetable.fulfilled || (timetable.terminated && !timetable.fulfilled)
|
|
||||||
? timetable.scheduledEndDate
|
|
||||||
: timetable.endDate,
|
|
||||||
this.$i18n.locale
|
|
||||||
)}</span>)`;
|
|
||||||
|
|
||||||
return { name, confirmed: i < timetable.confirmedStopsCount, beginDateHTML, endDateHTML };
|
const endDateHTML = ` (p. ${
|
||||||
|
timetable.endDate != timetable.scheduledEndDate && timetable.fulfilled
|
||||||
|
? `<s class="text--grayed">${this.localeTime(timetable.endDate, this.$i18n.locale)}</s>`
|
||||||
|
: ''
|
||||||
|
} <span>${this.localeTime(timetable.scheduledEndDate, this.$i18n.locale)}</span>)`;
|
||||||
|
|
||||||
|
return stopNames.map((stopName, i) => {
|
||||||
|
const confirmed = i < timetable.confirmedStopsCount;
|
||||||
|
|
||||||
|
if (i == 0) return { stopName, html: beginDateHTML, confirmed };
|
||||||
|
if (i == stopNames.length - 1) return { stopName, html: endDateHTML, confirmed };
|
||||||
|
|
||||||
|
const departureDateScheduled = this.stringToDate(timetable.checkpointDeparturesScheduled?.at(i));
|
||||||
|
const departureDateReal = this.stringToDate(timetable.checkpointDepartures?.at(i));
|
||||||
|
const arrivalDateScheduled = this.stringToDate(timetable.checkpointArrivalsScheduled?.at(i));
|
||||||
|
const arrivalDateReal = this.stringToDate(timetable.checkpointArrivals?.at(i));
|
||||||
|
|
||||||
|
const arrivalHTML =
|
||||||
|
(arrivalDateReal && arrivalDateScheduled && arrivalDateReal?.getTime() != arrivalDateScheduled?.getTime()
|
||||||
|
? `<s class="text--grayed">${this.parseDateToTimeString(arrivalDateScheduled)}</s> `
|
||||||
|
: '') + this.parseDateToTimeString(arrivalDateReal || arrivalDateScheduled);
|
||||||
|
|
||||||
|
const departureHTML =
|
||||||
|
(departureDateReal &&
|
||||||
|
departureDateScheduled &&
|
||||||
|
departureDateReal?.getTime() != departureDateScheduled?.getTime()
|
||||||
|
? `<s class="text--grayed">${this.parseDateToTimeString(departureDateScheduled)}</s> `
|
||||||
|
: '') + this.parseDateToTimeString(departureDateReal || departureDateScheduled);
|
||||||
|
|
||||||
|
let html = `${arrivalHTML}${departureHTML ? ` / ${departureHTML}` : ''}`;
|
||||||
|
|
||||||
|
if (html) html = ` (${html})`;
|
||||||
|
return { stopName, html, confirmed };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
showTimetable(timetable: TimetableHistory, target: EventTarget | null) {
|
||||||
|
if (timetable?.terminated) return;
|
||||||
|
|
||||||
showTimetable(timetable: TimetableHistory) {
|
this.selectModalTrain(timetable.driverName + timetable.trainNo.toString(), target);
|
||||||
if (!timetable) return;
|
|
||||||
if (timetable.terminated) return;
|
|
||||||
|
|
||||||
this.selectModalTrain(timetable.driverName + timetable.trainNo.toString());
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onImageError(e: Event) {
|
onImageError(e: Event) {
|
||||||
const imageEl = e.target as HTMLImageElement;
|
const imageEl = e.target as HTMLImageElement;
|
||||||
imageEl.src = this.getImage('unknown.png');
|
imageEl.src = this.getImage('unknown.png');
|
||||||
@@ -254,7 +392,7 @@ hr {
|
|||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-status {
|
&-badge {
|
||||||
padding: 0.05em 0.35em;
|
padding: 0.05em 0.35em;
|
||||||
color: black;
|
color: black;
|
||||||
|
|
||||||
@@ -288,10 +426,19 @@ hr {
|
|||||||
&-extended {
|
&-extended {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.general-train {
|
.general-train {
|
||||||
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
}
|
}
|
||||||
@@ -308,18 +455,64 @@ ul.stock-list {
|
|||||||
color: #aaa;
|
color: #aaa;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
li > img {
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
max-height: 60px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.scenery-list {
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// badge.scss
|
||||||
|
.badges {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stock-history {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5em;
|
||||||
|
margin-top: 1em;
|
||||||
|
|
||||||
|
button[data-checked='true'] {
|
||||||
|
color: $accentCol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop-list {
|
||||||
|
word-wrap: break-word;
|
||||||
|
gap: 0.25em;
|
||||||
|
font-size: 0.95em;
|
||||||
|
|
||||||
color: #adadad;
|
color: #adadad;
|
||||||
span.confirmed {
|
|
||||||
color: #a3eba3;
|
&-item[data-confirmed='true'] {
|
||||||
|
color: lightgreen;
|
||||||
|
|
||||||
|
.stop-name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn--show {
|
.btn--show {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: 1em;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 0.2em 0.45em;
|
padding: 0.2em 0.45em;
|
||||||
|
|
||||||
@@ -328,18 +521,8 @@ ul.stock-list {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-badge {
|
|
||||||
span:last-child {
|
|
||||||
color: black;
|
|
||||||
background-color: $accentCol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include smallScreen {
|
@include smallScreen {
|
||||||
.info-general {
|
.journal_item-info {
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.info-extended {
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,8 +531,19 @@ ul.stock-list {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-status {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.btn--show {
|
.btn--show {
|
||||||
margin: 1em auto 0 auto;
|
margin: 1em auto 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-general,
|
||||||
|
.general-train,
|
||||||
|
.stock-specs,
|
||||||
|
.stock-history {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,39 +1,61 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="scenery-dispatchers-history scenery-section">
|
<section class="scenery-table-section">
|
||||||
<Loading v-if="dataStatus != 2" />
|
<Loading v-if="dataStatus != DataStatus.Loaded && historyList.length == 0" />
|
||||||
|
<div class="no-history" v-else-if="historyList.length == 0">{{ $t('scenery.history-list-empty') }}</div>
|
||||||
|
|
||||||
<div class="list-warning" v-else-if="dispatcherHistoryList.length == 0">{{ $t('scenery.history-list-empty') }}</div>
|
<table class="scenery-history-table" v-else="historyList.length">
|
||||||
|
<thead>
|
||||||
|
<th>{{ $t('scenery.dispatchers-history-hash') }}</th>
|
||||||
|
<th>{{ $t('scenery.dispatchers-history-dispatcher') }}</th>
|
||||||
|
<th>{{ $t('scenery.dispatchers-history-level') }}</th>
|
||||||
|
<th>{{ $t('scenery.dispatchers-history-rate') }}</th>
|
||||||
|
<th>{{ $t('scenery.dispatchers-history-date') }}</th>
|
||||||
|
</thead>
|
||||||
|
|
||||||
<ul class="history-list" v-else>
|
<tbody>
|
||||||
<li class="list-item" v-for="item in dispatcherHistoryList">
|
<tr v-for="historyItem in historyList">
|
||||||
<router-link class="item-general" :to="`/journal/dispatchers?dispatcherName=${item.dispatcherName}`">
|
<td>#{{ historyItem.stationHash }}</td>
|
||||||
<span class="text--grayed">#{{ item.stationHash }} </span>
|
<td>
|
||||||
<b
|
<router-link :to="`/journal/dispatchers?dispatcherName=${historyItem.dispatcherName}`">
|
||||||
v-if="item.dispatcherLevel !== null"
|
<b>{{ historyItem.dispatcherName }}</b>
|
||||||
class="level-badge dispatcher"
|
</router-link>
|
||||||
:style="calculateExpStyle(item.dispatcherLevel, item.dispatcherIsSupporter)"
|
</td>
|
||||||
>
|
<td>
|
||||||
{{ item.dispatcherLevel >= 2 ? item.dispatcherLevel : 'L' }}
|
<b
|
||||||
</b>
|
v-if="historyItem.dispatcherLevel !== null"
|
||||||
|
class="level-badge dispatcher"
|
||||||
|
:style="calculateExpStyle(historyItem.dispatcherLevel, historyItem.dispatcherIsSupporter)"
|
||||||
|
>
|
||||||
|
{{ historyItem.dispatcherLevel >= 2 ? historyItem.dispatcherLevel : 'L' }}
|
||||||
|
</b>
|
||||||
|
</td>
|
||||||
|
<td class="text--primary">
|
||||||
|
<b>{{ historyItem.dispatcherRate }}</b>
|
||||||
|
</td>
|
||||||
|
<td style="min-width: 300px">
|
||||||
|
<div v-if="historyItem.timestampTo">
|
||||||
|
<b>{{ $d(historyItem.timestampFrom) }}</b>
|
||||||
|
|
||||||
<b>{{ item.dispatcherName }}</b>
|
{{ timestampToString(historyItem.timestampFrom) }}
|
||||||
</router-link>
|
- {{ timestampToString(historyItem.timestampTo) }} ({{ calculateDuration(historyItem.currentDuration) }})
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="item.timestampTo">
|
<div class="dispatcher-online" v-else>
|
||||||
<b>{{ $d(item.timestampFrom) }}</b>
|
{{ $t('journal.online-since') }}
|
||||||
|
<b>{{ timestampToString(historyItem.timestampFrom) }}</b>
|
||||||
{{ timestampToString(item.timestampFrom) }}
|
({{ calculateDuration(historyItem.currentDuration) }})
|
||||||
- {{ timestampToString(item.timestampTo) }} ({{ calculateDuration(item.currentDuration) }})
|
</div>
|
||||||
</div>
|
</td>
|
||||||
|
</tr>
|
||||||
<div class="dispatcher-online" v-else>
|
</tbody>
|
||||||
{{ $t('journal.online-since') }}
|
</table>
|
||||||
<b>{{ timestampToString(item.timestampFrom) }}</b>
|
|
||||||
({{ calculateDuration(item.currentDuration) }})
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<div class="bottom-info">
|
||||||
|
<button class="btn btn--option" v-if="historyList.length > 0" @click="navigateToHistory">
|
||||||
|
{{ $t('scenery.bottom-info') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -46,37 +68,52 @@ import Station from '../../scripts/interfaces/Station';
|
|||||||
import { URLs } from '../../scripts/utils/apiURLs';
|
import { URLs } from '../../scripts/utils/apiURLs';
|
||||||
import Loading from '../Global/Loading.vue';
|
import Loading from '../Global/Loading.vue';
|
||||||
import styleMixin from '../../mixins/styleMixin';
|
import styleMixin from '../../mixins/styleMixin';
|
||||||
|
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SceneryDispatchersHistory',
|
name: 'SceneryDispatchersHistory',
|
||||||
mixins: [dateMixin, styleMixin],
|
mixins: [dateMixin, styleMixin, listObserverMixin],
|
||||||
props: {
|
props: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as PropType<Station>,
|
type: Object as PropType<Station>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dispatcherHistoryList: [] as DispatcherHistory[],
|
historyList: [] as DispatcherHistory[],
|
||||||
dataStatus: DataStatus.Loading,
|
dataStatus: DataStatus.Loading,
|
||||||
|
DataStatus,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
activated() {
|
|
||||||
this.fetchAPIData();
|
async activated() {
|
||||||
|
// if (this.historyList.length == 0) {
|
||||||
|
const fetchedHistory = await this.fetchAPIData();
|
||||||
|
if (fetchedHistory) this.historyList = fetchedHistory;
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async fetchAPIData(countFrom = 0, countLimit = 30) {
|
async fetchAPIData(countFrom = 0, countLimit = 30): Promise<DispatcherHistory[] | null> {
|
||||||
try {
|
try {
|
||||||
|
this.dataStatus = DataStatus.Loading;
|
||||||
|
|
||||||
const requestString = `${URLs.stacjownikAPI}/api/getDispatchers?stationName=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
const requestString = `${URLs.stacjownikAPI}/api/getDispatchers?stationName=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||||
const historyAPIData: DispatcherHistory[] = await (await axios.get(requestString)).data;
|
const historyAPIData: DispatcherHistory[] = await (await axios.get(requestString)).data;
|
||||||
|
|
||||||
this.dispatcherHistoryList = historyAPIData;
|
|
||||||
this.dataStatus = DataStatus.Loaded;
|
this.dataStatus = DataStatus.Loaded;
|
||||||
|
return historyAPIData;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
this.dataStatus = DataStatus.Error;
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
navigateToHistory() {
|
||||||
|
this.$router.push(`/journal/dispatchers?sceneryName=${this.station.name}`);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: { Loading },
|
components: { Loading },
|
||||||
});
|
});
|
||||||
@@ -84,30 +121,10 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
@import '../../styles/SceneryView/styles.scss';
|
@import '../../styles/sceneryViewTables.scss';
|
||||||
|
|
||||||
.history-list {
|
.level-badge {
|
||||||
padding: 0 0.5em;
|
margin: 0 auto;
|
||||||
}
|
|
||||||
|
|
||||||
.list-item {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
text-align: left;
|
|
||||||
background-color: #353535;
|
|
||||||
padding: 0.5em;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
|
|
||||||
line-height: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-general {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.25em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dispatcher-online {
|
.dispatcher-online {
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
{{ station.name }}
|
{{ station.name }}
|
||||||
</a>
|
</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>
|
<div class="scenery-hash" v-if="station.onlineInfo?.hash">#{{ station.onlineInfo.hash }}</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
@@ -26,18 +30,26 @@ export default defineComponent({
|
|||||||
@import '../../styles/variables.scss';
|
@import '../../styles/variables.scss';
|
||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
|
|
||||||
|
.info-header {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.scenery-name {
|
.scenery-name {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
font-size: 3em;
|
font-size: 3em;
|
||||||
|
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scenery-abbrev {
|
||||||
|
font-size: 1.3em;
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
.scenery-hash {
|
.scenery-hash {
|
||||||
|
margin-top: 0.5em;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,9 @@
|
|||||||
style="color: salmon; text-decoration: underline; font-weight: bold"
|
style="color: salmon; text-decoration: underline; font-weight: bold"
|
||||||
:href="station.generalInfo.projectUrl"
|
:href="station.generalInfo.projectUrl"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>{{ station.generalInfo.project }}</a
|
|
||||||
>
|
>
|
||||||
|
{{ station.generalInfo.project }}
|
||||||
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -21,18 +21,11 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="status-badge" v-if="station.onlineInfo && onlineFrom > 0">
|
<StationStatusBadge
|
||||||
OD {{ new Date(onlineFrom).toLocaleTimeString('pl-PL', { hour: '2-digit', minute: '2-digit' }) }}
|
:statusID="station.onlineInfo?.statusID"
|
||||||
</span>
|
:isOnline="station.onlineInfo ? true : false"
|
||||||
|
:statusTimestamp="station.onlineInfo?.statusTimestamp"
|
||||||
<span class="status-badge" v-if="station.onlineInfo" :class="station.onlineInfo.statusID">
|
/>
|
||||||
{{ $t(`status.${station.onlineInfo.statusID}`) }}
|
|
||||||
{{ station.onlineInfo.statusID == 'online' ? timestampToString(station.onlineInfo.statusTimestamp) : '' }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="status-badge free" v-else>
|
|
||||||
{{ $t('status.free') }}
|
|
||||||
</span>
|
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -43,20 +36,21 @@ import imageMixin from '../../../mixins/imageMixin';
|
|||||||
import routerMixin from '../../../mixins/routerMixin';
|
import routerMixin from '../../../mixins/routerMixin';
|
||||||
import styleMixin from '../../../mixins/styleMixin';
|
import styleMixin from '../../../mixins/styleMixin';
|
||||||
import Station from '../../../scripts/interfaces/Station';
|
import Station from '../../../scripts/interfaces/Station';
|
||||||
|
import StationStatusBadge from '../../Global/StationStatusBadge.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [styleMixin, dateMixin, routerMixin, imageMixin],
|
mixins: [styleMixin, dateMixin, routerMixin, imageMixin],
|
||||||
props: {
|
props: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as () => Station,
|
type: Object as () => Station,
|
||||||
default: {},
|
default: {},
|
||||||
|
},
|
||||||
|
onlineFrom: {
|
||||||
|
type: Number,
|
||||||
|
default: -1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
components: { StationStatusBadge }
|
||||||
onlineFrom: {
|
|
||||||
type: Number,
|
|
||||||
default: -1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -104,3 +98,4 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,11 @@
|
|||||||
<b>{{ $t('scenery.one-way-routes') }}</b>
|
<b>{{ $t('scenery.one-way-routes') }}</b>
|
||||||
|
|
||||||
<ul class="routes-list">
|
<ul class="routes-list">
|
||||||
<li v-for="route in station.generalInfo.routes.oneWay">
|
<li v-for="route in station.generalInfo.routes.oneWay" @click="setActiveShowLength(route.name)">
|
||||||
<span :class="{ 'no-catenary': !route.catenary, internal: route.isInternal }"> {{ route.name }}</span>
|
<span :class="{ 'no-catenary': !route.catenary, internal: route.isInternal }"> {{ route.name }}</span>
|
||||||
<span v-if="route.speed" class="speed">{{ route.speed }}</span>
|
<span v-if="route.speed" class="speed">
|
||||||
|
{{ activeShowLength.includes(route.name) ? route.length + 'm' : route.speed }}
|
||||||
|
</span>
|
||||||
<span v-if="route.SBL" class="sbl">SBL</span>
|
<span v-if="route.SBL" class="sbl">SBL</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -16,9 +18,11 @@
|
|||||||
<b>{{ $t('scenery.two-way-routes') }}</b>
|
<b>{{ $t('scenery.two-way-routes') }}</b>
|
||||||
|
|
||||||
<ul class="routes-list">
|
<ul class="routes-list">
|
||||||
<li v-for="route in station.generalInfo.routes.twoWay">
|
<li v-for="(route, i) in station.generalInfo.routes.twoWay" @click="setActiveShowLength(route.name)">
|
||||||
<span :class="{ 'no-catenary': !route.catenary, internal: route.isInternal }">{{ route.name }}</span>
|
<span :class="{ 'no-catenary': !route.catenary, internal: route.isInternal }">{{ route.name }}</span>
|
||||||
<span v-if="route.speed" class="speed">{{ route.speed }}</span>
|
<span v-if="route.speed" class="speed">
|
||||||
|
{{ activeShowLength.includes(route.name) ? route.length + 'm' : route.speed }}
|
||||||
|
</span>
|
||||||
<span v-if="route.SBL" class="sbl">SBL</span>
|
<span v-if="route.SBL" class="sbl">SBL</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -37,6 +41,19 @@ export default defineComponent({
|
|||||||
default: {},
|
default: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
setActiveShowLength(name: string) {
|
||||||
|
if (this.activeShowLength.includes(name)) this.activeShowLength.splice(this.activeShowLength.indexOf(name), 1);
|
||||||
|
else this.activeShowLength.push(name);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeShowLength: [] as string[],
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -66,6 +83,11 @@ ul.routes-list {
|
|||||||
|
|
||||||
li {
|
li {
|
||||||
margin: 0.5em 0.25em;
|
margin: 0.5em 0.25em;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
padding: 0.2em 0.25em;
|
padding: 0.2em 0.25em;
|
||||||
@@ -100,7 +122,6 @@ ul.routes-list {
|
|||||||
|
|
||||||
&:only-child {
|
&:only-child {
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,9 @@
|
|||||||
<span v-if="station.onlineInfo">
|
<span v-if="station.onlineInfo">
|
||||||
<span
|
<span
|
||||||
class="badge spawn"
|
class="badge spawn"
|
||||||
v-for="(spawn, i) in station.onlineInfo.spawns"
|
v-for="(spawn, i) in sortedSpawns"
|
||||||
:key="spawn.spawnName + station.onlineInfo?.dispatcherName + i"
|
:key="spawn.spawnName + station.onlineInfo?.dispatcherName + i"
|
||||||
|
:data-electrified="spawn.isElectrified"
|
||||||
>
|
>
|
||||||
<span class="spawn_name">{{ spawn.spawnName }}</span>
|
<span class="spawn_name">{{ spawn.spawnName }}</span>
|
||||||
<span class="spawn_length">{{ spawn.spawnLength }}m</span>
|
<span class="spawn_length">{{ spawn.spawnLength }}m</span>
|
||||||
@@ -37,6 +38,12 @@ export default defineComponent({
|
|||||||
default: {},
|
default: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
sortedSpawns() {
|
||||||
|
return this.station.onlineInfo?.spawns.sort((s1, s2) => (s1.spawnLength < s2.spawnLength ? 1 : -1));
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -44,9 +51,15 @@ export default defineComponent({
|
|||||||
@import '../../../styles/variables.scss';
|
@import '../../../styles/variables.scss';
|
||||||
|
|
||||||
.spawn {
|
.spawn {
|
||||||
|
color: white;
|
||||||
|
|
||||||
&_length {
|
&_length {
|
||||||
background: $accentCol;
|
background-color: #404040;
|
||||||
color: black;
|
color: #cfcfcf;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-electrified='true'] > &_name {
|
||||||
|
background-color: #007599;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
:class="train.stopStatus"
|
:class="train.stopStatus"
|
||||||
:key="train.trainId"
|
:key="train.trainId"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@click="selectModalTrain(train.trainId)"
|
@click.prevent="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||||
@keydown.enter="selectModalTrain(train.trainId)"
|
@keydown.enter="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||||
>
|
>
|
||||||
<span class="user_train">{{ train.trainNo }}</span>
|
<span class="user_train">{{ train.trainNo }}</span>
|
||||||
<span class="user_name">{{ train.driverName }}</span>
|
<span class="user_name">{{ train.driverName }}</span>
|
||||||
@@ -27,7 +27,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
import { computed, defineComponent } from 'vue';
|
import { computed, defineComponent } from 'vue';
|
||||||
import imageMixin from '../../../mixins/imageMixin';
|
import imageMixin from '../../../mixins/imageMixin';
|
||||||
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
||||||
@@ -130,4 +129,3 @@ $disconnected: slategray;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -67,8 +67,8 @@
|
|||||||
v-for="(scheduledTrain, i) in computedScheduledTrains"
|
v-for="(scheduledTrain, i) in computedScheduledTrains"
|
||||||
:key="scheduledTrain.trainId"
|
:key="scheduledTrain.trainId"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@click.prevent.stop="selectModalTrain(scheduledTrain.trainId)"
|
@click.prevent.stop="selectModalTrain(scheduledTrain.trainId, $event.currentTarget)"
|
||||||
@keydown.enter.prevent="selectModalTrain(scheduledTrain.trainId)"
|
@keydown.enter.prevent="selectModalTrain(scheduledTrain.trainId, $event.currentTarget)"
|
||||||
>
|
>
|
||||||
<span class="timetable-general">
|
<span class="timetable-general">
|
||||||
<span class="general-info">
|
<span class="general-info">
|
||||||
@@ -121,25 +121,17 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="schedule-stop">
|
<span class="schedule-stop">
|
||||||
<span class="stop-time">
|
<span class="stop-connection">
|
||||||
<span v-if="scheduledTrain.stopInfo.stopTime">
|
{{ scheduledTrain.arrivingLine }}
|
||||||
{{ scheduledTrain.stopInfo.stopTime }}
|
|
||||||
{{ scheduledTrain.stopInfo.stopType || 'pt' }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-else> </span>
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="arrow"></span>
|
<span class="stop-time">
|
||||||
|
{{ scheduledTrain.stopInfo.stopTime || '' }}
|
||||||
|
{{ scheduledTrain.stopInfo.stopTime ? scheduledTrain.stopInfo.stopType || 'pt' : '' }}
|
||||||
|
</span>
|
||||||
|
|
||||||
<span class="stop-line">
|
<span class="stop-connection">
|
||||||
<span>
|
{{ scheduledTrain.departureLine }}
|
||||||
{{ scheduledTrain.arrivingLine }}
|
|
||||||
</span>
|
|
||||||
<span></span>
|
|
||||||
<span>
|
|
||||||
{{ scheduledTrain.departureLine }}
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -341,8 +333,8 @@ export default defineComponent({
|
|||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
gap: 2em 0.5em;
|
gap: 1.2em 0.5em;
|
||||||
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
@@ -368,7 +360,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
&-schedule {
|
&-schedule {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(30px, 1fr));
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 0.2em;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
@@ -400,33 +394,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.arrow {
|
|
||||||
border: solid white;
|
|
||||||
border-width: 0 2px 2px 0;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 2px;
|
|
||||||
margin-left: 50px;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
transform: rotate(-45deg);
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
width: 55px;
|
|
||||||
height: 3px;
|
|
||||||
top: 4px;
|
|
||||||
left: 4px;
|
|
||||||
|
|
||||||
transform: translate(-100%, -1px) rotate(45deg);
|
|
||||||
transform-origin: right bottom;
|
|
||||||
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.general-info {
|
.general-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -453,47 +420,34 @@ export default defineComponent({
|
|||||||
|
|
||||||
.schedule {
|
.schedule {
|
||||||
&-arrival,
|
&-arrival,
|
||||||
&-stop,
|
|
||||||
&-departure {
|
&-departure {
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
margin: 0 0.3rem;
|
|
||||||
font-size: 1.15em;
|
font-size: 1.15em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-stop {
|
&-stop {
|
||||||
position: relative;
|
display: grid;
|
||||||
display: flex;
|
grid-template-columns: repeat(3, 1fr);
|
||||||
flex-direction: column;
|
gap: 0.5em;
|
||||||
font-size: 0.9em;
|
align-items: end;
|
||||||
|
|
||||||
padding: 0.3em 0;
|
.stop-connection {
|
||||||
|
font-size: 0.95em;
|
||||||
.stop-line {
|
|
||||||
display: flex;
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
span {
|
|
||||||
width: 65px;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
span:first-child {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
span:last-child {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stop-time {
|
.stop-time {
|
||||||
position: absolute;
|
position: relative;
|
||||||
transform: translateY(-15px);
|
inline-size: max-content;
|
||||||
|
align-self: center;
|
||||||
|
font-size: 0.9em;
|
||||||
|
|
||||||
color: $accentCol;
|
color: $accentCol;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '\027F6';
|
||||||
|
display: block;
|
||||||
|
font-size: 2.2em;
|
||||||
|
line-height: 0.65em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="scenery-timetables-history scenery-section">
|
<section class="scenery-table-section">
|
||||||
<Loading v-if="dataStatus != 2" />
|
<Loading v-if="dataStatus != DataStatus.Loaded" />
|
||||||
|
<div class="no-history" v-else-if="historyList.length == 0">{{ $t('scenery.history-list-empty') }}</div>
|
||||||
|
|
||||||
<table v-else-if="sceneryHistoryList.length">
|
<table class="scenery-history-table" v-else>
|
||||||
<thead>
|
<thead>
|
||||||
<th>{{ $t('scenery.timetables-history-id') }}</th>
|
<th>{{ $t('scenery.timetables-history-id') }}</th>
|
||||||
<th>{{ $t('scenery.timetables-history-number')}}</th>
|
<th>{{ $t('scenery.timetables-history-number') }}</th>
|
||||||
<th>{{ $t('scenery.timetables-history-route')}}</th>
|
<th>{{ $t('scenery.timetables-history-route') }}</th>
|
||||||
<th>{{ $t('scenery.timetables-history-driver')}}</th>
|
<th>{{ $t('scenery.timetables-history-driver') }}</th>
|
||||||
<th>{{ $t('scenery.timetables-history-author')}}</th>
|
<th>{{ $t('scenery.timetables-history-author') }}</th>
|
||||||
<th>{{ $t('scenery.timetables-history-date')}}</th>
|
<th>{{ $t('scenery.timetables-history-date') }}</th>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="historyItem in sceneryHistoryList" @click="test">
|
<tr v-for="historyItem in historyList">
|
||||||
<td>
|
<td>
|
||||||
<router-link :to="`/journal/timetables?timetableId=${historyItem.id}`">#{{ historyItem.id }}</router-link>
|
<router-link :to="`/journal/timetables?timetableId=${historyItem.id}`">#{{ historyItem.id }}</router-link>
|
||||||
</td>
|
</td>
|
||||||
@@ -26,7 +27,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="historyItem.authorName"
|
v-if="historyItem.authorName"
|
||||||
:to="`/journal/dispatchers?dispatcherName=${historyItem.authorName}`"
|
:to="`/journal/timetables?authorName=${historyItem.authorName}`"
|
||||||
>{{ historyItem.authorName }}
|
>{{ historyItem.authorName }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<i v-else>{{ $t('scenery.timetable-author-unknown') }}</i>
|
<i v-else>{{ $t('scenery.timetable-author-unknown') }}</i>
|
||||||
@@ -38,34 +39,13 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</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>
|
</section>
|
||||||
|
|
||||||
|
<div class="bottom-info">
|
||||||
|
<button class="btn btn--option" v-if="historyList.length > 0" @click="navigateToHistory()">
|
||||||
|
{{ $t('scenery.bottom-info') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -77,40 +57,47 @@ import { TimetableHistory, SceneryTimetableHistory } from '../../scripts/interfa
|
|||||||
import Station from '../../scripts/interfaces/Station';
|
import Station from '../../scripts/interfaces/Station';
|
||||||
import { URLs } from '../../scripts/utils/apiURLs';
|
import { URLs } from '../../scripts/utils/apiURLs';
|
||||||
import Loading from '../Global/Loading.vue';
|
import Loading from '../Global/Loading.vue';
|
||||||
|
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SceneryTimetablesHistory',
|
name: 'SceneryTimetablesHistory',
|
||||||
mixins: [dateMixin],
|
mixins: [dateMixin, listObserverMixin],
|
||||||
props: {
|
props: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as PropType<Station>,
|
type: Object as PropType<Station>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
sceneryHistoryList: [] as TimetableHistory[],
|
historyList: [] as TimetableHistory[],
|
||||||
dataStatus: DataStatus.Loading,
|
dataStatus: DataStatus.Loading,
|
||||||
|
DataStatus,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
activated() {
|
|
||||||
this.fetchAPIData();
|
async activated() {
|
||||||
|
const fetchedHistory = await this.fetchAPIData();
|
||||||
|
if (fetchedHistory) this.historyList = fetchedHistory.timetables;
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async fetchAPIData(countFrom = 0, countLimit = 15) {
|
async fetchAPIData(countFrom = 0, countLimit = 15): Promise<SceneryTimetableHistory | null> {
|
||||||
try {
|
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;
|
const historyAPIData: SceneryTimetableHistory = await (await axios.get(requestString)).data;
|
||||||
|
|
||||||
this.sceneryHistoryList = historyAPIData.sceneryTimetables;
|
|
||||||
this.dataStatus = DataStatus.Loaded;
|
this.dataStatus = DataStatus.Loaded;
|
||||||
|
return historyAPIData;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
test() {
|
navigateToHistory() {
|
||||||
console.log('test');
|
this.$router.push(`/journal/timetables?issuedFrom=${this.station.name}`);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: { Loading },
|
components: { Loading },
|
||||||
@@ -119,46 +106,5 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
@import '../../styles/SceneryView/styles.scss';
|
@import '../../styles/sceneryViewTables.scss';
|
||||||
|
|
||||||
.list-warning {
|
|
||||||
padding: 1em 0.5em;
|
|
||||||
background-color: #444;
|
|
||||||
font-size: 1.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-list {
|
|
||||||
padding: 0 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
|
|
||||||
thead {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
background-color: #222222;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr {
|
|
||||||
background-color: #353535;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
padding: 0.75em;
|
|
||||||
border-bottom: solid 5px #111;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include smallScreen {
|
|
||||||
.list-item {
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,47 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="general-status">
|
<div class="general-status">
|
||||||
<span :class="scheduledTrain.stopStatus">
|
<span :class="computedScheduledTrain.stopStatus" :title="computedScheduledTrain.stopStatusDescription">
|
||||||
<span v-if="scheduledTrain.stopStatus == 'arriving'">
|
{{ computedScheduledTrain.stopStatusIndicator }}
|
||||||
<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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, PropType } from 'vue';
|
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({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -50,6 +22,58 @@ export default defineComponent({
|
|||||||
required: true,
|
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>
|
</script>
|
||||||
|
|
||||||
@@ -86,3 +110,4 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<button
|
<label @dblclick="handleDbClick">
|
||||||
class="btn--action"
|
<input v-model="option.value" type="checkbox" :class="option.section" :name="option.id" />
|
||||||
:class="option.section"
|
<span>
|
||||||
:data-selected="option.value"
|
{{ $t(`filters.${option.id}`) }}
|
||||||
@click="handleLeftClick"
|
</span>
|
||||||
@dblclick="handleDbClick"
|
</label>
|
||||||
>
|
|
||||||
{{ $t(`filters.${option.id}`) }}
|
|
||||||
</button>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -36,41 +33,24 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
watch: {
|
||||||
handleLeftClick() {
|
'option.value'() {
|
||||||
this.option.value = !this.option.value;
|
this.filterStore.changeFilterValue(this.option.name, !this.option.value);
|
||||||
this.filterStore.lastClickedFilterId = '';
|
|
||||||
|
|
||||||
this.filterStore.changeFilterValue({
|
|
||||||
name: this.option.name,
|
|
||||||
value: !this.option.value,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
handleDbClick(e: Event) {
|
handleDbClick(e: Event) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
|
||||||
const lastClicked = this.filterStore.lastClickedFilterId == this.option.id;
|
|
||||||
console.log(this.filterStore.lastClickedFilterId);
|
|
||||||
this.filterStore.lastClickedFilterId = this.option.id;
|
this.filterStore.lastClickedFilterId = this.option.id;
|
||||||
this.option.value = true;
|
this.option.value = true;
|
||||||
|
|
||||||
this.filterStore.changeFilterValue({
|
|
||||||
name: this.option.name,
|
|
||||||
value: !this.option.value,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.filterStore.inputs.options
|
this.filterStore.inputs.options
|
||||||
.filter((option) => {
|
.filter((option) => {
|
||||||
return option.section == this.option.section && option.id != this.option.id;
|
return option.section == this.option.section && option.id != this.option.id;
|
||||||
})
|
})
|
||||||
.forEach((option) => {
|
.forEach((option) => {
|
||||||
this.filterStore.changeFilterValue({
|
|
||||||
name: option.name,
|
|
||||||
value: this.option.value,
|
|
||||||
});
|
|
||||||
|
|
||||||
option.value = !this.option.value;
|
option.value = !this.option.value;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -79,68 +59,40 @@ export default defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
$realityCol: #e03b07;
|
@import '../../styles/variables.scss';
|
||||||
$accessCol: #e03b07;
|
|
||||||
$controlCol: #0085ff;
|
|
||||||
$signalCol: #bf7c00;
|
|
||||||
$statusCol: #349b32;
|
|
||||||
$saveCol: #28a826;
|
|
||||||
$routesCol: #9049c0;
|
|
||||||
|
|
||||||
button {
|
label {
|
||||||
padding: 0.25em;
|
position: relative;
|
||||||
border-radius: 0;
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
|
||||||
&:focus-visible {
|
span {
|
||||||
outline: 1px solid white;
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.25em;
|
||||||
|
background-color: #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-selected='true'] {
|
span:hover {
|
||||||
// &.reality {
|
background-color: #555;
|
||||||
// background-color: $realityCol;
|
}
|
||||||
// box-shadow: 0 0 6px 1px $realityCol;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// &.access {
|
input[type='checkbox'] {
|
||||||
// background-color: $accessCol;
|
cursor: pointer;
|
||||||
// box-shadow: 0 0 6px 1px $accessCol;
|
position: absolute;
|
||||||
// }
|
opacity: 0;
|
||||||
|
|
||||||
// &.control {
|
&:checked + span {
|
||||||
// background-color: $controlCol;
|
background-color: forestgreen;
|
||||||
// box-shadow: 0 0 6px 1px $controlCol;
|
font-weight: bold;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// &.signals {
|
&:focus-visible + span {
|
||||||
// background-color: $signalCol;
|
outline: 1px solid $accentCol;
|
||||||
// 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>
|
</style>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<button class="btn--filled btn--image" @click="toggleCard">
|
<button class="btn--filled btn--image" @click="toggleCard">
|
||||||
<img class="button_icon" :src="getIcon('filter2')" alt="filter icon" />
|
<img class="button_icon" :src="getIcon('filter2')" alt="filter icon" />
|
||||||
{{ $t('options.filters') }} [F]
|
{{ $t('options.filters') }} [F]
|
||||||
|
<span class="active-indicator" v-if="!filterStore.areFiltersAtDefault"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<label for="scenery-search">
|
<label for="scenery-search">
|
||||||
@@ -29,6 +30,22 @@
|
|||||||
<p class="card_info" v-html="$t('filters.desc')"></p>
|
<p class="card_info" v-html="$t('filters.desc')"></p>
|
||||||
|
|
||||||
<section class="card_options">
|
<section class="card_options">
|
||||||
|
<!-- QUICK ACTIONS (TODO) -->
|
||||||
|
<!-- <div class="quick-actions">
|
||||||
|
<h3 class="text--primary">{{ $t('filters.sections.quick') }}</h3>
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button class="btn--action" style="width: 100%" @click="filterStore.handleQuickAction('all-available')">
|
||||||
|
{{ $t('filters.all-available') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="btn--action" style="width: 100%" @click="filterStore.handleQuickAction('all-free')">
|
||||||
|
{{ $t('filters.all-free') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
<div class="option-section" v-for="section in filterStore.inputs.optionSections">
|
<div class="option-section" v-for="section in filterStore.inputs.optionSections">
|
||||||
<h3 class="text--primary">
|
<h3 class="text--primary">
|
||||||
{{ $t(`filters.sections.${section}`) }}
|
{{ $t(`filters.sections.${section}`) }}
|
||||||
@@ -39,7 +56,7 @@
|
|||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<div class="section-inputs">
|
<div class="section-inputs">
|
||||||
<filter-option
|
<FilterOption
|
||||||
v-for="(option, i) in filterStore.inputs.options.filter((o) => o.section == section)"
|
v-for="(option, i) in filterStore.inputs.options.filter((o) => o.section == section)"
|
||||||
:option="option"
|
:option="option"
|
||||||
:key="i"
|
:key="i"
|
||||||
@@ -128,7 +145,6 @@ import { useStore } from '../../store/store';
|
|||||||
|
|
||||||
import ActionButton from '../Global/ActionButton.vue';
|
import ActionButton from '../Global/ActionButton.vue';
|
||||||
import FilterOption from './FilterOption.vue';
|
import FilterOption from './FilterOption.vue';
|
||||||
import { filterInitStates } from '../../store/constants/initFilterStates';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { ActionButton, FilterOption },
|
components: { ActionButton, FilterOption },
|
||||||
@@ -177,6 +193,10 @@ export default defineComponent({
|
|||||||
.filter((s) => s.name.toLocaleLowerCase().includes(this.chosenSearchScenery.toLocaleLowerCase()))
|
.filter((s) => s.name.toLocaleLowerCase().includes(this.chosenSearchScenery.toLocaleLowerCase()))
|
||||||
.sort((s1, s2) => (s1.name > s2.name ? 1 : -1));
|
.sort((s1, s2) => (s1.name > s2.name ? 1 : -1));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
currentOptionsActive() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
@@ -205,10 +225,7 @@ export default defineComponent({
|
|||||||
handleInput(e: Event) {
|
handleInput(e: Event) {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
|
|
||||||
this.filterStore.changeFilterValue({
|
this.filterStore.changeFilterValue(target.name, target.value);
|
||||||
name: target.name,
|
|
||||||
value: target.value,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.saveOptions) StorageManager.setStringValue(target.name, target.value);
|
if (this.saveOptions) StorageManager.setStringValue(target.name, target.value);
|
||||||
},
|
},
|
||||||
@@ -222,11 +239,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
changeNumericFilterValue(name: string, value: number, saveToStorage = false) {
|
changeNumericFilterValue(name: string, value: number, saveToStorage = false) {
|
||||||
this.filterStore.changeFilterValue({
|
this.filterStore.changeFilterValue(name, value);
|
||||||
name,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.saveOptions && saveToStorage) StorageManager.setNumericValue(name, value);
|
if (this.saveOptions && saveToStorage) StorageManager.setNumericValue(name, value);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -427,33 +440,30 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card_options {
|
.option-section h3 {
|
||||||
.option-section h3 {
|
display: flex;
|
||||||
display: flex;
|
align-items: center;
|
||||||
align-items: center;
|
margin-bottom: 0.25em;
|
||||||
margin-bottom: 0.25em;
|
|
||||||
|
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
padding: 0.15em;
|
padding: 0.15em;
|
||||||
color: coral;
|
color: coral;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.section-inputs {
|
.section-inputs {
|
||||||
display: grid;
|
display: grid;
|
||||||
// flex-wrap: wrap;
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
gap: 0.5em;
|
||||||
// grid-template-rows: repeat(3, 1fr);
|
margin: 1em 0;
|
||||||
gap: 0.5em;
|
}
|
||||||
margin: 1em 0;
|
|
||||||
|
|
||||||
// @include smallScreen() {
|
.quick-actions div {
|
||||||
// grid-template-columns: repeat(auto-fit, minmax(8em, 1fr));
|
display: flex;
|
||||||
// grid-template-rows: auto;
|
margin: 1em 0;
|
||||||
// }
|
gap: 1em;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.slider {
|
.slider {
|
||||||
|
|||||||
@@ -1,33 +1,39 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="station_table">
|
<section class="station_table">
|
||||||
<button class="return-btn" @click="scrollToTop" v-if="showReturnButton">
|
|
||||||
<img :src="icons.arrow" alt="return arrow" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="table_wrapper">
|
<div class="table_wrapper">
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<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">
|
<span class="header_wrapper">
|
||||||
<div v-html="$t(`sceneries.${id}`)"></div>
|
<div v-html="$t(`sceneries.${headerName}`)"></div>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
class="sort-icon"
|
class="sort-icon"
|
||||||
v-if="sorterActive.index == i"
|
v-if="sorterActive.headerName == headerName"
|
||||||
:src="sorterActive.dir == 1 ? getIcon('arrow-asc') : getIcon('arrow-desc')"
|
:src="sorterActive.dir == 1 ? getIcon('arrow-asc') : getIcon('arrow-desc')"
|
||||||
alt="sort icon"
|
alt="sort icon"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</th>
|
</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">
|
<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
|
<img
|
||||||
class="sort-icon"
|
class="sort-icon"
|
||||||
v-if="sorterActive.index == i + 7"
|
v-if="sorterActive.headerName == headerName"
|
||||||
:src="sorterActive.dir == 1 ? getIcon('arrow-asc') : getIcon('arrow-desc')"
|
:src="sorterActive.dir == 1 ? getIcon('arrow-asc') : getIcon('arrow-desc')"
|
||||||
alt="sort icon"
|
alt="sort icon"
|
||||||
/>
|
/>
|
||||||
@@ -83,16 +89,11 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="station_status">
|
<td class="station_status">
|
||||||
<span class="status-badge" :class="station.onlineInfo.statusID" v-if="station.onlineInfo">
|
<StationStatusBadge
|
||||||
{{ $t(`status.${station.onlineInfo.statusID}`) }}
|
:statusID="station.onlineInfo?.statusID"
|
||||||
{{
|
:isOnline="station.onlineInfo ? true : false"
|
||||||
station.onlineInfo.statusID == 'online' ? timestampToString(station.onlineInfo.statusTimestamp) : ''
|
:statusTimestamp="station.onlineInfo?.statusTimestamp"
|
||||||
}}
|
/>
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="status-badge free" v-else>
|
|
||||||
{{ $t('status.free') }}
|
|
||||||
</span>
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="station_dispatcher-name">
|
<td class="station_dispatcher-name">
|
||||||
@@ -190,25 +191,31 @@
|
|||||||
|
|
||||||
<td class="station_users" :class="{ inactive: !station.onlineInfo }">
|
<td class="station_users" :class="{ inactive: !station.onlineInfo }">
|
||||||
<span>
|
<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>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="station_spawns" :class="{ inactive: !station.onlineInfo }">
|
<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>
|
||||||
|
|
||||||
<td class="station_schedules" :class="{ inactive: !station.onlineInfo }">
|
<td class="station_schedules" style="width: 30px" :class="{ inactive: !station.onlineInfo }">
|
||||||
<span>
|
<span class="highlight">
|
||||||
<span class="highlight">
|
{{ station.onlineInfo?.scheduledTrains?.length || 0 }}
|
||||||
{{ station.onlineInfo?.scheduledTrains?.length || '0' }}
|
</span>
|
||||||
</span>
|
</td>
|
||||||
/
|
|
||||||
<span style="color: #bbb">
|
<td class="station_schedules" style="width: 30px" :class="{ inactive: !station.onlineInfo }">
|
||||||
{{ station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed).length || '0' }}
|
<span style="color: #ccc">
|
||||||
</span>
|
{{ 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>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -236,6 +243,8 @@ import Station from '../../scripts/interfaces/Station';
|
|||||||
import { useStationFiltersStore } from '../../store/stationFiltersStore';
|
import { useStationFiltersStore } from '../../store/stationFiltersStore';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/store';
|
||||||
import Loading from '../Global/Loading.vue';
|
import Loading from '../Global/Loading.vue';
|
||||||
|
import { HeadIdsTypes, headIconsIds, headIds } from '../../scripts/data/stationHeaderNames';
|
||||||
|
import StationStatusBadge from '../Global/StationStatusBadge.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -245,12 +254,12 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
components: { Loading },
|
components: { Loading, StationStatusBadge },
|
||||||
mixins: [styleMixin, dateMixin, stationInfoMixin, returnBtnMixin, imageMixin],
|
mixins: [styleMixin, dateMixin, stationInfoMixin, returnBtnMixin, imageMixin],
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
headIds: ['station', 'min-lvl', 'status', 'dispatcher', 'dispatcher-lvl', 'routes', 'general'],
|
headIconsIds,
|
||||||
headIconsIds: ['user', 'spawn', 'timetable'],
|
headIds,
|
||||||
lastSelectedStationName: '',
|
lastSelectedStationName: '',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@@ -291,8 +300,10 @@ export default defineComponent({
|
|||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
},
|
},
|
||||||
|
|
||||||
changeSorter(i: number) {
|
changeSorter(headerName: HeadIdsTypes) {
|
||||||
this.stationFiltersStore.changeSorter(i);
|
if (headerName == 'general' || headerName == 'routes') return;
|
||||||
|
|
||||||
|
this.stationFiltersStore.changeSorter(headerName);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -349,9 +360,15 @@ table {
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
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;
|
background-color: $bgCol;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="train-info" tabindex="0">
|
<div class="train-info">
|
||||||
<section class="train-route">
|
<section class="train-route">
|
||||||
<div class="train_general">
|
<div class="train_general">
|
||||||
<b class="warning-timeout" v-if="train.isTimeout" :title="$t('trains.timeout')">?</b>
|
<b class="warning-timeout" v-if="train.isTimeout" :title="$t('trains.timeout')">?</b>
|
||||||
<span class="timetable-id" v-if="train.timetableData">#{{ train.timetableData.timetableId }}</span>
|
<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="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 twr" v-if="train.timetableData?.TWR" :title="$t('general.TWR')">TWR</span>
|
||||||
<span class="train-badge skr" v-if="train.timetableData?.SKR">SKR</span>
|
<span class="train-badge skr" v-if="train.timetableData?.SKR" :title="$t('general.SKR')">SKR</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<strong>
|
<strong>
|
||||||
@@ -41,13 +41,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="timetable_progress" style="margin-top: 0.5em" v-if="train.timetableData">
|
<div class="timetable_progress" style="margin-top: 0.5em" v-if="train.timetableData">
|
||||||
<span class="timetable_progress-bar">
|
<ProgressBar :progressPercent="confirmedPercentage(train.timetableData.followingStops)" />
|
||||||
<span class="bar-bg"></span>
|
|
||||||
<span
|
|
||||||
class="bar-fg"
|
|
||||||
:style="{ width: `${Math.floor(confirmedPercentage(train.timetableData.followingStops))}%` }"
|
|
||||||
></span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="timetable_progress-distance">
|
<span class="timetable_progress-distance">
|
||||||
{{ currentDistance(train.timetableData.followingStops) }} km /
|
{{ currentDistance(train.timetableData.followingStops) }} km /
|
||||||
@@ -96,6 +90,7 @@ import imageMixin from '../../mixins/imageMixin';
|
|||||||
import styleMixin from '../../mixins/styleMixin';
|
import styleMixin from '../../mixins/styleMixin';
|
||||||
import trainInfoMixin from '../../mixins/trainInfoMixin';
|
import trainInfoMixin from '../../mixins/trainInfoMixin';
|
||||||
import Train from '../../scripts/interfaces/Train';
|
import Train from '../../scripts/interfaces/Train';
|
||||||
|
import ProgressBar from '../Global/ProgressBar.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -103,14 +98,13 @@ export default defineComponent({
|
|||||||
type: Object as () => Train,
|
type: Object as () => Train,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
extended: {
|
extended: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [trainInfoMixin, imageMixin, styleMixin],
|
mixins: [trainInfoMixin, imageMixin, styleMixin],
|
||||||
|
components: { ProgressBar },
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -118,7 +112,6 @@ export default defineComponent({
|
|||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
@import '../../styles/badge.scss';
|
@import '../../styles/badge.scss';
|
||||||
|
|
||||||
|
|
||||||
.image-warning {
|
.image-warning {
|
||||||
height: 1em;
|
height: 1em;
|
||||||
|
|
||||||
@@ -182,26 +175,6 @@ export default defineComponent({
|
|||||||
gap: 0.25em;
|
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 {
|
.train-driver {
|
||||||
&.supporter {
|
&.supporter {
|
||||||
color: orange;
|
color: orange;
|
||||||
@@ -218,9 +191,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
.timetable_warnings {
|
.timetable_warnings {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.2em;
|
gap: 0.25em;
|
||||||
|
|
||||||
color: black;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.timetable_progress {
|
.timetable_progress {
|
||||||
@@ -229,31 +200,6 @@ export default defineComponent({
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timetable_progress-bar {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
width: 6em;
|
|
||||||
height: 1em;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
|
|
||||||
.bar-fg,
|
|
||||||
.bar-bg {
|
|
||||||
position: absolute;
|
|
||||||
height: 1em;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-fg {
|
|
||||||
background-color: springgreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-bg {
|
|
||||||
background-color: #5b5b5b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.timetable_progress-distance {
|
.timetable_progress-distance {
|
||||||
margin-right: 0.25em;
|
margin-right: 0.25em;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,10 +82,10 @@
|
|||||||
import { defineComponent, inject, PropType } from 'vue';
|
import { defineComponent, inject, PropType } from 'vue';
|
||||||
import imageMixin from '../../mixins/imageMixin';
|
import imageMixin from '../../mixins/imageMixin';
|
||||||
import keyMixin from '../../mixins/keyMixin';
|
import keyMixin from '../../mixins/keyMixin';
|
||||||
import { TrainFilter } from '../../types/Trains/TrainOptionsTypes';
|
|
||||||
import ActionButton from '../Global/ActionButton.vue';
|
import ActionButton from '../Global/ActionButton.vue';
|
||||||
import SelectBox from '../Global/SelectBox.vue';
|
import SelectBox from '../Global/SelectBox.vue';
|
||||||
import { TrainFilterSection } from '../../scripts/enums/TrainFilterType';
|
import { TrainFilterSection } from '../../scripts/enums/TrainFilterType';
|
||||||
|
import { TrainFilter } from '../../scripts/interfaces/Trains/TrainFilter';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { SelectBox, ActionButton },
|
components: { SelectBox, ActionButton },
|
||||||
|
|||||||
@@ -202,7 +202,6 @@ ul.stock-list {
|
|||||||
|
|
||||||
img {
|
img {
|
||||||
max-height: 60px;
|
max-height: 60px;
|
||||||
max-width: 320px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
class="train-row"
|
class="train-row"
|
||||||
v-for="train in currentTrains"
|
v-for="train in currentTrains"
|
||||||
:key="train.trainId"
|
:key="train.trainId"
|
||||||
@click.stop="selectModalTrain(train.trainId)"
|
tabindex="0"
|
||||||
@keydown.enter="selectModalTrain(train.trainId)"
|
@click.stop="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||||
|
@keydown.enter="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||||
>
|
>
|
||||||
<TrainInfo :train="train" />
|
<TrainInfo :train="train" />
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,28 +1,46 @@
|
|||||||
import { JournalFilterType } from "../../scripts/enums/JournalFilterType";
|
import { JournalFilterSection, JournalFilterType } from '../../scripts/enums/JournalFilterType';
|
||||||
import { JournalTimetableFilter } from "../../types/Journal/JournalTimetablesTypes";
|
import { JournalFilter } from '../../scripts/types/JournalTimetablesTypes';
|
||||||
|
|
||||||
export const journalTimetableFilters: JournalTimetableFilter[] = [
|
export const journalTimetableFilters: JournalFilter[] = [
|
||||||
{
|
{
|
||||||
id: JournalFilterType.all,
|
id: JournalFilterType.ALL,
|
||||||
filterSection: 'timetable-status',
|
filterSection: JournalFilterSection.TIMETABLE_STATUS,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: JournalFilterType.active,
|
id: JournalFilterType.ACTIVE,
|
||||||
filterSection: 'timetable-status',
|
filterSection: JournalFilterSection.TIMETABLE_STATUS,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: JournalFilterType.fulfilled,
|
id: JournalFilterType.FULFILLED,
|
||||||
filterSection: 'timetable-status',
|
filterSection: JournalFilterSection.TIMETABLE_STATUS,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: JournalFilterType.abandoned,
|
id: JournalFilterType.ABANDONED,
|
||||||
filterSection: 'timetable-status',
|
filterSection: JournalFilterSection.TIMETABLE_STATUS,
|
||||||
|
isActive: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: JournalFilterType.TWR_SKR,
|
||||||
|
filterSection: JournalFilterSection.TWRSKR,
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: JournalFilterType.TWR,
|
||||||
|
filterSection: JournalFilterSection.TWRSKR,
|
||||||
|
isActive: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: JournalFilterType.SKR,
|
||||||
|
filterSection: JournalFilterSection.TWRSKR,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TrainFilterSection, TrainFilterType } from '../../scripts/enums/TrainFilterType';
|
import { TrainFilterSection, TrainFilterType } from '../../scripts/enums/TrainFilterType';
|
||||||
import { TrainFilter } from '../../types/Trains/TrainOptionsTypes';
|
import { TrainFilter } from '../../scripts/interfaces/Trains/TrainFilter';
|
||||||
|
|
||||||
export const trainFilters: TrainFilter[] = [
|
export const trainFilters: TrainFilter[] = [
|
||||||
{
|
{
|
||||||
|
|||||||
+75
-20
@@ -1,7 +1,9 @@
|
|||||||
{
|
{
|
||||||
"general": {
|
"general": {
|
||||||
"and": " and ",
|
"and": " and ",
|
||||||
"refresh": "REFRESH"
|
"refresh": "REFRESH",
|
||||||
|
"TWR": "High risk freight train",
|
||||||
|
"SKR": "Train with exceeded gauge"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"sceneries": "SCENERIES",
|
"sceneries": "SCENERIES",
|
||||||
@@ -15,6 +17,9 @@
|
|||||||
"migration-confirm": "Roger that!",
|
"migration-confirm": "Roger that!",
|
||||||
"offline": "App is in the offline mode!"
|
"offline": "App is in the offline mode!"
|
||||||
},
|
},
|
||||||
|
"footer": {
|
||||||
|
"discord": "Stacjownik Discord server"
|
||||||
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"title": "New version of the app is available!",
|
"title": "New version of the app is available!",
|
||||||
"paragraph1": "Enjoy the application and may the green signal be with you!",
|
"paragraph1": "Enjoy the application and may the green signal be with you!",
|
||||||
@@ -94,19 +99,21 @@
|
|||||||
"search-dispatcher": "Dispatcher name",
|
"search-dispatcher": "Dispatcher name",
|
||||||
"search-station": "Scenery name",
|
"search-station": "Scenery name",
|
||||||
"search-author": "Timetable author name",
|
"search-author": "Timetable author name",
|
||||||
"search-timetables-date": "Timetable date (CEST / GMT+2)",
|
"search-issuedFrom": "Origin scenery name",
|
||||||
"search-dispatchers-date": "Service date (CEST / GMT+2)",
|
"search-timetables-date": "Timetable date (UTC+2 / CEST)",
|
||||||
|
"search-dispatchers-date": "Service date (UTC+2 / CEST)",
|
||||||
|
"search-date": "Date (UTC+2 / CEST)",
|
||||||
|
|
||||||
"sort-mass": "mass",
|
"sort-mass": "mass",
|
||||||
"sort-speed": "speed",
|
"sort-speed": "speed",
|
||||||
"sort-length": "length",
|
"sort-length": "length",
|
||||||
"sort-distance": "distance",
|
"sort-routeDistance": "route distance",
|
||||||
"sort-timetable": "train no.",
|
"sort-timetable": "train no.",
|
||||||
"sort-progress": "route progress",
|
"sort-progress": "route progress",
|
||||||
"sort-delay": "current delay",
|
"sort-delay": "current delay",
|
||||||
"sort-id": "timetable id",
|
"sort-id": "timetable id",
|
||||||
|
|
||||||
"sort-total-stops": "total stops",
|
"sort-allStopsCount": "total stops",
|
||||||
"sort-beginDate": "date",
|
"sort-beginDate": "date",
|
||||||
"sort-timetableId": "timetable ID",
|
"sort-timetableId": "timetable ID",
|
||||||
"sort-timestampFrom": "date",
|
"sort-timestampFrom": "date",
|
||||||
@@ -116,6 +123,7 @@
|
|||||||
"filter-withComments": "COMMENTS",
|
"filter-withComments": "COMMENTS",
|
||||||
"filter-twr": "HIGH RISK CARGO",
|
"filter-twr": "HIGH RISK CARGO",
|
||||||
"filter-skr": "EXCEEDED GAUGE",
|
"filter-skr": "EXCEEDED GAUGE",
|
||||||
|
"filter-twr-skr": "ALL TYPES",
|
||||||
"filter-common": "NO WARNINGS",
|
"filter-common": "NO WARNINGS",
|
||||||
"filter-passenger": "PASSENGER",
|
"filter-passenger": "PASSENGER",
|
||||||
"filter-freight": "FREIGHT",
|
"filter-freight": "FREIGHT",
|
||||||
@@ -126,6 +134,9 @@
|
|||||||
"filter-reset": "RESET FILTERS",
|
"filter-reset": "RESET FILTERS",
|
||||||
"filter-clear": "CLEAR FILTERS",
|
"filter-clear": "CLEAR FILTERS",
|
||||||
|
|
||||||
|
"filter-section-timetable-status": "TIMETABLE STATUS",
|
||||||
|
"filter-section-twrskr": "WARNINGS",
|
||||||
|
|
||||||
"filter-all": "ALL ENTRIES",
|
"filter-all": "ALL ENTRIES",
|
||||||
"filter-abandoned": "ABANDONED",
|
"filter-abandoned": "ABANDONED",
|
||||||
"filter-fulfilled": "FULFILLED",
|
"filter-fulfilled": "FULFILLED",
|
||||||
@@ -135,6 +146,7 @@
|
|||||||
"desc": " • Left mouse click: select / unselect chosen filter <br /> • Double left click: unselect all filters but chosen from a <b class='text--primary'>group</b> <br /> • <span style='color: coral'>RESET</span>: reset all filters from a <b class='text--primary'>group</b>",
|
"desc": " • Left mouse click: select / unselect chosen filter <br /> • Double left click: unselect all filters but chosen from a <b class='text--primary'>group</b> <br /> • <span style='color: coral'>RESET</span>: reset all filters from a <b class='text--primary'>group</b>",
|
||||||
|
|
||||||
"sections": {
|
"sections": {
|
||||||
|
"quick": "QUICK FILTERS",
|
||||||
"reality": "SCENERY REALITY",
|
"reality": "SCENERY REALITY",
|
||||||
"package-access": "IN-GAME AVAILABILITY",
|
"package-access": "IN-GAME AVAILABILITY",
|
||||||
"access": "GENERAL AVAILABILITY",
|
"access": "GENERAL AVAILABILITY",
|
||||||
@@ -145,6 +157,9 @@
|
|||||||
"status": "ONLINE STATUS"
|
"status": "ONLINE STATUS"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"all-available": "ALL AVAILABLE",
|
||||||
|
"all-free": "CURRENTLY FREE",
|
||||||
|
|
||||||
"endingStatus": "ENDS SOON",
|
"endingStatus": "ENDS SOON",
|
||||||
"afkStatus": "AFK",
|
"afkStatus": "AFK",
|
||||||
"noSpaceStatus": "NO SPACE",
|
"noSpaceStatus": "NO SPACE",
|
||||||
@@ -208,13 +223,15 @@
|
|||||||
"dispatcher-lvl": "Dispatcher\nlevel",
|
"dispatcher-lvl": "Dispatcher\nlevel",
|
||||||
"routes": "Routes\ndouble / single",
|
"routes": "Routes\ndouble / single",
|
||||||
"general": "General info",
|
"general": "General info",
|
||||||
"users": "Drivers online",
|
"user": "Drivers online",
|
||||||
"spawns": "Spawns online",
|
"spawn": "Spawns online",
|
||||||
"timetables": "Active timetables",
|
"timetableAll": "Active timetables",
|
||||||
|
"timetableConfirmed": "Confirmed timetables",
|
||||||
|
"timetableUnconfirmed": "Unconfirmed timetables",
|
||||||
"no-stations": "No stations to show here!",
|
"no-stations": "No stations to show here!",
|
||||||
"scenery-search": "Search for scenery..."
|
"scenery-search": "Search for scenery..."
|
||||||
},
|
},
|
||||||
"trains": {
|
"trains": {
|
||||||
"no-trains": "No trains to show here!",
|
"no-trains": "No trains to show here!",
|
||||||
"loading": "Loading train data...",
|
"loading": "Loading train data...",
|
||||||
"offline": "Offline ride",
|
"offline": "Offline ride",
|
||||||
@@ -261,6 +278,7 @@
|
|||||||
"title": "DISPATCHER HISTORY",
|
"title": "DISPATCHER HISTORY",
|
||||||
"loading": "Loading dispatcher history data...",
|
"loading": "Loading dispatcher history data...",
|
||||||
"no-history": "No dispatcher history found!",
|
"no-history": "No dispatcher history found!",
|
||||||
|
"data-refreshed-at": "Data refreshed at",
|
||||||
|
|
||||||
"section-timetables": "TIMETABLES",
|
"section-timetables": "TIMETABLES",
|
||||||
"section-dispatchers": "DISPATCHERS",
|
"section-dispatchers": "DISPATCHERS",
|
||||||
@@ -270,7 +288,7 @@
|
|||||||
|
|
||||||
"route-length": "Route length:",
|
"route-length": "Route length:",
|
||||||
"station-count": "Stations:",
|
"station-count": "Stations:",
|
||||||
"dispatcher-name": "Created by",
|
"dispatcher-name": "Author",
|
||||||
"timetable-day": "Timetable created at",
|
"timetable-day": "Timetable created at",
|
||||||
"timetable-active": "ACTIVE",
|
"timetable-active": "ACTIVE",
|
||||||
"timetable-fulfilled": "FULFILLED",
|
"timetable-fulfilled": "FULFILLED",
|
||||||
@@ -278,13 +296,15 @@
|
|||||||
|
|
||||||
"online-since": "ONLINE SINCE",
|
"online-since": "ONLINE SINCE",
|
||||||
"duty-lasted": "The duty lasted",
|
"duty-lasted": "The duty lasted",
|
||||||
"minutes": "{minutes} mins",
|
|
||||||
"hours": "{hours}h {minutes} mins",
|
"hours": "{value} hour | {value} hours",
|
||||||
|
"minutes": "{value} min | {value} mins",
|
||||||
|
"seconds": "{value} s",
|
||||||
|
|
||||||
"stock-info": "EXTRA INFO",
|
"stock-info": "EXTRA INFO",
|
||||||
"stock-length": "Length",
|
"stock-length": "Length",
|
||||||
"stock-mass": "Mass",
|
"stock-mass": "Mass",
|
||||||
"stock-max-speed": "Maximum registered speed",
|
"stock-max-speed": "Max. speed",
|
||||||
|
|
||||||
"load-data": "Load further data...",
|
"load-data": "Load further data...",
|
||||||
|
|
||||||
@@ -299,10 +319,13 @@
|
|||||||
"stats-distance": "DISTANCE",
|
"stats-distance": "DISTANCE",
|
||||||
"stats-stations": "STATIONS",
|
"stats-stations": "STATIONS",
|
||||||
|
|
||||||
"timetable-stats-total": "Today, dispatchers made so far {count} with total distance of {distance}",
|
"timetable-stats-title": "Daily stats on {date}",
|
||||||
"timetable-stats-longest": "The longest timetable today is #{id} made by {author} for {driver} - {distance}",
|
"timetable-stats-total": "Issued timetables: {count} (total distance: {distance})",
|
||||||
"timetable-stats-most-active": "The most active dispatcher today is {dispatcher} who created {count}",
|
"timetable-stats-longest": "The longest timetable: #{id} (made by {author} for {driver}, distance: {distance})",
|
||||||
"timetable-stats-most-active-many": "The most active dispatchers today are {dispatchers} who created {count} each",
|
"timetable-stats-most-active-dr": "The most active dispatcher: {dispatcher} (created {count})",
|
||||||
|
"timetable-stats-most-active-dr-many": "The most active dispatchers: {dispatchers} (created {count} each)",
|
||||||
|
"timetable-stats-most-active-driver": "The most active driver: {driver} (total driven distance: {distance})",
|
||||||
|
"timetable-stats-longest-duties": "The longest service: {dispatcher} at {station} (duration: {duration})",
|
||||||
|
|
||||||
"timetable-count": "timetable | timetables",
|
"timetable-count": "timetable | timetables",
|
||||||
|
|
||||||
@@ -313,7 +336,18 @@
|
|||||||
"driver-stats-info": "Enter a proper nickname into filters [F] to see user's driving statistics!",
|
"driver-stats-info": "Enter a proper nickname into filters [F] to see user's driving statistics!",
|
||||||
|
|
||||||
"stats-loading": "Fetching statistics...",
|
"stats-loading": "Fetching statistics...",
|
||||||
"stats-error": "Oops! An unexpected error occurred while trying to fetch statistics! :/"
|
"stats-error": "Oops! An unexpected error occurred while trying to fetch statistics! :/",
|
||||||
|
|
||||||
|
"timetable-location-signal": "signal:",
|
||||||
|
"timetable-location-route": "route:",
|
||||||
|
|
||||||
|
"history-name": "Scenery name",
|
||||||
|
"history-hash": "Hash",
|
||||||
|
"history-dispatcher": "Dispatcher",
|
||||||
|
"history-level": "Level",
|
||||||
|
"history-rate": "Rate",
|
||||||
|
"history-region": "Region",
|
||||||
|
"history-date": "Service date"
|
||||||
},
|
},
|
||||||
"scenery": {
|
"scenery": {
|
||||||
"users": "PLAYERS ONLINE",
|
"users": "PLAYERS ONLINE",
|
||||||
@@ -328,6 +362,7 @@
|
|||||||
"history-btn": "View the dispatcher history",
|
"history-btn": "View the dispatcher history",
|
||||||
"info-btn": "Return to the scenery view",
|
"info-btn": "Return to the scenery view",
|
||||||
"authors-title": "Scenery author | Scenery authors",
|
"authors-title": "Scenery author | Scenery authors",
|
||||||
|
"abbrev": "Station symbol:",
|
||||||
"lines-title": "Real lines",
|
"lines-title": "Real lines",
|
||||||
"project-title": "Project name",
|
"project-title": "Project name",
|
||||||
"one-way-routes": "One way routes",
|
"one-way-routes": "One way routes",
|
||||||
@@ -347,13 +382,21 @@
|
|||||||
"timetables-history-author": "TT author",
|
"timetables-history-author": "TT author",
|
||||||
"timetables-history-date": "Date",
|
"timetables-history-date": "Date",
|
||||||
|
|
||||||
|
"dispatchers-history-hash": "Hash",
|
||||||
|
"dispatchers-history-dispatcher": "Dispatcher",
|
||||||
|
"dispatchers-history-level": "Level",
|
||||||
|
"dispatchers-history-rate": "Rate",
|
||||||
|
"dispatchers-history-date": "Service date",
|
||||||
|
|
||||||
"req-level": "all dispatcher levels | dispatcher level {lvl} required | dispatcher level {lvl} required",
|
"req-level": "all dispatcher levels | dispatcher level {lvl} required | dispatcher level {lvl} required",
|
||||||
"history-list-empty": "No recorded scenery history!",
|
"history-list-empty": "No recorded scenery history!",
|
||||||
|
|
||||||
"forum-topic": "Official {name} forum topic",
|
"forum-topic": "Official {name} forum topic",
|
||||||
|
|
||||||
"pragotron-link": "Timetable pallet board (beta)",
|
"pragotron-link": "Timetable pallet board (beta)",
|
||||||
"tablice-link": "Timetable summary board (by Thundo)"
|
"tablice-link": "Timetable summary board (by Thundo)",
|
||||||
|
|
||||||
|
"bottom-info": "Show full history in the Journal tab"
|
||||||
},
|
},
|
||||||
"availability": {
|
"availability": {
|
||||||
"title": "Availability",
|
"title": "Availability",
|
||||||
@@ -368,7 +411,19 @@
|
|||||||
"end": "Timetable terminates here",
|
"end": "Timetable terminates here",
|
||||||
"terminated": "Timetable terminated",
|
"terminated": "Timetable terminated",
|
||||||
"begins": "BEGINS HERE",
|
"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": {
|
"history": {
|
||||||
"title": "TIMETABLE JOURNAL",
|
"title": "TIMETABLE JOURNAL",
|
||||||
|
|||||||
+73
-21
@@ -1,7 +1,9 @@
|
|||||||
{
|
{
|
||||||
"general": {
|
"general": {
|
||||||
"and": " oraz ",
|
"and": " oraz ",
|
||||||
"refresh": "ODŚWIEŻ"
|
"refresh": "ODŚWIEŻ",
|
||||||
|
"TWR": "Towar niebezpieczny wysokiego ryzyka",
|
||||||
|
"SKR": "Przekroczona skrajnia"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"sceneries": "SCENERIE",
|
"sceneries": "SCENERIE",
|
||||||
@@ -15,7 +17,9 @@
|
|||||||
"migration-confirm": "Przyjąłem!",
|
"migration-confirm": "Przyjąłem!",
|
||||||
"offline": "Aplikacja w trybie offline!"
|
"offline": "Aplikacja w trybie offline!"
|
||||||
},
|
},
|
||||||
|
"footer": {
|
||||||
|
"discord": "Serwer Discord Stacjownika"
|
||||||
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"title": "Nowa wersja Stacjownika jest dostępna!",
|
"title": "Nowa wersja Stacjownika jest dostępna!",
|
||||||
"paragraph1": "Miłego korzystania z aplikacji i niech S2 będzie z wami!",
|
"paragraph1": "Miłego korzystania z aplikacji i niech S2 będzie z wami!",
|
||||||
@@ -23,7 +27,6 @@
|
|||||||
"confirm-button": "ZAKTUALIZUJ",
|
"confirm-button": "ZAKTUALIZUJ",
|
||||||
"later-button": "PÓŹNIEJ"
|
"later-button": "PÓŹNIEJ"
|
||||||
},
|
},
|
||||||
|
|
||||||
"data-status": {
|
"data-status": {
|
||||||
"S1-offline": "<b>Sygnał S1</b> <br> Aplikacja działa w trybie offline!",
|
"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!",
|
"S1a-connection": "<b>Sygnał S1a</b> <br> Błąd podczas próby połączenia się z API Stacjownika!",
|
||||||
@@ -96,11 +99,13 @@
|
|||||||
"search-dispatcher": "Nick dyżurnego",
|
"search-dispatcher": "Nick dyżurnego",
|
||||||
"search-station": "Nazwa scenerii",
|
"search-station": "Nazwa scenerii",
|
||||||
"search-author": "Nick autora rozkładu jazdy",
|
"search-author": "Nick autora rozkładu jazdy",
|
||||||
"search-timetables-date": "Data rozkładu jazdy (czas polski)",
|
"search-issuedFrom": "Sceneria początkowa",
|
||||||
"search-dispatchers-date": "Data służby (czas polski)",
|
"search-timetables-date": "Data rozkładu jazdy (UTC+2 / CEST)",
|
||||||
|
"search-dispatchers-date": "Data służby (UTC+2 / CEST)",
|
||||||
|
"search-date": "Data (UTC+2 / CEST)",
|
||||||
|
|
||||||
"sort-distance": "kilometraż",
|
"sort-routeDistance": "kilometraż",
|
||||||
"sort-total-stops": "stacje",
|
"sort-allStopsCount": "stacje",
|
||||||
"sort-beginDate": "data",
|
"sort-beginDate": "data",
|
||||||
"sort-timetableId": "ID rozkładu",
|
"sort-timetableId": "ID rozkładu",
|
||||||
"sort-timestampFrom": "data",
|
"sort-timestampFrom": "data",
|
||||||
@@ -119,6 +124,7 @@
|
|||||||
"filter-noComments": "BEZ UWAG",
|
"filter-noComments": "BEZ UWAG",
|
||||||
"filter-twr": "WYS. RYZYKA",
|
"filter-twr": "WYS. RYZYKA",
|
||||||
"filter-skr": "SKRAJNIA",
|
"filter-skr": "SKRAJNIA",
|
||||||
|
"filter-twr-skr": "WSZYSTKIE",
|
||||||
"filter-common": "ZWYKŁE",
|
"filter-common": "ZWYKŁE",
|
||||||
"filter-passenger": "PASAŻERSKIE",
|
"filter-passenger": "PASAŻERSKIE",
|
||||||
"filter-freight": "TOWAROWE",
|
"filter-freight": "TOWAROWE",
|
||||||
@@ -129,6 +135,9 @@
|
|||||||
"filter-reset": "ZRESETUJ FILTRY",
|
"filter-reset": "ZRESETUJ FILTRY",
|
||||||
"filter-clear": "WYŁĄCZ FILTRY",
|
"filter-clear": "WYŁĄCZ FILTRY",
|
||||||
|
|
||||||
|
"filter-section-timetable-status": "STATUS ROZKŁADU JAZDY",
|
||||||
|
"filter-section-twrskr": "UWAGI",
|
||||||
|
|
||||||
"filter-all": "WSZYSTKIE",
|
"filter-all": "WSZYSTKIE",
|
||||||
"filter-abandoned": "PORZUCONE",
|
"filter-abandoned": "PORZUCONE",
|
||||||
"filter-fulfilled": "WYPEŁNIONE",
|
"filter-fulfilled": "WYPEŁNIONE",
|
||||||
@@ -138,6 +147,7 @@
|
|||||||
"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>",
|
"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": {
|
"sections": {
|
||||||
|
"quick": "SZYBKIE FILTRY",
|
||||||
"reality": "FIKCYJNOŚĆ SCENERII",
|
"reality": "FIKCYJNOŚĆ SCENERII",
|
||||||
"package-access": "DOSTĘPNOŚĆ W PACZCE",
|
"package-access": "DOSTĘPNOŚĆ W PACZCE",
|
||||||
"access": "DOSTĘPNOŚĆ OGÓLNA",
|
"access": "DOSTĘPNOŚĆ OGÓLNA",
|
||||||
@@ -148,6 +158,9 @@
|
|||||||
"status": "STATUS ONLINE"
|
"status": "STATUS ONLINE"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"all-available": "WSZYSTKIE DOSTĘPNE",
|
||||||
|
"all-free": "WSZYSTKIE WOLNE",
|
||||||
|
|
||||||
"endingStatus": "KOŃCZY",
|
"endingStatus": "KOŃCZY",
|
||||||
"afkStatus": "Z/W",
|
"afkStatus": "Z/W",
|
||||||
"noSpaceStatus": "BRAK MIEJSCA",
|
"noSpaceStatus": "BRAK MIEJSCA",
|
||||||
@@ -207,15 +220,18 @@
|
|||||||
},
|
},
|
||||||
"sceneries": {
|
"sceneries": {
|
||||||
"station": "Stacja",
|
"station": "Stacja",
|
||||||
|
"abbr": "Skrót\nposterunku",
|
||||||
"min-lvl": "Min. poziom\ndyżurnego",
|
"min-lvl": "Min. poziom\ndyżurnego",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"dispatcher": "Dyżurny",
|
"dispatcher": "Dyżurny",
|
||||||
"dispatcher-lvl": "Poziom\ndyżurnego",
|
"dispatcher-lvl": "Poziom\ndyżurnego",
|
||||||
"routes": "Szlaki\n2tor / 1tor",
|
"routes": "Szlaki\n2tor / 1tor",
|
||||||
"general": "Informacje\nogólne",
|
"general": "Informacje\nogólne",
|
||||||
"users": "Maszyniści online",
|
"user": "Maszyniści online",
|
||||||
"spawns": "Otwarte spawny",
|
"spawn": "Otwarte spawny",
|
||||||
"timetables": "Aktywne rozkłady jazdy",
|
"timetableAll": "Aktywne rozkłady jazdy",
|
||||||
|
"timetableConfirmed": "Zatwierdzone rozkłady jazdy",
|
||||||
|
"timetableUnconfirmed": "Niezatwierdzone rozkłady jazdy",
|
||||||
"no-stations": "Brak stacji do wyświetlenia!",
|
"no-stations": "Brak stacji do wyświetlenia!",
|
||||||
"scenery-search": "Wyszukaj scenerię..."
|
"scenery-search": "Wyszukaj scenerię..."
|
||||||
},
|
},
|
||||||
@@ -267,6 +283,7 @@
|
|||||||
"title": "HISTORIA DYŻURÓW",
|
"title": "HISTORIA DYŻURÓW",
|
||||||
"loading": "Ładowanie historii dyżurów...",
|
"loading": "Ładowanie historii dyżurów...",
|
||||||
"no-history": "Brak historii dyżurów dla tej scenerii!",
|
"no-history": "Brak historii dyżurów dla tej scenerii!",
|
||||||
|
"data-refreshed-at": "Dane odświeżone o",
|
||||||
|
|
||||||
"section-timetables": "ROZKŁADY JAZDY",
|
"section-timetables": "ROZKŁADY JAZDY",
|
||||||
"section-dispatchers": "DYŻURNI",
|
"section-dispatchers": "DYŻURNI",
|
||||||
@@ -276,12 +293,13 @@
|
|||||||
|
|
||||||
"online-since": "ONLINE OD",
|
"online-since": "ONLINE OD",
|
||||||
"duty-lasted": "Dyżur trwał",
|
"duty-lasted": "Dyżur trwał",
|
||||||
"minutes": "{minutes} min.",
|
"hours": "{value} godz.",
|
||||||
"hours": "{hours} godz. {minutes} min.",
|
"minutes": "{value} min.",
|
||||||
|
"seconds": "{value} sek.",
|
||||||
|
|
||||||
"route-length": "Kilometraż:",
|
"route-length": "Kilometraż:",
|
||||||
"station-count": "Stacje:",
|
"station-count": "Stacje:",
|
||||||
"dispatcher-name": "Wystawiony przez dyżurnego",
|
"dispatcher-name": "Autor",
|
||||||
"timetable-day": "Rozkład z dnia",
|
"timetable-day": "Rozkład z dnia",
|
||||||
"timetable-active": "AKTYWNY",
|
"timetable-active": "AKTYWNY",
|
||||||
"timetable-fulfilled": "WYPEŁNIONY",
|
"timetable-fulfilled": "WYPEŁNIONY",
|
||||||
@@ -290,7 +308,7 @@
|
|||||||
"stock-info": "DODATKOWE INFORMACJE",
|
"stock-info": "DODATKOWE INFORMACJE",
|
||||||
"stock-length": "Długość",
|
"stock-length": "Długość",
|
||||||
"stock-mass": "Masa",
|
"stock-mass": "Masa",
|
||||||
"stock-max-speed": "Maks. zarejestrowana prędkość",
|
"stock-max-speed": "Prędkość maks.",
|
||||||
|
|
||||||
"load-data": "Pobierz dalszą historię...",
|
"load-data": "Pobierz dalszą historię...",
|
||||||
|
|
||||||
@@ -305,10 +323,12 @@
|
|||||||
"stats-distance": "DYSTANS",
|
"stats-distance": "DYSTANS",
|
||||||
"stats-stations": "STACJE",
|
"stats-stations": "STACJE",
|
||||||
|
|
||||||
"timetable-stats-total": "Dyżurni stworzyli dziś {count} o łącznym dystansie {distance}",
|
"timetable-stats-total": "Stworzone rozkłady jazdy: {count} (łączny dystans: {distance})",
|
||||||
"timetable-stats-longest": "Najdłuższym rozkładem jazdy jest dzisiaj #{id} stworzony przez dyżurnego {author} dla maszynisty {driver} - {distance}",
|
"timetable-stats-longest": "Najdłuższy rozkład jazdy: #{id} (stworzony przez dyżurnego {author} dla maszynisty {driver} o dystansie {distance})",
|
||||||
"timetable-stats-most-active": "Dzisiejszym najaktywniejszym dyżurnym jest {dispatcher}, który stworzył {count}",
|
"timetable-stats-most-active-dr": "Najaktywniejszy dyżurny: {dispatcher} (stworzył {count})",
|
||||||
"timetable-stats-most-active-many": "Dzisiejszymi najaktywniejszymi dyżurnymi są {dispatchers}, którzy stworzyli po {count}",
|
"timetable-stats-most-active-dr-many": "Najaktywniejsi dyżurni: {dispatchers} (stworzyli po {count})",
|
||||||
|
"timetable-stats-most-active-driver": "Najaktywniejszy maszynista: {driver} (łączny przejechany dystans: {distance})",
|
||||||
|
"timetable-stats-longest-duties": "Najdłuższa służba: {dispatcher} na scenerii {station} (czas trwania: {duration})",
|
||||||
|
|
||||||
"timetable-count": "rozkład jazdy | rozkładów jazdy",
|
"timetable-count": "rozkład jazdy | rozkładów jazdy",
|
||||||
|
|
||||||
@@ -319,7 +339,18 @@
|
|||||||
"driver-stats-info": "Wpisz nazwę użytkownika w filtrach [F], aby zobaczyć jego statystyki maszynisty!",
|
"driver-stats-info": "Wpisz nazwę użytkownika w filtrach [F], aby zobaczyć jego statystyki maszynisty!",
|
||||||
|
|
||||||
"stats-loading": "Pobieranie statystyk...",
|
"stats-loading": "Pobieranie statystyk...",
|
||||||
"stats-error": "Ups! Wystąpił błąd podczas próby pobrania statystyk! :/"
|
"stats-error": "Ups! Wystąpił błąd podczas próby pobrania statystyk! :/",
|
||||||
|
|
||||||
|
"timetable-location-signal": "semafor:",
|
||||||
|
"timetable-location-route": "szlak:",
|
||||||
|
|
||||||
|
"history-name": "Sceneria",
|
||||||
|
"history-hash": "Hash",
|
||||||
|
"history-dispatcher": "Dyżurny",
|
||||||
|
"history-level": "Poziom",
|
||||||
|
"history-rate": "Ocena",
|
||||||
|
"history-region": "Region",
|
||||||
|
"history-date": "Data służby"
|
||||||
},
|
},
|
||||||
"scenery": {
|
"scenery": {
|
||||||
"users": "GRACZE ONLINE",
|
"users": "GRACZE ONLINE",
|
||||||
@@ -334,6 +365,7 @@
|
|||||||
"history-btn": "Przejdź do widoku historii dyżurnych ruchu",
|
"history-btn": "Przejdź do widoku historii dyżurnych ruchu",
|
||||||
"info-btn": "Wróć do widoku scenerii",
|
"info-btn": "Wróć do widoku scenerii",
|
||||||
"authors-title": "Autor scenerii | Autorzy scenerii",
|
"authors-title": "Autor scenerii | Autorzy scenerii",
|
||||||
|
"abbrev": "Skrót posterunku:",
|
||||||
"lines-title": "Rzeczywiste linie",
|
"lines-title": "Rzeczywiste linie",
|
||||||
"project-title": "Projekt",
|
"project-title": "Projekt",
|
||||||
"one-way-routes": "Szlaki jednotorowe",
|
"one-way-routes": "Szlaki jednotorowe",
|
||||||
@@ -353,13 +385,21 @@
|
|||||||
"timetables-history-author": "Autor RJ",
|
"timetables-history-author": "Autor RJ",
|
||||||
"timetables-history-date": "Data",
|
"timetables-history-date": "Data",
|
||||||
|
|
||||||
|
"dispatchers-history-hash": "Hash",
|
||||||
|
"dispatchers-history-dispatcher": "Dyżurny",
|
||||||
|
"dispatchers-history-level": "Poziom",
|
||||||
|
"dispatchers-history-rate": "Ocena",
|
||||||
|
"dispatchers-history-date": "Data służby",
|
||||||
|
|
||||||
"req-level": "ogólnodostępna | minimum {lvl} poziom dyżurnego | minimum {lvl} poziom dyżurnego",
|
"req-level": "ogólnodostępna | minimum {lvl} poziom dyżurnego | minimum {lvl} poziom dyżurnego",
|
||||||
"history-list-empty": "Brak historii dla tej scenerii!",
|
"history-list-empty": "Brak historii dla tej scenerii!",
|
||||||
|
|
||||||
"forum-topic": "Oficjalny wątek scenerii {name}",
|
"forum-topic": "Oficjalny wątek scenerii {name}",
|
||||||
|
|
||||||
"pragotron-link": "Paletowa tablica informacyjna (beta)",
|
"pragotron-link": "Paletowa tablica informacyjna (beta)",
|
||||||
"tablice-link": "Tablica informacyjna zbiorcza (autorstwa Thundo)"
|
"tablice-link": "Tablica informacyjna zbiorcza (autorstwa Thundo)",
|
||||||
|
|
||||||
|
"bottom-info": "Pokaż pełną historię w zakładce Dziennika"
|
||||||
},
|
},
|
||||||
"availability": {
|
"availability": {
|
||||||
"title": "Dostępność",
|
"title": "Dostępność",
|
||||||
@@ -374,7 +414,19 @@
|
|||||||
"end": "Koniec rozkładu jazdy",
|
"end": "Koniec rozkładu jazdy",
|
||||||
"terminated": "Rozkład jazdy zakończony",
|
"terminated": "Rozkład jazdy zakończony",
|
||||||
"begins": "ROZPOCZYNA\nBIEG",
|
"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": {
|
"history": {
|
||||||
"title": "DZIENNIK ROZKŁADÓW JAZDY"
|
"title": "DZIENNIK ROZKŁADÓW JAZDY"
|
||||||
|
|||||||
-10
@@ -7,7 +7,6 @@ import plLang from './locales/pl.json';
|
|||||||
|
|
||||||
import { createI18n } from 'vue-i18n';
|
import { createI18n } from 'vue-i18n';
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
import { registerSW } from 'virtual:pwa-register';
|
|
||||||
|
|
||||||
const i18n = createI18n({
|
const i18n = createI18n({
|
||||||
locale: 'pl',
|
locale: 'pl',
|
||||||
@@ -21,15 +20,6 @@ const i18n = createI18n({
|
|||||||
enableLegacy: false,
|
enableLegacy: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
registerSW({
|
|
||||||
onRegistered(r) {
|
|
||||||
r &&
|
|
||||||
setInterval(() => {
|
|
||||||
r.update();
|
|
||||||
}, 60 * 60 * 1000);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const clickOutsideDirective: Directive = {
|
const clickOutsideDirective: Directive = {
|
||||||
mounted(el, binding) {
|
mounted(el, binding) {
|
||||||
el.clickOutsideEvent = (event: Event) => {
|
el.clickOutsideEvent = (event: Event) => {
|
||||||
|
|||||||
+31
-4
@@ -21,6 +21,13 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
localeDateTime(dateString: string, locale: string) {
|
||||||
|
return new Date(dateString).toLocaleString(locale == 'pl' ? 'pl-PL' : 'en-GB', {
|
||||||
|
timeStyle: 'short',
|
||||||
|
dateStyle: 'medium'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
localeTime(dateString: string, locale: string) {
|
localeTime(dateString: string, locale: string) {
|
||||||
return new Date(dateString).toLocaleTimeString(locale == 'pl' ? 'pl-PL' : 'en-GB', {
|
return new Date(dateString).toLocaleTimeString(locale == 'pl' ? 'pl-PL' : 'en-GB', {
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
@@ -28,6 +35,19 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
stringToDate(dateString?: string) {
|
||||||
|
return dateString ? new Date(dateString) : null;
|
||||||
|
},
|
||||||
|
|
||||||
|
parseDateToTimeString(date: Date | null) {
|
||||||
|
return (
|
||||||
|
date?.toLocaleTimeString('pl-PL', {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
}) || ''
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
timestampToString(timestamp: number | null) {
|
timestampToString(timestamp: number | null) {
|
||||||
return timestamp
|
return timestamp
|
||||||
? new Date(timestamp).toLocaleTimeString('pl-PL', {
|
? new Date(timestamp).toLocaleTimeString('pl-PL', {
|
||||||
@@ -37,14 +57,21 @@ export default defineComponent({
|
|||||||
: '';
|
: '';
|
||||||
},
|
},
|
||||||
|
|
||||||
calculateDuration(timestampMs: number) {
|
calculateDuration(timestampMs: number, showSeconds = false) {
|
||||||
|
const secondsTotal = Math.floor(timestampMs / 1000);
|
||||||
const minsTotal = Math.round(timestampMs / 60000);
|
const minsTotal = Math.round(timestampMs / 60000);
|
||||||
const hoursTotal = Math.floor(minsTotal / 60);
|
const hoursTotal = Math.floor(minsTotal / 60);
|
||||||
const minsInHour = minsTotal % 60;
|
const minsInHour = minsTotal % 60;
|
||||||
|
|
||||||
return minsTotal > 60
|
return minsTotal >= 60
|
||||||
? this.$t('journal.hours', { hours: hoursTotal, minutes: minsInHour })
|
? `${this.$t('journal.hours', { value: hoursTotal }, hoursTotal)} ${this.$t(
|
||||||
: this.$t('journal.minutes', { minutes: minsTotal });
|
'journal.minutes',
|
||||||
|
{ value: minsInHour },
|
||||||
|
minsInHour
|
||||||
|
)}`
|
||||||
|
: showSeconds && secondsTotal <= 60
|
||||||
|
? this.$t('journal.seconds', { value: secondsTotal }, secondsTotal)
|
||||||
|
: this.$t('journal.minutes', { value: minsTotal }, minsTotal);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
data: () => ({
|
||||||
|
observer: null as IntersectionObserver | null,
|
||||||
|
observerTarget: null as Element | null,
|
||||||
|
}),
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
mountObserver(actionFunction: () => void, target: Element) {
|
||||||
|
this.observer = new IntersectionObserver((entries) => {
|
||||||
|
console.log(entries);
|
||||||
|
|
||||||
|
if (entries[0].intersectionRatio > 0.5) actionFunction();
|
||||||
|
}, { threshold: 0.2 });
|
||||||
|
|
||||||
|
this.observer.observe(target);
|
||||||
|
},
|
||||||
|
|
||||||
|
unmountObserver() {
|
||||||
|
if (!this.observerTarget) return;
|
||||||
|
|
||||||
|
this.observer?.unobserve(this.observerTarget);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { Ref, defineComponent } from 'vue';
|
||||||
import { useStore } from '../store/store';
|
import { useStore } from '../store/store';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@@ -15,15 +15,17 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
selectModalTrain(trainId: string) {
|
selectModalTrain(trainId: string, target?: EventTarget | null) {
|
||||||
this.store.chosenModalTrainId = trainId;
|
this.store.chosenModalTrainId = trainId;
|
||||||
document.body.classList.add('no-scroll');
|
document.body.classList.add('no-scroll');
|
||||||
|
if (target) this.store.modalLastClickedTarget = target;
|
||||||
},
|
},
|
||||||
|
|
||||||
closeModal() {
|
closeModal() {
|
||||||
this.store.chosenModalTrainId = undefined;
|
this.store.chosenModalTrainId = undefined;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
(this.store.modalLastClickedTarget as any)?.focus();
|
||||||
document.body.classList.remove('no-scroll');
|
document.body.classList.remove('no-scroll');
|
||||||
}, 150);
|
}, 150);
|
||||||
},
|
},
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import Filter from "../../scripts/interfaces/Filter";
|
import Filter from "../../interfaces/Filter";
|
||||||
|
|
||||||
export const filterInitStates: Filter = {
|
export const filterInitStates: Filter = {
|
||||||
default: false,
|
default: false,
|
||||||
@@ -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,6 +1,14 @@
|
|||||||
export const enum JournalFilterType {
|
export const enum JournalFilterType {
|
||||||
active = "active",
|
ACTIVE = 'active',
|
||||||
fulfilled = "fulfilled",
|
FULFILLED = 'fulfilled',
|
||||||
abandoned = "abandoned",
|
ABANDONED = 'abandoned',
|
||||||
all = "all"
|
ALL = 'all',
|
||||||
|
TWR = 'twr',
|
||||||
|
SKR = 'skr',
|
||||||
|
TWR_SKR = 'twr-skr',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum JournalFilterSection {
|
||||||
|
TIMETABLE_STATUS = 'timetable-status',
|
||||||
|
TWRSKR = 'twrskr',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,41 @@
|
|||||||
import TrainStop from "./TrainStop";
|
import TrainStop from './TrainStop';
|
||||||
|
|
||||||
export default interface ScheduledTrain {
|
export enum StopStatus {
|
||||||
trainId: string;
|
'arriving' = 'arriving',
|
||||||
trainNo: number;
|
'departed' = 'departed',
|
||||||
|
'departed-away' = 'departed-away',
|
||||||
driverName: string;
|
'online' = 'online',
|
||||||
driverId: number;
|
'stopped' = 'stopped',
|
||||||
currentStationName: string;
|
'terminated' = 'terminated',
|
||||||
currentStationHash: string;
|
}
|
||||||
category: string;
|
|
||||||
stopInfo: TrainStop;
|
export interface ScheduledTrain {
|
||||||
|
trainId: string;
|
||||||
terminatesAt: string;
|
trainNo: number;
|
||||||
beginsAt: string;
|
|
||||||
|
driverName: string;
|
||||||
prevStationName: string;
|
driverId: number;
|
||||||
nextStationName: string;
|
currentStationName: string;
|
||||||
|
currentStationHash: string;
|
||||||
arrivingLine: string | null;
|
category: string;
|
||||||
departureLine: string | null;
|
stopInfo: TrainStop;
|
||||||
|
|
||||||
prevDepartureLine: string | null;
|
terminatesAt: string;
|
||||||
nextArrivalLine: string | null;
|
beginsAt: string;
|
||||||
|
|
||||||
signal: string;
|
prevStationName: string;
|
||||||
connectedTrack: string;
|
nextStationName: string;
|
||||||
|
|
||||||
stopLabel: string;
|
arrivingLine: string | null;
|
||||||
stopStatus: string;
|
departureLine: string | null;
|
||||||
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 { Availability } from './store/storeTypes';
|
||||||
import ScheduledTrain from './ScheduledTrain';
|
import {ScheduledTrain} from './ScheduledTrain';
|
||||||
import StationRoutes from './StationRoutes';
|
import StationRoutes from './StationRoutes';
|
||||||
|
|
||||||
export default interface Station {
|
export default interface Station {
|
||||||
@@ -8,10 +8,12 @@ export default interface Station {
|
|||||||
generalInfo?: {
|
generalInfo?: {
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
|
abbr: string;
|
||||||
|
|
||||||
reqLevel: number;
|
reqLevel: number;
|
||||||
// supportersOnly: boolean;
|
// supportersOnly: boolean;
|
||||||
|
|
||||||
|
|
||||||
lines: string;
|
lines: string;
|
||||||
project: string;
|
project: string;
|
||||||
projectUrl?: string;
|
projectUrl?: string;
|
||||||
@@ -39,7 +41,7 @@ export default interface Station {
|
|||||||
maxUsers: number;
|
maxUsers: number;
|
||||||
currentUsers: number;
|
currentUsers: number;
|
||||||
|
|
||||||
spawns: { spawnName: string; spawnLength: number }[];
|
spawns: { spawnName: string; spawnLength: number; isElectrified: boolean }[];
|
||||||
dispatcherRate: number;
|
dispatcherRate: number;
|
||||||
dispatcherName: string;
|
dispatcherName: string;
|
||||||
dispatcherExp: number;
|
dispatcherExp: number;
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { TrainFilterSection, TrainFilterType } from '../../scripts/enums/TrainFilterType';
|
import { TrainFilterSection, TrainFilterType } from '../../enums/TrainFilterType'
|
||||||
|
|
||||||
export interface TrainFilter {
|
export interface TrainFilter {
|
||||||
id: TrainFilterType;
|
id: TrainFilterType;
|
||||||
@@ -7,6 +7,7 @@ export interface DispatcherHistory {
|
|||||||
dispatcherLevel: number | null;
|
dispatcherLevel: number | null;
|
||||||
dispatcherRate: number;
|
dispatcherRate: number;
|
||||||
dispatcherIsSupporter: boolean;
|
dispatcherIsSupporter: boolean;
|
||||||
|
dispatcherStatus?: number;
|
||||||
isOnline: boolean;
|
isOnline: boolean;
|
||||||
lastOnlineTimestamp: number;
|
lastOnlineTimestamp: number;
|
||||||
region: string;
|
region: string;
|
||||||
|
|||||||
@@ -14,6 +14,17 @@ export interface ITimetablesDailyStats {
|
|||||||
name: string;
|
name: string;
|
||||||
count: number;
|
count: number;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
|
mostActiveDrivers: {
|
||||||
|
name: string;
|
||||||
|
distance: number;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
longestDuties: {
|
||||||
|
name: string;
|
||||||
|
duration: number;
|
||||||
|
station: string;
|
||||||
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITimetablesDailyStatsResponse {
|
export interface ITimetablesDailyStatsResponse {
|
||||||
@@ -26,5 +37,16 @@ export interface ITimetablesDailyStatsResponse {
|
|||||||
name: string;
|
name: string;
|
||||||
count: number;
|
count: number;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
|
mostActiveDrivers: {
|
||||||
|
name: string;
|
||||||
|
distance: number;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
longestDuties: {
|
||||||
|
name: string;
|
||||||
|
duration: number;
|
||||||
|
station: string;
|
||||||
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export interface TimetableHistory {
|
|||||||
twr: number;
|
twr: number;
|
||||||
skr: number;
|
skr: number;
|
||||||
sceneriesString: string;
|
sceneriesString: string;
|
||||||
|
currentLocation: string[];
|
||||||
|
|
||||||
routeDistance: number;
|
routeDistance: number;
|
||||||
currentDistance: number;
|
currentDistance: number;
|
||||||
@@ -38,6 +39,8 @@ export interface TimetableHistory {
|
|||||||
stopsString?: string;
|
stopsString?: string;
|
||||||
|
|
||||||
stockString?: string;
|
stockString?: string;
|
||||||
|
stockHistory: string[];
|
||||||
|
|
||||||
stockMass?: number;
|
stockMass?: number;
|
||||||
stockLength?: number;
|
stockLength?: number;
|
||||||
maxSpeed?: number;
|
maxSpeed?: number;
|
||||||
@@ -45,10 +48,20 @@ export interface TimetableHistory {
|
|||||||
hashesString?: string;
|
hashesString?: string;
|
||||||
currentSceneryName?: string;
|
currentSceneryName?: string;
|
||||||
currentSceneryHash?: string;
|
currentSceneryHash?: string;
|
||||||
|
|
||||||
|
routeSceneries?: string;
|
||||||
|
|
||||||
|
checkpointArrivals?: string[];
|
||||||
|
checkpointDepartures?: string[];
|
||||||
|
|
||||||
|
checkpointArrivalsScheduled?: string[];
|
||||||
|
checkpointDeparturesScheduled?: string[];
|
||||||
|
|
||||||
|
checkpointStopTypes?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SceneryTimetableHistory {
|
export interface SceneryTimetableHistory {
|
||||||
sceneryTimetables: TimetableHistory[];
|
timetables: TimetableHistory[];
|
||||||
totalCount: number;
|
// totalCount: number;
|
||||||
sceneryName: string;
|
// sceneryName: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { JournalTimetableSorter } from '../../types/JournalTimetablesTypes';
|
||||||
|
|
||||||
|
export interface TimetablesQueryParams {
|
||||||
|
driverName?: string;
|
||||||
|
trainNo?: string;
|
||||||
|
timetableId?: string;
|
||||||
|
|
||||||
|
authorName?: string;
|
||||||
|
timestampFrom?: number;
|
||||||
|
timestampTo?: number;
|
||||||
|
issuedFrom?: string;
|
||||||
|
|
||||||
|
countFrom?: number;
|
||||||
|
countLimit?: number;
|
||||||
|
|
||||||
|
fulfilled?: number;
|
||||||
|
terminated?: number;
|
||||||
|
|
||||||
|
twr?: number;
|
||||||
|
skr?: number;
|
||||||
|
|
||||||
|
sortBy?: JournalTimetableSorter['id'];
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
import { Socket } from 'socket.io-client';
|
import { Socket } from 'socket.io-client';
|
||||||
import { DataStatus } from '../scripts/enums/DataStatus';
|
import { DataStatus } from '../../enums/DataStatus';
|
||||||
import StationAPIData from '../scripts/interfaces/api/StationAPIData';
|
import StationAPIData from '../api/StationAPIData';
|
||||||
import { TrainAPIData } from '../scripts/interfaces/api/TrainAPIData';
|
import { TrainAPIData } from '../api/TrainAPIData';
|
||||||
import Station from '../scripts/interfaces/Station';
|
import Station from '../Station';
|
||||||
import Train from '../scripts/interfaces/Train';
|
import Train from '../Train';
|
||||||
import { DispatcherStatsAPIData } from '../scripts/interfaces/api/DispatcherStatsAPIData';
|
import { DispatcherStatsAPIData } from '../api/DispatcherStatsAPIData';
|
||||||
import { DriverStatsAPIData } from '../scripts/interfaces/api/DriverStatsAPIData';
|
import { DriverStatsAPIData } from '../api/DriverStatsAPIData';
|
||||||
|
import { Ref } from 'vue';
|
||||||
|
|
||||||
export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault';
|
export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault';
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ export interface StoreState {
|
|||||||
|
|
||||||
chosenModalTrainId?: string;
|
chosenModalTrainId?: string;
|
||||||
|
|
||||||
currentStatsTab: 'daily' | 'driver';
|
currentStatsTab: 'daily' | 'driver' | null;
|
||||||
|
|
||||||
dataStatuses: {
|
dataStatuses: {
|
||||||
connection: DataStatus;
|
connection: DataStatus;
|
||||||
@@ -46,6 +47,7 @@ export interface StoreState {
|
|||||||
|
|
||||||
listenerLaunched: boolean;
|
listenerLaunched: boolean;
|
||||||
blockScroll: boolean;
|
blockScroll: boolean;
|
||||||
|
modalLastClickedTarget: EventTarget | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface APIData {
|
export interface APIData {
|
||||||
@@ -55,8 +57,19 @@ export interface APIData {
|
|||||||
connectedSocketCount: number;
|
connectedSocketCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface StationRoutesInfo {
|
||||||
|
routeName: string;
|
||||||
|
isElectric: boolean;
|
||||||
|
isInternal: boolean;
|
||||||
|
isRouteSBL: boolean;
|
||||||
|
routeLength: number;
|
||||||
|
routeSpeed: number;
|
||||||
|
routeTracks: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface StationJSONData {
|
export interface StationJSONData {
|
||||||
name: string;
|
name: string;
|
||||||
|
abbr: string;
|
||||||
url: string;
|
url: string;
|
||||||
lines: string;
|
lines: string;
|
||||||
project: string;
|
project: string;
|
||||||
@@ -69,7 +82,8 @@ export interface StationJSONData {
|
|||||||
|
|
||||||
SUP: boolean;
|
SUP: boolean;
|
||||||
|
|
||||||
routes: string;
|
// routes: string;
|
||||||
|
routesInfo: StationRoutesInfo[];
|
||||||
|
|
||||||
checkpoints: string | null;
|
checkpoints: string | null;
|
||||||
authors?: string;
|
authors?: string;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { TrainFilter } from '../../types/Trains/TrainOptionsTypes';
|
import { TrainFilter } from '../interfaces/Trains/TrainFilter';
|
||||||
import { TrainFilterType } from '../enums/TrainFilterType';
|
import { TrainFilterType } from '../enums/TrainFilterType';
|
||||||
import Train from '../interfaces/Train';
|
import Train from '../interfaces/Train';
|
||||||
import TrainStop from '../interfaces/TrainStop';
|
import TrainStop from '../interfaces/TrainStop';
|
||||||
@@ -44,7 +44,7 @@ function filterTrainList(trainList: Train[], searchedTrain: string, searchedDriv
|
|||||||
return !train.timetableData?.SKR;
|
return !train.timetableData?.SKR;
|
||||||
|
|
||||||
case TrainFilterType.common:
|
case TrainFilterType.common:
|
||||||
return train.timetableData?.SKR || train.timetableData?.TWR;
|
return train.timetableData?.SKR || train.timetableData?.TWR;
|
||||||
|
|
||||||
case TrainFilterType.passenger:
|
case TrainFilterType.passenger:
|
||||||
return !/^[AMRE]\D{2}$/.test(train.timetableData?.category || '');
|
return !/^[AMRE]\D{2}$/.test(train.timetableData?.category || '');
|
||||||
@@ -81,7 +81,7 @@ function sortTrainList(trainList: Train[], sorterActive: { id: string; dir: numb
|
|||||||
if (a.mass > b.mass) return sorterActive.dir;
|
if (a.mass > b.mass) return sorterActive.dir;
|
||||||
return -sorterActive.dir;
|
return -sorterActive.dir;
|
||||||
|
|
||||||
case 'distance':
|
case 'routeDistance':
|
||||||
if ((a.timetableData?.routeDistance || -1) > (b.timetableData?.routeDistance || -1)) return sorterActive.dir;
|
if ((a.timetableData?.routeDistance || -1) > (b.timetableData?.routeDistance || -1)) return sorterActive.dir;
|
||||||
|
|
||||||
return -sorterActive.dir;
|
return -sorterActive.dir;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { JournalFilterType } from '../../scripts/enums/JournalFilterType';
|
||||||
|
|
||||||
|
export type JournalTimetableSearchKey =
|
||||||
|
| 'search-driver'
|
||||||
|
| 'search-train'
|
||||||
|
| 'search-date'
|
||||||
|
| 'search-dispatcher'
|
||||||
|
| 'search-issuedFrom';
|
||||||
|
|
||||||
|
export type JournalTimetableSorterKey = 'timetableId' | 'beginDate' | 'distance' | 'total-stops';
|
||||||
|
|
||||||
|
export type JournalTimetableSearchType = {
|
||||||
|
[key in JournalTimetableSearchKey]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface JournalFilter {
|
||||||
|
id: JournalFilterType;
|
||||||
|
filterSection: string;
|
||||||
|
isActive: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JournalTimetableSorter {
|
||||||
|
id: JournalTimetableSorterKey;
|
||||||
|
dir: 'asc' | 'desc';
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
export const URLs = {
|
export const URLs = {
|
||||||
stacjownikAPI:
|
stacjownikAPI:
|
||||||
import.meta.env.VITE_APP_API_DEV == 1 && !import.meta.env.PROD
|
import.meta.env.VITE_APP_API_DEV == 1 && !import.meta.env.PROD
|
||||||
? 'http://localhost:3000'
|
? 'http://localhost:3001'
|
||||||
: 'https://spythere.pl',
|
: 'https://stacjownik.spythere.pl',
|
||||||
stacjownikAPIDev: 'localhost:3000',
|
stacjownikAPIDev: 'localhost:3000',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,57 +1,72 @@
|
|||||||
import Filter from '../../scripts/interfaces/Filter';
|
import { HeadIdsTypes } from '../data/stationHeaderNames';
|
||||||
import Station from '../../scripts/interfaces/Station';
|
import Filter from '../interfaces/Filter';
|
||||||
|
import Station from '../interfaces/Station';
|
||||||
|
|
||||||
export const sortStations = (a: Station, b: Station, sorter: { index: number; dir: number }) => {
|
export const sortStations = (a: Station, b: Station, sorter: { headerName: HeadIdsTypes; dir: number }) => {
|
||||||
switch (sorter.index) {
|
let diff = 0;
|
||||||
case 0:
|
|
||||||
|
switch (sorter.headerName) {
|
||||||
|
case 'station':
|
||||||
return sorter.dir == 1 ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name);
|
return sorter.dir == 1 ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name);
|
||||||
|
|
||||||
case 1:
|
case 'min-lvl':
|
||||||
if ((a.generalInfo?.reqLevel || 0) > (b.generalInfo?.reqLevel || 0)) return sorter.dir;
|
diff = (a.generalInfo?.reqLevel || 0) - (b.generalInfo?.reqLevel || 0);
|
||||||
if ((a.generalInfo?.reqLevel || 0) < (b.generalInfo?.reqLevel || 0)) return -sorter.dir;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 'status':
|
||||||
if ((a.onlineInfo?.statusTimestamp || 0) > (b.onlineInfo?.statusTimestamp || 0)) return sorter.dir;
|
diff = (a.onlineInfo?.statusTimestamp || 0) - (b.onlineInfo?.statusTimestamp || 0);
|
||||||
if ((a.onlineInfo?.statusTimestamp || 0) < (b.onlineInfo?.statusTimestamp || 0)) return -sorter.dir;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 'dispatcher':
|
||||||
if ((a.onlineInfo?.dispatcherName.toLowerCase() || '') > (b.onlineInfo?.dispatcherName.toLowerCase() || ''))
|
if ((a.onlineInfo?.dispatcherName.toLowerCase() || '') > (b.onlineInfo?.dispatcherName.toLowerCase() || ''))
|
||||||
return sorter.dir;
|
return sorter.dir;
|
||||||
if ((a.onlineInfo?.dispatcherName.toLowerCase() || '') < (b.onlineInfo?.dispatcherName.toLowerCase() || ''))
|
if ((a.onlineInfo?.dispatcherName.toLowerCase() || '') < (b.onlineInfo?.dispatcherName.toLowerCase() || ''))
|
||||||
return -sorter.dir;
|
return -sorter.dir;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 'dispatcher-lvl':
|
||||||
if ((a.onlineInfo?.dispatcherExp || 0) > (b.onlineInfo?.dispatcherExp || 0)) return sorter.dir;
|
diff = (a.onlineInfo?.dispatcherExp || 0) - (b.onlineInfo?.dispatcherExp || 0);
|
||||||
if ((a.onlineInfo?.dispatcherExp || 0) < (b.onlineInfo?.dispatcherExp || 0)) return -sorter.dir;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7:
|
case 'user':
|
||||||
if ((a.onlineInfo?.currentUsers || 0) > (b.onlineInfo?.currentUsers || 0)) return sorter.dir;
|
diff = (b.onlineInfo ? b.onlineInfo.currentUsers : -1) - (a.onlineInfo ? a.onlineInfo.currentUsers : -1);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 8:
|
case 'spawn':
|
||||||
if ((a.onlineInfo?.spawns.length || 0) > (b.onlineInfo?.spawns.length || 0)) return sorter.dir;
|
diff = (a.onlineInfo ? a.onlineInfo.spawns.length : -1) - (b.onlineInfo ? b.onlineInfo.spawns.length : -1);
|
||||||
if ((a.onlineInfo?.spawns.length || 0) < (b.onlineInfo?.spawns.length || 0)) return -sorter.dir;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 9:
|
case 'timetableConfirmed':
|
||||||
if ((a.onlineInfo?.scheduledTrains?.length || 0) > (b.onlineInfo?.scheduledTrains?.length || 0))
|
diff =
|
||||||
return sorter.dir;
|
(a.onlineInfo?.scheduledTrains
|
||||||
if ((a.onlineInfo?.scheduledTrains?.length || 0) < (b.onlineInfo?.scheduledTrains?.length || 0))
|
? a.onlineInfo.scheduledTrains.filter((train) => train.stopInfo.confirmed).length
|
||||||
return -sorter.dir;
|
: -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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (diff != 0) return Math.sign(diff) * sorter.dir;
|
||||||
return a.name.localeCompare(b.name);
|
return a.name.localeCompare(b.name);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import ScheduledTrain from '../interfaces/ScheduledTrain';
|
import { ScheduledTrain, StopStatus } from '../interfaces/ScheduledTrain';
|
||||||
import Train from '../interfaces/Train';
|
import Train from '../interfaces/Train';
|
||||||
import TrainStop from '../interfaces/TrainStop';
|
import TrainStop from '../interfaces/TrainStop';
|
||||||
|
|
||||||
@@ -66,40 +66,41 @@ export const parseSpawns = (spawnString: string) => {
|
|||||||
const spawnArray = spawn.split(',');
|
const spawnArray = spawn.split(',');
|
||||||
const spawnName = spawnArray[6] ? spawnArray[6] : spawnArray[0];
|
const spawnName = spawnArray[6] ? spawnArray[6] : spawnArray[0];
|
||||||
const spawnLength = parseInt(spawnArray[2]);
|
const spawnLength = parseInt(spawnArray[2]);
|
||||||
|
const isElectrified = spawnArray[3] == 'True';
|
||||||
|
|
||||||
return { spawnName, spawnLength };
|
return { spawnName, spawnLength, isElectrified };
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getTimestamp = (date: string | null): number => (date ? new Date(date).getTime() : 0);
|
export const getTimestamp = (date: string | null): number => (date ? new Date(date).getTime() : 0);
|
||||||
|
|
||||||
export const getTrainStopStatus = (stopInfo: TrainStop, currentStationName: string, stationName: string) => {
|
export const getTrainStopStatus = (stopInfo: TrainStop, currentStationName: string, stationName: string) => {
|
||||||
let stopStatus = '',
|
let stopStatus = StopStatus['arriving'],
|
||||||
stopLabel = '',
|
stopLabel = '',
|
||||||
stopStatusID = -1;
|
stopStatusID = -1;
|
||||||
|
|
||||||
if (stopInfo.terminatesHere && stopInfo.confirmed) {
|
if (stopInfo.terminatesHere && stopInfo.confirmed) {
|
||||||
stopStatus = 'terminated';
|
stopStatus = StopStatus['terminated'];
|
||||||
stopLabel = 'Skończył bieg';
|
stopLabel = 'Skończył bieg';
|
||||||
stopStatusID = 5;
|
stopStatusID = 5;
|
||||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == stationName) {
|
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == stationName) {
|
||||||
stopStatus = 'departed';
|
stopStatus = StopStatus['departed'];
|
||||||
stopLabel = 'Odprawiony';
|
stopLabel = 'Odprawiony';
|
||||||
stopStatusID = 2;
|
stopStatusID = 2;
|
||||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != stationName) {
|
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != stationName) {
|
||||||
stopStatus = 'departed-away';
|
stopStatus = StopStatus['departed-away'];
|
||||||
stopLabel = 'Odjechał';
|
stopLabel = 'Odjechał';
|
||||||
stopStatusID = 4;
|
stopStatusID = 4;
|
||||||
} else if (currentStationName == stationName && !stopInfo.stopped) {
|
} else if (currentStationName == stationName && !stopInfo.stopped) {
|
||||||
stopStatus = 'online';
|
stopStatus = StopStatus['online'];
|
||||||
stopLabel = 'Na stacji';
|
stopLabel = 'Na stacji';
|
||||||
stopStatusID = 0;
|
stopStatusID = 0;
|
||||||
} else if (currentStationName == stationName && stopInfo.stopped) {
|
} else if (currentStationName == stationName && stopInfo.stopped) {
|
||||||
stopStatus = 'stopped';
|
stopStatus = StopStatus['stopped'];
|
||||||
stopLabel = 'Postój';
|
stopLabel = 'Postój';
|
||||||
stopStatusID = 1;
|
stopStatusID = 1;
|
||||||
} else if (currentStationName != stationName) {
|
} else if (currentStationName != stationName) {
|
||||||
stopStatus = 'arriving';
|
stopStatus = StopStatus['arriving'];
|
||||||
stopLabel = 'W drodze';
|
stopLabel = 'W drodze';
|
||||||
stopStatusID = 3;
|
stopStatusID = 3;
|
||||||
}
|
}
|
||||||
@@ -122,7 +123,7 @@ export function getScheduledTrain(train: Train, trainStopIndex: number, stationN
|
|||||||
|
|
||||||
for (let i = trainStopIndex - 1; i >= 0; i--) {
|
for (let i = trainStopIndex - 1; i >= 0; i--) {
|
||||||
if (/strong|podg/g.test(followingStops[i].stopName)) {
|
if (/strong|podg/g.test(followingStops[i].stopName)) {
|
||||||
prevStationName = followingStops[i].stopNameRAW.replace(/,.*/g,"");
|
prevStationName = followingStops[i].stopNameRAW.replace(/,.*/g, '');
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -130,7 +131,7 @@ export function getScheduledTrain(train: Train, trainStopIndex: number, stationN
|
|||||||
|
|
||||||
for (let i = trainStopIndex + 1; i < followingStops.length; i++) {
|
for (let i = trainStopIndex + 1; i < followingStops.length; i++) {
|
||||||
if (/strong|podg/g.test(followingStops[i].stopName)) {
|
if (/strong|podg/g.test(followingStops[i].stopName)) {
|
||||||
nextStationName = followingStops[i].stopNameRAW.replace(/,.*/g,"");
|
nextStationName = followingStops[i].stopNameRAW.replace(/,.*/g, '');
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -172,7 +173,6 @@ export function getScheduledTrain(train: Train, trainStopIndex: number, stationN
|
|||||||
signal: train.signal,
|
signal: train.signal,
|
||||||
connectedTrack: train.connectedTrack,
|
connectedTrack: train.connectedTrack,
|
||||||
|
|
||||||
|
|
||||||
driverName: train.driverName,
|
driverName: train.driverName,
|
||||||
driverId: train.driverId,
|
driverId: train.driverId,
|
||||||
currentStationName: train.currentStationName,
|
currentStationName: train.currentStationName,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
export const useJournalFiltersStore = defineStore('journalFiltersStore', {
|
||||||
|
state: () => ({
|
||||||
|
timetableFilters: {
|
||||||
|
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import inputData from '../data/options.json';
|
import inputData from '../data/options.json';
|
||||||
import Filter from '../scripts/interfaces/Filter';
|
|
||||||
import Station from '../scripts/interfaces/Station';
|
import Station from '../scripts/interfaces/Station';
|
||||||
import StorageManager from '../scripts/managers/storageManager';
|
import StorageManager from '../scripts/managers/storageManager';
|
||||||
import { useStore } from './store';
|
import { useStore } from './store';
|
||||||
import { filterInitStates } from './constants/initFilterStates';
|
import { filterInitStates } from '../scripts/constants/stores/initFilterStates';
|
||||||
import { filterStations, sortStations } from './utils/filterUtils';
|
import { filterStations, sortStations } from '../scripts/utils/filterUtils';
|
||||||
|
import { HeadIdsTypes } from '../scripts/data/stationHeaderNames';
|
||||||
|
|
||||||
export const useStationFiltersStore = defineStore('stationFiltersStore', {
|
export const useStationFiltersStore = defineStore('stationFiltersStore', {
|
||||||
state() {
|
state() {
|
||||||
return {
|
return {
|
||||||
inputs: inputData,
|
inputs: inputData,
|
||||||
filters: { ...filterInitStates },
|
filters: { ...filterInitStates },
|
||||||
sorterActive: { index: 0, dir: 1 },
|
sorterActive: { headerName: 'station' as HeadIdsTypes, dir: 1 },
|
||||||
store: useStore(),
|
store: useStore(),
|
||||||
lastClickedFilterId: '',
|
lastClickedFilterId: '',
|
||||||
};
|
};
|
||||||
@@ -58,10 +58,29 @@ export const useStationFiltersStore = defineStore('stationFiltersStore', {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
changeFilterValue(filter: { name: string; value: any }) {
|
// Quick actions (TODO)
|
||||||
this.filters[filter.name] = filter.value;
|
handleQuickAction(actionName: string) {
|
||||||
|
// switch (actionName) {
|
||||||
|
// case 'all-available':
|
||||||
|
// this.resetFilters();
|
||||||
|
// this.inputs.options
|
||||||
|
// .filter((option) => /^(free|non-public)/.test(option.id))
|
||||||
|
// .forEach((option) => (option.value = !option.defaultValue));
|
||||||
|
// break;
|
||||||
|
// case 'all-free':
|
||||||
|
// this.resetFilters();
|
||||||
|
// this.inputs.options
|
||||||
|
// .filter((option) => /^(free|occupied)/.test(option.id))
|
||||||
|
// .forEach((option) => (option.value = !option.defaultValue));
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
|
||||||
if (StorageManager.isRegistered('options_saved')) StorageManager.setValue(filter.name, filter.value);
|
changeFilterValue(name: string, value: any) {
|
||||||
|
this.filters[name] = value;
|
||||||
|
if (StorageManager.isRegistered('options_saved')) StorageManager.setValue(name, value);
|
||||||
},
|
},
|
||||||
|
|
||||||
resetFilters() {
|
resetFilters() {
|
||||||
@@ -79,23 +98,19 @@ export const useStationFiltersStore = defineStore('stationFiltersStore', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
resetSectionOptions(section: string) {
|
resetSectionOptions(section: string) {
|
||||||
this.inputs.options.forEach((option) => {
|
this.inputs.options
|
||||||
if (option.section != section) return;
|
.filter((option) => option.section == section)
|
||||||
|
.forEach((option) => {
|
||||||
option.value = option.defaultValue;
|
option.value = option.defaultValue;
|
||||||
this.filters[option.id] = !option.defaultValue;
|
StorageManager.setBooleanValue(option.name, !option.defaultValue);
|
||||||
|
});
|
||||||
StorageManager.setBooleanValue(option.name, !option.defaultValue);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
changeSorter(index: number) {
|
changeSorter(headerName: HeadIdsTypes) {
|
||||||
if (index > 4 && index < 7) return;
|
if (headerName == this.sorterActive.headerName) this.sorterActive.dir = -1 * this.sorterActive.dir;
|
||||||
|
|
||||||
if (index == this.sorterActive.index) this.sorterActive.dir = -1 * this.sorterActive.dir;
|
|
||||||
else this.sorterActive.dir = 1;
|
else this.sorterActive.dir = 1;
|
||||||
|
|
||||||
this.sorterActive.index = index;
|
this.sorterActive.headerName = headerName;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
+34
-53
@@ -3,7 +3,7 @@ import { defineStore } from 'pinia';
|
|||||||
import { io } from 'socket.io-client';
|
import { io } from 'socket.io-client';
|
||||||
import { DataStatus } from '../scripts/enums/DataStatus';
|
import { DataStatus } from '../scripts/enums/DataStatus';
|
||||||
import StationAPIData from '../scripts/interfaces/api/StationAPIData';
|
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 Station from '../scripts/interfaces/Station';
|
||||||
import StationRoutes from '../scripts/interfaces/StationRoutes';
|
import StationRoutes from '../scripts/interfaces/StationRoutes';
|
||||||
import Train from '../scripts/interfaces/Train';
|
import Train from '../scripts/interfaces/Train';
|
||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
getScheduledTrain,
|
getScheduledTrain,
|
||||||
parseSpawns,
|
parseSpawns,
|
||||||
} from '../scripts/utils/storeUtils';
|
} from '../scripts/utils/storeUtils';
|
||||||
import { APIData, StationJSONData, StoreState } from './storeTypes';
|
import { APIData, StationJSONData, StoreState } from '../scripts/interfaces/store/storeTypes';
|
||||||
|
|
||||||
export const useStore = defineStore('store', {
|
export const useStore = defineStore('store', {
|
||||||
state: () =>
|
state: () =>
|
||||||
@@ -54,10 +54,11 @@ export const useStore = defineStore('store', {
|
|||||||
trains: DataStatus.Loading,
|
trains: DataStatus.Loading,
|
||||||
},
|
},
|
||||||
|
|
||||||
currentStatsTab: 'daily',
|
currentStatsTab: null,
|
||||||
|
|
||||||
blockScroll: false,
|
blockScroll: false,
|
||||||
listenerLaunched: false,
|
listenerLaunched: false,
|
||||||
|
modalLastClickedTarget: null
|
||||||
} as StoreState),
|
} as StoreState),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
@@ -286,9 +287,7 @@ export const useStore = defineStore('store', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async fetchStationsGeneralInfo() {
|
async fetchStationsGeneralInfo() {
|
||||||
const sceneryData: StationJSONData[] = await (
|
const sceneryData: StationJSONData[] = await (await axios.get(`${URLs.stacjownikAPI}/api/getSceneries`)).data;
|
||||||
await axios.get(`${URLs.stacjownikAPI}/api/getSceneries?timestamp=${Math.floor(Date.now() / 1800000)}`)
|
|
||||||
).data;
|
|
||||||
|
|
||||||
if (!sceneryData) {
|
if (!sceneryData) {
|
||||||
this.dataStatuses.sceneries = DataStatus.Error;
|
this.dataStatuses.sceneries = DataStatus.Error;
|
||||||
@@ -303,57 +302,39 @@ export const useStore = defineStore('store', {
|
|||||||
...scenery,
|
...scenery,
|
||||||
authors: scenery.authors?.split(',').map((a) => a.trim()),
|
authors: scenery.authors?.split(',').map((a) => a.trim()),
|
||||||
routes:
|
routes:
|
||||||
scenery.routes
|
scenery.routesInfo.reduce(
|
||||||
?.split(';')
|
(acc, route) => {
|
||||||
.filter((routeString) => routeString)
|
const propName: keyof StationRoutes = `${route.routeTracks == 2 ? 'twoWay' : 'oneWay'}${
|
||||||
.reduce(
|
route.isElectric ? '' : 'No'
|
||||||
(acc, routeString) => {
|
}CatenaryRouteNames`;
|
||||||
const specs1 = routeString.split('_')[0];
|
|
||||||
const isInternal = specs1.startsWith('!');
|
|
||||||
const name = isInternal ? specs1.replace('!', '') : specs1;
|
|
||||||
|
|
||||||
const specs2 = routeString.split('_')[1].split('');
|
acc[route.routeTracks == 2 ? 'twoWay' : 'oneWay'].push({
|
||||||
const twoWay = specs2[0] == '2';
|
name: route.routeName,
|
||||||
const catenary = specs2[1] == 'E';
|
SBL: route.isRouteSBL,
|
||||||
const SBL = specs2[2] == 'S';
|
TWB: false,
|
||||||
const TWB = specs2[3] ? true : false;
|
catenary: route.isElectric,
|
||||||
const speed = Number(routeString.split(':')[1]) || 0;
|
isInternal: route.isInternal,
|
||||||
const length = Number(routeString.split(':')[2]) || 0;
|
tracks: route.routeTracks,
|
||||||
|
length: route.routeLength,
|
||||||
|
speed: route.routeSpeed,
|
||||||
|
});
|
||||||
|
|
||||||
const propName = twoWay
|
if (!route.isInternal) acc[propName].push(route.routeName);
|
||||||
? catenary
|
|
||||||
? 'twoWayCatenaryRouteNames'
|
|
||||||
: 'twoWayNoCatenaryRouteNames'
|
|
||||||
: catenary
|
|
||||||
? 'oneWayCatenaryRouteNames'
|
|
||||||
: 'oneWayNoCatenaryRouteNames';
|
|
||||||
|
|
||||||
acc[twoWay ? 'twoWay' : 'oneWay'].push({
|
if (route.isRouteSBL) acc['sblRouteNames'].push(route.routeName);
|
||||||
name,
|
|
||||||
SBL,
|
|
||||||
TWB,
|
|
||||||
catenary,
|
|
||||||
isInternal,
|
|
||||||
tracks: twoWay ? 2 : 1,
|
|
||||||
length,
|
|
||||||
speed,
|
|
||||||
});
|
|
||||||
if (!isInternal) acc[propName].push(name);
|
|
||||||
|
|
||||||
if (SBL) acc['sblRouteNames'].push(name);
|
return acc;
|
||||||
|
},
|
||||||
return acc;
|
{
|
||||||
},
|
oneWay: [],
|
||||||
{
|
twoWay: [],
|
||||||
oneWay: [],
|
sblRouteNames: [],
|
||||||
twoWay: [],
|
oneWayCatenaryRouteNames: [],
|
||||||
sblRouteNames: [],
|
oneWayNoCatenaryRouteNames: [],
|
||||||
oneWayCatenaryRouteNames: [],
|
twoWayCatenaryRouteNames: [],
|
||||||
oneWayNoCatenaryRouteNames: [],
|
twoWayNoCatenaryRouteNames: [],
|
||||||
twoWayCatenaryRouteNames: [],
|
} as StationRoutes
|
||||||
twoWayNoCatenaryRouteNames: [],
|
) || {},
|
||||||
} as StationRoutes
|
|
||||||
) || {},
|
|
||||||
checkpoints: scenery.checkpoints
|
checkpoints: scenery.checkpoints
|
||||||
? scenery.checkpoints.split(';').map((sub) => ({ checkpointName: sub, scheduledTrains: [] }))
|
? scenery.checkpoints.split(';').map((sub) => ({ checkpointName: sub, scheduledTrains: [] }))
|
||||||
: [],
|
: [],
|
||||||
|
|||||||
@@ -23,6 +23,15 @@
|
|||||||
padding: 1em 0;
|
padding: 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.journal_refreshed-date {
|
||||||
|
background-color: #333;
|
||||||
|
color: #ddd;
|
||||||
|
text-align: end;
|
||||||
|
|
||||||
|
padding: 0.25em;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
.journal_warning {
|
.journal_warning {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
@@ -71,6 +80,10 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.journal_refreshed-date {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (orientation: landscape) {
|
@media (orientation: landscape) {
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
.scenery-section {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-warning {
|
|
||||||
padding: 1em 0.5em;
|
|
||||||
background-color: #444;
|
|
||||||
font-size: 1.2em;
|
|
||||||
}
|
|
||||||
+46
-5
@@ -4,12 +4,11 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
background: #585858;
|
|
||||||
|
|
||||||
margin: 0.25em;
|
margin: 0.25em;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
background: #585858;
|
||||||
padding: 0.2em 0.4em;
|
padding: 0.2em 0.4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +30,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 0.9em;
|
|
||||||
|
|
||||||
&.driver {
|
&.driver {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@@ -48,11 +46,54 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.region-badge {
|
.region-badge {
|
||||||
padding: 0 0.5em;
|
padding: 0.25em 0.5em;
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
color: white;
|
||||||
|
|
||||||
&.eu {
|
&[aria-describedby='eu'] {
|
||||||
background-color: forestgreen;
|
background-color: forestgreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&[aria-describedby='cae'] {
|
||||||
|
background-color: lightcoral;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[aria-describedby='usw'] {
|
||||||
|
background-color: lightblue;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[aria-describedby='us'] {
|
||||||
|
background-color: lightblue;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[aria-describedby='ru'] {
|
||||||
|
background-color: lightslategray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.offline {
|
||||||
|
background-color: #be3728;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,15 +11,6 @@
|
|||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-button .active-indicator {
|
|
||||||
width: 7px;
|
|
||||||
height: 7px;
|
|
||||||
background-color: lightgreen;
|
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1.option-title {
|
h1.option-title {
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
@@ -82,12 +73,16 @@ h1.option-title {
|
|||||||
padding: 0.25em 0.25em 0 0;
|
padding: 0.25em 0.25em 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.options_filter-sections section {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
.options_filters {
|
.options_filters {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
margin: 0.5em 0 0 0;
|
margin: 0.25em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sort-option,
|
.sort-option,
|
||||||
@@ -118,17 +113,6 @@ h1.option-title {
|
|||||||
margin: 0.5em auto;
|
margin: 0.5em auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search_actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5em;
|
|
||||||
margin: 1em 0;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-box {
|
.search-box {
|
||||||
.search-exit {
|
.search-exit {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -139,6 +123,17 @@ h1.option-title {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.options_actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5em;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 1em;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@include smallScreen() {
|
@include smallScreen() {
|
||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -155,13 +150,12 @@ h1.option-title {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-option,
|
|
||||||
.sort-option {
|
|
||||||
margin: 0.25em 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options_filters,
|
.options_filters,
|
||||||
.options_sorters {
|
.options_sorters {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-section {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,6 +138,15 @@ input {
|
|||||||
padding: 0.35em 0;
|
padding: 0.35em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.active-indicator {
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
background-color: lightgreen;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
.scenery-table-section {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.scenery-history-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
thead {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
background-color: #222222;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
background-color: #353535;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0.75em;
|
||||||
|
border-bottom: solid 5px #111;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-history {
|
||||||
|
padding: 1em 0.5em;
|
||||||
|
background-color: #444;
|
||||||
|
font-size: 1.2em;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
$free: #8a8a8a;
|
|
||||||
$ending: #e6c300;
|
|
||||||
$no-limit: #117fc9;
|
|
||||||
$unav: #ff3d5d;
|
|
||||||
$brb: #e6a100;
|
|
||||||
$no-space: #222;
|
|
||||||
$taken: #09a116;
|
|
||||||
$unknown: rgb(185, 60, 60);
|
|
||||||
|
|
||||||
.status-badge {
|
|
||||||
border-radius: 1rem;
|
|
||||||
font-weight: 500;
|
|
||||||
|
|
||||||
padding: 0.2em .55em;
|
|
||||||
|
|
||||||
background-color: $taken;
|
|
||||||
|
|
||||||
&.free {
|
|
||||||
background-color: $free;
|
|
||||||
font-size: 0.95em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.ending {
|
|
||||||
background-color: $ending;
|
|
||||||
color: black;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.no-limit {
|
|
||||||
background-color: $no-limit;
|
|
||||||
font-size: 0.85em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.not-signed,
|
|
||||||
&.unavailable {
|
|
||||||
background-color: $unav;
|
|
||||||
font-size: 0.85em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.brb {
|
|
||||||
background-color: $brb;
|
|
||||||
color: black;
|
|
||||||
font-size: 0.95em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.no-space {
|
|
||||||
background-color: $no-space;
|
|
||||||
color: white;
|
|
||||||
font-size: 0.85em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.unknown {
|
|
||||||
background-color: $unknown;
|
|
||||||
font-size: 0.95em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { JournalFilterType } from '../../scripts/enums/JournalFilterType';
|
|
||||||
|
|
||||||
export type JournalTimetableSearchKey = 'search-driver' | 'search-train' | 'search-date' | 'search-dispatcher';
|
|
||||||
|
|
||||||
export type JournalTimetableSearchType = {
|
|
||||||
[key in JournalTimetableSearchKey]: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface JournalTimetableFilter {
|
|
||||||
id: JournalFilterType;
|
|
||||||
filterSection: string;
|
|
||||||
isActive: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface JournalTimetableSorter {
|
|
||||||
id: 'timetableId' | 'beginDate' | 'distance' | 'total-stops';
|
|
||||||
dir: -1 | 1;
|
|
||||||
}
|
|
||||||
@@ -6,51 +6,25 @@
|
|||||||
<JournalOptions
|
<JournalOptions
|
||||||
@on-search-confirm="fetchHistoryData"
|
@on-search-confirm="fetchHistoryData"
|
||||||
@on-options-reset="resetOptions"
|
@on-options-reset="resetOptions"
|
||||||
@on-refresh-data="fetchHistoryData"
|
@on-refresh-data="fetchHistoryData(true)"
|
||||||
:sorter-option-ids="['timestampFrom', 'duration']"
|
:sorter-option-ids="['timestampFrom', 'duration']"
|
||||||
:data-status="dataStatus"
|
:data-status="dataStatus"
|
||||||
:current-options-active="currentOptionsActive"
|
:current-options-active="currentOptionsActive"
|
||||||
optionsType="dispatchers"
|
optionsType="dispatchers"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div class="journal_refreshed-date" v-if="dataRefreshedAt">
|
||||||
|
{{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="list_wrapper" @scroll="handleScroll">
|
<div class="list_wrapper" @scroll="handleScroll">
|
||||||
<transition name="status-anim" mode="out-in">
|
<JournalDispatchersList
|
||||||
<div :key="dataStatus">
|
:dispatcherHistory="computedHistoryList"
|
||||||
<div class="journal_warning" v-if="store.isOffline">
|
:addHistoryData="addHistoryData"
|
||||||
{{ $t('app.offline') }}
|
:dataStatus="dataStatus"
|
||||||
</div>
|
:scrollDataLoaded="scrollDataLoaded"
|
||||||
|
:scrollNoMoreData="scrollNoMoreData"
|
||||||
<Loading v-else-if="dataStatus == DataStatus.Loading" />
|
/>
|
||||||
|
|
||||||
<div v-else-if="dataStatus == DataStatus.Error" class="journal_warning error">
|
|
||||||
{{ $t('app.error') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="journal_warning" v-else-if="historyList.length == 0">
|
|
||||||
{{ $t('app.no-result') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else>
|
|
||||||
<JournalDispatchersList :dispatcherHistory="computedHistoryList" />
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="btn btn--option btn--load-data"
|
|
||||||
v-if="!scrollNoMoreData && scrollDataLoaded && computedHistoryList.length > 15"
|
|
||||||
@click="addHistoryData"
|
|
||||||
>
|
|
||||||
{{ $t('journal.load-data') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
|
|
||||||
<div class="journal_warning" v-if="scrollNoMoreData">
|
|
||||||
{{ $t('journal.no-further-data') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="journal_warning" v-else-if="!scrollDataLoaded">
|
|
||||||
{{ $t('journal.loading-further-data') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -70,7 +44,7 @@ import { URLs } from '../scripts/utils/apiURLs';
|
|||||||
import { DataStatus } from '../scripts/enums/DataStatus';
|
import { DataStatus } from '../scripts/enums/DataStatus';
|
||||||
import { useStore } from '../store/store';
|
import { useStore } from '../store/store';
|
||||||
import JournalDispatchersList from '../components/JournalView/JournalDispatchersList.vue';
|
import JournalDispatchersList from '../components/JournalView/JournalDispatchersList.vue';
|
||||||
import { JournalDispatcherSearcher, JournalDispatcherSorter } from '../types/Journal/JournalDispatcherTypes';
|
import { JournalDispatcherSearcher, JournalDispatcherSorter } from '../scripts/types/JournalDispatcherTypes';
|
||||||
import { DispatcherHistory } from '../scripts/interfaces/api/DispatchersAPIData';
|
import { DispatcherHistory } from '../scripts/interfaces/api/DispatchersAPIData';
|
||||||
import JournalHeader from '../components/JournalView/JournalHeader.vue';
|
import JournalHeader from '../components/JournalView/JournalHeader.vue';
|
||||||
import { LocationQuery } from 'vue-router';
|
import { LocationQuery } from 'vue-router';
|
||||||
@@ -104,6 +78,7 @@ export default defineComponent({
|
|||||||
data: () => ({
|
data: () => ({
|
||||||
currentQuery: '',
|
currentQuery: '',
|
||||||
currentQueryArray: [] as string[],
|
currentQueryArray: [] as string[],
|
||||||
|
dataRefreshedAt: null as Date | null,
|
||||||
|
|
||||||
scrollDataLoaded: true,
|
scrollDataLoaded: true,
|
||||||
scrollNoMoreData: false,
|
scrollNoMoreData: false,
|
||||||
@@ -134,6 +109,7 @@ export default defineComponent({
|
|||||||
provide('sorterActive', sorterActive);
|
provide('sorterActive', sorterActive);
|
||||||
provide('journalFilterActive', journalFilterActive);
|
provide('journalFilterActive', journalFilterActive);
|
||||||
provide('searchersValues', searchersValues);
|
provide('searchersValues', searchersValues);
|
||||||
|
provide('filterList', reactive([]));
|
||||||
|
|
||||||
const scrollElement: Ref<HTMLElement | null> = ref(null);
|
const scrollElement: Ref<HTMLElement | null> = ref(null);
|
||||||
|
|
||||||
@@ -188,8 +164,10 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleQueries(query: LocationQuery) {
|
handleQueries(query: LocationQuery) {
|
||||||
if ('sceneryName' in query) this.searchersValues['search-station'] = `${query.sceneryName}`;
|
const queryKeys = Object.keys(query);
|
||||||
if ('dispatcherName' in query) this.searchersValues['search-dispatcher'] = `${query.dispatcherName}`;
|
|
||||||
|
if (queryKeys.includes('sceneryName')) this.setSearchers('', `${query.sceneryName}`, '');
|
||||||
|
if (queryKeys.includes('dispatcherName')) this.setSearchers('', '', `${query.dispatcherName}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
setSearchers(date: string, station: string, dispatcher: string) {
|
setSearchers(date: string, station: string, dispatcher: string) {
|
||||||
@@ -208,10 +186,10 @@ export default defineComponent({
|
|||||||
async addHistoryData() {
|
async addHistoryData() {
|
||||||
this.scrollDataLoaded = false;
|
this.scrollDataLoaded = false;
|
||||||
|
|
||||||
const countFrom = this.historyList.length;
|
this.countFromIndex = this.historyList.length;
|
||||||
|
|
||||||
const responseData: DispatcherHistory[] = await (
|
const responseData: DispatcherHistory[] = await (
|
||||||
await axios.get(`${DISPATCHERS_API_URL}?${this.currentQuery}&countFrom=${countFrom}`)
|
await axios.get(`${DISPATCHERS_API_URL}?${this.currentQuery}&countFrom=${this.countFromIndex}`)
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
if (!responseData) return;
|
if (!responseData) return;
|
||||||
@@ -225,7 +203,7 @@ export default defineComponent({
|
|||||||
this.scrollDataLoaded = true;
|
this.scrollDataLoaded = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetchHistoryData() {
|
async fetchHistoryData(reset = false) {
|
||||||
const queries: string[] = [];
|
const queries: string[] = [];
|
||||||
|
|
||||||
const dispatcher = this.searchersValues['search-dispatcher'].trim();
|
const dispatcher = this.searchersValues['search-dispatcher'].trim();
|
||||||
@@ -239,7 +217,7 @@ export default defineComponent({
|
|||||||
if (station) queries.push(`stationName=${station}`);
|
if (station) queries.push(`stationName=${station}`);
|
||||||
if (timestampFrom && timestampTo) queries.push(`timestampFrom=${timestampFrom}`, `timestampTo=${timestampTo}`);
|
if (timestampFrom && timestampTo) queries.push(`timestampFrom=${timestampFrom}`, `timestampTo=${timestampTo}`);
|
||||||
|
|
||||||
// Z API: const SORT_TYPES = ['allStopsCount', 'endDate', 'beginDate', 'routeDistance'];
|
// API: const SORT_TYPES = ['allStopsCount', 'endDate', 'beginDate', 'routeDistance'];
|
||||||
if (this.sorterActive.id == 'timestampFrom') queries.push('sortBy=timestampFrom');
|
if (this.sorterActive.id == 'timestampFrom') queries.push('sortBy=timestampFrom');
|
||||||
else if (this.sorterActive.id == 'duration') queries.push('sortBy=currentDuration');
|
else if (this.sorterActive.id == 'duration') queries.push('sortBy=currentDuration');
|
||||||
else queries.push('sortBy=timestampFrom');
|
else queries.push('sortBy=timestampFrom');
|
||||||
@@ -252,6 +230,8 @@ export default defineComponent({
|
|||||||
this.currentQueryArray = queries;
|
this.currentQueryArray = queries;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (reset) this.dataStatus = DataStatus.Loading;
|
||||||
|
|
||||||
const responseData: DispatcherHistory[] = await (
|
const responseData: DispatcherHistory[] = await (
|
||||||
await axios.get(`${DISPATCHERS_API_URL}?${this.currentQuery}`)
|
await axios.get(`${DISPATCHERS_API_URL}?${this.currentQuery}`)
|
||||||
).data;
|
).data;
|
||||||
@@ -272,6 +252,7 @@ export default defineComponent({
|
|||||||
? this.historyList[0].dispatcherName
|
? this.historyList[0].dispatcherName
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
|
this.dataRefreshedAt = new Date();
|
||||||
this.dataStatus = DataStatus.Loaded;
|
this.dataStatus = DataStatus.Loaded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.dataStatus = DataStatus.Error;
|
this.dataStatus = DataStatus.Error;
|
||||||
@@ -287,4 +268,3 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../styles/JournalSection.scss';
|
@import '../styles/JournalSection.scss';
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
+120
-97
@@ -7,7 +7,7 @@
|
|||||||
@on-search-confirm="fetchHistoryData"
|
@on-search-confirm="fetchHistoryData"
|
||||||
@on-options-reset="resetOptions"
|
@on-options-reset="resetOptions"
|
||||||
@on-refresh-data="fetchHistoryData"
|
@on-refresh-data="fetchHistoryData"
|
||||||
:sorter-option-ids="['timetableId', 'beginDate', 'distance', 'total-stops']"
|
:sorter-option-ids="['timetableId', 'beginDate', 'routeDistance', 'allStopsCount']"
|
||||||
:filters="journalTimetableFilters"
|
:filters="journalTimetableFilters"
|
||||||
:currentOptionsActive="currentOptionsActive"
|
:currentOptionsActive="currentOptionsActive"
|
||||||
:data-status="dataStatus"
|
:data-status="dataStatus"
|
||||||
@@ -16,39 +16,18 @@
|
|||||||
|
|
||||||
<JournalStats />
|
<JournalStats />
|
||||||
|
|
||||||
|
<div class="journal_refreshed-date" v-if="dataRefreshedAt">
|
||||||
|
{{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="list_wrapper" @scroll="handleScroll">
|
<div class="list_wrapper" @scroll="handleScroll">
|
||||||
<transition name="status-anim" mode="out-in">
|
<JournalTimetablesList
|
||||||
<div :key="dataStatus">
|
:timetableHistory="timetableHistory"
|
||||||
<div class="journal_warning" v-if="store.isOffline">
|
:addHistoryData="addHistoryData"
|
||||||
{{ $t('app.offline') }}
|
:dataStatus="dataStatus"
|
||||||
</div>
|
:scrollDataLoaded="scrollDataLoaded"
|
||||||
|
:scrollNoMoreData="scrollNoMoreData"
|
||||||
<Loading v-else-if="dataStatus == DataStatus.Loading" />
|
/>
|
||||||
|
|
||||||
<div v-else-if="dataStatus == DataStatus.Error" class="journal_warning error">
|
|
||||||
{{ $t('app.error') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else-if="timetableHistory.length == 0" class="journal_warning">
|
|
||||||
{{ $t('app.no-result') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else>
|
|
||||||
<JournalTimetablesList :timetableHistory="timetableHistory" />
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="btn btn--option btn--load-data"
|
|
||||||
v-if="!scrollNoMoreData && scrollDataLoaded && timetableHistory.length >= 15"
|
|
||||||
@click="addHistoryData"
|
|
||||||
>
|
|
||||||
{{ $t('journal.load-data') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
|
|
||||||
<div class="journal_warning" v-if="scrollNoMoreData">{{ $t('journal.no-further-data') }}</div>
|
|
||||||
<div class="journal_warning" v-else-if="!scrollDataLoaded">{{ $t('journal.loading-further-data') }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -58,25 +37,32 @@
|
|||||||
import { defineComponent, provide, reactive, Ref, ref } from 'vue';
|
import { defineComponent, provide, reactive, Ref, ref } from 'vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
import DriverStats from '../components/JournalView/JournalDriverStats.vue';
|
import imageMixin from '../mixins/imageMixin';
|
||||||
import Loading from '../components/Global/Loading.vue';
|
|
||||||
import { JournalTimetableSorter } from '../types/Journal/JournalTimetablesTypes';
|
|
||||||
import dateMixin from '../mixins/dateMixin';
|
import dateMixin from '../mixins/dateMixin';
|
||||||
import routerMixin from '../mixins/routerMixin';
|
import routerMixin from '../mixins/routerMixin';
|
||||||
|
import modalTrainMixin from '../mixins/modalTrainMixin';
|
||||||
|
|
||||||
|
import DriverStats from '../components/JournalView/JournalDriverStats.vue';
|
||||||
|
import JournalOptions from '../components/JournalView/JournalOptions.vue';
|
||||||
|
import JournalStats from '../components/JournalView/JournalStats.vue';
|
||||||
|
import JournalHeader from '../components/JournalView/JournalHeader.vue';
|
||||||
|
import JournalTimetablesList from '../components/JournalView/JournalTimetablesList.vue';
|
||||||
|
import Loading from '../components/Global/Loading.vue';
|
||||||
|
|
||||||
import { DataStatus } from '../scripts/enums/DataStatus';
|
import { DataStatus } from '../scripts/enums/DataStatus';
|
||||||
import { JournalFilterType } from '../scripts/enums/JournalFilterType';
|
|
||||||
import { TimetableHistory } from '../scripts/interfaces/api/TimetablesAPIData';
|
import { TimetableHistory } from '../scripts/interfaces/api/TimetablesAPIData';
|
||||||
import { URLs } from '../scripts/utils/apiURLs';
|
import { URLs } from '../scripts/utils/apiURLs';
|
||||||
import { useStore } from '../store/store';
|
import { useStore } from '../store/store';
|
||||||
import JournalOptions from '../components/JournalView/JournalOptions.vue';
|
|
||||||
import { JournalTimetableSearchType } from '../types/Journal/JournalTimetablesTypes';
|
|
||||||
import modalTrainMixin from '../mixins/modalTrainMixin';
|
|
||||||
import imageMixin from '../mixins/imageMixin';
|
|
||||||
import JournalTimetablesList from '../components/JournalView/JournalTimetablesList.vue';
|
|
||||||
import { journalTimetableFilters } from '../constants/Journal/JournalTimetablesConsts';
|
|
||||||
import JournalStats from '../components/JournalView/JournalStats.vue';
|
|
||||||
import JournalHeader from '../components/JournalView/JournalHeader.vue';
|
|
||||||
import { LocationQuery } from 'vue-router';
|
import { LocationQuery } from 'vue-router';
|
||||||
|
import { TimetablesQueryParams } from '../scripts/interfaces/api/TimetablesQueryParams';
|
||||||
|
import { JournalFilterType } from '../scripts/enums/JournalFilterType';
|
||||||
|
import {
|
||||||
|
JournalFilter,
|
||||||
|
JournalTimetableSearchType,
|
||||||
|
JournalTimetableSorter,
|
||||||
|
} from '../scripts/types/JournalTimetablesTypes';
|
||||||
|
import { journalTimetableFilters } from '../constants/Journal/JournalTimetablesConsts';
|
||||||
|
|
||||||
const TIMETABLES_API_URL = `${URLs.stacjownikAPI}/api/getTimetables`;
|
const TIMETABLES_API_URL = `${URLs.stacjownikAPI}/api/getTimetables`;
|
||||||
|
|
||||||
@@ -93,8 +79,8 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
currentQuery: '',
|
currentQueryParams: {} as TimetablesQueryParams,
|
||||||
currentQueryArray: [] as string[],
|
dataRefreshedAt: null as Date | null,
|
||||||
|
|
||||||
scrollDataLoaded: true,
|
scrollDataLoaded: true,
|
||||||
scrollNoMoreData: false,
|
scrollNoMoreData: false,
|
||||||
@@ -113,13 +99,16 @@ export default defineComponent({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
const sorterActive: JournalTimetableSorter = reactive({ id: 'timetableId', dir: 1 });
|
const sorterActive: JournalTimetableSorter = reactive({ id: 'timetableId', dir: 'desc' });
|
||||||
const journalFilterActive = ref(journalTimetableFilters[0]);
|
// const journalFilterActive = ref(journalTimetableFilters[0]);
|
||||||
|
const initFilters: readonly JournalFilter[] = JSON.parse(JSON.stringify(journalTimetableFilters));
|
||||||
|
const filterList: JournalFilter[] = reactive(JSON.parse(JSON.stringify(initFilters)));
|
||||||
|
|
||||||
const searchersValues = reactive({
|
const searchersValues = reactive({
|
||||||
'search-train': '',
|
'search-train': '',
|
||||||
'search-driver': '',
|
'search-driver': '',
|
||||||
'search-dispatcher': '',
|
'search-dispatcher': '',
|
||||||
|
'search-issuedFrom': '',
|
||||||
'search-date': '',
|
'search-date': '',
|
||||||
} as JournalTimetableSearchType);
|
} as JournalTimetableSearchType);
|
||||||
|
|
||||||
@@ -128,14 +117,15 @@ export default defineComponent({
|
|||||||
|
|
||||||
provide('searchersValues', searchersValues);
|
provide('searchersValues', searchersValues);
|
||||||
provide('sorterActive', sorterActive);
|
provide('sorterActive', sorterActive);
|
||||||
provide('journalFilterActive', journalFilterActive);
|
provide('filterList', filterList);
|
||||||
|
|
||||||
const scrollElement: Ref<HTMLElement | null> = ref(null);
|
const scrollElement: Ref<HTMLElement | null> = ref(null);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sorterActive,
|
sorterActive,
|
||||||
journalFilterActive,
|
|
||||||
searchersValues,
|
searchersValues,
|
||||||
|
filterList,
|
||||||
|
initFilters,
|
||||||
|
|
||||||
countFromIndex,
|
countFromIndex,
|
||||||
countLimit,
|
countLimit,
|
||||||
@@ -147,8 +137,8 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
currentQueryArray(q: string[]) {
|
currentQueryParams(q: TimetablesQueryParams) {
|
||||||
this.currentOptionsActive = q.length >= 2 || q.some((qv) => qv.startsWith('sortBy=') && qv.split('=')[1]);
|
this.currentOptionsActive = Object.values(q).some((v) => v !== undefined);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -163,7 +153,6 @@ export default defineComponent({
|
|||||||
this.fetchHistoryData();
|
this.fetchHistoryData();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
handleScroll(e: Event) {
|
handleScroll(e: Event) {
|
||||||
const listElement = e.target as HTMLElement;
|
const listElement = e.target as HTMLElement;
|
||||||
@@ -176,32 +165,42 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleQueries(query: LocationQuery) {
|
handleQueries(query: LocationQuery) {
|
||||||
if ('timetableId' in query) this.searchersValues['search-train'] = `#${query.timetableId}`;
|
const queryKeys = Object.keys(query);
|
||||||
|
|
||||||
|
if (queryKeys.includes('timetableId')) this.setSearchers('', '', `#${query.timetableId}`, '', '');
|
||||||
|
if (queryKeys.includes('issuedFrom')) this.setSearchers('', '', '', '', `${query.issuedFrom}`);
|
||||||
|
if (queryKeys.includes('authorName')) this.setSearchers('', '', '', `${query.authorName}`, '');
|
||||||
},
|
},
|
||||||
|
|
||||||
setSearchers(date: string, driver: string, train: string, dispatcher: string) {
|
setSearchers(date: string, driver: string, train: string, dispatcher: string, issuedFrom: string) {
|
||||||
this.searchersValues['search-date'] = date;
|
this.searchersValues['search-date'] = date;
|
||||||
this.searchersValues['search-driver'] = driver;
|
this.searchersValues['search-driver'] = driver;
|
||||||
this.searchersValues['search-train'] = train;
|
this.searchersValues['search-train'] = train;
|
||||||
this.searchersValues['search-dispatcher'] = dispatcher;
|
this.searchersValues['search-dispatcher'] = dispatcher;
|
||||||
|
this.searchersValues['search-issuedFrom'] = issuedFrom;
|
||||||
},
|
},
|
||||||
|
|
||||||
resetOptions() {
|
resetOptions() {
|
||||||
this.setSearchers('', '', '', '');
|
this.setSearchers('', '', '', '', '');
|
||||||
|
|
||||||
this.journalFilterActive = this.journalTimetableFilters[0];
|
|
||||||
this.sorterActive.id = 'timetableId';
|
this.sorterActive.id = 'timetableId';
|
||||||
|
|
||||||
|
this.filterList.forEach(
|
||||||
|
(f) => (f.isActive = this.initFilters.find((initFilter) => initFilter.id == f.id)?.isActive || false)
|
||||||
|
);
|
||||||
|
|
||||||
this.fetchHistoryData();
|
this.fetchHistoryData();
|
||||||
},
|
},
|
||||||
|
|
||||||
async addHistoryData() {
|
async addHistoryData() {
|
||||||
this.scrollDataLoaded = false;
|
this.scrollDataLoaded = false;
|
||||||
|
|
||||||
const countFrom = this.timetableHistory.length;
|
this.currentQueryParams['countFrom'] = this.timetableHistory.length;
|
||||||
|
|
||||||
const responseData: TimetableHistory[] = await (
|
const responseData: TimetableHistory[] = await (
|
||||||
await axios.get(`${TIMETABLES_API_URL}?${this.currentQuery}&countFrom=${countFrom}`)
|
await axios.get(`${TIMETABLES_API_URL}`, {
|
||||||
|
params: { ...this.currentQueryParams },
|
||||||
|
})
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
if (!responseData) return;
|
if (!responseData) return;
|
||||||
@@ -216,57 +215,81 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
async fetchHistoryData() {
|
async fetchHistoryData() {
|
||||||
// if(this.dataStatus == DataStatus.Loading) return;
|
const driverName = this.searchersValues['search-driver'].trim() || undefined;
|
||||||
|
const trainNo = this.searchersValues['search-train'].trim() || undefined;
|
||||||
const queries: string[] = [];
|
const authorName = this.searchersValues['search-dispatcher'].trim() || undefined;
|
||||||
|
const dateString = this.searchersValues['search-date'].trim() || undefined;
|
||||||
const driverName = this.searchersValues['search-driver'].trim();
|
const issuedFrom = this.searchersValues['search-issuedFrom'].trim() || undefined;
|
||||||
const trainNo = this.searchersValues['search-train'].trim();
|
|
||||||
const authorName = this.searchersValues['search-dispatcher'].trim();
|
|
||||||
const dateString = this.searchersValues['search-date'].trim();
|
|
||||||
|
|
||||||
const timestampFrom = dateString ? Date.parse(new Date(dateString).toISOString()) - 120 * 60 * 1000 : undefined;
|
const timestampFrom = dateString ? Date.parse(new Date(dateString).toISOString()) - 120 * 60 * 1000 : undefined;
|
||||||
const timestampTo = timestampFrom ? timestampFrom + 86400000 : undefined;
|
const timestampTo = timestampFrom ? timestampFrom + 86400000 : undefined;
|
||||||
|
|
||||||
if (driverName) queries.push(`driverName=${driverName}`);
|
const queryParams: TimetablesQueryParams = {};
|
||||||
if (trainNo)
|
|
||||||
queries.push(trainNo.startsWith('#') ? `timetableId=${trainNo.replace('#', '')}` : `trainNo=${trainNo}`);
|
|
||||||
if (authorName) queries.push(`authorName=${authorName}`);
|
|
||||||
if (timestampFrom && timestampTo) queries.push(`timestampFrom=${timestampFrom}`, `timestampTo=${timestampTo}`);
|
|
||||||
|
|
||||||
// Z API: const SORT_TYPES = ['allStopsCount', 'endDate', 'beginDate', 'routeDistance'];
|
this.filterList
|
||||||
if (this.sorterActive.id == 'distance') queries.push('sortBy=routeDistance');
|
.filter((f) => f.isActive)
|
||||||
else if (this.sorterActive.id == 'total-stops') queries.push('sortBy=allStopsCount');
|
.forEach((f) => {
|
||||||
else if (this.sorterActive.id == 'beginDate') queries.push('sortBy=beginDate');
|
switch (f.id) {
|
||||||
// else queries.push('sortBy=timetableId');
|
case JournalFilterType.ABANDONED:
|
||||||
|
queryParams['fulfilled'] = 0;
|
||||||
|
queryParams['terminated'] = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
queries.push('countLimit=15');
|
case JournalFilterType.ACTIVE:
|
||||||
|
queryParams['fulfilled'] = undefined;
|
||||||
|
queryParams['terminated'] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
switch (this.journalFilterActive.id) {
|
case JournalFilterType.FULFILLED:
|
||||||
case JournalFilterType.abandoned:
|
queryParams['terminated'] = undefined;
|
||||||
queries.push('fulfilled=0', 'terminated=1');
|
queryParams['fulfilled'] = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JournalFilterType.active:
|
case JournalFilterType.ALL:
|
||||||
queries.push('terminated=0');
|
queryParams['terminated'] = undefined;
|
||||||
break;
|
queryParams['fulfilled'] = undefined;
|
||||||
|
break;
|
||||||
|
|
||||||
case JournalFilterType.fulfilled:
|
case JournalFilterType.TWR_SKR:
|
||||||
queries.push('fulfilled=1');
|
queryParams['twr'] = undefined;
|
||||||
break;
|
queryParams['skr'] = undefined;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
case JournalFilterType.TWR:
|
||||||
break;
|
queryParams['twr'] = 1;
|
||||||
}
|
queryParams['skr'] = undefined;
|
||||||
|
break;
|
||||||
|
|
||||||
if (this.currentQuery != queries.join('&')) this.dataStatus = DataStatus.Loading;
|
case JournalFilterType.SKR:
|
||||||
|
queryParams['twr'] = undefined;
|
||||||
|
queryParams['skr'] = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
this.currentQuery = queries.join('&');
|
default:
|
||||||
this.currentQueryArray = queries;
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
queryParams['driverName'] = driverName;
|
||||||
|
queryParams[trainNo?.startsWith('#') ? 'timetableId' : 'trainNo'] = trainNo?.replace('#', '');
|
||||||
|
queryParams['countFrom'] = undefined;
|
||||||
|
queryParams['countLimit'] = undefined;
|
||||||
|
|
||||||
|
queryParams['authorName'] = authorName;
|
||||||
|
queryParams['timestampFrom'] = timestampFrom;
|
||||||
|
queryParams['timestampTo'] = timestampTo;
|
||||||
|
queryParams['issuedFrom'] = issuedFrom;
|
||||||
|
queryParams['sortBy'] = this.sorterActive.id != 'timetableId' ? this.sorterActive.id : undefined;
|
||||||
|
|
||||||
|
if (JSON.stringify(this.currentQueryParams) != JSON.stringify(queryParams)) this.dataStatus = DataStatus.Loading;
|
||||||
|
|
||||||
|
this.currentQueryParams = queryParams;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const responseData: TimetableHistory[] = await (
|
const responseData: TimetableHistory[] = await (
|
||||||
await axios.get(`${TIMETABLES_API_URL}?${this.currentQuery}`)
|
await axios.get(`${TIMETABLES_API_URL}`, {
|
||||||
|
params: this.currentQueryParams,
|
||||||
|
})
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
if (!responseData) {
|
if (!responseData) {
|
||||||
@@ -287,6 +310,7 @@ export default defineComponent({
|
|||||||
: '';
|
: '';
|
||||||
|
|
||||||
this.dataStatus = DataStatus.Loaded;
|
this.dataStatus = DataStatus.Loaded;
|
||||||
|
this.dataRefreshedAt = new Date();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.dataStatus = DataStatus.Error;
|
this.dataStatus = DataStatus.Error;
|
||||||
this.dataErrorMessage = 'Ups! Coś poszło nie tak!';
|
this.dataErrorMessage = 'Ups! Coś poszło nie tak!';
|
||||||
@@ -302,4 +326,3 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../styles/JournalSection.scss';
|
@import '../styles/JournalSection.scss';
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -33,12 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<keep-alive>
|
<keep-alive>
|
||||||
<component
|
<component :is="currentViewCompontent" :station="stationInfo" :key="currentViewCompontent"></component>
|
||||||
:is="currentViewCompontent"
|
|
||||||
:station="stationInfo"
|
|
||||||
:timetableOnly="timetableOnly"
|
|
||||||
:key="currentViewCompontent"
|
|
||||||
></component>
|
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -208,14 +203,14 @@ button.back-btn {
|
|||||||
|
|
||||||
.scenery-right {
|
.scenery-right {
|
||||||
background: #181818;
|
background: #181818;
|
||||||
padding: 2em 0.5em;
|
padding: 1em 0.5em;
|
||||||
|
|
||||||
height: 95vh;
|
height: 95vh;
|
||||||
min-height: 550px;
|
min-height: 550px;
|
||||||
max-height: 1000px;
|
max-height: 1000px;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: auto 1fr;
|
grid-template-rows: auto 1fr auto;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import StorageManager from '../scripts/managers/storageManager';
|
|
||||||
import StationTable from '../components/StationsView/StationTable.vue';
|
import StationTable from '../components/StationsView/StationTable.vue';
|
||||||
import StationFilterCard from '../components/StationsView/StationFilterCard.vue';
|
import StationFilterCard from '../components/StationsView/StationFilterCard.vue';
|
||||||
import SelectBox from '../components/Global/SelectBox.vue';
|
import SelectBox from '../components/Global/SelectBox.vue';
|
||||||
@@ -44,25 +43,12 @@ export default defineComponent({
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
computedStationList() {
|
computedStationList() {
|
||||||
const list = this.filterStore.getFilteredStationList(this.store.stationList, this.store.region.id);
|
return this.filterStore.getFilteredStationList(this.store.stationList, this.store.region.id);
|
||||||
|
|
||||||
return list;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.filterStore.setupFilters();
|
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>
|
</script>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<section class="trains-view">
|
<section class="trains-view">
|
||||||
<div class="trains_wrapper">
|
<div class="trains_wrapper">
|
||||||
<TrainOptions
|
<TrainOptions
|
||||||
:sorter-option-ids="['distance', 'id', 'progress', 'delay', 'mass', 'speed', 'length']"
|
:sorter-option-ids="['routeDistance', 'id', 'progress', 'delay', 'mass', 'speed', 'length']"
|
||||||
:current-options-active="currentOptionsActive"
|
:current-options-active="currentOptionsActive"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ import modalTrainMixin from '../mixins/modalTrainMixin';
|
|||||||
import Train from '../scripts/interfaces/Train';
|
import Train from '../scripts/interfaces/Train';
|
||||||
import { filteredTrainList } from '../scripts/managers/trainFilterManager';
|
import { filteredTrainList } from '../scripts/managers/trainFilterManager';
|
||||||
import { useStore } from '../store/store';
|
import { useStore } from '../store/store';
|
||||||
import { TrainFilter } from '../types/Trains/TrainOptionsTypes';
|
import { TrainFilter } from '../scripts/interfaces/Trains/TrainFilter';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@@ -57,7 +57,7 @@ export default defineComponent({
|
|||||||
const store = useStore();
|
const store = useStore();
|
||||||
const initTrainFilters = [...trainFilters.map((f) => ({ ...f }))];
|
const initTrainFilters = [...trainFilters.map((f) => ({ ...f }))];
|
||||||
|
|
||||||
const sorterActive = reactive({ id: 'distance', dir: -1 });
|
const sorterActive = reactive({ id: 'routeDistance', dir: -1 });
|
||||||
const filterList = reactive([...trainFilters]) as TrainFilter[];
|
const filterList = reactive([...trainFilters]) as TrainFilter[];
|
||||||
|
|
||||||
const currentOptionsActive = ref(false);
|
const currentOptionsActive = ref(false);
|
||||||
@@ -77,7 +77,9 @@ export default defineComponent({
|
|||||||
watch([searchedTrain, searchedDriver, sorterActive, filterList], ([sT, sD, sA, fL]) => {
|
watch([searchedTrain, searchedDriver, sorterActive, filterList], ([sT, sD, sA, fL]) => {
|
||||||
const areFiltersActive = fL.some((f, i) => f.isActive !== initTrainFilters[i].isActive);
|
const areFiltersActive = fL.some((f, i) => f.isActive !== initTrainFilters[i].isActive);
|
||||||
|
|
||||||
currentOptionsActive.value = sT.length > 0 || sD.length > 0 || sA.id != 'distance' || areFiltersActive;
|
|
||||||
|
currentOptionsActive.value = sT.length > 0 || sD.length > 0 || sA.id != 'routeDistance' || areFiltersActive;
|
||||||
|
console.log(sA.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
+2
-2
@@ -9,13 +9,13 @@ export default defineConfig({
|
|||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
VitePWA({
|
VitePWA({
|
||||||
registerType: 'prompt',
|
registerType: 'autoUpdate',
|
||||||
|
|
||||||
workbox: {
|
workbox: {
|
||||||
globPatterns: ['**/*.{js,css,html,png,svg,jpg}'],
|
globPatterns: ['**/*.{js,css,html,png,svg,jpg}'],
|
||||||
runtimeCaching: [
|
runtimeCaching: [
|
||||||
{
|
{
|
||||||
urlPattern: new RegExp('^https://spythere.pl/api/getSceneries', 'i'),
|
urlPattern: new RegExp('^https://stacjownik.spythere.pl/api/getSceneries', 'i'),
|
||||||
handler: 'NetworkFirst',
|
handler: 'NetworkFirst',
|
||||||
options: {
|
options: {
|
||||||
cacheName: 'sceneries-cache',
|
cacheName: 'sceneries-cache',
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz"
|
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz"
|
||||||
integrity sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==
|
integrity sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==
|
||||||
|
|
||||||
"@babel/core@^7.11.1":
|
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.1", "@babel/core@^7.12.0", "@babel/core@^7.13.0", "@babel/core@^7.4.0-0":
|
||||||
version "7.20.7"
|
version "7.20.7"
|
||||||
resolved "https://registry.npmjs.org/@babel/core/-/core-7.20.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/core/-/core-7.20.7.tgz"
|
||||||
integrity sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==
|
integrity sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==
|
||||||
@@ -912,114 +912,9 @@
|
|||||||
"@babel/helper-validator-identifier" "^7.19.1"
|
"@babel/helper-validator-identifier" "^7.19.1"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@esbuild/android-arm64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.10.tgz#d784d8f13dbef50492ea55456fb50651e4036fbf"
|
|
||||||
integrity sha512-47Y+NwVKTldTlDhSgJHZ/RpvBQMUDG7eKihqaF/u6g7s0ZPz4J1vy8A3rwnnUOF2CuDn7w7Gj/QcMoWz3U3SJw==
|
|
||||||
|
|
||||||
"@esbuild/android-arm@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.10.tgz#becf6b5647c091b039121db8c17300a7dfd1ab4a"
|
|
||||||
integrity sha512-RmJjQTRrO6VwUWDrzTBLmV4OJZTarYsiepLGlF2rYTVB701hSorPywPGvP6d8HCuuRibyXa5JX4s3jN2kHEtjQ==
|
|
||||||
|
|
||||||
"@esbuild/android-x64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.10.tgz#648cacbb13a5047380a038e5d6d895015e31b525"
|
|
||||||
integrity sha512-C4PfnrBMcuAcOurQzpF1tTtZz94IXO5JmICJJ3NFJRHbXXsQUg9RFG45KvydKqtFfBaFLCHpduUkUfXwIvGnRg==
|
|
||||||
|
|
||||||
"@esbuild/darwin-arm64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.10.tgz#3ca7fd9a456d11752df77df6c030f2d08f27bda9"
|
|
||||||
integrity sha512-bH/bpFwldyOKdi9HSLCLhhKeVgRYr9KblchwXgY2NeUHBB/BzTUHtUSBgGBmpydB1/4E37m+ggXXfSrnD7/E7g==
|
|
||||||
|
|
||||||
"@esbuild/darwin-x64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.10.tgz#7eb71b8da4106627f01553def517d3c5e5942592"
|
|
||||||
integrity sha512-OXt7ijoLuy+AjDSKQWu+KdDFMBbdeaL6wtgMKtDUXKWHiAMKHan5+R1QAG6HD4+K0nnOvEJXKHeA9QhXNAjOTQ==
|
|
||||||
|
|
||||||
"@esbuild/freebsd-arm64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.10.tgz#c69c78ee1d17d35ad2cf76a1bb67788000a84b43"
|
|
||||||
integrity sha512-shSQX/3GHuspE3Uxtq5kcFG/zqC+VuMnJkqV7LczO41cIe6CQaXHD3QdMLA4ziRq/m0vZo7JdterlgbmgNIAlQ==
|
|
||||||
|
|
||||||
"@esbuild/freebsd-x64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.10.tgz#a9804ab1b9366f915812af24ad5cfc1c0db01441"
|
|
||||||
integrity sha512-5YVc1zdeaJGASijZmTzSO4h6uKzsQGG3pkjI6fuXvolhm3hVRhZwnHJkforaZLmzvNv5Tb7a3QL2FAVmrgySIA==
|
|
||||||
|
|
||||||
"@esbuild/linux-arm64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.10.tgz#d9a9ddfcb28ed8cced688bc112ef66283d6fa77f"
|
|
||||||
integrity sha512-2aqeNVxIaRfPcIaMZIFoblLh588sWyCbmj1HHCCs9WmeNWm+EIN0SmvsmPvTa/TsNZFKnxTcvkX2eszTcCqIrA==
|
|
||||||
|
|
||||||
"@esbuild/linux-arm@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.10.tgz#f32cdac1d3319c83ae7f9f31238dd1284ee6bba2"
|
|
||||||
integrity sha512-c360287ZWI2miBnvIj23bPyVctgzeMT2kQKR+x94pVqIN44h3GF8VMEs1SFPH1UgyDr3yBbx3vowDS1SVhyVhA==
|
|
||||||
|
|
||||||
"@esbuild/linux-ia32@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.10.tgz#1e023478e42f3a01cad48f4af50120d4b639af03"
|
|
||||||
integrity sha512-sqMIEWeyrLGU7J5RB5fTkLRIFwsgsQ7ieWXlDLEmC2HblPYGb3AucD7inw2OrKFpRPKsec1l+lssiM3+NV5aOw==
|
|
||||||
|
|
||||||
"@esbuild/linux-loong64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.10.tgz#f9098865a69d1d6e2f8bda51c7f9d4240f20b771"
|
|
||||||
integrity sha512-O7Pd5hLEtTg37NC73pfhUOGTjx/+aXu5YoSq3ahCxcN7Bcr2F47mv+kG5t840thnsEzrv0oB70+LJu3gUgchvg==
|
|
||||||
|
|
||||||
"@esbuild/linux-mips64el@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.10.tgz#574725ad2ea81b7783b7ba7d1ab3475f8fdd8d32"
|
|
||||||
integrity sha512-FN8mZOH7531iPHM0kaFhAOqqNHoAb6r/YHW2ZIxNi0a85UBi2DO4Vuyn7t1p4UN8a4LoAnLOT1PqNgHkgBJgbA==
|
|
||||||
|
|
||||||
"@esbuild/linux-ppc64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.10.tgz#11da658c54514a693813af56bb28951d563a90c3"
|
|
||||||
integrity sha512-Dg9RiqdvHOAWnOKIOTsIx8dFX9EDlY2IbPEY7YFzchrCiTZmMkD7jWA9UdZbNUygPjdmQBVPRCrLydReFlX9yg==
|
|
||||||
|
|
||||||
"@esbuild/linux-riscv64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.10.tgz#3af4600adbd6c5a4a6f1da05771f4aa6774baab2"
|
|
||||||
integrity sha512-XMqtpjwzbmlar0BJIxmzu/RZ7EWlfVfH68Vadrva0Wj5UKOdKvqskuev2jY2oPV3aoQUyXwnMbMrFmloO2GfAw==
|
|
||||||
|
|
||||||
"@esbuild/linux-s390x@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.10.tgz#9e3377aaf0191a9d6628e806a279085ec4391f3e"
|
|
||||||
integrity sha512-fu7XtnoeRNFMx8DjK3gPWpFBDM2u5ba+FYwg27SjMJwKvJr4bDyKz5c+FLXLUSSAkMAt/UL+cUbEbra+rYtUgw==
|
|
||||||
|
|
||||||
"@esbuild/linux-x64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.10.tgz"
|
|
||||||
integrity sha512-61lcjVC/RldNNMUzQQdyCWjCxp9YLEQgIxErxU9XluX7juBdGKb0pvddS0vPNuCvotRbzijZ1pzII+26haWzbA==
|
|
||||||
|
|
||||||
"@esbuild/netbsd-x64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.10.tgz#ebac59e3986834af04bbafcee7b0c1f31cd477c6"
|
|
||||||
integrity sha512-JeZXCX3viSA9j4HqSoygjssdqYdfHd6yCFWyfSekLbz4Ef+D2EjvsN02ZQPwYl5a5gg/ehdHgegHhlfOFP0HCA==
|
|
||||||
|
|
||||||
"@esbuild/openbsd-x64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.10.tgz#9eaa6cac3b80db45090c0946e62de5b5689c61d1"
|
|
||||||
integrity sha512-3qpxQKuEVIIg8SebpXsp82OBrqjPV/OwNWmG+TnZDr3VGyChNnGMHccC1xkbxCHDQNnnXjxhMQNyHmdFJbmbRA==
|
|
||||||
|
|
||||||
"@esbuild/sunos-x64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.10.tgz#31e5e4b814ef43d300e26511e486a4716a390d5f"
|
|
||||||
integrity sha512-z+q0xZ+et/7etz7WoMyXTHZ1rB8PMSNp/FOqURLJLOPb3GWJ2aj4oCqFCjPwEbW1rsT7JPpxeH/DwGAWk/I1Bg==
|
|
||||||
|
|
||||||
"@esbuild/win32-arm64@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.10.tgz#ca58472dc03ca79e6d03f8a31113979ff253d94f"
|
|
||||||
integrity sha512-+YYu5sbQ9npkNT9Dec+tn1F/kjg6SMgr6bfi/6FpXYZvCRfu2YFPZGb+3x8K30s8eRxFpoG4sGhiSUkr1xbHEw==
|
|
||||||
|
|
||||||
"@esbuild/win32-ia32@0.16.10":
|
|
||||||
version "0.16.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.10.tgz#c572df2c65ab118feed0a5da5a4a193846d74e43"
|
|
||||||
integrity sha512-Aw7Fupk7XNehR1ftHGYwUteyJ2q+em/aE+fVU3YMTBN2V5A7Z4aVCSV+SvCp9HIIHZavPFBpbdP3VfjQpdf6Xg==
|
|
||||||
|
|
||||||
"@esbuild/win32-x64@0.16.10":
|
"@esbuild/win32-x64@0.16.10":
|
||||||
version "0.16.10"
|
version "0.16.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.10.tgz#0e9c6a5e69c10d96aff2386b7ee9646138c2a831"
|
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.10.tgz"
|
||||||
integrity sha512-qddWullt3sC1EIpfHvCRBq3H4g3L86DZpD6n8k2XFjFVyp01D++uNbN1hT/JRsHxTbyyemZcpwL5aRlJwc/zFw==
|
integrity sha512-qddWullt3sC1EIpfHvCRBq3H4g3L86DZpD6n8k2XFjFVyp01D++uNbN1hT/JRsHxTbyyemZcpwL5aRlJwc/zFw==
|
||||||
|
|
||||||
"@firebase/analytics-compat@0.1.14":
|
"@firebase/analytics-compat@0.1.14":
|
||||||
@@ -1081,7 +976,7 @@
|
|||||||
"@firebase/util" "1.7.0"
|
"@firebase/util" "1.7.0"
|
||||||
tslib "^2.1.0"
|
tslib "^2.1.0"
|
||||||
|
|
||||||
"@firebase/app-compat@0.1.35":
|
"@firebase/app-compat@0.1.35", "@firebase/app-compat@0.x":
|
||||||
version "0.1.35"
|
version "0.1.35"
|
||||||
resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.1.35.tgz"
|
resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.1.35.tgz"
|
||||||
integrity sha512-6ax9yXCPEBSREHxo+nCpSgSg01mGTvR4I7u/EHqVNNqG8uEWog7sUan3Y3vr3q3zH8t5BkXDGejOH9atF+XnAQ==
|
integrity sha512-6ax9yXCPEBSREHxo+nCpSgSg01mGTvR4I7u/EHqVNNqG8uEWog7sUan3Y3vr3q3zH8t5BkXDGejOH9atF+XnAQ==
|
||||||
@@ -1092,12 +987,12 @@
|
|||||||
"@firebase/util" "1.7.0"
|
"@firebase/util" "1.7.0"
|
||||||
tslib "^2.1.0"
|
tslib "^2.1.0"
|
||||||
|
|
||||||
"@firebase/app-types@0.8.0":
|
"@firebase/app-types@0.8.0", "@firebase/app-types@0.x":
|
||||||
version "0.8.0"
|
version "0.8.0"
|
||||||
resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.8.0.tgz"
|
resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.8.0.tgz"
|
||||||
integrity sha512-Lec3VVquUwXPn2UReGSsfTxuMBVRmzGIwA/CJnF0LQuPgv9kOmXk9mVqsDMfHxHtqjai0n6wWHR2TqjdVV/bYA==
|
integrity sha512-Lec3VVquUwXPn2UReGSsfTxuMBVRmzGIwA/CJnF0LQuPgv9kOmXk9mVqsDMfHxHtqjai0n6wWHR2TqjdVV/bYA==
|
||||||
|
|
||||||
"@firebase/app@0.8.0":
|
"@firebase/app@0.8.0", "@firebase/app@0.x":
|
||||||
version "0.8.0"
|
version "0.8.0"
|
||||||
resolved "https://registry.npmjs.org/@firebase/app/-/app-0.8.0.tgz"
|
resolved "https://registry.npmjs.org/@firebase/app/-/app-0.8.0.tgz"
|
||||||
integrity sha512-9kZjhIDv4u4PlrCgcQVBA2u8BZHrP8rUWDltmCUi9BLHv0tltfxLMZODV5LeuAfCJKVp2dbIrpGHPxAaLLl/ww==
|
integrity sha512-9kZjhIDv4u4PlrCgcQVBA2u8BZHrP8rUWDltmCUi9BLHv0tltfxLMZODV5LeuAfCJKVp2dbIrpGHPxAaLLl/ww==
|
||||||
@@ -1384,7 +1279,7 @@
|
|||||||
node-fetch "2.6.7"
|
node-fetch "2.6.7"
|
||||||
tslib "^2.1.0"
|
tslib "^2.1.0"
|
||||||
|
|
||||||
"@firebase/util@1.7.0":
|
"@firebase/util@1.7.0", "@firebase/util@1.x":
|
||||||
version "1.7.0"
|
version "1.7.0"
|
||||||
resolved "https://registry.npmjs.org/@firebase/util/-/util-1.7.0.tgz"
|
resolved "https://registry.npmjs.org/@firebase/util/-/util-1.7.0.tgz"
|
||||||
integrity sha512-n5g1WWd+E5IYQwtKxmTJDlhfT762mk/d7yigeh8QaS46cnvngwguOhNwlS8fniEJ7pAgyZ9v05OQMKdfMnws6g==
|
integrity sha512-n5g1WWd+E5IYQwtKxmTJDlhfT762mk/d7yigeh8QaS46cnvngwguOhNwlS8fniEJ7pAgyZ9v05OQMKdfMnws6g==
|
||||||
@@ -1472,7 +1367,16 @@
|
|||||||
"@jridgewell/set-array" "^1.0.0"
|
"@jridgewell/set-array" "^1.0.0"
|
||||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||||
|
|
||||||
"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2":
|
"@jridgewell/gen-mapping@^0.3.0":
|
||||||
|
version "0.3.2"
|
||||||
|
resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz"
|
||||||
|
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
|
||||||
|
dependencies:
|
||||||
|
"@jridgewell/set-array" "^1.0.1"
|
||||||
|
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||||
|
"@jridgewell/trace-mapping" "^0.3.9"
|
||||||
|
|
||||||
|
"@jridgewell/gen-mapping@^0.3.2":
|
||||||
version "0.3.2"
|
version "0.3.2"
|
||||||
resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz"
|
resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz"
|
||||||
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
|
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
|
||||||
@@ -1499,7 +1403,7 @@
|
|||||||
"@jridgewell/gen-mapping" "^0.3.0"
|
"@jridgewell/gen-mapping" "^0.3.0"
|
||||||
"@jridgewell/trace-mapping" "^0.3.9"
|
"@jridgewell/trace-mapping" "^0.3.9"
|
||||||
|
|
||||||
"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13":
|
"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@1.4.14":
|
||||||
version "1.4.14"
|
version "1.4.14"
|
||||||
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz"
|
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz"
|
||||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||||
@@ -1520,7 +1424,7 @@
|
|||||||
"@nodelib/fs.stat" "2.0.5"
|
"@nodelib/fs.stat" "2.0.5"
|
||||||
run-parallel "^1.1.9"
|
run-parallel "^1.1.9"
|
||||||
|
|
||||||
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
|
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
||||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||||
@@ -1655,22 +1559,22 @@
|
|||||||
magic-string "^0.25.0"
|
magic-string "^0.25.0"
|
||||||
string.prototype.matchall "^4.0.6"
|
string.prototype.matchall "^4.0.6"
|
||||||
|
|
||||||
"@types/estree@0.0.39":
|
|
||||||
version "0.0.39"
|
|
||||||
resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz"
|
|
||||||
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
|
|
||||||
|
|
||||||
"@types/estree@^1.0.0":
|
"@types/estree@^1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz"
|
||||||
integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
|
integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
|
||||||
|
|
||||||
|
"@types/estree@0.0.39":
|
||||||
|
version "0.0.39"
|
||||||
|
resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz"
|
||||||
|
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
|
||||||
|
|
||||||
"@types/long@^4.0.1":
|
"@types/long@^4.0.1":
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz"
|
resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz"
|
||||||
integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
|
integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
|
||||||
|
|
||||||
"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@^18.11.17":
|
"@types/node@*", "@types/node@^18.11.17", "@types/node@>= 14", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
|
||||||
version "18.11.18"
|
version "18.11.18"
|
||||||
resolved "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz"
|
resolved "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz"
|
||||||
integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
|
integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
|
||||||
@@ -1757,15 +1661,7 @@
|
|||||||
estree-walker "^2.0.2"
|
estree-walker "^2.0.2"
|
||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
|
|
||||||
"@vue/compiler-dom@3.2.40":
|
"@vue/compiler-dom@^3.2.45", "@vue/compiler-dom@3.2.45":
|
||||||
version "3.2.40"
|
|
||||||
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.40.tgz"
|
|
||||||
integrity sha512-OZCNyYVC2LQJy4H7h0o28rtk+4v+HMQygRTpmibGoG9wZyomQiS5otU7qo3Wlq5UfHDw2RFwxb9BJgKjVpjrQw==
|
|
||||||
dependencies:
|
|
||||||
"@vue/compiler-core" "3.2.40"
|
|
||||||
"@vue/shared" "3.2.40"
|
|
||||||
|
|
||||||
"@vue/compiler-dom@3.2.45", "@vue/compiler-dom@^3.2.45":
|
|
||||||
version "3.2.45"
|
version "3.2.45"
|
||||||
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz"
|
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz"
|
||||||
integrity sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==
|
integrity sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==
|
||||||
@@ -1773,21 +1669,13 @@
|
|||||||
"@vue/compiler-core" "3.2.45"
|
"@vue/compiler-core" "3.2.45"
|
||||||
"@vue/shared" "3.2.45"
|
"@vue/shared" "3.2.45"
|
||||||
|
|
||||||
"@vue/compiler-sfc@3.2.40":
|
"@vue/compiler-dom@3.2.40":
|
||||||
version "3.2.40"
|
version "3.2.40"
|
||||||
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.40.tgz"
|
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.40.tgz"
|
||||||
integrity sha512-tzqwniIN1fu1PDHC3CpqY/dPCfN/RN1thpBC+g69kJcrl7mbGiHKNwbA6kJ3XKKy8R6JLKqcpVugqN4HkeBFFg==
|
integrity sha512-OZCNyYVC2LQJy4H7h0o28rtk+4v+HMQygRTpmibGoG9wZyomQiS5otU7qo3Wlq5UfHDw2RFwxb9BJgKjVpjrQw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/parser" "^7.16.4"
|
|
||||||
"@vue/compiler-core" "3.2.40"
|
"@vue/compiler-core" "3.2.40"
|
||||||
"@vue/compiler-dom" "3.2.40"
|
|
||||||
"@vue/compiler-ssr" "3.2.40"
|
|
||||||
"@vue/reactivity-transform" "3.2.40"
|
|
||||||
"@vue/shared" "3.2.40"
|
"@vue/shared" "3.2.40"
|
||||||
estree-walker "^2.0.2"
|
|
||||||
magic-string "^0.25.7"
|
|
||||||
postcss "^8.1.10"
|
|
||||||
source-map "^0.6.1"
|
|
||||||
|
|
||||||
"@vue/compiler-sfc@^3.2.45":
|
"@vue/compiler-sfc@^3.2.45":
|
||||||
version "3.2.45"
|
version "3.2.45"
|
||||||
@@ -1805,6 +1693,22 @@
|
|||||||
postcss "^8.1.10"
|
postcss "^8.1.10"
|
||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
|
|
||||||
|
"@vue/compiler-sfc@3.2.40":
|
||||||
|
version "3.2.40"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.40.tgz"
|
||||||
|
integrity sha512-tzqwniIN1fu1PDHC3CpqY/dPCfN/RN1thpBC+g69kJcrl7mbGiHKNwbA6kJ3XKKy8R6JLKqcpVugqN4HkeBFFg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.16.4"
|
||||||
|
"@vue/compiler-core" "3.2.40"
|
||||||
|
"@vue/compiler-dom" "3.2.40"
|
||||||
|
"@vue/compiler-ssr" "3.2.40"
|
||||||
|
"@vue/reactivity-transform" "3.2.40"
|
||||||
|
"@vue/shared" "3.2.40"
|
||||||
|
estree-walker "^2.0.2"
|
||||||
|
magic-string "^0.25.7"
|
||||||
|
postcss "^8.1.10"
|
||||||
|
source-map "^0.6.1"
|
||||||
|
|
||||||
"@vue/compiler-ssr@3.2.40":
|
"@vue/compiler-ssr@3.2.40":
|
||||||
version "3.2.40"
|
version "3.2.40"
|
||||||
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.40.tgz"
|
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.40.tgz"
|
||||||
@@ -1848,13 +1752,6 @@
|
|||||||
estree-walker "^2.0.2"
|
estree-walker "^2.0.2"
|
||||||
magic-string "^0.25.7"
|
magic-string "^0.25.7"
|
||||||
|
|
||||||
"@vue/reactivity@3.2.40":
|
|
||||||
version "3.2.40"
|
|
||||||
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.40.tgz"
|
|
||||||
integrity sha512-N9qgGLlZmtUBMHF9xDT4EkD9RdXde1Xbveb+niWMXuHVWQP5BzgRmE3SFyUBBcyayG4y1lhoz+lphGRRxxK4RA==
|
|
||||||
dependencies:
|
|
||||||
"@vue/shared" "3.2.40"
|
|
||||||
|
|
||||||
"@vue/reactivity@^3.2.45":
|
"@vue/reactivity@^3.2.45":
|
||||||
version "3.2.45"
|
version "3.2.45"
|
||||||
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz"
|
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz"
|
||||||
@@ -1862,6 +1759,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@vue/shared" "3.2.45"
|
"@vue/shared" "3.2.45"
|
||||||
|
|
||||||
|
"@vue/reactivity@3.2.40":
|
||||||
|
version "3.2.40"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.40.tgz"
|
||||||
|
integrity sha512-N9qgGLlZmtUBMHF9xDT4EkD9RdXde1Xbveb+niWMXuHVWQP5BzgRmE3SFyUBBcyayG4y1lhoz+lphGRRxxK4RA==
|
||||||
|
dependencies:
|
||||||
|
"@vue/shared" "3.2.40"
|
||||||
|
|
||||||
"@vue/runtime-core@3.2.40":
|
"@vue/runtime-core@3.2.40":
|
||||||
version "3.2.40"
|
version "3.2.40"
|
||||||
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.40.tgz"
|
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.40.tgz"
|
||||||
@@ -1887,22 +1791,22 @@
|
|||||||
"@vue/compiler-ssr" "3.2.40"
|
"@vue/compiler-ssr" "3.2.40"
|
||||||
"@vue/shared" "3.2.40"
|
"@vue/shared" "3.2.40"
|
||||||
|
|
||||||
|
"@vue/shared@^3.2.45", "@vue/shared@3.2.45":
|
||||||
|
version "3.2.45"
|
||||||
|
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz"
|
||||||
|
integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==
|
||||||
|
|
||||||
"@vue/shared@3.2.40":
|
"@vue/shared@3.2.40":
|
||||||
version "3.2.40"
|
version "3.2.40"
|
||||||
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.40.tgz"
|
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.40.tgz"
|
||||||
integrity sha512-0PLQ6RUtZM0vO3teRfzGi4ltLUO5aO+kLgwh4Um3THSR03rpQWLTuRCkuO5A41ITzwdWeKdPHtSARuPkoo5pCQ==
|
integrity sha512-0PLQ6RUtZM0vO3teRfzGi4ltLUO5aO+kLgwh4Um3THSR03rpQWLTuRCkuO5A41ITzwdWeKdPHtSARuPkoo5pCQ==
|
||||||
|
|
||||||
"@vue/shared@3.2.45", "@vue/shared@^3.2.45":
|
|
||||||
version "3.2.45"
|
|
||||||
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz"
|
|
||||||
integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==
|
|
||||||
|
|
||||||
acorn@^8.5.0:
|
acorn@^8.5.0:
|
||||||
version "8.8.1"
|
version "8.8.1"
|
||||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz"
|
resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz"
|
||||||
integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==
|
integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==
|
||||||
|
|
||||||
ajv@^8.6.0:
|
ajv@^8.6.0, ajv@>=8:
|
||||||
version "8.11.2"
|
version "8.11.2"
|
||||||
resolved "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz"
|
resolved "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz"
|
||||||
integrity sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==
|
integrity sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==
|
||||||
@@ -2019,7 +1923,7 @@ braces@^3.0.2, braces@~3.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fill-range "^7.0.1"
|
fill-range "^7.0.1"
|
||||||
|
|
||||||
browserslist@^4.21.3, browserslist@^4.21.4:
|
browserslist@^4.21.3, browserslist@^4.21.4, "browserslist@>= 4.21.0":
|
||||||
version "4.21.4"
|
version "4.21.4"
|
||||||
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz"
|
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz"
|
||||||
integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==
|
integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==
|
||||||
@@ -2048,9 +1952,9 @@ call-bind@^1.0.0, call-bind@^1.0.2:
|
|||||||
get-intrinsic "^1.0.2"
|
get-intrinsic "^1.0.2"
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001400:
|
caniuse-lite@^1.0.30001400:
|
||||||
version "1.0.30001441"
|
version "1.0.30001503"
|
||||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001441.tgz"
|
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz"
|
||||||
integrity sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==
|
integrity sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==
|
||||||
|
|
||||||
chalk@^2.0.0:
|
chalk@^2.0.0:
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
@@ -2107,16 +2011,16 @@ color-convert@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-name "~1.1.4"
|
color-name "~1.1.4"
|
||||||
|
|
||||||
color-name@1.1.3:
|
|
||||||
version "1.1.3"
|
|
||||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
|
||||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
|
||||||
|
|
||||||
color-name@~1.1.4:
|
color-name@~1.1.4:
|
||||||
version "1.1.4"
|
version "1.1.4"
|
||||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
||||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||||
|
|
||||||
|
color-name@1.1.3:
|
||||||
|
version "1.1.3"
|
||||||
|
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
||||||
|
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||||
|
|
||||||
combined-stream@^1.0.8:
|
combined-stream@^1.0.8:
|
||||||
version "1.0.8"
|
version "1.0.8"
|
||||||
resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
|
resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
|
||||||
@@ -2442,11 +2346,6 @@ fs.realpath@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||||
|
|
||||||
fsevents@~2.3.2:
|
|
||||||
version "2.3.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
|
||||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
|
||||||
|
|
||||||
function-bind@^1.1.1:
|
function-bind@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
|
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
|
||||||
@@ -2591,7 +2490,7 @@ http-parser-js@>=0.5.1:
|
|||||||
resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz"
|
resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz"
|
||||||
integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==
|
integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==
|
||||||
|
|
||||||
idb@7.0.1, idb@^7.0.1:
|
idb@^7.0.1, idb@7.0.1:
|
||||||
version "7.0.1"
|
version "7.0.1"
|
||||||
resolved "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz"
|
resolved "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz"
|
||||||
integrity sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==
|
integrity sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==
|
||||||
@@ -2614,7 +2513,7 @@ inflight@^1.0.4:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
wrappy "1"
|
wrappy "1"
|
||||||
|
|
||||||
inherits@2, inherits@~2.0.3:
|
inherits@~2.0.3, inherits@2:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
||||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||||
@@ -2937,7 +2836,14 @@ minimatch@^3.0.4, minimatch@^3.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion "^1.1.7"
|
brace-expansion "^1.1.7"
|
||||||
|
|
||||||
minimatch@^5.0.1, minimatch@^5.1.1:
|
minimatch@^5.0.1:
|
||||||
|
version "5.1.2"
|
||||||
|
resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz"
|
||||||
|
integrity sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==
|
||||||
|
dependencies:
|
||||||
|
brace-expansion "^2.0.1"
|
||||||
|
|
||||||
|
minimatch@^5.1.1:
|
||||||
version "5.1.2"
|
version "5.1.2"
|
||||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz"
|
resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz"
|
||||||
integrity sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==
|
integrity sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==
|
||||||
@@ -3237,14 +3143,14 @@ rollup-plugin-terser@^7.0.0:
|
|||||||
serialize-javascript "^4.0.0"
|
serialize-javascript "^4.0.0"
|
||||||
terser "^5.0.0"
|
terser "^5.0.0"
|
||||||
|
|
||||||
rollup@^2.43.1:
|
"rollup@^1.20.0 || ^2.0.0", rollup@^1.20.0||^2.0.0, rollup@^2.0.0, rollup@^2.43.1:
|
||||||
version "2.79.1"
|
version "2.79.1"
|
||||||
resolved "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz"
|
resolved "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz"
|
||||||
integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
|
integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
rollup@^3.7.0, rollup@^3.7.2:
|
rollup@^1.20.0||^2.0.0||^3.0.0, rollup@^3.7.0, rollup@^3.7.2:
|
||||||
version "3.7.5"
|
version "3.7.5"
|
||||||
resolved "https://registry.npmjs.org/rollup/-/rollup-3.7.5.tgz"
|
resolved "https://registry.npmjs.org/rollup/-/rollup-3.7.5.tgz"
|
||||||
integrity sha512-z0ZbqHBtS/et2EEUKMrAl2CoSdwN7ZPzL17UMiKN9RjjqHShTlv7F9J6ZJZJNREYjBh3TvBrdfjkFDIXFNeuiQ==
|
integrity sha512-z0ZbqHBtS/et2EEUKMrAl2CoSdwN7ZPzL17UMiKN9RjjqHShTlv7F9J6ZJZJNREYjBh3TvBrdfjkFDIXFNeuiQ==
|
||||||
@@ -3258,16 +3164,16 @@ run-parallel@^1.1.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
queue-microtask "^1.2.2"
|
queue-microtask "^1.2.2"
|
||||||
|
|
||||||
safe-buffer@>=5.1.0:
|
|
||||||
version "5.2.1"
|
|
||||||
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
|
|
||||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
|
||||||
|
|
||||||
safe-buffer@^5.1.0, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
safe-buffer@^5.1.0, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||||
version "5.1.2"
|
version "5.1.2"
|
||||||
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
|
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
|
||||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||||
|
|
||||||
|
safe-buffer@>=5.1.0:
|
||||||
|
version "5.2.1"
|
||||||
|
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
|
||||||
|
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||||
|
|
||||||
safe-regex-test@^1.0.0:
|
safe-regex-test@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz"
|
||||||
@@ -3277,7 +3183,7 @@ safe-regex-test@^1.0.0:
|
|||||||
get-intrinsic "^1.1.3"
|
get-intrinsic "^1.1.3"
|
||||||
is-regex "^1.1.4"
|
is-regex "^1.1.4"
|
||||||
|
|
||||||
sass@^1.53.0:
|
sass@*, sass@^1.53.0:
|
||||||
version "1.55.0"
|
version "1.55.0"
|
||||||
resolved "https://registry.npmjs.org/sass/-/sass-1.55.0.tgz"
|
resolved "https://registry.npmjs.org/sass/-/sass-1.55.0.tgz"
|
||||||
integrity sha512-Pk+PMy7OGLs9WaxZGJMn7S96dvlyVBwwtToX895WmCpAOr5YiJYEUJfiJidMuKb613z2xNWcXCHEuOvjZbqC6A==
|
integrity sha512-Pk+PMy7OGLs9WaxZGJMn7S96dvlyVBwwtToX895WmCpAOr5YiJYEUJfiJidMuKb613z2xNWcXCHEuOvjZbqC6A==
|
||||||
@@ -3339,7 +3245,7 @@ socket.io-parser@~4.2.0:
|
|||||||
"@socket.io/component-emitter" "~3.1.0"
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
debug "~4.3.1"
|
debug "~4.3.1"
|
||||||
|
|
||||||
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
|
source-map-js@^1.0.2, "source-map-js@>=0.6.2 <2.0.0":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
||||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||||
@@ -3352,7 +3258,7 @@ source-map-support@~0.5.20:
|
|||||||
buffer-from "^1.0.0"
|
buffer-from "^1.0.0"
|
||||||
source-map "^0.6.0"
|
source-map "^0.6.0"
|
||||||
|
|
||||||
source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1:
|
source-map@^0.6.0, source-map@^0.6.1, source-map@0.6.1:
|
||||||
version "0.6.1"
|
version "0.6.1"
|
||||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||||
@@ -3369,6 +3275,13 @@ sourcemap-codec@^1.4.8:
|
|||||||
resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz"
|
resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz"
|
||||||
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
|
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
|
||||||
|
|
||||||
|
string_decoder@~1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
|
||||||
|
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
||||||
|
dependencies:
|
||||||
|
safe-buffer "~5.1.0"
|
||||||
|
|
||||||
string-width@^4.1.0, string-width@^4.2.0:
|
string-width@^4.1.0, string-width@^4.2.0:
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
||||||
@@ -3410,13 +3323,6 @@ string.prototype.trimstart@^1.0.6:
|
|||||||
define-properties "^1.1.4"
|
define-properties "^1.1.4"
|
||||||
es-abstract "^1.20.4"
|
es-abstract "^1.20.4"
|
||||||
|
|
||||||
string_decoder@~1.1.1:
|
|
||||||
version "1.1.1"
|
|
||||||
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
|
|
||||||
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
|
||||||
dependencies:
|
|
||||||
safe-buffer "~5.1.0"
|
|
||||||
|
|
||||||
stringify-object@^3.3.0:
|
stringify-object@^3.3.0:
|
||||||
version "3.3.0"
|
version "3.3.0"
|
||||||
resolved "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz"
|
resolved "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz"
|
||||||
@@ -3445,7 +3351,14 @@ supports-color@^5.3.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-flag "^3.0.0"
|
has-flag "^3.0.0"
|
||||||
|
|
||||||
supports-color@^7.0.0, supports-color@^7.1.0:
|
supports-color@^7.0.0:
|
||||||
|
version "7.2.0"
|
||||||
|
resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
|
||||||
|
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
|
||||||
|
dependencies:
|
||||||
|
has-flag "^4.0.0"
|
||||||
|
|
||||||
|
supports-color@^7.1.0:
|
||||||
version "7.2.0"
|
version "7.2.0"
|
||||||
resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
|
resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
|
||||||
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
|
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
|
||||||
@@ -3472,7 +3385,7 @@ tempy@^0.6.0:
|
|||||||
type-fest "^0.16.0"
|
type-fest "^0.16.0"
|
||||||
unique-string "^2.0.0"
|
unique-string "^2.0.0"
|
||||||
|
|
||||||
terser@^5.0.0:
|
terser@^5.0.0, terser@^5.4.0:
|
||||||
version "5.16.1"
|
version "5.16.1"
|
||||||
resolved "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz"
|
resolved "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz"
|
||||||
integrity sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==
|
integrity sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==
|
||||||
@@ -3523,7 +3436,7 @@ type-fest@^0.16.0:
|
|||||||
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz"
|
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz"
|
||||||
integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==
|
integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==
|
||||||
|
|
||||||
typescript@^4.9.4:
|
typescript@*, typescript@^4.9.4, typescript@>=4.4.4:
|
||||||
version "4.9.4"
|
version "4.9.4"
|
||||||
resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz"
|
resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz"
|
||||||
integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==
|
integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==
|
||||||
@@ -3611,7 +3524,7 @@ vite-plugin-pwa@^0.14.0:
|
|||||||
workbox-build "^6.5.4"
|
workbox-build "^6.5.4"
|
||||||
workbox-window "^6.5.4"
|
workbox-window "^6.5.4"
|
||||||
|
|
||||||
vite@^4.0.3:
|
"vite@^3.1.0 || ^4.0.0", vite@^4.0.0, vite@^4.0.3:
|
||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.npmjs.org/vite/-/vite-4.0.3.tgz"
|
resolved "https://registry.npmjs.org/vite/-/vite-4.0.3.tgz"
|
||||||
integrity sha512-HvuNv1RdE7deIfQb8mPk51UKjqptO/4RXZ5yXSAvurd5xOckwS/gg8h9Tky3uSbnjYTgUm0hVCet1cyhKd73ZA==
|
integrity sha512-HvuNv1RdE7deIfQb8mPk51UKjqptO/4RXZ5yXSAvurd5xOckwS/gg8h9Tky3uSbnjYTgUm0hVCet1cyhKd73ZA==
|
||||||
@@ -3661,7 +3574,7 @@ vue-tsc@^1.0.18:
|
|||||||
"@volar/vue-language-core" "1.0.18"
|
"@volar/vue-language-core" "1.0.18"
|
||||||
"@volar/vue-typescript" "1.0.18"
|
"@volar/vue-typescript" "1.0.18"
|
||||||
|
|
||||||
vue@^3.2.37:
|
"vue@^2.6.14 || ^3.2.0", vue@^3.0.0, "vue@^3.0.0-0 || ^2.6.0", vue@^3.2.0, vue@^3.2.25, vue@^3.2.37, vue@3.2.40:
|
||||||
version "3.2.40"
|
version "3.2.40"
|
||||||
resolved "https://registry.npmjs.org/vue/-/vue-3.2.40.tgz"
|
resolved "https://registry.npmjs.org/vue/-/vue-3.2.40.tgz"
|
||||||
integrity sha512-1mGHulzUbl2Nk3pfvI5aXYYyJUs1nm4kyvuz38u4xlQkLUn1i2R7nDbI4TufECmY8v1qNBHYy62bCaM+3cHP2A==
|
integrity sha512-1mGHulzUbl2Nk3pfvI5aXYYyJUs1nm4kyvuz38u4xlQkLUn1i2R7nDbI4TufECmY8v1qNBHYy62bCaM+3cHP2A==
|
||||||
@@ -3874,7 +3787,7 @@ workbox-sw@6.5.4:
|
|||||||
resolved "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.5.4.tgz"
|
resolved "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.5.4.tgz"
|
||||||
integrity sha512-vo2RQo7DILVRoH5LjGqw3nphavEjK4Qk+FenXeUsknKn14eCNedHOXWbmnvP4ipKhlE35pvJ4yl4YYf6YsJArA==
|
integrity sha512-vo2RQo7DILVRoH5LjGqw3nphavEjK4Qk+FenXeUsknKn14eCNedHOXWbmnvP4ipKhlE35pvJ4yl4YYf6YsJArA==
|
||||||
|
|
||||||
workbox-window@6.5.4, workbox-window@^6.5.4:
|
workbox-window@^6.5.4, workbox-window@6.5.4:
|
||||||
version "6.5.4"
|
version "6.5.4"
|
||||||
resolved "https://registry.npmjs.org/workbox-window/-/workbox-window-6.5.4.tgz"
|
resolved "https://registry.npmjs.org/workbox-window/-/workbox-window-6.5.4.tgz"
|
||||||
integrity sha512-HnLZJDwYBE+hpG25AQBO8RUWBJRaCsI9ksQJEp3aCOFCaG5kqaToAYXFRAHxzRluM2cQbGzdQF5rjKPWPA1fug==
|
integrity sha512-HnLZJDwYBE+hpG25AQBO8RUWBJRaCsI9ksQJEp3aCOFCaG5kqaToAYXFRAHxzRluM2cQbGzdQF5rjKPWPA1fug==
|
||||||
|
|||||||
Reference in New Issue
Block a user