Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 60f7b3bbb5 | |||
| eaefe955a7 | |||
| edaa4f2684 | |||
| 30fce3787b | |||
| 4716f1c7a4 | |||
| bb7ccf98fd | |||
| c06d75b981 | |||
| c7da8477fa | |||
| e43f1e0819 | |||
| f130e6900b | |||
| db205915be | |||
| 05c38e10e3 | |||
| a8f683a585 | |||
| 68f6fc8a42 | |||
| 6d3b32cd7d | |||
| fadecc9d2c | |||
| 50602cb6db | |||
| 186ce81819 | |||
| f836a075b0 | |||
| 9acf3c740c | |||
| bc1c1bd3d2 | |||
| 2348277b95 | |||
| cd5f489df7 | |||
| f74962222b | |||
| e7f651d2b9 | |||
| 4862328090 | |||
| 87631d1f74 | |||
| 86bb9fcc2e | |||
| b85e3bfe1d | |||
| dd15072813 | |||
| 2f8376c996 | |||
| 514723cf74 | |||
| 0995ce15bc | |||
| 3b3c3bda31 | |||
| 2027b85450 | |||
| 0c6b55146f | |||
| 3c728e3cfa | |||
| adce339392 | |||
| 00a4a840b0 | |||
| 1e705ea496 | |||
| e8ed36df16 | |||
| f4be32aa39 | |||
| e0d3d2585d | |||
| ebfaf06a44 | |||
| 5a651aedf8 | |||
| b66af014b9 | |||
| 634c9e1514 | |||
| c4132a9be2 | |||
| 82a9a9165f | |||
| fcac03c0a4 | |||
| 39c3cf2329 | |||
| 59f4a0cb66 | |||
| e2b42d16a4 | |||
| e23663ed28 | |||
| dc7846c31e | |||
| d875433d56 | |||
| 71e5044cb4 | |||
| e83aa40f82 | |||
| d1c0e0b898 | |||
| 26a7c69886 | |||
| 0dc2c505db | |||
| 188857d335 | |||
| 3dbbb3b4f9 | |||
| 07a77c463b | |||
| 1a8e2231dd | |||
| f630d272ca | |||
| a381cf806c | |||
| 0023ab8cfd | |||
| a392940d52 | |||
| 74984ad653 | |||
| a8991434bc | |||
| 825610b4c2 | |||
| fef3991206 | |||
| a21cb31a0a | |||
| 23a954a0d1 | |||
| b7bc9625b8 | |||
| bc58196804 | |||
| 6550d6973e | |||
| d7a609a4f2 | |||
| 763506d5a9 | |||
| 8dbb32b821 | |||
| b8a21e0f70 | |||
| 7c2b5fbd50 | |||
| 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 | |||
| 4a4304d65f | |||
| edad5306f2 | |||
| 5b775dfec9 | |||
| a485652ca5 | |||
| ed308246d7 | |||
| 621bb1ad55 | |||
| 154ae2ddac | |||
| d9da49a867 |
@@ -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,28 @@
|
|||||||
<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"
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@500;700&display=swap" rel="stylesheet" />
|
/>
|
||||||
|
<meta
|
||||||
|
name="twitter:image"
|
||||||
|
content="https://raw.githubusercontent.com/Spythere/api/main/thumbnails/stacjownik.jpg"
|
||||||
|
/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.17.1",
|
"version": "1.20.3",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.17.1",
|
"version": "1.20.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.32.2",
|
"core-js": "^3.32.2",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
"howler": "^2.2.4",
|
"howler": "^2.2.4",
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.6",
|
||||||
"sass": "^1.67.0",
|
"sass": "^1.67.0",
|
||||||
"socket.io-client": "^4.7.2",
|
"socket.io-client": "^4.7.4",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-i18n": "^9.4.1",
|
"vue-i18n": "^9.4.1",
|
||||||
"vue-router": "^4.2.4"
|
"vue-router": "^4.2.4"
|
||||||
@@ -102,13 +102,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.18.6",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
|
||||||
"integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
|
"integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/highlight": "^7.18.6"
|
"@babel/highlight": "^7.23.4",
|
||||||
|
"chalk": "^2.4.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -156,14 +156,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/generator": {
|
"node_modules/@babel/generator": {
|
||||||
"version": "7.20.7",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz",
|
||||||
"integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==",
|
"integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.20.7",
|
"@babel/types": "^7.23.5",
|
||||||
"@jridgewell/gen-mapping": "^0.3.2",
|
"@jridgewell/gen-mapping": "^0.3.2",
|
||||||
|
"@jridgewell/trace-mapping": "^0.3.17",
|
||||||
"jsesc": "^2.5.1"
|
"jsesc": "^2.5.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -292,11 +292,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-environment-visitor": {
|
"node_modules/@babel/helper-environment-visitor": {
|
||||||
"version": "7.18.9",
|
"version": "7.22.20",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||||
"integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
|
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
@@ -315,27 +314,25 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-function-name": {
|
"node_modules/@babel/helper-function-name": {
|
||||||
"version": "7.19.0",
|
"version": "7.23.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||||
"integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
|
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.18.10",
|
"@babel/template": "^7.22.15",
|
||||||
"@babel/types": "^7.19.0"
|
"@babel/types": "^7.23.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-hoist-variables": {
|
"node_modules/@babel/helper-hoist-variables": {
|
||||||
"version": "7.18.6",
|
"version": "7.22.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
|
||||||
"integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
|
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.18.6"
|
"@babel/types": "^7.22.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -474,34 +471,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-split-export-declaration": {
|
"node_modules/@babel/helper-split-export-declaration": {
|
||||||
"version": "7.18.6",
|
"version": "7.22.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||||
"integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
|
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.18.6"
|
"@babel/types": "^7.22.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
"version": "7.19.4",
|
"version": "7.23.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
|
||||||
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
|
"integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
"version": "7.19.1",
|
"version": "7.22.20",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||||
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
|
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
@@ -548,14 +542,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/highlight": {
|
"node_modules/@babel/highlight": {
|
||||||
"version": "7.18.6",
|
"version": "7.23.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
|
||||||
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
|
"integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.18.6",
|
"@babel/helper-validator-identifier": "^7.22.20",
|
||||||
"chalk": "^2.0.0",
|
"chalk": "^2.4.2",
|
||||||
"js-tokens": "^4.0.0"
|
"js-tokens": "^4.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -563,11 +556,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.20.7",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz",
|
||||||
"integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==",
|
"integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
},
|
},
|
||||||
@@ -1740,35 +1731,33 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/template": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.20.7",
|
"version": "7.22.15",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
|
||||||
"integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
|
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.18.6",
|
"@babel/code-frame": "^7.22.13",
|
||||||
"@babel/parser": "^7.20.7",
|
"@babel/parser": "^7.22.15",
|
||||||
"@babel/types": "^7.20.7"
|
"@babel/types": "^7.22.15"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/traverse": {
|
"node_modules/@babel/traverse": {
|
||||||
"version": "7.20.10",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.10.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz",
|
||||||
"integrity": "sha512-oSf1juCgymrSez8NI4A2sr4+uB/mFd9MXplYGPEBnfAuWmmyeVcHa6xLPiaRBcXkcb/28bgxmQLTVwFKE1yfsg==",
|
"integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.18.6",
|
"@babel/code-frame": "^7.23.5",
|
||||||
"@babel/generator": "^7.20.7",
|
"@babel/generator": "^7.23.5",
|
||||||
"@babel/helper-environment-visitor": "^7.18.9",
|
"@babel/helper-environment-visitor": "^7.22.20",
|
||||||
"@babel/helper-function-name": "^7.19.0",
|
"@babel/helper-function-name": "^7.23.0",
|
||||||
"@babel/helper-hoist-variables": "^7.18.6",
|
"@babel/helper-hoist-variables": "^7.22.5",
|
||||||
"@babel/helper-split-export-declaration": "^7.18.6",
|
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||||
"@babel/parser": "^7.20.7",
|
"@babel/parser": "^7.23.5",
|
||||||
"@babel/types": "^7.20.7",
|
"@babel/types": "^7.23.5",
|
||||||
"debug": "^4.1.0",
|
"debug": "^4.1.0",
|
||||||
"globals": "^11.1.0"
|
"globals": "^11.1.0"
|
||||||
},
|
},
|
||||||
@@ -1777,14 +1766,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.20.7",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz",
|
||||||
"integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
|
"integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-string-parser": "^7.19.4",
|
"@babel/helper-string-parser": "^7.23.4",
|
||||||
"@babel/helper-validator-identifier": "^7.19.1",
|
"@babel/helper-validator-identifier": "^7.22.20",
|
||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2856,8 +2844,7 @@
|
|||||||
"node_modules/@socket.io/component-emitter": {
|
"node_modules/@socket.io/component-emitter": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||||
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==",
|
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
@@ -3241,18 +3228,6 @@
|
|||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-core/node_modules/@babel/parser": {
|
|
||||||
"version": "7.22.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
|
|
||||||
"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"parser": "bin/babel-parser.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@vue/compiler-dom": {
|
"node_modules/@vue/compiler-dom": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz",
|
||||||
@@ -3281,18 +3256,6 @@
|
|||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-sfc/node_modules/@babel/parser": {
|
|
||||||
"version": "7.22.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
|
|
||||||
"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"parser": "bin/babel-parser.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@vue/compiler-sfc/node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@vue/compiler-sfc/node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.15",
|
"version": "1.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||||
@@ -3311,42 +3274,6 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-sfc/node_modules/nanoid": {
|
|
||||||
"version": "3.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
|
||||||
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"nanoid": "bin/nanoid.cjs"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@vue/compiler-sfc/node_modules/postcss": {
|
|
||||||
"version": "8.4.20",
|
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz",
|
|
||||||
"integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==",
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/postcss/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "tidelift",
|
|
||||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"nanoid": "^3.3.4",
|
|
||||||
"picocolors": "^1.0.0",
|
|
||||||
"source-map-js": "^1.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^10 || ^12 || >=14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@vue/compiler-ssr": {
|
"node_modules/@vue/compiler-ssr": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz",
|
||||||
@@ -3464,18 +3391,6 @@
|
|||||||
"magic-string": "^0.30.0"
|
"magic-string": "^0.30.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/reactivity-transform/node_modules/@babel/parser": {
|
|
||||||
"version": "7.22.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
|
|
||||||
"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"parser": "bin/babel-parser.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@vue/reactivity-transform/node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@vue/reactivity-transform/node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.15",
|
"version": "1.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||||
@@ -3666,11 +3581,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.5.0",
|
"version": "1.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
|
||||||
"integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==",
|
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.0",
|
"follow-redirects": "^1.15.0",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
@@ -3942,9 +3856,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001503",
|
"version": "1.0.30001565",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz",
|
||||||
"integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==",
|
"integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3959,15 +3873,13 @@
|
|||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"license": "CC-BY-4.0"
|
|
||||||
},
|
},
|
||||||
"node_modules/chalk": {
|
"node_modules/chalk": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-styles": "^3.2.1",
|
"ansi-styles": "^3.2.1",
|
||||||
"escape-string-regexp": "^1.0.5",
|
"escape-string-regexp": "^1.0.5",
|
||||||
@@ -3982,7 +3894,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color-convert": "^1.9.0"
|
"color-convert": "^1.9.0"
|
||||||
},
|
},
|
||||||
@@ -3995,7 +3906,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color-name": "1.1.3"
|
"color-name": "1.1.3"
|
||||||
}
|
}
|
||||||
@@ -4004,15 +3914,13 @@
|
|||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/chalk/node_modules/has-flag": {
|
"node_modules/chalk/node_modules/has-flag": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
@@ -4022,7 +3930,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has-flag": "^3.0.0"
|
"has-flag": "^3.0.0"
|
||||||
},
|
},
|
||||||
@@ -4498,10 +4405,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/engine.io-client": {
|
"node_modules/engine.io-client": {
|
||||||
"version": "6.5.2",
|
"version": "6.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
|
||||||
"integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==",
|
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@socket.io/component-emitter": "~3.1.0",
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
"debug": "~4.3.1",
|
"debug": "~4.3.1",
|
||||||
@@ -4514,7 +4420,6 @@
|
|||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
|
||||||
"integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==",
|
"integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==",
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
}
|
}
|
||||||
@@ -4629,7 +4534,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
}
|
}
|
||||||
@@ -5182,9 +5086,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.5",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -5192,7 +5096,6 @@
|
|||||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
},
|
},
|
||||||
@@ -5246,6 +5149,19 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/function-bind": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||||
@@ -6083,8 +5999,7 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
@@ -6434,7 +6349,6 @@
|
|||||||
"version": "3.3.6",
|
"version": "3.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -6816,10 +6730,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.30",
|
"version": "8.4.31",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
||||||
"integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==",
|
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -6834,7 +6747,6 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.6",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
@@ -7477,11 +7389,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
@@ -7651,10 +7562,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/socket.io-client": {
|
"node_modules/socket.io-client": {
|
||||||
"version": "4.7.2",
|
"version": "4.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
|
||||||
"integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==",
|
"integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@socket.io/component-emitter": "~3.1.0",
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
"debug": "~4.3.2",
|
"debug": "~4.3.2",
|
||||||
@@ -7669,7 +7579,6 @@
|
|||||||
"version": "4.2.4",
|
"version": "4.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||||
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@socket.io/component-emitter": "~3.1.0",
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
"debug": "~4.3.1"
|
"debug": "~4.3.1"
|
||||||
@@ -8292,11 +8201,10 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "4.4.9",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz",
|
||||||
"integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==",
|
"integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.18.10",
|
"esbuild": "^0.18.10",
|
||||||
"postcss": "^8.4.27",
|
"postcss": "^8.4.27",
|
||||||
@@ -8872,7 +8780,6 @@
|
|||||||
"version": "8.11.0",
|
"version": "8.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
|
||||||
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
|
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
},
|
},
|
||||||
@@ -9009,12 +8916,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/code-frame": {
|
"@babel/code-frame": {
|
||||||
"version": "7.18.6",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
|
||||||
"integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
|
"integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/highlight": "^7.18.6"
|
"@babel/highlight": "^7.23.4",
|
||||||
|
"chalk": "^2.4.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/compat-data": {
|
"@babel/compat-data": {
|
||||||
@@ -9047,13 +8955,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/generator": {
|
"@babel/generator": {
|
||||||
"version": "7.20.7",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz",
|
||||||
"integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==",
|
"integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.20.7",
|
"@babel/types": "^7.23.5",
|
||||||
"@jridgewell/gen-mapping": "^0.3.2",
|
"@jridgewell/gen-mapping": "^0.3.2",
|
||||||
|
"@jridgewell/trace-mapping": "^0.3.17",
|
||||||
"jsesc": "^2.5.1"
|
"jsesc": "^2.5.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -9146,9 +9055,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/helper-environment-visitor": {
|
"@babel/helper-environment-visitor": {
|
||||||
"version": "7.18.9",
|
"version": "7.22.20",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||||
"integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
|
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@babel/helper-explode-assignable-expression": {
|
"@babel/helper-explode-assignable-expression": {
|
||||||
@@ -9161,22 +9070,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/helper-function-name": {
|
"@babel/helper-function-name": {
|
||||||
"version": "7.19.0",
|
"version": "7.23.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||||
"integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
|
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/template": "^7.18.10",
|
"@babel/template": "^7.22.15",
|
||||||
"@babel/types": "^7.19.0"
|
"@babel/types": "^7.23.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/helper-hoist-variables": {
|
"@babel/helper-hoist-variables": {
|
||||||
"version": "7.18.6",
|
"version": "7.22.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
|
||||||
"integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
|
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.18.6"
|
"@babel/types": "^7.22.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/helper-member-expression-to-functions": {
|
"@babel/helper-member-expression-to-functions": {
|
||||||
@@ -9273,24 +9182,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/helper-split-export-declaration": {
|
"@babel/helper-split-export-declaration": {
|
||||||
"version": "7.18.6",
|
"version": "7.22.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||||
"integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
|
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.18.6"
|
"@babel/types": "^7.22.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/helper-string-parser": {
|
"@babel/helper-string-parser": {
|
||||||
"version": "7.19.4",
|
"version": "7.23.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
|
||||||
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
|
"integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@babel/helper-validator-identifier": {
|
"@babel/helper-validator-identifier": {
|
||||||
"version": "7.19.1",
|
"version": "7.22.20",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||||
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
|
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@babel/helper-validator-option": {
|
"@babel/helper-validator-option": {
|
||||||
@@ -9323,21 +9232,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/highlight": {
|
"@babel/highlight": {
|
||||||
"version": "7.18.6",
|
"version": "7.23.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
|
||||||
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
|
"integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-validator-identifier": "^7.18.6",
|
"@babel/helper-validator-identifier": "^7.22.20",
|
||||||
"chalk": "^2.0.0",
|
"chalk": "^2.4.2",
|
||||||
"js-tokens": "^4.0.0"
|
"js-tokens": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/parser": {
|
"@babel/parser": {
|
||||||
"version": "7.20.7",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz",
|
||||||
"integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==",
|
"integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
|
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
|
||||||
"version": "7.18.6",
|
"version": "7.18.6",
|
||||||
@@ -10074,42 +9982,42 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/template": {
|
"@babel/template": {
|
||||||
"version": "7.20.7",
|
"version": "7.22.15",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
|
||||||
"integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
|
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "^7.18.6",
|
"@babel/code-frame": "^7.22.13",
|
||||||
"@babel/parser": "^7.20.7",
|
"@babel/parser": "^7.22.15",
|
||||||
"@babel/types": "^7.20.7"
|
"@babel/types": "^7.22.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/traverse": {
|
"@babel/traverse": {
|
||||||
"version": "7.20.10",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.10.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz",
|
||||||
"integrity": "sha512-oSf1juCgymrSez8NI4A2sr4+uB/mFd9MXplYGPEBnfAuWmmyeVcHa6xLPiaRBcXkcb/28bgxmQLTVwFKE1yfsg==",
|
"integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "^7.18.6",
|
"@babel/code-frame": "^7.23.5",
|
||||||
"@babel/generator": "^7.20.7",
|
"@babel/generator": "^7.23.5",
|
||||||
"@babel/helper-environment-visitor": "^7.18.9",
|
"@babel/helper-environment-visitor": "^7.22.20",
|
||||||
"@babel/helper-function-name": "^7.19.0",
|
"@babel/helper-function-name": "^7.23.0",
|
||||||
"@babel/helper-hoist-variables": "^7.18.6",
|
"@babel/helper-hoist-variables": "^7.22.5",
|
||||||
"@babel/helper-split-export-declaration": "^7.18.6",
|
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||||
"@babel/parser": "^7.20.7",
|
"@babel/parser": "^7.23.5",
|
||||||
"@babel/types": "^7.20.7",
|
"@babel/types": "^7.23.5",
|
||||||
"debug": "^4.1.0",
|
"debug": "^4.1.0",
|
||||||
"globals": "^11.1.0"
|
"globals": "^11.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/types": {
|
"@babel/types": {
|
||||||
"version": "7.20.7",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz",
|
||||||
"integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
|
"integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-string-parser": "^7.19.4",
|
"@babel/helper-string-parser": "^7.23.4",
|
||||||
"@babel/helper-validator-identifier": "^7.19.1",
|
"@babel/helper-validator-identifier": "^7.22.20",
|
||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -11151,13 +11059,6 @@
|
|||||||
"@vue/shared": "3.3.4",
|
"@vue/shared": "3.3.4",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/parser": {
|
|
||||||
"version": "7.22.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
|
|
||||||
"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA=="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@vue/compiler-dom": {
|
"@vue/compiler-dom": {
|
||||||
@@ -11186,11 +11087,6 @@
|
|||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": {
|
|
||||||
"version": "7.22.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
|
|
||||||
"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA=="
|
|
||||||
},
|
|
||||||
"@jridgewell/sourcemap-codec": {
|
"@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.15",
|
"version": "1.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||||
@@ -11203,21 +11099,6 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"nanoid": {
|
|
||||||
"version": "3.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
|
||||||
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
|
|
||||||
},
|
|
||||||
"postcss": {
|
|
||||||
"version": "8.4.20",
|
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz",
|
|
||||||
"integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==",
|
|
||||||
"requires": {
|
|
||||||
"nanoid": "^3.3.4",
|
|
||||||
"picocolors": "^1.0.0",
|
|
||||||
"source-map-js": "^1.0.2"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -11303,11 +11184,6 @@
|
|||||||
"magic-string": "^0.30.0"
|
"magic-string": "^0.30.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": {
|
|
||||||
"version": "7.22.16",
|
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
|
|
||||||
"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA=="
|
|
||||||
},
|
|
||||||
"@jridgewell/sourcemap-codec": {
|
"@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.15",
|
"version": "1.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||||
@@ -11450,9 +11326,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "1.5.0",
|
"version": "1.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
|
||||||
"integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==",
|
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"follow-redirects": "^1.15.0",
|
"follow-redirects": "^1.15.0",
|
||||||
@@ -11628,9 +11504,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"caniuse-lite": {
|
"caniuse-lite": {
|
||||||
"version": "1.0.30001503",
|
"version": "1.0.30001565",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz",
|
||||||
"integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==",
|
"integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
@@ -12007,9 +11883,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"engine.io-client": {
|
"engine.io-client": {
|
||||||
"version": "6.5.2",
|
"version": "6.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
|
||||||
"integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==",
|
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@socket.io/component-emitter": "~3.1.0",
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
"debug": "~4.3.1",
|
"debug": "~4.3.1",
|
||||||
@@ -12508,9 +12384,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"follow-redirects": {
|
"follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.5",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"form-data": {
|
"form-data": {
|
||||||
@@ -12548,6 +12424,12 @@
|
|||||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"fsevents": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"function-bind": {
|
"function-bind": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||||
@@ -13354,8 +13236,7 @@
|
|||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "3.3.6",
|
"version": "3.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"napi-build-utils": {
|
"napi-build-utils": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@@ -13602,10 +13483,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "8.4.30",
|
"version": "8.4.31",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
||||||
"integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==",
|
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.6",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
@@ -14046,9 +13926,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"serialize-javascript": {
|
"serialize-javascript": {
|
||||||
@@ -14163,9 +14043,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"socket.io-client": {
|
"socket.io-client": {
|
||||||
"version": "4.7.2",
|
"version": "4.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
|
||||||
"integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==",
|
"integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@socket.io/component-emitter": "~3.1.0",
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
"debug": "~4.3.2",
|
"debug": "~4.3.2",
|
||||||
@@ -14614,9 +14494,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"vite": {
|
"vite": {
|
||||||
"version": "4.4.9",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz",
|
||||||
"integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==",
|
"integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"esbuild": "^0.18.10",
|
"esbuild": "^0.18.10",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.18.0",
|
"version": "1.20.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@@ -18,27 +18,27 @@
|
|||||||
"howler": "^2.2.4",
|
"howler": "^2.2.4",
|
||||||
"pinia": "^2.1.6",
|
"pinia": "^2.1.6",
|
||||||
"sass": "^1.67.0",
|
"sass": "^1.67.0",
|
||||||
"socket.io-client": "^4.7.2",
|
"socket.io-client": "^4.7.4",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-i18n": "^9.4.1",
|
"vue-i18n": "^9.4.1",
|
||||||
"vue-router": "^4.2.4"
|
"vue-router": "^4.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@rushstack/eslint-patch": "^1.3.3",
|
||||||
"@types/node": "^20.6.2",
|
"@types/node": "^20.6.2",
|
||||||
"@vite-pwa/assets-generator": "^0.0.10",
|
"@vite-pwa/assets-generator": "^0.0.10",
|
||||||
"@vitejs/plugin-vue": "^4.3.4",
|
"@vitejs/plugin-vue": "^4.3.4",
|
||||||
|
"@vue/eslint-config-prettier": "^8.0.0",
|
||||||
|
"@vue/eslint-config-typescript": "^12.0.0",
|
||||||
|
"@vue/tsconfig": "^0.4.0",
|
||||||
"axios": "^1.5.0",
|
"axios": "^1.5.0",
|
||||||
|
"eslint": "^8.49.0",
|
||||||
|
"eslint-plugin-vue": "^9.17.0",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^4.4.9",
|
"vite": "^4.4.9",
|
||||||
"vite-plugin-pwa": "^0.16.5",
|
"vite-plugin-pwa": "^0.16.5",
|
||||||
"vue-tsc": "^1.8.11",
|
"vue-tsc": "^1.8.11"
|
||||||
"@vue/eslint-config-prettier": "^8.0.0",
|
|
||||||
"@vue/eslint-config-typescript": "^12.0.0",
|
|
||||||
"@vue/tsconfig": "^0.4.0",
|
|
||||||
"eslint": "^8.49.0",
|
|
||||||
"eslint-plugin-vue": "^9.17.0",
|
|
||||||
"@rushstack/eslint-patch": "^1.3.3"
|
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Warstwa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 159 38.8" style="enable-background:new 0 0 159 38.8;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#00A962;}
|
||||||
|
.st1{enable-background:new ;}
|
||||||
|
.st2{fill:#FFFFFF;}
|
||||||
|
.st3{fill:#1E3A33;}
|
||||||
|
.st4{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<path class="st0" d="M139.6,38.7H19.4C8.7,38.7,0,30.1,0,19.3l0,0C0,8.6,8.7-0.1,19.4-0.1h120.2c10.7,0,19.4,8.7,19.4,19.4l0,0
|
||||||
|
C159,30.1,150.3,38.7,139.6,38.7z"/>
|
||||||
|
<g class="st1">
|
||||||
|
<path class="st2" d="M48.9,23.7c0,0.5-0.4,0.9-0.9,0.9c-0.5,0-0.9-0.4-0.9-0.9v-9.9c0-0.6,0.4-1,1-1h3.7c2.5,0,3.6,1.9,3.6,3.7
|
||||||
|
s-1,3.7-3.6,3.7h-2.9V23.7z M48.9,14.5v4.1h2.8c1.3,0,1.9-1,1.9-2c0-1-0.5-2.1-1.8-2.1H48.9z"/>
|
||||||
|
<path class="st2" d="M56.3,20.5c0-2.5,1.9-4.1,4.1-4.1c2.3,0,4.2,1.6,4.2,4.1c0,2.5-1.9,4.2-4.2,4.2C58.2,24.7,56.3,23,56.3,20.5z
|
||||||
|
M62.9,20.5c0-1.5-1.1-2.4-2.4-2.4c-1.3,0-2.4,1-2.4,2.4c0,1.5,1.1,2.5,2.4,2.5C61.8,23,62.9,22,62.9,20.5z"/>
|
||||||
|
<path class="st2" d="M66.6,21.9c0.4-0.2,0.7,0.1,0.9,0.3c0.3,0.6,0.9,1,1.7,1c0.8,0,1.4-0.4,1.4-1c0-0.5-0.5-0.7-1.1-0.9l-1.1-0.3
|
||||||
|
c-1.7-0.5-2.3-1.4-2.2-2.7c0.1-1.2,1.4-2.1,2.8-2.1c1.1,0,2,0.3,2.5,1.2c0.2,0.4,0.1,0.8-0.2,1c-0.3,0.2-0.6,0.2-1-0.1
|
||||||
|
c-0.4-0.4-1-0.5-1.4-0.5c-0.4,0-0.9,0.2-1.1,0.4c-0.1,0.2-0.2,0.4-0.1,0.7c0.1,0.3,0.6,0.5,1,0.6l1.2,0.3c1.7,0.4,2.1,1.5,2.1,2.3
|
||||||
|
c0,1.5-1.3,2.4-3.2,2.4c-1.2,0-2.5-0.6-2.9-1.8C66,22.5,66.2,22.1,66.6,21.9z"/>
|
||||||
|
<path class="st2" d="M74.6,18h-0.8c-0.4,0-0.7-0.3-0.7-0.7c0-0.4,0.3-0.7,0.7-0.7h0.8v-2.2c0-0.5,0.4-0.9,0.9-0.9
|
||||||
|
c0.5,0,0.9,0.4,0.9,0.9v2.2h1c0.4,0,0.7,0.3,0.7,0.7c0,0.4-0.3,0.7-0.7,0.7h-1v5.7c0,0.5-0.4,0.9-0.9,0.9c-0.5,0-0.9-0.4-0.9-0.9
|
||||||
|
V18z"/>
|
||||||
|
<path class="st2" d="M85.7,23.4c-0.5,0.9-1.7,1.3-2.7,1.3c-2.1,0-4-1.6-4-4.1c0-2.5,1.9-4.1,4-4.1c1,0,2.1,0.4,2.7,1.3v-0.3
|
||||||
|
c0-0.5,0.4-0.9,0.9-0.9c0.5,0,0.9,0.4,0.9,0.9v6.3c0,0.5-0.4,0.9-0.9,0.9c-0.5,0-0.9-0.4-0.9-0.9V23.4z M83.2,23
|
||||||
|
c1.3,0,2.4-0.9,2.4-2.5c0-1.6-1.3-2.4-2.4-2.4c-1.3,0-2.4,1-2.4,2.4C80.8,22,81.9,23,83.2,23z"/>
|
||||||
|
<path class="st2" d="M95.1,16.6c0.5,0,0.9,0.3,1,0.8l1.6,4.6l1.7-4.8c0.2-0.5,0.6-0.7,1.1-0.6c0.5,0.1,0.7,0.6,0.6,1.1l-2.4,6.3
|
||||||
|
c-0.2,0.5-0.5,0.7-0.9,0.7h-0.1c-0.4,0-0.7-0.2-0.9-0.7L95.1,19l-1.7,4.9c-0.2,0.5-0.5,0.7-0.9,0.7h-0.1c-0.4,0-0.7-0.2-0.9-0.7
|
||||||
|
l-2.4-6.3c-0.2-0.4,0.1-1,0.6-1.1c0.5-0.1,0.9,0.1,1.1,0.6l1.7,4.8l1.6-4.6C94.2,16.8,94.6,16.6,95.1,16.6L95.1,16.6z"/>
|
||||||
|
<path class="st2" d="M112.9,23.2c0.3,0.3,0.3,0.9,0,1.2c-0.4,0.3-0.9,0.3-1.2,0l-3.2-3.5v2.9c0,0.5-0.4,0.9-0.9,0.9
|
||||||
|
c-0.5,0-0.8-0.4-0.8-0.9V13.1c0-0.5,0.4-0.9,0.8-0.9c0.5,0,0.9,0.4,0.9,0.9v6.1l2.4-2.4c0.3-0.3,0.9-0.3,1.2,0
|
||||||
|
c0.3,0.4,0.3,0.9,0,1.2l-2,2.1L112.9,23.2z"/>
|
||||||
|
<path class="st2" d="M120.8,23.4c-0.5,0.9-1.7,1.3-2.7,1.3c-2.1,0-4-1.6-4-4.1c0-2.5,1.9-4.1,4-4.1c1,0,2.1,0.4,2.7,1.3v-0.3
|
||||||
|
c0-0.5,0.4-0.9,0.8-0.9c0.5,0,0.9,0.4,0.9,0.9v6.3c0,0.5-0.4,0.9-0.9,0.9c-0.5,0-0.8-0.4-0.8-0.9V23.4z M118.4,23
|
||||||
|
c1.3,0,2.4-0.9,2.4-2.5c0-1.6-1.3-2.4-2.4-2.4c-1.3,0-2.4,1-2.4,2.4C115.9,22,117,23,118.4,23z"/>
|
||||||
|
<path class="st2" d="M130.3,16.6c0.5,0,0.9,0.3,1,0.8l1.6,4.6l1.7-4.8c0.2-0.5,0.6-0.7,1.1-0.6c0.5,0.1,0.7,0.6,0.6,1.1l-2.4,6.3
|
||||||
|
c-0.2,0.5-0.5,0.7-0.9,0.7h-0.1c-0.4,0-0.7-0.2-0.9-0.7l-1.7-4.9l-1.7,4.9c-0.2,0.5-0.5,0.7-0.9,0.7h-0.1c-0.4,0-0.7-0.2-0.9-0.7
|
||||||
|
l-2.4-6.3c-0.2-0.4,0.1-1,0.6-1.1c0.5-0.1,0.9,0.1,1.1,0.6l1.7,4.8l1.6-4.6C129.3,16.8,129.7,16.6,130.3,16.6L130.3,16.6z"/>
|
||||||
|
<path class="st2" d="M143.6,26.1c0,0.2,0.2,0.5,0.6,0.5c0.1,0,0.4,0,0.5-0.4c0.1-0.4,0.3-0.5,0.7-0.5c0.4,0.1,0.6,0.4,0.5,0.8
|
||||||
|
c-0.2,0.8-0.9,1.4-1.7,1.4c-1.3,0-1.9-0.8-1.9-1.7c0-0.2,0.1-0.6,0.2-0.8l0.5-1c-0.5,0.2-1,0.3-1.6,0.3c-2.3,0-4.1-1.6-4.1-4.2
|
||||||
|
c0-2.5,1.8-4.1,4.1-4.1c2.2,0,3.9,1.5,4,4c0,0.5-0.4,0.8-0.8,0.8h-5.5c0.2,1.2,1.2,2,2.4,2c0.8,0,1.3-0.3,1.9-0.8
|
||||||
|
c0.3-0.2,0.8-0.4,1.1-0.1c0.3,0.3,0.2,0.7,0,1.1C143.5,25.9,143.6,26.1,143.6,26.1z M143.7,19.9c-0.2-1.2-1.1-2-2.3-2
|
||||||
|
c-1.2,0-2.2,0.7-2.3,2H143.7z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st3" d="M21.6,26.7c-4.9,0-7.4-2.6-8.5-4.9c-1.2-2.4-1.4-5-1.4-6c0-2.2,1.8-3.8,4.3-3.8h7c0.7,0,1.3,0.6,1.3,1.3
|
||||||
|
c0,0.7-0.6,1.3-1.3,1.3h-7c-0.5,0-1,0.1-1.3,0.4c-0.3,0.2-0.4,0.4-0.4,0.8c0,1.9,0.5,8.3,7.3,8.3c5.8,0,7.3-4.6,7.9-8.1
|
||||||
|
c0-0.2,0-0.3,0.1-0.4c0.2-0.9,0.4-1.7,0.8-2.3C31,12.4,31.9,12,33,12c0.5,0,0.9,0.2,1.2,0.5c0.5,0.4,0.9,1.3,1.2,4.1
|
||||||
|
c0.1,1.4,0.1,2.6,0.1,2.7c0,0.7-0.6,1.3-1.3,1.3l0,0c-0.7,0-1.3-0.6-1.3-1.3c0,0,0-1.1-0.1-2.3c-0.1-1-0.2-1.7-0.3-2.1
|
||||||
|
c-0.1,0.3-0.2,0.9-0.3,1.1c0,0.1,0,0.2-0.1,0.4c-0.2,1.2-0.7,3.7-2.1,5.9c-0.8,1.3-1.9,2.3-3.2,3.1C25.4,26.3,23.6,26.7,21.6,26.7z
|
||||||
|
"/>
|
||||||
|
<ellipse class="st4" cx="26.7" cy="13.3" rx="1.3" ry="1.3"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
@@ -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 |
@@ -1,4 +1,4 @@
|
|||||||
<svg width="160" height="150" viewBox="0 0 160 150" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="160" height="150" viewBox="0 0 160 150" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M10.163 139L80 12.4204L149.837 139H80H10.163Z" stroke="white" stroke-width="12"/>
|
<path d="M10.163 139L80 12.4204L149.837 139H80H10.163Z" stroke="salmon" stroke-width="15"/>
|
||||||
<path d="M85.4488 50.3354V80.6619C85.4488 83.8784 85.2898 87.0418 84.9717 90.1522C84.6536 93.2273 84.2294 96.4968 83.6992 99.9606H74.8451C74.315 96.4968 73.8908 93.2273 73.5727 90.1522C73.2546 87.0418 73.0955 83.8784 73.0955 80.6619V50.3354H85.4488ZM71.0808 119.789C71.0808 118.694 71.2752 117.651 71.664 116.661C72.0882 115.672 72.6537 114.823 73.3606 114.117C74.1029 113.41 74.9689 112.844 75.9585 112.42C76.9482 111.996 78.0086 111.784 79.1396 111.784C80.2354 111.784 81.278 111.996 82.2677 112.42C83.2574 112.844 84.1057 113.41 84.8126 114.117C85.5195 114.823 86.085 115.672 86.5092 116.661C86.9333 117.651 87.1454 118.694 87.1454 119.789C87.1454 120.921 86.9333 121.981 86.5092 122.971C86.085 123.925 85.5195 124.756 84.8126 125.462C84.1057 126.169 83.2574 126.717 82.2677 127.106C81.278 127.53 80.2354 127.742 79.1396 127.742C78.0086 127.742 76.9482 127.53 75.9585 127.106C74.9689 126.717 74.1029 126.169 73.3606 125.462C72.6537 124.756 72.0882 123.925 71.664 122.971C71.2752 121.981 71.0808 120.921 71.0808 119.789Z" fill="#FFFBFB"/>
|
<path d="M85.4488 50.3354V80.6619C85.4488 83.8784 85.2898 87.0418 84.9717 90.1522C84.6536 93.2273 84.2294 96.4968 83.6992 99.9606H74.8451C74.315 96.4968 73.8908 93.2273 73.5727 90.1522C73.2546 87.0418 73.0955 83.8784 73.0955 80.6619V50.3354H85.4488ZM71.0808 119.789C71.0808 118.694 71.2752 117.651 71.664 116.661C72.0882 115.672 72.6537 114.823 73.3606 114.117C74.1029 113.41 74.9689 112.844 75.9585 112.42C76.9482 111.996 78.0086 111.784 79.1396 111.784C80.2354 111.784 81.278 111.996 82.2677 112.42C83.2574 112.844 84.1057 113.41 84.8126 114.117C85.5195 114.823 86.085 115.672 86.5092 116.661C86.9333 117.651 87.1454 118.694 87.1454 119.789C87.1454 120.921 86.9333 121.981 86.5092 122.971C86.085 123.925 85.5195 124.756 84.8126 125.462C84.1057 126.169 83.2574 126.717 82.2677 127.106C81.278 127.53 80.2354 127.742 79.1396 127.742C78.0086 127.742 76.9482 127.53 75.9585 127.106C74.9689 126.717 74.1029 126.169 73.3606 125.462C72.6537 124.756 72.0882 123.925 71.664 122.971C71.2752 121.981 71.0808 120.921 71.0808 119.789Z" fill="white"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -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 |
@@ -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 {
|
||||||
|
|||||||
@@ -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="SceneryView">
|
||||||
<component :is="Component" :key="$route.name" />
|
<component :is="Component" :key="$route.name" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</router-view>
|
</router-view>
|
||||||
@@ -33,31 +33,33 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, watch } from 'vue';
|
import { defineComponent, watch } from 'vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
import packageInfo from '.././package.json';
|
||||||
|
|
||||||
import Clock from './components/App/Clock.vue';
|
import Clock from './components/App/Clock.vue';
|
||||||
|
|
||||||
import packageInfo from '.././package.json';
|
import { useMainStore } from './store/mainStore';
|
||||||
|
|
||||||
import { useStore } from './store/store';
|
|
||||||
import StatusIndicator from './components/App/StatusIndicator.vue';
|
import StatusIndicator from './components/App/StatusIndicator.vue';
|
||||||
import SelectBox from './components/Global/SelectBox.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 TrainModal from './components/TrainsView/TrainModal.vue';
|
||||||
|
|
||||||
|
import StorageManager from './managers/storageManager';
|
||||||
|
import { useApiStore } from './store/apiStore';
|
||||||
|
import { Status } from './typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
Clock,
|
Clock,
|
||||||
StatusIndicator,
|
StatusIndicator,
|
||||||
SelectBox,
|
AppHeader,
|
||||||
TrainModal,
|
TrainModal
|
||||||
AppHeader
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
VERSION: packageInfo.version,
|
VERSION: packageInfo.version,
|
||||||
store: useStore(),
|
store: useMainStore(),
|
||||||
|
apiStore: useApiStore(),
|
||||||
|
|
||||||
currentLang: 'pl',
|
currentLang: 'pl',
|
||||||
releaseURL: '',
|
releaseURL: '',
|
||||||
@@ -65,32 +67,10 @@ export default defineComponent({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.loadLang();
|
this.init();
|
||||||
this.store.connectToAPI();
|
|
||||||
|
|
||||||
this.store.isOffline = !window.navigator.onLine;
|
|
||||||
|
|
||||||
window.addEventListener('offline', () => {
|
|
||||||
this.store.isOffline = true;
|
|
||||||
|
|
||||||
this.store.apiData = {
|
|
||||||
stations: [],
|
|
||||||
dispatchers: [],
|
|
||||||
trains: [],
|
|
||||||
connectedSocketCount: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
this.store.setStatuses();
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener('online', () => {
|
|
||||||
this.store.isOffline = false;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
this.setReleaseURL();
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => this.store.blockScroll,
|
() => this.store.blockScroll,
|
||||||
(value) => {
|
(value) => {
|
||||||
@@ -100,18 +80,37 @@ export default defineComponent({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
|
||||||
'$route.query.region': {
|
|
||||||
immediate: true,
|
|
||||||
handler(regionQuery: string) {
|
|
||||||
if (regionQuery) {
|
|
||||||
this.store.region.id = regionQuery;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.loadLang();
|
||||||
|
this.setReleaseURL();
|
||||||
|
this.setupOfflineHandling();
|
||||||
|
|
||||||
|
this.apiStore.setupAPIData();
|
||||||
|
},
|
||||||
|
|
||||||
|
setupOfflineHandling() {
|
||||||
|
this.store.isOffline = !window.navigator.onLine;
|
||||||
|
|
||||||
|
if (this.store.isOffline) this.handleOfflineMode();
|
||||||
|
|
||||||
|
window.addEventListener('offline', this.handleOfflineMode);
|
||||||
|
window.addEventListener('online', this.handleOnlineMode);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleOfflineMode() {
|
||||||
|
this.store.isOffline = true;
|
||||||
|
|
||||||
|
this.apiStore.activeData = undefined;
|
||||||
|
this.apiStore.dataStatuses.connection = Status.Data.Offline;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleOnlineMode() {
|
||||||
|
this.store.isOffline = false;
|
||||||
|
|
||||||
|
this.apiStore.setupAPIData();
|
||||||
|
},
|
||||||
|
|
||||||
changeLang(lang: string) {
|
changeLang(lang: string) {
|
||||||
this.$i18n.locale = lang;
|
this.$i18n.locale = lang;
|
||||||
this.currentLang = lang;
|
this.currentLang = lang;
|
||||||
|
|||||||
@@ -39,9 +39,9 @@
|
|||||||
<img src="/images/icon-train.svg" alt="icon train" />
|
<img src="/images/icon-train.svg" alt="icon train" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="info_region">
|
<div class="info_region">
|
||||||
<SelectBox :itemList="computedRegions" :defaultItemIndex="0" @selected="changeRegion" />
|
<RegionDropdown />
|
||||||
</span>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="header_links">
|
<span class="header_links">
|
||||||
@@ -68,11 +68,10 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useStore } from '../../store/store';
|
import { useMainStore } from '../../store/mainStore';
|
||||||
import options from '../../data/options.json';
|
|
||||||
import SelectBox from '../Global/SelectBox.vue';
|
|
||||||
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';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
emits: ['changeLang'],
|
emits: ['changeLang'],
|
||||||
@@ -85,15 +84,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
return {
|
return {
|
||||||
store: useStore()
|
store: useMainStore()
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
changeRegion(region: { id: string; value: string }) {
|
|
||||||
this.store.changeRegion(region);
|
|
||||||
},
|
|
||||||
|
|
||||||
changeLang(lang: string) {
|
changeLang(lang: string) {
|
||||||
this.$emit('changeLang', lang);
|
this.$emit('changeLang', lang);
|
||||||
}
|
}
|
||||||
@@ -101,37 +96,22 @@ 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() {
|
||||||
return this.onlineDispatchersCount == 0
|
return this.onlineDispatchersCount == 0
|
||||||
? '-'
|
? '-'
|
||||||
: (this.onlineTrainsCount / this.onlineDispatchersCount).toFixed(2);
|
: (this.onlineTrainsCount / this.onlineDispatchersCount).toFixed(2);
|
||||||
},
|
|
||||||
|
|
||||||
computedRegions() {
|
|
||||||
return options.regions.map((region) => {
|
|
||||||
const regionStationCount =
|
|
||||||
this.store.apiData.stations?.filter(
|
|
||||||
(station) => station.region == region.id && station.isOnline
|
|
||||||
).length || 0;
|
|
||||||
const regionTrainCount =
|
|
||||||
this.store.apiData.trains?.filter((train) => train.region == region.id && train.online)
|
|
||||||
.length || 0;
|
|
||||||
return {
|
|
||||||
id: region.id,
|
|
||||||
value: `${region.value} <div class='text--grayed'>${regionStationCount} / ${regionTrainCount}</div>`,
|
|
||||||
selectedValue: region.value
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: { SelectBox, StatusIndicator, Clock }
|
components: { StatusIndicator, Clock, RegionDropdown }
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -227,23 +207,8 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// REGION SELECTION
|
|
||||||
.info_region {
|
.info_region {
|
||||||
color: white;
|
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|
||||||
.select-box_content button {
|
|
||||||
background-color: transparent;
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 0.1em 0.5em;
|
|
||||||
color: paleturquoise;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options {
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -36,11 +36,11 @@
|
|||||||
<circle id="Ellipse 18" cx="15" cy="17" r="7" fill="#393838" />
|
<circle id="Ellipse 18" cx="15" cy="17" r="7" fill="#393838" />
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<g v-if="greenLight" filter="url(#filter0_d_843_28)">
|
<g v-if="indicator.lights.greenLight" filter="url(#filter0_d_843_28)">
|
||||||
<circle cx="15" cy="17" r="7" fill="#00FF0A" />
|
<circle cx="15" cy="17" r="7" fill="#00FF0A" />
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<g v-if="greenBlinkLight" filter="url(#filter0_d_843_28)">
|
<g v-if="indicator.lights.greenBlinkLight" filter="url(#filter0_d_843_28)">
|
||||||
<circle cx="15" cy="17" r="7" fill="#00FF0A" />
|
<circle cx="15" cy="17" r="7" fill="#00FF0A" />
|
||||||
|
|
||||||
<animate
|
<animate
|
||||||
@@ -52,14 +52,14 @@
|
|||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<g v-if="redTopLight" filter="url(#filter1_d_843_28)">
|
<g v-if="indicator.lights.redTopLight" filter="url(#filter1_d_843_28)">
|
||||||
<circle cx="15" cy="36" r="7" fill="#F40000" />
|
<circle cx="15" cy="36" r="7" fill="#F40000" />
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<g v-if="orangeLight" filter="url(#filter2_d_843_28)">
|
<g v-if="indicator.lights.orangeLight" filter="url(#filter2_d_843_28)">
|
||||||
<circle cx="15" cy="55" r="7" fill="#FFB800" />
|
<circle cx="15" cy="55" r="7" fill="#FFB800" />
|
||||||
</g>
|
</g>
|
||||||
<g v-if="redBottomLight" filter="url(#filter3_d_843_28)">
|
<g v-if="indicator.lights.redBottomLight" filter="url(#filter3_d_843_28)">
|
||||||
<circle cx="15" cy="74" r="7" fill="#F40000" />
|
<circle cx="15" cy="74" r="7" fill="#F40000" />
|
||||||
|
|
||||||
<animate
|
<animate
|
||||||
@@ -186,7 +186,11 @@
|
|||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<transition name="tooltip-anim">
|
<transition name="tooltip-anim">
|
||||||
<div v-html="$t(indicator.message)" class="indicator-tooltip" v-if="tooltipActive"></div>
|
<div
|
||||||
|
v-html="$t('data-status.' + indicator.message)"
|
||||||
|
class="indicator-tooltip"
|
||||||
|
v-if="tooltipActive"
|
||||||
|
></div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -194,124 +198,112 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
import { Status } from '../../typings/common';
|
||||||
import { useStore } from '../../store/store';
|
import { useApiStore } from '../../store/apiStore';
|
||||||
import { StoreState } from '../../scripts/interfaces/store/storeTypes';
|
import { APIDataStatus } from '../../typings/api';
|
||||||
|
|
||||||
|
interface Indicator {
|
||||||
|
// status: Status.Data;
|
||||||
|
message: string;
|
||||||
|
|
||||||
|
lights: {
|
||||||
|
greenLight: boolean;
|
||||||
|
greenBlinkLight: boolean;
|
||||||
|
redTopLight: boolean;
|
||||||
|
orangeLight: boolean;
|
||||||
|
redBottomLight: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tooltipActive: false,
|
tooltipActive: false,
|
||||||
indicator: {
|
apiStore: useApiStore()
|
||||||
offline: false,
|
|
||||||
status: DataStatus.Loading,
|
|
||||||
message: 'data-status.S3'
|
|
||||||
},
|
|
||||||
|
|
||||||
greenLight: false,
|
|
||||||
greenBlinkLight: false,
|
|
||||||
redTopLight: false,
|
|
||||||
orangeLight: false,
|
|
||||||
redBottomLight: false
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.setSignalStatus(DataStatus.Loading);
|
|
||||||
},
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
return {
|
|
||||||
dataStatus: store.dataStatuses,
|
|
||||||
store
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
dataStatus: {
|
|
||||||
deep: true,
|
|
||||||
|
|
||||||
handler(statuses: StoreState['dataStatuses']) {
|
|
||||||
const connectionStatus = statuses.connection;
|
|
||||||
const sceneryDataStatus = statuses.sceneries;
|
|
||||||
const trainsDataStatus = statuses.trains;
|
|
||||||
const dispatcherDataStatus = statuses.dispatchers;
|
|
||||||
|
|
||||||
if (this.store.isOffline) {
|
|
||||||
this.setSignalStatus(DataStatus.Initialized);
|
|
||||||
this.indicator.status = DataStatus.Initialized;
|
|
||||||
this.indicator.message = 'data-status.S1-offline';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connectionStatus == DataStatus.Error) {
|
|
||||||
this.setSignalStatus(connectionStatus);
|
|
||||||
this.indicator.status = connectionStatus;
|
|
||||||
this.indicator.message = 'data-status.S1a-connection';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sceneryDataStatus == DataStatus.Error) {
|
|
||||||
this.setSignalStatus(sceneryDataStatus);
|
|
||||||
this.indicator.status = sceneryDataStatus;
|
|
||||||
this.indicator.message = 'data-status.S1a-sceneries';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trainsDataStatus == DataStatus.Warning) {
|
|
||||||
this.setSignalStatus(trainsDataStatus);
|
|
||||||
this.indicator.status = trainsDataStatus;
|
|
||||||
this.indicator.message = 'data-status.S5-trains';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dispatcherDataStatus == DataStatus.Warning) {
|
|
||||||
this.setSignalStatus(dispatcherDataStatus);
|
|
||||||
this.indicator.status = dispatcherDataStatus;
|
|
||||||
this.indicator.message = 'data-status.S5-dispatchers';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sceneryDataStatus == DataStatus.Loaded) {
|
|
||||||
this.setSignalStatus(DataStatus.Loaded);
|
|
||||||
|
|
||||||
this.indicator.status = DataStatus.Loaded;
|
|
||||||
this.indicator.message = 'data-status.S2';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
setSignalStatus(status: DataStatus) {
|
setLights(message: string) {
|
||||||
this.greenLight = false;
|
let lights = {
|
||||||
this.greenBlinkLight = false;
|
greenBlinkLight: false,
|
||||||
this.redTopLight = false;
|
greenLight: false,
|
||||||
this.orangeLight = false;
|
orangeLight: false,
|
||||||
this.redBottomLight = false;
|
redBottomLight: false,
|
||||||
|
redTopLight: false
|
||||||
|
};
|
||||||
|
|
||||||
if (status == DataStatus.Initialized) {
|
switch (message) {
|
||||||
this.redTopLight = true;
|
case 'S3':
|
||||||
|
lights.greenBlinkLight = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'S2':
|
||||||
|
lights.greenLight = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'S1-offline':
|
||||||
|
lights.redTopLight = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'S1a-connection':
|
||||||
|
case 'S1a-sceneries':
|
||||||
|
lights.redTopLight = true;
|
||||||
|
lights.redBottomLight = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'S5-dispatchers':
|
||||||
|
case 'S5-trains':
|
||||||
|
lights.orangeLight = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Loaded) {
|
return lights;
|
||||||
this.greenLight = true;
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
indicator(): Indicator {
|
||||||
|
const dataStatuses = this.apiStore.dataStatuses;
|
||||||
|
const swdrStatuses = this.apiStore.activeData?.apiStatuses;
|
||||||
|
|
||||||
|
let message = 'S3';
|
||||||
|
|
||||||
|
switch (dataStatuses.connection) {
|
||||||
|
case Status.Data.Loading:
|
||||||
|
message = 'S3';
|
||||||
|
break;
|
||||||
|
case Status.Data.Loaded:
|
||||||
|
message = 'S2';
|
||||||
|
break;
|
||||||
|
case Status.Data.Offline:
|
||||||
|
message = 'S1-offline';
|
||||||
|
break;
|
||||||
|
case Status.Data.Error:
|
||||||
|
message = 'S1a-connection';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Warning) {
|
if (swdrStatuses?.dispatchersAPI == APIDataStatus.WARNING) {
|
||||||
this.orangeLight = true;
|
message = 'S5-dispatchers';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Error) {
|
if (swdrStatuses?.trainsAPI == APIDataStatus.WARNING) {
|
||||||
this.redTopLight = true;
|
message = 'S5-trains';
|
||||||
this.redBottomLight = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == DataStatus.Loading) {
|
if (swdrStatuses?.stationsAPI == APIDataStatus.WARNING) {
|
||||||
this.greenBlinkLight = true;
|
message = 'S1a-sceneries';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
lights: this.setLights(message),
|
||||||
|
message
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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 { useMainStore } from '../../store/mainStore';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
emits: ['toggleModal'],
|
||||||
|
|
||||||
|
props: {
|
||||||
|
isOpen: Boolean
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
store: useMainStore()
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
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,201 @@
|
|||||||
|
<template>
|
||||||
|
<div class="donation-modal" @keydown.esc="toggleModal(false)">
|
||||||
|
<button
|
||||||
|
class="btn-toggle 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 class="discord" 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">
|
||||||
|
<a
|
||||||
|
class="modal-action a-button btn--image coffee"
|
||||||
|
href="https://buycoffee.to/spythere"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<img src="/images/icon-coffee.png" width="20" alt="buycoffee.to donation" />
|
||||||
|
{{ $t('donations.action-buycoffee') }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
class="modal-action a-button btn--image paypal"
|
||||||
|
href="https://www.paypal.com/donate/?hosted_button_id=EDB3SKFAHXFTW"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<img src="/images/icon-dollar.svg" alt="paypal donation" />
|
||||||
|
{{ $t('donations.action-paypal') }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<button class="modal-action btn--image exit" @click="toggleModal(false)">
|
||||||
|
<img src="/images/icon-exit.svg" alt="dollar donation icon" />
|
||||||
|
{{ $t('donations.action-exit') }}
|
||||||
|
</button>
|
||||||
|
</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';
|
||||||
|
|
||||||
|
button.btn-toggle {
|
||||||
|
$btnColor: #254069;
|
||||||
|
|
||||||
|
background-color: $btnColor;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($btnColor, 5%);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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.discord {
|
||||||
|
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(220px, 1fr));
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
form button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal_actions > .modal-action {
|
||||||
|
&.paypal {
|
||||||
|
$btnColor: #254069;
|
||||||
|
|
||||||
|
background-color: $btnColor;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($btnColor, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.coffee {
|
||||||
|
$btnColor: #009255;
|
||||||
|
background-color: $btnColor;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($btnColor, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.exit {
|
||||||
|
$btnColor: #686868;
|
||||||
|
background-color: $btnColor;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: lighten($btnColor, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
<template>
|
||||||
|
<div class="region-dropdown" v-click-outside="clickedOutside">
|
||||||
|
<div class="content">
|
||||||
|
<button class="selected-region" @click="toggleBox">
|
||||||
|
<span>{{ selectedItem.name }}</span>
|
||||||
|
|
||||||
|
<img :src="`/images/icon-arrow-${listOpen ? 'asc' : 'desc'}.svg`" alt="Arrow icon" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<ul class="options">
|
||||||
|
<li class="option" v-for="(item, i) in regionList" :key="item.id">
|
||||||
|
<transition
|
||||||
|
name="unfold"
|
||||||
|
:style="`
|
||||||
|
--delay-in: ${i * 55}ms;
|
||||||
|
--delay-out: ${(regionList.length - 1 - i) * 55}ms`"
|
||||||
|
>
|
||||||
|
<label :for="item.id" v-if="listOpen">
|
||||||
|
<input type="button" :id="item.id" name="select-box" @click="selectOption(item)" />
|
||||||
|
<span :style="selectedItem.id == item.id ? 'color: gold;' : ''" v-html="item.value">
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</transition>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, Ref, ref } from 'vue';
|
||||||
|
import { regions as regionsJSON } from '../../data/options.json';
|
||||||
|
import { useMainStore } from '../../store/mainStore';
|
||||||
|
|
||||||
|
interface Item {
|
||||||
|
id: string;
|
||||||
|
value: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
store: useMainStore(),
|
||||||
|
selectedItemIndex: 0,
|
||||||
|
listOpen: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
let buttonRef: Ref<HTMLButtonElement | null> = ref(null);
|
||||||
|
|
||||||
|
return {
|
||||||
|
buttonRef
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
'store.region.id': {
|
||||||
|
handler(regionId) {
|
||||||
|
this.selectedItemIndex = this.regionList.findIndex((reg) => reg.id == regionId);
|
||||||
|
|
||||||
|
console.log('region id', regionId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'$route.query.region': {
|
||||||
|
immediate: true,
|
||||||
|
handler(regionQuery: string) {
|
||||||
|
if (regionQuery) {
|
||||||
|
this.store.region.id =
|
||||||
|
regionsJSON.find(
|
||||||
|
(reg) =>
|
||||||
|
reg.id == regionQuery.toLocaleLowerCase() ||
|
||||||
|
reg.value.toLocaleLowerCase() == regionQuery.toLocaleLowerCase()
|
||||||
|
)?.id || 'eu';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
selectedItem() {
|
||||||
|
return this.regionList[this.selectedItemIndex] || null;
|
||||||
|
},
|
||||||
|
|
||||||
|
regionList() {
|
||||||
|
return regionsJSON.map((region) => {
|
||||||
|
const regionStationCount = this.store.onlineSceneryList.filter(
|
||||||
|
(scenery) => scenery.region == region.id
|
||||||
|
).length;
|
||||||
|
|
||||||
|
const regionTrainCount =
|
||||||
|
this.store.trainList.filter((train) => train.region == region.id).length || 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: region.id,
|
||||||
|
value: `${region.value} <div class='text--grayed'>${regionStationCount} / ${regionTrainCount}</div>`,
|
||||||
|
name: region.name
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
selectOption(selectedRegion: Item) {
|
||||||
|
this.store.region = selectedRegion;
|
||||||
|
this.listOpen = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleBox(e: Event) {
|
||||||
|
this.listOpen = !this.listOpen;
|
||||||
|
|
||||||
|
if (!this.listOpen) (e.target as HTMLButtonElement).blur();
|
||||||
|
},
|
||||||
|
|
||||||
|
clickedOutside() {
|
||||||
|
this.listOpen = false;
|
||||||
|
this.buttonRef?.blur();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/variables.scss';
|
||||||
|
|
||||||
|
.region-dropdown {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
button img {
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 1.35em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.selected-region {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: paleturquoise;
|
||||||
|
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0.1em 0.5em;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background-color: #262626;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: relative;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.options {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
z-index: 100;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.option {
|
||||||
|
input {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
background: none;
|
||||||
|
|
||||||
|
&:focus + span {
|
||||||
|
color: $accentCol;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child label {
|
||||||
|
border-radius: 0 0 1em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #262626f2;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background-color: #333333f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
padding: 0.5em 0;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unfold {
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px) scale(0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: all 110ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-active {
|
||||||
|
transition-delay: var(--delay-in);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-leave-active {
|
||||||
|
transition-delay: var(--delay-out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="select-box">
|
|
||||||
<div class="select-box_content">
|
|
||||||
<button class="selected" @click="toggleBox">
|
|
||||||
<span>{{ computedSelectedItem.selectedValue || computedSelectedItem.value }}</span>
|
|
||||||
|
|
||||||
<div class="arrow">
|
|
||||||
<img :src="`/images/icon-arrow-${listOpen ? 'asc' : 'desc'}.svg`" alt="Arrow icon" />
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<ul class="options" :ref="(el) => (listRef = el as Element)">
|
|
||||||
<li class="option" v-for="(item, i) in itemList" :key="item.id">
|
|
||||||
<transition
|
|
||||||
name="unfold"
|
|
||||||
:style="`
|
|
||||||
--delay-in: ${i * 55}ms;
|
|
||||||
--delay-out: ${(itemList.length - 1 - i) * 55}ms`"
|
|
||||||
>
|
|
||||||
<label :for="item.id" v-if="listOpen">
|
|
||||||
<input type="button" :id="item.id" name="select-box" @click="selectOption(item)" />
|
|
||||||
<span
|
|
||||||
:style="computedSelectedItem.id == item.id ? 'color: gold;' : ''"
|
|
||||||
v-html="item.value"
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
</transition>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, Ref, ref, computed } from 'vue';
|
|
||||||
|
|
||||||
interface Item {
|
|
||||||
id: string;
|
|
||||||
value: string;
|
|
||||||
selectedValue?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
emits: ['selected'],
|
|
||||||
|
|
||||||
props: {
|
|
||||||
itemList: {
|
|
||||||
type: Array as () => Item[],
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
|
|
||||||
defaultItemIndex: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
|
|
||||||
prefix: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setup(props) {
|
|
||||||
let listRef: Ref<Element | null> = ref(null);
|
|
||||||
let buttonRef: Ref<HTMLButtonElement | null> = ref(null);
|
|
||||||
|
|
||||||
let activeEl: Ref<Element | null> = ref(document.activeElement);
|
|
||||||
|
|
||||||
let listOpen = ref(false);
|
|
||||||
let selectedItem: Ref<Item> = ref(props.itemList[props.defaultItemIndex]);
|
|
||||||
|
|
||||||
const computedSelectedItem = computed(() => {
|
|
||||||
return (
|
|
||||||
props.itemList.find((item) => item.id === selectedItem.value.id) ||
|
|
||||||
props.itemList[props.defaultItemIndex]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
computedSelectedItem,
|
|
||||||
listOpen,
|
|
||||||
selectedItem,
|
|
||||||
listRef,
|
|
||||||
buttonRef,
|
|
||||||
activeEl
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
'$route.query': {
|
|
||||||
immediate: true,
|
|
||||||
handler(newVal) {
|
|
||||||
if (newVal.region) {
|
|
||||||
const item = this.itemList.find((it) => it.id == newVal.region);
|
|
||||||
|
|
||||||
if (item) this.selectedItem = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
selectOption(item: Item) {
|
|
||||||
this.selectedItem = item;
|
|
||||||
this.listOpen = false;
|
|
||||||
|
|
||||||
this.$emit('selected', item);
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleBox(e: Event) {
|
|
||||||
this.listOpen = !this.listOpen;
|
|
||||||
|
|
||||||
if (!this.listOpen) (e.target as HTMLButtonElement).blur();
|
|
||||||
},
|
|
||||||
|
|
||||||
clickedOutside() {
|
|
||||||
this.listOpen = false;
|
|
||||||
this.buttonRef?.blur();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '../../styles/variables.scss';
|
|
||||||
|
|
||||||
.unfold {
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10px) scale(0.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: all 110ms ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-active {
|
|
||||||
transition-delay: var(--delay-in);
|
|
||||||
}
|
|
||||||
|
|
||||||
&-leave-active {
|
|
||||||
transition-delay: var(--delay-out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-box {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow {
|
|
||||||
img {
|
|
||||||
vertical-align: middle;
|
|
||||||
width: 1.35em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button.selected {
|
|
||||||
color: paleturquoise;
|
|
||||||
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 0.1em 0.5em;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
background-color: #262626;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-box_content {
|
|
||||||
position: relative;
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.options {
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
height: auto;
|
|
||||||
|
|
||||||
z-index: 100;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.option {
|
|
||||||
input {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
-webkit-appearance: none;
|
|
||||||
-moz-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
background: none;
|
|
||||||
|
|
||||||
&:focus + span {
|
|
||||||
color: $accentCol;
|
|
||||||
font-weight: 800;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child label {
|
|
||||||
border-radius: 0 0 1em 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: inline-block;
|
|
||||||
background-color: #262626f2;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
background-color: #333333f2;
|
|
||||||
}
|
|
||||||
|
|
||||||
padding: 0.5em 0;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -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 { API } from '../../typings/api';
|
||||||
import { RollingStockInfo } from '../../scripts/interfaces/github_api/StockInfoGithubData';
|
import { useApiStore } from '../../store/apiStore';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -63,15 +63,15 @@ export default defineComponent({
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
store: useStore()
|
apiStore: useApiStore()
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
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.apiStore.rollingStockData!.info).find((type) => {
|
||||||
return this.store.rollingStockData!.info[type as keyof RollingStockInfo].find(
|
return this.apiStore.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';
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
<template>
|
|
||||||
<span class="stop-date">
|
|
||||||
<span
|
|
||||||
class="date arrival"
|
|
||||||
v-if="!stop.beginsHere"
|
|
||||||
:class="{
|
|
||||||
delayed: stop.arrivalDelay > 0 && (stop.confirmed || stop.stopped),
|
|
||||||
preponed: stop.arrivalDelay < 0 && (stop.confirmed || stop.stopped),
|
|
||||||
'on-time': stop.arrivalDelay == 0 && stop.confirmed
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<span v-if="stop.arrivalDelay != 0 && (stop.confirmed || stop.stopped)">
|
|
||||||
<s>{{ timestampToString(stop.arrivalTimestamp) }}</s>
|
|
||||||
{{ timestampToString(stop.arrivalRealTimestamp) }}
|
|
||||||
({{ stop.arrivalDelay > 0 ? '+' : '' }}{{ stop.arrivalDelay }})
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-else>
|
|
||||||
{{ timestampToString(stop.arrivalTimestamp) }}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
class="date stop"
|
|
||||||
v-if="stop.stopTime || stop.stopped"
|
|
||||||
:class="stop.stopType.replace(', ', '-')"
|
|
||||||
>
|
|
||||||
{{ stop.stopTime }} {{ stop.stopType == '' ? 'pt' : stop.stopType }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
class="date departure"
|
|
||||||
v-if="!stop.terminatesHere && (stop.stopTime != 0 || stop.stopped)"
|
|
||||||
:class="{
|
|
||||||
delayed: stop.departureDelay > 0 && stop.confirmed,
|
|
||||||
preponed: stop.departureDelay < 0 && stop.confirmed
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<span v-if="stop.departureDelay != 0 && stop.confirmed">
|
|
||||||
<s>{{ timestampToString(stop.departureTimestamp) }}</s>
|
|
||||||
{{ timestampToString(stop.departureRealTimestamp) }}
|
|
||||||
|
|
||||||
({{ stop.departureDelay > 0 ? '+' : '' }}{{ stop.departureDelay }})
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-else>
|
|
||||||
{{ timestampToString(stop.departureTimestamp) }}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import dateMixin from '../../mixins/dateMixin';
|
|
||||||
import TrainStop from '../../scripts/interfaces/TrainStop';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
mixins: [dateMixin],
|
|
||||||
|
|
||||||
props: {
|
|
||||||
stop: {
|
|
||||||
type: Object as () => TrainStop,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
$preponedClr: lime;
|
|
||||||
$delayedClr: salmon;
|
|
||||||
$dateClr: #525151;
|
|
||||||
$stopExchangeClr: #db8e29;
|
|
||||||
$stopDefaultClr: #252525;
|
|
||||||
|
|
||||||
.stop-date {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.date {
|
|
||||||
background: $dateClr;
|
|
||||||
padding: 0.3em 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stop {
|
|
||||||
&.ph,
|
|
||||||
&.ph-pm,
|
|
||||||
&.pm {
|
|
||||||
background: $stopExchangeClr;
|
|
||||||
}
|
|
||||||
|
|
||||||
background: $stopDefaultClr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrival,
|
|
||||||
.departure {
|
|
||||||
&.delayed {
|
|
||||||
s {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: $delayedClr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.preponed {
|
|
||||||
s {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: $preponedClr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useStore } from '../../store/store';
|
import { API } from '../../typings/api';
|
||||||
import { RollingStockInfo } from '../../scripts/interfaces/github_api/StockInfoGithubData';
|
import { useApiStore } from '../../store/apiStore';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -34,7 +34,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
store: useStore(),
|
apiStore: useApiStore(),
|
||||||
isNotFound: false,
|
isNotFound: false,
|
||||||
isLoaded: false
|
isLoaded: false
|
||||||
};
|
};
|
||||||
@@ -50,11 +50,11 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
stockType() {
|
stockType() {
|
||||||
if (!this.store.rollingStockData) return 'vehicle-unknown';
|
if (!this.apiStore.rollingStockData) return 'vehicle-unknown';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
Object.keys(this.store.rollingStockData.info).find((type) => {
|
Object.keys(this.apiStore.rollingStockData.info).find((type) => {
|
||||||
return this.store.rollingStockData?.info[type as keyof RollingStockInfo].find(
|
return this.apiStore.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,250 +0,0 @@
|
|||||||
<template>
|
|
||||||
<section class="daily-stats">
|
|
||||||
<span :data-active="statsStatus">
|
|
||||||
<b v-if="statsStatus == DataStatus.Loading">
|
|
||||||
{{ $t('app.loading') }}
|
|
||||||
</b>
|
|
||||||
|
|
||||||
<b v-else-if="stats.distanceSum == null">
|
|
||||||
{{ $t('journal.daily-stats-info') }}
|
|
||||||
</b>
|
|
||||||
|
|
||||||
<span class="stats-list" v-else>
|
|
||||||
<h3>
|
|
||||||
{{ $t('journal.daily-stats-title') }}
|
|
||||||
<b class="text--primary">{{ new Date().toLocaleDateString($i18n.locale) }}</b>
|
|
||||||
</h3>
|
|
||||||
<hr style="margin-bottom: 0.5em" />
|
|
||||||
|
|
||||||
<div v-if="stats.totalTimetables">
|
|
||||||
•
|
|
||||||
<i18n-t keypath="journal.timetable-stats-total">
|
|
||||||
<template #count>
|
|
||||||
<b class="text--primary">
|
|
||||||
{{ stats.totalTimetables }}
|
|
||||||
{{ $t('journal.timetable-count', stats.totalTimetables) }}
|
|
||||||
</b>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #distance>
|
|
||||||
<b class="text--primary"> {{ stats.distanceSum?.toFixed(2) }} km</b>
|
|
||||||
</template>
|
|
||||||
</i18n-t>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="stats.timetableId">
|
|
||||||
•
|
|
||||||
<i18n-t keypath="journal.timetable-stats-longest">
|
|
||||||
<template #id>
|
|
||||||
<router-link :to="`/journal/timetables?timetableId=${stats.timetableId}`">
|
|
||||||
<b>{{ stats.timetableId }}</b>
|
|
||||||
</router-link>
|
|
||||||
</template>
|
|
||||||
<template #author>
|
|
||||||
<router-link :to="`/journal/dispatchers?dispatcherName=${stats.timetableAuthor}`">
|
|
||||||
<b>{{ stats.timetableAuthor }}</b>
|
|
||||||
</router-link>
|
|
||||||
</template>
|
|
||||||
<template #driver>
|
|
||||||
<b class="text--primary">{{ stats.timetableDriver }}</b>
|
|
||||||
</template>
|
|
||||||
<template #distance>
|
|
||||||
<b class="text--primary">{{ stats.timetableRouteDistance }} km</b>
|
|
||||||
</template>
|
|
||||||
</i18n-t>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="topDispatchers.length == 1">
|
|
||||||
•
|
|
||||||
<i18n-t keypath="journal.timetable-stats-most-active-dr">
|
|
||||||
<template #dispatcher>
|
|
||||||
<router-link :to="`/journal/dispatchers?dispatcherName=${topDispatchers[0].name}`">
|
|
||||||
<b>{{ topDispatchers[0].name }}</b>
|
|
||||||
</router-link>
|
|
||||||
</template>
|
|
||||||
<template #count>
|
|
||||||
<b class="text--primary">
|
|
||||||
{{ topDispatchers[0].count }}
|
|
||||||
{{ $t('journal.timetable-count', topDispatchers[0].count) }}
|
|
||||||
</b>
|
|
||||||
</template>
|
|
||||||
</i18n-t>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="topDispatchers.length > 1">
|
|
||||||
•
|
|
||||||
<i18n-t keypath="journal.timetable-stats-most-active-dr-many">
|
|
||||||
<template #dispatchers>
|
|
||||||
<span v-for="(disp, i) in topDispatchers" :key="i">
|
|
||||||
<span v-if="i == topDispatchers.length - 1"> {{ $t('general.and') }} </span>
|
|
||||||
|
|
||||||
<router-link :to="`/journal/dispatchers?dispatcherName=${disp.name}`">
|
|
||||||
<b>{{ disp.name }}</b>
|
|
||||||
</router-link>
|
|
||||||
|
|
||||||
<span v-if="i < topDispatchers.length - 2">, </span>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #count>
|
|
||||||
<b class="text--primary">
|
|
||||||
{{ topDispatchers[0].count }}
|
|
||||||
{{ $t('journal.timetable-count', topDispatchers[0].count) }}
|
|
||||||
</b>
|
|
||||||
</template>
|
|
||||||
</i18n-t>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="stats.longestDuties.length > 0">
|
|
||||||
•
|
|
||||||
<i18n-t keypath="journal.timetable-stats-longest-duties">
|
|
||||||
<template #dispatcher>
|
|
||||||
<router-link
|
|
||||||
:to="`/journal/dispatchers?dispatcherName=${stats.longestDuties[0].name}`"
|
|
||||||
>
|
|
||||||
<b>{{ stats.longestDuties[0].name }}</b>
|
|
||||||
</router-link>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #station>{{ stats.longestDuties[0].station }}</template>
|
|
||||||
|
|
||||||
<template #duration>
|
|
||||||
{{ calculateDuration(stats.longestDuties[0].duration) }}
|
|
||||||
</template>
|
|
||||||
</i18n-t>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="stats.mostActiveDrivers.length > 0">
|
|
||||||
•
|
|
||||||
<i18n-t keypath="journal.timetable-stats-most-active-driver">
|
|
||||||
<template #driver>
|
|
||||||
<b class="text--primary">{{ stats.mostActiveDrivers[0].name }}</b>
|
|
||||||
</template>
|
|
||||||
<template #distance>
|
|
||||||
<b class="text--primary">{{ stats.mostActiveDrivers[0].distance.toFixed(2) }} km</b>
|
|
||||||
</template>
|
|
||||||
</i18n-t>
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import axios from 'axios';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
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';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
mixins: [dateMixin],
|
|
||||||
emits: ['toggleStatsOpen'],
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
DataStatus,
|
|
||||||
statsStatus: DataStatus.Loading,
|
|
||||||
intervalId: -1,
|
|
||||||
|
|
||||||
stats: {
|
|
||||||
totalTimetables: 0,
|
|
||||||
distanceSum: 0,
|
|
||||||
distanceAvg: 0,
|
|
||||||
timetableAuthor: '',
|
|
||||||
timetableDriver: '',
|
|
||||||
timetableId: 0,
|
|
||||||
timetableRouteDistance: 0,
|
|
||||||
longestDuties: [],
|
|
||||||
mostActiveDrivers: [],
|
|
||||||
mostActiveDispatchers: []
|
|
||||||
} as ITimetablesDailyStats
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
activated() {
|
|
||||||
this.startFetchingDailyStats();
|
|
||||||
this.$emit('toggleStatsOpen', true);
|
|
||||||
},
|
|
||||||
|
|
||||||
deactivated() {
|
|
||||||
this.stopFetchingDailyStats();
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
topDispatchers() {
|
|
||||||
if (this.stats.mostActiveDispatchers.length == 0) return [];
|
|
||||||
const maxCount = this.stats.mostActiveDispatchers[0].count;
|
|
||||||
|
|
||||||
return this.stats.mostActiveDispatchers.filter((disp) => disp.count === maxCount);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
async fetchDailyTimetableStats() {
|
|
||||||
try {
|
|
||||||
const res: ITimetablesDailyStatsResponse = await (
|
|
||||||
await axios.get(`${URLs.stacjownikAPI}/api/getDailyTimetableStats`)
|
|
||||||
).data;
|
|
||||||
|
|
||||||
this.stats = {
|
|
||||||
totalTimetables: res.totalTimetables,
|
|
||||||
distanceSum: res.distanceSum,
|
|
||||||
distanceAvg: res.distanceAvg,
|
|
||||||
timetableAuthor: res.maxTimetable?.authorName || '',
|
|
||||||
timetableDriver: res.maxTimetable?.driverName || '',
|
|
||||||
timetableId: res.maxTimetable?.id || 0,
|
|
||||||
timetableRouteDistance: res.maxTimetable?.routeDistance || 0,
|
|
||||||
|
|
||||||
mostActiveDispatchers: res.mostActiveDispatchers,
|
|
||||||
mostActiveDrivers: res.mostActiveDrivers,
|
|
||||||
longestDuties: res.longestDuties
|
|
||||||
};
|
|
||||||
|
|
||||||
this.statsStatus = DataStatus.Loaded;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Ups! Wystąpił błąd podczas pobierania statystyk rozkładów jazdy...');
|
|
||||||
this.statsStatus = DataStatus.Error;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
startFetchingDailyStats() {
|
|
||||||
this.fetchDailyTimetableStats();
|
|
||||||
|
|
||||||
if (this.intervalId != -1) return;
|
|
||||||
|
|
||||||
this.intervalId = setInterval(this.fetchDailyTimetableStats, 60000);
|
|
||||||
},
|
|
||||||
|
|
||||||
stopFetchingDailyStats() {
|
|
||||||
clearInterval(this.intervalId);
|
|
||||||
this.intervalId = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '../../styles/responsive.scss';
|
|
||||||
|
|
||||||
.daily-stats {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.daily-stats > span[data-active='0'] {
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stats-list a {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include smallScreen {
|
|
||||||
h3 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="stats_container" v-click-outside="() => (cardVisible = false)">
|
|
||||||
<button class="stats_button" @click="toggleCard">
|
|
||||||
Statystyki dyżurnego {{ store.dispatcherStatsName }}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="stats_card" v-if="store.dispatcherStatsName && cardVisible">
|
|
||||||
<div>
|
|
||||||
<Loading v-if="!store.dispatcherStatsData" />
|
|
||||||
|
|
||||||
<div class="loading" v-else-if="!store.dispatcherStatsData._count._all">
|
|
||||||
Ten dyżurny nie ma jeszcze szczegółowych statystyk!
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else>
|
|
||||||
<h3>STATYSTYKI WYSTAWIONYCH ROZKŁADÓW</h3>
|
|
||||||
|
|
||||||
<div class="info-stats" v-if="store.dispatcherStatsData._count._all">
|
|
||||||
<span class="stat-badge">
|
|
||||||
<span>LICZBA</span>
|
|
||||||
<span>{{ store.dispatcherStatsData._count._all }}</span>
|
|
||||||
</span>
|
|
||||||
<span class="stat-badge">
|
|
||||||
<span>SUMA (KM)</span>
|
|
||||||
<span>{{ store.dispatcherStatsData._sum.routeDistance.toFixed(2) }}km</span>
|
|
||||||
</span>
|
|
||||||
<span class="stat-badge">
|
|
||||||
<span>NAJDŁUŻSZY</span>
|
|
||||||
<span>{{ store.dispatcherStatsData._max.routeDistance.toFixed(2) }}km</span>
|
|
||||||
</span>
|
|
||||||
<span class="stat-badge">
|
|
||||||
<span>ŚREDNIO</span>
|
|
||||||
<span>{{ store.dispatcherStatsData._avg.routeDistance.toFixed(2) }}km</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>OSTATNIE WYSTAWIONE ROZKŁADY</h3>
|
|
||||||
<div class="last-timetables">
|
|
||||||
<div class="timetable-row" v-for="timetable in timetables" :key="timetable.id">
|
|
||||||
#{{ timetable.timetableId }} |
|
|
||||||
<b>{{ timetable.trainCategoryCode }} {{ timetable.trainNo }}</b> |
|
|
||||||
{{ timetable.driverName }} ({{ timetable.routeDistance }}km)
|
|
||||||
<div>{{ timetable.route.replace('|', ' > ') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import axios from 'axios';
|
|
||||||
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 { useStore } from '../../store/store';
|
|
||||||
import Loading from '../Global/Loading.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: { Loading },
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
return {
|
|
||||||
store
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
cardVisible: false,
|
|
||||||
lastDispatcherName: '',
|
|
||||||
timetables: [] as TimetableHistory[]
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
toggleCard() {
|
|
||||||
if (!this.store.dispatcherStatsName) return;
|
|
||||||
|
|
||||||
this.cardVisible = !this.cardVisible;
|
|
||||||
if (this.cardVisible) this.fetchDispatcherStats();
|
|
||||||
},
|
|
||||||
|
|
||||||
async fetchDispatcherStats() {
|
|
||||||
if (this.lastDispatcherName != this.store.dispatcherStatsName) {
|
|
||||||
this.store.dispatcherStatsData = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const statsData: DispatcherStatsAPIData = await (
|
|
||||||
await axios.get(
|
|
||||||
`${URLs.stacjownikAPI}/api/getDispatcherInfo?name=${this.store.dispatcherStatsName}`
|
|
||||||
)
|
|
||||||
).data;
|
|
||||||
|
|
||||||
const timetables: TimetableHistory[] = await (
|
|
||||||
await axios.get(
|
|
||||||
`${URLs.stacjownikAPI}/api/getTimetables?authorName=${this.store.dispatcherStatsName}`
|
|
||||||
)
|
|
||||||
).data;
|
|
||||||
|
|
||||||
this.timetables = timetables;
|
|
||||||
this.store.dispatcherStatsData = statsData;
|
|
||||||
this.lastDispatcherName = this.store.dispatcherStatsName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '../../styles/responsive.scss';
|
|
||||||
@import '../../styles/variables.scss';
|
|
||||||
|
|
||||||
.stats_container {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stats_card {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 999;
|
|
||||||
top: 120%;
|
|
||||||
right: 0;
|
|
||||||
width: 500px;
|
|
||||||
max-width: 97vw;
|
|
||||||
min-height: 100px;
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
border-radius: 1em 0 1em 1em;
|
|
||||||
background-color: #222222f1;
|
|
||||||
box-shadow: 0 3px 10px 5px #131313;
|
|
||||||
padding: 1em 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.last-timetables {
|
|
||||||
max-height: 400px;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timetable-row {
|
|
||||||
width: 95%;
|
|
||||||
margin: 0.5em auto;
|
|
||||||
padding: 0.5em;
|
|
||||||
|
|
||||||
background-color: #4d4d4d;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2.card-title {
|
|
||||||
font-size: 1.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2,
|
|
||||||
h3 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.last-timetables {
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
<template>
|
||||||
|
<section class="daily-stats">
|
||||||
|
<span :data-active="statsStatus">
|
||||||
|
<span class="stats-list">
|
||||||
|
<h3>
|
||||||
|
{{ $t('journal.daily-stats.title') }}
|
||||||
|
<b class="text--primary">{{ new Date().toLocaleDateString($i18n.locale) }}</b>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<hr class="header-separator" />
|
||||||
|
|
||||||
|
<b v-if="statsStatus == Status.Data.Loading">
|
||||||
|
{{ $t('app.loading') }}
|
||||||
|
</b>
|
||||||
|
|
||||||
|
<b class="text--error" v-else-if="statsStatus == Status.Data.Error">
|
||||||
|
{{ $t('journal.stats-error') }}
|
||||||
|
</b>
|
||||||
|
|
||||||
|
<b v-else-if="topDispatchers.length == 0">
|
||||||
|
{{ $t('journal.daily-stats.info') }}
|
||||||
|
</b>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<div v-if="stats.totalTimetables">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.daily-stats.total">
|
||||||
|
<template #count>
|
||||||
|
<b class="text--primary">
|
||||||
|
{{ stats.totalTimetables }}
|
||||||
|
{{ $t('journal.daily-stats.count', stats.totalTimetables) }}
|
||||||
|
</b>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #distance>
|
||||||
|
<b class="text--primary"> {{ stats.distanceSum?.toFixed(2) }} km</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="stats.maxTimetable">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.daily-stats.longest">
|
||||||
|
<template #id>
|
||||||
|
<router-link :to="`/journal/timetables?search-train=%23${stats.maxTimetable.id}`">
|
||||||
|
<b>{{ stats.maxTimetable.id }}</b>
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
<template #author>
|
||||||
|
<router-link
|
||||||
|
:to="`/journal/timetables?search-dispatcher=${stats.maxTimetable.authorName}`"
|
||||||
|
>
|
||||||
|
<b>{{ stats.maxTimetable.authorName }}</b>
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
<template #driver>
|
||||||
|
<b class="text--primary">{{ stats.maxTimetable.driverName }}</b>
|
||||||
|
</template>
|
||||||
|
<template #distance>
|
||||||
|
<b class="text--primary">{{ stats.maxTimetable.routeDistance }} km</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="topDispatchers.length == 1">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.daily-stats.most-active-dr">
|
||||||
|
<template #dispatcher>
|
||||||
|
<router-link
|
||||||
|
:to="`/journal/dispatchers?search-dispatcher=${topDispatchers[0].name}`"
|
||||||
|
>
|
||||||
|
<b>{{ topDispatchers[0].name }}</b>
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
<template #count>
|
||||||
|
<b class="text--primary">
|
||||||
|
{{ topDispatchers[0].count }}
|
||||||
|
{{ $t('journal.daily-stats.count', topDispatchers[0].count) }}
|
||||||
|
</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="topDispatchers.length > 1">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.daily-stats.most-active-dr-many">
|
||||||
|
<template #dispatchers>
|
||||||
|
<span v-for="(disp, i) in topDispatchers" :key="i">
|
||||||
|
<span v-if="i == topDispatchers.length - 1"> {{ $t('general.and') }} </span>
|
||||||
|
|
||||||
|
<router-link :to="`/journal/dispatchers?search-dispatcher=${disp.name}`">
|
||||||
|
<b>{{ disp.name }}</b>
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<span v-if="i < topDispatchers.length - 2">, </span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #count>
|
||||||
|
<b class="text--primary">
|
||||||
|
{{ topDispatchers[0].count }}
|
||||||
|
{{ $t('journal.daily-stats.count', topDispatchers[0].count) }}
|
||||||
|
</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="stats.longestDuties.length > 0">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.daily-stats.longest-duties">
|
||||||
|
<template #dispatcher>
|
||||||
|
<router-link
|
||||||
|
:to="`/journal/dispatchers?search-dispatcher=${stats.longestDuties[0].name}`"
|
||||||
|
>
|
||||||
|
<b>{{ stats.longestDuties[0].name }}</b>
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #station>{{ stats.longestDuties[0].station }}</template>
|
||||||
|
|
||||||
|
<template #duration>
|
||||||
|
{{ calculateDuration(stats.longestDuties[0].duration) }}
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="stats.mostActiveDrivers.length > 0">
|
||||||
|
•
|
||||||
|
<i18n-t keypath="journal.daily-stats.most-active-driver">
|
||||||
|
<template #driver>
|
||||||
|
<router-link
|
||||||
|
:to="`/journal/timetables?search-driver=${stats.mostActiveDrivers[0].name}`"
|
||||||
|
>
|
||||||
|
<b>{{ stats.mostActiveDrivers[0].name }}</b>
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
<template #distance>
|
||||||
|
<b class="text--primary">{{ stats.mostActiveDrivers[0].distance.toFixed(2) }} km</b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="section-separator" />
|
||||||
|
|
||||||
|
<div class="stats-badges">
|
||||||
|
<span
|
||||||
|
class="stat-badge"
|
||||||
|
v-for="key in [
|
||||||
|
'rippedSwitches',
|
||||||
|
'derailments',
|
||||||
|
'skippedStopSignals',
|
||||||
|
'radioStops',
|
||||||
|
'kills'
|
||||||
|
]"
|
||||||
|
:key="key"
|
||||||
|
>
|
||||||
|
<span>{{ $t(`journal.daily-stats.${key}`) }}</span>
|
||||||
|
<span>{{
|
||||||
|
Object.entries(stats.globalDiff).find(([k, v]) => k == key)?.[1] || '--'
|
||||||
|
}}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
|
|
||||||
|
import { API } from '../../typings/api';
|
||||||
|
import { Status } from '../../typings/common';
|
||||||
|
import http from '../../http';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'journal-daily-stats',
|
||||||
|
|
||||||
|
mixins: [dateMixin],
|
||||||
|
// emits: ['toggleStatsOpen'],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
Status,
|
||||||
|
statsStatus: Status.Data.Loading,
|
||||||
|
intervalId: -1,
|
||||||
|
|
||||||
|
stats: {} as API.DailyStats.Response
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
activated() {
|
||||||
|
this.startFetchingDailyStats();
|
||||||
|
// this.$emit('toggleStatsOpen', true);
|
||||||
|
},
|
||||||
|
|
||||||
|
deactivated() {
|
||||||
|
this.stopFetchingDailyStats();
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
topDispatchers() {
|
||||||
|
if (this.stats.mostActiveDispatchers.length == 0) return [];
|
||||||
|
const maxCount = this.stats.mostActiveDispatchers[0].count;
|
||||||
|
|
||||||
|
return this.stats.mostActiveDispatchers.filter((disp) => disp.count === maxCount);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async fetchDailyTimetableStats() {
|
||||||
|
try {
|
||||||
|
const res: API.DailyStats.Response = await (await http.get('api/getDailyStats')).data;
|
||||||
|
|
||||||
|
this.stats = res;
|
||||||
|
|
||||||
|
this.statsStatus = Status.Data.Loaded;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ups! Wystąpił błąd podczas pobierania statystyk rozkładów jazdy...');
|
||||||
|
this.statsStatus = Status.Data.Error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
startFetchingDailyStats() {
|
||||||
|
this.fetchDailyTimetableStats();
|
||||||
|
|
||||||
|
if (this.intervalId != -1) return;
|
||||||
|
|
||||||
|
this.intervalId = window.setInterval(this.fetchDailyTimetableStats, 60000);
|
||||||
|
},
|
||||||
|
|
||||||
|
stopFetchingDailyStats() {
|
||||||
|
clearInterval(this.intervalId);
|
||||||
|
this.intervalId = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/responsive.scss';
|
||||||
|
@import '../../styles/JournalStats.scss';
|
||||||
|
@import '../../styles/badge.scss';
|
||||||
|
|
||||||
|
.daily-stats {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.daily-stats > span[data-active='0'] {
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-list a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-badges {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
h3 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<div class="journal-stats dispatcher" v-if="dispatcherName && stats">
|
||||||
|
<span class="loading" v-if="!stats.issuedTimetables && !stats.services">
|
||||||
|
{{ $t('journal.dispatcher-stats.empty') }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-else>
|
||||||
|
<h3>
|
||||||
|
<i18n-t keypath="journal.dispatcher-stats.title">
|
||||||
|
<template #name>
|
||||||
|
<span class="text--primary">{{ dispatcherName.toUpperCase() }}</span>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<hr class="header-separator" />
|
||||||
|
|
||||||
|
<div class="info-stats">
|
||||||
|
<span class="stat-badge" v-if="stats.services">
|
||||||
|
<span>{{ $t('journal.dispatcher-stats.services-count') }}</span>
|
||||||
|
<span>{{ stats.services.count }}</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="stat-badge" v-if="stats.services">
|
||||||
|
<span>{{ $t('journal.dispatcher-stats.service-max') }}</span>
|
||||||
|
<span>{{ calculateDuration(stats.services.durationMax) }}</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="stat-badge" v-if="stats.services">
|
||||||
|
<span>{{ $t('journal.dispatcher-stats.service-avg') }}</span>
|
||||||
|
<span>{{ calculateDuration(stats.services.durationAvg) }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="section-separator" />
|
||||||
|
|
||||||
|
<div class="info-stats">
|
||||||
|
<span class="stat-badge" v-if="stats.issuedTimetables">
|
||||||
|
<span>{{ $t('journal.dispatcher-stats.timetables-count') }}</span>
|
||||||
|
<span>{{ stats.issuedTimetables.count }}</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="stat-badge" v-if="stats.issuedTimetables">
|
||||||
|
<span>{{ $t('journal.dispatcher-stats.timetables-sum') }}</span>
|
||||||
|
<span>{{ stats.issuedTimetables.distanceSum.toFixed(2) }}km</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="stat-badge" v-if="stats.issuedTimetables">
|
||||||
|
<span>{{ $t('journal.dispatcher-stats.timetables-max') }}</span>
|
||||||
|
<span>{{ stats.issuedTimetables.distanceMax.toFixed(2) }}km</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="stat-badge" v-if="stats.issuedTimetables">
|
||||||
|
<span>{{ $t('journal.dispatcher-stats.timetables-avg') }}</span>
|
||||||
|
<span>{{ stats.issuedTimetables.distanceAvg.toFixed(2) }}km</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import dateMixin from '../../../mixins/dateMixin';
|
||||||
|
import { useMainStore } from '../../../store/mainStore';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'journal-dispatcher-stats',
|
||||||
|
|
||||||
|
mixins: [dateMixin],
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
const store = useMainStore();
|
||||||
|
|
||||||
|
return {
|
||||||
|
stats: store.dispatcherStatsData,
|
||||||
|
dispatcherName: store.dispatcherStatsName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../../styles/JournalStats.scss';
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
<template>
|
||||||
|
<transition name="status-anim" mode="out-in">
|
||||||
|
<div :key="dataStatus">
|
||||||
|
<div class="journal_warning" v-if="store.isOffline">
|
||||||
|
{{ $t('app.offline') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Loading v-else-if="dataStatus == Status.Data.Loading" />
|
||||||
|
|
||||||
|
<div v-else-if="dataStatus == Status.Data.Error" class="journal_warning error">
|
||||||
|
{{ $t('app.error') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="journal_warning" v-else-if="dispatcherHistory.length == 0">
|
||||||
|
{{ $t('app.no-result') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<table class="dispatchers-table">
|
||||||
|
<thead>
|
||||||
|
<th>{{ $t('journal.history-name') }}</th>
|
||||||
|
<th>{{ $t('journal.history-hash') }}</th>
|
||||||
|
<th>{{ $t('journal.history-dispatcher') }}</th>
|
||||||
|
<th>{{ $t('journal.history-level') }}</th>
|
||||||
|
<th>{{ $t('journal.history-rate') }}</th>
|
||||||
|
<th>{{ $t('journal.history-region') }}</th>
|
||||||
|
<th>{{ $t('journal.history-date') }}</th>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<transition-group name="list-anim">
|
||||||
|
<tr v-for="historyItem in dispatcherHistory" :key="historyItem.id">
|
||||||
|
<td>
|
||||||
|
<router-link
|
||||||
|
:to="`/journal/dispatchers?search-station=${historyItem.stationName}`"
|
||||||
|
>
|
||||||
|
<b>{{ historyItem.stationName }}</b>
|
||||||
|
</router-link>
|
||||||
|
</td>
|
||||||
|
<td>#{{ historyItem.stationHash }}</td>
|
||||||
|
<td>
|
||||||
|
<router-link
|
||||||
|
:to="`/journal/dispatchers?search-dispatcher=${historyItem.dispatcherName}`"
|
||||||
|
>
|
||||||
|
<b
|
||||||
|
v-if="isDonator(historyItem.dispatcherName)"
|
||||||
|
class="text--donator"
|
||||||
|
:title="$t('donations.dispatcher-message')"
|
||||||
|
>
|
||||||
|
{{ historyItem.dispatcherName }}
|
||||||
|
</b>
|
||||||
|
|
||||||
|
<b v-else>
|
||||||
|
{{ historyItem.dispatcherName }}
|
||||||
|
</b>
|
||||||
|
</router-link>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<b
|
||||||
|
v-if="historyItem.dispatcherLevel !== null"
|
||||||
|
class="level-badge dispatcher"
|
||||||
|
:style="
|
||||||
|
calculateExpStyle(
|
||||||
|
historyItem.dispatcherLevel,
|
||||||
|
historyItem.dispatcherIsSupporter
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ historyItem.dispatcherLevel >= 2 ? historyItem.dispatcherLevel : 'L' }}
|
||||||
|
</b>
|
||||||
|
</td>
|
||||||
|
<td class="text--primary">
|
||||||
|
<b>{{ historyItem.dispatcherRate }}</b>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<b class="region-badge" :aria-describedby="historyItem.region">{{
|
||||||
|
regions.find((r) => r.id == historyItem.region)?.value || '???'
|
||||||
|
}}</b>
|
||||||
|
</td>
|
||||||
|
<td style="min-width: 200px" class="time">
|
||||||
|
<span v-if="historyItem.timestampTo" class="text--offline">
|
||||||
|
<b>{{ $d(historyItem.timestampFrom) }}</b>
|
||||||
|
{{ timestampToString(historyItem.timestampFrom) }}
|
||||||
|
- {{ timestampToString(historyItem.timestampTo) }} ({{
|
||||||
|
calculateDuration(historyItem.currentDuration)
|
||||||
|
}})
|
||||||
|
</span>
|
||||||
|
<span class="dispatcher-online" v-else>
|
||||||
|
<b class="text--online">
|
||||||
|
<router-link :to="`/scenery?station=${historyItem.stationName}`">{{
|
||||||
|
$t('journal.online-since')
|
||||||
|
}}</router-link>
|
||||||
|
{{ timestampToString(historyItem.timestampFrom) }}
|
||||||
|
</b>
|
||||||
|
({{ calculateDuration(historyItem.currentDuration) }})
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</transition-group>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<AddDataButton
|
||||||
|
:list="dispatcherHistory"
|
||||||
|
:scrollDataLoaded="scrollDataLoaded"
|
||||||
|
:scrollNoMoreData="scrollNoMoreData"
|
||||||
|
@addHistoryData="addHistoryData"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="journal_warning" v-if="scrollNoMoreData">
|
||||||
|
{{ $t('journal.no-further-data') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="journal_warning" v-else-if="!scrollDataLoaded">
|
||||||
|
{{ $t('journal.loading-further-data') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, PropType } from 'vue';
|
||||||
|
import { regions } from '../../../data/options.json';
|
||||||
|
import { useMainStore } from '../../../store/mainStore';
|
||||||
|
import { API } from '../../../typings/api';
|
||||||
|
import { Status } from '../../../typings/common';
|
||||||
|
import Loading from '../../Global/Loading.vue';
|
||||||
|
import AddDataButton from '../../Global/AddDataButton.vue';
|
||||||
|
import dateMixin from '../../../mixins/dateMixin';
|
||||||
|
import donatorMixin from '../../../mixins/donatorMixin';
|
||||||
|
import styleMixin from '../../../mixins/styleMixin';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: { Loading, AddDataButton },
|
||||||
|
|
||||||
|
mixins: [dateMixin, styleMixin, donatorMixin],
|
||||||
|
|
||||||
|
props: {
|
||||||
|
dispatcherHistory: {
|
||||||
|
type: Array as PropType<API.DispatcherHistory.Response>,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
scrollNoMoreData: {
|
||||||
|
type: Boolean
|
||||||
|
},
|
||||||
|
scrollDataLoaded: {
|
||||||
|
type: Boolean
|
||||||
|
},
|
||||||
|
addHistoryData: {
|
||||||
|
type: Function as PropType<() => void>
|
||||||
|
},
|
||||||
|
dataStatus: {
|
||||||
|
type: Number as PropType<Status.Data>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
Status,
|
||||||
|
store: useMainStore(),
|
||||||
|
regions
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
computedDispatcherHistory() {
|
||||||
|
return this.dispatcherHistory.reduce(
|
||||||
|
(acc, historyItem, i) => {
|
||||||
|
if (this.isAnotherDay(i - 1, i))
|
||||||
|
acc.push(new Date(historyItem.timestampFrom).toLocaleDateString('pl-PL'));
|
||||||
|
acc.push(historyItem);
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
[] as (API.DispatcherHistory.Data | string)[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
navigateToScenery(name: string, isOnline: boolean) {
|
||||||
|
if (!isOnline) return;
|
||||||
|
|
||||||
|
this.$router.push(`/scenery?station=${name.trim().replace(/ /g, '_')}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
isAnotherDay(prevIndex: number, currIndex: number) {
|
||||||
|
if (currIndex == 0) return true;
|
||||||
|
|
||||||
|
return (
|
||||||
|
new Date(this.dispatcherHistory[prevIndex].timestampFrom).getDate() !=
|
||||||
|
new Date(this.dispatcherHistory[currIndex].timestampFrom).getDate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../../styles/animations.scss';
|
||||||
|
@import '../../../styles/responsive.scss';
|
||||||
|
@import '../../../styles/badge.scss';
|
||||||
|
@import '../../../styles/variables.scss';
|
||||||
|
@import '../../../styles/JournalSection.scss';
|
||||||
|
|
||||||
|
table.dispatchers-table {
|
||||||
|
--_bg-table: #111;
|
||||||
|
--_bg-head: #101010;
|
||||||
|
--_bg-row: #2f2f2f;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
margin-bottom: 1em;
|
||||||
|
|
||||||
|
thead {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
background-color: var(--_bg-head);
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
background-color: var(--_bg-row);
|
||||||
|
border-bottom: 2px solid black;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0.75em;
|
||||||
|
|
||||||
|
.level-badge {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
&--online {
|
||||||
|
color: springgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--offline {
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<transition name="status-anim" mode="out-in">
|
|
||||||
<div :key="dataStatus">
|
|
||||||
<div class="journal_warning" v-if="store.isOffline">
|
|
||||||
{{ $t('app.offline') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Loading v-else-if="dataStatus == DataStatus.Loading" />
|
|
||||||
|
|
||||||
<div v-else-if="dataStatus == DataStatus.Error" class="journal_warning error">
|
|
||||||
{{ $t('app.error') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="journal_warning" v-else-if="dispatcherHistory.length == 0">
|
|
||||||
{{ $t('app.no-result') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else>
|
|
||||||
<table class="scenery-history-table">
|
|
||||||
<thead>
|
|
||||||
<th>{{ $t('journal.history-name') }}</th>
|
|
||||||
<th>{{ $t('journal.history-hash') }}</th>
|
|
||||||
<th>{{ $t('journal.history-dispatcher') }}</th>
|
|
||||||
<th>{{ $t('journal.history-level') }}</th>
|
|
||||||
<th>{{ $t('journal.history-rate') }}</th>
|
|
||||||
<th>{{ $t('journal.history-region') }}</th>
|
|
||||||
<th>{{ $t('journal.history-date') }}</th>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
<transition-group name="list-anim">
|
|
||||||
<tr v-for="historyItem in dispatcherHistory" :key="historyItem.id">
|
|
||||||
<td>
|
|
||||||
<router-link
|
|
||||||
:to="`/journal/dispatchers?sceneryName=${historyItem.stationName}`"
|
|
||||||
>
|
|
||||||
<b>{{ historyItem.stationName }}</b>
|
|
||||||
</router-link>
|
|
||||||
</td>
|
|
||||||
<td>#{{ historyItem.stationHash }}</td>
|
|
||||||
<td>
|
|
||||||
<router-link
|
|
||||||
:to="`/journal/dispatchers?dispatcherName=${historyItem.dispatcherName}`"
|
|
||||||
>
|
|
||||||
<b>{{ historyItem.dispatcherName }}</b>
|
|
||||||
</router-link>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<b
|
|
||||||
v-if="historyItem.dispatcherLevel !== null"
|
|
||||||
class="level-badge dispatcher"
|
|
||||||
:style="
|
|
||||||
calculateExpStyle(
|
|
||||||
historyItem.dispatcherLevel,
|
|
||||||
historyItem.dispatcherIsSupporter
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ historyItem.dispatcherLevel >= 2 ? historyItem.dispatcherLevel : 'L' }}
|
|
||||||
</b>
|
|
||||||
</td>
|
|
||||||
<td class="text--primary">
|
|
||||||
<b>{{ historyItem.dispatcherRate }}</b>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<b class="region-badge" :aria-describedby="historyItem.region">{{
|
|
||||||
regions.find((r) => r.id == historyItem.region)?.value || '???'
|
|
||||||
}}</b>
|
|
||||||
</td>
|
|
||||||
<td style="min-width: 200px" class="time">
|
|
||||||
<span v-if="historyItem.timestampTo" class="text--offline">
|
|
||||||
<b>{{ $d(historyItem.timestampFrom) }}</b>
|
|
||||||
{{ timestampToString(historyItem.timestampFrom) }}
|
|
||||||
- {{ timestampToString(historyItem.timestampTo) }} ({{
|
|
||||||
calculateDuration(historyItem.currentDuration)
|
|
||||||
}})
|
|
||||||
</span>
|
|
||||||
<span class="dispatcher-online" v-else>
|
|
||||||
<b class="text--online">
|
|
||||||
<router-link :to="`/scenery?station=${historyItem.stationName}`">{{
|
|
||||||
$t('journal.online-since')
|
|
||||||
}}</router-link>
|
|
||||||
{{ timestampToString(historyItem.timestampFrom) }}
|
|
||||||
</b>
|
|
||||||
({{ calculateDuration(historyItem.currentDuration) }})
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</transition-group>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<AddDataButton
|
|
||||||
:list="dispatcherHistory"
|
|
||||||
:scrollDataLoaded="scrollDataLoaded"
|
|
||||||
:scrollNoMoreData="scrollNoMoreData"
|
|
||||||
@addHistoryData="addHistoryData"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
|
|
||||||
<div class="journal_warning" v-if="scrollNoMoreData">
|
|
||||||
{{ $t('journal.no-further-data') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="journal_warning" v-else-if="!scrollDataLoaded">
|
|
||||||
{{ $t('journal.loading-further-data') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, PropType } from 'vue';
|
|
||||||
import dateMixin from '../../mixins/dateMixin';
|
|
||||||
import { DispatcherHistory } from '../../scripts/interfaces/api/DispatchersAPIData';
|
|
||||||
import styleMixin from '../../mixins/styleMixin';
|
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
|
||||||
import { useStore } from '../../store/store';
|
|
||||||
import Loading from '../Global/Loading.vue';
|
|
||||||
import { regions } from '../../data/options.json';
|
|
||||||
import AddDataButton from '../Global/AddDataButton.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: { Loading, AddDataButton },
|
|
||||||
|
|
||||||
mixins: [dateMixin, styleMixin],
|
|
||||||
|
|
||||||
props: {
|
|
||||||
dispatcherHistory: {
|
|
||||||
type: Array as PropType<DispatcherHistory[]>,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
scrollNoMoreData: {
|
|
||||||
type: Boolean
|
|
||||||
},
|
|
||||||
scrollDataLoaded: {
|
|
||||||
type: Boolean
|
|
||||||
},
|
|
||||||
addHistoryData: {
|
|
||||||
type: Function as PropType<() => void>
|
|
||||||
},
|
|
||||||
dataStatus: {
|
|
||||||
type: Number as PropType<DataStatus>
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
DataStatus,
|
|
||||||
store: useStore(),
|
|
||||||
regions
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
computedDispatcherHistory() {
|
|
||||||
console.log(this.dispatcherHistory.length);
|
|
||||||
|
|
||||||
return this.dispatcherHistory.reduce(
|
|
||||||
(acc, historyItem, i) => {
|
|
||||||
if (this.isAnotherDay(i - 1, i))
|
|
||||||
acc.push(new Date(historyItem.timestampFrom).toLocaleDateString('pl-PL'));
|
|
||||||
acc.push(historyItem);
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
[] as (DispatcherHistory | string)[]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
navigateToScenery(name: string, isOnline: boolean) {
|
|
||||||
if (!isOnline) return;
|
|
||||||
|
|
||||||
this.$router.push(`/scenery?station=${name.trim().replace(/ /g, '_')}`);
|
|
||||||
},
|
|
||||||
|
|
||||||
isAnotherDay(prevIndex: number, currIndex: number) {
|
|
||||||
if (currIndex == 0) return true;
|
|
||||||
|
|
||||||
return (
|
|
||||||
new Date(this.dispatcherHistory[prevIndex].timestampFrom).getDate() !=
|
|
||||||
new Date(this.dispatcherHistory[currIndex].timestampFrom).getDate()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '../../styles/animations.scss';
|
|
||||||
@import '../../styles/responsive.scss';
|
|
||||||
@import '../../styles/badge.scss';
|
|
||||||
@import '../../styles/variables.scss';
|
|
||||||
@import '../../styles/JournalSection.scss';
|
|
||||||
|
|
||||||
table.scenery-history-table {
|
|
||||||
--_bg-table: #111;
|
|
||||||
--_bg-head: #101010;
|
|
||||||
--_bg-row: #2f2f2f;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
position: relative;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
margin-bottom: 1em;
|
|
||||||
|
|
||||||
thead {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
background-color: var(--_bg-head);
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr {
|
|
||||||
background-color: var(--_bg-row);
|
|
||||||
border-bottom: 2px solid black;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
padding: 0.75em;
|
|
||||||
|
|
||||||
.level-badge {
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 550px) {
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
&--online {
|
|
||||||
color: springgreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--offline {
|
|
||||||
color: #ddd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="filters-options" @keydown.esc="showOptions = false">
|
<div class="filters-options dropdown" @keydown.esc="showOptions = false">
|
||||||
<div class="bg" v-if="showOptions" @click="showOptions = false"></div>
|
<div class="dropdown_background" v-if="showOptions" @click="showOptions = false"></div>
|
||||||
|
|
||||||
<div class="actions-bar">
|
<div class="actions-bar">
|
||||||
<button
|
<button
|
||||||
@@ -27,13 +27,13 @@
|
|||||||
<option v-for="(sugg, i) in dispatcherSuggestions" :key="i" :value="sugg"></option>
|
<option v-for="(sugg, i) in dispatcherSuggestions" :key="i" :value="sugg"></option>
|
||||||
</datalist>
|
</datalist>
|
||||||
|
|
||||||
<transition name="options-anim">
|
<transition name="dropdown-anim">
|
||||||
<div class="options_wrapper" v-if="showOptions">
|
<div class="dropdown_wrapper" v-if="showOptions">
|
||||||
<div class="options_content">
|
<div class="options_content">
|
||||||
<h1 class="option-title">{{ $t('options.search-title') }}</h1>
|
<h1 class="option-title">{{ $t('options.search-title') }}</h1>
|
||||||
<div class="search_content">
|
<div class="search_content">
|
||||||
<div class="search" v-for="(_, propName) in searchersValues" :key="propName">
|
<div class="search" v-for="(_, propName) in searchersValues" :key="propName">
|
||||||
<label v-if="propName == 'search-date'" for="date">{{
|
<label v-if="propName == 'search-date'" for="search-date">{{
|
||||||
$t(`options.search-${optionsType}-date`)
|
$t(`options.search-${optionsType}-date`)
|
||||||
}}</label>
|
}}</label>
|
||||||
|
|
||||||
@@ -41,12 +41,13 @@
|
|||||||
<input
|
<input
|
||||||
class="search-input"
|
class="search-input"
|
||||||
v-model="searchersValues[propName]"
|
v-model="searchersValues[propName]"
|
||||||
@keydown.enter="onSearchConfirm"
|
@keydown.enter="searchConfirm"
|
||||||
@focus="preventKeyDown = true"
|
@focus="preventKeyDown = true"
|
||||||
@blur="preventKeyDown = false"
|
@blur="preventKeyDown = false"
|
||||||
:placeholder="$t(`options.${propName}`)"
|
:placeholder="$t(`options.${propName}`)"
|
||||||
:type="propName == 'search-date' ? 'date' : 'text'"
|
:type="propName == 'search-date' ? 'date' : 'text'"
|
||||||
:min="propName == 'search-date' ? '2022-02-01' : undefined"
|
:min="propName == 'search-date' ? '2022-02-01' : undefined"
|
||||||
|
:id="`${propName}`"
|
||||||
:list="propName.toString()"
|
:list="propName.toString()"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -110,15 +111,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
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 { useMainStore } from '../../store/mainStore';
|
||||||
import { DriverStatsAPIData } from '../../scripts/interfaces/api/DriverStatsAPIData';
|
import { Journal } from './typings';
|
||||||
import { URLs } from '../../scripts/utils/apiURLs';
|
import { Status } from '../../typings/common';
|
||||||
import { useStore } from '../../store/store';
|
import http from '../../http';
|
||||||
import { JournalFilterSection } from '../../scripts/enums/JournalFilterType';
|
|
||||||
import { JournalFilter } from '../../scripts/types/JournalTimetablesTypes';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
emits: ['onSearchConfirm', 'onOptionsReset', 'onRefreshData'],
|
emits: ['onSearchConfirm', 'onOptionsReset', 'onRefreshData'],
|
||||||
@@ -131,13 +129,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,15 +152,14 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showOptions: false,
|
showOptions: false,
|
||||||
JournalFilterSection,
|
|
||||||
|
|
||||||
driverSuggestions: [] as string[],
|
driverSuggestions: [] as string[],
|
||||||
dispatcherSuggestions: [] as string[],
|
dispatcherSuggestions: [] as string[],
|
||||||
|
|
||||||
searchTimeout: 0,
|
searchTimeout: 0,
|
||||||
store: useStore(),
|
store: useMainStore(),
|
||||||
|
|
||||||
DataStatus
|
JournalFilterSection: Journal.FilterSection
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -170,7 +167,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
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -184,12 +181,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
async 'store.driverStatsName'() {
|
|
||||||
await this.fetchDriverStats();
|
|
||||||
|
|
||||||
// if (value) this.store.currentStatsTab = 'driver';
|
|
||||||
},
|
|
||||||
|
|
||||||
async 'searchersValues.search-driver'(value: string | undefined) {
|
async 'searchersValues.search-driver'(value: string | undefined) {
|
||||||
clearTimeout(this.searchTimeout);
|
clearTimeout(this.searchTimeout);
|
||||||
|
|
||||||
@@ -208,29 +199,34 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async fetchDriverStats() {
|
// filters & sorters from URL params
|
||||||
this.store.driverStatsData = undefined;
|
handleRouteParams() {
|
||||||
|
this.$router.push({
|
||||||
|
query: {
|
||||||
|
...this.$route.query,
|
||||||
|
'sorter-active':
|
||||||
|
this.sorterOptionIds.indexOf(`${this.sorterActive.id}`) != 0
|
||||||
|
? this.sorterActive.id
|
||||||
|
: undefined,
|
||||||
|
...Object.keys(this.searchersValues).reduce(
|
||||||
|
(acc, k) => {
|
||||||
|
const searchVal = this.searchersValues[k as Journal.TimetableSearchKey];
|
||||||
|
|
||||||
if (!this.store.driverStatsName) {
|
acc[k] = searchVal || undefined;
|
||||||
this.store.driverStatsStatus = DataStatus.Initialized;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
return acc;
|
||||||
this.store.driverStatsStatus = DataStatus.Loading;
|
},
|
||||||
|
{} as { [k: string]: string | undefined }
|
||||||
const statsData: DriverStatsAPIData = await (
|
),
|
||||||
await axios.get(
|
...this.filterList?.reduce(
|
||||||
`${URLs.stacjownikAPI}/api/getDriverInfo?name=${this.store.driverStatsName}`
|
(acc, f) => {
|
||||||
|
if (f.isActive) acc[f.filterSection] = f.default ? undefined : f.id;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as { [k: string]: string | undefined }
|
||||||
)
|
)
|
||||||
).data;
|
}
|
||||||
|
});
|
||||||
this.store.driverStatsData = statsData;
|
|
||||||
this.store.driverStatsStatus = DataStatus.Loaded;
|
|
||||||
} catch (error) {
|
|
||||||
this.store.driverStatsStatus = DataStatus.Error;
|
|
||||||
console.error('Ups! Wystąpił błąd przy próbie pobrania statystyk maszynisty! :/');
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshData() {
|
refreshData() {
|
||||||
@@ -242,17 +238,17 @@ export default defineComponent({
|
|||||||
|
|
||||||
window.clearTimeout(this.searchTimeout);
|
window.clearTimeout(this.searchTimeout);
|
||||||
|
|
||||||
this.searchTimeout = setTimeout(async () => {
|
this.searchTimeout = window.setTimeout(async () => {
|
||||||
try {
|
try {
|
||||||
const suggestions: string[] = await (
|
const suggestions: string[] = await (
|
||||||
await axios.get(`${URLs.stacjownikAPI}/api/get${type}Suggestions?name=${value}`)
|
await http.get(`api/get${type}Suggestions?name=${value}`)
|
||||||
).data;
|
).data;
|
||||||
|
|
||||||
this[`${type}Suggestions`] = suggestions;
|
this[`${type}Suggestions`] = suggestions;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this[`${type}Suggestions`] = [];
|
this[`${type}Suggestions`] = [];
|
||||||
}
|
}
|
||||||
}, 450);
|
}, 250);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Override keyMixin function
|
// Override keyMixin function
|
||||||
@@ -267,40 +263,43 @@ export default defineComponent({
|
|||||||
onSorterChange(item: { id: string | number; value: string }) {
|
onSorterChange(item: { id: string | number; value: string }) {
|
||||||
this.sorterActive.id = item.id;
|
this.sorterActive.id = item.id;
|
||||||
this.sorterActive.dir = -1;
|
this.sorterActive.dir = -1;
|
||||||
this.$emit('onSearchConfirm');
|
this.searchConfirm();
|
||||||
},
|
},
|
||||||
|
|
||||||
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)
|
||||||
.forEach((f) => (f.isActive = false));
|
.forEach((f) => (f.isActive = false));
|
||||||
filter.isActive = true;
|
filter.isActive = true;
|
||||||
|
|
||||||
this.$emit('onSearchConfirm');
|
this.searchConfirm();
|
||||||
},
|
},
|
||||||
|
|
||||||
onInputClear(id: any) {
|
onInputClear(id: any) {
|
||||||
this.searchersValues[id] = '';
|
this.searchersValues[id] = '';
|
||||||
this.$emit('onSearchConfirm');
|
this.searchConfirm();
|
||||||
},
|
},
|
||||||
|
|
||||||
onSearchConfirm() {
|
searchConfirm() {
|
||||||
this.$emit('onSearchConfirm');
|
this.$emit('onSearchConfirm');
|
||||||
|
this.handleRouteParams();
|
||||||
},
|
},
|
||||||
|
|
||||||
onSearchButtonConfirm() {
|
onSearchButtonConfirm() {
|
||||||
this.showOptions = false;
|
this.showOptions = false;
|
||||||
this.$emit('onSearchConfirm');
|
this.searchConfirm();
|
||||||
},
|
},
|
||||||
|
|
||||||
onResetButtonClick() {
|
onResetButtonClick() {
|
||||||
this.$emit('onOptionsReset');
|
this.$emit('onOptionsReset');
|
||||||
|
this.handleRouteParams();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/filters_options.scss';
|
@import '../../styles/dropdown.scss';
|
||||||
|
@import '../../styles/dropdown_filters.scss';
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,121 +1,85 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="journal-stats" v-if="!store.isOffline">
|
<div
|
||||||
<div class="tabs">
|
class="journal-stats dropdown"
|
||||||
|
v-if="!mainStore.isOffline"
|
||||||
|
@keydown.esc="currentStatsTab = null"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="dropdown_background"
|
||||||
|
v-if="currentStatsTab !== null"
|
||||||
|
@click="currentStatsTab = null"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<div class="actions-bar">
|
||||||
<button
|
<button
|
||||||
v-for="tab in data.tabs"
|
v-for="button in statsButtons"
|
||||||
:key="tab.name"
|
:key="button.tab"
|
||||||
class="btn--filled"
|
class="btn--filled btn--image"
|
||||||
:data-selected="tab.name == store.currentStatsTab && areStatsOpen"
|
:data-selected="button.tab == currentStatsTab"
|
||||||
:data-inactive="tab.inactive"
|
:data-disabled="button.disabled"
|
||||||
:data-disabled="tab.inactive"
|
:disabled="button.disabled"
|
||||||
:disabled="tab.inactive"
|
@click="onTabButtonClick(button.tab)"
|
||||||
@click="onTabButtonClick(tab.name)"
|
|
||||||
>
|
>
|
||||||
{{ $t(tab.titlePath) }}
|
<img
|
||||||
|
v-if="button.iconName"
|
||||||
|
:src="`/images/icon-${button.iconName}.svg`"
|
||||||
|
:alt="button.iconName"
|
||||||
|
/>
|
||||||
|
{{ $t(button.localeKey) }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stats-tab" v-show="areStatsOpen">
|
<transition name="dropdown-anim">
|
||||||
<keep-alive>
|
<div class="dropdown_wrapper" v-if="currentStatsTab !== null">
|
||||||
<JournalDailyStats
|
<keep-alive>
|
||||||
v-if="store.currentStatsTab == 'daily'"
|
<component :is="currentStatsTab" :key="currentStatsTab"></component>
|
||||||
@toggleStatsOpen="toggleStatsOpen"
|
</keep-alive>
|
||||||
/>
|
</div>
|
||||||
<JournalDriverStats v-else-if="store.currentStatsTab == 'driver'" />
|
</transition>
|
||||||
</keep-alive>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
import { computed, onMounted, reactive, Ref, ref, watch } from 'vue';
|
import { defineComponent, PropType } from 'vue';
|
||||||
import { useStore } from '../../store/store';
|
import { useMainStore } from '../../store/mainStore';
|
||||||
import JournalDailyStats from './DailyStats.vue';
|
import StorageManager from '../../managers/storageManager';
|
||||||
import JournalDriverStats from './JournalDriverStats.vue';
|
import { Journal } from './typings';
|
||||||
import StorageManager from '../../scripts/managers/storageManager';
|
import JournalDailyStats from './JournalDailyStats.vue';
|
||||||
|
import JournalDispatcherStats from '../JournalView/JournalDispatchers/JournalDispatcherStats.vue';
|
||||||
|
import JournalDriverStats from '../JournalView/JournalTimetables/JournalDriverStats.vue';
|
||||||
|
|
||||||
// Types
|
export default defineComponent({
|
||||||
type TStatTab = 'daily' | 'driver';
|
components: { JournalDailyStats, JournalDriverStats, JournalDispatcherStats },
|
||||||
|
props: {
|
||||||
// Variables
|
statsButtons: {
|
||||||
const store = useStore();
|
type: Array as PropType<Journal.StatsButton[]>,
|
||||||
|
required: true
|
||||||
const lastDailyStatsOpen = ref(false);
|
|
||||||
const areStatsOpen = ref(false);
|
|
||||||
const lastClickedTab: Ref<'daily' | 'driver' | null> = ref(null);
|
|
||||||
|
|
||||||
let data = reactive({
|
|
||||||
tabs: [
|
|
||||||
{
|
|
||||||
name: 'daily',
|
|
||||||
titlePath: 'journal.daily-stats-title'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'driver',
|
|
||||||
titlePath: 'journal.driver-stats-title'
|
|
||||||
// inactive: true,
|
|
||||||
}
|
}
|
||||||
] as { name: TStatTab; titlePath: string; inactive?: boolean }[]
|
},
|
||||||
});
|
data() {
|
||||||
|
return {
|
||||||
|
Journal,
|
||||||
|
mainStore: useMainStore(),
|
||||||
|
currentStatsTab: null as Journal.StatsTab | null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
// Methods
|
methods: {
|
||||||
function onTabButtonClick(tab: TStatTab) {
|
onTabButtonClick(tab: Journal.StatsTab) {
|
||||||
if (lastClickedTab.value == tab || !lastClickedTab.value || !areStatsOpen.value) areStatsOpen.value = !areStatsOpen.value;
|
this.currentStatsTab = tab == this.currentStatsTab ? null : tab;
|
||||||
|
|
||||||
if (tab == 'daily') {
|
StorageManager.setStringValue('journalStatsTab', this.currentStatsTab ?? '');
|
||||||
StorageManager.setBooleanValue('dailyStatsOpen', areStatsOpen.value);
|
}
|
||||||
lastDailyStatsOpen.value = areStatsOpen.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
store.currentStatsTab = tab;
|
|
||||||
lastClickedTab.value = tab;
|
|
||||||
|
|
||||||
if (areStatsOpen.value == false) store.currentStatsTab = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleStatsOpen(open: boolean) {
|
|
||||||
areStatsOpen.value = open;
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
computed(() => store.driverStatsData),
|
|
||||||
(statsData) => {
|
|
||||||
store.currentStatsTab = statsData ? 'driver' : lastClickedTab.value;
|
|
||||||
areStatsOpen.value = statsData ? true : lastClickedTab.value !== null;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (StorageManager.getBooleanValue('dailyStatsOpen')) {
|
|
||||||
areStatsOpen.value = true;
|
|
||||||
store.currentStatsTab = 'daily';
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/JournalStats.scss';
|
@import '../../styles/dropdown.scss';
|
||||||
|
@import '../../styles/dropdown_filters.scss';
|
||||||
@import '../../styles/variables.scss';
|
@import '../../styles/variables.scss';
|
||||||
|
|
||||||
.tabs {
|
.dropdown_wrapper {
|
||||||
position: relative;
|
max-width: 100%;
|
||||||
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5em;
|
|
||||||
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
|
|
||||||
button {
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 0.5em 0.75em;
|
|
||||||
|
|
||||||
&[data-inactive='true'] {
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-selected='true'] {
|
|
||||||
color: $accentCol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="journal-stats">
|
<div class="journal-stats driver" v-if="store.driverStatsData">
|
||||||
<span v-if="store.driverStatsData">
|
<span>
|
||||||
<h3>
|
<h3>
|
||||||
{{ $t('journal.stats-title') }}
|
<i18n-t keypath="journal.driver-stats.title">
|
||||||
<span class="text--primary">{{ store.driverStatsName.toUpperCase() }}</span>
|
<template #name>
|
||||||
|
<span class="text--primary">{{ store.driverStatsName.toUpperCase() }}</span>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
<hr class="header-separator" />
|
||||||
|
|
||||||
<div class="info-stats">
|
<div class="info-stats">
|
||||||
<span class="stat-badge">
|
<span class="stat-badge">
|
||||||
<span>{{ $t('journal.stats-timetables') }}</span>
|
<span>{{ $t('journal.driver-stats.timetables') }}</span>
|
||||||
<span
|
<span
|
||||||
>{{ store.driverStatsData._count.fulfilled }} /
|
>{{ store.driverStatsData._count.fulfilled }} /
|
||||||
{{ store.driverStatsData._count._all }}</span
|
{{ store.driverStatsData._count._all }}</span
|
||||||
@@ -16,17 +21,17 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="stat-badge">
|
<span class="stat-badge">
|
||||||
<span>{{ $t('journal.stats-longest-timetable') }}</span>
|
<span>{{ $t('journal.driver-stats.longest-timetable') }}</span>
|
||||||
<span> {{ store.driverStatsData._max.routeDistance.toFixed(2) }}km </span>
|
<span> {{ store.driverStatsData._max.routeDistance.toFixed(2) }}km </span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="stat-badge">
|
<span class="stat-badge">
|
||||||
<span>{{ $t('journal.stats-avg-timetable') }}</span>
|
<span>{{ $t('journal.driver-stats.avg-timetable') }}</span>
|
||||||
<span> {{ store.driverStatsData._avg.routeDistance.toFixed(2) }}km </span>
|
<span> {{ store.driverStatsData._avg.routeDistance.toFixed(2) }}km </span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="stat-badge">
|
<span class="stat-badge">
|
||||||
<span>{{ $t('journal.stats-distance') }}</span>
|
<span>{{ $t('journal.driver-stats.distance') }}</span>
|
||||||
<span>
|
<span>
|
||||||
{{ store.driverStatsData._sum.currentDistance.toFixed(2) }} /
|
{{ store.driverStatsData._sum.currentDistance.toFixed(2) }} /
|
||||||
{{ store.driverStatsData._sum.routeDistance.toFixed(2) }}km
|
{{ store.driverStatsData._sum.routeDistance.toFixed(2) }}km
|
||||||
@@ -34,7 +39,7 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="stat-badge">
|
<span class="stat-badge">
|
||||||
<span>{{ $t('journal.stats-stations') }}</span>
|
<span>{{ $t('journal.driver-stats.stations') }}</span>
|
||||||
<span>
|
<span>
|
||||||
{{ store.driverStatsData._sum.confirmedStopsCount }} /
|
{{ store.driverStatsData._sum.confirmedStopsCount }} /
|
||||||
{{ store.driverStatsData._sum.allStopsCount }}
|
{{ store.driverStatsData._sum.allStopsCount }}
|
||||||
@@ -42,32 +47,26 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<b v-else-if="store.driverStatsStatus == DataStatus.Loading">{{
|
|
||||||
$t('journal.stats-loading')
|
|
||||||
}}</b>
|
|
||||||
<b v-else-if="store.driverStatsStatus == DataStatus.Error">
|
|
||||||
{{ $t('journal.stats-error ') }}
|
|
||||||
</b>
|
|
||||||
<b v-else>{{ $t('journal.driver-stats-info') }}</b>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
import { useMainStore } from '../../../store/mainStore';
|
||||||
import { useStore } from '../../store/store';
|
import { Status } from '../../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
name: 'journal-driver-stats',
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
store: useStore(),
|
store: useMainStore(),
|
||||||
DataStatus
|
Status: Status
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/JournalStats.scss';
|
@import '../../../styles/JournalStats.scss';
|
||||||
</style>
|
</style>
|
||||||
@@ -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 { useMainStore } 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,14 +64,14 @@ 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: useMainStore()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -28,7 +28,17 @@
|
|||||||
{{ timetable.driverLevel < 2 ? 'L' : `${timetable.driverLevel}` }}
|
{{ timetable.driverLevel < 2 ? 'L' : `${timetable.driverLevel}` }}
|
||||||
</strong>
|
</strong>
|
||||||
|
|
||||||
<strong>{{ timetable.driverName }}</strong>
|
<strong
|
||||||
|
v-if="isDonator(timetable.driverName)"
|
||||||
|
class="text--donator"
|
||||||
|
:title="$t('donations.driver-message')"
|
||||||
|
>
|
||||||
|
{{ timetable.driverName }}
|
||||||
|
</strong>
|
||||||
|
|
||||||
|
<strong v-else>
|
||||||
|
{{ timetable.driverName }}
|
||||||
|
</strong>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="general-time">
|
<span class="general-time">
|
||||||
@@ -62,24 +72,25 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PropType, defineComponent } from 'vue';
|
import { PropType, defineComponent } from 'vue';
|
||||||
import { TimetableHistory } from '../../../scripts/interfaces/api/TimetablesAPIData';
|
|
||||||
|
|
||||||
|
import { API } from '../../../typings/api';
|
||||||
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 donatorMixin from '../../../mixins/donatorMixin';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [dateMixin, modalTrainMixin, styleMixin],
|
mixins: [dateMixin, modalTrainMixin, styleMixin, donatorMixin],
|
||||||
|
|
||||||
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);
|
||||||
@@ -100,16 +111,17 @@ export default defineComponent({
|
|||||||
|
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
|
|
||||||
@include smallScreen() {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-date {
|
.info-date {
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badges {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
.info-badge {
|
.info-badge {
|
||||||
padding: 0.05em 0.35em;
|
padding: 0.05em 0.35em;
|
||||||
color: black;
|
color: black;
|
||||||
@@ -131,7 +143,14 @@ export default defineComponent({
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
.item-general {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -38,17 +38,19 @@
|
|||||||
|
|
||||||
<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({
|
||||||
|
components: { TimetableGeneral, TimetableStops, TimetableStatus, TimetableExtra },
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
timetableHistory: {
|
timetableHistory: {
|
||||||
type: Array as PropType<TimetableHistory[]>,
|
type: Array as PropType<API.TimetableHistory.Response>,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -59,9 +61,7 @@ export default defineComponent({
|
|||||||
showExtraInfo: ref(false)
|
showExtraInfo: ref(false)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
methods: {},
|
|
||||||
components: { TimetableGeneral, TimetableStops, TimetableStatus, TimetableExtra }
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -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,67 @@
|
|||||||
|
export namespace Journal {
|
||||||
|
export type DispatcherSearchKey = 'search-dispatcher' | 'search-station' | 'search-date';
|
||||||
|
|
||||||
|
export type TimetableSearchKey =
|
||||||
|
| 'search-driver'
|
||||||
|
| 'search-train'
|
||||||
|
| 'search-date'
|
||||||
|
| 'search-dispatcher'
|
||||||
|
| 'search-issuedFrom';
|
||||||
|
|
||||||
|
export type TimetableSearchType = {
|
||||||
|
[key in TimetableSearchKey]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DispatcherSearchType = {
|
||||||
|
[key in DispatcherSearchKey]: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TimetableSorterKey = 'timetableId' | 'beginDate' | 'distance' | 'total-stops';
|
||||||
|
export type DispatcherSorterKey = 'timestampFrom' | 'duration';
|
||||||
|
|
||||||
|
export interface DispatcherSorter {
|
||||||
|
id: DispatcherSorterKey;
|
||||||
|
dir: -1 | 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimetableSorter {
|
||||||
|
id: TimetableSorterKey;
|
||||||
|
dir: 'asc' | 'desc';
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum TimetableFilterId {
|
||||||
|
ALL_STATUSES = 'all-statuses',
|
||||||
|
ACTIVE = 'active',
|
||||||
|
FULFILLED = 'fulfilled',
|
||||||
|
ABANDONED = 'abandoned',
|
||||||
|
ALL_SPECIALS = 'all-specials',
|
||||||
|
TWR = 'twr',
|
||||||
|
SKR = 'skr',
|
||||||
|
TWR_SKR = 'twr-skr'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum FilterSection {
|
||||||
|
TIMETABLE_STATUS = 'timetable-status',
|
||||||
|
SPECIAL = 'special'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimetableFilter {
|
||||||
|
id: TimetableFilterId;
|
||||||
|
filterSection: string;
|
||||||
|
isActive: boolean;
|
||||||
|
default: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum StatsTab {
|
||||||
|
DRIVER_STATS = 'journal-driver-stats',
|
||||||
|
DISPATCHER_STATS = 'journal-dispatcher-stats',
|
||||||
|
DAILY_STATS = 'journal-daily-stats'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StatsButton {
|
||||||
|
tab: StatsTab;
|
||||||
|
localeKey: string;
|
||||||
|
iconName: string;
|
||||||
|
disabled: boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,9 @@
|
|||||||
<tr v-for="historyItem in historyList" :key="historyItem.id">
|
<tr v-for="historyItem in historyList" :key="historyItem.id">
|
||||||
<td>#{{ historyItem.stationHash }}</td>
|
<td>#{{ historyItem.stationHash }}</td>
|
||||||
<td>
|
<td>
|
||||||
<router-link :to="`/journal/dispatchers?dispatcherName=${historyItem.dispatcherName}`">
|
<router-link
|
||||||
|
:to="`/journal/dispatchers?search-dispatcher=${historyItem.dispatcherName}`"
|
||||||
|
>
|
||||||
<b>{{ historyItem.dispatcherName }}</b>
|
<b>{{ historyItem.dispatcherName }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
</td>
|
</td>
|
||||||
@@ -33,6 +35,8 @@
|
|||||||
>
|
>
|
||||||
{{ historyItem.dispatcherLevel >= 2 ? historyItem.dispatcherLevel : 'L' }}
|
{{ historyItem.dispatcherLevel >= 2 ? historyItem.dispatcherLevel : 'L' }}
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
|
<b v-else>?</b>
|
||||||
</td>
|
</td>
|
||||||
<td class="text--primary">
|
<td class="text--primary">
|
||||||
<b>{{ historyItem.dispatcherRate }}</b>
|
<b>{{ historyItem.dispatcherRate }}</b>
|
||||||
@@ -66,17 +70,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
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 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';
|
||||||
|
import http from '../../http';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SceneryDispatchersHistory',
|
name: 'SceneryDispatchersHistory',
|
||||||
@@ -84,20 +87,18 @@ export default defineComponent({
|
|||||||
components: { Loading },
|
components: { Loading },
|
||||||
props: {
|
props: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as PropType<Station>,
|
type: Object as PropType<Station>
|
||||||
required: true
|
|
||||||
},
|
},
|
||||||
onlineScenery: {
|
onlineScenery: {
|
||||||
type: Object as PropType<OnlineScenery>,
|
type: Object as PropType<OnlineScenery>
|
||||||
required: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
historyList: [] as DispatcherHistory[],
|
historyList: [] as API.DispatcherHistory.Response,
|
||||||
dataStatus: DataStatus.Loading,
|
dataStatus: Status.Data.Loading,
|
||||||
DataStatus
|
DataStatus: Status.Data
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -109,23 +110,38 @@ 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> {
|
||||||
|
if (!this.station && !this.onlineScenery) {
|
||||||
|
this.dataStatus = Status.Data.Loaded;
|
||||||
|
return 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 = `api/getDispatchers?stationName=${
|
||||||
const historyAPIData: DispatcherHistory[] = await (await axios.get(requestString)).data;
|
this.station?.name || this.onlineScenery?.name
|
||||||
|
}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||||
|
|
||||||
this.dataStatus = DataStatus.Loaded;
|
const historyAPIData: API.DispatcherHistory.Response = await (
|
||||||
|
await http.get(requestString)
|
||||||
|
).data;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
navigateToHistory() {
|
navigateToHistory() {
|
||||||
this.$router.push(`/journal/dispatchers?sceneryName=${this.station.name}`);
|
this.$router.push(
|
||||||
|
`/journal/dispatchers?search-station=${this.station?.name || this.onlineScenery?.name}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -153,3 +169,4 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
../../store/storeTypes
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="info-header">
|
<section class="info-header">
|
||||||
<a class="scenery-name" :href="station.generalInfo?.url" target="_blank">
|
<a class="scenery-name" :href="station?.generalInfo?.url" target="_blank">
|
||||||
{{ station.name }}
|
{{ stationName.replace(/_/g, ' ') }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="scenery-abbrev">
|
<div class="scenery-abbrev" v-if="station?.generalInfo?.abbr">
|
||||||
{{ $t('scenery.abbrev') }} <b>{{ station.generalInfo?.abbr }}</b>
|
{{ $t('scenery.abbrev') }} <b>{{ station.generalInfo.abbr }}</b>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="scenery-hash" v-if="onlineScenery?.hash">#{{ onlineScenery.hash }}</div>
|
<div class="scenery-hash" v-if="onlineScenery?.hash">#{{ onlineScenery.hash }}</div>
|
||||||
@@ -15,18 +15,21 @@
|
|||||||
<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: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as PropType<Station>,
|
type: Object as PropType<Station>
|
||||||
|
},
|
||||||
|
|
||||||
|
stationName: {
|
||||||
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
|
||||||
onlineScenery: {
|
onlineScenery: {
|
||||||
type: Object as PropType<OnlineScenery>,
|
type: Object as PropType<OnlineScenery>
|
||||||
required: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scenery-info">
|
<div class="scenery-info">
|
||||||
<section>
|
<section>
|
||||||
<div class="scenery-info-general" v-if="station.generalInfo">
|
<div class="scenery-info-general">
|
||||||
<SceneryInfoIcons :station="station" />
|
<SceneryInfoIcons :station="station" />
|
||||||
|
|
||||||
<div class="scenery-general-list">
|
<div class="scenery-general-list" v-if="station?.generalInfo">
|
||||||
<span>
|
<span>
|
||||||
<b>{{ $t('availability.title') }}:</b>
|
<b>{{ $t('availability.title') }}:</b>
|
||||||
{{ $t(`availability.${station.generalInfo.availability}`) }}
|
{{ $t(`availability.${station.generalInfo.availability}`) }}
|
||||||
@@ -46,11 +46,11 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SceneryInfoRoutes :station="station" />
|
<SceneryInfoRoutes v-if="station" :station="station" />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="scenery-authors"
|
class="scenery-authors"
|
||||||
v-if="station.generalInfo.authors && station.generalInfo.authors.length > 0"
|
v-if="station?.generalInfo?.authors && station.generalInfo.authors.length > 0"
|
||||||
>
|
>
|
||||||
<b>
|
<b>
|
||||||
{{
|
{{
|
||||||
@@ -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: {
|
||||||
@@ -102,15 +102,13 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as PropType<Station>,
|
type: Object as PropType<Station>
|
||||||
required: true
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onlineScenery: {
|
onlineScenery: {
|
||||||
type: Object as PropType<OnlineScenery>,
|
type: Object as PropType<OnlineScenery>
|
||||||
required: false
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,16 @@
|
|||||||
|
|
||||||
<router-link
|
<router-link
|
||||||
class="dispatcher_name"
|
class="dispatcher_name"
|
||||||
:to="`/journal/dispatchers?dispatcherName=${onlineScenery.dispatcherName}`"
|
:to="`/journal/dispatchers?search-dispatcher=${onlineScenery.dispatcherName}`"
|
||||||
>
|
>
|
||||||
{{ onlineScenery.dispatcherName }}
|
<span
|
||||||
|
class="text--donator"
|
||||||
|
v-if="isDonator(onlineScenery.dispatcherName)"
|
||||||
|
:title="$t('donations.dispatcher-message')"
|
||||||
|
>
|
||||||
|
{{ onlineScenery.dispatcherName }}
|
||||||
|
</span>
|
||||||
|
<span v-else>{{ onlineScenery.dispatcherName }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<span class="dispatcher_likes text--primary">
|
<span class="dispatcher_likes text--primary">
|
||||||
@@ -22,9 +29,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,10 +42,11 @@ 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';
|
||||||
|
import donatorMixin from '../../../mixins/donatorMixin';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [styleMixin, dateMixin, routerMixin],
|
mixins: [styleMixin, dateMixin, routerMixin, donatorMixin],
|
||||||
props: {
|
props: {
|
||||||
onlineScenery: {
|
onlineScenery: {
|
||||||
type: Object as PropType<OnlineScenery>,
|
type: Object as PropType<OnlineScenery>,
|
||||||
|
|||||||
@@ -1,24 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="info-icons">
|
<section class="info-icons">
|
||||||
<span
|
<span v-if="!station || !station.generalInfo">
|
||||||
v-if="station.generalInfo && station.generalInfo.reqLevel >= 0"
|
<img
|
||||||
class="scenery-icon icon-info level"
|
class="icon-info"
|
||||||
:style="calculateExpStyle(station.generalInfo.reqLevel)"
|
src="/images/icon-unknown.svg"
|
||||||
>
|
alt="icon-unknown"
|
||||||
{{ station.generalInfo.reqLevel >= 2 ? station.generalInfo.reqLevel : 'L' }}
|
:title="$t('desc.unknown')"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
v-if="station.generalInfo"
|
v-if="station?.generalInfo && station?.generalInfo.reqLevel >= 0"
|
||||||
|
class="scenery-icon icon-info level"
|
||||||
|
:style="calculateExpStyle(station?.generalInfo.reqLevel)"
|
||||||
|
>
|
||||||
|
{{ station?.generalInfo.reqLevel >= 2 ? station?.generalInfo.reqLevel : 'L' }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
v-if="station?.generalInfo"
|
||||||
class="scenery-icon icon-info"
|
class="scenery-icon icon-info"
|
||||||
:class="station.generalInfo.controlType.replace('+', '-')"
|
:class="station?.generalInfo.controlType.replace('+', '-')"
|
||||||
:title="$t('desc.control-type') + $t(`controls.${station.generalInfo.controlType}`)"
|
:title="$t('desc.control-type') + $t(`controls.${station?.generalInfo.controlType}`)"
|
||||||
v-html="getControlTypeAbbrev(station.generalInfo.controlType)"
|
v-html="getControlTypeAbbrev(station?.generalInfo.controlType)"
|
||||||
>
|
>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
v-if="station.generalInfo?.SUP"
|
v-if="station?.generalInfo?.SUP"
|
||||||
class="icon-info"
|
class="icon-info"
|
||||||
src="/images/icon-SUP.svg"
|
src="/images/icon-SUP.svg"
|
||||||
alt="SUP (RASP-UZK)"
|
alt="SUP (RASP-UZK)"
|
||||||
@@ -26,7 +35,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
v-if="station.generalInfo?.signalType"
|
v-if="station?.generalInfo?.signalType"
|
||||||
class="icon-info"
|
class="icon-info"
|
||||||
:src="`/images/icon-${station.generalInfo.signalType}.svg`"
|
:src="`/images/icon-${station.generalInfo.signalType}.svg`"
|
||||||
:alt="station.generalInfo.signalType"
|
:alt="station.generalInfo.signalType"
|
||||||
@@ -34,7 +43,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
v-if="station.generalInfo?.availability == 'nonPublic'"
|
v-if="station?.generalInfo?.availability == 'nonPublic'"
|
||||||
class="icon-info"
|
class="icon-info"
|
||||||
src="/images/icon-lock.svg"
|
src="/images/icon-lock.svg"
|
||||||
alt="Non-public scenery"
|
alt="Non-public scenery"
|
||||||
@@ -42,7 +51,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
v-if="station.generalInfo?.availability == 'unavailable'"
|
v-if="station?.generalInfo?.availability == 'unavailable'"
|
||||||
class="icon-info"
|
class="icon-info"
|
||||||
src="/images/icon-unavailable.svg"
|
src="/images/icon-unavailable.svg"
|
||||||
alt="Unavailable scenery"
|
alt="Unavailable scenery"
|
||||||
@@ -50,7 +59,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
v-if="station.generalInfo?.availability == 'abandoned'"
|
v-if="station?.generalInfo?.availability == 'abandoned'"
|
||||||
class="icon-info"
|
class="icon-info"
|
||||||
src="/images/icon-abandoned.svg"
|
src="/images/icon-abandoned.svg"
|
||||||
alt="Abandoned scenery"
|
alt="Abandoned scenery"
|
||||||
@@ -58,20 +67,12 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
v-if="station.generalInfo?.lines"
|
v-if="station?.generalInfo?.lines"
|
||||||
class="icon-info"
|
class="icon-info"
|
||||||
src="/images/icon-real.svg"
|
src="/images/icon-real.svg"
|
||||||
alt="real scenery"
|
alt="real scenery"
|
||||||
:title="`${$t('desc.real')} ${station.generalInfo.lines}`"
|
:title="`${$t('desc.real')} ${station.generalInfo.lines}`"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<img
|
|
||||||
v-if="!station.generalInfo"
|
|
||||||
class="icon-info"
|
|
||||||
src="/images/icon-unknown.svg"
|
|
||||||
alt="icon-unknown"
|
|
||||||
:title="$t('desc.unknown')"
|
|
||||||
/>
|
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -85,8 +86,7 @@ export default defineComponent({
|
|||||||
mixins: [stationInfoMixin, styleMixin],
|
mixins: [stationInfoMixin, styleMixin],
|
||||||
props: {
|
props: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as PropType<Station>,
|
type: Object as PropType<Station>
|
||||||
required: true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,41 +1,49 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="info-routes" v-if="station.generalInfo">
|
<section class="info-routes" v-if="station.generalInfo">
|
||||||
<div class="routes one-way" v-if="station.generalInfo.routes.oneWay.length > 0">
|
<div class="routes one-way" v-if="filteredOneWayRoutes.length > 0">
|
||||||
<b>{{ $t('scenery.one-way-routes') }}</b>
|
<b>{{ $t('scenery.one-way-routes') }}</b>
|
||||||
|
|
||||||
<ul class="routes-list">
|
<ul class="routes-list">
|
||||||
<li
|
<li
|
||||||
v-for="route in station.generalInfo.routes.oneWay"
|
v-for="route in filteredOneWayRoutes"
|
||||||
:key="route.name"
|
:key="route.routeName"
|
||||||
@click="setActiveShowLength(route.name)"
|
@click="setActiveShowLength(route.routeName)"
|
||||||
>
|
>
|
||||||
<span :class="{ 'no-catenary': !route.catenary, internal: route.isInternal }">
|
<span :class="{ 'no-catenary': !route.isElectric, internal: route.isInternal }">
|
||||||
{{ route.name }}</span
|
{{ route.routeName }}</span
|
||||||
>
|
>
|
||||||
<span v-if="route.speed" class="speed">
|
<span v-if="route.routeSpeed" class="speed">
|
||||||
{{ activeShowLength.includes(route.name) ? route.length + 'm' : route.speed }}
|
{{
|
||||||
|
activeShowLength.includes(route.routeName)
|
||||||
|
? route.routeLength + 'm'
|
||||||
|
: route.routeSpeed
|
||||||
|
}}
|
||||||
</span>
|
</span>
|
||||||
<span v-if="route.SBL" class="sbl">SBL</span>
|
<span v-if="route.isRouteSBL" class="sbl">SBL</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="routes two-way" v-if="station.generalInfo.routes.twoWay.length > 0">
|
<div class="routes two-way" v-if="filteredTwoWayRoutes.length > 0">
|
||||||
<b>{{ $t('scenery.two-way-routes') }}</b>
|
<b>{{ $t('scenery.two-way-routes') }}</b>
|
||||||
|
|
||||||
<ul class="routes-list">
|
<ul class="routes-list">
|
||||||
<li
|
<li
|
||||||
v-for="route in station.generalInfo.routes.twoWay"
|
v-for="route in filteredTwoWayRoutes"
|
||||||
:key="route.name"
|
:key="route.routeName"
|
||||||
@click="setActiveShowLength(route.name)"
|
@click="setActiveShowLength(route.routeName)"
|
||||||
>
|
>
|
||||||
<span :class="{ 'no-catenary': !route.catenary, internal: route.isInternal }">{{
|
<span :class="{ 'no-catenary': !route.isElectric, internal: route.isInternal }">{{
|
||||||
route.name
|
route.routeName
|
||||||
}}</span>
|
}}</span>
|
||||||
<span v-if="route.speed" class="speed">
|
<span v-if="route.routeSpeed" class="speed">
|
||||||
{{ activeShowLength.includes(route.name) ? route.length + 'm' : route.speed }}
|
{{
|
||||||
|
activeShowLength.includes(route.routeName)
|
||||||
|
? route.routeLength + 'm'
|
||||||
|
: route.routeSpeed
|
||||||
|
}}
|
||||||
</span>
|
</span>
|
||||||
<span v-if="route.SBL" class="sbl">SBL</span>
|
<span v-if="route.isRouteSBL" class="sbl">SBL</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -45,6 +53,9 @@
|
|||||||
<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 { StationRoutesInfo } from '../../../store/typings';
|
||||||
|
|
||||||
|
const routeFilter = (route: StationRoutesInfo) => !route.hidden;
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -66,6 +77,16 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
activeShowLength: [] as string[]
|
activeShowLength: [] as string[]
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
filteredOneWayRoutes() {
|
||||||
|
return this.station.generalInfo?.routes.oneWay.filter(routeFilter) || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
filteredTwoWayRoutes() {
|
||||||
|
return this.station.generalInfo?.routes.twoWay.filter(routeFilter) || [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -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],
|
||||||
|
|||||||
@@ -13,14 +13,14 @@
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="header_links">
|
<span class="header_links" v-if="station">
|
||||||
<a
|
<!-- <a
|
||||||
:href="`https://pragotron-td2.web.app/board?name=${station.name}`"
|
:href="`https://pragotron-td2.web.app/board?name=${station.name}`"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
:title="$t('scenery.pragotron-link')"
|
:title="$t('scenery.pragotron-link')"
|
||||||
>
|
>
|
||||||
<img src="/images/icon-pragotron.svg" alt="icon-pragotron" />
|
<img src="/images/icon-pragotron.svg" alt="icon-pragotron" />
|
||||||
</a>
|
</a> -->
|
||||||
|
|
||||||
<a :href="tabliceZbiorczeHref" target="_blank" :title="$t('scenery.tablice-link')">
|
<a :href="tabliceZbiorczeHref" target="_blank" :title="$t('scenery.tablice-link')">
|
||||||
<img src="/images/icon-tablice.ico" alt="icon-tablice" />
|
<img src="/images/icon-tablice.ico" alt="icon-tablice" />
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
<transition-group name="list-anim">
|
<transition-group name="list-anim">
|
||||||
<div
|
<div
|
||||||
style="padding-bottom: 5em"
|
style="padding-bottom: 5em"
|
||||||
v-if="store.dataStatuses.trains == 0 && computedScheduledTrains.length == 0"
|
v-if="apiStore.dataStatuses.connection == 0 && computedScheduledTrains.length == 0"
|
||||||
key="list-loading"
|
key="list-loading"
|
||||||
>
|
>
|
||||||
<Loading />
|
<Loading />
|
||||||
@@ -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,11 @@ 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 { useMainStore } 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';
|
||||||
|
import { useApiStore } from '../../store/apiStore';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SceneryTimetable',
|
name: 'SceneryTimetable',
|
||||||
@@ -199,12 +202,10 @@ export default defineComponent({
|
|||||||
|
|
||||||
props: {
|
props: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as PropType<Station>,
|
type: Object as PropType<Station>
|
||||||
required: true
|
|
||||||
},
|
},
|
||||||
onlineScenery: {
|
onlineScenery: {
|
||||||
type: Object as PropType<OnlineScenery>,
|
type: Object as PropType<OnlineScenery>
|
||||||
required: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -224,7 +225,8 @@ export default defineComponent({
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const currentURL = computed(() => `${location.origin}${route.fullPath}`);
|
const currentURL = computed(() => `${location.origin}${route.fullPath}`);
|
||||||
|
|
||||||
const store = useStore();
|
const apiStore = useApiStore();
|
||||||
|
const mainStore = useMainStore();
|
||||||
|
|
||||||
const chosenCheckpoint = ref(
|
const chosenCheckpoint = ref(
|
||||||
props.station?.generalInfo?.checkpoints?.length == 0
|
props.station?.generalInfo?.checkpoints?.length == 0
|
||||||
@@ -235,25 +237,29 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
currentURL,
|
currentURL,
|
||||||
chosenCheckpoint,
|
chosenCheckpoint,
|
||||||
store
|
apiStore,
|
||||||
|
mainStore
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
tabliceZbiorczeHref() {
|
tabliceZbiorczeHref() {
|
||||||
let url = `https://tablice-td2.web.app/?station=${this.station.name}`;
|
let url = `https://tablice-td2.web.app/?station=${this.station!.name}`;
|
||||||
if (this.chosenCheckpoint) url += `&checkpoint=${this.chosenCheckpoint}`;
|
if (this.chosenCheckpoint) url += `&checkpoint=${this.chosenCheckpoint}`;
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
|
|
||||||
computedScheduledTrains() {
|
computedScheduledTrains() {
|
||||||
|
if (!this.station) return [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
this.onlineScenery?.scheduledTrains
|
this.onlineScenery?.scheduledTrains
|
||||||
?.filter(
|
?.filter(
|
||||||
(train) =>
|
(train) =>
|
||||||
train.checkpointName.toLocaleLowerCase() ==
|
train.checkpointName.toLocaleLowerCase() ==
|
||||||
(this.chosenCheckpoint || this.station.name).toLocaleLowerCase()
|
(this.chosenCheckpoint || this.station!.name).toLocaleLowerCase() &&
|
||||||
|
train.region == this.mainStore.region.id
|
||||||
)
|
)
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
if (a.stopStatusID > b.stopStatusID) return 1;
|
if (a.stopStatusID > b.stopStatusID) return 1;
|
||||||
@@ -270,6 +276,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
loadSelectedOption() {
|
loadSelectedOption() {
|
||||||
|
if (!this.station) return;
|
||||||
|
|
||||||
this.chosenCheckpoint =
|
this.chosenCheckpoint =
|
||||||
this.station.generalInfo?.checkpoints[0]?.checkpointName || this.station.name;
|
this.station.generalInfo?.checkpoints[0]?.checkpointName || this.station.name;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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,20 +28,25 @@
|
|||||||
<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?search-train=%23${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 />
|
||||||
{{ historyItem.trainNo }}
|
{{ historyItem.trainNo }}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ historyItem.route.replace('|', ' -> ') }}</td>
|
<td>{{ historyItem.route.replace('|', ' -> ') }}</td>
|
||||||
<td>{{ historyItem.driverName }}</td>
|
<td>
|
||||||
|
<router-link :to="`/journal/timetables?search-driver=${historyItem.driverName}`">
|
||||||
|
{{ historyItem.driverName }}
|
||||||
|
</router-link>
|
||||||
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="historyItem.authorName"
|
v-if="historyItem.authorName"
|
||||||
:to="`/journal/timetables?authorName=${historyItem.authorName}`"
|
:to="`/journal/timetables?search-dispatcher=${historyItem.authorName}`"
|
||||||
>{{ historyItem.authorName }}
|
>{{ historyItem.authorName }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<i v-else>{{ $t('scenery.timetable-author-unknown') }}</i>
|
<i v-else>{{ $t('scenery.timetable-author-unknown') }}</i>
|
||||||
@@ -53,63 +68,72 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
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 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';
|
||||||
|
import http from '../../http';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'SceneryTimetablesHistory',
|
name: 'SceneryTimetablesHistory',
|
||||||
mixins: [dateMixin, listObserverMixin],
|
mixins: [dateMixin, listObserverMixin],
|
||||||
props: {
|
props: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as PropType<Station>,
|
type: Object as PropType<Station>
|
||||||
required: true
|
|
||||||
},
|
},
|
||||||
onlineScenery: {
|
onlineScenery: {
|
||||||
type: Object as PropType<OnlineScenery>,
|
type: Object as PropType<OnlineScenery>
|
||||||
required: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
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() {
|
||||||
try {
|
if (!this.station && !this.onlineScenery) {
|
||||||
const requestString = `${URLs.stacjownikAPI}/api/getIssuedTimetables?name=${this.station.name}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
this.dataStatus = Status.Data.Loaded;
|
||||||
const historyAPIData: SceneryTimetableHistory = await (await axios.get(requestString)).data;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.dataStatus = DataStatus.Loaded;
|
try {
|
||||||
return historyAPIData;
|
const response: API.TimetableHistory.Response = await (
|
||||||
|
await http.get('api/getTimetables', {
|
||||||
|
params: {
|
||||||
|
issuedFrom: this.station?.name || this.onlineScenery?.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
).data;
|
||||||
|
|
||||||
|
this.historyList = response;
|
||||||
|
|
||||||
|
this.dataStatus = Status.Data.Loaded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
navigateToHistory() {
|
navigateToHistory() {
|
||||||
this.$router.push(`/journal/timetables?issuedFrom=${this.station.name}`);
|
this.$router.push({
|
||||||
|
path: '/journal/timetables',
|
||||||
|
query: {
|
||||||
|
'search-issuedFrom': this.station?.name || this.onlineScenery?.name
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: { Loading }
|
components: { Loading }
|
||||||
@@ -119,4 +143,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;
|
||||||
|
|||||||
@@ -60,8 +60,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="card_timestamp" style="text-align: center">
|
<section class="card_timestamp">
|
||||||
<div>{{ $t('filters.minimum-hours-title') }}</div>
|
<h3 class="section-header">{{ $t('filters.minimum-hours-title') }}</h3>
|
||||||
|
|
||||||
<span class="clock">
|
<span class="clock">
|
||||||
<button class="btn--action" @click="subHour">-</button>
|
<button class="btn--action" @click="subHour">-</button>
|
||||||
<span>{{
|
<span>{{
|
||||||
@@ -75,16 +76,27 @@
|
|||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<datalist id="authors">
|
||||||
|
<option v-for="(author, i) in authors" :key="i" :value="author"></option>
|
||||||
|
</datalist>
|
||||||
|
|
||||||
<section class="card_authors-search">
|
<section class="card_authors-search">
|
||||||
<input
|
<h3 class="section-header">{{ $t('filters.authors-search') }}</h3>
|
||||||
type="text"
|
|
||||||
:placeholder="$t('filters.authors-search')"
|
<form action="javascript:void(0);" @submit="handleAuthorsInput">
|
||||||
name="authors"
|
<input
|
||||||
v-model="authorsInputValue"
|
type="text"
|
||||||
@input="handleAuthorsInput"
|
id="author"
|
||||||
@focus="preventKeyDown = true"
|
list="authors"
|
||||||
@blur="preventKeyDown = false"
|
name="authors"
|
||||||
/>
|
:placeholder="$t('filters.authors-placeholder')"
|
||||||
|
v-model="authorsInputValue"
|
||||||
|
@focus="preventKeyDown = true"
|
||||||
|
@blur="preventKeyDown = false"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button class="btn--action">{{ $t('filters.authors-button-title') }}</button>
|
||||||
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="card_sliders">
|
<section class="card_sliders">
|
||||||
@@ -138,11 +150,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 { useMainStore } 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 },
|
||||||
@@ -163,7 +175,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
const isVisible = inject('isFilterCardVisible');
|
const isVisible = inject('isFilterCardVisible');
|
||||||
const store = useStore();
|
const store = useMainStore();
|
||||||
const filterStore = useStationFiltersStore();
|
const filterStore = useStationFiltersStore();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -196,6 +208,19 @@ export default defineComponent({
|
|||||||
|
|
||||||
currentOptionsActive() {
|
currentOptionsActive() {
|
||||||
return true;
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
authors() {
|
||||||
|
return this.store.stationList
|
||||||
|
.reduce((acc, station) => {
|
||||||
|
station.generalInfo?.authors?.forEach((author) => {
|
||||||
|
if (author.trim() != '' && !acc.includes(author.toLocaleLowerCase()))
|
||||||
|
acc.push(author.toLocaleLowerCase());
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, [] as string[])
|
||||||
|
.sort((a, b) => a.localeCompare(b));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -230,12 +255,12 @@ export default defineComponent({
|
|||||||
if (this.saveOptions) StorageManager.setStringValue(target.name, target.value);
|
if (this.saveOptions) StorageManager.setStringValue(target.name, target.value);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleAuthorsInput(e: Event) {
|
handleAuthorsInput() {
|
||||||
clearTimeout(this.delayInputTimer);
|
console.log(this.authorsInputValue);
|
||||||
|
|
||||||
this.delayInputTimer = window.setTimeout(() => {
|
this.filterStore.changeFilterValue('authors', this.authorsInputValue);
|
||||||
this.handleInput(e);
|
|
||||||
}, 400);
|
if (this.saveOptions) StorageManager.setStringValue('authors', this.authorsInputValue);
|
||||||
},
|
},
|
||||||
|
|
||||||
changeNumericFilterValue(name: string, value: number, saveToStorage = false) {
|
changeNumericFilterValue(name: string, value: number, saveToStorage = false) {
|
||||||
@@ -295,150 +320,141 @@ 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 {
|
h3.section-header {
|
||||||
&-enter-active,
|
text-align: center;
|
||||||
&-leave-active {
|
margin: 0.5em 0;
|
||||||
transition: all $animDuration $animType;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translate(-50%, -50%) scale(0.45);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 1fr auto;
|
grid-template-rows: 1fr auto;
|
||||||
|
}
|
||||||
|
|
||||||
&_info {
|
.card_info {
|
||||||
background-color: #111;
|
background-color: #111;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card_controls {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
input {
|
||||||
|
border-radius: 0.5em 0.5em 0 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card_content {
|
||||||
|
padding: 1em 0.5em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
gap: 1em;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card_title {
|
||||||
|
font-size: 2em;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $accentCol;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card_regions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
label > input {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&_controls {
|
label > span {
|
||||||
|
padding: 0.25em 0.5em;
|
||||||
|
margin: 0 0.25em;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
background-color: gray;
|
||||||
|
|
||||||
|
&.checked {
|
||||||
|
background-color: seagreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card_timestamp {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.clock {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
font-size: 1.2em;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
span {
|
||||||
|
min-width: 120px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: $accentCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 0.2em 0.6em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card_authors-search {
|
||||||
|
margin: 1em 0;
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5em;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 70%;
|
||||||
|
max-width: 400px;
|
||||||
|
padding: 0.5em;
|
||||||
|
outline: 1px solid white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card_actions {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5em;
|
||||||
|
|
||||||
|
.filter-option {
|
||||||
|
max-width: 50%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
|
|
||||||
input {
|
|
||||||
border-radius: 0.5em 0.5em 0 0;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&_content {
|
|
||||||
padding: 1em 0.5em;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
gap: 1em;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&_title {
|
|
||||||
font-size: 2em;
|
|
||||||
font-weight: 700;
|
|
||||||
color: $accentCol;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&_regions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
label > input {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
label > span {
|
|
||||||
padding: 0.25em 0.5em;
|
|
||||||
margin: 0 0.25em;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
background-color: gray;
|
|
||||||
|
|
||||||
&.checked {
|
|
||||||
background-color: seagreen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&_timestamp {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
.clock {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
font-size: 1.2em;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
|
|
||||||
span {
|
|
||||||
min-width: 120px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: $accentCol;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
padding: 0.2em 0.6em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&_modes {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
.option {
|
|
||||||
margin: 0 1em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&_authors-search {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 60%;
|
|
||||||
min-width: 240px;
|
|
||||||
|
|
||||||
input {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0.5em;
|
|
||||||
border: 1px solid white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&_actions {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.5em;
|
|
||||||
|
|
||||||
.filter-option {
|
margin-top: 0.5em;
|
||||||
max-width: 50%;
|
|
||||||
|
button {
|
||||||
|
width: 50%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
padding: 0.5em;
|
||||||
|
|
||||||
.action-buttons {
|
&[data-selected='true'] {
|
||||||
display: flex;
|
background-color: forestgreen;
|
||||||
gap: 0.5em;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
margin-top: 0.5em;
|
|
||||||
|
|
||||||
button {
|
|
||||||
width: 50%;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0.5em;
|
|
||||||
|
|
||||||
&[data-selected='true'] {
|
|
||||||
background-color: forestgreen;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,7 +475,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
.section-inputs {
|
.section-inputs {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, 1fr);
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,14 +108,26 @@
|
|||||||
|
|
||||||
<td class="station_status">
|
<td class="station_status">
|
||||||
<StationStatusBadge
|
<StationStatusBadge
|
||||||
:statusID="station.onlineInfo?.statusID"
|
|
||||||
:isOnline="station.onlineInfo ? true : false"
|
:isOnline="station.onlineInfo ? true : false"
|
||||||
:statusTimestamp="station.onlineInfo?.statusTimestamp"
|
:dispatcherStatus="station.onlineInfo?.dispatcherStatus"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="station_dispatcher-name">
|
<td class="station_dispatcher-name">
|
||||||
{{ station.onlineInfo ? station.onlineInfo.dispatcherName : '' }}
|
<span v-if="station.onlineInfo?.dispatcherName">
|
||||||
|
<b
|
||||||
|
v-if="apiStore.donatorsData.includes(station.onlineInfo.dispatcherName)"
|
||||||
|
:title="$t('donations.dispatcher-message')"
|
||||||
|
@click.stop="openDonationModal"
|
||||||
|
>
|
||||||
|
<img src="/images/icon-diamond.svg" alt="" />
|
||||||
|
{{ station.onlineInfo.dispatcherName }}
|
||||||
|
</b>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
{{ station.onlineInfo.dispatcherName }}
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="station_dispatcher-exp">
|
<td class="station_dispatcher-exp">
|
||||||
@@ -128,7 +140,7 @@
|
|||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ 2 > station.onlineInfo.dispatcherExp ? 'L' : station.onlineInfo.dispatcherExp }}
|
{{ station.onlineInfo.dispatcherExp < 2 ? 'L' : station.onlineInfo.dispatcherExp }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@@ -267,7 +279,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Loading v-if="!isDataLoaded && stations.length == 0" />
|
<Loading v-if="apiStore.dataStatuses.connection == Status.Loading" />
|
||||||
|
|
||||||
<div class="no-stations" v-else-if="stations.length == 0">
|
<div class="no-stations" v-else-if="stations.length == 0">
|
||||||
{{ $t('sceneries.no-stations') }}
|
{{ $t('sceneries.no-stations') }}
|
||||||
@@ -276,17 +288,18 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, computed, PropType } from 'vue';
|
import { defineComponent, 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 { useMainStore } 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';
|
||||||
|
import { useApiStore } from '../../store/apiStore';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -296,6 +309,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
emits: ['toggleDonationModal'],
|
||||||
components: { Loading, StationStatusBadge },
|
components: { Loading, StationStatusBadge },
|
||||||
mixins: [styleMixin, dateMixin, stationInfoMixin],
|
mixins: [styleMixin, dateMixin, stationInfoMixin],
|
||||||
|
|
||||||
@@ -312,15 +326,15 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
const store = useStore();
|
const mainStore = useMainStore();
|
||||||
|
const apiStore = useApiStore();
|
||||||
const stationFiltersStore = useStationFiltersStore();
|
const stationFiltersStore = useStationFiltersStore();
|
||||||
|
|
||||||
const isDataLoaded = computed(() => {
|
|
||||||
return store.dataStatuses.sceneries != DataStatus.Loading;
|
|
||||||
});
|
|
||||||
return {
|
return {
|
||||||
isDataLoaded,
|
Status: Status.Data,
|
||||||
stationFiltersStore
|
stationFiltersStore,
|
||||||
|
mainStore,
|
||||||
|
apiStore
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -340,6 +354,11 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
openDonationModal(e: Event) {
|
||||||
|
this.$emit('toggleDonationModal', true);
|
||||||
|
this.mainStore.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 +393,17 @@ $rowCol: #424242;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
section.station_table {
|
.table_wrapper {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
font-weight: 500;
|
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%;
|
||||||
|
|
||||||
@include smallScreen() {
|
@include smallScreen() {
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
@@ -494,6 +509,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;
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
<template>
|
||||||
|
<span class="stop-label" :data-sbl="stop.isSBL">
|
||||||
|
<span class="name" v-html="stop.nameHtml"></span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
v-if="stop.position != 'begin'"
|
||||||
|
class="date arrival"
|
||||||
|
:data-status="
|
||||||
|
stop.arrivalDelay > 0 && stop.status != 'unconfirmed'
|
||||||
|
? 'delayed'
|
||||||
|
: stop.arrivalDelay < 0 && stop.status != 'unconfirmed'
|
||||||
|
? 'preponed'
|
||||||
|
: stop.arrivalDelay == 0 && stop.status == 'confirmed'
|
||||||
|
? 'on-time'
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span v-if="stop.arrivalDelay != 0 && stop.status != 'unconfirmed'">
|
||||||
|
<s>{{ timestampToString(stop.arrivalScheduled) }}</s>
|
||||||
|
{{ timestampToString(stop.arrivalReal) }}
|
||||||
|
({{ stop.arrivalDelay > 0 ? '+' : '' }}{{ stop.arrivalDelay }})
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-else>
|
||||||
|
{{ timestampToString(stop.arrivalScheduled) }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
v-if="
|
||||||
|
stop.duration ||
|
||||||
|
(stop.status == 'stopped' &&
|
||||||
|
stop.position != 'begin' &&
|
||||||
|
stop.departureDelay != stop.arrivalDelay)
|
||||||
|
"
|
||||||
|
class="date stop"
|
||||||
|
:data-stop-types="stop.type.replace(', ', '-')"
|
||||||
|
:data-stop-status="
|
||||||
|
stop.departureDelay - stop.arrivalDelay > 0 && !stop.duration ? 'delayed' : ''
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ stop.duration || stop.departureDelay - stop.arrivalDelay }}
|
||||||
|
{{ stop.type == '' ? 'pt' : stop.type }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
v-if="
|
||||||
|
stop.position != 'end' &&
|
||||||
|
(stop.duration != 0 || stop.status == 'stopped' || stop.departureDelay != stop.arrivalDelay)
|
||||||
|
"
|
||||||
|
class="date departure"
|
||||||
|
:data-status="
|
||||||
|
stop.departureDelay > 0 && stop.status == 'confirmed'
|
||||||
|
? 'delayed'
|
||||||
|
: stop.departureDelay < 0 && stop.status == 'confirmed'
|
||||||
|
? 'preponed'
|
||||||
|
: stop.departureDelay == 0 && stop.status == 'confirmed'
|
||||||
|
? 'on-time'
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span v-if="stop.departureDelay != 0 && stop.status == 'confirmed'">
|
||||||
|
<s>{{ timestampToString(stop.departureScheduled) }}</s>
|
||||||
|
{{ timestampToString(stop.departureReal) }}
|
||||||
|
|
||||||
|
({{ stop.departureDelay > 0 ? '+' : '' }}{{ stop.departureDelay }})
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-else>
|
||||||
|
{{ timestampToString(stop.departureScheduled) }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { PropType, defineComponent } from 'vue';
|
||||||
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
|
import { TrainScheduleStop } from './TrainSchedule.vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
mixins: [dateMixin],
|
||||||
|
|
||||||
|
props: {
|
||||||
|
stop: {
|
||||||
|
type: Object as PropType<TrainScheduleStop>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
$preponedClr: lime;
|
||||||
|
$delayedClr: salmon;
|
||||||
|
$dateClr: #525151;
|
||||||
|
$stopExchangeClr: #db8e29;
|
||||||
|
$stopDefaultClr: #252525;
|
||||||
|
$stopNameClr: #22a8d1;
|
||||||
|
|
||||||
|
.stop-label {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&[data-sbl='true'] {
|
||||||
|
.date {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
background: none;
|
||||||
|
color: #aaa;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
background: $stopNameClr;
|
||||||
|
padding: 0.3em 0.5em;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&.misc {
|
||||||
|
background: gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.date {
|
||||||
|
background: $dateClr;
|
||||||
|
padding: 0.3em 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop {
|
||||||
|
&[data-stop-types='ph'],
|
||||||
|
&[data-stop-types='ph-pm'],
|
||||||
|
&[data-stop-types='pm'] {
|
||||||
|
background: $stopExchangeClr;
|
||||||
|
}
|
||||||
|
|
||||||
|
background: $stopDefaultClr;
|
||||||
|
|
||||||
|
&[data-stop-status='delayed'] {
|
||||||
|
color: $delayedClr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrival,
|
||||||
|
.departure {
|
||||||
|
&[data-status='delayed'] {
|
||||||
|
s {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: $delayedClr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-status='preponed'] {
|
||||||
|
s {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: $preponedClr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -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="apiStore.donatorsData.includes(train.driverName)"
|
||||||
|
:title="$t('donations.driver-message')"
|
||||||
|
>
|
||||||
|
{{ 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,28 +59,33 @@
|
|||||||
|
|
||||||
<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">
|
||||||
|
<img src="/images/icon-offline.svg" alt="" />
|
||||||
{{ $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">
|
||||||
|
<img src="/images/icon-offline.svg" alt="" />
|
||||||
Offline {{ lastSeenMessage(train.lastSeen) }}
|
Offline {{ lastSeenMessage(train.lastSeen) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -111,6 +126,8 @@ 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 { useMainStore } from '../../store/mainStore';
|
||||||
|
import { useApiStore } from '../../store/apiStore';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [trainInfoMixin, styleMixin],
|
mixins: [trainInfoMixin, styleMixin],
|
||||||
@@ -125,6 +142,13 @@ export default defineComponent({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
store: useMainStore(),
|
||||||
|
apiStore: useApiStore()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -168,6 +192,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 +210,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 +228,45 @@ export default defineComponent({
|
|||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
margin-right: 1.5em;
|
margin-right: 1.5em;
|
||||||
}
|
}
|
||||||
.train-status-badges {
|
.general-status {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.train-driver {
|
.status-badges {
|
||||||
&.supporter {
|
|
||||||
color: orange;
|
|
||||||
text-shadow: orange 0 0 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.timetable_route {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timetable_warnings {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timetable_progress {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
|
||||||
|
|
||||||
.timetable_progress-distance {
|
gap: 0.25em;
|
||||||
margin-right: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comments {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
font-size: 0.9em;
|
|
||||||
|
|
||||||
margin-top: 1em;
|
|
||||||
|
|
||||||
img {
|
img {
|
||||||
margin-right: 0.5em;
|
height: 15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.general-timetable {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timetable-warnings {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timetable-progress {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-distance {
|
||||||
|
margin-right: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
@include smallScreen() {
|
@include smallScreen() {
|
||||||
.train-info {
|
.train-info {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
@@ -251,23 +276,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,28 +15,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||||
import trainInfoMixin from '../../mixins/trainInfoMixin';
|
import TrainInfo from './TrainInfo.vue';
|
||||||
import { useStore } from '../../store/store';
|
import TrainSchedule from './TrainSchedule.vue';
|
||||||
import TrainInfo from '../TrainsView/TrainInfo.vue';
|
|
||||||
import TrainSchedule from '../TrainsView/TrainSchedule.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { TrainInfo, TrainSchedule },
|
components: { TrainInfo, TrainSchedule },
|
||||||
mixins: [trainInfoMixin, modalTrainMixin],
|
mixins: [modalTrainMixin],
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
isTopBarVisible: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
return {
|
|
||||||
store
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
activated() {
|
activated() {
|
||||||
const contentEl = this.$refs['content'] as HTMLElement;
|
const contentEl = this.$refs['content'] as HTMLElement;
|
||||||
@@ -44,17 +28,6 @@ export default defineComponent({
|
|||||||
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>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="filters-options" @keydown.esc="showOptions = false">
|
<div class="dropdown" @keydown.esc="showOptions = false">
|
||||||
<div class="bg" v-if="showOptions" @click="showOptions = false"></div>
|
<div class="dropdown_background" v-if="showOptions" @click="showOptions = false"></div>
|
||||||
|
|
||||||
<button class="filter-button btn--filled btn--image" @click="toggleShowOptions" ref="button">
|
<button class="filter-button btn--filled btn--image" @click="toggleShowOptions" ref="button">
|
||||||
<img src="/images/icon-filter2.svg" alt="Open filters icon" />
|
<img src="/images/icon-filter2.svg" alt="Open filters icon" />
|
||||||
@@ -8,8 +8,8 @@
|
|||||||
<span class="active-indicator" v-if="currentOptionsActive"></span>
|
<span class="active-indicator" v-if="currentOptionsActive"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<transition name="options-anim">
|
<transition name="dropdown-anim">
|
||||||
<div class="options_wrapper" v-if="showOptions">
|
<div class="dropdown_wrapper" v-if="showOptions">
|
||||||
<div class="options_content">
|
<div class="options_content">
|
||||||
<h1 class="option-title">{{ $t('options.search-title') }}</h1>
|
<h1 class="option-title">{{ $t('options.search-title') }}</h1>
|
||||||
<div class="search_content">
|
<div class="search_content">
|
||||||
@@ -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>
|
||||||
@@ -79,6 +87,8 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div tabindex="0" @focus="showOptions = false"></div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
@@ -87,8 +97,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 +161,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;
|
||||||
},
|
},
|
||||||
@@ -180,7 +186,8 @@ export default defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/filters_options.scss';
|
@import '../../styles/dropdown.scss';
|
||||||
|
@import '../../styles/dropdown_filters.scss';
|
||||||
|
|
||||||
.search_content > div {
|
.search_content > div {
|
||||||
margin: 0.5em auto;
|
margin: 0.5em auto;
|
||||||
|
|||||||
@@ -2,83 +2,126 @@
|
|||||||
<div class="train-schedule" @click="toggleShowState">
|
<div class="train-schedule" @click="toggleShowState">
|
||||||
<StockList :trainStockList="train.stockList" />
|
<StockList :trainStockList="train.stockList" />
|
||||||
|
|
||||||
<!-- <div class="train-stock"> -->
|
|
||||||
<!-- <ul>
|
|
||||||
<li v-for="(stockName, i) in train.stockList" :key="i">
|
|
||||||
<p>{{ stockName.split(':')[0].split('_').splice(0, 2).join(' ') }} {{ stockName.split(':')[1] }}</p>
|
|
||||||
<TrainThumbnail :name="stockName" />
|
|
||||||
</li>
|
|
||||||
</ul> -->
|
|
||||||
<!-- </div> -->
|
|
||||||
|
|
||||||
<div class="schedule-wrapper" v-if="train.timetableData">
|
<div class="schedule-wrapper" v-if="train.timetableData">
|
||||||
<ul class="stop_list">
|
<div class="stops">
|
||||||
<li
|
<div
|
||||||
v-for="(stop, i) in train.timetableData.followingStops"
|
v-for="(stop, i) in scheduleStops"
|
||||||
:key="i"
|
:key="i"
|
||||||
class="stop"
|
class="stop"
|
||||||
:class="addClasses(stop, i)"
|
:data-status="stop.status"
|
||||||
|
:data-position="stop.position"
|
||||||
|
:data-delayed="stop.departureDelay > 0"
|
||||||
|
:data-stop-type="stop.type"
|
||||||
|
:data-minor-stop-active="stop.isActive"
|
||||||
|
:data-last-confirmed="stop.isLastConfirmed"
|
||||||
|
x
|
||||||
>
|
>
|
||||||
<span class="stop_info">
|
<span class="stop_info">
|
||||||
<div class="indicator"></div>
|
<span class="distance">
|
||||||
|
{{ stop.distance ? stop.distance.toFixed(1) : '' }}
|
||||||
<div class="progress-bar"></div>
|
|
||||||
|
|
||||||
<div class="stop-bar"></div>
|
|
||||||
|
|
||||||
<span class="distance" v-if="stop.stopDistance">
|
|
||||||
{{ Math.floor(stop.stopDistance) }}
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="stop-name" v-html="stop.stopName"> </span>
|
<div class="progress">
|
||||||
|
<div class="line line_node line_node-top"></div>
|
||||||
|
<div class="node"></div>
|
||||||
|
<div class="line line_node line_node-bottom"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<StopDate :stop="stop" />
|
<StopLabel :stop="stop" />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="stop_line" v-if="i < train.timetableData!.followingStops.length - 1">
|
<div class="stop_line">
|
||||||
<div class="progress-bar"></div>
|
<!-- Grid placeholder -->
|
||||||
|
<div></div>
|
||||||
|
|
||||||
<div v-if="stop.comments" style="color: salmon">
|
<div class="progress">
|
||||||
<b>{{ stop.stopNameRAW }} </b>: <span v-html="stop.comments"></span>
|
<div class="line line_connection" v-if="i < scheduleStops.length - 1"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span
|
<div class="bottom-line-info">
|
||||||
v-if="
|
<div class="info-comments" v-if="stop.comments" style="color: salmon">
|
||||||
stop.departureLine == train.timetableData!.followingStops[i + 1].arrivalLine &&
|
<img src="/images/icon-warning.svg" alt="icon-warning" width="20" />
|
||||||
!/sbl/gi.test(stop.departureLine!)
|
<b v-html="stop.comments"></b>
|
||||||
"
|
</div>
|
||||||
>
|
|
||||||
{{ stop.departureLine }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-else-if="!/sbl/gi.test(stop.departureLine!)">
|
<!-- Routes -->
|
||||||
{{ stop.departureLine }} /
|
<span
|
||||||
{{ train.timetableData!.followingStops[i + 1].arrivalLine }}
|
v-if="
|
||||||
</span>
|
stop.departureLine &&
|
||||||
</div>
|
stop.departureLine == scheduleStops[i + 1]?.arrivalLine &&
|
||||||
|
!/sbl/gi.test(stop.departureLine)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ stop.departureLine }}
|
||||||
|
</span>
|
||||||
|
|
||||||
<div class="stop_line" v-else>
|
<span v-else-if="stop.departureLine && !/sbl/gi.test(stop.departureLine)">
|
||||||
<div v-if="stop.comments" style="color: salmon">
|
<div>{{ stop.departureLine }}</div>
|
||||||
<b>{{ stop.stopNameRAW }} </b>: <span v-html="stop.comments"></span>
|
<div
|
||||||
|
class="scenery-change-name"
|
||||||
|
v-if="
|
||||||
|
i < scheduleStops.length - 1 &&
|
||||||
|
stop.sceneryName != scheduleStops[i + 1].sceneryName
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ scheduleStops[i + 1].sceneryName }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ scheduleStops[i + 1].arrivalLine }}
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, PropType } from 'vue';
|
import { 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 StopLabel from './StopLabel.vue';
|
||||||
import { useStore } from '../../store/store';
|
|
||||||
import StopDate from '../Global/StopDate.vue';
|
|
||||||
import StockList from '../Global/StockList.vue';
|
import StockList from '../Global/StockList.vue';
|
||||||
|
import { useMainStore } from '../../store/mainStore';
|
||||||
|
import { useApiStore } from '../../store/apiStore';
|
||||||
|
|
||||||
|
export interface TrainScheduleStop {
|
||||||
|
nameHtml: string;
|
||||||
|
nameRaw: string;
|
||||||
|
|
||||||
|
status: 'confirmed' | 'unconfirmed' | 'stopped';
|
||||||
|
type: string;
|
||||||
|
position: 'begin' | 'end' | 'en-route';
|
||||||
|
|
||||||
|
arrivalScheduled: number;
|
||||||
|
arrivalReal: number;
|
||||||
|
|
||||||
|
departureScheduled: number;
|
||||||
|
departureReal: number;
|
||||||
|
|
||||||
|
departureDelay: number;
|
||||||
|
arrivalDelay: number;
|
||||||
|
|
||||||
|
duration: number | null;
|
||||||
|
|
||||||
|
isActive: boolean;
|
||||||
|
isLastConfirmed: boolean;
|
||||||
|
isSBL: boolean;
|
||||||
|
|
||||||
|
sceneryName: string | null;
|
||||||
|
sceneryHash: string;
|
||||||
|
distance: number;
|
||||||
|
|
||||||
|
arrivalLine: string | null;
|
||||||
|
departureLine: string | null;
|
||||||
|
|
||||||
|
comments: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { StopDate, StockList },
|
components: { StopLabel, StockList },
|
||||||
props: {
|
props: {
|
||||||
train: {
|
train: {
|
||||||
type: Object as PropType<Train>,
|
type: Object as PropType<Train>,
|
||||||
@@ -90,62 +133,108 @@ export default defineComponent({
|
|||||||
|
|
||||||
emits: ['click'],
|
emits: ['click'],
|
||||||
|
|
||||||
setup(props) {
|
data() {
|
||||||
return {
|
return {
|
||||||
store: useStore(),
|
store: useMainStore(),
|
||||||
|
apiStore: useApiStore()
|
||||||
lastConfirmed: computed(() => {
|
|
||||||
return props.train.timetableData!.followingStops.findIndex(
|
|
||||||
(stop, i, stops) => stop.confirmed && !stops[i + 1]?.confirmed && !stops[i + 1]?.stopped
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
activeMinorStops: computed(() => {
|
|
||||||
const lastMajorConfirmed = props.train.timetableData!.followingStops.findIndex(
|
|
||||||
(stop, i, stops) => stop.confirmed && !stops[i + 1]?.confirmed
|
|
||||||
);
|
|
||||||
|
|
||||||
const activeMinorStopList: number[] = [];
|
|
||||||
if (lastMajorConfirmed + 1 >= props.train.timetableData!.followingStops.length)
|
|
||||||
return activeMinorStopList;
|
|
||||||
|
|
||||||
for (
|
|
||||||
let i = lastMajorConfirmed + 1;
|
|
||||||
i < props.train.timetableData!.followingStops.length;
|
|
||||||
i++
|
|
||||||
) {
|
|
||||||
if (/po\.|sbl/gi.test(props.train.timetableData!.followingStops[i].stopNameRAW))
|
|
||||||
activeMinorStopList.push(i);
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return activeMinorStopList;
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
scheduleStops(): TrainScheduleStop[] {
|
||||||
|
let currentSceneryIndex = 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
this.train.timetableData?.followingStops.map((stop, i, arr) => {
|
||||||
|
if (
|
||||||
|
i > 0 &&
|
||||||
|
stop.arrivalLine &&
|
||||||
|
stop.arrivalLine != arr[i - 1].departureLine &&
|
||||||
|
!/sbl/gi.test(stop.arrivalLine)
|
||||||
|
)
|
||||||
|
currentSceneryIndex++;
|
||||||
|
|
||||||
|
return {
|
||||||
|
nameHtml: stop.stopName,
|
||||||
|
nameRaw: stop.stopNameRAW,
|
||||||
|
|
||||||
|
arrivalScheduled: stop.arrivalTimestamp,
|
||||||
|
arrivalReal: stop.arrivalRealTimestamp,
|
||||||
|
|
||||||
|
departureScheduled: stop.departureTimestamp,
|
||||||
|
departureReal: stop.departureRealTimestamp,
|
||||||
|
|
||||||
|
departureDelay: stop.departureDelay,
|
||||||
|
arrivalDelay: stop.arrivalDelay,
|
||||||
|
|
||||||
|
duration: stop.stopTime,
|
||||||
|
|
||||||
|
comments: stop.comments ?? null,
|
||||||
|
|
||||||
|
arrivalLine: stop.arrivalLine,
|
||||||
|
departureLine: stop.departureLine,
|
||||||
|
|
||||||
|
type: stop.stopType,
|
||||||
|
distance: stop.stopDistance,
|
||||||
|
isActive: this.activeMinorStops.includes(i),
|
||||||
|
isLastConfirmed: this.lastConfirmed === i && !stop.terminatesHere,
|
||||||
|
isSBL: /sbl/gi.test(stop.stopName),
|
||||||
|
position: stop.beginsHere ? 'begin' : stop.terminatesHere ? 'end' : 'en-route',
|
||||||
|
sceneryHash: '',
|
||||||
|
sceneryName: this.timetableSceneryNames[currentSceneryIndex],
|
||||||
|
status: stop.confirmed ? 'confirmed' : stop.stopped ? 'stopped' : 'unconfirmed'
|
||||||
|
};
|
||||||
|
}) ?? []
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
lastConfirmed() {
|
||||||
|
return this.train.timetableData?.followingStops.findIndex(
|
||||||
|
(stop, i, stops) => stop.confirmed && !stops[i + 1]?.confirmed && !stops[i + 1]?.stopped
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
activeMinorStops() {
|
||||||
|
if (!this.train.timetableData) return [];
|
||||||
|
|
||||||
|
const lastMajorConfirmed = this.train.timetableData.followingStops.findIndex(
|
||||||
|
(stop, i, stops) => stop.confirmed && !stops[i + 1]?.confirmed
|
||||||
|
);
|
||||||
|
|
||||||
|
const activeMinorStopList: number[] = [];
|
||||||
|
if (lastMajorConfirmed + 1 >= this.train.timetableData.followingStops.length)
|
||||||
|
return activeMinorStopList;
|
||||||
|
|
||||||
|
for (
|
||||||
|
let i = lastMajorConfirmed + 1;
|
||||||
|
i < this.train.timetableData!.followingStops.length;
|
||||||
|
i++
|
||||||
|
) {
|
||||||
|
if (/po\.|sbl/gi.test(this.train.timetableData!.followingStops[i].stopNameRAW))
|
||||||
|
activeMinorStopList.push(i);
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return activeMinorStopList;
|
||||||
|
},
|
||||||
|
|
||||||
|
timetableSceneryNames() {
|
||||||
|
if (!this.train.timetableData?.sceneries) return [];
|
||||||
|
|
||||||
|
return this.train.timetableData?.sceneries
|
||||||
|
.map(
|
||||||
|
(sceneryHash) =>
|
||||||
|
this.store.onlineSceneryList.find((st) => st.hash === sceneryHash)?.name ??
|
||||||
|
this.apiStore.sceneryData.find((sd) => sd.hash === sceneryHash)?.name ??
|
||||||
|
sceneryHash
|
||||||
|
)
|
||||||
|
.reverse();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
toggleShowState() {
|
toggleShowState() {
|
||||||
this.$emit('click');
|
this.$emit('click');
|
||||||
},
|
|
||||||
|
|
||||||
addClasses(stop: TrainStop, index: number) {
|
|
||||||
return {
|
|
||||||
confirmed: stop.confirmed,
|
|
||||||
stopped: stop.stopped,
|
|
||||||
begin: stop.beginsHere,
|
|
||||||
end: stop.terminatesHere,
|
|
||||||
delayed: stop.departureDelay > 0,
|
|
||||||
sbl: /sbl/gi.test(stop.stopName),
|
|
||||||
[stop.stopType.replaceAll(', ', '-')]:
|
|
||||||
stop.stopType.match(new RegExp('ph|pm|pt')) && !stop.confirmed && !stop.beginsHere,
|
|
||||||
'minor-stop-active': this.activeMinorStops.includes(index),
|
|
||||||
'last-confirmed': index == this.lastConfirmed && !stop.terminatesHere
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
onImageError(e: Event) {
|
|
||||||
const imageEl = e.target as HTMLImageElement;
|
|
||||||
imageEl.src = '/images/icon-unknown.png';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -155,17 +244,18 @@ export default defineComponent({
|
|||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
|
|
||||||
$barClr: #b1b1b1;
|
$barClr: #b1b1b1;
|
||||||
$confirmedClr: #18d818;
|
$confirmedClr: #4ae24a;
|
||||||
$stoppedClr: #f55f31;
|
$stoppedClr: #f55f31;
|
||||||
$haltClr: #f8bb36;
|
$haltClr: #f8bb36;
|
||||||
$stopNameClr: #22a8d1;
|
|
||||||
|
$blinkAnim: 0.5s ease-in-out alternate infinite blink;
|
||||||
|
|
||||||
@keyframes blink {
|
@keyframes blink {
|
||||||
from {
|
from {
|
||||||
background-color: $barClr;
|
border-color: $barClr;
|
||||||
}
|
}
|
||||||
to {
|
to {
|
||||||
background-color: $confirmedClr;
|
border-color: $confirmedClr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,216 +271,247 @@ $stopNameClr: #22a8d1;
|
|||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-bar {
|
.stops {
|
||||||
position: absolute;
|
|
||||||
z-index: 10;
|
|
||||||
|
|
||||||
top: -1px;
|
|
||||||
left: -17px;
|
|
||||||
|
|
||||||
height: 100%;
|
|
||||||
width: 3px;
|
|
||||||
|
|
||||||
background-color: $barClr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stop-name {
|
|
||||||
background: $stopNameClr;
|
|
||||||
padding: 0.3em 0.5em;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&.misc {
|
|
||||||
background: gray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.stop-comment {
|
|
||||||
background: forestgreen;
|
|
||||||
padding: 0.3em 0.5em;
|
|
||||||
|
|
||||||
max-width: 250px;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
width: 2em;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.stop_list {
|
|
||||||
margin-left: 2.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.stop_list > li.stop {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
overflow-y: hidden;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
padding: 0 0.5em;
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
&.sbl {
|
.stop {
|
||||||
.stop-date {
|
// Begin stop
|
||||||
display: none;
|
&[data-position='begin'] {
|
||||||
}
|
.node {
|
||||||
|
|
||||||
.stop-name {
|
|
||||||
background: none;
|
|
||||||
color: #aaa;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&[class*='ph'] > .stop_info > .indicator {
|
|
||||||
border-color: $stopNameClr;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[class*='pt'] > .stop_info > .indicator {
|
|
||||||
border-color: #818181;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.begin {
|
|
||||||
.stop_info > .indicator {
|
|
||||||
border-color: lightgreen;
|
border-color: lightgreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stop_info > .progress-bar {
|
.line_node-top {
|
||||||
background: lightgreen;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.end {
|
// End stop
|
||||||
.stop_info > .indicator {
|
&[data-position='end'] {
|
||||||
|
.node {
|
||||||
border-color: salmon;
|
border-color: salmon;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stop_info > .progress-bar {
|
.line_node-bottom {
|
||||||
background: salmon;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.minor-stop-active {
|
// Stop types
|
||||||
.stop_info > .progress-bar {
|
&[data-stop-type*='pt'] .node {
|
||||||
animation: 0.5s ease-in-out alternate infinite blink;
|
border-color: #818181;
|
||||||
}
|
|
||||||
|
|
||||||
.stop_line > .progress-bar {
|
|
||||||
animation: 0.5s ease-in-out alternate infinite blink;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.last-confirmed {
|
&[data-stop-type*='ph'] .node {
|
||||||
.stop_line > .progress-bar {
|
border-color: $haltClr;
|
||||||
animation: 0.5s ease-in-out alternate infinite blink;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.confirmed {
|
&[data-minor-stop-active='true'] {
|
||||||
.stop_info {
|
.progress > .line {
|
||||||
> .progress-bar {
|
animation: $blinkAnim;
|
||||||
background-color: $confirmedClr;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .indicator {
|
|
||||||
border-color: $confirmedClr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stop_line > .progress-bar {
|
& + div {
|
||||||
background-color: $confirmedClr;
|
.progress > .line_node-top {
|
||||||
}
|
animation: $blinkAnim;
|
||||||
}
|
|
||||||
|
|
||||||
&.stopped {
|
|
||||||
.stop_info {
|
|
||||||
> .indicator {
|
|
||||||
border-color: $stoppedClr;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .stop-bar {
|
|
||||||
background: $stoppedClr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.stop_line {
|
// Last confirmed outpost / checkpoint
|
||||||
font-size: 0.8em;
|
&[data-last-confirmed='true'] {
|
||||||
color: #ccc;
|
.progress > .line_connection {
|
||||||
|
animation: $blinkAnim;
|
||||||
|
}
|
||||||
|
|
||||||
padding: 0.35em 0;
|
.progress > .line_node-bottom {
|
||||||
|
animation: $blinkAnim;
|
||||||
|
}
|
||||||
|
|
||||||
position: relative;
|
& + div {
|
||||||
|
.progress > .line_node-top {
|
||||||
.line-segment {
|
animation: $blinkAnim;
|
||||||
color: $barClr;
|
}
|
||||||
font-weight: 500;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.stop_info {
|
// Confirmed status
|
||||||
display: flex;
|
&[data-status='confirmed'] {
|
||||||
|
.progress > .node {
|
||||||
position: relative;
|
border-color: $confirmedClr;
|
||||||
text-align: center;
|
}
|
||||||
|
.progress > .line {
|
||||||
flex-wrap: wrap;
|
border-left: 2px solid $confirmedClr;
|
||||||
|
border-right: 2px solid $confirmedClr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.stop-bar {
|
// Stopped status
|
||||||
|
&[data-status='stopped'] {
|
||||||
|
.progress > .node {
|
||||||
|
border-color: $stoppedClr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress > .line_node {
|
||||||
|
border-color: $stoppedClr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unused so far
|
||||||
|
&[data-track-count-departure='2'] {
|
||||||
|
.progress > .line {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-track-count-arrival='2'] {
|
||||||
|
.progress > .line_node-top {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-track-count-arrival='1'] {
|
||||||
|
.progress > .line_node-top {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-electrified-departure] {
|
||||||
|
.stop_line > .line-speed > .speed-departure {
|
||||||
|
color: #00c1c7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-electrified-arrival] {
|
||||||
|
.stop_line > .line-speed > .speed-next-arrival {
|
||||||
|
color: #00c1c7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop_info,
|
||||||
|
.stop_line {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 30px 40px auto 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-speed {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: #9b9b9b;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop_info {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop_line {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #ccc;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.distance {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
& > .node {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
|
||||||
left: -17px;
|
|
||||||
|
|
||||||
z-index: 10;
|
|
||||||
|
|
||||||
width: 3px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.distance {
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(-100%, -50%);
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
margin-left: -1.75rem;
|
z-index: 15;
|
||||||
|
|
||||||
font-size: 0.75em;
|
|
||||||
color: #d6d6d6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.indicator {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 11;
|
|
||||||
|
|
||||||
top: 50%;
|
|
||||||
left: -1rem;
|
|
||||||
|
|
||||||
transform: translate(-47%, -50%);
|
|
||||||
|
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|
||||||
width: 15px;
|
width: 15px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
|
|
||||||
background: var(--clr-secondary);
|
background-color: var(--clr-secondary);
|
||||||
border: 3px solid $barClr;
|
border: 4px solid $barClr;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& > .line {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
// background-color: $barClr;
|
||||||
|
border-left: 2px solid $barClr;
|
||||||
|
border-right: 2px solid $barClr;
|
||||||
|
|
||||||
|
&.line_connection {
|
||||||
|
transform: translate(-50%, -6px);
|
||||||
|
height: calc(100% + 12px);
|
||||||
|
// height: calc(100% + 0.25em);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.line_node-top {
|
||||||
|
top: 0;
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.line_node-bottom {
|
||||||
|
top: 50%;
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.line_stop {
|
||||||
|
border-color: $stoppedClr;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-comments {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25em;
|
||||||
|
|
||||||
|
margin: 0.25em 0;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 1.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-line-info {
|
||||||
|
.scenery-change-name {
|
||||||
|
position: relative;
|
||||||
|
margin: 0.25em 0;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
height: 2px;
|
||||||
|
width: 30px;
|
||||||
|
background-color: #aaa;
|
||||||
|
|
||||||
|
top: 50%;
|
||||||
|
right: calc(100% + 5px);
|
||||||
|
transform: translate(0, -50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dropdown" @keydown.esc="showOptions = false" @focusout="showOptions = false">
|
||||||
|
<div class="bg" v-if="showOptions" @click="showOptions = false"></div>
|
||||||
|
|
||||||
|
<button class="filter-button btn--filled btn--image" @click="toggleShowOptions" ref="button">
|
||||||
|
<img src="/images/icon-stats.svg" alt="Open filters icon" />
|
||||||
|
{{ $t('train-stats.stats-button') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<transition name="dropdown-anim">
|
||||||
|
<div class="dropdown_wrapper" v-if="showOptions">
|
||||||
|
<h1 class="text--primary">
|
||||||
|
<img src="/images/icon-stats.svg" alt="Open filters icon" />
|
||||||
|
{{ $t('train-stats.title') }}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<hr style="margin: 0.5em 0" />
|
||||||
|
|
||||||
|
<div v-if="apiStore.dataStatuses.connection == Status.Loaded && regionTrains.length > 0">
|
||||||
|
<div class="top-list general">
|
||||||
|
<transition-group tag="ul" name="stats-anim">
|
||||||
|
<li class="badge" key="timetable-count">
|
||||||
|
<span>{{ $t('train-stats.timetable-count') }}</span>
|
||||||
|
<span>
|
||||||
|
<b>{{ regionTrainsWithTT.length }}</b>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="badge" key="avg-speed">
|
||||||
|
<span>{{ $t('train-stats.avg-speed') }}</span>
|
||||||
|
<span>
|
||||||
|
<b>{{ stats.avgSpeed.toFixed(1) }} km/h</b>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="badge" key="avg-distance">
|
||||||
|
<span>{{ $t('train-stats.avg-timetable') }}</span>
|
||||||
|
<span>
|
||||||
|
<b>{{ stats.avgDistance.toFixed(1) }} km</b>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</transition-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="top-list categories">
|
||||||
|
<h3>{{ $t('train-stats.top-categories') }}</h3>
|
||||||
|
|
||||||
|
<transition-group tag="ul" name="stats-anim">
|
||||||
|
<li class="badge" v-for="top in stats.topCategories" :key="top.name">
|
||||||
|
<span>{{ top.name }}</span>
|
||||||
|
<span>{{ top.count }}</span>
|
||||||
|
</li>
|
||||||
|
</transition-group>
|
||||||
|
|
||||||
|
<span class="no-data" v-if="stats.topCategories.length == 0">
|
||||||
|
{{ $t('train-stats.no-timetables') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="top-list vehicles">
|
||||||
|
<h3>{{ $t('train-stats.top-vehicles') }}</h3>
|
||||||
|
|
||||||
|
<transition-group tag="ul" name="stats-anim">
|
||||||
|
<li class="badge" v-for="top in stats.topVehicles" :key="top.name">
|
||||||
|
<span>{{ top.name }}</span>
|
||||||
|
<span>{{ top.count }}</span>
|
||||||
|
</li>
|
||||||
|
</transition-group>
|
||||||
|
|
||||||
|
<span class="no-data" v-if="stats.topVehicles.length == 0">
|
||||||
|
{{ $t('train-stats.no-vehicles') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="top-list vehicle-types">
|
||||||
|
<h3>{{ $t('train-stats.top-units') }}</h3>
|
||||||
|
|
||||||
|
<transition-group tag="ul" name="stats-anim">
|
||||||
|
<li class="badge" v-for="top in stats.topUnits.slice(0, 7)" :key="top.name">
|
||||||
|
<span>{{ top.name }}</span>
|
||||||
|
<span>{{ top.count }}</span>
|
||||||
|
</li>
|
||||||
|
</transition-group>
|
||||||
|
|
||||||
|
<span class="no-data" v-if="stats.topUnits.length == 0">
|
||||||
|
{{ $t('train-stats.no-units') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="apiStore.dataStatuses.connection != Status.Loaded">
|
||||||
|
{{ $t('train-stats.stats-loading') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="no-data" v-else>
|
||||||
|
{{ $t('train-stats.no-stats') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { useMainStore } from '../../store/mainStore';
|
||||||
|
import { Status } from '../../typings/common';
|
||||||
|
import { useApiStore } from '../../store/apiStore';
|
||||||
|
|
||||||
|
interface ITop {
|
||||||
|
name: string;
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IStats {
|
||||||
|
timetableCount: number;
|
||||||
|
avgSpeed: number;
|
||||||
|
avgDistance: number;
|
||||||
|
topCategories: ITop[];
|
||||||
|
topVehicles: ITop[];
|
||||||
|
topUnits: ITop[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareTop(top1: ITop, top2: ITop) {
|
||||||
|
return Math.sign(top2.count - top1.count) || top1.name.localeCompare(top2.name, 'pl-PL');
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showOptions: false,
|
||||||
|
store: useMainStore(),
|
||||||
|
apiStore: useApiStore(),
|
||||||
|
Status: Status.Data
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
regionTrains() {
|
||||||
|
return this.store.trainList.filter((train) => train.region == this.store.region.id);
|
||||||
|
},
|
||||||
|
|
||||||
|
regionTrainsWithTT() {
|
||||||
|
return this.regionTrains.filter((train) => train.timetableData);
|
||||||
|
},
|
||||||
|
|
||||||
|
stats() {
|
||||||
|
const stats = this.regionTrains.reduce(
|
||||||
|
(acc, train, i, arr) => {
|
||||||
|
// AVG SPEED
|
||||||
|
acc.avgSpeed += train.speed / arr.length;
|
||||||
|
|
||||||
|
// TOP VEHICLES
|
||||||
|
const locoType = train.locoType.split('-')[0];
|
||||||
|
const topVehicle = acc.topVehicles.find((top) => top.name == locoType);
|
||||||
|
|
||||||
|
if (!topVehicle) acc.topVehicles.push({ name: locoType, count: 1 });
|
||||||
|
else topVehicle.count++;
|
||||||
|
|
||||||
|
// TOP UNITS
|
||||||
|
const unitType = train.locoType;
|
||||||
|
const topUnit = acc.topUnits.find((top) => top.name == unitType);
|
||||||
|
|
||||||
|
if (!topUnit) acc.topUnits.push({ name: unitType, count: 1 });
|
||||||
|
else topUnit.count++;
|
||||||
|
|
||||||
|
if (train.timetableData !== undefined) {
|
||||||
|
acc.timetableCount++;
|
||||||
|
// AVG DISTANCE
|
||||||
|
acc.avgDistance += train.timetableData.routeDistance;
|
||||||
|
|
||||||
|
// TOP CATEGORIES
|
||||||
|
const topCategory = acc.topCategories.find(
|
||||||
|
(top) => top.name == train.timetableData!.category
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!topCategory)
|
||||||
|
acc.topCategories.push({ name: train.timetableData!.category, count: 1 });
|
||||||
|
else topCategory.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == arr.length - 1 && acc.timetableCount != 0) {
|
||||||
|
acc.avgDistance /= acc.timetableCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timetableCount: 0,
|
||||||
|
avgDistance: 0,
|
||||||
|
avgSpeed: 0,
|
||||||
|
topCategories: [],
|
||||||
|
topUnits: [],
|
||||||
|
topVehicles: []
|
||||||
|
} as IStats
|
||||||
|
);
|
||||||
|
|
||||||
|
stats.topCategories.sort(compareTop);
|
||||||
|
stats.topUnits.sort(compareTop);
|
||||||
|
stats.topVehicles.sort(compareTop);
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
toggleShowOptions() {
|
||||||
|
this.showOptions = !this.showOptions;
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.showOptions) (this.$refs['button'] as HTMLButtonElement)?.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../styles/dropdown.scss';
|
||||||
|
@import '../../styles/badge.scss';
|
||||||
|
@import '../../styles/responsive.scss';
|
||||||
|
|
||||||
|
h1 img {
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data {
|
||||||
|
font-size: 1.1em;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-list ul {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
// @include smallScreen {
|
||||||
|
// justify-content: center;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
& > span:first-child {
|
||||||
|
background-color: $accentCol;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown_wrapper {
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-anim {
|
||||||
|
&-move,
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: all 250ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-leave-active {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include smallScreen {
|
||||||
|
h1,
|
||||||
|
.no-data {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,44 +1,41 @@
|
|||||||
<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="apiStore.dataStatuses.connection">
|
||||||
<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="apiStore.dataStatuses.connection == Status.Loading" key="loading" />
|
||||||
|
|
||||||
|
<div class="table-info" key="no-trains" v-else-if="trains.length == 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 { useMainStore } 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';
|
||||||
|
import { useApiStore } from '../../store/apiStore';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { Loading, TrainInfo },
|
components: { Loading, TrainInfo },
|
||||||
@@ -52,19 +49,18 @@ export default defineComponent({
|
|||||||
|
|
||||||
mixins: [modalTrainMixin],
|
mixins: [modalTrainMixin],
|
||||||
|
|
||||||
setup(props) {
|
setup() {
|
||||||
const store = useStore();
|
const store = useMainStore();
|
||||||
|
const apiStore = useApiStore();
|
||||||
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,
|
||||||
|
apiStore,
|
||||||
|
Status: Status.Data,
|
||||||
sorterActive: inject('sorterActive') as {
|
sorterActive: inject('sorterActive') as {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
dir: number;
|
dir: number;
|
||||||
@@ -72,6 +68,17 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
dataStatus() {
|
||||||
|
if (this.store.isOffline) return Status.Data.Offline;
|
||||||
|
|
||||||
|
if (this.trains.length == 0 && this.apiStore.dataStatuses.connection == 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>
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { PropType, defineComponent } from 'vue';
|
||||||
|
import dateMixin from '../../mixins/dateMixin';
|
||||||
|
import { TrainScheduleStop } from './TrainSchedule.vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
mixins: [dateMixin],
|
||||||
|
|
||||||
|
props: {
|
||||||
|
stop: {
|
||||||
|
type: Object as PropType<TrainScheduleStop>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -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"
|
|
||||||
]
|
|
||||||
@@ -299,22 +299,27 @@
|
|||||||
"regions": [
|
"regions": [
|
||||||
{
|
{
|
||||||
"id": "eu",
|
"id": "eu",
|
||||||
|
"name": "PL1",
|
||||||
"value": "PL1"
|
"value": "PL1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "cae",
|
"id": "cae",
|
||||||
|
"name": "PL2",
|
||||||
"value": "PL2"
|
"value": "PL2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "usw",
|
"id": "usw",
|
||||||
|
"name": "DE",
|
||||||
"value": "DE"
|
"value": "DE"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "us",
|
"id": "us",
|
||||||
|
"name": "CZE",
|
||||||
"value": "CZE"
|
"value": "CZE"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "ru",
|
"id": "ru",
|
||||||
|
"name": "ENG",
|
||||||
"value": "ENG"
|
"value": "ENG"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const http = axios.create({
|
||||||
|
baseURL:
|
||||||
|
import.meta.env.VITE_API_MODE === 'development'
|
||||||
|
? 'http://localhost:3001'
|
||||||
|
: 'https://stacjownik.spythere.eu'
|
||||||
|
});
|
||||||
|
|
||||||
|
export default http;
|
||||||
@@ -1,4 +1,24 @@
|
|||||||
{
|
{
|
||||||
|
"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} (in case of PayPal it must be a payment including additional transaction fees) for the development of Stacjownik, will receive (upon a personal request) {img}{b2} of username in the app and 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-paypal": "DONATE WITH PAYPAL",
|
||||||
|
"action-buycoffee": "BUY ME A COFFEE!",
|
||||||
|
"dispatcher-message": "Dispatcher supporting the Stacjownik project!",
|
||||||
|
"driver-message": "Driver supporting the Stacjownik project!"
|
||||||
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"and": " and ",
|
"and": " and ",
|
||||||
"refresh": "REFRESH",
|
"refresh": "REFRESH",
|
||||||
@@ -78,8 +98,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": {
|
||||||
@@ -123,7 +144,8 @@
|
|||||||
"filter-withComments": "COMMENTS",
|
"filter-withComments": "COMMENTS",
|
||||||
"filter-twr": "HIGH RISK CARGO",
|
"filter-twr": "HIGH RISK CARGO",
|
||||||
"filter-skr": "EXCEEDED GAUGE",
|
"filter-skr": "EXCEEDED GAUGE",
|
||||||
"filter-twr-skr": "ALL TYPES",
|
"filter-twr-skr": "BOTH TYPES",
|
||||||
|
"filter-all-specials": "ALL",
|
||||||
"filter-common": "NO WARNINGS",
|
"filter-common": "NO WARNINGS",
|
||||||
"filter-passenger": "PASSENGER",
|
"filter-passenger": "PASSENGER",
|
||||||
"filter-freight": "FREIGHT",
|
"filter-freight": "FREIGHT",
|
||||||
@@ -135,9 +157,9 @@
|
|||||||
"filter-clear": "CLEAR FILTERS",
|
"filter-clear": "CLEAR FILTERS",
|
||||||
|
|
||||||
"filter-section-timetable-status": "TIMETABLE STATUS",
|
"filter-section-timetable-status": "TIMETABLE STATUS",
|
||||||
"filter-section-twrskr": "WARNINGS",
|
"filter-section-special": "SPECIAL TYPE",
|
||||||
|
|
||||||
"filter-all": "ALL ENTRIES",
|
"filter-all-statuses": "ALL",
|
||||||
"filter-abandoned": "ABANDONED",
|
"filter-abandoned": "ABANDONED",
|
||||||
"filter-fulfilled": "FULFILLED",
|
"filter-fulfilled": "FULFILLED",
|
||||||
"filter-active": "ACTIVE"
|
"filter-active": "ACTIVE"
|
||||||
@@ -205,7 +227,10 @@
|
|||||||
"routes-2t-cat": "MIN. CATENARY DOUBLE TRACK ROUTES",
|
"routes-2t-cat": "MIN. CATENARY DOUBLE TRACK ROUTES",
|
||||||
"routes-2t-other": "MIN. OTHER DOUBLE TRACK ROUTES"
|
"routes-2t-other": "MIN. OTHER DOUBLE TRACK ROUTES"
|
||||||
},
|
},
|
||||||
"authors-search": "Search by author (other filters apply)",
|
"authors-search": "SEARCH BY AUTHOR NAME (other filters apply):",
|
||||||
|
"authors-placeholder": "Enter the author nickname...",
|
||||||
|
"authors-button-title": "Search",
|
||||||
|
|
||||||
"minimum-hours-title": "SHOW ONLY SCENERIES UNTIL:",
|
"minimum-hours-title": "SHOW ONLY SCENERIES UNTIL:",
|
||||||
"now": "NOW",
|
"now": "NOW",
|
||||||
"hour": "h",
|
"hour": "h",
|
||||||
@@ -274,6 +299,21 @@
|
|||||||
"scenery-offline": "Offline ride",
|
"scenery-offline": "Offline ride",
|
||||||
"timeout": "An error occured while trying to refresh SWDR timetable data!"
|
"timeout": "An error occured while trying to refresh SWDR timetable data!"
|
||||||
},
|
},
|
||||||
|
"train-stats": {
|
||||||
|
"stats-button": "STATISTICS",
|
||||||
|
"title": "STATISTICS ONLINE",
|
||||||
|
"timetable-count": "ACTIVE TIMETABLES",
|
||||||
|
"avg-speed": "AVG SPEED",
|
||||||
|
"avg-timetable": "AVG TIMETABLE",
|
||||||
|
"top-categories": "Timetable categories",
|
||||||
|
"top-vehicles": "Vehicles online",
|
||||||
|
"top-units": "Common units online",
|
||||||
|
"stats-loading": "Loading...",
|
||||||
|
"no-timetables": "No active timetables in this region!",
|
||||||
|
"no-vehicles": "No active vehicles in this region!",
|
||||||
|
"no-units": "No active units in this region!",
|
||||||
|
"no-stats": "No statistics available for the current region!"
|
||||||
|
},
|
||||||
"journal": {
|
"journal": {
|
||||||
"title": "DISPATCHER HISTORY",
|
"title": "DISPATCHER HISTORY",
|
||||||
"loading": "Loading dispatcher history data...",
|
"loading": "Loading dispatcher history data...",
|
||||||
@@ -311,29 +351,49 @@
|
|||||||
"last-seen-at": "Last seen at",
|
"last-seen-at": "Last seen at",
|
||||||
"currently-at": "Currently at",
|
"currently-at": "Currently at",
|
||||||
|
|
||||||
"stats-title": "DRIVING STATISTICS OF",
|
"driver-stats": {
|
||||||
|
"button": "DRIVER STATS",
|
||||||
|
"title": "{name}'s DRIVER STATS",
|
||||||
|
"info": "Enter a proper nickname into filters [F] to see user's driving statistics!",
|
||||||
|
"timetables": "TIMETABLES",
|
||||||
|
"longest-timetable": "LONGEST TIMETABLE",
|
||||||
|
"avg-timetable": "AVERAGE TIMETABLE LENGTH",
|
||||||
|
"distance": "DISTANCE",
|
||||||
|
"stations": "STATIONS"
|
||||||
|
},
|
||||||
|
|
||||||
"stats-timetables": "TIMETABLES",
|
"daily-stats": {
|
||||||
"stats-longest-timetable": "LONGEST TIMETABLE",
|
"button": "DAILY STATS",
|
||||||
"stats-avg-timetable": "AVERAGE TIMETABLE LENGTH",
|
"title": "STATS OF THE DAY",
|
||||||
"stats-distance": "DISTANCE",
|
"info": "Today's statistics are unavailable yet!",
|
||||||
"stats-stations": "STATIONS",
|
"total": "Issued timetables: {count} (total distance: {distance})",
|
||||||
|
"longest": "The longest timetable: #{id} (made by {author} for {driver}, distance: {distance})",
|
||||||
|
"most-active-dr": "The most active dispatcher: {dispatcher} (created {count})",
|
||||||
|
"most-active-dr-many": "The most active dispatchers: {dispatchers} (created {count} each)",
|
||||||
|
"most-active-driver": "The most active driver: {driver} (total driven distance: {distance})",
|
||||||
|
"longest-duties": "The longest service: {dispatcher} at {station} (duration: {duration})",
|
||||||
|
"count": "timetable | timetables",
|
||||||
|
|
||||||
"timetable-stats-title": "Daily stats on {date}",
|
"rippedSwitches": "RIPPED SWITCHES",
|
||||||
"timetable-stats-total": "Issued timetables: {count} (total distance: {distance})",
|
"derailments": "DERAILMENTS",
|
||||||
"timetable-stats-longest": "The longest timetable: #{id} (made by {author} for {driver}, distance: {distance})",
|
"skippedStopSignals": "SKIPPED STOP SIGNALS",
|
||||||
"timetable-stats-most-active-dr": "The most active dispatcher: {dispatcher} (created {count})",
|
"radioStops": "RADIOSTOPS",
|
||||||
"timetable-stats-most-active-dr-many": "The most active dispatchers: {dispatchers} (created {count} each)",
|
"kills": "KILLS"
|
||||||
"timetable-stats-most-active-driver": "The most active driver: {driver} (total driven distance: {distance})",
|
},
|
||||||
"timetable-stats-longest-duties": "The longest service: {dispatcher} at {station} (duration: {duration})",
|
|
||||||
|
|
||||||
"timetable-count": "timetable | timetables",
|
"dispatcher-stats": {
|
||||||
|
"button": "DISPATCHER STATS",
|
||||||
"daily-stats-title": "DAILY STATS",
|
"title": "{name}'s DISPATCHER STATS",
|
||||||
"daily-stats-info": "Today's statistics are unavailable yet!",
|
"empty": "This user has no statistics saved yet!",
|
||||||
|
"info": "Enter a proper nickname into filters [F] to see user's dispatcher statistics!",
|
||||||
"driver-stats-title": "DRIVER STATS",
|
"services-count": "SERVICES",
|
||||||
"driver-stats-info": "Enter a proper nickname into filters [F] to see user's driving statistics!",
|
"service-max": "MAX SERVICE DURATION",
|
||||||
|
"service-avg": "AVG SERVICE DURATION",
|
||||||
|
"timetables-count": "ISSUED TIMETABLES",
|
||||||
|
"timetables-sum": "TIMETABLES DISTANCE SUM",
|
||||||
|
"timetables-max": "LONGEST TIMETABLE",
|
||||||
|
"timetables-avg": "AVG TIMETABLE DISTANCE"
|
||||||
|
},
|
||||||
|
|
||||||
"stats-loading": "Fetching statistics...",
|
"stats-loading": "Fetching statistics...",
|
||||||
"stats-error": "Oops! An unexpected error occurred while trying to fetch statistics! :/",
|
"stats-error": "Oops! An unexpected error occurred while trying to fetch statistics! :/",
|
||||||
@@ -369,8 +429,8 @@
|
|||||||
"two-way-routes": "Two way routes",
|
"two-way-routes": "Two way routes",
|
||||||
|
|
||||||
"option-active-timetables": "Active timetables",
|
"option-active-timetables": "Active timetables",
|
||||||
"option-timetables-history": "Timetables history",
|
"option-timetables-history": "Timetables history PL1",
|
||||||
"option-dispatchers-history": "Dispatchers history",
|
"option-dispatchers-history": "Dispatchers history PL1",
|
||||||
|
|
||||||
"timetable-author-title": "Issued by",
|
"timetable-author-title": "Issued by",
|
||||||
"timetable-author-unknown": "Author unknown",
|
"timetable-author-unknown": "Author unknown",
|
||||||
|
|||||||
@@ -1,434 +0,0 @@
|
|||||||
{
|
|
||||||
"general": {
|
|
||||||
"and": " oraz ",
|
|
||||||
"refresh": "ODŚWIEŻ",
|
|
||||||
"TWR": "Towar niebezpieczny wysokiego ryzyka",
|
|
||||||
"SKR": "Przekroczona skrajnia"
|
|
||||||
},
|
|
||||||
"app": {
|
|
||||||
"sceneries": "SCENERIE",
|
|
||||||
"trains": "POCIĄGI",
|
|
||||||
"journal": "DZIENNIK",
|
|
||||||
"loading": "Pobieranie danych...",
|
|
||||||
"support": "Wspomóż projekt",
|
|
||||||
"error": "Wystąpił problem z załadowaniem danych!",
|
|
||||||
"no-result": "Brak wyników o podanych kryteriach!",
|
|
||||||
"migration-warning": "Usługi Stacjownika będą niedostępne w godzinach 1:00-3:00 2 czerwca 2022r. z powodu migracji hostingów API!",
|
|
||||||
"migration-confirm": "Przyjąłem!",
|
|
||||||
"offline": "Aplikacja w trybie offline!"
|
|
||||||
},
|
|
||||||
"footer": {
|
|
||||||
"discord": "Serwer Discord Stacjownika"
|
|
||||||
},
|
|
||||||
"update": {
|
|
||||||
"title": "Nowa wersja Stacjownika jest dostępna!",
|
|
||||||
"paragraph1": "Miłego korzystania z aplikacji i niech S2 będzie z wami!",
|
|
||||||
"release-link": "Kliknij, aby przejrzeć listę zmian (GitHub)",
|
|
||||||
"confirm-button": "ZAKTUALIZUJ",
|
|
||||||
"later-button": "PÓŹNIEJ"
|
|
||||||
},
|
|
||||||
"data-status": {
|
|
||||||
"S1-offline": "<b>Sygnał S1</b> <br> Aplikacja działa w trybie offline!",
|
|
||||||
"S1a-connection": "<b>Sygnał S1a</b> <br> Błąd podczas próby połączenia się z API Stacjownika!",
|
|
||||||
"S1a-sceneries": "<b>Sygnał S1a</b> <br> Błąd podczas pobierania danych o sceneriach online!",
|
|
||||||
"S2": "<b>Sygnał S2</b> <br> Pomyślnie załadowano dane!",
|
|
||||||
"S3": "<b>Sygnał S3</b> <br> Pobieranie danych...",
|
|
||||||
"S5-timetables": "<b>Sygnał S5</b> <br> Rozkłady jazdy mogą być niekompletne!",
|
|
||||||
"S5-dispatchers": "<b>Sygnał S5</b> <br> Błąd podczas pobierania danych o statusach dyżurnych ruchu!",
|
|
||||||
"S5-trains": "<b>Sygnał S5</b> <br> Błąd podczas pobierania danych o pociągach online!"
|
|
||||||
},
|
|
||||||
"desc": {
|
|
||||||
"control-type": "Sterowanie: ",
|
|
||||||
"signals-type": "Sygnalizacja: ",
|
|
||||||
"SBL": "Sceneria posiada SBL na szlakach: ",
|
|
||||||
"SUP": "Wymaga programu SUP do kontroli systemu RASP-UZK",
|
|
||||||
"TWB-all": "Sceneria posiada blokadę dwukierunkową na wszystkich szlakach",
|
|
||||||
"TWB-routes": "Sceneria posiada blokadę dwukierunkową na szlakach: ",
|
|
||||||
"default": "Sceneria dostępna domyślnie w paczce z grą",
|
|
||||||
"non-public": "Sceneria niepubliczna",
|
|
||||||
"unavailable": "Sceneria niedostępna",
|
|
||||||
"unknown": "Nieznana sceneria",
|
|
||||||
"real": "Sceneria z realnymi liniami kolejowymi: ",
|
|
||||||
"abandoned": "Sceneria wycofana z rozgrywki"
|
|
||||||
},
|
|
||||||
"signals": {
|
|
||||||
"title": "Sygnalizacja",
|
|
||||||
"współczesna": "współczesna",
|
|
||||||
"mieszana": "mieszana",
|
|
||||||
"kształtowa": "kształtowa",
|
|
||||||
"historyczna": "historyczna"
|
|
||||||
},
|
|
||||||
"controls": {
|
|
||||||
"title": "Sterowanie",
|
|
||||||
"SPK": "SPK",
|
|
||||||
"SCS": "SCS",
|
|
||||||
"SCS-SPK": "SCS/SPK",
|
|
||||||
"SPE": "SPE",
|
|
||||||
"ręczne": "ręczne",
|
|
||||||
"ręczne+SPK": "ręczne z SPK",
|
|
||||||
"ręczne+SCS": "ręczne z SCS",
|
|
||||||
"mechaniczne": "mechaniczne",
|
|
||||||
"mechaniczne+SPK": "mechaniczne z SPK",
|
|
||||||
"mechaniczne+SCS": "mechaniczne z SCS"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"online": "DO ",
|
|
||||||
"free": "WOLNA",
|
|
||||||
"ending": "KOŃCZY",
|
|
||||||
"not-signed": "NIEZALOGOWANY",
|
|
||||||
"no-limit": "BEZ LIMITU",
|
|
||||||
"unavailable": "NIEDOSTĘPNY",
|
|
||||||
"brb": "Z/W",
|
|
||||||
"no-space": "BRAK MIEJSCA",
|
|
||||||
"unknown": "NIEZNANY"
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"filters": "FILTRY",
|
|
||||||
"donate": "WESPRZYJ",
|
|
||||||
|
|
||||||
"search-button": "Szukaj",
|
|
||||||
"reset-button": "Zresetuj",
|
|
||||||
|
|
||||||
"sort-title": "SORTUJ WG:",
|
|
||||||
"filter-title": "FILTRUJ WG:",
|
|
||||||
"search-title": "SZUKAJ:",
|
|
||||||
|
|
||||||
"search-train-no": "Nr pociągu",
|
|
||||||
"search-train": "Nr pociągu / #",
|
|
||||||
"search-driver": "Nick maszynisty",
|
|
||||||
"search-dispatcher": "Nick dyżurnego",
|
|
||||||
"search-station": "Nazwa scenerii",
|
|
||||||
"search-author": "Nick autora rozkładu jazdy",
|
|
||||||
"search-issuedFrom": "Sceneria początkowa",
|
|
||||||
"search-timetables-date": "Data rozkładu jazdy (UTC+2 / CEST)",
|
|
||||||
"search-dispatchers-date": "Data służby (UTC+2 / CEST)",
|
|
||||||
"search-date": "Data (UTC+2 / CEST)",
|
|
||||||
|
|
||||||
"sort-routeDistance": "kilometraż",
|
|
||||||
"sort-allStopsCount": "stacje",
|
|
||||||
"sort-beginDate": "data",
|
|
||||||
"sort-timetableId": "ID rozkładu",
|
|
||||||
"sort-timestampFrom": "data",
|
|
||||||
"sort-duration": "czas dyżuru",
|
|
||||||
"sort-id": "id rozkładu",
|
|
||||||
|
|
||||||
"sort-mass": "masa",
|
|
||||||
"sort-speed": "prędkość",
|
|
||||||
"sort-length": "długość",
|
|
||||||
"sort-timetable": "nr pociągu",
|
|
||||||
"sort-progress": "przebyta trasa",
|
|
||||||
"sort-delay": "opóźnienie",
|
|
||||||
"sort-comments": "uwagi ekspl.",
|
|
||||||
|
|
||||||
"filter-withComments": "UWAGI EKSPLOATACYJNE",
|
|
||||||
"filter-noComments": "BEZ UWAG",
|
|
||||||
"filter-twr": "WYS. RYZYKA",
|
|
||||||
"filter-skr": "SKRAJNIA",
|
|
||||||
"filter-twr-skr": "WSZYSTKIE",
|
|
||||||
"filter-common": "ZWYKŁE",
|
|
||||||
"filter-passenger": "PASAŻERSKIE",
|
|
||||||
"filter-freight": "TOWAROWE",
|
|
||||||
"filter-other": "INNE",
|
|
||||||
"filter-noTimetable": "BEZ RJ",
|
|
||||||
"filter-withTimetable": "ROZKŁAD JAZDY",
|
|
||||||
|
|
||||||
"filter-reset": "ZRESETUJ FILTRY",
|
|
||||||
"filter-clear": "WYŁĄCZ FILTRY",
|
|
||||||
|
|
||||||
"filter-section-timetable-status": "STATUS ROZKŁADU JAZDY",
|
|
||||||
"filter-section-twrskr": "UWAGI",
|
|
||||||
|
|
||||||
"filter-all": "WSZYSTKIE",
|
|
||||||
"filter-abandoned": "PORZUCONE",
|
|
||||||
"filter-fulfilled": "WYPEŁNIONE",
|
|
||||||
"filter-active": "AKTYWNE"
|
|
||||||
},
|
|
||||||
"filters": {
|
|
||||||
"desc": " • Kliknięcie: zaznaczenie / odznaczenie filtru <br /> • Podwójne kliknięcie: odznaczenie reszty filtrów z <b class='text--primary'>grupy</b> <br /> • <span style='color: coral'>RESET</span>: zresetowanie filtrów z <b class='text--primary'>grupy</b>",
|
|
||||||
|
|
||||||
"sections": {
|
|
||||||
"quick": "SZYBKIE FILTRY",
|
|
||||||
"reality": "FIKCYJNOŚĆ SCENERII",
|
|
||||||
"package-access": "DOSTĘPNOŚĆ W PACZCE",
|
|
||||||
"access": "DOSTĘPNOŚĆ OGÓLNA",
|
|
||||||
"control": "TYP STEROWANIA",
|
|
||||||
"signals": "TYP SYGNALIZACJI",
|
|
||||||
"addons": "DODATKOWE PROGRAMY",
|
|
||||||
"blockades": "BLOKADY LINIOWE",
|
|
||||||
"status": "STATUS ONLINE"
|
|
||||||
},
|
|
||||||
|
|
||||||
"all-available": "WSZYSTKIE DOSTĘPNE",
|
|
||||||
"all-free": "WSZYSTKIE WOLNE",
|
|
||||||
|
|
||||||
"endingStatus": "KOŃCZY",
|
|
||||||
"afkStatus": "Z/W",
|
|
||||||
"noSpaceStatus": "BRAK MIEJSCA",
|
|
||||||
"unavailableStatus": "NIEDOSTĘPNY",
|
|
||||||
|
|
||||||
"title": "FILTRUJ STACJE",
|
|
||||||
"default": "DOMYŚLNA",
|
|
||||||
"not-default": "POZA PACZKĄ",
|
|
||||||
"real": "REALNA",
|
|
||||||
"fictional": "FIKCYJNA",
|
|
||||||
"unavailable": "NIEDOSTĘPNA",
|
|
||||||
"non-public": "NIEPUBLICZNA",
|
|
||||||
"abandoned": "WYCOFANA",
|
|
||||||
|
|
||||||
"SPK": "SPK",
|
|
||||||
"SPK-R": "SPK + RĘCZNE",
|
|
||||||
"SPK-M": "SPK + MECH.",
|
|
||||||
"SCS": "SCS",
|
|
||||||
"SCS-R": "SCS + RĘCZNE",
|
|
||||||
"SCS-M": "SCS + MECH.",
|
|
||||||
"SPE": "SPE",
|
|
||||||
"manual": "RĘCZNE",
|
|
||||||
|
|
||||||
"SUP": "SUP (RASP-UZK)",
|
|
||||||
"noSUP": "BEZ SUP",
|
|
||||||
|
|
||||||
"SBL": "SAMOCZYNNA",
|
|
||||||
"PBL": "PÓŁSAMOCZYNNA",
|
|
||||||
|
|
||||||
"mechanical": "MECHANICZNE",
|
|
||||||
"modern": "WSPÓŁCZESNA",
|
|
||||||
"semaphores": "KSZTAŁTOWA",
|
|
||||||
"mixed": "MIESZANA",
|
|
||||||
"historical": "HISTORYCZNA",
|
|
||||||
|
|
||||||
"free": "WOLNA",
|
|
||||||
"occupied": "ZAJĘTA",
|
|
||||||
|
|
||||||
"sliders": {
|
|
||||||
"min-lvl": "MIN. WYMAGANY POZIOM DYŻURNEGO",
|
|
||||||
"max-lvl": "MAKS. WYMAGANY POZIOM DYŻURNEGO",
|
|
||||||
"routes-1t-cat": "SZLAKI JEDNOTOROWE ZELEKTR. (MINIMUM)",
|
|
||||||
"routes-1t-other": "SZLAKI JEDNOTOROWE NIEZELEKTR. (MINIMUM)",
|
|
||||||
"routes-2t-cat": "SZLAKI DWUTOROWE ZELEKTR. (MINIMUM)",
|
|
||||||
"routes-2t-other": "SZLAKI DWUTOROWE NIEZELEKTR. (MINIMUM)"
|
|
||||||
},
|
|
||||||
|
|
||||||
"authors-search": "Szukaj autora (uwzględnia inne filtry)",
|
|
||||||
"minimum-hours-title": "POKAŻ TYLKO SCENERIE DOSTĘPNE MINIMUM DO:",
|
|
||||||
"now": "TERAZ",
|
|
||||||
"hour": " godz.",
|
|
||||||
"no-limit": "BEZ LIMITU",
|
|
||||||
"include-selected": "POKAŻ ZAZNACZONE",
|
|
||||||
"save": "ZAPAMIĘTAJ FILTRY",
|
|
||||||
"reset": "RESETUJ FILTRY",
|
|
||||||
"close": "ZAMKNIJ FILTRY"
|
|
||||||
},
|
|
||||||
"sceneries": {
|
|
||||||
"station": "Stacja",
|
|
||||||
"abbr": "Skrót\nposterunku",
|
|
||||||
"min-lvl": "Min. poziom\ndyżurnego",
|
|
||||||
"status": "Status",
|
|
||||||
"dispatcher": "Dyżurny",
|
|
||||||
"dispatcher-lvl": "Poziom\ndyżurnego",
|
|
||||||
"routes": "Szlaki\n2tor / 1tor",
|
|
||||||
"general": "Informacje\nogólne",
|
|
||||||
"user": "Maszyniści online",
|
|
||||||
"spawn": "Otwarte spawny",
|
|
||||||
"timetableAll": "Aktywne rozkłady jazdy",
|
|
||||||
"timetableConfirmed": "Zatwierdzone rozkłady jazdy",
|
|
||||||
"timetableUnconfirmed": "Niezatwierdzone rozkłady jazdy",
|
|
||||||
"no-stations": "Brak stacji do wyświetlenia!",
|
|
||||||
"scenery-search": "Wyszukaj scenerię..."
|
|
||||||
},
|
|
||||||
"trains": {
|
|
||||||
"no-trains": "Brak pociągów do wyświetlenia!",
|
|
||||||
"loading": "Pobieranie danych o pociągach...",
|
|
||||||
"offline": "Przejazd offline",
|
|
||||||
|
|
||||||
"stats": "STATYSTYKI RUCHU",
|
|
||||||
"stats-speed": "PRĘDKOŚCI POCIĄGÓW (MIN, ŚR, MAX) [km/h]",
|
|
||||||
"stats-length": "DŁUGOŚCI ROZKŁADÓW (MIN, ŚR, MAX) [km]",
|
|
||||||
"stats-categories": "KATEGORIE RJ",
|
|
||||||
"stats-special-twr": "WYSOKIEGO RYZYKA",
|
|
||||||
"stats-special-skr": "PRZEKROCZONA SKRAJNIA",
|
|
||||||
"stats-locos": "NAJCZĘSTSZE JEDNOSTKI",
|
|
||||||
|
|
||||||
"current-scenery": "na scenerii",
|
|
||||||
"current-signal": "przy semaforze",
|
|
||||||
"current-track": "na szlaku",
|
|
||||||
|
|
||||||
"delayed": "Opóźniony: ",
|
|
||||||
"preponed": "Przed czasem: ",
|
|
||||||
"on-time": "Planowo",
|
|
||||||
|
|
||||||
"route-progress": "Postęp: ",
|
|
||||||
|
|
||||||
"detailed-timetable": "Szczegółowy rozkład jazdy pociągu ",
|
|
||||||
"via-title": "Przez: ",
|
|
||||||
"no-timetable": "brak rozkładu jazdy",
|
|
||||||
"distance-exceeded": "Uwaga! Z powodu wewnętrznego błędu serwera TD2, rozkłady jazdy o kilometrażu powyżej 200km mogą być niepoprawne!",
|
|
||||||
"cars": "Wagony",
|
|
||||||
"EZT": "EZT",
|
|
||||||
"SZT": "SZT",
|
|
||||||
"loco-electric": "Elektrowóz",
|
|
||||||
"loco-diesel": "Spalinowóz",
|
|
||||||
"timetable-comments": "Pociąg z uwagami eksploatacyjnymi",
|
|
||||||
"comment": "Uwagi eksploatacyjne dla: ",
|
|
||||||
"table-limit": "Dla płynności działania strony pokazanych jest tylko 10 pociągów zgodnie z wybranymi filtrami.",
|
|
||||||
|
|
||||||
"last-seen-now": "od niedawna",
|
|
||||||
"last-seen-min": "od minuty",
|
|
||||||
"last-seen-ago": "od {minutes} minut",
|
|
||||||
|
|
||||||
"scenery-offline": "Przejazd offline",
|
|
||||||
|
|
||||||
"timeout": "Wystąpił problem z aktualizacją rozkładów jazdy z SWDR"
|
|
||||||
},
|
|
||||||
"journal": {
|
|
||||||
"title": "HISTORIA DYŻURÓW",
|
|
||||||
"loading": "Ładowanie historii dyżurów...",
|
|
||||||
"no-history": "Brak historii dyżurów dla tej scenerii!",
|
|
||||||
"data-refreshed-at": "Dane odświeżone o",
|
|
||||||
|
|
||||||
"section-timetables": "ROZKŁADY JAZDY",
|
|
||||||
"section-dispatchers": "DYŻURNI",
|
|
||||||
|
|
||||||
"no-further-data": "Brak dalszych wyników dla podanych parametrów",
|
|
||||||
"loading-further-data": "Ładowanie...",
|
|
||||||
|
|
||||||
"online-since": "ONLINE OD",
|
|
||||||
"duty-lasted": "Dyżur trwał",
|
|
||||||
"hours": "{value} godz.",
|
|
||||||
"minutes": "{value} min.",
|
|
||||||
"seconds": "{value} sek.",
|
|
||||||
|
|
||||||
"route-length": "Kilometraż:",
|
|
||||||
"station-count": "Stacje:",
|
|
||||||
"dispatcher-name": "Autor",
|
|
||||||
"timetable-day": "Rozkład z dnia",
|
|
||||||
"timetable-active": "AKTYWNY",
|
|
||||||
"timetable-fulfilled": "WYPEŁNIONY",
|
|
||||||
"timetable-abandoned": "PORZUCONY",
|
|
||||||
|
|
||||||
"stock-info": "DODATKOWE INFORMACJE",
|
|
||||||
"stock-length": "Długość",
|
|
||||||
"stock-mass": "Masa",
|
|
||||||
"stock-max-speed": "Prędkość maks.",
|
|
||||||
|
|
||||||
"load-data": "Pobierz dalszą historię...",
|
|
||||||
|
|
||||||
"stats-title": "STATYSTYKI MASZYNISTY",
|
|
||||||
|
|
||||||
"last-seen-at": "Ostatnio widziany na: ",
|
|
||||||
"currently-at": "Obecnie na scenerii: ",
|
|
||||||
|
|
||||||
"stats-timetables": "ROZKŁADY JAZDY",
|
|
||||||
"stats-longest-timetable": "NAJDŁUŻSZY RJ",
|
|
||||||
"stats-avg-timetable": "ŚREDNIA DŁUGOŚĆ RJ",
|
|
||||||
"stats-distance": "DYSTANS",
|
|
||||||
"stats-stations": "STACJE",
|
|
||||||
|
|
||||||
"timetable-stats-total": "Stworzone rozkłady jazdy: {count} (łączny dystans: {distance})",
|
|
||||||
"timetable-stats-longest": "Najdłuższy rozkład jazdy: #{id} (stworzony przez dyżurnego {author} dla maszynisty {driver} o dystansie {distance})",
|
|
||||||
"timetable-stats-most-active-dr": "Najaktywniejszy dyżurny: {dispatcher} (stworzył {count})",
|
|
||||||
"timetable-stats-most-active-dr-many": "Najaktywniejsi dyżurni: {dispatchers} (stworzyli po {count})",
|
|
||||||
"timetable-stats-most-active-driver": "Najaktywniejszy maszynista: {driver} (łączny przejechany dystans: {distance})",
|
|
||||||
"timetable-stats-longest-duties": "Najdłuższa służba: {dispatcher} na scenerii {station} (czas trwania: {duration})",
|
|
||||||
|
|
||||||
"timetable-count": "rozkład jazdy | rozkładów jazdy",
|
|
||||||
|
|
||||||
"daily-stats-title": "STATYSTYKI DNIA",
|
|
||||||
"daily-stats-info": "Dzisiejsze statystyki nie są jeszcze dostępne!",
|
|
||||||
|
|
||||||
"driver-stats-title": "STATYSTYKI GRACZA",
|
|
||||||
"driver-stats-info": "Wpisz nazwę użytkownika w filtrach [F], aby zobaczyć jego statystyki maszynisty!",
|
|
||||||
|
|
||||||
"stats-loading": "Pobieranie statystyk...",
|
|
||||||
"stats-error": "Ups! Wystąpił błąd podczas próby pobrania statystyk! :/",
|
|
||||||
|
|
||||||
"timetable-location-signal": "semafor:",
|
|
||||||
"timetable-location-route": "szlak:",
|
|
||||||
|
|
||||||
"history-name": "Sceneria",
|
|
||||||
"history-hash": "Hash",
|
|
||||||
"history-dispatcher": "Dyżurny",
|
|
||||||
"history-level": "Poziom",
|
|
||||||
"history-rate": "Ocena",
|
|
||||||
"history-region": "Region",
|
|
||||||
"history-date": "Data służby"
|
|
||||||
},
|
|
||||||
"scenery": {
|
|
||||||
"users": "GRACZE ONLINE",
|
|
||||||
"spawns": "OTWARTE SPAWNY",
|
|
||||||
"timetables": "AKTYWNE ROZKŁADY JAZDY",
|
|
||||||
"no-timetables": "Brak aktywnych rozkładów!",
|
|
||||||
"offline": "Sceneria jest offline",
|
|
||||||
"no-users": "BRAK AKTYWNYCH GRACZY",
|
|
||||||
"no-spawns": "BRAK OTWARTYCH SPAWNÓW",
|
|
||||||
"no-scenery": "Ups! Ta sceneria nie istnieje!",
|
|
||||||
"return-btn": "Wróć na stronę główną",
|
|
||||||
"history-btn": "Przejdź do widoku historii dyżurnych ruchu",
|
|
||||||
"info-btn": "Wróć do widoku scenerii",
|
|
||||||
"authors-title": "Autor scenerii | Autorzy scenerii",
|
|
||||||
"abbrev": "Skrót posterunku:",
|
|
||||||
"lines-title": "Rzeczywiste linie",
|
|
||||||
"project-title": "Projekt",
|
|
||||||
"one-way-routes": "Szlaki jednotorowe",
|
|
||||||
"two-way-routes": "Szlaki dwutorowe",
|
|
||||||
|
|
||||||
"option-active-timetables": "Aktywne rozkłady jazdy",
|
|
||||||
"option-timetables-history": "Historia rozkładów",
|
|
||||||
"option-dispatchers-history": "Historia dyżurów",
|
|
||||||
|
|
||||||
"timetable-author-title": "Wydany przez",
|
|
||||||
"timetable-author-unknown": "Autor nieznany",
|
|
||||||
|
|
||||||
"timetables-history-id": "ID",
|
|
||||||
"timetables-history-number": "Numer",
|
|
||||||
"timetables-history-route": "Trasa",
|
|
||||||
"timetables-history-driver": "Maszynista",
|
|
||||||
"timetables-history-author": "Autor RJ",
|
|
||||||
"timetables-history-date": "Data",
|
|
||||||
|
|
||||||
"dispatchers-history-hash": "Hash",
|
|
||||||
"dispatchers-history-dispatcher": "Dyżurny",
|
|
||||||
"dispatchers-history-level": "Poziom",
|
|
||||||
"dispatchers-history-rate": "Ocena",
|
|
||||||
"dispatchers-history-date": "Data służby",
|
|
||||||
|
|
||||||
"req-level": "ogólnodostępna | minimum {lvl} poziom dyżurnego | minimum {lvl} poziom dyżurnego",
|
|
||||||
"history-list-empty": "Brak historii dla tej scenerii!",
|
|
||||||
|
|
||||||
"forum-topic": "Oficjalny wątek scenerii {name}",
|
|
||||||
|
|
||||||
"pragotron-link": "Paletowa tablica informacyjna (beta)",
|
|
||||||
"tablice-link": "Tablica informacyjna zbiorcza (autorstwa Thundo)",
|
|
||||||
|
|
||||||
"bottom-info": "Pokaż pełną historię w zakładce Dziennika"
|
|
||||||
},
|
|
||||||
"availability": {
|
|
||||||
"title": "Dostępność",
|
|
||||||
"default": "w paczce",
|
|
||||||
"nonDefault": "poza paczką",
|
|
||||||
"unavailable": "niedostępna",
|
|
||||||
"nonPublic": "niepubliczna",
|
|
||||||
"abandoned": "wycofana"
|
|
||||||
},
|
|
||||||
"timetables": {
|
|
||||||
"timetable-only": "Wyodrębnij rozkłady jazdy",
|
|
||||||
"end": "Koniec rozkładu jazdy",
|
|
||||||
"terminated": "Rozkład jazdy zakończony",
|
|
||||||
"begins": "ROZPOCZYNA\nBIEG",
|
|
||||||
"terminates": "KOŃCZY BIEG",
|
|
||||||
|
|
||||||
"from": "Z",
|
|
||||||
"to": "DO",
|
|
||||||
|
|
||||||
"desc-arriving": "Pociągu nie ma jeszcze na tej scenerii. Przyjedzie z: {prevStationName} (szlak {prevDepartureLine})",
|
|
||||||
"desc-online": "Pociąg jest na tej scenerii. Odjedzie do: {nextStationName} (szlak {nextArrivalLine})",
|
|
||||||
"desc-stopped": "Pociąg jest na tej scenerii i odbywa postój. Odjedzie do: {nextStationName} (szlak {nextArrivalLine})",
|
|
||||||
"desc-next-arrival": "Odjeżdża do: {nextStationName} (szlak {nextArrivalLine})",
|
|
||||||
"desc-departed": "Pociąg jest na tej scenerii i został odprawiony. Odjeżdża do: {nextStationName} (szlak {nextArrivalLine})",
|
|
||||||
"desc-departed-away": "Pociąg został odprawiony i odjechał do: {nextStationName} (szlak {nextArrivalLine})",
|
|
||||||
"desc-end": "Pociąg kończy bieg",
|
|
||||||
"desc-terminated": "Pociąg skończył bieg"
|
|
||||||
},
|
|
||||||
"history": {
|
|
||||||
"title": "DZIENNIK ROZKŁADÓW JAZDY"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,24 @@
|
|||||||
{
|
{
|
||||||
|
"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} (w przypadku PayPala musi być to opłata brutto z dodatkową opłatą za transakcję) na rozwój Stacjownika, otrzyma na życzenie symboliczne {img}{b2} nicku użytkownika na stronie 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-paypal": "PRZELEJ PAYPALEM",
|
||||||
|
"action-buycoffee": "POSTAW KAWĘ!",
|
||||||
|
"dispatcher-message": "Dyżurny wspierający projekt Stacjownika!",
|
||||||
|
"driver-message": "Maszynista wspierający projekt Stacjownika!"
|
||||||
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"and": " oraz ",
|
"and": " oraz ",
|
||||||
"refresh": "ODŚWIEŻ",
|
"refresh": "ODŚWIEŻ",
|
||||||
@@ -66,8 +86,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": {
|
||||||
@@ -112,7 +133,8 @@
|
|||||||
"filter-noComments": "BEZ UWAG",
|
"filter-noComments": "BEZ UWAG",
|
||||||
"filter-twr": "WYS. RYZYKA",
|
"filter-twr": "WYS. RYZYKA",
|
||||||
"filter-skr": "SKRAJNIA",
|
"filter-skr": "SKRAJNIA",
|
||||||
"filter-twr-skr": "WSZYSTKIE",
|
"filter-twr-skr": "TWR/SKR",
|
||||||
|
"filter-all-statuses": "WSZYSTKIE",
|
||||||
"filter-common": "ZWYKŁE",
|
"filter-common": "ZWYKŁE",
|
||||||
"filter-passenger": "PASAŻERSKIE",
|
"filter-passenger": "PASAŻERSKIE",
|
||||||
"filter-freight": "TOWAROWE",
|
"filter-freight": "TOWAROWE",
|
||||||
@@ -124,9 +146,9 @@
|
|||||||
"filter-clear": "WYŁĄCZ FILTRY",
|
"filter-clear": "WYŁĄCZ FILTRY",
|
||||||
|
|
||||||
"filter-section-timetable-status": "STATUS ROZKŁADU JAZDY",
|
"filter-section-timetable-status": "STATUS ROZKŁADU JAZDY",
|
||||||
"filter-section-twrskr": "UWAGI",
|
"filter-section-special": "TYPY SPECJALNE",
|
||||||
|
|
||||||
"filter-all": "WSZYSTKIE",
|
"filter-all-specials": "WSZYSTKIE",
|
||||||
"filter-abandoned": "PORZUCONE",
|
"filter-abandoned": "PORZUCONE",
|
||||||
"filter-fulfilled": "WYPEŁNIONE",
|
"filter-fulfilled": "WYPEŁNIONE",
|
||||||
"filter-active": "AKTYWNE"
|
"filter-active": "AKTYWNE"
|
||||||
@@ -196,7 +218,9 @@
|
|||||||
"routes-2t-other": "SZLAKI DWUTOROWE NIEZELEKTR. (MINIMUM)"
|
"routes-2t-other": "SZLAKI DWUTOROWE NIEZELEKTR. (MINIMUM)"
|
||||||
},
|
},
|
||||||
|
|
||||||
"authors-search": "Szukaj autora (uwzględnia inne filtry)",
|
"authors-search": "SZUKAJ AUTORA (uwzględnia inne filtry):",
|
||||||
|
"authors-placeholder": "Wpisz nick autora...",
|
||||||
|
"authors-button-title": "Szukaj",
|
||||||
"minimum-hours-title": "POKAŻ TYLKO SCENERIE DOSTĘPNE MINIMUM DO:",
|
"minimum-hours-title": "POKAŻ TYLKO SCENERIE DOSTĘPNE MINIMUM DO:",
|
||||||
"now": "TERAZ",
|
"now": "TERAZ",
|
||||||
"hour": " godz.",
|
"hour": " godz.",
|
||||||
@@ -257,6 +281,21 @@
|
|||||||
|
|
||||||
"timeout": "Wystąpił problem z aktualizacją rozkładów jazdy z SWDR"
|
"timeout": "Wystąpił problem z aktualizacją rozkładów jazdy z SWDR"
|
||||||
},
|
},
|
||||||
|
"train-stats": {
|
||||||
|
"stats-button": "STATYSTYKI",
|
||||||
|
"title": "STATYSTYKI ONLINE",
|
||||||
|
"timetable-count": "AKTYWNE RJ",
|
||||||
|
"avg-speed": "ŚREDNIA PRĘDKOŚĆ",
|
||||||
|
"avg-timetable": "ŚREDNI RJ",
|
||||||
|
"top-categories": "Kategorie RJ",
|
||||||
|
"top-vehicles": "Pojazdy w grze",
|
||||||
|
"top-units": "Najczęstsze jednostki w grze",
|
||||||
|
"stats-loading": "Ładowanie...",
|
||||||
|
"no-timetables": "Brak aktywnych rozkładów jazdy na tym serwerze!",
|
||||||
|
"no-vehicles": "Brak aktywnych pojazdów na tym serwerze!",
|
||||||
|
"no-units": "Brak aktywnych jednostek na tym serwerze!",
|
||||||
|
"no-stats": "Brak statystyk online dla wybranego serwera!"
|
||||||
|
},
|
||||||
"journal": {
|
"journal": {
|
||||||
"title": "HISTORIA DYŻURÓW",
|
"title": "HISTORIA DYŻURÓW",
|
||||||
"loading": "Ładowanie historii dyżurów...",
|
"loading": "Ładowanie historii dyżurów...",
|
||||||
@@ -290,31 +329,51 @@
|
|||||||
|
|
||||||
"load-data": "Pobierz dalszą historię...",
|
"load-data": "Pobierz dalszą historię...",
|
||||||
|
|
||||||
"stats-title": "STATYSTYKI MASZYNISTY",
|
|
||||||
|
|
||||||
"last-seen-at": "Ostatnio widziany na: ",
|
"last-seen-at": "Ostatnio widziany na: ",
|
||||||
"currently-at": "Obecnie na scenerii: ",
|
"currently-at": "Obecnie na scenerii: ",
|
||||||
|
|
||||||
"stats-timetables": "ROZKŁADY JAZDY",
|
"driver-stats": {
|
||||||
"stats-longest-timetable": "NAJDŁUŻSZY RJ",
|
"button": "STAT. MASZYNISTY",
|
||||||
"stats-avg-timetable": "ŚREDNIA DŁUGOŚĆ RJ",
|
"title": "STATYSTYKI MASZYNISTY {name}",
|
||||||
"stats-distance": "DYSTANS",
|
"info": "Wpisz nazwę użytkownika w filtrach [F], aby zobaczyć jego statystyki maszynisty!",
|
||||||
"stats-stations": "STACJE",
|
"timetables": "ROZKŁADY JAZDY",
|
||||||
|
"longest-timetable": "NAJDŁUŻSZY RJ",
|
||||||
|
"avg-timetable": "ŚREDNIA DŁUGOŚĆ RJ",
|
||||||
|
"distance": "DYSTANS",
|
||||||
|
"stations": "STACJE"
|
||||||
|
},
|
||||||
|
|
||||||
"timetable-stats-total": "Stworzone rozkłady jazdy: {count} (łączny dystans: {distance})",
|
"daily-stats": {
|
||||||
"timetable-stats-longest": "Najdłuższy rozkład jazdy: #{id} (stworzony przez dyżurnego {author} dla maszynisty {driver} o dystansie {distance})",
|
"button": "STATYSTYKI DNIA",
|
||||||
"timetable-stats-most-active-dr": "Najaktywniejszy dyżurny: {dispatcher} (stworzył {count})",
|
"title": "STATYSTYKI DNIA",
|
||||||
"timetable-stats-most-active-dr-many": "Najaktywniejsi dyżurni: {dispatchers} (stworzyli po {count})",
|
"info": "Dzisiejsze statystyki nie są jeszcze dostępne!",
|
||||||
"timetable-stats-most-active-driver": "Najaktywniejszy maszynista: {driver} (łączny przejechany dystans: {distance})",
|
"total": "Stworzone rozkłady jazdy: {count} (łączny dystans: {distance})",
|
||||||
"timetable-stats-longest-duties": "Najdłuższa służba: {dispatcher} na scenerii {station} (czas trwania: {duration})",
|
"longest": "Najdłuższy rozkład jazdy: #{id} (stworzony przez dyżurnego {author} dla maszynisty {driver} o dystansie {distance})",
|
||||||
|
"most-active-dr": "Najaktywniejszy dyżurny: {dispatcher} (stworzył {count})",
|
||||||
|
"most-active-dr-many": "Najaktywniejsi dyżurni: {dispatchers} (stworzyli po {count})",
|
||||||
|
"most-active-driver": "Najaktywniejszy maszynista: {driver} (łączny przejechany dystans: {distance})",
|
||||||
|
"longest-duties": "Najdłuższa służba: {dispatcher} na scenerii {station} (czas trwania: {duration})",
|
||||||
|
"count": "rozkład jazdy | rozkładów jazdy",
|
||||||
|
|
||||||
"timetable-count": "rozkład jazdy | rozkładów jazdy",
|
"rippedSwitches": "ROZPRUTE ZWROTNICE",
|
||||||
|
"derailments": "WYKOLEJENIA",
|
||||||
|
"skippedStopSignals": "POMINIĘTE S1",
|
||||||
|
"radioStops": "RADIOSTOPY",
|
||||||
|
"kills": "POTRĄCENIA"
|
||||||
|
},
|
||||||
|
|
||||||
"daily-stats-title": "STATYSTYKI DNIA",
|
"dispatcher-stats": {
|
||||||
"daily-stats-info": "Dzisiejsze statystyki nie są jeszcze dostępne!",
|
"button": "STATYSTYKI DYŻURNEGO",
|
||||||
|
"title": "STATYSTYKI DYŻURNEGO {name}",
|
||||||
"driver-stats-title": "STATYSTYKI GRACZA",
|
"info": "Wpisz nazwę użytkownika w filtrach [F], aby zobaczyć jego statystyki dyżurnego!",
|
||||||
"driver-stats-info": "Wpisz nazwę użytkownika w filtrach [F], aby zobaczyć jego statystyki maszynisty!",
|
"services-count": "DYŻURY",
|
||||||
|
"service-max": "MAKS. CZAS DYŻURU",
|
||||||
|
"service-avg": "ŚREDNI CZAS DYŻURU",
|
||||||
|
"timetables-count": "WYSTAWIONE RJ",
|
||||||
|
"timetables-sum": "SUMA WYSTAWIONYCH RJ",
|
||||||
|
"timetables-max": "NAJDŁUŻSZY WYSTAWIONY RJ",
|
||||||
|
"timetables-avg": "ŚREDNIA WYSTAWIONYCH RJ"
|
||||||
|
},
|
||||||
|
|
||||||
"stats-loading": "Pobieranie statystyk...",
|
"stats-loading": "Pobieranie statystyk...",
|
||||||
"stats-error": "Ups! Wystąpił błąd podczas próby pobrania statystyk!",
|
"stats-error": "Ups! Wystąpił błąd podczas próby pobrania statystyk!",
|
||||||
@@ -350,8 +409,8 @@
|
|||||||
"two-way-routes": "Szlaki dwutorowe",
|
"two-way-routes": "Szlaki dwutorowe",
|
||||||
|
|
||||||
"option-active-timetables": "Aktywne rozkłady jazdy",
|
"option-active-timetables": "Aktywne rozkłady jazdy",
|
||||||
"option-timetables-history": "Historia rozkładów",
|
"option-timetables-history": "Historia rozkładów PL1",
|
||||||
"option-dispatchers-history": "Historia dyżurów",
|
"option-dispatchers-history": "Historia dyżurów PL1",
|
||||||
|
|
||||||
"timetable-author-title": "Wydany przez",
|
"timetable-author-title": "Wydany przez",
|
||||||
"timetable-author-unknown": "Autor nieznany",
|
"timetable-author-unknown": "Autor nieznany",
|
||||||
|
|||||||
@@ -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
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { useApiStore } from '../store/apiStore';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
apiStore: useApiStore()
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
isDonator(name: string) {
|
||||||
|
return this.apiStore.donatorsData.includes(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -10,8 +10,6 @@ export default defineComponent({
|
|||||||
mountObserver(actionFunction: () => void, target: Element) {
|
mountObserver(actionFunction: () => void, target: Element) {
|
||||||
this.observer = new IntersectionObserver(
|
this.observer = new IntersectionObserver(
|
||||||
(entries) => {
|
(entries) => {
|
||||||
console.log(entries);
|
|
||||||
|
|
||||||
if (entries[0].intersectionRatio > 0.5) actionFunction();
|
if (entries[0].intersectionRatio > 0.5) actionFunction();
|
||||||
},
|
},
|
||||||
{ threshold: 0.2 }
|
{ threshold: 0.2 }
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useStore } from '../store/store';
|
import { useMainStore } from '../store/mainStore';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
store: useStore()
|
store: useMainStore()
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -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: () => ({
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
props: (route) => ({
|
props: (route) => ({
|
||||||
train: route.query.train,
|
train: route.query.train,
|
||||||
driver: route.query.driver,
|
driver: route.query.driver,
|
||||||
trainId: route.query.trainId
|
trainId: route.query.trainId,
|
||||||
|
region: route.query.region
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -39,9 +40,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
name: 'JournalTimetables',
|
name: 'JournalTimetables',
|
||||||
component: JournalTimetablesVue,
|
component: JournalTimetablesVue,
|
||||||
props: (route) => ({
|
props: (route) => ({
|
||||||
trainNo: route.query.trainNo,
|
region: route.query.region
|
||||||
driverName: route.query.driverName,
|
|
||||||
timetableId: route.query.timetableId
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -49,8 +48,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
name: 'JournalDispatchers',
|
name: 'JournalDispatchers',
|
||||||
component: JournalDispatchersVue,
|
component: JournalDispatchersVue,
|
||||||
props: (route) => ({
|
props: (route) => ({
|
||||||
sceneryName: route.query.sceneryName,
|
region: route.query.region
|
||||||
dispatcherName: route.query.dispatcherName
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -61,11 +59,10 @@ 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 !== to.name && from.query['view'] === undefined)
|
||||||
|
return { el: `.app_main` };
|
||||||
|
|
||||||
if (savedPosition) return savedPosition;
|
if (savedPosition) return savedPosition;
|
||||||
|
|
||||||
// if (from.name == 'SceneryView' && to.name == 'StationsView') return { el: `.last-selected`, top: 20 };
|
|
||||||
},
|
},
|
||||||
history: createWebHistory(),
|
history: createWebHistory(),
|
||||||
routes
|
routes
|
||||||
|
|||||||
@@ -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,6 +1,5 @@
|
|||||||
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 {
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -1,25 +1,8 @@
|
|||||||
export default interface StationRoutes {
|
import { StationRoutesInfo } from '../../store/typings';
|
||||||
oneWay: {
|
|
||||||
name: string;
|
|
||||||
catenary: boolean;
|
|
||||||
SBL: boolean;
|
|
||||||
TWB: boolean;
|
|
||||||
isInternal: boolean;
|
|
||||||
tracks: number;
|
|
||||||
speed: number;
|
|
||||||
length: number;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
twoWay: {
|
export interface StationRoutes {
|
||||||
name: string;
|
oneWay: StationRoutesInfo[];
|
||||||
catenary: boolean;
|
twoWay: StationRoutesInfo[];
|
||||||
SBL: boolean;
|
|
||||||
TWB: boolean;
|
|
||||||
isInternal: boolean;
|
|
||||||
tracks: number;
|
|
||||||
speed: number;
|
|
||||||
length: number;
|
|
||||||
}[];
|
|
||||||
|
|
||||||
/* [catenary, noCatenary] */
|
/* [catenary, noCatenary] */
|
||||||
oneWayCatenaryRouteNames: string[];
|
oneWayCatenaryRouteNames: string[];
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||