66 Commits

Author SHA1 Message Date
Spythere dcea5f7102 Merge pull request #17 from Spythere/development
hotfix: global states refresh
2025-05-07 18:31:51 +02:00
Spythere 2f5e61352a hotfix: global states refresh 2025-05-07 18:31:22 +02:00
Spythere 1d9df380fd Merge pull request #16 from Spythere/development
v1.5.2
2025-05-02 14:47:08 +02:00
Spythere 153d6ff0db bump: v1.5.2 2025-05-02 14:43:13 +02:00
Spythere a9a486a789 chore: added selecting train picker's scenery from query ID 2025-05-02 14:38:55 +02:00
Spythere 85772df972 Merge pull request #15 from Spythere/development
v1.5.1
2025-03-22 16:12:20 +01:00
Spythere 0464f4eae9 hotfix: recovered vue-tsc 2025-03-20 20:49:07 +01:00
Spythere 339b3edd1e chore: changed npm for yarn in gh workflows 2025-03-20 20:47:50 +01:00
Spythere 069b27beaa bump: v1.5.1 2025-03-20 20:45:23 +01:00
Spythere 7b18f84db1 fix: order typos, additional information 2025-03-20 20:44:27 +01:00
Spythere 42d0d1ddb9 refactor: changed fetching fonts from remote to local; changed sass import rules to use
chore: updated packages
2025-03-20 20:36:57 +01:00
Spythere b1a51bbd74 Merge pull request #14 from Spythere/development
v1.5.0
2025-02-07 14:10:47 +01:00
Spythere f28f1e31c2 chore: dark & light mode improvements 2025-02-07 14:08:06 +01:00
Spythere 0930dab77c chore: order picker regions 2025-02-07 13:55:53 +01:00
Spythere e81521ed09 chore: improved order header styling 2025-02-07 13:40:16 +01:00
Spythere b69c44c55a revamp: order train picker 2025-02-07 00:11:34 +01:00
Spythere fab3cef1f3 bump: v1.5.0 2025-02-06 20:48:11 +01:00
Spythere 99e55bb8b9 feat: order dark mode; refreshed color palette 2025-02-06 20:47:59 +01:00
Spythere d050cf0b89 Merge pull request #13 from Spythere/development
Wersja 1.4.3
2024-05-30 16:13:50 +02:00
Spythere 1b8bf5cc45 hotfix 2024-05-30 16:10:22 +02:00
Spythere a180215dd0 chore: order compatibility warnings 2024-05-30 16:08:44 +02:00
Spythere 5649e7c417 bump: 1.4.3 2024-05-30 15:50:05 +02:00
Spythere 8b8d69132d chore: minor fixes 2024-05-30 15:49:20 +02:00
Spythere af579f2cba chore: order stylings; fix: compatibility with deprecated orders 2024-05-30 15:34:03 +02:00
Spythere d0052f8dd3 Merge pull request #12 from Spythere/development
Wersja 1.4.2
2024-05-29 19:39:43 +02:00
Spythere 28ba4045a0 bump: 1.4.2 2024-05-28 16:21:11 +02:00
Spythere d76c9a8521 feature: order 'N' 6th row; chore: textareas sizing 2024-05-28 16:21:00 +02:00
Spythere 10d5beae3c Merge pull request #11 from Spythere/development
Wersja 1.4.1
2024-05-18 20:23:29 +02:00
Spythere d84ad635ee chore: version bump (1.4.1) 2024-05-18 20:20:41 +02:00
Spythere ae0beadb93 chore: order "O" field fix; responsiveness 2024-05-18 20:20:11 +02:00
Spythere 758bb9f997 Merge pull request #10 from Spythere/development
Wersja 1.4.0
2023-12-10 01:36:31 +01:00
Spythere 85c4fba8ba bump wersji: 1.4.0 2023-12-09 20:14:44 +01:00
Spythere af2af08fbc format & lint; poprawki do nowego API 2023-12-09 20:14:22 +01:00
Spythere 8aa2233d41 aktualizacja paczek i API 2023-12-09 19:20:09 +01:00
Spythere f663c96842 Merge do wersji 1.3.1
Wersja 1.3.1
2023-09-04 19:29:01 +02:00
Spythere b663f7408d bump: 1.3.1 2023-09-04 19:01:24 +02:00
Spythere 05f3f8f8b2 zapamiętywanie uzupełniania skrótu 2023-09-04 19:01:09 +02:00
Spythere bb285f9ba6 aktualizacja URLi 2023-09-04 18:52:56 +02:00
Spythere 43d74ddaea Merge do wersji 1.3.0 2023-06-13 17:26:51 +02:00
Spythere 53be6c8cf2 hotfix 2023-06-12 22:09:54 +02:00
Spythere 39236ece3e bump: 1.3.0; hotfixy 2023-06-12 22:03:36 +02:00
Spythere c40e699b40 fix: template W5 2023-06-12 22:02:32 +02:00
Spythere 76c6169be9 feature: generator pomijania W5 2023-06-12 20:10:47 +02:00
Spythere 76c1e97ddd Merge do wersji 1.2.1
Wersja 1.2.1
2023-05-16 02:14:36 +02:00
Spythere 71c9a47ea5 update gitignore 2023-05-16 02:10:03 +02:00
Spythere a066da006c bump: 1.2.1 2023-05-16 02:09:47 +02:00
Spythere 1783ae1fce bug fix; feature: autouzupełnianie godz. 2023-05-16 02:08:13 +02:00
Spythere 7921bd46e9 Wersja 1.2.0 (merge)
Wersja 1.2.0
2023-05-01 01:20:22 +02:00
Spythere 189720c206 bump wersji: 1.2.0 2023-05-01 01:16:34 +02:00
Spythere e5e0751024 feature: pobieranie skrótu posterunku z API 2023-05-01 01:16:20 +02:00
Spythere 45ac3248ac Merge pull request #5 from Spythere/development
Wersja 1.1.1
2022-12-31 18:55:47 +01:00
Spythere 06d33a30ed bump: v1.1.1 2022-12-31 18:54:50 +01:00
Spythere e7fd51142d fix: swdr api url 2022-12-31 18:52:33 +01:00
Spythere bed61c38f6 Merge pull request #4 from Spythere/development
Update API
2022-12-26 18:44:40 +01:00
Spythere a1d81986c6 Update API 2022-12-25 23:51:44 +01:00
Spythere e4ee67918a Merge do wersji 1.1.0
Wersja 1.1.0
2022-11-20 01:25:30 +01:00
Spythere f85bd13765 Wersja prod. 2022-11-20 01:24:39 +01:00
Spythere f2015a2af5 Zmiana projektu firebase 2022-11-20 01:14:38 +01:00
Spythere f7a456e791 Animacja checkboxa 2022-11-20 01:10:00 +01:00
Spythere 262042c5b1 Poprawka literówki 2022-11-17 21:19:12 +01:00
Spythere e8574efa42 Styl checkboxów 2022-11-17 21:11:38 +01:00
Spythere 2119399c45 Poprawki listy 2022-11-17 15:45:42 +01:00
Spythere df25fb0b36 Checkboxy i numeracja rozkazów 2022-11-17 15:34:05 +01:00
Spythere 94235df38d Poprawki responsywności 2022-11-17 14:33:00 +01:00
Spythere 3155487a29 Design 2022-11-16 12:54:14 +01:00
Spythere dc2062d906 Wybór posterunku 2022-11-16 12:26:31 +01:00
67 changed files with 5521 additions and 12428 deletions
+4 -2
View File
@@ -1,2 +1,4 @@
VITE_APP_API_URL=https://stacjownik-api-b9mrc.ondigitalocean.app/api
VITE_APP_SWDR_URL=https://api.td2.info.pl:9640
VITE_APP_API_URL=https://stacjownik.spythere.eu/api
VITE_APP_SWDR_URL=https://api.td2.info.pl
VITE_APP_ORDER_VERSION=2
+17
View File
@@ -0,0 +1,17 @@
/* eslint-env node */
module.exports = {
root: true,
extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting'
],
rules: {
'vue/multi-word-component-names': 'off'
},
parserOptions: {
ecmaVersion: 'latest'
}
};
+1 -1
View File
@@ -1,5 +1,5 @@
{
"projects": {
"default": "genera-tor"
"default": "generator-td2"
}
}
+3 -3
View File
@@ -11,10 +11,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm ci && npm run build
- run: yarn && yarn build
- uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: '${{ secrets.GITHUB_TOKEN }}'
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_GENERA_TOR }}'
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_GENERATOR_TD2 }}'
channelId: live
projectId: genera-tor
projectId: generator-td2
@@ -9,9 +9,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm ci && npm run build
- run: yarn && yarn build
- uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: '${{ secrets.GITHUB_TOKEN }}'
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_GENERA_TOR }}'
projectId: genera-tor
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_GENERATOR_TD2 }}'
projectId: generator-td2
+1
View File
@@ -2,6 +2,7 @@
node_modules
/dev-dist
.log
/dist
# local env files
.env.local
+7
View File
@@ -0,0 +1,7 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none"
}
-5
View File
@@ -1,5 +0,0 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

-4
View File
@@ -1,4 +0,0 @@
<svg width="144" height="144" viewBox="0 0 144 144" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M76.3333 17.9839C76.3267 15.5906 74.3812 13.6578 71.988 13.6667C69.5948 13.6756 67.6601 15.6229 67.6667 18.0161L76.3333 17.9839ZM72.2408 105.15L97.1394 61.7232L47.1027 61.9097L72.2408 105.15ZM67.6667 18.0161L67.7997 66.1659L76.4663 66.1336L76.3333 17.9839L67.6667 18.0161Z" fill="white"/>
<path d="M14 83.2536V127H131V83.2536" stroke="white" stroke-width="11.2667" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 530 B

File diff suppressed because one or more lines are too long
-9
View File
File diff suppressed because one or more lines are too long
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#00aba9</TileColor>
</tile>
</msapplication>
</browserconfig>
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 650 B

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

-36
View File
@@ -1,36 +0,0 @@
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<!-- Favicon -->
<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png" />
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png" />
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png" />
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png" />
<link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png" />
<link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png" />
<link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png" />
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png" />
<link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="manifest" href="/manifest.json" />
<meta name="msapplication-TileColor" content="#ffffff" />
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
<meta name="theme-color" content="#ffffff" />
<title>GeneraTOR</title>
<meta name="description" content="Generator rozkazów pisemnych online" />
<script type="module" crossorigin src="/assets/index.d3173749.js"></script>
<link rel="stylesheet" href="/assets/index.705ed11d.css">
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
<body>
<div id="app"></div>
</body>
</html>
-23
View File
@@ -1,23 +0,0 @@
{
"name": "GeneraTOR",
"short_name": "GeneraTOR",
"start_url": ".",
"display": "standalone",
"background_color": "#313638",
"theme_color": "#ff6060",
"description": "Generator rozkazów pisemnych",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}
-1
View File
@@ -1 +0,0 @@
{"name":"genera-tor","short_name":"genera-tor","start_url":"/","display":"standalone","background_color":"#ffffff","lang":"en","scope":"/"}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

-1
View File
@@ -1 +0,0 @@
if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js', { scope: '/' })})}
-42
View File
@@ -1,42 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.14, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M2310 5109 c-502 -55 -974 -249 -1355 -556 -129 -104 -340 -321 -433
-445 -265 -354 -434 -758 -498 -1193 -22 -147 -29 -428 -15 -575 42 -433 180
-833 405 -1174 414 -629 1047 -1032 1791 -1142 147 -22 428 -29 575 -15 433
42 833 180 1174 405 629 414 1032 1047 1142 1791 22 147 29 428 15 575 -51
524 -238 988 -558 1385 -104 129 -321 340 -445 433 -354 265 -755 432 -1193
498 -121 18 -487 26 -605 13z m-520 -1749 l0 -120 -325 0 -325 0 0 -470 0
-470 213 2 212 3 3 158 3 157 -96 0 -95 0 0 110 0 110 218 -2 217 -3 0 -280 0
-280 -30 -60 c-36 -73 -95 -116 -180 -133 -88 -18 -457 -16 -529 3 -117 31
-176 97 -196 221 -13 80 -13 852 0 933 20 122 76 188 184 215 88 23 91 23 424
25 l302 1 0 -120z m459 60 c16 -23 152 -228 303 -457 l273 -416 3 457 2 456
110 0 110 0 0 -660 c0 -653 0 -659 20 -670 18 -10 170 -162 256 -255 23 -26
179 -190 434 -458 41 -43 79 -90 84 -103 22 -65 -25 -134 -91 -134 -30 0 -46
11 -112 75 l-77 75 -995 0 -995 0 -69 -70 c-62 -62 -74 -70 -108 -70 -53 0
-87 35 -87 91 0 38 6 48 78 123 42 44 116 121 163 171 47 49 132 140 190 200
58 61 151 158 207 217 l102 108 0 680 0 680 85 0 85 0 29 -40z m1817 25 c62
-18 111 -54 146 -107 45 -67 53 -108 53 -298 0 -211 -12 -257 -84 -329 -25
-26 -56 -54 -69 -62 l-23 -14 31 -42 c20 -27 60 -123 111 -267 43 -123 79
-227 79 -230 0 -3 -57 -6 -128 -6 l-127 0 -79 238 c-43 130 -85 247 -92 260
-14 21 -20 22 -154 22 l-140 0 0 -260 0 -260 -130 0 -130 0 0 678 c0 373 3
682 7 685 3 4 158 7 343 7 267 0 347 -3 386 -15z"/>
<path d="M2270 2537 l0 -447 -30 0 c-28 0 -30 -2 -30 -39 0 -30 -8 -49 -36
-83 l-37 -43 428 -3 c236 -1 430 0 433 3 3 2 -10 21 -28 41 -28 33 -32 43 -27
80 l4 43 -41 3 -40 3 -284 430 c-155 237 -289 437 -297 445 -13 12 -15 -42
-15 -433z"/>
<path d="M2024 1808 c-33 -35 -65 -70 -71 -78 -10 -13 60 -15 618 -15 346 0
629 1 629 3 0 2 -32 37 -72 78 l-71 74 -486 0 -487 0 -60 -62z"/>
<path d="M1770 1540 l-92 -100 893 0 893 0 -44 48 c-25 26 -67 71 -95 100
l-49 52 -707 0 -707 0 -92 -100z"/>
<path d="M3590 3035 l0 -205 203 2 202 3 3 203 2 202 -205 0 -205 0 0 -205z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

