mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 13:28:11 +00:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
@@ -50,11 +50,6 @@
|
|||||||
name="twitter:image"
|
name="twitter:image"
|
||||||
content="https://raw.githubusercontent.com/Spythere/api/main/thumbnails/stacjownik.jpg"
|
content="https://raw.githubusercontent.com/Spythere/api/main/thumbnails/stacjownik.jpg"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<link
|
|
||||||
href="https://fonts.googleapis.com/css2?family=Quicksand:wght@500;700&display=swap"
|
|
||||||
rel="stylesheet"
|
|
||||||
/>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
Generated
+148
-20
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.19.4",
|
"version": "1.20.3",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.19.4",
|
"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,6 +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.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"
|
||||||
@@ -2840,6 +2841,11 @@
|
|||||||
"integrity": "sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==",
|
"integrity": "sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@socket.io/component-emitter": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
|
||||||
|
},
|
||||||
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
||||||
@@ -4156,7 +4162,6 @@
|
|||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
@@ -4399,6 +4404,26 @@
|
|||||||
"once": "^1.4.0"
|
"once": "^1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/engine.io-client": {
|
||||||
|
"version": "6.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
|
||||||
|
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.1",
|
||||||
|
"engine.io-parser": "~5.2.1",
|
||||||
|
"ws": "~8.11.0",
|
||||||
|
"xmlhttprequest-ssl": "~2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/engine.io-parser": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/es-abstract": {
|
"node_modules/es-abstract": {
|
||||||
"version": "1.20.5",
|
"version": "1.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz",
|
||||||
@@ -5061,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": [
|
||||||
{
|
{
|
||||||
@@ -5071,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"
|
||||||
},
|
},
|
||||||
@@ -6312,7 +6336,6 @@
|
|||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/muggle-string": {
|
"node_modules/muggle-string": {
|
||||||
@@ -7538,6 +7561,32 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/socket.io-client": {
|
||||||
|
"version": "4.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
|
||||||
|
"integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.2",
|
||||||
|
"engine.io-client": "~6.5.2",
|
||||||
|
"socket.io-parser": "~4.2.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socket.io-parser": {
|
||||||
|
"version": "4.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||||
|
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||||
|
"dependencies": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.8.0-beta.0",
|
"version": "0.8.0-beta.0",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
|
||||||
@@ -8152,9 +8201,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "4.5.1",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz",
|
||||||
"integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==",
|
"integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.18.10",
|
"esbuild": "^0.18.10",
|
||||||
@@ -8727,6 +8776,26 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
|
||||||
|
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": "^5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/xml-name-validator": {
|
"node_modules/xml-name-validator": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
|
||||||
@@ -8736,6 +8805,14 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/xmlhttprequest-ssl": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/y18n": {
|
"node_modules/y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
@@ -10722,6 +10799,11 @@
|
|||||||
"integrity": "sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==",
|
"integrity": "sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@socket.io/component-emitter": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
|
||||||
|
},
|
||||||
"@surma/rollup-plugin-off-main-thread": {
|
"@surma/rollup-plugin-off-main-thread": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
||||||
@@ -11640,7 +11722,6 @@
|
|||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
}
|
}
|
||||||
@@ -11801,6 +11882,23 @@
|
|||||||
"once": "^1.4.0"
|
"once": "^1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"engine.io-client": {
|
||||||
|
"version": "6.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
|
||||||
|
"integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
|
||||||
|
"requires": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.1",
|
||||||
|
"engine.io-parser": "~5.2.1",
|
||||||
|
"ws": "~8.11.0",
|
||||||
|
"xmlhttprequest-ssl": "~2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"engine.io-parser": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ=="
|
||||||
|
},
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.20.5",
|
"version": "1.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz",
|
||||||
@@ -12286,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": {
|
||||||
@@ -13127,8 +13225,7 @@
|
|||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"muggle-string": {
|
"muggle-string": {
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
@@ -13945,6 +14042,26 @@
|
|||||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"socket.io-client": {
|
||||||
|
"version": "4.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
|
||||||
|
"integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
|
||||||
|
"requires": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.2",
|
||||||
|
"engine.io-client": "~6.5.2",
|
||||||
|
"socket.io-parser": "~4.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"socket.io-parser": {
|
||||||
|
"version": "4.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||||
|
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||||
|
"requires": {
|
||||||
|
"@socket.io/component-emitter": "~3.1.0",
|
||||||
|
"debug": "~4.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.8.0-beta.0",
|
"version": "0.8.0-beta.0",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
|
||||||
@@ -14377,9 +14494,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"vite": {
|
"vite": {
|
||||||
"version": "4.5.1",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz",
|
||||||
"integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==",
|
"integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"esbuild": "^0.18.10",
|
"esbuild": "^0.18.10",
|
||||||
@@ -14776,12 +14893,23 @@
|
|||||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ws": {
|
||||||
|
"version": "8.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
|
||||||
|
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"xml-name-validator": {
|
"xml-name-validator": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
|
||||||
"integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
|
"integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"xmlhttprequest-ssl": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A=="
|
||||||
|
},
|
||||||
"y18n": {
|
"y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.19.4",
|
"version": "1.20.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@@ -18,6 +18,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.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"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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 |
+83
-40
@@ -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,SceneryView">
|
<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,26 +33,29 @@
|
|||||||
|
|
||||||
<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 { regions } from './data/options.json';
|
|
||||||
|
|
||||||
import { useMainStore } from './store/mainStore';
|
import { useMainStore } from './store/mainStore';
|
||||||
|
|
||||||
import StatusIndicator from './components/App/StatusIndicator.vue';
|
import StatusIndicator from './components/App/StatusIndicator.vue';
|
||||||
import TrainModal from './components/Global/TrainModal.vue';
|
|
||||||
import 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 StorageManager from './managers/storageManager';
|
||||||
import { useApiStore } from './store/apiStore';
|
import { useApiStore } from './store/apiStore';
|
||||||
|
import { Status } from './typings/common';
|
||||||
|
import { Websocket } from './typings/api';
|
||||||
|
import socket from './websocket';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
Clock,
|
Clock,
|
||||||
StatusIndicator,
|
StatusIndicator,
|
||||||
TrainModal,
|
AppHeader,
|
||||||
AppHeader
|
TrainModal
|
||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
@@ -66,26 +69,10 @@ export default defineComponent({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.loadLang();
|
this.init();
|
||||||
this.apiStore.setupAPI();
|
|
||||||
|
|
||||||
this.store.isOffline = !window.navigator.onLine;
|
|
||||||
|
|
||||||
window.addEventListener('offline', () => {
|
|
||||||
this.store.isOffline = true;
|
|
||||||
this.apiStore.activeData = undefined;
|
|
||||||
|
|
||||||
this.apiStore.setDataStatuses();
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener('online', () => {
|
|
||||||
this.store.isOffline = false;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
this.setReleaseURL();
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => this.store.blockScroll,
|
() => this.store.blockScroll,
|
||||||
(value) => {
|
(value) => {
|
||||||
@@ -95,23 +82,79 @@ export default defineComponent({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
methods: {
|
||||||
'$route.query.region': {
|
init() {
|
||||||
immediate: true,
|
this.loadLang();
|
||||||
handler(regionQuery: string) {
|
this.setReleaseURL();
|
||||||
if (regionQuery) {
|
this.setupOfflineHandling();
|
||||||
this.store.region.id =
|
|
||||||
regions.find(
|
this.apiStore.setupStaticAPIData();
|
||||||
(reg) =>
|
this.connectToWebsocket();
|
||||||
reg.id == regionQuery.toLocaleLowerCase() ||
|
},
|
||||||
reg.value.toLocaleLowerCase() == regionQuery.toLocaleLowerCase()
|
|
||||||
)?.id || 'eu';
|
async connectToWebsocket() {
|
||||||
}
|
this.apiStore.dataStatuses.connection = Status.Data.Loading;
|
||||||
}
|
|
||||||
}
|
console.log('ws connecting');
|
||||||
|
|
||||||
|
socket.on('connect_error', (err) => {
|
||||||
|
console.error(`WS connection error: ${err.message}`);
|
||||||
|
|
||||||
|
this.apiStore.dataStatuses.connection = Status.Data.Error;
|
||||||
|
this.apiStore.websocketData = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
let timeFrom = Date.now();
|
||||||
|
socket.on('connect', () => {
|
||||||
|
socket.emit('CONNECTION', { version: packageInfo.version }, () => {
|
||||||
|
console.log(`Connection time: ${Date.now() - timeFrom}ms`);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('ws connected');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('UPDATE', (data: Websocket.Payload) => {
|
||||||
|
console.log('ws update');
|
||||||
|
|
||||||
|
this.apiStore.websocketData = data;
|
||||||
|
this.apiStore.dataStatuses.connection = Status.Data.Loaded;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fetchWebsocketData();
|
||||||
|
},
|
||||||
|
|
||||||
|
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.websocketData = undefined;
|
||||||
|
this.apiStore.dataStatuses.connection = Status.Data.Offline;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleOnlineMode() {
|
||||||
|
this.store.isOffline = false;
|
||||||
|
|
||||||
|
this.apiStore.setupStaticAPIData();
|
||||||
|
this.connectToWebsocket();
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchWebsocketData() {
|
||||||
|
socket.emit('FETCH_DATA', (data: Websocket.Payload) => {
|
||||||
|
console.log('ws fetch data');
|
||||||
|
|
||||||
|
this.apiStore.websocketData = data;
|
||||||
|
this.apiStore.dataStatuses.connection = Status.Data.Loaded;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
changeLang(lang: string) {
|
changeLang(lang: string) {
|
||||||
this.$i18n.locale = lang;
|
this.$i18n.locale = lang;
|
||||||
this.currentLang = lang;
|
this.currentLang = lang;
|
||||||
|
|||||||
@@ -240,9 +240,9 @@ export default defineComponent({
|
|||||||
const trainsDataStatus = statuses.trains;
|
const trainsDataStatus = statuses.trains;
|
||||||
const dispatcherDataStatus = statuses.dispatchers;
|
const dispatcherDataStatus = statuses.dispatchers;
|
||||||
|
|
||||||
if (this.store.isOffline) {
|
if (connectionStatus == Status.Data.Offline) {
|
||||||
this.setSignalStatus(Status.Data.Initialized);
|
this.setSignalStatus(Status.Data.Offline);
|
||||||
this.indicator.status = Status.Data.Initialized;
|
this.indicator.status = Status.Data.Offline;
|
||||||
this.indicator.message = 'data-status.S1-offline';
|
this.indicator.message = 'data-status.S1-offline';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -293,7 +293,7 @@ export default defineComponent({
|
|||||||
this.orangeLight = false;
|
this.orangeLight = false;
|
||||||
this.redBottomLight = false;
|
this.redBottomLight = false;
|
||||||
|
|
||||||
if (status == Status.Data.Initialized) {
|
if (status == Status.Data.Initialized || status == Status.Data.Offline) {
|
||||||
this.redTopLight = true;
|
this.redTopLight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,21 @@ export default defineComponent({
|
|||||||
'store.region.id': {
|
'store.region.id': {
|
||||||
handler(regionId) {
|
handler(regionId) {
|
||||||
this.selectedItemIndex = this.regionList.findIndex((reg) => reg.id == 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';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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 { PropType, defineComponent } from 'vue';
|
|
||||||
import dateMixin from '../../mixins/dateMixin';
|
|
||||||
import { TrainStop } from '../../store/typings';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
mixins: [dateMixin],
|
|
||||||
|
|
||||||
props: {
|
|
||||||
stop: {
|
|
||||||
type: Object as PropType<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>
|
|
||||||
@@ -1,160 +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 { defineComponent } from 'vue';
|
|
||||||
import { useMainStore } from '../../store/mainStore';
|
|
||||||
import Loading from '../Global/Loading.vue';
|
|
||||||
import { API } from '../../typings/api';
|
|
||||||
import http from '../../http';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: { Loading },
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = useMainStore();
|
|
||||||
|
|
||||||
return {
|
|
||||||
store
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
cardVisible: false,
|
|
||||||
lastDispatcherName: '',
|
|
||||||
timetables: [] as API.TimetableHistory.Response
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
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: API.DispatcherStats.Response = await (
|
|
||||||
await http.get('api/getDispatcherInfo?name=${this.store.dispatcherStatsName}')
|
|
||||||
).data;
|
|
||||||
|
|
||||||
const timetables: API.TimetableHistory.Response = await (
|
|
||||||
await http.get('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>
|
|
||||||
@@ -1,25 +1,34 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="daily-stats">
|
<section class="daily-stats">
|
||||||
<span :data-active="statsStatus">
|
<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">
|
<b v-if="statsStatus == Status.Data.Loading">
|
||||||
{{ $t('app.loading') }}
|
{{ $t('app.loading') }}
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
<span class="stats-list" v-else>
|
<b class="text--error" v-else-if="statsStatus == Status.Data.Error">
|
||||||
<h3>
|
{{ $t('journal.stats-error') }}
|
||||||
{{ $t('journal.daily-stats-title') }}
|
</b>
|
||||||
<b class="text--primary">{{ new Date().toLocaleDateString($i18n.locale) }}</b>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<hr style="margin-bottom: 0.5em" />
|
<b v-else-if="topDispatchers.length == 0">
|
||||||
|
{{ $t('journal.daily-stats.info') }}
|
||||||
|
</b>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
<div v-if="stats.totalTimetables">
|
<div v-if="stats.totalTimetables">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-total">
|
<i18n-t keypath="journal.daily-stats.total">
|
||||||
<template #count>
|
<template #count>
|
||||||
<b class="text--primary">
|
<b class="text--primary">
|
||||||
{{ stats.totalTimetables }}
|
{{ stats.totalTimetables }}
|
||||||
{{ $t('journal.timetable-count', stats.totalTimetables) }}
|
{{ $t('journal.daily-stats.count', stats.totalTimetables) }}
|
||||||
</b>
|
</b>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -31,15 +40,15 @@
|
|||||||
|
|
||||||
<div v-if="stats.maxTimetable">
|
<div v-if="stats.maxTimetable">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-longest">
|
<i18n-t keypath="journal.daily-stats.longest">
|
||||||
<template #id>
|
<template #id>
|
||||||
<router-link :to="`/journal/timetables?timetableId=${stats.maxTimetable.id}`">
|
<router-link :to="`/journal/timetables?search-train=%23${stats.maxTimetable.id}`">
|
||||||
<b>{{ stats.maxTimetable.id }}</b>
|
<b>{{ stats.maxTimetable.id }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template #author>
|
<template #author>
|
||||||
<router-link
|
<router-link
|
||||||
:to="`/journal/dispatchers?dispatcherName=${stats.maxTimetable.authorName}`"
|
:to="`/journal/timetables?search-dispatcher=${stats.maxTimetable.authorName}`"
|
||||||
>
|
>
|
||||||
<b>{{ stats.maxTimetable.authorName }}</b>
|
<b>{{ stats.maxTimetable.authorName }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
@@ -55,16 +64,18 @@
|
|||||||
|
|
||||||
<div v-if="topDispatchers.length == 1">
|
<div v-if="topDispatchers.length == 1">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-most-active-dr">
|
<i18n-t keypath="journal.daily-stats.most-active-dr">
|
||||||
<template #dispatcher>
|
<template #dispatcher>
|
||||||
<router-link :to="`/journal/dispatchers?dispatcherName=${topDispatchers[0].name}`">
|
<router-link
|
||||||
|
:to="`/journal/dispatchers?search-dispatcher=${topDispatchers[0].name}`"
|
||||||
|
>
|
||||||
<b>{{ topDispatchers[0].name }}</b>
|
<b>{{ topDispatchers[0].name }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template #count>
|
<template #count>
|
||||||
<b class="text--primary">
|
<b class="text--primary">
|
||||||
{{ topDispatchers[0].count }}
|
{{ topDispatchers[0].count }}
|
||||||
{{ $t('journal.timetable-count', topDispatchers[0].count) }}
|
{{ $t('journal.daily-stats.count', topDispatchers[0].count) }}
|
||||||
</b>
|
</b>
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
@@ -72,12 +83,12 @@
|
|||||||
|
|
||||||
<div v-if="topDispatchers.length > 1">
|
<div v-if="topDispatchers.length > 1">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-most-active-dr-many">
|
<i18n-t keypath="journal.daily-stats.most-active-dr-many">
|
||||||
<template #dispatchers>
|
<template #dispatchers>
|
||||||
<span v-for="(disp, i) in topDispatchers" :key="i">
|
<span v-for="(disp, i) in topDispatchers" :key="i">
|
||||||
<span v-if="i == topDispatchers.length - 1"> {{ $t('general.and') }} </span>
|
<span v-if="i == topDispatchers.length - 1"> {{ $t('general.and') }} </span>
|
||||||
|
|
||||||
<router-link :to="`/journal/dispatchers?dispatcherName=${disp.name}`">
|
<router-link :to="`/journal/dispatchers?search-dispatcher=${disp.name}`">
|
||||||
<b>{{ disp.name }}</b>
|
<b>{{ disp.name }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
@@ -88,7 +99,7 @@
|
|||||||
<template #count>
|
<template #count>
|
||||||
<b class="text--primary">
|
<b class="text--primary">
|
||||||
{{ topDispatchers[0].count }}
|
{{ topDispatchers[0].count }}
|
||||||
{{ $t('journal.timetable-count', topDispatchers[0].count) }}
|
{{ $t('journal.daily-stats.count', topDispatchers[0].count) }}
|
||||||
</b>
|
</b>
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
@@ -96,10 +107,10 @@
|
|||||||
|
|
||||||
<div v-if="stats.longestDuties.length > 0">
|
<div v-if="stats.longestDuties.length > 0">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-longest-duties">
|
<i18n-t keypath="journal.daily-stats.longest-duties">
|
||||||
<template #dispatcher>
|
<template #dispatcher>
|
||||||
<router-link
|
<router-link
|
||||||
:to="`/journal/dispatchers?dispatcherName=${stats.longestDuties[0].name}`"
|
:to="`/journal/dispatchers?search-dispatcher=${stats.longestDuties[0].name}`"
|
||||||
>
|
>
|
||||||
<b>{{ stats.longestDuties[0].name }}</b>
|
<b>{{ stats.longestDuties[0].name }}</b>
|
||||||
</router-link>
|
</router-link>
|
||||||
@@ -115,15 +126,41 @@
|
|||||||
|
|
||||||
<div v-if="stats.mostActiveDrivers.length > 0">
|
<div v-if="stats.mostActiveDrivers.length > 0">
|
||||||
•
|
•
|
||||||
<i18n-t keypath="journal.timetable-stats-most-active-driver">
|
<i18n-t keypath="journal.daily-stats.most-active-driver">
|
||||||
<template #driver>
|
<template #driver>
|
||||||
<b class="text--primary">{{ stats.mostActiveDrivers[0].name }}</b>
|
<router-link
|
||||||
|
:to="`/journal/timetables?search-driver=${stats.mostActiveDrivers[0].name}`"
|
||||||
|
>
|
||||||
|
<b>{{ stats.mostActiveDrivers[0].name }}</b>
|
||||||
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template #distance>
|
<template #distance>
|
||||||
<b class="text--primary">{{ stats.mostActiveDrivers[0].distance.toFixed(2) }} km</b>
|
<b class="text--primary">{{ stats.mostActiveDrivers[0].distance.toFixed(2) }} km</b>
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</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>
|
||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
@@ -203,6 +240,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
|
@import '../../styles/JournalStats.scss';
|
||||||
|
@import '../../styles/badge.scss';
|
||||||
|
|
||||||
.daily-stats {
|
.daily-stats {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -215,6 +254,12 @@ export default defineComponent({
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stats-badges {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
@include smallScreen {
|
@include smallScreen {
|
||||||
h3 {
|
h3 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -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,260 +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 == 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="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
|
|
||||||
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>
|
|
||||||
</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 styleMixin from '../../mixins/styleMixin';
|
|
||||||
import { useMainStore } from '../../store/mainStore';
|
|
||||||
import Loading from '../Global/Loading.vue';
|
|
||||||
import { regions } from '../../data/options.json';
|
|
||||||
import AddDataButton from '../Global/AddDataButton.vue';
|
|
||||||
import { API } from '../../typings/api';
|
|
||||||
import { Status } from '../../typings/common';
|
|
||||||
import donatorMixin from '../../mixins/donatorMixin';
|
|
||||||
|
|
||||||
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() {
|
|
||||||
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 (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.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.text {
|
|
||||||
&--online {
|
|
||||||
color: springgreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--offline {
|
|
||||||
color: #ddd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
<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()"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -114,7 +115,6 @@ import { defineComponent, inject, PropType } from 'vue';
|
|||||||
import keyMixin from '../../mixins/keyMixin';
|
import keyMixin from '../../mixins/keyMixin';
|
||||||
import { useMainStore } from '../../store/mainStore';
|
import { useMainStore } from '../../store/mainStore';
|
||||||
import { Journal } from './typings';
|
import { Journal } from './typings';
|
||||||
import { API } from '../../typings/api';
|
|
||||||
import { Status } from '../../typings/common';
|
import { Status } from '../../typings/common';
|
||||||
import http from '../../http';
|
import http from '../../http';
|
||||||
|
|
||||||
@@ -181,10 +181,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
async 'store.driverStatsName'() {
|
|
||||||
await this.fetchDriverStats();
|
|
||||||
},
|
|
||||||
|
|
||||||
async 'searchersValues.search-driver'(value: string | undefined) {
|
async 'searchersValues.search-driver'(value: string | undefined) {
|
||||||
clearTimeout(this.searchTimeout);
|
clearTimeout(this.searchTimeout);
|
||||||
|
|
||||||
@@ -203,27 +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 = Status.Data.Initialized;
|
|
||||||
return;
|
return acc;
|
||||||
}
|
},
|
||||||
|
{} as { [k: string]: string | undefined }
|
||||||
try {
|
),
|
||||||
this.store.driverStatsStatus = Status.Data.Loading;
|
...this.filterList?.reduce(
|
||||||
|
(acc, f) => {
|
||||||
const statsData: API.DriverStats.Response = await (
|
if (f.isActive) acc[f.filterSection] = f.default ? undefined : f.id;
|
||||||
await http.get(`api/getDriverInfo?name=${this.store.driverStatsName}`)
|
return acc;
|
||||||
).data;
|
},
|
||||||
|
{} as { [k: string]: string | undefined }
|
||||||
this.store.driverStatsData = statsData;
|
)
|
||||||
this.store.driverStatsStatus = Status.Data.Loaded;
|
|
||||||
} catch (error) {
|
|
||||||
this.store.driverStatsStatus = Status.Data.Error;
|
|
||||||
console.error('Ups! Wystąpił błąd przy próbie pobrania statystyk maszynisty! :/');
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshData() {
|
refreshData() {
|
||||||
@@ -245,7 +248,7 @@ export default defineComponent({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
this[`${type}Suggestions`] = [];
|
this[`${type}Suggestions`] = [];
|
||||||
}
|
}
|
||||||
}, 450);
|
}, 250);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Override keyMixin function
|
// Override keyMixin function
|
||||||
@@ -260,7 +263,7 @@ 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: Journal.TimetableFilter) {
|
onFilterChange(filter: Journal.TimetableFilter) {
|
||||||
@@ -270,25 +273,27 @@ export default defineComponent({
|
|||||||
.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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="journal-stats" v-if="!store.isOffline">
|
<div
|
||||||
<div class="stats-buttons">
|
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="button in data.statsButtons"
|
v-for="button in statsButtons"
|
||||||
:key="button.name"
|
:key="button.tab"
|
||||||
class="btn--filled btn--image"
|
class="btn--filled btn--image"
|
||||||
:data-selected="button.name == currentStatsTab"
|
:data-selected="button.tab == currentStatsTab"
|
||||||
@click="onTabButtonClick(button.name)"
|
:data-disabled="button.disabled"
|
||||||
|
:disabled="button.disabled"
|
||||||
|
@click="onTabButtonClick(button.tab)"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
v-if="button.iconName"
|
v-if="button.iconName"
|
||||||
@@ -17,87 +29,57 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stats-tab" v-show="currentStatsTab !== null">
|
<transition name="dropdown-anim">
|
||||||
|
<div class="dropdown_wrapper" v-if="currentStatsTab !== null">
|
||||||
<keep-alive>
|
<keep-alive>
|
||||||
<JournalDailyStats v-if="currentStatsTab == 'journal-daily-stats'" />
|
<component :is="currentStatsTab" :key="currentStatsTab"></component>
|
||||||
<JournalDriverStats v-else-if="currentStatsTab == 'journal-driver-stats'" />
|
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</div>
|
</div>
|
||||||
|
</transition>
|
||||||
</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 { useMainStore } from '../../store/mainStore';
|
import { useMainStore } from '../../store/mainStore';
|
||||||
import JournalDailyStats from './JournalDailyStats.vue';
|
|
||||||
import JournalDriverStats from './JournalDriverStats.vue';
|
|
||||||
import StorageManager from '../../managers/storageManager';
|
import StorageManager from '../../managers/storageManager';
|
||||||
|
import { Journal } from './typings';
|
||||||
|
import JournalDailyStats from './JournalDailyStats.vue';
|
||||||
|
import JournalDispatcherStats from '../JournalView/JournalDispatchers/JournalDispatcherStats.vue';
|
||||||
|
import JournalDriverStats from '../JournalView/JournalTimetables/JournalDriverStats.vue';
|
||||||
|
|
||||||
export type JournalStatsTab = 'journal-driver-stats' | 'journal-daily-stats';
|
export default defineComponent({
|
||||||
|
components: { JournalDailyStats, JournalDriverStats, JournalDispatcherStats },
|
||||||
const store = useMainStore();
|
props: {
|
||||||
const currentStatsTab: Ref<JournalStatsTab | null> = ref(null);
|
statsButtons: {
|
||||||
|
type: Array as PropType<Journal.StatsButton[]>,
|
||||||
let data = reactive({
|
required: true
|
||||||
statsButtons: [
|
}
|
||||||
{
|
|
||||||
name: 'journal-daily-stats',
|
|
||||||
localeKey: 'journal.daily-stats-title',
|
|
||||||
iconName: 'stats'
|
|
||||||
},
|
},
|
||||||
{
|
data() {
|
||||||
name: 'journal-driver-stats',
|
return {
|
||||||
localeKey: 'journal.driver-stats-title',
|
Journal,
|
||||||
iconName: 'user'
|
mainStore: useMainStore(),
|
||||||
|
currentStatsTab: null as Journal.StatsTab | null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onTabButtonClick(tab: Journal.StatsTab) {
|
||||||
|
this.currentStatsTab = tab == this.currentStatsTab ? null : tab;
|
||||||
|
|
||||||
|
StorageManager.setStringValue('journalStatsTab', this.currentStatsTab ?? '');
|
||||||
}
|
}
|
||||||
] as { name: JournalStatsTab; localeKey: string; iconName?: string }[]
|
|
||||||
});
|
|
||||||
|
|
||||||
function onTabButtonClick(tab: JournalStatsTab) {
|
|
||||||
currentStatsTab.value = tab == currentStatsTab.value ? null : tab;
|
|
||||||
StorageManager.setStringValue('journalStatsTab', currentStatsTab.value ?? '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
|
||||||
computed(() => store.driverStatsData),
|
|
||||||
(newData, prevData) => {
|
|
||||||
currentStatsTab.value =
|
|
||||||
JSON.stringify(prevData) !== JSON.stringify(newData) && newData !== undefined
|
|
||||||
? 'journal-driver-stats'
|
|
||||||
: currentStatsTab.value;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
const storedTab = StorageManager.getStringValue('journalStatsTab');
|
|
||||||
|
|
||||||
if (storedTab && storedTab !== '') currentStatsTab.value = storedTab as JournalStatsTab;
|
|
||||||
});
|
});
|
||||||
</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';
|
||||||
|
|
||||||
.stats-buttons {
|
.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>
|
||||||
|
|||||||
+16
-19
@@ -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">
|
||||||
|
<template #name>
|
||||||
<span class="text--primary">{{ store.driverStatsName.toUpperCase() }}</span>
|
<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,21 +47,13 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<b v-else-if="store.driverStatsStatus == Status.Data.Loading">{{
|
|
||||||
$t('journal.stats-loading')
|
|
||||||
}}</b>
|
|
||||||
<b v-else-if="store.driverStatsStatus == Status.Data.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 { useMainStore } from '../../store/mainStore';
|
import { useMainStore } from '../../../store/mainStore';
|
||||||
import { Status } from '../../typings/common';
|
import { Status } from '../../../typings/common';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'journal-driver-stats',
|
name: 'journal-driver-stats',
|
||||||
@@ -71,5 +68,5 @@ export default defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/JournalStats.scss';
|
@import '../../../styles/JournalStats.scss';
|
||||||
</style>
|
</style>
|
||||||
@@ -1,12 +1,5 @@
|
|||||||
export namespace Journal {
|
export namespace Journal {
|
||||||
export type DispatcherSearcher = {
|
export type DispatcherSearchKey = 'search-dispatcher' | 'search-station' | 'search-date';
|
||||||
[key in 'search-dispatcher' | 'search-station' | 'search-date']: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface DispatcherSorter {
|
|
||||||
id: 'timestampFrom' | 'duration';
|
|
||||||
dir: -1 | 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TimetableSearchKey =
|
export type TimetableSearchKey =
|
||||||
| 'search-driver'
|
| 'search-driver'
|
||||||
@@ -19,11 +12,29 @@ export namespace Journal {
|
|||||||
[key in TimetableSearchKey]: string;
|
[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 {
|
export const enum TimetableFilterId {
|
||||||
|
ALL_STATUSES = 'all-statuses',
|
||||||
ACTIVE = 'active',
|
ACTIVE = 'active',
|
||||||
FULFILLED = 'fulfilled',
|
FULFILLED = 'fulfilled',
|
||||||
ABANDONED = 'abandoned',
|
ABANDONED = 'abandoned',
|
||||||
ALL = 'all',
|
ALL_SPECIALS = 'all-specials',
|
||||||
TWR = 'twr',
|
TWR = 'twr',
|
||||||
SKR = 'skr',
|
SKR = 'skr',
|
||||||
TWR_SKR = 'twr-skr'
|
TWR_SKR = 'twr-skr'
|
||||||
@@ -31,19 +42,26 @@ export namespace Journal {
|
|||||||
|
|
||||||
export enum FilterSection {
|
export enum FilterSection {
|
||||||
TIMETABLE_STATUS = 'timetable-status',
|
TIMETABLE_STATUS = 'timetable-status',
|
||||||
TWRSKR = 'twrskr'
|
SPECIAL = 'special'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TimetableFilter {
|
export interface TimetableFilter {
|
||||||
id: TimetableFilterId;
|
id: TimetableFilterId;
|
||||||
filterSection: string;
|
filterSection: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
default: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TimetableSorterKey = 'timetableId' | 'beginDate' | 'distance' | 'total-stops';
|
export enum StatsTab {
|
||||||
|
DRIVER_STATS = 'journal-driver-stats',
|
||||||
|
DISPATCHER_STATS = 'journal-dispatcher-stats',
|
||||||
|
DAILY_STATS = 'journal-daily-stats'
|
||||||
|
}
|
||||||
|
|
||||||
export interface TimetableSorter {
|
export interface StatsButton {
|
||||||
id: TimetableSorterKey;
|
tab: StatsTab;
|
||||||
dir: 'asc' | 'desc';
|
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>
|
||||||
@@ -138,7 +140,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
navigateToHistory() {
|
navigateToHistory() {
|
||||||
this.$router.push(
|
this.$router.push(
|
||||||
`/journal/dispatchers?sceneryName=${this.station?.name || this.onlineScenery?.name}`
|
`/journal/dispatchers?search-station=${this.station?.name || this.onlineScenery?.name}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<router-link
|
<router-link
|
||||||
class="dispatcher_name"
|
class="dispatcher_name"
|
||||||
:to="`/journal/dispatchers?dispatcherName=${onlineScenery.dispatcherName}`"
|
:to="`/journal/dispatchers?search-dispatcher=${onlineScenery.dispatcherName}`"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="text--donator"
|
class="text--donator"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -14,13 +14,13 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="header_links" v-if="station">
|
<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="apiStore.dataStatuses.trains == 0 && computedScheduledTrains.length == 0"
|
v-if="apiStore.dataStatuses.connection == 0 && computedScheduledTrains.length == 0"
|
||||||
key="list-loading"
|
key="list-loading"
|
||||||
>
|
>
|
||||||
<Loading />
|
<Loading />
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<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 }}
|
#{{ historyItem.id }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</td>
|
</td>
|
||||||
@@ -37,11 +37,16 @@
|
|||||||
{{ 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>
|
||||||
@@ -99,18 +104,20 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async fetchAPIData(countFrom = 0, countLimit = 15) {
|
async fetchAPIData() {
|
||||||
if (!this.station && !this.onlineScenery) {
|
if (!this.station && !this.onlineScenery) {
|
||||||
this.dataStatus = Status.Data.Loaded;
|
this.dataStatus = Status.Data.Loaded;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const requestString = `api/getTimetables?issuedFrom=${
|
const response: API.TimetableHistory.Response = await (
|
||||||
this.station?.name || this.onlineScenery?.name
|
await http.get('api/getTimetables', {
|
||||||
}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
params: {
|
||||||
|
issuedFrom: this.station?.name || this.onlineScenery?.name
|
||||||
const response: API.TimetableHistory.Response = await (await http.get(requestString)).data;
|
}
|
||||||
|
})
|
||||||
|
).data;
|
||||||
|
|
||||||
this.historyList = response;
|
this.historyList = response;
|
||||||
|
|
||||||
@@ -121,9 +128,12 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
navigateToHistory() {
|
navigateToHistory() {
|
||||||
this.$router.push(
|
this.$router.push({
|
||||||
`/journal/timetables?issuedFrom=${this.station?.name || this.onlineScenery?.name}`
|
path: '/journal/timetables',
|
||||||
);
|
query: {
|
||||||
|
'search-issuedFrom': this.station?.name || this.onlineScenery?.name
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: { Loading }
|
components: { Loading }
|
||||||
|
|||||||
@@ -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">
|
||||||
|
<h3 class="section-header">{{ $t('filters.authors-search') }}</h3>
|
||||||
|
|
||||||
|
<form action="javascript:void(0);" @submit="handleAuthorsInput">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="$t('filters.authors-search')"
|
id="author"
|
||||||
|
list="authors"
|
||||||
name="authors"
|
name="authors"
|
||||||
|
:placeholder="$t('filters.authors-placeholder')"
|
||||||
v-model="authorsInputValue"
|
v-model="authorsInputValue"
|
||||||
@input="handleAuthorsInput"
|
|
||||||
@focus="preventKeyDown = true"
|
@focus="preventKeyDown = true"
|
||||||
@blur="preventKeyDown = false"
|
@blur="preventKeyDown = false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<button class="btn--action">{{ $t('filters.authors-button-title') }}</button>
|
||||||
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="card_sliders">
|
<section class="card_sliders">
|
||||||
@@ -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) {
|
||||||
@@ -297,16 +322,22 @@ export default defineComponent({
|
|||||||
@import '../../styles/card.scss';
|
@import '../../styles/card.scss';
|
||||||
@import '../../styles/animations.scss';
|
@import '../../styles/animations.scss';
|
||||||
|
|
||||||
|
h3.section-header {
|
||||||
|
text-align: center;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
&_controls {
|
.card_controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
|
|
||||||
@@ -316,7 +347,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&_content {
|
.card_content {
|
||||||
padding: 1em 0.5em;
|
padding: 1em 0.5em;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -326,7 +357,7 @@ export default defineComponent({
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
&_title {
|
.card_title {
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: $accentCol;
|
color: $accentCol;
|
||||||
@@ -334,7 +365,7 @@ export default defineComponent({
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&_regions {
|
.card_regions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
@@ -356,7 +387,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&_timestamp {
|
.card_timestamp {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -367,7 +398,7 @@ export default defineComponent({
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
margin-top: 0.5em;
|
text-align: center;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
min-width: 120px;
|
min-width: 120px;
|
||||||
@@ -381,29 +412,27 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&_modes {
|
.card_authors-search {
|
||||||
|
margin: 1em 0;
|
||||||
|
|
||||||
|
form {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
.option {
|
gap: 0.5em;
|
||||||
margin: 0 1em;
|
width: 100%;
|
||||||
|
margin-top: 1em;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&_authors-search {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 60%;
|
|
||||||
min-width: 240px;
|
|
||||||
|
|
||||||
input {
|
input {
|
||||||
width: 100%;
|
width: 70%;
|
||||||
|
max-width: 400px;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
border: 1px solid white;
|
outline: 1px solid white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&_actions {
|
.card_actions {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
|
|
||||||
@@ -430,7 +459,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.option-section h3 {
|
.option-section h3 {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -447,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -279,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') }}
|
||||||
@@ -288,7 +288,7 @@
|
|||||||
</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';
|
||||||
@@ -330,12 +330,8 @@ export default defineComponent({
|
|||||||
const apiStore = useApiStore();
|
const apiStore = useApiStore();
|
||||||
const stationFiltersStore = useStationFiltersStore();
|
const stationFiltersStore = useStationFiltersStore();
|
||||||
|
|
||||||
const isDataLoaded = computed(() => {
|
|
||||||
return apiStore.dataStatuses.sceneries != Status.Data.Loading;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isDataLoaded,
|
Status: Status.Data,
|
||||||
stationFiltersStore,
|
stationFiltersStore,
|
||||||
mainStore,
|
mainStore,
|
||||||
apiStore
|
apiStore
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -15,19 +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 TrainInfo from '../TrainsView/TrainInfo.vue';
|
import TrainSchedule from './TrainSchedule.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
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
activated() {
|
activated() {
|
||||||
const contentEl = this.$refs['content'] as HTMLElement;
|
const contentEl = this.$refs['content'] as HTMLElement;
|
||||||
@@ -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>
|
||||||
<StopDate :stop="stop" />
|
<div class="node"></div>
|
||||||
</span>
|
<div class="line line_node line_node-bottom"></div>
|
||||||
|
|
||||||
<div class="stop_line" v-if="i < train.timetableData!.followingStops.length - 1">
|
|
||||||
<div class="progress-bar"></div>
|
|
||||||
|
|
||||||
<div v-if="stop.comments" style="color: salmon">
|
|
||||||
<b>{{ stop.stopNameRAW }} </b>: <span v-html="stop.comments"></span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<StopLabel :stop="stop" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="stop_line">
|
||||||
|
<!-- Grid placeholder -->
|
||||||
|
<div></div>
|
||||||
|
|
||||||
|
<div class="progress">
|
||||||
|
<div class="line line_connection" v-if="i < scheduleStops.length - 1"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bottom-line-info">
|
||||||
|
<div class="info-comments" v-if="stop.comments" style="color: salmon">
|
||||||
|
<img src="/images/icon-warning.svg" alt="icon-warning" width="20" />
|
||||||
|
<b v-html="stop.comments"></b>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Routes -->
|
||||||
<span
|
<span
|
||||||
v-if="
|
v-if="
|
||||||
stop.departureLine == train.timetableData!.followingStops[i + 1].arrivalLine &&
|
stop.departureLine &&
|
||||||
!/sbl/gi.test(stop.departureLine!)
|
stop.departureLine == scheduleStops[i + 1]?.arrivalLine &&
|
||||||
|
!/sbl/gi.test(stop.departureLine)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ stop.departureLine }}
|
{{ stop.departureLine }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span v-else-if="!/sbl/gi.test(stop.departureLine!)">
|
<span v-else-if="stop.departureLine && !/sbl/gi.test(stop.departureLine)">
|
||||||
{{ stop.departureLine }} /
|
<div>{{ stop.departureLine }}</div>
|
||||||
{{ train.timetableData!.followingStops[i + 1].arrivalLine }}
|
<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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stop_line" v-else>
|
|
||||||
<div v-if="stop.comments" style="color: salmon">
|
|
||||||
<b>{{ stop.stopNameRAW }} </b>: <span v-html="stop.comments"></span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
|
||||||
</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 { useMainStore } from '../../store/mainStore';
|
import StopLabel from './StopLabel.vue';
|
||||||
import StopDate from '../Global/StopDate.vue';
|
|
||||||
import StockList from '../Global/StockList.vue';
|
import StockList from '../Global/StockList.vue';
|
||||||
import { TrainStop } from '../../store/typings';
|
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: useMainStore(),
|
store: useMainStore(),
|
||||||
|
apiStore: useApiStore()
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
lastConfirmed: computed(() => {
|
computed: {
|
||||||
return props.train.timetableData!.followingStops.findIndex(
|
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
|
(stop, i, stops) => stop.confirmed && !stops[i + 1]?.confirmed && !stops[i + 1]?.stopped
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
activeMinorStops: computed(() => {
|
|
||||||
const lastMajorConfirmed = props.train.timetableData!.followingStops.findIndex(
|
activeMinorStops() {
|
||||||
|
if (!this.train.timetableData) return [];
|
||||||
|
|
||||||
|
const lastMajorConfirmed = this.train.timetableData.followingStops.findIndex(
|
||||||
(stop, i, stops) => stop.confirmed && !stops[i + 1]?.confirmed
|
(stop, i, stops) => stop.confirmed && !stops[i + 1]?.confirmed
|
||||||
);
|
);
|
||||||
|
|
||||||
const activeMinorStopList: number[] = [];
|
const activeMinorStopList: number[] = [];
|
||||||
if (lastMajorConfirmed + 1 >= props.train.timetableData!.followingStops.length)
|
if (lastMajorConfirmed + 1 >= this.train.timetableData.followingStops.length)
|
||||||
return activeMinorStopList;
|
return activeMinorStopList;
|
||||||
|
|
||||||
for (
|
for (
|
||||||
let i = lastMajorConfirmed + 1;
|
let i = lastMajorConfirmed + 1;
|
||||||
i < props.train.timetableData!.followingStops.length;
|
i < this.train.timetableData!.followingStops.length;
|
||||||
i++
|
i++
|
||||||
) {
|
) {
|
||||||
if (/po\.|sbl/gi.test(props.train.timetableData!.followingStops[i].stopNameRAW))
|
if (/po\.|sbl/gi.test(this.train.timetableData!.followingStops[i].stopNameRAW))
|
||||||
activeMinorStopList.push(i);
|
activeMinorStopList.push(i);
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return activeMinorStopList;
|
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-date {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stop-name {
|
.stop {
|
||||||
background: none;
|
// Begin stop
|
||||||
color: #aaa;
|
&[data-position='begin'] {
|
||||||
padding: 0;
|
.node {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&[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 {
|
&[data-stop-type*='ph'] .node {
|
||||||
animation: 0.5s ease-in-out alternate infinite blink;
|
border-color: $haltClr;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-minor-stop-active='true'] {
|
||||||
|
.progress > .line {
|
||||||
|
animation: $blinkAnim;
|
||||||
|
}
|
||||||
|
|
||||||
|
& + div {
|
||||||
|
.progress > .line_node-top {
|
||||||
|
animation: $blinkAnim;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.last-confirmed {
|
// Last confirmed outpost / checkpoint
|
||||||
.stop_line > .progress-bar {
|
&[data-last-confirmed='true'] {
|
||||||
animation: 0.5s ease-in-out alternate infinite blink;
|
.progress > .line_connection {
|
||||||
|
animation: $blinkAnim;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress > .line_node-bottom {
|
||||||
|
animation: $blinkAnim;
|
||||||
|
}
|
||||||
|
|
||||||
|
& + div {
|
||||||
|
.progress > .line_node-top {
|
||||||
|
animation: $blinkAnim;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.confirmed {
|
// Confirmed status
|
||||||
.stop_info {
|
&[data-status='confirmed'] {
|
||||||
> .progress-bar {
|
.progress > .node {
|
||||||
background-color: $confirmedClr;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .indicator {
|
|
||||||
border-color: $confirmedClr;
|
border-color: $confirmedClr;
|
||||||
}
|
}
|
||||||
}
|
.progress > .line {
|
||||||
|
border-left: 2px solid $confirmedClr;
|
||||||
.stop_line > .progress-bar {
|
border-right: 2px solid $confirmedClr;
|
||||||
background-color: $confirmedClr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.stopped {
|
// Stopped status
|
||||||
.stop_info {
|
&[data-status='stopped'] {
|
||||||
> .indicator {
|
.progress > .node {
|
||||||
border-color: $stoppedClr;
|
border-color: $stoppedClr;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .stop-bar {
|
.progress > .line_node {
|
||||||
background: $stoppedClr;
|
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 {
|
.stop_line {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
|
margin-top: 5px;
|
||||||
padding: 0.35em 0;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.line-segment {
|
|
||||||
color: $barClr;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.stop_info {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stop-bar {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: -17px;
|
|
||||||
|
|
||||||
z-index: 10;
|
|
||||||
|
|
||||||
width: 3px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.distance {
|
.distance {
|
||||||
position: absolute;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
top: 50%;
|
justify-content: center;
|
||||||
transform: translate(-100%, -50%);
|
|
||||||
|
|
||||||
margin-left: -1.75rem;
|
|
||||||
|
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
color: #d6d6d6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.indicator {
|
.progress {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
& > .node {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 11;
|
|
||||||
|
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: -1rem;
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
transform: translate(-47%, -50%);
|
z-index: 15;
|
||||||
|
|
||||||
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>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<hr style="margin: 0.5em 0" />
|
<hr style="margin: 0.5em 0" />
|
||||||
|
|
||||||
<div v-if="apiStore.dataStatuses.trains == Status.Loaded && regionTrains.length > 0">
|
<div v-if="apiStore.dataStatuses.connection == Status.Loaded && regionTrains.length > 0">
|
||||||
<div class="top-list general">
|
<div class="top-list general">
|
||||||
<transition-group tag="ul" name="stats-anim">
|
<transition-group tag="ul" name="stats-anim">
|
||||||
<li class="badge" key="timetable-count">
|
<li class="badge" key="timetable-count">
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="apiStore.dataStatuses.trains != Status.Loaded">
|
<div v-else-if="apiStore.dataStatuses.connection != Status.Loaded">
|
||||||
{{ $t('train-stats.stats-loading') }}
|
{{ $t('train-stats.stats-loading') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition name="status-anim" mode="out-in" tag="div" class="train-table">
|
<transition name="status-anim" mode="out-in" tag="div" class="train-table">
|
||||||
<div :key="apiStore.dataStatuses.trains">
|
<div :key="apiStore.dataStatuses.connection">
|
||||||
<div class="table-info" key="offline" v-if="store.isOffline">
|
<div class="table-info" key="offline" v-if="store.isOffline">
|
||||||
{{ $t('app.offline') }}
|
{{ $t('app.offline') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Loading v-else-if="trains.length == 0 && apiStore.dataStatuses.trains == 0" key="loading" />
|
<Loading v-else-if="apiStore.dataStatuses.connection == Status.Loading" key="loading" />
|
||||||
|
|
||||||
<div
|
<div class="table-info" key="no-trains" v-else-if="trains.length == 0">
|
||||||
class="table-info"
|
|
||||||
key="no-trains"
|
|
||||||
v-else-if="trains.length == 0 && apiStore.dataStatuses.trains != 0"
|
|
||||||
>
|
|
||||||
{{ $t('trains.no-trains') }}
|
{{ $t('trains.no-trains') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -64,6 +60,7 @@ export default defineComponent({
|
|||||||
searchedDriver,
|
searchedDriver,
|
||||||
store,
|
store,
|
||||||
apiStore,
|
apiStore,
|
||||||
|
Status: Status.Data,
|
||||||
sorterActive: inject('sorterActive') as {
|
sorterActive: inject('sorterActive') as {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
dir: number;
|
dir: number;
|
||||||
@@ -75,7 +72,7 @@ export default defineComponent({
|
|||||||
dataStatus() {
|
dataStatus() {
|
||||||
if (this.store.isOffline) return Status.Data.Offline;
|
if (this.store.isOffline) return Status.Data.Offline;
|
||||||
|
|
||||||
if (this.trains.length == 0 && this.apiStore.dataStatuses.trains == Status.Data.Loading)
|
if (this.trains.length == 0 && this.apiStore.dataStatuses.connection == Status.Data.Loading)
|
||||||
return Status.Data.Loading;
|
return Status.Data.Loading;
|
||||||
|
|
||||||
return Status.Data.Loaded;
|
return Status.Data.Loaded;
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -8732,7 +8732,7 @@
|
|||||||
"departureDelay": 0,
|
"departureDelay": 0,
|
||||||
"beginsHere": true,
|
"beginsHere": true,
|
||||||
"terminatesHere": false,
|
"terminatesHere": false,
|
||||||
"confirmed": 0,
|
"confirmed": 1,
|
||||||
"stopped": 0,
|
"stopped": 0,
|
||||||
"stopTime": null
|
"stopTime": null
|
||||||
},
|
},
|
||||||
@@ -9380,7 +9380,7 @@
|
|||||||
"stopType": "",
|
"stopType": "",
|
||||||
"stopDistance": 123.62,
|
"stopDistance": 123.62,
|
||||||
"pointId": "1663532077406",
|
"pointId": "1663532077406",
|
||||||
"comments": null,
|
"comments": "test121",
|
||||||
"mainStop": true,
|
"mainStop": true,
|
||||||
"arrivalLine": "Sk",
|
"arrivalLine": "Sk",
|
||||||
"arrivalTimestamp": 1701889320000,
|
"arrivalTimestamp": 1701889320000,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+49
-25
@@ -12,7 +12,7 @@
|
|||||||
"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": "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-b1": "5 PLN",
|
||||||
"p4-b2": "a symbolic highlight",
|
"p4-b2": "a symbolic highlight",
|
||||||
"p5": "Thank you and enjoy the app!<br />~ Spythegre",
|
"p5": "Thank you and enjoy the app!<br />~ Spythere",
|
||||||
"action-exit": "Maybe next time...",
|
"action-exit": "Maybe next time...",
|
||||||
"action-paypal": "DONATE WITH PAYPAL",
|
"action-paypal": "DONATE WITH PAYPAL",
|
||||||
"action-buycoffee": "BUY ME A COFFEE!",
|
"action-buycoffee": "BUY ME A COFFEE!",
|
||||||
@@ -144,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",
|
||||||
@@ -156,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"
|
||||||
@@ -226,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",
|
||||||
@@ -347,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! :/",
|
||||||
|
|||||||
+46
-23
@@ -133,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",
|
||||||
@@ -145,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"
|
||||||
@@ -217,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.",
|
||||||
@@ -326,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!",
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|||||||
+4
-6
@@ -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
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Availability, OnlineScenery, ScheduledTrain } from '../../store/typings';
|
import { Availability, OnlineScenery, ScheduledTrain } from '../../store/typings';
|
||||||
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[];
|
||||||
|
|||||||
+8
-51
@@ -1,6 +1,6 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import http from '../http';
|
import http from '../http';
|
||||||
import { API } from '../typings/api';
|
import { API, Websocket } from '../typings/api';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { Status } from '../typings/common';
|
import { Status } from '../typings/common';
|
||||||
import { StationJSONData } from './typings';
|
import { StationJSONData } from './typings';
|
||||||
@@ -18,31 +18,19 @@ export const useApiStore = defineStore('apiStore', {
|
|||||||
activeData: undefined as API.ActiveData.Response | undefined,
|
activeData: undefined as API.ActiveData.Response | undefined,
|
||||||
rollingStockData: undefined as API.RollingStock.Response | undefined,
|
rollingStockData: undefined as API.RollingStock.Response | undefined,
|
||||||
donatorsData: [] as API.Donators.Response,
|
donatorsData: [] as API.Donators.Response,
|
||||||
sceneryData: [] as StationJSONData[]
|
sceneryData: [] as StationJSONData[],
|
||||||
|
|
||||||
|
websocketData: undefined as Websocket.Payload | undefined
|
||||||
|
|
||||||
|
// activeDataTimeout: undefined as number | undefined
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
async setupAPI() {
|
async setupStaticAPIData() {
|
||||||
// Static data
|
// Static data
|
||||||
this.fetchStockInfoData();
|
this.fetchStockInfoData();
|
||||||
this.fetchDonatorsData();
|
this.fetchDonatorsData();
|
||||||
this.fetchStationsGeneralInfo();
|
this.fetchStationsGeneralInfo();
|
||||||
|
|
||||||
this.scheduleFetchActiveData();
|
|
||||||
},
|
|
||||||
|
|
||||||
async setDataStatuses() {
|
|
||||||
if (!this.activeData?.activeSceneries) {
|
|
||||||
this.dataStatuses.sceneries = Status.Data.Error;
|
|
||||||
this.dataStatuses.trains = Status.Data.Error;
|
|
||||||
this.dataStatuses.dispatchers = Status.Data.Error;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dataStatuses.sceneries = Status.Data.Loaded;
|
|
||||||
this.dataStatuses.trains = !this.activeData.trains ? Status.Data.Warning : Status.Data.Loaded;
|
|
||||||
this.dataStatuses.dispatchers = Status.Data.Loaded;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetchDonatorsData() {
|
async fetchDonatorsData() {
|
||||||
@@ -67,38 +55,6 @@ export const useApiStore = defineStore('apiStore', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async scheduleFetchActiveData() {
|
|
||||||
if (import.meta.env.VITE_API_MODE === 'mock') {
|
|
||||||
const mockActiveData = await import('../data/mockActiveData.json');
|
|
||||||
this.dataStatuses.connection = Status.Data.Loaded;
|
|
||||||
this.activeData = mockActiveData;
|
|
||||||
this.setDataStatuses();
|
|
||||||
|
|
||||||
console.warn('Stacjownik działa w trybie mockowania danych z WS');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = (await http.get<API.ActiveData.Response>('api/getActiveData')).data;
|
|
||||||
|
|
||||||
this.activeData = data;
|
|
||||||
this.dataStatuses.connection = Status.Data.Loaded;
|
|
||||||
|
|
||||||
this.setDataStatuses();
|
|
||||||
} catch (error) {
|
|
||||||
this.dataStatuses.connection = Status.Data.Error;
|
|
||||||
console.error('Wystąpił błąd podczas pobierania danych online z API!');
|
|
||||||
} finally {
|
|
||||||
setTimeout(
|
|
||||||
() => {
|
|
||||||
this.scheduleFetchActiveData();
|
|
||||||
},
|
|
||||||
~~(1000 * (Math.random() * (25 - 20) + 25))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async fetchStationsGeneralInfo() {
|
async fetchStationsGeneralInfo() {
|
||||||
const sceneryData: StationJSONData[] = (await http.get<StationJSONData[]>('api/getSceneries'))
|
const sceneryData: StationJSONData[] = (await http.get<StationJSONData[]>('api/getSceneries'))
|
||||||
.data;
|
.data;
|
||||||
@@ -108,6 +64,7 @@ export const useApiStore = defineStore('apiStore', {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.dataStatuses.sceneries = Status.Data.Loaded;
|
||||||
this.sceneryData = sceneryData;
|
this.sceneryData = sceneryData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-130
@@ -1,5 +1,4 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import StationRoutes from '../scripts/interfaces/StationRoutes';
|
|
||||||
import Train from '../scripts/interfaces/Train';
|
import Train from '../scripts/interfaces/Train';
|
||||||
import { parseSpawns, getScheduledTrains, getStationTrains } from './utils';
|
import { parseSpawns, getScheduledTrains, getStationTrains } from './utils';
|
||||||
|
|
||||||
@@ -9,6 +8,7 @@ import { Status } from '../typings/common';
|
|||||||
import Station from '../scripts/interfaces/Station';
|
import Station from '../scripts/interfaces/Station';
|
||||||
import { useApiStore } from './apiStore';
|
import { useApiStore } from './apiStore';
|
||||||
import { API } from '../typings/api';
|
import { API } from '../typings/api';
|
||||||
|
import { StationRoutes } from '../scripts/interfaces/StationRoutes';
|
||||||
|
|
||||||
export const useMainStore = defineStore('store', {
|
export const useMainStore = defineStore('store', {
|
||||||
state: () =>
|
state: () =>
|
||||||
@@ -18,7 +18,7 @@ export const useMainStore = defineStore('store', {
|
|||||||
isOffline: false,
|
isOffline: false,
|
||||||
|
|
||||||
dispatcherStatsName: '',
|
dispatcherStatsName: '',
|
||||||
dispatcherStatsData: undefined,
|
dispatcherStatsStatus: Status.Data.Initialized,
|
||||||
|
|
||||||
driverStatsName: '',
|
driverStatsName: '',
|
||||||
driverStatsData: undefined,
|
driverStatsData: undefined,
|
||||||
@@ -34,7 +34,7 @@ export const useMainStore = defineStore('store', {
|
|||||||
trainList(): Train[] {
|
trainList(): Train[] {
|
||||||
const apiStore = useApiStore();
|
const apiStore = useApiStore();
|
||||||
|
|
||||||
return (apiStore.activeData?.trains ?? [])
|
return (apiStore.websocketData?.activeTrains ?? [])
|
||||||
.filter((train) => train.timetable || train.online)
|
.filter((train) => train.timetable || train.online)
|
||||||
.map((train) => {
|
.map((train) => {
|
||||||
const stock = train.stockString.split(';');
|
const stock = train.stockString.split(';');
|
||||||
@@ -88,9 +88,9 @@ export const useMainStore = defineStore('store', {
|
|||||||
const apiStore = useApiStore();
|
const apiStore = useApiStore();
|
||||||
|
|
||||||
if (state.isOffline) return [];
|
if (state.isOffline) return [];
|
||||||
if (!apiStore.activeData?.activeSceneries) return [];
|
if (!apiStore.websocketData?.activeSceneries) return [];
|
||||||
|
|
||||||
return apiStore.activeData?.activeSceneries.reduce((list, scenery) => {
|
return apiStore.websocketData?.activeSceneries.reduce((list, scenery) => {
|
||||||
if (scenery.isOnline !== 1 && Date.now() - scenery.lastSeen > 1000 * 60 * 2) return list;
|
if (scenery.isOnline !== 1 && Date.now() - scenery.lastSeen > 1000 * 60 * 2) return list;
|
||||||
if (scenery.dispatcherStatus == Status.ActiveDispatcher.UNKNOWN) return list;
|
if (scenery.dispatcherStatus == Status.ActiveDispatcher.UNKNOWN) return list;
|
||||||
|
|
||||||
@@ -155,46 +155,39 @@ export const useMainStore = defineStore('store', {
|
|||||||
const apiStore = useApiStore();
|
const apiStore = useApiStore();
|
||||||
|
|
||||||
return apiStore.sceneryData.map((scenery) => {
|
return apiStore.sceneryData.map((scenery) => {
|
||||||
|
const routes = scenery.routesInfo.reduce(
|
||||||
|
(acc, route) => {
|
||||||
|
const tracksKey = route.routeTracks == 2 ? 'twoWay' : 'oneWay';
|
||||||
|
const isElectric = route.isElectric;
|
||||||
|
const routesKey: keyof StationRoutes = `${tracksKey}${
|
||||||
|
!isElectric ? 'No' : ''
|
||||||
|
}CatenaryRouteNames`;
|
||||||
|
|
||||||
|
if (!route.isInternal) acc[routesKey].push(route.routeName);
|
||||||
|
if (route.isRouteSBL) acc['sblRouteNames'].push(route.routeName);
|
||||||
|
|
||||||
|
acc[tracksKey].push(route);
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
oneWay: [],
|
||||||
|
oneWayCatenaryRouteNames: [],
|
||||||
|
oneWayNoCatenaryRouteNames: [],
|
||||||
|
twoWay: [],
|
||||||
|
twoWayCatenaryRouteNames: [],
|
||||||
|
twoWayNoCatenaryRouteNames: [],
|
||||||
|
sblRouteNames: []
|
||||||
|
} as StationRoutes
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: scenery.name,
|
name: scenery.name,
|
||||||
|
|
||||||
generalInfo: {
|
generalInfo: {
|
||||||
...scenery,
|
...scenery,
|
||||||
authors: scenery.authors?.split(',').map((a) => a.trim()),
|
authors: scenery.authors?.split(',').map((a) => a.trim()),
|
||||||
routes:
|
routes: routes,
|
||||||
scenery.routesInfo.reduce(
|
|
||||||
(acc, route) => {
|
|
||||||
const propName: keyof StationRoutes = `${
|
|
||||||
route.routeTracks == 2 ? 'twoWay' : 'oneWay'
|
|
||||||
}${route.isElectric ? '' : 'No'}CatenaryRouteNames`;
|
|
||||||
|
|
||||||
acc[route.routeTracks == 2 ? 'twoWay' : 'oneWay'].push({
|
|
||||||
name: route.routeName,
|
|
||||||
SBL: route.isRouteSBL,
|
|
||||||
TWB: false,
|
|
||||||
catenary: route.isElectric,
|
|
||||||
isInternal: route.isInternal,
|
|
||||||
tracks: route.routeTracks,
|
|
||||||
length: route.routeLength,
|
|
||||||
speed: route.routeSpeed
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!route.isInternal) acc[propName].push(route.routeName);
|
|
||||||
|
|
||||||
if (route.isRouteSBL) acc['sblRouteNames'].push(route.routeName);
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
oneWay: [],
|
|
||||||
twoWay: [],
|
|
||||||
sblRouteNames: [],
|
|
||||||
oneWayCatenaryRouteNames: [],
|
|
||||||
oneWayNoCatenaryRouteNames: [],
|
|
||||||
twoWayCatenaryRouteNames: [],
|
|
||||||
twoWayNoCatenaryRouteNames: []
|
|
||||||
} as StationRoutes
|
|
||||||
) || {},
|
|
||||||
checkpoints: scenery.checkpoints
|
checkpoints: scenery.checkpoints
|
||||||
? scenery.checkpoints
|
? scenery.checkpoints
|
||||||
.split(';')
|
.split(';')
|
||||||
@@ -204,96 +197,5 @@ export const useMainStore = defineStore('store', {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
async processStationsOnlineInfo(activeData: API.ActiveData.Response) {
|
|
||||||
if (!activeData.activeSceneries) return;
|
|
||||||
|
|
||||||
const onlineSceneries = activeData.activeSceneries.reduce((acc, scenery) => {
|
|
||||||
const savedStation = this.stationList.find((st) => scenery.stationName === st.name);
|
|
||||||
|
|
||||||
if (scenery.isOnline !== 1 && Date.now() - scenery.lastSeen > 1000 * 60 * 2) return acc;
|
|
||||||
if (scenery.dispatcherStatus == Status.ActiveDispatcher.UNKNOWN) return acc;
|
|
||||||
|
|
||||||
const station = this.stationList.find((s) => s.name === scenery.stationName);
|
|
||||||
|
|
||||||
const scheduledTrains = getScheduledTrains(this.trainList, scenery, station?.generalInfo);
|
|
||||||
|
|
||||||
const stationTrains = getStationTrains(
|
|
||||||
this.trainList,
|
|
||||||
scheduledTrains,
|
|
||||||
this.region.id,
|
|
||||||
scenery
|
|
||||||
);
|
|
||||||
|
|
||||||
// Remove checkpoint duplicates
|
|
||||||
const uniqueScheduledTrains = scheduledTrains.reduce(
|
|
||||||
(uniqueList, sTrain) =>
|
|
||||||
uniqueList.find((v) => v.trainId === sTrain.trainId)
|
|
||||||
? uniqueList
|
|
||||||
: [...uniqueList, sTrain],
|
|
||||||
[] as ScheduledTrain[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const dispatcherTimestamp =
|
|
||||||
scenery.dispatcherStatus == Status.ActiveDispatcher.NO_LIMIT
|
|
||||||
? Date.now() + 25500000
|
|
||||||
: scenery.dispatcherStatus > 5
|
|
||||||
? scenery.dispatcherStatus
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const onlineInfo = {
|
|
||||||
name: scenery.stationName,
|
|
||||||
hash: scenery.stationHash,
|
|
||||||
region: scenery.region,
|
|
||||||
maxUsers: scenery.maxUsers,
|
|
||||||
currentUsers: scenery.currentUsers,
|
|
||||||
spawns: parseSpawns(scenery.spawnString),
|
|
||||||
dispatcherName: scenery.dispatcherName,
|
|
||||||
dispatcherRate: scenery.dispatcherRate,
|
|
||||||
dispatcherId: scenery.dispatcherId,
|
|
||||||
dispatcherExp: scenery.dispatcherExp,
|
|
||||||
dispatcherIsSupporter: scenery.dispatcherIsSupporter,
|
|
||||||
scheduledTrains: scheduledTrains,
|
|
||||||
stationTrains: stationTrains,
|
|
||||||
dispatcherStatus: scenery.dispatcherStatus,
|
|
||||||
dispatcherTimestamp: dispatcherTimestamp,
|
|
||||||
|
|
||||||
isOnline: scenery.isOnline == 1,
|
|
||||||
|
|
||||||
scheduledTrainCount: {
|
|
||||||
all: uniqueScheduledTrains.length,
|
|
||||||
confirmed: uniqueScheduledTrains.filter((train) => train.stopInfo.confirmed).length,
|
|
||||||
unconfirmed: uniqueScheduledTrains.filter((train) => !train.stopInfo.confirmed).length
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (savedStation) savedStation.onlineInfo = onlineInfo;
|
|
||||||
else
|
|
||||||
this.stationList.push({
|
|
||||||
name: onlineInfo.name,
|
|
||||||
onlineInfo: onlineInfo
|
|
||||||
});
|
|
||||||
|
|
||||||
acc.push(onlineInfo);
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, [] as OnlineScenery[]);
|
|
||||||
|
|
||||||
// Reset online info of already offline sceneries
|
|
||||||
this.stationList
|
|
||||||
.filter(
|
|
||||||
(station) =>
|
|
||||||
station.onlineInfo &&
|
|
||||||
onlineSceneries.findIndex(
|
|
||||||
(os) => os.region == station.onlineInfo!.region && station.name == os.name
|
|
||||||
) != -1
|
|
||||||
)
|
|
||||||
.forEach((station) => (station.onlineInfo = undefined));
|
|
||||||
},
|
|
||||||
|
|
||||||
async changeRegion(region: StoreState['region']) {
|
|
||||||
this.region = region;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import Station from '../scripts/interfaces/Station';
|
|
||||||
import { API } from '../typings/api';
|
import { API } from '../typings/api';
|
||||||
import { Status } from '../typings/common';
|
import { Status } from '../typings/common';
|
||||||
|
|
||||||
@@ -36,6 +35,7 @@ export interface StationRoutesInfo {
|
|||||||
routeLength: number;
|
routeLength: number;
|
||||||
routeSpeed: number;
|
routeSpeed: number;
|
||||||
routeTracks: number;
|
routeTracks: number;
|
||||||
|
hidden?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StationJSONData {
|
export interface StationJSONData {
|
||||||
@@ -45,6 +45,7 @@ export interface StationJSONData {
|
|||||||
lines: string;
|
lines: string;
|
||||||
project: string;
|
project: string;
|
||||||
projectUrl: string;
|
projectUrl: string;
|
||||||
|
hash: string;
|
||||||
|
|
||||||
reqLevel: number;
|
reqLevel: number;
|
||||||
|
|
||||||
|
|||||||
@@ -196,6 +196,7 @@ export function getScheduledTrains(
|
|||||||
|
|
||||||
return trainList.reduce((acc: ScheduledTrain[], train) => {
|
return trainList.reduce((acc: ScheduledTrain[], train) => {
|
||||||
if (!train.timetableData) return acc;
|
if (!train.timetableData) return acc;
|
||||||
|
if (train.region != sceneryData.region) return acc;
|
||||||
|
|
||||||
const timetable = train.timetableData;
|
const timetable = train.timetableData;
|
||||||
if (!timetable.sceneries.includes(sceneryData.stationHash)) return acc;
|
if (!timetable.sceneries.includes(sceneryData.stationHash)) return acc;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: 90vh;
|
height: 90vh;
|
||||||
min-height: 550px;
|
min-height: 550px;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
|
||||||
padding-right: 0.2em;
|
padding-right: 0.2em;
|
||||||
}
|
}
|
||||||
@@ -24,7 +25,7 @@
|
|||||||
text-align: end;
|
text-align: end;
|
||||||
|
|
||||||
padding: 0.25em;
|
padding: 0.25em;
|
||||||
margin: 0.5em 0;
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.journal_warning {
|
.journal_warning {
|
||||||
@@ -53,9 +54,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn--load-data {
|
.btn--load-data {
|
||||||
|
|||||||
@@ -2,24 +2,35 @@
|
|||||||
@import 'responsive.scss';
|
@import 'responsive.scss';
|
||||||
|
|
||||||
.stats-tab {
|
.stats-tab {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
z-index: 99;
|
||||||
|
|
||||||
|
transform: translateY(1em);
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
background-color: #1a1a1a;
|
background-color: #1a1a1a;
|
||||||
box-shadow: 0 0 5px 1px $accentCol;
|
box-shadow: 0 0 5px 1px $accentCol;
|
||||||
|
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
margin-bottom: 0.5em;
|
hr.header-separator {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
width: 100%;
|
hr.section-separator {
|
||||||
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-stats {
|
.info-stats {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-badge {
|
.stat-badge {
|
||||||
|
|||||||
@@ -30,7 +30,8 @@
|
|||||||
top: calc(100% + 0.5em);
|
top: calc(100% + 0.5em);
|
||||||
|
|
||||||
background-color: $bgCol;
|
background-color: $bgCol;
|
||||||
box-shadow: 0 5px 10px 2px #0f0f0f;
|
// box-shadow: 0 5px 10px 2px #0f0f0f;
|
||||||
|
box-shadow: 0 0 5px 1px $accentCol;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 550px;
|
max-width: 550px;
|
||||||
|
|||||||
@@ -5,11 +5,6 @@
|
|||||||
.actions-bar {
|
.actions-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filters-options {
|
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h1.option-title {
|
h1.option-title {
|
||||||
@@ -57,6 +52,7 @@ h1.option-title {
|
|||||||
|
|
||||||
.sort-option[data-selected='true'] {
|
.sort-option[data-selected='true'] {
|
||||||
color: $accentCol;
|
color: $accentCol;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-option {
|
.filter-option {
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Quicksand';
|
||||||
|
src:
|
||||||
|
url('/fonts/Quicksand-Bold.woff2') format('woff2'),
|
||||||
|
url('/fonts/Quicksand-Bold.woff') format('woff');
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Quicksand';
|
||||||
|
src:
|
||||||
|
url('/fonts/Quicksand-SemiBold.woff2') format('woff2'),
|
||||||
|
url('/fonts/Quicksand-SemiBold.woff') format('woff');
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Quicksand';
|
||||||
|
src:
|
||||||
|
url('/fonts/Quicksand-Medium.woff2') format('woff2'),
|
||||||
|
url('/fonts/Quicksand-Medium.woff') format('woff');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Quicksand';
|
||||||
|
src:
|
||||||
|
url('/fonts/Quicksand-Regular.woff2') format('woff2'),
|
||||||
|
url('/fonts/Quicksand-Regular.woff') format('woff');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Quicksand';
|
||||||
|
src:
|
||||||
|
url('/fonts/Quicksand-Light.woff2') format('woff2'),
|
||||||
|
url('/fonts/Quicksand-Light.woff') format('woff');
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@import 'fonts.scss';
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--clr-primary: #ffc014;
|
--clr-primary: #ffc014;
|
||||||
--clr-secondary: #2f2f2f;
|
--clr-secondary: #2f2f2f;
|
||||||
@@ -11,7 +13,7 @@
|
|||||||
--clr-skr: #ff5100;
|
--clr-skr: #ff5100;
|
||||||
--clr-twr: #ffbb00;
|
--clr-twr: #ffbb00;
|
||||||
|
|
||||||
--clr-error: #df3e3e;
|
--clr-error: #fa3636;
|
||||||
--clr-warning: #c59429;
|
--clr-warning: #c59429;
|
||||||
|
|
||||||
--clr-donator: #f7a4ff;
|
--clr-donator: #f7a4ff;
|
||||||
@@ -158,6 +160,10 @@ ul {
|
|||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
color: var(--clr-error);
|
||||||
|
}
|
||||||
|
|
||||||
&--donator {
|
&--donator {
|
||||||
color: var(--clr-donator);
|
color: var(--clr-donator);
|
||||||
text-shadow: var(--clr-donator) 0 0 10px;
|
text-shadow: var(--clr-donator) 0 0 10px;
|
||||||
@@ -183,7 +189,7 @@ a.a-button {
|
|||||||
&[data-disabled='true'] {
|
&[data-disabled='true'] {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0.85;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.btn--filled {
|
&.btn--filled {
|
||||||
|
|||||||
+57
-12
@@ -31,7 +31,11 @@ export namespace API {
|
|||||||
|
|
||||||
export namespace DispatcherStats {
|
export namespace DispatcherStats {
|
||||||
export interface DistanceStat {
|
export interface DistanceStat {
|
||||||
routeDistance: number;
|
routeDistance: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DurationStat {
|
||||||
|
currentDuration: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Count {
|
export interface Count {
|
||||||
@@ -39,11 +43,18 @@ export namespace API {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Response {
|
export interface Response {
|
||||||
_sum: DistanceStat;
|
services: {
|
||||||
_max: DistanceStat;
|
count: number;
|
||||||
_min: DistanceStat;
|
durationMax: number;
|
||||||
_avg: DistanceStat;
|
durationAvg: number;
|
||||||
_count: Count;
|
} | null;
|
||||||
|
|
||||||
|
issuedTimetables: {
|
||||||
|
count: number;
|
||||||
|
distanceMax: number;
|
||||||
|
distanceAvg: number;
|
||||||
|
distanceSum: number;
|
||||||
|
} | null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,21 +274,47 @@ export namespace API {
|
|||||||
distanceAvg: number;
|
distanceAvg: number;
|
||||||
maxTimetable: API.TimetableHistory.Data | null;
|
maxTimetable: API.TimetableHistory.Data | null;
|
||||||
|
|
||||||
mostActiveDispatchers: {
|
globalDiff: GlobalDiff;
|
||||||
|
globalMax: GlobalMax;
|
||||||
|
|
||||||
|
mostActiveDispatchers: MostActiveDispatcher[];
|
||||||
|
mostActiveDrivers: MostActiveDriver[];
|
||||||
|
|
||||||
|
longestDuties: LongestDuty[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MostActiveDispatcher {
|
||||||
name: string;
|
name: string;
|
||||||
count: number;
|
count: number;
|
||||||
}[];
|
}
|
||||||
|
|
||||||
mostActiveDrivers: {
|
export interface MostActiveDriver {
|
||||||
name: string;
|
name: string;
|
||||||
distance: number;
|
distance: number;
|
||||||
}[];
|
}
|
||||||
|
|
||||||
longestDuties: {
|
export interface LongestDuty {
|
||||||
name: string;
|
name: string;
|
||||||
duration: number;
|
duration: number;
|
||||||
station: string;
|
station: string;
|
||||||
}[];
|
}
|
||||||
|
|
||||||
|
export interface GlobalDiff {
|
||||||
|
rippedSwitches: number;
|
||||||
|
derailments: number;
|
||||||
|
skippedStopSignals: number;
|
||||||
|
radioStops: number;
|
||||||
|
kills: number;
|
||||||
|
drivenKilometers: number;
|
||||||
|
routedTrains: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GlobalMax {
|
||||||
|
_max: {
|
||||||
|
drivers: number;
|
||||||
|
dispatchers: number;
|
||||||
|
timetables: number;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,3 +368,11 @@ export namespace GithubAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export namespace Websocket {
|
||||||
|
export interface Payload {
|
||||||
|
activeSceneries: API.ActiveSceneries.Response;
|
||||||
|
activeTrains: API.ActiveTrains.Response;
|
||||||
|
connectedSocketCount: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export namespace Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum Data {
|
export enum Data {
|
||||||
Offline = 2,
|
Offline = -2,
|
||||||
Initialized = -1,
|
Initialized = -1,
|
||||||
Loading = 0,
|
Loading = 0,
|
||||||
Error = 1,
|
Error = 1,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<JournalHeader />
|
<JournalHeader />
|
||||||
|
|
||||||
<div class="journal_wrapper">
|
<div class="journal_wrapper">
|
||||||
|
<div class="journal_top-bar">
|
||||||
<JournalOptions
|
<JournalOptions
|
||||||
@on-search-confirm="fetchHistoryData"
|
@on-search-confirm="fetchHistoryData"
|
||||||
@on-options-reset="resetOptions"
|
@on-options-reset="resetOptions"
|
||||||
@@ -13,6 +14,9 @@
|
|||||||
optionsType="dispatchers"
|
optionsType="dispatchers"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<JournalStats :statsButtons="statsButtons" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="journal_refreshed-date" v-if="dataRefreshedAt">
|
<div class="journal_refreshed-date" v-if="dataRefreshedAt">
|
||||||
{{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }}
|
{{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }}
|
||||||
</div>
|
</div>
|
||||||
@@ -33,22 +37,33 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, provide, reactive, Ref, ref } from 'vue';
|
import { defineComponent, provide, reactive, Ref, ref } from 'vue';
|
||||||
|
|
||||||
import JournalOptions from '../components/JournalView/JournalOptions.vue';
|
import http from '../http';
|
||||||
import { useMainStore } from '../store/mainStore';
|
import { useMainStore } from '../store/mainStore';
|
||||||
import JournalDispatchersList from '../components/JournalView/JournalDispatchersList.vue';
|
|
||||||
|
|
||||||
import JournalHeader from '../components/JournalView/JournalHeader.vue';
|
|
||||||
import { LocationQuery } from 'vue-router';
|
import { LocationQuery } from 'vue-router';
|
||||||
import { Journal } from '../components/JournalView/typings';
|
import { Journal } from '../components/JournalView/typings';
|
||||||
import { API } from '../typings/api';
|
import { API } from '../typings/api';
|
||||||
import { Status } from '../typings/common';
|
import { Status } from '../typings/common';
|
||||||
import http from '../http';
|
|
||||||
|
import JournalDispatchersList from '../components/JournalView/JournalDispatchers/JournalDispatchersList.vue';
|
||||||
|
import JournalOptions from '../components/JournalView/JournalOptions.vue';
|
||||||
|
import JournalHeader from '../components/JournalView/JournalHeader.vue';
|
||||||
|
import JournalStats from '../components/JournalView/JournalStats.vue';
|
||||||
|
|
||||||
|
const statsButtons: Journal.StatsButton[] = [
|
||||||
|
{
|
||||||
|
tab: Journal.StatsTab.DISPATCHER_STATS,
|
||||||
|
localeKey: 'journal.dispatcher-stats.button',
|
||||||
|
iconName: 'user',
|
||||||
|
disabled: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
JournalOptions,
|
JournalOptions,
|
||||||
JournalDispatchersList,
|
JournalHeader,
|
||||||
JournalHeader
|
JournalStats,
|
||||||
|
JournalDispatchersList
|
||||||
},
|
},
|
||||||
name: 'JournalDispatchers',
|
name: 'JournalDispatchers',
|
||||||
|
|
||||||
@@ -65,6 +80,8 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
|
statsButtons,
|
||||||
|
|
||||||
currentQuery: '',
|
currentQuery: '',
|
||||||
currentQueryArray: [] as string[],
|
currentQueryArray: [] as string[],
|
||||||
dataRefreshedAt: null as Date | null,
|
dataRefreshedAt: null as Date | null,
|
||||||
@@ -89,7 +106,7 @@ export default defineComponent({
|
|||||||
'search-dispatcher': '',
|
'search-dispatcher': '',
|
||||||
'search-station': '',
|
'search-station': '',
|
||||||
'search-date': ''
|
'search-date': ''
|
||||||
} as Journal.DispatcherSearcher);
|
} as Journal.DispatcherSearchType);
|
||||||
|
|
||||||
const countFromIndex = ref(0);
|
const countFromIndex = ref(0);
|
||||||
const countLimit = 15;
|
const countLimit = 15;
|
||||||
@@ -102,7 +119,7 @@ export default defineComponent({
|
|||||||
const scrollElement: Ref<HTMLElement | null> = ref(null);
|
const scrollElement: Ref<HTMLElement | null> = ref(null);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
store: useMainStore(),
|
mainStore: useMainStore(),
|
||||||
|
|
||||||
sorterActive,
|
sorterActive,
|
||||||
searchersValues,
|
searchersValues,
|
||||||
@@ -120,6 +137,15 @@ export default defineComponent({
|
|||||||
this.currentOptionsActive =
|
this.currentOptionsActive =
|
||||||
q.length > 2 ||
|
q.length > 2 ||
|
||||||
q.some((qv) => qv.startsWith('sortBy=') && qv.split('=')[1] != 'timestampFrom');
|
q.some((qv) => qv.startsWith('sortBy=') && qv.split('=')[1] != 'timestampFrom');
|
||||||
|
},
|
||||||
|
|
||||||
|
'mainStore.dispatcherStatsData'(stats) {
|
||||||
|
this.statsButtons.find((sb) => sb.tab == Journal.StatsTab.DISPATCHER_STATS)!.disabled =
|
||||||
|
stats === undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
async 'mainStore.dispatcherStatsName'() {
|
||||||
|
this.fetchDispatcherStats();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -142,6 +168,16 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
handleRouteParams() {
|
||||||
|
this.$router.push({
|
||||||
|
query: {
|
||||||
|
'search-date': this.searchersValues['search-date'] || undefined,
|
||||||
|
'search-station': this.searchersValues['search-station'] || undefined,
|
||||||
|
'search-dispatcher': this.searchersValues['search-dispatcher'] || undefined
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
handleScroll(e: Event) {
|
handleScroll(e: Event) {
|
||||||
const listElement = e.target as HTMLElement;
|
const listElement = e.target as HTMLElement;
|
||||||
const scrollTop = listElement.scrollTop;
|
const scrollTop = listElement.scrollTop;
|
||||||
@@ -154,24 +190,44 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleQueries(query: LocationQuery) {
|
handleQueries(query: LocationQuery) {
|
||||||
const queryKeys = Object.keys(query);
|
this.setOptions(query as any);
|
||||||
|
|
||||||
if (queryKeys.includes('sceneryName')) this.setSearchers('', `${query.sceneryName}`, '');
|
|
||||||
if (queryKeys.includes('dispatcherName'))
|
|
||||||
this.setSearchers('', '', `${query.dispatcherName}`);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setSearchers(date: string, station: string, dispatcher: string) {
|
async fetchDispatcherStats() {
|
||||||
this.searchersValues['search-date'] = date;
|
if (!this.mainStore.dispatcherStatsName) {
|
||||||
this.searchersValues['search-station'] = station;
|
this.mainStore.dispatcherStatsData = undefined;
|
||||||
this.searchersValues['search-dispatcher'] = dispatcher;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const statsData: API.DispatcherStats.Response = await (
|
||||||
|
await http.get('api/getDispatcherStats', {
|
||||||
|
params: {
|
||||||
|
name: this.mainStore.dispatcherStatsName
|
||||||
|
}
|
||||||
|
})
|
||||||
|
).data;
|
||||||
|
|
||||||
|
this.mainStore.dispatcherStatsData = statsData;
|
||||||
|
} catch (error) {
|
||||||
|
this.mainStore.dispatcherStatsData = undefined;
|
||||||
|
|
||||||
|
console.error('Ups! Wystąpił błąd przy próbie pobrania statystyk dyżurnego! :/');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setOptions(options: { [key: string]: string }) {
|
||||||
|
this.searchersValues['search-date'] = options['search-date'] ?? '';
|
||||||
|
this.searchersValues['search-station'] = options['search-station'] ?? '';
|
||||||
|
this.searchersValues['search-dispatcher'] = options['search-dispatcher'] ?? '';
|
||||||
|
|
||||||
|
this.sorterActive.id =
|
||||||
|
(options['sorter-active'] as Journal.DispatcherSorterKey) ?? 'timestampFrom';
|
||||||
},
|
},
|
||||||
|
|
||||||
resetOptions() {
|
resetOptions() {
|
||||||
this.setSearchers('', '', '');
|
this.setOptions({});
|
||||||
this.sorterActive.id = 'timestampFrom';
|
this.sorterActive.id = 'timestampFrom';
|
||||||
|
|
||||||
this.fetchHistoryData();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async addHistoryData() {
|
async addHistoryData() {
|
||||||
@@ -241,7 +297,7 @@ export default defineComponent({
|
|||||||
this.historyList = responseData;
|
this.historyList = responseData;
|
||||||
|
|
||||||
// Stats display
|
// Stats display
|
||||||
this.store.dispatcherStatsName =
|
this.mainStore.dispatcherStatsName =
|
||||||
this.historyList.length > 0 && this.searchersValues['search-dispatcher'].trim()
|
this.historyList.length > 0 && this.searchersValues['search-dispatcher'].trim()
|
||||||
? this.historyList[0].dispatcherName
|
? this.historyList[0].dispatcherName
|
||||||
: '';
|
: '';
|
||||||
|
|||||||
+128
-65
@@ -3,10 +3,10 @@
|
|||||||
<JournalHeader />
|
<JournalHeader />
|
||||||
|
|
||||||
<div class="journal_wrapper">
|
<div class="journal_wrapper">
|
||||||
|
<div class="journal_top-bar">
|
||||||
<JournalOptions
|
<JournalOptions
|
||||||
@on-search-confirm="fetchHistoryData"
|
@onOptionsReset="resetOptions"
|
||||||
@on-options-reset="resetOptions"
|
@onRefreshData="fetchHistoryData"
|
||||||
@on-refresh-data="fetchHistoryData"
|
|
||||||
:sorter-option-ids="['timetableId', 'beginDate', 'routeDistance', 'allStopsCount']"
|
:sorter-option-ids="['timetableId', 'beginDate', 'routeDistance', 'allStopsCount']"
|
||||||
:filters="journalTimetableFilters"
|
:filters="journalTimetableFilters"
|
||||||
:currentOptionsActive="currentOptionsActive"
|
:currentOptionsActive="currentOptionsActive"
|
||||||
@@ -14,7 +14,8 @@
|
|||||||
optionsType="timetables"
|
optionsType="timetables"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<JournalStats />
|
<JournalStats :statsButtons="statsButtons" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="journal_refreshed-date" v-if="dataRefreshedAt">
|
<div class="journal_refreshed-date" v-if="dataRefreshedAt">
|
||||||
{{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }}
|
{{ $t('journal.data-refreshed-at') }}: {{ dataRefreshedAt.toLocaleString($i18n.locale) }}
|
||||||
@@ -56,45 +57,58 @@ import http from '../http';
|
|||||||
|
|
||||||
export const journalTimetableFilters: Journal.TimetableFilter[] = [
|
export const journalTimetableFilters: Journal.TimetableFilter[] = [
|
||||||
{
|
{
|
||||||
id: Journal.TimetableFilterId.ALL,
|
id: Journal.TimetableFilterId.ALL_STATUSES,
|
||||||
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
||||||
isActive: true
|
isActive: true,
|
||||||
|
default: true
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: Journal.TimetableFilterId.ACTIVE,
|
id: Journal.TimetableFilterId.ACTIVE,
|
||||||
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
||||||
isActive: false
|
isActive: false,
|
||||||
|
default: false
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: Journal.TimetableFilterId.FULFILLED,
|
id: Journal.TimetableFilterId.FULFILLED,
|
||||||
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
||||||
isActive: false
|
isActive: false,
|
||||||
|
default: false
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: Journal.TimetableFilterId.ABANDONED,
|
id: Journal.TimetableFilterId.ABANDONED,
|
||||||
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
filterSection: Journal.FilterSection.TIMETABLE_STATUS,
|
||||||
isActive: false
|
isActive: false,
|
||||||
|
default: false
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: Journal.TimetableFilterId.TWR_SKR,
|
id: Journal.TimetableFilterId.ALL_SPECIALS,
|
||||||
filterSection: Journal.FilterSection.TWRSKR,
|
filterSection: Journal.FilterSection.SPECIAL,
|
||||||
isActive: true
|
isActive: true,
|
||||||
|
default: true
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: Journal.TimetableFilterId.TWR,
|
id: Journal.TimetableFilterId.TWR,
|
||||||
filterSection: Journal.FilterSection.TWRSKR,
|
filterSection: Journal.FilterSection.SPECIAL,
|
||||||
isActive: false
|
isActive: false,
|
||||||
|
default: false
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: Journal.TimetableFilterId.SKR,
|
id: Journal.TimetableFilterId.SKR,
|
||||||
filterSection: Journal.FilterSection.TWRSKR,
|
filterSection: Journal.FilterSection.SPECIAL,
|
||||||
isActive: false
|
isActive: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: Journal.TimetableFilterId.TWR_SKR,
|
||||||
|
filterSection: Journal.FilterSection.SPECIAL,
|
||||||
|
isActive: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -104,8 +118,12 @@ interface TimetablesQueryParams {
|
|||||||
timetableId?: string;
|
timetableId?: string;
|
||||||
|
|
||||||
authorName?: string;
|
authorName?: string;
|
||||||
timestampFrom?: number;
|
// timestampFrom?: number;
|
||||||
timestampTo?: number;
|
// timestampTo?: number;
|
||||||
|
|
||||||
|
dateFrom?: string;
|
||||||
|
dateTo?: string;
|
||||||
|
|
||||||
issuedFrom?: string;
|
issuedFrom?: string;
|
||||||
|
|
||||||
countFrom?: number;
|
countFrom?: number;
|
||||||
@@ -138,6 +156,24 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
|
journalTimetableFilters,
|
||||||
|
mainStore: useMainStore(),
|
||||||
|
|
||||||
|
statsButtons: [
|
||||||
|
{
|
||||||
|
tab: Journal.StatsTab.DAILY_STATS,
|
||||||
|
localeKey: 'journal.daily-stats.button',
|
||||||
|
iconName: 'stats',
|
||||||
|
disabled: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tab: Journal.StatsTab.DRIVER_STATS,
|
||||||
|
localeKey: 'journal.driver-stats.button',
|
||||||
|
iconName: 'train',
|
||||||
|
disabled: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
currentQueryParams: {} as TimetablesQueryParams,
|
currentQueryParams: {} as TimetablesQueryParams,
|
||||||
dataRefreshedAt: null as Date | null,
|
dataRefreshedAt: null as Date | null,
|
||||||
|
|
||||||
@@ -149,7 +185,6 @@ export default defineComponent({
|
|||||||
currentOptionsActive: false,
|
currentOptionsActive: false,
|
||||||
|
|
||||||
timetableHistory: [] as API.TimetableHistory.Response,
|
timetableHistory: [] as API.TimetableHistory.Response,
|
||||||
journalTimetableFilters,
|
|
||||||
|
|
||||||
dataStatus: Status.Data.Loading,
|
dataStatus: Status.Data.Loading,
|
||||||
dataErrorMessage: ''
|
dataErrorMessage: ''
|
||||||
@@ -157,10 +192,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
const sorterActive: Journal.TimetableSorter = reactive({ id: 'timetableId', dir: 'desc' });
|
const sorterActive: Journal.TimetableSorter = reactive({ id: 'timetableId', dir: 'desc' });
|
||||||
// const journalFilterActive = ref(journalTimetableFilters[0]);
|
|
||||||
const initFilters: readonly Journal.TimetableFilter[] = JSON.parse(
|
const initFilters: readonly Journal.TimetableFilter[] = JSON.parse(
|
||||||
JSON.stringify(journalTimetableFilters)
|
JSON.stringify(journalTimetableFilters)
|
||||||
);
|
);
|
||||||
|
|
||||||
const filterList: Journal.TimetableFilter[] = reactive(JSON.parse(JSON.stringify(initFilters)));
|
const filterList: Journal.TimetableFilter[] = reactive(JSON.parse(JSON.stringify(initFilters)));
|
||||||
|
|
||||||
const searchersValues = reactive({
|
const searchersValues = reactive({
|
||||||
@@ -189,15 +225,22 @@ export default defineComponent({
|
|||||||
countFromIndex,
|
countFromIndex,
|
||||||
countLimit,
|
countLimit,
|
||||||
|
|
||||||
scrollElement,
|
scrollElement
|
||||||
|
|
||||||
store: useMainStore()
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
currentQueryParams(q: TimetablesQueryParams) {
|
currentQueryParams(q: TimetablesQueryParams) {
|
||||||
this.currentOptionsActive = Object.values(q).some((v) => v !== undefined);
|
this.currentOptionsActive = Object.values(q).some((v) => v !== undefined);
|
||||||
|
},
|
||||||
|
|
||||||
|
'mainStore.driverStatsData'(driverStats) {
|
||||||
|
this.statsButtons.find((sb) => sb.tab == Journal.StatsTab.DRIVER_STATS)!.disabled =
|
||||||
|
driverStats === undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
async 'mainStore.driverStatsName'() {
|
||||||
|
this.fetchDriverStats();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -225,42 +268,51 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleQueries(query: LocationQuery) {
|
handleQueries(query: LocationQuery) {
|
||||||
const queryKeys = Object.keys(query);
|
this.setOptions(query as any);
|
||||||
|
|
||||||
if (queryKeys.includes('timetableId'))
|
|
||||||
this.setSearchers('', '', `#${query.timetableId}`, '', '');
|
|
||||||
if (queryKeys.includes('issuedFrom'))
|
|
||||||
this.setSearchers('', '', '', '', `${query.issuedFrom}`);
|
|
||||||
if (queryKeys.includes('authorName'))
|
|
||||||
this.setSearchers('', '', '', `${query.authorName}`, '');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setSearchers(
|
async fetchDriverStats() {
|
||||||
date: string,
|
if (!this.mainStore.driverStatsName) {
|
||||||
driver: string,
|
this.mainStore.driverStatsData = undefined;
|
||||||
train: string,
|
this.mainStore.driverStatsStatus = Status.Data.Initialized;
|
||||||
dispatcher: string,
|
return;
|
||||||
issuedFrom: string
|
}
|
||||||
) {
|
|
||||||
this.searchersValues['search-date'] = date;
|
try {
|
||||||
this.searchersValues['search-driver'] = driver;
|
this.mainStore.driverStatsStatus = Status.Data.Loading;
|
||||||
this.searchersValues['search-train'] = train;
|
|
||||||
this.searchersValues['search-dispatcher'] = dispatcher;
|
const statsData: API.DriverStats.Response = await (
|
||||||
this.searchersValues['search-issuedFrom'] = issuedFrom;
|
await http.get(`api/getDriverInfo?name=${this.mainStore.driverStatsName}`)
|
||||||
|
).data;
|
||||||
|
|
||||||
|
this.mainStore.driverStatsData = statsData;
|
||||||
|
this.mainStore.driverStatsStatus = Status.Data.Loaded;
|
||||||
|
} catch (error) {
|
||||||
|
this.mainStore.driverStatsData = undefined;
|
||||||
|
this.mainStore.driverStatsStatus = Status.Data.Error;
|
||||||
|
console.error('Ups! Wystąpił błąd przy próbie pobrania statystyk maszynisty! :/');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setOptions(options: { [key: string]: string }) {
|
||||||
|
this.searchersValues['search-date'] = options['search-date'] ?? '';
|
||||||
|
this.searchersValues['search-driver'] = options['search-driver'] ?? '';
|
||||||
|
this.searchersValues['search-train'] = options['search-train'] ?? '';
|
||||||
|
this.searchersValues['search-dispatcher'] = options['search-dispatcher'] ?? '';
|
||||||
|
this.searchersValues['search-issuedFrom'] = options['search-issuedFrom'] ?? '';
|
||||||
|
|
||||||
|
this.sorterActive.id =
|
||||||
|
(options['sorter-active'] as Journal.TimetableSorterKey) ?? 'timetableId';
|
||||||
|
|
||||||
|
this.filterList.forEach((f) => {
|
||||||
|
f.isActive =
|
||||||
|
options[f.filterSection] === f.id ||
|
||||||
|
(options[f.filterSection] === undefined && f.default);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
resetOptions() {
|
resetOptions() {
|
||||||
this.setSearchers('', '', '', '', '');
|
this.setOptions({});
|
||||||
|
|
||||||
this.sorterActive.id = 'timetableId';
|
|
||||||
|
|
||||||
this.filterList.forEach(
|
|
||||||
(f) =>
|
|
||||||
(f.isActive =
|
|
||||||
this.initFilters.find((initFilter) => initFilter.id == f.id)?.isActive || false)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.fetchHistoryData();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async addHistoryData() {
|
async addHistoryData() {
|
||||||
@@ -289,13 +341,19 @@ export default defineComponent({
|
|||||||
const driverName = this.searchersValues['search-driver'].trim() || undefined;
|
const driverName = this.searchersValues['search-driver'].trim() || undefined;
|
||||||
const trainNo = this.searchersValues['search-train'].trim() || undefined;
|
const trainNo = this.searchersValues['search-train'].trim() || undefined;
|
||||||
const authorName = this.searchersValues['search-dispatcher'].trim() || undefined;
|
const authorName = this.searchersValues['search-dispatcher'].trim() || undefined;
|
||||||
const dateString = this.searchersValues['search-date'].trim() || undefined;
|
const dateFrom = this.searchersValues['search-date'].trim() || undefined;
|
||||||
const issuedFrom = this.searchersValues['search-issuedFrom'].trim() || undefined;
|
const issuedFrom = this.searchersValues['search-issuedFrom'].trim() || undefined;
|
||||||
|
|
||||||
const timestampFrom = dateString
|
let dateTo: string | undefined = undefined;
|
||||||
? Date.parse(new Date(dateString).toISOString()) - 120 * 60 * 1000
|
|
||||||
: undefined;
|
if (dateFrom) {
|
||||||
const timestampTo = timestampFrom ? timestampFrom + 86400000 : undefined;
|
const d = new Date(dateFrom);
|
||||||
|
d.setDate(d.getDate() + 1);
|
||||||
|
|
||||||
|
dateTo = d.toISOString().split('T')[0];
|
||||||
|
}
|
||||||
|
// const timestampFrom = dateString ? Date.parse(new Date(dateString).toISOString()) : undefined;
|
||||||
|
// const timestampTo = timestampFrom ? timestampFrom + 86400000 : undefined;
|
||||||
|
|
||||||
const queryParams: TimetablesQueryParams = {};
|
const queryParams: TimetablesQueryParams = {};
|
||||||
|
|
||||||
@@ -318,23 +376,28 @@ export default defineComponent({
|
|||||||
queryParams['fulfilled'] = 1;
|
queryParams['fulfilled'] = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Journal.TimetableFilterId.ALL:
|
case Journal.TimetableFilterId.ALL_STATUSES:
|
||||||
queryParams['terminated'] = undefined;
|
queryParams['terminated'] = undefined;
|
||||||
queryParams['fulfilled'] = undefined;
|
queryParams['fulfilled'] = undefined;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Journal.TimetableFilterId.TWR_SKR:
|
case Journal.TimetableFilterId.ALL_SPECIALS:
|
||||||
queryParams['twr'] = undefined;
|
queryParams['twr'] = undefined;
|
||||||
queryParams['skr'] = undefined;
|
queryParams['skr'] = undefined;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Journal.TimetableFilterId.TWR:
|
case Journal.TimetableFilterId.TWR:
|
||||||
queryParams['twr'] = 1;
|
queryParams['twr'] = 1;
|
||||||
queryParams['skr'] = undefined;
|
queryParams['skr'] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Journal.TimetableFilterId.SKR:
|
case Journal.TimetableFilterId.SKR:
|
||||||
queryParams['twr'] = undefined;
|
queryParams['twr'] = 0;
|
||||||
|
queryParams['skr'] = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Journal.TimetableFilterId.TWR_SKR:
|
||||||
|
queryParams['twr'] = 1;
|
||||||
queryParams['skr'] = 1;
|
queryParams['skr'] = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -349,8 +412,8 @@ export default defineComponent({
|
|||||||
queryParams['countLimit'] = undefined;
|
queryParams['countLimit'] = undefined;
|
||||||
|
|
||||||
queryParams['authorName'] = authorName;
|
queryParams['authorName'] = authorName;
|
||||||
queryParams['timestampFrom'] = timestampFrom;
|
queryParams['dateFrom'] = dateFrom;
|
||||||
queryParams['timestampTo'] = timestampTo;
|
queryParams['dateTo'] = dateTo;
|
||||||
queryParams['issuedFrom'] = issuedFrom;
|
queryParams['issuedFrom'] = issuedFrom;
|
||||||
queryParams['sortBy'] =
|
queryParams['sortBy'] =
|
||||||
this.sorterActive.id != 'timetableId' ? this.sorterActive.id : undefined;
|
this.sorterActive.id != 'timetableId' ? this.sorterActive.id : undefined;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scenery-view">
|
<div class="scenery-view">
|
||||||
<!-- <div
|
|
||||||
class="scenery-offline"
|
|
||||||
v-if="!stationInfo && !onlineSceneryInfo && store.dataStatuses.sceneries == 2"
|
|
||||||
>
|
|
||||||
<div>{{ $t('scenery.no-scenery') }}</div>
|
|
||||||
|
|
||||||
<action-button>
|
|
||||||
<router-link to="/">{{ $t('scenery.return-btn') }}</router-link>
|
|
||||||
</action-button>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div class="scenery-wrapper" ref="card-wrapper">
|
<div class="scenery-wrapper" ref="card-wrapper">
|
||||||
<div class="scenery-left">
|
<div class="scenery-left">
|
||||||
<div class="scenery-actions">
|
<div class="scenery-actions">
|
||||||
@@ -43,7 +32,7 @@
|
|||||||
<div
|
<div
|
||||||
v-if="
|
v-if="
|
||||||
apiStore.dataStatuses.sceneries == Status.Loading ||
|
apiStore.dataStatuses.sceneries == Status.Loading ||
|
||||||
apiStore.dataStatuses.trains == Status.Loading
|
apiStore.dataStatuses.connection == Status.Loading
|
||||||
"
|
"
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { io } from 'socket.io-client';
|
||||||
|
|
||||||
|
const URL =
|
||||||
|
import.meta.env.VITE_WS_MODE === 'development'
|
||||||
|
? 'http://localhost:3001'
|
||||||
|
: 'https://stacjownik.spythere.eu';
|
||||||
|
|
||||||
|
const socket = io(URL, {
|
||||||
|
transports: ['websocket', 'polling'],
|
||||||
|
rememberUpgrade: true,
|
||||||
|
reconnection: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export default socket;
|
||||||
+4
-2
@@ -6,20 +6,22 @@ export default defineConfig({
|
|||||||
server: {
|
server: {
|
||||||
port: 5001
|
port: 5001
|
||||||
},
|
},
|
||||||
|
publicDir: 'public',
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
VitePWA({
|
VitePWA({
|
||||||
registerType: 'autoUpdate',
|
registerType: 'autoUpdate',
|
||||||
|
includeAssets: ['/images/*.png', '/fonts/*.woff', '/fonts/*.woff2'],
|
||||||
|
|
||||||
workbox: {
|
workbox: {
|
||||||
|
disableDevLogs: true,
|
||||||
globPatterns: ['**/*.{js,css,html,png,svg,jpg}'],
|
globPatterns: ['**/*.{js,css,html,png,svg,jpg}'],
|
||||||
runtimeCaching: [
|
runtimeCaching: [
|
||||||
{
|
{
|
||||||
urlPattern: new RegExp('^https://stacjownik.spythere.pl/api/getSceneries', 'i'),
|
urlPattern: new RegExp('^https://stacjownik.spythere.eu/api/getSceneries', 'i'),
|
||||||
handler: 'NetworkFirst',
|
handler: 'NetworkFirst',
|
||||||
options: {
|
options: {
|
||||||
cacheName: 'sceneries-cache',
|
cacheName: 'sceneries-cache',
|
||||||
|
|
||||||
cacheableResponse: {
|
cacheableResponse: {
|
||||||
statuses: [0, 200]
|
statuses: [0, 200]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz"
|
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz"
|
||||||
integrity sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==
|
integrity sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==
|
||||||
|
|
||||||
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.1", "@babel/core@^7.12.0", "@babel/core@^7.13.0", "@babel/core@^7.4.0-0":
|
"@babel/core@^7.11.1":
|
||||||
version "7.20.7"
|
version "7.20.7"
|
||||||
resolved "https://registry.npmjs.org/@babel/core/-/core-7.20.7.tgz"
|
resolved "https://registry.npmjs.org/@babel/core/-/core-7.20.7.tgz"
|
||||||
integrity sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==
|
integrity sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw==
|
||||||
@@ -929,11 +929,116 @@
|
|||||||
resolved "https://registry.npmjs.org/@canvas/image-data/-/image-data-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/@canvas/image-data/-/image-data-1.0.0.tgz"
|
||||||
integrity sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==
|
integrity sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==
|
||||||
|
|
||||||
|
"@esbuild/android-arm64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622"
|
||||||
|
integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==
|
||||||
|
|
||||||
|
"@esbuild/android-arm@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682"
|
||||||
|
integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==
|
||||||
|
|
||||||
|
"@esbuild/android-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2"
|
||||||
|
integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==
|
||||||
|
|
||||||
|
"@esbuild/darwin-arm64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1"
|
||||||
|
integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==
|
||||||
|
|
||||||
|
"@esbuild/darwin-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d"
|
||||||
|
integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==
|
||||||
|
|
||||||
|
"@esbuild/freebsd-arm64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54"
|
||||||
|
integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==
|
||||||
|
|
||||||
|
"@esbuild/freebsd-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e"
|
||||||
|
integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==
|
||||||
|
|
||||||
|
"@esbuild/linux-arm64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0"
|
||||||
|
integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==
|
||||||
|
|
||||||
|
"@esbuild/linux-arm@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0"
|
||||||
|
integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==
|
||||||
|
|
||||||
|
"@esbuild/linux-ia32@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7"
|
||||||
|
integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==
|
||||||
|
|
||||||
|
"@esbuild/linux-loong64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d"
|
||||||
|
integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==
|
||||||
|
|
||||||
|
"@esbuild/linux-mips64el@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231"
|
||||||
|
integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==
|
||||||
|
|
||||||
|
"@esbuild/linux-ppc64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb"
|
||||||
|
integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==
|
||||||
|
|
||||||
|
"@esbuild/linux-riscv64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6"
|
||||||
|
integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==
|
||||||
|
|
||||||
|
"@esbuild/linux-s390x@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071"
|
||||||
|
integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==
|
||||||
|
|
||||||
"@esbuild/linux-x64@0.18.20":
|
"@esbuild/linux-x64@0.18.20":
|
||||||
version "0.18.20"
|
version "0.18.20"
|
||||||
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz"
|
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz"
|
||||||
integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==
|
integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==
|
||||||
|
|
||||||
|
"@esbuild/netbsd-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1"
|
||||||
|
integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==
|
||||||
|
|
||||||
|
"@esbuild/openbsd-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae"
|
||||||
|
integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==
|
||||||
|
|
||||||
|
"@esbuild/sunos-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d"
|
||||||
|
integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==
|
||||||
|
|
||||||
|
"@esbuild/win32-arm64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9"
|
||||||
|
integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==
|
||||||
|
|
||||||
|
"@esbuild/win32-ia32@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102"
|
||||||
|
integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==
|
||||||
|
|
||||||
|
"@esbuild/win32-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d"
|
||||||
|
integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==
|
||||||
|
|
||||||
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
|
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
|
||||||
version "4.4.0"
|
version "4.4.0"
|
||||||
resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz"
|
resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz"
|
||||||
@@ -1025,7 +1130,7 @@
|
|||||||
"@firebase/util" "1.9.3"
|
"@firebase/util" "1.9.3"
|
||||||
tslib "^2.1.0"
|
tslib "^2.1.0"
|
||||||
|
|
||||||
"@firebase/app-compat@0.2.19", "@firebase/app-compat@0.x":
|
"@firebase/app-compat@0.2.19":
|
||||||
version "0.2.19"
|
version "0.2.19"
|
||||||
resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.19.tgz"
|
resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.19.tgz"
|
||||||
integrity sha512-QkJDqYqjhvs4fTMcRVXQkP9hbo5yfoJXDWkhU4VA5Vzs8Qsp76VPzYbqx5SD5OmBy+bz/Ot1UV8qySPGI4aKuw==
|
integrity sha512-QkJDqYqjhvs4fTMcRVXQkP9hbo5yfoJXDWkhU4VA5Vzs8Qsp76VPzYbqx5SD5OmBy+bz/Ot1UV8qySPGI4aKuw==
|
||||||
@@ -1036,12 +1141,12 @@
|
|||||||
"@firebase/util" "1.9.3"
|
"@firebase/util" "1.9.3"
|
||||||
tslib "^2.1.0"
|
tslib "^2.1.0"
|
||||||
|
|
||||||
"@firebase/app-types@0.9.0", "@firebase/app-types@0.x":
|
"@firebase/app-types@0.9.0":
|
||||||
version "0.9.0"
|
version "0.9.0"
|
||||||
resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz"
|
resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz"
|
||||||
integrity sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==
|
integrity sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==
|
||||||
|
|
||||||
"@firebase/app@0.9.19", "@firebase/app@0.x":
|
"@firebase/app@0.9.19":
|
||||||
version "0.9.19"
|
version "0.9.19"
|
||||||
resolved "https://registry.npmjs.org/@firebase/app/-/app-0.9.19.tgz"
|
resolved "https://registry.npmjs.org/@firebase/app/-/app-0.9.19.tgz"
|
||||||
integrity sha512-t/SHyZ3xWkR77ZU9VMoobDNFLdDKQ5xqoCAn4o16gTsA1C8sJ6ZOMZ02neMOPxNHuQXVE4tA8ukilnDbnK7uJA==
|
integrity sha512-t/SHyZ3xWkR77ZU9VMoobDNFLdDKQ5xqoCAn4o16gTsA1C8sJ6ZOMZ02neMOPxNHuQXVE4tA8ukilnDbnK7uJA==
|
||||||
@@ -1326,7 +1431,7 @@
|
|||||||
node-fetch "2.6.7"
|
node-fetch "2.6.7"
|
||||||
tslib "^2.1.0"
|
tslib "^2.1.0"
|
||||||
|
|
||||||
"@firebase/util@1.9.3", "@firebase/util@1.x":
|
"@firebase/util@1.9.3":
|
||||||
version "1.9.3"
|
version "1.9.3"
|
||||||
resolved "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz"
|
resolved "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz"
|
||||||
integrity sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==
|
integrity sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==
|
||||||
@@ -1431,7 +1536,7 @@
|
|||||||
"@jridgewell/gen-mapping" "^0.3.0"
|
"@jridgewell/gen-mapping" "^0.3.0"
|
||||||
"@jridgewell/trace-mapping" "^0.3.9"
|
"@jridgewell/trace-mapping" "^0.3.9"
|
||||||
|
|
||||||
"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@1.4.14":
|
"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10":
|
||||||
version "1.4.14"
|
version "1.4.14"
|
||||||
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz"
|
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz"
|
||||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||||
@@ -1457,7 +1562,7 @@
|
|||||||
"@nodelib/fs.stat" "2.0.5"
|
"@nodelib/fs.stat" "2.0.5"
|
||||||
run-parallel "^1.1.9"
|
run-parallel "^1.1.9"
|
||||||
|
|
||||||
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
|
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
||||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||||
@@ -1577,6 +1682,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz"
|
resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz"
|
||||||
integrity sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==
|
integrity sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==
|
||||||
|
|
||||||
|
"@socket.io/component-emitter@~3.1.0":
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz"
|
||||||
|
integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
|
||||||
|
|
||||||
"@surma/rollup-plugin-off-main-thread@^2.2.3":
|
"@surma/rollup-plugin-off-main-thread@^2.2.3":
|
||||||
version "2.2.3"
|
version "2.2.3"
|
||||||
resolved "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz"
|
resolved "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz"
|
||||||
@@ -1597,26 +1707,16 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz"
|
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz"
|
||||||
integrity sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==
|
integrity sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
|
||||||
version "18.11.18"
|
version "18.11.18"
|
||||||
resolved "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz"
|
resolved "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz"
|
||||||
integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
|
integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
|
||||||
|
|
||||||
"@types/node@^20.6.2", "@types/node@>= 14":
|
"@types/node@^20.6.2":
|
||||||
version "20.6.2"
|
version "20.6.2"
|
||||||
resolved "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz"
|
resolved "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz"
|
||||||
integrity sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==
|
integrity sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==
|
||||||
|
|
||||||
"@types/node@>=12.12.47":
|
|
||||||
version "18.11.18"
|
|
||||||
resolved "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz"
|
|
||||||
integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
|
|
||||||
|
|
||||||
"@types/node@>=13.7.0":
|
|
||||||
version "18.11.18"
|
|
||||||
resolved "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz"
|
|
||||||
integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
|
|
||||||
|
|
||||||
"@types/resolve@1.17.1":
|
"@types/resolve@1.17.1":
|
||||||
version "1.17.1"
|
version "1.17.1"
|
||||||
resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz"
|
resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz"
|
||||||
@@ -1651,7 +1751,7 @@
|
|||||||
semver "^7.5.4"
|
semver "^7.5.4"
|
||||||
ts-api-utils "^1.0.1"
|
ts-api-utils "^1.0.1"
|
||||||
|
|
||||||
"@typescript-eslint/parser@^6.0.0 || ^6.0.0-alpha", "@typescript-eslint/parser@^6.7.0":
|
"@typescript-eslint/parser@^6.7.0":
|
||||||
version "6.9.1"
|
version "6.9.1"
|
||||||
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.1.tgz"
|
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.1.tgz"
|
||||||
integrity sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==
|
integrity sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==
|
||||||
@@ -1741,14 +1841,14 @@
|
|||||||
resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.3.4.tgz"
|
resolved "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.3.4.tgz"
|
||||||
integrity sha512-ciXNIHKPriERBisHFBvnTbfKa6r9SAesOYXeGDzgegcvy9Q4xdScSHAmKbNT0M3O0S9LKhIf5/G+UYG4NnnzYw==
|
integrity sha512-ciXNIHKPriERBisHFBvnTbfKa6r9SAesOYXeGDzgegcvy9Q4xdScSHAmKbNT0M3O0S9LKhIf5/G+UYG4NnnzYw==
|
||||||
|
|
||||||
"@volar/language-core@~1.10.0", "@volar/language-core@1.10.1":
|
"@volar/language-core@1.10.1", "@volar/language-core@~1.10.0":
|
||||||
version "1.10.1"
|
version "1.10.1"
|
||||||
resolved "https://registry.npmjs.org/@volar/language-core/-/language-core-1.10.1.tgz"
|
resolved "https://registry.npmjs.org/@volar/language-core/-/language-core-1.10.1.tgz"
|
||||||
integrity sha512-JnsM1mIPdfGPxmoOcK1c7HYAsL6YOv0TCJ4aW3AXPZN/Jb4R77epDyMZIVudSGjWMbvv/JfUa+rQ+dGKTmgwBA==
|
integrity sha512-JnsM1mIPdfGPxmoOcK1c7HYAsL6YOv0TCJ4aW3AXPZN/Jb4R77epDyMZIVudSGjWMbvv/JfUa+rQ+dGKTmgwBA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@volar/source-map" "1.10.1"
|
"@volar/source-map" "1.10.1"
|
||||||
|
|
||||||
"@volar/source-map@~1.10.0", "@volar/source-map@1.10.1":
|
"@volar/source-map@1.10.1", "@volar/source-map@~1.10.0":
|
||||||
version "1.10.1"
|
version "1.10.1"
|
||||||
resolved "https://registry.npmjs.org/@volar/source-map/-/source-map-1.10.1.tgz"
|
resolved "https://registry.npmjs.org/@volar/source-map/-/source-map-1.10.1.tgz"
|
||||||
integrity sha512-3/S6KQbqa7pGC8CxPrg69qHLpOvkiPHGJtWPkI/1AXCsktkJ6gIk/5z4hyuMp8Anvs6eS/Kvp/GZa3ut3votKA==
|
integrity sha512-3/S6KQbqa7pGC8CxPrg69qHLpOvkiPHGJtWPkI/1AXCsktkJ6gIk/5z4hyuMp8Anvs6eS/Kvp/GZa3ut3votKA==
|
||||||
@@ -1772,7 +1872,7 @@
|
|||||||
estree-walker "^2.0.2"
|
estree-walker "^2.0.2"
|
||||||
source-map-js "^1.0.2"
|
source-map-js "^1.0.2"
|
||||||
|
|
||||||
"@vue/compiler-dom@^3.3.0", "@vue/compiler-dom@3.3.4":
|
"@vue/compiler-dom@3.3.4", "@vue/compiler-dom@^3.3.0":
|
||||||
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"
|
||||||
integrity sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==
|
integrity sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==
|
||||||
@@ -1851,7 +1951,7 @@
|
|||||||
estree-walker "^2.0.2"
|
estree-walker "^2.0.2"
|
||||||
magic-string "^0.30.0"
|
magic-string "^0.30.0"
|
||||||
|
|
||||||
"@vue/reactivity@^3.3.0", "@vue/reactivity@3.3.4":
|
"@vue/reactivity@3.3.4", "@vue/reactivity@^3.3.0":
|
||||||
version "3.3.4"
|
version "3.3.4"
|
||||||
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz"
|
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz"
|
||||||
integrity sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==
|
integrity sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==
|
||||||
@@ -1883,7 +1983,7 @@
|
|||||||
"@vue/compiler-ssr" "3.3.4"
|
"@vue/compiler-ssr" "3.3.4"
|
||||||
"@vue/shared" "3.3.4"
|
"@vue/shared" "3.3.4"
|
||||||
|
|
||||||
"@vue/shared@^3.3.0", "@vue/shared@3.3.4":
|
"@vue/shared@3.3.4", "@vue/shared@^3.3.0":
|
||||||
version "3.3.4"
|
version "3.3.4"
|
||||||
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz"
|
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz"
|
||||||
integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==
|
integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==
|
||||||
@@ -1906,7 +2006,7 @@ acorn-jsx@^5.3.2:
|
|||||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
||||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||||
|
|
||||||
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.10.0, acorn@^8.5.0, acorn@^8.9.0:
|
acorn@^8.10.0, acorn@^8.5.0, acorn@^8.9.0:
|
||||||
version "8.10.0"
|
version "8.10.0"
|
||||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz"
|
resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz"
|
||||||
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
|
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
|
||||||
@@ -1921,7 +2021,7 @@ ajv@^6.12.4:
|
|||||||
json-schema-traverse "^0.4.1"
|
json-schema-traverse "^0.4.1"
|
||||||
uri-js "^4.2.2"
|
uri-js "^4.2.2"
|
||||||
|
|
||||||
ajv@^8.6.0, ajv@>=8:
|
ajv@^8.6.0:
|
||||||
version "8.11.2"
|
version "8.11.2"
|
||||||
resolved "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz"
|
resolved "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz"
|
||||||
integrity sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==
|
integrity sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==
|
||||||
@@ -2084,7 +2184,7 @@ braces@^3.0.2, braces@~3.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fill-range "^7.0.1"
|
fill-range "^7.0.1"
|
||||||
|
|
||||||
browserslist@^4.21.3, browserslist@^4.21.4, "browserslist@>= 4.21.0":
|
browserslist@^4.21.3, browserslist@^4.21.4:
|
||||||
version "4.21.4"
|
version "4.21.4"
|
||||||
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz"
|
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz"
|
||||||
integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==
|
integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==
|
||||||
@@ -2151,15 +2251,7 @@ chalk@^2.4.2:
|
|||||||
escape-string-regexp "^1.0.5"
|
escape-string-regexp "^1.0.5"
|
||||||
supports-color "^5.3.0"
|
supports-color "^5.3.0"
|
||||||
|
|
||||||
chalk@^4.0.0:
|
chalk@^4.0.0, chalk@^4.0.2:
|
||||||
version "4.1.2"
|
|
||||||
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
|
|
||||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
|
||||||
dependencies:
|
|
||||||
ansi-styles "^4.1.0"
|
|
||||||
supports-color "^7.1.0"
|
|
||||||
|
|
||||||
chalk@^4.0.2:
|
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
|
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
|
||||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||||
@@ -2210,16 +2302,16 @@ color-convert@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-name "~1.1.4"
|
color-name "~1.1.4"
|
||||||
|
|
||||||
color-name@^1.0.0, color-name@~1.1.4:
|
|
||||||
version "1.1.4"
|
|
||||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
|
||||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
|
||||||
|
|
||||||
color-name@1.1.3:
|
color-name@1.1.3:
|
||||||
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==
|
||||||
|
|
||||||
|
color-name@^1.0.0, color-name@~1.1.4:
|
||||||
|
version "1.1.4"
|
||||||
|
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
||||||
|
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||||
|
|
||||||
color-string@^1.9.0:
|
color-string@^1.9.0:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz"
|
resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz"
|
||||||
@@ -2314,7 +2406,7 @@ de-indent@^1.0.2:
|
|||||||
resolved "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz"
|
||||||
integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
|
integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
|
||||||
|
|
||||||
debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
|
debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
|
||||||
version "4.3.4"
|
version "4.3.4"
|
||||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
|
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
|
||||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||||
@@ -2449,6 +2541,22 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
once "^1.4.0"
|
once "^1.4.0"
|
||||||
|
|
||||||
|
engine.io-client@~6.5.2:
|
||||||
|
version "6.5.3"
|
||||||
|
resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz"
|
||||||
|
integrity sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.1"
|
||||||
|
engine.io-parser "~5.2.1"
|
||||||
|
ws "~8.11.0"
|
||||||
|
xmlhttprequest-ssl "~2.0.0"
|
||||||
|
|
||||||
|
engine.io-parser@~5.2.1:
|
||||||
|
version "5.2.1"
|
||||||
|
resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz"
|
||||||
|
integrity sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==
|
||||||
|
|
||||||
es-abstract@^1.19.0, es-abstract@^1.20.4:
|
es-abstract@^1.19.0, es-abstract@^1.20.4:
|
||||||
version "1.20.5"
|
version "1.20.5"
|
||||||
resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz"
|
resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz"
|
||||||
@@ -2545,7 +2653,7 @@ eslint-plugin-prettier@^5.0.0:
|
|||||||
prettier-linter-helpers "^1.0.0"
|
prettier-linter-helpers "^1.0.0"
|
||||||
synckit "^0.8.5"
|
synckit "^0.8.5"
|
||||||
|
|
||||||
eslint-plugin-vue@^9.0.0, eslint-plugin-vue@^9.17.0:
|
eslint-plugin-vue@^9.17.0:
|
||||||
version "9.18.1"
|
version "9.18.1"
|
||||||
resolved "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.18.1.tgz"
|
resolved "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.18.1.tgz"
|
||||||
integrity sha512-7hZFlrEgg9NIzuVik2I9xSnJA5RsmOfueYgsUGUokEDLJ1LHtxO0Pl4duje1BriZ/jDWb+44tcIlC3yi0tdlZg==
|
integrity sha512-7hZFlrEgg9NIzuVik2I9xSnJA5RsmOfueYgsUGUokEDLJ1LHtxO0Pl4duje1BriZ/jDWb+44tcIlC3yi0tdlZg==
|
||||||
@@ -2571,7 +2679,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4
|
|||||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
|
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
|
||||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||||
|
|
||||||
"eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^6.2.0 || ^7.0.0 || ^8.0.0", "eslint@^7.0.0 || ^8.0.0", eslint@^8.49.0, "eslint@>= 8.0.0", eslint@>=6.0.0, eslint@>=7.0.0, eslint@>=8.0.0:
|
eslint@^8.49.0:
|
||||||
version "8.52.0"
|
version "8.52.0"
|
||||||
resolved "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz"
|
resolved "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz"
|
||||||
integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==
|
integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==
|
||||||
@@ -2819,9 +2927,9 @@ flatted@^3.2.9:
|
|||||||
integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==
|
integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==
|
||||||
|
|
||||||
follow-redirects@^1.15.0:
|
follow-redirects@^1.15.0:
|
||||||
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==
|
||||||
|
|
||||||
form-data@^4.0.0:
|
form-data@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
@@ -2852,6 +2960,11 @@ fs.realpath@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||||
|
|
||||||
|
fsevents@~2.3.2:
|
||||||
|
version "2.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
|
||||||
|
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
||||||
|
|
||||||
function-bind@^1.1.1:
|
function-bind@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
|
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
|
||||||
@@ -3052,7 +3165,7 @@ ico-endec@*:
|
|||||||
resolved "https://registry.npmjs.org/ico-endec/-/ico-endec-0.1.6.tgz"
|
resolved "https://registry.npmjs.org/ico-endec/-/ico-endec-0.1.6.tgz"
|
||||||
integrity sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==
|
integrity sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==
|
||||||
|
|
||||||
idb@^7.0.1, idb@7.0.1:
|
idb@7.0.1, idb@^7.0.1:
|
||||||
version "7.0.1"
|
version "7.0.1"
|
||||||
resolved "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz"
|
resolved "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz"
|
||||||
integrity sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==
|
integrity sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==
|
||||||
@@ -3098,7 +3211,7 @@ inflight@^1.0.4:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
wrappy "1"
|
wrappy "1"
|
||||||
|
|
||||||
inherits@^2.0.3, inherits@^2.0.4, inherits@2:
|
inherits@2, inherits@^2.0.3, inherits@^2.0.4:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
||||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||||
@@ -3826,7 +3939,7 @@ prettier-linter-helpers@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fast-diff "^1.1.2"
|
fast-diff "^1.1.2"
|
||||||
|
|
||||||
prettier@^3.0.3, "prettier@>= 3.0.0", prettier@>=3.0.0:
|
prettier@^3.0.3:
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz"
|
resolved "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz"
|
||||||
integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
|
integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
|
||||||
@@ -4023,7 +4136,7 @@ rollup-plugin-terser@^7.0.0:
|
|||||||
serialize-javascript "^4.0.0"
|
serialize-javascript "^4.0.0"
|
||||||
terser "^5.0.0"
|
terser "^5.0.0"
|
||||||
|
|
||||||
"rollup@^1.20.0 || ^2.0.0", rollup@^1.20.0||^2.0.0, rollup@^2.0.0, rollup@^2.43.1:
|
rollup@^2.43.1:
|
||||||
version "2.79.1"
|
version "2.79.1"
|
||||||
resolved "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz"
|
resolved "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz"
|
||||||
integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
|
integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
|
||||||
@@ -4051,7 +4164,7 @@ run-parallel@^1.1.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
queue-microtask "^1.2.2"
|
queue-microtask "^1.2.2"
|
||||||
|
|
||||||
safe-buffer@^5.0.1, safe-buffer@>=5.1.0, safe-buffer@~5.2.0:
|
safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@~5.2.0:
|
||||||
version "5.2.1"
|
version "5.2.1"
|
||||||
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
|
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
|
||||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||||
@@ -4070,7 +4183,7 @@ safe-regex-test@^1.0.0:
|
|||||||
get-intrinsic "^1.1.3"
|
get-intrinsic "^1.1.3"
|
||||||
is-regex "^1.1.4"
|
is-regex "^1.1.4"
|
||||||
|
|
||||||
sass@*, sass@^1.67.0:
|
sass@^1.67.0:
|
||||||
version "1.67.0"
|
version "1.67.0"
|
||||||
resolved "https://registry.npmjs.org/sass/-/sass-1.67.0.tgz"
|
resolved "https://registry.npmjs.org/sass/-/sass-1.67.0.tgz"
|
||||||
integrity sha512-SVrO9ZeX/QQyEGtuZYCVxoeAL5vGlYjJ9p4i4HFuekWl8y/LtJ7tJc10Z+ck1c8xOuoBm2MYzcLfTAffD0pl/A==
|
integrity sha512-SVrO9ZeX/QQyEGtuZYCVxoeAL5vGlYjJ9p4i4HFuekWl8y/LtJ7tJc10Z+ck1c8xOuoBm2MYzcLfTAffD0pl/A==
|
||||||
@@ -4084,28 +4197,7 @@ semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
|
|||||||
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
|
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
|
||||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||||
|
|
||||||
semver@^7.3.5:
|
semver@^7.3.5, semver@^7.3.6, semver@^7.3.8, semver@^7.5.4:
|
||||||
version "7.5.4"
|
|
||||||
resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"
|
|
||||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
|
||||||
dependencies:
|
|
||||||
lru-cache "^6.0.0"
|
|
||||||
|
|
||||||
semver@^7.3.6:
|
|
||||||
version "7.5.4"
|
|
||||||
resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"
|
|
||||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
|
||||||
dependencies:
|
|
||||||
lru-cache "^6.0.0"
|
|
||||||
|
|
||||||
semver@^7.3.8:
|
|
||||||
version "7.5.4"
|
|
||||||
resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"
|
|
||||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
|
||||||
dependencies:
|
|
||||||
lru-cache "^6.0.0"
|
|
||||||
|
|
||||||
semver@^7.5.4:
|
|
||||||
version "7.5.4"
|
version "7.5.4"
|
||||||
resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"
|
resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"
|
||||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
||||||
@@ -4194,7 +4286,25 @@ slash@^3.0.0:
|
|||||||
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
|
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
|
||||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||||
|
|
||||||
source-map-js@^1.0.2, "source-map-js@>=0.6.2 <2.0.0":
|
socket.io-client@^4.7.4:
|
||||||
|
version "4.7.4"
|
||||||
|
resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz"
|
||||||
|
integrity sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.2"
|
||||||
|
engine.io-client "~6.5.2"
|
||||||
|
socket.io-parser "~4.2.4"
|
||||||
|
|
||||||
|
socket.io-parser@~4.2.4:
|
||||||
|
version "4.2.4"
|
||||||
|
resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz"
|
||||||
|
integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==
|
||||||
|
dependencies:
|
||||||
|
"@socket.io/component-emitter" "~3.1.0"
|
||||||
|
debug "~4.3.1"
|
||||||
|
|
||||||
|
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
||||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||||
@@ -4232,13 +4342,6 @@ streamx@^2.15.0:
|
|||||||
fast-fifo "^1.1.0"
|
fast-fifo "^1.1.0"
|
||||||
queue-tick "^1.0.1"
|
queue-tick "^1.0.1"
|
||||||
|
|
||||||
string_decoder@^1.1.1:
|
|
||||||
version "1.3.0"
|
|
||||||
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
|
|
||||||
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
|
|
||||||
dependencies:
|
|
||||||
safe-buffer "~5.2.0"
|
|
||||||
|
|
||||||
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
||||||
@@ -4280,6 +4383,13 @@ string.prototype.trimstart@^1.0.6:
|
|||||||
define-properties "^1.1.4"
|
define-properties "^1.1.4"
|
||||||
es-abstract "^1.20.4"
|
es-abstract "^1.20.4"
|
||||||
|
|
||||||
|
string_decoder@^1.1.1:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
|
||||||
|
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
|
||||||
|
dependencies:
|
||||||
|
safe-buffer "~5.2.0"
|
||||||
|
|
||||||
stringify-object@^3.3.0:
|
stringify-object@^3.3.0:
|
||||||
version "3.3.0"
|
version "3.3.0"
|
||||||
resolved "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz"
|
resolved "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz"
|
||||||
@@ -4402,7 +4512,7 @@ tempy@^0.6.0:
|
|||||||
type-fest "^0.16.0"
|
type-fest "^0.16.0"
|
||||||
unique-string "^2.0.0"
|
unique-string "^2.0.0"
|
||||||
|
|
||||||
terser@^5.0.0, terser@^5.4.0:
|
terser@^5.0.0:
|
||||||
version "5.16.1"
|
version "5.16.1"
|
||||||
resolved "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz"
|
resolved "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz"
|
||||||
integrity sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==
|
integrity sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==
|
||||||
@@ -4485,7 +4595,7 @@ type-fest@^0.20.2:
|
|||||||
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
|
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
|
||||||
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
|
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
|
||||||
|
|
||||||
typescript@*, typescript@^5.2.2, typescript@>=4.2.0, typescript@>=4.4.4:
|
typescript@^5.2.2:
|
||||||
version "5.2.2"
|
version "5.2.2"
|
||||||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz"
|
resolved "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz"
|
||||||
integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
|
integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
|
||||||
@@ -4591,10 +4701,10 @@ vite-plugin-pwa@^0.16.5:
|
|||||||
workbox-build "^7.0.0"
|
workbox-build "^7.0.0"
|
||||||
workbox-window "^7.0.0"
|
workbox-window "^7.0.0"
|
||||||
|
|
||||||
"vite@^3.1.0 || ^4.0.0", vite@^4.0.0, vite@^4.4.9:
|
vite@^4.4.9:
|
||||||
version "4.5.1"
|
version "4.5.2"
|
||||||
resolved "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz"
|
resolved "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz"
|
||||||
integrity sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==
|
integrity sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.18.10"
|
esbuild "^0.18.10"
|
||||||
postcss "^8.4.27"
|
postcss "^8.4.27"
|
||||||
@@ -4653,7 +4763,7 @@ vue-tsc@^1.8.11:
|
|||||||
"@vue/typescript" "1.8.11"
|
"@vue/typescript" "1.8.11"
|
||||||
semver "^7.3.8"
|
semver "^7.3.8"
|
||||||
|
|
||||||
"vue@^2.6.14 || ^3.3.0", vue@^3.0.0, "vue@^3.0.0-0 || ^2.6.0", vue@^3.2.0, vue@^3.2.25, vue@^3.3.4, vue@3.3.4:
|
vue@^3.3.4:
|
||||||
version "3.3.4"
|
version "3.3.4"
|
||||||
resolved "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz"
|
resolved "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz"
|
||||||
integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==
|
integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==
|
||||||
@@ -4873,7 +4983,7 @@ workbox-sw@7.0.0:
|
|||||||
resolved "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.0.0.tgz"
|
resolved "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.0.0.tgz"
|
||||||
integrity sha512-SWfEouQfjRiZ7GNABzHUKUyj8pCoe+RwjfOIajcx6J5mtgKkN+t8UToHnpaJL5UVVOf5YhJh+OHhbVNIHe+LVA==
|
integrity sha512-SWfEouQfjRiZ7GNABzHUKUyj8pCoe+RwjfOIajcx6J5mtgKkN+t8UToHnpaJL5UVVOf5YhJh+OHhbVNIHe+LVA==
|
||||||
|
|
||||||
workbox-window@^7.0.0, workbox-window@7.0.0:
|
workbox-window@7.0.0, workbox-window@^7.0.0:
|
||||||
version "7.0.0"
|
version "7.0.0"
|
||||||
resolved "https://registry.npmjs.org/workbox-window/-/workbox-window-7.0.0.tgz"
|
resolved "https://registry.npmjs.org/workbox-window/-/workbox-window-7.0.0.tgz"
|
||||||
integrity sha512-j7P/bsAWE/a7sxqTzXo3P2ALb1reTfZdvVp6OJ/uLr/C2kZAMvjeWGm8V4htQhor7DOvYg0sSbFN2+flT5U0qA==
|
integrity sha512-j7P/bsAWE/a7sxqTzXo3P2ALb1reTfZdvVp6OJ/uLr/C2kZAMvjeWGm8V4htQhor7DOvYg0sSbFN2+flT5U0qA==
|
||||||
@@ -4895,11 +5005,21 @@ wrappy@1:
|
|||||||
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
|
||||||
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
|
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
|
||||||
|
|
||||||
|
ws@~8.11.0:
|
||||||
|
version "8.11.0"
|
||||||
|
resolved "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz"
|
||||||
|
integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
|
||||||
|
|
||||||
xml-name-validator@^4.0.0:
|
xml-name-validator@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz"
|
resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz"
|
||||||
integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==
|
integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==
|
||||||
|
|
||||||
|
xmlhttprequest-ssl@~2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz"
|
||||||
|
integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==
|
||||||
|
|
||||||
y18n@^5.0.5:
|
y18n@^5.0.5:
|
||||||
version "5.0.8"
|
version "5.0.8"
|
||||||
resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
|
resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
|
||||||
|
|||||||
Reference in New Issue
Block a user