Merge do wersji 1.1.0
Wersja 1.1.0
@@ -0,0 +1,2 @@
|
|||||||
|
VITE_APP_API_URL=https://stacjownik-api-b9mrc.ondigitalocean.app/api
|
||||||
|
VITE_APP_SWDR_URL=https://api.td2.info.pl:9640
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"projects": {
|
"projects": {
|
||||||
"default": "genera-tor"
|
"default": "generator-td2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# This file was auto-generated by the Firebase CLI
|
||||||
|
# https://github.com/firebase/firebase-tools
|
||||||
|
|
||||||
|
name: Deploy to Firebase Hosting on merge
|
||||||
|
'on':
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
jobs:
|
||||||
|
build_and_deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: npm ci && npm run build
|
||||||
|
- uses: FirebaseExtended/action-hosting-deploy@v0
|
||||||
|
with:
|
||||||
|
repoToken: '${{ secrets.GITHUB_TOKEN }}'
|
||||||
|
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_GENERATOR_TD2 }}'
|
||||||
|
channelId: live
|
||||||
|
projectId: generator-td2
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# This file was auto-generated by the Firebase CLI
|
||||||
|
# https://github.com/firebase/firebase-tools
|
||||||
|
|
||||||
|
name: Deploy to Firebase Hosting on PR
|
||||||
|
'on': pull_request
|
||||||
|
jobs:
|
||||||
|
build_and_preview:
|
||||||
|
if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: npm ci && npm run build
|
||||||
|
- uses: FirebaseExtended/action-hosting-deploy@v0
|
||||||
|
with:
|
||||||
|
repoToken: '${{ secrets.GITHUB_TOKEN }}'
|
||||||
|
firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_GENERATOR_TD2 }}'
|
||||||
|
projectId: generator-td2
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
/dist
|
|
||||||
/dev-dist
|
/dev-dist
|
||||||
.log
|
.log
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<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>
|
||||||
|
After Width: | Height: | Size: 530 B |
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<browserconfig>
|
||||||
|
<msapplication>
|
||||||
|
<tile>
|
||||||
|
<square150x150logo src="/mstile-150x150.png"/>
|
||||||
|
<TileColor>#00aba9</TileColor>
|
||||||
|
</tile>
|
||||||
|
</msapplication>
|
||||||
|
</browserconfig>
|
||||||
|
After Width: | Height: | Size: 650 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,89 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Welcome to Firebase Hosting</title>
|
||||||
|
|
||||||
|
<!-- update the version number as needed -->
|
||||||
|
<script defer src="/__/firebase/9.14.0/firebase-app-compat.js"></script>
|
||||||
|
<!-- include only the Firebase features as you need -->
|
||||||
|
<script defer src="/__/firebase/9.14.0/firebase-auth-compat.js"></script>
|
||||||
|
<script defer src="/__/firebase/9.14.0/firebase-database-compat.js"></script>
|
||||||
|
<script defer src="/__/firebase/9.14.0/firebase-firestore-compat.js"></script>
|
||||||
|
<script defer src="/__/firebase/9.14.0/firebase-functions-compat.js"></script>
|
||||||
|
<script defer src="/__/firebase/9.14.0/firebase-messaging-compat.js"></script>
|
||||||
|
<script defer src="/__/firebase/9.14.0/firebase-storage-compat.js"></script>
|
||||||
|
<script defer src="/__/firebase/9.14.0/firebase-analytics-compat.js"></script>
|
||||||
|
<script defer src="/__/firebase/9.14.0/firebase-remote-config-compat.js"></script>
|
||||||
|
<script defer src="/__/firebase/9.14.0/firebase-performance-compat.js"></script>
|
||||||
|
<!--
|
||||||
|
initialize the SDK after all desired features are loaded, set useEmulator to false
|
||||||
|
to avoid connecting the SDK to running emulators.
|
||||||
|
-->
|
||||||
|
<script defer src="/__/firebase/init.js?useEmulator=true"></script>
|
||||||
|
|
||||||
|
<style media="screen">
|
||||||
|
body { background: #ECEFF1; color: rgba(0,0,0,0.87); font-family: Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; }
|
||||||
|
#message { background: white; max-width: 360px; margin: 100px auto 16px; padding: 32px 24px; border-radius: 3px; }
|
||||||
|
#message h2 { color: #ffa100; font-weight: bold; font-size: 16px; margin: 0 0 8px; }
|
||||||
|
#message h1 { font-size: 22px; font-weight: 300; color: rgba(0,0,0,0.6); margin: 0 0 16px;}
|
||||||
|
#message p { line-height: 140%; margin: 16px 0 24px; font-size: 14px; }
|
||||||
|
#message a { display: block; text-align: center; background: #039be5; text-transform: uppercase; text-decoration: none; color: white; padding: 16px; border-radius: 4px; }
|
||||||
|
#message, #message a { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); }
|
||||||
|
#load { color: rgba(0,0,0,0.4); text-align: center; font-size: 13px; }
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
body, #message { margin-top: 0; background: white; box-shadow: none; }
|
||||||
|
body { border-top: 16px solid #ffa100; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="message">
|
||||||
|
<h2>Welcome</h2>
|
||||||
|
<h1>Firebase Hosting Setup Complete</h1>
|
||||||
|
<p>You're seeing this because you've successfully setup Firebase Hosting. Now it's time to go build something extraordinary!</p>
|
||||||
|
<a target="_blank" href="https://firebase.google.com/docs/hosting/">Open Hosting Documentation</a>
|
||||||
|
</div>
|
||||||
|
<p id="load">Firebase SDK Loading…</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const loadEl = document.querySelector('#load');
|
||||||
|
// // 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
|
||||||
|
// // The Firebase SDK is initialized and available here!
|
||||||
|
//
|
||||||
|
// firebase.auth().onAuthStateChanged(user => { });
|
||||||
|
// firebase.database().ref('/path/to/ref').on('value', snapshot => { });
|
||||||
|
// firebase.firestore().doc('/foo/bar').get().then(() => { });
|
||||||
|
// firebase.functions().httpsCallable('yourFunction')().then(() => { });
|
||||||
|
// firebase.messaging().requestPermission().then(() => { });
|
||||||
|
// firebase.storage().ref('/path/to/ref').getDownloadURL().then(() => { });
|
||||||
|
// firebase.analytics(); // call to activate
|
||||||
|
// firebase.analytics().logEvent('tutorial_completed');
|
||||||
|
// firebase.performance(); // call to activate
|
||||||
|
//
|
||||||
|
// // 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
|
||||||
|
|
||||||
|
try {
|
||||||
|
let app = firebase.app();
|
||||||
|
let features = [
|
||||||
|
'auth',
|
||||||
|
'database',
|
||||||
|
'firestore',
|
||||||
|
'functions',
|
||||||
|
'messaging',
|
||||||
|
'storage',
|
||||||
|
'analytics',
|
||||||
|
'remoteConfig',
|
||||||
|
'performance',
|
||||||
|
].filter(feature => typeof app[feature] === 'function');
|
||||||
|
loadEl.textContent = `Firebase SDK loaded with ${features.join(', ')}`;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
loadEl.textContent = 'Error loading the Firebase SDK, check the console.';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"name":"genera-tor","short_name":"genera-tor","start_url":"/","display":"standalone","background_color":"#ffffff","lang":"en","scope":"/"}
|
||||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1 @@
|
|||||||
|
if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js', { scope: '/' })})}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?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>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
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,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "genera-tor",
|
"name": "genera-tor",
|
||||||
"version": "1.0.2",
|
"version": "1.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --port 8080",
|
"dev": "vite --port 8080",
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"axios": "^1.1.3",
|
||||||
"pinia": "^2.0.14",
|
"pinia": "^2.0.14",
|
||||||
"vue": "^3.2.37",
|
"vue": "^3.2.37",
|
||||||
"vue-i18n": "9",
|
"vue-i18n": "9",
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
<div id="app_wrapper">
|
<div id="app_wrapper">
|
||||||
<router-view />
|
<router-view />
|
||||||
|
|
||||||
|
<transition name="slide-anim">
|
||||||
|
<div v-if="needRefresh" class="update-prompt" @click="updateServiceWorker(true)">Nowa wersja GeneraTORa dostępna! <u>Kliknij, aby odświeżyć aplikację!</u></div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
© <a href="https://td2.info.pl/profile/?u=20777">Spythere</a> {{ new Date().getUTCFullYear() }} | v.{{
|
© <a href="https://td2.info.pl/profile/?u=20777">Spythere</a> {{ new Date().getUTCFullYear() }} | v.{{
|
||||||
appVersion
|
appVersion
|
||||||
@@ -11,24 +15,43 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { useRegisterSW } from 'virtual:pwa-register/vue';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import packageInfo from '../package.json';
|
import packageInfo from '../package.json';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
const { offlineReady, needRefresh, updateServiceWorker } = useRegisterSW({
|
||||||
|
immediate: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
offlineReady,
|
||||||
|
needRefresh,
|
||||||
|
updateServiceWorker,
|
||||||
|
};
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
appVersion: packageInfo.version,
|
appVersion: packageInfo.version,
|
||||||
|
needRefreshTest: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
document.title = `GeneraTOR ${this.appVersion}`
|
document.title = `GeneraTOR ${this.appVersion}`;
|
||||||
}
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.needRefreshTest = true;
|
||||||
|
}, 500);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import './styles/global.scss';
|
@import './styles/global.scss';
|
||||||
|
@import './styles/anims.scss';
|
||||||
|
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
color: white;
|
color: white;
|
||||||
@@ -36,6 +59,22 @@ export default defineComponent({
|
|||||||
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;
|
||||||
@@ -43,7 +82,7 @@ footer {
|
|||||||
|
|
||||||
@media screen and (max-width: 500px) {
|
@media screen and (max-width: 500px) {
|
||||||
#app {
|
#app {
|
||||||
font-size: calc(1vw + 0.5rem);
|
font-size: calc(1vw + 0.65rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
.flex-row {
|
.flex-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-around;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
|
|||||||
@@ -54,8 +54,9 @@ export default defineComponent({
|
|||||||
if (!order) return;
|
if (!order) return;
|
||||||
|
|
||||||
this.removeLocalOrder(order);
|
this.removeLocalOrder(order);
|
||||||
|
|
||||||
this.localOrderList = this.localOrderList.filter((o) => o.id != order.id);
|
this.localOrderList = this.localOrderList.filter((o) => o.id != order.id);
|
||||||
|
|
||||||
|
if (this.localOrderList.length == 0) this.saveOrderSetting('orderCount', 0);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -104,22 +105,26 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.order-list {
|
.order-list {
|
||||||
padding: 1em;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
max-height: 750px;
|
overflow: hidden;
|
||||||
height: 80vh;
|
|
||||||
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
background-color: #222;
|
||||||
|
padding: 1em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
|
|||||||
@@ -18,6 +18,29 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</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>Aktualizuj numer rozkazu po skopiowaniu</span>
|
||||||
|
</label>
|
||||||
|
<label for="save-increment" class="g-checkbox">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="save-increment"
|
||||||
|
id="save-increment"
|
||||||
|
v-model="incrementOnSave"
|
||||||
|
@change="onCheckboxChange"
|
||||||
|
/>
|
||||||
|
<span>Aktualizuj numer rozkazu po zapisaniu</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<transition name="monit-anim">
|
<transition name="monit-anim">
|
||||||
<div class="action_monit" v-if="actionMonit" v-html="actionMonit"></div>
|
<div class="action_monit" v-if="actionMonit" v-html="actionMonit"></div>
|
||||||
</transition>
|
</transition>
|
||||||
@@ -42,6 +65,9 @@ export default defineComponent({
|
|||||||
saveIcon,
|
saveIcon,
|
||||||
actionMonit: '',
|
actionMonit: '',
|
||||||
monitTimeout: undefined as number | undefined,
|
monitTimeout: undefined as number | undefined,
|
||||||
|
|
||||||
|
incrementOnSave: true,
|
||||||
|
incrementOnCopy: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -51,6 +77,11 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.incrementOnSave = this.getOrderSetting('save-increment') === 'false' ? false : true;
|
||||||
|
this.incrementOnCopy = this.getOrderSetting('copy-increment') === 'false' ? false : true;
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
fullOrderMessage() {
|
fullOrderMessage() {
|
||||||
return this.store.orderMessage + this.store.footerMessage;
|
return this.store.orderMessage + this.store.footerMessage;
|
||||||
@@ -58,6 +89,13 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
onCheckboxChange(e: Event) {
|
||||||
|
const checkbox = e.target as HTMLInputElement;
|
||||||
|
console.log(checkbox.id, checkbox.checked);
|
||||||
|
|
||||||
|
this.saveOrderSetting(checkbox.id, checkbox.checked);
|
||||||
|
},
|
||||||
|
|
||||||
showActionMonit(text: string) {
|
showActionMonit(text: string) {
|
||||||
if (this.monitTimeout) {
|
if (this.monitTimeout) {
|
||||||
this.actionMonit = '';
|
this.actionMonit = '';
|
||||||
@@ -81,6 +119,12 @@ export default defineComponent({
|
|||||||
}, 5000);
|
}, 5000);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
incrementOrderNo() {
|
||||||
|
const order = this.store[this.store.chosenOrderType];
|
||||||
|
|
||||||
|
order.header.orderNo = (Number(order.header.orderNo) + 1).toString();
|
||||||
|
},
|
||||||
|
|
||||||
copyMessage() {
|
copyMessage() {
|
||||||
if (!navigator.clipboard)
|
if (!navigator.clipboard)
|
||||||
return this.showActionMonit(
|
return this.showActionMonit(
|
||||||
@@ -90,8 +134,14 @@ export default defineComponent({
|
|||||||
const hasAtLeastOneRow = /(\[ \d \])/g.test(this.fullOrderMessage);
|
const hasAtLeastOneRow = /(\[ \d \])/g.test(this.fullOrderMessage);
|
||||||
const hasAllInputsFilled = !/_/g.test(this.store.orderMessage);
|
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 (!hasAllInputsFilled)
|
||||||
if (!hasAtLeastOneRow) return this.showActionMonit(`<span class="text--warn">Dodaj co najmniej jedną działkę rozkazu przed jego skopiowaniem!</span>`);
|
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();
|
const fieldsToCorrect = this.verifyOrderFields();
|
||||||
|
|
||||||
@@ -104,6 +154,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
navigator.clipboard.writeText(this.fullOrderMessage);
|
navigator.clipboard.writeText(this.fullOrderMessage);
|
||||||
|
|
||||||
|
if (this.incrementOnCopy) this.incrementOrderNo();
|
||||||
|
|
||||||
this.showActionMonit(
|
this.showActionMonit(
|
||||||
'<b class="text--accent">Skopiowano!</b> Możesz teraz wkleić treść rozkazu na czacie symulatora!'
|
'<b class="text--accent">Skopiowano!</b> Możesz teraz wkleić treść rozkazu na czacie symulatora!'
|
||||||
);
|
);
|
||||||
@@ -123,6 +175,8 @@ export default defineComponent({
|
|||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
this.showActionMonit('Zapisano treść <b class="text--accent">rozkazu</b> w pamięci przeglądarki!');
|
this.showActionMonit('Zapisano treść <b class="text--accent">rozkazu</b> w pamięci przeglądarki!');
|
||||||
|
|
||||||
|
if (this.incrementOnSave) this.incrementOrderNo();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -153,8 +207,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.order-message {
|
.order-message {
|
||||||
padding: 1em;
|
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
@@ -203,6 +255,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message_checkboxes {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.action_monit {
|
.action_monit {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 1.5em;
|
padding: 1.5em;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<section class="header" ref="header">
|
<section class="header" ref="header">
|
||||||
<h2 class="flex-center">
|
<h2 class="flex-center">
|
||||||
Rozkaz pisemny "N" nr
|
Rozkaz pisemny "N" nr
|
||||||
<input type="text" v-model="order.header.orderNo" placeholder="nr rozkazu" />
|
<input type="number" v-model="order.header.orderNo" placeholder="nr rozkazu" min="1" />
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex-row">
|
<div class="flex-row">
|
||||||
dla pociągu nr <input type="text" v-model="order.header.trainNo" placeholder="nr pociągu" /> dnia
|
dla pociągu nr <input type="text" v-model="order.header.trainNo" placeholder="nr pociągu" /> dnia
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
<section class="order_header">
|
<section class="order_header">
|
||||||
<h2 class="flex-center" style="padding: 0 0.5em">
|
<h2 class="flex-center" style="padding: 0 0.5em">
|
||||||
Rozkaz pisemny "O" nr
|
Rozkaz pisemny "O" nr
|
||||||
<input type="text" v-model="order.header.orderNo" />
|
<input type="number" v-model="order.header.orderNo" placeholder="nr rozkazu" min="1" />
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="flex-row" style="padding: 0 0.5em">
|
<div class="flex-row" style="padding: 0 0.5em">
|
||||||
dla pociągu nr <input type="text" v-model="order.header.trainNo" /> dnia
|
dla pociągu nr <input type="text" v-model="order.header.trainNo" placeholder="nr pociągu" /> dnia
|
||||||
<input type="text" v-model="order.header.date" />
|
<input type="text" v-model="order.header.date" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<section class="header">
|
<section class="header">
|
||||||
<h2 class="flex-center">
|
<h2 class="flex-center">
|
||||||
Rozkaz pisemny "S" nr
|
Rozkaz pisemny "S" nr
|
||||||
<input type="text" v-model="order.header.orderNo" placeholder="nr rozkazu" />
|
<input type="number" v-model="order.header.orderNo" placeholder="nr rozkazu" min="1" />
|
||||||
</h2>
|
</h2>
|
||||||
<div class="flex-row">
|
<div class="flex-row">
|
||||||
dla
|
dla
|
||||||
@@ -209,7 +209,7 @@
|
|||||||
<td ref="row-4">
|
<td ref="row-4">
|
||||||
Inne:
|
Inne:
|
||||||
<br />
|
<br />
|
||||||
<textarea id="" cols="30" rows="10" v-model="order.rows[3].content" placeholder="Np.: "></textarea>
|
<textarea id="" cols="30" rows="10" v-model="order.rows[3].content"></textarea>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -304,7 +304,7 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
activated() {
|
activated() {
|
||||||
this.generateMessage();
|
this.generateMessage();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -335,7 +335,7 @@ activated() {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
generateMessage() {
|
generateMessage() {
|
||||||
let message = this.rowMethods[0]();
|
let message = this.rowMethods[0]();
|
||||||
|
|
||||||
for (let i = 0; i < 4; i++) {
|
for (let i = 0; i < 4; i++) {
|
||||||
|
|||||||
@@ -0,0 +1,309 @@
|
|||||||
|
<template>
|
||||||
|
<div class="order-train-picker">
|
||||||
|
<div class="options">
|
||||||
|
<label for="dispatcher-select">
|
||||||
|
<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>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="scenery-select">
|
||||||
|
<select
|
||||||
|
name="scenery-select"
|
||||||
|
id="scenery-select"
|
||||||
|
v-model="selectedSceneryName"
|
||||||
|
:disabled="sceneryNameList.length == 0"
|
||||||
|
>
|
||||||
|
<option :value="null" disabled>Sceneria</option>
|
||||||
|
<option :value="sceneryName" v-for="sceneryName in sceneryNameList">
|
||||||
|
{{ sceneryName }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="checkpoint-select">
|
||||||
|
<select
|
||||||
|
name="checkpoint-select"
|
||||||
|
id="checkpoint-select"
|
||||||
|
v-model="selectedCheckpointName"
|
||||||
|
:disabled="sceneryNameList.length == 0"
|
||||||
|
>
|
||||||
|
<option :value="null" disabled>Posterunek</option>
|
||||||
|
<option :value="cp" v-for="cp in checkpointNameList">
|
||||||
|
{{ cp }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label for="fill-checkpoint" class="g-checkbox">
|
||||||
|
<input type="checkbox" name="fill-checkpoint" id="fill-checkpoint" v-model="fillCheckpointName" />
|
||||||
|
<span> Uzupełniaj skrót post.</span>
|
||||||
|
</label>
|
||||||
|
</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, currentFormattedHours, currentFormattedMinutes } 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,
|
||||||
|
selectedCheckpointName: null as string | null,
|
||||||
|
|
||||||
|
fillCheckpointName: false,
|
||||||
|
|
||||||
|
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];
|
||||||
|
},
|
||||||
|
|
||||||
|
selectedSceneryName() {
|
||||||
|
this.selectedCheckpointName = this.checkpointNameList.length == 0 ? null : this.checkpointNameList[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));
|
||||||
|
},
|
||||||
|
|
||||||
|
checkpointNameList() {
|
||||||
|
if (!this.selectedSceneryName) return [];
|
||||||
|
|
||||||
|
const name = this.selectedSceneryName;
|
||||||
|
const checkpoints = this.sceneriesData.find(
|
||||||
|
(s) => s.name.toLocaleLowerCase() == name.toLocaleLowerCase()
|
||||||
|
)?.checkpoints;
|
||||||
|
|
||||||
|
if (!checkpoints || checkpoints.length == 0) return [name];
|
||||||
|
|
||||||
|
return checkpoints.split(';');
|
||||||
|
},
|
||||||
|
|
||||||
|
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.selectedCheckpointName?.split(',')[0] || this.selectedSceneryName;
|
||||||
|
this.store.orderFooter.hour = currentFormattedHours();
|
||||||
|
this.store.orderFooter.minutes = currentFormattedMinutes();
|
||||||
|
|
||||||
|
if (this.fillCheckpointName)
|
||||||
|
this.store.orderFooter.checkpointName = this.store.orderFooter.stationName.slice(0, 2);
|
||||||
|
|
||||||
|
this.store.orderMode = 'OrderMessage';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../styles/global.scss';
|
||||||
|
|
||||||
|
.order-train-picker {
|
||||||
|
height: 90vh;
|
||||||
|
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1em;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
label {
|
||||||
|
width: 45%;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
border: 2px solid white;
|
||||||
|
color: white;
|
||||||
|
font-size: 1em;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.15em;
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
|
||||||
@@ -63,16 +63,6 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../styles/global.scss';
|
@import '../styles/global.scss';
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
z-index: 999;
|
|
||||||
|
|
||||||
transform: translate(-100%, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar_content {
|
.sidebar_content {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: repeat(3, 1fr);
|
grid-template-rows: repeat(3, 1fr);
|
||||||
@@ -137,14 +127,6 @@ button.option-save {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 650px) {
|
@media screen and (max-width: 650px) {
|
||||||
.sidebar {
|
|
||||||
left: 50%;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
transform: translate(-50%, -100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar_content {
|
.sidebar_content {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ 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');
|
createApp(App).use(router).use(createPinia()).mount('#app');
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,18 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
saveOrderSetting(key: string, value: string | number | boolean) {
|
||||||
|
window.localStorage.setItem(key, value.toString());
|
||||||
|
},
|
||||||
|
|
||||||
|
getOrderSetting(key: string) {
|
||||||
|
return window.localStorage.getItem(key);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeOrderSetting(key: string) {
|
||||||
|
window.localStorage.removeItem(key);
|
||||||
|
},
|
||||||
|
|
||||||
saveLocalOrder() {
|
saveLocalOrder() {
|
||||||
let orderObj: LocalStorageOrder = {
|
let orderObj: LocalStorageOrder = {
|
||||||
id: '',
|
id: '',
|
||||||
@@ -120,3 +132,4 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { IOrderN, IOrderO, IOrderS, TOrder } from '../types/orderTypes';
|
import { IOrderN, IOrderO, IOrderS, TOrder } from '../types/orderTypes';
|
||||||
|
import { currentFormattedDate, currentFormattedHours, currentFormattedMinutes } from '../utils/dateUtils';
|
||||||
|
|
||||||
export const useStore = defineStore('store', {
|
export const useStore = defineStore('store', {
|
||||||
state: () => {
|
state: () => {
|
||||||
@@ -14,8 +15,8 @@ export const useStore = defineStore('store', {
|
|||||||
orderFooter: {
|
orderFooter: {
|
||||||
stationName: '',
|
stationName: '',
|
||||||
checkpointName: '',
|
checkpointName: '',
|
||||||
hour: new Date().toLocaleTimeString('pl-PL', { hour: '2-digit' }),
|
hour: currentFormattedHours(),
|
||||||
minutes: new Date().toLocaleTimeString('pl-PL', { minute: '2-digit' }),
|
minutes: currentFormattedMinutes(),
|
||||||
dispatcherName: '',
|
dispatcherName: '',
|
||||||
secondaryDispatcherName: '',
|
secondaryDispatcherName: '',
|
||||||
},
|
},
|
||||||
@@ -27,7 +28,7 @@ export const useStore = defineStore('store', {
|
|||||||
header: {
|
header: {
|
||||||
orderNo: '1',
|
orderNo: '1',
|
||||||
trainNo: '',
|
trainNo: '',
|
||||||
date: new Date().toLocaleDateString('pl-PL', { day: 'numeric', month: 'numeric', year: 'numeric' }) + "r.",
|
date: currentFormattedDate(),
|
||||||
},
|
},
|
||||||
|
|
||||||
orderList: [
|
orderList: [
|
||||||
@@ -79,7 +80,7 @@ export const useStore = defineStore('store', {
|
|||||||
header: {
|
header: {
|
||||||
orderNo: '1',
|
orderNo: '1',
|
||||||
trainNo: '',
|
trainNo: '',
|
||||||
date: new Date().toLocaleDateString('pl-PL', { day: 'numeric', month: 'numeric', year: 'numeric' }) + "r.",
|
date: currentFormattedDate(),
|
||||||
},
|
},
|
||||||
|
|
||||||
rows: [
|
rows: [
|
||||||
@@ -141,7 +142,7 @@ export const useStore = defineStore('store', {
|
|||||||
orderNo: '1',
|
orderNo: '1',
|
||||||
trainNo: '',
|
trainNo: '',
|
||||||
for: 'pociągu',
|
for: 'pociągu',
|
||||||
date: new Date().toLocaleDateString('pl-PL', { day: 'numeric', month: 'numeric', year: 'numeric' }) + "r.",
|
date: currentFormattedDate(),
|
||||||
},
|
},
|
||||||
|
|
||||||
rows: [
|
rows: [
|
||||||
@@ -183,5 +184,3 @@ export const useStore = defineStore('store', {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
.slide-anim {
|
||||||
|
&-enter-active,
|
||||||
|
&-leave-active {
|
||||||
|
transition: all 125ms ease;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-enter-from,
|
||||||
|
&-leave-to {
|
||||||
|
transform: translateY(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -143,3 +143,46 @@ ul {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checkbox
|
||||||
|
label.g-checkbox {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0.25em 0;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #aaa;
|
||||||
|
|
||||||
|
span {
|
||||||
|
transition: color 125ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
span::before {
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
width: 1ch;
|
||||||
|
height: 1ch;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
background-color: greenyellow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
export declare module ApiSWDR {
|
||||||
|
export interface IStationsOnline {
|
||||||
|
success: boolean;
|
||||||
|
respCode: number;
|
||||||
|
message: IStationsOnlineMessage[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IStationsOnlineMessage {
|
||||||
|
dispatcherId: number;
|
||||||
|
dispatcherName: string;
|
||||||
|
dispatcherIsSupporter: boolean;
|
||||||
|
stationName: string;
|
||||||
|
stationHash: string;
|
||||||
|
region: string;
|
||||||
|
maxUsers: number;
|
||||||
|
currentUsers: number;
|
||||||
|
spawn: number;
|
||||||
|
lastSeen: any;
|
||||||
|
dispatcherExp: number;
|
||||||
|
nameFromHeader: string;
|
||||||
|
spawnString: string;
|
||||||
|
networkConnectionString: string;
|
||||||
|
isOnline: number;
|
||||||
|
dispatcherRate: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// export interface ITrainsOnline {
|
||||||
|
// success: boolean;
|
||||||
|
// respCode: number;
|
||||||
|
// message: ITrainsOnlineMessage[];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export interface ITrainsOnlineMessage {
|
||||||
|
// trainNo: number;
|
||||||
|
// driverId: number;
|
||||||
|
// driverName: string;
|
||||||
|
// driverIsSupporter: boolean;
|
||||||
|
// dataSignal: string;
|
||||||
|
// dataSceneryConnection: string;
|
||||||
|
// dataDistance: number;
|
||||||
|
// dataCon: string;
|
||||||
|
// dataSpeed: number;
|
||||||
|
// dataMass: number;
|
||||||
|
// dataLength: number;
|
||||||
|
// region: string;
|
||||||
|
// isOnline: number;
|
||||||
|
// lastSeen: number;
|
||||||
|
// station?: ISceneryData;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare module ApiStacjownik {
|
||||||
|
export interface IActiveTrain {
|
||||||
|
trainNo: number;
|
||||||
|
|
||||||
|
mass: number;
|
||||||
|
length: number;
|
||||||
|
speed: number;
|
||||||
|
|
||||||
|
signal: string;
|
||||||
|
distance: number;
|
||||||
|
connectedTrack: string;
|
||||||
|
stockString: string;
|
||||||
|
|
||||||
|
driverName: string;
|
||||||
|
driverId: number;
|
||||||
|
driverIsSupporter: boolean;
|
||||||
|
|
||||||
|
currentStationName: string;
|
||||||
|
currentStationHash?: string;
|
||||||
|
|
||||||
|
online: boolean;
|
||||||
|
lastSeen: number;
|
||||||
|
|
||||||
|
region: string;
|
||||||
|
|
||||||
|
timetable?: {
|
||||||
|
timetableId: number;
|
||||||
|
category: string;
|
||||||
|
route: string;
|
||||||
|
stopList: IActiveTrainStop[];
|
||||||
|
TWR: boolean;
|
||||||
|
SKR: boolean;
|
||||||
|
sceneries: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
isTimeout: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IActiveTrainStop {
|
||||||
|
stopName: string;
|
||||||
|
stopNameRAW: string;
|
||||||
|
stopType: string;
|
||||||
|
stopDistance: number;
|
||||||
|
pointId: number;
|
||||||
|
|
||||||
|
mainStop: boolean;
|
||||||
|
|
||||||
|
arrivalLine: string;
|
||||||
|
arrivalTimestamp: number;
|
||||||
|
arrivalRealTimestamp: number;
|
||||||
|
arrivalDelay: number;
|
||||||
|
|
||||||
|
departureLine: string;
|
||||||
|
departureTimestamp: number;
|
||||||
|
departureRealTimestamp: number;
|
||||||
|
departureDelay: number;
|
||||||
|
|
||||||
|
comments?: any;
|
||||||
|
|
||||||
|
beginsHere: boolean;
|
||||||
|
terminatesHere: boolean;
|
||||||
|
confirmed: boolean;
|
||||||
|
stopped: boolean;
|
||||||
|
stopTime: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
export interface ISceneryOnline {
|
||||||
|
dispatcherId: number;
|
||||||
|
dispatcherName: string;
|
||||||
|
dispatcherIsSupporter: boolean;
|
||||||
|
stationName: string;
|
||||||
|
stationHash: string;
|
||||||
|
region: string;
|
||||||
|
maxUsers: number;
|
||||||
|
currentUsers: number;
|
||||||
|
spawn: number;
|
||||||
|
lastSeen: any;
|
||||||
|
dispatcherExp: number;
|
||||||
|
nameFromHeader: string;
|
||||||
|
spawnString: string;
|
||||||
|
networkConnectionString: string;
|
||||||
|
isOnline: number;
|
||||||
|
dispatcherRate: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISceneryData {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
SUP: boolean;
|
||||||
|
authors: string;
|
||||||
|
availability: string;
|
||||||
|
checkpoints: string;
|
||||||
|
controlType: string;
|
||||||
|
lines: string;
|
||||||
|
project: string;
|
||||||
|
reqLevel: number;
|
||||||
|
routes: string;
|
||||||
|
signalType: 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;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export function currentFormattedDate() {
|
||||||
|
return new Date().toLocaleDateString('pl-PL', { day: 'numeric', month: 'numeric', year: 'numeric' }) + 'r.';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function currentFormattedMinutes() {
|
||||||
|
return new Date().toLocaleTimeString('pl-PL', { minute: '2-digit' });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function currentFormattedHours() {
|
||||||
|
return new Date().toLocaleTimeString('pl-PL', { hour: '2-digit' });
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ import OrderMessage from '../components/OrderMessage.vue';
|
|||||||
import OrderList from '../components/OrderList.vue';
|
import OrderList from '../components/OrderList.vue';
|
||||||
import { useStore } from '../store/store';
|
import { useStore } from '../store/store';
|
||||||
import OrderHelper from '../components/OrderHelper.vue';
|
import OrderHelper from '../components/OrderHelper.vue';
|
||||||
|
import OrderTrainPicker from '../components/OrderTrainPicker.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { OrderVue, SideBar, OrderHelper },
|
components: { OrderVue, SideBar, OrderHelper },
|
||||||
@@ -56,6 +57,10 @@ export default defineComponent({
|
|||||||
mode: 'OrderList',
|
mode: 'OrderList',
|
||||||
value: 'ZAPISANE ROZKAZY',
|
value: 'ZAPISANE ROZKAZY',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
mode: 'OrderTrainPicker',
|
||||||
|
value: 'POCIĄGI',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -79,6 +84,8 @@ export default defineComponent({
|
|||||||
return OrderMessage;
|
return OrderMessage;
|
||||||
case 'OrderList':
|
case 'OrderList':
|
||||||
return OrderList;
|
return OrderList;
|
||||||
|
case 'OrderTrainPicker':
|
||||||
|
return OrderTrainPicker;
|
||||||
default:
|
default:
|
||||||
return OrderMessage;
|
return OrderMessage;
|
||||||
}
|
}
|
||||||
@@ -108,26 +115,41 @@ export default defineComponent({
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@media screen and (max-width: 650px) {
|
@media screen and (max-width: 650px) {
|
||||||
padding-top: 5em;
|
padding: 1em 0.5em;
|
||||||
padding-bottom: 5em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.order_container {
|
.order_container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 550px;
|
max-width: 600px;
|
||||||
|
|
||||||
position: relative;
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
|
||||||
|
@media screen and (max-width: 650px) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.message_container {
|
.message_container {
|
||||||
width: 500px;
|
width: 500px;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
height: 95vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message_nav {
|
.message_nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
margin-bottom: 2em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,30 @@ import { VitePWA } from 'vite-plugin-pwa';
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
port: 8081
|
port: 8081,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
VitePWA({
|
VitePWA({
|
||||||
registerType: 'autoUpdate',
|
registerType: 'prompt',
|
||||||
workbox: {
|
workbox: {
|
||||||
globPatterns: ['**/*.{js,css,html,png,svg,img}'],
|
globPatterns: ['**/*.{js,css,html,png,svg,img}'],
|
||||||
|
runtimeCaching: [
|
||||||
|
{
|
||||||
|
urlPattern: /^https:\/\/stacjownik-api-b9mrc\.ondigitalocean\.app\/api\/getSceneries/i,
|
||||||
|
handler: 'CacheFirst',
|
||||||
|
options: {
|
||||||
|
cacheName: 'sceneries-data-cache',
|
||||||
|
expiration: {
|
||||||
|
maxEntries: 250,
|
||||||
|
maxAgeSeconds: 60 * 60 * 24 * 7, // <== 7 days
|
||||||
|
},
|
||||||
|
cacheableResponse: {
|
||||||
|
statuses: [0, 200],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
devOptions: {
|
devOptions: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -20,3 +36,4 @@ export default defineConfig({
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||