-19
View File
@@ -1,19 +0,0 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}
Vendored
-1
View File
@@ -1 +0,0 @@
if(!self.define){let e,i={};const n=(n,r)=>(n=new URL(n+".js",r).href,i[n]||new Promise((i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()})).then((()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didnt register its module`);return e})));self.define=(r,s)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(i[o])return;let d={};const c=e=>n(e,o),t={module:{uri:o},exports:d,require:c};i[o]=Promise.all(r.map((e=>t[e]||c(e)))).then((e=>(s(...e),d)))}}define(["./workbox-3625d7b0"],(function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"android-chrome-192x192.png",revision:"587a303e0bc5130743216d71e95e2b3f"},{url:"android-chrome-512x512.png",revision:"a2b75707c3b4e4dc7be3c0493a2e11fd"},{url:"apple-touch-icon.png",revision:"a72231c73410e833e7542f9ae34b4c4d"},{url:"assets/icon-save.5a12487e.svg",revision:null},{url:"assets/index.705ed11d.css",revision:null},{url:"assets/index.d3173749.js",revision:null},{url:"favicon-16x16.png",revision:"90a108cf04a9bd9990266d9d8337ed6a"},{url:"favicon-32x32.png",revision:"8411776198fb04093e6862bc7a2f7734"},{url:"index.html",revision:"c54b79fee86bfc30080bbf0b58d85200"},{url:"mstile-150x150.png",revision:"7930e41cef90048a1570dabcecd74d0b"},{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"safari-pinned-tab.svg",revision:"bfc326d45774cbb917a60157231c7a39"},{url:"manifest.webmanifest",revision:"a0d456bb8bd7fce3475d10d340ee9776"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))}));
-1
View File
File diff suppressed because one or more lines are too long
-9015
View File
File diff suppressed because it is too large Load Diff
+22 -13
View File
@@ -1,26 +1,35 @@
{
"name": "genera-tor",
"version": "1.1.3dev",
"version": "1.5.2",
"private": true,
"type": "module",
"scripts": {
"dev": "vite --port 8080",
"deploy": "yarn build && firebase deploy --only hosting",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview"
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"axios": "^1.1.3",
"pinia": "^2.0.14",
"vue": "^3.2.37",
"vue-i18n": "9",
"vue-router": "^4.0.0-0",
"vue-tsc": "^1.0.9"
"axios": "^1.6.2",
"pinia": "^2.1.7",
"vue": "^3.3.11",
"vue-i18n": "9.8.0",
"vue-router": "^4.2.5",
"vue-tsc": "^2.2.8"
},
"devDependencies": {
"@vitejs/plugin-vue": "^3.2.0",
"sass": "^1.56.0",
"typescript": "^4.8.4",
"vite": "^3.2.2",
"vite-plugin-pwa": "^0.13.2"
"@types/node": "^22.13.10",
"@vitejs/plugin-vue": "^4.5.2",
"@vue/eslint-config-prettier": "^8.0.0",
"@vue/eslint-config-typescript": "^12.0.0",
"eslint": "^8.49.0",
"eslint-plugin-vue": "^9.17.0",
"prettier": "^3.0.3",
"sass": "^1.69.5",
"typescript": "^5.3.3",
"vite": "^5.0.7",
"vite-plugin-pwa": "^0.17.4"
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+27 -27
View File
@@ -3,13 +3,15 @@
<router-view />
<transition name="slide-anim">
<div v-if="needRefresh" class="update-prompt" @click="updateServiceWorker(true)">Nowa wersja GeneraTORa dostępna! <u>Kliknij, aby odświeżyć aplikację!</u></div>
<div v-if="needRefresh" class="update-prompt" @click="updateServiceWorker(true)">
Nowa wersja GeneraTORa dostępna!
<u>Kliknij, aby odświeżyć aplikację!</u>
</div>
</transition>
<footer>
&copy; <a href="https://td2.info.pl/profile/?u=20777">Spythere</a> {{ new Date().getUTCFullYear() }} | v.{{
appVersion
}}
&copy; <a href="https://td2.info.pl/profile/?u=20777">Spythere</a>
{{ new Date().getUTCFullYear() }} | v.{{ appVersion }}
</footer>
</div>
</template>
@@ -18,40 +20,39 @@
import { useRegisterSW } from 'virtual:pwa-register/vue';
import { defineComponent } from 'vue';
import packageInfo from '../package.json';
import { useStore } from './store/store';
import orderStorageMixin from './mixins/orderStorageMixin';
export default defineComponent({
setup() {
const { offlineReady, needRefresh, updateServiceWorker } = useRegisterSW({
immediate: true,
});
mixins: [orderStorageMixin],
return {
offlineReady,
needRefresh,
updateServiceWorker,
};
setup() {
const { offlineReady, needRefresh, updateServiceWorker } = useRegisterSW({ immediate: true });
return { offlineReady, needRefresh, updateServiceWorker };
},
data() {
return {
appVersion: packageInfo.version,
needRefreshTest: false,
};
return { appVersion: packageInfo.version, store: useStore() };
},
created() {
document.title = `GeneraTOR ${this.appVersion}`;
this.store.orderDarkMode = this.getOrderSetting('dark-mode') === 'true';
setTimeout(() => {
this.needRefreshTest = true;
}, 500);
},
const query = new URLSearchParams(window.location.search);
const id = query.get('sceneryId');
if (id != null) {
this.store.orderMode = 'OrderTrainPicker';
}
}
});
</script>
<style lang="scss">
@import './styles/global.scss';
@import './styles/anims.scss';
@use 'styles/anims';
@use 'styles/colors';
#app {
color: white;
@@ -70,7 +71,7 @@ export default defineComponent({
text-align: center;
width: 100%;
background-color: $accentCol;
background-color: colors.$accentCol;
cursor: pointer;
}
@@ -82,8 +83,7 @@ footer {
@media screen and (max-width: 500px) {
#app {
font-size: calc(1vw + 0.5rem);
font-size: calc(1vw + 0.65rem);
}
}
</style>
+95 -53
View File
@@ -1,5 +1,5 @@
<template>
<div class="order">
<div class="order" :class="{ dark: store.orderDarkMode }">
<div class="order_content">
<transition name="order-anim" mode="out-in">
<keep-alive>
@@ -19,11 +19,7 @@ import OrderSVue from './OrderS.vue';
import OrderFooter from './OrderFooter.vue';
import OrderOVue from './OrderO.vue';
const orderComponents = {
orderN: OrderNVue,
orderS: OrderSVue,
orderO: OrderOVue,
};
const orderComponents = { orderN: OrderNVue, orderS: OrderSVue, orderO: OrderOVue };
export default defineComponent({
components: { OrderNVue, OrderSVue, OrderFooter },
@@ -31,44 +27,31 @@ export default defineComponent({
setup() {
const store = useStore();
return {
store,
};
return { store };
},
computed: {
chosenOrderComponent() {
return orderComponents[this.store.chosenOrderType];
},
},
}
}
});
</script>
<style lang="scss">
@import '../styles/global.scss';
@use '../styles/colors';
// Order scrollbar
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
background: #fff;
}
::-webkit-scrollbar-thumb {
background: #ccc;
}
::-webkit-scrollbar-thumb:hover {
background: #aaa;
}
$darkModeTextCol: #eee;
.order {
background-color: white;
color: black;
height: 925px;
&.dark {
background-color: colors.$bgColDarker;
color: $darkModeTextCol;
}
max-height: 95vh;
overflow: auto;
@@ -79,10 +62,28 @@ export default defineComponent({
padding: 0;
}
.header {
padding: 0.5em;
border: 2px solid black;
border-bottom: none;
textarea:focus-visible {
outline: 2px solid colors.$accentCol;
}
input[type='checkbox']:focus-visible,
input[type='radio']:focus-visible {
outline: 2px solid colors.$accentCol;
}
input[type='checkbox'],
input[type='radio'],
select {
margin-top: 0.5em;
margin-right: 0.5em;
font-size: 0.8em;
color: black;
}
textarea.others {
width: 100%;
min-height: 200px;
resize: vertical;
}
@media screen and (max-width: 550px) {
@@ -90,6 +91,12 @@ export default defineComponent({
}
}
.order_header {
padding: 0.5em;
border: 2px solid black;
border-bottom: none;
}
.order_content {
padding: 0.5em;
}
@@ -112,19 +119,26 @@ export default defineComponent({
align-items: center;
}
input {
.horizontal-bar {
width: 100%;
height: 2px;
background-color: black;
margin: 0.5em 0;
}
.order input {
max-width: 100px;
background-color: transparent;
outline: none;
border: none;
font-size: 1em;
border-bottom: 2px dotted black;
font-size: 0.9em;
text-align: center;
color: black;
border-bottom: 2px dotted black;
&:focus-visible {
border-bottom: 2px solid $accentCol;
border-bottom: 2px solid colors.$accentCol;
}
&.row-checkbox + input::placeholder {
@@ -132,23 +146,52 @@ input {
}
}
input[type='checkbox'],
input[type='radio'],
textarea,
select {
&:focus-visible {
outline: 2px solid $accentCol;
/* Dark mode */
.order.dark {
input {
border-color: $darkModeTextCol !important;
color: $darkModeTextCol !important;
&:focus-visible {
border-bottom: 2px solid colors.$accentCol !important;
}
&::placeholder {
color: #ccc !important;
}
}
select {
color: $darkModeTextCol !important;
border-color: $darkModeTextCol;
&:focus-visible {
border-color: colors.$accentCol;
}
}
option,
textarea {
color: $darkModeTextCol !important;
border-color: $darkModeTextCol !important;
background-color: colors.$bgColDarker !important;
}
.horizontal-bar {
background-color: white;
}
.order_header,
.order_other,
table,
tr,
td {
border-color: $darkModeTextCol !important;
}
}
select {
margin-top: 0.5em;
margin-right: 0.5em;
font-size: 0.8em;
}
.table-section {
table.options-table {
.order_table-container {
table {
width: 100%;
td:first-child {
@@ -187,4 +230,3 @@ select {
}
}
</style>
+9 -5
View File
@@ -36,7 +36,11 @@
</td>
<td colspan="5">
<input type="text" v-model="footerInfo.secondaryDispatcherName" placeholder="dyżurny (wypełnić jedno)" />
<input
type="text"
v-model="footerInfo.secondaryDispatcherName"
placeholder="dyżurny (wypełnić jedno)"
/>
<br />
z polecenia dyżurnego ruchu
</td>
@@ -59,7 +63,7 @@ export default defineComponent({
return {
store,
footerInfo: store.orderFooter,
footerInfo: store.orderFooter
};
},
@@ -68,9 +72,9 @@ export default defineComponent({
deep: true,
handler() {
this.generateFooter();
},
},
},
}
}
}
});
</script>
+12 -12
View File
@@ -11,11 +11,14 @@
<li>
<b>Przetaczanie (manewr) taboru poza wskaźnik W 5 (granicy przetaczania)</b>
<p>
Rozkazu <u>nie stosujemy</u> w przypadku wyjazdu taboru na szlak dwutorowy, na którym odbywa się ruch w
kierunku zasadniczym, tj. "prawostronnym". Dla wszystkich szlaków jednotorowych lub dwutorowych w sytuacji innej niż wymieniona
wykorzystujemy działkę 4. rozkazu pisemnego "S".
<br><br>
<i>Szczegółowe informacje: instrukcja Ir-1 (R-1) § 12 pkt 4 "Manewry na torach głównych"</i>
Rozkazu <u>nie stosujemy</u> w przypadku wyjazdu taboru na szlak dwutorowy, na którym
odbywa się ruch w kierunku zasadniczym, tj. "prawostronnym". Dla wszystkich szlaków
jednotorowych lub dwutorowych w sytuacji innej niż wymieniona wykorzystujemy działkę 4.
rozkazu pisemnego "S". <br /><br />
<i
>Szczegółowe informacje: instrukcja Ir-1 (R-1) § 12 pkt 4 "Manewry na torach
głównych"</i
>
</p>
<button class="g-button action">Wygeneruj treść rozkazu</button>
</li>
@@ -31,16 +34,13 @@ import orderHelperData from '../data/orderHelperData.json';
export default defineComponent({
setup() {
return {
store: useStore(),
orderHelperData,
};
},
return { store: useStore(), orderHelperData };
}
});
</script>
<style lang="scss" scoped>
@import "../styles/global.scss";
@use '../styles/colors';
.content {
width: 100%;
@@ -63,7 +63,7 @@ ul {
li b {
font-size: 1.1em;
color: $accentCol;
color: colors.$accentCol;
}
}
</style>
+76 -28
View File
@@ -3,20 +3,37 @@
<h3>Zapisane rozkazy pisemne ({{ localOrderList.length }})</h3>
<transition-group name="list" tag="ul">
<li class="no-orders-warning" v-if="sortedOrderList.length == 0" :key="-1">Brak zapisanych rozkazów!</li>
<li class="no-orders-warning" v-if="sortedOrderList.length == 0" :key="-1">
Brak zapisanych rozkazów!
</li>
<li v-for="order in sortedOrderList" :selected="order.id == store.chosenLocalOrderId" :key="order.id">
<li
v-for="order in sortedOrderList"
:selected="order.id == store.chosenLocalOrderId"
:key="order.id"
>
<b class="text--accent">#{{ order.id.split('-')[1] }}&nbsp;</b>
<b>
{{ getOrderName(order.orderType) }} nr {{ order.orderBody['header']['orderNo'] }} dla pociągu nr
{{ order.orderBody['header']['trainNo'] }}
{{ getOrderName(order.orderType) }} nr {{ order.orderBody['header']['orderNo'] }} dla
pociągu nr {{ order.orderBody['header']['trainNo'] }}
</b>
<span
v-if="!order.orderVersion || order.orderVersion != ORDER_VERSION"
class="wrong-order-indicator"
tabindex="0"
data-tooltip="Przestarzała wersja rozkazu! Może generować złe informacje!"
>&#9888;
</span>
<br />
{{ order.createdAt ? 'Dodano: ' : 'Zaktualizowano: ' }}
{{ new Date(order.createdAt || order.updatedAt || 0).toLocaleString('pl-PL') }}
<br />
<button class="g-button action" @click="selectLocalOrder(order)">Wybierz</button>
<button class="g-button action" @click="removeOrder(order)">Usuń</button>
<hr />
<div class="buttons">
<button class="g-button" @click="selectLocalOrder(order)">Wybierz</button>
<button class="g-button" @click="removeOrder(order)">Usuń</button>
</div>
</li>
</transition-group>
</section>
@@ -35,13 +52,14 @@ export default defineComponent({
data() {
return {
localOrderList: [] as LocalStorageOrder[],
ORDER_VERSION: import.meta.env['VITE_APP_ORDER_VERSION']
};
},
setup() {
return {
store: useStore(),
localStorage: window.localStorage,
localStorage: window.localStorage
};
},
@@ -54,15 +72,18 @@ export default defineComponent({
if (!order) return;
this.removeLocalOrder(order);
this.localOrderList = this.localOrderList.filter((o) => o.id != order.id);
},
if (this.localOrderList.length == 0) this.saveOrderSetting('orderCount', 0);
}
},
computed: {
sortedOrderList() {
return this.localOrderList.sort((a, b) => (b.createdAt || b.updatedAt!) - (a.createdAt || a.updatedAt!));
},
return this.localOrderList
.slice()
.sort((a, b) => (b.createdAt || b.updatedAt!) - (a.createdAt || a.updatedAt!));
}
},
activated() {
@@ -79,12 +100,12 @@ export default defineComponent({
}
this.localOrderList = orderList;
},
}
});
</script>
<style lang="scss" scoped>
@import '../styles/global.scss';
@use '../styles/colors';
.list {
&-move,
@@ -104,44 +125,71 @@ export default defineComponent({
}
.order-list {
padding: 1em;
overflow: auto;
}
hr {
border: 1px solid #aaa;
height: 0;
}
ul {
max-height: 750px;
height: 80vh;
overflow-y: auto;
overflow-x: hidden;
position: relative;
overflow: hidden;
}
h3 {
position: sticky;
top: 0;
z-index: 100;
margin: 0;
margin-bottom: 1em;
text-align: center;
background-color: colors.$bgColDarker;
padding: 1em;
margin-bottom: 0.5em;
}
li {
text-align: left;
padding: 1em;
margin: 0.5em;
background-color: #222;
background-color: colors.$bgColDarker;
cursor: pointer;
button {
margin: 1em 1em 0 0;
&[selected='true'] {
outline: 1px solid colors.$accentCol;
}
&[selected='true'] {
outline: 1px solid $accentCol;
}
&.no-orders-warning {
text-align: center;
font-size: 1.2em;
cursor: default;
}
}
</style>
.wrong-order-indicator {
color: colors.$accentCol;
padding: 0 0.25em;
}
.buttons {
display: flex;
gap: 0.5em;
button {
padding: 0.5em;
background-color: colors.$bgColLighter;
&:hover {
background-color: #666;
}
&:focus-visible {
outline: 2px solid colors.$accentCol;
}
}
}
</style>
+123 -17
View File
@@ -4,13 +4,18 @@
<div class="message_body" v-html="fullOrderMessage"></div>
<p class="message_info">
Po wygenerowaniu rozkazu skopiuj jego treść lub zapisz w pamięci przeglądarki za pomocą przycisków poniżej
Po wygenerowaniu rozkazu skopiuj jego treść lub zapisz w pamięci przeglądarki za pomocą
przycisków poniżej
</p>
<div class="message_actions">
<button class="g-button action" @click="saveOrder">Zapisz nowy rozkaz</button>
<button class="g-button action" @click="copyMessage">Kopiuj treść rozkazu</button>
<button class="g-button action" :data-disabled="!store.chosenLocalOrderId" @click="updateOrder">
<button
class="g-button action"
:data-disabled="!store.chosenLocalOrderId"
@click="updateOrder"
>
Zaktualizuj rozkaz
<span class="text--accent"
>{{ store.chosenLocalOrderId && `#${store.chosenLocalOrderId.split('-')[1]}` }}
@@ -18,6 +23,52 @@
</button>
</div>
<div class="message_checkboxes">
<label for="dark-mode" class="g-checkbox">
<input
type="checkbox"
name="dark-mode"
id="dark-mode"
v-model="store.orderDarkMode"
@change="onCheckboxChange"
/>
<span>Ciemny motyw rozkazu</span>
</label>
<label for="copy-increment" class="g-checkbox">
<input
type="checkbox"
name="copy-increment"
id="copy-increment"
v-model="incrementOnCopy"
@change="onCheckboxChange"
/>
<span>Aktualizuj numer rozkazu po skopiowaniu</span>
</label>
<label for="save-increment" class="g-checkbox">
<input
type="checkbox"
name="save-increment"
id="save-increment"
v-model="incrementOnSave"
@change="onCheckboxChange"
/>
<span>Aktualizuj numer rozkazu po zapisaniu</span>
</label>
<label for="update-date" class="g-checkbox">
<input
type="checkbox"
name="update-date"
id="update-date"
v-model="updateDate"
@change="onCheckboxChange"
/>
<span>Aktualizuj godziny przy edycji</span>
</label>
</div>
<transition name="monit-anim">
<div class="action_monit" v-if="actionMonit" v-html="actionMonit"></div>
</transition>
@@ -31,6 +82,7 @@ import { useStore } from '../store/store';
import saveIcon from '../assets/icon-save.svg';
import orderStorageMixin from '../mixins/orderStorageMixin';
import orderValidationMixin from '../mixins/orderValidationMixin';
import { currentFormattedHours, currentFormattedMinutes } from '../utils/dateUtils';
export default defineComponent({
name: 'OrderMessage',
@@ -42,22 +94,46 @@ export default defineComponent({
saveIcon,
actionMonit: '',
monitTimeout: undefined as number | undefined,
incrementOnSave: true,
incrementOnCopy: true,
updateDate: true
};
},
setup() {
return {
store: useStore(),
store: useStore()
};
},
mounted() {
this.incrementOnSave = this.getOrderSetting('save-increment') === 'true';
this.incrementOnCopy = this.getOrderSetting('copy-increment') === 'true';
this.updateDate = this.getOrderSetting('update-date') === 'true';
},
computed: {
fullOrderMessage() {
return this.store.orderMessage + this.store.footerMessage;
},
}
},
watch: {
fullOrderMessage() {
if (this.updateDate) {
this.store.orderFooter['hour'] = currentFormattedHours();
this.store.orderFooter['minutes'] = currentFormattedMinutes();
}
}
},
methods: {
onCheckboxChange(e: Event) {
const checkbox = e.target as HTMLInputElement;
this.saveOrderSetting(checkbox.id, checkbox.checked);
},
showActionMonit(text: string) {
if (this.monitTimeout) {
this.actionMonit = '';
@@ -81,6 +157,12 @@ export default defineComponent({
}, 5000);
},
incrementOrderNo() {
const order = this.store[this.store.chosenOrderType];
order.header.orderNo = (Number(order.header.orderNo) + 1).toString();
},
copyMessage() {
if (!navigator.clipboard)
return this.showActionMonit(
@@ -90,8 +172,14 @@ export default defineComponent({
const hasAtLeastOneRow = /(\[ \d \])/g.test(this.fullOrderMessage);
const hasAllInputsFilled = !/_/g.test(this.store.orderMessage);
if (!hasAllInputsFilled) return this.showActionMonit(`<span class="text--warn">Wypełnij puste rubryki rozkazu przed jego skopiowaniem!</span>`);
if (!hasAtLeastOneRow) return this.showActionMonit(`<span class="text--warn">Dodaj co najmniej jedną działkę rozkazu przed jego skopiowaniem!</span>`);
if (!hasAllInputsFilled)
return this.showActionMonit(
`<span class="text--warn">Wypełnij puste rubryki rozkazu przed jego skopiowaniem!</span>`
);
if (!hasAtLeastOneRow)
return this.showActionMonit(
`<span class="text--warn">Dodaj co najmniej jedną działkę rozkazu przed jego skopiowaniem!</span>`
);
const fieldsToCorrect = this.verifyOrderFields();
@@ -104,6 +192,8 @@ export default defineComponent({
navigator.clipboard.writeText(this.fullOrderMessage);
if (this.incrementOnCopy) this.incrementOrderNo();
this.showActionMonit(
'<b class="text--accent">Skopiowano!</b> Możesz teraz wkleić treść rozkazu na czacie symulatora!'
);
@@ -119,10 +209,16 @@ export default defineComponent({
);
break;
case 0:
this.showActionMonit('<span class="text--warn">Ostatni zapisany rozkaz jest identyczny z obecnym!</span>');
this.showActionMonit(
'<span class="text--warn">Ostatni zapisany rozkaz jest identyczny z obecnym!</span>'
);
break;
case 1:
this.showActionMonit('Zapisano treść <b class="text--accent">rozkazu</b> w pamięci przeglądarki!');
this.showActionMonit(
'Zapisano treść <b class="text--accent">rozkazu</b> w pamięci przeglądarki!'
);
if (this.incrementOnSave) this.incrementOrderNo();
break;
default:
@@ -135,26 +231,30 @@ export default defineComponent({
switch (updatedOrderStatus) {
case -1:
this.showActionMonit('<span class="text--warn">Wystąpił błąd podczas aktualizowania tego rozkazu! :/</span>');
this.showActionMonit(
'<span class="text--warn">Wystąpił błąd podczas aktualizowania tego rozkazu! :/</span>'
);
break;
case 0:
this.showActionMonit('<span class="text--warn">Nie wybrałeś żadnego zapisanego rozkazu!</span>');
this.showActionMonit(
'<span class="text--warn">Nie wybrałeś żadnego zapisanego rozkazu!</span>'
);
break;
case 1:
this.showActionMonit('Zaktualizowano treść <b class="text--accent">rozkazu</b>!');
break;
}
},
},
}
}
});
</script>
<style lang="scss" scoped>
.order-message {
padding: 1em;
@use '../styles/colors';
.order-message {
h3 {
margin: 0;
margin-bottom: 1em;
@@ -169,11 +269,12 @@ export default defineComponent({
.message_body {
height: 250px;
overflow: auto;
background-color: colors.$bgColLighter;
color: white;
text-align: justify;
background-color: #fff;
border-radius: 0.5em;
color: black;
padding: 0.5em;
user-select: none;
-moz-user-select: none;
@@ -203,6 +304,12 @@ export default defineComponent({
}
}
.message_checkboxes {
display: flex;
flex-direction: column;
margin-top: 1em;
}
.action_monit {
text-align: center;
padding: 1.5em;
@@ -222,4 +329,3 @@ export default defineComponent({
}
}
</style>
+126 -48
View File
@@ -1,17 +1,20 @@
<template>
<section class="order-n">
<section class="header" ref="header">
<section class="order_header" ref="header">
<h2 class="flex-center">
Rozkaz pisemny "N" nr
<input type="text" v-model="order.header.orderNo" placeholder="nr rozkazu" />
Rozkaz pisemny "N" nr &nbsp;
<input type="number" v-model="order.header.orderNo" placeholder="nr rozkazu" min="1" />
</h2>
<div class="flex-row">
dla pociągu nr <input type="text" v-model="order.header.trainNo" placeholder="nr pociągu" /> dnia
dla pociągu nr
<input type="text" v-model="order.header.trainNo" placeholder="nr pociągu" />
dnia
<input type="text" v-model="order.header.date" placeholder="data" />
</div>
</section>
<section class="table-section">
<table class="options-table">
<section class="order_table-container">
<table>
<tbody>
<tr>
<td>
@@ -21,10 +24,13 @@
</div>
</td>
<td ref="row-1">
Od <input type="text" v-model="order.rows[0].from" holder="stacja / post." /> do
<input type="text" v-model="order.rows[0].to" holder="stacja / post." /> tor nr
<input type="text" v-model="order.rows[0].trackNo" holder="nr toru" /> jest zamknięty, ruch jednotorowy
dwukierunkowy wprowadzono po torze nr
Od
<input type="text" v-model="order.rows[0].from" holder="stacja / post." />
do
<input type="text" v-model="order.rows[0].to" holder="stacja / post." />
tor nr
<input type="text" v-model="order.rows[0].trackNo" holder="nr toru" />
jest zamknięty, ruch jednotorowy dwukierunkowy wprowadzono po torze nr
<input type="text" v-model="order.rows[0].trackNo2" holder="nr toru" />
</td>
</tr>
@@ -69,7 +75,8 @@
v-model="order.rows[1].signal1"
holder="nazwa sem."
:radio-checked="
order.rows[1].checkbox == 'checkbox-2a' && order.rows[1].signalType == 'wyjazdowego'
order.rows[1].checkbox == 'checkbox-2a' &&
order.rows[1].signalType == 'wyjazdowego'
"
/>
</label>
@@ -89,7 +96,8 @@
v-model="order.rows[1].signal2"
holder="nazwa sem."
:radio-checked="
order.rows[1].checkbox == 'checkbox-2a' && order.rows[1].signalType == 'drogowskazowego'
order.rows[1].checkbox == 'checkbox-2a' &&
order.rows[1].signalType == 'drogowskazowego'
"
/>
(odnoszącego się do wyjazdu pociągu)
@@ -110,7 +118,8 @@
v-model="order.rows[1].signal3"
holder="nazwa sem."
:radio-checked="
order.rows[1].checkbox == 'checkbox-2a' && order.rows[1].signalType == 'wjazdowego'
order.rows[1].checkbox == 'checkbox-2a' &&
order.rows[1].signalType == 'wjazdowego'
"
/>
na post. odg. bez sem. wyjazdowego
@@ -191,15 +200,19 @@
<option value="Popychanie">Popychanie</option>
</select>
pociągu odbędzie się w kierunku:
<input type="text" v-model="order.rows[2].direction" holder="stacja / post." /> do km
<input type="text" v-model="order.rows[2].toKilometer" holder="kilometry" /> skąd
<input type="text" v-model="order.rows[2].direction" holder="stacja / post." />
do km
<input type="text" v-model="order.rows[2].toKilometer" holder="kilometry" />
skąd
<select v-model="order.rows[2].option2">
<option value="pociąg">pociąg</option>
<option value="popychacz">popychacz</option>
</select>
ma wrócić po torze lewym nr
<input type="text" v-model="order.rows[2].trackNo" holder="nr toru" /> najpóźniej o godz.
<input type="text" v-model="order.rows[2].untilHour" holder="godzina" /> min.
<input type="text" v-model="order.rows[2].trackNo" holder="nr toru" />
najpóźniej o godz.
<input type="text" v-model="order.rows[2].untilHour" holder="godzina" />
min.
<input type="text" v-model="order.rows[2].untilMin" holder="minuta" />
</td>
</tr>
@@ -212,13 +225,14 @@
</td>
<td ref="row-4">
<strong>WJAZD</strong> z toru szlakowego nr
<input type="text" v-model="order.rows[3].trackNo" holder="nr toru" /> na
<input type="text" v-model="order.rows[3].trackNo" holder="nr toru" />
na
<select v-model="order.rows[3].optionStation">
<option value="stację">stację</option>
<option value="posterunek odgałęźny">posterunek odgałęźny</option>
</select>
<input type="text" v-model="order.rows[3].stationName" holder="stacja / post." /> odbędzie się po
otrzymaniu:
<input type="text" v-model="order.rows[3].stationName" holder="stacja / post." />
odbędzie się po otrzymaniu:
<div style="margin-top: 0.5rem">
<input
type="radio"
@@ -259,8 +273,10 @@
</td>
<td ref="row-5">
<strong>ZEZWALAM</strong> wjechać z toru szlakowego nr
<input type="text" v-model="order.rows[4].trackNo" holder="nr toru" /> z kierunku
<input type="text" v-model="order.rows[4].direction" holder="stacja / post." /> na
<input type="text" v-model="order.rows[4].trackNo" holder="nr toru" />
z kierunku
<input type="text" v-model="order.rows[4].direction" holder="stacja / post." />
na
<select v-model="order.rows[4].stationType">
<option value="stację">stację</option>
<option value="posterunek odgałęźny">posterunek odgałęźny</option>
@@ -270,6 +286,46 @@
<input type="text" v-model="order.rows[4].on" holder="nazwa sygnału" />
</td>
</tr>
<tr style="height: 270px">
<td>
<label for="row-enabled-6">6</label>
<div>
<input type="checkbox" id="row-enabled-6" v-model="order.rows[5].enabled" />
</div>
</td>
<td ref="row-6">
<button
class="g-button text"
@click="order.rows[5].twoWay.enabled = !order.rows[5].twoWay.enabled"
>
&gt;
<span v-if="!order.rows[5].twoWay.enabled">
Wygeneruj treść na wprowadzenie ruchu dwukierunkowego
</span>
<span v-else>Wpisz treść własnoręcznie</span>
</button>
<div>Inne:</div>
<div v-if="order.rows[5].twoWay.enabled">
od
<input type="text" v-model="order.rows[5].twoWay.from" holder="stacja / post." />
do
<input type="text" v-model="order.rows[5].twoWay.to" holder="stacja / post." />
po torze nr
<input type="text" v-model="order.rows[5].twoWay.trackNo" holder="nr toru" />
wprowadzono ruch dwukierunkowy.
</div>
<textarea
v-else
class="others"
cols="30"
rows="10"
v-model="order.rows[5].content"
></textarea>
</td>
</tr>
</tbody>
</table>
</section>
@@ -306,7 +362,9 @@ export default defineComponent({
const message = `Od ${row.from || '_'} do ${row.to || '_'} tor nr ${
row.trackNo || '_'
} jest zamknięty, ruch jednotorowy dwukierunkowy wprowadzono po torze nr ${row.trackNo2 || '_'}`;
} jest zamknięty, ruch jednotorowy dwukierunkowy wprowadzono po torze nr ${
row.trackNo2 || '_'
}`;
return message;
},
@@ -317,20 +375,25 @@ export default defineComponent({
let message = `ZEZWALAM po otrzymaniu ${row.option1 || '_'}`;
if (row.checkbox == 'checkbox-2a') {
message += ` przejechać obok wskazującego sygnał "Stój" semafora ${row.signalType || '_'} `;
message += ` przejechać obok wskazującego sygnał "Stój" semafora ${
row.signalType || '_'
} `;
if (row.signalType == 'wyjazdowego') message += row.signal1 || '_';
if (row.signalType == 'drogowskazowego')
message += `${row.signal2 || '_'} (odnoszącego się do wyjazdu pociągu)`;
if (row.signalType == 'wjazdowego') message += `${row.signal3 || '_'} na post. odg. bez sem. wyjazdowego`;
if (row.signalType == 'wjazdowego')
message += `${row.signal3 || '_'} na post. odg. bez sem. wyjazdowego`;
message += ` i wyjechać w kierunku ${row.direction1 || '_'} na tor szlakowy ${row.option2 || '_'} nr ${
row.trackNoTo1 || '_'
}`;
message += ` i wyjechać w kierunku ${row.direction1 || '_'} na tor szlakowy ${
row.option2 || '_'
} nr ${row.trackNoTo1 || '_'}`;
}
if (row.checkbox == 'checkbox-2b') {
message += ` z toru nr ${row.trackNoFrom || '_'} nie posiadającego semafora wyjazdowego wyjechać w kierunku ${
message += ` z toru nr ${
row.trackNoFrom || '_'
} nie posiadającego semafora wyjazdowego wyjechać w kierunku ${
row.direction2 || '_'
} na tor szlakowy ${row.option3 || '_'} nr ${row.trackNoTo2 || '_'}`;
}
@@ -341,11 +404,11 @@ export default defineComponent({
() => {
const row = order.rows[2];
let message = `${row.option1 || '_'} pociągu odbędzie się w kierunku: ${row.direction || '_'} do km ${
row.toKilometer || '_'
} skąd ${row.option2 || '_'} ma wrócić po torze lewym nr ${row.trackNo || '_'} najpóźniej o godz. ${
row.untilHour || '_'
} min. ${row.untilMin || '_'}`;
let message = `${row.option1 || '_'} pociągu odbędzie się w kierunku: ${
row.direction || '_'
} do km ${row.toKilometer || '_'} skąd ${row.option2 || '_'} ma wrócić po torze lewym nr ${
row.trackNo || '_'
} najpóźniej o godz. ${row.untilHour || '_'} min. ${row.untilMin || '_'}`;
return message;
},
@@ -353,15 +416,18 @@ export default defineComponent({
() => {
const row = order.rows[3];
let message = `WJAZD z toru szlakowego nr ${row.trackNo || '_'} na ${row.optionStation || '_'} ${
row.stationName || '_'
} odbędzie się po otrzymaniu: `;
let message = `WJAZD z toru szlakowego nr ${row.trackNo || '_'} na ${
row.optionStation || '_'
} ${row.stationName || '_'} odbędzie się po otrzymaniu: `;
if (row.checkbox == 'checkbox-4a')
message += `sygnału zastępczego "Sz" na osobnym urządzeniu ustawionym z ${row.side || '_'} strony toru`;
message += `sygnału zastępczego "Sz" na osobnym urządzeniu ustawionym z ${
row.side || '_'
} strony toru`;
if (row.checkbox == 'checkbox-4b')
message += 'rozkazu pisemnego "N" (doręczonego lub przekazanego przez urządzenia łączności)';
message +=
'rozkazu pisemnego "N" (doręczonego lub przekazanego przez urządzenia łączności)';
return message;
},
@@ -371,16 +437,29 @@ export default defineComponent({
const message = `ZEZWALAM wjechać z toru szlakowego nr ${row.trackNo || '_'} z kierunku ${
row.direction || '_'
} na ${row.stationType || '_'} ${row.stationName || '_'} i przejechać obok sygnału "Stój" na ${row.on || '_'} `;
} na ${row.stationType || '_'} ${
row.stationName || '_'
} i przejechać obok sygnału "Stój" na ${row.on || '_'} `;
return message;
},
() => {
const row = order.rows[5];
if (row.twoWay.enabled)
return `Inne: od ${row.twoWay.from || '_'} do ${row.twoWay.to || '_'} po torze nr ${
row.twoWay.trackNo || '_'
} wprowadzono ruch dwukierunkowy.`;
return 'Inne: ' + row.content;
}
];
return {
store,
order,
rowMethods,
rowMethods
};
},
@@ -389,14 +468,14 @@ export default defineComponent({
deep: true,
handler() {
this.generateMessage();
},
}
},
'order.rows': {
deep: true,
handler() {
this.updatePlaceholders();
},
},
}
}
},
mounted() {
@@ -426,15 +505,14 @@ export default defineComponent({
generateMessage() {
let message = this.rowMethods[0]();
for (let i = 0; i < 5; i++) {
for (let i = 0; i < this.order.rows.length; i++) {
if (!this.order.rows[i].enabled) continue;
message += ` <b> [ ${i + 1} ] </b> ${this.rowMethods[i + 1]()}`;
}
this.store.orderMessage = message;
},
},
}
}
});
</script>
+26 -40
View File
@@ -2,12 +2,14 @@
<section class="order-o">
<section class="order_header">
<h2 class="flex-center" style="padding: 0 0.5em">
Rozkaz pisemny "O" nr
<input type="text" v-model="order.header.orderNo" placeholder="nr rozkazu"/>
Rozkaz pisemny "O" nr &nbsp;
<input type="number" v-model="order.header.orderNo" placeholder="nr rozkazu" min="1" />
</h2>
<div class="flex-row" style="padding: 0 0.5em">
dla pociągu nr <input type="text" v-model="order.header.trainNo" placeholder="nr pociągu" /> dnia
dla pociągu nr
<input type="text" v-model="order.header.trainNo" placeholder="nr pociągu" />
dnia
<input type="text" v-model="order.header.date" />
</div>
@@ -41,7 +43,7 @@
<td colspan="2">kilometra</td>
</tr>
<tr v-for="row in order.orderList" class="tr-data">
<tr v-for="(row, i) in order.orderList" :key="i" class="tr-data">
<td>
<textarea v-model="row.name"></textarea>
</td>
@@ -63,13 +65,13 @@
</tr>
</tbody>
</table>
<div class="order_other">
<span><b>2.</b> Inne:</span>
<br />
<textarea v-model="order.other"></textarea>
</div>
</section>
<div class="order_other">
<span><b>2.</b> Inne:</span>
<br />
<textarea class="others" cols="30" rows="10" v-model="order.other"></textarea>
</div>
</section>
</template>
@@ -88,16 +90,16 @@ export default defineComponent({
() => {
const { header } = order;
return `<i>Rozkaz pisemny "O" nr ${header.orderNo || '_'} dla pociągu nr ${header.trainNo || '_'} dnia ${
header.date || '_'
}</i>`;
},
return `<i>Rozkaz pisemny "O" nr ${header.orderNo || '_'} dla pociągu nr ${
header.trainNo || '_'
} dnia ${header.date || '_'}</i>`;
}
];
return {
store,
order,
rowMethods,
rowMethods
};
},
@@ -110,8 +112,8 @@ export default defineComponent({
deep: true,
handler() {
this.generateMessage();
},
},
}
}
},
methods: {
@@ -137,13 +139,13 @@ export default defineComponent({
rowsMessageList.push(rowMessage);
}
message += rowsMessageList.join("; ");
message += rowsMessageList.join('; ');
if (this.order.other) message += ` <b> [ 2 ] </b> Inne: ${this.order.other}`;
this.store.orderMessage = message;
},
},
}
}
});
</script>
@@ -157,16 +159,6 @@ th {
.order_header {
padding: 0.5em 0;
border: 2px solid black;
border-bottom: none;
}
.horizontal-bar {
width: 100%;
height: 2px;
background-color: black;
margin: 0.5em 0;
}
.order_table {
@@ -187,10 +179,12 @@ th {
input {
width: 80%;
}
}
.order_table {
textarea {
width: 80%;
height: 40px;
width: 90%;
min-height: 50px;
resize: vertical;
}
}
@@ -201,15 +195,7 @@ th {
display: flex;
flex-direction: column;
height: 285px;
padding: 0.5em;
textarea {
resize: vertical;
height: 220px;
width: 95%;
}
}
</style>
+121 -42
View File
@@ -1,9 +1,9 @@
<template>
<section class="order-s">
<section class="header">
<section class="order_header">
<h2 class="flex-center">
Rozkaz pisemny "S" nr
<input type="text" v-model="order.header.orderNo" placeholder="nr rozkazu" />
Rozkaz pisemny "S" nr &nbsp;
<input type="number" v-model="order.header.orderNo" placeholder="nr rozkazu" min="1" />
</h2>
<div class="flex-row">
dla
@@ -11,12 +11,15 @@
<option value="pociągu">pociągu</option>
<option value="manewru">manewru</option>
</select>
nr <input type="text" v-model="order.header.trainNo" :placeholder="`nr ${order.header.for}`" /> dnia
nr
<input type="text" v-model="order.header.trainNo" :placeholder="`nr ${order.header.for}`" />
dnia
<input type="text" v-model="order.header.date" placeholder="data" />
</div>
</section>
<section class="table-section">
<table class="options-table">
<section class="order_table-container">
<table>
<tbody>
<tr>
<td>
@@ -57,6 +60,7 @@
holder="nazwa sem."
:radio-checked="order.rows[0].radio1 == 'radio-1a-1'"
/>
<span v-if="order.rows[0].optionSignal == 'drogowskazowego'"> (odnoszącego się do wyjazdu pociągu)</span>
<br />
</label>
<hr />
@@ -130,7 +134,7 @@
holder="nazwa sem."
:radio-checked="order.rows[1].signalType == 'drogowskazowego'"
/>
(odnoszącego się do wyjazdu pociągu)
(odnoszącego się do wjazdu pociągu)
</label>
<br />
<input
@@ -184,17 +188,23 @@
</div>
</td>
<td ref="row-3">
Od <input type="text" v-model="order.rows[2].from" holder="stacja / post." /> do
<input type="text" v-model="order.rows[2].to" holder="stacja / post." /> po torze nr
<input type="text" v-model="order.rows[2].trackNo" holder="nr toru" /> ruch pociągów prowadzony jest w
odstępie posterunków następczych. Wskazania semaforów sbl nieważne. Zachować ostrożność od ostatniego
semafora ze wskaźnikiem "W18". Szlak wolny, ostatni pociąg nr
<input type="text" v-model="order.rows[2].trainNo" holder="nr pociągu" /> przybył do
<input type="text" v-model="order.rows[2].arrivedTo" holder="stacja / post." /> o godzinie
Od
<input type="text" v-model="order.rows[2].from" holder="stacja / post." />
do
<input type="text" v-model="order.rows[2].to" holder="stacja / post." />
po torze nr
<input type="text" v-model="order.rows[2].trackNo" holder="nr toru" />
ruch pociągów prowadzony jest w odstępie posterunków następczych. Wskazania semaforów
sbl nieważne. Zachować ostrożność od ostatniego semafora ze wskaźnikiem "W18".
Szlak wolny, ostatni pociąg nr
<input type="text" v-model="order.rows[2].trainNo" holder="nr pociągu" />
przybył do
<input type="text" v-model="order.rows[2].arrivedTo" holder="stacja / post." />
o godzinie
<input type="text" v-model="order.rows[2].hour" holder="godzina" />
</td>
</tr>
<tr style="height: 255px">
<tr style="height: 270px">
<td>
<label for="row-enabled-4">4</label>
<div>
@@ -207,9 +217,63 @@
</div>
</td>
<td ref="row-4">
Inne:
<br />
<textarea id="" cols="30" rows="10" v-model="order.rows[3].content"></textarea>
<button
class="g-button text"
@click="order.rows[3].w5.enabled = !order.rows[3].w5.enabled"
>
&gt;
<span v-if="!order.rows[3].w5.enabled"
>Wygeneruj treść na pominięcie wskaźnika W5</span
>
<span v-else>Wpisz treść własnoręcznie</span>
</button>
<div>Inne:</div>
<div v-if="order.rows[3].w5.enabled">
zezwalam na wyjazd poza
<select id="select-borderType" v-model="order.rows[3].w5.borderType">
<option value="wskaźnik przetaczania W5">wskaźnik przetaczania W5</option>
<option value="granicę przetaczania">granicę przetaczania</option>
</select>
po torze szlakowym nr
<input type="text" v-model="order.rows[3].w5.trackNo" holder="nr szlaku" />
do kilometra
<input type="text" v-model="order.rows[3].w5.maxKm" holder="km szlaku" />. Powrót
odbędzie się na
<select
id="select-returnWay"
v-model="order.rows[3].w5.returnWay"
style="width: 250px"
>
<option :value="`sygnał ręczny &quot;Do mnie&quot;`">
sygnał ręczny "Do mnie"
</option>
<option
:value="`sygnał &quot;Do mnie&quot; przekazany przez urządzenia radiołączności`"
>
sygnał "Do mnie" przekazany przez urządzenia radiołączności
</option>
<option value="sygnał Ms2 podany na tarczy manewrowej">
sygnał Ms2 podany na tarczy manewrowej
</option>
</select>
<input
type="text"
v-model="order.rows[3].w5.tmName"
holder="nazwa tarczy"
v-if="order.rows[3].w5.returnWay.includes('tarczy')"
/>
do godziny
<input type="text" v-model="order.rows[3].w5.maxHour" holder="godzina" />
</div>
<textarea
v-else
class="others"
cols="30"
rows="10"
v-model="order.rows[3].content"
></textarea>
</td>
</tr>
</tbody>
@@ -247,10 +311,13 @@ export default defineComponent({
let message = `zezwalam po otrzymaniu ${row.option1 || '_'}`;
if (row.radio1 == 'radio-1a-1')
message += ` przejechać obok wskazującego sygnał "Stój" semafora ${row.optionSignal || '_'} ${
row.signal1 || '_'
}`;
else message += ` wyjechać z toru nr ${row.trackNo || '_'} nie posiadającego semafora wyjazdowego`;
message += ` przejechać obok wskazującego sygnał "Stój" semafora ${
row.optionSignal || '_'
} ${row.signal1 || '_'}${row.optionSignal == 'drogowskazowego' ? ' (odnoszącego się do wyjazdu pociągu)' : ''}`;
else
message += ` wyjechać z toru nr ${
row.trackNo || '_'
} nie posiadającego semafora wyjazdowego`;
return message;
},
@@ -265,13 +332,15 @@ export default defineComponent({
message += `wjazdowego ${row.signal1 || '_'}`;
break;
case 'drogowskazowego':
message += `drogowskazowego ${row.signal2 || '_'}`;
message += `drogowskazowego ${row.signal2 || '_'} (odnoszącego się do wjazdu pociągu)`;
break;
case 'odstępowego':
message += `odstępowego ${row.signal3 || '_'}`;
break;
case 'toru':
message += `wjechać z zamkniętego toru nr ${row.trackNo || '_'} nie posiadającego semafora wjazdowego`;
message += `wjechać z zamkniętego toru nr ${
row.trackNo || '_'
} nie posiadającego semafora wjazdowego`;
break;
default:
@@ -293,18 +362,37 @@ export default defineComponent({
() => {
const row = order.rows[3];
if (row.w5.enabled) {
const { borderType, trackNo, maxHour, maxKm, returnWay, tmName } = row.w5;
const textArray = [];
textArray.push(
'Inne: zezwalam na wyjazd poza',
borderType || '_',
'po torze szlakowym nr',
trackNo || '_'
);
if (maxKm) textArray.push(`do kilometra ${maxKm}`);
textArray.push('.');
textArray.push('Powrót odbędzie się na', returnWay || '_');
if (returnWay.includes('tarczy')) textArray.push(tmName || '_');
textArray.push(`do godziny ${maxHour || '_'}`);
return textArray.join(' ').replace(/ \./, '.');
}
return `Inne: ${row.content}`;
},
}
];
return {
store,
order,
rowMethods,
rowMethods
};
},
activated() {
activated() {
this.generateMessage();
},
@@ -317,15 +405,15 @@ activated() {
deep: true,
handler() {
this.generateMessage();
},
}
},
'order.rows': {
deep: true,
handler() {
this.updatePlaceholders();
},
},
}
}
},
methods: {
@@ -335,7 +423,7 @@ activated() {
});
},
generateMessage() {
generateMessage() {
let message = this.rowMethods[0]();
for (let i = 0; i < 4; i++) {
@@ -354,16 +442,7 @@ activated() {
this.$nextTick(() => {
handleOrderPlaceholders(isRowEnabled, rowRef);
});
},
},
}
}
});
</script>
<style lang="scss" scoped>
textarea {
width: 95%;
height: 200px;
resize: none;
}
</style>
+245 -131
View File
@@ -1,48 +1,102 @@
<template>
<div class="order-train-picker">
<div class="options">
<select name="dispatcher-select" id="dispatcher-select" v-model="selectedDispatcherName">
<option :value="null" disabled>Nick dyżurnego</option>
<option v-for="dispatcherName in dispatcherNameList" :value="dispatcherName">
{{ dispatcherName }}
<div class="options-top">
<select
name="dispatcher-select"
id="dispatcher-select"
v-model="selectedSceneryId"
@change="selectOption"
>
<option :value="null" disabled>Sceneria</option>
<option
v-for="scenery in filteredSceneries"
:value="`${scenery.stationName}|${scenery.stationHash}|${scenery.dispatcherName}|${scenery.region}`"
:key="scenery.dispatcherName + scenery.stationName"
>
{{ scenery.stationName }} &bull; {{ scenery.dispatcherName }}
</option>
</select>
<select
name="region-select"
id="region-select"
v-model="selectedRegion"
@change="selectOption"
>
<option :value="null" disabled>Region</option>
<option v-for="region in regions" :value="region" :key="region">
{{ getRegionNameById(region) }}
</option>
<!-- <option
v-for="scenery in filteredSceneries"
:value="`${scenery.stationName}|${scenery.stationHash}|${scenery.dispatcherName}|${scenery.region}`"
:key="scenery.dispatcherName + scenery.stationName"
>
</option> -->
</select>
</div>
<select
name="checkpoint-select"
id="checkpoint-select"
v-model="selectedCheckpointName"
:disabled="!selectedScenery"
>
<option :value="null" disabled>Posterunek</option>
<option :value="cp" v-for="cp in checkpointNameList" :key="cp">
{{ cp }}
</option>
</select>
<select
name="scenery-select"
id="scenery-select"
v-model="selectedSceneryName"
:disabled="sceneryNameList.length == 0"
>
<option :value="null" disabled>Sceneria</option>
<option :value="sceneryName" v-for="sceneryName in sceneryNameList">
{{ sceneryName }}
</option>
</select>
<label for="fill-checkpoint" class="g-checkbox">
<input
type="checkbox"
name="fill-checkpoint"
id="fill-checkpoint"
v-model="fillCheckpointName"
/>
<span> Uzupełniaj skrót wybranego posterunku</span>
</label>
</div>
<div class="content">
<b v-if="!selectedSceneryName" class="text--accent"> Wybierz dyżurnego oraz scenerię, aby zobaczyć pociągi </b>
<b v-if="!selectedSceneryId" class="text--accent">
Wybierz dyżurnego oraz scenerię, aby zobaczyć pociągi
</b>
<div v-else>
<b class="text--accent">Kliknij na gracza, aby wypełnić obecny rozkaz jego danymi</b>
<div style="margin-bottom: 0.5em">
<h3 style="margin-bottom: 0.5em">Aktywne RJ i gracze na scenerii</h3>
<b class="text--accent">Kliknij na gracza, aby wypełnić obecny rozkaz jego danymi</b>
</div>
<p>Gracze online bez RJ</p>
<ul class="train-list">
<li v-for="train in sceneryTrains" @click="fillOrder(train.trainNo)">
<b>{{ train.trainNo }} | {{ train.driverName }}</b>
<li
v-for="train in sceneryTrains"
:key="train.trainNo + train.driverName"
@click="fillOrder(train.trainNo)"
>
<button class="g-button">
<span
v-if="train.currentStationName == selectedScenery?.stationName"
class="online-indicator"
></span>
<b>
{{ train.driverName }} &bull;
<span v-if="train.timetable" style="color: gold">{{
train.timetable.category
}}</span>
{{ train.trainNo }}
</b>
</button>
</li>
<li class="no-trains" v-if="sceneryTrains.length == 0 && selectedSceneryName">Brak graczy</li>
</ul>
<p>Aktywne rozkłady jazdy</p>
<ul class="train-list">
<li v-for="train in sceneryScheduledTrains" @click="fillOrder(train.trainNo)">
<b>{{ train.trainNo }} | {{ train.driverName }}</b>
<li class="no-trains" v-if="sceneryTrains?.length == 0 && selectedSceneryId">
Brak graczy
</li>
<li class="no-trains" v-if="sceneryScheduledTrains.length == 0">Brak aktywnych rozkładów</li>
</ul>
</div>
</div>
@@ -51,39 +105,51 @@
<script lang="ts">
import { defineComponent } from 'vue';
import axios from 'axios';
import { ApiSWDR, ApiStacjownik } from '../types/apiTypes';
import { useStore } from '../store/store';
import { currentFormattedDate } from '../utils/dateUtils';
import { ISceneryOnline, ISceneryData } from '../types/dataTypes';
import {
currentFormattedDate,
currentFormattedHours,
currentFormattedMinutes
} from '../utils/dateUtils';
import http from '../http';
import { ISceneryData } from '../types/dataTypes';
import { API } from '../types/apiTypes';
import { getRegionNameById } from '../utils/sceneryUtils';
export default defineComponent({
name: 'order-train-picker',
data() {
return {
sceneriesData: [] as ISceneryData[],
sceneriesOnline: [] as ISceneryOnline[],
trainsOnline: [] as ApiStacjownik.IActiveTrain[],
sceneriesData: undefined as ISceneryData[] | undefined,
activeData: undefined as API.ActiveData.Response | undefined,
selectedSceneryName: null as string | null,
selectedDispatcherName: null as string | null,
selectedSceneryId: null as string | null,
selectedCheckpointName: null as string | null,
selectedRegion: 'eu',
fillCheckpointName: false,
refreshInterval: -1,
store: useStore(),
regions: ['eu', 'cae', 'usw', 'us', 'ru']
};
},
created() {
this.fillCheckpointName = window.localStorage.getItem('fill-checkpoint') == 'true';
this.fetchSceneriesData();
},
activated() {
this.fetchOnlineData();
async activated() {
await this.fetchActiveData();
this.handleQueries();
this.refreshInterval = window.setInterval(() => {
this.fetchOnlineData();
}, 35 * 1000);
this.fetchActiveData();
}, 25 * 1000);
},
deactivated() {
@@ -91,161 +157,209 @@ export default defineComponent({
},
watch: {
selectedDispatcherName() {
this.selectedSceneryName = this.sceneryNameList.length == 0 ? null : this.sceneryNameList[0];
},
fillCheckpointName(val: boolean) {
window.localStorage.setItem('fill-checkpoint', `${val}`);
}
},
computed: {
selectedSceneryHash() {
return this.sceneriesOnline.find((s) => this.selectedSceneryName == s.stationName)?.stationHash;
},
sceneriesOnlinePL1() {
return this.sceneriesOnline.filter((s) => s.region == 'eu' && s.isOnline);
},
dispatcherNameList() {
return [...new Set(this.sceneriesOnlinePL1.map((s) => s.dispatcherName))].sort((a, b) =>
a.toLocaleLowerCase() < b.toLocaleLowerCase() ? -1 : 1
selectedScenery() {
return this.activeData?.activeSceneries?.find(
(scenery) =>
this.selectedSceneryId ==
`${scenery.stationName}|${scenery.stationHash}|${scenery.dispatcherName}|${scenery.region}` &&
this.selectedRegion == scenery.region
);
},
sceneryNameList() {
return this.sceneriesOnlinePL1
.filter((s) => s.dispatcherName == this.selectedDispatcherName)
.map((s) => s.stationName)
.sort((a, b) => (a < b ? -1 : 1));
filteredSceneries() {
return this.activeData?.activeSceneries
?.filter((s) => s.isOnline && s.region == this.selectedRegion)
.sort((s1, s2) => s1.stationName.localeCompare(s2.stationName));
},
checkpointNameList() {
if (!this.selectedScenery) return [];
const checkpoints =
this.sceneriesData?.find((s) => s.name == this.selectedScenery?.stationName)?.checkpoints ??
'';
if (checkpoints.length == 0) return [this.selectedScenery.stationName];
return checkpoints.split(';');
},
sceneryTrains() {
return this.trainsOnline.filter(
(t) => t.online && t.currentStationName == this.selectedSceneryName && this.selectedSceneryName && !t.timetable
);
},
if (!this.selectedScenery || !this.activeData?.trains) return [];
sceneryScheduledTrains() {
if (!this.selectedSceneryHash) return [];
const hash = this.selectedSceneryHash;
const scenery = this.selectedScenery;
return this.trainsOnline
.filter((t) => t.timetable?.sceneries.includes(hash))
.sort((t1, t2) => t1.trainNo - t2.trainNo);
},
return this.activeData.trains
?.filter(
(t) =>
(t.currentStationName == scenery.stationName &&
t.region == scenery.region &&
(t.online || t.lastSeen >= Date.now() - 60000)) ||
t.timetable?.path.includes(`${scenery.stationName} ${scenery.stationHash}.sc`)
)
.sort((t1, t2) => {
return (
(t2.currentStationName == scenery.stationName ? 1 : -1) -
(t1.currentStationName == scenery.stationName ? 1 : -1) ||
t1.driverName.localeCompare(t2.driverName)
);
});
}
},
methods: {
async fetchSceneriesData() {
const data: ISceneryData[] = await (await axios.get(`${import.meta.env['VITE_APP_API_URL']}/getSceneries`)).data;
getRegionNameById,
if (!data) return;
async fetchSceneriesData() {
const data: ISceneryData[] = (await http.get<ISceneryData[]>('api/getSceneries')).data;
this.sceneriesData = data;
},
async fetchOnlineData() {
this.fetchSceneriesOnline();
this.fetchTrainsOnline();
async fetchActiveData() {
const data: API.ActiveData.Response = await (await http.get('api/getActiveData')).data;
this.activeData = data;
},
async fetchSceneriesOnline() {
const data: ApiSWDR.IStationsOnline = await (
await axios.get(`${import.meta.env['VITE_APP_SWDR_URL']}/?method=getStationsOnline`)
).data;
if (!data.success) return;
this.sceneriesOnline = data.message;
},
async fetchTrainsOnline() {
const data: ApiStacjownik.IActiveTrain[] = await (
await axios.get(`${import.meta.env['VITE_APP_API_URL']}/getActiveTrainList`)
).data;
if (!data) return;
this.trainsOnline = data;
selectOption() {
this.selectedCheckpointName =
this.checkpointNameList.length == 0 ? null : this.checkpointNameList[0];
},
fillOrder(trainNo: number) {
if (!this.selectedDispatcherName || !this.selectedSceneryName) return;
if (!this.selectedScenery) return;
const chosenOrder = this.store[this.store.chosenOrderType];
chosenOrder.header.trainNo = trainNo.toString();
chosenOrder.header.date = currentFormattedDate();
this.store.orderFooter.dispatcherName = this.selectedDispatcherName;
this.store.orderFooter.stationName = this.selectedSceneryName;
this.store.orderFooter.dispatcherName = this.selectedScenery.stationName;
this.store.orderFooter.stationName =
this.selectedCheckpointName?.split(',')[0] || this.selectedScenery.stationName;
this.store.orderFooter.hour = currentFormattedHours();
this.store.orderFooter.minutes = currentFormattedMinutes();
if (this.fillCheckpointName) {
const sceneryAbbrev = this.sceneriesData?.find(
({ name }) => name === this.selectedSceneryId
)?.abbr;
this.store.orderFooter.checkpointName =
sceneryAbbrev || this.store.orderFooter.stationName.slice(0, 2);
}
this.store.orderMode = 'OrderMessage';
},
},
handleQueries() {
const query = new URLSearchParams(window.location.search);
const id = query.get('sceneryId');
if (id) {
const [sceneryName, sceneryRegion] = id.split('|');
this.selectedRegion = sceneryRegion;
const queryScenery = this.activeData?.activeSceneries?.find(
(sc) => sc.stationName == sceneryName && sc.region == sceneryRegion && sc.isOnline
);
if (queryScenery) {
this.selectedSceneryId = `${queryScenery.stationName}|${queryScenery.stationHash}|${queryScenery.dispatcherName}|${queryScenery.region}`;
console.log(this.selectedRegion);
this.selectOption();
this.store.orderMode = 'OrderTrainPicker';
}
}
}
}
});
</script>
<style lang="scss" scoped>
@import '../styles/global.scss';
@use '../styles/colors';
.order-train-picker {
padding: 1em;
height: 90vh;
overflow-y: auto;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 1em;
overflow: auto;
padding: 0 0.5em;
}
.options {
display: flex;
flex-wrap: wrap;
width: 100%;
gap: 1em;
gap: 0.5em;
select {
border: 2px solid white;
color: white;
background-color: colors.$bgColDarker;
font-size: 1em;
width: 100%;
margin: 0;
padding: 0.15em;
}
option {
color: black;
&[disabled] {
color: gray;
}
}
}
.options-top {
display: grid;
grid-template-columns: 3fr auto;
gap: 0.5em;
width: 100%;
}
.content {
margin-top: 1em;
width: 100%;
text-align: center;
p {
margin: 1em 0;
font-weight: bold;
font-size: 1.1em;
}
}
ul.train-list {
li {
background-color: #111;
padding: 1px;
li.no-trains {
font-weight: bold;
background-color: colors.$bgColDarker;
padding: 0.5em;
margin-top: 0.5em;
}
li > button {
width: 100%;
background-color: colors.$bgColDarker;
padding: 0.5em;
margin-top: 0.5em;
cursor: pointer;
&:hover {
background-color: colors.$bgColLighter;
}
&.no-trains {
font-weight: bold;
background-color: #222;
cursor: default;
&:focus-visible {
outline: 1px solid colors.$accentCol;
}
}
}
</style>
.online-indicator {
display: inline-block;
width: 9px;
height: 9px;
vertical-align: middle;
background-color: greenyellow;
border-radius: 100%;
margin: 0 5px;
}
</style>
+12 -31
View File
@@ -31,22 +31,22 @@ export default defineComponent({
orderTypeList: [
{
id: 'orderN',
name: 'N',
name: 'N'
},
{
id: 'orderS',
name: 'S',
name: 'S'
},
{
id: 'orderO',
name: 'O',
},
],
name: 'O'
}
]
};
},
setup() {
return {
store: useStore(),
store: useStore()
};
},
@@ -55,23 +55,13 @@ export default defineComponent({
if (type != this.store.chosenOrderType) this.store.chosenLocalOrderId = '';
this.store.chosenOrderType = type;
},
},
}
}
});
</script>
<style lang="scss" scoped>
@import '../styles/global.scss';
.sidebar {
position: absolute;
top: 0;
left: 0;
z-index: 999;
transform: translate(-100%, 0);
}
@use '../styles/colors';
.sidebar_content {
display: grid;
@@ -91,7 +81,7 @@ export default defineComponent({
align-items: center;
color: white;
background-color: #1d1d1d;
background-color: colors.$bgColDarker;
width: 50px;
height: 85px;
@@ -110,7 +100,7 @@ export default defineComponent({
&[data-selected='true'] .bar {
transform: translateX(0);
background-color: $accentCol;
background-color: colors.$accentCol;
}
&:hover {
@@ -132,19 +122,11 @@ button.option-save {
}
&[data-selected='true'] {
background-color: $accentCol;
background-color: colors.$accentCol;
}
}
@media screen and (max-width: 650px) {
.sidebar {
left: 50%;
top: 0;
width: 100%;
transform: translate(-50%, -100%);
}
.sidebar_content {
display: flex;
justify-content: space-between;
@@ -161,4 +143,3 @@ button.option-save {
}
}
</style>
+1 -3
View File
@@ -1,5 +1,3 @@
{
"orderS": [
"D"
]
"orderS": ["D"]
}
+4 -2
View File
@@ -13,8 +13,10 @@ export const handleOrderPlaceholders = (isRowEnabled: boolean, rowRef: HTMLTable
if (!node.getAttribute('holder')) return;
const radioCheckedAttr = node.getAttribute('radio-checked');
if (radioCheckedAttr == null) return node.setAttribute('placeholder', node.getAttribute('holder')!);
if (radioCheckedAttr == 'true') return node.setAttribute('placeholder', node.getAttribute('holder')!);
if (radioCheckedAttr == null)
return node.setAttribute('placeholder', node.getAttribute('holder')!);
if (radioCheckedAttr == 'true')
return node.setAttribute('placeholder', node.getAttribute('holder')!);
if (node.getAttribute('placeholder') == null) return;
node.setAttribute('holder', node.getAttribute('placeholder')!);
+7
View File
@@ -0,0 +1,7 @@
import axios from 'axios';
const http = axios.create({
baseURL: 'https://stacjownik.spythere.eu'
});
export default http;
-1
View File
@@ -4,4 +4,3 @@ import router from './router';
import { createPinia } from 'pinia';
createApp(App).use(router).use(createPinia()).mount('#app');
+3 -4
View File
@@ -4,7 +4,7 @@ import { useStore } from '../store/store';
export default defineComponent({
setup() {
return {
store: useStore(),
store: useStore()
};
},
@@ -25,7 +25,6 @@ export default defineComponent({
this.store.footerMessage = ` <b>|</b> ${messageArray.join(
', '
)} <b>|</b> Rozkaz otrzymałem, maszynista: (potwierdzić otrzymanie rozkazu)`;
},
},
}
}
});
+78 -37
View File
@@ -2,21 +2,39 @@ import { defineComponent } from 'vue';
import { useStore } from '../store/store';
import { LocalStorageOrder } from '../types/orderTypes';
function alertWrongOrderFormat() {
alert('Wystąpił błąd podczas przetwarzania rozkazu! Informacje mogą być niepoprawne!');
console.warn('Zły format zapisanego rozkazu!');
}
export default defineComponent({
setup() {
return {
store: useStore(),
store: useStore()
};
},
methods: {
saveOrderSetting(key: string, value: string | number | boolean) {
window.localStorage.setItem(key, value.toString());
},
getOrderSetting(key: string) {
return window.localStorage.getItem(key);
},
removeOrderSetting(key: string) {
window.localStorage.removeItem(key);
},
saveLocalOrder() {
let orderObj: LocalStorageOrder = {
const orderObj: LocalStorageOrder = {
id: '',
orderType: this.store.chosenOrderType,
orderBody: this.store[this.store.chosenOrderType],
orderFooter: this.store.orderFooter,
createdAt: Date.now(),
orderVersion: import.meta.env['VITE_APP_ORDER_VERSION'] || '1'
};
const headerInfo = orderObj['orderBody']['header'];
@@ -52,12 +70,13 @@ export default defineComponent({
if (!localOrder) return -1;
let orderObj: LocalStorageOrder = {
const orderObj: LocalStorageOrder = {
id: this.store.chosenLocalOrderId,
orderType: this.store.chosenOrderType,
orderBody: this.store[this.store.chosenOrderType],
orderFooter: this.store.orderFooter,
updatedAt: Date.now(),
orderVersion: import.meta.env['VITE_APP_ORDER_VERSION'] || '1'
};
window.localStorage.setItem(this.store.chosenLocalOrderId, JSON.stringify(orderObj));
@@ -72,51 +91,73 @@ export default defineComponent({
// localStorage.setItem('orderCount', (Number(localStorage.getItem('orderCount')) - 1).toString());
},
selectLocalOrder(order: LocalStorageOrder) {
this.store.chosenOrderType = order.orderType;
this.store.chosenLocalOrderId = order.id;
selectLocalOrder(localOrder: LocalStorageOrder) {
// const localOrder = JSON.parse(JSON.stringify(order));
const { orderBody: localOrderBody, orderFooter: localOrderFooter } = localOrder;
const localOrder = JSON.parse(JSON.stringify(order));
const localOrderBody = localOrder['orderBody'];
const localOrderFooter = localOrder['orderFooter'];
this.store[localOrder.orderType].header.date = localOrderBody.header.date;
this.store[localOrder.orderType].header.orderNo = localOrderBody.header.orderNo;
this.store[localOrder.orderType].header.trainNo = localOrderBody.header.trainNo;
let storeOrderObj;
if (localOrder.orderType == 'orderN' || localOrder.orderType == 'orderS') {
const currentOrder = this.store[localOrder.orderType];
switch (order.orderType) {
case 'orderN':
case 'orderS':
storeOrderObj = this.store[order.orderType];
for (let orderKey in storeOrderObj) {
for (let propKey in (storeOrderObj as any)[orderKey]) {
(storeOrderObj as any)[orderKey][propKey] = localOrderBody[orderKey][propKey];
}
if (localOrderBody.rows.length != currentOrder.rows.length) {
alertWrongOrderFormat();
return;
}
for (let rowIndex = 0; rowIndex < currentOrder.rows.length; rowIndex++) {
const row = currentOrder.rows[rowIndex];
if (localOrderBody.rows[rowIndex] === undefined) {
alertWrongOrderFormat();
continue;
}
break;
case 'orderO':
storeOrderObj = this.store[order.orderType];
storeOrderObj['other'] = localOrderBody['other'];
storeOrderObj['header']['date'] = localOrderBody['header']['date'];
storeOrderObj['header']['orderNo'] = localOrderBody['header']['orderNo'];
storeOrderObj['header']['trainNo'] = localOrderBody['header']['trainNo'];
for (let i = 0; i < storeOrderObj['orderList'].length; i++) {
const orderItem = storeOrderObj['orderList'][i];
for (let prop in orderItem) {
(storeOrderObj['orderList'][i] as any)[prop] = localOrderBody['orderList'][i][prop];
for (const rowProp in row) {
if (localOrderBody.rows[rowIndex][rowProp] === undefined) {
alertWrongOrderFormat();
continue;
}
}
break;
(currentOrder.rows[rowIndex] as any)[rowProp] = localOrderBody.rows[rowIndex][rowProp];
}
}
}
for (let key in this.store.orderFooter) {
if (localOrder.orderType == 'orderO') {
const currentOrder = this.store[localOrder.orderType];
for (let rowIndex = 0; rowIndex < currentOrder.orderList.length; rowIndex++) {
const row = currentOrder.orderList[rowIndex];
if (localOrderBody.orderList[rowIndex] === undefined) {
alertWrongOrderFormat();
continue;
}
for (const rowProp in row) {
if (localOrderBody.orderList[rowIndex][rowProp] === undefined) {
alertWrongOrderFormat();
continue;
}
(currentOrder.orderList[rowIndex] as any)[rowProp] =
localOrderBody.orderList[rowIndex][rowProp];
}
}
currentOrder.other = localOrderBody.other;
}
for (const key in this.store.orderFooter) {
(this.store.orderFooter as any)[key] = localOrderFooter[key];
}
this.store.chosenOrderType = localOrder.orderType;
this.store.chosenLocalOrderId = localOrder.id;
this.store.orderMode = 'OrderMessage';
},
},
}
}
});
+3 -6
View File
@@ -4,7 +4,7 @@ import { useStore } from '../store/store';
export default defineComponent({
setup() {
return {
store: useStore(),
store: useStore()
};
},
@@ -27,9 +27,6 @@ export default defineComponent({
fieldsToCorrect.push('dyżurny ruchu (lub z polecenia dyżurnego ruchu)');
return fieldsToCorrect;
},
},
}
}
});
+6 -6
View File
@@ -1,17 +1,17 @@
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import Home from '../views/Home.vue'
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import Home from '../views/Home.vue';
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'Home',
component: Home
},
]
}
];
const router = createRouter({
history: createWebHistory(),
routes
})
});
export default router
export default router;
+51 -28
View File
@@ -1,11 +1,16 @@
import { defineStore } from 'pinia';
import { IOrderN, IOrderO, IOrderS, TOrder } from '../types/orderTypes';
import { currentFormattedDate } from '../utils/dateUtils';
import {
currentFormattedDate,
currentFormattedHours,
currentFormattedMinutes
} from '../utils/dateUtils';
export const useStore = defineStore('store', {
state: () => {
return {
helperModalOpen: false,
orderDarkMode: false,
chosenOrderType: 'orderN' as TOrder,
chosenLocalOrderId: '',
@@ -15,10 +20,10 @@ export const useStore = defineStore('store', {
orderFooter: {
stationName: '',
checkpointName: '',
hour: new Date().toLocaleTimeString('pl-PL', { hour: '2-digit' }),
minutes: new Date().toLocaleTimeString('pl-PL', { minute: '2-digit' }),
hour: currentFormattedHours(),
minutes: currentFormattedMinutes(),
dispatcherName: '',
secondaryDispatcherName: '',
secondaryDispatcherName: ''
},
orderMessage: '',
@@ -28,7 +33,7 @@ export const useStore = defineStore('store', {
header: {
orderNo: '1',
trainNo: '',
date: currentFormattedDate(),
date: currentFormattedDate()
},
orderList: [
@@ -38,7 +43,7 @@ export const useStore = defineStore('store', {
to: '',
vmax: '',
jo: false,
reason: '',
reason: ''
},
{
name: '',
@@ -46,7 +51,7 @@ export const useStore = defineStore('store', {
to: '',
vmax: '',
jo: false,
reason: '',
reason: ''
},
{
name: '',
@@ -54,7 +59,7 @@ export const useStore = defineStore('store', {
to: '',
vmax: '',
jo: false,
reason: '',
reason: ''
},
{
name: '',
@@ -62,7 +67,7 @@ export const useStore = defineStore('store', {
to: '',
vmax: '',
jo: false,
reason: '',
reason: ''
},
{
name: '',
@@ -70,17 +75,17 @@ export const useStore = defineStore('store', {
to: '',
vmax: '',
jo: false,
reason: '',
},
reason: ''
}
],
other: '',
other: ''
} as IOrderO,
orderN: {
header: {
orderNo: '1',
trainNo: '',
date: currentFormattedDate(),
date: currentFormattedDate()
},
rows: [
@@ -89,7 +94,7 @@ export const useStore = defineStore('store', {
from: '',
to: '',
trackNo: '',
trackNo2: '',
trackNo2: ''
},
{
enabled: false,
@@ -105,7 +110,7 @@ export const useStore = defineStore('store', {
direction2: '',
trackNoFrom: '',
trackNoTo1: '',
trackNoTo2: '',
trackNoTo2: ''
},
{
enabled: false,
@@ -116,7 +121,7 @@ export const useStore = defineStore('store', {
toKilometer: '',
trackNo: '',
untilHour: '',
untilMin: '',
untilMin: ''
},
{
enabled: false,
@@ -124,7 +129,7 @@ export const useStore = defineStore('store', {
optionStation: 'stację',
stationName: '',
checkbox: 'checkbox-4a',
side: 'lewej',
side: 'lewej'
},
{
enabled: false,
@@ -132,9 +137,19 @@ export const useStore = defineStore('store', {
direction: '',
stationType: 'stację',
stationName: '',
on: '',
on: ''
},
],
{
enabled: false,
content: '',
twoWay: {
enabled: false,
from: '',
to: '',
trackNo: ''
}
}
]
} as IOrderN,
orderS: {
@@ -142,7 +157,7 @@ export const useStore = defineStore('store', {
orderNo: '1',
trainNo: '',
for: 'pociągu',
date: currentFormattedDate(),
date: currentFormattedDate()
},
rows: [
@@ -152,7 +167,7 @@ export const useStore = defineStore('store', {
optionSignal: 'wyjazdowego',
radio1: 'radio-1a-1',
signal1: '',
trackNo: '',
trackNo: ''
},
{
@@ -161,7 +176,7 @@ export const useStore = defineStore('store', {
signal1: '',
signal2: '',
signal3: '',
trackNo: '',
trackNo: ''
},
{
@@ -171,16 +186,24 @@ export const useStore = defineStore('store', {
trackNo: '',
trainNo: '',
arrivedTo: '',
hour: '',
hour: ''
},
{
enabled: false,
content: '',
},
],
} as IOrderS,
w5: {
enabled: false,
maxHour: '',
borderType: 'wskaźnik przetaczania W5',
tmName: '',
maxKm: '',
returnWay: 'sygnał ręczny "Do mnie"',
trackNo: ''
}
}
]
} as IOrderS
};
},
}
});
@@ -10,4 +10,3 @@
transform: translateY(100%);
}
}
+6
View File
@@ -0,0 +1,6 @@
$bgCol: #141414;
$bgColLighter: #292929;
$bgColDarker: #080808;
$accentCol: #ff6060;
$warnCol: #ffe02e;
$whiteDimmerCol: #ccc;
+24
View File
@@ -0,0 +1,24 @@
@font-face {
font-family: 'Libre Franklin';
src: url('/fonts/LibreFranklin-Bold.woff2') format('woff2');
font-weight: 800;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Libre Franklin';
src: url('/fonts/LibreFranklin-Regular.woff2') format('woff2');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Libre Franklin';
src: url('/fonts/LibreFranklin-SemiBold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
+251
View File
@@ -0,0 +1,251 @@
@use 'fonts';
@use 'colors';
// Global scrollbar style
::-webkit-scrollbar {
width: 15px;
}
::-webkit-scrollbar-track {
background: #333;
}
::-webkit-scrollbar-thumb {
background: #888;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
body,
html {
padding: 0;
margin: 0;
min-height: 100vh;
background-color: colors.$bgCol;
font-family: 'Libre Franklin', sans-serif;
font-weight: 500;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
a {
color: white;
text-decoration: none;
&:hover {
color: colors.$accentCol;
}
}
button {
border: none;
outline: none;
background: none;
transition:
color 90ms ease-in,
border 90ms ease-in;
font-family: 'Libre Franklin', sans-serif;
cursor: pointer;
font-weight: bold;
font-size: 1em;
}
button.g-button {
text-align: center;
color: inherit;
transition:
color 100ms ease-in,
background-color 100ms ease-in;
&.action {
background-color: colors.$bgColDarker;
padding: 0.5em;
&:focus-visible {
outline: 2px solid colors.$accentCol;
}
&:hover:not([data-disabled='true']) {
background-color: colors.$bgColLighter;
}
}
&.option {
position: relative;
margin: 0 0.25em;
padding: 0.25em;
&:focus-visible::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 2px;
background-color: colors.$accentCol;
}
&[data-active='true'] {
color: colors.$accentCol;
}
}
&.text {
padding: 0;
&:focus-visible {
color: colors.$accentCol;
}
}
}
// Text styles
.text {
&--accent {
color: colors.$accentCol;
}
&--warn {
color: colors.$warnCol;
}
}
// Select style
select {
border: 2px solid black;
background: none;
padding: 0.1em 0;
border-radius: 0.3em;
text-align: center;
border: 2px solid #888;
color: white;
outline: none;
margin: 0;
padding: 0.15em;
&[disabled] {
color: gray;
}
&:focus-visible {
border-color: colors.$accentCol;
}
}
option[disabled] {
color: #ccc;
}
// List style
ul {
padding: 0;
margin: 0;
list-style: none;
text-align: center;
}
// Modal
.g-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
.modal-bg {
position: fixed;
width: 100vw;
height: 100vh;
cursor: pointer;
background-color: #000000aa;
}
.modal-content {
position: relative;
z-index: 1001;
overflow: auto;
}
}
// Checkbox
label.g-checkbox {
display: inline-block;
margin: 0.25em 0;
cursor: pointer;
color: #aaa;
user-select: none;
-moz-user-select: none;
span {
transition: color 125ms ease;
}
span::before {
content: '\2717';
display: inline-block;
// background-color: #aaa;
border-radius: 50%;
margin-right: 0.25em;
transition: background-color 125ms ease;
}
input {
width: 0;
opacity: 0;
&:focus-visible + span {
text-decoration: underline;
}
&:checked + span {
color: greenyellow;
&::before {
content: '\2713';
// background-color: greenyellow;
}
}
}
}
// Tooltip
[data-tooltip] {
cursor: pointer;
}
[data-tooltip]:hover::after,
[data-tooltip]:focus::after {
position: absolute;
content: attr(data-tooltip);
color: white;
background: black;
padding: 0.5em;
margin: 0.25em;
max-width: 300px;
z-index: 100;
}
-145
View File
@@ -1,145 +0,0 @@
@import url('https://fonts.googleapis.com/css2?family=Libre+Franklin:wght@400;600&display=swap');
$bgCol: #313638;
$accentCol: #ff6060;
$warnCol: #ffe02e;
body,
html {
padding: 0;
margin: 0;
min-height: 100vh;
background-color: $bgCol;
font-family: 'Libre Franklin', sans-serif;
font-weight: 500;
}
* {
box-sizing: border-box;
}
a {
color: white;
text-decoration: none;
&:hover {
color: $accentCol;
}
}
button {
border: none;
outline: none;
background: none;
transition: all 150ms ease-in;
font-family: 'Libre Franklin', sans-serif;
cursor: pointer;
font-weight: bold;
font-size: 1em;
}
button.g-button {
text-align: center;
color: white;
&.action {
outline: 2px solid white;
padding: 0.5em;
&:focus-visible {
outline: 2px solid $accentCol;
}
}
&.option {
margin: 0 0.25em;
&:focus-visible {
outline: 1px solid $accentCol;
}
&[data-active='true'] {
color: $accentCol;
}
}
}
// Text styles
.text {
&--accent {
color: $accentCol;
}
&--warn {
color: $warnCol;
}
}
// Select style
select {
border: 2px solid black;
background: none;
padding: 0.1em 0;
border-radius: 0.3em;
text-align: center;
}
// List style
ul {
padding: 0;
margin: 0;
list-style: none;
text-align: center;
}
// Global scrollbar style
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
background: #333;
}
::-webkit-scrollbar-thumb {
background: #888;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
// Modal
.g-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 1000;
display: flex;
justify-content: center;
align-items: center;
.modal-bg {
position: fixed;
width: 100vw;
height: 100vh;
cursor: pointer;
background-color: #000000aa;
}
.modal-content {
position: relative;
z-index: 1001;
overflow: auto;
}
}
View File
+85 -96
View File
@@ -1,117 +1,106 @@
export declare module ApiSWDR {
export interface IStationsOnline {
success: boolean;
respCode: number;
message: IStationsOnlineMessage[];
export declare module API {
export namespace ActiveData {
export interface Response {
activeSceneries?: API.ActiveSceneries.Response;
trains?: API.ActiveTrains.Response;
}
}
export interface IStationsOnlineMessage {
dispatcherId: number;
dispatcherName: string;
dispatcherIsSupporter: boolean;
stationName: string;
stationHash: string;
region: string;
maxUsers: number;
currentUsers: number;
spawn: number;
lastSeen: any;
dispatcherExp: number;
nameFromHeader: string;
spawnString: string;
networkConnectionString: string;
isOnline: number;
dispatcherRate: number;
export namespace ActiveSceneries {
export interface Data {
dispatcherId: number;
dispatcherName: string;
dispatcherIsSupporter: boolean;
stationName: string;
stationHash: string;
region: string;
maxUsers: number;
currentUsers: number;
spawn: number;
lastSeen: number;
dispatcherExp: number;
nameFromHeader: string;
spawnString: string | null;
networkConnectionString: string;
isOnline: number;
dispatcherRate: number;
dispatcherStatus: number;
}
export type Response = Data[];
}
// export interface ITrainsOnline {
// success: boolean;
// respCode: number;
// message: ITrainsOnlineMessage[];
// }
export namespace ActiveTrains {
export type Response = Data[];
// export interface ITrainsOnlineMessage {
// trainNo: number;
// driverId: number;
// driverName: string;
// driverIsSupporter: boolean;
// dataSignal: string;
// dataSceneryConnection: string;
// dataDistance: number;
// dataCon: string;
// dataSpeed: number;
// dataMass: number;
// dataLength: number;
// region: string;
// isOnline: number;
// lastSeen: number;
// station?: ISceneryData;
// }
}
export interface Data {
trainNo: number;
export declare module ApiStacjownik {
export interface IActiveTrain {
trainNo: number;
mass: number;
length: number;
speed: number;
stockString: string;
mass: number;
length: number;
speed: number;
signal: string;
distance: number;
connectedTrack: string;
signal: string;
distance: number;
connectedTrack: string;
stockString: string;
driverName: string;
driverId: number;
driverIsSupporter: boolean;
driverLevel?: number;
driverName: string;
driverId: number;
driverIsSupporter: boolean;
currentStationName: string;
currentStationHash?: string;
currentStationName: string;
currentStationHash?: string;
online: number;
lastSeen: number;
online: boolean;
lastSeen: number;
region: string;
isTimeout: boolean;
region: string;
timetable?: Timetable;
}
timetable?: {
export interface TimetableStop {
stopName: string;
stopNameRAW: string;
stopType: string;
stopDistance: number;
pointId: string;
mainStop: boolean;
arrivalLine: string | null;
arrivalTimestamp: number;
arrivalRealTimestamp: number;
arrivalDelay: number;
departureLine: string | null;
departureTimestamp: number;
departureRealTimestamp: number;
departureDelay: number;
comments?: any;
beginsHere: boolean;
terminatesHere: boolean;
confirmed: number;
stopped: number;
stopTime: number | null;
}
export interface Timetable {
timetableId: number;
category: string;
route: string;
stopList: IActiveTrainStop[];
stopList: TimetableStop[];
TWR: boolean;
SKR: boolean;
sceneries: string[];
};
isTimeout: boolean;
}
export interface IActiveTrainStop {
stopName: string;
stopNameRAW: string;
stopType: string;
stopDistance: number;
pointId: number;
mainStop: boolean;
arrivalLine: string;
arrivalTimestamp: number;
arrivalRealTimestamp: number;
arrivalDelay: number;
departureLine: string;
departureTimestamp: number;
departureRealTimestamp: number;
departureDelay: number;
comments?: any;
beginsHere: boolean;
terminatesHere: boolean;
confirmed: boolean;
stopped: boolean;
stopTime: number;
path: string;
}
}
}
+1 -2
View File
@@ -20,6 +20,7 @@ export interface ISceneryOnline {
export interface ISceneryData {
id: string;
name: string;
abbr: string;
SUP: boolean;
authors: string;
availability: string;
@@ -49,5 +50,3 @@ export interface ISceneryData {
// lastSeen: number;
// station?: ISceneryData;
// }
+21
View File
@@ -7,6 +7,7 @@ export interface LocalStorageOrder {
orderFooter: any;
createdAt?: number;
updatedAt?: number;
orderVersion?: string;
}
export interface IOrderN {
@@ -66,6 +67,16 @@ export interface IOrderN {
stationType: string;
stationName: string;
on: string;
},
{
enabled: boolean;
content: string;
twoWay: {
enabled: boolean;
from: string;
to: string;
trackNo: string;
};
}
];
}
@@ -107,6 +118,16 @@ export interface IOrderS {
{
enabled: boolean;
content: string;
w5: {
enabled: boolean;
borderType: string;
trackNo: string;
maxKm: string;
returnWay: string;
maxHour: string;
tmName: string;
};
}
];
}
+16 -1
View File
@@ -1,3 +1,18 @@
export function currentFormattedDate() {
return new Date().toLocaleDateString('pl-PL', { day: 'numeric', month: 'numeric', year: 'numeric' }) + 'r.';
return (
new Date().toLocaleDateString('pl-PL', {
day: 'numeric',
month: 'numeric',
year: 'numeric'
}) + 'r.'
);
}
export function currentFormattedMinutes() {
const date = new Date();
return (date.getMinutes() < 10 ? '0' : '') + date.getMinutes();
}
export function currentFormattedHours() {
return new Date().toLocaleTimeString('pl-PL', { hour: '2-digit' });
}
+21
View File
@@ -0,0 +1,21 @@
export const getRegionNameById = (id: string) => {
switch (id) {
case 'eu':
return 'PL1';
case 'cae':
return 'PL2';
case 'us':
return 'CZE';
case 'usw':
return 'DE';
case 'ru':
return 'ENG';
default:
return 'PL1';
}
};
+30 -17
View File
@@ -10,7 +10,7 @@
<div class="message_container">
<div class="message_nav">
<span v-for="(action, i) in navActions">
<span v-for="(action, i) in navActions" :key="action.mode">
<b v-if="i > 0">&bull;</b>
<button
@@ -43,7 +43,6 @@ import { useStore } from '../store/store';
import OrderHelper from '../components/OrderHelper.vue';
import OrderTrainPicker from '../components/OrderTrainPicker.vue';
export default defineComponent({
components: { OrderVue, SideBar, OrderHelper },
@@ -52,29 +51,29 @@ export default defineComponent({
navActions: [
{
mode: 'OrderMessage',
value: 'TREŚĆ ROZKAZU',
value: 'TREŚĆ ROZKAZU'
},
{
mode: 'OrderList',
value: 'ZAPISANE ROZKAZY',
value: 'ZAPISANE ROZKAZY'
},
{
mode: 'OrderTrainPicker',
value: 'POCIĄGI',
},
],
value: 'POCIĄGI'
}
]
};
},
methods: {
selectOrderMode(mode: string) {
this.store.orderMode = mode;
},
}
},
setup() {
return {
store: useStore(),
store: useStore()
};
},
@@ -90,8 +89,8 @@ export default defineComponent({
default:
return OrderMessage;
}
},
},
}
}
});
</script>
@@ -116,27 +115,41 @@ export default defineComponent({
width: 100%;
@media screen and (max-width: 650px) {
padding-top: 5em;
padding-bottom: 5em;
padding: 1em 0.5em;
}
}
.order_container {
width: 100%;
max-width: 550px;
max-width: 600px;
position: relative;
display: flex;
align-items: start;
@media screen and (max-width: 650px) {
flex-direction: column;
}
}
.message_container {
width: 500px;
width: 100%;
max-width: 500px;
display: grid;
grid-template-rows: auto 1fr;
height: 95vh;
overflow: auto;
}
.message_nav {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 2em;
}
}
</style>
+3 -3
View File
@@ -1,7 +1,7 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
import type { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>;
export default component;
}
+15 -4
View File
@@ -2,11 +2,22 @@ import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { VitePWA } from 'vite-plugin-pwa';
import path from 'path';
export default defineConfig({
server: {
port: 8081,
},
css: {
preprocessorOptions: {
scss: { additionalData: `@use '@/styles/global';`, silenceDeprecations: ['legacy-js-api'] },
},
},
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
plugins: [
vue(),
VitePWA({
@@ -15,10 +26,10 @@ export default defineConfig({
globPatterns: ['**/*.{js,css,html,png,svg,img}'],
runtimeCaching: [
{
urlPattern: /^https:\/\/stacjownik-api-b9mrc\.ondigitalocean\.app\/api\/getSceneries/i,
urlPattern: /^https:\/\/stacjownik.spythere.eu\/\/api\/getSceneries/i,
handler: 'CacheFirst',
options: {
cacheName: 'sceneries-data-cache',
cacheName: 'sceneries-cache',
expiration: {
maxEntries: 250,
maxAgeSeconds: 60 * 60 * 24 * 7, // <== 7 days
@@ -31,9 +42,9 @@ export default defineConfig({
],
},
devOptions: {
enabled: true,
// enabled: true,
suppressWarnings: true
},
}),
],
});
+3963 -2447
View File
File diff suppressed because it is too large Load Diff