Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c09fc81886 | |||
| 30f72d518d | |||
| 9b86e07152 | |||
| 4e0fb5dc01 | |||
| a392991030 | |||
| ff7ca27fe6 | |||
| 94cd7aaa60 | |||
| 843289d8d7 | |||
| 66cae68e19 | |||
| b38e50396a | |||
| 7888e59117 | |||
| 46e700583d | |||
| fc56c38c45 | |||
| 9594e2c21a | |||
| a8bab5283b | |||
| 1cc799706c | |||
| 5ee8f72652 | |||
| 942f883b91 | |||
| 54b47d44e5 | |||
| f9aaf21f7a | |||
| d79705ca5c | |||
| 55c64d5f0a | |||
| 4ca1c7bb9c | |||
| abc8fda98e | |||
| aaec23d210 | |||
| 0af7b68138 | |||
| ae24eaf8e4 | |||
| f73a07daee | |||
| 89f5bf2e95 | |||
| 8137c1ff95 | |||
| 4b0d9b887e | |||
| 506064cf9a | |||
| 825e25434a | |||
| 32c601d50a | |||
| b88a96237e | |||
| 6c724440d7 | |||
| 71016e63bb | |||
| fb85352ce3 |
@@ -1,6 +1,7 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
/dev-dist
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
||||
@@ -1,54 +1,48 @@
|
||||
<!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" />
|
||||
|
||||
<meta name="keywords" content="Stacjownik, TD2, Train Driver 2, stacjownik-td2" />
|
||||
<meta name="description" content="Automatycznie odświeżana strona wyświetlająca stacje w Train Driver 2!" />
|
||||
|
||||
<title>Stacjownik</title>
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
||||
<meta name="msapplication-TileColor" content="#da532c" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
|
||||
<link rel="icon" href="favicon-64.png" sizes="64x64" type="image/png" />
|
||||
<link rel="icon" href="favicon-32.png" sizes="32x32" type="image/png" />
|
||||
<link rel="icon" href="favicon-62.png" sizes="62x62" type="image/png" />
|
||||
<link rel="icon" href="favicon-16.png" sizes="16x16" type="image/png" />
|
||||
<link rel="icon" href="favicon.ico" />
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;700&display=swap" rel="stylesheet" />
|
||||
|
||||
<script src="https://www.gstatic.com/firebasejs/8.1.1/firebase-app.js"></script>
|
||||
|
||||
<script>
|
||||
const firebaseConfig = {
|
||||
apiKey: 'AIzaSyBI36X2-p7vU1flxoJdCEc0noByyTe1mpw',
|
||||
authDomain: 'stacjownik-td2.firebaseapp.com',
|
||||
databaseURL: 'https://stacjownik-td2.firebaseio.com',
|
||||
projectId: 'stacjownik-td2',
|
||||
storageBucket: 'stacjownik-td2.appspot.com',
|
||||
};
|
||||
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<strong
|
||||
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please
|
||||
enable it to continue.</strong
|
||||
>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
<!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" />
|
||||
|
||||
<meta name="keywords" content="Stacjownik, TD2, Train Driver 2, stacjownik-td2" />
|
||||
<meta name="description" content="Automatycznie odświeżana strona wyświetlająca stacje w Train Driver 2!" />
|
||||
|
||||
<title>Stacjownik</title>
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
||||
<meta name="msapplication-TileColor" content="#da532c" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
|
||||
<link rel="icon" href="favicon-64.png" sizes="64x64" type="image/png" />
|
||||
<link rel="icon" href="favicon-32.png" sizes="32x32" type="image/png" />
|
||||
<link rel="icon" href="favicon-62.png" sizes="62x62" type="image/png" />
|
||||
<link rel="icon" href="favicon-16.png" sizes="16x16" type="image/png" />
|
||||
<link rel="icon" href="favicon.ico" />
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;700&display=swap" rel="stylesheet" />
|
||||
|
||||
<script src="https://www.gstatic.com/firebasejs/8.1.1/firebase-app.js"></script>
|
||||
|
||||
<script>
|
||||
const firebaseConfig = {
|
||||
apiKey: 'AIzaSyBI36X2-p7vU1flxoJdCEc0noByyTe1mpw',
|
||||
authDomain: 'stacjownik-td2.firebaseapp.com',
|
||||
databaseURL: 'https://stacjownik-td2.firebaseio.com',
|
||||
projectId: 'stacjownik-td2',
|
||||
storageBucket: 'stacjownik-td2.appspot.com',
|
||||
};
|
||||
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,41 +1,35 @@
|
||||
{
|
||||
"name": "stacjownik",
|
||||
"version": "1.9.9",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"deploy-prod": "npm run build && firebase deploy --only hosting:prod",
|
||||
"deploy-dev": "npm run build && firebase deploy --only hosting:dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.12.1",
|
||||
"dotenv": "^8.6.0",
|
||||
"firebase": "^9.8.1",
|
||||
"howler": "^2.2.1",
|
||||
"pinia": "^2.0.14",
|
||||
"socket.io-client": "^4.4.1",
|
||||
"vue": "^3.2.34",
|
||||
"vue-i18n": "^9.1.6",
|
||||
"vue-router": "^4.0.0-0",
|
||||
"vuex": "^4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.35",
|
||||
"@vue/cli-plugin-babel": "^5.0.4",
|
||||
"@vue/cli-plugin-router": "^5.0.4",
|
||||
"@vue/cli-plugin-typescript": "^5.0.4",
|
||||
"@vue/cli-plugin-vuex": "^5.0.4",
|
||||
"@vue/cli-service": "^5.0.4",
|
||||
"@vue/compiler-sfc": "^3.1.0",
|
||||
"axios": "^0.21.1",
|
||||
"sass": "^1.32.13",
|
||||
"sass-loader": "^8.0.2",
|
||||
"typescript": "^4.7.3"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
}
|
||||
{
|
||||
"name": "stacjownik",
|
||||
"version": "1.10.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.12.1",
|
||||
"dotenv": "^8.6.0",
|
||||
"firebase": "^9.8.1",
|
||||
"howler": "^2.2.1",
|
||||
"pinia": "^2.0.14",
|
||||
"sass": "^1.53.0",
|
||||
"socket.io-client": "^4.4.1",
|
||||
"vue": "^3.2.37",
|
||||
"vue-i18n": "^9.1.6",
|
||||
"vue-router": "^4.0.0-0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.35",
|
||||
"@vitejs/plugin-vue": "^3.0.0",
|
||||
"axios": "^0.21.1",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^3.0.0",
|
||||
"vue-tsc": "^0.38.4"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 951 B |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 799 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.00251 14.9297L0 1.07422H6.14651L8.00251 4.27503L9.84583 1.07422H16L8.00251 14.9297Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 215 B |
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "",
|
||||
"short_name": "",
|
||||
"name": "Stacjownik TD2",
|
||||
"short_name": "Stacjownik",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
@@ -13,7 +13,8 @@
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
"theme_color": "#ffc014",
|
||||
"background_color": "#4d4d4d",
|
||||
"display": "standalone",
|
||||
"start_url": "."
|
||||
}
|
||||
|
||||
@@ -17,6 +17,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
.modal-anim {
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all $animDuration $animType;
|
||||
}
|
||||
|
||||
&-enter-from,
|
||||
&-leave-to {
|
||||
transform: translateY(-25%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.route {
|
||||
margin: 0 0.2em;
|
||||
|
||||
@@ -27,7 +40,7 @@
|
||||
}
|
||||
|
||||
// APP
|
||||
.app {
|
||||
#app {
|
||||
color: white;
|
||||
font-size: 1rem;
|
||||
|
||||
@@ -40,8 +53,8 @@
|
||||
.app_container {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
height: 100vh;
|
||||
min-height: 800px;
|
||||
|
||||
min-height: 100vh;
|
||||
|
||||
header {
|
||||
flex: 0 0 auto;
|
||||
@@ -213,7 +226,6 @@
|
||||
font-weight: bold;
|
||||
padding: 0.1em 0.5em;
|
||||
color: paleturquoise;
|
||||
|
||||
}
|
||||
|
||||
.options {
|
||||
|
||||
@@ -1,106 +1,113 @@
|
||||
<template>
|
||||
<div class="app">
|
||||
<div class="app_container">
|
||||
<!-- <div class="wip-alert">
|
||||
<img class="icon-error" :src="iconError" alt="error" />
|
||||
<h2>Stacjownik tymczasowo nieaktywny!</h2>
|
||||
<p>Absolutny zakaz wjazdu!</p>
|
||||
</div> -->
|
||||
<header class="app_header">
|
||||
<div class="header_container">
|
||||
<div class="header_icons">
|
||||
<span class="icons-top">
|
||||
<img :src="icons.pl" alt="icon-pl" @click="changeLang('en')" v-if="currentLang == 'pl'" />
|
||||
<img :src="icons.en" alt="icon-en" @click="changeLang('pl')" v-else />
|
||||
</span>
|
||||
<span class="icons-bottom">
|
||||
<a href="https://www.paypal.com/paypalme/spythere" target="_blank">
|
||||
<img :src="icons.dollar" alt="icon paypal" />
|
||||
</a>
|
||||
<div class="app_container">
|
||||
<UpdateModal />
|
||||
|
||||
<a href="https://discord.gg/x2mpNN3svk" target="_blank">
|
||||
<img :src="icons.discord" alt="icon discord" />
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<transition name="modal-anim">
|
||||
<keep-alive>
|
||||
<TrainModal v-if="store.chosenModalTrainId" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
|
||||
<div class="header_body">
|
||||
<status-indicator />
|
||||
<span class="header_brand">
|
||||
<img :src="brand_logo" alt="Stacjownik" />
|
||||
</span>
|
||||
<header class="app_header">
|
||||
<div class="header_container">
|
||||
<div class="header_icons">
|
||||
<span class="icons-top">
|
||||
<img :src="getIcon('pl')" alt="icon-pl" @click="changeLang('en')" v-if="currentLang == 'pl'" />
|
||||
<img :src="getIcon('en', 'jpg')" alt="icon-en" @click="changeLang('pl')" v-else />
|
||||
</span>
|
||||
<span class="icons-bottom">
|
||||
<a href="https://www.paypal.com/paypalme/spythere" target="_blank">
|
||||
<img :src="getIcon('dollar')" alt="icon paypal" />
|
||||
</a>
|
||||
|
||||
<span class="header_info">
|
||||
<Clock />
|
||||
|
||||
<div class="info_counter">
|
||||
<img src="@/assets/icon-dispatcher.svg" alt="icon dispatcher" />
|
||||
<span class="text--primary">{{ onlineDispatchers.length }}</span>
|
||||
<span class="text--grayed"> / </span>
|
||||
<span class="text--primary">{{ trainList.length }}</span>
|
||||
<img src="@/assets/icon-train.svg" alt="icon train" />
|
||||
</div>
|
||||
|
||||
<span class="info_region">
|
||||
<SelectBox :itemList="computedRegions" :defaultItemIndex="0" @selected="changeRegion" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="header_links">
|
||||
<router-link class="route" active-class="route-active" to="/" exact>
|
||||
{{ $t('app.sceneries') }}
|
||||
</router-link>
|
||||
/
|
||||
<router-link class="route" active-class="route-active" to="/trains">{{ $t('app.trains') }}</router-link>
|
||||
/
|
||||
<router-link class="route" active-class="route-active" to="/journal">
|
||||
{{ $t('app.journal') }}
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
<a href="https://discord.gg/x2mpNN3svk" target="_blank">
|
||||
<img :src="getIcon('discord', 'png')" alt="icon discord" />
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="app_main">
|
||||
<router-view v-slot="{ Component }">
|
||||
<!-- <transition name="view-anim" mode="out-in"> -->
|
||||
<keep-alive>
|
||||
<component :is="Component" :key="$route.path" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</main>
|
||||
<div class="header_body">
|
||||
<status-indicator />
|
||||
<span class="header_brand">
|
||||
<img :src="getImage('stacjownik-header-logo.svg')" alt="Stacjownik" />
|
||||
</span>
|
||||
|
||||
<footer class="app_footer">
|
||||
©
|
||||
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
||||
{{ new Date().getUTCFullYear() }} | v{{ VERSION }}
|
||||
<span class="header_info">
|
||||
<Clock />
|
||||
|
||||
<div style="display: none">∫ ukryta taktyczna całka do programowania w HTMLu</div>
|
||||
</footer>
|
||||
</div>
|
||||
<div class="info_counter">
|
||||
<img :src="getIcon('dispatcher')" alt="icon dispatcher" />
|
||||
<span class="text--primary">{{ onlineDispatchers.length }}</span>
|
||||
<span class="text--grayed"> / </span>
|
||||
<span class="text--primary">{{ trainList.length }}</span>
|
||||
<img :src="getIcon('train')" alt="icon train" />
|
||||
</div>
|
||||
|
||||
<span class="info_region">
|
||||
<SelectBox :itemList="computedRegions" :defaultItemIndex="0" @selected="changeRegion" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="header_links">
|
||||
<router-link class="route" active-class="route-active" to="/" exact>
|
||||
{{ $t('app.sceneries') }}
|
||||
</router-link>
|
||||
/
|
||||
<router-link class="route" active-class="route-active" to="/trains">{{ $t('app.trains') }}</router-link>
|
||||
/
|
||||
<router-link class="route" active-class="route-active" to="/journal/timetables">
|
||||
{{ $t('app.journal') }}
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="app_main">
|
||||
<router-view v-slot="{ Component }">
|
||||
<keep-alive>
|
||||
<component :is="Component" :key="$route.path" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</main>
|
||||
|
||||
<footer class="app_footer">
|
||||
©
|
||||
<a href="https://td2.info.pl/profile/?u=20777" target="_blank">Spythere</a>
|
||||
{{ new Date().getUTCFullYear() }} | <a :href="releaseURL" target="_blank">v{{ VERSION }}</a>
|
||||
|
||||
<div style="display: none">∫ ukryta taktyczna całka do programowania w HTMLu</div>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, provide, ref } from 'vue';
|
||||
|
||||
import Clock from '@/components/App/Clock.vue';
|
||||
import StorageManager from '@/scripts/managers/storageManager';
|
||||
import Clock from './components/App/Clock.vue';
|
||||
|
||||
import packageInfo from '.././package.json';
|
||||
import options from '@/data/options.json';
|
||||
import options from './data/options.json';
|
||||
|
||||
import StatusIndicator from '@/components/App/StatusIndicator.vue';
|
||||
import SelectBox from '@/components/Global/SelectBox.vue';
|
||||
import StatusIndicator from './components/App/StatusIndicator.vue';
|
||||
import SelectBox from './components/Global/SelectBox.vue';
|
||||
import { useStore } from './store/store';
|
||||
import UpdateModal from './components/App/UpdateModal.vue';
|
||||
import TrainModal from './components/Global/TrainModal.vue';
|
||||
import StorageManager from './scripts/managers/storageManager';
|
||||
import imageMixin from './mixins/imageMixin';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Clock,
|
||||
StatusIndicator,
|
||||
SelectBox,
|
||||
UpdateModal,
|
||||
TrainModal,
|
||||
},
|
||||
|
||||
mixins: [imageMixin],
|
||||
|
||||
setup() {
|
||||
const store = useStore();
|
||||
store.connectToAPI();
|
||||
@@ -129,7 +136,8 @@ export default defineComponent({
|
||||
return this.options.regions.map((region) => {
|
||||
const regionStationCount =
|
||||
this.store.apiData.stations?.filter((station) => station.region == region.id && station.isOnline).length || 0;
|
||||
const regionTrainCount = this.store.apiData.trains?.filter((train) => train.region == region.id && train.online).length || 0;
|
||||
const regionTrainCount =
|
||||
this.store.apiData.trains?.filter((train) => train.region == region.id && train.online).length || 0;
|
||||
|
||||
return {
|
||||
id: region.id,
|
||||
@@ -142,23 +150,10 @@ export default defineComponent({
|
||||
|
||||
data: () => ({
|
||||
VERSION: packageInfo.version,
|
||||
updateModalVisible: false,
|
||||
hasReleaseNotes: false,
|
||||
options,
|
||||
|
||||
currentLang: 'pl',
|
||||
|
||||
brand_logo: require('@/assets/stacjownik-header-logo.svg'),
|
||||
|
||||
icons: {
|
||||
en: require('@/assets/icon-en.jpg'),
|
||||
pl: require('@/assets/icon-pl.svg'),
|
||||
error: require('@/assets/icon-error.svg'),
|
||||
dollar: require('@/assets/icon-dollar.svg'),
|
||||
dispatcher: require('@/assets/icon-dispatcher.svg'),
|
||||
train: require('@/assets/icon-train.svg'),
|
||||
discord: require('@/assets/icon-discord.png'),
|
||||
},
|
||||
releaseURL: '',
|
||||
}),
|
||||
|
||||
created() {
|
||||
@@ -166,23 +161,11 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
if (StorageManager.getStringValue('version') != this.VERSION) {
|
||||
StorageManager.setStringValue('version', this.VERSION);
|
||||
|
||||
if (this.hasReleaseNotes) StorageManager.setBooleanValue('version_notes_read', false);
|
||||
}
|
||||
|
||||
this.updateModalVisible = this.hasReleaseNotes && !StorageManager.getBooleanValue('version_notes_read');
|
||||
|
||||
this.updateToNewestVersion();
|
||||
this.updateStorage();
|
||||
this.setReleaseURL();
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleUpdateModal() {
|
||||
this.updateModalVisible = !this.updateModalVisible;
|
||||
StorageManager.setBooleanValue('version_notes_read', true);
|
||||
},
|
||||
|
||||
changeRegion(region: { id: string; value: string }) {
|
||||
this.store.changeRegion(region);
|
||||
},
|
||||
@@ -194,7 +177,13 @@ export default defineComponent({
|
||||
StorageManager.setStringValue('lang', lang);
|
||||
},
|
||||
|
||||
updateToNewestVersion() {
|
||||
setReleaseURL() {
|
||||
const releaseURL = StorageManager.getStringValue('releaseURL');
|
||||
|
||||
this.releaseURL = releaseURL || '';
|
||||
},
|
||||
|
||||
updateStorage() {
|
||||
if (!StorageManager.isRegistered('unavailable-status')) {
|
||||
StorageManager.setBooleanValue('unavailable-status', true);
|
||||
StorageManager.setBooleanValue('ending-status', true);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "@vue/runtime-core";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
props: ["message"],
|
||||
|
||||
@@ -161,18 +161,15 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { DataStatus } from '@/scripts/enums/DataStatus';
|
||||
import { StoreData } from '@/scripts/interfaces/StoreData';
|
||||
import { useStore } from '@/store/store';
|
||||
import { StoreState } from '@/store/storeTypes';
|
||||
import { computed, defineComponent, watch } from 'vue';
|
||||
|
||||
import { defineComponent } from 'vue';
|
||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||
import { useStore } from '../../store/store';
|
||||
import { StoreState } from '../../store/storeTypes';
|
||||
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
icons: {
|
||||
statusIndicator: require('@/assets/signal-status-indicator.svg'),
|
||||
},
|
||||
tooltipActive: false,
|
||||
indicator: {
|
||||
status: DataStatus.Loading,
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<transition name="modal-anim">
|
||||
<section class="update-modal card" v-if="releaseData && modalOpen">
|
||||
<h2 class="modal_header text--primary">
|
||||
<img :src="getImage('stacjownik-header-logo.svg')" alt="stacjownik logo" />
|
||||
|
||||
{{ releaseData.tag_name }}
|
||||
</h2>
|
||||
|
||||
<div class="horizontal"></div>
|
||||
|
||||
<div class="modal_content">
|
||||
<h3>{{ $t('update.title') }}</h3>
|
||||
<a :href="releaseData.html_url" target="_blank">{{ $t('update.release-link') }}</a>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<p>{{ $t('update.paragraph1') }}</p>
|
||||
|
||||
<!-- <div class="modal_changelog" v-html="markdownReleaseBody"></div> -->
|
||||
</div>
|
||||
|
||||
<div class="modal_actions">
|
||||
<button class="btn btn--option" @click="modalOpen = false">{{ $t('update.confirm-button') }}</button>
|
||||
</div>
|
||||
</section>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import axios from 'axios';
|
||||
import { defineComponent } from 'vue';
|
||||
import packageInfo from '../../../package.json';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import { ReleaseAPIData } from '../../scripts/interfaces/github_api/ReleaseAPIData';
|
||||
import StorageManager from '../../scripts/managers/storageManager';
|
||||
import { useStore } from '../../store/store';
|
||||
|
||||
|
||||
const GH_LASTEST_RELEASE_URL = 'https://api.github.com/repos/Spythere/stacjownik/releases/latest';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [imageMixin],
|
||||
|
||||
mounted() {
|
||||
this.fetchReleases();
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
modalOpen: false,
|
||||
|
||||
releaseData: null as ReleaseAPIData | null,
|
||||
};
|
||||
},
|
||||
|
||||
setup() {
|
||||
return {
|
||||
store: useStore()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async fetchReleases() {
|
||||
const storedVersion = StorageManager.getStringValue('appVersion');
|
||||
const appVersion = packageInfo.version;
|
||||
|
||||
// Zmiana
|
||||
if (appVersion != storedVersion) {
|
||||
StorageManager.setStringValue('appVersion', appVersion);
|
||||
|
||||
// Znajdź changelog na GitHubie, jeśli jest pokaż modal
|
||||
try {
|
||||
const releaseData: ReleaseAPIData = await (await axios.get(GH_LASTEST_RELEASE_URL)).data;
|
||||
if (!releaseData) return;
|
||||
|
||||
const lastReleaseVersion = releaseData.tag_name.slice(1);
|
||||
|
||||
if (lastReleaseVersion == appVersion) {
|
||||
this.releaseData = releaseData;
|
||||
this.modalOpen = true;
|
||||
|
||||
StorageManager.setStringValue('releaseURL', releaseData.html_url);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Wystąpił błąd podczas pobierania danych z API GitHuba: ${error}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../styles/card.scss';
|
||||
@import '../../styles/responsive.scss';
|
||||
|
||||
|
||||
.modal-anim {
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all $animDuration $animType;
|
||||
}
|
||||
|
||||
&-enter-from,
|
||||
&-leave-to {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -50%) scale(0.45);
|
||||
}
|
||||
}
|
||||
|
||||
.update-modal {
|
||||
text-align: center;
|
||||
background-color: var(--clr-secondary);
|
||||
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.horizontal {
|
||||
margin: 1em 0;
|
||||
|
||||
height: 2px;
|
||||
width: 100%;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.modal_header {
|
||||
font-size: 1.6em;
|
||||
|
||||
img {
|
||||
width: 50%;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
}
|
||||
|
||||
.modal_content {
|
||||
font-size: 1.1em;
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.modal_actions {
|
||||
margin-top: 2em;
|
||||
|
||||
button {
|
||||
color: white;
|
||||
padding: 0.5em;
|
||||
font-size: 1.2em;
|
||||
|
||||
background-color: black;
|
||||
}
|
||||
}
|
||||
|
||||
.modal_changelog {
|
||||
font-size: 0.8em;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
@include smallScreen {
|
||||
.update-modal {
|
||||
height: auto;
|
||||
max-width: 95%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,47 +0,0 @@
|
||||
<template>
|
||||
<section
|
||||
class="updates card"
|
||||
v-if="cardOpen"
|
||||
>
|
||||
<h2>Ostatnie aktualizacje w Stacjowniku</h2>
|
||||
<p>Tutaj będą pojawiać się informacje o kolejnych nowościach na stronie :)</p>
|
||||
|
||||
<ul>
|
||||
<li
|
||||
v-for="(update, i) in updates"
|
||||
:key="i"
|
||||
>
|
||||
<div>{{update.date}}</div>
|
||||
|
||||
<div>
|
||||
<span
|
||||
v-for="(line, l) in content"
|
||||
:key="l"
|
||||
>{{line}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from "@vue/runtime-core";
|
||||
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
updates: {
|
||||
date: "08/08/20",
|
||||
content: [
|
||||
"Lekko odświeżono wygląd strony, dodano nowy widok z pociągami online",
|
||||
"Dodano animacje zmieniania widoków (zakładek)",
|
||||
"Dodano przycisk zamykający kartę z filtrami",
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<img
|
||||
class="search-exit"
|
||||
:src="exitIcon"
|
||||
:src="getIcon('exit')"
|
||||
alt="exit-icon"
|
||||
@click="clearValue"
|
||||
/>
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch } from "vue";
|
||||
import imageMixin from "../../mixins/imageMixin";
|
||||
|
||||
export default defineComponent({
|
||||
data: () => ({
|
||||
exitIcon: require("@/assets/icon-exit.svg"),
|
||||
}),
|
||||
mixins: [imageMixin],
|
||||
|
||||
emits: ["update:searchedValue", "clearValue"],
|
||||
props: {
|
||||
searchedValue: {
|
||||
@@ -59,7 +59,7 @@ export default defineComponent({
|
||||
emit("clearValue");
|
||||
};
|
||||
|
||||
const updateValue = (e) => {
|
||||
const updateValue = (e: any) => {
|
||||
if (!props.updateOnInput && e.keyCode == 13)
|
||||
emit("update:searchedValue", compSearchedValue.value);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="select-box" >
|
||||
<div class="select-box">
|
||||
<div class="select-box_content">
|
||||
<button class="selected" @click="toggleBox">
|
||||
<span class="text--primary">{{ prefix }}</span>
|
||||
@@ -24,13 +24,14 @@
|
||||
</div>
|
||||
|
||||
<div class="arrow">
|
||||
<img :src="listOpen ? ascIcon : descIcon" alt="arrow-icon" />
|
||||
<img :src="listOpen ? getIcon('arrow-asc') : getIcon('arrow-desc')" alt="arrow-icon" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, Ref, ref } from '@vue/runtime-core';
|
||||
import { defineComponent, Ref, ref, computed } from 'vue';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
|
||||
interface Item {
|
||||
id: string;
|
||||
@@ -40,6 +41,7 @@ interface Item {
|
||||
|
||||
export default defineComponent({
|
||||
emits: ['selected'],
|
||||
mixins: [imageMixin],
|
||||
|
||||
props: {
|
||||
itemList: {
|
||||
@@ -58,11 +60,6 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
ascIcon: require('@/assets/icon-arrow-asc.svg'),
|
||||
descIcon: require('@/assets/icon-arrow-desc.svg'),
|
||||
}),
|
||||
|
||||
setup(props) {
|
||||
let listRef: Ref<Element | null> = ref(null);
|
||||
let buttonRef: Ref<HTMLButtonElement | null> = ref(null);
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import dateMixin from '@/mixins/dateMixin';
|
||||
import TrainStop from '@/scripts/interfaces/TrainStop';
|
||||
import { defineComponent } from 'vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import TrainStop from '../../scripts/interfaces/TrainStop';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [dateMixin],
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
<template>
|
||||
<div class="train-modal" v-if="chosenTrain" @keydown.esc="closeModal">
|
||||
<div class="modal_background" @click="closeModal"></div>
|
||||
<div class="modal_content" ref="content" tabindex="0">
|
||||
<button class="btn exit" @click="closeModal">
|
||||
<img :src="getIcon('exit')" alt="close card" />
|
||||
</button>
|
||||
|
||||
<TrainInfo :train="chosenTrain" :extended="false" ref="trainInfo" />
|
||||
<TrainSchedule :train="chosenTrain" tabindex="0" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||
import trainInfoMixin from '../../mixins/trainInfoMixin';
|
||||
import { useStore } from '../../store/store';
|
||||
import TrainInfo from '../TrainsView/TrainInfo.vue';
|
||||
import TrainSchedule from '../TrainsView/TrainSchedule.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { TrainInfo, TrainSchedule },
|
||||
mixins: [trainInfoMixin, modalTrainMixin, imageMixin],
|
||||
|
||||
data() {
|
||||
return {
|
||||
isTopBarVisible: false,
|
||||
};
|
||||
},
|
||||
|
||||
setup() {
|
||||
const store = useStore();
|
||||
|
||||
return {
|
||||
store,
|
||||
};
|
||||
},
|
||||
|
||||
activated() {
|
||||
const contentEl = this.$refs['content'] as HTMLElement;
|
||||
|
||||
this.$nextTick(() => {
|
||||
contentEl.focus();
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleContentScroll(e: Event) {
|
||||
const trainInfoCompHeight: number = (this.$refs['trainInfo'] as any).$el.getBoundingClientRect().height;
|
||||
|
||||
const posTop = (e.target as HTMLElement).scrollTop;
|
||||
this.isTopBarVisible = posTop > trainInfoCompHeight;
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/card.scss';
|
||||
|
||||
.top-info-bar-anim {
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all 150ms ease-in-out;
|
||||
}
|
||||
|
||||
&-enter-from,
|
||||
&-leave-to {
|
||||
transform: translate(-50%, -50%) scale(0.8);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.exit {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
margin: 0.5em 1em;
|
||||
|
||||
padding: 0.25em;
|
||||
|
||||
z-index: 201;
|
||||
|
||||
img {
|
||||
width: 1.5rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.train-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
|
||||
color: white;
|
||||
z-index: 200;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.modal_background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
background-color: rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
.modal_content {
|
||||
position: relative;
|
||||
overflow-y: scroll;
|
||||
|
||||
margin-top: 1em;
|
||||
|
||||
width: 95vw;
|
||||
max-height: 96vh;
|
||||
|
||||
background-color: #1a1a1a;
|
||||
box-shadow: 0 0 15px 10px #0e0e0e;
|
||||
}
|
||||
|
||||
@include midScreen {
|
||||
.exit {
|
||||
margin: 0.5em;
|
||||
|
||||
img {
|
||||
width: 1.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include smallScreen {
|
||||
.train-modal {
|
||||
font-size: 1.05em;
|
||||
}
|
||||
|
||||
.modal_content {
|
||||
max-height: 85vh;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -48,12 +48,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { DispatcherStatsAPIData } from '@/scripts/interfaces/api/DispatcherStatsAPIData';
|
||||
import { TimetableHistory } from '@/scripts/interfaces/api/TimetablesAPIData';
|
||||
import { URLs } from '@/scripts/utils/apiURLs';
|
||||
import { useStore } from '@/store/store';
|
||||
|
||||
import axios from 'axios';
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import { DispatcherStatsAPIData } from '../../scripts/interfaces/api/DispatcherStatsAPIData';
|
||||
import { TimetableHistory } from '../../scripts/interfaces/api/TimetablesAPIData';
|
||||
import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import { useStore } from '../../store/store';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
@@ -51,12 +51,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { DriverStatsAPIData } from '@/scripts/interfaces/api/DriverStatsAPIData';
|
||||
import { TimetableHistory } from '@/scripts/interfaces/api/TimetablesAPIData';
|
||||
import { URLs } from '@/scripts/utils/apiURLs';
|
||||
import { useStore } from '@/store/store';
|
||||
|
||||
import axios from 'axios';
|
||||
import { defineComponent } from 'vue';
|
||||
import { DriverStatsAPIData } from '../../scripts/interfaces/api/DriverStatsAPIData';
|
||||
import { TimetableHistory } from '../../scripts/interfaces/api/TimetablesAPIData';
|
||||
import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import { useStore } from '../../store/store';
|
||||
|
||||
export default defineComponent({
|
||||
emits: ['closeCard'],
|
||||
|
||||
@@ -79,26 +79,21 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, JournalFilter, JournalSearcher, provide, reactive, Ref, ref, watch } from 'vue';
|
||||
import { computed, defineComponent, JournalFilter, provide, reactive, Ref, ref } from 'vue';
|
||||
import axios from 'axios';
|
||||
|
||||
import SearchBox from '@/components/Global/SearchBox.vue';
|
||||
import dateMixin from '@/mixins/dateMixin';
|
||||
import { DataStatus } from '@/scripts/enums/DataStatus';
|
||||
import ActionButton from '../../components/Global/ActionButton.vue';
|
||||
import JournalOptions from '../../components/JournalView/JournalOptions.vue';
|
||||
import DispatcherStats from '../../components/JournalView/DispatcherStats.vue';
|
||||
import SearchBox from '../Global/SearchBox.vue';
|
||||
|
||||
import ActionButton from '@/components/Global/ActionButton.vue';
|
||||
import JournalOptions from '@/components/JournalView/JournalOptions.vue';
|
||||
import DispatcherStats from '@/components/JournalView/DispatcherStats.vue';
|
||||
|
||||
import { URLs } from '@/scripts/utils/apiURLs';
|
||||
import { useStore } from '@/store/store';
|
||||
import { DispatcherStatsAPIData } from '@/scripts/interfaces/api/DispatcherStatsAPIData';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||
import { useStore } from '../../store/store';
|
||||
|
||||
const PROD_MODE = process.env.VUE_APP_JORUNAL_DISPATCHERS_DEV != '1' || process.env.NODE_ENV === 'production';
|
||||
|
||||
const DISPATCHERS_API_URL = (PROD_MODE ? `${URLs.stacjownikAPI}/api` : 'http://localhost:3001/api') + '/getDispatchers';
|
||||
const DISPATCHERS_API_URL = `${URLs.stacjownikAPI}/api/getDispatchers`;
|
||||
|
||||
interface DispatcherHistoryItem {
|
||||
id: string;
|
||||
@@ -119,6 +114,10 @@ interface DispatcherHistoryItem {
|
||||
isOnline: boolean;
|
||||
}
|
||||
|
||||
type JournalDispatcherSearcher = {
|
||||
[key in 'search-dispatcher' | 'search-station']: string;
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
components: { SearchBox, ActionButton, JournalOptions, DispatcherStats, Loading },
|
||||
mixins: [dateMixin],
|
||||
@@ -137,10 +136,6 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
icons: {
|
||||
arrow: require('@/assets/icon-arrow-asc.svg'),
|
||||
},
|
||||
|
||||
currentQuery: '',
|
||||
scrollDataLoaded: true,
|
||||
scrollNoMoreData: false,
|
||||
@@ -157,10 +152,10 @@ export default defineComponent({
|
||||
|
||||
const sorterActive = ref({ id: 'timestampFrom', dir: -1 });
|
||||
const journalFilterActive = ref({});
|
||||
const searchersValues = reactive([
|
||||
{ id: 'search-dispatcher', value: '' },
|
||||
{ id: 'search-station', value: '' },
|
||||
]);
|
||||
const searchersValues = reactive({
|
||||
'search-dispatcher': '',
|
||||
'search-station': '',
|
||||
} as JournalDispatcherSearcher);
|
||||
|
||||
const countFromIndex = ref(0);
|
||||
const countLimit = 15;
|
||||
@@ -202,8 +197,8 @@ export default defineComponent({
|
||||
|
||||
activated() {
|
||||
if (this.sceneryName || this.dispatcherName) {
|
||||
this.searchersValues[1].value = this.sceneryName?.toString() || '';
|
||||
this.searchersValues[0].value = this.dispatcherName?.toString() || '';
|
||||
this.searchersValues['search-station'] = this.sceneryName?.toString() || '';
|
||||
this.searchersValues['search-dispatcher'] = this.dispatcherName?.toString() || '';
|
||||
this.search();
|
||||
}
|
||||
|
||||
@@ -289,7 +284,7 @@ export default defineComponent({
|
||||
|
||||
async fetchHistoryData(
|
||||
props: {
|
||||
searchers?: JournalSearcher[];
|
||||
searchers?: JournalDispatcherSearcher;
|
||||
filter?: JournalFilter;
|
||||
} = {}
|
||||
) {
|
||||
@@ -297,8 +292,11 @@ export default defineComponent({
|
||||
|
||||
const queries: string[] = [];
|
||||
|
||||
const dispatcher = props.searchers?.find((s) => s.id == 'search-dispatcher')?.value.trim();
|
||||
const station = props.searchers?.find((s) => s.id == 'search-station')?.value.trim();
|
||||
// const dispatcher = props.searchers?.find((s) => s.id == 'search-dispatcher')?.value.trim();
|
||||
// const station = props.searchers?.find((s) => s.id == 'search-station')?.value.trim();
|
||||
|
||||
const dispatcher = props.searchers?.['search-dispatcher'].trim();
|
||||
const station = props.searchers?.['search-station'].trim();
|
||||
|
||||
if (dispatcher) queries.push(`dispatcherName=${dispatcher}`);
|
||||
if (station) queries.push(`stationName=${station}`);
|
||||
@@ -330,7 +328,9 @@ export default defineComponent({
|
||||
|
||||
// Stats display
|
||||
this.store.dispatcherStatsName =
|
||||
this.historyList.length > 0 && this.searchersValues[0].value.trim() ? this.historyList[0].dispatcherName : '';
|
||||
this.historyList.length > 0 && this.searchersValues['search-dispatcher'].trim()
|
||||
? this.historyList[0].dispatcherName
|
||||
: '';
|
||||
|
||||
this.historyDataStatus.status = DataStatus.Loaded;
|
||||
} catch (error) {
|
||||
|
||||
@@ -12,15 +12,15 @@
|
||||
</div>
|
||||
|
||||
<div class="content_search">
|
||||
<div class="search-box" v-for="search in searchersValues" :key="search.id">
|
||||
<div class="search-box" v-for="(value, propName) in searchersValues" :key="propName">
|
||||
<input
|
||||
class="search-input"
|
||||
:placeholder="$t(`journal.${search.id}`)"
|
||||
v-model="search.value"
|
||||
:placeholder="$t(`journal.${propName}`)"
|
||||
v-model="searchersValues[propName]"
|
||||
@keydown.enter="onInputSearch"
|
||||
/>
|
||||
|
||||
<img class="search-exit" :src="exitIcon" alt="exit-icon" @click="onInputClear(search.id)" />
|
||||
<img class="search-exit" :src="getIcon('exit')" alt="exit-icon" @click="onInputClear(propName)" />
|
||||
</div>
|
||||
<!-- <div class="search-box">
|
||||
<input
|
||||
@@ -67,12 +67,15 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, inject, JournalFilter, PropType } from 'vue';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import ActionButton from '../Global/ActionButton.vue';
|
||||
import SelectBox from '../Global/SelectBox.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { SelectBox, ActionButton },
|
||||
emits: ['onSorterChange', 'onInputChange', 'onFilterChange'],
|
||||
mixins: [imageMixin],
|
||||
|
||||
props: {
|
||||
sorterOptionIds: {
|
||||
type: Array as PropType<Array<string>>,
|
||||
@@ -85,13 +88,10 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
exitIcon: require('@/assets/icon-exit.svg'),
|
||||
}),
|
||||
|
||||
setup() {
|
||||
return {
|
||||
searchersValues: inject('searchersValues') as {id: string; value: string}[],
|
||||
searchersValues: inject('searchersValues') as {[key: string]: string},
|
||||
sorterActive: inject('sorterActive') as { id: string | number; dir: number },
|
||||
journalFilterActive: inject('journalFilterActive') as JournalFilter,
|
||||
};
|
||||
@@ -123,8 +123,8 @@ export default defineComponent({
|
||||
this.$emit('onInputChange');
|
||||
},
|
||||
|
||||
onInputClear(id: string) {
|
||||
this.searchersValues.find(s => s.id == id)!.value = "";
|
||||
onInputClear(id: any) {
|
||||
this.searchersValues[id] = '';
|
||||
this.onInputSearch();
|
||||
},
|
||||
},
|
||||
|
||||
@@ -13,17 +13,6 @@
|
||||
:sorter-option-ids="['timetableId', 'beginDate', 'distance', 'total-stops']"
|
||||
:filters="journalTimetableFilters"
|
||||
/>
|
||||
|
||||
<!-- <button
|
||||
class="btn btn--option"
|
||||
:disabled="store.driverStatsName == ''"
|
||||
@click="() => (statsCardOpen = !statsCardOpen)"
|
||||
>
|
||||
<span v-if="store.driverStatsName">
|
||||
Statystyki maszynisty <b>{{ store.driverStatsName }}</b>
|
||||
</span>
|
||||
<span v-else>Statystyki maszynisty niedostępne</span>
|
||||
</button> -->
|
||||
</div>
|
||||
|
||||
<div class="journal-list">
|
||||
@@ -158,42 +147,40 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, JournalFilter, JournalSearcher, provide, reactive, Ref, ref } from 'vue';
|
||||
import { computed, defineComponent, JournalFilter, provide, reactive, Ref, ref } from 'vue';
|
||||
import axios from 'axios';
|
||||
|
||||
import SearchBox from '@/components/Global/SearchBox.vue';
|
||||
import dateMixin from '@/mixins/dateMixin';
|
||||
import { DataStatus } from '@/scripts/enums/DataStatus';
|
||||
|
||||
import ActionButton from '@/components/Global/ActionButton.vue';
|
||||
import JournalOptions from '@/components/JournalView/JournalOptions.vue';
|
||||
|
||||
import { URLs } from '@/scripts/utils/apiURLs';
|
||||
import { journalTimetableFilters } from '@/data/journalFilters';
|
||||
import { JournalFilterType } from '@/scripts/enums/JournalFilterType';
|
||||
import routerMixin from '@/mixins/routerMixin';
|
||||
import { useStore } from '@/store/store';
|
||||
import DriverStats from './DriverStats.vue';
|
||||
import { TimetableHistory } from '@/scripts/interfaces/api/TimetablesAPIData';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import { journalTimetableFilters } from '../../data/journalFilters';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import routerMixin from '../../mixins/routerMixin';
|
||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||
import { JournalFilterType } from '../../scripts/enums/JournalFilterType';
|
||||
import { TimetableHistory } from '../../scripts/interfaces/api/TimetablesAPIData';
|
||||
import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import { useStore } from '../../store/store';
|
||||
import JournalOptions from './JournalOptions.vue';
|
||||
|
||||
const PROD_MODE = process.env.VUE_APP_JOURNAL_TIMETABLES_DEV != '1' || process.env.NODE_ENV === 'production';
|
||||
const TIMETABLES_API_URL = `${URLs.stacjownikAPI}/api/getTimetables`;
|
||||
|
||||
const TIMETABLES_API_URL = PROD_MODE
|
||||
? `${URLs.stacjownikAPI}/api/getTimetables`
|
||||
: 'http://localhost:3001/api/getTimetables';
|
||||
type JournalTimetableSearcher = {
|
||||
[key in 'search-driver' | 'search-train']: string;
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
components: { SearchBox, ActionButton, JournalOptions, DriverStats, Loading },
|
||||
components: { DriverStats, Loading, JournalOptions },
|
||||
mixins: [dateMixin, routerMixin],
|
||||
|
||||
name: 'JournalTimetables',
|
||||
|
||||
data: () => ({
|
||||
icons: {
|
||||
arrow: require('@/assets/icon-arrow-asc.svg'),
|
||||
props: {
|
||||
timetableId: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
currentQuery: '',
|
||||
scrollDataLoaded: true,
|
||||
scrollNoMoreData: false,
|
||||
@@ -213,10 +200,11 @@ export default defineComponent({
|
||||
const sorterActive = ref({ id: 'timetableId', dir: -1 });
|
||||
const journalFilterActive = ref(journalTimetableFilters[0]);
|
||||
|
||||
const searchersValues = reactive([
|
||||
{ id: 'search-train', value: '' },
|
||||
{ id: 'search-driver', value: '' },
|
||||
]);
|
||||
const searchersValues = reactive({
|
||||
'search-train': '',
|
||||
'search-driver': '',
|
||||
} as JournalTimetableSearcher);
|
||||
|
||||
const countFromIndex = ref(0);
|
||||
const countLimit = 15;
|
||||
|
||||
@@ -249,10 +237,15 @@ export default defineComponent({
|
||||
|
||||
activated() {
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
|
||||
if (this.timetableId) {
|
||||
this.searchersValues['search-train'] = `#${this.timetableId}`;
|
||||
this.search();
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.search();
|
||||
if (!this.timetableId) this.search();
|
||||
},
|
||||
|
||||
deactivated() {
|
||||
@@ -329,7 +322,7 @@ export default defineComponent({
|
||||
|
||||
async fetchHistoryData(
|
||||
props: {
|
||||
searchers?: JournalSearcher[];
|
||||
searchers?: JournalTimetableSearcher;
|
||||
filter?: JournalFilter;
|
||||
} = {}
|
||||
) {
|
||||
@@ -337,11 +330,11 @@ export default defineComponent({
|
||||
|
||||
const queries: string[] = [];
|
||||
|
||||
const driver = props.searchers?.find((s) => s.id == 'search-driver')?.value.trim();
|
||||
const train = props.searchers?.find((s) => s.id == 'search-train')?.value.trim();
|
||||
const driver = props.searchers?.['search-driver'].trim();
|
||||
const train = props.searchers?.['search-train'].trim();
|
||||
|
||||
if (driver) queries.push(`driverName=${driver}`);
|
||||
if (train) queries.push(`trainNo=${train}`);
|
||||
if (train) queries.push(train.startsWith('#') ? `timetableId=${train.replace('#', '')}` : `trainNo=${train}`);
|
||||
|
||||
// Z API: const SORT_TYPES = ['allStopsCount', 'endDate', 'beginDate', 'routeDistance'];
|
||||
if (this.sorterActive.id == 'distance') queries.push('sortBy=routeDistance');
|
||||
@@ -381,13 +374,6 @@ export default defineComponent({
|
||||
return;
|
||||
}
|
||||
|
||||
// if (responseData) {
|
||||
// this.historyDataStatus.status = DataStatus.Error;
|
||||
// this.historyDataStatus.error = responseData;
|
||||
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (!responseData) return;
|
||||
|
||||
// Response data exists
|
||||
@@ -395,7 +381,9 @@ export default defineComponent({
|
||||
|
||||
// Stats display
|
||||
this.store.driverStatsName =
|
||||
this.historyList.length > 0 && this.searchersValues[1].value.trim() ? this.historyList[0].driverName : '';
|
||||
this.historyList.length > 0 && this.searchersValues['search-driver'].trim()
|
||||
? this.historyList[0].driverName
|
||||
: '';
|
||||
|
||||
this.historyDataStatus.status = DataStatus.Loaded;
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<section class="scenery-dispatchers-history scenery-section">
|
||||
<section class="scenery-dispatchers-history scenery-section">
|
||||
<Loading v-if="dataStatus != 2" />
|
||||
|
||||
<div class="list-warning" v-else-if="dispatcherHistoryList.length == 0">{{ $t('scenery.history-list-empty') }}</div>
|
||||
@@ -7,8 +7,10 @@
|
||||
<ul class="history-list" v-else>
|
||||
<li class="list-item" v-for="historyItem in dispatcherHistoryList">
|
||||
<div>
|
||||
<span class="text--grayed">#{{ historyItem.stationHash }} </span>
|
||||
<b class="text--primary">{{ historyItem.dispatcherName }}</b>
|
||||
<router-link :to="`/journal/dispatchers?dispatcherName=${historyItem.dispatcherName}`">
|
||||
<span class="text--grayed">#{{ historyItem.stationHash }} </span>
|
||||
<b>{{ historyItem.dispatcherName }}</b>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<div v-if="historyItem.timestampTo">
|
||||
@@ -22,7 +24,6 @@
|
||||
{{ $t('journal.online-since') }}
|
||||
<b>{{ timestampToString(historyItem.timestampFrom) }}</b>
|
||||
({{ calculateDuration(historyItem.currentDuration) }})
|
||||
<span></span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -30,13 +31,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import dateMixin from '@/mixins/dateMixin';
|
||||
import { DataStatus } from '@/scripts/enums/DataStatus';
|
||||
import { DispatcherHistory } from '@/scripts/interfaces/api/DispatchersAPIData';
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import { URLs } from '@/scripts/utils/apiURLs';
|
||||
|
||||
import axios from 'axios';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||
import { DispatcherHistory } from '../../scripts/interfaces/api/DispatchersAPIData';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
|
||||
export default defineComponent({
|
||||
@@ -80,7 +82,6 @@ export default defineComponent({
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/SceneryView/styles.scss';
|
||||
|
||||
|
||||
.history-list {
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
@@ -103,6 +104,9 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
@include smallScreen {
|
||||
.history-list {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
.list-item {
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
<template>
|
||||
<section class="info-header">
|
||||
<div class="scenery-name">
|
||||
<a v-if="station.generalInfo?.url" :href="station.generalInfo.url" target="_blank" rel="noopener noreferrer">
|
||||
{{ station.name }}
|
||||
</a>
|
||||
|
||||
<span v-else>{{ station.name }}</span>
|
||||
{{ station.name }}
|
||||
</div>
|
||||
|
||||
<div class="scenery-hash" v-if="station.onlineInfo?.hash">#{{ station.onlineInfo.hash }}</div>
|
||||
@@ -14,8 +10,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -33,7 +29,6 @@ export default defineComponent({
|
||||
|
||||
.scenery-name {
|
||||
font-weight: bold;
|
||||
color: $accentCol;
|
||||
|
||||
position: relative;
|
||||
|
||||
@@ -52,3 +47,4 @@ export default defineComponent({
|
||||
font-size: 1.2em;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
<span v-if="station.generalInfo.reqLevel > -1">
|
||||
- {{ $tc('scenery.req-level', station.generalInfo.reqLevel, { lvl: station.generalInfo.reqLevel }) }}
|
||||
</span>
|
||||
|
||||
<!-- <span v-if="station.generalInfo.reqLevel > 0">
|
||||
- minimum {{ station.generalInfo.reqLevel }} poziom dyżurnego
|
||||
</span>
|
||||
<span v-else-if="station.generalInfo.reqLevel == 0">- dla wszystkich poziomów</span> -->
|
||||
</span>
|
||||
|
||||
<span>
|
||||
@@ -41,12 +36,17 @@
|
||||
<b> {{ $tc('scenery.authors-title', station.generalInfo.authors.length) }}: </b>
|
||||
{{ station.generalInfo.authors.join(', ') }}
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<div class="scenery-topic" v-if="station.generalInfo.url">
|
||||
<a :href="station.generalInfo.url" target="_blank">
|
||||
> {{ $t('scenery.forum-topic', { name: station.name }) }} <
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin: 2em 0; height: 2px; background-color: white" />
|
||||
|
||||
<!-- info stats -->
|
||||
<!-- <scenery-info-stats :station="station" /> -->
|
||||
<!-- info dispatcher -->
|
||||
<scenery-info-dispatcher :station="station" :onlineFrom="onlineFrom" />
|
||||
|
||||
@@ -57,10 +57,6 @@
|
||||
<!-- spawn list -->
|
||||
<scenery-info-spawn-list :station="station" />
|
||||
</div>
|
||||
|
||||
<!-- info icons -->
|
||||
|
||||
<!-- info routes -->
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
@@ -74,8 +70,8 @@ import SceneryInfoStats from './SceneryInfo/SceneryInfoStats.vue';
|
||||
import SceneryInfoUserList from './SceneryInfo/SceneryInfoUserList.vue';
|
||||
import SceneryInfoSpawnList from './SceneryInfo/SceneryInfoSpawnList.vue';
|
||||
import SceneryInfoRoutes from './SceneryInfo/SceneryInfoRoutes.vue';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@@ -103,6 +99,7 @@ export default defineComponent({
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../styles/responsive.scss';
|
||||
@import '../../styles/badge.scss';
|
||||
|
||||
h3.section-header {
|
||||
margin: 0.5em 0;
|
||||
@@ -143,32 +140,7 @@ h3.section-header {
|
||||
}
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-weight: 600;
|
||||
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
|
||||
background: #585858;
|
||||
|
||||
margin: 0.25em;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 0.2em 0.4em;
|
||||
}
|
||||
|
||||
&-none {
|
||||
font-weight: 600;
|
||||
|
||||
padding: 0.2em 0.4em;
|
||||
background: firebrick;
|
||||
|
||||
text-align: center;
|
||||
|
||||
@include smallScreen() {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
.scenery-topic a {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</router-link>
|
||||
|
||||
<span class="dispatcher_likes text--primary">
|
||||
<img :src="icons.like" alt="icon-like" />
|
||||
<img :src="getIcon('like')" alt="icon-like" />
|
||||
<span>{{ station.onlineInfo?.dispatcherRate || '0' }}</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -35,14 +35,14 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
import styleMixin from '@/mixins/styleMixin';
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import dateMixin from '@/mixins/dateMixin';
|
||||
import routerMixin from '@/mixins/routerMixin';
|
||||
import dateMixin from '../../../mixins/dateMixin';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import routerMixin from '../../../mixins/routerMixin';
|
||||
import styleMixin from '../../../mixins/styleMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [styleMixin, dateMixin, routerMixin],
|
||||
mixins: [styleMixin, dateMixin, routerMixin, imageMixin],
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
@@ -54,13 +54,6 @@ export default defineComponent({
|
||||
default: -1,
|
||||
},
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
icons: {
|
||||
spawn: require('@/assets/icon-spawn.svg'),
|
||||
like: require('@/assets/icon-like.svg'),
|
||||
},
|
||||
}),
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<img
|
||||
v-if="station.generalInfo?.SUP"
|
||||
class="icon-info"
|
||||
:src="require(`@/assets/icon-SUP.svg`)"
|
||||
:src="getIcon('SUP')"
|
||||
alt="SUP (RASP-UZK)"
|
||||
:title="$t('desc.SUP')"
|
||||
/>
|
||||
@@ -28,7 +28,7 @@
|
||||
<img
|
||||
v-if="station.generalInfo?.signalType"
|
||||
class="icon-info"
|
||||
:src="require(`@/assets/icon-${station.generalInfo.signalType}.svg`)"
|
||||
:src="getIcon(station.generalInfo.signalType)"
|
||||
:alt="station.generalInfo.signalType"
|
||||
:title="$t('desc.signals-type') + $t(`signals.${station.generalInfo.signalType}`)"
|
||||
/>
|
||||
@@ -36,7 +36,7 @@
|
||||
<img
|
||||
v-if="station.generalInfo?.availability == 'nonPublic'"
|
||||
class="icon-info"
|
||||
:src="icons.lock"
|
||||
:src="getIcon('lock')"
|
||||
alt="Non-public scenery"
|
||||
:title="$t('desc.non-public')"
|
||||
/>
|
||||
@@ -44,7 +44,7 @@
|
||||
<img
|
||||
v-if="station.generalInfo?.availability == 'unavailable'"
|
||||
class="icon-info"
|
||||
:src="icons.unavailable"
|
||||
:src="getIcon('unavailable')"
|
||||
alt="Unavailable scenery"
|
||||
:title="$t('desc.unavailable')"
|
||||
/>
|
||||
@@ -52,7 +52,7 @@
|
||||
<img
|
||||
v-if="station.generalInfo?.availability == 'abandoned'"
|
||||
class="icon-info"
|
||||
:src="icons.abandoned"
|
||||
:src="getIcon('abandoned')"
|
||||
alt="Abandoned scenery"
|
||||
:title="$t('desc.abandoned')"
|
||||
/>
|
||||
@@ -60,7 +60,7 @@
|
||||
<img
|
||||
v-if="station.generalInfo?.lines"
|
||||
class="icon-info"
|
||||
:src="icons.real"
|
||||
:src="getIcon('real')"
|
||||
alt="real scenery"
|
||||
:title="`${$t('desc.real')} ${station.generalInfo.lines}`"
|
||||
/>
|
||||
@@ -68,7 +68,7 @@
|
||||
<img
|
||||
v-if="!station.generalInfo"
|
||||
class="icon-info"
|
||||
:src="icons.unknown"
|
||||
:src="getImage('unknown.png')"
|
||||
alt="icon-unknown"
|
||||
:title="$t('desc.unknown')"
|
||||
/>
|
||||
@@ -77,31 +77,19 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import stationInfoMixin from '@/mixins/stationInfoMixin';
|
||||
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import styleMixin from '@/mixins/styleMixin';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import stationInfoMixin from '../../../mixins/stationInfoMixin';
|
||||
import styleMixin from '../../../mixins/styleMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [stationInfoMixin, styleMixin],
|
||||
mixins: [stationInfoMixin, styleMixin, imageMixin],
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
icons: {
|
||||
td2: require('@/assets/icon-td2.svg'),
|
||||
lock: require('@/assets/icon-lock.svg'),
|
||||
unavailable: require('@/assets/icon-unavailable.svg'),
|
||||
unknown: require('@/assets/icon-unknown.svg'),
|
||||
abandoned: require('@/assets/icon-abandoned.svg'),
|
||||
|
||||
real: require('@/assets/icon-real.svg'),
|
||||
},
|
||||
}),
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -130,3 +118,4 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -57,8 +57,8 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import { defineComponent } from 'vue';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section class="info-spawn-list">
|
||||
<h3 class="spawn-header section-header">
|
||||
<img :src="icons.spawn" alt="icon-spawn" />
|
||||
<img :src="getIcon('spawn')" alt="icon-spawn" />
|
||||
{{ $t('scenery.spawns') }}
|
||||
<span class="text--primary">{{ station.onlineInfo?.spawns.length || '0' }}</span>
|
||||
</h3>
|
||||
@@ -24,22 +24,19 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import { defineComponent } from 'vue';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [imageMixin],
|
||||
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
icons: {
|
||||
spawn: require('@/assets/icon-spawn.svg'),
|
||||
},
|
||||
}),
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<section class="info-stats" :class="!station.onlineInfo ? 'no-stats' : ''">
|
||||
<span class="likes">
|
||||
<img :src="icons.like" alt="icon-like" />
|
||||
<img :src="getIcon('like')" alt="icon-like" />
|
||||
<span>{{ station.onlineInfo?.dispatcherRate || '0' }}</span>
|
||||
</span>
|
||||
|
||||
<span class="users">
|
||||
<img :src="icons.user" alt="icon-user" />
|
||||
<img :src="getIcon('user')" alt="icon-user" />
|
||||
<span>{{ station.onlineInfo?.currentUsers || '0' }}</span>
|
||||
/
|
||||
<span>{{ station.onlineInfo?.maxUsers || '0' }}</span>
|
||||
</span>
|
||||
|
||||
<span class="spawns">
|
||||
<img :src="icons.spawn" alt="icon-spawn" />
|
||||
<img :src="getIcon('spawn')" alt="icon-spawn" />
|
||||
<span>{{ station.onlineInfo?.spawns.length || '0' }}</span>
|
||||
</span>
|
||||
|
||||
<span class="schedules">
|
||||
<img :src="icons.timetable" alt="icon-timetable" />
|
||||
<img :src="getIcon('timetable')" alt="icon-timetable" />
|
||||
<span>
|
||||
<span style="color: #eee">{{ station.onlineInfo?.scheduledTrains?.length || '0' }}</span>
|
||||
/
|
||||
@@ -32,25 +32,17 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [imageMixin],
|
||||
props: {
|
||||
station: {
|
||||
type: Object as () => Station,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
icons: {
|
||||
like: require('@/assets/icon-like.svg'),
|
||||
timetable: require('@/assets/icon-timetable.svg'),
|
||||
user: require('@/assets/icon-user.svg'),
|
||||
spawn: require('@/assets/icon-spawn.svg'),
|
||||
},
|
||||
}),
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -83,7 +75,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
span > img {
|
||||
width: 1.2em;
|
||||
width: 1.2em;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section class="info-user-list">
|
||||
<h3 class="user-header section-header">
|
||||
<img :src="icons.user" alt="icon-user" />
|
||||
<img :src="getIcon('user')" alt="icon-user" />
|
||||
{{ $t('scenery.users') }}
|
||||
<span class="text--primary">{{ station.onlineInfo?.currentUsers || '0' }}</span
|
||||
> / <span class="text--primary">{{ station.onlineInfo?.maxUsers || '0' }}</span>
|
||||
@@ -11,10 +11,10 @@
|
||||
v-for="(train, i) in computedStationTrains"
|
||||
class="badge user"
|
||||
:class="train.stopStatus"
|
||||
:key="train.trainNo + i"
|
||||
:key="train.trainId"
|
||||
tabindex="0"
|
||||
@click="navigateTo('/trains', { trainNo: train.trainNo, driverName: train.driverName })"
|
||||
@keydown.enter="navigateTo('/trains', { trainNo: train.trainNo, driverName: train.driverName })"
|
||||
@click="selectModalTrain(train.trainId)"
|
||||
@keydown.enter="selectModalTrain(train.trainId)"
|
||||
>
|
||||
<span class="user_train">{{ train.trainNo }}</span>
|
||||
<span class="user_name">{{ train.driverName }}</span>
|
||||
@@ -27,12 +27,16 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import routerMixin from '@/mixins/routerMixin';
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import imageMixin from '../../../mixins/imageMixin';
|
||||
import modalTrainMixin from '../../../mixins/modalTrainMixin';
|
||||
import routerMixin from '../../../mixins/routerMixin';
|
||||
import Station from '../../../scripts/interfaces/Station';
|
||||
import { useStore } from '../../../store/store';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [routerMixin],
|
||||
mixins: [routerMixin, imageMixin, modalTrainMixin],
|
||||
|
||||
props: {
|
||||
station: {
|
||||
@@ -42,6 +46,8 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const store = useStore();
|
||||
|
||||
const computedStationTrains = computed(() => {
|
||||
if (!props.station) return [];
|
||||
|
||||
@@ -59,14 +65,8 @@ export default defineComponent({
|
||||
});
|
||||
});
|
||||
|
||||
return { computedStationTrains };
|
||||
return { computedStationTrains, store };
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
icons: {
|
||||
user: require('@/assets/icon-user.svg'),
|
||||
},
|
||||
}),
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -130,3 +130,4 @@ $disconnected: slategray;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<section class="scenery-timetable">
|
||||
<div class="timetable-header">
|
||||
<h3>
|
||||
<img :src="icons.timetable" alt="icon-timetable" />
|
||||
<img :src="getIcon('timetable')" alt="icon-timetable" />
|
||||
<span>{{ $t('scenery.timetables') }}</span>
|
||||
|
||||
<span class="text--primary">{{ station.onlineInfo?.scheduledTrains?.length || '0' }}</span>
|
||||
@@ -32,7 +32,11 @@
|
||||
<Loading />
|
||||
</div>
|
||||
|
||||
<span class="timetable-item empty" v-else-if="computedScheduledTrains.length == 0">
|
||||
<span class="timetable-item empty" v-else-if="computedScheduledTrains.length == 0 && !station.onlineInfo">
|
||||
{{ $t('scenery.offline') }}
|
||||
</span>
|
||||
|
||||
<span class="timetable-item empty" v-else-if="computedScheduledTrains.length == 0">
|
||||
{{ $t('scenery.no-timetables') }}
|
||||
</span>
|
||||
|
||||
@@ -41,13 +45,8 @@
|
||||
v-for="(scheduledTrain, i) in computedScheduledTrains"
|
||||
:key="i + 1"
|
||||
tabindex="0"
|
||||
@click="navigateTo('/trains', { trainNo: scheduledTrain.trainNo, driverName: scheduledTrain.driverName })"
|
||||
@keydown.enter="
|
||||
navigateTo('/trains', {
|
||||
trainNo: scheduledTrain.trainNo,
|
||||
driverName: scheduledTrain.driverName,
|
||||
})
|
||||
"
|
||||
@click.prevent.stop="selectModalTrain(scheduledTrain.trainId)"
|
||||
@keydown.enter.prevent="selectModalTrain(scheduledTrain.trainId)"
|
||||
>
|
||||
<span class="timetable-general">
|
||||
<span class="general-info">
|
||||
@@ -56,7 +55,7 @@
|
||||
{{ scheduledTrain.trainNo }}
|
||||
|
||||
<span class="g-tooltip" v-if="scheduledTrain.stopInfo.comments">
|
||||
<img :src="icons.warning" />
|
||||
<img :src="getIcon('warning')" />
|
||||
<span class="content" v-html="scheduledTrain.stopInfo.comments"> </span>
|
||||
</span>
|
||||
</span>
|
||||
@@ -158,21 +157,25 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import SelectBox from '../Global/SelectBox.vue';
|
||||
import { computed, defineComponent, PropType, ref } from '@vue/runtime-core';
|
||||
import { useRoute } from 'vue-router';
|
||||
import dateMixin from '@/mixins/dateMixin';
|
||||
import routerMixin from '@/mixins/routerMixin';
|
||||
import { useStore } from '@/store/store';
|
||||
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import TrainModal from '../Global/TrainModal.vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import routerMixin from '../../mixins/routerMixin';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { useStore } from '../../store/store';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryTimetable',
|
||||
|
||||
components: { SelectBox, Loading },
|
||||
components: { SelectBox, Loading, TrainModal },
|
||||
|
||||
mixins: [dateMixin, routerMixin],
|
||||
mixins: [dateMixin, routerMixin, imageMixin, modalTrainMixin],
|
||||
|
||||
props: {
|
||||
station: {
|
||||
@@ -182,12 +185,8 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
viewIcon: require('@/assets/icon-view.svg'),
|
||||
listOpen: false,
|
||||
icons: {
|
||||
warning: require('@/assets/icon-warning.svg'),
|
||||
timetable: require('@/assets/icon-timetable.svg'),
|
||||
},
|
||||
|
||||
}),
|
||||
|
||||
setup(props) {
|
||||
|
||||
@@ -9,10 +9,13 @@
|
||||
<b>{{ localeDay(historyItem.beginDate, $i18n.locale) }}</b>
|
||||
{{ localeTime(historyItem.beginDate, $i18n.locale) }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="text--grayed"> #{{ historyItem.timetableId }} </span>
|
||||
<b class="text--primary"> {{ historyItem.trainCategoryCode }} {{ historyItem.trainNo }}</b>
|
||||
<div>{{ historyItem.driverName }}</div>
|
||||
<router-link :to="`/journal/timetables?timetableId=${historyItem.timetableId}`">
|
||||
<span class="text--grayed"> #{{ historyItem.timetableId }} </span>
|
||||
<b class="text--primary"> {{ historyItem.trainCategoryCode }} {{ historyItem.trainNo }}</b>
|
||||
<div>{{ historyItem.driverName }}</div>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<div>{{ historyItem.route.replace('|', ' -> ') }}</div>
|
||||
@@ -30,13 +33,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import dateMixin from '@/mixins/dateMixin';
|
||||
import { DataStatus } from '@/scripts/enums/DataStatus';
|
||||
import { SceneryTimetableHistory, TimetableHistory } from '@/scripts/interfaces/api/TimetablesAPIData';
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import { URLs } from '@/scripts/utils/apiURLs';
|
||||
|
||||
import axios from 'axios';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||
import { TimetableHistory, SceneryTimetableHistory } from '../../scripts/interfaces/api/TimetablesAPIData';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { URLs } from '../../scripts/utils/apiURLs';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
|
||||
export default defineComponent({
|
||||
@@ -102,9 +106,13 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
@include smallScreen {
|
||||
.history-list {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.list-item {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
font-size: 1.05em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<section class="filter-card" v-click-outside="closeCard">
|
||||
<div class="card_btn">
|
||||
<button class="btn btn--option" @click="toggleCard">
|
||||
<img class="button_icon" :src="filterIcon" alt="icon-filter" />
|
||||
<img class="button_icon" :src="getIcon('filter2')" alt="icon-filter" />
|
||||
{{ $t('options.filters') }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -91,21 +91,22 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, inject } from '@vue/runtime-core';
|
||||
|
||||
import inputData from '@/data/options.json';
|
||||
import { defineComponent, inject } from 'vue';
|
||||
import inputData from '../../data/options.json';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import StorageManager from '../../scripts/managers/storageManager';
|
||||
import { useStore } from '../../store/store';
|
||||
|
||||
import StorageManager from '@/scripts/managers/storageManager';
|
||||
import ActionButton from '../Global/ActionButton.vue';
|
||||
import FilterOption from './FilterOption.vue';
|
||||
import { useStore } from '@/store/store';
|
||||
|
||||
export default defineComponent({
|
||||
components: { ActionButton, FilterOption },
|
||||
emits: ['changeFilterValue', 'invertFilters', 'resetFilters'],
|
||||
mixins: [imageMixin],
|
||||
|
||||
data: () => ({
|
||||
filterIcon: require('@/assets/icon-filter2.svg'),
|
||||
|
||||
inputs: { ...inputData },
|
||||
saveOptions: false,
|
||||
@@ -165,7 +166,7 @@ export default defineComponent({
|
||||
handleAuthorsInput(e: Event) {
|
||||
clearTimeout(this.delayInputTimer);
|
||||
|
||||
this.delayInputTimer = setTimeout(() => {
|
||||
this.delayInputTimer = window.setTimeout(() => {
|
||||
this.handleInput(e);
|
||||
}, 400);
|
||||
},
|
||||
@@ -200,7 +201,7 @@ export default defineComponent({
|
||||
this.$emit('invertFilters');
|
||||
},
|
||||
|
||||
saveFilters(change: { value }) {
|
||||
saveFilters(change: { value: any }) {
|
||||
this.saveOptions = change.value;
|
||||
|
||||
if (!this.saveOptions) {
|
||||
@@ -257,8 +258,8 @@ export default defineComponent({
|
||||
|
||||
&-enter-from,
|
||||
&-leave-to {
|
||||
transform: translate(-50%, -50%) scale(0.8);
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -50%) scale(0.45);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<img
|
||||
class="sort-icon"
|
||||
v-if="sorterActive.index == i"
|
||||
:src="sorterActive.dir == 1 ? ascIcon : descIcon"
|
||||
:src="sorterActive.dir == 1 ? getIcon('arrow-asc') : getIcon('arrow-desc')"
|
||||
alt="sort icon"
|
||||
/>
|
||||
</span>
|
||||
@@ -23,12 +23,12 @@
|
||||
|
||||
<th v-for="(id, i) in headIconsIds" :key="id" @click="() => changeSorter(i + 7)">
|
||||
<span class="header_wrapper">
|
||||
<img :src="require(`@/assets/icon-${id}.svg`)" :alt="id" :title="$t(`sceneries.${id}s`)" />
|
||||
<img :src="getIcon(id)" :alt="id" :title="$t(`sceneries.${id}s`)" />
|
||||
|
||||
<img
|
||||
class="sort-icon"
|
||||
v-if="sorterActive.index == i + 7"
|
||||
:src="sorterActive.dir == 1 ? ascIcon : descIcon"
|
||||
:src="sorterActive.dir == 1 ? getIcon('arrow-asc') : getIcon('arrow-desc')"
|
||||
alt="sort icon"
|
||||
/>
|
||||
</span>
|
||||
@@ -67,15 +67,15 @@
|
||||
</span>
|
||||
|
||||
<span v-else-if="station.generalInfo.availability == 'abandoned'">
|
||||
<img :src="abandonedIcon" alt="non-public" :title="$t('desc.abandoned')" />
|
||||
<img :src="getIcon('abandoned')" alt="non-public" :title="$t('desc.abandoned')" />
|
||||
</span>
|
||||
|
||||
<span v-else-if="station.generalInfo.availability == 'nonPublic'">
|
||||
<img :src="lockIcon" alt="non-public" :title="$t('desc.non-public')" />
|
||||
<img :src="getIcon('lock')" alt="non-public" :title="$t('desc.non-public')" />
|
||||
</span>
|
||||
|
||||
<span v-else>
|
||||
<img :src="unavailableIcon" alt="unavailable" :title="$t('desc.unavailable')" />
|
||||
<img :src="getIcon('unavailable')" alt="unavailable" :title="$t('desc.unavailable')" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
<img
|
||||
class="icon-info"
|
||||
v-if="station.generalInfo.SUP"
|
||||
:src="require(`@/assets/icon-SUP.svg`)"
|
||||
:src="getIcon('SUP')"
|
||||
alt="SUP (RASP-UZK)"
|
||||
:title="$t('desc.SUP')"
|
||||
/>
|
||||
@@ -164,7 +164,7 @@
|
||||
<img
|
||||
class="icon-info"
|
||||
v-if="station.generalInfo.signalType"
|
||||
:src="require(`@/assets/icon-${station.generalInfo.signalType}.svg`)"
|
||||
:src="getIcon(station.generalInfo.signalType)"
|
||||
:alt="station.generalInfo.signalType"
|
||||
:title="$t('desc.signals-type') + $t(`signals.${station.generalInfo.signalType}`)"
|
||||
/>
|
||||
@@ -174,7 +174,7 @@
|
||||
<img
|
||||
class="icon-info"
|
||||
v-if="station.generalInfo && station.generalInfo.routes.sblRouteNames.length > 0"
|
||||
:src="SBLIcon"
|
||||
:src="getIcon('SBL')"
|
||||
alt="SBL"
|
||||
:title="$t('desc.SBL') + `${station.generalInfo.routes.sblRouteNames.join(',')}`"
|
||||
/>
|
||||
@@ -182,7 +182,7 @@
|
||||
</td>
|
||||
|
||||
<td class="station_info" v-else>
|
||||
<img class="icon-info" :src="unknownIcon" alt="icon-unknown" :title="$t('desc.unknown')" />
|
||||
<img class="icon-info" :src="getImage('unknown.png')" alt="icon-unknown" :title="$t('desc.unknown')" />
|
||||
</td>
|
||||
|
||||
<td class="station_users" :class="{ inactive: !station.onlineInfo }">
|
||||
@@ -222,16 +222,15 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import styleMixin from '@/mixins/styleMixin';
|
||||
import dateMixin from '@/mixins/dateMixin';
|
||||
import stationInfoMixin from '@/mixins/stationInfoMixin';
|
||||
import returnBtnMixin from '@/mixins/returnBtnMixin';
|
||||
|
||||
import { DataStatus } from '@/scripts/enums/DataStatus';
|
||||
import { computed, ComputedRef, defineComponent } from '@vue/runtime-core';
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import { StoreData } from '@/scripts/interfaces/StoreData';
|
||||
import { useStore } from '@/store/store';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import returnBtnMixin from '../../mixins/returnBtnMixin';
|
||||
import stationInfoMixin from '../../mixins/stationInfoMixin';
|
||||
import styleMixin from '../../mixins/styleMixin';
|
||||
import { DataStatus } from '../../scripts/enums/DataStatus';
|
||||
import Station from '../../scripts/interfaces/Station';
|
||||
import { useStore } from '../../store/store';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
|
||||
export default defineComponent({
|
||||
@@ -250,21 +249,8 @@ export default defineComponent({
|
||||
setFocusedStation: { type: Function, required: true },
|
||||
changeSorter: { type: Function, required: true },
|
||||
},
|
||||
mixins: [styleMixin, dateMixin, stationInfoMixin, returnBtnMixin],
|
||||
mixins: [styleMixin, dateMixin, stationInfoMixin, returnBtnMixin, imageMixin],
|
||||
data: () => ({
|
||||
likeIcon: require('@/assets/icon-like.svg'),
|
||||
spawnIcon: require('@/assets/icon-spawn.svg'),
|
||||
timetableIcon: require('@/assets/icon-timetable.svg'),
|
||||
userIcon: require('@/assets/icon-user.svg'),
|
||||
trainIcon: require('@/assets/icon-train.svg'),
|
||||
SBLIcon: require('@/assets/icon-SBL.svg'),
|
||||
SUPIcon: require('@/assets/icon-SUP.svg'),
|
||||
lockIcon: require('@/assets/icon-lock.svg'),
|
||||
unavailableIcon: require('@/assets/icon-unavailable.svg'),
|
||||
unknownIcon: require('@/assets/icon-unknown.svg'),
|
||||
abandonedIcon: require('@/assets/icon-abandoned.svg'),
|
||||
ascIcon: require('@/assets/icon-arrow-asc.svg'),
|
||||
descIcon: require('@/assets/icon-arrow-desc.svg'),
|
||||
headIds: ['station', 'min-lvl', 'status', 'dispatcher', 'dispatcher-lvl', 'routes', 'general'],
|
||||
headIconsIds: ['user', 'spawn', 'timetable'],
|
||||
lastSelectedStationName: '',
|
||||
|
||||
@@ -1,103 +1,72 @@
|
||||
<template>
|
||||
<div class="train-info simple" tabindex="0">
|
||||
<section>
|
||||
<span>
|
||||
<div>
|
||||
<span>
|
||||
<!-- <router-link
|
||||
v-if="train.timetableData"
|
||||
:to="`/journal/timetables?timetableId=${train.timetableData.timetableId}`"
|
||||
style="color: #ddd; margin-right: 0.3em"
|
||||
>
|
||||
#{{ train.timetableData.timetableId }}
|
||||
</router-link> -->
|
||||
<div class="train-info" tabindex="0">
|
||||
<section class="train-route">
|
||||
<div class="train_general">
|
||||
<span>
|
||||
<span class="timetable-id" v-if="train.timetableData">#{{ train.timetableData.timetableId }}</span>
|
||||
|
||||
<span class="timetable-id" v-if="train.timetableData">#{{ train.timetableData.timetableId }}</span>
|
||||
|
||||
<span class="timetable_warnings">
|
||||
<span class="warning twr" v-if="train.timetableData?.TWR">TWR</span>
|
||||
<span class="warning skr" v-if="train.timetableData?.SKR">SKR</span>
|
||||
</span>
|
||||
<strong v-if="train.timetableData">{{ train.timetableData.category }} </strong>
|
||||
<strong>{{ train.trainNo }}</strong>
|
||||
<span> | {{ train.driverName }} </span>
|
||||
<span class="timetable_warnings">
|
||||
<span class="train-badge twr" v-if="train.timetableData?.TWR">TWR</span>
|
||||
<span class="train-badge skr" v-if="train.timetableData?.SKR">SKR</span>
|
||||
</span>
|
||||
<strong v-if="train.timetableData">{{ train.timetableData.category }} </strong>
|
||||
<strong>{{ train.trainNo }}</strong>
|
||||
<span> | {{ train.driverName }} </span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<img
|
||||
class="image-offline"
|
||||
style="height: 1em"
|
||||
v-if="!train.currentStationHash"
|
||||
:src="icons.offline"
|
||||
alt="offline"
|
||||
:title="$t('trains.offline')"
|
||||
/>
|
||||
<div class="timetable_route" v-if="train.timetableData">
|
||||
<strong>{{ train.timetableData.route.replace('|', ' - ') }}</strong>
|
||||
<img
|
||||
v-if="getSceneriesWithComments(train.timetableData).length > 0"
|
||||
class="image-warning"
|
||||
:src="getIcon('warning')"
|
||||
:title="`${$t('trains.timetable-comments')} (${getSceneriesWithComments(train.timetableData)})`"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<hr style="margin: 0.25em 0" />
|
||||
|
||||
<div class="timetable_stops" v-if="train.timetableData">
|
||||
<span v-if="train.timetableData.followingStops.length > 2">
|
||||
{{ $t('trains.via-title') }}
|
||||
<span v-html="displayStopList(train.timetableData.followingStops)"></span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="timetable_progress" style="margin-top: 0.5em" v-if="train.timetableData">
|
||||
<!-- <span> </span> -->
|
||||
<span class="timetable_progress-bar">
|
||||
<!-- {{ confirmedPercentage(train.timetableData.followingStops) }}% -->
|
||||
<span class="bar-bg"></span>
|
||||
<span
|
||||
class="bar-fg"
|
||||
:style="{ width: `${Math.floor(confirmedPercentage(train.timetableData.followingStops))}%` }"
|
||||
></span>
|
||||
</span>
|
||||
|
||||
<span class="timetable_progress-distance">
|
||||
{{ currentDistance(train.timetableData.followingStops) }} km /
|
||||
<span class="text--primary"> {{ train.timetableData.routeDistance }} km </span>
|
||||
|
|
||||
<span v-html="currentDelay(train.timetableData.followingStops)"></span>
|
||||
</span>
|
||||
|
||||
<div class="train-status-badges">
|
||||
<div v-if="!train.currentStationHash" class="train-badge offline">{{ $t('trains.scenery-offline') }}</div>
|
||||
<div v-if="!train.online" class="train-badge offline">Offline {{ lastSeenMessage(train.lastSeen) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timetable_route" v-if="train.timetableData">
|
||||
<strong>{{ train.timetableData.route.replace('|', ' - ') }}</strong>
|
||||
<img
|
||||
v-if="getSceneriesWithComments(train.timetableData).length > 0"
|
||||
class="image-warning"
|
||||
:src="icons.warning"
|
||||
:title="`${$t('trains.timetable-comments')} (${getSceneriesWithComments(train.timetableData)})`"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<hr style="margin: 0.25em 0" />
|
||||
|
||||
<div class="timetable_stops" v-if="train.timetableData">
|
||||
<span v-if="train.timetableData.followingStops.length > 2">
|
||||
{{ $t('trains.via-title') }}
|
||||
<span v-html="displayStopList(train.timetableData.followingStops)"></span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="timetable_progress" style="margin-top: 0.5em" v-if="train.timetableData">
|
||||
<!-- <span> </span> -->
|
||||
<span class="timetable_progress-bar">
|
||||
<!-- {{ confirmedPercentage(train.timetableData.followingStops) }}% -->
|
||||
<span class="bar-bg"></span>
|
||||
<span
|
||||
class="bar-fg"
|
||||
:style="{ width: `${Math.floor(confirmedPercentage(train.timetableData.followingStops))}%` }"
|
||||
></span>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{{ currentDistance(train.timetableData.followingStops) }} km /
|
||||
<span class="text--primary"> {{ train.timetableData.routeDistance }} km </span>
|
||||
|
|
||||
<span v-html="currentDelay(train.timetableData.followingStops)"></span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="!train.online" style="color: salmon">Offline - {{ lastSeenMessage(train.lastSeen) }}</div>
|
||||
|
||||
<div class="driver_position text--grayed" style="margin-top: 0.25em">
|
||||
<span v-if="train.currentStationHash">
|
||||
{{ $t('trains.current-scenery') }} <span>{{ train['currentStationName'] }} </span>
|
||||
</span>
|
||||
|
||||
<span v-else>
|
||||
{{ $t('trains.current-scenery') }}
|
||||
<span>{{ train['currentStationName'].replace(/.[a-zA-Z0-9]+.sc/, '') }} (offline) </span>
|
||||
</span>
|
||||
|
||||
<span v-if="train.signal">
|
||||
{{ $t('trains.current-signal') }} <span>{{ train['signal'] }} </span>
|
||||
</span>
|
||||
|
||||
<span v-if="train.connectedTrack">
|
||||
{{ $t('trains.current-track') }} <span>{{ train['connectedTrack'] }} </span>
|
||||
</span>
|
||||
|
||||
<span v-if="train.distance">({{ displayDistance(train.distance) }})</span>
|
||||
</div>
|
||||
</span>
|
||||
<div class="driver_position text--grayed" style="margin-top: 0.25em">
|
||||
{{ displayTrainPosition(train) }}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="train-image" style="display: flex; justify-content: center; align-items: center">
|
||||
<img :src="train.locoURL" loading="lazy" alt="Loco image not found" @error="onImageError" />
|
||||
<section class="train-stats">
|
||||
<div>
|
||||
<img :src="train.locoURL" loading="lazy" alt="Loco image not found" @error="onImageError" />
|
||||
</div>
|
||||
|
||||
<div class="text--grayed">
|
||||
{{ train.locoType }}
|
||||
@@ -108,21 +77,20 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<span v-for="(stat, i) in STATS.main" :key="stat.name">
|
||||
<span v-if="i > 0"> • </span>
|
||||
<span>{{ `${~~(train[stat.name] * (stat.multiplier || 1))}${stat.unit}` }} </span>
|
||||
</span>
|
||||
</div>
|
||||
<span v-for="(stat, i) in STATS.main" :key="stat.name">
|
||||
<span v-if="i > 0"> • </span>
|
||||
<span>{{ `${~~((train as any)[stat.name] * (stat.multiplier || 1))}${stat.unit}` }} </span>
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import trainInfoMixin from '@/mixins/trainInfoMixin';
|
||||
import Train from '@/scripts/interfaces/Train';
|
||||
import { defineComponent } from 'vue';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import trainInfoMixin from '../../mixins/trainInfoMixin';
|
||||
import Train from '../../scripts/interfaces/Train';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -130,32 +98,33 @@ export default defineComponent({
|
||||
type: Object as () => Train,
|
||||
required: true,
|
||||
},
|
||||
|
||||
extended: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
|
||||
mixins: [trainInfoMixin],
|
||||
|
||||
data: () => ({
|
||||
icons: {
|
||||
warning: require('@/assets/icon-warning.svg'),
|
||||
offline: require('@/assets/icon-offline.svg'),
|
||||
},
|
||||
}),
|
||||
mixins: [trainInfoMixin, imageMixin],
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../styles/responsive.scss';
|
||||
|
||||
.image-warning,
|
||||
.image-offline {
|
||||
.image-warning {
|
||||
height: 1em;
|
||||
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.train-image {
|
||||
.train-stats {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
margin: 0.5em 0;
|
||||
@@ -163,18 +132,15 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
.simple {
|
||||
.train-info {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
|
||||
padding: 1em;
|
||||
background-color: #202020;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
.driver_position:first-letter {
|
||||
text-transform: capitalize;
|
||||
background-color: #1a1a1a;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
.timetable-id {
|
||||
@@ -186,6 +152,37 @@ export default defineComponent({
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
.train_general {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.train-status-badges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.train-badge {
|
||||
padding: 0.15em 0.35em;
|
||||
margin-right: 0.3em;
|
||||
|
||||
font-weight: bold;
|
||||
|
||||
font-size: 0.9em;
|
||||
|
||||
&.twr {
|
||||
background-color: var(--clr-twr);
|
||||
}
|
||||
|
||||
&.skr {
|
||||
background-color: var(--clr-skr);
|
||||
}
|
||||
|
||||
&.offline {
|
||||
background-color: #b83b2d;
|
||||
}
|
||||
}
|
||||
|
||||
.timetable_route {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -195,22 +192,6 @@ export default defineComponent({
|
||||
|
||||
.timetable_warnings {
|
||||
color: black;
|
||||
|
||||
.warning {
|
||||
padding: 0.1em 0.3em;
|
||||
margin-right: 0.3em;
|
||||
border-radius: 1em;
|
||||
|
||||
font-weight: bold;
|
||||
|
||||
&.twr {
|
||||
background: var(--clr-twr);
|
||||
}
|
||||
|
||||
&.skr {
|
||||
background: var(--clr-skr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.timetable_progress {
|
||||
@@ -244,6 +225,10 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
.timetable_progress-distance {
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
|
||||
.comments {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -258,16 +243,28 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
@include smallScreen() {
|
||||
.simple {
|
||||
.train-info {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1em 0;
|
||||
text-align: center;
|
||||
|
||||
font-size: 1.25em;
|
||||
font-size: 1.15em;
|
||||
}
|
||||
|
||||
.info-stats {
|
||||
text-align: center;
|
||||
.train-stats {
|
||||
font-size: 1.1em;
|
||||
|
||||
img {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.train_general {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.train-status-badges {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.timetable_route {
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
<div class="search-box">
|
||||
<input class="search-input" v-model="searchedTrain" :placeholder="$t('trains.search-train')" />
|
||||
|
||||
<img class="search-exit" :src="exitIcon" alt="exit-icon" @click="() => (searchedTrain = '')" />
|
||||
<img class="search-exit" :src="getIcon('exit')" alt="exit-icon" @click="() => (searchedTrain = '')" />
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
<input class="search-input" v-model="searchedDriver" :placeholder="$t('trains.search-driver')" />
|
||||
|
||||
<img class="search-exit" :src="exitIcon" alt="exit-icon" @click="() => (searchedDriver = '')" />
|
||||
<img class="search-exit" :src="getIcon('exit')" alt="exit-icon" @click="() => (searchedDriver = '')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -58,15 +58,13 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, TrainFilter } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import SelectBox from '../Global/SelectBox.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { SelectBox },
|
||||
emits: ['changeSearchedTrain', 'changeSearchedDriver', 'changeSorter'],
|
||||
|
||||
data: () => ({
|
||||
exitIcon: require('@/assets/icon-exit.svg'),
|
||||
}),
|
||||
mixins: [imageMixin],
|
||||
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<section class="filter-card" v-click-outside="closeCard">
|
||||
<div class="card_btn">
|
||||
<action-button @click="toggleCard">
|
||||
<img class="button_icon" :src="filterIcon" alt="icon-filter" />
|
||||
<img class="button_icon" :src="getIcon('filter2')" alt="icon-filter" />
|
||||
<p>{{ $t('options.filters') }}</p>
|
||||
</action-button>
|
||||
</div>
|
||||
@@ -26,13 +26,13 @@
|
||||
<div class="search-box">
|
||||
<input class="search-input" v-model="searchedTrain" :placeholder="$t('trains.search-train')" />
|
||||
|
||||
<img class="search-exit" :src="exitIcon" alt="exit-icon" @click="() => (searchedTrain = '')" />
|
||||
<img class="search-exit" :src="getIcon('exit')" alt="exit-icon" @click="() => (searchedTrain = '')" />
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
<input class="search-input" v-model="searchedDriver" :placeholder="$t('trains.search-driver')" />
|
||||
|
||||
<img class="search-exit" :src="exitIcon" alt="exit-icon" @click="() => (searchedDriver = '')" />
|
||||
<img class="search-exit" :src="getIcon('exit')" alt="exit-icon" @click="() => (searchedDriver = '')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -50,24 +50,21 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, inject } from '@vue/runtime-core';
|
||||
import inputData from "../../data/options.json";
|
||||
|
||||
import inputData from '@/data/options.json';
|
||||
|
||||
import ActionButton from '@/components/Global/ActionButton.vue';
|
||||
import { sorterOptions } from '@/data/trainOptions';
|
||||
import { TrainFilter, computed } from 'vue';
|
||||
import { TrainFilter, computed, defineComponent, inject } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import SelectBox from '../Global/SelectBox.vue';
|
||||
import ActionButton from '../Global/ActionButton.vue';
|
||||
import { sorterOptions } from '../../data/trainOptions';
|
||||
import imageMixin from "../../mixins/imageMixin";
|
||||
|
||||
export default defineComponent({
|
||||
components: { ActionButton, SelectBox },
|
||||
emits: ['changeFilterValue', 'invertFilters', 'resetFilters'],
|
||||
mixins: [imageMixin],
|
||||
|
||||
data: () => ({
|
||||
filterIcon: require('@/assets/icon-filter2.svg'),
|
||||
exitIcon: require('@/assets/icon-exit.svg'),
|
||||
|
||||
inputs: { ...inputData },
|
||||
}),
|
||||
|
||||
@@ -128,18 +125,6 @@ export default defineComponent({
|
||||
@import '../../styles/responsive';
|
||||
@import '../../styles/card';
|
||||
|
||||
.card-anim {
|
||||
&-enter-active,
|
||||
&-leave-active {
|
||||
transition: all $animDuration $animType;
|
||||
}
|
||||
|
||||
&-enter-from,
|
||||
&-leave-to {
|
||||
transform: translate(-50%, -50%) scale(0.85);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
section {
|
||||
|
||||
@@ -60,11 +60,11 @@
|
||||
<b>{{ stop.stopNameRAW }} </b>: <span v-html="stop.comments"></span>
|
||||
</div>
|
||||
|
||||
<span v-if="stop.departureLine == train.timetableData!.followingStops[i + 1].arrivalLine">
|
||||
<span v-if="stop.departureLine == train.timetableData!.followingStops[i + 1].arrivalLine && !/sbl/gi.test(stop.departureLine!)">
|
||||
{{ stop.departureLine }}
|
||||
</span>
|
||||
|
||||
<span v-else>
|
||||
<span v-else-if="!/sbl/gi.test(stop.departureLine!)">
|
||||
{{ stop.departureLine }} /
|
||||
{{ train.timetableData!.followingStops[i + 1].arrivalLine }}
|
||||
</span>
|
||||
@@ -83,10 +83,11 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from '@vue/runtime-core';
|
||||
import dateMixin from '@/mixins/dateMixin';
|
||||
import TrainStop from '@/scripts/interfaces/TrainStop';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import Train from '../../scripts/interfaces/Train';
|
||||
import TrainStop from '../../scripts/interfaces/TrainStop';
|
||||
import StopDate from '../Global/StopDate.vue';
|
||||
import Train from '@/scripts/interfaces/Train';
|
||||
|
||||
export default defineComponent({
|
||||
components: { StopDate },
|
||||
@@ -97,16 +98,10 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
|
||||
mixins: [dateMixin],
|
||||
mixins: [dateMixin, imageMixin],
|
||||
|
||||
emits: ['click'],
|
||||
|
||||
data: () => ({
|
||||
icons: {
|
||||
warning: require('@/assets/icon-warning.svg'),
|
||||
},
|
||||
}),
|
||||
|
||||
setup(props) {
|
||||
return {
|
||||
lastConfirmed: computed(() => {
|
||||
@@ -154,7 +149,7 @@ export default defineComponent({
|
||||
|
||||
onImageError(e: Event) {
|
||||
const imageEl = e.target as HTMLImageElement;
|
||||
imageEl.src = require('@/assets/unknown.png');
|
||||
imageEl.src = this.getImage('unknown.png');
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -179,7 +174,6 @@ $stopNameClr: #22a8d1;
|
||||
}
|
||||
|
||||
.train-schedule {
|
||||
background-color: #202020;
|
||||
padding: 0 0.25em;
|
||||
|
||||
@include smallScreen() {
|
||||
@@ -192,10 +186,11 @@ $stopNameClr: #22a8d1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
ul.stock-list {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
overflow-x: auto;
|
||||
overflow: auto;
|
||||
padding-bottom: 1em;
|
||||
|
||||
li > div {
|
||||
@@ -207,7 +202,6 @@ ul.stock-list {
|
||||
|
||||
.schedule-wrapper {
|
||||
overflow-y: auto;
|
||||
max-height: 500px;
|
||||
width: 100%;
|
||||
z-index: 5;
|
||||
|
||||
@@ -278,13 +272,14 @@ ul.stop_list > li.stop {
|
||||
padding: 0 0.5em;
|
||||
|
||||
&.sbl {
|
||||
.stop-name,
|
||||
.stop-date {
|
||||
opacity: 0.7;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.stop-name {
|
||||
background-color: #333;
|
||||
background: none;
|
||||
color: #aaa;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,8 +376,6 @@ ul.stop_list > li.stop {
|
||||
text-align: center;
|
||||
|
||||
flex-wrap: wrap;
|
||||
|
||||
padding: 0.15em 0;
|
||||
}
|
||||
|
||||
.stop-bar {
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
<template>
|
||||
<div class="train-stats" v-click-outside="closeStats">
|
||||
<action-button class="stats_button" @click="toggleStatsOpen">
|
||||
<img :src="statsIcon" :alt="$t('trains.stats')" />
|
||||
<p>{{ $t("trains.stats") }}</p>
|
||||
<img :src="getIcon('stats')" :alt="$t('trains.stats')" />
|
||||
<p>{{ $t('trains.stats') }}</p>
|
||||
</action-button>
|
||||
|
||||
<transition name="stats-anim" class="stats_wrapper" tag="div">
|
||||
<div class="stats-body" v-if="trainStatsOpen">
|
||||
<h2 class="stats-header">
|
||||
<img :src="statsIcon" :alt="$t('trains.stats')" />
|
||||
{{ $t("trains.stats") }}
|
||||
<img :src="getIcon('stats')" :alt="$t('trains.stats')" />
|
||||
{{ $t('trains.stats') }}
|
||||
</h2>
|
||||
|
||||
<div class="stats-speed">
|
||||
<div class="title stats-title">
|
||||
{{ $t("trains.stats-speed") }}
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
{{ speedStats.min }} | {{ speedStats.avg }} | {{ speedStats.max }}
|
||||
{{ $t('trains.stats-speed') }}
|
||||
</div>
|
||||
<div class="stats-content">{{ speedStats.min }} | {{ speedStats.avg }} | {{ speedStats.max }}</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-length">
|
||||
<div class="title stats-title">
|
||||
{{ $t("trains.stats-length") }}
|
||||
{{ $t('trains.stats-length') }}
|
||||
</div>
|
||||
<div class="stats-content">
|
||||
{{ timetableStats.min }} | {{ timetableStats.avg }} |
|
||||
@@ -33,15 +31,11 @@
|
||||
|
||||
<div class="stats-categories">
|
||||
<div class="title stats-title">
|
||||
{{ $t("trains.stats-categories") }}
|
||||
{{ $t('trains.stats-categories') }}
|
||||
</div>
|
||||
|
||||
<div class="category-list">
|
||||
<span
|
||||
class="category"
|
||||
v-for="[key, value] of categoryList"
|
||||
:key="key"
|
||||
>
|
||||
<span class="category" v-for="[key, value] of categoryList" :key="key">
|
||||
<span class="category-type">{{ key }}</span>
|
||||
<span class="category-count">{{ value }}</span>
|
||||
</span>
|
||||
@@ -49,28 +43,22 @@
|
||||
|
||||
<div class="special-list">
|
||||
<span class="special twr">
|
||||
<span class="special-type">{{
|
||||
$t("trains.stats-special-twr")
|
||||
}}</span>
|
||||
<span class="special-type">{{ $t('trains.stats-special-twr') }}</span>
|
||||
<span class="special-count">{{ specialTrainCount[0] }}</span>
|
||||
</span>
|
||||
|
||||
<span class="special skr">
|
||||
<span class="special-type">{{
|
||||
$t("trains.stats-special-skr")
|
||||
}}</span>
|
||||
<span class="special-type">{{ $t('trains.stats-special-skr') }}</span>
|
||||
<span class="special-count">{{ specialTrainCount[1] }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-locos">
|
||||
<div class="title stats-title">{{ $t("trains.stats-locos") }}</div>
|
||||
<div class="title stats-title">{{ $t('trains.stats-locos') }}</div>
|
||||
|
||||
<div class="loco-list stats-content">
|
||||
<div class="loco-item" v-for="(loco, i) in locoList" :key="i">
|
||||
{{ loco[0] }} | {{ loco[1] }}
|
||||
</div>
|
||||
<div class="loco-item" v-for="(loco, i) in locoList" :key="i">{{ loco[0] }} | {{ loco[1] }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -79,13 +67,15 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import ActionButton from "@/components/Global/ActionButton.vue";
|
||||
|
||||
import Train from "@/scripts/interfaces/Train";
|
||||
import { computed, defineComponent, inject } from "@vue/runtime-core";
|
||||
import { defineComponent, computed, inject } from 'vue';
|
||||
import imageMixin from '../../mixins/imageMixin';
|
||||
import Train from '../../scripts/interfaces/Train';
|
||||
import ActionButton from '../Global/ActionButton.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { ActionButton },
|
||||
mixins: [imageMixin],
|
||||
|
||||
props: {
|
||||
trains: {
|
||||
type: Array as () => Train[],
|
||||
@@ -95,7 +85,6 @@ export default defineComponent({
|
||||
|
||||
data: () => ({
|
||||
trainStatsOpen: false,
|
||||
statsIcon: require("@/assets/icon-stats.svg"),
|
||||
}),
|
||||
|
||||
methods: {
|
||||
@@ -110,14 +99,11 @@ export default defineComponent({
|
||||
|
||||
setup(props) {
|
||||
const speedStats = computed(() => {
|
||||
if (props.trains.length == 0) return { avg: "0", min: "0", max: "0" };
|
||||
if (props.trains.length == 0) return { avg: '0', min: '0', max: '0' };
|
||||
|
||||
const trainList = props.trains.filter((train) => train.timetableData);
|
||||
|
||||
const avg = (
|
||||
trainList.reduce((acc, train) => acc + train.speed, 0) /
|
||||
trainList.length
|
||||
).toFixed(2);
|
||||
const avg = (trainList.reduce((acc, train) => acc + train.speed, 0) / trainList.length).toFixed(2);
|
||||
|
||||
const minMaxSpeed = trainList.reduce((acc, train) => {
|
||||
if (!train.timetableData) return acc;
|
||||
@@ -136,32 +122,21 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const timetableStats = computed(() => {
|
||||
if (props.trains.length == 0) return { avg: "0", min: "0", max: "0" };
|
||||
if (props.trains.length == 0) return { avg: '0', min: '0', max: '0' };
|
||||
|
||||
const activeTrainsLength = props.trains.filter(
|
||||
(train) => train.timetableData
|
||||
).length;
|
||||
const activeTrainsLength = props.trains.filter((train) => train.timetableData).length;
|
||||
|
||||
const avg = (
|
||||
props.trains.reduce(
|
||||
(acc, train) =>
|
||||
train.timetableData ? acc + train.timetableData.routeDistance : acc,
|
||||
0
|
||||
) / activeTrainsLength
|
||||
props.trains.reduce((acc, train) => (train.timetableData ? acc + train.timetableData.routeDistance : acc), 0) /
|
||||
activeTrainsLength
|
||||
).toFixed(2);
|
||||
|
||||
const minMaxDistance = props.trains.reduce((acc, train) => {
|
||||
if (!train.timetableData) return acc;
|
||||
|
||||
acc[0] =
|
||||
!acc[0] || train.timetableData.routeDistance < acc[0]
|
||||
? train.timetableData.routeDistance
|
||||
: acc[0];
|
||||
acc[0] = !acc[0] || train.timetableData.routeDistance < acc[0] ? train.timetableData.routeDistance : acc[0];
|
||||
|
||||
acc[1] =
|
||||
!acc[1] || train.timetableData.routeDistance > acc[1]
|
||||
? train.timetableData.routeDistance
|
||||
: acc[1];
|
||||
acc[1] = !acc[1] || train.timetableData.routeDistance > acc[1] ? train.timetableData.routeDistance : acc[1];
|
||||
return acc;
|
||||
}, [] as any);
|
||||
|
||||
@@ -178,9 +153,7 @@ export default defineComponent({
|
||||
|
||||
acc.set(
|
||||
train.timetableData.category,
|
||||
acc.get(train.timetableData.category)
|
||||
? acc.get(train.timetableData.category) + 1
|
||||
: 1
|
||||
acc.get(train.timetableData.category) ? acc.get(train.timetableData.category) + 1 : 1
|
||||
);
|
||||
|
||||
return acc;
|
||||
@@ -193,35 +166,26 @@ export default defineComponent({
|
||||
const map: Map<string, number> = props.trains.reduce((acc, train) => {
|
||||
if (!train.timetableData || !train.locoType) return acc;
|
||||
|
||||
acc.set(
|
||||
train.locoType,
|
||||
acc.get(train.locoType) ? acc.get(train.locoType) + 1 : 1
|
||||
);
|
||||
acc.set(train.locoType, acc.get(train.locoType) ? acc.get(train.locoType) + 1 : 1);
|
||||
|
||||
return acc;
|
||||
}, new Map());
|
||||
|
||||
const sorted = [...map.entries()]
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.filter((v, i) => i < 3);
|
||||
const sorted = [...map.entries()].sort((a, b) => b[1] - a[1]).filter((v, i) => i < 3);
|
||||
|
||||
return sorted;
|
||||
});
|
||||
|
||||
const specialTrainCount = computed(() => {
|
||||
const twrList = props.trains.filter(
|
||||
(train) => train.timetableData && train.timetableData.TWR
|
||||
);
|
||||
const twrList = props.trains.filter((train) => train.timetableData && train.timetableData.TWR);
|
||||
|
||||
const skrList = props.trains.filter(
|
||||
(train) => train.timetableData && train.timetableData.SKR
|
||||
);
|
||||
const skrList = props.trains.filter((train) => train.timetableData && train.timetableData.SKR);
|
||||
|
||||
return [twrList.length, skrList.length];
|
||||
});
|
||||
|
||||
/* Inject list from TrainsView for category filter */
|
||||
const chosenTrainCategories = inject("chosenTrainCategories") as string[];
|
||||
const chosenTrainCategories = inject('chosenTrainCategories') as string[];
|
||||
|
||||
return {
|
||||
speedStats,
|
||||
@@ -229,14 +193,14 @@ export default defineComponent({
|
||||
categoryList,
|
||||
locoList,
|
||||
specialTrainCount,
|
||||
chosenTrainCategories
|
||||
chosenTrainCategories,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../styles/responsive";
|
||||
@import '../../styles/responsive';
|
||||
|
||||
.stats-anim {
|
||||
&-enter-active,
|
||||
@@ -370,4 +334,4 @@ export default defineComponent({
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
<template>
|
||||
<div class="train-table" @keydown.esc="closeTimetable">
|
||||
<button class="return-btn" @click="scrollToTop" v-if="showReturnButton">
|
||||
<img :src="icons.arrowAsc" alt="return arrow" />
|
||||
</button>
|
||||
|
||||
<div class="train-table">
|
||||
<transition name="anim" mode="out-in">
|
||||
<div :key="store.dataStatuses.trains">
|
||||
<Loading v-if="trains.length == 0 && store.dataStatuses.trains == 0" />
|
||||
@@ -16,13 +12,11 @@
|
||||
<li
|
||||
class="train-row"
|
||||
v-for="train in currentTrains"
|
||||
:key="train.trainNo + train.driverId"
|
||||
@click="toggleTimetable(train)"
|
||||
@keydown.enter="toggleTimetable(train)"
|
||||
:key="train.trainId"
|
||||
@click.stop="selectModalTrain(train.trainId)"
|
||||
@keydown.enter="selectModalTrain(train.trainId)"
|
||||
>
|
||||
<TrainInfo :train="train" />
|
||||
|
||||
<TrainSchedule v-if="chosenTrainId == getTrainId(train)" :train="train" ref="card-inner" tabindex="0" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -31,27 +25,25 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, inject, Ref } from '@vue/runtime-core';
|
||||
|
||||
import defaultVehicleIconsJSON from '@/data/defaultVehicleIcons.json';
|
||||
|
||||
import Train from '@/scripts/interfaces/Train';
|
||||
|
||||
import TrainSchedule from '@/components/TrainsView/TrainSchedule.vue';
|
||||
import TrainInfo from '@/components/TrainsView/TrainInfo.vue';
|
||||
|
||||
import returnBtnMixin from '@/mixins/returnBtnMixin';
|
||||
import { useStore } from '@/store/store';
|
||||
import { defineComponent, inject, Ref, computed } from 'vue';
|
||||
import modalTrainMixin from '../../mixins/modalTrainMixin';
|
||||
import returnBtnMixin from '../../mixins/returnBtnMixin';
|
||||
import Train from '../../scripts/interfaces/Train';
|
||||
import { useStore } from '../../store/store';
|
||||
import Loading from '../Global/Loading.vue';
|
||||
import TrainModal from '../Global/TrainModal.vue';
|
||||
import TrainInfo from './TrainInfo.vue';
|
||||
import TrainSchedule from './TrainSchedule.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
TrainSchedule,
|
||||
TrainInfo,
|
||||
Loading,
|
||||
TrainModal,
|
||||
},
|
||||
|
||||
mixins: [returnBtnMixin],
|
||||
mixins: [returnBtnMixin, modalTrainMixin],
|
||||
|
||||
props: {
|
||||
trains: {
|
||||
@@ -60,18 +52,6 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
defaultLocoImage: require('@/assets/unknown.png'),
|
||||
|
||||
icons: {
|
||||
arrowAsc: require('@/assets/icon-arrow-asc.svg'),
|
||||
arrowDesc: require('@/assets/icon-arrow-desc.svg'),
|
||||
},
|
||||
|
||||
defaultVehicleIcons: defaultVehicleIconsJSON,
|
||||
chosenTrainId: null as string | null,
|
||||
}),
|
||||
|
||||
setup(props) {
|
||||
const store = useStore();
|
||||
|
||||
@@ -103,15 +83,11 @@ export default defineComponent({
|
||||
this.searchedTrain = query.trainNo.toString();
|
||||
|
||||
setTimeout(() => {
|
||||
this.chosenTrainId = query.driverName + <string>query.trainNo;
|
||||
this.selectModalTrain(query.driverName + <string>query.trainNo);
|
||||
}, 20);
|
||||
}
|
||||
},
|
||||
|
||||
deactivated() {
|
||||
this.chosenTrainId = null;
|
||||
},
|
||||
|
||||
methods: {
|
||||
enter(el: HTMLElement) {
|
||||
const maxHeight = getComputedStyle(el).height;
|
||||
@@ -137,24 +113,6 @@ export default defineComponent({
|
||||
}, 10);
|
||||
},
|
||||
|
||||
toggleTimetable(train: Train, state?: boolean) {
|
||||
const id = this.getTrainId(train);
|
||||
|
||||
if (state !== undefined) {
|
||||
this.chosenTrainId = state ? id : null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.chosenTrainId = this.chosenTrainId && this.chosenTrainId == id ? null : id;
|
||||
},
|
||||
|
||||
closeTimetable() {
|
||||
this.chosenTrainId = null;
|
||||
},
|
||||
|
||||
getTrainId(train: Train) {
|
||||
return train.driverName + train.trainNo.toString();
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { JournalFilterType } from "@/scripts/enums/JournalFilterType";
|
||||
import { JournalFilter } from "vue";
|
||||
import { JournalFilterType } from "../scripts/enums/JournalFilterType";
|
||||
|
||||
export const journalTimetableFilters: JournalFilter[] = [
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TrainFilterType } from "@/scripts/enums/TrainFilterType";
|
||||
import { TrainFilter } from "vue";
|
||||
import { TrainFilterType } from "../scripts/enums/TrainFilterType";
|
||||
|
||||
export const trainFilters: TrainFilter[] = [
|
||||
{
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
"migration-warning": "Stacjownik services will be unavailable 2/06/2022 between 1-3am (CEST time) due to the migration of API hostings!",
|
||||
"migration-confirm": "Roger that!"
|
||||
},
|
||||
"update": {
|
||||
"title": "New Stacjownik version is available!",
|
||||
"paragraph1": "Enjoy the application and may the green signal be with you!",
|
||||
"release-link": "Click here to browse version changelog (GitHub)",
|
||||
"confirm-button": "Understood!"
|
||||
},
|
||||
"data-status": {
|
||||
"S1a-connection": "<b>S1a signal</b> <br> Cannot connect with Stacjownik API service!",
|
||||
"S1a-sceneries": "<b>S1a signal</b> <br> Cannot load online stations data!",
|
||||
@@ -185,9 +191,11 @@
|
||||
"comment": "Exploitation comments for: ",
|
||||
"table-limit": "For performance reasons there's a limit of 10 trains shown at the same time.",
|
||||
|
||||
"last-seen-now": "last seen: just now",
|
||||
"last-seen-min": "last seen: one minute ago",
|
||||
"last-seen-ago": "last seen: {minutes} mins ago"
|
||||
"last-seen-now": "since now",
|
||||
"last-seen-min": "since one minute",
|
||||
"last-seen-ago": "since {minutes} minutes",
|
||||
|
||||
"scenery-offline": "Offline ride"
|
||||
},
|
||||
"journal": {
|
||||
"title": "DISPATCHER HISTORY",
|
||||
@@ -198,7 +206,7 @@
|
||||
"section-dispatchers": "DISPATCHERS",
|
||||
|
||||
"search": "Search",
|
||||
"search-train": "Train no.",
|
||||
"search-train": "Train no. / #",
|
||||
"search-driver": "Driver name",
|
||||
"search-dispatcher": "Dispatcher name",
|
||||
"search-station": "Scenery name",
|
||||
@@ -238,6 +246,7 @@
|
||||
"spawns": "OPEN SPAWNS",
|
||||
"timetables": "ACTIVE TIMETABLES",
|
||||
"no-timetables": "No active timetables!",
|
||||
"offline": "Scenery is offline",
|
||||
"no-users": "NO ACTIVE PLAYERS",
|
||||
"no-spawns": "NO OPEN SPAWNS",
|
||||
"no-scenery": "Oops! This scenery doesn't exist!",
|
||||
@@ -258,12 +267,14 @@
|
||||
"timetable-author-unknown": "Author unknown",
|
||||
|
||||
"req-level": "all dispatcher levels | dispatcher level {lvl} required | dispatcher level {lvl} required",
|
||||
"history-list-empty": "No recorded scenery history!"
|
||||
"history-list-empty": "No recorded scenery history!",
|
||||
|
||||
"forum-topic": "Official {name} forum topic"
|
||||
},
|
||||
"availability": {
|
||||
"title": "Availability",
|
||||
"default": "in-game",
|
||||
"nonDefault": "downloadable",
|
||||
"nonDefault": "additional",
|
||||
"unavailable": "unavailable",
|
||||
"nonPublic": "private",
|
||||
"abandoned": "abandoned"
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
"migration-confirm": "Przyjąłem!"
|
||||
},
|
||||
|
||||
"update": {
|
||||
"title": "Nowa wersja Stacjownika jest dostępna!",
|
||||
"paragraph1": "Miłego korzystania z aplikacji i niech S2 będzie z wami!",
|
||||
"release-link": "Kliknij, aby przejrzeć listę zmian (GitHub)",
|
||||
"confirm-button": "Przyjąłem!"
|
||||
},
|
||||
|
||||
"data-status": {
|
||||
"S1a-connection": "<b>Sygnał S1a</b> <br> Błąd podczas próby połączenia się z API Stacjownika!",
|
||||
"S1a-sceneries": "<b>Sygnał S1a</b> <br> Błąd podczas pobierania danych o sceneriach online!",
|
||||
@@ -186,9 +193,11 @@
|
||||
"comment": "Uwagi eksploatacyjne dla: ",
|
||||
"table-limit": "Dla płynności działania strony pokazanych jest tylko 10 pociągów zgodnie z wybranymi filtrami.",
|
||||
|
||||
"last-seen-now": "ostatnio widziany: przed chwilą",
|
||||
"last-seen-min": "ostatnio widziany: minutę temu",
|
||||
"last-seen-ago": "ostatnio widziany: {minutes} min. temu"
|
||||
"last-seen-now": "od niedawna",
|
||||
"last-seen-min": "od minuty",
|
||||
"last-seen-ago": "od {minutes} minut",
|
||||
|
||||
"scenery-offline": "Przejazd offline"
|
||||
},
|
||||
"journal": {
|
||||
"title": "HISTORIA DYŻURÓW",
|
||||
@@ -199,7 +208,7 @@
|
||||
"section-dispatchers": "DYŻURNI",
|
||||
|
||||
"search": "Szukaj",
|
||||
"search-train": "Numer pociągu",
|
||||
"search-train": "Nr pociągu / #",
|
||||
"search-driver": "Nick maszynisty",
|
||||
"search-dispatcher": "Nick dyżurnego",
|
||||
"search-station": "Nazwa scenerii",
|
||||
@@ -239,6 +248,7 @@
|
||||
"spawns": "OTWARTE SPAWNY",
|
||||
"timetables": "AKTYWNE ROZKŁADY JAZDY",
|
||||
"no-timetables": "Brak aktywnych rozkładów!",
|
||||
"offline": "Sceneria jest offline",
|
||||
"no-users": "BRAK AKTYWNYCH GRACZY",
|
||||
"no-spawns": "BRAK OTWARTYCH SPAWNÓW",
|
||||
"no-scenery": "Ups! Ta sceneria nie istnieje!",
|
||||
@@ -259,7 +269,9 @@
|
||||
"timetable-author-unknown": "Autor nieznany",
|
||||
|
||||
"req-level": "ogólnodostępna | minimum {lvl} poziom dyżurnego | minimum {lvl} poziom dyżurnego",
|
||||
"history-list-empty": "Brak historii dla tej scenerii!"
|
||||
"history-list-empty": "Brak historii dla tej scenerii!",
|
||||
|
||||
"forum-topic": "Oficjalny wątek scenerii {name}"
|
||||
},
|
||||
"availability": {
|
||||
"title": "Dostępność",
|
||||
|
||||
@@ -2,8 +2,8 @@ import { createApp, Directive, ref } from 'vue';
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
|
||||
import enLang from '@/locales/en.json';
|
||||
import plLang from '@/locales/pl.json';
|
||||
import enLang from './locales/en.json';
|
||||
import plLang from './locales/pl.json';
|
||||
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import { createPinia } from 'pinia';
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
methods: {
|
||||
getIcon(name: string, ext = 'svg') {
|
||||
return new URL(`../assets/icon-${name}.${ext}`, import.meta.url).href;
|
||||
},
|
||||
|
||||
getImage(name: string) {
|
||||
return new URL(`../assets/${name}`, import.meta.url).href;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { useStore } from '../store/store';
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
return {
|
||||
store: useStore(),
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
console.log('Mixin mounted');
|
||||
},
|
||||
|
||||
computed: {
|
||||
chosenTrain() {
|
||||
return this.store.trainList.find((train) => train.trainId == this.store.chosenModalTrainId);
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
selectModalTrain(trainId: string) {
|
||||
this.store.chosenModalTrainId = trainId;
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.store.chosenModalTrainId = undefined;
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,31 +1,34 @@
|
||||
import { defineComponent, h } from "vue";
|
||||
import { defineComponent, h } from 'vue';
|
||||
import imageMixin from './imageMixin';
|
||||
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
icons: {
|
||||
arrow: require('@/assets/icon-arrow-asc.svg'),
|
||||
},
|
||||
mixins: [imageMixin],
|
||||
|
||||
showReturnButton: false
|
||||
}
|
||||
data() {
|
||||
return {
|
||||
icons: {
|
||||
arrow: this.getIcon('arrow-asc'),
|
||||
},
|
||||
|
||||
showReturnButton: false,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
scrollToTop() {
|
||||
window.scrollTo({ top: 0 });
|
||||
},
|
||||
|
||||
methods: {
|
||||
scrollToTop() {
|
||||
window.scrollTo({ top: 0 });
|
||||
},
|
||||
|
||||
handleScroll() {
|
||||
this.showReturnButton = window.scrollY > window.innerHeight * 0.35;
|
||||
}
|
||||
handleScroll() {
|
||||
this.showReturnButton = window.scrollY > window.innerHeight * 0.35;
|
||||
},
|
||||
},
|
||||
|
||||
activated() {
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
activated() {
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
|
||||
deactivated() {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
})
|
||||
deactivated() {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import Train from '@/scripts/interfaces/Train';
|
||||
import TrainStop from '@/scripts/interfaces/TrainStop';
|
||||
import { defineComponent } from 'vue';
|
||||
import Train from '../scripts/interfaces/Train';
|
||||
import TrainStop from '../scripts/interfaces/TrainStop';
|
||||
import imageMixin from './imageMixin';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [imageMixin],
|
||||
|
||||
data: () => ({
|
||||
STATS: {
|
||||
main: [
|
||||
@@ -55,6 +58,23 @@ export default defineComponent({
|
||||
: this.$t('trains.last-seen-ago', { minutes: diffMins });
|
||||
},
|
||||
|
||||
displayTrainPosition(train: Train) {
|
||||
let positionString = '';
|
||||
|
||||
positionString += this.$t('trains.current-scenery') + ' ';
|
||||
|
||||
if (train.currentStationHash) positionString += train.currentStationName + ' ';
|
||||
else positionString += train['currentStationName'].replace(/.[a-zA-Z0-9]+.sc/, '') + ' (offline) ';
|
||||
|
||||
if (train.signal) positionString += this.$t('trains.current-signal') + ' ' + train.signal + ' ';
|
||||
|
||||
if (train.connectedTrack) positionString += this.$t('trains.current-track') + ' ' + train.connectedTrack + ' ';
|
||||
|
||||
if (train.distance) positionString += `(${this.displayDistance(train.distance)})`;
|
||||
|
||||
return positionString.charAt(0).toUpperCase() + positionString.slice(1);
|
||||
},
|
||||
|
||||
displayStopList(stops: TrainStop[]): string | undefined {
|
||||
if (!stops) return '';
|
||||
|
||||
@@ -62,11 +82,7 @@ export default defineComponent({
|
||||
.reduce((acc: string[], stop: TrainStop, i: number) => {
|
||||
if (stop.stopType.includes('ph') && !stop.stopNameRAW.includes('po.'))
|
||||
acc.push(`<strong style='color:${stop.confirmed ? 'springgreen' : 'white'}'>${stop.stopName}</strong>`);
|
||||
else if (
|
||||
i > 0 &&
|
||||
i < stops.length - 1 &&
|
||||
!/po\.|sbl/gi.test(stop.stopNameRAW)
|
||||
)
|
||||
else if (i > 0 && i < stops.length - 1 && !/po\.|sbl/gi.test(stop.stopNameRAW))
|
||||
acc.push(`<span style='color:${stop.confirmed ? 'springgreen' : 'lightgray'}'>${stop.stopName}</span>`);
|
||||
return acc;
|
||||
}, [])
|
||||
@@ -121,7 +137,7 @@ export default defineComponent({
|
||||
|
||||
onImageError(e: Event) {
|
||||
const imageEl = e.target as HTMLImageElement;
|
||||
imageEl.src = require('@/assets/unknown.png');
|
||||
imageEl.src = this.getImage('unknown.png');
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,42 +1,45 @@
|
||||
import JournalDispatchersVue from '@/components/JournalView/JournalDispatchers.vue';
|
||||
import JournalTimetablesVue from '@/components/JournalView/JournalTimetables.vue';
|
||||
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
|
||||
import JournalDispatchersVue from '../components/JournalView/JournalDispatchers.vue';
|
||||
import JournalTimetablesVue from '../components/JournalView/JournalTimetables.vue';
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'StationsView',
|
||||
component: () => import('@/views/StationsView.vue'),
|
||||
component: () => import('../views/StationsView.vue'),
|
||||
},
|
||||
{
|
||||
path: '/trains',
|
||||
name: 'TrainsView',
|
||||
component: () => import('@/views/TrainsView.vue'),
|
||||
component: () => import('../views/TrainsView.vue'),
|
||||
props: (route) => ({ train: route.query.train, driver: route.query.driver }),
|
||||
},
|
||||
{
|
||||
path: '/scenery',
|
||||
name: 'SceneryView',
|
||||
component: () => import('@/views/SceneryView.vue'),
|
||||
component: () => import('../views/SceneryView.vue'),
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: '/journal',
|
||||
name: 'JournalView',
|
||||
component: () => import('@/views/JournalView.vue'),
|
||||
component: () => import('../views/JournalView.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirect: '/journal/timetables',
|
||||
name: 'JournalTimetables',
|
||||
component: JournalTimetablesVue,
|
||||
alias: '/timetables',
|
||||
},
|
||||
{
|
||||
path: 'dispatchers',
|
||||
name: 'JournalDispatchers',
|
||||
component: JournalDispatchersVue,
|
||||
props: (route) => ({ sceneryName: route.query.sceneryName, dispatcherName: route.query.dispatcherName }),
|
||||
},
|
||||
{
|
||||
path: 'timetables',
|
||||
name: 'JournalTimetables',
|
||||
component: JournalTimetablesVue,
|
||||
props: (route) => ({
|
||||
trainNo: route.query.trainNo,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import TrainStop from "./TrainStop";
|
||||
|
||||
export default interface ScheduledTrain {
|
||||
trainId: string;
|
||||
trainNo: number;
|
||||
|
||||
driverName: string;
|
||||
driverId: number;
|
||||
currentStationName: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Availability } from "@/store/storeTypes";
|
||||
import ScheduledTrain from "./ScheduledTrain";
|
||||
import StationRoutes from "./StationRoutes";
|
||||
import { Availability } from '../../store/storeTypes';
|
||||
import ScheduledTrain from './ScheduledTrain';
|
||||
import StationRoutes from './StationRoutes';
|
||||
|
||||
export default interface Station {
|
||||
name: string;
|
||||
@@ -53,9 +53,10 @@ export default interface Station {
|
||||
driverName: string;
|
||||
driverId: number;
|
||||
trainNo: number;
|
||||
trainId: string;
|
||||
stopStatus?: string;
|
||||
}[];
|
||||
|
||||
scheduledTrains?: ScheduledTrain[];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import TrainStop from "@/scripts/interfaces/TrainStop";
|
||||
import TrainStop from './TrainStop';
|
||||
|
||||
export default interface Train {
|
||||
trainId: string;
|
||||
|
||||
mass: number;
|
||||
length: number;
|
||||
speed: number;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
export interface Author {
|
||||
login: string;
|
||||
id: number;
|
||||
node_id: string;
|
||||
avatar_url: string;
|
||||
gravatar_id: string;
|
||||
url: string;
|
||||
html_url: string;
|
||||
followers_url: string;
|
||||
following_url: string;
|
||||
gists_url: string;
|
||||
starred_url: string;
|
||||
subscriptions_url: string;
|
||||
organizations_url: string;
|
||||
repos_url: string;
|
||||
events_url: string;
|
||||
received_events_url: string;
|
||||
type: string;
|
||||
site_admin: boolean;
|
||||
}
|
||||
|
||||
export interface ReleaseAPIData {
|
||||
url: string;
|
||||
assets_url: string;
|
||||
upload_url: string;
|
||||
html_url: string;
|
||||
id: number;
|
||||
author: Author;
|
||||
node_id: string;
|
||||
tag_name: string;
|
||||
target_commitish: string;
|
||||
name: string;
|
||||
draft: boolean;
|
||||
prerelease: boolean;
|
||||
created_at: Date;
|
||||
published_at: Date;
|
||||
assets: any[];
|
||||
tarball_url: string;
|
||||
zipball_url: string;
|
||||
body: string;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import Filter from '@/scripts/interfaces/Filter';
|
||||
import Filter from '../interfaces/Filter';
|
||||
import Station from '../interfaces/Station';
|
||||
import StorageManager from './storageManager';
|
||||
|
||||
const sortStations = (a: Station, b: Station, sorter: { index: number; dir: number }) => {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
export const URLs = {
|
||||
stacjownikAPI: process.env.VUE_APP_API_DEV != 1 ? 'https://stacjownik.eu-4.evennode.com' : 'http://localhost:3000',
|
||||
stacjownikAPI:
|
||||
import.meta.env.VITE_APP_API_DEV == 1 && !import.meta.env.PROD
|
||||
? 'http://localhost:3000'
|
||||
: 'https://stacjownik.eu-4.evennode.com',
|
||||
stacjownikAPIDev: 'localhost:3000',
|
||||
// trains: "https://api.td2.info.pl:9640/?method=getTrainsOnline",
|
||||
// getTimetableURL: (trainNo: string | number, region = "eu") => `https://api.td2.info.pl:9640/?method=readFromSWDR&value=getTimetable%3B${trainNo}%3B${region}`
|
||||
|
||||
@@ -159,6 +159,8 @@ export function getScheduledTrain(train: Train, trainStopIndex: number, stationN
|
||||
|
||||
return {
|
||||
trainNo: train.trainNo,
|
||||
trainId: train.trainId,
|
||||
|
||||
driverName: train.driverName,
|
||||
driverId: train.driverId,
|
||||
currentStationName: train.currentStationName,
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
/* eslint-disable */
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
import { DataStatus } from '@/scripts/enums/DataStatus';
|
||||
import StationAPIData from '@/scripts/interfaces/api/StationAPIData';
|
||||
import ScheduledTrain from '@/scripts/interfaces/ScheduledTrain';
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import StationRoutes from '@/scripts/interfaces/StationRoutes';
|
||||
import Train from '@/scripts/interfaces/Train';
|
||||
import { URLs } from '@/scripts/utils/apiURLs';
|
||||
import {
|
||||
getLocoURL,
|
||||
getScheduledTrain,
|
||||
getStatusID,
|
||||
getStatusTimestamp,
|
||||
parseSpawns,
|
||||
} from '@/scripts/utils/storeUtils';
|
||||
import axios from 'axios';
|
||||
import { defineStore } from 'pinia';
|
||||
import { io } from 'socket.io-client';
|
||||
import { DataStatus } from '../scripts/enums/DataStatus';
|
||||
import StationAPIData from '../scripts/interfaces/api/StationAPIData';
|
||||
import ScheduledTrain from '../scripts/interfaces/ScheduledTrain';
|
||||
import Station from '../scripts/interfaces/Station';
|
||||
import StationRoutes from '../scripts/interfaces/StationRoutes';
|
||||
import Train from '../scripts/interfaces/Train';
|
||||
import { URLs } from '../scripts/utils/apiURLs';
|
||||
import {
|
||||
getLocoURL,
|
||||
getStatusTimestamp,
|
||||
getStatusID,
|
||||
getScheduledTrain,
|
||||
parseSpawns,
|
||||
} from '../scripts/utils/storeUtils';
|
||||
import { APIData, StationJSONData, StoreState } from './storeTypes';
|
||||
|
||||
export const useStore = defineStore('store', {
|
||||
@@ -41,6 +41,8 @@ export const useStore = defineStore('store', {
|
||||
driverStatsName: '',
|
||||
driverStatsData: undefined,
|
||||
|
||||
chosenModalTrainId: undefined,
|
||||
|
||||
dataStatuses: {
|
||||
connection: DataStatus.Loading,
|
||||
sceneries: DataStatus.Loading,
|
||||
@@ -56,7 +58,7 @@ export const useStore = defineStore('store', {
|
||||
setTrainsOnlineData() {
|
||||
const { trains } = this.apiData;
|
||||
|
||||
if (!trains) return [];
|
||||
if (!trains) return [];
|
||||
|
||||
this.trainList = trains
|
||||
.filter(
|
||||
@@ -70,6 +72,8 @@ export const useStore = defineStore('store', {
|
||||
const timetable = train.timetable;
|
||||
|
||||
return {
|
||||
trainId: train.driverName + train.trainNo.toString(),
|
||||
|
||||
trainNo: train.trainNo,
|
||||
mass: train.mass,
|
||||
length: train.length,
|
||||
@@ -200,7 +204,12 @@ export const useStore = defineStore('store', {
|
||||
(train) =>
|
||||
train?.region === this.region.id && train.online && train.currentStationName === stationAPIData.stationName
|
||||
)
|
||||
.map((train) => ({ driverName: train.driverName, driverId: train.driverId, trainNo: train.trainNo }));
|
||||
.map((train) => ({
|
||||
driverName: train.driverName,
|
||||
driverId: train.driverId,
|
||||
trainNo: train.trainNo,
|
||||
trainId: train.trainId,
|
||||
}));
|
||||
},
|
||||
|
||||
setStationsOnlineInfo() {
|
||||
@@ -334,7 +343,7 @@ export const useStore = defineStore('store', {
|
||||
transports: ['websocket', 'polling'],
|
||||
rememberUpgrade: true,
|
||||
reconnection: true,
|
||||
timeout: 10000
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
socket.on('connect_error', (err) => {
|
||||
@@ -377,13 +386,13 @@ export const useStore = defineStore('store', {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.dataStatuses.sceneries = DataStatus.Loaded;
|
||||
this.dataStatuses.trains = !this.apiData.trains ? DataStatus.Warning : DataStatus.Loaded;
|
||||
this.dataStatuses.dispatchers = !this.apiData.dispatchers ? DataStatus.Warning : DataStatus.Loaded;
|
||||
|
||||
|
||||
this.setTrainsOnlineData();
|
||||
this.setStationsOnlineInfo();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { DataStatus } from '@/scripts/enums/DataStatus';
|
||||
import { DispatcherStatsAPIData } from '@/scripts/interfaces/api/DispatcherStatsAPIData';
|
||||
import { DriverStatsAPIData } from '@/scripts/interfaces/api/DriverStatsAPIData';
|
||||
import StationAPIData from '@/scripts/interfaces/api/StationAPIData';
|
||||
import TrainAPIData from '@/scripts/interfaces/api/TrainAPIData';
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
import Train from '@/scripts/interfaces/Train';
|
||||
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { DataStatus } from '../scripts/enums/DataStatus';
|
||||
import { DispatcherStatsAPIData } from '../scripts/interfaces/api/DispatcherStatsAPIData';
|
||||
import { DriverStatsAPIData } from '../scripts/interfaces/api/DriverStatsAPIData';
|
||||
import StationAPIData from '../scripts/interfaces/api/StationAPIData';
|
||||
import TrainAPIData from '../scripts/interfaces/api/TrainAPIData';
|
||||
import Station from '../scripts/interfaces/Station';
|
||||
import Train from '../scripts/interfaces/Train';
|
||||
|
||||
export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault';
|
||||
|
||||
@@ -30,6 +31,8 @@ export interface StoreState {
|
||||
driverStatsName: string;
|
||||
driverStatsData?: DriverStatsAPIData;
|
||||
|
||||
chosenModalTrainId?: string;
|
||||
|
||||
dataStatuses: {
|
||||
connection: DataStatus;
|
||||
sceneries: DataStatus;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
.badge {
|
||||
font-weight: 600;
|
||||
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
|
||||
background: #585858;
|
||||
|
||||
margin: 0.25em;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 0.2em 0.4em;
|
||||
}
|
||||
|
||||
&-none {
|
||||
font-weight: 600;
|
||||
|
||||
padding: 0.2em 0.4em;
|
||||
background: firebrick;
|
||||
|
||||
text-align: center;
|
||||
|
||||
@include smallScreen() {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,19 @@
|
||||
<template>
|
||||
<div class="error-view">
|
||||
<div class="container">
|
||||
<img :src="icons.error" alt="error" />
|
||||
<img :src="getIcon('error')" alt="error" />
|
||||
<div class="desc">Z powodu błędu w zapisywaniu rozkładów jazdy w tej zakładce można do odwołania nacieszyć się animacją sygnału S1a. Jak naprawię to będzie :)</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '@vue/runtime-core';
|
||||
import { defineComponent } from "vue";
|
||||
import imageMixin from "../mixins/imageMixin";
|
||||
|
||||
|
||||
export default defineComponent({
|
||||
data: () => ({
|
||||
icons: {
|
||||
error: require('@/assets/icon-error.svg'),
|
||||
},
|
||||
}),
|
||||
mixins: [imageMixin]
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -21,13 +21,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import JournalTimetables from '@/components/JournalView/JournalTimetables.vue';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import JournalDispatchers from '@/components/JournalView/JournalDispatchers.vue';
|
||||
import JournalDispatchers from '../components/JournalView/JournalDispatchers.vue';
|
||||
import JournalTimetables from '../components/JournalView/JournalTimetables.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { JournalTimetables, JournalDispatchers },
|
||||
|
||||
components: { JournalDispatchers, JournalTimetables },
|
||||
setup() {
|
||||
const journalTypeChosen = ref('journalTimetables');
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="scenery-left">
|
||||
<div class="scenery-actions">
|
||||
<button v-if="!timetableOnly" class="back-btn btn" :title="$t('scenery.return-btn')" @click="navigateTo('/')">
|
||||
<img :src="icons.back" alt="Back to scenery" />
|
||||
<img :src="getIcon('back')" alt="Back to scenery" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -41,19 +41,17 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import SceneryInfo from '@/components/SceneryView/SceneryInfo.vue';
|
||||
import SceneryTimetable from '@/components/SceneryView/SceneryTimetable.vue';
|
||||
import SceneryTimetablesHistory from '../components/SceneryView/SceneryTimetablesHistory.vue';
|
||||
import SceneryDispatchersHistory from '@/components/SceneryView/SceneryDispatchersHistory.vue';
|
||||
import SceneryHeader from '@/components/SceneryView/SceneryHeader.vue';
|
||||
|
||||
import ActionButton from '@/components/Global/ActionButton.vue';
|
||||
|
||||
import { computed, defineComponent, ref } from '@vue/runtime-core';
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { useStore } from '@/store/store';
|
||||
import routerMixin from '@/mixins/routerMixin';
|
||||
import routerMixin from '../mixins/routerMixin';
|
||||
import { useStore } from '../store/store';
|
||||
import SceneryInfo from '../components/SceneryView/SceneryInfo.vue';
|
||||
import SceneryHeader from '../components/SceneryView/SceneryHeader.vue';
|
||||
import SceneryTimetable from '../components/SceneryView/SceneryTimetable.vue';
|
||||
import SceneryTimetablesHistory from '../components/SceneryView/SceneryTimetablesHistory.vue';
|
||||
import SceneryDispatchersHistory from '../components/SceneryView/SceneryDispatchersHistory.vue';
|
||||
import ActionButton from '../components/Global/ActionButton.vue';
|
||||
import imageMixin from '../mixins/imageMixin';
|
||||
|
||||
enum SceneryViewMode {
|
||||
'TIMETABLES_ACTIVE',
|
||||
@@ -70,15 +68,8 @@ export default defineComponent({
|
||||
SceneryTimetablesHistory,
|
||||
SceneryDispatchersHistory,
|
||||
},
|
||||
|
||||
mixins: [routerMixin],
|
||||
|
||||
mixins: [routerMixin, imageMixin],
|
||||
data: () => ({
|
||||
icons: {
|
||||
user: require('@/assets/icon-user.svg'),
|
||||
back: require('@/assets/icon-back.svg'),
|
||||
},
|
||||
|
||||
viewModes: [
|
||||
{
|
||||
id: 'scenery.option-active-timetables',
|
||||
@@ -93,32 +84,22 @@ export default defineComponent({
|
||||
component: 'SceneryDispatchersHistory',
|
||||
},
|
||||
],
|
||||
|
||||
sceneryViewMode: SceneryViewMode,
|
||||
|
||||
selectedCheckpoint: '',
|
||||
|
||||
currentViewCompontent: 'SceneryTimetable',
|
||||
|
||||
onlineFrom: -1,
|
||||
}),
|
||||
|
||||
activated() {
|
||||
this.loadSelectedCheckpoint();
|
||||
},
|
||||
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const store = useStore();
|
||||
|
||||
const timetableOnly = computed(() => (route.query['timetable_only'] == '1' ? true : false));
|
||||
|
||||
const isComponentVisible = computed(() => route.path === '/scenery');
|
||||
|
||||
const stationInfo = computed(() => {
|
||||
return store.stationList.find((station) => station.name === route.query.station?.toString().replace(/_/g, ' '));
|
||||
});
|
||||
|
||||
return {
|
||||
timetableOnly,
|
||||
isComponentVisible,
|
||||
@@ -126,19 +107,15 @@ export default defineComponent({
|
||||
store,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
setViewMode(componentName: string) {
|
||||
this.currentViewCompontent = componentName;
|
||||
},
|
||||
|
||||
loadSelectedCheckpoint() {
|
||||
if (!this.stationInfo?.generalInfo?.checkpoints) return;
|
||||
if (this.stationInfo.generalInfo.checkpoints.length == 0) return;
|
||||
|
||||
this.selectedCheckpoint = this.stationInfo.generalInfo.checkpoints[0].checkpointName;
|
||||
},
|
||||
|
||||
selectCheckpoint(cp: { checkpointName: string }) {
|
||||
this.selectedCheckpoint = cp.checkpointName;
|
||||
},
|
||||
@@ -283,15 +260,15 @@ button.back-btn {
|
||||
border-radius: 1em;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.info-actions {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
@include smallScreen {
|
||||
.scenery-left, .scenery-right {
|
||||
.scenery-left {
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
||||
.scenery-right {
|
||||
height: 100vh;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="wrapper">
|
||||
<div class="body">
|
||||
<div class="options-bar">
|
||||
<FilterCard
|
||||
<StationFilterCard
|
||||
:showCard="filterCardOpen"
|
||||
:exit="closeCard"
|
||||
@changeFilterValue="changeFilterValue"
|
||||
@@ -25,30 +25,25 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Station from '@/scripts/interfaces/Station';
|
||||
|
||||
import StorageManager from '@/scripts/managers/storageManager';
|
||||
import StationFilterManager from '@/scripts/managers/stationFilterManager';
|
||||
|
||||
import inputData from '@/data/options.json';
|
||||
|
||||
import StationTable from '@/components/StationsView/StationTable.vue';
|
||||
import FilterCard from '@/components/StationsView/StationFilterCard.vue';
|
||||
import SelectBox from '@/components/Global/SelectBox.vue';
|
||||
import inputData from '../data/options.json';
|
||||
|
||||
import { computed, ComputedRef, defineComponent, reactive } from 'vue';
|
||||
import { useStore } from '@/store/store';
|
||||
import { useStore } from '../store/store';
|
||||
import StationFilterManager from '../scripts/managers/stationFilterManager';
|
||||
import Station from '../scripts/interfaces/Station';
|
||||
import StorageManager from '../scripts/managers/storageManager';
|
||||
import StationTable from '../components/StationsView/StationTable.vue';
|
||||
import StationFilterCard from '../components/StationsView/StationFilterCard.vue';
|
||||
import SelectBox from '../components/Global/SelectBox.vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
StationTable,
|
||||
FilterCard,
|
||||
StationFilterCard,
|
||||
SelectBox,
|
||||
},
|
||||
data: () => ({
|
||||
trainIcon: require('@/assets/icon-train.svg'),
|
||||
timetableIcon: require('@/assets/icon-timetable.svg'),
|
||||
dolarIcon: require('@/assets/icon-dolar.svg'),
|
||||
filterCardOpen: false,
|
||||
modalHidden: true,
|
||||
STORAGE_KEY: 'options_saved',
|
||||
|
||||
@@ -11,16 +11,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, ComputedRef, defineComponent, PropType, provide, reactive, ref, TrainFilter } from 'vue';
|
||||
import { filteredTrainList } from '@/scripts/managers/trainFilterManager';
|
||||
import { trainFilters } from '@/data/trainOptions';
|
||||
|
||||
import Train from '@/scripts/interfaces/Train';
|
||||
import TrainTable from '@/components/TrainsView/TrainTable.vue';
|
||||
import TrainStats from '@/components/TrainsView/TrainStats.vue';
|
||||
import TrainOptions from '@/components/TrainsView/TrainOptions.vue';
|
||||
|
||||
import { useStore } from '@/store/store';
|
||||
import { computed, ComputedRef, defineComponent, provide, reactive, ref, TrainFilter } from 'vue';
|
||||
import TrainOptions from '../components/TrainsView/TrainOptions.vue';
|
||||
import TrainStats from '../components/TrainsView/TrainStats.vue';
|
||||
import TrainTable from '../components/TrainsView/TrainTable.vue';
|
||||
import { trainFilters } from '../data/trainOptions';
|
||||
import Train from '../scripts/interfaces/Train';
|
||||
import { filteredTrainList } from '../scripts/managers/trainFilterManager';
|
||||
import { useStore } from '../store/store';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@@ -42,7 +40,6 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
statsIcon: require('@/assets/icon-stats.svg'),
|
||||
trainStatsOpen: false,
|
||||
}),
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
|
||||
}
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_APP_API_DEV: number;
|
||||
readonly VITE_APP_WS_DEV: number;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,8 +26,5 @@ declare module '@vue/runtime-core' {
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
interface JournalSearcher {
|
||||
id: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +1,30 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"importHelpers": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"noImplicitAny": false,
|
||||
"moduleResolution": "node",
|
||||
"experimentalDecorators": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"baseUrl": ".",
|
||||
"types": [
|
||||
"webpack-env"
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
"ESNext",
|
||||
"DOM"
|
||||
],
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"src/**/**/*.vue",
|
||||
"tests/**/*.ts",
|
||||
"tests/**/*.tsx"
|
||||
"src/**/*.vue"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
});
|
||||
|
||||
// PWA
|
||||
|
||||
// VitePWA({
|
||||
// registerType: 'autoUpdate',
|
||||
// workbox: {
|
||||
// globPatterns: ['**/*.{js,css,html,png,svg,img}'],
|
||||
// runtimeCaching: [
|
||||
// {
|
||||
// urlPattern: new RegExp('^https://stacjownik.eu-4.evennode.com/api/getSceneries'),
|
||||
// handler: 'NetworkFirst',
|
||||
// options: {
|
||||
// cacheName: 'sceneries-cache',
|
||||
// expiration: {
|
||||
// maxEntries: 200,
|
||||
// maxAgeSeconds: 60 * 60 * 24 * 60, // <== 60 days
|
||||
// },
|
||||
// cacheableResponse: {
|
||||
// statuses: [0, 200],
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// devOptions: {
|
||||
// enabled: true,
|
||||
// },
|
||||
// }),
|
||||
@@ -1,3 +0,0 @@
|
||||
// module.exports = {
|
||||
// publicPath: process.env.NODE_ENV === "production" ? "/dist" : "/",
|
||||
// };
|
||||