mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 13:28:11 +00:00
Migracja z wersji Vue 2 na Vue 3
This commit is contained in:
Generated
+492
-127
@@ -1055,6 +1055,74 @@
|
||||
"postcss": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"@intlify/core-base": {
|
||||
"version": "9.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.6.tgz",
|
||||
"integrity": "sha512-d5GDPpsQbqPkisSJA5b6nJFEkalY/IHAd7vOLNd/Sj4YaNRzXtInu2FoqKiOv8e/lQnXGTpurdCZg5Jxq1Gsxw==",
|
||||
"requires": {
|
||||
"@intlify/devtools-if": "9.1.6",
|
||||
"@intlify/message-compiler": "9.1.6",
|
||||
"@intlify/message-resolver": "9.1.6",
|
||||
"@intlify/runtime": "9.1.6",
|
||||
"@intlify/shared": "9.1.6",
|
||||
"@intlify/vue-devtools": "9.1.6"
|
||||
}
|
||||
},
|
||||
"@intlify/devtools-if": {
|
||||
"version": "9.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.6.tgz",
|
||||
"integrity": "sha512-m8Api+kh+BtFa2FZ/JjIdr1ibsGGqBjdKCzWo5BZecEUxBquIeOQZwpokPh/0K5j+/PZleFXkVAMC5mNt+9WdA==",
|
||||
"requires": {
|
||||
"@intlify/shared": "9.1.6"
|
||||
}
|
||||
},
|
||||
"@intlify/message-compiler": {
|
||||
"version": "9.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.6.tgz",
|
||||
"integrity": "sha512-DR8645VOrVK6x/8tkaCpHnckMAIcoOgeNS5j0wB12RfZoXYQp7vAXMaOP511KMll2mXCREgIB0ojpajiof7yzQ==",
|
||||
"requires": {
|
||||
"@intlify/message-resolver": "9.1.6",
|
||||
"@intlify/shared": "9.1.6",
|
||||
"source-map": "0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@intlify/message-resolver": {
|
||||
"version": "9.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.6.tgz",
|
||||
"integrity": "sha512-UUnbawQa5U9sffd5wRIscqtyY1xWlwJbyfwCLPEWLvBhyAnCwPYlvaHGnnO0CSi0fzJTVwlV9DYzobh3agDeMA=="
|
||||
},
|
||||
"@intlify/runtime": {
|
||||
"version": "9.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.6.tgz",
|
||||
"integrity": "sha512-U1QZ+TPf3kQQvWo4BA2mj3cHAxMRHXNTBhu2u+deh6ubTqXdZ19XGBTMSasrXG6RE+zSio9oM+ndoLja7JGtPg==",
|
||||
"requires": {
|
||||
"@intlify/message-compiler": "9.1.6",
|
||||
"@intlify/message-resolver": "9.1.6",
|
||||
"@intlify/shared": "9.1.6"
|
||||
}
|
||||
},
|
||||
"@intlify/shared": {
|
||||
"version": "9.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.6.tgz",
|
||||
"integrity": "sha512-6MtsKulyfZxdD7OuxjaODjj8QWoHCnLFAk4wkWiHqBCa6UCTC0qXjtEeZ1MxpQihvFmmJZauBUu25EvtngW5qQ=="
|
||||
},
|
||||
"@intlify/vue-devtools": {
|
||||
"version": "9.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.6.tgz",
|
||||
"integrity": "sha512-UdNovg4OML9rIr1sOGZzTfNr1nUy4UQpDf5ni4dNC93T6FIkVJz0n1Np7Vp7e6gDjcmufRYcV99tEwjQSN9+5A==",
|
||||
"requires": {
|
||||
"@intlify/message-resolver": "9.1.6",
|
||||
"@intlify/runtime": "9.1.6",
|
||||
"@intlify/shared": "9.1.6"
|
||||
}
|
||||
},
|
||||
"@mrmlnc/readdir-enhanced": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
||||
@@ -1135,6 +1203,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/estree": {
|
||||
"version": "0.0.48",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz",
|
||||
"integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/express": {
|
||||
"version": "4.17.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz",
|
||||
@@ -1597,6 +1671,52 @@
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
@@ -1611,6 +1731,41 @@
|
||||
"requires": {
|
||||
"minipass": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"vue-loader-v16": {
|
||||
"version": "npm:vue-loader@16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.2.0.tgz",
|
||||
"integrity": "sha512-TitGhqSQ61RJljMmhIGvfWzJ2zk9m1Qug049Ugml6QP3t0e95o0XJjk29roNEiPKJQBEi8Ord5hFuSuELzSp8Q==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
"hash-sum": "^2.0.0",
|
||||
"loader-utils": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
|
||||
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1642,6 +1797,143 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vue/compat": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compat/-/compat-3.1.2.tgz",
|
||||
"integrity": "sha512-6pS22V01LmvkPMtpZvgk0udtR3pNTfxvFR+E4Ut+H9HHusyGf7Gx+PnQwnmawGOxuATNGzfasMaxIkQpbdT8jQ=="
|
||||
},
|
||||
"@vue/compiler-core": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.1.2.tgz",
|
||||
"integrity": "sha512-nHmq7vLjq/XM2IMbZUcKWoH5sPXa2uR/nIKZtjbK5F3TcbnYE/zKsrSUR9WZJ03unlwotNBX1OyxVt9HbWD7/Q==",
|
||||
"requires": {
|
||||
"@babel/parser": "^7.12.0",
|
||||
"@babel/types": "^7.12.0",
|
||||
"@vue/shared": "3.1.2",
|
||||
"estree-walker": "^2.0.1",
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
|
||||
"integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg=="
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz",
|
||||
"integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA=="
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz",
|
||||
"integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==",
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.14.5",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vue/compiler-dom": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.1.2.tgz",
|
||||
"integrity": "sha512-k2+SWcWH0jL6WQAX7Or2ONqu5MbtTgTO0dJrvebQYzgqaKMXNI90RNeWeCxS4BnNFMDONpHBeFgbwbnDWIkmRg==",
|
||||
"requires": {
|
||||
"@vue/compiler-core": "3.1.2",
|
||||
"@vue/shared": "3.1.2"
|
||||
}
|
||||
},
|
||||
"@vue/compiler-sfc": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.1.2.tgz",
|
||||
"integrity": "sha512-SeG/2+DvwejQ7oAiSx8BrDh5qOdqCYHGClPiTvVIHTfSIHiS2JjMbCANdDCjHkTOh/O7WZzo2JhdKm98bRBxTw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/parser": "^7.13.9",
|
||||
"@babel/types": "^7.13.0",
|
||||
"@types/estree": "^0.0.48",
|
||||
"@vue/compiler-core": "3.1.2",
|
||||
"@vue/compiler-dom": "3.1.2",
|
||||
"@vue/compiler-ssr": "3.1.2",
|
||||
"@vue/shared": "3.1.2",
|
||||
"consolidate": "^0.16.0",
|
||||
"estree-walker": "^2.0.1",
|
||||
"hash-sum": "^2.0.0",
|
||||
"lru-cache": "^5.1.1",
|
||||
"magic-string": "^0.25.7",
|
||||
"merge-source-map": "^1.1.0",
|
||||
"postcss": "^8.1.10",
|
||||
"postcss-modules": "^4.0.0",
|
||||
"postcss-selector-parser": "^6.0.4",
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
|
||||
"integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.14.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz",
|
||||
"integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz",
|
||||
"integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.14.5",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"consolidate": {
|
||||
"version": "0.16.0",
|
||||
"resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.16.0.tgz",
|
||||
"integrity": "sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bluebird": "^3.7.2"
|
||||
}
|
||||
},
|
||||
"postcss": {
|
||||
"version": "8.3.5",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz",
|
||||
"integrity": "sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"colorette": "^1.2.2",
|
||||
"nanoid": "^3.1.23",
|
||||
"source-map-js": "^0.6.2"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vue/compiler-ssr": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.1.2.tgz",
|
||||
"integrity": "sha512-BwXo9LFk5OSWdMyZQ4bX1ELHX0Z/9F+ld/OaVnpUPzAZCHslBYLvyKUVDwv2C/lpLjRffpC2DOUEdl1+RP1aGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@vue/compiler-dom": "3.1.2",
|
||||
"@vue/shared": "3.1.2"
|
||||
}
|
||||
},
|
||||
"@vue/component-compiler-utils": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.2.0.tgz",
|
||||
@@ -1689,12 +1981,49 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vue/devtools-api": {
|
||||
"version": "6.0.0-beta.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.0-beta.15.tgz",
|
||||
"integrity": "sha512-quBx4Jjpexo6KDiNUGFr/zF/2A4srKM9S9v2uHgMXSU//hjgq1eGzqkIFql8T9gfX5ZaVOUzYBP3jIdIR3PKIA=="
|
||||
},
|
||||
"@vue/preload-webpack-plugin": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.2.tgz",
|
||||
"integrity": "sha512-LIZMuJk38pk9U9Ur4YzHjlIyMuxPlACdBIHH9/nGYVTsaGKOSnSuELiE8vS9wa+dJpIYspYUOqk+L1Q4pgHQHQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@vue/reactivity": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.2.tgz",
|
||||
"integrity": "sha512-glJzJoN2xE7I2lRvwKM5u1BHRPTd1yc8iaf//Lai/78/uYAvE5DXp5HzWRFOwMlbRvMGJHIQjOqoxj87cDAaag==",
|
||||
"requires": {
|
||||
"@vue/shared": "3.1.2"
|
||||
}
|
||||
},
|
||||
"@vue/runtime-core": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.1.2.tgz",
|
||||
"integrity": "sha512-gsPZG4dRIkixuuKmoj4P9IHgfT0yaFLcqWOM5F/bCk0nxQn1XtxH8oUehWuET726KhbukvDoJfe9G2CKviy80w==",
|
||||
"requires": {
|
||||
"@vue/reactivity": "3.1.2",
|
||||
"@vue/shared": "3.1.2"
|
||||
}
|
||||
},
|
||||
"@vue/runtime-dom": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.1.2.tgz",
|
||||
"integrity": "sha512-QvINxjLucEZFzp5f0NVu7JqWYCv5TKQfkH2FDs/N6QNE4iKcYtKrWdT0HKfABnVXG28Znqv6rIH0dH4ZAOwxpA==",
|
||||
"requires": {
|
||||
"@vue/runtime-core": "3.1.2",
|
||||
"@vue/shared": "3.1.2",
|
||||
"csstype": "^2.6.8"
|
||||
}
|
||||
},
|
||||
"@vue/shared": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.2.tgz",
|
||||
"integrity": "sha512-EmH/poaDWBPJaPILXNI/1fvUbArJQmmTyVCwvvyDYDFnkPoTclAbHRAtyIvqfez7jybTDn077HTNILpxlsoWhg=="
|
||||
},
|
||||
"@vue/web-component-wrapper": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz",
|
||||
@@ -3876,6 +4205,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"csstype": {
|
||||
"version": "2.6.17",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.17.tgz",
|
||||
"integrity": "sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A=="
|
||||
},
|
||||
"cyclist": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
|
||||
@@ -3891,12 +4225,6 @@
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"de-indent": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
|
||||
"integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
@@ -4583,6 +4911,11 @@
|
||||
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
|
||||
"dev": true
|
||||
},
|
||||
"estree-walker": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
||||
},
|
||||
"esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
@@ -5033,14 +5366,16 @@
|
||||
"integrity": "sha1-jHyF2gcTtAYFVrTXHAF3XuEmnrk=",
|
||||
"requires": {
|
||||
"websocket-extensions": ">=0.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"websocket-extensions": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz",
|
||||
"integrity": "sha1-domUmcGEtu91Q3fC27DNbLVdKec="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"websocket-extensions": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
|
||||
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5194,6 +5529,15 @@
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
},
|
||||
"generic-names": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz",
|
||||
"integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loader-utils": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"gensync": {
|
||||
"version": "1.0.0-beta.1",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz",
|
||||
@@ -5787,6 +6131,12 @@
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
}
|
||||
},
|
||||
"icss-replace-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
|
||||
"integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=",
|
||||
"dev": true
|
||||
},
|
||||
"icss-utils": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz",
|
||||
@@ -6496,6 +6846,12 @@
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.camelcase": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.defaultsdeep": {
|
||||
"version": "4.6.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz",
|
||||
@@ -6571,6 +6927,15 @@
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.25.7",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
|
||||
"integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sourcemap-codec": "^1.4.4"
|
||||
}
|
||||
},
|
||||
"make-dir": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
|
||||
@@ -6918,6 +7283,12 @@
|
||||
"thenify-all": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.1.23",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
|
||||
"integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
|
||||
"dev": true
|
||||
},
|
||||
"nanomatch": {
|
||||
"version": "1.2.13",
|
||||
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
|
||||
@@ -7871,6 +8242,65 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"postcss-modules": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.1.3.tgz",
|
||||
"integrity": "sha512-dBT39hrXe4OAVYJe/2ZuIZ9BzYhOe7t+IhedYeQ2OxKwDpAGlkEN/fR0fGnrbx4BvgbMReRX4hCubYK9cE/pJQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"generic-names": "^2.0.1",
|
||||
"icss-replace-symbols": "^1.1.0",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"postcss-modules-extract-imports": "^3.0.0",
|
||||
"postcss-modules-local-by-default": "^4.0.0",
|
||||
"postcss-modules-scope": "^3.0.0",
|
||||
"postcss-modules-values": "^4.0.0",
|
||||
"string-hash": "^1.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"icss-utils": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
|
||||
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
|
||||
"dev": true
|
||||
},
|
||||
"postcss-modules-extract-imports": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
|
||||
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
|
||||
"dev": true
|
||||
},
|
||||
"postcss-modules-local-by-default": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz",
|
||||
"integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"icss-utils": "^5.0.0",
|
||||
"postcss-selector-parser": "^6.0.2",
|
||||
"postcss-value-parser": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"postcss-modules-scope": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz",
|
||||
"integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"postcss-selector-parser": "^6.0.4"
|
||||
}
|
||||
},
|
||||
"postcss-modules-values": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
|
||||
"integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"icss-utils": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"postcss-modules-extract-imports": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz",
|
||||
@@ -9209,6 +9639,12 @@
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
|
||||
"dev": true
|
||||
},
|
||||
"source-map-js": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
|
||||
"integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map-resolve": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
|
||||
@@ -9246,6 +9682,12 @@
|
||||
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
|
||||
"dev": true
|
||||
},
|
||||
"sourcemap-codec": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
|
||||
"dev": true
|
||||
},
|
||||
"spdx-correct": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
|
||||
@@ -9443,6 +9885,12 @@
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
|
||||
"dev": true
|
||||
},
|
||||
"string-hash": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz",
|
||||
"integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
@@ -9724,8 +10172,7 @@
|
||||
"to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
|
||||
},
|
||||
"to-object-path": {
|
||||
"version": "0.3.0",
|
||||
@@ -9947,9 +10394,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.9.9",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
|
||||
"integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.6.tgz",
|
||||
"integrity": "sha512-pxnwLxeb/Z5SP80JDRzVjh58KsM6jZHRAOtTpS7sXLS4ogXNKC9ANxHHZqLLeVHZN35jCtI4JdmLLbLiC1kBow==",
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
@@ -10289,9 +10736,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"vue": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.12.tgz",
|
||||
"integrity": "sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg=="
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.1.2.tgz",
|
||||
"integrity": "sha512-q/rbKpb7aofax4ugqu2k/uj7BYuNPcd6Z5/qJtfkJQsE0NkwVoCyeSh7IZGH61hChwYn3CEkh4bHolvUPxlQ+w==",
|
||||
"requires": {
|
||||
"@vue/compiler-dom": "3.1.2",
|
||||
"@vue/runtime-dom": "3.1.2",
|
||||
"@vue/shared": "3.1.2"
|
||||
}
|
||||
},
|
||||
"vue-class-component": {
|
||||
"version": "7.2.6",
|
||||
@@ -10305,9 +10757,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"vue-i18n": {
|
||||
"version": "8.24.4",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.24.4.tgz",
|
||||
"integrity": "sha512-RZE94WUAGxEiBAANxQ0pptbRwDkNKNSXl3fnJslpFOxVMF6UkUtMDSuYGuW2blDrVgweIXVpethOVkYoNNT9xw=="
|
||||
"version": "9.1.6",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.6.tgz",
|
||||
"integrity": "sha512-FEC4HZkTH6QRIu/A0wlo0VS/GH3w/fuCC6xfvoC8IyhhtbG9A+go9NfW+HZ1ZXdAcO4EWcVQi04M+iSwuxgixw==",
|
||||
"requires": {
|
||||
"@intlify/core-base": "9.1.6",
|
||||
"@intlify/shared": "9.1.6",
|
||||
"@intlify/vue-devtools": "9.1.6",
|
||||
"@vue/devtools-api": "^6.0.0-beta.7"
|
||||
}
|
||||
},
|
||||
"vue-loader": {
|
||||
"version": "15.9.7",
|
||||
@@ -10330,99 +10788,13 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-loader-v16": {
|
||||
"version": "npm:vue-loader@16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.2.0.tgz",
|
||||
"integrity": "sha512-TitGhqSQ61RJljMmhIGvfWzJ2zk9m1Qug049Ugml6QP3t0e95o0XJjk29roNEiPKJQBEi8Ord5hFuSuELzSp8Q==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
"hash-sum": "^2.0.0",
|
||||
"loader-utils": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
|
||||
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-property-decorator": {
|
||||
"version": "8.5.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-property-decorator/-/vue-property-decorator-8.5.1.tgz",
|
||||
"integrity": "sha512-O6OUN2OMsYTGPvgFtXeBU3jPnX5ffQ9V4I1WfxFQ6dqz6cOUbR3Usou7kgFpfiXDvV7dJQSFcJ5yUPgOtPPm1Q==",
|
||||
"requires": {
|
||||
"vue-class-component": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"vue-router": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.1.tgz",
|
||||
"integrity": "sha512-RRQNLT8Mzr8z7eL4p7BtKvRaTSGdCbTy2+Mm5HTJvLGYSSeG9gDzNasJPP/yOYKLy+/cLG/ftrqq5fvkFwBJEw=="
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.10.tgz",
|
||||
"integrity": "sha512-YbPf6QnZpyyWfnk7CUt2Bme+vo7TLfg1nGZNkvYqKYh4vLaFw6Gn8bPGdmt5m4qrGnKoXLqc4htAsd3dIukICA==",
|
||||
"requires": {
|
||||
"@vue/devtools-api": "^6.0.0-beta.14"
|
||||
}
|
||||
},
|
||||
"vue-style-loader": {
|
||||
"version": "4.1.3",
|
||||
@@ -10442,16 +10814,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-template-compiler": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz",
|
||||
"integrity": "sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"vue-template-es2015-compiler": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz",
|
||||
@@ -10459,9 +10821,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"vuex": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz",
|
||||
"integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw=="
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
|
||||
"integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==",
|
||||
"requires": {
|
||||
"@vue/devtools-api": "^6.0.0-beta.11"
|
||||
}
|
||||
},
|
||||
"vuex-class": {
|
||||
"version": "0.3.2",
|
||||
|
||||
+2
-4
@@ -12,10 +12,8 @@
|
||||
"dotenv": "^8.6.0",
|
||||
"firestore": "^1.1.6",
|
||||
"howler": "^2.2.1",
|
||||
"vue": "^2.6.12",
|
||||
"vue": "^3.1.2",
|
||||
"vue-class-component": "^7.2.6",
|
||||
"vue-property-decorator": "^8.5.1",
|
||||
"@vue/compat": "^3.1.0",
|
||||
"vue-i18n": "^9.1.6",
|
||||
"vue-router": "^4.0.0-0",
|
||||
"vuex": "^4.0.0-0"
|
||||
@@ -29,7 +27,7 @@
|
||||
"axios": "^0.21.1",
|
||||
"sass": "^1.32.13",
|
||||
"sass-loader": "^8.0.2",
|
||||
"typescript": "^3.9.9",
|
||||
"typescript": "~4.1.5",
|
||||
"@vue/compiler-sfc": "^3.1.0",
|
||||
"vuex-class": "^0.3.2",
|
||||
"vuex-module-decorators": "^0.17.0"
|
||||
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
@import "./styles/responsive.scss";
|
||||
@import "./styles/variables.scss";
|
||||
@import "./styles/global.scss";
|
||||
@import "./styles/scenery_status.scss";
|
||||
|
||||
:root {
|
||||
--clr-primary: #ffc014;
|
||||
--clr-secondary: #2f2f2f;
|
||||
|
||||
--clr-bg: #333;
|
||||
|
||||
--clr-accent: #1085b3;
|
||||
--clr-accent2: #ff3d5d;
|
||||
|
||||
--clr-skr: #ff5100;
|
||||
--clr-twr: #ffbb00;
|
||||
}
|
||||
|
||||
// VUE ROUTE CHANGE ANIMATION
|
||||
.view-anim {
|
||||
&-enter-from,
|
||||
&-leave-to {
|
||||
opacity: 0.02;
|
||||
}
|
||||
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all $animDuration $animType;
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.route {
|
||||
margin: 0 0.2em;
|
||||
|
||||
&-active {
|
||||
color: $accentCol;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
// APP
|
||||
.app {
|
||||
background: $bgCol;
|
||||
color: white;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
font-size: 1rem;
|
||||
|
||||
@include smallScreen() {
|
||||
font-size: calc(0.45rem + 1vw);
|
||||
}
|
||||
}
|
||||
|
||||
// CONTAINER
|
||||
.app_container {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
|
||||
min-width: 0;
|
||||
min-height: 100vh;
|
||||
|
||||
header {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
footer {
|
||||
flex: 0 1 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
// HEADER
|
||||
.app_header {
|
||||
background: $primaryCol;
|
||||
padding: 0.15em;
|
||||
|
||||
border-radius: 0 0 1em 1em;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.header {
|
||||
&_brand {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
font-size: 4.25em;
|
||||
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
width: 0.8em;
|
||||
}
|
||||
|
||||
.brand_lang {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
|
||||
transform: translate(110%, -35%);
|
||||
|
||||
img {
|
||||
width: 0.6em;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&_info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
font-size: 1.25em;
|
||||
|
||||
margin: 0 0.3em;
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
&_links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
border-radius: 0.7em;
|
||||
|
||||
font-size: 1.25em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
// COUNTER
|
||||
.info_counter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: $accentCol;
|
||||
|
||||
span {
|
||||
margin: 0 0.15em;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 1.35em;
|
||||
}
|
||||
}
|
||||
|
||||
// FOOTER
|
||||
footer.app_footer {
|
||||
max-width: 100%;
|
||||
padding: 0.5em;
|
||||
|
||||
z-index: 10;
|
||||
|
||||
background: #111;
|
||||
color: white;
|
||||
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
+213
-379
@@ -1,379 +1,213 @@
|
||||
git <template>
|
||||
<div class="app">
|
||||
<UpdateModal
|
||||
:currentVersion="VERSION"
|
||||
@toggleUpdateModal="toggleUpdateModal"
|
||||
v-if="updateModalVisible"
|
||||
/>
|
||||
|
||||
<div class="app_container">
|
||||
<header class="app_header">
|
||||
<div class="header_body">
|
||||
<span class="header_brand">
|
||||
<span>
|
||||
<span>Stacj</span>
|
||||
<img
|
||||
src="@/assets/trainlogo.png"
|
||||
alt="trainlogo"
|
||||
/>
|
||||
<span>wnik</span>
|
||||
</span>
|
||||
|
||||
<span class="brand_lang">
|
||||
|
||||
<span
|
||||
class="lang pl"
|
||||
@click="changeLang('en')"
|
||||
:class="{ current: currentLang == 'pl' }"
|
||||
v-if="currentLang == 'pl'"
|
||||
>
|
||||
<img
|
||||
:src="iconPL"
|
||||
alt="icon-pl"
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="lang en"
|
||||
@click="changeLang('pl')"
|
||||
:class="{ current: currentLang == 'en' }"
|
||||
v-if="currentLang == 'en'"
|
||||
>
|
||||
<img
|
||||
:src="iconEN"
|
||||
alt="icon-en"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="header_info">
|
||||
<Clock />
|
||||
<div class="info_counter">
|
||||
<img
|
||||
src="@/assets/icon-dispatcher.svg"
|
||||
alt="icon dispatcher"
|
||||
/>
|
||||
<span>{{ data.activeStationCount }}</span>
|
||||
<span>{{ data.activeTrainCount }}</span>
|
||||
<img
|
||||
src="@/assets/icon-train.svg"
|
||||
alt="icon train"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<span class="header_links">
|
||||
<router-link
|
||||
class="route"
|
||||
active-class="route-active"
|
||||
to="/"
|
||||
exact
|
||||
>{{ $t("app.sceneries") }}
|
||||
</router-link>
|
||||
/
|
||||
<router-link
|
||||
class="route"
|
||||
active-class="route-active"
|
||||
to="/trains"
|
||||
>{{ $t("app.trains") }}
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="app_main">
|
||||
<transition
|
||||
name="view-anim"
|
||||
mode="out-in"
|
||||
>
|
||||
<keep-alive>
|
||||
<router-view />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</main>
|
||||
|
||||
<footer class="app_footer">
|
||||
©
|
||||
<a
|
||||
href="https://td2.info.pl/profile/?u=20777"
|
||||
target="_blank"
|
||||
>
|
||||
Spythere
|
||||
</a>
|
||||
2021 | v{{ VERSION }}
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from "vue-property-decorator";
|
||||
import { Action, Getter } from "vuex-class";
|
||||
|
||||
import UpdateModal from "@/components/Global/UpdateModal.vue";
|
||||
import Clock from "@/components/App/Clock.vue";
|
||||
|
||||
import StorageManager from "@/scripts/managers/storageManager";
|
||||
import { StoreData } from "./scripts/interfaces/StoreData";
|
||||
|
||||
@Component({
|
||||
components: { Clock, UpdateModal },
|
||||
})
|
||||
export default class App extends Vue {
|
||||
@Action("synchronizeData") synchronizeData;
|
||||
@Getter("getAllData") data!: StoreData;
|
||||
|
||||
private VERSION = "1.4.7";
|
||||
|
||||
hasReleaseNotes = false;
|
||||
updateModalVisible = false;
|
||||
|
||||
currentLang = "pl";
|
||||
|
||||
iconEN = require("@/assets/icon-en.jpg");
|
||||
iconPL = require("@/assets/icon-pl.svg");
|
||||
|
||||
toggleUpdateModal() {
|
||||
this.updateModalVisible = !this.updateModalVisible;
|
||||
StorageManager.setBooleanValue("version_notes_read", true);
|
||||
}
|
||||
|
||||
changeLang(lang: string) {
|
||||
this.$i18n.locale = lang;
|
||||
this.currentLang = lang;
|
||||
|
||||
StorageManager.setStringValue("lang", lang);
|
||||
}
|
||||
|
||||
loadLang() {
|
||||
const storageLang = StorageManager.getStringValue("lang");
|
||||
|
||||
if (storageLang) {
|
||||
this.changeLang(storageLang);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window.navigator.language) {
|
||||
this.changeLang("pl");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (window.navigator.language) {
|
||||
case "pl-PL":
|
||||
this.changeLang("pl");
|
||||
break;
|
||||
case "en-EN":
|
||||
default:
|
||||
this.changeLang("en");
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
created() {
|
||||
this.loadLang();
|
||||
this.synchronizeData();
|
||||
}
|
||||
|
||||
mounted() {
|
||||
if (this.detectIEVersion() != -1)
|
||||
alert(
|
||||
"Stacjownik nie wspiera reliktów przeszłości. Przesiądź się na nowszą przeglądarkę!"
|
||||
);
|
||||
|
||||
if (StorageManager.getStringValue("version") != this.VERSION) {
|
||||
StorageManager.setStringValue("version", this.VERSION);
|
||||
|
||||
if (this.hasReleaseNotes)
|
||||
StorageManager.setBooleanValue("version_notes_read", false);
|
||||
}
|
||||
|
||||
this.updateModalVisible =
|
||||
this.hasReleaseNotes &&
|
||||
!StorageManager.getBooleanValue("version_notes_read");
|
||||
}
|
||||
|
||||
detectIEVersion() {
|
||||
var rv = -1;
|
||||
if (navigator.appName == "Microsoft Internet Explorer") {
|
||||
var ua = navigator.userAgent;
|
||||
var re = new RegExp("MSIE ([0-9]{1,}[\\.0-9]{0,})");
|
||||
if (re.exec(ua) != null) rv = parseFloat(RegExp.$1);
|
||||
} else if (navigator.appName == "Netscape") {
|
||||
var ua = navigator.userAgent;
|
||||
var re = new RegExp("Trident/.*rv:([0-9]{1,}[\\.0-9]{0,})");
|
||||
if (re.exec(ua) != null) rv = parseFloat(RegExp.$1);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "./styles/responsive.scss";
|
||||
@import "./styles/variables.scss";
|
||||
@import "./styles/global.scss";
|
||||
@import "./styles/scenery_status.scss";
|
||||
|
||||
:root {
|
||||
--clr-primary: #ffc014;
|
||||
--clr-secondary: #2f2f2f;
|
||||
|
||||
--clr-bg: #333;
|
||||
|
||||
--clr-accent: #1085b3;
|
||||
--clr-accent2: #ff3d5d;
|
||||
|
||||
--clr-skr: #ff5100;
|
||||
--clr-twr: #ffbb00;
|
||||
}
|
||||
|
||||
// VUE ROUTE CHANGE ANIMATION
|
||||
.view-anim {
|
||||
&-enter,
|
||||
&-leave-to {
|
||||
opacity: 0.02;
|
||||
}
|
||||
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all $animDuration $animType;
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.route {
|
||||
margin: 0 0.2em;
|
||||
|
||||
&-active {
|
||||
color: $accentCol;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
// APP
|
||||
.app {
|
||||
background: $bgCol;
|
||||
color: white;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
font-size: 1rem;
|
||||
|
||||
@include smallScreen() {
|
||||
font-size: calc(0.45rem + 1vw);
|
||||
}
|
||||
}
|
||||
|
||||
// CONTAINER
|
||||
.app_container {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
|
||||
min-width: 0;
|
||||
min-height: 100vh;
|
||||
|
||||
header {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
footer {
|
||||
flex: 0 1 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
// HEADER
|
||||
.app_header {
|
||||
background: $primaryCol;
|
||||
padding: 0.15em;
|
||||
|
||||
border-radius: 0 0 1em 1em;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.header {
|
||||
&_brand {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
font-size: 4.25em;
|
||||
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
width: 0.8em;
|
||||
}
|
||||
|
||||
.brand_lang {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
|
||||
transform: translate(110%, -35%);
|
||||
|
||||
img {
|
||||
width: 0.6em;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&_info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
font-size: 1.25em;
|
||||
|
||||
margin: 0 0.3em;
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
&_links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
border-radius: 0.7em;
|
||||
|
||||
font-size: 1.25em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
// COUNTER
|
||||
.info_counter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: $accentCol;
|
||||
|
||||
span {
|
||||
margin: 0 0.15em;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 1.35em;
|
||||
}
|
||||
}
|
||||
|
||||
// FOOTER
|
||||
footer.app_footer {
|
||||
max-width: 100%;
|
||||
padding: 0.5em;
|
||||
|
||||
z-index: 10;
|
||||
|
||||
background: #111;
|
||||
color: white;
|
||||
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div class="app">
|
||||
<!-- <UpdateModal
|
||||
:currentVersion="VERSION"
|
||||
@toggleUpdateModal="toggleUpdateModal"
|
||||
v-if="updateModalVisible"
|
||||
/> -->
|
||||
|
||||
<div class="app_container">
|
||||
<header class="app_header">
|
||||
<div class="header_body">
|
||||
<span class="header_brand">
|
||||
<span>
|
||||
<span>Stacj</span>
|
||||
<img
|
||||
src="@/assets/trainlogo.png"
|
||||
alt="trainlogo"
|
||||
/>
|
||||
<span>wnik</span>
|
||||
</span>
|
||||
|
||||
<span class="brand_lang">
|
||||
|
||||
<span
|
||||
class="lang pl"
|
||||
@click="changeLang('en')"
|
||||
:class="{ current: currentLang == 'pl' }"
|
||||
v-if="currentLang == 'pl'"
|
||||
>
|
||||
<img
|
||||
:src="iconPL"
|
||||
alt="icon-pl"
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="lang en"
|
||||
@click="changeLang('pl')"
|
||||
:class="{ current: currentLang == 'en' }"
|
||||
v-if="currentLang == 'en'"
|
||||
>
|
||||
<img
|
||||
:src="iconEN"
|
||||
alt="icon-en"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="header_info">
|
||||
<Clock />
|
||||
<div class="info_counter">
|
||||
<img
|
||||
src="@/assets/icon-dispatcher.svg"
|
||||
alt="icon dispatcher"
|
||||
/>
|
||||
<span>{{ data.activeStationCount }}</span>
|
||||
<span>{{ data.activeTrainCount }}</span>
|
||||
<img
|
||||
src="@/assets/icon-train.svg"
|
||||
alt="icon train"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<span class="header_links">
|
||||
<router-link
|
||||
class="route"
|
||||
active-class="route-active"
|
||||
to="/"
|
||||
exact
|
||||
>{{ $t("app.sceneries") }}
|
||||
</router-link>
|
||||
/
|
||||
<router-link
|
||||
class="route"
|
||||
active-class="route-active"
|
||||
to="/trains"
|
||||
>{{ $t("app.trains") }}
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="app_main">
|
||||
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition
|
||||
name="view-anim"
|
||||
mode="out-in"
|
||||
>
|
||||
<keep-alive>
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
|
||||
</router-view>
|
||||
</main>
|
||||
|
||||
<footer class="app_footer">
|
||||
©
|
||||
<a
|
||||
href="https://td2.info.pl/profile/?u=20777"
|
||||
target="_blank"
|
||||
>
|
||||
Spythere
|
||||
</a>
|
||||
2021 | v{{ VERSION }}
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
// import UpdateModal from "@/components/Global/UpdateModal.vue";
|
||||
import Clock from "@/components/App/Clock.vue";
|
||||
|
||||
import StorageManager from "@/scripts/managers/storageManager";
|
||||
import { computed, ComputedRef, defineComponent } from "vue";
|
||||
import { GETTERS } from "./constants/storeConstants";
|
||||
import { StoreData } from "./scripts/interfaces/StoreData";
|
||||
import { useStore } from "./store";
|
||||
// import { StoreData } from "./scripts/interfaces/StoreData";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Clock,
|
||||
},
|
||||
|
||||
setup() {
|
||||
const store = useStore();
|
||||
store.dispatch("synchronizeData");
|
||||
|
||||
const data: ComputedRef<StoreData> = computed(
|
||||
() => store.getters[GETTERS.allData]
|
||||
);
|
||||
|
||||
return {
|
||||
data,
|
||||
};
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
VERSION: "1.4.7",
|
||||
updateModalVisible: false,
|
||||
hasReleaseNotes: false,
|
||||
currentLang: "pl",
|
||||
|
||||
iconEN: require("@/assets/icon-en.jpg"),
|
||||
iconPL: require("@/assets/icon-pl.svg"),
|
||||
}),
|
||||
|
||||
created() {
|
||||
this.loadLang();
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (StorageManager.getStringValue("version") != this.VERSION) {
|
||||
StorageManager.setStringValue("version", this.VERSION);
|
||||
|
||||
if (this.hasReleaseNotes)
|
||||
StorageManager.setBooleanValue("version_notes_read", false);
|
||||
}
|
||||
|
||||
this.updateModalVisible =
|
||||
this.hasReleaseNotes &&
|
||||
!StorageManager.getBooleanValue("version_notes_read");
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleUpdateModal() {
|
||||
this.updateModalVisible = !this.updateModalVisible;
|
||||
StorageManager.setBooleanValue("version_notes_read", true);
|
||||
},
|
||||
|
||||
changeLang(lang: string) {
|
||||
this.$i18n.locale = lang;
|
||||
this.currentLang = lang;
|
||||
|
||||
StorageManager.setStringValue("lang", lang);
|
||||
},
|
||||
|
||||
loadLang() {
|
||||
const storageLang = StorageManager.getStringValue("lang");
|
||||
|
||||
if (storageLang) {
|
||||
this.changeLang(storageLang);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window.navigator.language) {
|
||||
this.changeLang("pl");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (window.navigator.language) {
|
||||
case "pl-PL":
|
||||
this.changeLang("pl");
|
||||
break;
|
||||
case "en-EN":
|
||||
default:
|
||||
this.changeLang("en");
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" src="./App.scss"></style>
|
||||
@@ -1,27 +1,28 @@
|
||||
<template>
|
||||
<div class="clock">{{ formattedDate }}</div>
|
||||
<div class="clock">{{ computedDate }}</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
export default Vue.extend({
|
||||
import { computed, defineComponent, ref } from "vue";
|
||||
export default defineComponent({
|
||||
name: "clock",
|
||||
data: () => ({
|
||||
timestamp: Date.now(),
|
||||
}),
|
||||
computed: {
|
||||
formattedDate() {
|
||||
return new Date(this.timestamp).toLocaleString("pl-PL", {
|
||||
setup() {
|
||||
let timestamp = ref(Date.now());
|
||||
|
||||
const computedDate = computed(() => new Date(timestamp.value).toLocaleString("pl-PL", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
setInterval(() => (this.timestamp = Date.now()), 1000);
|
||||
},
|
||||
}));
|
||||
|
||||
setInterval(() => (timestamp.value = Date.now()), 1000);
|
||||
|
||||
return { computedDate }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component, Prop } from "vue-property-decorator";
|
||||
import { defineComponent } from "@vue/runtime-core";
|
||||
|
||||
@Component
|
||||
export default class Loading extends Vue {
|
||||
@Prop() readonly message!: string;
|
||||
}
|
||||
export default defineComponent({
|
||||
props: ["message"],
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
<template>
|
||||
<section class="updates card" v-if="cardOpen">
|
||||
<section
|
||||
class="updates card"
|
||||
v-if="cardOpen"
|
||||
>
|
||||
<h2>Ostatnie aktualizacje w Stacjowniku</h2>
|
||||
<p>Tutaj będą pojawiać się informacje o kolejnych nowościach na stronie :)</p>
|
||||
|
||||
<ul>
|
||||
<li v-for="(update, i) in updates" :key="i">
|
||||
<li
|
||||
v-for="(update, i) in updates"
|
||||
:key="i"
|
||||
>
|
||||
<div>{{update.date}}</div>
|
||||
|
||||
<div>
|
||||
<span v-for="(line, l) in content" :key="l">{{line}}</span>
|
||||
<span
|
||||
v-for="(line, l) in content"
|
||||
:key="l"
|
||||
>{{line}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -16,7 +25,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
import { defineComponent } from "@vue/runtime-core";
|
||||
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
updates: {
|
||||
@@ -29,7 +40,7 @@ export default {
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -5,13 +5,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
@Component
|
||||
export default class ActionButton extends Vue {}
|
||||
export default defineComponent({});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style lang="scss">
|
||||
@import "../../styles/variables";
|
||||
@import "../../styles/responsive";
|
||||
|
||||
@@ -40,15 +39,12 @@ export default class ActionButton extends Vue {}
|
||||
img {
|
||||
width: 1.25em;
|
||||
vertical-align: middle;
|
||||
|
||||
margin-right: 0.35em;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1em;
|
||||
overflow: hidden;
|
||||
|
||||
transition: max-width 0.35s ease-in-out;
|
||||
}
|
||||
|
||||
&.open {
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
<template>
|
||||
<div class="search-box">
|
||||
<input v-model="searchedItem" :placeholder="title" />
|
||||
|
||||
<img
|
||||
class="search-exit"
|
||||
:src="exitIcon"
|
||||
alt="exit-icon"
|
||||
@click="() => (searchedItem = '')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop, Model } from "vue-property-decorator";
|
||||
|
||||
@Component
|
||||
export default class SearchBox extends Vue {
|
||||
@Prop({ required: true }) title!: string;
|
||||
@Model("changed") readonly searchedItem!: string;
|
||||
|
||||
// @Emit("changed")
|
||||
// onItemChanged() {
|
||||
// return this.searchedItem;
|
||||
// }
|
||||
|
||||
exitIcon = require("@/assets/icon-exit.svg");
|
||||
|
||||
// searchedItem: string = "";
|
||||
|
||||
// @Watch("searchedItem")
|
||||
// watchSelectedItem(item) {
|
||||
// this.onItemChanged();
|
||||
// }
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search {
|
||||
&-box {
|
||||
position: relative;
|
||||
|
||||
background: #333;
|
||||
border-radius: 0.5em;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
&-exit {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
|
||||
top: 50%;
|
||||
right: 10px;
|
||||
transform: translateY(-50%);
|
||||
|
||||
width: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
border: none;
|
||||
|
||||
min-width: 85%;
|
||||
padding: 0.35em 0.5em;
|
||||
}
|
||||
</style>
|
||||
@@ -1,12 +1,22 @@
|
||||
<template>
|
||||
<div class="select-box">
|
||||
<div class="select-box_content">
|
||||
<button class="selected" @click="toggleBox">
|
||||
{{ selectedItemComp ? selectedItemComp.value : "" }}
|
||||
<button
|
||||
class="selected"
|
||||
@click="toggleBox"
|
||||
>
|
||||
{{ computedSelectedItem.value }}
|
||||
</button>
|
||||
|
||||
<div class="options" v-if="boxVisible">
|
||||
<div class="option" v-for="item in itemList" :key="item.id">
|
||||
<div
|
||||
class="options"
|
||||
v-if="boxVisible"
|
||||
>
|
||||
<div
|
||||
class="option"
|
||||
v-for="item in itemList"
|
||||
:key="item.id"
|
||||
>
|
||||
<label :for="item.id">
|
||||
<input
|
||||
type="button"
|
||||
@@ -15,7 +25,7 @@
|
||||
@click="selectOption(item)"
|
||||
/>
|
||||
|
||||
<span :style="selectedItemComp.id == item.id ? 'color: gold;' : ''">
|
||||
<span :style="computedSelectedItem.id == item.id ? 'color: gold;' : ''">
|
||||
{{ item.value }}
|
||||
</span>
|
||||
</label>
|
||||
@@ -24,51 +34,79 @@
|
||||
</div>
|
||||
|
||||
<div class="arrow">
|
||||
<img :src="boxVisible ? ascIcon : descIcon" alt="arrow-icon" />
|
||||
<img
|
||||
:src="boxVisible ? ascIcon : descIcon"
|
||||
alt="arrow-icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop, Emit } from "vue-property-decorator";
|
||||
import {
|
||||
computed,
|
||||
defineComponent,
|
||||
defineEmit,
|
||||
Ref,
|
||||
ref,
|
||||
} from "@vue/runtime-core";
|
||||
|
||||
@Component
|
||||
export default class SelectBox extends Vue {
|
||||
@Prop({ required: true }) itemList!: { id: string | number; value: string }[];
|
||||
@Prop({ default: 0 }) defaultItemIndex!: number;
|
||||
|
||||
boxVisible = false;
|
||||
|
||||
test() {
|
||||
console.log("test");
|
||||
}
|
||||
|
||||
@Emit("selected")
|
||||
onItemSelected() {
|
||||
return this.selectedItem;
|
||||
}
|
||||
|
||||
ascIcon = require("@/assets/icon-arrow-asc.svg");
|
||||
descIcon = require("@/assets/icon-arrow-desc.svg");
|
||||
|
||||
selectedItem: { id: string | number; value: string } | null = null;
|
||||
|
||||
get selectedItemComp() {
|
||||
if (!this.selectedItem) return this.itemList[this.defaultItemIndex];
|
||||
|
||||
return this.itemList.find((item) => item.id === this.selectedItem?.id);
|
||||
}
|
||||
|
||||
toggleBox() {
|
||||
this.boxVisible = !this.boxVisible;
|
||||
}
|
||||
|
||||
selectOption(item: { id: string | number; value: string }) {
|
||||
this.selectedItem = item;
|
||||
this.boxVisible = false;
|
||||
this.onItemSelected();
|
||||
}
|
||||
interface Item {
|
||||
id: string | number;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
emits: ["selected"],
|
||||
|
||||
props: {
|
||||
itemList: {
|
||||
type: Array as () => Item[],
|
||||
required: true,
|
||||
},
|
||||
|
||||
defaultItemIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
ascIcon: require("@/assets/icon-arrow-asc.svg"),
|
||||
descIcon: require("@/assets/icon-arrow-desc.svg"),
|
||||
}),
|
||||
|
||||
setup(props) {
|
||||
let boxVisible = ref(false);
|
||||
let selectedItem: Ref<Item> = ref(props.itemList[props.defaultItemIndex]);
|
||||
|
||||
const computedSelectedItem = computed(() => {
|
||||
return (
|
||||
props.itemList.find((item) => item.id === selectedItem.value.id) ||
|
||||
props.itemList[props.defaultItemIndex]
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
computedSelectedItem,
|
||||
boxVisible,
|
||||
selectedItem,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
selectOption(item: Item) {
|
||||
this.selectedItem = item;
|
||||
this.boxVisible = false;
|
||||
|
||||
this.$emit("selected", item);
|
||||
},
|
||||
|
||||
toggleBox() {
|
||||
this.boxVisible = !this.boxVisible;
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
<template>
|
||||
<div class="modal">
|
||||
<div class="header">
|
||||
<span>Stacj</span>
|
||||
<img src="@/assets/trainlogo.png" alt="trainlogo" />
|
||||
<span>wnik</span>
|
||||
<sup style="font-size: 0.5em; margin-left: 10px;" class="title">1.4</sup>
|
||||
</div>
|
||||
|
||||
<div class="title">Dziennik Aktywności Scenerii dostępny w wersji beta!</div>
|
||||
|
||||
<div class="content">
|
||||
Do użytku został oddany Dziennik Aktywności Scenerii, który pozwala na dostęp do informacji kto i kiedy dyżurował na danej stacji.
|
||||
Aby przejść do zakładki z dziennikiem wystarczy wybrać opcję "DZIENNIK" w menu na górze strony. Funkcjonalność ta jest nadal w trakcie prac,
|
||||
więc informacje, które pokazuje, mogą być niepoprawne, a dane kasowane w ramach dalszych testów.
|
||||
<div style="text-align: center; font-weight: bold; margin: 0.5em 0;">Miłego korzystania!</div>
|
||||
</div>
|
||||
|
||||
<button class="button" @click="toggleUpdateModal">PRZYJĄŁEM!</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||
|
||||
@Component
|
||||
export default class UpdateModal extends Vue {
|
||||
@Prop() currentVersion!: string;
|
||||
|
||||
STORAGE_ID = "modal_update";
|
||||
|
||||
toggleUpdateModal(type: string) {
|
||||
this.$emit("toggleUpdateModal");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../styles/responsive";
|
||||
|
||||
.modal {
|
||||
z-index: 100;
|
||||
|
||||
padding: 1em;
|
||||
|
||||
border-radius: 1em;
|
||||
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
|
||||
width: 65%;
|
||||
max-width: 950px;
|
||||
|
||||
max-height: 95vh;
|
||||
overflow: auto;
|
||||
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
background: rgba(black, 0.85);
|
||||
color: white;
|
||||
|
||||
text-align: center;
|
||||
|
||||
@include smallScreen() {
|
||||
font-size: 0.8em;
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
font-size: 4.5em;
|
||||
|
||||
img {
|
||||
width: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 1.4em;
|
||||
|
||||
text-align: justify;
|
||||
|
||||
ul {
|
||||
list-style: square inside;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
font-size: 1.25em;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
@@ -7,12 +7,14 @@
|
||||
:href="stationInfo.stationURL"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>{{ stationInfo.stationName }}</a
|
||||
>
|
||||
>{{ stationInfo.stationName }}</a>
|
||||
|
||||
<span v-else>{{ stationInfo.stationName }}</span>
|
||||
</div>
|
||||
<div class="scenery-hash" v-if="stationInfo.stationHash">
|
||||
<div
|
||||
class="scenery-hash"
|
||||
v-if="stationInfo.stationHash"
|
||||
>
|
||||
#{{ stationInfo.stationHash }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -23,24 +25,36 @@
|
||||
:class="!stationInfo.stationHash ? 'no-stats' : ''"
|
||||
>
|
||||
<span class="likes">
|
||||
<img :src="likeIcon" alt="icon-like" />
|
||||
<img
|
||||
:src="likeIcon"
|
||||
alt="icon-like"
|
||||
/>
|
||||
<span>{{ stationInfo.dispatcherRate }}</span>
|
||||
</span>
|
||||
|
||||
<span class="users">
|
||||
<img :src="userIcon" alt="icon-user" />
|
||||
<img
|
||||
:src="userIcon"
|
||||
alt="icon-user"
|
||||
/>
|
||||
<span>{{ stationInfo.currentUsers }}</span>
|
||||
/
|
||||
<span>{{ stationInfo.maxUsers }}</span>
|
||||
</span>
|
||||
|
||||
<span class="spawns">
|
||||
<img :src="spawnIcon" alt="icon-spawn" />
|
||||
<img
|
||||
:src="spawnIcon"
|
||||
alt="icon-spawn"
|
||||
/>
|
||||
<span>{{ stationInfo.spawns.length }}</span>
|
||||
</span>
|
||||
|
||||
<span class="schedules">
|
||||
<img :src="timetableIcon" alt="icon-timetable" />
|
||||
<img
|
||||
:src="timetableIcon"
|
||||
alt="icon-timetable"
|
||||
/>
|
||||
<span v-if="stationInfo.scheduledTrains">
|
||||
<span style="color: #eee">{{
|
||||
stationInfo.scheduledTrains.length
|
||||
@@ -111,7 +125,10 @@
|
||||
</div>
|
||||
|
||||
<div class="info-dispatcher">
|
||||
<div class="dispatcher" v-if="stationInfo.stationHash">
|
||||
<div
|
||||
class="dispatcher"
|
||||
v-if="stationInfo.stationHash"
|
||||
>
|
||||
<span
|
||||
class="dispatcher_level"
|
||||
:style="
|
||||
@@ -129,7 +146,10 @@
|
||||
<span class="dispatcher_name">{{ stationInfo.dispatcherName }}</span>
|
||||
</div>
|
||||
|
||||
<span class="status-badge" :class="stationInfo.statusID">
|
||||
<span
|
||||
class="status-badge"
|
||||
:class="stationInfo.statusID"
|
||||
>
|
||||
{{ $t(`status.${stationInfo.statusID}`) }}
|
||||
{{
|
||||
stationInfo.statusID == "online" ? stationInfo.statusTimeString : ""
|
||||
@@ -141,7 +161,10 @@
|
||||
<div class="user-list">
|
||||
<h3 class="user-header">
|
||||
{{ $t("scenery.users") }}
|
||||
<img :src="userIcon" alt="icon-user" />
|
||||
<img
|
||||
:src="userIcon"
|
||||
alt="icon-user"
|
||||
/>
|
||||
</h3>
|
||||
|
||||
<div
|
||||
@@ -166,7 +189,10 @@
|
||||
<div class="spawn-list">
|
||||
<h3 class="spawn-header">
|
||||
{{ $t("scenery.spawns") }}
|
||||
<img :src="spawnIcon" alt="icon-spawn" />
|
||||
<img
|
||||
:src="spawnIcon"
|
||||
alt="icon-spawn"
|
||||
/>
|
||||
</h3>
|
||||
|
||||
<span
|
||||
@@ -181,7 +207,7 @@
|
||||
<span
|
||||
class="spawn none"
|
||||
v-if="!stationInfo.spawns || stationInfo.spawns.length == 0"
|
||||
>{{ $t("scenery.no-spawns") }}
|
||||
>{{ $t("scenery.no-spawns") }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -190,44 +216,56 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop } from "vue-property-decorator";
|
||||
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
|
||||
import styleMixin from "@/mixins/styleMixin";
|
||||
import { computed, defineComponent } from "@vue/runtime-core";
|
||||
|
||||
@Component
|
||||
export default class SceneryInfo extends styleMixin {
|
||||
@Prop() readonly stationInfo!: Station;
|
||||
@Prop() readonly timetableOnly!: boolean;
|
||||
export default defineComponent({
|
||||
props: {
|
||||
stationInfo: {
|
||||
type: Object as () => Station,
|
||||
},
|
||||
|
||||
likeIcon: string = require("@/assets/icon-like.svg");
|
||||
spawnIcon: string = require("@/assets/icon-spawn.svg");
|
||||
timetableIcon: string = require("@/assets/icon-timetable.svg");
|
||||
userIcon: string = require("@/assets/icon-user.svg");
|
||||
timetableOnly: Boolean,
|
||||
},
|
||||
|
||||
get computedStationTrains() {
|
||||
if (!this.stationInfo) return null;
|
||||
mixins: [styleMixin],
|
||||
|
||||
return this.stationInfo.stationTrains.map((stationTrain) => {
|
||||
const scheduledData = this.stationInfo?.scheduledTrains.find(
|
||||
(scheduledTrain) => scheduledTrain.trainNo === stationTrain.trainNo
|
||||
);
|
||||
data: () => ({
|
||||
likeIcon: require("@/assets/icon-like.svg"),
|
||||
spawnIcon: require("@/assets/icon-spawn.svg"),
|
||||
timetableIcon: require("@/assets/icon-timetable.svg"),
|
||||
userIcon: require("@/assets/icon-user.svg"),
|
||||
}),
|
||||
|
||||
return {
|
||||
...stationTrain,
|
||||
stopStatus: scheduledData?.stopStatus || "no-timetable",
|
||||
};
|
||||
setup(props) {
|
||||
const computedStationTrains = computed(() => {
|
||||
if (!props.stationInfo) return [];
|
||||
|
||||
return props.stationInfo.stationTrains.map((train) => {
|
||||
const scheduledTrainStatus = props.stationInfo?.scheduledTrains.find(
|
||||
(st) => st.trainNo === train.trainNo
|
||||
);
|
||||
|
||||
return {
|
||||
...train,
|
||||
stopStatus: scheduledTrainStatus?.stopStatus || "no-timetable",
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
navigateToTrain(trainNo: number) {
|
||||
this.$router.push({
|
||||
name: "TrainsView",
|
||||
params: { queryTrain: trainNo.toString() },
|
||||
});
|
||||
}
|
||||
}
|
||||
return { computedStationTrains };
|
||||
},
|
||||
|
||||
methods: {
|
||||
navigateToTrain(trainNo: number) {
|
||||
this.$router.push({
|
||||
name: "TrainsView",
|
||||
params: { queryTrain: trainNo.toString() },
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -25,11 +25,14 @@
|
||||
value: cp.checkpointName,
|
||||
}))
|
||||
"
|
||||
@selected="chooseOption"
|
||||
@selected="selectCheckpoint"
|
||||
></select-box>
|
||||
</div>
|
||||
|
||||
<span class="timetable-item loading" v-if="dataStatus == 0">{{
|
||||
<span
|
||||
class="timetable-item loading"
|
||||
v-if="dataStatus == 0"
|
||||
>{{
|
||||
$t("app.loading")
|
||||
}}</span>
|
||||
|
||||
@@ -48,14 +51,12 @@
|
||||
>
|
||||
<span class="timetable-general">
|
||||
<span class="general-info">
|
||||
<router-link
|
||||
:to="{
|
||||
<router-link :to="{
|
||||
name: 'TrainsView',
|
||||
params: {
|
||||
queryTrain: scheduledTrain.trainNo.toString(),
|
||||
},
|
||||
}"
|
||||
>
|
||||
}">
|
||||
<span>
|
||||
<strong>{{ scheduledTrain.category }}</strong>
|
||||
{{ scheduledTrain.trainNo }}
|
||||
@@ -68,21 +69,17 @@
|
||||
'https://td2.info.pl/profile/?u=' + scheduledTrain.driverId
|
||||
"
|
||||
target="_blank"
|
||||
>{{ scheduledTrain.driverName }}</a
|
||||
>
|
||||
>{{ scheduledTrain.driverName }}</a>
|
||||
</span>
|
||||
|
||||
<div class="info-route">
|
||||
<strong
|
||||
>{{ scheduledTrain.beginsAt }} -
|
||||
{{ scheduledTrain.terminatesAt }}</strong
|
||||
>
|
||||
<strong>{{ scheduledTrain.beginsAt }} -
|
||||
{{ scheduledTrain.terminatesAt }}</strong>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<span class="general-status">
|
||||
<span :class="scheduledTrain.stopStatus"
|
||||
>{{ $t(`timetables.${scheduledTrain.stopStatus}`) }}
|
||||
<span :class="scheduledTrain.stopStatus">{{ $t(`timetables.${scheduledTrain.stopStatus}`) }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
@@ -95,7 +92,10 @@
|
||||
v-html="$t('timetables.begins')"
|
||||
>
|
||||
</span>
|
||||
<span class="arrival-time" v-else>
|
||||
<span
|
||||
class="arrival-time"
|
||||
v-else
|
||||
>
|
||||
{{ scheduledTrain.stopInfo.arrivalTimeString }} ({{
|
||||
scheduledTrain.stopInfo.arrivalDelay
|
||||
}})
|
||||
@@ -103,7 +103,10 @@
|
||||
</span>
|
||||
|
||||
<span class="schedule-stop">
|
||||
<span class="stop-time" v-if="scheduledTrain.stopInfo.stopTime">
|
||||
<span
|
||||
class="stop-time"
|
||||
v-if="scheduledTrain.stopInfo.stopTime"
|
||||
>
|
||||
{{ scheduledTrain.stopInfo.stopTime }}
|
||||
{{ scheduledTrain.stopInfo.stopType }}
|
||||
</span>
|
||||
@@ -116,7 +119,10 @@
|
||||
v-html="$t('timetables.terminates')"
|
||||
>
|
||||
</span>
|
||||
<span class="departure-time" v-else>
|
||||
<span
|
||||
class="departure-time"
|
||||
v-else
|
||||
>
|
||||
{{ scheduledTrain.stopInfo.departureTimeString }} ({{
|
||||
scheduledTrain.stopInfo.departureDelay
|
||||
}})
|
||||
@@ -129,74 +135,96 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import ScheduledTrain from "@/scripts/interfaces/ScheduledTrain";
|
||||
import SelectBox from "../Global/SelectBox.vue";
|
||||
import { computed, defineComponent, ref } from "@vue/runtime-core";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
@Component({ components: { SelectBox } })
|
||||
export default class SceneryTimetable extends Vue {
|
||||
@Prop() readonly stationInfo!: Station;
|
||||
@Prop() readonly timetableOnly!: boolean;
|
||||
@Prop() readonly dataStatus!: number;
|
||||
export default defineComponent({
|
||||
components: { SelectBox },
|
||||
|
||||
viewIcon: string = require("@/assets/icon-view.svg");
|
||||
props: {
|
||||
stationInfo: {
|
||||
type: Object as () => Station,
|
||||
},
|
||||
timetableOnly: {
|
||||
type: Boolean,
|
||||
},
|
||||
dataStatus: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
|
||||
listOpen: boolean = false;
|
||||
selectedOption: string = "";
|
||||
data: () => ({
|
||||
viewIcon: require("@/assets/icon-view.svg"),
|
||||
listOpen: false,
|
||||
}),
|
||||
|
||||
loadSelectedOption() {
|
||||
if (!this.stationInfo) return;
|
||||
if (!this.stationInfo.checkpoints) return;
|
||||
if (this.selectedOption != "") return;
|
||||
setup(props) {
|
||||
const route = useRoute();
|
||||
const currentURL = computed(() => `${location.origin}${route.fullPath}`);
|
||||
|
||||
this.selectedOption = this.stationInfo.checkpoints[0].checkpointName;
|
||||
}
|
||||
const selectedCheckpoint = ref("");
|
||||
|
||||
const computedScheduledTrains = computed(() => {
|
||||
if (!props.stationInfo) return [];
|
||||
|
||||
let scheduledTrains = props.stationInfo.checkpoints?.find(
|
||||
(cp) => cp.checkpointName === selectedCheckpoint.value
|
||||
)?.scheduledTrains;
|
||||
|
||||
// if (props.stationInfo.checkpoints)
|
||||
// scheduledTrains = props.stationInfo.checkpoints.find(
|
||||
// (cp) => cp.checkpointName === selectedCheckpoint.value
|
||||
// )?.scheduledTrains;
|
||||
// else scheduledTrains = props.stationInfo.scheduledTrains;
|
||||
|
||||
return (
|
||||
scheduledTrains?.sort((a, b) => {
|
||||
if (a.stopStatusID > b.stopStatusID) return 1;
|
||||
else if (a.stopStatusID < b.stopStatusID) return -1;
|
||||
|
||||
if (a.stopInfo.arrivalTimestamp > b.stopInfo.arrivalTimestamp)
|
||||
return 1;
|
||||
else if (a.stopInfo.arrivalTimestamp < b.stopInfo.arrivalTimestamp)
|
||||
return -1;
|
||||
|
||||
return a.stopInfo.departureTimestamp > b.stopInfo.departureTimestamp
|
||||
? 1
|
||||
: -1;
|
||||
}) || []
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
currentURL,
|
||||
selectedCheckpoint,
|
||||
computedScheduledTrains,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadSelectedOption() {
|
||||
if (!this.stationInfo) return;
|
||||
if (!this.stationInfo.checkpoints) return;
|
||||
if (this.selectedCheckpoint != "") return;
|
||||
|
||||
this.selectedCheckpoint = this.stationInfo.checkpoints[0].checkpointName;
|
||||
},
|
||||
|
||||
selectCheckpoint(item: { id: number | string; value: string }) {
|
||||
this.selectedCheckpoint = item.value;
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.loadSelectedOption();
|
||||
}
|
||||
},
|
||||
|
||||
activated() {
|
||||
this.loadSelectedOption();
|
||||
}
|
||||
|
||||
chooseOption(item: { id: number | string; value: string }) {
|
||||
this.selectedOption = item.value;
|
||||
}
|
||||
|
||||
get currentURL() {
|
||||
return `${location.origin}${this.$route.fullPath}`;
|
||||
}
|
||||
|
||||
get computedScheduledTrains() {
|
||||
if (!this.stationInfo) return [];
|
||||
|
||||
let scheduledTrains: ScheduledTrain[] | undefined;
|
||||
|
||||
if (this.stationInfo.checkpoints)
|
||||
scheduledTrains = this.stationInfo.checkpoints.find(
|
||||
(cp) => cp.checkpointName === this.selectedOption
|
||||
)?.scheduledTrains;
|
||||
else scheduledTrains = this.stationInfo.scheduledTrains;
|
||||
|
||||
return (
|
||||
scheduledTrains?.sort((a, b) => {
|
||||
if (a.stopStatusID > b.stopStatusID) return 1;
|
||||
else if (a.stopStatusID < b.stopStatusID) return -1;
|
||||
|
||||
if (a.stopInfo.arrivalTimestamp > b.stopInfo.arrivalTimestamp) return 1;
|
||||
else if (a.stopInfo.arrivalTimestamp < b.stopInfo.arrivalTimestamp)
|
||||
return -1;
|
||||
|
||||
return a.stopInfo.departureTimestamp > b.stopInfo.departureTimestamp
|
||||
? 1
|
||||
: -1;
|
||||
}) || []
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<section class="card">
|
||||
<section
|
||||
class="card"
|
||||
v-if="showCard"
|
||||
>
|
||||
<div
|
||||
class="card-exit"
|
||||
@click="exit"
|
||||
@@ -79,13 +82,13 @@
|
||||
<div class="card-actions flex">
|
||||
<action-button
|
||||
class="outlined"
|
||||
@click.native="resetFilters"
|
||||
@click="resetFilters"
|
||||
>
|
||||
{{ $t("filters.reset") }}
|
||||
</action-button>
|
||||
<action-button
|
||||
class="outlined"
|
||||
@click.native="exit"
|
||||
@click="exit"
|
||||
>{{
|
||||
$t("filters.close")
|
||||
}}</action-button>
|
||||
@@ -94,83 +97,85 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component, Prop } from "vue-property-decorator";
|
||||
|
||||
import inputData from "@/data/options.json";
|
||||
|
||||
import StorageManager from "@/scripts/managers/storageManager";
|
||||
import { defineComponent } from "@vue/runtime-core";
|
||||
import ActionButton from "../Global/ActionButton.vue";
|
||||
|
||||
@Component({ components: { ActionButton } })
|
||||
export default class FilterCard extends Vue {
|
||||
inputs = { ...inputData };
|
||||
saveOptions: boolean = false;
|
||||
STORAGE_KEY: string = "options_saved";
|
||||
export default defineComponent({
|
||||
components: { ActionButton },
|
||||
props: ["showCard", "exit"],
|
||||
|
||||
@Prop() exit!: () => void;
|
||||
data: () => ({
|
||||
inputs: { ...inputData },
|
||||
saveOptions: false,
|
||||
STORAGE_KEY: "options_saved",
|
||||
}),
|
||||
|
||||
mounted() {
|
||||
this.saveOptions = StorageManager.isRegistered(this.STORAGE_KEY);
|
||||
}
|
||||
},
|
||||
|
||||
handleChange(e: Event): void {
|
||||
const target = <HTMLInputElement>e.target;
|
||||
methods: {
|
||||
handleChange(e: Event) {
|
||||
const target = e.target as HTMLInputElement;
|
||||
|
||||
this.$emit("changeFilterValue", {
|
||||
name: target.name,
|
||||
value: !target.checked,
|
||||
});
|
||||
this.$emit("changeFilterValue", {
|
||||
name: target.name,
|
||||
value: !target.checked,
|
||||
});
|
||||
if (this.saveOptions)
|
||||
StorageManager.setBooleanValue(target.name, target.checked);
|
||||
},
|
||||
|
||||
if (this.saveOptions)
|
||||
StorageManager.setBooleanValue(target.name, target.checked);
|
||||
}
|
||||
handleInput(e: Event) {
|
||||
const target = e.target as HTMLInputElement;
|
||||
|
||||
handleInput(e: Event): void {
|
||||
const target = <HTMLInputElement>e.target;
|
||||
this.$emit("changeFilterValue", {
|
||||
name: target.name,
|
||||
value: target.value,
|
||||
});
|
||||
this.$emit("changeFilterValue", {
|
||||
name: target.name,
|
||||
value: target.value,
|
||||
});
|
||||
if (this.saveOptions)
|
||||
StorageManager.setStringValue(target.name, target.value);
|
||||
},
|
||||
|
||||
if (this.saveOptions)
|
||||
StorageManager.setStringValue(target.name, target.value);
|
||||
}
|
||||
saveFilters() {
|
||||
if (!this.saveOptions) {
|
||||
StorageManager.unregisterStorage(this.STORAGE_KEY);
|
||||
return;
|
||||
}
|
||||
|
||||
saveFilters(): void {
|
||||
if (!this.saveOptions) {
|
||||
StorageManager.unregisterStorage(this.STORAGE_KEY);
|
||||
return;
|
||||
}
|
||||
StorageManager.registerStorage(this.STORAGE_KEY);
|
||||
|
||||
StorageManager.registerStorage(this.STORAGE_KEY);
|
||||
this.inputs.options.forEach((option) =>
|
||||
StorageManager.setBooleanValue(option.name, option.value)
|
||||
);
|
||||
|
||||
this.inputs.options.forEach((option) =>
|
||||
StorageManager.setBooleanValue(option.name, option.value)
|
||||
);
|
||||
this.inputs.sliders.forEach((slider) =>
|
||||
StorageManager.setNumericValue(slider.name, slider.value)
|
||||
);
|
||||
},
|
||||
|
||||
this.inputs.sliders.forEach((slider) =>
|
||||
StorageManager.setNumericValue(slider.name, slider.value)
|
||||
);
|
||||
}
|
||||
resetFilters() {
|
||||
this.inputs.options.forEach((option) => {
|
||||
option.value = option.defaultValue;
|
||||
StorageManager.setBooleanValue(option.name, option.value);
|
||||
});
|
||||
|
||||
resetFilters(): void {
|
||||
this.inputs.options.forEach((option) => {
|
||||
option.value = option.defaultValue;
|
||||
StorageManager.setBooleanValue(option.name, option.value);
|
||||
});
|
||||
this.inputs.sliders.forEach((slider) => {
|
||||
slider.value = slider.defaultValue;
|
||||
StorageManager.setNumericValue(slider.name, slider.value);
|
||||
});
|
||||
|
||||
this.inputs.sliders.forEach((slider) => {
|
||||
slider.value = slider.defaultValue;
|
||||
StorageManager.setNumericValue(slider.name, slider.value);
|
||||
});
|
||||
this.$emit("resetFilters");
|
||||
},
|
||||
|
||||
this.$emit("resetFilters");
|
||||
}
|
||||
|
||||
closeCard(): void {
|
||||
this.exit();
|
||||
}
|
||||
}
|
||||
closeCard() {
|
||||
this.exit();
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
<template>
|
||||
<div class="options">
|
||||
<div class="options-actions">
|
||||
<button
|
||||
class="action-btn"
|
||||
:class="{'open': filterCardOpen}"
|
||||
@click="() => toggleCardsState('filter')"
|
||||
>
|
||||
<img :src="require('@/assets/icon-filter2.svg')" alt="icon-filter" />
|
||||
<p>FILTRY</p>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="action-btn"
|
||||
:class="{'open': legendCardOpen}"
|
||||
@click="() => toggleCardsState('legend')"
|
||||
>
|
||||
<img :src="require('@/assets/icon-legend.svg')" alt="icon legend" />
|
||||
<p>LEGENDA</p>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="options-content">
|
||||
<transition name="card-anim"></transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from "vue-property-decorator";
|
||||
|
||||
@Component({})
|
||||
export default class Options extends Vue {
|
||||
filterCardOpen: boolean = false;
|
||||
legendCardOpen: boolean = false;
|
||||
|
||||
toggleCardsState(name: string): void {
|
||||
if (name == "filter") {
|
||||
this.legendCardOpen = false;
|
||||
this.filterCardOpen = !this.filterCardOpen;
|
||||
}
|
||||
|
||||
if (name == "legend") {
|
||||
this.filterCardOpen = false;
|
||||
this.legendCardOpen = !this.legendCardOpen;
|
||||
}
|
||||
}
|
||||
|
||||
toggleCardState(): void {
|
||||
this.filterCardOpen = !this.filterCardOpen;
|
||||
}
|
||||
|
||||
toggleLegendCardState(): void {
|
||||
this.legendCardOpen = !this.legendCardOpen;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../styles/variables.scss";
|
||||
@import "../../styles/responsive.scss";
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.card-anim {
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all 0.25s ease-in-out;
|
||||
}
|
||||
|
||||
&-enter,
|
||||
&-leave-to {
|
||||
transform: translate(-45%, -50%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
&-actions {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
background: #333;
|
||||
border: none;
|
||||
|
||||
color: #e0e0e0;
|
||||
font-size: 0.4em;
|
||||
|
||||
padding: 0.3em;
|
||||
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
|
||||
transition: all 0.3s;
|
||||
|
||||
img {
|
||||
width: 1.3em;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 0;
|
||||
font-size: 1em;
|
||||
overflow: hidden;
|
||||
|
||||
transition: max-width 0.35s ease-in-out;
|
||||
}
|
||||
|
||||
&:hover > p,
|
||||
&.open > p {
|
||||
max-width: 500px;
|
||||
color: $accentCol;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(#e0e0e0, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
@include smallScreen {
|
||||
.options {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -160,6 +160,7 @@
|
||||
$t('desc.signals-type') + $t(`signals.${station.signalType}`)
|
||||
"
|
||||
/>
|
||||
|
||||
<img
|
||||
v-if="station.SBL && station.SBL !== ''"
|
||||
:src="require(`@/assets/icon-SBL.svg`)"
|
||||
@@ -236,80 +237,87 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop } from "vue-property-decorator";
|
||||
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import styleMixin from "@/mixins/styleMixin";
|
||||
|
||||
import { Getter } from "vuex-class";
|
||||
|
||||
import Options from "@/components/StationsView/Options.vue";
|
||||
import { StoreData } from "@/scripts/interfaces/StoreData";
|
||||
import { DataStatus } from "@/scripts/enums/DataStatus";
|
||||
import { computed, ComputedRef, defineComponent } from "@vue/runtime-core";
|
||||
import { useStore } from "@/store";
|
||||
import { GETTERS } from "@/constants/storeConstants";
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
|
||||
@Component({
|
||||
components: { Options },
|
||||
})
|
||||
export default class StationTable extends styleMixin {
|
||||
@Prop() readonly stations!: Station[];
|
||||
@Prop() readonly sorterActive!: number;
|
||||
export default defineComponent({
|
||||
props: {
|
||||
stations: {
|
||||
type: Array as () => Station[],
|
||||
required: true,
|
||||
},
|
||||
|
||||
@Prop() readonly setFocusedStation!: () => void;
|
||||
@Prop() readonly changeSorter!: () => void;
|
||||
sorterActive: {
|
||||
type: Object as () => { id: string; dir: number },
|
||||
required: true,
|
||||
},
|
||||
|
||||
@Getter("getAllData") storeAPIData!: StoreData;
|
||||
setFocusedStation: Function,
|
||||
changeSorter: Function,
|
||||
},
|
||||
|
||||
likeIcon: string = require("@/assets/icon-like.svg");
|
||||
spawnIcon: string = require("@/assets/icon-spawn.svg");
|
||||
timetableIcon: string = require("@/assets/icon-timetable.svg");
|
||||
userIcon: string = require("@/assets/icon-user.svg");
|
||||
trainIcon: string = require("@/assets/icon-train.svg");
|
||||
mixins: [styleMixin],
|
||||
|
||||
ascIcon: string = require("@/assets/icon-arrow-asc.svg");
|
||||
descIcon: string = require("@/assets/icon-arrow-desc.svg");
|
||||
data: () => ({
|
||||
likeIcon: require("@/assets/icon-like.svg"),
|
||||
spawnIcon: require("@/assets/icon-spawn.svg"),
|
||||
timetableIcon: require("@/assets/icon-timetable.svg"),
|
||||
userIcon: require("@/assets/icon-user.svg"),
|
||||
trainIcon: require("@/assets/icon-train.svg"),
|
||||
|
||||
headIds = [
|
||||
"station",
|
||||
"min-lvl",
|
||||
"status",
|
||||
"dispatcher",
|
||||
"dispatcher-lvl",
|
||||
"routes",
|
||||
"general",
|
||||
];
|
||||
ascIcon: require("@/assets/icon-arrow-asc.svg"),
|
||||
descIcon: require("@/assets/icon-arrow-desc.svg"),
|
||||
|
||||
headIconsIds = ["user", "spawn", "timetable"];
|
||||
headIds: [
|
||||
"station",
|
||||
"min-lvl",
|
||||
"status",
|
||||
"dispatcher",
|
||||
"dispatcher-lvl",
|
||||
"routes",
|
||||
"general",
|
||||
],
|
||||
|
||||
headTitles: string[][] = [
|
||||
["Stacja"],
|
||||
["Min. poziom", "dyżurnego"],
|
||||
["Status"],
|
||||
["Dyżurny"],
|
||||
["Poziom", "dyżurnego"],
|
||||
["Szlaki", "2tor | 1tor"],
|
||||
["Informacje", "ogólne"],
|
||||
[this.userIcon, "Mechanicy online"],
|
||||
[this.spawnIcon, "Otwarte spawny"],
|
||||
[this.timetableIcon, "Aktywne RJ"],
|
||||
];
|
||||
headIconsIds: ["user", "spawn", "timetable"],
|
||||
}),
|
||||
|
||||
setScenery(name: string) {
|
||||
const station = this.stations.find(
|
||||
(station) => station.stationName === name
|
||||
setup() {
|
||||
const store = useStore();
|
||||
|
||||
const dataConnectionStatus: ComputedRef<DataStatus> = computed(
|
||||
() => store.getters[GETTERS.dataStatus]
|
||||
);
|
||||
|
||||
if (!station) return;
|
||||
const isDataLoaded = () =>
|
||||
computed(() => {
|
||||
dataConnectionStatus.value == DataStatus.Loaded;
|
||||
});
|
||||
|
||||
this.$router.push({
|
||||
name: "SceneryView",
|
||||
query: { station: station.stationName.replaceAll(" ", "_") },
|
||||
});
|
||||
}
|
||||
return {
|
||||
isDataLoaded,
|
||||
};
|
||||
},
|
||||
|
||||
get isDataLoaded() {
|
||||
return this.storeAPIData.dataConnectionStatus == DataStatus.Loaded;
|
||||
}
|
||||
}
|
||||
methods: {
|
||||
setScenery(name: string) {
|
||||
const station = this.stations.find(
|
||||
(station) => station.stationName === name
|
||||
);
|
||||
|
||||
if (!station) return;
|
||||
|
||||
this.$router.push({
|
||||
name: "SceneryView",
|
||||
query: { station: station.stationName.replaceAll(" ", "_") },
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -358,6 +366,7 @@ table {
|
||||
|
||||
padding: 0.5em;
|
||||
background-color: $primaryCol;
|
||||
white-space: pre-wrap;
|
||||
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
@@ -442,8 +451,8 @@ td.station {
|
||||
}
|
||||
|
||||
.track {
|
||||
margin: 0 0.3em;
|
||||
padding: 0.35em 0.1em;
|
||||
margin: 0 0.35em;
|
||||
padding: 0.35em;
|
||||
font-size: 1.05em;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
<template>
|
||||
<div class="station-timetable">
|
||||
<div class="timetable-wrapper">
|
||||
<div class="timetable-title title">
|
||||
<div style="font-size: 1.5em">{{ stationName.toUpperCase() }}</div>
|
||||
<div style="font-size: 0.7em">AKTYWNE ROZKŁADY JAZDY</div>
|
||||
</div>
|
||||
|
||||
<div class="timetable-content">
|
||||
<div
|
||||
class="timetable-item"
|
||||
v-for="(scheduledTrain, i) in computedScheduledTrains"
|
||||
:key="i"
|
||||
>
|
||||
<span class="timetable-general">
|
||||
<span class="general-info">
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'TrainsView',
|
||||
params: {
|
||||
passedSearchedTrain: scheduledTrain.trainNo.toString(),
|
||||
},
|
||||
}"
|
||||
>
|
||||
<span>
|
||||
<strong>{{ scheduledTrain.category }}</strong>
|
||||
{{ scheduledTrain.trainNo }}
|
||||
</span>
|
||||
</router-link>
|
||||
|
|
||||
<span>
|
||||
<a
|
||||
:href="
|
||||
'https://td2.info.pl/profile/?u=' + scheduledTrain.driverId
|
||||
"
|
||||
target="_blank"
|
||||
>{{ scheduledTrain.driverName }}</a
|
||||
>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="general-status">
|
||||
<span :class="scheduledTrain.stopStatus">{{
|
||||
scheduledTrain.stopLabel
|
||||
}}</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="timetable-schedule">
|
||||
<span class="schedule-arrival">
|
||||
<span
|
||||
class="arrival-time begins"
|
||||
v-if="scheduledTrain.stopInfo.beginsHere"
|
||||
>ROZPOCZYNA BIEG</span
|
||||
>
|
||||
<span class="arrival-time" v-else
|
||||
>{{ scheduledTrain.stopInfo.arrivalTimeString }} ({{
|
||||
scheduledTrain.stopInfo.arrivalDelay
|
||||
}})</span
|
||||
>
|
||||
</span>
|
||||
|
||||
<span class="schedule-stop">
|
||||
<span class="stop-time" v-if="scheduledTrain.stopInfo.stopTime"
|
||||
>{{ scheduledTrain.stopInfo.stopTime }}
|
||||
{{ scheduledTrain.stopInfo.stopType }}</span
|
||||
>
|
||||
<span class="stop-arrow arrow"></span>
|
||||
</span>
|
||||
<span class="schedule-departure">
|
||||
<span
|
||||
class="departure-time terminates"
|
||||
v-if="scheduledTrain.stopInfo.terminatesHere"
|
||||
>KOŃCZY BIEG</span
|
||||
>
|
||||
<span class="departure-time" v-else
|
||||
>{{ scheduledTrain.stopInfo.departureTimeString }} ({{
|
||||
scheduledTrain.stopInfo.departureDelay
|
||||
}})</span
|
||||
>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||
|
||||
@Component
|
||||
export default class StationTimetable extends Vue {
|
||||
@Prop() readonly scheduledTrains;
|
||||
@Prop() readonly stationName;
|
||||
|
||||
get computedScheduledTrains() {
|
||||
return this.scheduledTrains.sort((a, b) => {
|
||||
if (a.stopInfo.arrivalTimestamp > b.stopInfo.arrivalTimestamp) return 1;
|
||||
else if (a.stopInfo.arrivalTimestamp < b.stopInfo.arrivalTimestamp)
|
||||
return -1;
|
||||
|
||||
return a.stopInfo.departureTimestamp > b.stopInfo.departureTimestamp
|
||||
? 1
|
||||
: -1;
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../styles/variables.scss";
|
||||
@import "../../styles/responsive.scss";
|
||||
|
||||
.station-timetable {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
transform: translateY(-100%);
|
||||
-webikit-transform: translateY(-100%);
|
||||
|
||||
&.show {
|
||||
transform: translateY(0);
|
||||
-webkit-transform: translateY(0);
|
||||
}
|
||||
|
||||
transition: transform 150ms ease-out;
|
||||
|
||||
background: #333;
|
||||
|
||||
@include smallScreen() {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
}
|
||||
|
||||
.timetable {
|
||||
&-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&-title {
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 0.3rem;
|
||||
font-size: 1.6em;
|
||||
}
|
||||
|
||||
&-wrapper {
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&-item {
|
||||
margin: 1em auto;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
|
||||
|
||||
padding: 0 1rem;
|
||||
|
||||
@include smallScreen() {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.timetable {
|
||||
&-general {
|
||||
padding: 0.3rem 0.7rem;
|
||||
border: 2px solid white;
|
||||
border-radius: 10px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
@include smallScreen() {
|
||||
width: 95%;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
}
|
||||
|
||||
&-schedule {
|
||||
@include smallScreen() {
|
||||
width: 80%;
|
||||
margin: 0.7em 0;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(50px, 1fr));
|
||||
font-size: 1.35em;
|
||||
}
|
||||
}
|
||||
|
||||
.arrow {
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
display: inline-block;
|
||||
padding: 2px;
|
||||
margin-left: 50px;
|
||||
|
||||
position: relative;
|
||||
|
||||
transform: rotate(-45deg);
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 55px;
|
||||
height: 3px;
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
|
||||
transform: translate(-100%, -1px) rotate(45deg);
|
||||
transform-origin: right bottom;
|
||||
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
|
||||
.general-info {
|
||||
span {
|
||||
color: $accentCol;
|
||||
}
|
||||
}
|
||||
|
||||
.general-status {
|
||||
span.arriving {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
span.departed {
|
||||
color: lime;
|
||||
}
|
||||
|
||||
span.stopped {
|
||||
color: #ffa600;
|
||||
}
|
||||
|
||||
span.online {
|
||||
color: gold;
|
||||
}
|
||||
|
||||
span.terminated {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
.schedule {
|
||||
&-arrival,
|
||||
&-stop,
|
||||
&-departure {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
margin: 0 0.3rem;
|
||||
}
|
||||
|
||||
&-stop {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.stop-time {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.arrival-time.begins,
|
||||
.departure-time.terminates {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
</style>
|
||||
@@ -42,96 +42,98 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch, Prop, Emit } from "vue-property-decorator";
|
||||
import { computed, defineComponent } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import SelectBox from "../Global/SelectBox.vue";
|
||||
|
||||
@Component({ components: { SelectBox } })
|
||||
export default class TrainOptions extends Vue {
|
||||
// Passed as component parameters
|
||||
@Prop() readonly queryTrain!: string;
|
||||
export default defineComponent({
|
||||
components: { SelectBox },
|
||||
props: ["queryTrain"],
|
||||
emits: ["changeSearchedTrain", "changeSearchedDriver", "changeSorter"],
|
||||
|
||||
exitIcon = require("@/assets/icon-exit.svg");
|
||||
data: () => ({
|
||||
exitIcon: require("@/assets/icon-exit.svg"),
|
||||
searchedTrain: "",
|
||||
searchedDriver: "",
|
||||
}),
|
||||
|
||||
searchedTrain = "";
|
||||
searchedDriver = "";
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
|
||||
sorterOptions: { id: string; value: string }[] = [
|
||||
{
|
||||
id: "mass",
|
||||
value: "masa",
|
||||
},
|
||||
{
|
||||
id: "speed",
|
||||
value: "prędkość",
|
||||
},
|
||||
{
|
||||
id: "length",
|
||||
value: "długość",
|
||||
},
|
||||
{
|
||||
id: "distance",
|
||||
value: "kilometraż",
|
||||
},
|
||||
{
|
||||
id: "timetable",
|
||||
value: "numer pociągu",
|
||||
},
|
||||
];
|
||||
const sorterOptions = [
|
||||
{
|
||||
id: "mass",
|
||||
value: "masa",
|
||||
},
|
||||
{
|
||||
id: "speed",
|
||||
value: "prędkość",
|
||||
},
|
||||
{
|
||||
id: "length",
|
||||
value: "długość",
|
||||
},
|
||||
{
|
||||
id: "distance",
|
||||
value: "kilometraż",
|
||||
},
|
||||
{
|
||||
id: "timetable",
|
||||
value: "numer pociągu",
|
||||
},
|
||||
];
|
||||
|
||||
get translatedSorterOptions() {
|
||||
return this.sorterOptions.map((option) => ({
|
||||
id: option.id,
|
||||
value: this.$t(`trains.option-${option.id}`),
|
||||
}));
|
||||
}
|
||||
const translatedSorterOptions = computed(() =>
|
||||
sorterOptions.map(({ id }) => ({
|
||||
id,
|
||||
value: t(`trains.option-${id}`),
|
||||
}))
|
||||
);
|
||||
|
||||
return {
|
||||
translatedSorterOptions,
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.queryTrain) {
|
||||
this.searchedTrain = this.queryTrain;
|
||||
this.searchedDriver = "";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/* Emitters to TrainsView managing variables */
|
||||
methods: {
|
||||
chooseTrain(train: string) {
|
||||
this.$emit("changeSearchedTrain", train);
|
||||
},
|
||||
|
||||
@Emit("changeSearchedTrain")
|
||||
chooseTrain(train: string) {
|
||||
return train;
|
||||
}
|
||||
chooseDriver(driverName: string) {
|
||||
this.$emit("changeSearchedDriver", driverName);
|
||||
},
|
||||
|
||||
@Emit("changeSearchedDriver")
|
||||
chooseDriver(driverName: string) {
|
||||
return driverName;
|
||||
}
|
||||
changeSorter(item: { id: string | number; value: string }) {
|
||||
this.$emit("changeSorter", { id: item.id, dir: -1 });
|
||||
},
|
||||
},
|
||||
|
||||
@Emit()
|
||||
changeSorter(item: { id: string | number; value: string }) {
|
||||
return { id: item.id, dir: -1 };
|
||||
}
|
||||
watch: {
|
||||
searchedTrain(value: string) {
|
||||
this.chooseTrain(value);
|
||||
},
|
||||
|
||||
/* Watchers for search boxes */
|
||||
searchedDriver(value: string) {
|
||||
this.chooseDriver(value);
|
||||
},
|
||||
|
||||
@Watch("searchedTrain")
|
||||
watchSearchedTrain(train: string) {
|
||||
this.chooseTrain(train);
|
||||
}
|
||||
queryTrain(train: string) {
|
||||
if (!train) return;
|
||||
if (train == "") return;
|
||||
|
||||
@Watch("searchedDriver")
|
||||
watchSearchedDriver(driver: string) {
|
||||
this.chooseDriver(driver);
|
||||
}
|
||||
|
||||
/* Watcher for train no passed in link params */
|
||||
|
||||
@Watch("queryTrain")
|
||||
onQueryTrainChanged(train: string | undefined) {
|
||||
if (!train) return;
|
||||
if (train == "") return;
|
||||
|
||||
this.searchedTrain = train;
|
||||
this.searchedDriver = "";
|
||||
}
|
||||
}
|
||||
this.searchedTrain = train;
|
||||
this.searchedDriver = "";
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<div class="train-schedule" @click="click">
|
||||
<div
|
||||
class="train-schedule"
|
||||
@click="this.$emit('click')"
|
||||
>
|
||||
<div class="schedule-wrapper">
|
||||
<ul class="stop_list">
|
||||
<li
|
||||
@@ -19,11 +22,17 @@
|
||||
|
||||
<div class="stop-bar"></div>
|
||||
|
||||
<span class="distance" v-if="stop.stopDistance">
|
||||
<span
|
||||
class="distance"
|
||||
v-if="stop.stopDistance"
|
||||
>
|
||||
{{ Math.floor(stop.stopDistance) }}
|
||||
</span>
|
||||
|
||||
<span class="stop-name" v-html="stop.stopName"></span>
|
||||
<span
|
||||
class="stop-name"
|
||||
v-html="stop.stopName"
|
||||
></span>
|
||||
<span class="stop-date">
|
||||
<span
|
||||
class="date arrival"
|
||||
@@ -79,9 +88,7 @@
|
||||
<div class="progress-bar"></div>
|
||||
|
||||
<span v-if="i < followingStops.length - 1">
|
||||
<span
|
||||
v-if="stop.departureLine == followingStops[i + 1].arrivalLine"
|
||||
>
|
||||
<span v-if="stop.departureLine == followingStops[i + 1].arrivalLine">
|
||||
{{ stop.departureLine }}
|
||||
</span>
|
||||
|
||||
@@ -98,32 +105,23 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||
import { defineComponent } from "@vue/runtime-core";
|
||||
|
||||
import TrainStop from "@/scripts/interfaces/TrainStop";
|
||||
export default defineComponent({
|
||||
props: ["followingStops", "currentStationName"],
|
||||
emits: ["click"],
|
||||
|
||||
@Component
|
||||
export default class TrainSchedule extends Vue {
|
||||
@Prop() readonly followingStops!: TrainStop[];
|
||||
@Prop() readonly currentStationName!: string;
|
||||
|
||||
stylizeTime(timeString: string, delay: number, confirmed: boolean) {
|
||||
return (
|
||||
timeString +
|
||||
(delay != 0 && confirmed
|
||||
? " (" + (delay > 0 ? "+" : "") + delay.toString() + ")"
|
||||
: "")
|
||||
);
|
||||
}
|
||||
|
||||
click() {
|
||||
this.$emit("click");
|
||||
}
|
||||
|
||||
mounted() {
|
||||
console.log("mounted");
|
||||
}
|
||||
}
|
||||
methods: {
|
||||
stylizeTime(timeString: string, delay: number, confirmed: boolean) {
|
||||
return (
|
||||
timeString +
|
||||
(delay != 0 && confirmed
|
||||
? " (" + (delay > 0 ? "+" : "") + delay.toString() + ")"
|
||||
: "")
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
<template>
|
||||
<div class="train-stats">
|
||||
<div class="stats_button">
|
||||
<action-button @click.native="toggleStatsOpen">
|
||||
<img :src="statsIcon" :alt="$t('trains.stats')" />
|
||||
{{ $t("trains.stats") }}
|
||||
<action-button @click="toggleStatsOpen">
|
||||
<img
|
||||
:src="statsIcon"
|
||||
:alt="$t('trains.stats')"
|
||||
/>
|
||||
<p class="xd">{{ $t("trains.stats") }}</p>
|
||||
</action-button>
|
||||
</div>
|
||||
|
||||
<transition name="stats-anim" class="stats_wrapper" tag="div">
|
||||
<div class="stats-body" v-if="trainStatsOpen">
|
||||
<transition
|
||||
name="stats-anim"
|
||||
class="stats_wrapper"
|
||||
tag="div"
|
||||
>
|
||||
<div
|
||||
class="stats-body"
|
||||
v-if="trainStatsOpen"
|
||||
>
|
||||
<h2 class="stats-header">
|
||||
<img :src="statsIcon" :alt="$t('trains.stats')" />
|
||||
<img
|
||||
:src="statsIcon"
|
||||
:alt="$t('trains.stats')"
|
||||
/>
|
||||
{{ $t("trains.stats") }}
|
||||
</h2>
|
||||
|
||||
@@ -70,7 +83,11 @@
|
||||
<div class="title stats-title">{{ $t("trains.stats-locos") }}</div>
|
||||
|
||||
<div class="loco-list stats-content">
|
||||
<div class="loco-item" v-for="(loco, i) in locoList" :key="i">
|
||||
<div
|
||||
class="loco-item"
|
||||
v-for="(loco, i) in locoList"
|
||||
:key="i"
|
||||
>
|
||||
{{ loco[0] }} | {{ loco[1] }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,120 +98,145 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||
import ActionButton from "@/components/Global/ActionButton.vue";
|
||||
|
||||
import Train from "@/scripts/interfaces/Train";
|
||||
import { computed, defineComponent } from "@vue/runtime-core";
|
||||
|
||||
@Component({ components: { ActionButton } })
|
||||
export default class TrainStats extends Vue {
|
||||
@Prop() readonly trains!: Train[];
|
||||
trainStatsOpen = false;
|
||||
export default defineComponent({
|
||||
components: { ActionButton },
|
||||
props: {
|
||||
trains: {
|
||||
type: Array as () => Train[],
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
toggleStatsOpen() {
|
||||
this.trainStatsOpen = !this.trainStatsOpen;
|
||||
}
|
||||
data: () => ({
|
||||
trainStatsOpen: false,
|
||||
statsIcon: require("@/assets/icon-stats.svg"),
|
||||
}),
|
||||
|
||||
statsIcon = require("@/assets/icon-stats.svg");
|
||||
methods: {
|
||||
toggleStatsOpen() {
|
||||
this.trainStatsOpen = !this.trainStatsOpen;
|
||||
},
|
||||
},
|
||||
|
||||
get speedStats(): { avg: string; min: string; max: string } {
|
||||
if (this.trains.length == 0) return { avg: "0", min: "0", max: "0" };
|
||||
setup(props) {
|
||||
const speedStats = computed(() => {
|
||||
if (props.trains.length == 0) return { avg: "0", min: "0", max: "0" };
|
||||
|
||||
const avg = (
|
||||
this.trains.reduce((acc, train) => acc + train.speed, 0) /
|
||||
this.trains.length
|
||||
).toFixed(2);
|
||||
const avg = (
|
||||
props.trains.reduce((acc, train) => acc + train.speed, 0) /
|
||||
props.trains.length
|
||||
).toFixed(2);
|
||||
|
||||
const minMax = this.trains.reduce((acc, train) => {
|
||||
if (!train.timetableData) return acc;
|
||||
const minMaxSpeed = props.trains.reduce((acc, train) => {
|
||||
if (!train.timetableData) return acc;
|
||||
|
||||
acc[0] =
|
||||
acc[0] === undefined || train.speed < acc[0] ? train.speed : acc[0];
|
||||
acc[0] = !acc[0] || train.speed < acc[0] ? train.speed : acc[0];
|
||||
|
||||
acc[1] =
|
||||
acc[1] === undefined || train.speed > acc[1] ? train.speed : acc[1];
|
||||
return acc;
|
||||
}, [] as any);
|
||||
acc[1] = !acc[1] || train.speed > acc[1] ? train.speed : acc[1];
|
||||
return acc;
|
||||
}, [] as any);
|
||||
|
||||
return { avg, min: minMax[0].toString(), max: minMax[1].toString() };
|
||||
}
|
||||
return {
|
||||
avg,
|
||||
min: minMaxSpeed[0].toString(),
|
||||
max: minMaxSpeed[1].toString(),
|
||||
};
|
||||
});
|
||||
|
||||
get timetableStats(): { avg: string; min: string; max: string } {
|
||||
if (this.trains.length == 0) return { avg: "0", min: "0", max: "0" };
|
||||
const timetableStats = computed(() => {
|
||||
if (props.trains.length == 0) return { avg: "0", min: "0", max: "0" };
|
||||
|
||||
const avg = (
|
||||
this.trains.reduce(
|
||||
(acc, train) =>
|
||||
train.timetableData ? acc + train.timetableData.routeDistance : acc,
|
||||
0
|
||||
) / this.trains.length
|
||||
).toFixed(2);
|
||||
const avg = (
|
||||
props.trains.reduce(
|
||||
(acc, train) =>
|
||||
train.timetableData ? acc + train.timetableData.routeDistance : acc,
|
||||
0
|
||||
) / props.trains.length
|
||||
).toFixed(2);
|
||||
|
||||
const minMax = this.trains.reduce((acc, train) => {
|
||||
if (!train.timetableData) return acc;
|
||||
const minMaxDistance = props.trains.reduce((acc, train) => {
|
||||
if (!train.timetableData) return acc;
|
||||
|
||||
acc[0] =
|
||||
acc[0] === undefined || train.timetableData.routeDistance < acc[0]
|
||||
? train.timetableData.routeDistance
|
||||
: acc[0];
|
||||
acc[0] =
|
||||
!acc[0] || train.timetableData.routeDistance < acc[0]
|
||||
? train.timetableData.routeDistance
|
||||
: acc[0];
|
||||
|
||||
acc[1] =
|
||||
acc[1] === undefined || train.timetableData.routeDistance > acc[1]
|
||||
? train.timetableData.routeDistance
|
||||
: acc[1];
|
||||
return acc;
|
||||
}, [] as any);
|
||||
acc[1] =
|
||||
!acc[1] || train.timetableData.routeDistance > acc[1]
|
||||
? train.timetableData.routeDistance
|
||||
: acc[1];
|
||||
return acc;
|
||||
}, [] as any);
|
||||
|
||||
return { avg, min: minMax[0].toString(), max: minMax[1].toString() };
|
||||
}
|
||||
return {
|
||||
avg,
|
||||
min: minMaxDistance[0].toString(),
|
||||
max: minMaxDistance[1].toString(),
|
||||
};
|
||||
});
|
||||
|
||||
get categoryList(): Map<string, number> {
|
||||
const map = this.trains.reduce((acc, train) => {
|
||||
if (!train.timetableData || !train.timetableData.category) return acc;
|
||||
const categoryList = computed(() => {
|
||||
const map = props.trains.reduce((acc, train) => {
|
||||
if (!train.timetableData || !train.timetableData.category) return acc;
|
||||
|
||||
acc.set(
|
||||
train.timetableData.category,
|
||||
acc.get(train.timetableData.category)
|
||||
? acc.get(train.timetableData.category) + 1
|
||||
: 1
|
||||
acc.set(
|
||||
train.timetableData.category,
|
||||
acc.get(train.timetableData.category)
|
||||
? acc.get(train.timetableData.category) + 1
|
||||
: 1
|
||||
);
|
||||
|
||||
return acc;
|
||||
}, new Map());
|
||||
|
||||
return new Map([...map.entries()].sort((a, b) => b[1] - a[1]));
|
||||
});
|
||||
|
||||
const locoList = computed(() => {
|
||||
const map: Map<string, number> = props.trains.reduce((acc, train) => {
|
||||
if (!train.timetableData || !train.locoType) return acc;
|
||||
|
||||
acc.set(
|
||||
train.locoType,
|
||||
acc.get(train.locoType) ? acc.get(train.locoType) + 1 : 1
|
||||
);
|
||||
|
||||
return acc;
|
||||
}, new Map());
|
||||
|
||||
const sorted = [...map.entries()]
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.filter((v, i) => i < 3);
|
||||
|
||||
return sorted;
|
||||
});
|
||||
|
||||
const specialTrainCount = computed(() => {
|
||||
const twrList = props.trains.filter(
|
||||
(train) => train.timetableData && train.timetableData.TWR
|
||||
);
|
||||
const skrList = props.trains.filter(
|
||||
(train) => train.timetableData && train.timetableData.SKR
|
||||
);
|
||||
|
||||
return acc;
|
||||
}, new Map());
|
||||
return [twrList.length, skrList.length];
|
||||
});
|
||||
|
||||
return new Map([...map.entries()].sort((a, b) => b[1] - a[1]));
|
||||
}
|
||||
|
||||
get locoList(): any[] {
|
||||
const map = this.trains.reduce((acc, train) => {
|
||||
if (!train.timetableData || !train.locoType) return acc;
|
||||
|
||||
acc.set(
|
||||
train.locoType,
|
||||
acc.get(train.locoType) ? acc.get(train.locoType) + 1 : 1
|
||||
);
|
||||
|
||||
return acc;
|
||||
}, new Map());
|
||||
|
||||
const sorted = [...map.entries()]
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.filter((v, i) => i < 3);
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
get specialTrainCount(): [number, number] {
|
||||
const twrList = this.trains.filter(
|
||||
(train) => train.timetableData && train.timetableData.TWR
|
||||
);
|
||||
const skrList = this.trains.filter(
|
||||
(train) => train.timetableData && train.timetableData.SKR
|
||||
);
|
||||
|
||||
return [twrList.length, skrList.length];
|
||||
}
|
||||
}
|
||||
return {
|
||||
speedStats,
|
||||
timetableStats,
|
||||
categoryList,
|
||||
locoList,
|
||||
specialTrainCount,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -206,7 +248,7 @@ export default class TrainStats extends Vue {
|
||||
transition: all 150ms ease-out;
|
||||
}
|
||||
|
||||
&-enter,
|
||||
&-enter-from,
|
||||
&-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
class="train-row"
|
||||
v-for="(train, i) in computedTrains"
|
||||
:key="i"
|
||||
:ref="train.timetableData ? train.timetableData.timetableId : -1"
|
||||
:ref="train.timetableData && (el => { elList[train.timetableData.timetableId] = el })"
|
||||
>
|
||||
<div
|
||||
class="wrapper no-timetable"
|
||||
@@ -319,117 +319,163 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component, Prop, Watch } from "vue-property-decorator";
|
||||
|
||||
import Train from "@/scripts/interfaces/Train";
|
||||
import TrainStop from "@/scripts/interfaces/TrainStop";
|
||||
|
||||
import TrainSchedule from "@/components/TrainsView/TrainSchedule.vue";
|
||||
import { DataStatus } from "@/scripts/enums/DataStatus";
|
||||
import {
|
||||
computed,
|
||||
ComputedRef,
|
||||
defineComponent,
|
||||
onBeforeUpdate,
|
||||
Ref,
|
||||
ref,
|
||||
} from "@vue/runtime-core";
|
||||
import { useStore } from "@/store";
|
||||
import { GETTERS } from "@/constants/storeConstants";
|
||||
|
||||
@Component({
|
||||
components: { TrainSchedule },
|
||||
})
|
||||
export default class TrainTable extends Vue {
|
||||
@Prop() computedTrains!: Train[];
|
||||
@Prop() timetableDataStatus!: DataStatus;
|
||||
@Prop() queryTrain!: string;
|
||||
export default defineComponent({
|
||||
components: {
|
||||
TrainSchedule,
|
||||
},
|
||||
|
||||
showedSchedule = 0;
|
||||
props: {
|
||||
computedTrains: {
|
||||
type: Array as () => Train[],
|
||||
required: true,
|
||||
},
|
||||
|
||||
defaultLocoImage = require("@/assets/unknown.png");
|
||||
queryTrain: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
|
||||
ascSVG = require("@/assets/icon-arrow-asc.svg");
|
||||
descSVG = require("@/assets/icon-arrow-desc.svg");
|
||||
data: () => ({
|
||||
showedSchedule: 0,
|
||||
defaultLocoImage: require("@/assets/unknown.png"),
|
||||
|
||||
speedIcon: string = require("@/assets/icon-speed.svg");
|
||||
massIcon: string = require("@/assets/icon-mass.svg");
|
||||
lengthIcon: string = require("@/assets/icon-length.svg");
|
||||
ascSVG: require("@/assets/icon-arrow-asc.svg"),
|
||||
descSVG: require("@/assets/icon-arrow-desc.svg"),
|
||||
|
||||
distanceIcon: string = require("@/assets/icon-distance.svg");
|
||||
sceneryIcon: string = require("@/assets/icon-scenery.svg");
|
||||
signalIcon: string = require("@/assets/icon-signal.svg");
|
||||
routeIcon: string = require("@/assets/icon-route.svg");
|
||||
speedIcon: require("@/assets/icon-speed.svg"),
|
||||
massIcon: require("@/assets/icon-mass.svg"),
|
||||
lengthIcon: require("@/assets/icon-length.svg"),
|
||||
|
||||
get timetableLoaded() {
|
||||
return this.timetableDataStatus == DataStatus.Loaded;
|
||||
}
|
||||
distanceIcon: require("@/assets/icon-distance.svg"),
|
||||
sceneryIcon: require("@/assets/icon-scenery.svg"),
|
||||
signalIcon: require("@/assets/icon-signal.svg"),
|
||||
routeIcon: require("@/assets/icon-route.svg"),
|
||||
}),
|
||||
|
||||
get timetableError() {
|
||||
return this.timetableDataStatus == DataStatus.Error;
|
||||
}
|
||||
setup(props) {
|
||||
const store = useStore();
|
||||
const elList: Ref<HTMLElement[]> = ref([]);
|
||||
|
||||
get distanceLimitExceeded() {
|
||||
return (
|
||||
this.computedTrains.findIndex(
|
||||
(train) =>
|
||||
train.timetableData && train.timetableData.routeDistance > 200
|
||||
) != -1
|
||||
);
|
||||
}
|
||||
|
||||
changeScheduleShowState(elementId: number) {
|
||||
if (elementId < 0) return;
|
||||
|
||||
this.showedSchedule = this.showedSchedule == elementId ? 0 : elementId;
|
||||
|
||||
this.$nextTick(() => {
|
||||
const currentEl: HTMLElement = this.$refs[elementId][0];
|
||||
|
||||
currentEl.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "nearest",
|
||||
});
|
||||
onBeforeUpdate(() => {
|
||||
elList.value.length = 0;
|
||||
});
|
||||
}
|
||||
|
||||
@Watch("queryTrain")
|
||||
onSearchedTrainChange(trainNo: string) {
|
||||
const timetableId = this.computedTrains.find(
|
||||
(train) => train.trainNo == parseInt(trainNo)
|
||||
)?.timetableData?.timetableId;
|
||||
const timetableDataStatus: ComputedRef<DataStatus> = computed(
|
||||
() => store.getters[GETTERS.timetableDataStatus]
|
||||
);
|
||||
|
||||
if (!timetableId) return;
|
||||
const timetableLoaded = computed(
|
||||
() => timetableDataStatus.value === DataStatus.Loaded
|
||||
);
|
||||
const timetableError = computed(
|
||||
() => timetableDataStatus.value === DataStatus.Error
|
||||
);
|
||||
|
||||
this.changeScheduleShowState(timetableId);
|
||||
}
|
||||
const distanceLimitExceeded = computed(
|
||||
() =>
|
||||
props.computedTrains.findIndex(
|
||||
({ timetableData }) =>
|
||||
timetableData && timetableData.routeDistance > 200
|
||||
) != -1
|
||||
);
|
||||
|
||||
onImageError(e: Event) {
|
||||
const imageEl = e.target as HTMLImageElement;
|
||||
return {
|
||||
timetableLoaded,
|
||||
timetableError,
|
||||
distanceLimitExceeded,
|
||||
elList,
|
||||
};
|
||||
},
|
||||
|
||||
imageEl.src = this.defaultLocoImage;
|
||||
}
|
||||
methods: {
|
||||
changeScheduleShowState(timetableId: number) {
|
||||
if (timetableId < 0) return;
|
||||
|
||||
generateStopList(stops: any): string | undefined {
|
||||
if (!stops) return "";
|
||||
this.showedSchedule =
|
||||
this.showedSchedule == timetableId ? 0 : timetableId;
|
||||
|
||||
return stops
|
||||
.reduce((acc, stop: TrainStop, i) => {
|
||||
if (stop.stopType.includes("ph"))
|
||||
acc.push(
|
||||
`<strong style='color:${
|
||||
stop.confirmed ? "springgreen" : "white"
|
||||
}'>${stop.stopName}</strong>`
|
||||
);
|
||||
else if (
|
||||
i > 0 &&
|
||||
i < stops.length - 1 &&
|
||||
!stop.stopNameRAW.includes("po.") &&
|
||||
!stop.stopNameRAW.includes("SBL")
|
||||
)
|
||||
acc.push(`<span style='color:${ stop.confirmed ? "springgreen" : "lightgray" }'>${stop.stopName}</span>`);
|
||||
return acc;
|
||||
}, [])
|
||||
.join(" > ");
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
const currentEl: HTMLElement = this.elList[timetableId];
|
||||
|
||||
calculateCars(locoType: string, cars: string[]) {
|
||||
if (cars.length == 0 && locoType.includes("EN")) return "EZT";
|
||||
else if (cars.length == 0) return "LOK";
|
||||
currentEl.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "nearest",
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
return `${this.$t("trains.cars")}: <span style='color:gold'> ${cars.length}</span>`;
|
||||
}
|
||||
}
|
||||
onImageError(e: Event) {
|
||||
const imageEl = e.target as HTMLImageElement;
|
||||
|
||||
imageEl.src = this.defaultLocoImage;
|
||||
},
|
||||
|
||||
generateStopList(stops: TrainStop[]): string | undefined {
|
||||
if (!stops) return "";
|
||||
|
||||
return stops
|
||||
.reduce((acc: string[], stop: TrainStop, i: number) => {
|
||||
if (stop.stopType.includes("ph"))
|
||||
acc.push(
|
||||
`<strong style='color:${
|
||||
stop.confirmed ? "springgreen" : "white"
|
||||
}'>${stop.stopName}</strong>`
|
||||
);
|
||||
else if (
|
||||
i > 0 &&
|
||||
i < stops.length - 1 &&
|
||||
!stop.stopNameRAW.includes("po.") &&
|
||||
!stop.stopNameRAW.includes("SBL")
|
||||
)
|
||||
acc.push(
|
||||
`<span style='color:${
|
||||
stop.confirmed ? "springgreen" : "lightgray"
|
||||
}'>${stop.stopName}</span>`
|
||||
);
|
||||
return acc;
|
||||
}, [])
|
||||
.join(" > ");
|
||||
},
|
||||
|
||||
calculateCars(locoType: string, cars: string[]) {
|
||||
if (cars.length == 0 && locoType.includes("EN")) return "EZT";
|
||||
else if (cars.length == 0) return "LOK";
|
||||
|
||||
return `${this.$t("trains.cars")}: <span style='color:gold'> ${
|
||||
cars.length
|
||||
}</span>`;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
queryTrain(trainNo: string) {
|
||||
const timetableId = this.computedTrains.find(
|
||||
(train) => train.trainNo == parseInt(trainNo)
|
||||
)?.timetableData?.timetableId;
|
||||
|
||||
if (!timetableId) return;
|
||||
|
||||
this.changeScheduleShowState(timetableId);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
export const ACTIONS = {
|
||||
synchronizeData: "synchronizeData",
|
||||
fetchOnlineData: "fetchOnlineData",
|
||||
fetchTimetableData: "fetchTimetableData"
|
||||
}
|
||||
|
||||
export const MUTATIONS = {
|
||||
SET_SCENERY_DATA: "SET_SCENERY_DATA",
|
||||
SET_SCENERY_DATA_STATUS: "SET_SCENERY_DATA_STATUS",
|
||||
SET_DATA_CONNECTION_STATUS: "SET_DATA_CONNECTION_STATUS",
|
||||
UPDATE_STATIONS: "UPDATE_STATIONS",
|
||||
UPDATE_TRAINS: "UPDATE_TRAINS",
|
||||
UPDATE_TIMETABLES: "UPDATE_TIMETABLES"
|
||||
}
|
||||
|
||||
export const GETTERS = {
|
||||
stationList: "stationList",
|
||||
trainList: "trainList",
|
||||
allData: "allData",
|
||||
timetableDataStatus: "timetableDataStatus",
|
||||
sceneryDataStatus: "sceneryDataStatus",
|
||||
dataStatus: "dataStatus"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"success":true,"respCode":10,"message":[{"dispatcherId":13983,"dispatcherName":"Don350","dispatcherIsSupporter":true,"stationName":"Hetmanice","stationHash":"f7389af5","region":"eu","maxUsers":8,"currentUsers":0,"spawn":1,"lastSeen":1606776450625,"dispatcherExp":14,"nameFromHeader":"Hetmanice","spawnString":"He_Tm1,1,550,True,False,False,ALL","networkConnectionString":"2020.1.1Stable004","isOnline":1,"dispatcherRate":22},{"dispatcherId":22620,"dispatcherName":"Calleman","dispatcherIsSupporter":true,"stationName":"Wielichowo","stationHash":"e4f61c89","region":"ru","maxUsers":29,"currentUsers":1,"spawn":0,"lastSeen":1606776448323,"dispatcherExp":11,"nameFromHeader":"Wielichowo","spawnString":null,"networkConnectionString":"2020.1.1Stable004","isOnline":1,"dispatcherRate":0},{"dispatcherId":10048,"dispatcherName":"Sprytny_Zbys","dispatcherIsSupporter":false,"stationName":"Piaskowo","stationHash":"74a6c5ba","region":"eu","maxUsers":29,"currentUsers":0,"spawn":1,"lastSeen":1606776447873,"dispatcherExp":11,"nameFromHeader":"Piaskowo","spawnString":"Ps_G3,1,650,True,False,False,ALL;Ps_G4,1,650,True,False,False,ALL;Ps_N,-1,185,True,False,False,PAS","networkConnectionString":"2020.1.1Stable004","isOnline":1,"dispatcherRate":23},{"dispatcherId":4310,"dispatcherName":"jedrek386","dispatcherIsSupporter":true,"stationName":"Niedoradz","stationHash":"2a7a048e","region":"eu","maxUsers":7,"currentUsers":0,"spawn":1,"lastSeen":1606776454351,"dispatcherExp":1,"nameFromHeader":"Niedoradz","spawnString":"Ne_H,1,200,True,False,False,H","networkConnectionString":"2020.1.1Stable004","isOnline":1,"dispatcherRate":2},{"dispatcherId":10048,"dispatcherName":"Sprytny_Zbys","dispatcherIsSupporter":false,"stationName":"LCS Skrzynki","stationHash":"c9d5dc18","region":"eu","maxUsers":10,"currentUsers":1,"spawn":0,"lastSeen":1606776460199,"dispatcherExp":11,"nameFromHeader":"LCS Skrzynki","spawnString":null,"networkConnectionString":"2020.1.1Stable004","isOnline":1,"dispatcherRate":0},{"dispatcherId":6975,"dispatcherName":"ziolek","dispatcherIsSupporter":false,"stationName":"Kcynia","stationHash":"64f1a3ba","region":"ru","maxUsers":9,"currentUsers":0,"spawn":0,"lastSeen":1606775846330,"dispatcherExp":4,"nameFromHeader":"Kcynia","spawnString":null,"networkConnectionString":"2020.1.1Stable004","isOnline":0,"dispatcherRate":0},{"dispatcherId":7240,"dispatcherName":"ASkier","dispatcherIsSupporter":false,"stationName":"Głębce","stationHash":"3f7e4639","region":"ru","maxUsers":4,"currentUsers":0,"spawn":0,"lastSeen":1606775877861,"dispatcherExp":1,"nameFromHeader":"Głębce","spawnString":null,"networkConnectionString":"2020.1.1Stable004","isOnline":0,"dispatcherRate":0},{"dispatcherId":16658,"dispatcherName":"NIEMIEC141","dispatcherIsSupporter":false,"stationName":"Buk 2018","stationHash":"4c831fc3","region":"eu","maxUsers":4,"currentUsers":0,"spawn":0,"lastSeen":1606775836686,"dispatcherExp":7,"nameFromHeader":"Buk 2018","spawnString":"NO_SPAWN","networkConnectionString":"2020.1.1Stable004","isOnline":0,"dispatcherRate":0},{"dispatcherId":6975,"dispatcherName":"ziolek","dispatcherIsSupporter":false,"stationName":"Kolsko","stationHash":"687dcf5b","region":"ru","maxUsers":6,"currentUsers":0,"spawn":0,"lastSeen":1606776448954,"dispatcherExp":4,"nameFromHeader":"Kolsko","spawnString":null,"networkConnectionString":"2020.1.1Stable004","isOnline":1,"dispatcherRate":0},{"dispatcherId":7240,"dispatcherName":"ASkier","dispatcherIsSupporter":false,"stationName":"Karszynek","stationHash":"c0e19184","region":"ru","maxUsers":5,"currentUsers":0,"spawn":0,"lastSeen":1606776456733,"dispatcherExp":1,"nameFromHeader":"Karszynek","spawnString":null,"networkConnectionString":"2020.1.1Stable004","isOnline":1,"dispatcherRate":0},{"dispatcherId":3619,"dispatcherName":"SzybkiWiewiór","dispatcherIsSupporter":false,"stationName":"Knot","stationHash":"cbaad885","region":"ru","maxUsers":14,"currentUsers":1,"spawn":0,"lastSeen":1606776460872,"dispatcherExp":7,"nameFromHeader":"Knot","spawnString":null,"networkConnectionString":"2020.1.1Stable004","isOnline":1,"dispatcherRate":0},{"dispatcherId":16658,"dispatcherName":"NIEMIEC141","dispatcherIsSupporter":false,"stationName":"Parzęczewo","stationHash":"325b1a74","region":"eu","maxUsers":29,"currentUsers":0,"spawn":1,"lastSeen":1606776392453,"dispatcherExp":7,"nameFromHeader":"Parzęczewo","spawnString":"LUZ1,-1,50,True,False,True,;LUZ2,-1,50,True,False,True,;POSP1,-1,200,True,False,False,;POSP2,-1,300,True,False,False,;POSP3,-1,200,True,False,False,;Pr_P20,1,200,True,True,False,;Pr_T28,1,750,True,False,False,;Pr_T34,1,750,True,False,False,;Pr_U38,-1,750,True,False,False,","networkConnectionString":"2020.1.1Stable004","isOnline":1,"dispatcherRate":0}]}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import { createI18n, LocaleMessages, VueMessageType } from 'vue-i18n'
|
||||
|
||||
/**
|
||||
* Load locale messages
|
||||
*
|
||||
* The loaded `JSON` locale messages is pre-compiled by `@intlify/vue-i18n-loader`, which is integrated into `vue-cli-plugin-i18n`.
|
||||
* See: https://github.com/intlify/vue-i18n-loader#rocket-i18n-resource-pre-compilation
|
||||
*/
|
||||
function loadLocaleMessages(): LocaleMessages<VueMessageType> {
|
||||
const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i)
|
||||
const messages: LocaleMessages<VueMessageType> = {}
|
||||
locales.keys().forEach(key => {
|
||||
const matched = key.match(/([A-Za-z0-9-_]+)\./i)
|
||||
if (matched && matched.length > 1) {
|
||||
const locale = matched[1]
|
||||
messages[locale] = locales(key)
|
||||
}
|
||||
})
|
||||
return messages
|
||||
}
|
||||
|
||||
export default createI18n({
|
||||
legacy: false,
|
||||
locale: process.env.VUE_APP_I18N_LOCALE || 'en',
|
||||
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en',
|
||||
messages: loadLocaleMessages()
|
||||
})
|
||||
@@ -1,142 +1,142 @@
|
||||
{
|
||||
"app": {
|
||||
"sceneries": "SCENERIES",
|
||||
"trains": "TRAINS",
|
||||
"journal": "JOURNAL",
|
||||
"loading": "Loading data...",
|
||||
"support": "Support the project"
|
||||
},
|
||||
"desc": {
|
||||
"control-type": "Control type: ",
|
||||
"signals-type": "Signals type: ",
|
||||
"SBL": "This scenery has automatic line blockade system on following routes: ",
|
||||
"default": "This scenery is available by default",
|
||||
"non-public": "This scenery is not public",
|
||||
"unavailable": "This scenery is unavailable",
|
||||
"real": "This scenery is real"
|
||||
},
|
||||
"signals": {
|
||||
"współczesna": "modern",
|
||||
"mieszana": "mixed",
|
||||
"kształtowa": "mechanical",
|
||||
"historyczna": "historyczna"
|
||||
},
|
||||
"controls": {
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SCS-SPK": "SCS/SPK",
|
||||
"SPE": "SPE",
|
||||
"ręczne": "manual",
|
||||
"ręczne+SPK": "manual + SPK",
|
||||
"ręczne+SCS": "manual + SCS",
|
||||
"mechaniczne": "levers (mechanical)",
|
||||
"mechaniczne+SPK": "levers + SPK",
|
||||
"mechaniczne+SCS": "levers + SCS"
|
||||
},
|
||||
"status": {
|
||||
"online": "UNTIL ",
|
||||
"free": "FREE",
|
||||
"ending": "ENDS SOON",
|
||||
"not-signed": "NOT SIGNED IN",
|
||||
"no-limit": "NO LIMIT",
|
||||
"unavailable": "UNAVAILABLE",
|
||||
"brb": "AFK",
|
||||
"no-space": "NO SPACE"
|
||||
},
|
||||
"options": {
|
||||
"filters": "FILTERS",
|
||||
"donate": "DONATE"
|
||||
},
|
||||
"filters": {
|
||||
"title": "STATION FILTER",
|
||||
"default": "DEFAULT",
|
||||
"not-default": "OTHER",
|
||||
"real": "REAL",
|
||||
"fictional": "FICTIONAL",
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SPE": "SPE",
|
||||
"manual": "MANUAL",
|
||||
"mechanical": "MECHANICAL",
|
||||
"modern": "MODERN",
|
||||
"semaphores": "SEMAPHORES",
|
||||
"mixed": "MIXED",
|
||||
"historical": "HISTORICAL",
|
||||
"free": "FREE",
|
||||
"occupied": "OCCUPIED",
|
||||
"sliders": {
|
||||
"min-lvl": "MIN. REQUIRED DISPATCHER LEVEL",
|
||||
"max-lvl": "MAX. REQUIRED DISPATCHER LEVEL",
|
||||
"routes-1t-cat": "MIN. CATENARY SINGLE TRACK ROUTES",
|
||||
"routes-1t-other": "MIN. OTHER SINGLE TRACK ROUTES",
|
||||
"routes-2t-cat": "MIN. CATENARY DOUBLE TRACK ROUTES",
|
||||
"routes-2t-other": "MIN. OTHER DOUBLE TRACK ROUTES"
|
||||
},
|
||||
"save": "SAVE FILTERS",
|
||||
"reset": "RESET FILTERS",
|
||||
"close": "CLOSE FILTERS"
|
||||
},
|
||||
"sceneries": {
|
||||
"station": "Station",
|
||||
"min-lvl": "Min. dispatcher <br> level",
|
||||
"status": "Status",
|
||||
"dispatcher": "Dispatcher",
|
||||
"dispatcher-lvl": "Dispatcher <br> level",
|
||||
"routes": "Routes <br> double | single",
|
||||
"general": "General info",
|
||||
"users": "Drivers online",
|
||||
"spawns": "Spawns online",
|
||||
"timetables": "Active timetables",
|
||||
"no-stations": "No stations to show here!"
|
||||
},
|
||||
"trains": {
|
||||
"no-trains": "Oops! No trains online!",
|
||||
"loading": "Loading train data...",
|
||||
"stats": "TRAFFIC STATISTICS",
|
||||
"stats-speed": "TRAINS SPEED (MIN | AVG | MAX) [km/h]",
|
||||
"stats-length": "TIMETABLES LENGTH (MIN | AVG | MAX) [km]",
|
||||
"stats-categories": "TIMETABLE CATEGORIES",
|
||||
"stats-special-twr": "HIGH RISK",
|
||||
"stats-special-skr": "EXCEEDED STRUCT. GAUGE",
|
||||
"stats-locos": "MOST COMMON UNITS",
|
||||
"option-mass": "mass",
|
||||
"option-speed": "speed",
|
||||
"option-length": "length",
|
||||
"option-distance": "distance",
|
||||
"option-timetable": "train no.",
|
||||
"search-no": "Search for train no...",
|
||||
"search-driver": "Search for driver...",
|
||||
"detailed-timetable": "Detailed timetable for train no. ",
|
||||
"via-title": "Via: ",
|
||||
"no-timetable": "no current timetable",
|
||||
"distance-exceeded": "Attention! Due to an internal error, timetables with route distance greater than 200km might be incorrect!",
|
||||
"cars": "Cars"
|
||||
},
|
||||
"journal": {
|
||||
"title": "SCENERY ACTIVITY JOURNAL",
|
||||
"subtitle": "Shows all recent dispatchers on a selected scenery",
|
||||
"disclaimer": "<b>This functionality is unfinished!</b> <br> Information shown here could be false or incorrect!",
|
||||
"select": "Select a scenery"
|
||||
},
|
||||
"scenery": {
|
||||
"users": "PLAYERS ONLINE",
|
||||
"spawns": "OPEN SPAWNS",
|
||||
"timetables": "ACTIVE TIMETABLES",
|
||||
"no-timetables": "No active timetables!",
|
||||
"no-users": "NO ACTIVE PLAYERS",
|
||||
"no-spawns": "NO OPEN SPAWNS",
|
||||
"no-scenery": "Oops! This scenery doesn't exist!",
|
||||
"return-btn": "Return to main site"
|
||||
},
|
||||
"timetables": {
|
||||
"timetable-only": "Switch to timetable-only view",
|
||||
"online": "At station",
|
||||
"departed": "Dispatched",
|
||||
"departed-away": "Departed",
|
||||
"arriving": "En route",
|
||||
"stopped": "Stopped",
|
||||
"terminated": "Terminated",
|
||||
"begins": "BEGINS HERE",
|
||||
"terminates": "TERMINATES <br /> HERE"
|
||||
}
|
||||
}
|
||||
{
|
||||
"app": {
|
||||
"sceneries": "SCENERIES",
|
||||
"trains": "TRAINS",
|
||||
"journal": "JOURNAL",
|
||||
"loading": "Loading data...",
|
||||
"support": "Support the project"
|
||||
},
|
||||
"desc": {
|
||||
"control-type": "Control type: ",
|
||||
"signals-type": "Signals type: ",
|
||||
"SBL": "This scenery has automatic line blockade system on following routes: ",
|
||||
"default": "This scenery is available by default",
|
||||
"non-public": "This scenery is not public",
|
||||
"unavailable": "This scenery is unavailable",
|
||||
"real": "This scenery is real"
|
||||
},
|
||||
"signals": {
|
||||
"współczesna": "modern",
|
||||
"mieszana": "mixed",
|
||||
"kształtowa": "mechanical",
|
||||
"historyczna": "historyczna"
|
||||
},
|
||||
"controls": {
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SCS-SPK": "SCS/SPK",
|
||||
"SPE": "SPE",
|
||||
"ręczne": "manual",
|
||||
"ręczne+SPK": "manual + SPK",
|
||||
"ręczne+SCS": "manual + SCS",
|
||||
"mechaniczne": "levers (mechanical)",
|
||||
"mechaniczne+SPK": "levers + SPK",
|
||||
"mechaniczne+SCS": "levers + SCS"
|
||||
},
|
||||
"status": {
|
||||
"online": "UNTIL ",
|
||||
"free": "FREE",
|
||||
"ending": "ENDS SOON",
|
||||
"not-signed": "NOT SIGNED IN",
|
||||
"no-limit": "NO LIMIT",
|
||||
"unavailable": "UNAVAILABLE",
|
||||
"brb": "AFK",
|
||||
"no-space": "NO SPACE"
|
||||
},
|
||||
"options": {
|
||||
"filters": "FILTERS",
|
||||
"donate": "DONATE"
|
||||
},
|
||||
"filters": {
|
||||
"title": "STATION FILTER",
|
||||
"default": "DEFAULT",
|
||||
"not-default": "OTHER",
|
||||
"real": "REAL",
|
||||
"fictional": "FICTIONAL",
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SPE": "SPE",
|
||||
"manual": "MANUAL",
|
||||
"mechanical": "MECHANICAL",
|
||||
"modern": "MODERN",
|
||||
"semaphores": "SEMAPHORES",
|
||||
"mixed": "MIXED",
|
||||
"historical": "HISTORICAL",
|
||||
"free": "FREE",
|
||||
"occupied": "OCCUPIED",
|
||||
"sliders": {
|
||||
"min-lvl": "MIN. REQUIRED DISPATCHER LEVEL",
|
||||
"max-lvl": "MAX. REQUIRED DISPATCHER LEVEL",
|
||||
"routes-1t-cat": "MIN. CATENARY SINGLE TRACK ROUTES",
|
||||
"routes-1t-other": "MIN. OTHER SINGLE TRACK ROUTES",
|
||||
"routes-2t-cat": "MIN. CATENARY DOUBLE TRACK ROUTES",
|
||||
"routes-2t-other": "MIN. OTHER DOUBLE TRACK ROUTES"
|
||||
},
|
||||
"save": "SAVE FILTERS",
|
||||
"reset": "RESET FILTERS",
|
||||
"close": "CLOSE FILTERS"
|
||||
},
|
||||
"sceneries": {
|
||||
"station": "Station",
|
||||
"min-lvl": "Min. dispatcher\nlevel",
|
||||
"status": "Status",
|
||||
"dispatcher": "Dispatcher",
|
||||
"dispatcher-lvl": "Dispatcher\nlevel",
|
||||
"routes": "Routes\ndouble / single",
|
||||
"general": "General info",
|
||||
"users": "Drivers online",
|
||||
"spawns": "Spawns online",
|
||||
"timetables": "Active timetables",
|
||||
"no-stations": "No stations to show here!"
|
||||
},
|
||||
"trains": {
|
||||
"no-trains": "Oops! No trains online!",
|
||||
"loading": "Loading train data...",
|
||||
"stats": "TRAFFIC STATISTICS",
|
||||
"stats-speed": "TRAINS SPEED (MIN, AVG, MAX) [km/h]",
|
||||
"stats-length": "TIMETABLES LENGTH (MIN, AVG, MAX) [km]",
|
||||
"stats-categories": "TIMETABLE CATEGORIES",
|
||||
"stats-special-twr": "HIGH RISK",
|
||||
"stats-special-skr": "EXCEEDED STRUCT. GAUGE",
|
||||
"stats-locos": "MOST COMMON UNITS",
|
||||
"option-mass": "mass",
|
||||
"option-speed": "speed",
|
||||
"option-length": "length",
|
||||
"option-distance": "distance",
|
||||
"option-timetable": "train no.",
|
||||
"search-no": "Search for train no...",
|
||||
"search-driver": "Search for driver...",
|
||||
"detailed-timetable": "Detailed timetable for train no. ",
|
||||
"via-title": "Via: ",
|
||||
"no-timetable": "no current timetable",
|
||||
"distance-exceeded": "Attention! Due to an internal error, timetables with route distance greater than 200km might be incorrect!",
|
||||
"cars": "Cars"
|
||||
},
|
||||
"journal": {
|
||||
"title": "SCENERY ACTIVITY JOURNAL",
|
||||
"subtitle": "Shows all recent dispatchers on a selected scenery",
|
||||
"disclaimer": "<b>This functionality is unfinished!</b> \n Information shown here could be false or incorrect!",
|
||||
"select": "Select a scenery"
|
||||
},
|
||||
"scenery": {
|
||||
"users": "PLAYERS ONLINE",
|
||||
"spawns": "OPEN SPAWNS",
|
||||
"timetables": "ACTIVE TIMETABLES",
|
||||
"no-timetables": "No active timetables!",
|
||||
"no-users": "NO ACTIVE PLAYERS",
|
||||
"no-spawns": "NO OPEN SPAWNS",
|
||||
"no-scenery": "Oops! This scenery doesn't exist!",
|
||||
"return-btn": "Return to main site"
|
||||
},
|
||||
"timetables": {
|
||||
"timetable-only": "Switch to timetable-only view",
|
||||
"online": "At station",
|
||||
"departed": "Dispatched",
|
||||
"departed-away": "Departed",
|
||||
"arriving": "En route",
|
||||
"stopped": "Stopped",
|
||||
"terminated": "Terminated",
|
||||
"begins": "BEGINS HERE",
|
||||
"terminates": "TERMINATES\nHERE"
|
||||
}
|
||||
}
|
||||
@@ -1,142 +1,142 @@
|
||||
{
|
||||
"app": {
|
||||
"sceneries": "SCENERIE",
|
||||
"trains": "POCIĄGI",
|
||||
"journal": "DZIENNIK",
|
||||
"loading": "Pobieranie danych...",
|
||||
"support": "Wspomóż projekt"
|
||||
},
|
||||
"desc": {
|
||||
"control-type": "Sterowanie: ",
|
||||
"signals-type": "Sygnalizacja: ",
|
||||
"SBL": "Sceneria posiada SBL na szlakach: ",
|
||||
"default": "Sceneria dostępna domyślnie w paczce z grą",
|
||||
"non-public": "Sceneria niepubliczna",
|
||||
"unavailable": "Sceneria niedostępna",
|
||||
"real": "Sceneria realna"
|
||||
},
|
||||
"signals": {
|
||||
"współczesna": "współczesna",
|
||||
"mieszana": "mieszana",
|
||||
"kształtowa": "kształtowa",
|
||||
"historyczna": "historyczna"
|
||||
},
|
||||
"controls": {
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SCS-SPK": "SCS/SPK",
|
||||
"SPE": "SPE",
|
||||
"ręczne": "ręczne",
|
||||
"ręczne+SPK": "ręczne + SPK",
|
||||
"ręczne+SCS": "ręczne + SCS",
|
||||
"mechaniczne": "mechaniczne",
|
||||
"mechaniczne+SPK": "mechaniczne + SPK",
|
||||
"mechaniczne+SCS": "mechaniczne + SCS"
|
||||
},
|
||||
"status": {
|
||||
"online": "DO ",
|
||||
"free": "WOLNA",
|
||||
"ending": "KOŃCZY",
|
||||
"not-signed": "NIEZALOGOWANY",
|
||||
"no-limit": "BEZ LIMITU",
|
||||
"unavailable": "NIEDOSTĘPNY",
|
||||
"brb": "Z/W",
|
||||
"no-space": "BRAK MIEJSCA"
|
||||
},
|
||||
"options": {
|
||||
"filters": "FILTRY",
|
||||
"donate": "WESPRZYJ"
|
||||
},
|
||||
"filters": {
|
||||
"title": "FILTRUJ STACJE",
|
||||
"default": "DOMYŚLNA",
|
||||
"not-default": "POZA PACZKĄ",
|
||||
"real": "REALNA",
|
||||
"fictional": "FIKCYJNA",
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SPE": "SPE",
|
||||
"manual": "RĘCZNE",
|
||||
"mechanical": "MECHANICZNE",
|
||||
"modern": "WSPÓŁCZESNA",
|
||||
"semaphores": "KSZTAŁTOWA",
|
||||
"mixed": "MIESZANA",
|
||||
"historical": "HISTORYCZNA",
|
||||
"free": "WOLNA",
|
||||
"occupied": "ZAJĘTA",
|
||||
"sliders": {
|
||||
"min-lvl": "MIN. WYMAGANY POZIOM DYŻURNEGO",
|
||||
"max-lvl": "MAKS. WYMAGANY POZIOM DYŻURNEGO",
|
||||
"routes-1t-cat": "SZLAKI JEDNOTOROWE ZELEKTR. (MINIMUM)",
|
||||
"routes-1t-other": "SZLAKI JEDNOTOROWE NIEZELEKTR. (MINIMUM)",
|
||||
"routes-2t-cat": "SZLAKI DWUTOROWE ZELEKTR. (MINIMUM)",
|
||||
"routes-2t-other": "SZLAKI DWUTOROWE NIEZELEKTR. (MINIMUM)"
|
||||
},
|
||||
"save": "ZAPISZ FILTRY",
|
||||
"reset": "RESETUJ FILTRY",
|
||||
"close": "ZAMKNIJ FILTRY"
|
||||
},
|
||||
"sceneries": {
|
||||
"station": "Stacja",
|
||||
"min-lvl": "Min. poziom <br/> dyżurnego",
|
||||
"status": "Status",
|
||||
"dispatcher": "Dyżurny",
|
||||
"dispatcher-lvl": "Poziom <br> dyżurnego",
|
||||
"routes": "Szlaki <br> 2tor | 1tor",
|
||||
"general": "Informacje <br> ogólne",
|
||||
"users": "Maszyniści online",
|
||||
"spawns": "Otwarte spawny",
|
||||
"timetables": "Aktywne rozkłady jazdy",
|
||||
"no-stations": "Brak stacji do wyświetlenia!"
|
||||
},
|
||||
"trains": {
|
||||
"no-trains": "Brak pociągów online!",
|
||||
"loading": "Pobieranie danych o pociągach...",
|
||||
"stats": "STATYSTYKI RUCHU",
|
||||
"stats-speed": "PRĘDKOŚCI POCIĄGÓW (MIN | ŚR | MAX) [km/h]",
|
||||
"stats-length": "DŁUGOŚCI ROZKŁADÓW (MIN | ŚR | MAX) [km]",
|
||||
"stats-categories": "KATEGORIE RJ",
|
||||
"stats-special-twr": "WYSOKIEGO RYZYKA",
|
||||
"stats-special-skr": "PRZEKROCZONA SKRAJNIA",
|
||||
"stats-locos": "NAJCZĘSTSZE JEDNOSTKI",
|
||||
"option-mass": "masa",
|
||||
"option-speed": "prędkość",
|
||||
"option-length": "długość",
|
||||
"option-distance": "kilometraż",
|
||||
"option-timetable": "numer pociągu",
|
||||
"search-no": "Szukaj nr pociągu...",
|
||||
"search-driver": "Szukaj maszynisty...",
|
||||
"detailed-timetable": "Szczegółowy rozkład jazdy pociągu ",
|
||||
"via-title": "Przez: ",
|
||||
"no-timetable": "brak rozkładu jazdy",
|
||||
"distance-exceeded": "Uwaga! Z powodu wewnętrznego błędu serwera TD2, rozkłady jazdy o kilometrażu powyżej 200km mogą być niepoprawne!",
|
||||
"cars": "Wagony"
|
||||
},
|
||||
"journal": {
|
||||
"title": "DZIENNIK AKTYWNOŚCI SCENERII",
|
||||
"subtitle": "Pokazuje dyżurnych, którzy ostatnio byli aktywni na wybranej scenerii",
|
||||
"disclaimer": "<b>Ta funkcjonalność jest w testach beta!</b> <br> Informacje pokazywane na ekranie mogą znikać, a ich zawartość może być fałszywa!",
|
||||
"select": "Wybierz scenerię"
|
||||
},
|
||||
"scenery": {
|
||||
"users": "GRACZE ONLINE",
|
||||
"spawns": "OTWARTE SPAWNY",
|
||||
"timetables": "AKTYWNE ROZKŁADY JAZDY",
|
||||
"no-timetables": "Brak aktywnych rozkładów!",
|
||||
"no-users": "BRAK AKTYWNYCH GRACZY",
|
||||
"no-spawns": "BRAK OTWARTYCH SPAWNÓW",
|
||||
"no-scenery": "Ups! Ta sceneria nie istnieje!",
|
||||
"return-btn": "Wróć na stronę główną"
|
||||
},
|
||||
"timetables": {
|
||||
"timetable-only": "Wyodrębnij rozkłady jazdy",
|
||||
"online": "Na stacji",
|
||||
"departed": "Odprawiony",
|
||||
"departed-away": "Odjechał",
|
||||
"arriving": "W drodze",
|
||||
"stopped": "Postój",
|
||||
"terminated": "Skończył bieg",
|
||||
"begins": "ROZPOCZYNA <br /> BIEG",
|
||||
"terminates": "KOŃCZY BIEG"
|
||||
}
|
||||
}
|
||||
{
|
||||
"app": {
|
||||
"sceneries": "SCENERIE",
|
||||
"trains": "POCIĄGI",
|
||||
"journal": "DZIENNIK",
|
||||
"loading": "Pobieranie danych...",
|
||||
"support": "Wspomóż projekt"
|
||||
},
|
||||
"desc": {
|
||||
"control-type": "Sterowanie: ",
|
||||
"signals-type": "Sygnalizacja: ",
|
||||
"SBL": "Sceneria posiada SBL na szlakach: ",
|
||||
"default": "Sceneria dostępna domyślnie w paczce z grą",
|
||||
"non-public": "Sceneria niepubliczna",
|
||||
"unavailable": "Sceneria niedostępna",
|
||||
"real": "Sceneria realna"
|
||||
},
|
||||
"signals": {
|
||||
"współczesna": "współczesna",
|
||||
"mieszana": "mieszana",
|
||||
"kształtowa": "kształtowa",
|
||||
"historyczna": "historyczna"
|
||||
},
|
||||
"controls": {
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SCS-SPK": "SCS/SPK",
|
||||
"SPE": "SPE",
|
||||
"ręczne": "ręczne",
|
||||
"ręczne+SPK": "ręczne + SPK",
|
||||
"ręczne+SCS": "ręczne + SCS",
|
||||
"mechaniczne": "mechaniczne",
|
||||
"mechaniczne+SPK": "mechaniczne + SPK",
|
||||
"mechaniczne+SCS": "mechaniczne + SCS"
|
||||
},
|
||||
"status": {
|
||||
"online": "DO ",
|
||||
"free": "WOLNA",
|
||||
"ending": "KOŃCZY",
|
||||
"not-signed": "NIEZALOGOWANY",
|
||||
"no-limit": "BEZ LIMITU",
|
||||
"unavailable": "NIEDOSTĘPNY",
|
||||
"brb": "Z/W",
|
||||
"no-space": "BRAK MIEJSCA"
|
||||
},
|
||||
"options": {
|
||||
"filters": "FILTRY",
|
||||
"donate": "WESPRZYJ"
|
||||
},
|
||||
"filters": {
|
||||
"title": "FILTRUJ STACJE",
|
||||
"default": "DOMYŚLNA",
|
||||
"not-default": "POZA PACZKĄ",
|
||||
"real": "REALNA",
|
||||
"fictional": "FIKCYJNA",
|
||||
"SPK": "SPK",
|
||||
"SCS": "SCS",
|
||||
"SPE": "SPE",
|
||||
"manual": "RĘCZNE",
|
||||
"mechanical": "MECHANICZNE",
|
||||
"modern": "WSPÓŁCZESNA",
|
||||
"semaphores": "KSZTAŁTOWA",
|
||||
"mixed": "MIESZANA",
|
||||
"historical": "HISTORYCZNA",
|
||||
"free": "WOLNA",
|
||||
"occupied": "ZAJĘTA",
|
||||
"sliders": {
|
||||
"min-lvl": "MIN. WYMAGANY POZIOM DYŻURNEGO",
|
||||
"max-lvl": "MAKS. WYMAGANY POZIOM DYŻURNEGO",
|
||||
"routes-1t-cat": "SZLAKI JEDNOTOROWE ZELEKTR. (MINIMUM)",
|
||||
"routes-1t-other": "SZLAKI JEDNOTOROWE NIEZELEKTR. (MINIMUM)",
|
||||
"routes-2t-cat": "SZLAKI DWUTOROWE ZELEKTR. (MINIMUM)",
|
||||
"routes-2t-other": "SZLAKI DWUTOROWE NIEZELEKTR. (MINIMUM)"
|
||||
},
|
||||
"save": "ZAPISZ FILTRY",
|
||||
"reset": "RESETUJ FILTRY",
|
||||
"close": "ZAMKNIJ FILTRY"
|
||||
},
|
||||
"sceneries": {
|
||||
"station": "Stacja",
|
||||
"min-lvl": "Min. poziom\ndyżurnego",
|
||||
"status": "Status",
|
||||
"dispatcher": "Dyżurny",
|
||||
"dispatcher-lvl": "Poziom\ndyżurnego",
|
||||
"routes": "Szlaki\n2tor / 1tor",
|
||||
"general": "Informacje\nogólne",
|
||||
"users": "Maszyniści online",
|
||||
"spawns": "Otwarte spawny",
|
||||
"timetables": "Aktywne rozkłady jazdy",
|
||||
"no-stations": "Brak stacji do wyświetlenia!"
|
||||
},
|
||||
"trains": {
|
||||
"no-trains": "Brak pociągów online!",
|
||||
"loading": "Pobieranie danych o pociągach...",
|
||||
"stats": "STATYSTYKI RUCHU",
|
||||
"stats-speed": "PRĘDKOŚCI POCIĄGÓW (MIN, ŚR, MAX) [km/h]",
|
||||
"stats-length": "DŁUGOŚCI ROZKŁADÓW (MIN, ŚR, MAX) [km]",
|
||||
"stats-categories": "KATEGORIE RJ",
|
||||
"stats-special-twr": "WYSOKIEGO RYZYKA",
|
||||
"stats-special-skr": "PRZEKROCZONA SKRAJNIA",
|
||||
"stats-locos": "NAJCZĘSTSZE JEDNOSTKI",
|
||||
"option-mass": "masa",
|
||||
"option-speed": "prędkość",
|
||||
"option-length": "długość",
|
||||
"option-distance": "kilometraż",
|
||||
"option-timetable": "numer pociągu",
|
||||
"search-no": "Szukaj nr pociągu...",
|
||||
"search-driver": "Szukaj maszynisty...",
|
||||
"detailed-timetable": "Szczegółowy rozkład jazdy pociągu ",
|
||||
"via-title": "Przez: ",
|
||||
"no-timetable": "brak rozkładu jazdy",
|
||||
"distance-exceeded": "Uwaga! Z powodu wewnętrznego błędu serwera TD2, rozkłady jazdy o kilometrażu powyżej 200km mogą być niepoprawne!",
|
||||
"cars": "Wagony"
|
||||
},
|
||||
"journal": {
|
||||
"title": "DZIENNIK AKTYWNOŚCI SCENERII",
|
||||
"subtitle": "Pokazuje dyżurnych, którzy ostatnio byli aktywni na wybranej scenerii",
|
||||
"disclaimer": "<b>Ta funkcjonalność jest w testach beta!</b> \n Informacje pokazywane na ekranie mogą znikać, a ich zawartość może być fałszywa!",
|
||||
"select": "Wybierz scenerię"
|
||||
},
|
||||
"scenery": {
|
||||
"users": "GRACZE ONLINE",
|
||||
"spawns": "OTWARTE SPAWNY",
|
||||
"timetables": "AKTYWNE ROZKŁADY JAZDY",
|
||||
"no-timetables": "Brak aktywnych rozkładów!",
|
||||
"no-users": "BRAK AKTYWNYCH GRACZY",
|
||||
"no-spawns": "BRAK OTWARTYCH SPAWNÓW",
|
||||
"no-scenery": "Ups! Ta sceneria nie istnieje!",
|
||||
"return-btn": "Wróć na stronę główną"
|
||||
},
|
||||
"timetables": {
|
||||
"timetable-only": "Wyodrębnij rozkłady jazdy",
|
||||
"online": "Na stacji",
|
||||
"departed": "Odprawiony",
|
||||
"departed-away": "Odjechał",
|
||||
"arriving": "W drodze",
|
||||
"stopped": "Postój",
|
||||
"terminated": "Skończył bieg",
|
||||
"begins": "ROZPOCZYNA\nBIEG",
|
||||
"terminates": "KOŃCZY BIEG"
|
||||
}
|
||||
}
|
||||
+15
-18
@@ -1,28 +1,25 @@
|
||||
import Vue from 'vue';
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
import VueI18n from 'vue-i18n';
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import { store, key } from './store'
|
||||
|
||||
import enLang from '@/lang/en.json';
|
||||
import plLang from '@/lang/pl.json';
|
||||
import enLang from '@/locales/en.json';
|
||||
import plLang from '@/locales/pl.json';
|
||||
|
||||
Vue.use(VueI18n);
|
||||
import { createI18n } from 'vue-i18n'
|
||||
|
||||
const i18n = new VueI18n({
|
||||
const i18n = createI18n({
|
||||
locale: 'pl',
|
||||
fallbackLocale: 'pl',
|
||||
messages: {
|
||||
en: enLang,
|
||||
pl: plLang,
|
||||
},
|
||||
});
|
||||
enableLegacy: false
|
||||
})
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
i18n,
|
||||
render: h => h(App),
|
||||
}).$mount('#app');
|
||||
createApp(App)
|
||||
.use(store, key)
|
||||
.use(router)
|
||||
.use(i18n)
|
||||
.mount('#app')
|
||||
|
||||
+40
-41
@@ -1,47 +1,46 @@
|
||||
import Vue from 'vue';
|
||||
import Component from 'vue-class-component';
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
// You can declare mixins as the same style as components.
|
||||
@Component
|
||||
export default class styleMixin extends Vue {
|
||||
calculateExpStyle(exp: string | number, isSupporter: boolean = false): string {
|
||||
const bgColor = exp > -1 ? (exp < 2 ? '#26B0D9' : `hsl(${-exp * 5 + 100}, 85%, 50%)`) : '#666';
|
||||
export default defineComponent({
|
||||
methods: {
|
||||
calculateExpStyle(exp: string | number, isSupporter = false): string {
|
||||
const bgColor = exp > -1 ? (exp < 2 ? '#26B0D9' : `hsl(${-exp * 5 + 100}, 85%, 50%)`) : '#666';
|
||||
|
||||
const fontColor = exp > 15 || exp == -1 ? 'white' : 'black';
|
||||
const boxShadow = isSupporter ? `box-shadow: 0 0 10px 2px ${bgColor};` : '';
|
||||
|
||||
return `background-color: ${bgColor}; color: ${fontColor}; ${boxShadow}`;
|
||||
},
|
||||
|
||||
const fontColor = exp > 15 || exp == -1 ? 'white' : 'black';
|
||||
const boxShadow = isSupporter ? `0 0 10px 2px ${bgColor}` : '';
|
||||
statusClasses(occupiedTo: string) {
|
||||
let className = '';
|
||||
|
||||
return `backgroundColor: ${bgColor}; color: ${fontColor}; box-shadow: ${boxShadow};`;
|
||||
}
|
||||
switch (occupiedTo) {
|
||||
case 'WOLNA':
|
||||
className = 'free';
|
||||
break;
|
||||
case 'KOŃCZY':
|
||||
className = 'ending';
|
||||
break;
|
||||
case 'NIEZALOGOWANY':
|
||||
className = 'not-signed';
|
||||
break;
|
||||
case 'BEZ LIMITU':
|
||||
className = 'no-limit';
|
||||
break;
|
||||
case 'NIEDOSTĘPNY':
|
||||
className = 'unavailable';
|
||||
break;
|
||||
case 'Z/W':
|
||||
className = 'brb';
|
||||
break;
|
||||
case 'BRAK MIEJSCA':
|
||||
className = 'no-space';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
statusClasses(occupiedTo: string) {
|
||||
let className = '';
|
||||
|
||||
switch (occupiedTo) {
|
||||
case 'WOLNA':
|
||||
className = 'free';
|
||||
break;
|
||||
case 'KOŃCZY':
|
||||
className = 'ending';
|
||||
break;
|
||||
case 'NIEZALOGOWANY':
|
||||
className = 'not-signed';
|
||||
break;
|
||||
case 'BEZ LIMITU':
|
||||
className = 'no-limit';
|
||||
break;
|
||||
case 'NIEDOSTĘPNY':
|
||||
className = 'unavailable';
|
||||
break;
|
||||
case 'Z/W':
|
||||
className = 'brb';
|
||||
break;
|
||||
case 'BRAK MIEJSCA':
|
||||
className = 'no-space';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
return className;
|
||||
}
|
||||
|
||||
return className;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
+14
-23
@@ -1,22 +1,19 @@
|
||||
import Vue from "vue";
|
||||
import VueRouter, { RouteConfig } from "vue-router";
|
||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
|
||||
|
||||
import StationsView from "../views/StationsView.vue";
|
||||
import TrainsView from "../views/TrainsView.vue";
|
||||
import StationsView from "@/views/StationsView.vue";
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
const routes: Array<RouteConfig> = [
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/",
|
||||
name: "StationsView",
|
||||
path: '/',
|
||||
name: 'StationsView',
|
||||
component: StationsView
|
||||
},
|
||||
{
|
||||
path: "/trains",
|
||||
name: "TrainsView",
|
||||
component: TrainsView,
|
||||
props: true
|
||||
component: () => import("@/views/TrainsView.vue"),
|
||||
props: true,
|
||||
|
||||
},
|
||||
{
|
||||
path: "/scenery",
|
||||
@@ -24,17 +21,11 @@ const routes: Array<RouteConfig> = [
|
||||
component: () => import("@/views/SceneryView.vue"),
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: "/history",
|
||||
name: "HistoryView",
|
||||
component: () => import("@/views/HistoryView.vue")
|
||||
}
|
||||
];
|
||||
]
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: "history",
|
||||
base: process.env.BASE_URL,
|
||||
routes
|
||||
});
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
})
|
||||
|
||||
export default router;
|
||||
export default router
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
export default interface Filter {
|
||||
[key: string]: (boolean | number),
|
||||
default: boolean;
|
||||
notDefault: boolean;
|
||||
real: boolean;
|
||||
fictional: boolean;
|
||||
SPK: boolean;
|
||||
SCS: boolean;
|
||||
SPE: boolean;
|
||||
"SPK": boolean;
|
||||
"SCS": boolean;
|
||||
"SPE": boolean;
|
||||
ręczne: boolean;
|
||||
mechaniczne: boolean;
|
||||
współczesna: boolean;
|
||||
@@ -23,4 +24,5 @@ export default interface Filter {
|
||||
free: boolean;
|
||||
occupied: boolean;
|
||||
ending: boolean;
|
||||
nonPublic: boolean;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ export default interface Station {
|
||||
stationTrains: {
|
||||
driverName: number;
|
||||
trainNo: number;
|
||||
stopStatus?: string;
|
||||
}[];
|
||||
|
||||
scheduledTrains: ScheduledTrain[];
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import TrainStop from "./TrainStop";
|
||||
|
||||
export default interface Timetable {
|
||||
trainNo: number;
|
||||
driverName: string;
|
||||
driverId: number;
|
||||
currentStationName: string;
|
||||
currentStationHash: string;
|
||||
timetableId: number;
|
||||
category: string;
|
||||
route: string;
|
||||
TWR: boolean;
|
||||
SKR: boolean;
|
||||
routeDistance: number;
|
||||
followingStops: TrainStop[];
|
||||
followingSceneries: string[];
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
export default interface StationAPIData {
|
||||
dispatcherId: number;
|
||||
dispatcherName: string;
|
||||
dispatcherIsSupporter: boolean;
|
||||
stationName: string;
|
||||
stationHash: string;
|
||||
region: string;
|
||||
maxUsers: number;
|
||||
currentUsers: number;
|
||||
spawn: number;
|
||||
lastSeen: number;
|
||||
dispatcherExp: number;
|
||||
nameFromHeader: string;
|
||||
spawnString: string;
|
||||
networkConnectionString: string;
|
||||
isOnline: number;
|
||||
dispatcherRate: number;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
export default interface TimetableAPIData {
|
||||
trainInfo: {
|
||||
timetableId: number;
|
||||
trainNo: number;
|
||||
trainCategoryCode: string;
|
||||
driverId: number;
|
||||
driverName: string;
|
||||
route: string;
|
||||
twr: boolean;
|
||||
skr: boolean;
|
||||
sceneries: string[];
|
||||
};
|
||||
|
||||
stopPoints: {
|
||||
arrivalLine: string | null;
|
||||
arrivalTime: string | null;
|
||||
arrivalDelay: number;
|
||||
arrivalRealTime: string | null;
|
||||
pointDistance: number;
|
||||
pointName: string;
|
||||
pointNameRAW: string;
|
||||
entryId: number;
|
||||
pointId: number;
|
||||
comments: string | null;
|
||||
confirmed: boolean;
|
||||
isStopped: boolean;
|
||||
pointStopTime: number | null;
|
||||
pointStopType: string;
|
||||
departureLine: string | null;
|
||||
departureTime: string | null;
|
||||
departureDelay: number;
|
||||
departureRealTime: string | null;
|
||||
}[];
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import StationAPIData from "./StationAPIData";
|
||||
|
||||
export default interface TrainAPIData {
|
||||
trainNo: number;
|
||||
driverId: number;
|
||||
driverName: string;
|
||||
driverIsSupporter: boolean;
|
||||
station: StationAPIData;
|
||||
dataSignal: string;
|
||||
dataSceneryConnection: string;
|
||||
dataDistance: number;
|
||||
dataCon: string;
|
||||
dataSpeed: number;
|
||||
dataMass: number;
|
||||
dataLength: number;
|
||||
region: string;
|
||||
isOnline: boolean;
|
||||
lastSeen: number;
|
||||
}
|
||||
@@ -122,6 +122,7 @@ export default class StationFilterManager {
|
||||
free: true,
|
||||
occupied: false,
|
||||
ending: false,
|
||||
nonPublic: false
|
||||
};
|
||||
|
||||
private filters: Filter = { ...this.filterInitStates };
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export const URLs = {
|
||||
stations: "https://api.td2.info.pl:9640/?method=getStationsOnline",
|
||||
trains: "https://api.td2.info.pl:9640/?method=getTrainsOnline",
|
||||
dispatchers: "https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1",
|
||||
getTimetableURL: (trainNo: string | number) => `https://api.td2.info.pl:9640/?method=readFromSWDR&value=getTimetable%3B${trainNo}%3Beu`
|
||||
};
|
||||
@@ -1,10 +1,9 @@
|
||||
import Station from "../interfaces/Station";
|
||||
import TrainStop from "../interfaces/TrainStop";
|
||||
|
||||
const timetableURL = (trainNo: number) => `https://api.td2.info.pl:9640/?method=readFromSWDR&value=getTimetable%3B${trainNo}%3Beu`;
|
||||
const getLocoURL = (locoType: string) => `https://rj.td2.info.pl/dist/img/thumbnails/${locoType.includes("EN") ? locoType + "rb" : locoType}.png`;
|
||||
export const getLocoURL = (locoType: string): string => (`https://rj.td2.info.pl/dist/img/thumbnails/${locoType.includes("EN") ? locoType + "rb" : locoType}.png`)
|
||||
|
||||
const getStatusID = (stationStatus: any) => {
|
||||
export const getStatusID = (stationStatus: any): string => {
|
||||
if (!stationStatus) return "not-signed";
|
||||
|
||||
const statusCode = stationStatus[2];
|
||||
@@ -33,7 +32,7 @@ const getStatusID = (stationStatus: any) => {
|
||||
return "unavailable";
|
||||
};
|
||||
|
||||
const getStatusTimestamp = (stationStatus: any) => {
|
||||
export const getStatusTimestamp = (stationStatus: any): number => {
|
||||
if (!stationStatus) return -2;
|
||||
|
||||
const statusCode = stationStatus[2];
|
||||
@@ -56,7 +55,7 @@ const getStatusTimestamp = (stationStatus: any) => {
|
||||
return -1;
|
||||
};
|
||||
|
||||
const parseSpawns = (spawnString: string) => {
|
||||
export const parseSpawns = (spawnString: string) => {
|
||||
if (!spawnString) return [];
|
||||
if (spawnString === "NO_SPAWN") return [];
|
||||
|
||||
@@ -69,9 +68,9 @@ const parseSpawns = (spawnString: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
const getTimestamp = (date: string | null) => (date ? new Date(date).getTime() : 0);
|
||||
export const getTimestamp = (date: string | null): number => (date ? new Date(date).getTime() : 0);
|
||||
|
||||
const timestampToString = (timestamp: number | null) =>
|
||||
export const timestampToString = (timestamp: number | null): string =>
|
||||
timestamp
|
||||
? new Date(timestamp).toLocaleTimeString("pl-PL", {
|
||||
hour: "2-digit",
|
||||
@@ -79,10 +78,10 @@ const timestampToString = (timestamp: number | null) =>
|
||||
})
|
||||
: "";
|
||||
|
||||
const getTrainStopStatus = (stopInfo: TrainStop, timetableData: { currentStationName: string }, station: Station) => {
|
||||
let stopStatus: string = "",
|
||||
stopLabel: string = "",
|
||||
stopStatusID: number = -1;
|
||||
export const getTrainStopStatus = (stopInfo: TrainStop, timetableData: { currentStationName: string }, station: Station) => {
|
||||
let stopStatus = "",
|
||||
stopLabel = "",
|
||||
stopStatusID = -1;
|
||||
|
||||
if (stopInfo.terminatesHere && stopInfo.confirmed) {
|
||||
stopStatus = "terminated";
|
||||
@@ -111,15 +110,4 @@ const getTrainStopStatus = (stopInfo: TrainStop, timetableData: { currentStation
|
||||
}
|
||||
|
||||
return { stopStatus, stopLabel, stopStatusID };
|
||||
};
|
||||
|
||||
export default {
|
||||
timetableURL,
|
||||
getLocoURL,
|
||||
getStatusID,
|
||||
parseSpawns,
|
||||
getTimestamp,
|
||||
timestampToString,
|
||||
getStatusTimestamp,
|
||||
getTrainStopStatus
|
||||
};
|
||||
};
|
||||
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
import Vue, { VNode } from 'vue'
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
// tslint:disable no-empty-interface
|
||||
interface Element extends VNode {}
|
||||
// tslint:disable no-empty-interface
|
||||
interface ElementClass extends Vue {}
|
||||
interface IntrinsicElements {
|
||||
[elem: string]: any
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+4
-2
@@ -1,4 +1,6 @@
|
||||
/* eslint-disable */
|
||||
declare module '*.vue' {
|
||||
import Vue from 'vue'
|
||||
export default Vue
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
|
||||
+455
-9
@@ -1,12 +1,458 @@
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
/* eslint-disable */
|
||||
|
||||
import Store from '@/store/store';
|
||||
import { InjectionKey } from 'vue'
|
||||
import { createStore, useStore as baseUseStore, Store } from 'vuex'
|
||||
|
||||
Vue.use(Vuex);
|
||||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
Store,
|
||||
import axios from "axios";
|
||||
|
||||
import JSONStationData from "@/data/stationData.json";
|
||||
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import Train from "@/scripts/interfaces/Train";
|
||||
import TrainStop from "@/scripts/interfaces/TrainStop";
|
||||
|
||||
import { StoreData } from "@/scripts/interfaces/StoreData";
|
||||
|
||||
import TimetableAPIData from '@/scripts/interfaces/api/TimetableAPIData';
|
||||
import StationAPIData from '@/scripts/interfaces/api/StationAPIData';
|
||||
import TrainAPIData from '@/scripts/interfaces/api/TrainAPIData';
|
||||
import Timetable from '@/scripts/interfaces/Timetable';
|
||||
|
||||
import { ACTIONS, MUTATIONS } from "@/constants/storeConstants";
|
||||
import { DataStatus } from "@/scripts/enums/DataStatus";
|
||||
|
||||
import { getLocoURL, getStatusID, getStatusTimestamp, getTimestamp, getTrainStopStatus, parseSpawns, timestampToString } from "@/scripts/utils/storeUtils";
|
||||
import { URLs } from '@/scripts/utils/apiURLs';
|
||||
|
||||
|
||||
export interface State {
|
||||
stationList: Station[],
|
||||
trainList: Train[],
|
||||
|
||||
trainCount: number;
|
||||
stationCount: number;
|
||||
|
||||
dataConnectionStatus: DataStatus;
|
||||
sceneryDataStatus: DataStatus;
|
||||
timetableDataStatus: DataStatus;
|
||||
|
||||
listenerLaunched: boolean;
|
||||
}
|
||||
|
||||
export const key: InjectionKey<Store<State>> = Symbol()
|
||||
|
||||
export const store = createStore<State>({
|
||||
state: () => ({
|
||||
stationList: [],
|
||||
trainList: [],
|
||||
|
||||
trainCount: 0,
|
||||
stationCount: 0,
|
||||
|
||||
dataConnectionStatus: DataStatus.Loading,
|
||||
sceneryDataStatus: DataStatus.Loading,
|
||||
timetableDataStatus: DataStatus.Loading,
|
||||
|
||||
listenerLaunched: false
|
||||
}),
|
||||
|
||||
getters: {
|
||||
stationList: (state) => state.stationList,
|
||||
trainList: (state) => state.trainList,
|
||||
allData: (state): StoreData => ({
|
||||
stationList: state.stationList,
|
||||
trainList: state.trainList,
|
||||
|
||||
activeTrainCount: state.trainCount,
|
||||
activeStationCount: state.stationCount,
|
||||
|
||||
dataConnectionStatus: state.dataConnectionStatus,
|
||||
timetableDataStatus: state.timetableDataStatus
|
||||
}),
|
||||
timetableDataStatus: (state): DataStatus => state.timetableDataStatus,
|
||||
sceneryDataStatus: (state): DataStatus => state.sceneryDataStatus,
|
||||
dataStatus: (state): DataStatus => state.dataConnectionStatus
|
||||
},
|
||||
});
|
||||
export default store;
|
||||
|
||||
actions: {
|
||||
async synchronizeData({ commit, dispatch, state }) {
|
||||
if(state.listenerLaunched) return;
|
||||
|
||||
commit(MUTATIONS.SET_SCENERY_DATA);
|
||||
commit(MUTATIONS.SET_SCENERY_DATA_STATUS, DataStatus.Loaded);
|
||||
|
||||
dispatch(ACTIONS.fetchOnlineData);
|
||||
|
||||
setInterval(() => dispatch(ACTIONS.fetchOnlineData), 30000);
|
||||
|
||||
},
|
||||
|
||||
async fetchOnlineData({ commit, dispatch }) {
|
||||
Promise.all([axios.get(URLs.stations), axios.get(URLs.trains), axios.get(URLs.dispatchers)])
|
||||
.then(async response => {
|
||||
const onlineStationsData: StationAPIData[] = response[0].data.message;
|
||||
const onlineTrainsData: TrainAPIData[] = await response[1].data.message;
|
||||
const onlineDispatchersData: string[][] = await response[2].data.message;
|
||||
|
||||
const updatedStationList = onlineStationsData.reduce((acc, station) => {
|
||||
if (station.region !== "eu" || !station.isOnline) return acc;
|
||||
|
||||
const stationStatus = onlineDispatchersData.find((status: string[]) => status[0] == station.stationHash && status[1] == "eu");
|
||||
|
||||
const statusTimestamp = getStatusTimestamp(stationStatus);
|
||||
const statusID = getStatusID(stationStatus);
|
||||
|
||||
const stationTrains = onlineTrainsData
|
||||
.filter(train => train.region === "eu" && train.isOnline && train.station.stationName === station.stationName)
|
||||
.map(train => ({ driverName: train.driverName, trainNo: train.trainNo }));
|
||||
|
||||
acc.push({
|
||||
stationName: station.stationName,
|
||||
stationHash: station.stationHash,
|
||||
maxUsers: station.maxUsers,
|
||||
currentUsers: station.currentUsers,
|
||||
spawns: parseSpawns(station.spawnString),
|
||||
dispatcherName: station.dispatcherName,
|
||||
dispatcherRate: station.dispatcherRate,
|
||||
dispatcherId: station.dispatcherId,
|
||||
dispatcherExp: station.dispatcherExp,
|
||||
dispatcherIsSupporter: station.dispatcherIsSupporter,
|
||||
stationTrains,
|
||||
statusTimestamp,
|
||||
statusID,
|
||||
statusTimeString: timestampToString(statusTimestamp)
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, [] as any);
|
||||
|
||||
const updatedTrainList = await Promise.all(
|
||||
onlineTrainsData
|
||||
.filter(train => train.region === "eu")
|
||||
.map(async train => {
|
||||
const locoType = train.dataCon.split(";") ? train.dataCon.split(";")[0] : train.dataCon;
|
||||
|
||||
return {
|
||||
trainNo: train.trainNo,
|
||||
mass: train.dataMass,
|
||||
length: train.dataLength,
|
||||
speed: train.dataSpeed,
|
||||
distance: train.dataDistance,
|
||||
signal: train.dataSignal,
|
||||
online: train.isOnline,
|
||||
driverId: train.driverId,
|
||||
driverName: train.driverName,
|
||||
currentStationName: train.station.stationName,
|
||||
currentStationHash: train.station.stationHash,
|
||||
connectedTrack: train.dataSceneryConnection,
|
||||
locoType,
|
||||
locoURL: getLocoURL(locoType),
|
||||
cars: train.dataCon.split(";").filter((train, i) => i > 0) || []
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
// Pass reduced lists to mutations
|
||||
commit(MUTATIONS.UPDATE_STATIONS, updatedStationList);
|
||||
commit(MUTATIONS.UPDATE_TRAINS, updatedTrainList);
|
||||
|
||||
dispatch(ACTIONS.fetchTimetableData);
|
||||
})
|
||||
.catch(() => {
|
||||
commit(MUTATIONS.SET_DATA_CONNECTION_STATUS, DataStatus.Error);
|
||||
});
|
||||
},
|
||||
|
||||
async fetchTimetableData({ commit }) {
|
||||
const reducedList = this.state.trainList.reduce(async (acc: Promise<Timetable[]>, train: Train) => {
|
||||
const timetable: TimetableAPIData = await (await axios.get(URLs.getTimetableURL(train.trainNo))).data.message;
|
||||
const trainInfo = timetable.trainInfo;
|
||||
|
||||
if (!timetable || !trainInfo) return acc;
|
||||
|
||||
const followingStops: TrainStop[] = timetable.stopPoints.reduce((stopsAcc: TrainStop[], point) => {
|
||||
if (point.pointNameRAW.toLowerCase().includes("sbl")) return stopsAcc;
|
||||
|
||||
const arrivalTimestamp = getTimestamp(point.arrivalTime);
|
||||
const arrivalRealTimestamp = getTimestamp(point.arrivalRealTime);
|
||||
|
||||
const departureTimestamp = getTimestamp(point.departureTime);
|
||||
const departureRealTimestamp = getTimestamp(point.departureRealTime);
|
||||
|
||||
stopsAcc.push({
|
||||
stopName: point.pointName,
|
||||
stopNameRAW: point.pointNameRAW,
|
||||
stopType: point.pointStopType,
|
||||
stopDistance: point.pointDistance,
|
||||
|
||||
mainStop: point.pointName.includes("strong"),
|
||||
|
||||
arrivalLine: point.arrivalLine,
|
||||
arrivalTimeString: timestampToString(arrivalTimestamp),
|
||||
arrivalTimestamp: arrivalTimestamp,
|
||||
arrivalRealTimeString: timestampToString(arrivalRealTimestamp),
|
||||
arrivalRealTimestamp: arrivalRealTimestamp,
|
||||
arrivalDelay: point.arrivalDelay,
|
||||
|
||||
departureLine: point.departureLine,
|
||||
departureTimeString: timestampToString(departureTimestamp),
|
||||
departureTimestamp: departureTimestamp,
|
||||
departureRealTimeString: timestampToString(departureRealTimestamp),
|
||||
departureRealTimestamp: departureRealTimestamp,
|
||||
departureDelay: point.departureDelay,
|
||||
|
||||
beginsHere: arrivalTimestamp == 0,
|
||||
terminatesHere: departureTimestamp == 0,
|
||||
|
||||
confirmed: point.confirmed,
|
||||
stopped: point.isStopped,
|
||||
stopTime: point.pointStopTime
|
||||
});
|
||||
|
||||
return stopsAcc;
|
||||
}, []);
|
||||
|
||||
(await acc).push({
|
||||
trainNo: train.trainNo,
|
||||
driverName: train.driverName,
|
||||
driverId: train.driverId,
|
||||
currentStationName: train.currentStationName,
|
||||
currentStationHash: train.currentStationHash,
|
||||
timetableId: trainInfo.timetableId,
|
||||
category: trainInfo.trainCategoryCode,
|
||||
route: trainInfo.route,
|
||||
TWR: trainInfo.twr,
|
||||
SKR: trainInfo.skr,
|
||||
routeDistance: timetable.stopPoints[timetable.stopPoints.length - 1].pointDistance,
|
||||
followingStops,
|
||||
followingSceneries: trainInfo.sceneries
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, Promise.resolve([]));
|
||||
|
||||
commit(MUTATIONS.UPDATE_TIMETABLES, (await reducedList));
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
mutations: {
|
||||
SET_SCENERY_DATA(state) {
|
||||
state.stationList = JSONStationData.map(station => ({
|
||||
stationName: station[0] as string,
|
||||
stationURL: station[1] as string,
|
||||
stationLines: station[2] as string,
|
||||
stationProject: station[3] as string,
|
||||
reqLevel: station[4] as string,
|
||||
supportersOnly: station[5] == "TAK",
|
||||
signalType: station[6] as string,
|
||||
controlType: station[7] as string,
|
||||
SBL: station[8] as string,
|
||||
TWB: station[9] as string,
|
||||
routes: {
|
||||
oneWay: {
|
||||
catenary: station[10] as number,
|
||||
noCatenary: station[11] as number
|
||||
},
|
||||
twoWay: {
|
||||
catenary: station[12] as number,
|
||||
noCatenary: station[13] as number
|
||||
}
|
||||
},
|
||||
checkpoints: station[14] ? (station[14] as string[]).map(sub => ({ checkpointName: sub, scheduledTrains: [] })) : null,
|
||||
stops: station[15] as string[],
|
||||
|
||||
default: station[16] as boolean,
|
||||
nonPublic: station[17] as boolean,
|
||||
unavailable: station[18] as boolean,
|
||||
|
||||
stationHash: "",
|
||||
maxUsers: 0,
|
||||
currentUsers: 0,
|
||||
dispatcherName: "",
|
||||
dispatcherRate: 0,
|
||||
dispatcherExp: -1,
|
||||
dispatcherId: 0,
|
||||
dispatcherIsSupporter: false,
|
||||
online: false,
|
||||
statusTimestamp: -3,
|
||||
statusID: "free",
|
||||
statusTimeString: "",
|
||||
stationTrains: [],
|
||||
scheduledTrains: [],
|
||||
spawns: []
|
||||
}));
|
||||
},
|
||||
|
||||
SET_SCENERY_DATA_STATUS(state, status: DataStatus) {
|
||||
state.sceneryDataStatus = status;
|
||||
},
|
||||
|
||||
SET_DATA_CONNECTION_STATUS(state, status: DataStatus) {
|
||||
state.dataConnectionStatus = status;
|
||||
},
|
||||
|
||||
UPDATE_STATIONS(state, updatedStationList: any[]) {
|
||||
state.stationList = state.stationList.reduce((acc: Station[], station) => {
|
||||
const onlineStationData = updatedStationList.find(updatedStation => updatedStation.stationName === station.stationName);
|
||||
const listedStationData = JSONStationData.find(data => data[0] === station.stationName);
|
||||
|
||||
if (onlineStationData)
|
||||
acc.push({
|
||||
...station,
|
||||
...onlineStationData,
|
||||
online: true
|
||||
});
|
||||
else if (listedStationData)
|
||||
acc.push({
|
||||
...station,
|
||||
stationProject: "",
|
||||
stationHash: "",
|
||||
maxUsers: 0,
|
||||
currentUsers: 0,
|
||||
dispatcherName: "",
|
||||
dispatcherRate: 0,
|
||||
dispatcherExp: -1,
|
||||
dispatcherId: 0,
|
||||
dispatcherIsSupporter: false,
|
||||
online: false,
|
||||
statusID: "free",
|
||||
statusTimestamp: -3,
|
||||
statusTimeString: "",
|
||||
stationTrains: [],
|
||||
scheduledTrains: [],
|
||||
checkpoints: null
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, [] as Station[]);
|
||||
|
||||
updatedStationList
|
||||
.filter(uStation => !state.stationList.some(station => uStation.stationName === station.stationName))
|
||||
.forEach(uStation => {
|
||||
state.stationList.push({
|
||||
...uStation,
|
||||
scheduledTrains: [],
|
||||
stationTrains: uStation.stationTrains || [],
|
||||
subStations: [],
|
||||
online: true,
|
||||
reqLevel: "-1",
|
||||
nonPublic: true
|
||||
});
|
||||
});
|
||||
|
||||
state.stationCount = state.stationList.filter(station => station.online).length;
|
||||
state.dataConnectionStatus = DataStatus.Loaded;
|
||||
},
|
||||
|
||||
UPDATE_TRAINS(state, updatedTrainList: any[]) {
|
||||
state.trainList = updatedTrainList.reduce((acc, updatedTrain) => {
|
||||
const trainData = state.trainList.find(train => train.trainNo === updatedTrain.trainNo);
|
||||
|
||||
if (trainData) acc.push({ ...trainData, ...updatedTrain });
|
||||
else acc.push({ ...updatedTrain });
|
||||
|
||||
return acc;
|
||||
}, [] as Train[]);
|
||||
|
||||
state.trainCount = state.trainList.filter(train => train.online).length;
|
||||
state.dataConnectionStatus = DataStatus.Loaded;
|
||||
},
|
||||
|
||||
UPDATE_TIMETABLES(state, timetableList: Timetable[]) {
|
||||
state.stationList = state.stationList.map(station => {
|
||||
const stationName = station.stationName.toLowerCase();
|
||||
|
||||
const scheduledTrains: Station["scheduledTrains"] = timetableList.reduce((acc: Station["scheduledTrains"], timetable: Timetable) => {
|
||||
if (!timetable.followingSceneries.includes(station.stationHash)) return acc;
|
||||
|
||||
const stopInfoIndex = timetable.followingStops.findIndex(stop => {
|
||||
const stopName = stop.stopNameRAW.toLowerCase();
|
||||
|
||||
if (stationName === stopName) return true;
|
||||
if (stopName.includes(stationName) && !stop.stopName.includes("po.") && !stop.stopName.includes("podg.")) return true;
|
||||
if (stationName.includes(stopName) && !stop.stopName.includes("po.") && !stop.stopName.includes("podg.")) return true;
|
||||
if (stopName.includes("podg.") && stopName.split(", podg.")[0] && stationName.includes(stopName.split(", podg.")[0])) return true;
|
||||
|
||||
if (station.stops && station.stops.includes(stop.stopNameRAW)) return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (stopInfoIndex == -1) return acc;
|
||||
|
||||
const trainStop = timetable.followingStops[stopInfoIndex];
|
||||
const trainStopStatus = getTrainStopStatus(trainStop, timetable, station);
|
||||
|
||||
acc.push({
|
||||
trainNo: timetable.trainNo,
|
||||
driverName: timetable.driverName,
|
||||
driverId: timetable.driverId,
|
||||
currentStationName: timetable.currentStationName,
|
||||
currentStationHash: timetable.currentStationHash,
|
||||
category: timetable.category,
|
||||
beginsAt: timetable.followingStops[0].stopNameRAW,
|
||||
terminatesAt: timetable.followingStops[timetable.followingStops.length - 1].stopNameRAW,
|
||||
nearestStop: "",
|
||||
stopInfo: trainStop,
|
||||
stopLabel: trainStopStatus.stopLabel,
|
||||
stopStatus: trainStopStatus.stopStatus,
|
||||
stopStatusID: trainStopStatus.stopStatusID
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
if (station.checkpoints) {
|
||||
station.checkpoints.forEach(cp => (cp.scheduledTrains.length = 0));
|
||||
|
||||
for (const checkpoint of station.checkpoints) {
|
||||
timetableList.forEach(timetable => {
|
||||
timetable.followingStops
|
||||
.filter(trainStop => trainStop.stopNameRAW.toLowerCase() === checkpoint.checkpointName.toLowerCase())
|
||||
.forEach(trainStop => {
|
||||
const trainStopStatus = getTrainStopStatus(trainStop, timetable, station);
|
||||
|
||||
checkpoint.scheduledTrains.push({
|
||||
trainNo: timetable.trainNo,
|
||||
driverName: timetable.driverName,
|
||||
driverId: timetable.driverId,
|
||||
currentStationName: timetable.currentStationName,
|
||||
currentStationHash: timetable.currentStationHash,
|
||||
category: timetable.category,
|
||||
beginsAt: timetable.followingStops[0].stopNameRAW,
|
||||
terminatesAt: timetable.followingStops[timetable.followingStops.length - 1].stopNameRAW,
|
||||
nearestStop: "",
|
||||
stopInfo: trainStop,
|
||||
stopLabel: trainStopStatus.stopLabel,
|
||||
stopStatus: trainStopStatus.stopStatus,
|
||||
stopStatusID: trainStopStatus.stopStatusID
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { ...station, scheduledTrains };
|
||||
});
|
||||
|
||||
state.trainList = state.trainList.reduce((acc, train) => {
|
||||
const timetableData = timetableList.find(data => data && data.trainNo === train.trainNo);
|
||||
|
||||
const trainStopData = state.stationList
|
||||
.find(station => station.stationName === train.currentStationName)
|
||||
?.scheduledTrains.find(stationTrain => stationTrain.trainNo === train.trainNo);
|
||||
|
||||
acc.push({ ...train, timetableData, stopStatus: trainStopData?.stopStatus || "", stopLabel: trainStopData?.stopLabel || "" });
|
||||
|
||||
return acc;
|
||||
}, [] as Train[]);
|
||||
|
||||
state.timetableDataStatus = DataStatus.Loaded;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export function useStore(): Store<State> {
|
||||
return baseUseStore(key)
|
||||
}
|
||||
@@ -1,591 +0,0 @@
|
||||
import { Module, VuexModule, Mutation, Action } from "vuex-module-decorators";
|
||||
import axios from "axios";
|
||||
|
||||
import JSONStationData from "@/data/stationData.json";
|
||||
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import Train from "@/scripts/interfaces/Train";
|
||||
import TrainStop from "@/scripts/interfaces/TrainStop";
|
||||
|
||||
import utils from "@/scripts/utils/storeUtils";
|
||||
import { DataStatus } from "@/scripts/enums/DataStatus";
|
||||
import { StoreData } from "@/scripts/interfaces/StoreData";
|
||||
|
||||
interface TimetableAPIData {
|
||||
trainInfo: {
|
||||
timetableId: number;
|
||||
trainNo: number;
|
||||
trainCategoryCode: string;
|
||||
driverId: number;
|
||||
driverName: string;
|
||||
route: string;
|
||||
twr: boolean;
|
||||
skr: boolean;
|
||||
sceneries: string[];
|
||||
};
|
||||
|
||||
stopPoints: {
|
||||
arrivalLine: string | null;
|
||||
arrivalTime: string | null;
|
||||
arrivalDelay: number;
|
||||
arrivalRealTime: string | null;
|
||||
pointDistance: number;
|
||||
pointName: string;
|
||||
pointNameRAW: string;
|
||||
entryId: number;
|
||||
pointId: number;
|
||||
comments: string | null;
|
||||
confirmed: boolean;
|
||||
isStopped: boolean;
|
||||
pointStopTime: number | null;
|
||||
pointStopType: string;
|
||||
departureLine: string | null;
|
||||
departureTime: string | null;
|
||||
departureDelay: number;
|
||||
departureRealTime: string | null;
|
||||
}[];
|
||||
}
|
||||
|
||||
interface StationAPIData {
|
||||
dispatcherId: number;
|
||||
dispatcherName: string;
|
||||
dispatcherIsSupporter: boolean;
|
||||
stationName: string;
|
||||
stationHash: string;
|
||||
region: string;
|
||||
maxUsers: number;
|
||||
currentUsers: number;
|
||||
spawn: number;
|
||||
lastSeen: number;
|
||||
dispatcherExp: number;
|
||||
nameFromHeader: string;
|
||||
spawnString: string;
|
||||
networkConnectionString: string;
|
||||
isOnline: number;
|
||||
dispatcherRate: number;
|
||||
}
|
||||
|
||||
interface TrainAPIData {
|
||||
trainNo: number;
|
||||
driverId: number;
|
||||
driverName: string;
|
||||
driverIsSupporter: boolean;
|
||||
station: StationAPIData;
|
||||
dataSignal: string;
|
||||
dataSceneryConnection: string;
|
||||
dataDistance: number;
|
||||
dataCon: string;
|
||||
dataSpeed: number;
|
||||
dataMass: number;
|
||||
dataLength: number;
|
||||
region: string;
|
||||
isOnline: boolean;
|
||||
lastSeen: number;
|
||||
}
|
||||
|
||||
interface Timetable {
|
||||
trainNo: number;
|
||||
driverName: string;
|
||||
driverId: number;
|
||||
currentStationName: string;
|
||||
currentStationHash: string;
|
||||
timetableId: number;
|
||||
category: string;
|
||||
route: string;
|
||||
TWR: boolean;
|
||||
SKR: boolean;
|
||||
routeDistance: number;
|
||||
followingStops: TrainStop[];
|
||||
followingSceneries: string[];
|
||||
}
|
||||
|
||||
// interface OnlineStationData {
|
||||
// dispatcherId: number;
|
||||
// dispatcherName: string;
|
||||
// dispatcherIsSupporter: boolean;
|
||||
// stationName: string;
|
||||
// stationHash: string;
|
||||
// region: string;
|
||||
// maxUsers: number;
|
||||
// currentUsers: number;
|
||||
// spawn: number;
|
||||
// lastSeen: number;
|
||||
// dispatcherExp: number;
|
||||
// nameFromHeader: string;
|
||||
// spawnString: string;
|
||||
// networkConnectionString: string;
|
||||
// isOnline: number;
|
||||
// dispatcherRate: number;
|
||||
// }
|
||||
|
||||
// interface TrainData {
|
||||
// trainNo: number;
|
||||
// driverId: number;
|
||||
// driverName: string;
|
||||
// driverIsSupporter: boolean;
|
||||
// dataSignal: string;
|
||||
// dataSceneryConnection: string;
|
||||
// dataDistance: number;
|
||||
// dataCon: string;
|
||||
// dataSpeed: number;
|
||||
// dataMass: number;
|
||||
// dataLength: number;
|
||||
// station: OnlineStationData;
|
||||
// region: string;
|
||||
// isOnline: number;
|
||||
// lastSeen: number;
|
||||
// }
|
||||
|
||||
const URLs = {
|
||||
stations: "https://api.td2.info.pl:9640/?method=getStationsOnline",
|
||||
trains: "https://api.td2.info.pl:9640/?method=getTrainsOnline",
|
||||
dispatchers: "https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1"
|
||||
};
|
||||
|
||||
@Module
|
||||
export default class Store extends VuexModule {
|
||||
private trainCount: number = 0;
|
||||
private stationCount: number = 0;
|
||||
|
||||
private dataConnectionStatus: DataStatus = DataStatus.Loading;
|
||||
private sceneryDataStatus: DataStatus = DataStatus.Loading;
|
||||
private timetableDataStatus: DataStatus = DataStatus.Loading;
|
||||
|
||||
private stationList: Station[] = [];
|
||||
private trainList: Train[] = [];
|
||||
|
||||
//GETTERS
|
||||
get getAllData(): StoreData {
|
||||
return {
|
||||
stationList: this.stationList,
|
||||
trainList: this.trainList,
|
||||
|
||||
activeTrainCount: this.trainCount,
|
||||
activeStationCount: this.stationCount,
|
||||
|
||||
dataConnectionStatus: this.dataConnectionStatus,
|
||||
timetableDataStatus: this.timetableDataStatus
|
||||
};
|
||||
}
|
||||
|
||||
get getStationList() {
|
||||
return this.stationList;
|
||||
}
|
||||
|
||||
get getTrainList() {
|
||||
return this.trainList;
|
||||
}
|
||||
|
||||
get getTimetableDataStatus() {
|
||||
return this.timetableDataStatus;
|
||||
}
|
||||
|
||||
get getDataStatus() {
|
||||
return this.dataConnectionStatus;
|
||||
}
|
||||
|
||||
get getSceneryDataStatus() {
|
||||
return this.sceneryDataStatus;
|
||||
}
|
||||
|
||||
//ACTIONS
|
||||
@Action
|
||||
async synchronizeData() {
|
||||
this.context.commit("setSceneryData");
|
||||
this.context.commit("setSceneryDataStatus", DataStatus.Loaded);
|
||||
|
||||
this.context.dispatch("fetchOnlineData");
|
||||
setInterval(() => this.context.dispatch("fetchOnlineData"), 20000);
|
||||
}
|
||||
|
||||
// Fetching all station and train data from API
|
||||
@Action
|
||||
async fetchOnlineData() {
|
||||
Promise.all([axios.get(URLs.stations), axios.get(URLs.trains), axios.get(URLs.dispatchers)])
|
||||
.then(async response => {
|
||||
const onlineStationsData: StationAPIData[] = response[0].data.message;
|
||||
const onlineTrainsData: TrainAPIData[] = await response[1].data.message;
|
||||
const onlineDispatchersData: string[][] = await response[2].data.message;
|
||||
|
||||
const updatedStationList = onlineStationsData.reduce((acc, station) => {
|
||||
if (station.region !== "eu" || !station.isOnline) return acc;
|
||||
|
||||
const stationStatus = onlineDispatchersData.find((status: string[]) => status[0] == station.stationHash && status[1] == "eu");
|
||||
|
||||
const statusTimestamp = utils.getStatusTimestamp(stationStatus);
|
||||
const statusID = utils.getStatusID(stationStatus);
|
||||
|
||||
const stationTrains = onlineTrainsData
|
||||
.filter(train => train.region === "eu" && train.isOnline && train.station.stationName === station.stationName)
|
||||
.map(train => ({ driverName: train.driverName, trainNo: train.trainNo }));
|
||||
|
||||
acc.push({
|
||||
stationName: station.stationName,
|
||||
stationHash: station.stationHash,
|
||||
maxUsers: station.maxUsers,
|
||||
currentUsers: station.currentUsers,
|
||||
spawns: utils.parseSpawns(station.spawnString),
|
||||
dispatcherName: station.dispatcherName,
|
||||
dispatcherRate: station.dispatcherRate,
|
||||
dispatcherId: station.dispatcherId,
|
||||
dispatcherExp: station.dispatcherExp,
|
||||
dispatcherIsSupporter: station.dispatcherIsSupporter,
|
||||
stationTrains,
|
||||
statusTimestamp,
|
||||
statusID,
|
||||
statusTimeString: utils.timestampToString(statusTimestamp)
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, [] as any);
|
||||
|
||||
const updatedTrainList = await Promise.all(
|
||||
onlineTrainsData
|
||||
.filter(train => train.region === "eu")
|
||||
.map(async train => {
|
||||
const locoType = train.dataCon.split(";") ? train.dataCon.split(";")[0] : train.dataCon;
|
||||
|
||||
return {
|
||||
trainNo: train.trainNo,
|
||||
mass: train.dataMass,
|
||||
length: train.dataLength,
|
||||
speed: train.dataSpeed,
|
||||
distance: train.dataDistance,
|
||||
signal: train.dataSignal,
|
||||
online: train.isOnline,
|
||||
driverId: train.driverId,
|
||||
driverName: train.driverName,
|
||||
currentStationName: train.station.stationName,
|
||||
currentStationHash: train.station.stationHash,
|
||||
connectedTrack: train.dataSceneryConnection,
|
||||
locoType,
|
||||
locoURL: utils.getLocoURL(locoType),
|
||||
cars: train.dataCon.split(";").filter((train, i) => i > 0) || []
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
this.context.commit("updateOnlineStations", updatedStationList);
|
||||
this.context.commit("updateOnlineTrains", updatedTrainList);
|
||||
|
||||
this.context.dispatch("fetchTimetableData");
|
||||
})
|
||||
.catch(() => {
|
||||
this.context.commit("setDataConnectionStatus", DataStatus.Error);
|
||||
});
|
||||
}
|
||||
|
||||
// Fetching timetable data from API basing on online trains
|
||||
@Action({ commit: "updateTimetableData" })
|
||||
async fetchTimetableData() {
|
||||
return this.trainList.reduce(async (acc: Promise<Timetable[]>, train: Train) => {
|
||||
const timetable: TimetableAPIData = await (await axios.get(utils.timetableURL(train.trainNo))).data.message;
|
||||
const trainInfo = timetable.trainInfo;
|
||||
|
||||
if (!timetable || !trainInfo) return acc;
|
||||
|
||||
const followingStops: TrainStop[] = timetable.stopPoints.reduce((stopsAcc: TrainStop[], point) => {
|
||||
if (point.pointNameRAW.toLowerCase().includes("sbl")) return stopsAcc;
|
||||
|
||||
const arrivalTimestamp = utils.getTimestamp(point.arrivalTime);
|
||||
const arrivalRealTimestamp = utils.getTimestamp(point.arrivalRealTime);
|
||||
|
||||
const departureTimestamp = utils.getTimestamp(point.departureTime);
|
||||
const departureRealTimestamp = utils.getTimestamp(point.departureRealTime);
|
||||
|
||||
stopsAcc.push({
|
||||
stopName: point.pointName,
|
||||
stopNameRAW: point.pointNameRAW,
|
||||
stopType: point.pointStopType,
|
||||
stopDistance: point.pointDistance,
|
||||
|
||||
mainStop: point.pointName.includes("strong"),
|
||||
|
||||
arrivalLine: point.arrivalLine,
|
||||
arrivalTimeString: utils.timestampToString(arrivalTimestamp),
|
||||
arrivalTimestamp: arrivalTimestamp,
|
||||
arrivalRealTimeString: utils.timestampToString(arrivalRealTimestamp),
|
||||
arrivalRealTimestamp: arrivalRealTimestamp,
|
||||
arrivalDelay: point.arrivalDelay,
|
||||
|
||||
departureLine: point.departureLine,
|
||||
departureTimeString: utils.timestampToString(departureTimestamp),
|
||||
departureTimestamp: departureTimestamp,
|
||||
departureRealTimeString: utils.timestampToString(departureRealTimestamp),
|
||||
departureRealTimestamp: departureRealTimestamp,
|
||||
departureDelay: point.departureDelay,
|
||||
|
||||
beginsHere: arrivalTimestamp == 0,
|
||||
terminatesHere: departureTimestamp == 0,
|
||||
|
||||
confirmed: point.confirmed,
|
||||
stopped: point.isStopped,
|
||||
stopTime: point.pointStopTime
|
||||
});
|
||||
|
||||
return stopsAcc;
|
||||
}, []);
|
||||
|
||||
(await acc).push({
|
||||
trainNo: train.trainNo,
|
||||
driverName: train.driverName,
|
||||
driverId: train.driverId,
|
||||
currentStationName: train.currentStationName,
|
||||
currentStationHash: train.currentStationHash,
|
||||
timetableId: trainInfo.timetableId,
|
||||
category: trainInfo.trainCategoryCode,
|
||||
route: trainInfo.route,
|
||||
TWR: trainInfo.twr,
|
||||
SKR: trainInfo.skr,
|
||||
routeDistance: timetable.stopPoints[timetable.stopPoints.length - 1].pointDistance,
|
||||
followingStops,
|
||||
followingSceneries: trainInfo.sceneries
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, Promise.resolve([]));
|
||||
}
|
||||
|
||||
//MUTATIONS
|
||||
@Mutation
|
||||
private setDataConnectionStatus(status: DataStatus) {
|
||||
this.dataConnectionStatus = status;
|
||||
}
|
||||
|
||||
@Mutation
|
||||
private setSceneryDataStatus(status: DataStatus) {
|
||||
this.sceneryDataStatus = status;
|
||||
}
|
||||
|
||||
@Mutation
|
||||
private setSceneryData() {
|
||||
/*
|
||||
0: stationName,
|
||||
1: stationURL,
|
||||
2: stationlines,
|
||||
3: stationProject?,
|
||||
4: reqLevel,
|
||||
5: supportersOnly,
|
||||
6: signalType,
|
||||
7: controlType,
|
||||
8: SBL,
|
||||
9: two-way block,
|
||||
10: routes, one-way, catenary,
|
||||
11: routes, one-way, no catenary,
|
||||
12: routes, two-way, catenary,
|
||||
13: routes, two-way, no catenary,
|
||||
14: subStations?,
|
||||
15: stops?,
|
||||
16: default,
|
||||
17: nonPublic,
|
||||
18: unavailable
|
||||
*/
|
||||
|
||||
this.stationList = JSONStationData.map(station => ({
|
||||
stationName: station[0] as string,
|
||||
stationURL: station[1] as string,
|
||||
stationLines: station[2] as string,
|
||||
stationProject: station[3] as string,
|
||||
reqLevel: station[4] as string,
|
||||
supportersOnly: station[5] == "TAK",
|
||||
signalType: station[6] as string,
|
||||
controlType: station[7] as string,
|
||||
SBL: station[8] as string,
|
||||
TWB: station[9] as string,
|
||||
routes: {
|
||||
oneWay: {
|
||||
catenary: station[10] as number,
|
||||
noCatenary: station[11] as number
|
||||
},
|
||||
twoWay: {
|
||||
catenary: station[12] as number,
|
||||
noCatenary: station[13] as number
|
||||
}
|
||||
},
|
||||
checkpoints: station[14] ? (station[14] as string[]).map(sub => ({ checkpointName: sub, scheduledTrains: [] })) : null,
|
||||
stops: station[15] as string[],
|
||||
|
||||
default: station[16] as boolean,
|
||||
nonPublic: station[17] as boolean,
|
||||
unavailable: station[18] as boolean,
|
||||
|
||||
stationHash: "",
|
||||
maxUsers: 0,
|
||||
currentUsers: 0,
|
||||
dispatcherName: "",
|
||||
dispatcherRate: 0,
|
||||
dispatcherExp: -1,
|
||||
dispatcherId: 0,
|
||||
dispatcherIsSupporter: false,
|
||||
online: false,
|
||||
statusTimestamp: -3,
|
||||
statusID: "free",
|
||||
statusTimeString: "",
|
||||
stationTrains: [],
|
||||
scheduledTrains: [],
|
||||
spawns: []
|
||||
}));
|
||||
}
|
||||
|
||||
@Mutation
|
||||
private updateOnlineStations(updatedStationList: any[]) {
|
||||
this.stationList = this.stationList.reduce((acc: Station[], station) => {
|
||||
const onlineStationData = updatedStationList.find(updatedStation => updatedStation.stationName === station.stationName);
|
||||
const listedStationData = JSONStationData.find(data => data[0] === station.stationName);
|
||||
|
||||
if (onlineStationData)
|
||||
acc.push({
|
||||
...station,
|
||||
...onlineStationData,
|
||||
online: true
|
||||
});
|
||||
else if (listedStationData)
|
||||
acc.push({
|
||||
...station,
|
||||
stationProject: "",
|
||||
stationHash: "",
|
||||
maxUsers: 0,
|
||||
currentUsers: 0,
|
||||
dispatcherName: "",
|
||||
dispatcherRate: 0,
|
||||
dispatcherExp: -1,
|
||||
dispatcherId: 0,
|
||||
dispatcherIsSupporter: false,
|
||||
online: false,
|
||||
statusID: "free",
|
||||
statusTimestamp: -3,
|
||||
statusTimeString: "",
|
||||
stationTrains: [],
|
||||
scheduledTrains: [],
|
||||
checkpoints: null
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, [] as Station[]);
|
||||
|
||||
updatedStationList
|
||||
.filter(uStation => !this.stationList.some(station => uStation.stationName === station.stationName))
|
||||
.forEach(uStation => {
|
||||
this.stationList.push({
|
||||
...uStation,
|
||||
scheduledTrains: [],
|
||||
stationTrains: uStation.stationTrains || [],
|
||||
subStations: [],
|
||||
online: true,
|
||||
reqLevel: "-1",
|
||||
nonPublic: true
|
||||
});
|
||||
});
|
||||
|
||||
this.stationCount = this.stationList.filter(station => station.online).length;
|
||||
this.dataConnectionStatus = DataStatus.Loaded;
|
||||
}
|
||||
|
||||
@Mutation
|
||||
private updateOnlineTrains(updatedTrainList) {
|
||||
this.trainList = updatedTrainList.reduce((acc, updatedTrain) => {
|
||||
const trainData = this.trainList.find(train => train.trainNo === updatedTrain.trainNo);
|
||||
|
||||
if (trainData) acc.push({ ...trainData, ...updatedTrain });
|
||||
else acc.push({ ...updatedTrain });
|
||||
|
||||
return acc;
|
||||
}, [] as Train[]);
|
||||
|
||||
this.trainCount = this.trainList.filter(train => train.online).length;
|
||||
this.dataConnectionStatus = DataStatus.Loaded;
|
||||
}
|
||||
|
||||
@Mutation
|
||||
private updateTimetableData(timetableList: Timetable[]) {
|
||||
this.stationList = this.stationList.map(station => {
|
||||
const stationName = station.stationName.toLowerCase();
|
||||
|
||||
const scheduledTrains: Station["scheduledTrains"] = timetableList.reduce((acc: Station["scheduledTrains"], timetable: Timetable, index) => {
|
||||
if (!timetable.followingSceneries.includes(station.stationHash)) return acc;
|
||||
|
||||
const stopInfoIndex = timetable.followingStops.findIndex(stop => {
|
||||
const stopName = stop.stopNameRAW.toLowerCase();
|
||||
|
||||
if (stationName === stopName) return true;
|
||||
if (stopName.includes(stationName) && !stop.stopName.includes("po.") && !stop.stopName.includes("podg.")) return true;
|
||||
if (stationName.includes(stopName) && !stop.stopName.includes("po.") && !stop.stopName.includes("podg.")) return true;
|
||||
if (stopName.includes("podg.") && stopName.split(", podg.")[0] && stationName.includes(stopName.split(", podg.")[0])) return true;
|
||||
|
||||
if (station.stops && station.stops.includes(stop.stopNameRAW)) return true;
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (stopInfoIndex == -1) return acc;
|
||||
|
||||
const trainStop = timetable.followingStops[stopInfoIndex];
|
||||
const trainStopStatus = utils.getTrainStopStatus(trainStop, timetable, station);
|
||||
|
||||
acc.push({
|
||||
trainNo: timetable.trainNo,
|
||||
driverName: timetable.driverName,
|
||||
driverId: timetable.driverId,
|
||||
currentStationName: timetable.currentStationName,
|
||||
currentStationHash: timetable.currentStationHash,
|
||||
category: timetable.category,
|
||||
beginsAt: timetable.followingStops[0].stopNameRAW,
|
||||
terminatesAt: timetable.followingStops[timetable.followingStops.length - 1].stopNameRAW,
|
||||
nearestStop: "",
|
||||
stopInfo: trainStop,
|
||||
stopLabel: trainStopStatus.stopLabel,
|
||||
stopStatus: trainStopStatus.stopStatus,
|
||||
stopStatusID: trainStopStatus.stopStatusID
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
if (station.checkpoints) {
|
||||
station.checkpoints.forEach(cp => (cp.scheduledTrains.length = 0));
|
||||
|
||||
for (let checkpoint of station.checkpoints) {
|
||||
timetableList.forEach(timetable => {
|
||||
timetable.followingStops
|
||||
.filter(trainStop => trainStop.stopNameRAW.toLowerCase() === checkpoint.checkpointName.toLowerCase())
|
||||
.forEach(trainStop => {
|
||||
const trainStopStatus = utils.getTrainStopStatus(trainStop, timetable, station);
|
||||
|
||||
checkpoint.scheduledTrains.push({
|
||||
trainNo: timetable.trainNo,
|
||||
driverName: timetable.driverName,
|
||||
driverId: timetable.driverId,
|
||||
currentStationName: timetable.currentStationName,
|
||||
currentStationHash: timetable.currentStationHash,
|
||||
category: timetable.category,
|
||||
beginsAt: timetable.followingStops[0].stopNameRAW,
|
||||
terminatesAt: timetable.followingStops[timetable.followingStops.length - 1].stopNameRAW,
|
||||
nearestStop: "",
|
||||
stopInfo: trainStop,
|
||||
stopLabel: trainStopStatus.stopLabel,
|
||||
stopStatus: trainStopStatus.stopStatus,
|
||||
stopStatusID: trainStopStatus.stopStatusID
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { ...station, scheduledTrains };
|
||||
});
|
||||
|
||||
this.trainList = this.trainList.reduce((acc, train) => {
|
||||
const timetableData = timetableList.find(data => data && data.trainNo === train.trainNo);
|
||||
|
||||
const trainStopData = this.stationList
|
||||
.find(station => station.stationName === train.currentStationName)
|
||||
?.scheduledTrains.find(stationTrain => stationTrain.trainNo === train.trainNo);
|
||||
|
||||
acc.push({ ...train, timetableData, stopStatus: trainStopData?.stopStatus || "", stopLabel: trainStopData?.stopLabel || "" });
|
||||
|
||||
return acc;
|
||||
}, [] as Train[]);
|
||||
|
||||
this.timetableDataStatus = DataStatus.Loaded;
|
||||
}
|
||||
}
|
||||
@@ -1,333 +0,0 @@
|
||||
<template>
|
||||
<div class="history_view">
|
||||
<div class="history_wrapper">
|
||||
<div class="header">
|
||||
<h2>{{ $t("journal.title") }}</h2>
|
||||
<p style="color: #ccc">
|
||||
{{ $t("journal.subtitle") }}
|
||||
</p>
|
||||
|
||||
<!-- <select-box
|
||||
:itemList="filteredStationList"
|
||||
:title="$t('journal.select')"
|
||||
@itemSelected="itemSelected"
|
||||
/> -->
|
||||
|
||||
<div class="disclaimer" v-html="$t('journal.disclaimer')"></div>
|
||||
</div>
|
||||
|
||||
<div class="list">
|
||||
<div class="list_wrapper">
|
||||
<!-- <div class="list_loading" v-if="dataLoading">POBIERANIE DANYCH...</div> -->
|
||||
<transition name="list-anim" mode="out-in">
|
||||
<ul
|
||||
class="list_content"
|
||||
v-if="
|
||||
!dataLoading &&
|
||||
!historyLoading &&
|
||||
computedHistoryList.length != 0
|
||||
"
|
||||
:key="inputStationName"
|
||||
>
|
||||
<li v-if="currentDispatcherFrom != -1" class="current">
|
||||
<div class="dispatcher-name">
|
||||
<a
|
||||
:href="`https://td2.info.pl/profile/?u=${currentDispatcherId}`"
|
||||
>{{ currentDispatcher }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="dispatcher-date">
|
||||
<span style="color: #bbb">{{
|
||||
new Date(currentDispatcherFrom).toLocaleDateString("pl-PL")
|
||||
}}</span>
|
||||
{{
|
||||
new Date(currentDispatcherFrom).toLocaleTimeString(
|
||||
"pl-PL",
|
||||
{ hour: "2-digit", minute: "2-digit" }
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li v-for="(history, i) in computedHistoryList" :key="i">
|
||||
<div class="dispatcher-name">
|
||||
<a
|
||||
:href="`https://td2.info.pl/profile/?u=${history.dispatcherId}`"
|
||||
>{{ history.dispatcherName }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="dispatcher-date">
|
||||
<div>
|
||||
<span style="color: #888">{{
|
||||
history.dispatcherFromDate
|
||||
}}</span>
|
||||
{{ history.dispatcherFromTime }}
|
||||
</div>
|
||||
<div>
|
||||
<span style="color: #888">{{
|
||||
history.dispatcherToDate
|
||||
}}</span>
|
||||
{{ history.dispatcherToTime }}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import axios from "axios";
|
||||
|
||||
import { Component, Vue, Watch } from "vue-property-decorator";
|
||||
import { Getter } from "vuex-class";
|
||||
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import Scenery from "@/scripts/interfaces/Scenery";
|
||||
|
||||
import SelectBox from "@/components/Global/SelectBox.vue";
|
||||
|
||||
@Component({ components: { SelectBox } })
|
||||
export default class HistoryView extends Vue {
|
||||
@Getter("getStationList") stationList!: Station[];
|
||||
|
||||
sceneryHistoryList: Scenery[] = [];
|
||||
currentSceneryHistory: Scenery["dispatcherHistory"] = [];
|
||||
|
||||
currentDispatcher: string = "";
|
||||
currentDispatcherId: number = 0;
|
||||
currentDispatcherFrom: number = -1;
|
||||
|
||||
inputStationName = "";
|
||||
|
||||
dataLoading = true; /* Initial data */
|
||||
historyLoading = false; /* History loaded after input is checked */
|
||||
|
||||
async mounted() {
|
||||
try {
|
||||
const responseData: Scenery[] = await (
|
||||
await axios.get(
|
||||
"https://stacjownik.herokuapp.com/api/getSceneryInfo?items=-1"
|
||||
)
|
||||
).data;
|
||||
|
||||
this.sceneryHistoryList = responseData;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
this.dataLoading = false;
|
||||
}
|
||||
|
||||
get filteredStationList() {
|
||||
return this.sceneryHistoryList
|
||||
.map((station) => station.stationName)
|
||||
.sort((a, b) => (a.toLowerCase() >= b.toLowerCase() ? 1 : -1));
|
||||
}
|
||||
|
||||
get computedHistoryList() {
|
||||
return this.currentSceneryHistory
|
||||
.map(
|
||||
({ dispatcherName, dispatcherFrom, dispatcherTo, dispatcherId }) => ({
|
||||
dispatcherName,
|
||||
dispatcherFrom,
|
||||
dispatcherTo,
|
||||
dispatcherId,
|
||||
dispatcherFromDate: new Date(dispatcherFrom).toLocaleDateString(
|
||||
"pl-PL"
|
||||
),
|
||||
dispatcherFromTime: new Date(dispatcherFrom).toLocaleTimeString(
|
||||
"pl-PL",
|
||||
{ hour: "2-digit", minute: "2-digit" }
|
||||
),
|
||||
dispatcherToDate: new Date(dispatcherTo).toLocaleDateString("pl-PL"),
|
||||
dispatcherToTime: new Date(dispatcherTo).toLocaleTimeString("pl-PL", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
}),
|
||||
})
|
||||
)
|
||||
.reverse();
|
||||
}
|
||||
|
||||
async itemSelected(itemName: string) {
|
||||
try {
|
||||
this.historyLoading = true;
|
||||
|
||||
const selectedScenery: Scenery = await (
|
||||
await axios.get(
|
||||
`https://stacjownik.herokuapp.com/api/getSceneryInfo?name=${itemName}&items=10`
|
||||
)
|
||||
).data;
|
||||
|
||||
this.currentSceneryHistory = selectedScenery.dispatcherHistory;
|
||||
this.currentDispatcher = selectedScenery.currentDispatcher;
|
||||
this.currentDispatcherId = selectedScenery.currentDispatcherId;
|
||||
this.currentDispatcherFrom = selectedScenery.currentDispatcherFrom;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
this.historyLoading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "../styles/responsive.scss";
|
||||
|
||||
.history {
|
||||
&_view {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
&_wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.list-anim {
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all 150ms ease-out;
|
||||
}
|
||||
|
||||
&-enter,
|
||||
&-leave-to {
|
||||
opacity: 0.1;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
&-move {
|
||||
transition: transform 100ms;
|
||||
}
|
||||
}
|
||||
|
||||
.disclaimer {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&_content {
|
||||
position: relative;
|
||||
margin: 1em 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
select {
|
||||
border: none;
|
||||
font-size: 1em;
|
||||
|
||||
background-color: rgb(87, 87, 87);
|
||||
padding: 0.3em;
|
||||
padding-right: 50px;
|
||||
outline: none;
|
||||
|
||||
color: white;
|
||||
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
label {
|
||||
position: relative;
|
||||
|
||||
&.disabled::after {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "<>";
|
||||
|
||||
position: absolute;
|
||||
top: -5%;
|
||||
right: 0.3em;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
text-align: center;
|
||||
margin: 1em 0;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
&_loading,
|
||||
&_no-info {
|
||||
margin: 0.3em 0;
|
||||
padding: 0.5em 2em;
|
||||
|
||||
color: white;
|
||||
}
|
||||
|
||||
&_loading {
|
||||
background-color: #b96b11;
|
||||
}
|
||||
|
||||
&_no-info {
|
||||
background-color: firebrick;
|
||||
}
|
||||
|
||||
&_wrapper {
|
||||
@include smallScreen() {
|
||||
width: 95%;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
|
||||
&_content {
|
||||
max-height: 75vh;
|
||||
overflow: auto;
|
||||
|
||||
padding: 0.2em 0.5em;
|
||||
}
|
||||
|
||||
&_content > li {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
|
||||
background: #222;
|
||||
padding: 0.3em 0.8em;
|
||||
margin: 0.3em 0;
|
||||
|
||||
gap: 10em;
|
||||
|
||||
@include smallScreen() {
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
& > div {
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
&.current {
|
||||
background: #007200;
|
||||
}
|
||||
|
||||
& > .dispatcher-name {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
font-size: 1.1em;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+51
-36
@@ -11,8 +11,14 @@
|
||||
</action-button>
|
||||
</div>
|
||||
|
||||
<div class="scenery-wrapper" v-if="stationInfo">
|
||||
<SceneryInfo :stationInfo="stationInfo" :timetableOnly="timetableOnly" />
|
||||
<div
|
||||
class="scenery-wrapper"
|
||||
v-if="stationInfo"
|
||||
>
|
||||
<SceneryInfo
|
||||
:stationInfo="stationInfo"
|
||||
:timetableOnly="timetableOnly"
|
||||
/>
|
||||
|
||||
<SceneryTimetable
|
||||
:stationInfo="stationInfo"
|
||||
@@ -24,49 +30,58 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from "vue-property-decorator";
|
||||
|
||||
import { Getter } from "vuex-class";
|
||||
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
import { StoreData } from "@/scripts/interfaces/StoreData";
|
||||
import { DataStatus } from "@/scripts/enums/DataStatus";
|
||||
|
||||
import SceneryInfo from "@/components/SceneryView/SceneryInfo.vue";
|
||||
import SceneryTimetable from "@/components/SceneryView/SceneryTimetable.vue";
|
||||
import { StoreData } from "@/scripts/interfaces/StoreData";
|
||||
import { DataStatus } from "@/scripts/enums/DataStatus";
|
||||
import ActionButton from "@/components/Global/ActionButton.vue";
|
||||
|
||||
@Component({
|
||||
import { computed, ComputedRef, defineComponent } from "@vue/runtime-core";
|
||||
import { useStore } from "@/store";
|
||||
import { GETTERS } from "@/constants/storeConstants";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
export default defineComponent({
|
||||
components: { SceneryInfo, SceneryTimetable, ActionButton },
|
||||
})
|
||||
export default class SceneryView extends Vue {
|
||||
@Getter("getAllData") data!: StoreData;
|
||||
|
||||
timetableOnly: boolean = false;
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const store = useStore();
|
||||
|
||||
activated() {
|
||||
this.timetableOnly =
|
||||
this.$route.query["timetable_only"] == "1" ? true : false;
|
||||
}
|
||||
|
||||
get isComponentVisible() {
|
||||
return this.$route.path === "/scenery";
|
||||
}
|
||||
|
||||
get isDataLoaded() {
|
||||
return this.data.dataConnectionStatus == DataStatus.Loaded;
|
||||
}
|
||||
|
||||
get stationInfo(): Station | undefined {
|
||||
if (!this.$route.query.station) return;
|
||||
|
||||
return this.data.stationList.find(
|
||||
(station) =>
|
||||
station.stationName ===
|
||||
this.$route.query.station.toString().replaceAll("_", " ")
|
||||
const data: ComputedRef<StoreData> = computed(
|
||||
() => store.getters[GETTERS.allData]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const timetableOnly = computed(() =>
|
||||
route.query["timetable_only"] == "1" ? true : false
|
||||
);
|
||||
|
||||
const isComponentVisible = computed(() => route.path === "/scenery");
|
||||
|
||||
const isDataLoaded = computed(
|
||||
() => data.value.dataConnectionStatus === DataStatus.Loaded
|
||||
);
|
||||
|
||||
const stationInfo = computed(() => {
|
||||
if (!route.query.station) return;
|
||||
|
||||
return data.value.stationList.find(
|
||||
(station) =>
|
||||
station.stationName ===
|
||||
route.query.station?.toString().replaceAll("_", " ")
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
timetableOnly,
|
||||
isComponentVisible,
|
||||
isDataLoaded,
|
||||
stationInfo,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
+82
-113
@@ -1,14 +1,9 @@
|
||||
<template>
|
||||
<div class="stations-view">
|
||||
<DonationModal
|
||||
:modalHidden="modalHidden"
|
||||
@toggleModal="toggleModal"
|
||||
/>
|
||||
|
||||
<div class="wrapper">
|
||||
<div class="body">
|
||||
<div class="options-bar">
|
||||
<action-button @click.native="() => toggleCardsState('filter')">
|
||||
<action-button @click="() => toggleCardsState('filter')">
|
||||
<img
|
||||
class="button_icon"
|
||||
:src="require('@/assets/icon-filter2.svg')"
|
||||
@@ -42,7 +37,7 @@
|
||||
|
||||
<transition name="card-anim">
|
||||
<FilterCard
|
||||
v-if="filterCardOpen"
|
||||
:showCard="filterCardOpen"
|
||||
:exit="() => toggleCardsState('filter')"
|
||||
@changeFilterValue="changeFilterValue"
|
||||
@resetFilters="resetFilters"
|
||||
@@ -52,10 +47,6 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from "vue-property-decorator";
|
||||
|
||||
import { Getter } from "vuex-class";
|
||||
|
||||
import Station from "@/scripts/interfaces/Station";
|
||||
|
||||
import StorageManager from "@/scripts/managers/storageManager";
|
||||
@@ -68,128 +59,106 @@ import FilterCard from "@/components/StationsView/FilterCard.vue";
|
||||
import ActionButton from "@/components/Global/ActionButton.vue";
|
||||
import { StoreData } from "@/scripts/interfaces/StoreData";
|
||||
import { DataStatus } from "@/scripts/enums/DataStatus";
|
||||
import { computed, ComputedRef, defineComponent, reactive } from "vue";
|
||||
import { useStore } from "@/store";
|
||||
import { GETTERS } from "@/constants/storeConstants";
|
||||
|
||||
@Component({
|
||||
export default defineComponent({
|
||||
components: {
|
||||
StationTable,
|
||||
FilterCard,
|
||||
ActionButton,
|
||||
},
|
||||
})
|
||||
export default class StationsView extends Vue {
|
||||
STORAGE_KEY: string = "options_saved";
|
||||
STORAGE_MODAL: string = "modal";
|
||||
data: () => ({
|
||||
trainIcon: require("@/assets/icon-train.svg"),
|
||||
timetableIcon: require("@/assets/icon-timetable.svg"),
|
||||
dolarIcon: require("@/assets/icon-dolar.svg"),
|
||||
filterCardOpen: false,
|
||||
modalHidden: true,
|
||||
STORAGE_KEY: "options_saved",
|
||||
inputs: inputData,
|
||||
}),
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const filterManager = reactive(new StationFilterManager());
|
||||
const focusedStationName = "";
|
||||
|
||||
trainIcon: string = require("@/assets/icon-train.svg");
|
||||
timetableIcon: string = require("@/assets/icon-timetable.svg");
|
||||
dolarIcon: string = require("@/assets/icon-dolar.svg");
|
||||
const data: ComputedRef<StoreData> = computed(
|
||||
() => store.getters[GETTERS.allData]
|
||||
);
|
||||
|
||||
filterManager: StationFilterManager = new StationFilterManager();
|
||||
|
||||
focusedStationName: string = "";
|
||||
filterCardOpen: boolean = false;
|
||||
modalHidden: boolean = true;
|
||||
|
||||
inputs = inputData;
|
||||
|
||||
@Getter("getStationList") stationList!: Station[];
|
||||
@Getter("getAllData") data!: StoreData;
|
||||
|
||||
get dataStatusClass() {
|
||||
if (this.data.dataConnectionStatus == DataStatus.Loading) return "loading";
|
||||
if (this.data.dataConnectionStatus == DataStatus.Error) return "error";
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
get timetableDataStatusClass() {
|
||||
if (this.data.timetableDataStatus == DataStatus.Loading) return "loading";
|
||||
if (this.data.timetableDataStatus == DataStatus.Error) return "error";
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
mounted() {
|
||||
this.initializeOptionsStorage();
|
||||
// this.initializeModalStorage();
|
||||
|
||||
window.addEventListener("keydown", (e: KeyboardEvent) => {
|
||||
if (e.keyCode == 27 && this.focusedStationName != "") {
|
||||
this.focusedStationName = "";
|
||||
}
|
||||
const computedStations: ComputedRef<Station[]> = computed(() => {
|
||||
return filterManager.getFilteredStationList(
|
||||
store.getters[GETTERS.stationList]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
initializeOptionsStorage() {
|
||||
const getStatusClass = computed(() => {
|
||||
if (data.value.dataConnectionStatus == DataStatus.Loading)
|
||||
return "loading";
|
||||
if (data.value.dataConnectionStatus == DataStatus.Error) return "error";
|
||||
return "success";
|
||||
});
|
||||
|
||||
const timetableDataStatusClass = computed(() => {
|
||||
if (data.value.timetableDataStatus == DataStatus.Loading)
|
||||
return "loading";
|
||||
if (data.value.timetableDataStatus == DataStatus.Error) return "error";
|
||||
return "success";
|
||||
});
|
||||
|
||||
const focusedStationInfo = computed(() =>
|
||||
computedStations.value.find(
|
||||
(station) => station.stationName === focusedStationName
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
data,
|
||||
computedStations,
|
||||
filterManager,
|
||||
getStatusClass,
|
||||
timetableDataStatusClass,
|
||||
focusedStationName,
|
||||
focusedStationInfo,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (!StorageManager.isRegistered(this.STORAGE_KEY)) return;
|
||||
|
||||
this.inputs.options.forEach((option) => {
|
||||
const value = StorageManager.getBooleanValue(option.name);
|
||||
|
||||
this.changeFilterValue({ name: option.name, value: value ? 0 : 1 });
|
||||
option.value = value;
|
||||
});
|
||||
|
||||
this.inputs.sliders.forEach((slider) => {
|
||||
const value = StorageManager.getNumericValue(slider.name);
|
||||
|
||||
this.changeFilterValue({ name: slider.name, value });
|
||||
slider.value = value;
|
||||
});
|
||||
}
|
||||
|
||||
initializeModalStorage() {
|
||||
if (StorageManager.isRegistered(`${this.STORAGE_MODAL}_hidden`))
|
||||
this.modalHidden = StorageManager.getBooleanValue(
|
||||
`${this.STORAGE_MODAL}_hidden`
|
||||
);
|
||||
}
|
||||
|
||||
toggleModal() {
|
||||
this.modalHidden = !this.modalHidden;
|
||||
|
||||
StorageManager.setBooleanValue(
|
||||
`${this.STORAGE_MODAL}_hidden`,
|
||||
this.modalHidden
|
||||
);
|
||||
}
|
||||
|
||||
toggleCardsState(name: string): void {
|
||||
if (name == "filter") {
|
||||
this.filterCardOpen = !this.filterCardOpen;
|
||||
}
|
||||
}
|
||||
|
||||
changeSorter(index: number) {
|
||||
this.filterManager.changeSorter(index);
|
||||
}
|
||||
|
||||
changeFilterValue(filter: { name: string; value: number }) {
|
||||
this.filterManager.changeFilterValue(filter);
|
||||
}
|
||||
|
||||
resetFilters() {
|
||||
this.filterManager.resetFilters();
|
||||
}
|
||||
|
||||
get computedStations() {
|
||||
return this.filterManager.getFilteredStationList(this.stationList);
|
||||
}
|
||||
|
||||
closeCard() {
|
||||
this.focusedStationName = "";
|
||||
}
|
||||
|
||||
setFocusedStation(name: string) {
|
||||
this.focusedStationName = this.focusedStationName == name ? "" : name;
|
||||
}
|
||||
|
||||
get focusedStationInfo() {
|
||||
return this.computedStations.find(
|
||||
(station) => station.stationName === this.focusedStationName
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleCardsState(name: string): void {
|
||||
if (name == "filter") {
|
||||
this.filterCardOpen = !this.filterCardOpen;
|
||||
}
|
||||
},
|
||||
changeSorter(index: number) {
|
||||
this.filterManager.changeSorter(index);
|
||||
},
|
||||
changeFilterValue(filter: { name: string; value: number }) {
|
||||
this.filterManager.changeFilterValue(filter);
|
||||
},
|
||||
resetFilters() {
|
||||
this.filterManager.resetFilters();
|
||||
},
|
||||
closeCard() {
|
||||
this.focusedStationName = "";
|
||||
},
|
||||
setFocusedStation(name: string) {
|
||||
this.focusedStationName = this.focusedStationName == name ? "" : name;
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -202,7 +171,7 @@ export default class StationsView extends Vue {
|
||||
transition: all $animDuration $animType;
|
||||
}
|
||||
|
||||
&-enter,
|
||||
&-enter-from,
|
||||
&-leave-to {
|
||||
transform: translate(-50%, -50%) scale(0.85);
|
||||
opacity: 0;
|
||||
|
||||
+110
-78
@@ -2,11 +2,14 @@
|
||||
<section class="trains-view">
|
||||
<div class="wrapper">
|
||||
<div class="options-bar">
|
||||
<TrainStats :trains="trains" :trainStatsOpen="trainStatsOpen" />
|
||||
<TrainStats
|
||||
:trains="trainList"
|
||||
:trainStatsOpen="trainStatsOpen"
|
||||
/>
|
||||
|
||||
<TrainOptions
|
||||
:queryTrain="queryTrain"
|
||||
@change-sorter="changeSorter"
|
||||
@changeSorter="changeSorter"
|
||||
@changeSearchedTrain="changeSearchedTrain"
|
||||
@changeSearchedDriver="changeSearchedDriver"
|
||||
/>
|
||||
@@ -14,7 +17,6 @@
|
||||
|
||||
<TrainTable
|
||||
:computedTrains="computedTrains"
|
||||
:timetableDataStatus="timetableDataStatus"
|
||||
:queryTrain="queryTrain"
|
||||
/>
|
||||
</div>
|
||||
@@ -22,105 +24,135 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
import { Component, Prop } from "vue-property-decorator";
|
||||
import { Getter } from "vuex-class";
|
||||
import { computed, ComputedRef, defineComponent, ref } from "vue";
|
||||
|
||||
import { DataStatus } from "@/scripts/enums/DataStatus";
|
||||
import Train from "@/scripts/interfaces/Train";
|
||||
|
||||
import TrainTable from "@/components/TrainsView/TrainTable.vue";
|
||||
import TrainStats from "@/components/TrainsView/TrainStats.vue";
|
||||
import TrainOptions from "@/components/TrainsView/TrainOptions.vue";
|
||||
import ActionButton from "@/components/Global/ActionButton.vue";
|
||||
import { DataStatus } from "@/scripts/enums/DataStatus";
|
||||
|
||||
@Component({
|
||||
import { useStore } from "@/store";
|
||||
import { GETTERS } from "@/constants/storeConstants";
|
||||
|
||||
const filteredTrainList = (
|
||||
trainList: Train[],
|
||||
searchedTrain: string,
|
||||
searchedDriver: string,
|
||||
sorterActive: { id: string; dir: number }
|
||||
) => {
|
||||
return trainList
|
||||
.filter(
|
||||
(train) =>
|
||||
train.online &&
|
||||
(searchedTrain.length > 0
|
||||
? train.trainNo.toString().includes(searchedTrain)
|
||||
: true) &&
|
||||
(searchedDriver.length > 0
|
||||
? train.driverName
|
||||
.toLowerCase()
|
||||
.includes(searchedDriver.toLowerCase())
|
||||
: true)
|
||||
)
|
||||
.sort((a: Train, b: Train) => {
|
||||
switch (sorterActive.id) {
|
||||
case "mass":
|
||||
if (a.mass > b.mass) return sorterActive.dir;
|
||||
return -sorterActive.dir;
|
||||
|
||||
case "distance":
|
||||
if (
|
||||
(a.timetableData?.routeDistance || -1) >
|
||||
(b.timetableData?.routeDistance || -1)
|
||||
)
|
||||
return sorterActive.dir;
|
||||
|
||||
return -sorterActive.dir;
|
||||
|
||||
case "speed":
|
||||
if (a.speed > b.speed) return sorterActive.dir;
|
||||
return -sorterActive.dir;
|
||||
|
||||
case "timetable":
|
||||
if (a.trainNo > b.trainNo) return sorterActive.dir;
|
||||
return -sorterActive.dir;
|
||||
|
||||
case "length":
|
||||
if (a.length > b.length) return sorterActive.dir;
|
||||
return -sorterActive.dir;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
TrainTable,
|
||||
TrainStats,
|
||||
TrainOptions,
|
||||
ActionButton,
|
||||
},
|
||||
})
|
||||
export default class TrainsView extends Vue {
|
||||
@Getter("getTrainList") trains!: Train[];
|
||||
@Getter("getTimetableDataStatus") timetableDataStatus!: DataStatus;
|
||||
|
||||
// Passed in route as query parameters
|
||||
@Prop() readonly queryTrain!: string;
|
||||
props: ["queryTrain"],
|
||||
|
||||
statsIcon = require("@/assets/icon-stats.svg");
|
||||
data: () => ({
|
||||
statsIcon: require("@/assets/icon-stats.svg"),
|
||||
trainStatsOpen: false,
|
||||
}),
|
||||
|
||||
sorterActive: { id: string; dir: number } = { id: "distance", dir: -1 };
|
||||
setup() {
|
||||
const store = useStore();
|
||||
|
||||
trainStatsOpen: boolean = false;
|
||||
const trainList: ComputedRef<Train[]> = computed(
|
||||
() => store.getters[GETTERS.trainList]
|
||||
);
|
||||
|
||||
searchedTrain: string = "";
|
||||
searchedDriver: string = "";
|
||||
const timetableDataStatus: ComputedRef<DataStatus> = computed(
|
||||
() => store.getters[GETTERS.timetableDataStatus]
|
||||
);
|
||||
|
||||
changeSearchedTrain(trainNo: string) {
|
||||
this.searchedTrain = trainNo;
|
||||
}
|
||||
const sorterActive = ref({ id: "distance", dir: -1 });
|
||||
const searchedDriver = ref("");
|
||||
const searchedTrain = ref("");
|
||||
|
||||
changeSearchedDriver(name: string) {
|
||||
this.searchedDriver = name;
|
||||
}
|
||||
const computedTrains: ComputedRef<Train[]> = computed(() => {
|
||||
if (timetableDataStatus.value != DataStatus.Loaded) return [];
|
||||
|
||||
changeSorter(sorter: { id: string; dir: number }) {
|
||||
this.sorterActive = sorter;
|
||||
}
|
||||
return filteredTrainList(
|
||||
trainList.value,
|
||||
searchedTrain.value,
|
||||
searchedDriver.value,
|
||||
sorterActive.value
|
||||
);
|
||||
});
|
||||
|
||||
get computedTrains() {
|
||||
return this.timetableDataStatus != DataStatus.Loaded
|
||||
? []
|
||||
: this.trains
|
||||
.filter(
|
||||
(train) =>
|
||||
train.online &&
|
||||
(this.searchedTrain.length > 0
|
||||
? train.trainNo.toString().includes(this.searchedTrain)
|
||||
: true) &&
|
||||
(this.searchedDriver.length > 0
|
||||
? train.driverName
|
||||
.toLowerCase()
|
||||
.includes(this.searchedDriver.toLowerCase())
|
||||
: true)
|
||||
)
|
||||
.sort((a, b) => {
|
||||
switch (this.sorterActive.id) {
|
||||
case "mass":
|
||||
if (a.mass > b.mass) return this.sorterActive.dir;
|
||||
return -this.sorterActive.dir;
|
||||
return {
|
||||
trainList,
|
||||
computedTrains,
|
||||
searchedTrain,
|
||||
searchedDriver,
|
||||
sorterActive,
|
||||
};
|
||||
},
|
||||
|
||||
case "distance":
|
||||
if (
|
||||
(a.timetableData?.routeDistance || -1) >
|
||||
(b.timetableData?.routeDistance || -1)
|
||||
)
|
||||
return this.sorterActive.dir;
|
||||
methods: {
|
||||
changeSearchedTrain(trainNo: string) {
|
||||
this.searchedTrain = trainNo;
|
||||
},
|
||||
|
||||
return -this.sorterActive.dir;
|
||||
changeSearchedDriver(name: string) {
|
||||
this.searchedDriver = name;
|
||||
},
|
||||
|
||||
case "speed":
|
||||
if (a.speed > b.speed) return this.sorterActive.dir;
|
||||
return -this.sorterActive.dir;
|
||||
|
||||
case "timetable":
|
||||
if (a.trainNo > b.trainNo) return this.sorterActive.dir;
|
||||
return -this.sorterActive.dir;
|
||||
|
||||
case "length":
|
||||
if (a.length > b.length) return this.sorterActive.dir;
|
||||
return -this.sorterActive.dir;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
changeSorter(sorter: { id: string; dir: number }) {
|
||||
this.sorterActive = sorter;
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
import { ComponentCustomProperties } from 'vue'
|
||||
import { Store } from 'vuex'
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
// declare your own store states
|
||||
interface State {
|
||||
count: number
|
||||
}
|
||||
|
||||
// provide typings for `this.$store`
|
||||
interface ComponentCustomProperties {
|
||||
$store: Store<State>
|
||||
}
|
||||
}
|
||||
+1
-21
@@ -1,23 +1,3 @@
|
||||
// module.exports = {
|
||||
// publicPath: process.env.NODE_ENV === "production" ? "/dist" : "/",
|
||||
// };
|
||||
|
||||
module.exports = {
|
||||
chainWebpack: config => {
|
||||
config.resolve.alias.set('vue', '@vue/compat')
|
||||
|
||||
config.module
|
||||
.rule('vue')
|
||||
.use('vue-loader')
|
||||
.tap(options => {
|
||||
return {
|
||||
...options,
|
||||
compilerOptions: {
|
||||
compatConfig: {
|
||||
MODE: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// };
|
||||
Reference in New Issue
Block a user