mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 13:28:11 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ac740c2743 | |||
| 916f19df72 | |||
| de8facfb05 | |||
| 5d5ad44508 | |||
| 647055d2f0 | |||
| 1947555724 | |||
| 86417f3422 | |||
| a224b58d17 | |||
| 69be01fb1e | |||
| 6ef04f0dbd | |||
| 451d90f854 | |||
| b01d3e894b | |||
| 13dc6a0e32 | |||
| 96714550d0 | |||
| 2b6c751f55 | |||
| 08d3a2a03a | |||
| a79ca78781 | |||
| e08333dba1 | |||
| 8705dd1df5 | |||
| 7b4da9d422 | |||
| e51b2fe2f3 | |||
| f8b4ce103f | |||
| e82b4b8817 | |||
| 36e9df82b0 | |||
| cbce9af00b |
+25
-11
@@ -1,11 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="pl">
|
<html lang="pl">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||||
|
|
||||||
<meta name="keywords" content="Stacjownik, TD2, Train Driver 2, stacjownik-td2, stacjownik, td2.info.pl" />
|
<meta
|
||||||
|
name="keywords"
|
||||||
|
content="Stacjownik, TD2, Train Driver 2, stacjownik-td2, stacjownik, td2.info.pl"
|
||||||
|
/>
|
||||||
<meta name="description" content="Pomocnik maszynisty i dyżurnego symulatora Train Driver 2" />
|
<meta name="description" content="Pomocnik maszynisty i dyżurnego symulatora Train Driver 2" />
|
||||||
|
|
||||||
<title>Stacjownik</title>
|
<title>Stacjownik</title>
|
||||||
@@ -18,10 +21,6 @@
|
|||||||
<meta name="msapplication-TileColor" content="#da532c" />
|
<meta name="msapplication-TileColor" content="#da532c" />
|
||||||
<meta name="theme-color" content="#222222" />
|
<meta name="theme-color" content="#222222" />
|
||||||
|
|
||||||
<link rel="icon" href="favicon-64.png" sizes="64x64" type="image/png" />
|
|
||||||
<link rel="icon" href="favicon-62.png" sizes="62x62" type="image/png" />
|
|
||||||
<link rel="icon" href="favicon-32.png" sizes="32x32" type="image/png" />
|
|
||||||
<link rel="icon" href="favicon-16.png" sizes="16x16" type="image/png" />
|
|
||||||
<link rel="icon" href="favicon.ico" />
|
<link rel="icon" href="favicon.ico" />
|
||||||
|
|
||||||
<!-- Static OpenGraph meta -->
|
<!-- Static OpenGraph meta -->
|
||||||
@@ -29,18 +28,33 @@
|
|||||||
<meta property="og:url" content="https://stacjownik-td2.web.app/" />
|
<meta property="og:url" content="https://stacjownik-td2.web.app/" />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:title" content="Stacjownik" />
|
<meta property="og:title" content="Stacjownik" />
|
||||||
<meta property="og:description" content="Pomocnik maszynisty i dyżurnego symulatora Train Driver 2" />
|
<meta
|
||||||
<meta property="og:image" content="https://raw.githubusercontent.com/Spythere/api/main/thumbnails/stacjownik.jpg" />
|
property="og:description"
|
||||||
|
content="Pomocnik maszynisty i dyżurnego symulatora Train Driver 2"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
property="og:image"
|
||||||
|
content="https://raw.githubusercontent.com/Spythere/api/main/thumbnails/stacjownik.jpg"
|
||||||
|
/>
|
||||||
<meta property="og:image:width" content="1200" />
|
<meta property="og:image:width" content="1200" />
|
||||||
<meta property="og:image:height" content="630" />
|
<meta property="og:image:height" content="630" />
|
||||||
<meta property="og:site_name" content="Stacjownik" />
|
<meta property="og:site_name" content="Stacjownik" />
|
||||||
|
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name="twitter:title" content="Stacjownik" />
|
<meta name="twitter:title" content="Stacjownik" />
|
||||||
<meta name="twitter:description" content="Pomocnik maszynisty i dyżurnego symulatora Train Driver 2" />
|
<meta
|
||||||
<meta name="twitter:image" content="https://raw.githubusercontent.com/Spythere/api/main/thumbnails/stacjownik.jpg" />
|
name="twitter:description"
|
||||||
|
content="Pomocnik maszynisty i dyżurnego symulatora Train Driver 2"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
name="twitter:image"
|
||||||
|
content="https://raw.githubusercontent.com/Spythere/api/main/thumbnails/stacjownik.jpg"
|
||||||
|
/>
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@500;700&display=swap" rel="stylesheet" />
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Quicksand:wght@500;700&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.17.1",
|
"version": "1.18.4",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.17.1",
|
"version": "1.18.4",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.32.2",
|
"core-js": "^3.32.2",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.18.2",
|
"version": "1.18.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<svg width="256" height="213" viewBox="0 0 256 213" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_d_1571_41)">
|
||||||
|
<path d="M217.048 55.9333L238 80.4039L128 194.6L18 80.4039L38.9524 55.9333L71.6905 18.6H128H184.31L217.048 55.9333Z" fill="#F47FFF"/>
|
||||||
|
<path d="M238 80.4039L217.048 55.9333L184.31 18.6M238 80.4039L128 194.6M238 80.4039H164.536M128 194.6L18 80.4039M128 194.6L91.4641 80.4039M128 194.6L164.536 80.4039M184.31 18.6H128M184.31 18.6L164.536 80.4039M18 80.4039L38.9524 55.9333L71.6905 18.6M18 80.4039H91.4641M71.6905 18.6L91.4641 80.4039M71.6905 18.6H128M91.4641 80.4039H128H164.536M91.4641 80.4039L128 18.6M128 18.6L164.536 80.4039" stroke="#ECECEC" stroke-width="7.45763" stroke-linejoin="round"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_1571_41" x="0.367179" y="0.967155" width="255.266" height="211.266" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="6.952"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0.956863 0 0 0 0 0.498039 0 0 0 0 1 0 0 0 1 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1571_41"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1571_41" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="18px" height="18px"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1.41 16.09V20h-2.67v-1.93c-1.71-.36-3.16-1.46-3.27-3.4h1.96c.1 1.05.82 1.87 2.65 1.87 1.96 0 2.4-.98 2.4-1.59 0-.83-.44-1.61-2.67-2.14-2.48-.6-4.18-1.62-4.18-3.67 0-1.72 1.39-2.84 3.11-3.21V4h2.67v1.95c1.86.45 2.79 1.86 2.85 3.39H14.3c-.05-1.11-.64-1.87-2.22-1.87-1.5 0-2.4.68-2.4 1.64 0 .84.65 1.39 2.67 1.91s4.18 1.39 4.18 3.91c-.01 1.83-1.38 2.83-3.12 3.16z"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 582 B |
@@ -1,3 +1 @@
|
|||||||
<svg width="144" height="144" viewBox="0 0 144 144" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="18px" height="18px"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1.41 16.09V20h-2.67v-1.93c-1.71-.36-3.16-1.46-3.27-3.4h1.96c.1 1.05.82 1.87 2.65 1.87 1.96 0 2.4-.98 2.4-1.59 0-.83-.44-1.61-2.67-2.14-2.48-.6-4.18-1.62-4.18-3.67 0-1.72 1.39-2.84 3.11-3.21V4h2.67v1.95c1.86.45 2.79 1.86 2.85 3.39H14.3c-.05-1.11-.64-1.87-2.22-1.87-1.5 0-2.4.68-2.4 1.64 0 .84.65 1.39 2.67 1.91s4.18 1.39 4.18 3.91c-.01 1.83-1.38 2.83-3.12 3.16z"/></svg>
|
||||||
<path d="M67.4283 9.79351L67.8252 31.2232H79.5983L79.8628 9.79351H67.4283ZM67.8252 110.989L67.4283 132.816H79.8628L79.466 110.989H67.8252ZM91.6359 51.33L103.938 43.7899C102.439 40.527 100.322 37.3963 97.5886 34.3979C94.9429 31.3995 91.5918 28.9303 87.5352 26.9901C83.5667 25.05 78.8046 24.0799 73.2487 24.0799C67.6929 24.0799 62.7103 25.1382 58.3009 27.2547C53.8915 29.3712 50.4081 32.1932 47.8506 35.7207C45.3814 39.2483 44.1467 43.1726 44.1467 47.4938C44.1467 51.9032 44.9404 55.6512 46.5278 58.7378C48.1152 61.8243 50.1435 64.47 52.6128 66.6747C55.082 68.7912 57.6836 70.5549 60.4174 71.9659C63.2394 73.2888 65.7969 74.347 68.0897 75.1407C71.6173 76.4635 74.9243 77.8745 78.0109 79.3737C81.1856 80.8729 83.7431 82.7249 85.6832 84.9296C87.7115 87.0461 88.7257 89.824 88.7257 93.2633C88.7257 95.9089 88.1966 98.2018 87.1383 100.142C86.1683 101.994 84.625 103.405 82.5085 104.375C80.4801 105.345 77.8786 105.83 74.7038 105.83C71.0881 105.83 67.8693 105.08 65.0473 103.581C62.3134 102.082 59.8001 99.9215 57.5072 97.0995C55.2143 94.2775 53.0978 90.8381 51.1577 86.7815L39.12 94.5861C41.0602 99.3483 43.7499 103.581 47.1892 107.285C50.6286 110.989 54.6411 113.943 59.2269 116.148C63.8126 118.265 68.7512 119.323 74.0424 119.323C80.6565 119.323 86.2564 118.265 90.8422 116.148C95.428 113.943 98.9555 110.813 101.425 106.756C103.894 102.699 105.129 97.9814 105.129 92.6019C105.129 88.4571 104.423 84.8414 103.012 81.7548C101.601 78.6682 99.7492 76.0667 97.4563 73.9502C95.1634 71.7455 92.606 69.8935 89.784 68.3943C87.0501 66.8951 84.3604 65.6605 81.7148 64.6904C78.0109 63.2794 74.5275 61.8684 71.2645 60.4574C68.0016 59.0464 65.3559 57.3709 63.3276 55.4307C61.2993 53.4906 60.2851 51.0213 60.2851 48.0229C60.2851 45.7301 60.7261 43.7899 61.6079 42.2025C62.578 40.527 64.0331 39.2483 65.9732 38.3664C68.0016 37.4845 70.559 37.0436 73.6456 37.0436C76.644 37.0436 79.2455 37.705 81.4502 39.0278C83.6549 40.3506 85.5509 42.1144 87.1383 44.319C88.8139 46.4356 90.3131 48.7725 91.6359 51.33Z" fill="white"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 582 B |
@@ -0,0 +1,48 @@
|
|||||||
|
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="512" height="512" rx="256" fill="#121212"/>
|
||||||
|
<rect x="325.818" y="405.665" width="7.11086" height="143.867" rx="3.55543" transform="rotate(90 325.818 405.665)" fill="white"/>
|
||||||
|
<rect x="361.785" y="430.553" width="10.6663" height="208.608" rx="5.33314" transform="rotate(90 361.785 430.553)" fill="white"/>
|
||||||
|
<g filter="url(#filter0_d_272_208)">
|
||||||
|
<rect width="25.0328" height="117.468" rx="12.5164" transform="matrix(0.711174 0.703016 -0.711174 0.703016 211.54 363)" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter1_d_272_208)">
|
||||||
|
<rect width="25.0328" height="117.468" rx="12.5164" transform="matrix(-0.711174 0.703016 0.711174 0.703016 300.46 363)" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter2_d_272_208)">
|
||||||
|
<rect x="139.352" y="65.4912" width="232.66" height="325.893" rx="41.5866" stroke="#7A7A7A" stroke-width="8.31733"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M135.193 107.078C135.193 81.8134 155.674 61.3325 180.938 61.3325H330.425C355.69 61.3325 376.171 81.8134 376.171 107.078V349.797C376.171 375.062 355.69 395.543 330.426 395.543H180.938C155.674 395.543 135.193 375.062 135.193 349.797V107.078ZM208.217 338.656C208.217 352.401 196.774 363.544 182.659 363.544C168.543 363.544 157.1 352.401 157.1 338.656C157.1 324.91 168.543 313.768 182.659 313.768C196.774 313.768 208.217 324.91 208.217 338.656ZM328.706 363.544C342.821 363.544 354.264 352.401 354.264 338.656C354.264 324.91 342.821 313.768 328.706 313.768C314.591 313.768 303.148 324.91 303.148 338.656C303.148 352.401 314.591 363.544 328.706 363.544ZM248.38 136.323C248.38 132.07 244.932 128.622 240.679 128.622H164.802C160.549 128.622 157.101 132.07 157.101 136.323V203.223C157.101 207.476 160.549 210.924 164.802 210.924H240.679C244.932 210.924 248.38 207.476 248.38 203.223V136.323ZM346.563 128.622C350.817 128.622 354.265 132.07 354.265 136.323V203.223C354.265 207.476 350.817 210.924 346.563 210.924H270.686C266.433 210.924 262.985 207.476 262.985 203.223V136.323C262.985 132.07 266.433 128.622 270.686 128.622H346.563Z" fill="white"/>
|
||||||
|
<ellipse cx="255.682" cy="64.888" rx="25.5582" ry="24.888" fill="#F3F1F1"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_d_272_208" x="106.676" y="341.617" width="143.99" height="142.947" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="13.269"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_272_208"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_272_208" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter1_d_272_208" x="261.334" y="341.617" width="143.99" height="142.947" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="13.269"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_272_208"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_272_208" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter2_d_272_208" x="110.241" y="15.048" width="290.882" height="405.446" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="12.476"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_272_208"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_272_208" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.2 KiB |
+7
-42
@@ -1,33 +1,7 @@
|
|||||||
@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/animations.scss';
|
||||||
// VUE ROUTE CHANGE ANIMATION
|
|
||||||
.view-anim {
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
opacity: 0.02;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: all $animDuration $animType;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-anim {
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: all $animDuration $animType;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
transform: translateY(-25%);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.route {
|
.route {
|
||||||
margin: 0 0.2em;
|
margin: 0 0.2em;
|
||||||
@@ -56,24 +30,15 @@
|
|||||||
|
|
||||||
// CONTAINER
|
// CONTAINER
|
||||||
.app_container {
|
.app_container {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-flow: column;
|
grid-template-rows: auto 1fr auto;
|
||||||
|
grid-template-columns: 100%;
|
||||||
|
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
header {
|
.app_main {
|
||||||
flex: 0 0 auto;
|
padding: 0 0.5em;
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
|
|
||||||
padding: 0 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
flex: 0 1 0.2em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning {
|
.warning {
|
||||||
|
|||||||
+6
-9
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<main class="app_main">
|
<main class="app_main">
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<keep-alive exclude="JournalView">
|
<keep-alive exclude="JournalView,SceneryView">
|
||||||
<component :is="Component" :key="$route.name" />
|
<component :is="Component" :key="$route.name" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</router-view>
|
</router-view>
|
||||||
@@ -39,12 +39,12 @@ import Clock from './components/App/Clock.vue';
|
|||||||
import packageInfo from '.././package.json';
|
import packageInfo from '.././package.json';
|
||||||
import { regions } from './data/options.json';
|
import { regions } from './data/options.json';
|
||||||
|
|
||||||
import { useStore } from './store/store';
|
import { useStore } from './store/mainStore';
|
||||||
import StatusIndicator from './components/App/StatusIndicator.vue';
|
import StatusIndicator from './components/App/StatusIndicator.vue';
|
||||||
import TrainModal from './components/Global/TrainModal.vue';
|
import TrainModal from './components/Global/TrainModal.vue';
|
||||||
import StorageManager from './scripts/managers/storageManager';
|
|
||||||
import AppHeader from './components/App/AppHeader.vue';
|
import AppHeader from './components/App/AppHeader.vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import StorageManager from './managers/storageManager';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@@ -72,12 +72,9 @@ export default defineComponent({
|
|||||||
window.addEventListener('offline', () => {
|
window.addEventListener('offline', () => {
|
||||||
this.store.isOffline = true;
|
this.store.isOffline = true;
|
||||||
|
|
||||||
this.store.apiData = {
|
this.store.activeData.activeSceneries = [];
|
||||||
stations: [],
|
this.store.activeData.trains = [];
|
||||||
dispatchers: [],
|
this.store.activeData.connectedSocketCount = 0;
|
||||||
trains: [],
|
|
||||||
connectedSocketCount: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
this.store.setStatuses();
|
this.store.setStatuses();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/mainStore';
|
||||||
import StatusIndicator from './StatusIndicator.vue';
|
import StatusIndicator from './StatusIndicator.vue';
|
||||||
import Clock from './Clock.vue';
|
import Clock from './Clock.vue';
|
||||||
import RegionDropdown from '../Global/RegionDropdown.vue';
|
import RegionDropdown from '../Global/RegionDropdown.vue';
|
||||||
@@ -96,11 +96,13 @@ export default defineComponent({
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
onlineTrainsCount() {
|
onlineTrainsCount() {
|
||||||
return this.store.trainList.filter((train) => train.online).length;
|
return this.store.trainList.filter((train) => train.region == this.store.region.id).length;
|
||||||
},
|
},
|
||||||
|
|
||||||
onlineDispatchersCount() {
|
onlineDispatchersCount() {
|
||||||
return this.store.onlineSceneryList.length;
|
return this.store.onlineSceneryList.filter(
|
||||||
|
(scenery) => scenery.region == this.store.region.id
|
||||||
|
).length;
|
||||||
},
|
},
|
||||||
|
|
||||||
factorU() {
|
factorU() {
|
||||||
|
|||||||
@@ -194,9 +194,9 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
import { StoreState } from '../../store/typings';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/mainStore';
|
||||||
import { StoreState } from '../../scripts/interfaces/store/storeTypes';
|
import { Status } from '../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
data() {
|
data() {
|
||||||
@@ -204,7 +204,7 @@ export default defineComponent({
|
|||||||
tooltipActive: false,
|
tooltipActive: false,
|
||||||
indicator: {
|
indicator: {
|
||||||
offline: false,
|
offline: false,
|
||||||
status: DataStatus.Loading,
|
status: Status.Data.Loading,
|
||||||
message: 'data-status.S3'
|
message: 'data-status.S3'
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.setSignalStatus(DataStatus.Loading);
|
this.setSignalStatus(Status.Data.Loading);
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
@@ -240,44 +240,44 @@ export default defineComponent({
|
|||||||
const dispatcherDataStatus = statuses.dispatchers;
|
const dispatcherDataStatus = statuses.dispatchers;
|
||||||
|
|
||||||
if (this.store.isOffline) {
|
if (this.store.isOffline) {
|
||||||
this.setSignalStatus(DataStatus.Initialized);
|
this.setSignalStatus(Status.Data.Initialized);
|
||||||
this.indicator.status = DataStatus.Initialized;
|
this.indicator.status = Status.Data.Initialized;
|
||||||
this.indicator.message = 'data-status.S1-offline';
|
this.indicator.message = 'data-status.S1-offline';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectionStatus == DataStatus.Error) {
|
if (connectionStatus == Status.Data.Error) {
|
||||||
this.setSignalStatus(connectionStatus);
|
this.setSignalStatus(connectionStatus);
|
||||||
this.indicator.status = connectionStatus;
|
this.indicator.status = connectionStatus;
|
||||||
this.indicator.message = 'data-status.S1a-connection';
|
this.indicator.message = 'data-status.S1a-connection';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sceneryDataStatus == DataStatus.Error) {
|
if (sceneryDataStatus == Status.Data.Error) {
|
||||||
this.setSignalStatus(sceneryDataStatus);
|
this.setSignalStatus(sceneryDataStatus);
|
||||||
this.indicator.status = sceneryDataStatus;
|
this.indicator.status = sceneryDataStatus;
|
||||||
this.indicator.message = 'data-status.S1a-sceneries';
|
this.indicator.message = 'data-status.S1a-sceneries';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trainsDataStatus == DataStatus.Warning) {
|
if (trainsDataStatus == Status.Data.Warning) {
|
||||||
this.setSignalStatus(trainsDataStatus);
|
this.setSignalStatus(trainsDataStatus);
|
||||||
this.indicator.status = trainsDataStatus;
|
this.indicator.status = trainsDataStatus;
|
||||||
this.indicator.message = 'data-status.S5-trains';
|
this.indicator.message = 'data-status.S5-trains';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dispatcherDataStatus == DataStatus.Warning) {
|
if (dispatcherDataStatus == Status.Data.Warning) {
|
||||||
this.setSignalStatus(dispatcherDataStatus);
|
this.setSignalStatus(dispatcherDataStatus);
|
||||||
this.indicator.status = dispatcherDataStatus;
|
this.indicator.status = dispatcherDataStatus;
|
||||||
this.indicator.message = 'data-status.S5-dispatchers';
|
this.indicator.message = 'data-status.S5-dispatchers';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sceneryDataStatus == DataStatus.Loaded) {
|
if (sceneryDataStatus == Status.Data.Loaded) {
|
||||||
this.setSignalStatus(DataStatus.Loaded);
|
this.setSignalStatus(Status.Data.Loaded);
|
||||||
|
|
||||||
this.indicator.status = DataStatus.Loaded;
|
this.indicator.status = Status.Data.Loaded;
|
||||||
this.indicator.message = 'data-status.S2';
|
this.indicator.message = 'data-status.S2';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -285,31 +285,31 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
setSignalStatus(status: DataStatus) {
|
setSignalStatus(status: Status.Data) {
|
||||||
this.greenLight = false;
|
this.greenLight = false;
|
||||||
this.greenBlinkLight = false;
|
this.greenBlinkLight = false;
|
||||||
this.redTopLight = false;
|
this.redTopLight = false;
|
||||||
this.orangeLight = false;
|
this.orangeLight = false;
|
||||||
this.redBottomLight = false;
|
this.redBottomLight = false;
|
||||||
|
|
||||||
if (status == DataStatus.Initialized) {
|
if (status == Status.Data.Initialized) {
|
||||||
this.redTopLight = true;
|
this.redTopLight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Loaded) {
|
if (status == Status.Data.Loaded) {
|
||||||
this.greenLight = true;
|
this.greenLight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Warning) {
|
if (status == Status.Data.Warning) {
|
||||||
this.orangeLight = true;
|
this.orangeLight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Error) {
|
if (status == Status.Data.Error) {
|
||||||
this.redTopLight = true;
|
this.redTopLight = true;
|
||||||
this.redBottomLight = true;
|
this.redBottomLight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Loading) {
|
if (status == Status.Data.Loading) {
|
||||||
this.greenBlinkLight = true;
|
this.greenBlinkLight = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<transition name="modal-anim" tag="div" class="modal">
|
||||||
|
<div class="body" v-if="isOpen">
|
||||||
|
<div class="background" @click="toggleModal(false)"></div>
|
||||||
|
<div class="wrapper" ref="wrapper" tabindex="0">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
<div class="tab-exit" ref="exit" tabindex="0" @focus="toggleModal(false)"></div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { useStore } from '../../store/mainStore';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
emits: ['toggleModal'],
|
||||||
|
|
||||||
|
props: {
|
||||||
|
isOpen: Boolean
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
store: useStore()
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
isOpen(v) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (v) (this.$refs['wrapper'] as HTMLElement).focus();
|
||||||
|
else (this.store.modalLastClickedTarget as HTMLElement)?.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
toggleModal(value: boolean) {
|
||||||
|
this.$emit('toggleModal', value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/responsive.scss';
|
||||||
|
|
||||||
|
.body {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 200;
|
||||||
|
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.background {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
background-color: rgba(0, 0, 0, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
box-shadow: 0 0 15px 10px #333333;
|
||||||
|
|
||||||
|
width: 95%;
|
||||||
|
max-width: 800px;
|
||||||
|
max-height: 95vh;
|
||||||
|
|
||||||
|
& > :slotted(div) {
|
||||||
|
max-height: 95vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
.wrapper {
|
||||||
|
top: 0;
|
||||||
|
transform: translate(-50%, 1em);
|
||||||
|
max-height: 90vh;
|
||||||
|
|
||||||
|
& > :slotted(div) {
|
||||||
|
max-height: 90vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
<template>
|
||||||
|
<div class="donation-modal" @keydown.esc="toggleModal(false)">
|
||||||
|
<button
|
||||||
|
class="modal_button action btn--image"
|
||||||
|
ref="btn"
|
||||||
|
@click="toggleModal(true)"
|
||||||
|
@focus="toggleModal(false)"
|
||||||
|
>
|
||||||
|
<img src="/images/icon-dollar.svg" alt="dollar donation icon" />
|
||||||
|
<span>{{ $t('donations.button-title') }}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<AnimatedModal :isOpen="isModalOpen" @toggleModal="toggleModal">
|
||||||
|
<div class="modal_content">
|
||||||
|
<div class="modal_main">
|
||||||
|
<h1 v-html="$t('donations.header')"></h1>
|
||||||
|
<br />
|
||||||
|
<p v-html="$t('donations.p1')"></p>
|
||||||
|
<br />
|
||||||
|
<i18n-t keypath="donations.p2" tag="p">
|
||||||
|
<template v-slot:b1>
|
||||||
|
<b>{{ $t('donations.p2-b1') }}</b>
|
||||||
|
</template>
|
||||||
|
<template v-slot:b2>
|
||||||
|
<b>{{ $t('donations.p2-b2') }}</b>
|
||||||
|
</template>
|
||||||
|
<template v-slot:b3>
|
||||||
|
<b>{{ $t('donations.p2-b3') }}</b>
|
||||||
|
</template>
|
||||||
|
<template v-slot:link>
|
||||||
|
<a href="https://discord.gg/x2mpNN3svk" target="_blank">
|
||||||
|
{{ $t('donations.p2-a1') }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
<br />
|
||||||
|
<p v-html="$t('donations.p3')"></p>
|
||||||
|
<br />
|
||||||
|
<i18n-t keypath="donations.p4" tag="p">
|
||||||
|
<template v-slot:img>
|
||||||
|
<img src="/images/icon-diamond.svg" alt="donator diamond icon" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:b1>
|
||||||
|
<b>{{ $t('donations.p4-b1') }}</b>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:b2>
|
||||||
|
<b>{{ $t('donations.p4-b2') }}</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
<br />
|
||||||
|
<i
|
||||||
|
v-html="$t('donations.p5')"
|
||||||
|
style="display: flex; justify-content: flex-end; text-align: right"
|
||||||
|
>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal_actions">
|
||||||
|
<button class="modal_button exit btn--image" @click="toggleModal(false)">
|
||||||
|
<img src="/images/icon-exit.svg" alt="dollar donation icon" />
|
||||||
|
{{ $t('donations.action-exit') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<form action="https://www.paypal.com/donate" method="post">
|
||||||
|
<input type="hidden" name="hosted_button_id" value="EDB3SKFAHXFTW" />
|
||||||
|
|
||||||
|
<button class="modal_button action btn--image" @click="toggleModal(false)">
|
||||||
|
<img src="/images/icon-dollar.svg" alt="dollar donation icon" />
|
||||||
|
{{ $t('donations.action-confirm') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AnimatedModal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import AnimatedModal from './AnimatedModal.vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
isModalOpen: Boolean
|
||||||
|
},
|
||||||
|
emits: ['toggleModal'],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
toggleModal(value: boolean) {
|
||||||
|
this.$emit('toggleModal', value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: { AnimatedModal }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/responsive.scss';
|
||||||
|
|
||||||
|
.modal_button {
|
||||||
|
&.action {
|
||||||
|
$btnColor: #254069;
|
||||||
|
|
||||||
|
background-color: $btnColor;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($btnColor, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.exit {
|
||||||
|
$btnColor: crimson;
|
||||||
|
|
||||||
|
background-color: $btnColor;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($btnColor, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-logo {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
|
||||||
|
width: 6em;
|
||||||
|
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal_content {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 1fr auto;
|
||||||
|
gap: 1em;
|
||||||
|
|
||||||
|
font-size: 1.1em;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 1.95em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal_main {
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-height: 20px;
|
||||||
|
margin-right: 5px;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal_actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(13em, 1fr));
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
form button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -29,8 +29,8 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, Ref, ref } from 'vue';
|
import { defineComponent, Ref, ref } from 'vue';
|
||||||
import { useStore } from '../../store/store';
|
|
||||||
import { regions as regionsJSON } from '../../data/options.json';
|
import { regions as regionsJSON } from '../../data/options.json';
|
||||||
|
import { useStore } from '../../store/mainStore';
|
||||||
|
|
||||||
interface Item {
|
interface Item {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -67,16 +67,15 @@ export default defineComponent({
|
|||||||
selectedItem() {
|
selectedItem() {
|
||||||
return this.regionList[this.selectedItemIndex] || null;
|
return this.regionList[this.selectedItemIndex] || null;
|
||||||
},
|
},
|
||||||
|
|
||||||
regionList() {
|
regionList() {
|
||||||
return regionsJSON.map((region) => {
|
return regionsJSON.map((region) => {
|
||||||
const regionStationCount =
|
const regionStationCount = this.store.onlineSceneryList.filter(
|
||||||
this.store.apiData.stations?.filter(
|
(scenery) => scenery.region == region.id
|
||||||
(station) => station.region == region.id && station.isOnline
|
).length;
|
||||||
).length || 0;
|
|
||||||
|
|
||||||
const regionTrainCount =
|
const regionTrainCount =
|
||||||
this.store.apiData.trains?.filter((train) => train.region == region.id && train.online)
|
this.store.trainList.filter((train) => train.region == region.id).length || 0;
|
||||||
.length || 0;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: region.id,
|
id: region.id,
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<span class="status-badge" :class="statusID" v-if="isOnline">
|
<span class="status-badge" :class="statusName" v-if="isOnline">
|
||||||
{{ $t(`status.${statusID}`) }}
|
{{ $t(`status.${statusName}`) }}
|
||||||
{{ statusID == 'online' ? timestampToString(statusTimestamp!) : '' }}
|
{{
|
||||||
|
statusName == 'online' && dispatcherStatus && dispatcherStatus > 5
|
||||||
|
? timestampToString(dispatcherStatus)
|
||||||
|
: ''
|
||||||
|
}}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="status-badge free" v-else>
|
<span class="status-badge free" v-else>
|
||||||
@@ -10,22 +14,61 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import dateMixin from '../../mixins/dateMixin';
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
|
import { Status } from '../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
statusID: {
|
dispatcherStatus: {
|
||||||
type: String
|
type: Number as PropType<Status.ActiveDispatcher | number>
|
||||||
},
|
},
|
||||||
statusTimestamp: {
|
dispatcherTimestamp: {
|
||||||
type: Number
|
type: Number as PropType<number | null>
|
||||||
},
|
},
|
||||||
isOnline: {
|
isOnline: {
|
||||||
type: Boolean
|
type: Boolean
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mixins: [dateMixin]
|
mixins: [dateMixin],
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
statusName() {
|
||||||
|
if (this.dispatcherStatus === undefined) return 'free';
|
||||||
|
|
||||||
|
switch (this.dispatcherStatus) {
|
||||||
|
case Status.ActiveDispatcher.AFK:
|
||||||
|
return 'afk';
|
||||||
|
|
||||||
|
case Status.ActiveDispatcher.NO_LIMIT:
|
||||||
|
return 'no-limit';
|
||||||
|
|
||||||
|
case Status.ActiveDispatcher.ENDING:
|
||||||
|
return 'ending';
|
||||||
|
|
||||||
|
case Status.ActiveDispatcher.INVALID:
|
||||||
|
return 'invalid';
|
||||||
|
|
||||||
|
case Status.ActiveDispatcher.NOT_LOGGED_IN:
|
||||||
|
return 'not-signed';
|
||||||
|
|
||||||
|
case Status.ActiveDispatcher.NO_SPACE:
|
||||||
|
return 'no-space';
|
||||||
|
|
||||||
|
case Status.ActiveDispatcher.UNAVAILABLE:
|
||||||
|
return 'unavailable';
|
||||||
|
|
||||||
|
case Status.ActiveDispatcher.UNKNOWN:
|
||||||
|
return 'unknown';
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (this.dispatcherTimestamp != null && this.dispatcherStatus >= Date.now() + 25500000)
|
||||||
|
return 'no-limit';
|
||||||
|
|
||||||
|
return 'online';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -34,10 +77,10 @@ $free: #8a8a8a;
|
|||||||
$ending: #e6c300;
|
$ending: #e6c300;
|
||||||
$no-limit: #117fc9;
|
$no-limit: #117fc9;
|
||||||
$unav: #ff3d5d;
|
$unav: #ff3d5d;
|
||||||
$brb: #e6a100;
|
$afk: #e6a100;
|
||||||
$no-space: #222;
|
$no-space: #222;
|
||||||
$online: #09a116;
|
$online: #09a116;
|
||||||
$unknown: rgb(185, 60, 60);
|
$unknown: #b93c3c;
|
||||||
|
|
||||||
.status-badge {
|
.status-badge {
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
@@ -69,8 +112,8 @@ $unknown: rgb(185, 60, 60);
|
|||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.brb {
|
&.afk {
|
||||||
background-color: $brb;
|
background-color: $afk;
|
||||||
color: black;
|
color: black;
|
||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
}
|
}
|
||||||
@@ -82,7 +125,8 @@ $unknown: rgb(185, 60, 60);
|
|||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.unknown {
|
&.unknown,
|
||||||
|
&.invalid {
|
||||||
background-color: $unknown;
|
background-color: $unknown;
|
||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,8 +50,8 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PropType, defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/mainStore';
|
||||||
import { RollingStockInfo } from '../../scripts/interfaces/github_api/StockInfoGithubData';
|
import { API } from '../../typings/api';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -71,7 +71,7 @@ export default defineComponent({
|
|||||||
onImageError(event: Event, stockName: string) {
|
onImageError(event: Event, stockName: string) {
|
||||||
const fallbackName =
|
const fallbackName =
|
||||||
Object.keys(this.store.rollingStockData!.info).find((type) => {
|
Object.keys(this.store.rollingStockData!.info).find((type) => {
|
||||||
return this.store.rollingStockData!.info[type as keyof RollingStockInfo].find(
|
return this.store.rollingStockData!.info[type as keyof API.RollingStock.Info].find(
|
||||||
(v) => v[0] === stockName.split(':')[0]
|
(v) => v[0] === stockName.split(':')[0]
|
||||||
);
|
);
|
||||||
}) || 'vehicle-unknown';
|
}) || 'vehicle-unknown';
|
||||||
|
|||||||
@@ -51,16 +51,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import dateMixin from '../../mixins/dateMixin';
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
import TrainStop from '../../scripts/interfaces/TrainStop';
|
import { TrainStop } from '../../store/typings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [dateMixin],
|
mixins: [dateMixin],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
stop: {
|
stop: {
|
||||||
type: Object as () => TrainStop,
|
type: Object as PropType<TrainStop>,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||||
import trainInfoMixin from '../../mixins/trainInfoMixin';
|
import trainInfoMixin from '../../mixins/trainInfoMixin';
|
||||||
import { useStore } from '../../store/store';
|
|
||||||
import TrainInfo from '../TrainsView/TrainInfo.vue';
|
import TrainInfo from '../TrainsView/TrainInfo.vue';
|
||||||
import TrainSchedule from '../TrainsView/TrainSchedule.vue';
|
import TrainSchedule from '../TrainsView/TrainSchedule.vue';
|
||||||
|
|
||||||
@@ -30,31 +29,12 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
return {
|
|
||||||
store
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
activated() {
|
activated() {
|
||||||
const contentEl = this.$refs['content'] as HTMLElement;
|
const contentEl = this.$refs['content'] as HTMLElement;
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
contentEl.focus();
|
contentEl.focus();
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
handleContentScroll(e: Event) {
|
|
||||||
const trainInfoCompHeight: number = (
|
|
||||||
this.$refs['trainInfo'] as any
|
|
||||||
).$el.getBoundingClientRect().height;
|
|
||||||
|
|
||||||
const posTop = (e.target as HTMLElement).scrollTop;
|
|
||||||
this.isTopBarVisible = posTop > trainInfoCompHeight;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/mainStore';
|
||||||
import { RollingStockInfo } from '../../scripts/interfaces/github_api/StockInfoGithubData';
|
import { API } from '../../typings/api';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -54,7 +54,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
Object.keys(this.store.rollingStockData.info).find((type) => {
|
Object.keys(this.store.rollingStockData.info).find((type) => {
|
||||||
return this.store.rollingStockData?.info[type as keyof RollingStockInfo].find(
|
return this.store.rollingStockData?.info[type as keyof API.RollingStock.Info].find(
|
||||||
(v) => v[0] === this.name.split(':')[0]
|
(v) => v[0] === this.name.split(':')[0]
|
||||||
);
|
);
|
||||||
}) || 'vehicle-unknown'
|
}) || 'vehicle-unknown'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="daily-stats">
|
<section class="daily-stats">
|
||||||
<span :data-active="statsStatus">
|
<span :data-active="statsStatus">
|
||||||
<b v-if="statsStatus == DataStatus.Loading">
|
<b v-if="statsStatus == Status.Data.Loading">
|
||||||
{{ $t('app.loading') }}
|
{{ $t('app.loading') }}
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
@@ -32,24 +32,26 @@
|
|||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="stats.timetableId">
|
<div v-if="stats.maxTimetable">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-longest">
|
<i18n-t keypath="journal.timetable-stats-longest">
|
||||||
<template #id>
|
<template #id>
|
||||||
<router-link :to="`/journal/timetables?timetableId=${stats.timetableId}`">
|
<router-link :to="`/journal/timetables?timetableId=${stats.maxTimetable.id}`">
|
||||||
<b>{{ stats.timetableId }}</b>
|
<b>{{ stats.maxTimetable.id }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template #author>
|
<template #author>
|
||||||
<router-link :to="`/journal/dispatchers?dispatcherName=${stats.timetableAuthor}`">
|
<router-link
|
||||||
<b>{{ stats.timetableAuthor }}</b>
|
:to="`/journal/dispatchers?dispatcherName=${stats.maxTimetable.authorName}`"
|
||||||
|
>
|
||||||
|
<b>{{ stats.maxTimetable.authorName }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template #driver>
|
<template #driver>
|
||||||
<b class="text--primary">{{ stats.timetableDriver }}</b>
|
<b class="text--primary">{{ stats.maxTimetable.driverName }}</b>
|
||||||
</template>
|
</template>
|
||||||
<template #distance>
|
<template #distance>
|
||||||
<b class="text--primary">{{ stats.timetableRouteDistance }} km</b>
|
<b class="text--primary">{{ stats.maxTimetable.routeDistance }} km</b>
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
@@ -134,12 +136,10 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import dateMixin from '../../mixins/dateMixin';
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
|
||||||
import {
|
|
||||||
ITimetablesDailyStats,
|
|
||||||
ITimetablesDailyStatsResponse
|
|
||||||
} from '../../scripts/interfaces/api/StatsAPIData';
|
|
||||||
import { URLs } from '../../scripts/utils/apiURLs';
|
import { URLs } from '../../scripts/utils/apiURLs';
|
||||||
|
import { API } from '../../typings/api';
|
||||||
|
import { Status } from '../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [dateMixin],
|
mixins: [dateMixin],
|
||||||
@@ -147,22 +147,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
DataStatus,
|
Status,
|
||||||
statsStatus: DataStatus.Loading,
|
statsStatus: Status.Data.Loading,
|
||||||
intervalId: -1,
|
intervalId: -1,
|
||||||
|
|
||||||
stats: {
|
stats: {} as API.DailyStats.Response
|
||||||
totalTimetables: 0,
|
|
||||||
distanceSum: 0,
|
|
||||||
distanceAvg: 0,
|
|
||||||
timetableAuthor: '',
|
|
||||||
timetableDriver: '',
|
|
||||||
timetableId: 0,
|
|
||||||
timetableRouteDistance: 0,
|
|
||||||
longestDuties: [],
|
|
||||||
mostActiveDrivers: [],
|
|
||||||
mostActiveDispatchers: []
|
|
||||||
} as ITimetablesDailyStats
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -187,28 +176,30 @@ export default defineComponent({
|
|||||||
methods: {
|
methods: {
|
||||||
async fetchDailyTimetableStats() {
|
async fetchDailyTimetableStats() {
|
||||||
try {
|
try {
|
||||||
const res: ITimetablesDailyStatsResponse = await (
|
const res: API.DailyStats.Response = await (
|
||||||
await axios.get(`${URLs.stacjownikAPI}/api/getDailyTimetableStats`)
|
await axios.get(`${URLs.stacjownikAPI}/api/getDailyTimetableStats`)
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
this.stats = {
|
// this.stats = {
|
||||||
totalTimetables: res.totalTimetables,
|
// totalTimetables: res.totalTimetables,
|
||||||
distanceSum: res.distanceSum,
|
// distanceSum: res.distanceSum,
|
||||||
distanceAvg: res.distanceAvg,
|
// distanceAvg: res.distanceAvg,
|
||||||
timetableAuthor: res.maxTimetable?.authorName || '',
|
// // timetableAuthor: res.maxTimetable?.authorName || '',
|
||||||
timetableDriver: res.maxTimetable?.driverName || '',
|
// // timetableDriver: res.maxTimetable?.driverName || '',
|
||||||
timetableId: res.maxTimetable?.id || 0,
|
// // timetableId: res.maxTimetable?.id || 0,
|
||||||
timetableRouteDistance: res.maxTimetable?.routeDistance || 0,
|
// // timetableRouteDistance: res.maxTimetable?.routeDistance || 0,
|
||||||
|
|
||||||
mostActiveDispatchers: res.mostActiveDispatchers,
|
// mostActiveDispatchers: res.mostActiveDispatchers,
|
||||||
mostActiveDrivers: res.mostActiveDrivers,
|
// mostActiveDrivers: res.mostActiveDrivers,
|
||||||
longestDuties: res.longestDuties
|
// longestDuties: res.longestDuties
|
||||||
};
|
// };
|
||||||
|
|
||||||
this.statsStatus = DataStatus.Loaded;
|
this.stats = res;
|
||||||
|
|
||||||
|
this.statsStatus = Status.Data.Loaded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Ups! Wystąpił błąd podczas pobierania statystyk rozkładów jazdy...');
|
console.error('Ups! Wystąpił błąd podczas pobierania statystyk rozkładów jazdy...');
|
||||||
this.statsStatus = DataStatus.Error;
|
this.statsStatus = Status.Data.Error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -52,11 +52,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { DispatcherStatsAPIData } from '../../scripts/interfaces/api/DispatcherStatsAPIData';
|
|
||||||
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/mainStore';
|
||||||
import Loading from '../Global/Loading.vue';
|
import Loading from '../Global/Loading.vue';
|
||||||
|
import { API } from '../../typings/api';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { Loading },
|
components: { Loading },
|
||||||
@@ -73,7 +72,7 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
cardVisible: false,
|
cardVisible: false,
|
||||||
lastDispatcherName: '',
|
lastDispatcherName: '',
|
||||||
timetables: [] as TimetableHistory[]
|
timetables: [] as API.TimetableHistory.Response
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -90,13 +89,13 @@ export default defineComponent({
|
|||||||
this.store.dispatcherStatsData = undefined;
|
this.store.dispatcherStatsData = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const statsData: DispatcherStatsAPIData = await (
|
const statsData: API.DispatcherStats.Response = await (
|
||||||
await axios.get(
|
await axios.get(
|
||||||
`${URLs.stacjownikAPI}/api/getDispatcherInfo?name=${this.store.dispatcherStatsName}`
|
`${URLs.stacjownikAPI}/api/getDispatcherInfo?name=${this.store.dispatcherStatsName}`
|
||||||
)
|
)
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
const timetables: TimetableHistory[] = await (
|
const timetables: API.TimetableHistory.Response = await (
|
||||||
await axios.get(
|
await axios.get(
|
||||||
`${URLs.stacjownikAPI}/api/getTimetables?authorName=${this.store.dispatcherStatsName}`
|
`${URLs.stacjownikAPI}/api/getTimetables?authorName=${this.store.dispatcherStatsName}`
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
{{ $t('app.offline') }}
|
{{ $t('app.offline') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Loading v-else-if="dataStatus == DataStatus.Loading" />
|
<Loading v-else-if="dataStatus == Status.Data.Loading" />
|
||||||
|
|
||||||
<div v-else-if="dataStatus == DataStatus.Error" class="journal_warning error">
|
<div v-else-if="dataStatus == Status.Data.Error" class="journal_warning error">
|
||||||
{{ $t('app.error') }}
|
{{ $t('app.error') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -114,13 +114,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, PropType } from 'vue';
|
import { defineComponent, PropType } from 'vue';
|
||||||
import dateMixin from '../../mixins/dateMixin';
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
import { DispatcherHistory } from '../../scripts/interfaces/api/DispatchersAPIData';
|
|
||||||
import styleMixin from '../../mixins/styleMixin';
|
import styleMixin from '../../mixins/styleMixin';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
import { useStore } from '../../store/mainStore';
|
||||||
import { useStore } from '../../store/store';
|
|
||||||
import Loading from '../Global/Loading.vue';
|
import Loading from '../Global/Loading.vue';
|
||||||
import { regions } from '../../data/options.json';
|
import { regions } from '../../data/options.json';
|
||||||
import AddDataButton from '../Global/AddDataButton.vue';
|
import AddDataButton from '../Global/AddDataButton.vue';
|
||||||
|
import { API } from '../../typings/api';
|
||||||
|
import { Status } from '../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { Loading, AddDataButton },
|
components: { Loading, AddDataButton },
|
||||||
@@ -129,7 +129,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
props: {
|
props: {
|
||||||
dispatcherHistory: {
|
dispatcherHistory: {
|
||||||
type: Array as PropType<DispatcherHistory[]>,
|
type: Array as PropType<API.DispatcherHistory.Response>,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
scrollNoMoreData: {
|
scrollNoMoreData: {
|
||||||
@@ -142,13 +142,13 @@ export default defineComponent({
|
|||||||
type: Function as PropType<() => void>
|
type: Function as PropType<() => void>
|
||||||
},
|
},
|
||||||
dataStatus: {
|
dataStatus: {
|
||||||
type: Number as PropType<DataStatus>
|
type: Number as PropType<Status.Data>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
DataStatus,
|
Status,
|
||||||
store: useStore(),
|
store: useStore(),
|
||||||
regions
|
regions
|
||||||
};
|
};
|
||||||
@@ -166,7 +166,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
[] as (DispatcherHistory | string)[]
|
[] as (API.DispatcherHistory.Data | string)[]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -235,10 +235,6 @@ table.scenery-history-table {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 550px) {
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
|
|||||||
@@ -43,10 +43,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<b v-else-if="store.driverStatsStatus == DataStatus.Loading">{{
|
<b v-else-if="store.driverStatsStatus == Status.Data.Loading">{{
|
||||||
$t('journal.stats-loading')
|
$t('journal.stats-loading')
|
||||||
}}</b>
|
}}</b>
|
||||||
<b v-else-if="store.driverStatsStatus == DataStatus.Error">
|
<b v-else-if="store.driverStatsStatus == Status.Data.Error">
|
||||||
{{ $t('journal.stats-error ') }}
|
{{ $t('journal.stats-error ') }}
|
||||||
</b>
|
</b>
|
||||||
<b v-else>{{ $t('journal.driver-stats-info') }}</b>
|
<b v-else>{{ $t('journal.driver-stats-info') }}</b>
|
||||||
@@ -55,14 +55,14 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
import { useStore } from '../../store/mainStore';
|
||||||
import { useStore } from '../../store/store';
|
import { Status } from '../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
store: useStore(),
|
store: useStore(),
|
||||||
DataStatus
|
Status: Status
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -113,12 +113,11 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { defineComponent, inject, PropType } from 'vue';
|
import { defineComponent, inject, PropType } from 'vue';
|
||||||
import keyMixin from '../../mixins/keyMixin';
|
import keyMixin from '../../mixins/keyMixin';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
|
||||||
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/mainStore';
|
||||||
import { JournalFilterSection } from '../../scripts/enums/JournalFilterType';
|
import { Journal } from './typings';
|
||||||
import { JournalFilter } from '../../scripts/types/JournalTimetablesTypes';
|
import { API } from '../../typings/api';
|
||||||
|
import { Status } from '../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
emits: ['onSearchConfirm', 'onOptionsReset', 'onRefreshData'],
|
emits: ['onSearchConfirm', 'onOptionsReset', 'onRefreshData'],
|
||||||
@@ -131,13 +130,13 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
filters: {
|
filters: {
|
||||||
type: Array as PropType<JournalFilter[]>,
|
type: Array as PropType<Journal.TimetableFilter[]>,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
|
|
||||||
dataStatus: {
|
dataStatus: {
|
||||||
type: Number as PropType<DataStatus>,
|
type: Number as PropType<Status.Data>,
|
||||||
default: DataStatus.Initialized
|
default: -1
|
||||||
},
|
},
|
||||||
|
|
||||||
currentOptionsActive: {
|
currentOptionsActive: {
|
||||||
@@ -154,7 +153,6 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showOptions: false,
|
showOptions: false,
|
||||||
JournalFilterSection,
|
|
||||||
|
|
||||||
driverSuggestions: [] as string[],
|
driverSuggestions: [] as string[],
|
||||||
dispatcherSuggestions: [] as string[],
|
dispatcherSuggestions: [] as string[],
|
||||||
@@ -162,7 +160,7 @@ export default defineComponent({
|
|||||||
searchTimeout: 0,
|
searchTimeout: 0,
|
||||||
store: useStore(),
|
store: useStore(),
|
||||||
|
|
||||||
DataStatus
|
JournalFilterSection: Journal.FilterSection
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -170,7 +168,7 @@ 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 },
|
||||||
filterList: inject('filterList') as JournalFilter[] | undefined
|
filterList: inject('filterList') as Journal.TimetableFilter[] | undefined
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -212,23 +210,23 @@ export default defineComponent({
|
|||||||
this.store.driverStatsData = undefined;
|
this.store.driverStatsData = undefined;
|
||||||
|
|
||||||
if (!this.store.driverStatsName) {
|
if (!this.store.driverStatsName) {
|
||||||
this.store.driverStatsStatus = DataStatus.Initialized;
|
this.store.driverStatsStatus = Status.Data.Initialized;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.store.driverStatsStatus = DataStatus.Loading;
|
this.store.driverStatsStatus = Status.Data.Loading;
|
||||||
|
|
||||||
const statsData: DriverStatsAPIData = await (
|
const statsData: API.DriverStats.Response = await (
|
||||||
await axios.get(
|
await axios.get(
|
||||||
`${URLs.stacjownikAPI}/api/getDriverInfo?name=${this.store.driverStatsName}`
|
`${URLs.stacjownikAPI}/api/getDriverInfo?name=${this.store.driverStatsName}`
|
||||||
)
|
)
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
this.store.driverStatsData = statsData;
|
this.store.driverStatsData = statsData;
|
||||||
this.store.driverStatsStatus = DataStatus.Loaded;
|
this.store.driverStatsStatus = Status.Data.Loaded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.store.driverStatsStatus = DataStatus.Error;
|
this.store.driverStatsStatus = Status.Data.Error;
|
||||||
console.error('Ups! Wystąpił błąd przy próbie pobrania statystyk maszynisty! :/');
|
console.error('Ups! Wystąpił błąd przy próbie pobrania statystyk maszynisty! :/');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -270,7 +268,7 @@ export default defineComponent({
|
|||||||
this.$emit('onSearchConfirm');
|
this.$emit('onSearchConfirm');
|
||||||
},
|
},
|
||||||
|
|
||||||
onFilterChange(filter: JournalFilter) {
|
onFilterChange(filter: Journal.TimetableFilter) {
|
||||||
// this.journalFilterActive = filter;
|
// this.journalFilterActive = filter;
|
||||||
this.filterList
|
this.filterList
|
||||||
?.filter((f) => f.filterSection === filter.filterSection)
|
?.filter((f) => f.filterSection === filter.filterSection)
|
||||||
|
|||||||
@@ -29,10 +29,10 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, reactive, Ref, ref, watch } from 'vue';
|
import { computed, onMounted, reactive, Ref, ref, watch } from 'vue';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/mainStore';
|
||||||
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';
|
import StorageManager from '../../managers/storageManager';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
type TStatTab = 'daily' | 'driver';
|
type TStatTab = 'daily' | 'driver';
|
||||||
@@ -60,7 +60,8 @@ let data = reactive({
|
|||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
function onTabButtonClick(tab: TStatTab) {
|
function onTabButtonClick(tab: TStatTab) {
|
||||||
if (lastClickedTab.value == tab || !lastClickedTab.value || !areStatsOpen.value) areStatsOpen.value = !areStatsOpen.value;
|
if (lastClickedTab.value == tab || !lastClickedTab.value || !areStatsOpen.value)
|
||||||
|
areStatsOpen.value = !areStatsOpen.value;
|
||||||
|
|
||||||
if (tab == 'daily') {
|
if (tab == 'daily') {
|
||||||
StorageManager.setBooleanValue('dailyStatsOpen', areStatsOpen.value);
|
StorageManager.setBooleanValue('dailyStatsOpen', areStatsOpen.value);
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
{{ $t('app.offline') }}
|
{{ $t('app.offline') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Loading v-else-if="dataStatus == DataStatus.Loading" />
|
<Loading v-else-if="dataStatus == Status.Data.Loading" />
|
||||||
|
|
||||||
<div v-else-if="dataStatus == DataStatus.Error" class="journal_warning error">
|
<div v-else-if="dataStatus == Status.Data.Error" class="journal_warning error">
|
||||||
{{ $t('app.error') }}
|
{{ $t('app.error') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -38,20 +38,20 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, PropType } from 'vue';
|
import { defineComponent, PropType } from 'vue';
|
||||||
import { DataStatus } from '../../../scripts/enums/DataStatus';
|
|
||||||
import { TimetableHistory } from '../../../scripts/interfaces/api/TimetablesAPIData';
|
|
||||||
import { useStore } from '../../../store/store';
|
|
||||||
|
|
||||||
import Loading from '../../Global/Loading.vue';
|
import Loading from '../../Global/Loading.vue';
|
||||||
import AddDataButton from '../../Global/AddDataButton.vue';
|
import AddDataButton from '../../Global/AddDataButton.vue';
|
||||||
import TimetableHistoryList from './TimetableHistoryList.vue';
|
import TimetableHistoryList from './TimetableHistoryList.vue';
|
||||||
|
import { useStore } from '../../../store/mainStore';
|
||||||
|
import { Status } from '../../../typings/common';
|
||||||
|
import { API } from '../../../typings/api';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { Loading, AddDataButton, TimetableHistoryList },
|
components: { Loading, AddDataButton, TimetableHistoryList },
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
timetableHistory: {
|
timetableHistory: {
|
||||||
type: Array as PropType<TimetableHistory[]>,
|
type: Array as PropType<API.TimetableHistory.Response>,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
scrollNoMoreData: {
|
scrollNoMoreData: {
|
||||||
@@ -64,13 +64,13 @@ export default defineComponent({
|
|||||||
type: Function as PropType<() => void>
|
type: Function as PropType<() => void>
|
||||||
},
|
},
|
||||||
dataStatus: {
|
dataStatus: {
|
||||||
type: Number as PropType<DataStatus>
|
type: Number as PropType<Status.Data>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
DataStatus,
|
Status,
|
||||||
store: useStore()
|
store: useStore()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,8 +77,8 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PropType, defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import { TimetableHistory } from '../../../scripts/interfaces/api/TimetablesAPIData';
|
|
||||||
import StockList from '../../Global/StockList.vue';
|
import StockList from '../../Global/StockList.vue';
|
||||||
|
import { API } from '../../../typings/api';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { StockList },
|
components: { StockList },
|
||||||
@@ -88,7 +88,7 @@ export default defineComponent({
|
|||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
timetable: {
|
timetable: {
|
||||||
type: Object as PropType<TimetableHistory>,
|
type: Object as PropType<API.TimetableHistory.Data>,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -62,24 +62,24 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PropType, defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import { TimetableHistory } from '../../../scripts/interfaces/api/TimetablesAPIData';
|
|
||||||
|
|
||||||
import dateMixin from '../../../mixins/dateMixin';
|
import dateMixin from '../../../mixins/dateMixin';
|
||||||
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
||||||
import styleMixin from '../../../mixins/styleMixin';
|
import styleMixin from '../../../mixins/styleMixin';
|
||||||
|
import { API } from '../../../typings/api';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [dateMixin, modalTrainMixin, styleMixin],
|
mixins: [dateMixin, modalTrainMixin, styleMixin],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
timetable: {
|
timetable: {
|
||||||
type: Object as PropType<TimetableHistory>,
|
type: Object as PropType<API.TimetableHistory.Data>,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
showTimetable(timetable: TimetableHistory, target: EventTarget | null) {
|
showTimetable(timetable: API.TimetableHistory.Data, target: EventTarget | null) {
|
||||||
if (timetable?.terminated) return;
|
if (timetable?.terminated) return;
|
||||||
|
|
||||||
this.selectModalTrain(timetable.driverName + timetable.trainNo.toString(), target);
|
this.selectModalTrain(timetable.driverName + timetable.trainNo.toString(), target);
|
||||||
|
|||||||
@@ -38,17 +38,17 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PropType, defineComponent, ref } from 'vue';
|
import { PropType, defineComponent, ref } from 'vue';
|
||||||
import { TimetableHistory } from '../../../scripts/interfaces/api/TimetablesAPIData';
|
|
||||||
|
|
||||||
import TimetableGeneral from './TimetableGeneral.vue';
|
import TimetableGeneral from './TimetableGeneral.vue';
|
||||||
import TimetableStops from './TimetableStops.vue';
|
import TimetableStops from './TimetableStops.vue';
|
||||||
import TimetableStatus from './TimetableStatus.vue';
|
import TimetableStatus from './TimetableStatus.vue';
|
||||||
import TimetableExtra from './TimetableExtra.vue';
|
import TimetableExtra from './TimetableExtra.vue';
|
||||||
|
import { API } from '../../../typings/api';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
timetableHistory: {
|
timetableHistory: {
|
||||||
type: Array as PropType<TimetableHistory[]>,
|
type: Array as PropType<API.TimetableHistory.Response>,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -44,14 +44,14 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PropType, defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import { TimetableHistory } from '../../../scripts/interfaces/api/TimetablesAPIData';
|
|
||||||
import ProgressBar from '../../Global/ProgressBar.vue';
|
import ProgressBar from '../../Global/ProgressBar.vue';
|
||||||
|
import { API } from '../../../typings/api';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { ProgressBar },
|
components: { ProgressBar },
|
||||||
props: {
|
props: {
|
||||||
timetable: {
|
timetable: {
|
||||||
type: Object as PropType<TimetableHistory>,
|
type: Object as PropType<API.TimetableHistory.Data>,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PropType, defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import dateMixin from '../../../mixins/dateMixin';
|
import dateMixin from '../../../mixins/dateMixin';
|
||||||
|
import { API } from '../../../typings/api';
|
||||||
import { TimetableHistory } from '../../../scripts/interfaces/api/TimetablesAPIData';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [dateMixin],
|
mixins: [dateMixin],
|
||||||
@@ -37,7 +36,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
timetable: {
|
timetable: {
|
||||||
type: Object as PropType<TimetableHistory>,
|
type: Object as PropType<API.TimetableHistory.Data>,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
export namespace Journal {
|
||||||
|
export type DispatcherSearcher = {
|
||||||
|
[key in 'search-dispatcher' | 'search-station' | 'search-date']: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface DispatcherSorter {
|
||||||
|
id: 'timestampFrom' | 'duration';
|
||||||
|
dir: -1 | 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TimetableSearchKey =
|
||||||
|
| 'search-driver'
|
||||||
|
| 'search-train'
|
||||||
|
| 'search-date'
|
||||||
|
| 'search-dispatcher'
|
||||||
|
| 'search-issuedFrom';
|
||||||
|
|
||||||
|
export type TimetableSearchType = {
|
||||||
|
[key in TimetableSearchKey]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const enum TimetableFilterId {
|
||||||
|
ACTIVE = 'active',
|
||||||
|
FULFILLED = 'fulfilled',
|
||||||
|
ABANDONED = 'abandoned',
|
||||||
|
ALL = 'all',
|
||||||
|
TWR = 'twr',
|
||||||
|
SKR = 'skr',
|
||||||
|
TWR_SKR = 'twr-skr'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum FilterSection {
|
||||||
|
TIMETABLE_STATUS = 'timetable-status',
|
||||||
|
TWRSKR = 'twrskr'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimetableFilter {
|
||||||
|
id: TimetableFilterId;
|
||||||
|
filterSection: string;
|
||||||
|
isActive: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TimetableSorterKey = 'timetableId' | 'beginDate' | 'distance' | 'total-stops';
|
||||||
|
|
||||||
|
export interface TimetableSorter {
|
||||||
|
id: TimetableSorterKey;
|
||||||
|
dir: 'asc' | 'desc';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -69,14 +69,14 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { defineComponent, PropType } from 'vue';
|
import { defineComponent, PropType } from 'vue';
|
||||||
import dateMixin from '../../mixins/dateMixin';
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
|
||||||
import { DispatcherHistory } from '../../scripts/interfaces/api/DispatchersAPIData';
|
|
||||||
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 styleMixin from '../../mixins/styleMixin';
|
import styleMixin from '../../mixins/styleMixin';
|
||||||
import listObserverMixin from '../../mixins/listObserverMixin';
|
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||||
import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes';
|
import { OnlineScenery } from '../../store/typings';
|
||||||
|
import { API } from '../../typings/api';
|
||||||
|
import { Status } from '../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SceneryDispatchersHistory',
|
name: 'SceneryDispatchersHistory',
|
||||||
@@ -95,9 +95,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
historyList: [] as DispatcherHistory[],
|
historyList: [] as API.DispatcherHistory.Response,
|
||||||
dataStatus: DataStatus.Loading,
|
dataStatus: Status.Data.Loading,
|
||||||
DataStatus
|
DataStatus: Status.Data
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -109,17 +109,22 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async fetchAPIData(countFrom = 0, countLimit = 30): Promise<DispatcherHistory[] | null> {
|
async fetchAPIData(
|
||||||
|
countFrom = 0,
|
||||||
|
countLimit = 30
|
||||||
|
): Promise<API.DispatcherHistory.Response | null> {
|
||||||
try {
|
try {
|
||||||
this.dataStatus = DataStatus.Loading;
|
this.dataStatus = Status.Data.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: API.DispatcherHistory.Response = await (
|
||||||
|
await axios.get(requestString)
|
||||||
|
).data;
|
||||||
|
|
||||||
this.dataStatus = DataStatus.Loaded;
|
this.dataStatus = Status.Data.Loaded;
|
||||||
return historyAPIData;
|
return historyAPIData;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.dataStatus = DataStatus.Error;
|
this.dataStatus = Status.Data.Error;
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -153,3 +158,4 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
../../store/storeTypes
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PropType, defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import Station from '../../scripts/interfaces/Station';
|
import Station from '../../scripts/interfaces/Station';
|
||||||
import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes';
|
import { OnlineScenery } from '../../store/typings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -58,3 +58,4 @@ export default defineComponent({
|
|||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
../../store/storeTypes
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ import SceneryInfoUserList from './SceneryInfo/SceneryInfoUserList.vue';
|
|||||||
import SceneryInfoSpawnList from './SceneryInfo/SceneryInfoSpawnList.vue';
|
import SceneryInfoSpawnList from './SceneryInfo/SceneryInfoSpawnList.vue';
|
||||||
import SceneryInfoRoutes from './SceneryInfo/SceneryInfoRoutes.vue';
|
import SceneryInfoRoutes from './SceneryInfo/SceneryInfoRoutes.vue';
|
||||||
import Station from '../../scripts/interfaces/Station';
|
import Station from '../../scripts/interfaces/Station';
|
||||||
import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes';
|
import { OnlineScenery } from '../../store/typings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@@ -110,7 +110,7 @@ export default defineComponent({
|
|||||||
type: Object as PropType<OnlineScenery>,
|
type: Object as PropType<OnlineScenery>,
|
||||||
required: false
|
required: false
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<StationStatusBadge
|
<StationStatusBadge
|
||||||
:statusID="onlineScenery?.statusID"
|
|
||||||
:isOnline="onlineScenery ? true : false"
|
:isOnline="onlineScenery ? true : false"
|
||||||
:statusTimestamp="onlineScenery?.statusTimestamp"
|
:dispatcherStatus="onlineScenery?.dispatcherStatus"
|
||||||
|
:dispatcherTimestamp="onlineScenery?.dispatcherTimestamp"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
@@ -35,7 +35,7 @@ import dateMixin from '../../../mixins/dateMixin';
|
|||||||
import routerMixin from '../../../mixins/routerMixin';
|
import routerMixin from '../../../mixins/routerMixin';
|
||||||
import styleMixin from '../../../mixins/styleMixin';
|
import styleMixin from '../../../mixins/styleMixin';
|
||||||
import StationStatusBadge from '../../Global/StationStatusBadge.vue';
|
import StationStatusBadge from '../../Global/StationStatusBadge.vue';
|
||||||
import { OnlineScenery } from '../../../scripts/interfaces/store/storeTypes';
|
import { OnlineScenery } from '../../../store/typings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [styleMixin, dateMixin, routerMixin],
|
mixins: [styleMixin, dateMixin, routerMixin],
|
||||||
|
|||||||
@@ -7,7 +7,11 @@
|
|||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<transition-group name="spawns-anim" tag="ul">
|
<transition-group name="spawns-anim" tag="ul">
|
||||||
<li class="badge spawn badge-none" v-if="!onlineScenery || onlineScenery.spawns.length == 0" key="no-spawns">
|
<li
|
||||||
|
class="badge spawn badge-none"
|
||||||
|
v-if="!onlineScenery || onlineScenery.spawns.length == 0"
|
||||||
|
key="no-spawns"
|
||||||
|
>
|
||||||
{{ $t('scenery.no-spawns') }}
|
{{ $t('scenery.no-spawns') }}
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -26,7 +30,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PropType, defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import { OnlineScenery } from '../../../scripts/interfaces/store/storeTypes';
|
import { OnlineScenery } from '../../../store/typings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
import { PropType, defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
||||||
import routerMixin from '../../../mixins/routerMixin';
|
import routerMixin from '../../../mixins/routerMixin';
|
||||||
import { OnlineScenery } from '../../../scripts/interfaces/store/storeTypes';
|
import { OnlineScenery } from '../../../store/typings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [routerMixin, modalTrainMixin],
|
mixins: [routerMixin, modalTrainMixin],
|
||||||
|
|||||||
@@ -85,9 +85,11 @@
|
|||||||
<strong>{{ scheduledTrain.category }}</strong>
|
<strong>{{ scheduledTrain.category }}</strong>
|
||||||
{{ scheduledTrain.trainNo }}
|
{{ scheduledTrain.trainNo }}
|
||||||
|
|
||||||
<span class="g-tooltip" v-if="scheduledTrain.stopInfo.comments">
|
<span
|
||||||
|
v-if="scheduledTrain.stopInfo.comments"
|
||||||
|
:title="scheduledTrain.stopInfo.comments"
|
||||||
|
>
|
||||||
<img src="/images/icon-warning.svg" />
|
<img src="/images/icon-warning.svg" />
|
||||||
<span class="content" v-html="scheduledTrain.stopInfo.comments"> </span>
|
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
|
||||||
@@ -185,10 +187,10 @@ import Loading from '../Global/Loading.vue';
|
|||||||
import dateMixin from '../../mixins/dateMixin';
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
import routerMixin from '../../mixins/routerMixin';
|
import routerMixin from '../../mixins/routerMixin';
|
||||||
import Station from '../../scripts/interfaces/Station';
|
import Station from '../../scripts/interfaces/Station';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/mainStore';
|
||||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||||
import ScheduledTrainStatus from './ScheduledTrainStatus.vue';
|
import ScheduledTrainStatus from './ScheduledTrainStatus.vue';
|
||||||
import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes';
|
import { OnlineScenery } from '../../store/typings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SceneryTimetable',
|
name: 'SceneryTimetable',
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<!-- WIP -->
|
||||||
|
<!-- <div class="top-filters">
|
||||||
|
<button class="btn btn--option">ROZPOCZYNA BIEG</button>
|
||||||
|
|
||||||
|
<button class="btn btn--option">PRZEZ</button>
|
||||||
|
|
||||||
|
<button class="btn btn--option">KOŃCZY BIEG</button>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
<section class="scenery-table-section">
|
<section class="scenery-table-section">
|
||||||
<Loading v-if="dataStatus != DataStatus.Loaded" />
|
<Loading v-if="dataStatus != DataStatus.Loaded" />
|
||||||
|
|
||||||
<div class="no-history" v-else-if="historyList.length == 0">
|
<div class="no-history" v-else-if="historyList.length == 0">
|
||||||
{{ $t('scenery.history-list-empty') }}
|
{{ $t('scenery.history-list-empty') }}
|
||||||
</div>
|
</div>
|
||||||
@@ -18,9 +28,9 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="historyItem in historyList" :key="historyItem.id">
|
<tr v-for="historyItem in historyList" :key="historyItem.id">
|
||||||
<td>
|
<td>
|
||||||
<router-link :to="`/journal/timetables?timetableId=${historyItem.id}`"
|
<router-link :to="`/journal/timetables?timetableId=${historyItem.id}`">
|
||||||
>#{{ historyItem.id }}</router-link
|
#{{ historyItem.id }}
|
||||||
>
|
</router-link>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<b class="text--primary">{{ historyItem.trainCategoryCode }}</b> <br />
|
<b class="text--primary">{{ historyItem.trainCategoryCode }}</b> <br />
|
||||||
@@ -56,16 +66,14 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { defineComponent, PropType } from 'vue';
|
import { defineComponent, PropType } from 'vue';
|
||||||
import dateMixin from '../../mixins/dateMixin';
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
|
||||||
import {
|
|
||||||
TimetableHistory,
|
|
||||||
SceneryTimetableHistory
|
|
||||||
} from '../../scripts/interfaces/api/TimetablesAPIData';
|
|
||||||
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';
|
import listObserverMixin from '../../mixins/listObserverMixin';
|
||||||
import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes';
|
import { OnlineScenery } from '../../store/typings';
|
||||||
|
import { API } from '../../typings/api';
|
||||||
|
import { Status } from '../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SceneryTimetablesHistory',
|
name: 'SceneryTimetablesHistory',
|
||||||
@@ -83,28 +91,28 @@ export default defineComponent({
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
historyList: [] as TimetableHistory[],
|
historyList: [] as API.TimetableHistory.Response,
|
||||||
dataStatus: DataStatus.Loading,
|
dataStatus: Status.Data.Loading,
|
||||||
DataStatus
|
DataStatus: Status.Data
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
async activated() {
|
async activated() {
|
||||||
const fetchedHistory = await this.fetchAPIData();
|
this.fetchAPIData();
|
||||||
if (fetchedHistory) this.historyList = fetchedHistory.timetables;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async fetchAPIData(countFrom = 0, countLimit = 15): Promise<SceneryTimetableHistory | null> {
|
async fetchAPIData(countFrom = 0, countLimit = 15) {
|
||||||
try {
|
try {
|
||||||
const requestString = `${URLs.stacjownikAPI}/api/getIssuedTimetables?name=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
const requestString = `${URLs.stacjownikAPI}/api/getTimetables?issuedFrom=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||||
const historyAPIData: SceneryTimetableHistory = await (await axios.get(requestString)).data;
|
|
||||||
|
|
||||||
this.dataStatus = DataStatus.Loaded;
|
const response: API.TimetableHistory.Response = await (await axios.get(requestString)).data;
|
||||||
return historyAPIData;
|
|
||||||
|
this.historyList = response;
|
||||||
|
|
||||||
|
this.dataStatus = Status.Data.Loaded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -119,4 +127,14 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
@import '../../styles/sceneryViewTables.scss';
|
@import '../../styles/sceneryViewTables.scss';
|
||||||
|
|
||||||
|
.top-filters {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, PropType } from 'vue';
|
import { defineComponent, PropType } from 'vue';
|
||||||
import { ScheduledTrain, StopStatus } from '../../scripts/interfaces/ScheduledTrain';
|
import { ScheduledTrain, StopStatus } from '../../store/typings';
|
||||||
|
|
||||||
interface ScheduledTrainComp extends ScheduledTrain {
|
interface ScheduledTrainComp extends ScheduledTrain {
|
||||||
stopStatusIndicator: string;
|
stopStatusIndicator: string;
|
||||||
@@ -42,7 +42,7 @@ export default defineComponent({
|
|||||||
stopStatusIndicator = '';
|
stopStatusIndicator = '';
|
||||||
|
|
||||||
switch (stopStatus) {
|
switch (stopStatus) {
|
||||||
case StopStatus.arriving:
|
case StopStatus.ARRIVING:
|
||||||
stopStatusIndicator = `${this.$t('timetables.from')}: ${prevDepartureIndicator}`;
|
stopStatusIndicator = `${this.$t('timetables.from')}: ${prevDepartureIndicator}`;
|
||||||
stopStatusDescription = this.$t('timetables.desc-arriving', {
|
stopStatusDescription = this.$t('timetables.desc-arriving', {
|
||||||
prevStationName,
|
prevStationName,
|
||||||
@@ -50,8 +50,8 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case StopStatus.online:
|
case StopStatus.ONLINE:
|
||||||
case StopStatus.stopped:
|
case StopStatus.STOPPED:
|
||||||
stopStatusIndicator = nextArrivalLine
|
stopStatusIndicator = nextArrivalLine
|
||||||
? `${this.$t('timetables.to')}: ${nextArrivalIndicator}`
|
? `${this.$t('timetables.to')}: ${nextArrivalIndicator}`
|
||||||
: `${this.$t('timetables.desc-end')}`;
|
: `${this.$t('timetables.desc-end')}`;
|
||||||
@@ -60,7 +60,7 @@ export default defineComponent({
|
|||||||
: '';
|
: '';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case StopStatus.departed:
|
case StopStatus.DEPARTED:
|
||||||
stopStatusIndicator = `${this.$t('timetables.to')}: ${nextArrivalIndicator}`;
|
stopStatusIndicator = `${this.$t('timetables.to')}: ${nextArrivalIndicator}`;
|
||||||
stopStatusDescription = this.$t('timetables.desc-departed', {
|
stopStatusDescription = this.$t('timetables.desc-departed', {
|
||||||
nextStationName,
|
nextStationName,
|
||||||
@@ -68,7 +68,7 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case StopStatus['departed-away']:
|
case StopStatus.DEPARTED_AWAY:
|
||||||
stopStatusIndicator = `${this.$t('timetables.to')}: ${nextArrivalIndicator}`;
|
stopStatusIndicator = `${this.$t('timetables.to')}: ${nextArrivalIndicator}`;
|
||||||
stopStatusDescription = this.$t('timetables.desc-departed-away', {
|
stopStatusDescription = this.$t('timetables.desc-departed-away', {
|
||||||
nextStationName,
|
nextStationName,
|
||||||
@@ -76,7 +76,7 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case StopStatus.terminated:
|
case StopStatus.TERMINATED:
|
||||||
stopStatusIndicator = `X ${this.$t('timetables.desc-terminated')}`;
|
stopStatusIndicator = `X ${this.$t('timetables.desc-terminated')}`;
|
||||||
stopStatusDescription = this.$t('timetables.desc-terminated');
|
stopStatusDescription = this.$t('timetables.desc-terminated');
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -138,11 +138,11 @@
|
|||||||
import { defineComponent, inject } from 'vue';
|
import { defineComponent, inject } from 'vue';
|
||||||
import keyMixin from '../../mixins/keyMixin';
|
import keyMixin from '../../mixins/keyMixin';
|
||||||
import routerMixin from '../../mixins/routerMixin';
|
import routerMixin from '../../mixins/routerMixin';
|
||||||
import StorageManager from '../../scripts/managers/storageManager';
|
|
||||||
import { useStationFiltersStore } from '../../store/stationFiltersStore';
|
import { useStationFiltersStore } from '../../store/stationFiltersStore';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/mainStore';
|
||||||
|
|
||||||
import FilterOption from './FilterOption.vue';
|
import FilterOption from './FilterOption.vue';
|
||||||
|
import StorageManager from '../../managers/storageManager';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { FilterOption },
|
components: { FilterOption },
|
||||||
@@ -295,19 +295,7 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
@import '../../styles/card.scss';
|
@import '../../styles/card.scss';
|
||||||
|
@import '../../styles/animations.scss';
|
||||||
.card-anim {
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: all $animDuration $animType;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translate(-50%, -50%) scale(0.45);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@@ -1,271 +1,277 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="station_table">
|
<section class="station_table">
|
||||||
<div class="table_wrapper">
|
<table>
|
||||||
<table>
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
<tr>
|
<th
|
||||||
<th
|
v-for="headerName in headIds"
|
||||||
v-for="headerName in headIds"
|
:key="headerName"
|
||||||
:key="headerName"
|
@click="changeSorter(headerName)"
|
||||||
@click="changeSorter(headerName)"
|
class="header-text"
|
||||||
class="header-text"
|
|
||||||
>
|
|
||||||
<span class="header_wrapper">
|
|
||||||
<div v-html="$t(`sceneries.${headerName}`)"></div>
|
|
||||||
|
|
||||||
<img
|
|
||||||
class="sort-icon"
|
|
||||||
v-if="sorterActive.headerName == headerName"
|
|
||||||
:src="`/images/icon-arrow-${sorterActive.dir == 1 ? 'asc' : 'desc'}.svg`"
|
|
||||||
alt="sort icon"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
|
|
||||||
<th
|
|
||||||
v-for="headerName in headIconsIds"
|
|
||||||
:key="headerName"
|
|
||||||
@click="changeSorter(headerName)"
|
|
||||||
class="header-image"
|
|
||||||
>
|
|
||||||
<span class="header_wrapper">
|
|
||||||
<img
|
|
||||||
:src="`/images/icon-${headerName}.svg`"
|
|
||||||
:alt="headerName"
|
|
||||||
:title="$t(`sceneries.${headerName}`)"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<img
|
|
||||||
class="sort-icon"
|
|
||||||
v-if="sorterActive.headerName == headerName"
|
|
||||||
:src="`/images/icon-arrow-${sorterActive.dir == 1 ? 'asc' : 'desc'}.svg`"
|
|
||||||
alt="sort icon"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
<tr
|
|
||||||
class="station"
|
|
||||||
:class="{ 'last-selected': lastSelectedStationName == station.name }"
|
|
||||||
v-for="(station, i) in stations"
|
|
||||||
:key="i + station.name"
|
|
||||||
@click.left="setScenery(station.name)"
|
|
||||||
@click.right="openForumSite($event, station.generalInfo?.url)"
|
|
||||||
@keydown.enter="setScenery(station.name)"
|
|
||||||
@keydown.space="openForumSite($event, station.generalInfo?.url)"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
>
|
||||||
<td class="station_name" :class="station.generalInfo?.availability">
|
<span class="header_wrapper">
|
||||||
<b v-if="station.generalInfo?.project" style="color: salmon">{{
|
<div v-html="$t(`sceneries.${headerName}`)"></div>
|
||||||
station.generalInfo.project
|
|
||||||
}}</b>
|
|
||||||
{{ station.name }}
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td class="station_level">
|
<img
|
||||||
<span v-if="station.generalInfo">
|
class="sort-icon"
|
||||||
<span
|
v-if="sorterActive.headerName == headerName"
|
||||||
v-if="
|
:src="`/images/icon-arrow-${sorterActive.dir == 1 ? 'asc' : 'desc'}.svg`"
|
||||||
station.generalInfo.reqLevel > -1 &&
|
alt="sort icon"
|
||||||
station.generalInfo.availability != 'nonPublic' &&
|
|
||||||
station.generalInfo.availability != 'unavailable'
|
|
||||||
"
|
|
||||||
:style="calculateExpStyle(station.generalInfo.reqLevel)"
|
|
||||||
>
|
|
||||||
{{ station.generalInfo.reqLevel >= 2 ? station.generalInfo.reqLevel : 'L' }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-else-if="station.generalInfo.availability == 'abandoned'">
|
|
||||||
<img
|
|
||||||
src="/images/icon-abandoned.svg"
|
|
||||||
alt="non-public"
|
|
||||||
:title="$t('desc.abandoned')"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-else-if="station.generalInfo.availability == 'nonPublic'">
|
|
||||||
<img
|
|
||||||
src="/images/icon-lock.svg"
|
|
||||||
alt="non-public"
|
|
||||||
:title="$t('desc.non-public')"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-else>
|
|
||||||
<img
|
|
||||||
src="/images/icon-unavailable.svg"
|
|
||||||
alt="unavailable"
|
|
||||||
:title="$t('desc.unavailable')"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-else> ? </span>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td class="station_status">
|
|
||||||
<StationStatusBadge
|
|
||||||
:statusID="station.onlineInfo?.statusID"
|
|
||||||
:isOnline="station.onlineInfo ? true : false"
|
|
||||||
:statusTimestamp="station.onlineInfo?.statusTimestamp"
|
|
||||||
/>
|
/>
|
||||||
</td>
|
</span>
|
||||||
|
</th>
|
||||||
|
|
||||||
<td class="station_dispatcher-name">
|
<th
|
||||||
{{ station.onlineInfo ? station.onlineInfo.dispatcherName : '' }}
|
v-for="headerName in headIconsIds"
|
||||||
</td>
|
:key="headerName"
|
||||||
|
@click="changeSorter(headerName)"
|
||||||
|
class="header-image"
|
||||||
|
>
|
||||||
|
<span class="header_wrapper">
|
||||||
|
<img
|
||||||
|
:src="`/images/icon-${headerName}.svg`"
|
||||||
|
:alt="headerName"
|
||||||
|
:title="$t(`sceneries.${headerName}`)"
|
||||||
|
/>
|
||||||
|
|
||||||
<td class="station_dispatcher-exp">
|
<img
|
||||||
<span
|
class="sort-icon"
|
||||||
v-if="station.onlineInfo"
|
v-if="sorterActive.headerName == headerName"
|
||||||
:style="
|
:src="`/images/icon-arrow-${sorterActive.dir == 1 ? 'asc' : 'desc'}.svg`"
|
||||||
calculateExpStyle(
|
alt="sort icon"
|
||||||
station.onlineInfo.dispatcherExp,
|
/>
|
||||||
station.onlineInfo.dispatcherIsSupporter
|
</span>
|
||||||
)
|
</th>
|
||||||
"
|
</tr>
|
||||||
>
|
</thead>
|
||||||
{{ 2 > station.onlineInfo.dispatcherExp ? 'L' : station.onlineInfo.dispatcherExp }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td class="station_tracks twoway">
|
<tbody>
|
||||||
|
<tr
|
||||||
|
class="station"
|
||||||
|
:class="{ 'last-selected': lastSelectedStationName == station.name }"
|
||||||
|
v-for="(station, i) in stations"
|
||||||
|
:key="i + station.name"
|
||||||
|
@click.left="setScenery(station.name)"
|
||||||
|
@click.right="openForumSite($event, station.generalInfo?.url)"
|
||||||
|
@keydown.enter="setScenery(station.name)"
|
||||||
|
@keydown.space="openForumSite($event, station.generalInfo?.url)"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<td class="station_name" :class="station.generalInfo?.availability">
|
||||||
|
<b v-if="station.generalInfo?.project" style="color: salmon">{{
|
||||||
|
station.generalInfo.project
|
||||||
|
}}</b>
|
||||||
|
{{ station.name }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="station_level">
|
||||||
|
<span v-if="station.generalInfo">
|
||||||
<span
|
<span
|
||||||
v-if="
|
v-if="
|
||||||
station.generalInfo &&
|
station.generalInfo.reqLevel > -1 &&
|
||||||
station.generalInfo.routes.twoWayCatenaryRouteNames.length > 0
|
station.generalInfo.availability != 'nonPublic' &&
|
||||||
|
station.generalInfo.availability != 'unavailable'
|
||||||
"
|
"
|
||||||
class="track catenary"
|
:style="calculateExpStyle(station.generalInfo.reqLevel)"
|
||||||
:title="`Liczba zelektryfikowanych szlaków dwutorowych: ${station.generalInfo.routes.twoWayCatenaryRouteNames.length}`"
|
|
||||||
>
|
>
|
||||||
{{ station.generalInfo.routes.twoWayCatenaryRouteNames.length }}
|
{{ station.generalInfo.reqLevel >= 2 ? station.generalInfo.reqLevel : 'L' }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span
|
<span v-else-if="station.generalInfo.availability == 'abandoned'">
|
||||||
v-if="
|
|
||||||
station.generalInfo &&
|
|
||||||
station.generalInfo.routes.twoWayNoCatenaryRouteNames.length > 0
|
|
||||||
"
|
|
||||||
class="track no-catenary"
|
|
||||||
:title="`Liczba niezelektryfikowanych szlaków dwutorowych: ${station.generalInfo.routes.twoWayNoCatenaryRouteNames.length}`"
|
|
||||||
>
|
|
||||||
{{ station.generalInfo.routes.twoWayNoCatenaryRouteNames.length }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="separator"></span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
v-if="
|
|
||||||
station.generalInfo &&
|
|
||||||
station.generalInfo.routes.oneWayCatenaryRouteNames.length > 0
|
|
||||||
"
|
|
||||||
class="track catenary"
|
|
||||||
:title="`Liczba zelektryfikowanych szlaków jednotorowych: ${station.generalInfo.routes.oneWayCatenaryRouteNames.length}`"
|
|
||||||
>
|
|
||||||
{{ station.generalInfo.routes.oneWayCatenaryRouteNames.length }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
v-if="
|
|
||||||
station.generalInfo &&
|
|
||||||
station.generalInfo.routes.oneWayNoCatenaryRouteNames.length > 0
|
|
||||||
"
|
|
||||||
class="track no-catenary"
|
|
||||||
:title="`Liczba niezelektryfikowanych szlaków jednotorowych: ${station.generalInfo.routes.oneWayNoCatenaryRouteNames.length}`"
|
|
||||||
>
|
|
||||||
{{ station.generalInfo.routes.oneWayNoCatenaryRouteNames.length }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td class="station_info" v-if="station.generalInfo">
|
|
||||||
<span
|
|
||||||
class="scenery-icon icon-info"
|
|
||||||
:class="station.generalInfo.controlType.replace('+', '-')"
|
|
||||||
:title="$t('desc.control-type') + $t(`controls.${station.generalInfo.controlType}`)"
|
|
||||||
v-html="getControlTypeAbbrev(station.generalInfo.controlType)"
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span>
|
|
||||||
<img
|
<img
|
||||||
class="icon-info"
|
src="/images/icon-abandoned.svg"
|
||||||
v-if="station.generalInfo.SUP"
|
alt="non-public"
|
||||||
src="/images/icon-SUP.svg"
|
:title="$t('desc.abandoned')"
|
||||||
alt="SUP (RASP-UZK)"
|
|
||||||
:title="$t('desc.SUP')"
|
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span>
|
<span v-else-if="station.generalInfo.availability == 'nonPublic'">
|
||||||
<img
|
<img src="/images/icon-lock.svg" alt="non-public" :title="$t('desc.non-public')" />
|
||||||
class="icon-info"
|
|
||||||
v-if="station.generalInfo.signalType"
|
|
||||||
:src="`/images/icon-${station.generalInfo.signalType}.svg`"
|
|
||||||
:alt="station.generalInfo.signalType"
|
|
||||||
:title="$t('desc.signals-type') + $t(`signals.${station.generalInfo.signalType}`)"
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span>
|
<span v-else>
|
||||||
<img
|
<img
|
||||||
class="icon-info"
|
src="/images/icon-unavailable.svg"
|
||||||
v-if="station.generalInfo && station.generalInfo.routes.sblRouteNames.length > 0"
|
alt="unavailable"
|
||||||
src="/images/icon-SBL.svg"
|
:title="$t('desc.unavailable')"
|
||||||
alt="SBL"
|
|
||||||
:title="$t('desc.SBL') + `${station.generalInfo.routes.sblRouteNames.join(',')}`"
|
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</span>
|
||||||
|
|
||||||
<td class="station_info" v-else>
|
<span v-else> ? </span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="station_status">
|
||||||
|
<StationStatusBadge
|
||||||
|
:isOnline="station.onlineInfo ? true : false"
|
||||||
|
:dispatcherStatus="station.onlineInfo?.dispatcherStatus"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="station_dispatcher-name">
|
||||||
|
<span v-if="station.onlineInfo?.dispatcherName">
|
||||||
|
<b
|
||||||
|
v-if="store.donatorsData.includes(station.onlineInfo.dispatcherName)"
|
||||||
|
title="Dyżurny wspierający projekt Stacjownika!"
|
||||||
|
@click.stop="openDonationModal"
|
||||||
|
>
|
||||||
|
<img src="/images/icon-diamond.svg" alt="" />
|
||||||
|
{{ station.onlineInfo.dispatcherName }}
|
||||||
|
</b>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
{{ station.onlineInfo.dispatcherName }}
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="station_dispatcher-exp">
|
||||||
|
<span
|
||||||
|
v-if="station.onlineInfo"
|
||||||
|
:style="
|
||||||
|
calculateExpStyle(
|
||||||
|
station.onlineInfo.dispatcherExp,
|
||||||
|
station.onlineInfo.dispatcherIsSupporter
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ station.onlineInfo.dispatcherExp < 2 ? 'L' : station.onlineInfo.dispatcherExp }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="station_tracks twoway">
|
||||||
|
<span
|
||||||
|
v-if="
|
||||||
|
station.generalInfo &&
|
||||||
|
station.generalInfo.routes.twoWayCatenaryRouteNames.length > 0
|
||||||
|
"
|
||||||
|
class="track catenary"
|
||||||
|
:title="`Liczba zelektryfikowanych szlaków dwutorowych: ${station.generalInfo.routes.twoWayCatenaryRouteNames.length}`"
|
||||||
|
>
|
||||||
|
{{ station.generalInfo.routes.twoWayCatenaryRouteNames.length }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
v-if="
|
||||||
|
station.generalInfo &&
|
||||||
|
station.generalInfo.routes.twoWayNoCatenaryRouteNames.length > 0
|
||||||
|
"
|
||||||
|
class="track no-catenary"
|
||||||
|
:title="`Liczba niezelektryfikowanych szlaków dwutorowych: ${station.generalInfo.routes.twoWayNoCatenaryRouteNames.length}`"
|
||||||
|
>
|
||||||
|
{{ station.generalInfo.routes.twoWayNoCatenaryRouteNames.length }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="separator"></span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
v-if="
|
||||||
|
station.generalInfo &&
|
||||||
|
station.generalInfo.routes.oneWayCatenaryRouteNames.length > 0
|
||||||
|
"
|
||||||
|
class="track catenary"
|
||||||
|
:title="`Liczba zelektryfikowanych szlaków jednotorowych: ${station.generalInfo.routes.oneWayCatenaryRouteNames.length}`"
|
||||||
|
>
|
||||||
|
{{ station.generalInfo.routes.oneWayCatenaryRouteNames.length }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
v-if="
|
||||||
|
station.generalInfo &&
|
||||||
|
station.generalInfo.routes.oneWayNoCatenaryRouteNames.length > 0
|
||||||
|
"
|
||||||
|
class="track no-catenary"
|
||||||
|
:title="`Liczba niezelektryfikowanych szlaków jednotorowych: ${station.generalInfo.routes.oneWayNoCatenaryRouteNames.length}`"
|
||||||
|
>
|
||||||
|
{{ station.generalInfo.routes.oneWayNoCatenaryRouteNames.length }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="station_info" v-if="station.generalInfo">
|
||||||
|
<span
|
||||||
|
class="scenery-icon icon-info"
|
||||||
|
:class="station.generalInfo.controlType.replace('+', '-')"
|
||||||
|
:title="$t('desc.control-type') + $t(`controls.${station.generalInfo.controlType}`)"
|
||||||
|
v-html="getControlTypeAbbrev(station.generalInfo.controlType)"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
<img
|
<img
|
||||||
class="icon-info"
|
class="icon-info"
|
||||||
src="/images/icon-unknown.svg"
|
v-if="station.generalInfo.SUP"
|
||||||
alt="icon-unknown"
|
src="/images/icon-SUP.svg"
|
||||||
:title="$t('desc.unknown')"
|
alt="SUP (RASP-UZK)"
|
||||||
|
:title="$t('desc.SUP')"
|
||||||
/>
|
/>
|
||||||
</td>
|
</span>
|
||||||
|
|
||||||
<td class="station_users" :class="{ inactive: !station.onlineInfo }">
|
<span>
|
||||||
<span>{{ station.onlineInfo?.currentUsers || 0 }}</span>
|
<img
|
||||||
/
|
class="icon-info"
|
||||||
<span>{{ station.onlineInfo?.maxUsers || 0 }}</span>
|
v-if="station.generalInfo.signalType"
|
||||||
</td>
|
:src="`/images/icon-${station.generalInfo.signalType}.svg`"
|
||||||
|
:alt="station.generalInfo.signalType"
|
||||||
|
:title="$t('desc.signals-type') + $t(`signals.${station.generalInfo.signalType}`)"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
|
||||||
<td class="station_spawns" :class="{ inactive: !station.onlineInfo }">
|
<span>
|
||||||
<span>{{ station.onlineInfo?.spawns.length || 0 }}</span>
|
<img
|
||||||
</td>
|
class="icon-info"
|
||||||
|
v-if="station.generalInfo && station.generalInfo.routes.sblRouteNames.length > 0"
|
||||||
|
src="/images/icon-SBL.svg"
|
||||||
|
alt="SBL"
|
||||||
|
:title="$t('desc.SBL') + `${station.generalInfo.routes.sblRouteNames.join(',')}`"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
<td
|
<td class="station_info" v-else>
|
||||||
class="station_schedules all"
|
<img
|
||||||
style="width: 30px"
|
class="icon-info"
|
||||||
:class="{ inactive: !station.onlineInfo }"
|
src="/images/icon-unknown.svg"
|
||||||
>
|
alt="icon-unknown"
|
||||||
{{ station.onlineInfo?.scheduledTrainCount.all }}
|
:title="$t('desc.unknown')"
|
||||||
</td>
|
/>
|
||||||
|
</td>
|
||||||
|
|
||||||
<td
|
<td class="station_users" :class="{ inactive: !station.onlineInfo }">
|
||||||
class="station_schedules unconfirmed"
|
<span>{{ station.onlineInfo?.currentUsers || 0 }}</span>
|
||||||
style="width: 30px"
|
/
|
||||||
:class="{ inactive: !station.onlineInfo }"
|
<span>{{ station.onlineInfo?.maxUsers || 0 }}</span>
|
||||||
>
|
</td>
|
||||||
{{ station.onlineInfo?.scheduledTrainCount.unconfirmed }}
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td
|
<td class="station_spawns" :class="{ inactive: !station.onlineInfo }">
|
||||||
class="station_schedules confirmed"
|
<span>{{ station.onlineInfo?.spawns.length || 0 }}</span>
|
||||||
style="width: 30px"
|
</td>
|
||||||
:class="{ inactive: !station.onlineInfo }"
|
|
||||||
>
|
<td
|
||||||
{{ station.onlineInfo?.scheduledTrainCount.confirmed }}
|
class="station_schedules all"
|
||||||
</td>
|
style="width: 30px"
|
||||||
</tr>
|
:class="{ inactive: !station.onlineInfo }"
|
||||||
</tbody>
|
>
|
||||||
</table>
|
{{ station.onlineInfo?.scheduledTrainCount.all }}
|
||||||
</div>
|
</td>
|
||||||
|
|
||||||
|
<td
|
||||||
|
class="station_schedules unconfirmed"
|
||||||
|
style="width: 30px"
|
||||||
|
:class="{ inactive: !station.onlineInfo }"
|
||||||
|
>
|
||||||
|
{{ station.onlineInfo?.scheduledTrainCount.unconfirmed }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td
|
||||||
|
class="station_schedules confirmed"
|
||||||
|
style="width: 30px"
|
||||||
|
:class="{ inactive: !station.onlineInfo }"
|
||||||
|
>
|
||||||
|
{{ station.onlineInfo?.scheduledTrainCount.confirmed }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
<Loading v-if="!isDataLoaded && stations.length == 0" />
|
<Loading v-if="!isDataLoaded && stations.length == 0" />
|
||||||
|
|
||||||
@@ -280,13 +286,13 @@ import { defineComponent, computed, PropType } from 'vue';
|
|||||||
import dateMixin from '../../mixins/dateMixin';
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
import stationInfoMixin from '../../mixins/stationInfoMixin';
|
import stationInfoMixin from '../../mixins/stationInfoMixin';
|
||||||
import styleMixin from '../../mixins/styleMixin';
|
import styleMixin from '../../mixins/styleMixin';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
|
||||||
import Station from '../../scripts/interfaces/Station';
|
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/mainStore';
|
||||||
import Loading from '../Global/Loading.vue';
|
import Loading from '../Global/Loading.vue';
|
||||||
import { HeadIdsTypes, headIconsIds, headIds } from '../../scripts/data/stationHeaderNames';
|
import { HeadIdsTypes, headIconsIds, headIds } from '../../scripts/data/stationHeaderNames';
|
||||||
import StationStatusBadge from '../Global/StationStatusBadge.vue';
|
import StationStatusBadge from '../Global/StationStatusBadge.vue';
|
||||||
|
import { Status } from '../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -296,6 +302,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
emits: ['toggleDonationModal'],
|
||||||
components: { Loading, StationStatusBadge },
|
components: { Loading, StationStatusBadge },
|
||||||
mixins: [styleMixin, dateMixin, stationInfoMixin],
|
mixins: [styleMixin, dateMixin, stationInfoMixin],
|
||||||
|
|
||||||
@@ -316,11 +323,13 @@ export default defineComponent({
|
|||||||
const stationFiltersStore = useStationFiltersStore();
|
const stationFiltersStore = useStationFiltersStore();
|
||||||
|
|
||||||
const isDataLoaded = computed(() => {
|
const isDataLoaded = computed(() => {
|
||||||
return store.dataStatuses.sceneries != DataStatus.Loading;
|
return store.dataStatuses.sceneries != Status.Data.Loading;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isDataLoaded,
|
isDataLoaded,
|
||||||
stationFiltersStore
|
stationFiltersStore,
|
||||||
|
store
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -340,6 +349,11 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
openDonationModal(e: Event) {
|
||||||
|
this.$emit('toggleDonationModal', true);
|
||||||
|
this.store.modalLastClickedTarget = e.target;
|
||||||
|
},
|
||||||
|
|
||||||
openForumSite(e: Event, url: string | undefined) {
|
openForumSite(e: Event, url: string | undefined) {
|
||||||
if (!url) return;
|
if (!url) return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -374,21 +388,15 @@ $rowCol: #424242;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
section.station_table {
|
|
||||||
overflow: auto;
|
|
||||||
overflow-y: hidden;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table_wrapper {
|
|
||||||
overflow: auto;
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
table {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
min-width: 1350px;
|
// min-width: 1350px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
@include smallScreen() {
|
@include smallScreen() {
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
@@ -494,6 +502,15 @@ td.station {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// &_dispatcher-name {
|
||||||
|
// position: relative;
|
||||||
|
// }
|
||||||
|
|
||||||
|
&_dispatcher-name img {
|
||||||
|
max-width: 1.35em;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
&_level {
|
&_level {
|
||||||
span {
|
span {
|
||||||
background-color: #888;
|
background-color: #888;
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
export default interface Filter {
|
export interface FilterOption {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
value: boolean;
|
||||||
|
defaultValue: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Filter {
|
||||||
[key: string]: boolean | number | string;
|
[key: string]: boolean | number | string;
|
||||||
default: boolean;
|
default: boolean;
|
||||||
notDefault: boolean;
|
notDefault: boolean;
|
||||||
@@ -1,22 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="train-info">
|
<div class="train-info">
|
||||||
<section class="train-route">
|
<section class="train-general">
|
||||||
<div class="train_general">
|
<div class="general-info">
|
||||||
<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"
|
<span class="timetable-id" v-if="train.timetableData">
|
||||||
>#{{ train.timetableData.timetableId }}</span
|
#{{ train.timetableData.timetableId }}
|
||||||
>
|
</span>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
class="timetable_warnings"
|
class="timetable-warnings"
|
||||||
v-if="train.timetableData?.TWR || train.timetableData?.SKR"
|
v-if="train.timetableData?.TWR || train.timetableData?.SKR"
|
||||||
>
|
>
|
||||||
<span class="train-badge twr" v-if="train.timetableData?.TWR" :title="$t('general.TWR')"
|
<span class="train-badge twr" v-if="train.timetableData?.TWR" :title="$t('general.TWR')">
|
||||||
>TWR</span
|
TWR
|
||||||
>
|
</span>
|
||||||
<span class="train-badge skr" v-if="train.timetableData?.SKR" :title="$t('general.SKR')"
|
<span class="train-badge skr" v-if="train.timetableData?.SKR" :title="$t('general.SKR')">
|
||||||
>SKR</span
|
SKR
|
||||||
>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<strong>
|
<strong>
|
||||||
@@ -32,10 +32,20 @@
|
|||||||
>
|
>
|
||||||
{{ train.driverLevel < 2 ? 'L' : `${train.driverLevel}` }}
|
{{ train.driverLevel < 2 ? 'L' : `${train.driverLevel}` }}
|
||||||
</b>
|
</b>
|
||||||
<span>{{ train.driverName }}</span>
|
|
||||||
|
<div class="train-driver">
|
||||||
|
<b
|
||||||
|
v-if="store.donatorsData.includes(train.driverName)"
|
||||||
|
title="Dyżurny wspierający projekt Stacjownika!"
|
||||||
|
>
|
||||||
|
{{ train.driverName }}
|
||||||
|
<img src="/images/icon-diamond.svg" alt="donator diamond icon" />
|
||||||
|
</b>
|
||||||
|
<span v-else>{{ train.driverName }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="timetable_route" v-if="train.timetableData">
|
<div class="general-timetable" v-if="train.timetableData">
|
||||||
<strong>{{ train.timetableData.route.replace('|', ' - ') }}</strong>
|
<strong>{{ train.timetableData.route.replace('|', ' - ') }}</strong>
|
||||||
<img
|
<img
|
||||||
v-if="getSceneriesWithComments(train.timetableData).length > 0"
|
v-if="getSceneriesWithComments(train.timetableData).length > 0"
|
||||||
@@ -49,27 +59,30 @@
|
|||||||
|
|
||||||
<hr style="margin: 0.25em 0" />
|
<hr style="margin: 0.25em 0" />
|
||||||
|
|
||||||
<div class="timetable_stops" v-if="train.timetableData">
|
<div class="general-stops" v-if="train.timetableData">
|
||||||
<span v-if="train.timetableData.followingStops.length > 2">
|
<span v-if="train.timetableData.followingStops.length > 2">
|
||||||
{{ $t('trains.via-title') }}
|
{{ $t('trains.via-title') }}
|
||||||
<span v-html="displayStopList(train.timetableData.followingStops)"></span>
|
<span v-html="displayStopList(train.timetableData.followingStops)"></span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="timetable_progress" style="margin-top: 0.5em" v-if="train.timetableData">
|
<div class="general-status">
|
||||||
<ProgressBar :progressPercent="confirmedPercentage(train.timetableData.followingStops)" />
|
<div class="timetable-progress" v-if="train.timetableData">
|
||||||
|
<ProgressBar :progressPercent="confirmedPercentage(train.timetableData.followingStops)" />
|
||||||
|
|
||||||
<span class="timetable_progress-distance">
|
<span class="progress-distance">
|
||||||
{{ currentDistance(train.timetableData.followingStops) }} km /
|
{{ currentDistance(train.timetableData.followingStops) }} km /
|
||||||
<span class="text--primary"> {{ train.timetableData.routeDistance }} km </span>
|
<span class="text--primary"> {{ train.timetableData.routeDistance }} km </span>
|
||||||
|
|
|
|
||||||
<span v-html="currentDelay(train.timetableData.followingStops)"></span>
|
<span v-html="currentDelay(train.timetableData.followingStops)"></span>
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="train-status-badges">
|
<div class="status-badges">
|
||||||
<div v-if="!train.currentStationHash" class="train-badge offline">
|
<div v-if="!train.currentStationHash" class="train-badge offline">
|
||||||
{{ $t('trains.scenery-offline') }}
|
{{ $t('trains.scenery-offline') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!train.online" class="train-badge offline">
|
<div v-if="!train.online" class="train-badge offline">
|
||||||
Offline {{ lastSeenMessage(train.lastSeen) }}
|
Offline {{ lastSeenMessage(train.lastSeen) }}
|
||||||
</div>
|
</div>
|
||||||
@@ -111,6 +124,7 @@ import trainInfoMixin from '../../mixins/trainInfoMixin';
|
|||||||
import Train from '../../scripts/interfaces/Train';
|
import Train from '../../scripts/interfaces/Train';
|
||||||
import ProgressBar from '../Global/ProgressBar.vue';
|
import ProgressBar from '../Global/ProgressBar.vue';
|
||||||
import TrainThumbnail from '../Global/TrainThumbnail.vue';
|
import TrainThumbnail from '../Global/TrainThumbnail.vue';
|
||||||
|
import { useStore } from '../../store/mainStore';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [trainInfoMixin, styleMixin],
|
mixins: [trainInfoMixin, styleMixin],
|
||||||
@@ -125,6 +139,12 @@ export default defineComponent({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
store: useStore()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -168,6 +188,11 @@ export default defineComponent({
|
|||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.train-driver img {
|
||||||
|
max-height: 20px;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
.timetable-id {
|
.timetable-id {
|
||||||
color: #d2d2d2;
|
color: #d2d2d2;
|
||||||
}
|
}
|
||||||
@@ -181,11 +206,17 @@ export default defineComponent({
|
|||||||
padding: 0 0.25em;
|
padding: 0 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timetable_stops {
|
.train-general {
|
||||||
font-size: 0.75em;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.train_general {
|
.general-stops {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.general-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -193,55 +224,41 @@ export default defineComponent({
|
|||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
margin-right: 1.5em;
|
margin-right: 1.5em;
|
||||||
}
|
}
|
||||||
.train-status-badges {
|
.general-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
gap: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badges {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.train-driver {
|
.general-timetable {
|
||||||
&.supporter {
|
|
||||||
color: orange;
|
|
||||||
text-shadow: orange 0 0 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.timetable_route {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.timetable_warnings {
|
.timetable-warnings {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timetable_progress {
|
.timetable-progress {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timetable_progress-distance {
|
.progress-distance {
|
||||||
margin-right: 0.25em;
|
margin-right: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comments {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
font-size: 0.9em;
|
|
||||||
|
|
||||||
margin-top: 1em;
|
|
||||||
|
|
||||||
img {
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include smallScreen() {
|
@include smallScreen() {
|
||||||
.train-info {
|
.train-info {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
@@ -251,23 +268,13 @@ export default defineComponent({
|
|||||||
font-size: 1.15em;
|
font-size: 1.15em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.train-stats {
|
.general-info,
|
||||||
font-size: 1.1em;
|
.general-status,
|
||||||
}
|
.general-timetable {
|
||||||
|
|
||||||
.train_general {
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.train-status-badges {
|
.timetable-progress {
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timetable_route {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timetable_progress {
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,11 @@
|
|||||||
v-model="searchedTrain"
|
v-model="searchedTrain"
|
||||||
/>
|
/>
|
||||||
<button class="search-exit">
|
<button class="search-exit">
|
||||||
<img src="/images/icon-exit.svg" alt="Trains search clear icon" @click="onInputClear('train')" />
|
<img
|
||||||
|
src="/images/icon-exit.svg"
|
||||||
|
alt="Trains search clear icon"
|
||||||
|
@click="onInputClear('train')"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -36,7 +40,11 @@
|
|||||||
v-model="searchedDriver"
|
v-model="searchedDriver"
|
||||||
/>
|
/>
|
||||||
<button class="search-exit">
|
<button class="search-exit">
|
||||||
<img src="/images/icon-exit.svg" alt="Driver search clear icon" @click="onInputClear('driver')" />
|
<img
|
||||||
|
src="/images/icon-exit.svg"
|
||||||
|
alt="Driver search clear icon"
|
||||||
|
@click="onInputClear('driver')"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -87,8 +95,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, inject, PropType } from 'vue';
|
import { defineComponent, inject, PropType } from 'vue';
|
||||||
import keyMixin from '../../mixins/keyMixin';
|
import keyMixin from '../../mixins/keyMixin';
|
||||||
import { TrainFilterSection } from '../../scripts/enums/TrainFilterType';
|
import { TrainFilter, TrainFilterSection } from './typings';
|
||||||
import { TrainFilter } from '../../scripts/interfaces/Trains/TrainFilter';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [keyMixin],
|
mixins: [keyMixin],
|
||||||
@@ -152,9 +159,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onFilterChange(filter: TrainFilter) {
|
onFilterChange(filter: TrainFilter) {
|
||||||
// if (this.lastSelectedFilter?.id === filter.id)
|
|
||||||
// this.trainFilterList.forEach((tf) => (tf.isActive = filter.id === tf.id));
|
|
||||||
|
|
||||||
filter.isActive = !filter.isActive;
|
filter.isActive = !filter.isActive;
|
||||||
this.lastSelectedFilter = filter;
|
this.lastSelectedFilter = filter;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -72,10 +72,10 @@
|
|||||||
import { computed, defineComponent, PropType } from 'vue';
|
import { computed, defineComponent, PropType } from 'vue';
|
||||||
import dateMixin from '../../mixins/dateMixin';
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
import Train from '../../scripts/interfaces/Train';
|
import Train from '../../scripts/interfaces/Train';
|
||||||
import TrainStop from '../../scripts/interfaces/TrainStop';
|
import { useStore } from '../../store/mainStore';
|
||||||
import { useStore } from '../../store/store';
|
|
||||||
import StopDate from '../Global/StopDate.vue';
|
import StopDate from '../Global/StopDate.vue';
|
||||||
import StockList from '../Global/StockList.vue';
|
import StockList from '../Global/StockList.vue';
|
||||||
|
import { TrainStop } from '../../store/typings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { StopDate, StockList },
|
components: { StopDate, StockList },
|
||||||
|
|||||||
@@ -1,44 +1,44 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="train-table">
|
<transition name="status-anim" mode="out-in" tag="div" class="train-table">
|
||||||
<transition name="anim" mode="out-in">
|
<div :key="store.dataStatuses.trains">
|
||||||
<div :key="store.dataStatuses.trains">
|
<div class="table-info" key="offline" v-if="store.isOffline">
|
||||||
<div class="table-info" v-if="store.isOffline">
|
{{ $t('app.offline') }}
|
||||||
{{ $t('app.offline') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Loading v-else-if="trains.length == 0 && store.dataStatuses.trains == 0" />
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="table-info no-trains"
|
|
||||||
v-else-if="trains.length == 0 && store.dataStatuses.trains != 0"
|
|
||||||
>
|
|
||||||
{{ $t('trains.no-trains') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<transition-group name="list-anim" tag="ul" class="train-list" v-else>
|
|
||||||
<li
|
|
||||||
class="train-row"
|
|
||||||
v-for="train in currentTrains"
|
|
||||||
:key="train.trainId"
|
|
||||||
tabindex="0"
|
|
||||||
@click.stop="selectModalTrain(train.trainId, $event.currentTarget)"
|
|
||||||
@keydown.enter="selectModalTrain(train.trainId, $event.currentTarget)"
|
|
||||||
>
|
|
||||||
<TrainInfo :train="train" />
|
|
||||||
</li>
|
|
||||||
</transition-group>
|
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
</div>
|
<Loading v-else-if="trains.length == 0 && store.dataStatuses.trains == 0" key="loading" />
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="table-info"
|
||||||
|
key="no-trains"
|
||||||
|
v-else-if="trains.length == 0 && store.dataStatuses.trains != 0"
|
||||||
|
>
|
||||||
|
{{ $t('trains.no-trains') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<transition-group name="list-anim" tag="ul">
|
||||||
|
<li
|
||||||
|
class="train-row"
|
||||||
|
v-for="train in trains"
|
||||||
|
:key="train.trainId"
|
||||||
|
tabindex="0"
|
||||||
|
@click.stop="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||||
|
@keydown.enter="selectModalTrain(train.trainId, $event.currentTarget)"
|
||||||
|
>
|
||||||
|
<TrainInfo :train="train" />
|
||||||
|
</li>
|
||||||
|
</transition-group>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, inject, PropType, Ref } from 'vue';
|
import { defineComponent, inject, PropType, Ref } from 'vue';
|
||||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||||
import Train from '../../scripts/interfaces/Train';
|
import Train from '../../scripts/interfaces/Train';
|
||||||
import { useStore } from '../../store/store';
|
import { useStore } from '../../store/mainStore';
|
||||||
import Loading from '../Global/Loading.vue';
|
import Loading from '../Global/Loading.vue';
|
||||||
import TrainInfo from './TrainInfo.vue';
|
import TrainInfo from './TrainInfo.vue';
|
||||||
|
import { Status } from '../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { Loading, TrainInfo },
|
components: { Loading, TrainInfo },
|
||||||
@@ -52,18 +52,14 @@ export default defineComponent({
|
|||||||
|
|
||||||
mixins: [modalTrainMixin],
|
mixins: [modalTrainMixin],
|
||||||
|
|
||||||
setup(props) {
|
setup() {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const searchedTrain = inject('searchedTrain') as Ref<string>;
|
const searchedTrain = inject('searchedTrain') as Ref<string>;
|
||||||
const searchedDriver = inject('searchedDriver') as Ref<string>;
|
const searchedDriver = inject('searchedDriver') as Ref<string>;
|
||||||
const currentTrains = computed(() => {
|
|
||||||
return props.trains;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
searchedTrain,
|
searchedTrain,
|
||||||
searchedDriver,
|
searchedDriver,
|
||||||
currentTrains,
|
|
||||||
store,
|
store,
|
||||||
sorterActive: inject('sorterActive') as {
|
sorterActive: inject('sorterActive') as {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
@@ -72,6 +68,17 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
dataStatus() {
|
||||||
|
if (this.store.isOffline) return Status.Data.Offline;
|
||||||
|
|
||||||
|
if (this.trains.length == 0 && this.store.dataStatuses.trains == Status.Data.Loading)
|
||||||
|
return Status.Data.Loading;
|
||||||
|
|
||||||
|
return Status.Data.Loaded;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
activated() {
|
activated() {
|
||||||
const query = this.$route.query;
|
const query = this.$route.query;
|
||||||
if (query.trainNo && query.driverName) {
|
if (query.trainNo && query.driverName) {
|
||||||
@@ -89,19 +96,13 @@ export default defineComponent({
|
|||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
@import '../../styles/animations.scss';
|
@import '../../styles/animations.scss';
|
||||||
|
|
||||||
.anim {
|
.train-table {
|
||||||
&-enter-from,
|
position: relative;
|
||||||
&-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-active {
|
height: 90vh;
|
||||||
transition: all 100ms ease-out;
|
min-height: 550px;
|
||||||
}
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
&-leave-active {
|
|
||||||
transition: all 100ms ease-out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-info {
|
.table-info {
|
||||||
@@ -114,96 +115,11 @@ export default defineComponent({
|
|||||||
background: #1a1a1a;
|
background: #1a1a1a;
|
||||||
}
|
}
|
||||||
|
|
||||||
img.train-image {
|
li.train-row {
|
||||||
width: 12em;
|
background-color: var(--clr-secondary);
|
||||||
}
|
margin-bottom: 1em;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
.traffic-warning {
|
cursor: pointer;
|
||||||
padding: 1em 0;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
background: var(--clr-warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
.timeouts-warning {
|
|
||||||
background-color: #333;
|
|
||||||
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1.05em;
|
|
||||||
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.warning-timeout {
|
|
||||||
background-color: #be3728;
|
|
||||||
color: white;
|
|
||||||
|
|
||||||
display: inline-block;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
width: 1.25em;
|
|
||||||
height: 1.25em;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.train {
|
|
||||||
&-list {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
@include smallScreen() {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-row {
|
|
||||||
background-color: var(--clr-secondary);
|
|
||||||
margin-bottom: 1em;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&_cars {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.paginator {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
&_item {
|
|
||||||
padding: 0.25em 0.5em;
|
|
||||||
margin: 0 0.5em;
|
|
||||||
outline: 2px solid salmon;
|
|
||||||
|
|
||||||
min-width: 30px;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.page-number {
|
|
||||||
font-weight: bold;
|
|
||||||
color: gold;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disabled {
|
|
||||||
outline: 2px solid lightgray;
|
|
||||||
color: lightgray;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: 2px solid white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include smallScreen() {
|
|
||||||
.info-bottom {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,63 +1,93 @@
|
|||||||
import { TrainFilterSection, TrainFilterType } from '../../scripts/enums/TrainFilterType';
|
export enum TrainFilterSection {
|
||||||
import { TrainFilter } from '../../scripts/interfaces/Trains/TrainFilter';
|
TRAIN_TYPE = 'TRAIN_TYPE',
|
||||||
|
TIMETABLE_TYPE = 'TIMETABLE_TYPE',
|
||||||
|
COMMENTS = 'COMMENTS',
|
||||||
|
TIMETABLE = 'TIMETABLE'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum TrainFilterId {
|
||||||
|
noComments = 'noComments',
|
||||||
|
withComments = 'withComments',
|
||||||
|
|
||||||
|
twr = 'twr',
|
||||||
|
skr = 'skr',
|
||||||
|
common = 'common',
|
||||||
|
|
||||||
|
passenger = 'passenger',
|
||||||
|
freight = 'freight',
|
||||||
|
other = 'other',
|
||||||
|
noTimetable = 'noTimetable',
|
||||||
|
withTimetable = 'withTimetable'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TrainFilter {
|
||||||
|
id: TrainFilterId;
|
||||||
|
section: TrainFilterSection;
|
||||||
|
isActive: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TrainSorter {
|
||||||
|
id: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const trainFilters: TrainFilter[] = [
|
export const trainFilters: TrainFilter[] = [
|
||||||
{
|
{
|
||||||
id: TrainFilterType.twr,
|
id: TrainFilterId.twr,
|
||||||
section: TrainFilterSection.TRAIN_TYPE,
|
section: TrainFilterSection.TRAIN_TYPE,
|
||||||
isActive: true
|
isActive: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: TrainFilterType.skr,
|
id: TrainFilterId.skr,
|
||||||
section: TrainFilterSection.TRAIN_TYPE,
|
section: TrainFilterSection.TRAIN_TYPE,
|
||||||
isActive: true
|
isActive: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: TrainFilterType.common,
|
id: TrainFilterId.common,
|
||||||
section: TrainFilterSection.TRAIN_TYPE,
|
section: TrainFilterSection.TRAIN_TYPE,
|
||||||
isActive: true
|
isActive: true
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: TrainFilterType.passenger,
|
id: TrainFilterId.passenger,
|
||||||
section: TrainFilterSection.TIMETABLE_TYPE,
|
section: TrainFilterSection.TIMETABLE_TYPE,
|
||||||
isActive: true
|
isActive: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: TrainFilterType.freight,
|
id: TrainFilterId.freight,
|
||||||
section: TrainFilterSection.TIMETABLE_TYPE,
|
section: TrainFilterSection.TIMETABLE_TYPE,
|
||||||
isActive: true
|
isActive: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: TrainFilterType.other,
|
id: TrainFilterId.other,
|
||||||
section: TrainFilterSection.TIMETABLE_TYPE,
|
section: TrainFilterSection.TIMETABLE_TYPE,
|
||||||
isActive: true
|
isActive: true
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: TrainFilterType.withComments,
|
id: TrainFilterId.withComments,
|
||||||
section: TrainFilterSection.COMMENTS,
|
section: TrainFilterSection.COMMENTS,
|
||||||
isActive: true
|
isActive: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: TrainFilterType.noComments,
|
id: TrainFilterId.noComments,
|
||||||
section: TrainFilterSection.COMMENTS,
|
section: TrainFilterSection.COMMENTS,
|
||||||
isActive: true
|
isActive: true
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: TrainFilterType.withTimetable,
|
id: TrainFilterId.withTimetable,
|
||||||
section: TrainFilterSection.TIMETABLE,
|
section: TrainFilterSection.TIMETABLE,
|
||||||
isActive: true
|
isActive: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: TrainFilterType.noTimetable,
|
id: TrainFilterId.noTimetable,
|
||||||
section: TrainFilterSection.TIMETABLE,
|
section: TrainFilterSection.TIMETABLE,
|
||||||
isActive: true
|
isActive: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export const sorterOptions = [
|
export const sorterOptions: TrainSorter[] = [
|
||||||
{
|
{
|
||||||
id: 'distance',
|
id: 'distance',
|
||||||
value: 'kilometraż'
|
value: 'kilometraż'
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import { JournalFilterSection, JournalFilterType } from '../../scripts/enums/JournalFilterType';
|
|
||||||
import { JournalFilter } from '../../scripts/types/JournalTimetablesTypes';
|
|
||||||
|
|
||||||
export const journalTimetableFilters: JournalFilter[] = [
|
|
||||||
{
|
|
||||||
id: JournalFilterType.ALL,
|
|
||||||
filterSection: JournalFilterSection.TIMETABLE_STATUS,
|
|
||||||
isActive: true
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
id: JournalFilterType.ACTIVE,
|
|
||||||
filterSection: JournalFilterSection.TIMETABLE_STATUS,
|
|
||||||
isActive: false
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
id: JournalFilterType.FULFILLED,
|
|
||||||
filterSection: JournalFilterSection.TIMETABLE_STATUS,
|
|
||||||
isActive: false
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
id: JournalFilterType.ABANDONED,
|
|
||||||
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
|
|
||||||
}
|
|
||||||
];
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
[
|
|
||||||
"EP07-356",
|
|
||||||
"EP07-356",
|
|
||||||
"EP07-356",
|
|
||||||
"ET41-074",
|
|
||||||
"2EN57-694+716rb",
|
|
||||||
"EU07E-083",
|
|
||||||
"EN57-716rb",
|
|
||||||
"EN57-716rb",
|
|
||||||
"EN57-716rb",
|
|
||||||
"EN57-038rb",
|
|
||||||
"EN57-038rb",
|
|
||||||
"SM42-329_PLREG",
|
|
||||||
"2EN57-038+1715rb",
|
|
||||||
"EN57-1953rb",
|
|
||||||
"EN57-1953rb",
|
|
||||||
"SM42-1121",
|
|
||||||
"SM42-091",
|
|
||||||
"SM42-404",
|
|
||||||
"SM42-404",
|
|
||||||
"EN57-1914rb",
|
|
||||||
"EN57-961rb"
|
|
||||||
]
|
|
||||||
+1438
-13428
File diff suppressed because it is too large
Load Diff
+19
-1
@@ -1,4 +1,21 @@
|
|||||||
{
|
{
|
||||||
|
"donations": {
|
||||||
|
"button-title": "TOSS A COIN",
|
||||||
|
"header": "Toss a coin to Stacjownik!",
|
||||||
|
"p1": "<b>Hello o7!</b> This is Spythere, the creator of Stacjownik, Pojazdownik and several other applications that enhance the gameplay of Train Driver 2!",
|
||||||
|
"p2": "{b1} is a completely free tool, created and continuously developed for the Train Driver 2 simulator community since 2020. However, a part of the project is sustained solely through my private financial contribution. Features such as {b2} or {b3} (operating on my {link} - to which you are warmly invited) must function on a dedicated server where they can collect and process data, and then display it on the website.",
|
||||||
|
"p2-b1": "Stacjownik",
|
||||||
|
"p2-b2": "Journal",
|
||||||
|
"p2-b3": "Stacjobot (Stacjownik bot)",
|
||||||
|
"p2-a1": "Discord server",
|
||||||
|
"p3": "<b>If you have the means and would like to support my work, I would be grateful for any financial assistance that could help cover at least some of the server costs and further enhance the capabilities of the application!</b>",
|
||||||
|
"p4": "Every person who decides to contribute at least {b1} for the development of Stacjownik, will receive (upon a personal request) {img}{b2} of username in the \"Sceneries\" and \"Trains\" tabs of the application, as well as on my Discord server (after verifying the payment author, preferably by providing the username directly with the payment).",
|
||||||
|
"p4-b1": "5 PLN",
|
||||||
|
"p4-b2": "a symbolic highlight",
|
||||||
|
"p5": "Thank you and enjoy the app!<br />~ Spythere",
|
||||||
|
"action-exit": "Maybe next time...",
|
||||||
|
"action-confirm": "DONATE!"
|
||||||
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"and": " and ",
|
"and": " and ",
|
||||||
"refresh": "REFRESH",
|
"refresh": "REFRESH",
|
||||||
@@ -78,8 +95,9 @@
|
|||||||
"not-signed": "NOT SIGNED IN",
|
"not-signed": "NOT SIGNED IN",
|
||||||
"no-limit": "NO LIMIT",
|
"no-limit": "NO LIMIT",
|
||||||
"unavailable": "UNAVAILABLE",
|
"unavailable": "UNAVAILABLE",
|
||||||
"brb": "AFK",
|
"afk": "AFK",
|
||||||
"no-space": "NO SPACE",
|
"no-space": "NO SPACE",
|
||||||
|
"invalid": "INVALID HASH",
|
||||||
"unknown": "UNKNOWN"
|
"unknown": "UNKNOWN"
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
|
|||||||
+19
-1
@@ -1,4 +1,21 @@
|
|||||||
{
|
{
|
||||||
|
"donations": {
|
||||||
|
"button-title": "GROSZA DAJ",
|
||||||
|
"header": "Grosza daj Stacjownikowi!",
|
||||||
|
"p1": "<b>Hej o7!</b> Z tej strony Spythere, twórca Stacjownika, Pojazdownika oraz kilku innych aplikacji wspomagających rozgrywkę symulatora Train Driver 2!",
|
||||||
|
"p2": "{b1} to narzędzie całkowicie darmowe, tworzone i rozwijane dla społeczności symulatora TD2 nieprzerwanie od 2020 roku. Jednakże, część projektu jest podtrzymywana wyłącznie dzięki mojemu prywatnemu wkładowi finansowemu. Funkcje takie jak {b2} czy też {b3} działający na moim {link} (na który serdeczne zapraszam) muszą działać na wydzielonym serwerze, gdzie będą mogły zbierać i przetwarzać dane, aby następnie pokazać je na stronie.",
|
||||||
|
"p2-b1": "Stacjownik",
|
||||||
|
"p2-b2": "Dziennik",
|
||||||
|
"p2-b3": "Stacjobot",
|
||||||
|
"p2-a1": "serwerze Discord",
|
||||||
|
"p3": "<b>Jeśli masz możliwość i chcesz wspomóc moją twórczość dla symulatora, będę wdzięczny za wszelkie pomoce finansowe, które pozwolą na choćby częściowe pokrycie kosztów serwera oraz dalsze rozwijanie możliwości aplikacji!</b>",
|
||||||
|
"p4": "Każda osoba, która postanowi przelać co najmniej {b1} na rozwój Stacjownika, otrzyma na życzenie symboliczne {img}{b2} nicku użytkownika w zakładkach \"Scenerie\" i \"Pociągi\" aplikacji i moim serwerze Discord (po zweryfikowaniu autora płatności, najlepiej poprzez podanie nicku bezpośrednio przy niej).",
|
||||||
|
"p4-b1": "5 złotych",
|
||||||
|
"p4-b2": "wyróżnienie",
|
||||||
|
"p5": "Dzięki i miłego korzystania z aplikacji! <br />~ Spythere",
|
||||||
|
"action-exit": "Może kiedy indziej...",
|
||||||
|
"action-confirm": "WSPOMÓŻ!"
|
||||||
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"and": " oraz ",
|
"and": " oraz ",
|
||||||
"refresh": "ODŚWIEŻ",
|
"refresh": "ODŚWIEŻ",
|
||||||
@@ -66,8 +83,9 @@
|
|||||||
"not-signed": "NIEZALOGOWANY",
|
"not-signed": "NIEZALOGOWANY",
|
||||||
"no-limit": "BEZ LIMITU",
|
"no-limit": "BEZ LIMITU",
|
||||||
"unavailable": "NIEDOSTĘPNY",
|
"unavailable": "NIEDOSTĘPNY",
|
||||||
"brb": "Z/W",
|
"afk": "Z/W",
|
||||||
"no-space": "BRAK MIEJSCA",
|
"no-space": "BRAK MIEJSCA",
|
||||||
|
"invalid": "NIEWPISANY",
|
||||||
"unknown": "NIEZNANY"
|
"unknown": "NIEZNANY"
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { TrainFilter } from '../interfaces/Trains/TrainFilter';
|
import { TrainFilter, TrainFilterId } from '../components/TrainsView/typings';
|
||||||
import { TrainFilterType } from '../enums/TrainFilterType';
|
import Train from '../scripts/interfaces/Train';
|
||||||
import Train from '../interfaces/Train';
|
import { TrainStop } from '../store/typings';
|
||||||
import TrainStop from '../interfaces/TrainStop';
|
|
||||||
|
|
||||||
function confirmedPercentage(stops: TrainStop[] | undefined) {
|
function confirmedPercentage(stops: TrainStop[] | undefined) {
|
||||||
if (!stops) return -1;
|
if (!stops) return -1;
|
||||||
@@ -32,34 +31,34 @@ function filterTrainList(
|
|||||||
if (f.isActive) return true;
|
if (f.isActive) return true;
|
||||||
|
|
||||||
switch (f.id) {
|
switch (f.id) {
|
||||||
case TrainFilterType.noTimetable:
|
case TrainFilterId.noTimetable:
|
||||||
return train.timetableData;
|
return train.timetableData;
|
||||||
|
|
||||||
case TrainFilterType.withTimetable:
|
case TrainFilterId.withTimetable:
|
||||||
return !train.timetableData;
|
return !train.timetableData;
|
||||||
|
|
||||||
case TrainFilterType.withComments:
|
case TrainFilterId.withComments:
|
||||||
return !train.timetableData?.followingStops.some((stop) => stop.comments);
|
return !train.timetableData?.followingStops.some((stop) => stop.comments);
|
||||||
|
|
||||||
case TrainFilterType.noComments:
|
case TrainFilterId.noComments:
|
||||||
return train.timetableData?.followingStops.some((stop) => stop.comments);
|
return train.timetableData?.followingStops.some((stop) => stop.comments);
|
||||||
|
|
||||||
case TrainFilterType.twr:
|
case TrainFilterId.twr:
|
||||||
return !train.timetableData?.TWR;
|
return !train.timetableData?.TWR;
|
||||||
|
|
||||||
case TrainFilterType.skr:
|
case TrainFilterId.skr:
|
||||||
return !train.timetableData?.SKR;
|
return !train.timetableData?.SKR;
|
||||||
|
|
||||||
case TrainFilterType.common:
|
case TrainFilterId.common:
|
||||||
return train.timetableData?.SKR || train.timetableData?.TWR;
|
return train.timetableData?.SKR || train.timetableData?.TWR;
|
||||||
|
|
||||||
case TrainFilterType.passenger:
|
case TrainFilterId.passenger:
|
||||||
return !/^[AMRE]\D{2}$/.test(train.timetableData?.category || '');
|
return !/^[AMRE]\D{2}$/.test(train.timetableData?.category || '');
|
||||||
|
|
||||||
case TrainFilterType.freight:
|
case TrainFilterId.freight:
|
||||||
return !train.timetableData?.category.startsWith('T');
|
return !train.timetableData?.category.startsWith('T');
|
||||||
|
|
||||||
case TrainFilterType.other:
|
case TrainFilterId.other:
|
||||||
return !/^[PXZL]\D{2}$/.test(train.timetableData?.category || '');
|
return !/^[PXZL]\D{2}$/.test(train.timetableData?.category || '');
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -72,7 +71,6 @@ function filterTrainList(
|
|||||||
(searchedDriver.length > 0
|
(searchedDriver.length > 0
|
||||||
? train.driverName.toLowerCase().startsWith(searchedDriver.toLowerCase())
|
? train.driverName.toLowerCase().startsWith(searchedDriver.toLowerCase())
|
||||||
: true) &&
|
: true) &&
|
||||||
(!train.timetableData ? train.online : train.timetableData) &&
|
|
||||||
isFiltered
|
isFiltered
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useStore } from '../store/store';
|
import { useStore } from '../store/mainStore';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import Train from '../scripts/interfaces/Train';
|
import Train from '../scripts/interfaces/Train';
|
||||||
import TrainStop from '../scripts/interfaces/TrainStop';
|
import { TrainStop } from '../store/typings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
data: () => ({
|
data: () => ({
|
||||||
|
|||||||
+2
-1
@@ -61,7 +61,8 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
scrollBehavior(to, from, savedPosition) {
|
scrollBehavior(to, from, savedPosition) {
|
||||||
if (to.name == 'SceneryView' && from.name) return { el: `.app_main` };
|
if (to.name == 'SceneryView' && from.name && from.query['view'] === undefined)
|
||||||
|
return { el: `.app_main` };
|
||||||
|
|
||||||
if (savedPosition) return savedPosition;
|
if (savedPosition) return savedPosition;
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
import Filter from '../../interfaces/Filter';
|
|
||||||
|
|
||||||
export const filterInitStates: Filter = {
|
|
||||||
default: false,
|
|
||||||
notDefault: false,
|
|
||||||
real: false,
|
|
||||||
fictional: false,
|
|
||||||
SPK: false,
|
|
||||||
SCS: false,
|
|
||||||
SPE: false,
|
|
||||||
SUP: false,
|
|
||||||
noSUP: false,
|
|
||||||
ręczne: false,
|
|
||||||
'ręczne+SPK': false,
|
|
||||||
'ręczne+SCS': false,
|
|
||||||
mechaniczne: false,
|
|
||||||
'mechaniczne+SPK': false,
|
|
||||||
'mechaniczne+SCS': false,
|
|
||||||
współczesna: false,
|
|
||||||
kształtowa: false,
|
|
||||||
historyczna: false,
|
|
||||||
mieszana: false,
|
|
||||||
SBL: false,
|
|
||||||
PBL: false,
|
|
||||||
minLevel: 0,
|
|
||||||
maxLevel: 20,
|
|
||||||
minOneWayCatenary: 0,
|
|
||||||
minOneWay: 0,
|
|
||||||
minTwoWayCatenary: 0,
|
|
||||||
minTwoWay: 0,
|
|
||||||
'include-selected': false,
|
|
||||||
'no-1track': false,
|
|
||||||
'no-2track': false,
|
|
||||||
free: true,
|
|
||||||
occupied: false,
|
|
||||||
ending: false,
|
|
||||||
nonPublic: false,
|
|
||||||
unavailable: true,
|
|
||||||
abandoned: true,
|
|
||||||
afkStatus: false,
|
|
||||||
endingStatus: false,
|
|
||||||
noSpaceStatus: false,
|
|
||||||
unavailableStatus: false,
|
|
||||||
unsignedStatus: false,
|
|
||||||
|
|
||||||
authors: '',
|
|
||||||
|
|
||||||
onlineFromHours: 0
|
|
||||||
};
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
export enum DataStatus {
|
|
||||||
Initialized = -1,
|
|
||||||
Loading = 0,
|
|
||||||
Error = 1,
|
|
||||||
Loaded = 2,
|
|
||||||
Warning = 3
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
export enum DispatcherStatusID {
|
|
||||||
Unknown = 'unknown',
|
|
||||||
Outdated = 'outdated',
|
|
||||||
Unauthorized = 'not-signed',
|
|
||||||
OnlineNoLimit = 'no-limit',
|
|
||||||
Afk = 'brb',
|
|
||||||
Ending = 'ending',
|
|
||||||
NoSpace = 'no-space',
|
|
||||||
Unavailable = 'unavailable',
|
|
||||||
OnlineWithHours = 'online'
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
export const enum JournalFilterType {
|
|
||||||
ACTIVE = 'active',
|
|
||||||
FULFILLED = 'fulfilled',
|
|
||||||
ABANDONED = 'abandoned',
|
|
||||||
ALL = 'all',
|
|
||||||
TWR = 'twr',
|
|
||||||
SKR = 'skr',
|
|
||||||
TWR_SKR = 'twr-skr'
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum JournalFilterSection {
|
|
||||||
TIMETABLE_STATUS = 'timetable-status',
|
|
||||||
TWRSKR = 'twrskr'
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
export enum TrainFilterSection {
|
|
||||||
TRAIN_TYPE = 'TRAIN_TYPE',
|
|
||||||
TIMETABLE_TYPE = 'TIMETABLE_TYPE',
|
|
||||||
COMMENTS = 'COMMENTS',
|
|
||||||
TIMETABLE = 'TIMETABLE'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum TrainFilterType {
|
|
||||||
noComments = 'noComments',
|
|
||||||
withComments = 'withComments',
|
|
||||||
|
|
||||||
twr = 'twr',
|
|
||||||
skr = 'skr',
|
|
||||||
common = 'common',
|
|
||||||
|
|
||||||
passenger = 'passenger',
|
|
||||||
freight = 'freight',
|
|
||||||
other = 'other',
|
|
||||||
noTimetable = 'noTimetable',
|
|
||||||
withTimetable = 'withTimetable'
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export default interface FilterOption {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
value: boolean;
|
|
||||||
defaultValue: boolean;
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
interface Scenery {
|
|
||||||
stationName: string;
|
|
||||||
stationURL: string;
|
|
||||||
stationLines: string;
|
|
||||||
stationProject: string;
|
|
||||||
|
|
||||||
reqLevel: string;
|
|
||||||
supportersOnly: string;
|
|
||||||
signalType: string;
|
|
||||||
controlType: string;
|
|
||||||
SBL: string;
|
|
||||||
twoWayBlock: string;
|
|
||||||
|
|
||||||
routesOneWayCatenary: number;
|
|
||||||
routesOneWayOther: number;
|
|
||||||
routesTwoWayCatenary: number;
|
|
||||||
routesToWayOther: number;
|
|
||||||
|
|
||||||
default: boolean;
|
|
||||||
nonPublic: boolean;
|
|
||||||
unavailable: boolean;
|
|
||||||
hasData: boolean;
|
|
||||||
|
|
||||||
stops: string[];
|
|
||||||
checkpoints: string[];
|
|
||||||
|
|
||||||
currentDispatcher: string;
|
|
||||||
currentDispatcherId: number;
|
|
||||||
currentDispatcherFrom: number;
|
|
||||||
dispatcherHistory: {
|
|
||||||
dispatcherName: string;
|
|
||||||
dispatcherId: number;
|
|
||||||
dispatcherFrom: number;
|
|
||||||
dispatcherTo: number;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Scenery;
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
import TrainStop from './TrainStop';
|
|
||||||
|
|
||||||
export enum StopStatus {
|
|
||||||
'arriving' = 'arriving',
|
|
||||||
'departed' = 'departed',
|
|
||||||
'departed-away' = 'departed-away',
|
|
||||||
'online' = 'online',
|
|
||||||
'stopped' = 'stopped',
|
|
||||||
'terminated' = 'terminated'
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ScheduledTrain {
|
|
||||||
checkpointName: string;
|
|
||||||
|
|
||||||
trainId: string;
|
|
||||||
trainNo: number;
|
|
||||||
|
|
||||||
driverName: string;
|
|
||||||
driverId: number;
|
|
||||||
currentStationName: string;
|
|
||||||
currentStationHash: string;
|
|
||||||
category: string;
|
|
||||||
stopInfo: TrainStop;
|
|
||||||
|
|
||||||
terminatesAt: string;
|
|
||||||
beginsAt: string;
|
|
||||||
|
|
||||||
prevStationName: string;
|
|
||||||
nextStationName: string;
|
|
||||||
|
|
||||||
arrivingLine: string | null;
|
|
||||||
departureLine: string | null;
|
|
||||||
|
|
||||||
prevDepartureLine: string | null;
|
|
||||||
nextArrivalLine: string | null;
|
|
||||||
|
|
||||||
signal: string;
|
|
||||||
connectedTrack: string;
|
|
||||||
|
|
||||||
stopLabel: string;
|
|
||||||
stopStatus: StopStatus;
|
|
||||||
stopStatusID: number;
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Availability, OnlineScenery } from './store/storeTypes';
|
import { Availability, OnlineScenery, ScheduledTrain } from '../../store/typings';
|
||||||
import { ScheduledTrain } from './ScheduledTrain';
|
|
||||||
import StationRoutes from './StationRoutes';
|
import StationRoutes from './StationRoutes';
|
||||||
|
|
||||||
export default interface Station {
|
export default interface Station {
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { DataStatus } from '../enums/DataStatus';
|
|
||||||
import Station from './Station';
|
|
||||||
import Train from './Train';
|
|
||||||
|
|
||||||
export interface StoreData {
|
|
||||||
stationList: Station[];
|
|
||||||
trainList: Train[];
|
|
||||||
dispatcherCount: number;
|
|
||||||
|
|
||||||
sceneryDataStatus: DataStatus;
|
|
||||||
dispatcherDataStatus: DataStatus;
|
|
||||||
trainsDataStatus: DataStatus;
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import TrainStop from './TrainStop';
|
|
||||||
|
|
||||||
export default interface Timetable {
|
|
||||||
trainNo: number;
|
|
||||||
|
|
||||||
success: boolean;
|
|
||||||
|
|
||||||
data?: {
|
|
||||||
trainNo: number;
|
|
||||||
driverName: string;
|
|
||||||
driverId: number;
|
|
||||||
currentStationName: string;
|
|
||||||
currentStationHash: string;
|
|
||||||
timetableId: number;
|
|
||||||
category: string;
|
|
||||||
route: string;
|
|
||||||
TWR: boolean;
|
|
||||||
SKR: boolean;
|
|
||||||
routeDistance: number;
|
|
||||||
followingStops: TrainStop[];
|
|
||||||
followingSceneries: string[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import TrainStop from './TrainStop';
|
import { TrainStop } from '../../store/typings';
|
||||||
|
|
||||||
export default interface Train {
|
export default interface Train {
|
||||||
trainId: string;
|
trainId: string;
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
export default interface TrainStop {
|
|
||||||
stopName: string;
|
|
||||||
stopNameRAW: string;
|
|
||||||
stopType: string;
|
|
||||||
stopDistance: number;
|
|
||||||
mainStop: boolean;
|
|
||||||
|
|
||||||
arrivalLine: string | null;
|
|
||||||
// arrivalTimeString: string | null;
|
|
||||||
arrivalTimestamp: number;
|
|
||||||
// arrivalRealTimeString: string | null;
|
|
||||||
arrivalRealTimestamp: number;
|
|
||||||
arrivalDelay: number;
|
|
||||||
|
|
||||||
departureLine: string | null;
|
|
||||||
// departureTimeString: string | null;
|
|
||||||
departureTimestamp: number;
|
|
||||||
// departureRealTimeString: string | null;
|
|
||||||
departureRealTimestamp: number;
|
|
||||||
departureDelay: number;
|
|
||||||
pointId: number;
|
|
||||||
|
|
||||||
comments?: any;
|
|
||||||
|
|
||||||
beginsHere: boolean;
|
|
||||||
terminatesHere: boolean;
|
|
||||||
confirmed: boolean;
|
|
||||||
stopped: boolean;
|
|
||||||
stopTime: number | null;
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import { TrainFilterSection, TrainFilterType } from '../../enums/TrainFilterType';
|
|
||||||
|
|
||||||
export interface TrainFilter {
|
|
||||||
id: TrainFilterType;
|
|
||||||
section: TrainFilterSection;
|
|
||||||
isActive: boolean;
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
export interface Sum {
|
|
||||||
routeDistance: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Max {
|
|
||||||
routeDistance: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Min {
|
|
||||||
routeDistance: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Avg {
|
|
||||||
routeDistance: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Count {
|
|
||||||
_all: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DispatcherStatsAPIData {
|
|
||||||
_sum: Sum;
|
|
||||||
_max: Max;
|
|
||||||
_min: Min;
|
|
||||||
_avg: Avg;
|
|
||||||
_count: Count;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
export interface DispatcherHistory {
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
currentDuration: number;
|
|
||||||
dispatcherId: number;
|
|
||||||
dispatcherName: string;
|
|
||||||
dispatcherLevel: number | null;
|
|
||||||
dispatcherRate: number;
|
|
||||||
dispatcherIsSupporter: boolean;
|
|
||||||
dispatcherStatus?: number;
|
|
||||||
isOnline: boolean;
|
|
||||||
lastOnlineTimestamp: number;
|
|
||||||
region: string;
|
|
||||||
stationHash: string;
|
|
||||||
stationName: string;
|
|
||||||
timestampFrom: number;
|
|
||||||
timestampTo?: number;
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
export interface Sum {
|
|
||||||
routeDistance: number;
|
|
||||||
confirmedStopsCount: number;
|
|
||||||
allStopsCount: number;
|
|
||||||
currentDistance: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Count {
|
|
||||||
fulfilled: number;
|
|
||||||
terminated: number;
|
|
||||||
_all: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Max {
|
|
||||||
routeDistance: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Avg {
|
|
||||||
routeDistance: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DriverStatsAPIData {
|
|
||||||
_sum: Sum;
|
|
||||||
_count: Count;
|
|
||||||
_max: Max;
|
|
||||||
_avg: Avg;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
export default interface StationAPIData {
|
|
||||||
dispatcherId: number;
|
|
||||||
dispatcherName: string;
|
|
||||||
dispatcherIsSupporter: boolean;
|
|
||||||
stationName: string;
|
|
||||||
stationHash: string;
|
|
||||||
region: string;
|
|
||||||
maxUsers: number;
|
|
||||||
currentUsers: number;
|
|
||||||
spawn: number;
|
|
||||||
lastSeen: number;
|
|
||||||
dispatcherExp: number;
|
|
||||||
nameFromHeader: string;
|
|
||||||
spawnString: string | null;
|
|
||||||
networkConnectionString: string;
|
|
||||||
isOnline: number;
|
|
||||||
dispatcherRate: number;
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import { TimetableHistory } from './TimetablesAPIData';
|
|
||||||
|
|
||||||
export interface ITimetablesDailyStats {
|
|
||||||
totalTimetables: number;
|
|
||||||
distanceSum: number;
|
|
||||||
distanceAvg: number;
|
|
||||||
|
|
||||||
timetableId: number;
|
|
||||||
timetableAuthor: string;
|
|
||||||
timetableDriver: string;
|
|
||||||
timetableRouteDistance: number;
|
|
||||||
|
|
||||||
mostActiveDispatchers: {
|
|
||||||
name: string;
|
|
||||||
count: number;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
mostActiveDrivers: {
|
|
||||||
name: string;
|
|
||||||
distance: number;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
longestDuties: {
|
|
||||||
name: string;
|
|
||||||
duration: number;
|
|
||||||
station: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITimetablesDailyStatsResponse {
|
|
||||||
totalTimetables: number;
|
|
||||||
distanceSum: number;
|
|
||||||
distanceAvg: number;
|
|
||||||
maxTimetable: TimetableHistory | null;
|
|
||||||
|
|
||||||
mostActiveDispatchers: {
|
|
||||||
name: string;
|
|
||||||
count: number;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
mostActiveDrivers: {
|
|
||||||
name: string;
|
|
||||||
distance: number;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
longestDuties: {
|
|
||||||
name: string;
|
|
||||||
duration: number;
|
|
||||||
station: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
export interface TimetableHistory {
|
|
||||||
id: number;
|
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
|
|
||||||
timetableId: number;
|
|
||||||
trainNo: number;
|
|
||||||
trainCategoryCode: string;
|
|
||||||
|
|
||||||
driverId: number;
|
|
||||||
driverName: string;
|
|
||||||
driverLevel: number | null;
|
|
||||||
driverIsSupporter: boolean;
|
|
||||||
|
|
||||||
route: string;
|
|
||||||
twr: number;
|
|
||||||
skr: number;
|
|
||||||
sceneriesString: string;
|
|
||||||
currentLocation: string[];
|
|
||||||
|
|
||||||
routeDistance: number;
|
|
||||||
currentDistance: number;
|
|
||||||
|
|
||||||
confirmedStopsCount: number;
|
|
||||||
allStopsCount: number;
|
|
||||||
|
|
||||||
beginDate: string;
|
|
||||||
endDate: string;
|
|
||||||
|
|
||||||
scheduledBeginDate: string;
|
|
||||||
scheduledEndDate: string;
|
|
||||||
|
|
||||||
terminated: boolean;
|
|
||||||
fulfilled: boolean;
|
|
||||||
|
|
||||||
authorName?: string;
|
|
||||||
authorId?: number;
|
|
||||||
|
|
||||||
stopsString?: string;
|
|
||||||
|
|
||||||
stockString?: string;
|
|
||||||
stockHistory: string[];
|
|
||||||
|
|
||||||
stockMass?: number;
|
|
||||||
stockLength?: number;
|
|
||||||
maxSpeed?: number;
|
|
||||||
|
|
||||||
hashesString?: string;
|
|
||||||
currentSceneryName?: string;
|
|
||||||
currentSceneryHash?: string;
|
|
||||||
|
|
||||||
routeSceneries?: string;
|
|
||||||
|
|
||||||
checkpointArrivals?: string[];
|
|
||||||
checkpointDepartures?: string[];
|
|
||||||
|
|
||||||
checkpointArrivalsScheduled?: string[];
|
|
||||||
checkpointDeparturesScheduled?: string[];
|
|
||||||
|
|
||||||
checkpointStopTypes?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SceneryTimetableHistory {
|
|
||||||
timetables: TimetableHistory[];
|
|
||||||
// totalCount: number;
|
|
||||||
// sceneryName: string;
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
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,68 +0,0 @@
|
|||||||
export interface TimetableStop {
|
|
||||||
stopName: string;
|
|
||||||
stopNameRAW: string;
|
|
||||||
stopType: string;
|
|
||||||
stopDistance: number;
|
|
||||||
pointId: number;
|
|
||||||
|
|
||||||
mainStop: boolean;
|
|
||||||
|
|
||||||
arrivalLine: string;
|
|
||||||
arrivalTimestamp: number;
|
|
||||||
arrivalRealTimestamp: number;
|
|
||||||
arrivalDelay: number;
|
|
||||||
|
|
||||||
departureLine: string;
|
|
||||||
departureTimestamp: number;
|
|
||||||
departureRealTimestamp: number;
|
|
||||||
departureDelay: number;
|
|
||||||
|
|
||||||
comments?: any;
|
|
||||||
|
|
||||||
beginsHere: boolean;
|
|
||||||
terminatesHere: boolean;
|
|
||||||
confirmed: boolean;
|
|
||||||
stopped: boolean;
|
|
||||||
stopTime: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TrainTimetable {
|
|
||||||
timetableId: number;
|
|
||||||
category: string;
|
|
||||||
route: string;
|
|
||||||
|
|
||||||
stopList: TimetableStop[];
|
|
||||||
|
|
||||||
TWR: boolean;
|
|
||||||
SKR: boolean;
|
|
||||||
sceneries: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TrainAPIData {
|
|
||||||
trainNo: number;
|
|
||||||
|
|
||||||
mass: number;
|
|
||||||
length: number;
|
|
||||||
speed: number;
|
|
||||||
stockString: string;
|
|
||||||
|
|
||||||
signal: string;
|
|
||||||
distance: number;
|
|
||||||
connectedTrack: string;
|
|
||||||
|
|
||||||
driverName: string;
|
|
||||||
driverId: number;
|
|
||||||
driverIsSupporter: boolean;
|
|
||||||
driverLevel?: number;
|
|
||||||
|
|
||||||
currentStationName: string;
|
|
||||||
currentStationHash: string;
|
|
||||||
|
|
||||||
online: boolean;
|
|
||||||
lastSeen: number;
|
|
||||||
|
|
||||||
region: string;
|
|
||||||
isTimeout: boolean;
|
|
||||||
|
|
||||||
timetable?: TrainTimetable;
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
export interface Author {
|
|
||||||
login: string;
|
|
||||||
id: number;
|
|
||||||
node_id: string;
|
|
||||||
avatar_url: string;
|
|
||||||
gravatar_id: string;
|
|
||||||
url: string;
|
|
||||||
html_url: string;
|
|
||||||
followers_url: string;
|
|
||||||
following_url: string;
|
|
||||||
gists_url: string;
|
|
||||||
starred_url: string;
|
|
||||||
subscriptions_url: string;
|
|
||||||
organizations_url: string;
|
|
||||||
repos_url: string;
|
|
||||||
events_url: string;
|
|
||||||
received_events_url: string;
|
|
||||||
type: string;
|
|
||||||
site_admin: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReleaseAPIData {
|
|
||||||
url: string;
|
|
||||||
assets_url: string;
|
|
||||||
upload_url: string;
|
|
||||||
html_url: string;
|
|
||||||
id: number;
|
|
||||||
author: Author;
|
|
||||||
node_id: string;
|
|
||||||
tag_name: string;
|
|
||||||
target_commitish: string;
|
|
||||||
name: string;
|
|
||||||
draft: boolean;
|
|
||||||
prerelease: boolean;
|
|
||||||
created_at: Date;
|
|
||||||
published_at: Date;
|
|
||||||
assets: any[];
|
|
||||||
tarball_url: string;
|
|
||||||
zipball_url: string;
|
|
||||||
body: string;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
export interface RollingStockGithubData {
|
|
||||||
usage: Record<string, string>;
|
|
||||||
info: RollingStockInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RollingStockInfo {
|
|
||||||
'loco-e': [string, string, string, string, boolean][];
|
|
||||||
'loco-s': [string, string, string, string, boolean][];
|
|
||||||
'loco-szt': [string, string, string, string, boolean][];
|
|
||||||
'loco-ezt': [string, string, string, string, boolean][];
|
|
||||||
'car-passenger': [string, string, boolean, boolean, string][];
|
|
||||||
'car-cargo': [string, string, boolean, boolean, string][];
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
import { Socket } from 'socket.io-client';
|
|
||||||
import { DataStatus } from '../../enums/DataStatus';
|
|
||||||
import StationAPIData from '../api/StationAPIData';
|
|
||||||
import { TrainAPIData } from '../api/TrainAPIData';
|
|
||||||
import { DispatcherStatsAPIData } from '../api/DispatcherStatsAPIData';
|
|
||||||
import { DriverStatsAPIData } from '../api/DriverStatsAPIData';
|
|
||||||
import { RollingStockGithubData } from '../github_api/StockInfoGithubData';
|
|
||||||
import Station from '../Station';
|
|
||||||
import { ScheduledTrain } from '../ScheduledTrain';
|
|
||||||
import { DispatcherStatusID } from '../../enums/DispatcherStatus';
|
|
||||||
|
|
||||||
export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault';
|
|
||||||
|
|
||||||
export interface StoreState {
|
|
||||||
stationList: Station[];
|
|
||||||
apiData: APIData;
|
|
||||||
rollingStockData?: RollingStockGithubData;
|
|
||||||
|
|
||||||
lastDispatcherStatuses: { hash: string; statusTimestamp: number; statusID: DispatcherStatusID }[];
|
|
||||||
|
|
||||||
sceneryData: any[][];
|
|
||||||
|
|
||||||
region: { id: string; value: string };
|
|
||||||
trainCount: number;
|
|
||||||
stationCount: number;
|
|
||||||
|
|
||||||
webSocket?: Socket;
|
|
||||||
isOffline: boolean;
|
|
||||||
|
|
||||||
dispatcherStatsName: string;
|
|
||||||
dispatcherStatsData?: DispatcherStatsAPIData;
|
|
||||||
|
|
||||||
driverStatsName: string;
|
|
||||||
driverStatsData?: DriverStatsAPIData;
|
|
||||||
driverStatsStatus: DataStatus;
|
|
||||||
|
|
||||||
chosenModalTrainId?: string;
|
|
||||||
|
|
||||||
currentStatsTab: 'daily' | 'driver' | null;
|
|
||||||
|
|
||||||
dataStatuses: {
|
|
||||||
connection: DataStatus;
|
|
||||||
sceneries: DataStatus;
|
|
||||||
timetables: DataStatus;
|
|
||||||
dispatchers: DataStatus;
|
|
||||||
trains: DataStatus;
|
|
||||||
};
|
|
||||||
|
|
||||||
listenerLaunched: boolean;
|
|
||||||
blockScroll: boolean;
|
|
||||||
modalLastClickedTarget: EventTarget | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface APIData {
|
|
||||||
stations?: StationAPIData[];
|
|
||||||
dispatchers?: string[][];
|
|
||||||
trains?: TrainAPIData[];
|
|
||||||
connectedSocketCount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StationRoutesInfo {
|
|
||||||
routeName: string;
|
|
||||||
isElectric: boolean;
|
|
||||||
isInternal: boolean;
|
|
||||||
isRouteSBL: boolean;
|
|
||||||
routeLength: number;
|
|
||||||
routeSpeed: number;
|
|
||||||
routeTracks: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StationJSONData {
|
|
||||||
name: string;
|
|
||||||
abbr: string;
|
|
||||||
url: string;
|
|
||||||
lines: string;
|
|
||||||
project: string;
|
|
||||||
projectUrl: string;
|
|
||||||
|
|
||||||
reqLevel: number;
|
|
||||||
|
|
||||||
signalType: string;
|
|
||||||
controlType: string;
|
|
||||||
|
|
||||||
SUP: boolean;
|
|
||||||
|
|
||||||
// routes: string;
|
|
||||||
routesInfo: StationRoutesInfo[];
|
|
||||||
|
|
||||||
checkpoints: string | null;
|
|
||||||
authors?: string;
|
|
||||||
|
|
||||||
availability: Availability;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StationTrain {
|
|
||||||
driverName: string;
|
|
||||||
driverId: number;
|
|
||||||
trainNo: number;
|
|
||||||
trainId: string;
|
|
||||||
stopStatus: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OnlineScenery {
|
|
||||||
name: string;
|
|
||||||
hash: string;
|
|
||||||
region: string;
|
|
||||||
maxUsers: number;
|
|
||||||
currentUsers: number;
|
|
||||||
spawns: { spawnName: string; spawnLength: number; isElectrified: boolean }[];
|
|
||||||
dispatcherName: string;
|
|
||||||
dispatcherRate: number;
|
|
||||||
dispatcherId: number;
|
|
||||||
dispatcherExp: number;
|
|
||||||
dispatcherIsSupporter: boolean;
|
|
||||||
|
|
||||||
statusTimestamp: number;
|
|
||||||
statusID: DispatcherStatusID;
|
|
||||||
|
|
||||||
isOnline: boolean;
|
|
||||||
|
|
||||||
stationTrains?: StationTrain[];
|
|
||||||
scheduledTrains?: ScheduledTrain[];
|
|
||||||
|
|
||||||
scheduledTrainCount: {
|
|
||||||
all: number;
|
|
||||||
confirmed: number;
|
|
||||||
unconfirmed: number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
export type JournalDispatcherSearcher = {
|
|
||||||
[key in 'search-dispatcher' | 'search-station' | 'search-date']: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface JournalDispatcherSorter {
|
|
||||||
id: 'timestampFrom' | 'duration';
|
|
||||||
dir: -1 | 1;
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
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';
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,6 @@ 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:3001'
|
? 'http://localhost:3001'
|
||||||
: 'https://stacjownik.spythere.pl',
|
: 'https://stacjownik.spythere.eu',
|
||||||
stacjownikAPIDev: 'localhost:3000'
|
stacjownikAPIDev: 'localhost:3000'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
|
import { Filter } from '../../components/StationsView/typings';
|
||||||
|
import { Status } from '../../typings/common';
|
||||||
import { HeadIdsTypes } from '../data/stationHeaderNames';
|
import { HeadIdsTypes } from '../data/stationHeaderNames';
|
||||||
import { DispatcherStatusID } from '../enums/DispatcherStatus';
|
|
||||||
import Filter from '../interfaces/Filter';
|
|
||||||
import Station from '../interfaces/Station';
|
import Station from '../interfaces/Station';
|
||||||
|
|
||||||
|
const dispatcherStatusPriority = [
|
||||||
|
Status.ActiveDispatcher.UNKNOWN,
|
||||||
|
Status.ActiveDispatcher.INVALID,
|
||||||
|
Status.ActiveDispatcher.NOT_LOGGED_IN,
|
||||||
|
Status.ActiveDispatcher.UNAVAILABLE,
|
||||||
|
Status.ActiveDispatcher.AFK,
|
||||||
|
Status.ActiveDispatcher.ENDING,
|
||||||
|
Status.ActiveDispatcher.NO_SPACE,
|
||||||
|
undefined
|
||||||
|
];
|
||||||
|
|
||||||
export const sortStations = (
|
export const sortStations = (
|
||||||
a: Station,
|
a: Station,
|
||||||
b: Station,
|
b: Station,
|
||||||
@@ -19,7 +30,11 @@ export const sortStations = (
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'status':
|
case 'status':
|
||||||
diff = (a.onlineInfo?.statusTimestamp || 0) - (b.onlineInfo?.statusTimestamp || 0);
|
diff =
|
||||||
|
(a.onlineInfo?.dispatcherTimestamp ??
|
||||||
|
dispatcherStatusPriority.indexOf(a.onlineInfo?.dispatcherStatus)) -
|
||||||
|
(b.onlineInfo?.dispatcherTimestamp ??
|
||||||
|
dispatcherStatusPriority.indexOf(b.onlineInfo?.dispatcherStatus));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'dispatcher':
|
case 'dispatcher':
|
||||||
@@ -81,27 +96,28 @@ export const filterStations = (station: Station, filters: Filter) => {
|
|||||||
if (!station.onlineInfo && filters['free']) return false;
|
if (!station.onlineInfo && filters['free']) return false;
|
||||||
|
|
||||||
if (station.onlineInfo) {
|
if (station.onlineInfo) {
|
||||||
const { statusID, statusTimestamp } = station.onlineInfo;
|
const { dispatcherStatus } = station.onlineInfo;
|
||||||
|
|
||||||
const isEnding = statusID == DispatcherStatusID.Ending && filters['endingStatus'];
|
const isEnding = dispatcherStatus == Status.ActiveDispatcher.ENDING && filters['endingStatus'];
|
||||||
|
|
||||||
const isNotSigned =
|
const isNotSigned =
|
||||||
(statusID == 'not-signed' || statusID == 'unavailable') && filters['unavailableStatus'];
|
(dispatcherStatus == Status.ActiveDispatcher.NOT_LOGGED_IN ||
|
||||||
|
dispatcherStatus == Status.ActiveDispatcher.UNAVAILABLE) &&
|
||||||
|
filters['unavailableStatus'];
|
||||||
|
|
||||||
const isAFK = statusID == 'brb' && filters['afkStatus'];
|
const isAFK = dispatcherStatus == Status.ActiveDispatcher.AFK && filters['afkStatus'];
|
||||||
|
|
||||||
const isNoSpace = statusID == 'no-space' && filters['noSpaceStatus'];
|
const isNoSpace =
|
||||||
|
dispatcherStatus == Status.ActiveDispatcher.NO_SPACE && filters['noSpaceStatus'];
|
||||||
|
|
||||||
const isOccupied = station.onlineInfo && filters['occupied'];
|
const isOccupied = station.onlineInfo && filters['occupied'];
|
||||||
|
|
||||||
const isOnlineInBounds =
|
if (isEnding || isNotSigned || isAFK || isNoSpace || isOccupied) return false;
|
||||||
(filters['onlineFromHours'] < 8 &&
|
|
||||||
statusTimestamp > 0 &&
|
|
||||||
statusTimestamp <= Date.now() + filters['onlineFromHours'] * 3600000) ||
|
|
||||||
(filters['onlineFromHours'] > 0 && statusTimestamp <= 0) ||
|
|
||||||
(filters['onlineFromHours'] == 8 && statusID != 'no-limit');
|
|
||||||
|
|
||||||
if (isEnding || isOnlineInBounds || isNotSigned || isAFK || isNoSpace || isOccupied)
|
if (
|
||||||
|
filters['onlineFromHours'] > 0 &&
|
||||||
|
dispatcherStatus <= Date.now() + filters['onlineFromHours'] * 3600000
|
||||||
|
)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +1,26 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { io } from 'socket.io-client';
|
import { io } from 'socket.io-client';
|
||||||
import { DataStatus } from '../scripts/enums/DataStatus';
|
|
||||||
import StationRoutes from '../scripts/interfaces/StationRoutes';
|
import StationRoutes from '../scripts/interfaces/StationRoutes';
|
||||||
import Train from '../scripts/interfaces/Train';
|
import Train from '../scripts/interfaces/Train';
|
||||||
import { URLs } from '../scripts/utils/apiURLs';
|
import { URLs } from '../scripts/utils/apiURLs';
|
||||||
import {
|
import { parseSpawns, getScheduledTrains, getStationTrains } from './utils';
|
||||||
getDispatcherStatus,
|
|
||||||
parseSpawns,
|
|
||||||
getScheduledTrains,
|
|
||||||
getStationTrains
|
|
||||||
} from '../scripts/utils/storeUtils';
|
|
||||||
|
|
||||||
import {
|
import { OnlineScenery, ScheduledTrain, StationJSONData, StoreState } from './typings';
|
||||||
APIData,
|
|
||||||
OnlineScenery,
|
|
||||||
StationJSONData,
|
|
||||||
StoreState
|
|
||||||
} from '../scripts/interfaces/store/storeTypes';
|
|
||||||
|
|
||||||
import packageInfo from '../../package.json';
|
import packageInfo from '../../package.json';
|
||||||
import { RollingStockGithubData } from '../scripts/interfaces/github_api/StockInfoGithubData';
|
import { Websocket, API, GithubAPI } from '../typings/api';
|
||||||
import { ScheduledTrain } from '../scripts/interfaces/ScheduledTrain';
|
import { Status } from '../typings/common';
|
||||||
import { DispatcherStatusID } from '../scripts/enums/DispatcherStatus';
|
|
||||||
|
|
||||||
export const useStore = defineStore('store', {
|
export const useStore = defineStore('store', {
|
||||||
state: () =>
|
state: () =>
|
||||||
({
|
({
|
||||||
apiData: {} as unknown,
|
activeData: {} as unknown,
|
||||||
rollingStockData: undefined,
|
rollingStockData: undefined,
|
||||||
|
donatorsData: [],
|
||||||
|
|
||||||
stationList: [],
|
stationList: [],
|
||||||
|
regionOnlineCounters: [],
|
||||||
|
|
||||||
routesList: [],
|
routesList: [],
|
||||||
|
|
||||||
@@ -50,33 +40,36 @@ export const useStore = defineStore('store', {
|
|||||||
|
|
||||||
driverStatsName: '',
|
driverStatsName: '',
|
||||||
driverStatsData: undefined,
|
driverStatsData: undefined,
|
||||||
driverStatsStatus: DataStatus.Initialized,
|
driverStatsStatus: Status.Data.Initialized,
|
||||||
|
|
||||||
chosenModalTrainId: undefined,
|
chosenModalTrainId: undefined,
|
||||||
|
|
||||||
dataStatuses: {
|
dataStatuses: {
|
||||||
connection: DataStatus.Loading,
|
connection: Status.Data.Loading,
|
||||||
sceneries: DataStatus.Loading,
|
sceneries: Status.Data.Loading,
|
||||||
timetables: DataStatus.Loading,
|
timetables: Status.Data.Loading,
|
||||||
dispatchers: DataStatus.Loading,
|
dispatchers: Status.Data.Loading,
|
||||||
trains: DataStatus.Loading
|
trains: Status.Data.Loading
|
||||||
},
|
},
|
||||||
|
|
||||||
currentStatsTab: null,
|
currentStatsTab: null,
|
||||||
|
|
||||||
blockScroll: false,
|
blockScroll: false,
|
||||||
listenerLaunched: false,
|
listenerLaunched: false,
|
||||||
modalLastClickedTarget: null
|
modalLastClickedTarget: null,
|
||||||
|
|
||||||
|
tooltip: {
|
||||||
|
content: '',
|
||||||
|
visible: false,
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
}
|
||||||
}) as StoreState,
|
}) as StoreState,
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
trainList(): Train[] {
|
trainList(): Train[] {
|
||||||
return (this.apiData?.trains ?? [])
|
return (this.activeData?.trains ?? [])
|
||||||
.filter(
|
.filter((train) => train.timetable || train.online)
|
||||||
(train) =>
|
|
||||||
train.region === this.region.id &&
|
|
||||||
(train.online || train.timetable || train.lastSeen > Date.now() - 180000)
|
|
||||||
)
|
|
||||||
.map((train) => {
|
.map((train) => {
|
||||||
const stock = train.stockString.split(';');
|
const stock = train.stockString.split(';');
|
||||||
const locoType = stock ? stock[0] : train.stockString;
|
const locoType = stock ? stock[0] : train.stockString;
|
||||||
@@ -127,75 +120,67 @@ export const useStore = defineStore('store', {
|
|||||||
|
|
||||||
onlineSceneryList(state): OnlineScenery[] {
|
onlineSceneryList(state): OnlineScenery[] {
|
||||||
if (state.isOffline) return [];
|
if (state.isOffline) return [];
|
||||||
if (!state.apiData?.stations) return [];
|
if (!state.activeData?.activeSceneries) return [];
|
||||||
|
|
||||||
return (
|
return state.activeData?.activeSceneries.reduce((list, scenery) => {
|
||||||
state.apiData?.stations
|
if (scenery.isOnline !== 1 && Date.now() - scenery.lastSeen > 1000 * 60 * 2) return list;
|
||||||
// ?.filter((apiStation) => apiStation.region == state.region.id)
|
if (scenery.dispatcherStatus == Status.ActiveDispatcher.UNKNOWN) return list;
|
||||||
.reduce((list, apiStation) => {
|
|
||||||
if (apiStation.region != state.region.id) return list;
|
|
||||||
|
|
||||||
if (apiStation.isOnline !== 1 && Date.now() - apiStation.lastSeen > 1000 * 60 * 3)
|
const station = this.stationList.find((s) => s.name === scenery.stationName);
|
||||||
return list;
|
|
||||||
|
|
||||||
const dispatcherStatus = getDispatcherStatus(state as StoreState, apiStation);
|
const scheduledTrains = getScheduledTrains(this.trainList, scenery, station?.generalInfo);
|
||||||
|
|
||||||
if (dispatcherStatus.statusID == DispatcherStatusID.Unknown) return list;
|
const stationTrains = getStationTrains(
|
||||||
|
this.trainList,
|
||||||
|
scheduledTrains,
|
||||||
|
this.region.id,
|
||||||
|
scenery
|
||||||
|
);
|
||||||
|
|
||||||
const station = this.stationList.find((s) => s.name === apiStation.stationName);
|
// Remove checkpoint duplicates
|
||||||
|
const uniqueScheduledTrains = scheduledTrains.reduce(
|
||||||
|
(uniqueList, sTrain) =>
|
||||||
|
uniqueList.find((v) => v.trainId === sTrain.trainId)
|
||||||
|
? uniqueList
|
||||||
|
: [...uniqueList, sTrain],
|
||||||
|
[] as ScheduledTrain[]
|
||||||
|
);
|
||||||
|
|
||||||
const scheduledTrains = getScheduledTrains(
|
const dispatcherTimestamp =
|
||||||
this.trainList,
|
scenery.dispatcherStatus == Status.ActiveDispatcher.NO_LIMIT
|
||||||
apiStation,
|
? Date.now() + 25500000
|
||||||
station?.generalInfo
|
: scenery.dispatcherStatus > 5
|
||||||
);
|
? scenery.dispatcherStatus
|
||||||
|
: null;
|
||||||
|
|
||||||
const stationTrains = getStationTrains(
|
list.push({
|
||||||
this.trainList,
|
name: scenery.stationName,
|
||||||
scheduledTrains,
|
hash: scenery.stationHash,
|
||||||
this.region.id,
|
region: scenery.region,
|
||||||
apiStation
|
maxUsers: scenery.maxUsers,
|
||||||
);
|
currentUsers: scenery.currentUsers,
|
||||||
|
spawns: parseSpawns(scenery.spawnString),
|
||||||
|
dispatcherName: scenery.dispatcherName,
|
||||||
|
dispatcherRate: scenery.dispatcherRate,
|
||||||
|
dispatcherId: scenery.dispatcherId,
|
||||||
|
dispatcherExp: scenery.dispatcherExp,
|
||||||
|
dispatcherIsSupporter: scenery.dispatcherIsSupporter,
|
||||||
|
scheduledTrains: scheduledTrains,
|
||||||
|
stationTrains: stationTrains,
|
||||||
|
dispatcherStatus: scenery.dispatcherStatus,
|
||||||
|
dispatcherTimestamp: dispatcherTimestamp,
|
||||||
|
|
||||||
// Remove checkpoint duplicates
|
isOnline: scenery.isOnline == 1,
|
||||||
const uniqueScheduledTrains = scheduledTrains.reduce(
|
|
||||||
(uniqueList, sTrain) =>
|
|
||||||
uniqueList.find((v) => v.trainId === sTrain.trainId)
|
|
||||||
? uniqueList
|
|
||||||
: [...uniqueList, sTrain],
|
|
||||||
[] as ScheduledTrain[]
|
|
||||||
);
|
|
||||||
|
|
||||||
list.push({
|
scheduledTrainCount: {
|
||||||
name: apiStation.stationName,
|
all: uniqueScheduledTrains.length,
|
||||||
hash: apiStation.stationHash,
|
confirmed: uniqueScheduledTrains.filter((train) => train.stopInfo.confirmed).length,
|
||||||
region: apiStation.region,
|
unconfirmed: uniqueScheduledTrains.filter((train) => !train.stopInfo.confirmed).length
|
||||||
maxUsers: apiStation.maxUsers,
|
}
|
||||||
currentUsers: apiStation.currentUsers,
|
});
|
||||||
spawns: parseSpawns(apiStation.spawnString),
|
|
||||||
dispatcherName: apiStation.dispatcherName,
|
|
||||||
dispatcherRate: apiStation.dispatcherRate,
|
|
||||||
dispatcherId: apiStation.dispatcherId,
|
|
||||||
dispatcherExp: apiStation.dispatcherExp,
|
|
||||||
dispatcherIsSupporter: apiStation.dispatcherIsSupporter,
|
|
||||||
scheduledTrains: scheduledTrains,
|
|
||||||
stationTrains: stationTrains,
|
|
||||||
statusTimestamp: dispatcherStatus.statusTimestamp,
|
|
||||||
statusID: dispatcherStatus.statusID,
|
|
||||||
|
|
||||||
isOnline: apiStation.isOnline == 1,
|
return list;
|
||||||
|
}, [] as OnlineScenery[]);
|
||||||
scheduledTrainCount: {
|
|
||||||
all: uniqueScheduledTrains.length,
|
|
||||||
confirmed: uniqueScheduledTrains.filter((train) => train.stopInfo.confirmed).length,
|
|
||||||
unconfirmed: uniqueScheduledTrains.filter((train) => !train.stopInfo.confirmed)
|
|
||||||
.length
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}, [] as OnlineScenery[])
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@@ -205,7 +190,7 @@ export const useStore = defineStore('store', {
|
|||||||
).data;
|
).data;
|
||||||
|
|
||||||
if (!sceneryData) {
|
if (!sceneryData) {
|
||||||
this.dataStatuses.sceneries = DataStatus.Error;
|
this.dataStatuses.sceneries = Status.Data.Error;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,8 +248,8 @@ export const useStore = defineStore('store', {
|
|||||||
async connectToWebsocket() {
|
async connectToWebsocket() {
|
||||||
if (import.meta.env.VITE_APP_WS_DEV === '1') {
|
if (import.meta.env.VITE_APP_WS_DEV === '1') {
|
||||||
const mockWebsocketData = await import('../data/mockWebsocketData.json');
|
const mockWebsocketData = await import('../data/mockWebsocketData.json');
|
||||||
this.dataStatuses.connection = DataStatus.Loaded;
|
this.dataStatuses.connection = Status.Data.Loaded;
|
||||||
this.apiData = mockWebsocketData as any;
|
this.activeData = mockWebsocketData as any;
|
||||||
this.setStatuses();
|
this.setStatuses();
|
||||||
|
|
||||||
console.warn('Stacjownik działa w trybie mockowania danych z WS');
|
console.warn('Stacjownik działa w trybie mockowania danych z WS');
|
||||||
@@ -281,18 +266,19 @@ export const useStore = defineStore('store', {
|
|||||||
socket.emit('CONNECTION', { version: packageInfo.version });
|
socket.emit('CONNECTION', { version: packageInfo.version });
|
||||||
|
|
||||||
socket.on('connect_error', () => {
|
socket.on('connect_error', () => {
|
||||||
this.dataStatuses.connection = DataStatus.Error;
|
this.dataStatuses.connection = Status.Data.Error;
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('UPDATE', (data: APIData) => {
|
socket.on('UPDATE', (data: Websocket.ActiveData) => {
|
||||||
this.apiData = data;
|
this.activeData = data;
|
||||||
this.dataStatuses.connection = DataStatus.Loaded;
|
this.dataStatuses.connection = Status.Data.Loaded;
|
||||||
|
|
||||||
this.setStatuses();
|
this.setStatuses();
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.emit('FETCH_DATA', { version: packageInfo.version }, (data: APIData) => {
|
socket.emit('FETCH_DATA', { version: packageInfo.version }, (data: Websocket.ActiveData) => {
|
||||||
this.dataStatuses.connection = DataStatus.Loaded;
|
this.dataStatuses.connection = Status.Data.Loaded;
|
||||||
this.apiData = data;
|
this.activeData = data;
|
||||||
this.setStatuses();
|
this.setStatuses();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -302,6 +288,7 @@ export const useStore = defineStore('store', {
|
|||||||
async connectToAPI() {
|
async connectToAPI() {
|
||||||
this.connectToWebsocket();
|
this.connectToWebsocket();
|
||||||
this.fetchStockInfoData();
|
this.fetchStockInfoData();
|
||||||
|
this.fetchDonatorsData();
|
||||||
this.fetchStationsGeneralInfo();
|
this.fetchStationsGeneralInfo();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -312,7 +299,7 @@ export const useStore = defineStore('store', {
|
|||||||
async fetchStockInfoData() {
|
async fetchStockInfoData() {
|
||||||
try {
|
try {
|
||||||
this.rollingStockData = (
|
this.rollingStockData = (
|
||||||
await axios.get<RollingStockGithubData>(
|
await axios.get<API.RollingStock.Response>(
|
||||||
'https://raw.githubusercontent.com/Spythere/api/main/td2/data/stockInfo.json'
|
'https://raw.githubusercontent.com/Spythere/api/main/td2/data/stockInfo.json'
|
||||||
)
|
)
|
||||||
).data;
|
).data;
|
||||||
@@ -321,22 +308,30 @@ export const useStore = defineStore('store', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async fetchDonatorsData() {
|
||||||
|
try {
|
||||||
|
const response = await axios.get<GithubAPI.Donators.Response>(
|
||||||
|
'https://raw.githubusercontent.com/Spythere/api/main/td2/data/donators.json'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.data) this.donatorsData = response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ups! Wystąpił błąd podczas pobierania informacji o donatorach:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
async setStatuses() {
|
async setStatuses() {
|
||||||
if (!this.apiData.stations) {
|
if (!this.activeData.activeSceneries) {
|
||||||
this.dataStatuses.sceneries = DataStatus.Error;
|
this.dataStatuses.sceneries = Status.Data.Error;
|
||||||
this.dataStatuses.trains = DataStatus.Error;
|
this.dataStatuses.trains = Status.Data.Error;
|
||||||
this.dataStatuses.dispatchers = DataStatus.Error;
|
this.dataStatuses.dispatchers = Status.Data.Error;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dataStatuses.sceneries = DataStatus.Loaded;
|
this.dataStatuses.sceneries = Status.Data.Loaded;
|
||||||
this.dataStatuses.trains = !this.apiData.trains ? DataStatus.Warning : DataStatus.Loaded;
|
this.dataStatuses.trains = !this.activeData.trains ? Status.Data.Warning : Status.Data.Loaded;
|
||||||
this.dataStatuses.dispatchers = !this.apiData.dispatchers
|
this.dataStatuses.dispatchers = Status.Data.Loaded;
|
||||||
? DataStatus.Warning
|
|
||||||
: DataStatus.Loaded;
|
|
||||||
|
|
||||||
// if (this.apiData.dispatchers != null) this.lastDispatcherStatuses = prevDispatcherStatuses;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1,10 +1,58 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import inputData from '../data/options.json';
|
import inputData from '../data/options.json';
|
||||||
import StorageManager from '../scripts/managers/storageManager';
|
import { useStore } from './mainStore';
|
||||||
import { useStore } from './store';
|
|
||||||
import { filterInitStates } from '../scripts/constants/stores/initFilterStates';
|
|
||||||
import { filterStations, sortStations } from '../scripts/utils/filterUtils';
|
import { filterStations, sortStations } from '../scripts/utils/filterUtils';
|
||||||
import { HeadIdsTypes } from '../scripts/data/stationHeaderNames';
|
import { HeadIdsTypes } from '../scripts/data/stationHeaderNames';
|
||||||
|
import StorageManager from '../managers/storageManager';
|
||||||
|
import { Filter } from '../components/StationsView/typings';
|
||||||
|
|
||||||
|
const filterInitStates: Filter = {
|
||||||
|
default: false,
|
||||||
|
notDefault: false,
|
||||||
|
real: false,
|
||||||
|
fictional: false,
|
||||||
|
SPK: false,
|
||||||
|
SCS: false,
|
||||||
|
SPE: false,
|
||||||
|
SUP: false,
|
||||||
|
noSUP: false,
|
||||||
|
ręczne: false,
|
||||||
|
'ręczne+SPK': false,
|
||||||
|
'ręczne+SCS': false,
|
||||||
|
mechaniczne: false,
|
||||||
|
'mechaniczne+SPK': false,
|
||||||
|
'mechaniczne+SCS': false,
|
||||||
|
współczesna: false,
|
||||||
|
kształtowa: false,
|
||||||
|
historyczna: false,
|
||||||
|
mieszana: false,
|
||||||
|
SBL: false,
|
||||||
|
PBL: false,
|
||||||
|
minLevel: 0,
|
||||||
|
maxLevel: 20,
|
||||||
|
minOneWayCatenary: 0,
|
||||||
|
minOneWay: 0,
|
||||||
|
minTwoWayCatenary: 0,
|
||||||
|
minTwoWay: 0,
|
||||||
|
'include-selected': false,
|
||||||
|
'no-1track': false,
|
||||||
|
'no-2track': false,
|
||||||
|
free: true,
|
||||||
|
occupied: false,
|
||||||
|
ending: false,
|
||||||
|
nonPublic: false,
|
||||||
|
unavailable: true,
|
||||||
|
abandoned: true,
|
||||||
|
afkStatus: false,
|
||||||
|
endingStatus: false,
|
||||||
|
noSpaceStatus: false,
|
||||||
|
unavailableStatus: false,
|
||||||
|
unsignedStatus: false,
|
||||||
|
|
||||||
|
authors: '',
|
||||||
|
|
||||||
|
onlineFromHours: 0
|
||||||
|
};
|
||||||
|
|
||||||
export const useStationFiltersStore = defineStore('stationFiltersStore', {
|
export const useStationFiltersStore = defineStore('stationFiltersStore', {
|
||||||
state() {
|
state() {
|
||||||
@@ -26,7 +74,9 @@ export const useStationFiltersStore = defineStore('stationFiltersStore', {
|
|||||||
return store.stationList
|
return store.stationList
|
||||||
.map((station) => ({
|
.map((station) => ({
|
||||||
...station,
|
...station,
|
||||||
onlineInfo: store.onlineSceneryList.find((os) => os.name == station.name)
|
onlineInfo: store.onlineSceneryList.find(
|
||||||
|
(os) => os.name == station.name && os.region == store.region.id
|
||||||
|
)
|
||||||
}))
|
}))
|
||||||
.filter((station) => filterStations(station, state.filters))
|
.filter((station) => filterStations(station, state.filters))
|
||||||
.sort((a, b) => sortStations(a, b, state.sorterActive));
|
.sort((a, b) => sortStations(a, b, state.sorterActive));
|
||||||
|
|||||||
@@ -0,0 +1,205 @@
|
|||||||
|
import { Socket } from 'socket.io-client';
|
||||||
|
import Station from '../scripts/interfaces/Station';
|
||||||
|
import { API, GithubAPI, Websocket } from '../typings/api';
|
||||||
|
import { Status } from '../typings/common';
|
||||||
|
|
||||||
|
export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault';
|
||||||
|
|
||||||
|
export interface RegionCounters {
|
||||||
|
stationCount: number;
|
||||||
|
trainsCount: number;
|
||||||
|
timetablesCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StoreState {
|
||||||
|
stationList: Station[];
|
||||||
|
activeData: Websocket.ActiveData;
|
||||||
|
rollingStockData?: API.RollingStock.Response;
|
||||||
|
donatorsData: GithubAPI.Donators.Response;
|
||||||
|
|
||||||
|
regionOnlineCounters: RegionCounters[];
|
||||||
|
|
||||||
|
lastDispatcherStatuses: {
|
||||||
|
hash: string;
|
||||||
|
statusTimestamp: number;
|
||||||
|
statusID: Status.ActiveDispatcher;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
sceneryData: any[][];
|
||||||
|
|
||||||
|
region: { id: string; value: string };
|
||||||
|
trainCount: number;
|
||||||
|
stationCount: number;
|
||||||
|
|
||||||
|
webSocket?: Socket;
|
||||||
|
isOffline: boolean;
|
||||||
|
|
||||||
|
dispatcherStatsName: string;
|
||||||
|
dispatcherStatsData?: API.DispatcherStats.Response;
|
||||||
|
|
||||||
|
driverStatsName: string;
|
||||||
|
driverStatsData?: API.DriverStats.Response;
|
||||||
|
driverStatsStatus: Status.Data;
|
||||||
|
|
||||||
|
chosenModalTrainId?: string;
|
||||||
|
|
||||||
|
currentStatsTab: 'daily' | 'driver' | null;
|
||||||
|
|
||||||
|
dataStatuses: {
|
||||||
|
connection: Status.Data;
|
||||||
|
sceneries: Status.Data;
|
||||||
|
timetables: Status.Data;
|
||||||
|
dispatchers: Status.Data;
|
||||||
|
trains: Status.Data;
|
||||||
|
};
|
||||||
|
|
||||||
|
listenerLaunched: boolean;
|
||||||
|
blockScroll: boolean;
|
||||||
|
modalLastClickedTarget: EventTarget | null;
|
||||||
|
|
||||||
|
tooltip: {
|
||||||
|
visible: boolean;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StationRoutesInfo {
|
||||||
|
routeName: string;
|
||||||
|
isElectric: boolean;
|
||||||
|
isInternal: boolean;
|
||||||
|
isRouteSBL: boolean;
|
||||||
|
routeLength: number;
|
||||||
|
routeSpeed: number;
|
||||||
|
routeTracks: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StationJSONData {
|
||||||
|
name: string;
|
||||||
|
abbr: string;
|
||||||
|
url: string;
|
||||||
|
lines: string;
|
||||||
|
project: string;
|
||||||
|
projectUrl: string;
|
||||||
|
|
||||||
|
reqLevel: number;
|
||||||
|
|
||||||
|
signalType: string;
|
||||||
|
controlType: string;
|
||||||
|
|
||||||
|
SUP: boolean;
|
||||||
|
|
||||||
|
// routes: string;
|
||||||
|
routesInfo: StationRoutesInfo[];
|
||||||
|
|
||||||
|
checkpoints: string | null;
|
||||||
|
authors?: string;
|
||||||
|
|
||||||
|
availability: Availability;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OnlineScenery {
|
||||||
|
name: string;
|
||||||
|
hash: string;
|
||||||
|
region: string;
|
||||||
|
maxUsers: number;
|
||||||
|
currentUsers: number;
|
||||||
|
spawns: { spawnName: string; spawnLength: number; isElectrified: boolean }[];
|
||||||
|
dispatcherName: string;
|
||||||
|
dispatcherRate: number;
|
||||||
|
dispatcherId: number;
|
||||||
|
dispatcherExp: number;
|
||||||
|
dispatcherIsSupporter: boolean;
|
||||||
|
|
||||||
|
dispatcherStatus: Status.ActiveDispatcher | number;
|
||||||
|
dispatcherTimestamp: number | null;
|
||||||
|
|
||||||
|
isOnline: boolean;
|
||||||
|
|
||||||
|
stationTrains?: StationTrain[];
|
||||||
|
scheduledTrains?: ScheduledTrain[];
|
||||||
|
|
||||||
|
scheduledTrainCount: {
|
||||||
|
all: number;
|
||||||
|
confirmed: number;
|
||||||
|
unconfirmed: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StationTrain {
|
||||||
|
driverName: string;
|
||||||
|
driverId: number;
|
||||||
|
trainNo: number;
|
||||||
|
trainId: string;
|
||||||
|
stopStatus: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScheduledTrain {
|
||||||
|
checkpointName: string;
|
||||||
|
|
||||||
|
trainId: string;
|
||||||
|
trainNo: number;
|
||||||
|
|
||||||
|
driverName: string;
|
||||||
|
driverId: number;
|
||||||
|
currentStationName: string;
|
||||||
|
currentStationHash: string;
|
||||||
|
category: string;
|
||||||
|
stopInfo: TrainStop;
|
||||||
|
|
||||||
|
terminatesAt: string;
|
||||||
|
beginsAt: string;
|
||||||
|
|
||||||
|
prevStationName: string;
|
||||||
|
nextStationName: string;
|
||||||
|
|
||||||
|
arrivingLine: string | null;
|
||||||
|
departureLine: string | null;
|
||||||
|
|
||||||
|
prevDepartureLine: string | null;
|
||||||
|
nextArrivalLine: string | null;
|
||||||
|
|
||||||
|
signal: string;
|
||||||
|
connectedTrack: string;
|
||||||
|
|
||||||
|
stopLabel: string;
|
||||||
|
stopStatus: StopStatus;
|
||||||
|
stopStatusID: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum StopStatus {
|
||||||
|
ARRIVING = 'arriving',
|
||||||
|
DEPARTED = 'departed',
|
||||||
|
DEPARTED_AWAY = 'departed-away',
|
||||||
|
ONLINE = 'online',
|
||||||
|
STOPPED = 'stopped',
|
||||||
|
TERMINATED = 'terminated'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TrainStop {
|
||||||
|
stopName: string;
|
||||||
|
stopNameRAW: string;
|
||||||
|
stopType: string;
|
||||||
|
stopDistance: number;
|
||||||
|
mainStop: boolean;
|
||||||
|
|
||||||
|
arrivalLine: string | null;
|
||||||
|
arrivalTimestamp: number;
|
||||||
|
arrivalRealTimestamp: number;
|
||||||
|
arrivalDelay: number;
|
||||||
|
|
||||||
|
departureLine: string | null;
|
||||||
|
departureTimestamp: number;
|
||||||
|
departureRealTimestamp: number;
|
||||||
|
departureDelay: number;
|
||||||
|
pointId: number;
|
||||||
|
|
||||||
|
comments?: string;
|
||||||
|
|
||||||
|
beginsHere: boolean;
|
||||||
|
terminatesHere: boolean;
|
||||||
|
confirmed: boolean;
|
||||||
|
stopped: boolean;
|
||||||
|
stopTime: number | null;
|
||||||
|
}
|
||||||
@@ -1,52 +1,15 @@
|
|||||||
import { DispatcherStatusID } from '../enums/DispatcherStatus';
|
import Station from '../scripts/interfaces/Station';
|
||||||
import { ScheduledTrain, StopStatus } from '../interfaces/ScheduledTrain';
|
import Train from '../scripts/interfaces/Train';
|
||||||
import Station from '../interfaces/Station';
|
import { API } from '../typings/api';
|
||||||
import Train from '../interfaces/Train';
|
import { ScheduledTrain, StationTrain, StopStatus, TrainStop } from './typings';
|
||||||
import TrainStop from '../interfaces/TrainStop';
|
|
||||||
import StationAPIData from '../interfaces/api/StationAPIData';
|
|
||||||
import { StationTrain, StoreState } from '../interfaces/store/storeTypes';
|
|
||||||
|
|
||||||
export const getLocoURL = (locoType: string): string =>
|
export function getLocoURL(locoType: string): string {
|
||||||
`https://rj.td2.info.pl/dist/img/thumbnails/${
|
return `https://rj.td2.info.pl/dist/img/thumbnails/${
|
||||||
locoType.includes('EN') ? locoType + 'rb' : locoType
|
locoType.includes('EN') ? locoType + 'rb' : locoType
|
||||||
}.png`;
|
}.png`;
|
||||||
|
}
|
||||||
|
|
||||||
export const getStatusID = (
|
export function getStatusTimestamp(stationStatus: any): number {
|
||||||
stationStatus: any[] | undefined,
|
|
||||||
isSWDROnline: boolean
|
|
||||||
): DispatcherStatusID => {
|
|
||||||
if (isSWDROnline && !stationStatus) return DispatcherStatusID.Unauthorized;
|
|
||||||
if (!stationStatus) return DispatcherStatusID.Unknown;
|
|
||||||
|
|
||||||
// if (stationStatus == -1) return DispatcherStatusID.Unauthorized;
|
|
||||||
|
|
||||||
const statusCode = stationStatus[2];
|
|
||||||
const statusTimestamp = stationStatus[3];
|
|
||||||
|
|
||||||
switch (statusCode) {
|
|
||||||
case 0:
|
|
||||||
if (statusTimestamp - Date.now() > 21000000) return DispatcherStatusID.OnlineNoLimit;
|
|
||||||
|
|
||||||
return DispatcherStatusID.OnlineWithHours;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
return DispatcherStatusID.Afk;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
if (statusTimestamp == 0) return DispatcherStatusID.Ending;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
return DispatcherStatusID.NoSpace;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DispatcherStatusID.Unavailable;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getStatusTimestamp = (stationStatus: any): number => {
|
|
||||||
if (!stationStatus) return -2;
|
if (!stationStatus) return -2;
|
||||||
|
|
||||||
const statusCode = stationStatus[2];
|
const statusCode = stationStatus[2];
|
||||||
@@ -67,9 +30,9 @@ export const getStatusTimestamp = (stationStatus: any): number => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
};
|
}
|
||||||
|
|
||||||
export const parseSpawns = (spawnString: string | null) => {
|
export function parseSpawns(spawnString: string | null) {
|
||||||
if (!spawnString) return [];
|
if (!spawnString) return [];
|
||||||
if (spawnString === 'NO_SPAWN') return [];
|
if (spawnString === 'NO_SPAWN') return [];
|
||||||
|
|
||||||
@@ -81,47 +44,49 @@ export const parseSpawns = (spawnString: string | null) => {
|
|||||||
|
|
||||||
return { spawnName, spawnLength, isElectrified };
|
return { spawnName, spawnLength, isElectrified };
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
export const getTimestamp = (date: string | null): number => (date ? new Date(date).getTime() : 0);
|
export function getTimestamp(date: string | null): number {
|
||||||
|
return date ? new Date(date).getTime() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
export const getTrainStopStatus = (
|
export function getTrainStopStatus(
|
||||||
stopInfo: TrainStop,
|
stopInfo: TrainStop,
|
||||||
currentStationName: string,
|
currentStationName: string,
|
||||||
sceneryName: string
|
sceneryName: string
|
||||||
) => {
|
) {
|
||||||
let stopStatus = StopStatus['arriving'],
|
let stopStatus = StopStatus.ARRIVING,
|
||||||
stopLabel = '',
|
stopLabel = '',
|
||||||
stopStatusID = -1;
|
stopStatusID = -1;
|
||||||
|
|
||||||
if (stopInfo.terminatesHere && stopInfo.confirmed) {
|
if (stopInfo.terminatesHere && stopInfo.confirmed) {
|
||||||
stopStatus = StopStatus['terminated'];
|
stopStatus = StopStatus.TERMINATED;
|
||||||
stopLabel = 'Skończył bieg';
|
stopLabel = 'Skończył bieg';
|
||||||
stopStatusID = 5;
|
stopStatusID = 5;
|
||||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == sceneryName) {
|
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == sceneryName) {
|
||||||
stopStatus = StopStatus['departed'];
|
stopStatus = StopStatus.DEPARTED;
|
||||||
stopLabel = 'Odprawiony';
|
stopLabel = 'Odprawiony';
|
||||||
stopStatusID = 2;
|
stopStatusID = 2;
|
||||||
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != sceneryName) {
|
} else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != sceneryName) {
|
||||||
stopStatus = StopStatus['departed-away'];
|
stopStatus = StopStatus.DEPARTED_AWAY;
|
||||||
stopLabel = 'Odjechał';
|
stopLabel = 'Odjechał';
|
||||||
stopStatusID = 4;
|
stopStatusID = 4;
|
||||||
} else if (currentStationName == sceneryName && !stopInfo.stopped) {
|
} else if (currentStationName == sceneryName && !stopInfo.stopped) {
|
||||||
stopStatus = StopStatus['online'];
|
stopStatus = StopStatus.ONLINE;
|
||||||
stopLabel = 'Na stacji';
|
stopLabel = 'Na stacji';
|
||||||
stopStatusID = 0;
|
stopStatusID = 0;
|
||||||
} else if (currentStationName == sceneryName && stopInfo.stopped) {
|
} else if (currentStationName == sceneryName && stopInfo.stopped) {
|
||||||
stopStatus = StopStatus['stopped'];
|
stopStatus = StopStatus.STOPPED;
|
||||||
stopLabel = 'Postój';
|
stopLabel = 'Postój';
|
||||||
stopStatusID = 1;
|
stopStatusID = 1;
|
||||||
} else if (currentStationName != sceneryName) {
|
} else if (currentStationName != sceneryName) {
|
||||||
stopStatus = StopStatus['arriving'];
|
stopStatus = StopStatus.ARRIVING;
|
||||||
stopLabel = 'W drodze';
|
stopLabel = 'W drodze';
|
||||||
stopStatusID = 3;
|
stopStatusID = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { stopStatus, stopLabel, stopStatusID };
|
return { stopStatus, stopLabel, stopStatusID };
|
||||||
};
|
}
|
||||||
|
|
||||||
export function getCheckpointTrain(
|
export function getCheckpointTrain(
|
||||||
train: Train,
|
train: Train,
|
||||||
@@ -218,40 +183,12 @@ export function getCheckpointTrain(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDispatcherStatus(state: StoreState, onlineStationData: StationAPIData) {
|
|
||||||
const { dispatchers } = state.apiData;
|
|
||||||
|
|
||||||
const prevDispatcherStatus = state.lastDispatcherStatuses.find(
|
|
||||||
(dispatcher) => dispatcher.hash === onlineStationData.stationHash
|
|
||||||
);
|
|
||||||
|
|
||||||
const stationStatus = dispatchers?.find(
|
|
||||||
(status: string[]) => status[0] == onlineStationData.stationHash && status[1] == state.region.id
|
|
||||||
);
|
|
||||||
|
|
||||||
const statusTimestamp =
|
|
||||||
prevDispatcherStatus && !dispatchers
|
|
||||||
? prevDispatcherStatus.statusTimestamp
|
|
||||||
: getStatusTimestamp(stationStatus);
|
|
||||||
|
|
||||||
const statusID =
|
|
||||||
prevDispatcherStatus && !dispatchers
|
|
||||||
? prevDispatcherStatus.statusID
|
|
||||||
: getStatusID(stationStatus, onlineStationData.isOnline === 1);
|
|
||||||
|
|
||||||
return {
|
|
||||||
hash: onlineStationData.stationHash,
|
|
||||||
statusID,
|
|
||||||
statusTimestamp
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getScheduledTrains(
|
export function getScheduledTrains(
|
||||||
trainList: Train[],
|
trainList: Train[],
|
||||||
stationAPIData: StationAPIData,
|
sceneryData: API.ActiveSceneries.Data,
|
||||||
stationGeneralInfo: Station['generalInfo']
|
stationGeneralInfo: Station['generalInfo']
|
||||||
): ScheduledTrain[] {
|
): ScheduledTrain[] {
|
||||||
const stationName = stationAPIData.stationName.toLocaleLowerCase();
|
const stationNameLower = sceneryData.stationName.toLocaleLowerCase();
|
||||||
|
|
||||||
stationGeneralInfo?.checkpoints.forEach((cp) => (cp.scheduledTrains.length = 0));
|
stationGeneralInfo?.checkpoints.forEach((cp) => (cp.scheduledTrains.length = 0));
|
||||||
|
|
||||||
@@ -259,17 +196,17 @@ export function getScheduledTrains(
|
|||||||
if (!train.timetableData) return acc;
|
if (!train.timetableData) return acc;
|
||||||
|
|
||||||
const timetable = train.timetableData;
|
const timetable = train.timetableData;
|
||||||
if (!timetable.sceneries.includes(stationAPIData.stationHash)) return acc;
|
if (!timetable.sceneries.includes(sceneryData.stationHash)) return acc;
|
||||||
|
|
||||||
const stopInfoIndex = timetable.followingStops.findIndex((stop) => {
|
const stopInfoIndex = timetable.followingStops.findIndex((stop) => {
|
||||||
const stopName = stop.stopNameRAW.toLowerCase();
|
const stopNameLower = stop.stopNameRAW.toLocaleLowerCase();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
stationName == stopName ||
|
stationNameLower == stopNameLower ||
|
||||||
(!/(po\.|podg\.)/.test(stopName) && stopName.includes(stationName)) ||
|
(!/(po\.|podg\.)/.test(stopNameLower) && stopNameLower.includes(stationNameLower)) ||
|
||||||
(!/(po\.|podg\.)/.test(stationName) && stationName.includes(stopName)) ||
|
(!/(po\.|podg\.)/.test(stationNameLower) && stationNameLower.includes(stopNameLower)) ||
|
||||||
(stopName.split(', podg.')[0] !== undefined &&
|
(stopNameLower.split(', podg.')[0] !== undefined &&
|
||||||
stationName.startsWith(stopName.split(', podg.')[0]))
|
stationNameLower.startsWith(stopNameLower.split(', podg.')[0]))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -277,12 +214,12 @@ export function getScheduledTrains(
|
|||||||
|
|
||||||
if (stopInfoIndex != -1) {
|
if (stopInfoIndex != -1) {
|
||||||
checkpointScheduledTrains.push(
|
checkpointScheduledTrains.push(
|
||||||
getCheckpointTrain(train, stopInfoIndex, stationAPIData.stationName)
|
getCheckpointTrain(train, stopInfoIndex, sceneryData.stationName)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
stationGeneralInfo?.checkpoints?.forEach((checkpoint) => {
|
stationGeneralInfo?.checkpoints?.forEach((checkpoint) => {
|
||||||
if (checkpoint.checkpointName.toLocaleLowerCase() == stationName) return;
|
// if (checkpoint.checkpointName.toLocaleLowerCase() == stationNameLower) return;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
checkpointScheduledTrains.findIndex(
|
checkpointScheduledTrains.findIndex(
|
||||||
@@ -298,9 +235,7 @@ export function getScheduledTrains(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (index > -1)
|
if (index > -1)
|
||||||
checkpointScheduledTrains.push(
|
checkpointScheduledTrains.push(getCheckpointTrain(train, index, sceneryData.stationName));
|
||||||
getCheckpointTrain(train, index, stationAPIData.stationName)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
acc.push(...checkpointScheduledTrains);
|
acc.push(...checkpointScheduledTrains);
|
||||||
@@ -312,14 +247,14 @@ export function getStationTrains(
|
|||||||
trainList: Train[],
|
trainList: Train[],
|
||||||
scheduledTrainList: ScheduledTrain[],
|
scheduledTrainList: ScheduledTrain[],
|
||||||
region: string,
|
region: string,
|
||||||
apiStation: StationAPIData
|
sceneryData: API.ActiveSceneries.Data
|
||||||
): StationTrain[] {
|
): StationTrain[] {
|
||||||
return trainList
|
return trainList
|
||||||
.filter(
|
.filter(
|
||||||
(train) =>
|
(train) =>
|
||||||
train?.region === region &&
|
train?.region === region &&
|
||||||
train.online &&
|
train.online &&
|
||||||
train.currentStationName === apiStation.stationName
|
train.currentStationName === sceneryData.stationName
|
||||||
)
|
)
|
||||||
.map((train) => ({
|
.map((train) => ({
|
||||||
driverName: train.driverName,
|
driverName: train.driverName,
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
|
$animDuration: 150ms;
|
||||||
|
$animType: ease-in-out;
|
||||||
|
|
||||||
|
// List animation
|
||||||
.list-anim-move,
|
.list-anim-move,
|
||||||
.list-anim-enter-active,
|
.list-anim-enter-active,
|
||||||
.list-anim-leave-active {
|
.list-anim-leave-active {
|
||||||
transition: all 250ms ease;
|
transition: all $animDuration ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-anim-enter-from,
|
.list-anim-enter-from,
|
||||||
@@ -15,6 +19,21 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// View animation
|
||||||
|
.view-anim {
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0.02;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: all $animDuration $animType;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data status list animation
|
||||||
.status-anim {
|
.status-anim {
|
||||||
&-enter-from,
|
&-enter-from,
|
||||||
&-leave-to {
|
&-leave-to {
|
||||||
@@ -22,10 +41,38 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-enter-active {
|
&-enter-active {
|
||||||
transition: all 100ms ease-out;
|
transition: all $animDuration ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-leave-active {
|
&-leave-active {
|
||||||
transition: all 100ms ease-out;
|
transition: all $animDuration ease-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Card animation
|
||||||
|
.card-anim {
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: all $animDuration $animType;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50%, -50%) scale(0.45);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modal animation
|
||||||
|
.modal-anim {
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: all $animDuration $animType;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
transform: translateY(-25%);
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
.filters-options {
|
.filters-options {
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions-bar {
|
.actions-bar {
|
||||||
@@ -57,7 +58,7 @@ h1.option-title {
|
|||||||
background-color: $bgCol;
|
background-color: $bgCol;
|
||||||
box-shadow: 0 5px 10px 2px #0f0f0f;
|
box-shadow: 0 5px 10px 2px #0f0f0f;
|
||||||
|
|
||||||
width: 97%;
|
width: 100%;
|
||||||
max-width: 550px;
|
max-width: 550px;
|
||||||
|
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
|
|||||||
+9
-34
@@ -14,6 +14,8 @@
|
|||||||
--clr-error: #df3e3e;
|
--clr-error: #df3e3e;
|
||||||
--clr-warning: #c59429;
|
--clr-warning: #c59429;
|
||||||
|
|
||||||
|
--clr-honorable: #f47fff;
|
||||||
|
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,38 +56,6 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.g-tooltip {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
.content {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
z-index: 100;
|
|
||||||
|
|
||||||
visibility: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
min-width: 250px;
|
|
||||||
|
|
||||||
background-color: #202020;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
border-radius: 0.5em;
|
|
||||||
|
|
||||||
transition: opacity 0.3s;
|
|
||||||
padding: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover > .content {
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
button,
|
||||||
input,
|
input,
|
||||||
select {
|
select {
|
||||||
@@ -187,16 +157,23 @@ ul {
|
|||||||
&--grayed {
|
&--grayed {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--honorable {
|
||||||
|
color: var(--clr-honorable);
|
||||||
|
text-shadow: var(--clr-honorable) 0 0 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: white;
|
color: white;
|
||||||
background: none;
|
background: none;
|
||||||
|
border-radius: 0.25em;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
padding: 0.25em 0.5em;
|
padding: 0.25em 0.5em;
|
||||||
|
|
||||||
@@ -211,7 +188,6 @@ button {
|
|||||||
|
|
||||||
button.btn--filled {
|
button.btn--filled {
|
||||||
background-color: #1a1a1a;
|
background-color: #1a1a1a;
|
||||||
border-radius: 0.25em;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #2a2a2a;
|
background-color: #2a2a2a;
|
||||||
@@ -245,7 +221,6 @@ button.btn--image {
|
|||||||
|
|
||||||
img {
|
img {
|
||||||
width: 1.5em;
|
width: 1.5em;
|
||||||
margin-right: 0.5em;
|
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,3 @@ $accent2Col: #ff3d5d;
|
|||||||
|
|
||||||
$skr: #ff5100;
|
$skr: #ff5100;
|
||||||
$twr: #ffbb00;
|
$twr: #ffbb00;
|
||||||
|
|
||||||
$animDuration: 150ms;
|
|
||||||
$animType: ease-in-out;
|
|
||||||
|
|||||||
@@ -0,0 +1,335 @@
|
|||||||
|
import { Status } from './common';
|
||||||
|
|
||||||
|
export namespace API {
|
||||||
|
export namespace DispatcherHistory {
|
||||||
|
export type Response = Data[];
|
||||||
|
|
||||||
|
export interface Data {
|
||||||
|
id: string;
|
||||||
|
currentDuration: number;
|
||||||
|
dispatcherId: number;
|
||||||
|
dispatcherName: string;
|
||||||
|
dispatcherLevel: number | null;
|
||||||
|
dispatcherRate: number;
|
||||||
|
dispatcherIsSupporter: boolean;
|
||||||
|
dispatcherStatus?: number;
|
||||||
|
isOnline: boolean;
|
||||||
|
lastOnlineTimestamp: number;
|
||||||
|
region: string;
|
||||||
|
stationHash: string;
|
||||||
|
stationName: string;
|
||||||
|
timestampFrom: number;
|
||||||
|
timestampTo?: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace DispatcherStats {
|
||||||
|
export interface DistanceStat {
|
||||||
|
routeDistance: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Count {
|
||||||
|
_all: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Response {
|
||||||
|
_sum: DistanceStat;
|
||||||
|
_max: DistanceStat;
|
||||||
|
_min: DistanceStat;
|
||||||
|
_avg: DistanceStat;
|
||||||
|
_count: Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace DriverStats {
|
||||||
|
export interface SumStats {
|
||||||
|
routeDistance: number;
|
||||||
|
confirmedStopsCount: number;
|
||||||
|
allStopsCount: number;
|
||||||
|
currentDistance: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CountStats {
|
||||||
|
fulfilled: number;
|
||||||
|
terminated: number;
|
||||||
|
_all: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MaxStats {
|
||||||
|
routeDistance: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AvdStats {
|
||||||
|
routeDistance: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Response {
|
||||||
|
_sum: SumStats;
|
||||||
|
_count: CountStats;
|
||||||
|
_max: MaxStats;
|
||||||
|
_avg: AvdStats;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace ActiveSceneries {
|
||||||
|
export interface Data {
|
||||||
|
dispatcherId: number;
|
||||||
|
dispatcherName: string;
|
||||||
|
dispatcherIsSupporter: boolean;
|
||||||
|
stationName: string;
|
||||||
|
stationHash: string;
|
||||||
|
region: string;
|
||||||
|
maxUsers: number;
|
||||||
|
currentUsers: number;
|
||||||
|
spawn: number;
|
||||||
|
lastSeen: number;
|
||||||
|
dispatcherExp: number;
|
||||||
|
nameFromHeader: string;
|
||||||
|
spawnString: string | null;
|
||||||
|
networkConnectionString: string;
|
||||||
|
isOnline: number;
|
||||||
|
dispatcherRate: number;
|
||||||
|
dispatcherStatus: Status.ActiveDispatcher | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Response = Data[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace ActiveTrains {
|
||||||
|
export type Response = Data[];
|
||||||
|
|
||||||
|
export interface Data {
|
||||||
|
trainNo: number;
|
||||||
|
|
||||||
|
mass: number;
|
||||||
|
length: number;
|
||||||
|
speed: number;
|
||||||
|
stockString: string;
|
||||||
|
|
||||||
|
signal: string;
|
||||||
|
distance: number;
|
||||||
|
connectedTrack: string;
|
||||||
|
|
||||||
|
driverName: string;
|
||||||
|
driverId: number;
|
||||||
|
driverIsSupporter: boolean;
|
||||||
|
driverLevel?: number;
|
||||||
|
|
||||||
|
currentStationName: string;
|
||||||
|
currentStationHash: string;
|
||||||
|
|
||||||
|
online: boolean;
|
||||||
|
lastSeen: number;
|
||||||
|
|
||||||
|
region: string;
|
||||||
|
isTimeout: boolean;
|
||||||
|
|
||||||
|
timetable?: Timetable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimetableStop {
|
||||||
|
stopName: string;
|
||||||
|
stopNameRAW: string;
|
||||||
|
stopType: string;
|
||||||
|
stopDistance: number;
|
||||||
|
pointId: number;
|
||||||
|
|
||||||
|
mainStop: boolean;
|
||||||
|
|
||||||
|
arrivalLine: string;
|
||||||
|
arrivalTimestamp: number;
|
||||||
|
arrivalRealTimestamp: number;
|
||||||
|
arrivalDelay: number;
|
||||||
|
|
||||||
|
departureLine: string;
|
||||||
|
departureTimestamp: number;
|
||||||
|
departureRealTimestamp: number;
|
||||||
|
departureDelay: number;
|
||||||
|
|
||||||
|
comments?: any;
|
||||||
|
|
||||||
|
beginsHere: boolean;
|
||||||
|
terminatesHere: boolean;
|
||||||
|
confirmed: boolean;
|
||||||
|
stopped: boolean;
|
||||||
|
stopTime: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Timetable {
|
||||||
|
timetableId: number;
|
||||||
|
category: string;
|
||||||
|
route: string;
|
||||||
|
|
||||||
|
stopList: TimetableStop[];
|
||||||
|
|
||||||
|
TWR: boolean;
|
||||||
|
SKR: boolean;
|
||||||
|
sceneries: string[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace TimetableHistory {
|
||||||
|
export interface Data {
|
||||||
|
id: number;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
|
||||||
|
timetableId: number;
|
||||||
|
trainNo: number;
|
||||||
|
trainCategoryCode: string;
|
||||||
|
|
||||||
|
driverId: number;
|
||||||
|
driverName: string;
|
||||||
|
driverLevel: number | null;
|
||||||
|
driverIsSupporter: boolean;
|
||||||
|
|
||||||
|
route: string;
|
||||||
|
twr: number;
|
||||||
|
skr: number;
|
||||||
|
sceneriesString: string;
|
||||||
|
currentLocation: string[];
|
||||||
|
|
||||||
|
routeDistance: number;
|
||||||
|
currentDistance: number;
|
||||||
|
|
||||||
|
confirmedStopsCount: number;
|
||||||
|
allStopsCount: number;
|
||||||
|
|
||||||
|
beginDate: string;
|
||||||
|
endDate: string;
|
||||||
|
|
||||||
|
scheduledBeginDate: string;
|
||||||
|
scheduledEndDate: string;
|
||||||
|
|
||||||
|
terminated: boolean;
|
||||||
|
fulfilled: boolean;
|
||||||
|
|
||||||
|
authorName?: string;
|
||||||
|
authorId?: number;
|
||||||
|
|
||||||
|
stopsString?: string;
|
||||||
|
|
||||||
|
stockString?: string;
|
||||||
|
stockHistory: string[];
|
||||||
|
|
||||||
|
stockMass?: number;
|
||||||
|
stockLength?: number;
|
||||||
|
maxSpeed?: number;
|
||||||
|
|
||||||
|
hashesString?: string;
|
||||||
|
currentSceneryName?: string;
|
||||||
|
currentSceneryHash?: string;
|
||||||
|
|
||||||
|
routeSceneries?: string;
|
||||||
|
|
||||||
|
checkpointArrivals?: string[];
|
||||||
|
checkpointDepartures?: string[];
|
||||||
|
|
||||||
|
checkpointArrivalsScheduled?: string[];
|
||||||
|
checkpointDeparturesScheduled?: string[];
|
||||||
|
|
||||||
|
checkpointStopTypes?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Response = Data[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace RollingStock {
|
||||||
|
export interface Response {
|
||||||
|
usage: Record<string, string>;
|
||||||
|
info: Info;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Info {
|
||||||
|
'loco-e': [string, string, string, string, boolean][];
|
||||||
|
'loco-s': [string, string, string, string, boolean][];
|
||||||
|
'loco-szt': [string, string, string, string, boolean][];
|
||||||
|
'loco-ezt': [string, string, string, string, boolean][];
|
||||||
|
'car-passenger': [string, string, boolean, boolean, string][];
|
||||||
|
'car-cargo': [string, string, boolean, boolean, string][];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace DailyStats {
|
||||||
|
export interface Response {
|
||||||
|
totalTimetables: number;
|
||||||
|
distanceSum: number;
|
||||||
|
distanceAvg: number;
|
||||||
|
maxTimetable: API.TimetableHistory.Data | null;
|
||||||
|
|
||||||
|
mostActiveDispatchers: {
|
||||||
|
name: string;
|
||||||
|
count: number;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
mostActiveDrivers: {
|
||||||
|
name: string;
|
||||||
|
distance: number;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
longestDuties: {
|
||||||
|
name: string;
|
||||||
|
duration: number;
|
||||||
|
station: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace Websocket {
|
||||||
|
export interface ActiveData {
|
||||||
|
activeSceneries?: API.ActiveSceneries.Response;
|
||||||
|
trains?: API.ActiveTrains.Response;
|
||||||
|
connectedSocketCount: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace GithubAPI {
|
||||||
|
export namespace Release {
|
||||||
|
export interface Author {
|
||||||
|
login: string;
|
||||||
|
id: number;
|
||||||
|
node_id: string;
|
||||||
|
avatar_url: string;
|
||||||
|
gravatar_id: string;
|
||||||
|
url: string;
|
||||||
|
html_url: string;
|
||||||
|
followers_url: string;
|
||||||
|
following_url: string;
|
||||||
|
gists_url: string;
|
||||||
|
starred_url: string;
|
||||||
|
subscriptions_url: string;
|
||||||
|
organizations_url: string;
|
||||||
|
repos_url: string;
|
||||||
|
events_url: string;
|
||||||
|
received_events_url: string;
|
||||||
|
type: string;
|
||||||
|
site_admin: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Response {
|
||||||
|
url: string;
|
||||||
|
assets_url: string;
|
||||||
|
upload_url: string;
|
||||||
|
html_url: string;
|
||||||
|
id: number;
|
||||||
|
author: Author;
|
||||||
|
node_id: string;
|
||||||
|
tag_name: string;
|
||||||
|
target_commitish: string;
|
||||||
|
name: string;
|
||||||
|
draft: boolean;
|
||||||
|
prerelease: boolean;
|
||||||
|
created_at: Date;
|
||||||
|
published_at: Date;
|
||||||
|
assets: any[];
|
||||||
|
tarball_url: string;
|
||||||
|
zipball_url: string;
|
||||||
|
body: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace Donators {
|
||||||
|
export type Response = string[];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
export namespace Status {
|
||||||
|
export enum ActiveDispatcher {
|
||||||
|
INVALID = -2,
|
||||||
|
UNKNOWN = -1,
|
||||||
|
NO_LIMIT = 0,
|
||||||
|
AFK = 1,
|
||||||
|
ENDING = 2,
|
||||||
|
NO_SPACE = 3,
|
||||||
|
UNAVAILABLE = 4,
|
||||||
|
NOT_LOGGED_IN = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Data {
|
||||||
|
Offline = 2,
|
||||||
|
Initialized = -1,
|
||||||
|
Loading = 0,
|
||||||
|
Error = 1,
|
||||||
|
Loaded = 2,
|
||||||
|
Warning = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,16 +36,14 @@ import axios from 'axios';
|
|||||||
|
|
||||||
import JournalOptions from '../components/JournalView/JournalOptions.vue';
|
import JournalOptions from '../components/JournalView/JournalOptions.vue';
|
||||||
import { URLs } from '../scripts/utils/apiURLs';
|
import { URLs } from '../scripts/utils/apiURLs';
|
||||||
import { DataStatus } from '../scripts/enums/DataStatus';
|
import { useStore } from '../store/mainStore';
|
||||||
import { useStore } from '../store/store';
|
|
||||||
import JournalDispatchersList from '../components/JournalView/JournalDispatchersList.vue';
|
import JournalDispatchersList from '../components/JournalView/JournalDispatchersList.vue';
|
||||||
import {
|
|
||||||
JournalDispatcherSearcher,
|
|
||||||
JournalDispatcherSorter
|
|
||||||
} from '../scripts/types/JournalDispatcherTypes';
|
|
||||||
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';
|
||||||
|
import { Journal } from '../components/JournalView/typings';
|
||||||
|
import { API } from '../typings/api';
|
||||||
|
import { Status } from '../typings/common';
|
||||||
|
|
||||||
const DISPATCHERS_API_URL = `${URLs.stacjownikAPI}/api/getDispatchers`;
|
const DISPATCHERS_API_URL = `${URLs.stacjownikAPI}/api/getDispatchers`;
|
||||||
|
|
||||||
@@ -81,21 +79,20 @@ export default defineComponent({
|
|||||||
statsCardOpen: false,
|
statsCardOpen: false,
|
||||||
currentOptionsActive: false,
|
currentOptionsActive: false,
|
||||||
|
|
||||||
dataStatus: DataStatus.Loading,
|
dataStatus: Status.Data.Loading,
|
||||||
DataStatus,
|
|
||||||
|
|
||||||
historyList: [] as DispatcherHistory[]
|
historyList: [] as API.DispatcherHistory.Response
|
||||||
}),
|
}),
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
const sorterActive: JournalDispatcherSorter = reactive({ id: 'timestampFrom', dir: -1 });
|
const sorterActive: Journal.DispatcherSorter = reactive({ id: 'timestampFrom', dir: -1 });
|
||||||
const journalFilterActive = ref({});
|
const journalFilterActive = ref({});
|
||||||
|
|
||||||
const searchersValues = reactive({
|
const searchersValues = reactive({
|
||||||
'search-dispatcher': '',
|
'search-dispatcher': '',
|
||||||
'search-station': '',
|
'search-station': '',
|
||||||
'search-date': ''
|
'search-date': ''
|
||||||
} as JournalDispatcherSearcher);
|
} as Journal.DispatcherSearcher);
|
||||||
|
|
||||||
const countFromIndex = ref(0);
|
const countFromIndex = ref(0);
|
||||||
const countLimit = 15;
|
const countLimit = 15;
|
||||||
@@ -153,7 +150,7 @@ export default defineComponent({
|
|||||||
const scrollTop = listElement.scrollTop;
|
const scrollTop = listElement.scrollTop;
|
||||||
const elementHeight = listElement.scrollHeight - listElement.offsetHeight;
|
const elementHeight = listElement.scrollHeight - listElement.offsetHeight;
|
||||||
|
|
||||||
if (!this.scrollDataLoaded || this.scrollNoMoreData || this.dataStatus != DataStatus.Loaded)
|
if (!this.scrollDataLoaded || this.scrollNoMoreData || this.dataStatus != Status.Data.Loaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (scrollTop > elementHeight * 0.85) this.addHistoryData();
|
if (scrollTop > elementHeight * 0.85) this.addHistoryData();
|
||||||
@@ -185,7 +182,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
this.countFromIndex = this.historyList.length;
|
this.countFromIndex = this.historyList.length;
|
||||||
|
|
||||||
const responseData: DispatcherHistory[] = await (
|
const responseData: API.DispatcherHistory.Response = await (
|
||||||
await axios.get(
|
await axios.get(
|
||||||
`${DISPATCHERS_API_URL}?${this.currentQuery}&countFrom=${this.countFromIndex}`
|
`${DISPATCHERS_API_URL}?${this.currentQuery}&countFrom=${this.countFromIndex}`
|
||||||
)
|
)
|
||||||
@@ -226,20 +223,20 @@ export default defineComponent({
|
|||||||
|
|
||||||
queries.push('countLimit=30');
|
queries.push('countLimit=30');
|
||||||
|
|
||||||
if (this.currentQuery != queries.join('&')) this.dataStatus = DataStatus.Loading;
|
if (this.currentQuery != queries.join('&')) this.dataStatus = Status.Data.Loading;
|
||||||
|
|
||||||
this.currentQuery = queries.join('&');
|
this.currentQuery = queries.join('&');
|
||||||
this.currentQueryArray = queries;
|
this.currentQueryArray = queries;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (reset) this.dataStatus = DataStatus.Loading;
|
if (reset) this.dataStatus = Status.Data.Loading;
|
||||||
|
|
||||||
const responseData: DispatcherHistory[] = await (
|
const responseData: API.DispatcherHistory.Response = await (
|
||||||
await axios.get(`${DISPATCHERS_API_URL}?${this.currentQuery}`)
|
await axios.get(`${DISPATCHERS_API_URL}?${this.currentQuery}`)
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
if (!responseData) {
|
if (!responseData) {
|
||||||
this.dataStatus = DataStatus.Error;
|
this.dataStatus = Status.Data.Error;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,9 +252,9 @@ export default defineComponent({
|
|||||||
: '';
|
: '';
|
||||||
|
|
||||||
this.dataRefreshedAt = new Date();
|
this.dataRefreshedAt = new Date();
|
||||||
this.dataStatus = DataStatus.Loaded;
|
this.dataStatus = Status.Data.Loaded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.dataStatus = DataStatus.Error;
|
this.dataStatus = Status.Data.Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scrollNoMoreData = false;
|
this.scrollNoMoreData = false;
|
||||||
|
|||||||
@@ -45,24 +45,84 @@ import JournalOptions from '../components/JournalView/JournalOptions.vue';
|
|||||||
import JournalStats from '../components/JournalView/JournalStats.vue';
|
import JournalStats from '../components/JournalView/JournalStats.vue';
|
||||||
import JournalHeader from '../components/JournalView/JournalHeader.vue';
|
import JournalHeader from '../components/JournalView/JournalHeader.vue';
|
||||||
|
|
||||||
import { DataStatus } from '../scripts/enums/DataStatus';
|
|
||||||
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/mainStore';
|
||||||
|
|
||||||
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';
|
|
||||||
import JournalTimetablesList from '../components/JournalView/JournalTimetables/JournalTimetablesList.vue';
|
import JournalTimetablesList from '../components/JournalView/JournalTimetables/JournalTimetablesList.vue';
|
||||||
|
import { Journal } from '../components/JournalView/typings';
|
||||||
|
import { Status } from '../typings/common';
|
||||||
|
import { API } from '../typings/api';
|
||||||
|
|
||||||
const TIMETABLES_API_URL = `${URLs.stacjownikAPI}/api/getTimetables`;
|
const TIMETABLES_API_URL = `${URLs.stacjownikAPI}/api/getTimetables`;
|
||||||
|
|
||||||
|
export const journalTimetableFilters: Journal.TimetableFilter[] = [
|
||||||
|
{
|
||||||
|
id: Journal.TimetableFilterId.ALL,
|
||||||
|
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
||||||
|
isActive: true
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: Journal.TimetableFilterId.ACTIVE,
|
||||||
|
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
||||||
|
isActive: false
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: Journal.TimetableFilterId.FULFILLED,
|
||||||
|
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
||||||
|
isActive: false
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: Journal.TimetableFilterId.ABANDONED,
|
||||||
|
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
||||||
|
isActive: false
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: Journal.TimetableFilterId.TWR_SKR,
|
||||||
|
filterSection: Journal.FilterSection.TWRSKR,
|
||||||
|
isActive: true
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: Journal.TimetableFilterId.TWR,
|
||||||
|
filterSection: Journal.FilterSection.TWRSKR,
|
||||||
|
isActive: false
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: Journal.TimetableFilterId.SKR,
|
||||||
|
filterSection: Journal.FilterSection.TWRSKR,
|
||||||
|
isActive: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
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?: Journal.TimetableSorter['id'];
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
JournalOptions,
|
JournalOptions,
|
||||||
@@ -91,22 +151,20 @@ export default defineComponent({
|
|||||||
statsCardOpen: false,
|
statsCardOpen: false,
|
||||||
currentOptionsActive: false,
|
currentOptionsActive: false,
|
||||||
|
|
||||||
timetableHistory: [] as TimetableHistory[],
|
timetableHistory: [] as API.TimetableHistory.Response,
|
||||||
journalTimetableFilters,
|
journalTimetableFilters,
|
||||||
|
|
||||||
dataStatus: DataStatus.Loading,
|
dataStatus: Status.Data.Loading,
|
||||||
dataErrorMessage: '',
|
dataErrorMessage: ''
|
||||||
|
|
||||||
DataStatus
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
const sorterActive: JournalTimetableSorter = reactive({ id: 'timetableId', dir: 'desc' });
|
const sorterActive: Journal.TimetableSorter = reactive({ id: 'timetableId', dir: 'desc' });
|
||||||
// const journalFilterActive = ref(journalTimetableFilters[0]);
|
// const journalFilterActive = ref(journalTimetableFilters[0]);
|
||||||
const initFilters: readonly JournalFilter[] = JSON.parse(
|
const initFilters: readonly Journal.TimetableFilter[] = JSON.parse(
|
||||||
JSON.stringify(journalTimetableFilters)
|
JSON.stringify(journalTimetableFilters)
|
||||||
);
|
);
|
||||||
const filterList: JournalFilter[] = reactive(JSON.parse(JSON.stringify(initFilters)));
|
const filterList: Journal.TimetableFilter[] = reactive(JSON.parse(JSON.stringify(initFilters)));
|
||||||
|
|
||||||
const searchersValues = reactive({
|
const searchersValues = reactive({
|
||||||
'search-train': '',
|
'search-train': '',
|
||||||
@@ -114,7 +172,7 @@ export default defineComponent({
|
|||||||
'search-dispatcher': '',
|
'search-dispatcher': '',
|
||||||
'search-issuedFrom': '',
|
'search-issuedFrom': '',
|
||||||
'search-date': ''
|
'search-date': ''
|
||||||
} as JournalTimetableSearchType);
|
} as Journal.TimetableSearchType);
|
||||||
|
|
||||||
const countFromIndex = ref(0);
|
const countFromIndex = ref(0);
|
||||||
const countLimit = 15;
|
const countLimit = 15;
|
||||||
@@ -163,7 +221,7 @@ export default defineComponent({
|
|||||||
const scrollTop = listElement.scrollTop;
|
const scrollTop = listElement.scrollTop;
|
||||||
const elementHeight = listElement.scrollHeight - listElement.offsetHeight;
|
const elementHeight = listElement.scrollHeight - listElement.offsetHeight;
|
||||||
|
|
||||||
if (!this.scrollDataLoaded || this.scrollNoMoreData || this.dataStatus != DataStatus.Loaded)
|
if (!this.scrollDataLoaded || this.scrollNoMoreData || this.dataStatus != Status.Data.Loaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (scrollTop > elementHeight * 0.85) this.addHistoryData();
|
if (scrollTop > elementHeight * 0.85) this.addHistoryData();
|
||||||
@@ -213,7 +271,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
this.currentQueryParams['countFrom'] = this.timetableHistory.length;
|
this.currentQueryParams['countFrom'] = this.timetableHistory.length;
|
||||||
|
|
||||||
const responseData: TimetableHistory[] = await (
|
const responseData: API.TimetableHistory.Response = await (
|
||||||
await axios.get(`${TIMETABLES_API_URL}`, {
|
await axios.get(`${TIMETABLES_API_URL}`, {
|
||||||
params: { ...this.currentQueryParams }
|
params: { ...this.currentQueryParams }
|
||||||
})
|
})
|
||||||
@@ -248,37 +306,37 @@ export default defineComponent({
|
|||||||
.filter((f) => f.isActive)
|
.filter((f) => f.isActive)
|
||||||
.forEach((f) => {
|
.forEach((f) => {
|
||||||
switch (f.id) {
|
switch (f.id) {
|
||||||
case JournalFilterType.ABANDONED:
|
case Journal.TimetableFilterId.ABANDONED:
|
||||||
queryParams['fulfilled'] = 0;
|
queryParams['fulfilled'] = 0;
|
||||||
queryParams['terminated'] = 1;
|
queryParams['terminated'] = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JournalFilterType.ACTIVE:
|
case Journal.TimetableFilterId.ACTIVE:
|
||||||
queryParams['fulfilled'] = undefined;
|
queryParams['fulfilled'] = undefined;
|
||||||
queryParams['terminated'] = 0;
|
queryParams['terminated'] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JournalFilterType.FULFILLED:
|
case Journal.TimetableFilterId.FULFILLED:
|
||||||
queryParams['terminated'] = undefined;
|
queryParams['terminated'] = undefined;
|
||||||
queryParams['fulfilled'] = 1;
|
queryParams['fulfilled'] = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JournalFilterType.ALL:
|
case Journal.TimetableFilterId.ALL:
|
||||||
queryParams['terminated'] = undefined;
|
queryParams['terminated'] = undefined;
|
||||||
queryParams['fulfilled'] = undefined;
|
queryParams['fulfilled'] = undefined;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JournalFilterType.TWR_SKR:
|
case Journal.TimetableFilterId.TWR_SKR:
|
||||||
queryParams['twr'] = undefined;
|
queryParams['twr'] = undefined;
|
||||||
queryParams['skr'] = undefined;
|
queryParams['skr'] = undefined;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JournalFilterType.TWR:
|
case Journal.TimetableFilterId.TWR:
|
||||||
queryParams['twr'] = 1;
|
queryParams['twr'] = 1;
|
||||||
queryParams['skr'] = undefined;
|
queryParams['skr'] = undefined;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JournalFilterType.SKR:
|
case Journal.TimetableFilterId.SKR:
|
||||||
queryParams['twr'] = undefined;
|
queryParams['twr'] = undefined;
|
||||||
queryParams['skr'] = 1;
|
queryParams['skr'] = 1;
|
||||||
break;
|
break;
|
||||||
@@ -301,19 +359,19 @@ export default defineComponent({
|
|||||||
this.sorterActive.id != 'timetableId' ? this.sorterActive.id : undefined;
|
this.sorterActive.id != 'timetableId' ? this.sorterActive.id : undefined;
|
||||||
|
|
||||||
if (JSON.stringify(this.currentQueryParams) != JSON.stringify(queryParams))
|
if (JSON.stringify(this.currentQueryParams) != JSON.stringify(queryParams))
|
||||||
this.dataStatus = DataStatus.Loading;
|
this.dataStatus = Status.Data.Loading;
|
||||||
|
|
||||||
this.currentQueryParams = queryParams;
|
this.currentQueryParams = queryParams;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const responseData: TimetableHistory[] = await (
|
const responseData: API.TimetableHistory.Response = await (
|
||||||
await axios.get(`${TIMETABLES_API_URL}`, {
|
await axios.get(`${TIMETABLES_API_URL}`, {
|
||||||
params: this.currentQueryParams
|
params: this.currentQueryParams
|
||||||
})
|
})
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
if (!responseData) {
|
if (!responseData) {
|
||||||
this.dataStatus = DataStatus.Error;
|
this.dataStatus = Status.Data.Error;
|
||||||
this.dataErrorMessage = 'Brak danych!';
|
this.dataErrorMessage = 'Brak danych!';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -329,10 +387,10 @@ export default defineComponent({
|
|||||||
? this.timetableHistory[0].driverName
|
? this.timetableHistory[0].driverName
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
this.dataStatus = DataStatus.Loaded;
|
this.dataStatus = Status.Data.Loaded;
|
||||||
this.dataRefreshedAt = new Date();
|
this.dataRefreshedAt = new Date();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.dataStatus = DataStatus.Error;
|
this.dataStatus = Status.Data.Error;
|
||||||
this.dataErrorMessage = 'Ups! Coś poszło nie tak!';
|
this.dataErrorMessage = 'Ups! Coś poszło nie tak!';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user