Compare commits
124 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3713289339 | |||
| cafdbb9653 | |||
| 7934a83cfd | |||
| 33f59db5f3 | |||
| 201c49845f | |||
| a1d0c47910 | |||
| fb82ac9fb2 | |||
| 76a31c345d | |||
| 4181119bd2 | |||
| 53029d37a5 | |||
| f5747db62d | |||
| 35bc44b969 | |||
| 1085170004 | |||
| d762d42344 | |||
| 31c241b3b7 | |||
| e4a5c7babb | |||
| b4c673ea51 | |||
| e53cf6faba | |||
| 3a3ba61454 | |||
| 6dcc96a677 | |||
| 897091468c | |||
| 0160a27bf4 | |||
| 802da68576 | |||
| 78e82df63d | |||
| b5a4ba9c0a | |||
| b93a65007e | |||
| 70d29284a5 | |||
| 5fb235c9a7 | |||
| 40c7e47632 | |||
| eac9b47e10 | |||
| 6af0e9b822 | |||
| 6306a07562 | |||
| a0a5e72701 | |||
| 7784e08f03 | |||
| 98fda8e849 | |||
| 81f484793f | |||
| 5a2be7b25e | |||
| 73c397a1bc | |||
| f54eada94d | |||
| fa4504fec7 | |||
| 9118c186cf | |||
| 14f730f8ca | |||
| 7afef587cc | |||
| 35a883d608 | |||
| 2efa4a4f9a | |||
| 92586fb880 | |||
| 3c9cdac832 | |||
| 4162f5e137 | |||
| b2b5716cc6 | |||
| 26b0556bfa | |||
| d59152fccd | |||
| 864967a77a | |||
| 37c2650841 | |||
| 5b9b86248f | |||
| 43b0dc9fa0 | |||
| 972c73281d | |||
| 8538072a60 | |||
| e298a17ab7 | |||
| 519665697b | |||
| c5221e337b | |||
| 2f5e61352a | |||
| 153d6ff0db | |||
| a9a486a789 | |||
| 85772df972 | |||
| 0464f4eae9 | |||
| 339b3edd1e | |||
| 069b27beaa | |||
| 7b18f84db1 | |||
| 42d0d1ddb9 | |||
| b1a51bbd74 | |||
| f28f1e31c2 | |||
| 0930dab77c | |||
| e81521ed09 | |||
| b69c44c55a | |||
| fab3cef1f3 | |||
| 99e55bb8b9 | |||
| d050cf0b89 | |||
| 1b8bf5cc45 | |||
| a180215dd0 | |||
| 5649e7c417 | |||
| 8b8d69132d | |||
| af579f2cba | |||
| d0052f8dd3 | |||
| 28ba4045a0 | |||
| d76c9a8521 | |||
| 10d5beae3c | |||
| d84ad635ee | |||
| ae0beadb93 | |||
| 758bb9f997 | |||
| 85c4fba8ba | |||
| af2af08fbc | |||
| 8aa2233d41 | |||
| f663c96842 | |||
| b663f7408d | |||
| 05f3f8f8b2 | |||
| bb285f9ba6 | |||
| 43d74ddaea | |||
| 53be6c8cf2 | |||
| 39236ece3e | |||
| c40e699b40 | |||
| 76c6169be9 | |||
| 76c1e97ddd | |||
| 71c9a47ea5 | |||
| a066da006c | |||
| 1783ae1fce | |||
| 7921bd46e9 | |||
| 189720c206 | |||
| e5e0751024 | |||
| 45ac3248ac | |||
| 06d33a30ed | |||
| e7fd51142d | |||
| bed61c38f6 | |||
| a1d81986c6 | |||
| e4ee67918a | |||
| f85bd13765 | |||
| f2015a2af5 | |||
| f7a456e791 | |||
| 262042c5b1 | |||
| e8574efa42 | |||
| 2119399c45 | |||
| df25fb0b36 | |||
| 94235df38d | |||
| 3155487a29 | |||
| dc2062d906 |
@@ -1,2 +1,5 @@
|
|||||||
VITE_APP_API_URL=https://stacjownik-api-b9mrc.ondigitalocean.app/api
|
VITE_APP_API_URL=https://stacjownik.spythere.eu/api
|
||||||
VITE_APP_SWDR_URL=https://api.td2.info.pl:9640
|
VITE_APP_SWDR_URL=https://api.td2.info.pl
|
||||||
|
|
||||||
|
VITE_APP_ORDER_VERSION=3 # 3 - NEW 2025 ORDER INSTRUCTIONS
|
||||||
|
#VITE_UPDATE_TEST='test'
|
||||||
@@ -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,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"projects": {
|
"projects": {
|
||||||
"default": "genera-tor"
|
"default": "generator-td2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- run: npm ci && npm run build
|
- run: yarn && yarn build
|
||||||
- uses: FirebaseExtended/action-hosting-deploy@v0
|
- uses: FirebaseExtended/action-hosting-deploy@v0
|
||||||
with:
|
with:
|
||||||
repoToken: '${{ secrets.GITHUB_TOKEN }}'
|
repoToken: '${{ secrets.GITHUB_TOKEN }}'
|
||||||
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_GENERA_TOR }}'
|
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_GENERATOR_TD2 }}'
|
||||||
channelId: live
|
channelId: live
|
||||||
projectId: genera-tor
|
projectId: generator-td2
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- run: npm ci && npm run build
|
- run: yarn && yarn build
|
||||||
- uses: FirebaseExtended/action-hosting-deploy@v0
|
- uses: FirebaseExtended/action-hosting-deploy@v0
|
||||||
with:
|
with:
|
||||||
repoToken: '${{ secrets.GITHUB_TOKEN }}'
|
repoToken: '${{ secrets.GITHUB_TOKEN }}'
|
||||||
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_GENERA_TOR }}'
|
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_GENERATOR_TD2 }}'
|
||||||
projectId: genera-tor
|
projectId: generator-td2
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
github-releases-to-discord:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Github Releases To Discord
|
||||||
|
uses: SethCohen/github-releases-to-discord@v1.13.1
|
||||||
|
with:
|
||||||
|
webhook_url: '${{ secrets.WEBHOOK_URL }}'
|
||||||
|
color: '9936031'
|
||||||
|
footer_title: 'Changelog - GeneraTOR'
|
||||||
|
footer_timestamp: true
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
node_modules
|
node_modules
|
||||||
/dev-dist
|
/dev-dist
|
||||||
.log
|
.log
|
||||||
|
/dist
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env.local
|
.env.local
|
||||||
@@ -24,3 +25,6 @@ pnpm-debug.log*
|
|||||||
|
|
||||||
# Firebase
|
# Firebase
|
||||||
.firebase
|
.firebase
|
||||||
|
|
||||||
|
#Yarn lock files
|
||||||
|
yarn.lock
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/prettierrc",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 100,
|
||||||
|
"trailingComma": "none"
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
presets: [
|
|
||||||
'@vue/cli-plugin-babel/preset'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
@@ -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 |
@@ -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>
|
|
||||||
|
Before Width: | Height: | Size: 650 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 15 KiB |
@@ -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>
|
|
||||||
@@ -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 +0,0 @@
|
|||||||
{"name":"genera-tor","short_name":"genera-tor","start_url":"/","display":"standalone","background_color":"#ffffff","lang":"en","scope":"/"}
|
|
||||||
|
Before Width: | Height: | Size: 4.5 KiB |
@@ -1 +0,0 @@
|
|||||||
if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js', { scope: '/' })})}
|
|
||||||
@@ -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 |
@@ -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"
|
|
||||||
}
|
|
||||||
@@ -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} didn’t 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,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="pl">
|
<html lang="pl">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
@@ -24,6 +24,36 @@
|
|||||||
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
|
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
|
|
||||||
|
<!-- Preloads -->
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/fonts/libre-franklin-500.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/fonts/libre-franklin-700.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/fonts/libre-franklin-800.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/fonts/libre-franklin-regular.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin
|
||||||
|
/>
|
||||||
|
|
||||||
<title>GeneraTOR</title>
|
<title>GeneraTOR</title>
|
||||||
<meta name="description" content="Generator rozkazów pisemnych online" />
|
<meta name="description" content="Generator rozkazów pisemnych online" />
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -1,26 +1,38 @@
|
|||||||
{
|
{
|
||||||
"name": "genera-tor",
|
"name": "genera-tor",
|
||||||
"version": "1.1.3dev",
|
"version": "1.7.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --port 8080",
|
"dev": "vite --port 8080",
|
||||||
"deploy": "yarn build && firebase deploy --only hosting",
|
"deploy": "yarn build && firebase deploy --only hosting",
|
||||||
"build": "vue-tsc --noEmit && vite build",
|
"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": {
|
"dependencies": {
|
||||||
"axios": "^1.1.3",
|
"axios": "^1.6.2",
|
||||||
"pinia": "^2.0.14",
|
"lucide-vue-next": "^0.525.0",
|
||||||
"vue": "^3.2.37",
|
"pinia": "^2.1.7",
|
||||||
"vue-i18n": "9",
|
"showdown": "^2.1.0",
|
||||||
"vue-router": "^4.0.0-0",
|
"vue": "^3.3.11",
|
||||||
"vue-tsc": "^1.0.9"
|
"vue-i18n": "11",
|
||||||
|
"vue-router": "^4.2.5",
|
||||||
|
"vue-tsc": "^2.2.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^3.2.0",
|
"@types/node": "^22.13.10",
|
||||||
"sass": "^1.56.0",
|
"@types/showdown": "^2.0.6",
|
||||||
"typescript": "^4.8.4",
|
"@vitejs/plugin-vue": "^4.5.2",
|
||||||
"vite": "^3.2.2",
|
"@vue/eslint-config-prettier": "^8.0.0",
|
||||||
"vite-plugin-pwa": "^0.13.2"
|
"@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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,89 +1,114 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app_wrapper">
|
<div>
|
||||||
<router-view />
|
|
||||||
|
|
||||||
<transition name="slide-anim">
|
<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>
|
<UpdateCard />
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<footer>
|
<transition name="slide-anim">
|
||||||
© <a href="https://td2.info.pl/profile/?u=20777">Spythere</a> {{ new Date().getUTCFullYear() }} | v.{{
|
<UpdatePrompt />
|
||||||
appVersion
|
</transition>
|
||||||
}}
|
|
||||||
</footer>
|
<div class="app-body">
|
||||||
|
<AppNavbar />
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<RouterView />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { useRegisterSW } from 'virtual:pwa-register/vue';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import packageInfo from '../package.json';
|
import packageInfo from '../package.json';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { useStore } from './store/store';
|
||||||
|
|
||||||
export default defineComponent({
|
import UpdateCard from './components/Global/UpdateCard.vue';
|
||||||
setup() {
|
import UpdatePrompt from './components/Global/UpdatePrompt.vue';
|
||||||
const { offlineReady, needRefresh, updateServiceWorker } = useRegisterSW({
|
import AppNavbar from './components/App/AppNavbar.vue';
|
||||||
immediate: true,
|
import StorageManager from './managers/storageManager';
|
||||||
});
|
import { onMounted } from 'vue';
|
||||||
|
|
||||||
return {
|
const STORAGE_VERSION_KEY = 'app_version';
|
||||||
offlineReady,
|
|
||||||
needRefresh,
|
|
||||||
updateServiceWorker,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
appVersion: packageInfo.version,
|
|
||||||
needRefreshTest: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
const store = useStore();
|
||||||
document.title = `GeneraTOR ${this.appVersion}`;
|
const appVersion = packageInfo.version;
|
||||||
|
|
||||||
setTimeout(() => {
|
onMounted(() => {
|
||||||
this.needRefreshTest = true;
|
loadLang();
|
||||||
}, 500);
|
loadSettings();
|
||||||
},
|
checkAppVersion();
|
||||||
|
handleQueries();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function loadSettings() {
|
||||||
|
document.title = `GeneraTOR ${appVersion}`;
|
||||||
|
store.orderDarkMode = StorageManager.getBooleanValue('dark-mode');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleQueries() {
|
||||||
|
const query = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
const id = query.get('sceneryId');
|
||||||
|
|
||||||
|
if (id != null) {
|
||||||
|
store.panelMode = 'OrderTrainPickerPanel';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkAppVersion() {
|
||||||
|
const storageVersion = StorageManager.getStringValue(STORAGE_VERSION_KEY);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const releaseData = await (
|
||||||
|
await axios.get('https://api.github.com/repos/Spythere/genera-tor/releases/latest')
|
||||||
|
).data;
|
||||||
|
|
||||||
|
if (!releaseData) return;
|
||||||
|
|
||||||
|
store.appUpdateData.version = appVersion;
|
||||||
|
store.appUpdateData.changelog = releaseData.body;
|
||||||
|
store.appUpdateData.releaseURL = releaseData.html_url;
|
||||||
|
|
||||||
|
store.updateCardOpen =
|
||||||
|
(storageVersion != '' && storageVersion != appVersion) ||
|
||||||
|
import.meta.env.VITE_UPDATE_TEST === 'test';
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Wystąpił błąd podczas pobierania danych z API GitHuba: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageManager.setStringValue(STORAGE_VERSION_KEY, appVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadLang() {
|
||||||
|
const storageLang = StorageManager.getStringValue('lang');
|
||||||
|
|
||||||
|
if (storageLang) {
|
||||||
|
store.changeLang(storageLang);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window.navigator.language) return;
|
||||||
|
|
||||||
|
const naviLanguage = window.navigator.language.toString();
|
||||||
|
|
||||||
|
if (!naviLanguage.startsWith('pl')) {
|
||||||
|
store.changeLang('en');
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import './styles/global.scss';
|
@use 'styles/anims';
|
||||||
@import './styles/anims.scss';
|
@use 'styles/colors';
|
||||||
|
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.update-prompt {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
padding: 0.5em;
|
|
||||||
|
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
background-color: $accentCol;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0.5em 0;
|
padding: 0.5em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 500px) {
|
|
||||||
#app {
|
|
||||||
font-size: calc(1vw + 0.5rem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<footer>
|
||||||
|
© <a href="https://td2.info.pl/profile/?u=20777">Spythere</a>
|
||||||
|
{{ new Date().getUTCFullYear() }} |
|
||||||
|
<button class="g-button text" @click="store.updateCardOpen = true">v{{ props.version }}</button>
|
||||||
|
</footer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
version: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<nav class="app-navbar">
|
||||||
|
<div class="navbar-brand">
|
||||||
|
<img src="/favicon.ico" alt="generator logo" width="30" />
|
||||||
|
<b>
|
||||||
|
Genera<span class="text--accent">TOR</span> <sup class="text--grayed">v{{ version }}</sup>
|
||||||
|
</b>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="navbar-actions">
|
||||||
|
<button class="g-button action icon" @click="switchDarkMode">
|
||||||
|
<LucideMoon :size="20" v-if="store.orderDarkMode" />
|
||||||
|
<LucideSun :size="20" v-else />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="g-button action icon" @click="switchLang">
|
||||||
|
<LucideGlobe :size="20" />
|
||||||
|
<span>{{ store.currentAppLocale == 'pl' ? 'POL' : 'ENG' }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { LucideGlobe, LucideMoon, LucideSun } from 'lucide-vue-next';
|
||||||
|
import { version } from '../../../package.json';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
function switchDarkMode() {
|
||||||
|
store.orderDarkMode = !store.orderDarkMode;
|
||||||
|
window.localStorage.setItem('dark-mode', `${store.orderDarkMode}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchLang() {
|
||||||
|
store.changeLang(store.currentAppLocale == 'pl' ? 'en' : 'pl');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.app-navbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0.25em;
|
||||||
|
background-color: #1c1c1c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-brand {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
sup {
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 0.5em;
|
||||||
|
gap: 0.25em;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
<template>
|
||||||
|
<div class="update-card" v-if="store.updateCardOpen" @toggle-card="toggleCard(false)">
|
||||||
|
<div class="card-background"></div>
|
||||||
|
<div class="card-content">
|
||||||
|
<h1 style="margin-bottom: 0.5em">🚀 {{ $t('update.title') }}</h1>
|
||||||
|
|
||||||
|
<div class="changelog" v-if="htmlChangelog != ''" v-html="htmlChangelog"></div>
|
||||||
|
<div class="no-features" v-else>{{ $t('update.no-data') }}</div>
|
||||||
|
|
||||||
|
<button class="g-button action btn-confirm" ref="confirmButtonEl" @click="toggleCard(false)">
|
||||||
|
{{ $t('update.confirm') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<p class="bottom-info">
|
||||||
|
{{ $t('update.info-1') }}
|
||||||
|
<br />
|
||||||
|
<span v-html="$t('update.info-2')"></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, watch } from 'vue';
|
||||||
|
import { Converter } from 'showdown';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
|
||||||
|
const converter = new Converter();
|
||||||
|
const store = useStore();
|
||||||
|
const confirmButtonEl = ref<HTMLButtonElement | null>(null);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
computed(() => store.updateCardOpen),
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
confirmButtonEl.value?.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const htmlChangelog = computed(() => {
|
||||||
|
if (store.appUpdateData.changelog == '') return '';
|
||||||
|
|
||||||
|
return converter.makeHtml(store.appUpdateData.changelog);
|
||||||
|
});
|
||||||
|
|
||||||
|
function toggleCard(value: boolean) {
|
||||||
|
store.updateCardOpen = value;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
// Converter styles
|
||||||
|
::v-deep(h1) {
|
||||||
|
text-align: center;
|
||||||
|
color: var(--clr-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep(h2) {
|
||||||
|
padding: 0.25em 0;
|
||||||
|
border-bottom: 1px solid #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep(ul) {
|
||||||
|
list-style: disc;
|
||||||
|
padding: 1em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
.update-card {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 200;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-background {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 250;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
background-color: rgba(0, 0, 0, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto 1fr auto;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
margin: 1em;
|
||||||
|
|
||||||
|
max-height: 95vh;
|
||||||
|
max-height: 95dvh;
|
||||||
|
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
box-shadow: 0 0 15px 10px #0e0e0e;
|
||||||
|
border-radius: 1em;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
padding: 1em;
|
||||||
|
min-height: 700px;
|
||||||
|
overflow: auto;
|
||||||
|
max-width: 700px;
|
||||||
|
|
||||||
|
z-index: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-features {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.changelog {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.btn-confirm {
|
||||||
|
padding: 0.5em 0.75em;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.bottom-info {
|
||||||
|
text-align: center;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="needRefresh" class="update-prompt" @click="updateServiceWorker(true)">
|
||||||
|
{{ $t('update.update-available-text') }}
|
||||||
|
<u>{{ $t('update.update-available-underline') }}</u>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useRegisterSW } from 'virtual:pwa-register/vue';
|
||||||
|
|
||||||
|
const { offlineReady, needRefresh, updateServiceWorker } = useRegisterSW({ immediate: true });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@use '../../styles/colors';
|
||||||
|
|
||||||
|
.update-prompt {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: 0.5em;
|
||||||
|
|
||||||
|
z-index: 200;
|
||||||
|
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
background-color: colors.$accentCol;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="order">
|
|
||||||
<div class="order_content">
|
|
||||||
<transition name="order-anim" mode="out-in">
|
|
||||||
<keep-alive>
|
|
||||||
<component :is="chosenOrderComponent" :key="chosenOrderComponent.name"></component>
|
|
||||||
</keep-alive>
|
|
||||||
</transition>
|
|
||||||
<OrderFooter />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
import OrderNVue from './OrderN.vue';
|
|
||||||
import OrderSVue from './OrderS.vue';
|
|
||||||
import OrderFooter from './OrderFooter.vue';
|
|
||||||
import OrderOVue from './OrderO.vue';
|
|
||||||
|
|
||||||
const orderComponents = {
|
|
||||||
orderN: OrderNVue,
|
|
||||||
orderS: OrderSVue,
|
|
||||||
orderO: OrderOVue,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: { OrderNVue, OrderSVue, OrderFooter },
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
return {
|
|
||||||
store,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
chosenOrderComponent() {
|
|
||||||
return orderComponents[this.store.chosenOrderType];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import '../styles/global.scss';
|
|
||||||
|
|
||||||
// Order scrollbar
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
background: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.order {
|
|
||||||
background-color: white;
|
|
||||||
color: black;
|
|
||||||
|
|
||||||
height: 925px;
|
|
||||||
max-height: 95vh;
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
font-size: 15px;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
padding: 0.5em;
|
|
||||||
border: 2px solid black;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 550px) {
|
|
||||||
font-size: 3vw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.order_content {
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-row {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
align-items: flex-end;
|
|
||||||
|
|
||||||
margin-top: 0.5em;
|
|
||||||
|
|
||||||
input {
|
|
||||||
max-width: 10em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-center {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
max-width: 100px;
|
|
||||||
background-color: transparent;
|
|
||||||
outline: none;
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
border-bottom: 2px dotted black;
|
|
||||||
font-size: 0.9em;
|
|
||||||
text-align: center;
|
|
||||||
color: black;
|
|
||||||
|
|
||||||
&:focus-visible {
|
|
||||||
border-bottom: 2px solid $accentCol;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.row-checkbox + input::placeholder {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type='checkbox'],
|
|
||||||
input[type='radio'],
|
|
||||||
textarea,
|
|
||||||
select {
|
|
||||||
&:focus-visible {
|
|
||||||
outline: 2px solid $accentCol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-section {
|
|
||||||
table.options-table {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
td:first-child {
|
|
||||||
width: 10%;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
padding: 0.35em;
|
|
||||||
text-align: justify;
|
|
||||||
vertical-align: top;
|
|
||||||
|
|
||||||
line-height: 1.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table,
|
|
||||||
td {
|
|
||||||
border: 2px solid black;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.order-anim {
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: opacity 150ms ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<template>
|
||||||
|
<div class="order" :class="{ dark: store.orderDarkMode }">
|
||||||
|
<OrderHeader />
|
||||||
|
<OrderMainContent />
|
||||||
|
<OrderFooter />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
import OrderHeader from './OrderHeader.vue';
|
||||||
|
import OrderMainContent from './OrderMainContent.vue';
|
||||||
|
import OrderFooter from './OrderFooter.vue';
|
||||||
|
import { computed, onMounted, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
generateMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
store.orderData,
|
||||||
|
() => {
|
||||||
|
generateMessage();
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
computed(() => store.currentAppLocale),
|
||||||
|
() => {
|
||||||
|
generateMessage();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function generateMessage() {
|
||||||
|
let messageHtml = `<b>${t('order.title')}</b><br />`;
|
||||||
|
messageHtml += '-------------<br />';
|
||||||
|
|
||||||
|
const headerData = store.orderData['header'];
|
||||||
|
const headerDateString = headerData['B']
|
||||||
|
? new Date(headerData['B']).toLocaleDateString('pl-PL', {
|
||||||
|
day: '2-digit',
|
||||||
|
month: '2-digit',
|
||||||
|
year: 'numeric'
|
||||||
|
})
|
||||||
|
: '';
|
||||||
|
|
||||||
|
messageHtml += `${t('order.header.A')}: ${headerData['A'] || '---'}<br />`;
|
||||||
|
messageHtml += `${t('order.header.B')}: ${headerDateString || '---'}<br />`;
|
||||||
|
messageHtml += `${t('order.header.C')}: ${headerData['C'] || '---'}<br />`;
|
||||||
|
messageHtml += `${t('order.header.D')}: ${headerData['D'] || '---'}<br />`;
|
||||||
|
|
||||||
|
const instructions = store.orderData['instructions'];
|
||||||
|
|
||||||
|
Object.entries(instructions).forEach(([i, value]) => {
|
||||||
|
if (value.active) {
|
||||||
|
if (value.inputFields) {
|
||||||
|
const localeKey = `order.${value.key}`;
|
||||||
|
|
||||||
|
const messageValues = Object.values(value.inputFields).map((fieldKey: string) => {
|
||||||
|
if (fieldKey.startsWith('select')) return t(`order.${value.key}.${fieldKey}`);
|
||||||
|
|
||||||
|
return fieldKey || '---';
|
||||||
|
});
|
||||||
|
|
||||||
|
messageHtml += '-------------<br />';
|
||||||
|
|
||||||
|
messageHtml += `<b>[${value.name}]</b> ${t(
|
||||||
|
localeKey + '.message-html',
|
||||||
|
messageValues,
|
||||||
|
Object.keys(value.inputFields).filter(
|
||||||
|
(k) => value.optionalFieldNames.includes(k) && value.inputFields[k].trim() != ''
|
||||||
|
).length
|
||||||
|
)}<br />`;
|
||||||
|
|
||||||
|
if (value.key == '2310' && value.listFields) {
|
||||||
|
messageHtml += '<br />';
|
||||||
|
value.listFields.forEach((listItem, i) => {
|
||||||
|
if (!listItem.active) return;
|
||||||
|
|
||||||
|
const listItemValues = Object.values(listItem.values).map((itemFieldKey) => {
|
||||||
|
return itemFieldKey || '---';
|
||||||
|
});
|
||||||
|
|
||||||
|
messageHtml += t(
|
||||||
|
`${localeKey}.message-html-list`,
|
||||||
|
[i + 1, ...listItemValues],
|
||||||
|
Object.keys(listItem.values).filter(
|
||||||
|
(k) => listItem.values[k].trim() != '' && k.startsWith('signalbox')
|
||||||
|
).length
|
||||||
|
);
|
||||||
|
messageHtml += '<br />';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
messageHtml += `<b>[${i}]</b> ${t('order.' + i + '.message-html')}<br />`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const footerData = store.orderData['footer'];
|
||||||
|
|
||||||
|
messageHtml += '-------------<br />';
|
||||||
|
messageHtml += `${t('order.footer.V')}: ${footerData['V'] || '---'}<br />`;
|
||||||
|
messageHtml += `${t('order.footer.W')}: ${footerData['W'] || '---'}<br />`;
|
||||||
|
messageHtml += `${t('order.footer.Y')}: ${footerData['Y'] || '---'}<br />`;
|
||||||
|
messageHtml += `${t('order.footer.Z')}: ${footerData['Z'] || '---'}<br />`;
|
||||||
|
|
||||||
|
store.orderMessage = messageHtml;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@use '../../styles/order';
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<table class="order-table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td width="50%">
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="order-input"
|
||||||
|
id="footer-V"
|
||||||
|
v-model="store.orderData.footer.V"
|
||||||
|
:placeholder="t('order.footer.V-placeholder')"
|
||||||
|
/>
|
||||||
|
<label class="order-input-label" for="footer-V">{{ t('order.footer.V') }}</label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="order-input"
|
||||||
|
id="footer-W"
|
||||||
|
v-model="store.orderData.footer.W"
|
||||||
|
:placeholder="t('order.footer.W-placeholder')"
|
||||||
|
/>
|
||||||
|
<label class="order-input-label" for="footer-W">{{ t('order.footer.W') }}</label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="order-input"
|
||||||
|
id="footer-Y"
|
||||||
|
v-model="store.orderData.footer.Y"
|
||||||
|
:placeholder="t('order.footer.Y-placeholder')"
|
||||||
|
/>
|
||||||
|
<label class="order-input-label" for="footer-Y">{{ t('order.footer.Y') }}</label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="order-input"
|
||||||
|
id="footer-Z"
|
||||||
|
v-model="store.orderData.footer.Z"
|
||||||
|
:placeholder="t('order.footer.Z-placeholder')"
|
||||||
|
/>
|
||||||
|
<label class="order-input-label" for="footer-Z">{{ t('order.footer.Z') }}</label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.order-input {
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-table > tbody > tr > td > div {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5em 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
<template>
|
||||||
|
<table class="order-table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 0.25em" colspan="2">
|
||||||
|
<b>{{ t('order.title') }}</b>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td width="50%">
|
||||||
|
<div class="header-input-box">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="order-input"
|
||||||
|
id="header-A"
|
||||||
|
v-model="store.orderData.header.A"
|
||||||
|
:placeholder="t('order.header.A-placeholder')"
|
||||||
|
/>
|
||||||
|
<label class="order-input-label" for="header-A">{{ t('order.header.A') }}</label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="header-input-box">
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
class="order-input"
|
||||||
|
id="header-B"
|
||||||
|
v-model="store.orderData.header.B"
|
||||||
|
/>
|
||||||
|
<label class="order-input-label" for="header-B">{{ t('order.header.B') }}</label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="header-input-box">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="order-input"
|
||||||
|
id="header-C"
|
||||||
|
v-model="store.orderData.header.C"
|
||||||
|
:placeholder="t('order.header.C-placeholder')"
|
||||||
|
/>
|
||||||
|
<label class="order-input-label" for="header-C">{{ t('order.header.C') }}</label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="header-input-box">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="order-input"
|
||||||
|
id="header-D"
|
||||||
|
v-model="store.orderData.header.D"
|
||||||
|
:placeholder="t('order.header.D-placeholder')"
|
||||||
|
/>
|
||||||
|
<label class="order-input-label" for="header-D">{{ t('order.header.D') }}</label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const store = useStore();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.header-input-box {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-input {
|
||||||
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-table,
|
||||||
|
.order-table tr:last-child td {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
<template>
|
||||||
|
<table class="order-table">
|
||||||
|
<tbody>
|
||||||
|
<!-- First row - 22 & 99 instructions -->
|
||||||
|
<tr>
|
||||||
|
<td width="10%" class="order-instruction-number">
|
||||||
|
<OrderRowCheckbox :row-index="0" />
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<b>
|
||||||
|
{{ t('order.22.text') }}
|
||||||
|
</b>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td width="5%" class="order-instruction-number">
|
||||||
|
<OrderRowCheckbox :row-index="1" />
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td width="45%">
|
||||||
|
<div>
|
||||||
|
<b>{{ t('order.99.text') }}</b>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="order-input"
|
||||||
|
id="input-99-x1"
|
||||||
|
v-model="store.orderData.instructions[1].inputFields!.x1"
|
||||||
|
/>
|
||||||
|
<label for="input-99-x1" class="order-input-label">{{ t('order.99.x1') }}</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- From 21.10 -->
|
||||||
|
<tr
|
||||||
|
v-for="(instruction, i) in store.orderData.instructions.slice(2)"
|
||||||
|
:class="{
|
||||||
|
'bg-lighter': instruction.key.startsWith('218'),
|
||||||
|
dark: store.orderDarkMode
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<td width="10%" class="order-instruction-number">
|
||||||
|
<OrderRowCheckbox :row-index="i + 2" />
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td colspan="3">
|
||||||
|
<i18n-t :keypath="`order.${instruction.key}.text`" tag="div" scope="global">
|
||||||
|
<!-- For text directives (<b>, <u>, <br> etc.) -->
|
||||||
|
<template v-slot:[directive] v-for="directive in instruction.textDirectives">
|
||||||
|
<b v-if="directive.startsWith('bold')">
|
||||||
|
{{ t(`order.${instruction.key}.${directive}`) }}
|
||||||
|
</b>
|
||||||
|
<u v-else-if="directive.startsWith('underline')">
|
||||||
|
{{ t(`order.${instruction.key}.${directive}`) }}
|
||||||
|
</u>
|
||||||
|
<u v-else-if="directive.startsWith('highlight')">
|
||||||
|
<b>{{ t(`order.${instruction.key}.${directive}`) }}</b>
|
||||||
|
</u>
|
||||||
|
<br v-if="directive.startsWith('br')" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- For all instructions with input fields -->
|
||||||
|
<template v-slot:[fieldKey] v-for="(_, fieldKey) in instruction.inputFields">
|
||||||
|
<textarea
|
||||||
|
v-if="fieldKey == 'other2320'"
|
||||||
|
v-model="instruction.inputFields[fieldKey]"
|
||||||
|
class="order-textarea"
|
||||||
|
:id="`order-${instruction.key}-${fieldKey}`"
|
||||||
|
:placeholder="t(`order.${instruction.key}.${fieldKey}`)"
|
||||||
|
autocomplete="off"
|
||||||
|
></textarea>
|
||||||
|
|
||||||
|
<label class="order-input-box" v-else>
|
||||||
|
<input
|
||||||
|
v-model="instruction.inputFields[fieldKey]"
|
||||||
|
class="order-input"
|
||||||
|
:id="`order-${instruction.key}-${fieldKey}`"
|
||||||
|
:style="{ width: calculateInputWidthByFieldName(fieldKey) }"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
<span>{{ t(`order.${instruction.key}.${fieldKey}`) }}</span>
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- For all instructions with select fields -->
|
||||||
|
<template v-for="(selectField, fieldKey) in instruction.selectFields" v-slot:[fieldKey]>
|
||||||
|
<select
|
||||||
|
class="order-select"
|
||||||
|
:id="`order-${instruction.key}-${fieldKey}`"
|
||||||
|
v-model="instruction.inputFields[fieldKey]"
|
||||||
|
>
|
||||||
|
<option :value="value" v-for="value in selectField.options">
|
||||||
|
{{ t(`order.${instruction.key}.${value}`) }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- For 23.10 only -->
|
||||||
|
<template v-slot:text-list v-if="instruction.key == '2310'">
|
||||||
|
<i18n-t
|
||||||
|
v-for="(listItem, i) in instruction.listFields"
|
||||||
|
:keypath="`order.${instruction.key}.text-list`"
|
||||||
|
tag="div"
|
||||||
|
scope="global"
|
||||||
|
>
|
||||||
|
<template v-slot:bold>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
v-model="listItem.active"
|
||||||
|
type="checkbox"
|
||||||
|
:id="`order-${instruction.key}-checkbox-${i}`"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<b>{{ t(`order.${instruction.key}.bold`, [i + 1]) }}</b>
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:v>
|
||||||
|
<br />
|
||||||
|
<span style="font-size: 1.5em">v</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:[fieldKey] v-for="(_, fieldKey, j) in listItem.values">
|
||||||
|
<label class="order-input-box">
|
||||||
|
<input
|
||||||
|
v-model="instruction.listFields![i]['values'][fieldKey]"
|
||||||
|
class="order-input"
|
||||||
|
:id="`order-${instruction.key}-${fieldKey}-${i}`"
|
||||||
|
:style="{ width: calculateInputWidthByFieldName(fieldKey) }"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
<span>{{
|
||||||
|
t(`order.${instruction.key}.${fieldKey}`, [j + 1 + 6 * i, 91 + i])
|
||||||
|
}}</span>
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
import OrderRowCheckbox from './OrderRowCheckbox.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
function calculateInputWidthByFieldName(fieldName: string) {
|
||||||
|
if (fieldName.startsWith('track')) return '90px';
|
||||||
|
else if (fieldName.startsWith('signalbox')) return '130px';
|
||||||
|
else if (fieldName.startsWith('signal')) return '150px';
|
||||||
|
else if (fieldName.startsWith('train')) return '150px';
|
||||||
|
else if (fieldName.startsWith('other2320')) return '100%';
|
||||||
|
else if (fieldName.startsWith('other')) return '200px';
|
||||||
|
|
||||||
|
return '100px';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.order-table {
|
||||||
|
border-top: none;
|
||||||
|
border-bottom: none;
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:not(:first-child) td {
|
||||||
|
padding: 0.25em 1em;
|
||||||
|
line-height: 2em;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.bg-lighter {
|
||||||
|
background-color: #eeece1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.bg-lighter.dark {
|
||||||
|
background-color: #111;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-instruction-number {
|
||||||
|
position: relative;
|
||||||
|
height: 60px;
|
||||||
|
|
||||||
|
& > label {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
<template>
|
||||||
|
<label class="order-instruction-checkbox">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
v-model="instructionObject.active"
|
||||||
|
:id="`instruction-checkbox-${instructionObject.name}`"
|
||||||
|
/>
|
||||||
|
<div class="checkmark" :class="{ dark: store.orderDarkMode }"></div>
|
||||||
|
<div class="text">{{ instructionObject.name }}</div>
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
rowIndex: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const instructionObject = computed(() => store.orderData.instructions[props.rowIndex]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.order-instruction-checkbox {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
& > input {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:checked ~ .checkmark:after {
|
||||||
|
content: '\d7';
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible ~ .text {
|
||||||
|
text-decoration: underline;
|
||||||
|
outline: 1px solid black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkmark {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
background-color: #eee;
|
||||||
|
border: 2px solid black;
|
||||||
|
|
||||||
|
background-color: gold;
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
font-size: 20px;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover input ~ .checkmark {
|
||||||
|
background-color: #ffe44b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
<template>
|
|
||||||
<section class="order_info">
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td colspan="4">
|
|
||||||
<input type="text" v-model="footerInfo.stationName" placeholder="nazwa stacji" />
|
|
||||||
<br />
|
|
||||||
stacja
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td colspan="3">
|
|
||||||
<input type="text" v-model="footerInfo.checkpointName" placeholder="skrót posterunku" />
|
|
||||||
<br />
|
|
||||||
posterunek
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td colspan="2">
|
|
||||||
<input type="text" v-model="footerInfo.hour" placeholder="godzina" />
|
|
||||||
<br />
|
|
||||||
godz.
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td colspan="1">
|
|
||||||
<input type="text" v-model="footerInfo.minutes" placeholder="minuta" />
|
|
||||||
<br />
|
|
||||||
min.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td colspan="5">
|
|
||||||
<input type="text" v-model="footerInfo.dispatcherName" placeholder="dyżurny" />
|
|
||||||
<br />
|
|
||||||
dyżurny ruchu
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td colspan="5">
|
|
||||||
<input type="text" v-model="footerInfo.secondaryDispatcherName" placeholder="dyżurny (wypełnić jedno)" />
|
|
||||||
<br />
|
|
||||||
z polecenia dyżurnego ruchu
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import orderFooterMixin from '../mixins/orderFooterMixin';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
mixins: [orderFooterMixin],
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
return {
|
|
||||||
store,
|
|
||||||
footerInfo: store.orderFooter,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
footerInfo: {
|
|
||||||
deep: true,
|
|
||||||
handler() {
|
|
||||||
this.generateFooter();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.order_info {
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
width: 100%;
|
|
||||||
table-layout: fixed;
|
|
||||||
|
|
||||||
td {
|
|
||||||
border: 2px solid black;
|
|
||||||
border-collapse: collapse;
|
|
||||||
padding: 0.35em;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
max-width: 95%;
|
|
||||||
}
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="order-helper g-modal">
|
|
||||||
<div class="modal-bg" @click="store.helperModalOpen = false"></div>
|
|
||||||
|
|
||||||
<div class="content modal-content">
|
|
||||||
<h2>Rozkazy pisemne - najczęstsze przypadki zastosowań w TD2</h2>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<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>
|
|
||||||
</p>
|
|
||||||
<button class="g-button action">Wygeneruj treść rozkazu</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
import orderHelperData from '../data/orderHelperData.json';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
store: useStore(),
|
|
||||||
orderHelperData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import "../styles/global.scss";
|
|
||||||
|
|
||||||
.content {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 800px;
|
|
||||||
|
|
||||||
height: 100vh;
|
|
||||||
max-height: 800px;
|
|
||||||
|
|
||||||
margin: 1em;
|
|
||||||
padding: 1em;
|
|
||||||
background-color: #2b2b2b;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
li b {
|
|
||||||
font-size: 1.1em;
|
|
||||||
color: $accentCol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
<template>
|
|
||||||
<section class="order-list">
|
|
||||||
<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 v-for="order in sortedOrderList" :selected="order.id == store.chosenLocalOrderId" :key="order.id">
|
|
||||||
<b class="text--accent">#{{ order.id.split('-')[1] }} </b>
|
|
||||||
<b>
|
|
||||||
{{ getOrderName(order.orderType) }} nr {{ order.orderBody['header']['orderNo'] }} dla pociągu nr
|
|
||||||
{{ order.orderBody['header']['trainNo'] }}
|
|
||||||
</b>
|
|
||||||
<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>
|
|
||||||
</li>
|
|
||||||
</transition-group>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import orderStorageMixin from '../mixins/orderStorageMixin';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
import { LocalStorageOrder } from '../types/orderTypes';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'OrderList',
|
|
||||||
mixins: [orderStorageMixin],
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
localOrderList: [] as LocalStorageOrder[],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
store: useStore(),
|
|
||||||
localStorage: window.localStorage,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
getOrderName(orderType: string) {
|
|
||||||
return `Rozkaz "${orderType.split('order')[1]}"`;
|
|
||||||
},
|
|
||||||
|
|
||||||
removeOrder(order: LocalStorageOrder) {
|
|
||||||
if (!order) return;
|
|
||||||
|
|
||||||
this.removeLocalOrder(order);
|
|
||||||
|
|
||||||
this.localOrderList = this.localOrderList.filter((o) => o.id != order.id);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
sortedOrderList() {
|
|
||||||
return this.localOrderList.sort((a, b) => (b.createdAt || b.updatedAt!) - (a.createdAt || a.updatedAt!));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
activated() {
|
|
||||||
const localStorage = window.localStorage;
|
|
||||||
const orderList = [];
|
|
||||||
|
|
||||||
for (let key in localStorage) {
|
|
||||||
if (!/^order-/g.test(key)) continue;
|
|
||||||
|
|
||||||
const orderObj: LocalStorageOrder = JSON.parse(localStorage[key]);
|
|
||||||
if (!orderObj) continue;
|
|
||||||
|
|
||||||
orderList.push(orderObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.localOrderList = orderList;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '../styles/global.scss';
|
|
||||||
|
|
||||||
.list {
|
|
||||||
&-move,
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: all 250ms ease;
|
|
||||||
}
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(30px);
|
|
||||||
}
|
|
||||||
|
|
||||||
&-leave-active {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.order-list {
|
|
||||||
padding: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
max-height: 750px;
|
|
||||||
height: 80vh;
|
|
||||||
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin: 0;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
text-align: left;
|
|
||||||
padding: 1em;
|
|
||||||
margin: 0.5em;
|
|
||||||
background-color: #222;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
button {
|
|
||||||
margin: 1em 1em 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[selected='true'] {
|
|
||||||
outline: 1px solid $accentCol;
|
|
||||||
}
|
|
||||||
&.no-orders-warning {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1.2em;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@@ -1,225 +0,0 @@
|
|||||||
<template>
|
|
||||||
<section class="order-message">
|
|
||||||
<h3>Wiadomość do wyświetlenia na czacie symulatora:</h3>
|
|
||||||
|
|
||||||
<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
|
|
||||||
</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">
|
|
||||||
Zaktualizuj rozkaz
|
|
||||||
<span class="text--accent"
|
|
||||||
>{{ store.chosenLocalOrderId && `#${store.chosenLocalOrderId.split('-')[1]}` }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<transition name="monit-anim">
|
|
||||||
<div class="action_monit" v-if="actionMonit" v-html="actionMonit"></div>
|
|
||||||
</transition>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
|
|
||||||
import saveIcon from '../assets/icon-save.svg';
|
|
||||||
import orderStorageMixin from '../mixins/orderStorageMixin';
|
|
||||||
import orderValidationMixin from '../mixins/orderValidationMixin';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'OrderMessage',
|
|
||||||
|
|
||||||
mixins: [orderStorageMixin, orderValidationMixin],
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
saveIcon,
|
|
||||||
actionMonit: '',
|
|
||||||
monitTimeout: undefined as number | undefined,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
store: useStore(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
fullOrderMessage() {
|
|
||||||
return this.store.orderMessage + this.store.footerMessage;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
showActionMonit(text: string) {
|
|
||||||
if (this.monitTimeout) {
|
|
||||||
this.actionMonit = '';
|
|
||||||
clearTimeout(this.monitTimeout);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.actionMonit = text;
|
|
||||||
|
|
||||||
this.monitTimeout = window.setTimeout(() => {
|
|
||||||
this.actionMonit = '';
|
|
||||||
}, 5000);
|
|
||||||
}, 300);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.actionMonit = text;
|
|
||||||
|
|
||||||
this.monitTimeout = window.setTimeout(() => {
|
|
||||||
this.actionMonit = '';
|
|
||||||
}, 5000);
|
|
||||||
},
|
|
||||||
|
|
||||||
copyMessage() {
|
|
||||||
if (!navigator.clipboard)
|
|
||||||
return this.showActionMonit(
|
|
||||||
'Ups! Twoja przeglądarka musi być dosyć przestarzała, ponieważ nie obsługuje zapisu do schowka! :/'
|
|
||||||
);
|
|
||||||
|
|
||||||
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>`);
|
|
||||||
|
|
||||||
const fieldsToCorrect = this.verifyOrderFields();
|
|
||||||
|
|
||||||
if (fieldsToCorrect.length > 0)
|
|
||||||
return this.showActionMonit(
|
|
||||||
`<span class="text--warn">Uzupełnij następujące rubryki na dole rozkazu przed jego skopiowaniem: ${fieldsToCorrect.join(
|
|
||||||
', '
|
|
||||||
)}</span>`
|
|
||||||
);
|
|
||||||
|
|
||||||
navigator.clipboard.writeText(this.fullOrderMessage);
|
|
||||||
|
|
||||||
this.showActionMonit(
|
|
||||||
'<b class="text--accent">Skopiowano!</b> Możesz teraz wkleić treść rozkazu na czacie symulatora!'
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
saveOrder() {
|
|
||||||
const savedOrderStatus = this.saveLocalOrder();
|
|
||||||
|
|
||||||
switch (savedOrderStatus) {
|
|
||||||
case -1:
|
|
||||||
this.showActionMonit(
|
|
||||||
'<span class="text--warn">Wypełnij numer rozkazu, numer pociągu i datę zanim dodasz rozkaz!</span>'
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
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!');
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
updateOrder() {
|
|
||||||
const updatedOrderStatus = this.updateLocalOrder();
|
|
||||||
|
|
||||||
switch (updatedOrderStatus) {
|
|
||||||
case -1:
|
|
||||||
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>');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
this.showActionMonit('Zaktualizowano treść <b class="text--accent">rozkazu</b>!');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.order-message {
|
|
||||||
padding: 1em;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin: 0;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
margin: 0 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.message_body {
|
|
||||||
height: 250px;
|
|
||||||
overflow: auto;
|
|
||||||
text-align: justify;
|
|
||||||
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 0.5em;
|
|
||||||
color: black;
|
|
||||||
padding: 0.5em;
|
|
||||||
user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message_info {
|
|
||||||
text-align: center;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message_actions {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 1em;
|
|
||||||
|
|
||||||
button img {
|
|
||||||
height: 2ch;
|
|
||||||
vertical-align: text-bottom;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
button[data-disabled='true'] {
|
|
||||||
user-select: none;
|
|
||||||
color: #aaa;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action_monit {
|
|
||||||
text-align: center;
|
|
||||||
padding: 1.5em;
|
|
||||||
font-size: 1.15em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.monit-anim {
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: all 100ms ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter-from,
|
|
||||||
&-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-20px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@@ -1,440 +0,0 @@
|
|||||||
<template>
|
|
||||||
<section class="order-n">
|
|
||||||
<section class="header" ref="header">
|
|
||||||
<h2 class="flex-center">
|
|
||||||
Rozkaz pisemny "N" nr
|
|
||||||
<input type="text" v-model="order.header.orderNo" placeholder="nr rozkazu" />
|
|
||||||
</h2>
|
|
||||||
<div class="flex-row">
|
|
||||||
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">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label for="row-enabled-1">1</label>
|
|
||||||
<div>
|
|
||||||
<input type="checkbox" id="row-enabled-1" v-model="order.rows[0].enabled" />
|
|
||||||
</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
|
|
||||||
<input type="text" v-model="order.rows[0].trackNo2" holder="nr toru" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label for="row-enabled-2">2</label>
|
|
||||||
<div>
|
|
||||||
<input type="checkbox" id="row-enabled-2" v-model="order.rows[1].enabled" />
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td ref="row-2">
|
|
||||||
<strong>ZEZWALAM</strong> po otrzymaniu
|
|
||||||
<select id="select-2a" v-model="order.rows[1].option1">
|
|
||||||
<option :value="`sygnału "Nakaz Jazdy"`">sygnału "Nakaz Jazdy"</option>
|
|
||||||
<option value="tylko tego rozkazu pisemnego">tylko tego rozkazu pisemnego</option>
|
|
||||||
</select>
|
|
||||||
<div style="margin-top: 0.5rem">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-2"
|
|
||||||
id="checkbox-2a"
|
|
||||||
value="checkbox-2a"
|
|
||||||
v-model="order.rows[1].checkbox"
|
|
||||||
:checked="order.rows[1].checkbox == 'checkbox-2a'"
|
|
||||||
@change="handleRowCheckboxChange(2)"
|
|
||||||
/>
|
|
||||||
<label for="checkbox-2a">
|
|
||||||
przejechać obok wskazującego sygnał "Stój" semafora
|
|
||||||
<div style="margin-left: 1rem">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-2a"
|
|
||||||
id="radio-2a-1"
|
|
||||||
value="wyjazdowego"
|
|
||||||
v-model="order.rows[1].signalType"
|
|
||||||
@change="handleRowCheckboxChange(2)"
|
|
||||||
/>
|
|
||||||
<label for="radio-2a-1">
|
|
||||||
wyjazdowego
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].signal1"
|
|
||||||
holder="nazwa sem."
|
|
||||||
:radio-checked="
|
|
||||||
order.rows[1].checkbox == 'checkbox-2a' && order.rows[1].signalType == 'wyjazdowego'
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<br />
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-2a"
|
|
||||||
id="radio-2a-2"
|
|
||||||
value="drogowskazowego"
|
|
||||||
v-model="order.rows[1].signalType"
|
|
||||||
@change="handleRowCheckboxChange(2)"
|
|
||||||
/>
|
|
||||||
<label for="radio-2a-2">
|
|
||||||
drogowskazowego
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].signal2"
|
|
||||||
holder="nazwa sem."
|
|
||||||
:radio-checked="
|
|
||||||
order.rows[1].checkbox == 'checkbox-2a' && order.rows[1].signalType == 'drogowskazowego'
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
(odnoszącego się do wyjazdu pociągu)
|
|
||||||
</label>
|
|
||||||
<br />
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-2a"
|
|
||||||
id="radio-2a-3"
|
|
||||||
value="wjazdowego"
|
|
||||||
v-model="order.rows[1].signalType"
|
|
||||||
@change="handleRowCheckboxChange(2)"
|
|
||||||
/>
|
|
||||||
<label for="radio-2a-3">
|
|
||||||
wjazdowego
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].signal3"
|
|
||||||
holder="nazwa sem."
|
|
||||||
:radio-checked="
|
|
||||||
order.rows[1].checkbox == 'checkbox-2a' && order.rows[1].signalType == 'wjazdowego'
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
na post. odg. bez sem. wyjazdowego
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
i wyjechać w kierunku
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].direction1"
|
|
||||||
holder="stacja / post."
|
|
||||||
:radio-checked="order.rows[1].checkbox == 'checkbox-2a'"
|
|
||||||
/>
|
|
||||||
na tor szlakowy
|
|
||||||
<select v-model="order.rows[1].option2">
|
|
||||||
<option value="lewy">lewy</option>
|
|
||||||
<option value="prawy">prawy</option>
|
|
||||||
</select>
|
|
||||||
nr
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].trackNoTo1"
|
|
||||||
holder="nr toru"
|
|
||||||
:radio-checked="order.rows[1].checkbox == 'checkbox-2a'"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div style="margin-top: 0.5rem">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-2"
|
|
||||||
id="checkbox-2b"
|
|
||||||
value="checkbox-2b"
|
|
||||||
v-model="order.rows[1].checkbox"
|
|
||||||
:checked="order.rows[1].checkbox == 'checkbox-2b'"
|
|
||||||
@change="handleRowCheckboxChange(2)"
|
|
||||||
/>
|
|
||||||
<label for="checkbox-2b">
|
|
||||||
z toru nr
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].trackNoFrom"
|
|
||||||
holder="nr toru"
|
|
||||||
:radio-checked="order.rows[1].checkbox == 'checkbox-2b'"
|
|
||||||
/>
|
|
||||||
nie posiadającego semafora wyjazdowego wyjechać w kierunku
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].direction2"
|
|
||||||
holder="stacja / post."
|
|
||||||
:radio-checked="order.rows[1].checkbox == 'checkbox-2b'"
|
|
||||||
/>
|
|
||||||
na tor szlakowy
|
|
||||||
<select v-model="order.rows[1].option3">
|
|
||||||
<option value="lewy">lewy</option>
|
|
||||||
<option value="prawy">prawy</option>
|
|
||||||
</select>
|
|
||||||
nr
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].trackNoTo2"
|
|
||||||
holder="nr toru"
|
|
||||||
:radio-checked="order.rows[1].checkbox == 'checkbox-2b'"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label for="row-enabled-3">3</label>
|
|
||||||
<div>
|
|
||||||
<input type="checkbox" id="row-enabled-3" v-model="order.rows[2].enabled" />
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td ref="row-3">
|
|
||||||
<select v-model="order.rows[2].option1">
|
|
||||||
<option value="Jazda">Jazda</option>
|
|
||||||
<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
|
|
||||||
<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].untilMin" holder="minuta" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label for="row-enabled-4">4</label>
|
|
||||||
<div>
|
|
||||||
<input type="checkbox" id="row-enabled-4" v-model="order.rows[3].enabled" />
|
|
||||||
</div>
|
|
||||||
</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
|
|
||||||
<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:
|
|
||||||
<div style="margin-top: 0.5rem">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-4"
|
|
||||||
id="checkbox-4a"
|
|
||||||
value="checkbox-4a"
|
|
||||||
v-model="order.rows[3].checkbox"
|
|
||||||
/>
|
|
||||||
<label for="checkbox-4a">
|
|
||||||
sygnału zastępczego "Sz" na osobnym urządzeniu ustawionym z
|
|
||||||
<select v-model="order.rows[3].side">
|
|
||||||
<option value="lewej">lewej</option>
|
|
||||||
<option value="prawej">prawej</option>
|
|
||||||
</select>
|
|
||||||
strony toru
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div style="margin-top: 0.5rem">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-4"
|
|
||||||
id="checkbox-4b"
|
|
||||||
value="checkbox-4b"
|
|
||||||
v-model="order.rows[3].checkbox"
|
|
||||||
/>
|
|
||||||
<label for="checkbox-4b">
|
|
||||||
rozkazu pisemnego "N" (doręczonego lub przekazanego przez urządzenia łączności)
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label for="row-enabled-5">5</label>
|
|
||||||
<div>
|
|
||||||
<input type="checkbox" id="row-enabled-5" v-model="order.rows[4].enabled" />
|
|
||||||
</div>
|
|
||||||
</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
|
|
||||||
<select v-model="order.rows[4].stationType">
|
|
||||||
<option value="stację">stację</option>
|
|
||||||
<option value="posterunek odgałęźny">posterunek odgałęźny</option>
|
|
||||||
</select>
|
|
||||||
<input type="text" v-model="order.rows[4].stationName" holder="stacja / post." />
|
|
||||||
i przejechać obok sygnału "Stój" na
|
|
||||||
<input type="text" v-model="order.rows[4].on" holder="nazwa sygnału" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, reactive } from 'vue';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
import { handleOrderPlaceholders } from '../handlers/orderPlaceholderHandler';
|
|
||||||
|
|
||||||
type TOrderRows = 1 | 2 | 3 | 4 | 5;
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'OrderN',
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = useStore();
|
|
||||||
const order = reactive(store.orderN);
|
|
||||||
|
|
||||||
const rowMethods = [
|
|
||||||
() => {
|
|
||||||
const { header } = order;
|
|
||||||
|
|
||||||
const message = `<i>Rozkaz pisemny "N" nr ${header.orderNo || '_'} dla pociągu nr ${
|
|
||||||
header.trainNo || '_'
|
|
||||||
} dnia ${header.date}</i>`;
|
|
||||||
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
|
|
||||||
() => {
|
|
||||||
const row = order.rows[0];
|
|
||||||
|
|
||||||
const message = `Od ${row.from || '_'} do ${row.to || '_'} tor nr ${
|
|
||||||
row.trackNo || '_'
|
|
||||||
} jest zamknięty, ruch jednotorowy dwukierunkowy wprowadzono po torze nr ${row.trackNo2 || '_'}`;
|
|
||||||
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
|
|
||||||
() => {
|
|
||||||
const row = order.rows[1];
|
|
||||||
|
|
||||||
let message = `ZEZWALAM po otrzymaniu ${row.option1 || '_'}`;
|
|
||||||
|
|
||||||
if (row.checkbox == 'checkbox-2a') {
|
|
||||||
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`;
|
|
||||||
|
|
||||||
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 ${
|
|
||||||
row.direction2 || '_'
|
|
||||||
} na tor szlakowy ${row.option3 || '_'} nr ${row.trackNoTo2 || '_'}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
|
|
||||||
() => {
|
|
||||||
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 || '_'}`;
|
|
||||||
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
|
|
||||||
() => {
|
|
||||||
const row = order.rows[3];
|
|
||||||
|
|
||||||
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`;
|
|
||||||
|
|
||||||
if (row.checkbox == 'checkbox-4b')
|
|
||||||
message += 'rozkazu pisemnego "N" (doręczonego lub przekazanego przez urządzenia łączności)';
|
|
||||||
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
|
|
||||||
() => {
|
|
||||||
const row = order.rows[4];
|
|
||||||
|
|
||||||
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 || '_'} `;
|
|
||||||
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return {
|
|
||||||
store,
|
|
||||||
order,
|
|
||||||
rowMethods,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
order: {
|
|
||||||
deep: true,
|
|
||||||
handler() {
|
|
||||||
this.generateMessage();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'order.rows': {
|
|
||||||
deep: true,
|
|
||||||
handler() {
|
|
||||||
this.updatePlaceholders();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.updatePlaceholders();
|
|
||||||
},
|
|
||||||
|
|
||||||
activated() {
|
|
||||||
this.generateMessage();
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
updatePlaceholders() {
|
|
||||||
this.order.rows.forEach((_, i) => {
|
|
||||||
this.handleRowCheckboxChange((i + 1) as TOrderRows);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
handleRowCheckboxChange(rowIndex: TOrderRows) {
|
|
||||||
const isRowEnabled = this.order.rows[rowIndex - 1].enabled;
|
|
||||||
const rowRef = this.$refs[`row-${rowIndex}`] as HTMLTableElement;
|
|
||||||
|
|
||||||
this.$nextTick(() => {
|
|
||||||
handleOrderPlaceholders(isRowEnabled, rowRef);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
generateMessage() {
|
|
||||||
let message = this.rowMethods[0]();
|
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
if (!this.order.rows[i].enabled) continue;
|
|
||||||
|
|
||||||
message += ` <b> [ ${i + 1} ] </b> ${this.rowMethods[i + 1]()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.store.orderMessage = message;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
@@ -1,215 +0,0 @@
|
|||||||
<template>
|
|
||||||
<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"/>
|
|
||||||
</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
|
|
||||||
<input type="text" v-model="order.header.date" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="horizontal-bar"></div>
|
|
||||||
|
|
||||||
<div style="display: flex; padding: 0 0.5em">
|
|
||||||
<b>1.</b>
|
|
||||||
|
|
||||||
<div style="margin-left: 1.5em">
|
|
||||||
1) zmniejszyć prędkość jazdy i zachować ostrożność <br />2) jechać ostrożnie (j.o.)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="order_table">
|
|
||||||
<table cellborder="1">
|
|
||||||
<tbody>
|
|
||||||
<tr class="tr-header">
|
|
||||||
<td rowspan="2" width="35%">
|
|
||||||
Na posterunku, <br />
|
|
||||||
na szlaku
|
|
||||||
</td>
|
|
||||||
<td width="20%">od</td>
|
|
||||||
<td width="20%">do</td>
|
|
||||||
<td rowspan="2">1) prędkość najwyżej km/h</td>
|
|
||||||
<td rowspan="2">2) j.o.</td>
|
|
||||||
<td rowspan="2" width="35%">z powodu</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="tr-header">
|
|
||||||
<td colspan="2">kilometra</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr v-for="row in order.orderList" class="tr-data">
|
|
||||||
<td>
|
|
||||||
<textarea v-model="row.name"></textarea>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<textarea v-model="row.from"></textarea>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<textarea v-model="row.to"></textarea>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="text" v-model="row.vmax" />
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" v-model="row.jo" />
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<textarea v-model="row.reason"></textarea>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="order_other">
|
|
||||||
<span><b>2.</b> Inne:</span>
|
|
||||||
<br />
|
|
||||||
<textarea v-model="order.other"></textarea>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, reactive } from 'vue';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'OrderO',
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = useStore();
|
|
||||||
const order = reactive(store.orderO);
|
|
||||||
|
|
||||||
const rowMethods = [
|
|
||||||
() => {
|
|
||||||
const { header } = order;
|
|
||||||
|
|
||||||
return `<i>Rozkaz pisemny "O" nr ${header.orderNo || '_'} dla pociągu nr ${header.trainNo || '_'} dnia ${
|
|
||||||
header.date || '_'
|
|
||||||
}</i>`;
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return {
|
|
||||||
store,
|
|
||||||
order,
|
|
||||||
rowMethods,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
activated() {
|
|
||||||
this.generateMessage();
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
order: {
|
|
||||||
deep: true,
|
|
||||||
handler() {
|
|
||||||
this.generateMessage();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
generateMessage() {
|
|
||||||
let message = this.rowMethods[0]();
|
|
||||||
|
|
||||||
if (this.order.orderList.some((row) => row.name)) message += `<b> [ 1 ] </b>`;
|
|
||||||
|
|
||||||
const rowsMessageList = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < this.order.orderList.length; i++) {
|
|
||||||
const row = this.order.orderList[i];
|
|
||||||
if (!row.name) continue;
|
|
||||||
|
|
||||||
let rowMessage = '';
|
|
||||||
rowMessage += ` ${row.name || '_'} od ${row.from || '_'} do ${row.to || '_'} kilometra`;
|
|
||||||
|
|
||||||
if (row.vmax) rowMessage += ` prędkość najwyżej ${row.vmax} km/h`;
|
|
||||||
if (row.jo) rowMessage += ` jechać ostrożnie`;
|
|
||||||
|
|
||||||
rowMessage += ` z powodu: ${row.reason || '_'}`;
|
|
||||||
|
|
||||||
rowsMessageList.push(rowMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
message += rowsMessageList.join("; ");
|
|
||||||
|
|
||||||
if (this.order.other) message += ` <b> [ 2 ] </b> Inne: ${this.order.other}`;
|
|
||||||
|
|
||||||
this.store.orderMessage = message;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
table,
|
|
||||||
td,
|
|
||||||
th {
|
|
||||||
border: 2px solid black;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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 {
|
|
||||||
.tr-header td {
|
|
||||||
padding: 1em 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tr-data td {
|
|
||||||
padding: 0.5em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tbody {
|
|
||||||
font-weight: normal;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
width: 80%;
|
|
||||||
height: 40px;
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.order_other {
|
|
||||||
border-left: 2px solid black;
|
|
||||||
border-right: 2px solid black;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 285px;
|
|
||||||
|
|
||||||
padding: 0.5em;
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
resize: vertical;
|
|
||||||
height: 220px;
|
|
||||||
width: 95%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@@ -1,369 +0,0 @@
|
|||||||
<template>
|
|
||||||
<section class="order-s">
|
|
||||||
<section class="header">
|
|
||||||
<h2 class="flex-center">
|
|
||||||
Rozkaz pisemny "S" nr
|
|
||||||
<input type="text" v-model="order.header.orderNo" placeholder="nr rozkazu" />
|
|
||||||
</h2>
|
|
||||||
<div class="flex-row">
|
|
||||||
dla
|
|
||||||
<select id="select-header" v-model="order.header.for">
|
|
||||||
<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
|
|
||||||
<input type="text" v-model="order.header.date" placeholder="data" />
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="table-section">
|
|
||||||
<table class="options-table">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label for="row-enabled-1">1</label>
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
id="row-enabled-1"
|
|
||||||
v-model="order.rows[0].enabled"
|
|
||||||
@change="handleRowCheckboxChange(1)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td ref="row-1">
|
|
||||||
zezwalam po otrzymaniu
|
|
||||||
<select id="select-1a" v-model="order.rows[0].option1">
|
|
||||||
<option :value="`sygnału "nakaz jazdy"`">sygnału "nakaz jazdy"</option>
|
|
||||||
<option value="tylko tego rozkazu pisemnego">tylko tego rozkazu pisemnego</option>
|
|
||||||
</select>
|
|
||||||
<div style="margin-top: 0.5rem">
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-1a"
|
|
||||||
id="radio-1a-1"
|
|
||||||
value="radio-1a-1"
|
|
||||||
v-model="order.rows[0].radio1"
|
|
||||||
@change="handleRowCheckboxChange(1)"
|
|
||||||
/>
|
|
||||||
<label for="radio-1a-1">
|
|
||||||
przejechać obok wskazującego sygnał "Stój" semafora
|
|
||||||
<select id="select-signal" v-model="order.rows[0].optionSignal">
|
|
||||||
<option value="wyjazdowego">wyjazdowego</option>
|
|
||||||
<option value="drogowskazowego">drogowskazowego</option>
|
|
||||||
</select>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[0].signal1"
|
|
||||||
holder="nazwa sem."
|
|
||||||
:radio-checked="order.rows[0].radio1 == 'radio-1a-1'"
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
</label>
|
|
||||||
<hr />
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-1a"
|
|
||||||
id="radio-1a-2"
|
|
||||||
value="radio-1a-2"
|
|
||||||
v-model="order.rows[0].radio1"
|
|
||||||
@change="handleRowCheckboxChange(1)"
|
|
||||||
/>
|
|
||||||
<label for="radio-1a-2">
|
|
||||||
wyjechać z toru nr
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[0].trackNo"
|
|
||||||
holder="nr toru"
|
|
||||||
:radio-checked="order.rows[0].radio1 == 'radio-1a-2'"
|
|
||||||
/>
|
|
||||||
nie posiadającego semafora wyjazdowego
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label for="row-enabled-2">2</label>
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
id="row-enabled-2"
|
|
||||||
v-model="order.rows[1].enabled"
|
|
||||||
@change="handleRowCheckboxChange(2)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td ref="row-2">
|
|
||||||
zezwalam przejechać obok wskazującego sygnał "Stój" semafora:
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-2a"
|
|
||||||
id="radio-2a-1"
|
|
||||||
value="wyjazdowego"
|
|
||||||
@change="handleRowCheckboxChange(2)"
|
|
||||||
v-model="order.rows[1].signalType"
|
|
||||||
/>
|
|
||||||
<label for="radio-2a-1">
|
|
||||||
wjazdowego
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].signal1"
|
|
||||||
holder="nazwa sem."
|
|
||||||
:radio-checked="order.rows[1].signalType == 'wyjazdowego'"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<br />
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-2a"
|
|
||||||
id="radio-2a-2"
|
|
||||||
value="drogowskazowego"
|
|
||||||
@change="handleRowCheckboxChange(2)"
|
|
||||||
v-model="order.rows[1].signalType"
|
|
||||||
/>
|
|
||||||
<label for="radio-2a-2">
|
|
||||||
drogowskazowego
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].signal2"
|
|
||||||
holder="nazwa sem."
|
|
||||||
:radio-checked="order.rows[1].signalType == 'drogowskazowego'"
|
|
||||||
/>
|
|
||||||
(odnoszącego się do wyjazdu pociągu)
|
|
||||||
</label>
|
|
||||||
<br />
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-2a"
|
|
||||||
id="radio-2a-3"
|
|
||||||
value="odstępowego"
|
|
||||||
@change="handleRowCheckboxChange(2)"
|
|
||||||
v-model="order.rows[1].signalType"
|
|
||||||
/>
|
|
||||||
<label for="radio-2a-3">
|
|
||||||
odstępowego
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].signal3"
|
|
||||||
holder="nazwa sem."
|
|
||||||
:radio-checked="order.rows[1].signalType == 'odstępowego'"
|
|
||||||
/></label>
|
|
||||||
<br />
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="section-2a"
|
|
||||||
id="radio-2a-4"
|
|
||||||
value="toru"
|
|
||||||
v-model="order.rows[1].signalType"
|
|
||||||
@change="handleRowCheckboxChange(2)"
|
|
||||||
/>
|
|
||||||
<label for="radio-2a-4">
|
|
||||||
wjechać z zamkniętego toru nr
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="order.rows[1].trackNo"
|
|
||||||
holder="nr toru"
|
|
||||||
:radio-checked="order.rows[1].signalType == 'toru'"
|
|
||||||
/>
|
|
||||||
nie posiadającego semafora wjazdowego
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<label for="row-enabled-3">3</label>
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
id="row-enabled-3"
|
|
||||||
v-model="order.rows[2].enabled"
|
|
||||||
@change="handleRowCheckboxChange(3)"
|
|
||||||
/>
|
|
||||||
</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 są 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">
|
|
||||||
<td>
|
|
||||||
<label for="row-enabled-4">4</label>
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
id="row-enabled-4"
|
|
||||||
v-model="order.rows[3].enabled"
|
|
||||||
@change="handleRowCheckboxChange(4)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td ref="row-4">
|
|
||||||
Inne:
|
|
||||||
<br />
|
|
||||||
<textarea id="" cols="30" rows="10" v-model="order.rows[3].content"></textarea>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, reactive } from 'vue';
|
|
||||||
import { handleOrderPlaceholders } from '../handlers/orderPlaceholderHandler';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
|
|
||||||
type TOrderRows = 1 | 2 | 3 | 4;
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'OrderS',
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = useStore();
|
|
||||||
const order = reactive(store.orderS);
|
|
||||||
|
|
||||||
const rowMethods = [
|
|
||||||
() => {
|
|
||||||
const { header } = order;
|
|
||||||
|
|
||||||
return `<i>Rozkaz pisemny "S" nr ${header.orderNo || '_'} dla ${header.for || '_'} nr ${
|
|
||||||
header.trainNo || '_'
|
|
||||||
} dnia ${header.date || '_'}</i>`;
|
|
||||||
},
|
|
||||||
|
|
||||||
() => {
|
|
||||||
const row = order.rows[0];
|
|
||||||
|
|
||||||
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`;
|
|
||||||
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
|
|
||||||
() => {
|
|
||||||
const row = order.rows[1];
|
|
||||||
|
|
||||||
let message = `zezwalam przejechać obok wskazującego sygnał "Stój" semafora `;
|
|
||||||
|
|
||||||
switch (row.signalType) {
|
|
||||||
case 'wyjazdowego':
|
|
||||||
message += `wjazdowego ${row.signal1 || '_'}`;
|
|
||||||
break;
|
|
||||||
case 'drogowskazowego':
|
|
||||||
message += `drogowskazowego ${row.signal2 || '_'}`;
|
|
||||||
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`;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
const row = order.rows[2];
|
|
||||||
|
|
||||||
return `Od ${row.from || '_'} do ${row.to || '_'} po torze nr ${
|
|
||||||
row.trackNo || '_'
|
|
||||||
} ruch pociągów prowadzony jest w odstępie posterunków następczych. Wskazania semaforów sbl są nieważne. Zachować ostrożność od ostatniego semafora ze wskaźnikiem "W18". Szlak wolny, ostatni pociąg nr ${
|
|
||||||
row.trainNo || '_'
|
|
||||||
} przybył do ${row.arrivedTo || '_'} o godzinie ${row.hour || '_'}`;
|
|
||||||
},
|
|
||||||
|
|
||||||
() => {
|
|
||||||
const row = order.rows[3];
|
|
||||||
|
|
||||||
return `Inne: ${row.content}`;
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return {
|
|
||||||
store,
|
|
||||||
order,
|
|
||||||
rowMethods,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
activated() {
|
|
||||||
this.generateMessage();
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.updatePlaceholders();
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
order: {
|
|
||||||
deep: true,
|
|
||||||
handler() {
|
|
||||||
this.generateMessage();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
'order.rows': {
|
|
||||||
deep: true,
|
|
||||||
handler() {
|
|
||||||
this.updatePlaceholders();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
updatePlaceholders() {
|
|
||||||
this.order.rows.forEach((_, i) => {
|
|
||||||
this.handleRowCheckboxChange((i + 1) as TOrderRows);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
generateMessage() {
|
|
||||||
let message = this.rowMethods[0]();
|
|
||||||
|
|
||||||
for (let i = 0; i < 4; i++) {
|
|
||||||
if (!this.order.rows[i].enabled) continue;
|
|
||||||
|
|
||||||
message += ` <b> [ ${i + 1} ] </b> ${this.rowMethods[i + 1]()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.store.orderMessage = message;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleRowCheckboxChange(rowIndex: TOrderRows) {
|
|
||||||
const isRowEnabled = this.order.rows[rowIndex - 1].enabled;
|
|
||||||
const rowRef = this.$refs[`row-${rowIndex}`] as HTMLTableElement;
|
|
||||||
|
|
||||||
this.$nextTick(() => {
|
|
||||||
handleOrderPlaceholders(isRowEnabled, rowRef);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
textarea {
|
|
||||||
width: 95%;
|
|
||||||
height: 200px;
|
|
||||||
resize: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@@ -1,251 +0,0 @@
|
|||||||
<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 }}
|
|
||||||
</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>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content">
|
|
||||||
<b v-if="!selectedSceneryName" 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>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<li class="no-trains" v-if="sceneryScheduledTrains.length == 0">Brak aktywnych rozkładów</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<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';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'order-train-picker',
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
sceneriesData: [] as ISceneryData[],
|
|
||||||
sceneriesOnline: [] as ISceneryOnline[],
|
|
||||||
trainsOnline: [] as ApiStacjownik.IActiveTrain[],
|
|
||||||
|
|
||||||
selectedSceneryName: null as string | null,
|
|
||||||
selectedDispatcherName: null as string | null,
|
|
||||||
|
|
||||||
refreshInterval: -1,
|
|
||||||
store: useStore(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
this.fetchSceneriesData();
|
|
||||||
},
|
|
||||||
|
|
||||||
activated() {
|
|
||||||
this.fetchOnlineData();
|
|
||||||
|
|
||||||
this.refreshInterval = window.setInterval(() => {
|
|
||||||
this.fetchOnlineData();
|
|
||||||
}, 35 * 1000);
|
|
||||||
},
|
|
||||||
|
|
||||||
deactivated() {
|
|
||||||
window.clearInterval(this.refreshInterval);
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
selectedDispatcherName() {
|
|
||||||
this.selectedSceneryName = this.sceneryNameList.length == 0 ? null : this.sceneryNameList[0];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
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
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
sceneryNameList() {
|
|
||||||
return this.sceneriesOnlinePL1
|
|
||||||
.filter((s) => s.dispatcherName == this.selectedDispatcherName)
|
|
||||||
.map((s) => s.stationName)
|
|
||||||
.sort((a, b) => (a < b ? -1 : 1));
|
|
||||||
},
|
|
||||||
|
|
||||||
sceneryTrains() {
|
|
||||||
return this.trainsOnline.filter(
|
|
||||||
(t) => t.online && t.currentStationName == this.selectedSceneryName && this.selectedSceneryName && !t.timetable
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
sceneryScheduledTrains() {
|
|
||||||
if (!this.selectedSceneryHash) return [];
|
|
||||||
const hash = this.selectedSceneryHash;
|
|
||||||
|
|
||||||
return this.trainsOnline
|
|
||||||
.filter((t) => t.timetable?.sceneries.includes(hash))
|
|
||||||
.sort((t1, t2) => t1.trainNo - t2.trainNo);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
async fetchSceneriesData() {
|
|
||||||
const data: ISceneryData[] = await (await axios.get(`${import.meta.env['VITE_APP_API_URL']}/getSceneries`)).data;
|
|
||||||
|
|
||||||
if (!data) return;
|
|
||||||
|
|
||||||
this.sceneriesData = data;
|
|
||||||
},
|
|
||||||
|
|
||||||
async fetchOnlineData() {
|
|
||||||
this.fetchSceneriesOnline();
|
|
||||||
this.fetchTrainsOnline();
|
|
||||||
},
|
|
||||||
|
|
||||||
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;
|
|
||||||
},
|
|
||||||
|
|
||||||
fillOrder(trainNo: number) {
|
|
||||||
if (!this.selectedDispatcherName || !this.selectedSceneryName) 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.orderMode = 'OrderMessage';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '../styles/global.scss';
|
|
||||||
|
|
||||||
.order-train-picker {
|
|
||||||
padding: 1em;
|
|
||||||
height: 90vh;
|
|
||||||
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
gap: 1em;
|
|
||||||
|
|
||||||
select {
|
|
||||||
border: 2px solid white;
|
|
||||||
color: white;
|
|
||||||
font-size: 1em;
|
|
||||||
width: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0.15em;
|
|
||||||
}
|
|
||||||
|
|
||||||
option {
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.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: 0.5em;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.no-trains {
|
|
||||||
font-weight: bold;
|
|
||||||
background-color: #222;
|
|
||||||
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
<template>
|
||||||
|
<section class="order-list">
|
||||||
|
<h3>{{ t('order-list.title') }} ({{ storageOrderList.length }})</h3>
|
||||||
|
|
||||||
|
<transition-group name="list" tag="ul">
|
||||||
|
<li class="no-orders-warning" v-if="sortedOrderList.length == 0" :key="-1">
|
||||||
|
{{ t('order-list.no-saved-orders') }}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li
|
||||||
|
v-for="order in sortedOrderList"
|
||||||
|
:selected="order.id == store.chosenLocalOrderId"
|
||||||
|
:key="order.id"
|
||||||
|
>
|
||||||
|
<b class="text--accent">#{{ order.id.split('-')[2] }} </b>
|
||||||
|
<b>
|
||||||
|
{{
|
||||||
|
t('order-list.order-title', {
|
||||||
|
trainNo: order.orderData.header.A
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</b>
|
||||||
|
<span
|
||||||
|
v-if="!order.orderVersion || order.orderVersion != ORDER_VERSION"
|
||||||
|
class="wrong-order-indicator"
|
||||||
|
tabindex="0"
|
||||||
|
:data-tooltip="t('order-list.warning-deprecated-version')"
|
||||||
|
>⚠
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{{
|
||||||
|
t('order-list.order-subtitle', [
|
||||||
|
order.orderData.instructions
|
||||||
|
.filter((v) => v.active)
|
||||||
|
.map((v) => v.name)
|
||||||
|
.join(', ')
|
||||||
|
])
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{{ t(`order-list.order-${order.createdAt ? 'added' : 'updated'}`) }}
|
||||||
|
{{ new Date(order.createdAt || order.updatedAt || 0).toLocaleString('pl-PL') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<button class="g-button" @click="selectLocalOrder(order)">
|
||||||
|
{{ t('order-list.button-order-select') }}
|
||||||
|
</button>
|
||||||
|
<button class="g-button" @click="removeOrder(order.id)">
|
||||||
|
{{ t('order-list.button-order-remove') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</transition-group>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, onActivated, onMounted, Reactive, reactive } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
import { IStorageOrderData, LocalStorageOrderLegacy } from '../../types/orderTypes';
|
||||||
|
import StorageManager from '../../managers/storageManager';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const store = useStore();
|
||||||
|
const storageOrderList = reactive<Reactive<IStorageOrderData[]>>([]);
|
||||||
|
|
||||||
|
const ORDER_VERSION = import.meta.env['VITE_APP_ORDER_VERSION'];
|
||||||
|
|
||||||
|
function removeOrder(orderId: string) {
|
||||||
|
StorageManager.removeValue(orderId);
|
||||||
|
|
||||||
|
if (store.chosenLocalOrderId == orderId) store.chosenLocalOrderId = '';
|
||||||
|
|
||||||
|
const orderIndex = storageOrderList.findIndex((o) => o.id == orderId);
|
||||||
|
if (orderIndex != -1) storageOrderList.splice(orderIndex, 1);
|
||||||
|
|
||||||
|
if (storageOrderList.length == 0) StorageManager.setNumericValue('orderCountV3', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectLocalOrder(order: IStorageOrderData) {
|
||||||
|
Object.entries(order.orderData.header).forEach(([k, v]) => {
|
||||||
|
(store.orderData['header'] as any)[k] = v;
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.entries(order.orderData.footer).forEach(([k, v]) => {
|
||||||
|
(store.orderData['footer'] as any)[k] = v;
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.entries(order.orderData.instructions).forEach(([k, v]) => {
|
||||||
|
(store.orderData['instructions'] as any)[k] = v;
|
||||||
|
});
|
||||||
|
|
||||||
|
store.panelMode = 'OrderMessagePanel';
|
||||||
|
store.chosenLocalOrderId = order.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOrderDeprecated(
|
||||||
|
order: IStorageOrderData | LocalStorageOrderLegacy
|
||||||
|
): order is LocalStorageOrderLegacy {
|
||||||
|
return 'orderType' in order;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedOrderList = computed(() => {
|
||||||
|
return storageOrderList
|
||||||
|
.slice()
|
||||||
|
.sort((a, b) => (b.createdAt || b.updatedAt || 0) - (a.createdAt || a.updatedAt || 0));
|
||||||
|
});
|
||||||
|
|
||||||
|
onActivated(() => {
|
||||||
|
const localStorage = window.localStorage;
|
||||||
|
const orderList: IStorageOrderData[] = [];
|
||||||
|
|
||||||
|
let deprecatedOrders: string[] = [];
|
||||||
|
for (let key in localStorage) {
|
||||||
|
if (!/^order-/g.test(key)) continue;
|
||||||
|
|
||||||
|
const orderObj: IStorageOrderData | LocalStorageOrderLegacy = JSON.parse(localStorage[key]);
|
||||||
|
if (!orderObj) continue;
|
||||||
|
|
||||||
|
if (isOrderDeprecated(orderObj)) {
|
||||||
|
console.warn(`Deprecated order found with ID: ${orderObj.id}`);
|
||||||
|
deprecatedOrders.push(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
orderList.push(orderObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
storageOrderList.length = 0;
|
||||||
|
storageOrderList.push(...orderList);
|
||||||
|
|
||||||
|
if (deprecatedOrders.length > 0) {
|
||||||
|
window.alert(
|
||||||
|
t('order-list.warning-removed-deprecated-orders', { count: deprecatedOrders.length })
|
||||||
|
);
|
||||||
|
|
||||||
|
deprecatedOrders.forEach((orderKey) => StorageManager.removeValue(orderKey));
|
||||||
|
StorageManager.removeValue('orderCount');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@use '../../styles/colors';
|
||||||
|
|
||||||
|
.list {
|
||||||
|
&-move,
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: all 250ms ease;
|
||||||
|
}
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-leave-active {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-list {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
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: colors.$bgColDarker;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&[selected='true'] {
|
||||||
|
outline: 1px solid colors.$accentCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no-orders-warning {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2em;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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>
|
||||||
@@ -0,0 +1,491 @@
|
|||||||
|
<template>
|
||||||
|
<section class="order-message">
|
||||||
|
<h3>{{ $t('order-message.title') }}</h3>
|
||||||
|
|
||||||
|
<div class="message_body" v-html="orderMessagePreview"></div>
|
||||||
|
<p class="message_info">
|
||||||
|
{{ $t('order-message.info') }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="message_actions">
|
||||||
|
<button class="g-button action icon" @click="saveOrder">
|
||||||
|
<LucideSave />
|
||||||
|
{{ $t('order-message.button-save') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="g-button action icon" @click="copyMessage">
|
||||||
|
<LucideCopy />
|
||||||
|
{{ $t('order-message.button-copy') }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="g-button action icon"
|
||||||
|
:data-disabled="!store.chosenLocalOrderId"
|
||||||
|
@click="updateOrder"
|
||||||
|
>
|
||||||
|
<LucidePencil />
|
||||||
|
{{ $t('order-message.button-update') }}
|
||||||
|
<span class="text--accent">
|
||||||
|
{{ store.chosenLocalOrderId && `#${store.chosenLocalOrderId.split('-')[2]}` }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button class="g-button action icon" @click="resetOrder">
|
||||||
|
<LucideRotateCcw />
|
||||||
|
{{ $t('order-message.button-reset') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="message_checkboxes">
|
||||||
|
<label for="copy-increment" class="g-checkbox">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="copy-increment"
|
||||||
|
id="copy-increment"
|
||||||
|
v-model="incrementOnCopy"
|
||||||
|
@change="onCheckboxChange"
|
||||||
|
/>
|
||||||
|
<span>{{ $t('order-options.update-number-on-copy') }}</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="save-increment" class="g-checkbox">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="save-increment"
|
||||||
|
id="save-increment"
|
||||||
|
v-model="incrementOnSave"
|
||||||
|
@change="onCheckboxChange"
|
||||||
|
/>
|
||||||
|
<span>{{ $t('order-options.update-number-on-save') }}</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="update-date" class="g-checkbox">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="update-date"
|
||||||
|
id="update-date"
|
||||||
|
v-model="updateDate"
|
||||||
|
@change="onCheckboxChange"
|
||||||
|
/>
|
||||||
|
<span>{{ $t('order-options.update-hours') }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<transition name="monit-anim">
|
||||||
|
<div
|
||||||
|
class="action_monit"
|
||||||
|
v-if="actionMonit.content"
|
||||||
|
v-html="actionMonit.content"
|
||||||
|
:class="{
|
||||||
|
'text--warn': actionMonit.type == 'warning'
|
||||||
|
}"
|
||||||
|
></div>
|
||||||
|
</transition>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, onMounted, Reactive, reactive, ref, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import { LucideCopy, LucidePencil, LucideRotateCcw, LucideSave } from 'lucide-vue-next';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
import { IOrderHeader, IOrderFooter, IStorageOrderData } from '../../types/orderTypes';
|
||||||
|
import StorageManager from '../../managers/storageManager';
|
||||||
|
import { getOrderFullId } from '../../utils/orderUtils';
|
||||||
|
|
||||||
|
type TActionMonitType = 'warning' | 'info' | 'success';
|
||||||
|
|
||||||
|
interface IActionMonit {
|
||||||
|
type: TActionMonitType;
|
||||||
|
content: string;
|
||||||
|
timeoutId: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
const actionMonit: Reactive<IActionMonit> = reactive({
|
||||||
|
visible: false,
|
||||||
|
type: 'info',
|
||||||
|
content: '',
|
||||||
|
timeoutId: null
|
||||||
|
});
|
||||||
|
|
||||||
|
const incrementOnSave = ref(true);
|
||||||
|
const incrementOnCopy = ref(true);
|
||||||
|
const updateDate = ref(true);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
incrementOnSave.value = StorageManager.getBooleanValue('save-increment');
|
||||||
|
incrementOnCopy.value = StorageManager.getBooleanValue('copy-increment');
|
||||||
|
updateDate.value = StorageManager.getBooleanValue('update-date');
|
||||||
|
});
|
||||||
|
|
||||||
|
const orderMessagePreview = computed(() => store.orderMessage);
|
||||||
|
|
||||||
|
watch(orderMessagePreview, () => {
|
||||||
|
if (updateDate.value == true) {
|
||||||
|
store.orderData.header.B = new Date().toISOString().split('T')[0];
|
||||||
|
|
||||||
|
store.orderData.footer.Y = new Date().toLocaleTimeString('pl-PL', {
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: '2-digit'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function onCheckboxChange(e: Event) {
|
||||||
|
const checkbox = e.target as HTMLInputElement;
|
||||||
|
StorageManager.setBooleanValue(checkbox.id, checkbox.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showActionMonit(content: string, type: TActionMonitType) {
|
||||||
|
if (actionMonit.timeoutId != null) {
|
||||||
|
actionMonit.content = '';
|
||||||
|
|
||||||
|
clearTimeout(actionMonit.timeoutId);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
actionMonit.content = content;
|
||||||
|
actionMonit.type = type;
|
||||||
|
|
||||||
|
actionMonit.timeoutId = window.setTimeout(() => {
|
||||||
|
actionMonit.content = '';
|
||||||
|
actionMonit.timeoutId = null;
|
||||||
|
}, 5000);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
actionMonit.content = content;
|
||||||
|
actionMonit.type = type;
|
||||||
|
|
||||||
|
actionMonit.timeoutId = window.setTimeout(() => {
|
||||||
|
actionMonit.content = '';
|
||||||
|
actionMonit.timeoutId = null;
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkConflicts() {
|
||||||
|
if (
|
||||||
|
store.orderData.instructions
|
||||||
|
.filter((i) => i.key == '2110' || i.key == '2115')
|
||||||
|
.every((i) => i.active)
|
||||||
|
) {
|
||||||
|
showActionMonit(
|
||||||
|
t('order-message.warning-conflicting-instructions', ['21.10', '21.15']),
|
||||||
|
'warning'
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function areOrderFieldsCorrect() {
|
||||||
|
const fieldsToCorrect: string[] = [];
|
||||||
|
|
||||||
|
for (let headerKey in store.orderData.header) {
|
||||||
|
if (store.orderData.header[headerKey as keyof IOrderHeader].trim() == '') {
|
||||||
|
fieldsToCorrect.push(headerKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let footerKey in store.orderData.footer) {
|
||||||
|
if (store.orderData.footer[footerKey as keyof IOrderFooter].trim() == '') {
|
||||||
|
fieldsToCorrect.push(footerKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const areConflicting = checkConflicts();
|
||||||
|
|
||||||
|
if (areConflicting) return false;
|
||||||
|
|
||||||
|
// Header & footer fields check
|
||||||
|
if (fieldsToCorrect.length > 0) {
|
||||||
|
showActionMonit(t('order-message.warning-fill-missing'), 'warning');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Active instructions' fields check
|
||||||
|
let hasAllInputsFilled = true,
|
||||||
|
hasNoActiveInstructions = true;
|
||||||
|
|
||||||
|
for (const instructionKey in store.orderData.instructions) {
|
||||||
|
const instruction = store.orderData.instructions[instructionKey];
|
||||||
|
|
||||||
|
if (!instruction.active) continue;
|
||||||
|
|
||||||
|
hasNoActiveInstructions = false;
|
||||||
|
|
||||||
|
for (const fieldKey in instruction.inputFields) {
|
||||||
|
const fieldValue = instruction.inputFields[fieldKey];
|
||||||
|
|
||||||
|
if (fieldValue.trim() == '' && !instruction.optionalFieldNames.includes(fieldKey)) {
|
||||||
|
hasAllInputsFilled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction.listFields) {
|
||||||
|
let hasAtLeastOneActive = false;
|
||||||
|
|
||||||
|
for (const listFieldKey in instruction.listFields) {
|
||||||
|
const listField = instruction.listFields[listFieldKey];
|
||||||
|
|
||||||
|
if (listField.active == false) continue;
|
||||||
|
|
||||||
|
hasAtLeastOneActive = true;
|
||||||
|
|
||||||
|
for (const fieldKey in listField.values) {
|
||||||
|
const fieldValue = listField.values[fieldKey];
|
||||||
|
|
||||||
|
if (fieldValue.trim() == '') {
|
||||||
|
hasAllInputsFilled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasAtLeastOneActive) {
|
||||||
|
hasAllInputsFilled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Active instructions check
|
||||||
|
if (hasNoActiveInstructions) {
|
||||||
|
showActionMonit(t('order-message.warning-add-instruction'), 'warning');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasAllInputsFilled) {
|
||||||
|
showActionMonit(t('order-message.warning-fill-inputs'), 'warning');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasHeaderFieldsComplete() {
|
||||||
|
return Object.values(store.orderData.header).every((v) => {
|
||||||
|
return v.trim().length != 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function incrementOrderNo() {
|
||||||
|
const idData = store.orderData.footer.Z.split('-');
|
||||||
|
|
||||||
|
if (idData.length == 4) {
|
||||||
|
const sceneryHash = idData[2];
|
||||||
|
let orderNumber = Number(idData[1]) || 0;
|
||||||
|
|
||||||
|
store.orderData.footer.Z = getOrderFullId(++orderNumber, sceneryHash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyMessage() {
|
||||||
|
if (!navigator.clipboard)
|
||||||
|
return showActionMonit(t('order-message.warning-outdated-clipboard'), 'warning');
|
||||||
|
|
||||||
|
const areFieldsCorrect = areOrderFieldsCorrect();
|
||||||
|
|
||||||
|
if (!areFieldsCorrect) return;
|
||||||
|
|
||||||
|
const simulatorChatMessage = '\n' + orderMessagePreview.value.replace(/<br \/>/g, '\n');
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(simulatorChatMessage);
|
||||||
|
|
||||||
|
if (incrementOnCopy.value) incrementOrderNo();
|
||||||
|
|
||||||
|
showActionMonit(t('order-message.success-copy-html'), 'success');
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveOrder() {
|
||||||
|
if (!hasHeaderFieldsComplete()) {
|
||||||
|
showActionMonit(`${t('order-message.warning-fill-top-save')}`, 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderDataToSave: IStorageOrderData = {
|
||||||
|
id: '',
|
||||||
|
createdAt: Date.now(),
|
||||||
|
orderVersion: import.meta.env['VITE_APP_ORDER_VERSION'] || '3',
|
||||||
|
orderData: store.orderData
|
||||||
|
};
|
||||||
|
|
||||||
|
const localOrderCount = StorageManager.getNumericValue('orderCountV3') || 0;
|
||||||
|
|
||||||
|
if (localOrderCount == 0) StorageManager.setNumericValue('orderCountV3', 0);
|
||||||
|
|
||||||
|
const prevLocalOrder = StorageManager.getValue(`order-v3-${localOrderCount}`);
|
||||||
|
|
||||||
|
if (prevLocalOrder) {
|
||||||
|
try {
|
||||||
|
const prevOrderObj = JSON.parse(prevLocalOrder) as IStorageOrderData;
|
||||||
|
|
||||||
|
if (JSON.stringify(prevOrderObj.orderData) == JSON.stringify(orderDataToSave.orderData)) {
|
||||||
|
showActionMonit(t('order-message.warning-order-identical'), 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
`Ups! An error occured when trying to parse previous local order (count: ${localOrderCount})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextOrderCount = localOrderCount + 1;
|
||||||
|
const nextOrderId = `order-v3-${nextOrderCount}`;
|
||||||
|
orderDataToSave['id'] = nextOrderId;
|
||||||
|
|
||||||
|
StorageManager.setNumericValue('orderCountV3', nextOrderCount);
|
||||||
|
StorageManager.setValue(nextOrderId, JSON.stringify(orderDataToSave));
|
||||||
|
|
||||||
|
store.chosenLocalOrderId = nextOrderId;
|
||||||
|
showActionMonit(t('order-message.success-save-html'), 'success');
|
||||||
|
|
||||||
|
if (incrementOnSave.value) incrementOrderNo();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateOrder() {
|
||||||
|
if (!store.chosenLocalOrderId) {
|
||||||
|
showActionMonit(t('order-message.warning-no-order-selected'), 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasHeaderFieldsComplete()) {
|
||||||
|
showActionMonit(t('order-message.warning-fill-top-update'), 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localOrder = window.localStorage.getItem(store.chosenLocalOrderId);
|
||||||
|
|
||||||
|
if (!localOrder) {
|
||||||
|
showActionMonit(t('order-message.error-update'), 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderDataToUpdate: IStorageOrderData = {
|
||||||
|
id: store.chosenLocalOrderId,
|
||||||
|
orderData: store.orderData,
|
||||||
|
updatedAt: Date.now(),
|
||||||
|
orderVersion: import.meta.env['VITE_APP_ORDER_VERSION'] || '3'
|
||||||
|
};
|
||||||
|
|
||||||
|
window.localStorage.setItem(store.chosenLocalOrderId, JSON.stringify(orderDataToUpdate));
|
||||||
|
showActionMonit(t('order-message.success-update-html'), 'success');
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetOrder() {
|
||||||
|
Object.keys(store.orderData.header).forEach((k) => {
|
||||||
|
store.orderData['header'][k as keyof IOrderHeader] = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(store.orderData.footer).forEach((k) => {
|
||||||
|
store.orderData['footer'][k as keyof IOrderFooter] = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
store.orderData.instructions.forEach((instruction) => {
|
||||||
|
instruction.active = false;
|
||||||
|
|
||||||
|
Object.keys(instruction.inputFields).forEach((k) => {
|
||||||
|
instruction.inputFields[k] = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (instruction.listFields) {
|
||||||
|
instruction.listFields.forEach((field) => {
|
||||||
|
Object.keys(field.values).forEach((k) => {
|
||||||
|
field.active = false;
|
||||||
|
field.values[k] = '';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@use '../../styles/colors';
|
||||||
|
|
||||||
|
.order-message {
|
||||||
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 0 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message_body {
|
||||||
|
height: 350px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
background-color: colors.$bgColLighter;
|
||||||
|
color: white;
|
||||||
|
text-align: justify;
|
||||||
|
|
||||||
|
border-radius: 0.5em;
|
||||||
|
padding: 0.5em;
|
||||||
|
user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message_info {
|
||||||
|
text-align: center;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message_actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
button.icon {
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button img {
|
||||||
|
height: 2ch;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[data-disabled='true'] {
|
||||||
|
user-select: none;
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message_checkboxes {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action_monit {
|
||||||
|
text-align: center;
|
||||||
|
padding: 1.5em;
|
||||||
|
font-size: 1.15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monit-anim {
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: all 100ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-20px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,337 @@
|
|||||||
|
<template>
|
||||||
|
<div class="order-train-picker">
|
||||||
|
<div class="options">
|
||||||
|
<div class="options-top">
|
||||||
|
<select
|
||||||
|
name="dispatcher-select"
|
||||||
|
id="dispatcher-select"
|
||||||
|
v-model="selectedSceneryId"
|
||||||
|
@change="selectCheckpointOption"
|
||||||
|
>
|
||||||
|
<option :value="null" disabled>
|
||||||
|
{{ $t('order-train-picker.placeholder-scenery-name') }}
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
v-for="scenery in filteredSceneries"
|
||||||
|
:value="`${scenery.stationName}|${scenery.stationHash}|${scenery.dispatcherName}|${scenery.region}`"
|
||||||
|
:key="scenery.dispatcherName + scenery.stationName"
|
||||||
|
>
|
||||||
|
{{ scenery.stationName }} • {{ scenery.dispatcherName }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select
|
||||||
|
name="region-select"
|
||||||
|
id="region-select"
|
||||||
|
v-model="selectedRegion"
|
||||||
|
@change="selectCheckpointOption"
|
||||||
|
>
|
||||||
|
<option :value="null" disabled>
|
||||||
|
{{ $t('order-train-picker.placeholder-region-name') }}
|
||||||
|
</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>
|
||||||
|
{{ $t('order-train-picker.placeholder-checkpoint-name') }}
|
||||||
|
</option>
|
||||||
|
<option :value="cp" v-for="cp in checkpointNameList" :key="cp">
|
||||||
|
{{ cp }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<b v-if="!selectedSceneryId" class="text--accent">
|
||||||
|
{{ $t('order-train-picker.info') }}
|
||||||
|
</b>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<div style="margin-bottom: 0.5em">
|
||||||
|
<h3 style="margin-bottom: 0.5em">{{ $t('order-train-picker.title') }}</h3>
|
||||||
|
<b class="text--accent">{{ $t('order-train-picker.subtitle') }}</b>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="train-list">
|
||||||
|
<li
|
||||||
|
v-for="train in sceneryTrains"
|
||||||
|
:key="train.trainNo + train.driverName"
|
||||||
|
@click="fillOrderData(train)"
|
||||||
|
>
|
||||||
|
<button class="g-button">
|
||||||
|
<span
|
||||||
|
v-if="train.currentStationName == selectedScenery?.stationName"
|
||||||
|
class="online-indicator"
|
||||||
|
></span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{{ train.driverName }} •
|
||||||
|
<span v-if="train.timetable" style="color: gold">{{
|
||||||
|
train.timetable.category
|
||||||
|
}}</span>
|
||||||
|
{{ train.trainNo }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="no-trains" v-if="sceneryTrains?.length == 0 && selectedSceneryId">
|
||||||
|
{{ $t('order-train-picker.no-trains') }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted, onActivated, onDeactivated, computed } from 'vue';
|
||||||
|
import http from '../../http';
|
||||||
|
import { useStore } from '../../store/store';
|
||||||
|
import { API } from '../../types/apiTypes';
|
||||||
|
import { ISceneryData } from '../../types/dataTypes';
|
||||||
|
import StorageManager from '../../managers/storageManager';
|
||||||
|
import { getRegionNameById } from '../../utils/sceneryUtils';
|
||||||
|
import { getOrderFullId } from '../../utils/orderUtils';
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
const regions = ['eu', 'cae', 'usw', 'us', 'ru'];
|
||||||
|
const refreshInterval = ref(-1);
|
||||||
|
|
||||||
|
let sceneriesData = ref<ISceneryData[] | null>(null);
|
||||||
|
let activeData = ref<API.ActiveData.Response | null>(null);
|
||||||
|
|
||||||
|
const selectedSceneryId = ref<string | null>(null);
|
||||||
|
const selectedCheckpointName = ref<string | null>(null);
|
||||||
|
const selectedRegion = ref('eu');
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchSceneriesData();
|
||||||
|
});
|
||||||
|
|
||||||
|
onActivated(async () => {
|
||||||
|
await fetchActiveData();
|
||||||
|
handleQueries();
|
||||||
|
|
||||||
|
window.clearInterval(refreshInterval.value);
|
||||||
|
|
||||||
|
refreshInterval.value = window.setInterval(() => {
|
||||||
|
fetchActiveData();
|
||||||
|
}, 25000);
|
||||||
|
});
|
||||||
|
|
||||||
|
onDeactivated(() => {
|
||||||
|
window.clearInterval(refreshInterval.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedScenery = computed(() => {
|
||||||
|
if (activeData.value == null) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
activeData.value.activeSceneries?.find(
|
||||||
|
(scenery) =>
|
||||||
|
selectedSceneryId.value ==
|
||||||
|
`${scenery.stationName}|${scenery.stationHash}|${scenery.dispatcherName}|${scenery.region}` &&
|
||||||
|
selectedRegion.value == scenery.region
|
||||||
|
) ?? null
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const filteredSceneries = computed(() => {
|
||||||
|
return activeData.value?.activeSceneries
|
||||||
|
?.filter((s) => s.isOnline && s.region == selectedRegion.value)
|
||||||
|
.sort((s1, s2) => s1.stationName.localeCompare(s2.stationName));
|
||||||
|
});
|
||||||
|
|
||||||
|
const checkpointNameList = computed(() => {
|
||||||
|
if (!selectedScenery.value) return [];
|
||||||
|
|
||||||
|
const checkpoints =
|
||||||
|
sceneriesData.value?.find((s) => s.name == selectedScenery.value?.stationName)?.checkpoints ??
|
||||||
|
'';
|
||||||
|
|
||||||
|
if (checkpoints.length == 0) return [selectedScenery.value.stationName];
|
||||||
|
|
||||||
|
return checkpoints.split(';');
|
||||||
|
});
|
||||||
|
|
||||||
|
const sceneryTrains = computed(() => {
|
||||||
|
if (!selectedScenery.value || !activeData.value?.trains) return [];
|
||||||
|
|
||||||
|
const scenery = selectedScenery.value;
|
||||||
|
|
||||||
|
return activeData.value.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)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
async function fetchSceneriesData() {
|
||||||
|
const data = (await http.get<ISceneryData[]>('api/getSceneries')).data;
|
||||||
|
|
||||||
|
sceneriesData.value = data ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchActiveData() {
|
||||||
|
const data = (await http.get<API.ActiveData.Response>('api/getActiveData')).data;
|
||||||
|
|
||||||
|
activeData.value = data ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectCheckpointOption() {
|
||||||
|
selectedCheckpointName.value =
|
||||||
|
checkpointNameList.value.length == 0 ? null : checkpointNameList.value[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillOrderData(train: API.ActiveTrains.Data) {
|
||||||
|
if (!selectedScenery.value) return;
|
||||||
|
|
||||||
|
const scenery = selectedScenery.value;
|
||||||
|
|
||||||
|
store.orderData.header.A = train.trainNo.toString();
|
||||||
|
store.orderData.header.C = train.currentStationName;
|
||||||
|
store.orderData.header.D = selectedCheckpointName.value || scenery.stationName;
|
||||||
|
|
||||||
|
store.orderData.footer.V = train.driverName;
|
||||||
|
store.orderData.footer.W = scenery.dispatcherName;
|
||||||
|
|
||||||
|
const idData = store.orderData.footer.Z.split('-');
|
||||||
|
|
||||||
|
if (idData.length != 4) {
|
||||||
|
store.orderData.footer.Z = getOrderFullId(0, scenery.stationHash);
|
||||||
|
} else {
|
||||||
|
store.orderData.footer.Z = getOrderFullId(Number(idData[1]) || 0, scenery.stationHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
store.panelMode = 'OrderMessagePanel';
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleQueries() {
|
||||||
|
const query = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
const id = query.get('sceneryId');
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
const [sceneryName, sceneryRegion] = id.split('|');
|
||||||
|
|
||||||
|
selectedRegion.value = sceneryRegion;
|
||||||
|
|
||||||
|
const queryScenery = activeData.value?.activeSceneries?.find(
|
||||||
|
(sc) => sc.stationName == sceneryName && sc.region == sceneryRegion && sc.isOnline
|
||||||
|
);
|
||||||
|
|
||||||
|
if (queryScenery) {
|
||||||
|
selectedSceneryId.value = `${queryScenery.stationName}|${queryScenery.stationHash}|${queryScenery.dispatcherName}|${queryScenery.region}`;
|
||||||
|
|
||||||
|
selectCheckpointOption();
|
||||||
|
|
||||||
|
store.panelMode = 'OrderTrainPickerPanel';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@use '../../styles/colors';
|
||||||
|
|
||||||
|
.order-train-picker {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
width: 100%;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
select {
|
||||||
|
background-color: colors.$bgColDarker;
|
||||||
|
|
||||||
|
font-size: 1em;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&[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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.train-list {
|
||||||
|
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;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: colors.$bgColLighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 1px solid colors.$accentCol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.online-indicator {
|
||||||
|
display: inline-block;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: greenyellow;
|
||||||
|
border-radius: 100%;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
<template>
|
|
||||||
<section class="sidebar">
|
|
||||||
<div class="sidebar_content">
|
|
||||||
<!-- <button class="option-save" @click="toggleOrderMode" :data-selected="store.orderMode == 'OrderList'">
|
|
||||||
<img :src="saveIcon" alt="save icon" />
|
|
||||||
</button> -->
|
|
||||||
|
|
||||||
<!-- <button @click="store.helperModalOpen = true">?</button> -->
|
|
||||||
|
|
||||||
<button
|
|
||||||
v-for="orderType in orderTypeList"
|
|
||||||
:key="orderType.id"
|
|
||||||
@click="selectOrderType(orderType.id)"
|
|
||||||
:data-selected="store.chosenOrderType == orderType.id"
|
|
||||||
>
|
|
||||||
{{ orderType.name }}
|
|
||||||
|
|
||||||
<div class="bar"></div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
orderTypeList: [
|
|
||||||
{
|
|
||||||
id: 'orderN',
|
|
||||||
name: 'N',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'orderS',
|
|
||||||
name: 'S',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'orderO',
|
|
||||||
name: 'O',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
store: useStore(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
selectOrderType(type: any) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar_content {
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: repeat(3, 1fr);
|
|
||||||
gap: 0.25em;
|
|
||||||
|
|
||||||
font-size: 1.5em;
|
|
||||||
font-weight: bold;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
& > button {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
color: white;
|
|
||||||
background-color: #1d1d1d;
|
|
||||||
width: 50px;
|
|
||||||
height: 85px;
|
|
||||||
|
|
||||||
.bar {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
height: 100%;
|
|
||||||
width: 4px;
|
|
||||||
|
|
||||||
transform: translateX(100%);
|
|
||||||
transition: all 200ms ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-selected='true'] .bar {
|
|
||||||
transform: translateX(0);
|
|
||||||
|
|
||||||
background-color: $accentCol;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus-visible {
|
|
||||||
background-color: #6d6d6d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button.option-save {
|
|
||||||
background-color: #000000aa;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 80%;
|
|
||||||
height: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-selected='true'] {
|
|
||||||
background-color: $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;
|
|
||||||
|
|
||||||
& > button {
|
|
||||||
height: 40px;
|
|
||||||
width: 100px;
|
|
||||||
|
|
||||||
.bar {
|
|
||||||
width: 100%;
|
|
||||||
height: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"orderS": [
|
|
||||||
"D"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const http = axios.create({
|
||||||
|
baseURL: 'https://stacjownik.spythere.eu'
|
||||||
|
});
|
||||||
|
|
||||||
|
export default http;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import enLang from './locales/en.json';
|
||||||
|
import plLang from './locales/pl.json';
|
||||||
|
|
||||||
|
import { createI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
const i18n = createI18n({
|
||||||
|
locale: 'pl',
|
||||||
|
legacy: false,
|
||||||
|
warnHtmlMessage: false,
|
||||||
|
fallbackLocale: 'pl',
|
||||||
|
|
||||||
|
messages: {
|
||||||
|
en: enLang,
|
||||||
|
pl: plLang
|
||||||
|
},
|
||||||
|
enableLegacy: false
|
||||||
|
});
|
||||||
|
|
||||||
|
export default i18n;
|
||||||
@@ -0,0 +1,281 @@
|
|||||||
|
{
|
||||||
|
"locale": {
|
||||||
|
"pl": "POL",
|
||||||
|
"en": "ENG"
|
||||||
|
},
|
||||||
|
"navbar": {
|
||||||
|
"OrderMessagePanel": "MESSAGE",
|
||||||
|
"OrderListPanel": "SAVED",
|
||||||
|
"OrderTrainPickerPanel": "TRAINS"
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"update-available-text": "New GeneraTOR version is available!",
|
||||||
|
"update-available-underline": "Click here to update!",
|
||||||
|
"title": "GeneraTOR update!",
|
||||||
|
"confirm": "ROGER THAT!",
|
||||||
|
"no-data": "No changelog available!",
|
||||||
|
"info-1": "This changelog will be available to see once again after clicking the version number in the footer",
|
||||||
|
"info-2": "The full app changelog available on <a href='https://github.com/Spythere/genera-tor' target='_blank'>the project's GitHub</a>"
|
||||||
|
},
|
||||||
|
"order-message": {
|
||||||
|
"title": "Message to display in the simulator's chatbox:",
|
||||||
|
"info": "Copy or save the content of the generated train order using buttons below:",
|
||||||
|
"button-save": "Save as new order",
|
||||||
|
"button-copy": "Copy order message",
|
||||||
|
"button-update": "Update order",
|
||||||
|
"button-reset": "Reset order",
|
||||||
|
"warning-outdated-clipboard": "Oops! Your browser may be a little bit depraceted since it's not supporting saving data to the clipboard! :/",
|
||||||
|
"warning-fill-inputs": "Fill all the empty fields before copying the order!",
|
||||||
|
"warning-add-instruction": "Add at least one order instruction before copying the order!",
|
||||||
|
"warning-fill-missing": "Fill rows in the order's header and footer before copying it!",
|
||||||
|
"warning-fill-top-save": "Fill at least fields A, B, C and D in the order's header before saving it!",
|
||||||
|
"warning-fill-top-update": "Fill at least fields A, B, C and D in the order's header before updating it!",
|
||||||
|
"warning-order-identical": "Last saved order is identical as the current one!",
|
||||||
|
"warning-no-order-selected": "Choose the already saved order first!",
|
||||||
|
"warning-conflicting-instructions": "Instruction {0} and {1} can't be on the same order!",
|
||||||
|
"error-update": "An error occurred while saving this order! :/",
|
||||||
|
"success-update-html": "Updated this <b class=\"text--accent\">order's</b> message!",
|
||||||
|
"success-save-html": "Saved <b class=\"text--accent\">order's</b> message in the browser memory!",
|
||||||
|
"success-copy-html": "<b class=\"text--accent\">Success!</b> You may paste the order message in the simulator's chatbox now!"
|
||||||
|
},
|
||||||
|
"order-footer": {
|
||||||
|
"field-stationName": "station",
|
||||||
|
"field-checkpointName": "checkpoint",
|
||||||
|
"field-hour": "hour",
|
||||||
|
"field-minutes": "minute",
|
||||||
|
"field-dispatcherName": "dispatcher",
|
||||||
|
"field-secondaryDispatcherName": "ordering dispatcher",
|
||||||
|
"field-dispatcherOrSecondaryName": "dispatcher (or ordering dispatcher)"
|
||||||
|
},
|
||||||
|
"order-options": {
|
||||||
|
"dark-mode": "Order dark theme",
|
||||||
|
"update-number-on-copy": "Update order number on copy",
|
||||||
|
"update-number-on-save": "Update order number on save",
|
||||||
|
"update-hours": "Update order hour on edit"
|
||||||
|
},
|
||||||
|
"order-list": {
|
||||||
|
"title": "Saved train orders",
|
||||||
|
"order-title": "Train order for no. {trainNo}",
|
||||||
|
"order-subtitle": "Selected instructions: {0}",
|
||||||
|
"no-saved-orders": "No saved orders!",
|
||||||
|
"order-added": "Added:",
|
||||||
|
"order-updated": "Updated:",
|
||||||
|
"button-order-select": "Select",
|
||||||
|
"button-order-remove": "Remove",
|
||||||
|
"warning-deprecated-version": "Deprecated version of the order - may generate incorrect information!",
|
||||||
|
"warning-removed-deprecated-orders": "Removed deprecated train orders ({count}) due to their replacement with a new format in Polish railway!"
|
||||||
|
},
|
||||||
|
"order-train-picker": {
|
||||||
|
"placeholder-scenery-name": "Scenery name",
|
||||||
|
"placeholder-region-name": "Region",
|
||||||
|
"placeholder-checkpoint-name": "Checkpoint name",
|
||||||
|
"autofill-checkpoint-id": "Autofill checkpoint's abbreviation",
|
||||||
|
"info": "Select scenery name to display active trains",
|
||||||
|
"title": "Active timetables and trains on the scenery",
|
||||||
|
"subtitle": "Click on the user below to fill the current order with their information",
|
||||||
|
"no-trains": "No trains to display"
|
||||||
|
},
|
||||||
|
"order": {
|
||||||
|
"title": "Polish Railway Train Order",
|
||||||
|
"header": {
|
||||||
|
"A": "A Train No {'|'} Shunting composition No",
|
||||||
|
"A-placeholder": "Train / shunting composition number",
|
||||||
|
"B": "B Date",
|
||||||
|
"C": "C Location of train {'|'} Location of shunting composition",
|
||||||
|
"C-placeholder": "Name of the post / line / scenery",
|
||||||
|
"D": "D Location of issuer",
|
||||||
|
"D-placeholder": "Name of the post / scenery"
|
||||||
|
},
|
||||||
|
"22": {
|
||||||
|
"text": "Applies to left-track traffic",
|
||||||
|
"message-html": "<b>Applies to left-track traffic</b>"
|
||||||
|
},
|
||||||
|
"99": {
|
||||||
|
"text": "Revoke the train order",
|
||||||
|
"x1": "x.1 Train order identifier",
|
||||||
|
"message-html": "<b>Revoke the train order</b> {0}"
|
||||||
|
},
|
||||||
|
"2110": {
|
||||||
|
"text": "{bold1} from track no. {track1} from {signalbox1} {br} to track no. {track2} in the direction of {signalbox2} {br} Pass Stop signals {signal1} and {signal2} and {signal3}",
|
||||||
|
"bold1": "Is allowed to exit",
|
||||||
|
"track1": "x.1 track",
|
||||||
|
"signalbox1": "x.2 signalbox",
|
||||||
|
"track2": "x.3 track",
|
||||||
|
"signalbox2": "x.4 signalbox",
|
||||||
|
"signal1": "x.5 signal",
|
||||||
|
"signal2": "x.6 signal",
|
||||||
|
"signal3": "x.7 signal",
|
||||||
|
"message-html": "<b>Is allowed to exit</b> from track no. {0} from {1} to track no. {2} in the direction of {3}. Pass Stop signals {4} and {5} and {6}"
|
||||||
|
},
|
||||||
|
"2115": {
|
||||||
|
"text": "{bold1} from track no. {track1} to {signalbox1} on track no. {track2} {br} Pass signals {signal1} and {signal2} and {signal3}",
|
||||||
|
"bold1": "Is allowed to enter",
|
||||||
|
"track1": "x.1 track",
|
||||||
|
"signalbox1": "x.2 signalbox",
|
||||||
|
"track2": "x.3 track",
|
||||||
|
"signal1": "x.4 signal",
|
||||||
|
"signal2": "x.5 signal",
|
||||||
|
"signal3": "x.6 signal",
|
||||||
|
"message-html": "<b>Is allowed to enter</b> from track no. {0} to {1} on track no. {2}. Pass signals {3} and {4} and {5}"
|
||||||
|
},
|
||||||
|
"2120": {
|
||||||
|
"text": "From {signalbox1} to {signalbox2} on track {track1} {br} {highlight1} {br} {underline1}{highlight2}.",
|
||||||
|
"highlight1": "SBL signalling indications are to be ignored.",
|
||||||
|
"underline1": "Stay alert after passing the signal with indicator",
|
||||||
|
"highlight2": " W18",
|
||||||
|
"signalbox1": "x.1 signalbox",
|
||||||
|
"signalbox2": "x.2 signalbox",
|
||||||
|
"track1": "x.3 track no",
|
||||||
|
"message-html": "From {0} to {1} on track {2} <b>SBL signals are to be ignored.</b> Stay alert after passing the signal with indicator <b>W18.</b>"
|
||||||
|
},
|
||||||
|
"2125": {
|
||||||
|
"text": "Is allowed to pass {select1} in the direction of {signalbox1} on track {track1} to km {km1} to hour {hour1}.",
|
||||||
|
"select1-a": "indicator W5",
|
||||||
|
"select1-b": "last switch",
|
||||||
|
"signalbox1": "x.1 signalbox",
|
||||||
|
"track1": "x.2 track",
|
||||||
|
"km1": "x.3 km",
|
||||||
|
"hour1": "x.4 hour",
|
||||||
|
"message-html": "Is allowed to pass {0} in the direction of {1} on track {2} to km {3} to hour {4}."
|
||||||
|
},
|
||||||
|
"2135": {
|
||||||
|
"text": "{bold1} on track no. {track1} in the direction of {signalbox1}.",
|
||||||
|
"bold1": "Is allowed to proceed",
|
||||||
|
"track1": "x.1 track",
|
||||||
|
"signalbox1": "x.2 signalbox",
|
||||||
|
"message-html": "<b>Is allowed to proceed</b> on track no. {0} in the direction of {1}"
|
||||||
|
},
|
||||||
|
"2140": {
|
||||||
|
"text": "{bold1} at post/line {signalbox1}{'|'}{signalbox2} at km {km1} for {other1}",
|
||||||
|
"bold1": "Train halt",
|
||||||
|
"signalbox1": "x.1 signalbox",
|
||||||
|
"signalbox2": "x.2 signalbox",
|
||||||
|
"km1": "x.3 km",
|
||||||
|
"other1": "x.96 cause",
|
||||||
|
"message-html": "<b>Train halt</b> at post {0} at km {2} for {3} | <b>Train halt</b> on line {0} {'|'} {1} at km {2} for {3} | <b>Train halt</b> on line {0} {'|'} {1} at km {2} for {3}"
|
||||||
|
},
|
||||||
|
"2145": {
|
||||||
|
"text": "At {signalbox1} the clear signal {signal1}{br}{bold1}",
|
||||||
|
"bold1": "is invalid. Stop the train before this signal.",
|
||||||
|
"signalbox1": "x.1 signalbox",
|
||||||
|
"signal1": "x.2 signal",
|
||||||
|
"message-html": "At {0} the clear signal {1} <b>is invalid, stop the train before this signal.</b>"
|
||||||
|
},
|
||||||
|
"2150": {
|
||||||
|
"text": "{bold1} at post/line {br} {signalbox1} / {signalbox2} referring to level crossing at km {km1}{br}{bold2}",
|
||||||
|
"bold1": "Level crossing distant signals (TOP)",
|
||||||
|
"bold2": "are to be ignored. Proceed with timetable speed.",
|
||||||
|
"signalbox1": "x.1 signalbox",
|
||||||
|
"signalbox2": "x.2 signalbox",
|
||||||
|
"km1": "x.3 km",
|
||||||
|
"message-html": "<b>Level crossing distant signals (TOP)</b> at post {0} referring to level crossing at km {1} <b>are to be ignored. Proceed with timetable speed.</b> | <b>Wskazania tarcz ostrzegawczych</b> na line {0} / {1} referring to level crossing at km {2} <b>are to be ignored. Proceed with timetable speed.</b> | <b>Wskazania tarcz ostrzegawczych</b> na line {0} / {1} referring to level crossing at km {2} <b>are to be ignored. Proceed with timetable speed.</b>"
|
||||||
|
},
|
||||||
|
"2155": {
|
||||||
|
"text": "{bold1} at post/line {signalbox1}{'|'}{signalbox2} referring to signal {signal1}.",
|
||||||
|
"bold1": "Damaged SHP device",
|
||||||
|
"signalbox1": "x.1 signalbox",
|
||||||
|
"signalbox2": "x.2 signalbox",
|
||||||
|
"signal1": "x.3 signal",
|
||||||
|
"message-html": "<b>Damaged SHP device</b> at post {0} referring to signal {2}|<b>Damaged SHP device</b> on line {0} {'|'} {1} referring to signal {2}|<b>Uszkodzone urządzenia SHP</b> on line {0} {'|'} {1} referring to signal {2}"
|
||||||
|
},
|
||||||
|
"2160": {
|
||||||
|
"text": "{bold1} from {signalbox1} to {signalbox2}, rerouted via {signalbox3} by line {line1} with the speed of {vmax1}.",
|
||||||
|
"bold1": "Route change",
|
||||||
|
"signalbox1": "x.1 signalbox",
|
||||||
|
"signalbox2": "x.2 signalbox",
|
||||||
|
"signalbox3": "x.3 signalbox",
|
||||||
|
"line1": "x.4 line",
|
||||||
|
"vmax1": "x.5 km/h",
|
||||||
|
"message-html": "<b>Route change</b> from {0} to {1}, rerouted via {2} by line {3} with the speed of {4}."
|
||||||
|
},
|
||||||
|
"2165": {
|
||||||
|
"text": "{bold1} from {km1} to {km2}.",
|
||||||
|
"bold1": "Run with lowered pantographs",
|
||||||
|
"km1": "x.1 km",
|
||||||
|
"km2": "x.2 km",
|
||||||
|
"message-html": "<b>Run with lowered pantographs</b> from {0} to {1}."
|
||||||
|
},
|
||||||
|
"2170": {
|
||||||
|
"text": "{bold1} {signalbox1} and {signalbox2} of the line no. {line1}{br}{bold2}",
|
||||||
|
"bold1": "At section between",
|
||||||
|
"bold2": "ride with the analog contact.",
|
||||||
|
"signalbox1": "x.1 signalbox",
|
||||||
|
"signalbox2": "x.2 signalbox",
|
||||||
|
"line1": "x.3 line",
|
||||||
|
"message-html": "<b>At section between</b> {0} and {1} of the line no. {2} <b>ride with the analog contact.</b>"
|
||||||
|
},
|
||||||
|
"2180": {
|
||||||
|
"text": "{bold1} no. {track1} in the directon of {signalbox1} to km {km1} turning to {signalbox2} until hour {hour1}",
|
||||||
|
"bold1": "Run on the closed track",
|
||||||
|
"track1": "x.1 tor",
|
||||||
|
"signalbox1": "x.2 signalbox",
|
||||||
|
"km1": "x.3 km",
|
||||||
|
"signalbox2": "x.4 signalbox",
|
||||||
|
"hour1": "x.5 hour",
|
||||||
|
"message-html": "<b>Run on the closed track</b> no. {0} in the directon of {1} to km {2} turning to {3} until hour {4}"
|
||||||
|
},
|
||||||
|
"2181": {
|
||||||
|
"text": "{bold1}",
|
||||||
|
"bold1": "Track is closed with no rolling stock",
|
||||||
|
"message-html": "<b>Track is closed with no rolling stock</b> "
|
||||||
|
},
|
||||||
|
"2182": {
|
||||||
|
"text": "Train {train1} {bold1} at km {km1}",
|
||||||
|
"bold1": "is working on track",
|
||||||
|
"train1": "x.1 train no.",
|
||||||
|
"km1": "x.2 km",
|
||||||
|
"message-html": "Train {0} <b>is working on track</b> at km {1}"
|
||||||
|
},
|
||||||
|
"2183": {
|
||||||
|
"text": "Train {train1} {bold1} to km {km1}",
|
||||||
|
"bold1": "will be dispatched",
|
||||||
|
"train1": "x.1 train no.",
|
||||||
|
"km1": "x.2 km",
|
||||||
|
"message-html": "Train {0} <b>will be dispatched</b> to km {1}"
|
||||||
|
},
|
||||||
|
"2185": {
|
||||||
|
"text": "{bold1} on track no. {track1} at km {km1} on line {signalbox1} {'|'} {signalbox2}",
|
||||||
|
"bold1": "Is allowed to insert a PSD vehicle",
|
||||||
|
"track1": "x.1 track",
|
||||||
|
"km1": "x.2 km",
|
||||||
|
"signalbox1": "x.3 signalbox",
|
||||||
|
"signalbox2": "x.4 signalbox",
|
||||||
|
"message-html": "<b>Is allowed to insert a PSD vehicle</b> on track no. {0} at km {1} on line {2} {'|'} {3}"
|
||||||
|
},
|
||||||
|
"2310": {
|
||||||
|
"text": "{bold1}{br}{text-list}",
|
||||||
|
"bold1": "Do not exceed the speed and stay alert:",
|
||||||
|
"text-list": "{bold} {signalbox1}/{signalbox2} track no. {track1} {v} {vmax1} from {km1} to {km2} {other1}",
|
||||||
|
"bold": "{0}. On post/line",
|
||||||
|
"signalbox1": "x.{0} signalbox",
|
||||||
|
"signalbox2": "x.{0} signalbox",
|
||||||
|
"track1": "x.{0} track",
|
||||||
|
"vmax1": "x.{0} km/h",
|
||||||
|
"km1": "x.{0} km",
|
||||||
|
"km2": "x.{0} km",
|
||||||
|
"other1": "x.{1} cause",
|
||||||
|
"message-html": "<b>Nie przekraczać prędkości i zachować ostrożność:</b>",
|
||||||
|
"message-html-list": "<b>{0}. On post</b> {1} track no. {3} v{4}km/h from {5}km to {6}km - cause: {7}|<b>{0}. On post</b> {1} tor nr {3} v{4} from {5}km to {6}km - cause: {7}|<b>{0}. On line</b> {1}/{2} tor nr {3} v{4} from {5}km to {6}km - cause: {7}"
|
||||||
|
},
|
||||||
|
"2311": {
|
||||||
|
"text": "{bold1}",
|
||||||
|
"bold1": "Use „Baczność” signal multiple times",
|
||||||
|
"message-html": "<b>Use „Baczność” signal multiple times</b>"
|
||||||
|
},
|
||||||
|
"2320": {
|
||||||
|
"text": "{other2320}",
|
||||||
|
"other2320": "x.96 other",
|
||||||
|
"message-html": "Other: {0}"
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"V": "V Driver identifier",
|
||||||
|
"V-placeholder": "Driver nickname",
|
||||||
|
"W": "W Issuer identifier",
|
||||||
|
"W-placeholder": "Dispatcher nickname",
|
||||||
|
"Y": "Y Hour",
|
||||||
|
"Y-placeholder": "HH:MM, e.g. 09:25",
|
||||||
|
"Z": "Z Train order identifier",
|
||||||
|
"Z-placeholder": "RD-(order no.)-(sc. hash)-(2 last year digits)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,281 @@
|
|||||||
|
{
|
||||||
|
"locale": {
|
||||||
|
"pl": "POL",
|
||||||
|
"en": "ENG"
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"update-available-text": "Nowa wersja GeneraTORa dostępna!",
|
||||||
|
"update-available-underline": "Kliknij, aby odświeżyć aplikację!",
|
||||||
|
"title": "Aktualizacja GeneraTORa!",
|
||||||
|
"no-data": "Brak dostępnego changelogu!",
|
||||||
|
"confirm": "Przyjąłem!",
|
||||||
|
"info-1": "Ten changelog będzie zawsze dostępny po kliknięciu numeru wersji w stopce strony",
|
||||||
|
"info-2": "Pełny changelog dostępny na <a href='https://github.com/Spythere/genera-tor' target='_blank'>GitHubie projektu</a>"
|
||||||
|
},
|
||||||
|
"navbar": {
|
||||||
|
"OrderMessagePanel": "WIADOMOŚĆ",
|
||||||
|
"OrderListPanel": "ZAPISANE",
|
||||||
|
"OrderTrainPickerPanel": "POCIĄGI"
|
||||||
|
},
|
||||||
|
"order-message": {
|
||||||
|
"title": "Wiadomość do wyświetlenia na czacie symulatora:",
|
||||||
|
"info": "Po wygenerowaniu rozkazu skopiuj jego treść lub zapisz w pamięci przeglądarki za pomocą przycisków poniżej:",
|
||||||
|
"button-save": "Zapisz nowy rozkaz",
|
||||||
|
"button-copy": "Kopiuj treść rozkazu",
|
||||||
|
"button-update": "Zaktualizuj rozkaz",
|
||||||
|
"button-reset": "Wyczyść rozkaz",
|
||||||
|
"warning-outdated-clipboard": "Ups! Twoja przeglądarka musi być dosyć przestarzała, ponieważ nie obsługuje zapisu do schowka! :/",
|
||||||
|
"warning-fill-inputs": "Wypełnij puste rubryki rozkazu przed jego skopiowaniem!",
|
||||||
|
"warning-add-instruction": "Dodaj co najmniej jedną instrukcję rozkazu przed jego skopiowaniem!",
|
||||||
|
"warning-fill-missing": "Uzupełnij rubryki w nagłówku i stopce rozkazu przed jego skopiowaniem!",
|
||||||
|
"warning-fill-top-save": "Wypełnij co najmniej rubryki A, B, C i D w nagłówku rozkazu przed jego zapisaniem!",
|
||||||
|
"warning-fill-top-update": "Wypełnij co najmniej rubryki A, B, C i D w nagłówku rozkazu przed jego zaktualizowaniem!",
|
||||||
|
"warning-order-identical": "Ostatni zapisany rozkaz jest identyczny z obecnym!",
|
||||||
|
"warning-no-order-selected": "Wybierz rozkaz, który chcesz zaktualizować!",
|
||||||
|
"warning-conflicting-instructions": "Instrukcje {0} i {1} nie mogą znajdować się na tym samym rozkazie jednocześnie!",
|
||||||
|
"error-update": "Wystąpił błąd podczas aktualizowania tego rozkazu! :/",
|
||||||
|
"success-update-html": "Zaktualizowano treść <b class=\"text--accent\">rozkazu</b>!",
|
||||||
|
"success-save-html": "Zapisano treść <b class=\"text--accent\">rozkazu</b> w pamięci przeglądarki!",
|
||||||
|
"success-copy-html": "<b class=\"text--accent\">Skopiowano!</b> Możesz teraz wkleić treść rozkazu na czacie symulatora!"
|
||||||
|
},
|
||||||
|
"order-footer": {
|
||||||
|
"field-stationName": "stacja",
|
||||||
|
"field-checkpointName": "posterunek",
|
||||||
|
"field-hour": "godzina",
|
||||||
|
"field-minutes": "minuta",
|
||||||
|
"field-dispatcherName": "dyżurny ruchu",
|
||||||
|
"field-secondaryDispatcherName": "z polecenia dyżurnego ruchu",
|
||||||
|
"field-dispatcherOrSecondaryName": "dyżurny ruchu (lub z polecenia dyżurnego ruchu)"
|
||||||
|
},
|
||||||
|
"order-options": {
|
||||||
|
"dark-mode": "Ciemny motyw bloczka rozkazu",
|
||||||
|
"update-number-on-copy": "Aktualizuj numer rozkazu po skopiowaniu",
|
||||||
|
"update-number-on-save": "Aktualizuj numer rozkazu po zapisaniu",
|
||||||
|
"update-hours": "Aktualizuj godziny przy edycji"
|
||||||
|
},
|
||||||
|
"order-list": {
|
||||||
|
"title": "Zapisane rozkazy pisemne",
|
||||||
|
"no-saved-orders": "Brak zapisanych rozkazów!",
|
||||||
|
"order-title": "Rozkaz pisemny dla pociągu nr {trainNo}",
|
||||||
|
"order-subtitle": "Zaznaczone instrukcje: {0}",
|
||||||
|
"order-added": "Dodano:",
|
||||||
|
"order-updated": "Zaktualizowano:",
|
||||||
|
"button-order-select": "Wybierz",
|
||||||
|
"button-order-remove": "Usuń",
|
||||||
|
"warning-deprecated-version": "Przestarzała wersja rozkazu! Może generować złe informacje!",
|
||||||
|
"warning-removed-deprecated-orders": "Usunięto nieaktualne rozkazy pisemne ({count}) w związku z wejściem w życie ich nowego formatu!"
|
||||||
|
},
|
||||||
|
"order-train-picker": {
|
||||||
|
"placeholder-scenery-name": "Sceneria",
|
||||||
|
"placeholder-region-name": "Region",
|
||||||
|
"placeholder-checkpoint-name": "Posterunek",
|
||||||
|
"autofill-checkpoint-id": "Uzupełniaj skrót wybranego posterunku",
|
||||||
|
"info": "Wybierz dyżurnego oraz scenerię, aby zobaczyć pociągi",
|
||||||
|
"title": "Aktywne RJ i gracze na scenerii",
|
||||||
|
"subtitle": "Kliknij na gracza, aby wypełnić obecny rozkaz jego danymi",
|
||||||
|
"no-trains": "Brak pociągów do wyświetlenia"
|
||||||
|
},
|
||||||
|
"order": {
|
||||||
|
"title": "Rozkaz pisemny",
|
||||||
|
"header": {
|
||||||
|
"A": "A Nr pociągu {'|'} składu manewrowego",
|
||||||
|
"A-placeholder": "Numer pociągu lub manewru",
|
||||||
|
"B": "B Data",
|
||||||
|
"C": "C Lokalizacja pociągu {'|'} składu manewrowego",
|
||||||
|
"C-placeholder": "Nazwa posterunku / szlaku / scenerii",
|
||||||
|
"D": "D Lokalizacja nadawcy",
|
||||||
|
"D-placeholder": "Nazwa posterunku / scenerii"
|
||||||
|
},
|
||||||
|
"22": {
|
||||||
|
"text": "Dotyczy jazdy torem lewym",
|
||||||
|
"message-html": "<b>Dotyczy jazdy torem lewym</b>"
|
||||||
|
},
|
||||||
|
"99": {
|
||||||
|
"text": "Odwołanie rozkazu pisemnego",
|
||||||
|
"x1": "x.1 Identyfikator rozkazu pisemnego",
|
||||||
|
"message-html": "<b>Odwołanie rozkazu pisemnego</b> {0}"
|
||||||
|
},
|
||||||
|
"2110": {
|
||||||
|
"text": "{bold1} z toru nr {track1} z {signalbox1} {br} na tor nr {track2} w kierunku {signalbox2} {br} Pominięcie sygnałów stój {signal1} i {signal2} i {signal3}",
|
||||||
|
"bold1": "Zezwalam na wyjazd",
|
||||||
|
"track1": "x.1 tor",
|
||||||
|
"signalbox1": "x.2 posterunek",
|
||||||
|
"track2": "x.3 tor",
|
||||||
|
"signalbox2": "x.4 posterunek",
|
||||||
|
"signal1": "x.5 sygnalizator",
|
||||||
|
"signal2": "x.6 sygnalizator",
|
||||||
|
"signal3": "x.7 sygnalizator",
|
||||||
|
"message-html": "<b>Zezwalam na wyjazd</b> z toru nr {0} z {1} na tor nr {2} w kierunku {3}. Pominięcie sygnałów stój {4} i {5} i {6}"
|
||||||
|
},
|
||||||
|
"2115": {
|
||||||
|
"text": "{bold1} z toru nr {track1} do {signalbox1} na tor nr {track2} {br} Pominięcie sygnałów {signal1} i {signal2} i {signal3}",
|
||||||
|
"bold1": "Zezwalam na wjazd",
|
||||||
|
"track1": "x.1 tor",
|
||||||
|
"signalbox1": "x.2 posterunek",
|
||||||
|
"track2": "x.3 tor",
|
||||||
|
"signal1": "x.4 sygnalizator",
|
||||||
|
"signal2": "x.5 sygnalizator",
|
||||||
|
"signal3": "x.6 sygnalizator",
|
||||||
|
"message-html": "<b>Zezwalam na wjazd</b> z toru nr {0} do {1} na tor nr {2}. Pominięcie sygnałów {3} i {4} i {5}"
|
||||||
|
},
|
||||||
|
"2120": {
|
||||||
|
"text": "Od {signalbox1} do {signalbox2} po torze {track1} {br} {highlight1} {br} {underline1}{highlight2}.",
|
||||||
|
"highlight1": "wskazania semaforów SBL są nieważne.",
|
||||||
|
"underline1": "Zachować ostrożność od semafora ze wskaźnikiem",
|
||||||
|
"highlight2": " W18",
|
||||||
|
"signalbox1": "x.1 posterunek",
|
||||||
|
"signalbox2": "x.2 posterunek",
|
||||||
|
"track1": "x.3 nr toru",
|
||||||
|
"message-html": "Od {0} do {1} po torze {2} <b>wskazania semaforów SBL są nieważne.</b> Zachować ostrożność od semafora ze wskaźnikiem <b>W18.</b>"
|
||||||
|
},
|
||||||
|
"2125": {
|
||||||
|
"text": "Zezwalam przejechać za {select1} w kierunku {signalbox1} torem {track1} do km {km1} do godz. {hour1}.",
|
||||||
|
"select1-a": "wskaźnik W5",
|
||||||
|
"select1-b": "ostatni rozjazd",
|
||||||
|
"signalbox1": "x.1 posterunek",
|
||||||
|
"track1": "x.2 tor",
|
||||||
|
"km1": "x.3 km",
|
||||||
|
"hour1": "x.4 godzina",
|
||||||
|
"message-html": "Zezwalam przejechać za {0} w kierunku {1} torem {2} do km {3} do godz. {4}."
|
||||||
|
},
|
||||||
|
"2135": {
|
||||||
|
"text": "{bold1} po torze nr {track1} w kierunku {signalbox1}.",
|
||||||
|
"bold1": "Zezwalam na kontynuacje jazdy",
|
||||||
|
"track1": "x.1 tor",
|
||||||
|
"signalbox1": "x.2 posterunek",
|
||||||
|
"message-html": "<b>Zezwalam na kontynuacje jazdy</b> po torze nr {0} w kierunku {1}"
|
||||||
|
},
|
||||||
|
"2140": {
|
||||||
|
"text": "{bold1} na posterunku/szlaku {signalbox1}{'|'}{signalbox2} w km {km1} celem {other1}",
|
||||||
|
"bold1": "Zatrzymanie pociągu",
|
||||||
|
"signalbox1": "x.1 posterunek",
|
||||||
|
"signalbox2": "x.2 posterunek",
|
||||||
|
"km1": "x.3 km",
|
||||||
|
"other1": "x.96 inne",
|
||||||
|
"message-html": "<b>Zatrzymanie pociągu</b> na posterunku {0} w km {2} celem {3} | <b>Zatrzymanie pociągu</b> na szlaku {0} {'|'} {1} w km {2} celem {3} | <b>Zatrzymanie pociągu</b> na szlaku {0} {'|'} {1} w km {2} celem {3}"
|
||||||
|
},
|
||||||
|
"2145": {
|
||||||
|
"text": "Na {signalbox1} na sygnalizatorze {signal1}{br}{bold1}",
|
||||||
|
"bold1": "sygnał zezwalający jest nieważny, zatrzymać pociąg przed tym sygnalizatorem.",
|
||||||
|
"signalbox1": "x.1 posterunek",
|
||||||
|
"signal1": "x.2 sygnalizator",
|
||||||
|
"message-html": "Na {0} na sygnalizatorze {1} <b>sygnał zezwalający jest nieważny, zatrzymać pociąg przed tym sygnalizatorem.</b>"
|
||||||
|
},
|
||||||
|
"2150": {
|
||||||
|
"text": "{bold1} przejazdowych na posterunku/szlaku {br} {signalbox1} / {signalbox2} odnoszących się do przejazdu w km {km1}{br}{bold2}",
|
||||||
|
"bold1": "Wskazania tarcz ostrzegawczych",
|
||||||
|
"bold2": "są nieważne. Jazda z prędkością rozkładową.",
|
||||||
|
"signalbox1": "x.1 posterunek",
|
||||||
|
"signalbox2": "x.2 posterunek",
|
||||||
|
"km1": "x.3 km",
|
||||||
|
"message-html": "<b>Wskazania tarcz ostrzegawczych</b> przejazdowych na posterunku {0} odnoszących się do przejazdu w km {1} <b>są nieważne. Jazda z prędkością rozkładową.</b> | <b>Wskazania tarcz ostrzegawczych</b> przejazdowych na szlaku {0} / {1} odnoszących się do przejazdu w km {2} <b>są nieważne. Jazda z prędkością rozkładową.</b> | <b>Wskazania tarcz ostrzegawczych</b> przejazdowych na szlaku {0} / {1} odnoszących się do przejazdu w km {2} <b>są nieważne. Jazda z prędkością rozkładową.</b>"
|
||||||
|
},
|
||||||
|
"2155": {
|
||||||
|
"text": "{bold1} na posterunku/szlaku {signalbox1}{'|'}{signalbox2} odnoszące się do sygnalizatora {signal1}.",
|
||||||
|
"bold1": "Uszkodzone urządzenia SHP",
|
||||||
|
"signalbox1": "x.1 posterunek",
|
||||||
|
"signalbox2": "x.2 posterunek",
|
||||||
|
"signal1": "x.3 sygnalizator",
|
||||||
|
"message-html": "<b>Uszkodzone urządzenia SHP</b> na posterunku {0} odnoszące się do sygnalizatora {2}|<b>Uszkodzone urządzenia SHP</b> na szlaku {0} {'|'} {1} odnoszące się do sygnalizatora {2}|<b>Uszkodzone urządzenia SHP</b> na szlaku {0} {'|'} {1} odnoszące się do sygnalizatora {2}"
|
||||||
|
},
|
||||||
|
"2160": {
|
||||||
|
"text": "{bold1} na odcinku od {signalbox1} do {signalbox2}, jazda przez {signalbox3} linią {line1} z prędkością {vmax1}.",
|
||||||
|
"bold1": "Zmiana trasy",
|
||||||
|
"signalbox1": "x.1 posterunek",
|
||||||
|
"signalbox2": "x.2 posterunek",
|
||||||
|
"signalbox3": "x.3 posterunek",
|
||||||
|
"line1": "x.4 linia",
|
||||||
|
"vmax1": "x.5 km/h",
|
||||||
|
"message-html": "<b>Zmiana trasy</b> na odcinku od {0} do {1}, jazda przez {2} linią {3} z prędkością {4}."
|
||||||
|
},
|
||||||
|
"2165": {
|
||||||
|
"text": "{bold1} na odcinku od {km1} do {km2}.",
|
||||||
|
"bold1": "Jazda z opuszczonymi pantografami",
|
||||||
|
"km1": "x.1 km",
|
||||||
|
"km2": "x.2 km",
|
||||||
|
"message-html": "<b>Jazda z opuszczonymi pantografami</b> na odcinku od {0} do {1}."
|
||||||
|
},
|
||||||
|
"2170": {
|
||||||
|
"text": "{bold1} od {signalbox1} do {signalbox2} linii nr {line1}{br}{bold2}",
|
||||||
|
"bold1": "Na odcinku",
|
||||||
|
"bold2": "jazda pociągu z łącznością analogową.",
|
||||||
|
"signalbox1": "x.1 posterunek",
|
||||||
|
"signalbox2": "x.2 posterunek",
|
||||||
|
"line1": "x.3 linia",
|
||||||
|
"message-html": "<b>Na odcinku</b> na odcinku od {0} do {1} linii nr {2} <b>jazda pociągu z łącznością analogową.</b>"
|
||||||
|
},
|
||||||
|
"2180": {
|
||||||
|
"text": "{bold1} nr {track1} w kierunku {signalbox1} do km {km1} zjazd do {signalbox2} do godz. {hour1}",
|
||||||
|
"bold1": "Polecam jazdę po torze zamkniętym",
|
||||||
|
"track1": "x.1 tor",
|
||||||
|
"signalbox1": "x.2 posterunek",
|
||||||
|
"km1": "x.3 km",
|
||||||
|
"signalbox2": "x.4 posterunek",
|
||||||
|
"hour1": "x.5 godzina",
|
||||||
|
"message-html": "<b>Polecam jazdę po torze zamkniętym</b> nr {0} w kierunku {1} do km {2} zjazd do {3} do godz. {4}"
|
||||||
|
},
|
||||||
|
"2181": {
|
||||||
|
"text": "{bold1}",
|
||||||
|
"bold1": "Tor zamknięty wolny od taboru",
|
||||||
|
"message-html": "<b>Tor zamknięty wolny od taboru</b> "
|
||||||
|
},
|
||||||
|
"2182": {
|
||||||
|
"text": "{bold1} {train1} w km {km1}",
|
||||||
|
"bold1": "Na torze pracuje pociąg",
|
||||||
|
"train1": "x.1 numer pociągu",
|
||||||
|
"km1": "x.2 km",
|
||||||
|
"message-html": "<b>Na torze pracuje pociąg</b> {0} w km {1}"
|
||||||
|
},
|
||||||
|
"2183": {
|
||||||
|
"text": "{bold1} {train1} do km {km1}",
|
||||||
|
"bold1": "Na tor zostanie wyprawiony pociąg",
|
||||||
|
"train1": "x.1 numer pociągu",
|
||||||
|
"km1": "x.2 km",
|
||||||
|
"message-html": "<b>Na tor zostanie wyprawiony pociąg</b> {0} do km {1}"
|
||||||
|
},
|
||||||
|
"2185": {
|
||||||
|
"text": "{bold1} na tor nr {track1} w km {km1} na szlaku {signalbox1} {'|'} {signalbox2}",
|
||||||
|
"bold1": "Zezwalam na wstawienie PSD",
|
||||||
|
"track1": "x.1 tor",
|
||||||
|
"km1": "x.2 km",
|
||||||
|
"signalbox1": "x.3 posterunek",
|
||||||
|
"signalbox2": "x.4 posterunek",
|
||||||
|
"message-html": "<b>Zezwalam na wstawienie PSD</b> na tor nr {0} w km {1} na szlaku {2} {'|'} {3}"
|
||||||
|
},
|
||||||
|
"2310": {
|
||||||
|
"text": "{bold1}{br}{text-list}",
|
||||||
|
"bold1": "Nie przekraczać prędkości i zachować ostrożność:",
|
||||||
|
"text-list": "{bold} {signalbox1}/{signalbox2} tor nr {track1} {v} {vmax1} od {km1} do {km2} {other1}",
|
||||||
|
"bold": "{0}. Na posterunku/szlaku",
|
||||||
|
"signalbox1": "x.{0} posterunek",
|
||||||
|
"signalbox2": "x.{0} posterunek",
|
||||||
|
"track1": "x.{0} tor",
|
||||||
|
"vmax1": "x.{0} km/h",
|
||||||
|
"km1": "x.{0} km",
|
||||||
|
"km2": "x.{0} km",
|
||||||
|
"other1": "x.{1} przyczyna",
|
||||||
|
"message-html": "<b>Nie przekraczać prędkości i zachować ostrożność:</b>",
|
||||||
|
"message-html-list": "<b>{0}. Na posterunku</b> {1} tor nr {3} v{4}km/h od {5}km do {6}km - przyczyna: {7}|<b>{0}. Na posterunku</b> {1} tor nr {3} v{4} od {5}km do {6}km - przyczyna: {7}|<b>{0}. Na szlaku</b> {1}/{2} tor nr {3} v{4} od {5}km do {6}km - przyczyna: {7}"
|
||||||
|
},
|
||||||
|
"2311": {
|
||||||
|
"text": "{bold1}",
|
||||||
|
"bold1": "Podawać sygnał „Baczność”",
|
||||||
|
"message-html": "<b>Podawać sygnał „Baczność”</b>"
|
||||||
|
},
|
||||||
|
"2320": {
|
||||||
|
"text": "{other2320}",
|
||||||
|
"other2320": "x.96 inne",
|
||||||
|
"message-html": "Inne: {0}"
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"V": "V Identyfikator maszynisty",
|
||||||
|
"V-placeholder": "Nick maszynisty",
|
||||||
|
"W": "W Identyfikator nadawcy",
|
||||||
|
"W-placeholder": "Nick dyżurnego",
|
||||||
|
"Y": "Y Godzina",
|
||||||
|
"Y-placeholder": "Godzina w formacie HH:MM np. 09:25",
|
||||||
|
"Z": "Z Identyfikator rozkazu pisemnego",
|
||||||
|
"Z-placeholder": "RD-(nr rozkazu)-(hash sc.)-(2 ostatnie cyfry roku)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,5 +3,6 @@ import App from './App.vue';
|
|||||||
import router from './router';
|
import router from './router';
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
|
|
||||||
createApp(App).use(router).use(createPinia()).mount('#app');
|
import i18n from './i18n';
|
||||||
|
|
||||||
|
createApp(App).use(router).use(i18n).use(createPinia()).mount('#app');
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
export default class StorageManager {
|
||||||
|
static registerStorage(name: string) {
|
||||||
|
window.localStorage.setItem(name, '1');
|
||||||
|
}
|
||||||
|
|
||||||
|
static unregisterStorage(name: string) {
|
||||||
|
window.localStorage.removeItem(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static isRegistered(name: string) {
|
||||||
|
return window.localStorage.getItem(name) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static setBooleanValue(key: string, val: boolean) {
|
||||||
|
window.localStorage.setItem(key, val.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
static setNumericValue(key: string, val: number) {
|
||||||
|
window.localStorage.setItem(key, val.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
static setStringValue(key: string, val: string) {
|
||||||
|
window.localStorage.setItem(key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static setValue(key: string, val: any) {
|
||||||
|
if (typeof val == 'boolean') this.setBooleanValue(key, val);
|
||||||
|
else if (typeof val == 'number') this.setNumericValue(key, val);
|
||||||
|
else if (typeof val == 'string') this.setStringValue(key, val);
|
||||||
|
else this.setStringValue(key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static removeValue(key: string) {
|
||||||
|
window.localStorage.removeItem(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getValue(key: string) {
|
||||||
|
return window.localStorage.getItem(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getBooleanValue(key: string): boolean {
|
||||||
|
return window.localStorage.getItem(key) === 'true' ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getStringValue(key: string): string {
|
||||||
|
return window.localStorage.getItem(key) || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
static getNumericValue(key: string): number {
|
||||||
|
const itemValue = window.localStorage.getItem(key);
|
||||||
|
return itemValue ? parseInt(itemValue) : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
store: useStore(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
generateFooter() {
|
|
||||||
const footer = this.store.orderFooter;
|
|
||||||
|
|
||||||
const messageArray = [];
|
|
||||||
|
|
||||||
if (footer.stationName) messageArray.push(`stacja: ${footer.stationName}`);
|
|
||||||
if (footer.checkpointName) messageArray.push(`posterunek: ${footer.checkpointName}`);
|
|
||||||
if (footer.hour) messageArray.push(`godz. ${footer.hour}`);
|
|
||||||
if (footer.minutes) messageArray.push(`min. ${footer.minutes}`);
|
|
||||||
if (footer.dispatcherName) messageArray.push(`dyżurny ruchu ${footer.dispatcherName}`);
|
|
||||||
if (footer.secondaryDispatcherName)
|
|
||||||
messageArray.push(`z polecenia dyżurnego ruchu ${footer.secondaryDispatcherName}`);
|
|
||||||
|
|
||||||
this.store.footerMessage = ` <b>|</b> ${messageArray.join(
|
|
||||||
', '
|
|
||||||
)} <b>|</b> Rozkaz otrzymałem, maszynista: (potwierdzić otrzymanie rozkazu)`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
import { LocalStorageOrder } from '../types/orderTypes';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
store: useStore(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
saveLocalOrder() {
|
|
||||||
let orderObj: LocalStorageOrder = {
|
|
||||||
id: '',
|
|
||||||
orderType: this.store.chosenOrderType,
|
|
||||||
orderBody: this.store[this.store.chosenOrderType],
|
|
||||||
orderFooter: this.store.orderFooter,
|
|
||||||
createdAt: Date.now(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const headerInfo = orderObj['orderBody']['header'];
|
|
||||||
|
|
||||||
if (!headerInfo['orderNo']) return -1;
|
|
||||||
if (!headerInfo['trainNo']) return -1;
|
|
||||||
if (!headerInfo['date']) return -1;
|
|
||||||
|
|
||||||
const localStorage = window.localStorage;
|
|
||||||
const localOrderCount = localStorage.getItem('orderCount') || '0';
|
|
||||||
|
|
||||||
if (localOrderCount == '0') localStorage.setItem('orderCount', '0');
|
|
||||||
|
|
||||||
const prevLocalOrder = localStorage.getItem(`order-${Number(localOrderCount)}`);
|
|
||||||
if (prevLocalOrder && prevLocalOrder == JSON.stringify(orderObj)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextOrderCount = Number(localOrderCount) + 1;
|
|
||||||
const orderId = `order-${nextOrderCount}`;
|
|
||||||
orderObj['id'] = orderId;
|
|
||||||
|
|
||||||
localStorage.setItem('orderCount', `${nextOrderCount}`);
|
|
||||||
localStorage.setItem(orderId, JSON.stringify(orderObj));
|
|
||||||
|
|
||||||
this.store.chosenLocalOrderId = orderId;
|
|
||||||
return 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
updateLocalOrder() {
|
|
||||||
if (!this.store.chosenLocalOrderId) return 0;
|
|
||||||
const localOrder = window.localStorage.getItem(this.store.chosenLocalOrderId);
|
|
||||||
|
|
||||||
if (!localOrder) return -1;
|
|
||||||
|
|
||||||
let orderObj: LocalStorageOrder = {
|
|
||||||
id: this.store.chosenLocalOrderId,
|
|
||||||
orderType: this.store.chosenOrderType,
|
|
||||||
orderBody: this.store[this.store.chosenOrderType],
|
|
||||||
orderFooter: this.store.orderFooter,
|
|
||||||
updatedAt: Date.now(),
|
|
||||||
};
|
|
||||||
|
|
||||||
window.localStorage.setItem(this.store.chosenLocalOrderId, JSON.stringify(orderObj));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
removeLocalOrder(order: LocalStorageOrder) {
|
|
||||||
localStorage.removeItem(order.id);
|
|
||||||
|
|
||||||
if (this.store.chosenLocalOrderId == order.id) this.store.chosenLocalOrderId = '';
|
|
||||||
// localStorage.setItem('orderCount', (Number(localStorage.getItem('orderCount')) - 1).toString());
|
|
||||||
},
|
|
||||||
|
|
||||||
selectLocalOrder(order: LocalStorageOrder) {
|
|
||||||
this.store.chosenOrderType = order.orderType;
|
|
||||||
this.store.chosenLocalOrderId = order.id;
|
|
||||||
|
|
||||||
const localOrder = JSON.parse(JSON.stringify(order));
|
|
||||||
const localOrderBody = localOrder['orderBody'];
|
|
||||||
const localOrderFooter = localOrder['orderFooter'];
|
|
||||||
|
|
||||||
let storeOrderObj;
|
|
||||||
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let key in this.store.orderFooter) {
|
|
||||||
(this.store.orderFooter as any)[key] = localOrderFooter[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.store.orderMode = 'OrderMessage';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useStore } from '../store/store';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
store: useStore(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
verifyOrderFields() {
|
|
||||||
// const header = this.store[this.store.chosenOrderType].header;
|
|
||||||
const footer = this.store.orderFooter;
|
|
||||||
|
|
||||||
const fieldsToCorrect = [];
|
|
||||||
|
|
||||||
// if (!header.orderNo) fieldsToCorrect.push('numer rozkazu');
|
|
||||||
// if (!header.trainNo) fieldsToCorrect.push('numer pociągu / manewru');
|
|
||||||
// if (!header.date) fieldsToCorrect.push('data');
|
|
||||||
|
|
||||||
if (!footer.stationName) fieldsToCorrect.push('stacja');
|
|
||||||
if (!footer.checkpointName) fieldsToCorrect.push('posterunek');
|
|
||||||
if (!footer.hour) fieldsToCorrect.push('godzina');
|
|
||||||
if (!footer.minutes) fieldsToCorrect.push('minuta');
|
|
||||||
if (!footer.dispatcherName && !footer.secondaryDispatcherName)
|
|
||||||
fieldsToCorrect.push('dyżurny ruchu (lub z polecenia dyżurnego ruchu)');
|
|
||||||
|
|
||||||
return fieldsToCorrect;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
|
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
|
||||||
import Home from '../views/Home.vue'
|
import Home from '../views/Home.vue';
|
||||||
|
|
||||||
const routes: Array<RouteRecordRaw> = [
|
const routes: Array<RouteRecordRaw> = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
component: Home
|
component: Home
|
||||||
},
|
}
|
||||||
]
|
];
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHistory(),
|
||||||
routes
|
routes
|
||||||
})
|
});
|
||||||
|
|
||||||
export default router
|
export default router;
|
||||||
|
|||||||
@@ -1,186 +1,351 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { IOrderN, IOrderO, IOrderS, TOrder } from '../types/orderTypes';
|
import { IOrderData } from '../types/orderTypes';
|
||||||
import { currentFormattedDate } from '../utils/dateUtils';
|
|
||||||
|
import StorageManager from '../managers/storageManager';
|
||||||
|
import i18n from '../i18n';
|
||||||
|
import { TPanelMode } from '../types/dataTypes';
|
||||||
|
|
||||||
export const useStore = defineStore('store', {
|
export const useStore = defineStore('store', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
helperModalOpen: false,
|
currentAppLocale: 'pl',
|
||||||
|
|
||||||
chosenOrderType: 'orderN' as TOrder,
|
appUpdateData: {
|
||||||
chosenLocalOrderId: '',
|
version: '',
|
||||||
|
changelog: '',
|
||||||
orderMode: 'OrderMessage',
|
releaseURL: ''
|
||||||
|
|
||||||
orderFooter: {
|
|
||||||
stationName: '',
|
|
||||||
checkpointName: '',
|
|
||||||
hour: new Date().toLocaleTimeString('pl-PL', { hour: '2-digit' }),
|
|
||||||
minutes: new Date().toLocaleTimeString('pl-PL', { minute: '2-digit' }),
|
|
||||||
dispatcherName: '',
|
|
||||||
secondaryDispatcherName: '',
|
|
||||||
},
|
},
|
||||||
|
|
||||||
orderMessage: '',
|
updateCardOpen: false,
|
||||||
footerMessage: '',
|
orderDarkMode: false,
|
||||||
|
|
||||||
orderO: {
|
panelMode: 'OrderMessagePanel' as TPanelMode,
|
||||||
|
|
||||||
|
chosenLocalOrderId: '',
|
||||||
|
|
||||||
|
orderData: {
|
||||||
header: {
|
header: {
|
||||||
orderNo: '1',
|
A: '',
|
||||||
trainNo: '',
|
B: '',
|
||||||
date: currentFormattedDate(),
|
C: '',
|
||||||
|
D: ''
|
||||||
},
|
},
|
||||||
|
instructions: [
|
||||||
orderList: [
|
|
||||||
{
|
{
|
||||||
name: '',
|
key: '22',
|
||||||
from: '',
|
name: '22',
|
||||||
to: '',
|
active: false,
|
||||||
vmax: '',
|
inputFields: {},
|
||||||
jo: false,
|
optionalFieldNames: [],
|
||||||
reason: '',
|
textDirectives: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '',
|
key: '99',
|
||||||
from: '',
|
name: '99',
|
||||||
to: '',
|
active: false,
|
||||||
vmax: '',
|
inputFields: {
|
||||||
jo: false,
|
x1: ''
|
||||||
reason: '',
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '',
|
key: '2110',
|
||||||
from: '',
|
name: '21.10',
|
||||||
to: '',
|
active: false,
|
||||||
vmax: '',
|
inputFields: {
|
||||||
jo: false,
|
track1: '',
|
||||||
reason: '',
|
signalbox1: '',
|
||||||
|
track2: '',
|
||||||
|
signalbox2: '',
|
||||||
|
signal1: '',
|
||||||
|
signal2: '',
|
||||||
|
signal3: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: ['signal1', 'signal2', 'signal3'],
|
||||||
|
textDirectives: ['bold1', 'br']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '',
|
key: '2115',
|
||||||
from: '',
|
name: '21.15',
|
||||||
to: '',
|
active: false,
|
||||||
vmax: '',
|
inputFields: {
|
||||||
jo: false,
|
track1: '',
|
||||||
reason: '',
|
signalbox1: '',
|
||||||
|
track2: '',
|
||||||
|
signal1: '',
|
||||||
|
signal2: '',
|
||||||
|
signal3: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: ['signal1', 'signal2', 'signal3'],
|
||||||
|
textDirectives: ['bold1', 'br']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '',
|
key: '2120',
|
||||||
from: '',
|
name: '21.20',
|
||||||
to: '',
|
active: false,
|
||||||
vmax: '',
|
inputFields: {
|
||||||
jo: false,
|
signalbox1: '',
|
||||||
reason: '',
|
signalbox2: '',
|
||||||
|
track1: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['highlight1', 'highlight2', 'underline1', 'br']
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: '2125',
|
||||||
|
name: '21.25',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
select1: 'select1-a',
|
||||||
|
signalbox1: '',
|
||||||
|
track1: '',
|
||||||
|
km1: '',
|
||||||
|
hour1: ''
|
||||||
|
},
|
||||||
|
selectFields: {
|
||||||
|
select1: {
|
||||||
|
options: ['select1-a', 'select1-b']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2135',
|
||||||
|
name: '21.35',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
track1: '',
|
||||||
|
signalbox1: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2140',
|
||||||
|
name: '21.40',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
signalbox1: '',
|
||||||
|
signalbox2: '',
|
||||||
|
km1: '',
|
||||||
|
other1: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: ['signalbox2'],
|
||||||
|
textDirectives: ['bold1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2145',
|
||||||
|
name: '21.45',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
signalbox1: '',
|
||||||
|
signal1: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1', 'br']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2150',
|
||||||
|
name: '21.50',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
signalbox1: '',
|
||||||
|
signalbox2: '',
|
||||||
|
km1: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: ['signalbox2'],
|
||||||
|
textDirectives: ['bold1', 'br', 'bold2']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2155',
|
||||||
|
name: '21.55',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
signalbox1: '',
|
||||||
|
signalbox2: '',
|
||||||
|
signal1: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: ['signalbox2'],
|
||||||
|
textDirectives: ['bold1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2160',
|
||||||
|
name: '21.60',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
signalbox1: '',
|
||||||
|
signalbox2: '',
|
||||||
|
signalbox3: '',
|
||||||
|
line1: '',
|
||||||
|
vmax1: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2165',
|
||||||
|
name: '21.65',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
km1: '',
|
||||||
|
km2: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2170',
|
||||||
|
name: '21.70',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
signalbox1: '',
|
||||||
|
signalbox2: '',
|
||||||
|
line1: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1', 'br', 'bold2']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2180',
|
||||||
|
name: '21.80',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
track1: '',
|
||||||
|
signalbox1: '',
|
||||||
|
km1: '',
|
||||||
|
signalbox2: '',
|
||||||
|
hour1: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2181',
|
||||||
|
name: '21.81',
|
||||||
|
active: false,
|
||||||
|
inputFields: {},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2182',
|
||||||
|
name: '21.82',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
train1: '',
|
||||||
|
km1: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2183',
|
||||||
|
name: '21.83',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
train1: '',
|
||||||
|
km1: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2185',
|
||||||
|
name: '21.85',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
track1: '',
|
||||||
|
km1: '',
|
||||||
|
signalbox1: '',
|
||||||
|
signalbox2: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2310',
|
||||||
|
name: '23.10',
|
||||||
|
active: false,
|
||||||
|
inputFields: {},
|
||||||
|
listFields: [
|
||||||
|
{
|
||||||
|
active: false,
|
||||||
|
values: {
|
||||||
|
signalbox1: '',
|
||||||
|
signalbox2: '',
|
||||||
|
track1: '',
|
||||||
|
vmax1: '',
|
||||||
|
km1: '',
|
||||||
|
km2: '',
|
||||||
|
other1: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active: false,
|
||||||
|
values: {
|
||||||
|
signalbox1: '',
|
||||||
|
signalbox2: '',
|
||||||
|
track1: '',
|
||||||
|
vmax1: '',
|
||||||
|
km1: '',
|
||||||
|
km2: '',
|
||||||
|
other1: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
active: false,
|
||||||
|
values: {
|
||||||
|
signalbox1: '',
|
||||||
|
signalbox2: '',
|
||||||
|
track1: '',
|
||||||
|
vmax1: '',
|
||||||
|
km1: '',
|
||||||
|
km2: '',
|
||||||
|
other1: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1', 'br']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2311',
|
||||||
|
name: '23.11',
|
||||||
|
active: false,
|
||||||
|
inputFields: {},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: ['bold1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2320',
|
||||||
|
name: '23.20',
|
||||||
|
active: false,
|
||||||
|
inputFields: {
|
||||||
|
other2320: ''
|
||||||
|
},
|
||||||
|
optionalFieldNames: [],
|
||||||
|
textDirectives: []
|
||||||
|
}
|
||||||
],
|
],
|
||||||
other: '',
|
footer: {
|
||||||
} as IOrderO,
|
V: '',
|
||||||
|
W: '',
|
||||||
|
Y: '',
|
||||||
|
Z: ''
|
||||||
|
}
|
||||||
|
} as IOrderData,
|
||||||
|
|
||||||
orderN: {
|
orderMessage: ''
|
||||||
header: {
|
|
||||||
orderNo: '1',
|
|
||||||
trainNo: '',
|
|
||||||
date: currentFormattedDate(),
|
|
||||||
},
|
|
||||||
|
|
||||||
rows: [
|
|
||||||
{
|
|
||||||
enabled: false,
|
|
||||||
from: '',
|
|
||||||
to: '',
|
|
||||||
trackNo: '',
|
|
||||||
trackNo2: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: false,
|
|
||||||
option1: 'sygnału "Nakaz Jazdy"',
|
|
||||||
option2: 'lewy',
|
|
||||||
option3: 'lewy',
|
|
||||||
signal1: '',
|
|
||||||
signal2: '',
|
|
||||||
signal3: '',
|
|
||||||
signalType: 'wyjazdowego',
|
|
||||||
checkbox: 'checkbox-2a',
|
|
||||||
direction1: '',
|
|
||||||
direction2: '',
|
|
||||||
trackNoFrom: '',
|
|
||||||
trackNoTo1: '',
|
|
||||||
trackNoTo2: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: false,
|
|
||||||
option1: 'Jazda',
|
|
||||||
option2: 'pociąg',
|
|
||||||
|
|
||||||
direction: '',
|
|
||||||
toKilometer: '',
|
|
||||||
trackNo: '',
|
|
||||||
untilHour: '',
|
|
||||||
untilMin: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: false,
|
|
||||||
trackNo: '',
|
|
||||||
optionStation: 'stację',
|
|
||||||
stationName: '',
|
|
||||||
checkbox: 'checkbox-4a',
|
|
||||||
side: 'lewej',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: false,
|
|
||||||
trackNo: '',
|
|
||||||
direction: '',
|
|
||||||
stationType: 'stację',
|
|
||||||
stationName: '',
|
|
||||||
on: '',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
} as IOrderN,
|
|
||||||
|
|
||||||
orderS: {
|
|
||||||
header: {
|
|
||||||
orderNo: '1',
|
|
||||||
trainNo: '',
|
|
||||||
for: 'pociągu',
|
|
||||||
date: currentFormattedDate(),
|
|
||||||
},
|
|
||||||
|
|
||||||
rows: [
|
|
||||||
{
|
|
||||||
enabled: false,
|
|
||||||
option1: 'sygnału "nakaz jazdy"',
|
|
||||||
optionSignal: 'wyjazdowego',
|
|
||||||
radio1: 'radio-1a-1',
|
|
||||||
signal1: '',
|
|
||||||
trackNo: '',
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
enabled: false,
|
|
||||||
signalType: 'wyjazdowego',
|
|
||||||
signal1: '',
|
|
||||||
signal2: '',
|
|
||||||
signal3: '',
|
|
||||||
trackNo: '',
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
enabled: false,
|
|
||||||
from: '',
|
|
||||||
to: '',
|
|
||||||
trackNo: '',
|
|
||||||
trainNo: '',
|
|
||||||
arrivedTo: '',
|
|
||||||
hour: '',
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
enabled: false,
|
|
||||||
content: '',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
} as IOrderS,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
actions: {
|
||||||
|
changeLang(lang: string) {
|
||||||
|
i18n.global.locale.value = lang as typeof i18n.global.locale.value;
|
||||||
|
this.currentAppLocale = lang;
|
||||||
|
|
||||||
|
StorageManager.setStringValue('lang', lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -10,4 +10,3 @@
|
|||||||
transform: translateY(100%);
|
transform: translateY(100%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
$bgCol: #0e0e0e;
|
||||||
|
$bgColLighter: #292929;
|
||||||
|
$bgColDarker: #080808;
|
||||||
|
$accentCol: #ff6060;
|
||||||
|
$warnCol: #ffe02e;
|
||||||
|
$whiteDimmerCol: #ccc;
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||||
|
/* libre-franklin-regular - latin_latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-display: swap;
|
||||||
|
font-family: 'Libre Franklin';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url('/fonts/libre-franklin-regular.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
/* libre-franklin-500 - latin_latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-display: swap;
|
||||||
|
font-family: 'Libre Franklin';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: url('/fonts/libre-franklin-500.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
/* libre-franklin-700 - latin_latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-display: swap;
|
||||||
|
font-family: 'Libre Franklin';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: url('/fonts/libre-franklin-700.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
/* libre-franklin-800 - latin_latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-display: swap;
|
||||||
|
font-family: 'Libre Franklin';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
src: url('/fonts/libre-franklin-800.woff2') format('woff2');
|
||||||
|
}
|
||||||
@@ -0,0 +1,249 @@
|
|||||||
|
@use 'fonts';
|
||||||
|
@use 'colors';
|
||||||
|
@use 'sass:color';
|
||||||
|
|
||||||
|
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: color.adjust(colors.$bgColDarker, $lightness: 15%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 1px solid white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text styles
|
||||||
|
.text {
|
||||||
|
&--accent {
|
||||||
|
color: colors.$accentCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--warn {
|
||||||
|
color: colors.$warnCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--grayed {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
@use 'colors';
|
||||||
|
|
||||||
|
$darkModeTextCol: #eee;
|
||||||
|
|
||||||
|
.order {
|
||||||
|
width: 100%;
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
background-color: colors.$bgColDarker;
|
||||||
|
color: $darkModeTextCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 550px) {
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table.order-table {
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
table-layout: fixed;
|
||||||
|
min-width: 750px;
|
||||||
|
|
||||||
|
border: 2px solid black;
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
td {
|
||||||
|
border: 2px solid black;
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
text-align: justify;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-input-box {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 1.25em;
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 0;
|
||||||
|
transform: translate(-50%, 2em);
|
||||||
|
font-size: 0.8em;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.order-input {
|
||||||
|
max-width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
font-size: 1em;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 2px dotted black;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
border-bottom: 2px solid colors.$accentCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.row-checkbox + input::placeholder {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[type='checkbox']:focus-visible,
|
||||||
|
&[type='radio']:focus-visible {
|
||||||
|
outline: 2px solid colors.$accentCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[type='checkbox'],
|
||||||
|
&[type='radio'] {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label.order-input-label {
|
||||||
|
display: block;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.order-select {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea.order-textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 200px;
|
||||||
|
resize: vertical;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid colors.$accentCol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dark mode
|
||||||
|
.order.dark {
|
||||||
|
input.order-input {
|
||||||
|
border-color: $darkModeTextCol !important;
|
||||||
|
color: $darkModeTextCol !important;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
border-bottom: 2px solid colors.$accentCol !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: #ccc !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select.order-select {
|
||||||
|
color: $darkModeTextCol !important;
|
||||||
|
border-color: $darkModeTextCol;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
border-color: colors.$accentCol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select.order-select option,
|
||||||
|
textarea.order-textarea {
|
||||||
|
color: $darkModeTextCol !important;
|
||||||
|
border-color: $darkModeTextCol !important;
|
||||||
|
background-color: colors.$bgColDarker !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-bar {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order_header,
|
||||||
|
.order_other,
|
||||||
|
table.order-table,
|
||||||
|
tr,
|
||||||
|
td {
|
||||||
|
border-color: $darkModeTextCol !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,117 +1,106 @@
|
|||||||
export declare module ApiSWDR {
|
export declare module API {
|
||||||
export interface IStationsOnline {
|
export namespace ActiveData {
|
||||||
success: boolean;
|
export interface Response {
|
||||||
respCode: number;
|
activeSceneries?: API.ActiveSceneries.Response;
|
||||||
message: IStationsOnlineMessage[];
|
trains?: API.ActiveTrains.Response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IStationsOnlineMessage {
|
export namespace ActiveSceneries {
|
||||||
dispatcherId: number;
|
export interface Data {
|
||||||
dispatcherName: string;
|
dispatcherId: number;
|
||||||
dispatcherIsSupporter: boolean;
|
dispatcherName: string;
|
||||||
stationName: string;
|
dispatcherIsSupporter: boolean;
|
||||||
stationHash: string;
|
stationName: string;
|
||||||
region: string;
|
stationHash: string;
|
||||||
maxUsers: number;
|
region: string;
|
||||||
currentUsers: number;
|
maxUsers: number;
|
||||||
spawn: number;
|
currentUsers: number;
|
||||||
lastSeen: any;
|
spawn: number;
|
||||||
dispatcherExp: number;
|
lastSeen: number;
|
||||||
nameFromHeader: string;
|
dispatcherExp: number;
|
||||||
spawnString: string;
|
nameFromHeader: string;
|
||||||
networkConnectionString: string;
|
spawnString: string | null;
|
||||||
isOnline: number;
|
networkConnectionString: string;
|
||||||
dispatcherRate: number;
|
isOnline: number;
|
||||||
|
dispatcherRate: number;
|
||||||
|
dispatcherStatus: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Response = Data[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// export interface ITrainsOnline {
|
export namespace ActiveTrains {
|
||||||
// success: boolean;
|
export type Response = Data[];
|
||||||
// respCode: number;
|
|
||||||
// message: ITrainsOnlineMessage[];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export interface ITrainsOnlineMessage {
|
export interface Data {
|
||||||
// trainNo: number;
|
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 declare module ApiStacjownik {
|
mass: number;
|
||||||
export interface IActiveTrain {
|
length: number;
|
||||||
trainNo: number;
|
speed: number;
|
||||||
|
stockString: string;
|
||||||
|
|
||||||
mass: number;
|
signal: string;
|
||||||
length: number;
|
distance: number;
|
||||||
speed: number;
|
connectedTrack: string;
|
||||||
|
|
||||||
signal: string;
|
driverName: string;
|
||||||
distance: number;
|
driverId: number;
|
||||||
connectedTrack: string;
|
driverIsSupporter: boolean;
|
||||||
stockString: string;
|
driverLevel?: number;
|
||||||
|
|
||||||
driverName: string;
|
currentStationName: string;
|
||||||
driverId: number;
|
currentStationHash?: string;
|
||||||
driverIsSupporter: boolean;
|
|
||||||
|
|
||||||
currentStationName: string;
|
online: number;
|
||||||
currentStationHash?: string;
|
lastSeen: number;
|
||||||
|
|
||||||
online: boolean;
|
region: string;
|
||||||
lastSeen: number;
|
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;
|
timetableId: number;
|
||||||
category: string;
|
category: string;
|
||||||
route: string;
|
route: string;
|
||||||
stopList: IActiveTrainStop[];
|
|
||||||
|
stopList: TimetableStop[];
|
||||||
|
|
||||||
TWR: boolean;
|
TWR: boolean;
|
||||||
SKR: boolean;
|
SKR: boolean;
|
||||||
sceneries: string[];
|
sceneries: string[];
|
||||||
};
|
path: 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@ export interface ISceneryOnline {
|
|||||||
export interface ISceneryData {
|
export interface ISceneryData {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
abbr: string;
|
||||||
SUP: boolean;
|
SUP: boolean;
|
||||||
authors: string;
|
authors: string;
|
||||||
availability: string;
|
availability: string;
|
||||||
@@ -32,22 +33,5 @@ export interface ISceneryData {
|
|||||||
signalType: string;
|
signalType: string;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
// export interface ITrainData {
|
|
||||||
// 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 type TPanelMode = 'OrderListPanel' | 'OrderMessagePanel' | 'OrderTrainPickerPanel';
|
||||||
@@ -1,165 +1,56 @@
|
|||||||
export type TOrder = 'orderO' | 'orderS' | 'orderN';
|
export type TOrder = 'orderO' | 'orderS' | 'orderN';
|
||||||
|
|
||||||
export interface LocalStorageOrder {
|
export interface LocalStorageOrderLegacy {
|
||||||
id: string;
|
id: string;
|
||||||
orderType: TOrder;
|
orderType: TOrder;
|
||||||
orderBody: any;
|
orderBody: any;
|
||||||
orderFooter: any;
|
orderFooter: any;
|
||||||
createdAt?: number;
|
createdAt?: number;
|
||||||
updatedAt?: number;
|
updatedAt?: number;
|
||||||
|
orderVersion?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOrderN {
|
export interface IStorageOrderData {
|
||||||
header: {
|
id: string;
|
||||||
orderNo: string;
|
orderVersion: string;
|
||||||
trainNo: string;
|
createdAt?: number;
|
||||||
date: string;
|
updatedAt?: number;
|
||||||
};
|
orderData: IOrderData;
|
||||||
|
|
||||||
rows: [
|
|
||||||
{
|
|
||||||
enabled: boolean;
|
|
||||||
from: string;
|
|
||||||
to: string;
|
|
||||||
trackNo: string;
|
|
||||||
trackNo2: string;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: boolean;
|
|
||||||
option1: string;
|
|
||||||
option2: string;
|
|
||||||
option3: string;
|
|
||||||
signal1: string;
|
|
||||||
signal2: string;
|
|
||||||
signal3: string;
|
|
||||||
signalType: string;
|
|
||||||
checkbox: string;
|
|
||||||
direction1: string;
|
|
||||||
direction2: string;
|
|
||||||
trackNoFrom: string;
|
|
||||||
trackNoTo1: string;
|
|
||||||
trackNoTo2: string;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: boolean;
|
|
||||||
option1: string;
|
|
||||||
option2: string;
|
|
||||||
|
|
||||||
direction: string;
|
|
||||||
toKilometer: string;
|
|
||||||
trackNo: string;
|
|
||||||
untilHour: string;
|
|
||||||
untilMin: string;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: boolean;
|
|
||||||
trackNo: string;
|
|
||||||
optionStation: string;
|
|
||||||
stationName: string;
|
|
||||||
checkbox: string;
|
|
||||||
side: string;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: boolean;
|
|
||||||
trackNo: string;
|
|
||||||
direction: string;
|
|
||||||
stationType: string;
|
|
||||||
stationName: string;
|
|
||||||
on: string;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOrderS {
|
export interface IOrderData {
|
||||||
header: {
|
header: IOrderHeader;
|
||||||
orderNo: string;
|
instructions: IOrderInstruction[];
|
||||||
trainNo: string;
|
footer: IOrderFooter;
|
||||||
for: string;
|
|
||||||
date: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
rows: [
|
|
||||||
{
|
|
||||||
enabled: boolean;
|
|
||||||
option1: string;
|
|
||||||
optionSignal: string;
|
|
||||||
radio1: string;
|
|
||||||
signal1: string;
|
|
||||||
trackNo: string;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: boolean;
|
|
||||||
signalType: string;
|
|
||||||
signal1: string;
|
|
||||||
signal2: string;
|
|
||||||
signal3: string;
|
|
||||||
trackNo: string;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: boolean;
|
|
||||||
from: string;
|
|
||||||
to: string;
|
|
||||||
trackNo: string;
|
|
||||||
trainNo: string;
|
|
||||||
arrivedTo: string;
|
|
||||||
hour: string;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enabled: boolean;
|
|
||||||
content: string;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOrderO {
|
export interface IOrderHeader {
|
||||||
header: {
|
A: string;
|
||||||
orderNo: string;
|
B: string;
|
||||||
trainNo: string;
|
C: string;
|
||||||
date: string;
|
D: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
orderList: [
|
export interface IOrderFooter {
|
||||||
{
|
V: string;
|
||||||
name: string;
|
W: string;
|
||||||
from: string;
|
Y: string;
|
||||||
to: string;
|
Z: string;
|
||||||
vmax: string;
|
}
|
||||||
jo: boolean;
|
|
||||||
reason: string;
|
export interface IOrderFieldItem {
|
||||||
},
|
active: false;
|
||||||
{
|
values: Record<string, string>;
|
||||||
name: string;
|
}
|
||||||
from: string;
|
|
||||||
to: string;
|
export interface IOrderInstruction {
|
||||||
vmax: string;
|
key: string;
|
||||||
jo: boolean;
|
name: string;
|
||||||
reason: string;
|
active: boolean;
|
||||||
},
|
inputFields: Record<string, string>;
|
||||||
{
|
optionalFieldNames: string[];
|
||||||
name: string;
|
textDirectives: string[];
|
||||||
from: string;
|
|
||||||
to: string;
|
selectFields?: Record<string, Record<string, string[]>>;
|
||||||
vmax: string;
|
listFields?: IOrderFieldItem[];
|
||||||
jo: boolean;
|
|
||||||
reason: string;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: string;
|
|
||||||
from: string;
|
|
||||||
to: string;
|
|
||||||
vmax: string;
|
|
||||||
jo: boolean;
|
|
||||||
reason: string;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: string;
|
|
||||||
from: string;
|
|
||||||
to: string;
|
|
||||||
vmax: string;
|
|
||||||
jo: boolean;
|
|
||||||
reason: string;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
other: string;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
export function currentFormattedDate() {
|
|
||||||
return new Date().toLocaleDateString('pl-PL', { day: 'numeric', month: 'numeric', year: 'numeric' }) + 'r.';
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
// For use inside OrderS and OrderN
|
export const getOrderFullId = (orderNumber: number, sceneryHash: string) => {
|
||||||
|
return `RD-${orderNumber}-${sceneryHash}-${new Date().getUTCFullYear().toString().slice(2)}`;
|
||||||
|
};
|
||||||
|
|
||||||
export const handleOrderPlaceholders = (isRowEnabled: boolean, rowRef: HTMLTableElement) => {
|
export const handleOrderPlaceholders = (isRowEnabled: boolean, rowRef: HTMLTableElement) => {
|
||||||
rowRef.querySelectorAll('input[type="text"]').forEach((node) => {
|
rowRef.querySelectorAll('input[type="text"]').forEach((node) => {
|
||||||
if (!isRowEnabled) {
|
if (!isRowEnabled) {
|
||||||
@@ -13,8 +16,10 @@ export const handleOrderPlaceholders = (isRowEnabled: boolean, rowRef: HTMLTable
|
|||||||
if (!node.getAttribute('holder')) return;
|
if (!node.getAttribute('holder')) return;
|
||||||
const radioCheckedAttr = node.getAttribute('radio-checked');
|
const radioCheckedAttr = node.getAttribute('radio-checked');
|
||||||
|
|
||||||
if (radioCheckedAttr == null) return node.setAttribute('placeholder', node.getAttribute('holder')!);
|
if (radioCheckedAttr == null)
|
||||||
if (radioCheckedAttr == 'true') return node.setAttribute('placeholder', node.getAttribute('holder')!);
|
return node.setAttribute('placeholder', node.getAttribute('holder')!);
|
||||||
|
if (radioCheckedAttr == 'true')
|
||||||
|
return node.setAttribute('placeholder', node.getAttribute('holder')!);
|
||||||
if (node.getAttribute('placeholder') == null) return;
|
if (node.getAttribute('placeholder') == null) return;
|
||||||
|
|
||||||
node.setAttribute('holder', node.getAttribute('placeholder')!);
|
node.setAttribute('holder', node.getAttribute('placeholder')!);
|
||||||
@@ -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';
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,31 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- <OrderHelper v-if="store.helperModalOpen" /> -->
|
|
||||||
|
|
||||||
<div class="home">
|
<div class="home">
|
||||||
<div class="home_container">
|
<div class="home-container">
|
||||||
<div class="order_container">
|
<div class="order-container">
|
||||||
<SideBar />
|
<Order />
|
||||||
<OrderVue />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="message_container">
|
<div class="panel-container">
|
||||||
<div class="message_nav">
|
<div class="panel-nav">
|
||||||
<span v-for="(action, i) in navActions">
|
<button
|
||||||
<b v-if="i > 0">•</b>
|
key="OrderMessagePanel"
|
||||||
|
class="g-button"
|
||||||
|
:data-active="store.panelMode == 'OrderMessagePanel'"
|
||||||
|
@click="selectOrderMode('OrderMessagePanel')"
|
||||||
|
>
|
||||||
|
<MessageSquareTextIcon :size="20" />
|
||||||
|
{{ t(`navbar.OrderMessagePanel`) }}
|
||||||
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="g-button option"
|
key="OrderListPanel"
|
||||||
:data-active="store.orderMode == action.mode"
|
class="g-button"
|
||||||
@click="selectOrderMode(action.mode)"
|
:data-active="store.panelMode == 'OrderListPanel'"
|
||||||
>
|
@click="selectOrderMode('OrderListPanel')"
|
||||||
{{ action.value }}
|
>
|
||||||
</button>
|
<BookMarkedIcon :size="20" />
|
||||||
</span>
|
{{ t(`navbar.OrderListPanel`) }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
key="OrderTrainPickerPanel"
|
||||||
|
class="g-button"
|
||||||
|
:data-active="store.panelMode == 'OrderTrainPickerPanel'"
|
||||||
|
@click="selectOrderMode('OrderTrainPickerPanel')"
|
||||||
|
>
|
||||||
|
<TrainFrontIcon :size="20" />
|
||||||
|
{{ t(`navbar.OrderTrainPickerPanel`) }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<transition name="order-anim" mode="out-in">
|
<transition name="order-anim" mode="out-in">
|
||||||
<keep-alive>
|
<keep-alive>
|
||||||
<Component :is="orderModeComponent" />
|
<Component :is="panelComponent" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
@@ -33,71 +48,42 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import { computed } from 'vue';
|
||||||
import OrderVue from '../components/Order.vue';
|
|
||||||
import SideBar from '../components/SideBar.vue';
|
|
||||||
import OrderMessage from '../components/OrderMessage.vue';
|
|
||||||
import OrderList from '../components/OrderList.vue';
|
|
||||||
import { useStore } from '../store/store';
|
import { useStore } from '../store/store';
|
||||||
import OrderHelper from '../components/OrderHelper.vue';
|
import { useI18n } from 'vue-i18n';
|
||||||
import OrderTrainPicker from '../components/OrderTrainPicker.vue';
|
|
||||||
|
|
||||||
|
import Order from '../components/Order/Order.vue';
|
||||||
|
import OrderMessagePanel from '../components/Panels/OrderMessagePanel.vue';
|
||||||
|
import OrderListPanel from '../components/Panels/OrderListPanel.vue';
|
||||||
|
import OrderTrainPickerPanel from '../components/Panels/OrderTrainPickerPanel.vue';
|
||||||
|
import { TPanelMode } from '../types/dataTypes';
|
||||||
|
import { BookMarkedIcon, MessageSquareTextIcon, TrainFrontIcon } from 'lucide-vue-next';
|
||||||
|
|
||||||
export default defineComponent({
|
const { t } = useI18n();
|
||||||
components: { OrderVue, SideBar, OrderHelper },
|
const store = useStore();
|
||||||
|
|
||||||
data() {
|
function selectOrderMode(mode: TPanelMode) {
|
||||||
return {
|
store.panelMode = mode;
|
||||||
navActions: [
|
}
|
||||||
{
|
|
||||||
mode: 'OrderMessage',
|
|
||||||
value: 'TREŚĆ ROZKAZU',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mode: 'OrderList',
|
|
||||||
value: 'ZAPISANE ROZKAZY',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mode: 'OrderTrainPicker',
|
|
||||||
value: 'POCIĄGI',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
const panelComponent = computed(() => {
|
||||||
selectOrderMode(mode: string) {
|
switch (store.panelMode) {
|
||||||
this.store.orderMode = mode;
|
case 'OrderListPanel':
|
||||||
},
|
return OrderListPanel;
|
||||||
},
|
case 'OrderTrainPickerPanel':
|
||||||
|
return OrderTrainPickerPanel;
|
||||||
setup() {
|
case 'OrderMessagePanel':
|
||||||
return {
|
default:
|
||||||
store: useStore(),
|
return OrderMessagePanel;
|
||||||
};
|
}
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
orderModeComponent() {
|
|
||||||
switch (this.store.orderMode) {
|
|
||||||
case 'OrderMessage':
|
|
||||||
return OrderMessage;
|
|
||||||
case 'OrderList':
|
|
||||||
return OrderList;
|
|
||||||
case 'OrderTrainPicker':
|
|
||||||
return OrderTrainPicker;
|
|
||||||
default:
|
|
||||||
return OrderMessage;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@use '../styles/colors';
|
||||||
|
|
||||||
.home {
|
.home {
|
||||||
min-height: 100vh;
|
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -105,38 +91,90 @@ export default defineComponent({
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.home_container {
|
.home-container {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-wrap: wrap;
|
grid-template-columns: 800px 500px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 2em 1em;
|
gap: 2em 1em;
|
||||||
padding: 0.5em;
|
padding: 1em;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
height: calc(100vh - 5em);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1350px) {
|
||||||
|
grid-template-columns: auto;
|
||||||
|
padding: 1em 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
max-width: 800px;
|
||||||
|
|
||||||
|
@media screen and (max-width: 650px) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-container {
|
||||||
|
padding: 2px;
|
||||||
|
max-width: 800px;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto auto 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-nav {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25em;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-nav > button {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
min-width: 8em;
|
||||||
|
padding: 0.25em 0.5em;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 1px solid white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
bottom: -3px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
|
||||||
|
width: 0;
|
||||||
|
height: 3px;
|
||||||
|
|
||||||
|
transition: all 0.25s;
|
||||||
|
|
||||||
|
background-color: colors.$accentCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-active='true'] {
|
||||||
|
color: colors.$accentCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-active='true']::before {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@media screen and (max-width: 650px) {
|
|
||||||
padding-top: 5em;
|
|
||||||
padding-bottom: 5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.order_container {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 550px;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message_container {
|
|
||||||
width: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message_nav {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
declare module '*.vue' {
|
declare module '*.vue' {
|
||||||
import type { DefineComponent } from 'vue'
|
import type { DefineComponent } from 'vue';
|
||||||
const component: DefineComponent<{}, {}, any>
|
const component: DefineComponent<{}, {}, any>;
|
||||||
export default component
|
export default component;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,23 +2,34 @@ import { defineConfig } from 'vite';
|
|||||||
import vue from '@vitejs/plugin-vue';
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
|
||||||
import { VitePWA } from 'vite-plugin-pwa';
|
import { VitePWA } from 'vite-plugin-pwa';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
port: 8081,
|
port: 8081,
|
||||||
},
|
},
|
||||||
|
css: {
|
||||||
|
preprocessorOptions: {
|
||||||
|
scss: { additionalData: `@use '@/styles/global';`, silenceDeprecations: ['legacy-js-api'] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, 'src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
VitePWA({
|
VitePWA({
|
||||||
registerType: 'prompt',
|
registerType: 'prompt',
|
||||||
workbox: {
|
workbox: {
|
||||||
globPatterns: ['**/*.{js,css,html,png,svg,img}'],
|
globPatterns: ['**/*.{js,css,html,png,svg,img,woff2}'],
|
||||||
runtimeCaching: [
|
runtimeCaching: [
|
||||||
{
|
{
|
||||||
urlPattern: /^https:\/\/stacjownik-api-b9mrc\.ondigitalocean\.app\/api\/getSceneries/i,
|
urlPattern: /^https:\/\/stacjownik.spythere.eu\/\/api\/getSceneries/i,
|
||||||
handler: 'CacheFirst',
|
handler: 'CacheFirst',
|
||||||
options: {
|
options: {
|
||||||
cacheName: 'sceneries-data-cache',
|
cacheName: 'sceneries-cache',
|
||||||
expiration: {
|
expiration: {
|
||||||
maxEntries: 250,
|
maxEntries: 250,
|
||||||
maxAgeSeconds: 60 * 60 * 24 * 7, // <== 7 days
|
maxAgeSeconds: 60 * 60 * 24 * 7, // <== 7 days
|
||||||
@@ -31,9 +42,9 @@ export default defineConfig({
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
devOptions: {
|
devOptions: {
|
||||||
enabled: true,
|
// enabled: true,
|
||||||
|
suppressWarnings: true
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||