mirror of
https://github.com/Spythere/srjp-td2.git
synced 2026-05-02 21:18:12 +00:00
init: almost production-ready app
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["Vue.volar"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Vue 3 + TypeScript + Vite
|
||||||
|
|
||||||
|
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||||
|
|
||||||
|
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Vite + Vue + TS</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "srjp-td2",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vue-tsc -b && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.7.9",
|
||||||
|
"pinia": "^2.3.1",
|
||||||
|
"vue": "^3.5.13"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
|
"@vue/tsconfig": "^0.7.0",
|
||||||
|
"autoprefixer": "^10.4.20",
|
||||||
|
"postcss": "^8.5.1",
|
||||||
|
"tailwindcss": "^3.4.17",
|
||||||
|
"typescript": "~5.6.2",
|
||||||
|
"vite": "^6.0.5",
|
||||||
|
"vue-tsc": "^2.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
+394
@@ -0,0 +1,394 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app">
|
||||||
|
<select name="trains" id="trains-select" class="mb-2 bg-zinc-800 p-1 rounded-md" v-model="selectedTrainId">
|
||||||
|
<option :value="train.id" v-for="train in timetableTrains">{{ train.driverName }} | {{ train.timetable?.category }} {{ train.trainNo }}</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<table class="srjp-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="50" class="border border-white">Nr linii</th>
|
||||||
|
<th width="100" class="border border-white">Km</th>
|
||||||
|
<th width="40" class="border border-white" colspan="2">V<sub>D</sub></th>
|
||||||
|
<th width="250" class="border border-white">Stacja</th>
|
||||||
|
<th width="100" class="border border-white">Godzina</th>
|
||||||
|
<th width="50" class="border border-white text-xs p-0">
|
||||||
|
<table class="header-table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Lok I</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Lok II</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Lok III</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</th>
|
||||||
|
<th width="60" class="border border-white text-xs p-0">
|
||||||
|
<table class="header-table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Obc. lok.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Dł. poc.</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</th>
|
||||||
|
<th width="50" class="border border-white">Vmax</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody v-if="computedTimetable">
|
||||||
|
<tr v-for="(row, i) in computedTimetable">
|
||||||
|
<td class="text-center align-top border border-white">{{ row.realLine }}</td>
|
||||||
|
<td class="border border-white">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="align-top">{{ row.arrivalKm }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="align-bottom">{{ row.departureKm }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<!-- :class="{ 'border-t-4': i > 0 && computedTimetable[i - 1].sceneryName != row.sceneryName }" -->
|
||||||
|
<!-- :class="{ 'border-ts': i > 0 && computedTimetable[i - 1].sceneryName != row.sceneryName }" -->
|
||||||
|
<td class="text-center align-top font-bold p-0 border-l-4" colspan="2">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
:class="{
|
||||||
|
'align-top': i == 0 || computedTimetable[i - 1].departureTracks == row.arrivalTracks,
|
||||||
|
'border-t': i != 0 && computedTimetable[i - 1].departureSpeed != row.arrivalSpeed,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<td :colspan="row.arrivalTracks == 2 ? '1' : '2'">
|
||||||
|
{{
|
||||||
|
i == 0 ||
|
||||||
|
computedTimetable[i - 1].departureSpeed != row.arrivalSpeed ||
|
||||||
|
computedTimetable[i - 1].departureTracks != row.arrivalTracks
|
||||||
|
? row.arrivalSpeed
|
||||||
|
: ' '
|
||||||
|
}}
|
||||||
|
<!-- {{ row.arrivalTracks }} -->
|
||||||
|
</td>
|
||||||
|
<td v-if="row.arrivalTracks == 2" class="border-l">
|
||||||
|
{{
|
||||||
|
i == 0 ||
|
||||||
|
computedTimetable[i - 1].departureSpeed != row.arrivalSpeed ||
|
||||||
|
computedTimetable[i - 1].departureTracks != row.arrivalTracks
|
||||||
|
? row.arrivalSpeed
|
||||||
|
: ' '
|
||||||
|
}}
|
||||||
|
<!-- {{ row.arrivalTracks }} -->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr
|
||||||
|
class=""
|
||||||
|
:class="{
|
||||||
|
'border-b': row.departureSpeed != row.arrivalSpeed || i == computedTimetable.length - 1,
|
||||||
|
'border-t': row.arrivalTracks != row.departureTracks,
|
||||||
|
'align-bottom': row.arrivalTracks == row.departureTracks,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<td :colspan="row.departureTracks == 2 ? '1' : '2'">
|
||||||
|
{{ row.departureSpeed != row.arrivalSpeed || row.departureTracks != row.arrivalTracks ? row.departureSpeed : ' ' }}
|
||||||
|
<!-- {{ row.departureTracks }} -->
|
||||||
|
</td>
|
||||||
|
<td v-if="row.departureTracks == 2" class="border-l">
|
||||||
|
{{ row.departureSpeed != row.arrivalSpeed || row.departureTracks != row.arrivalTracks ? row.departureSpeed : ' ' }}
|
||||||
|
<!-- {{ row.departureTracks }} -->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- <tr
|
||||||
|
class="align-top"
|
||||||
|
:class="{
|
||||||
|
'border-b':
|
||||||
|
row.arrivalSpeed && row.departureSpeed && (row.arrivalSpeed != row.departureSpeed || row.arrivalTracks != row.departureTracks),
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<td :colspan="row.arrivalTracks == 2 ? '1' : '2'">{{ row.arrivalSpeed || ' ' }}</td>
|
||||||
|
<td v-if="row.arrivalTracks == 2" class="border-l">{{ row.arrivalSpeed || ' ' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr
|
||||||
|
class="align-bottom"
|
||||||
|
:class="{
|
||||||
|
'border-b':
|
||||||
|
i < computedTimetable.length - 1 &&
|
||||||
|
(computedTimetable[i + 1].arrivalSpeed != row.departureSpeed || computedTimetable[i + 1].arrivalTracks != row.departureTracks),
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<td :colspan="row.departureTracks == 2 ? '1' : '2'">{{ row.departureSpeed || ' ' }}</td>
|
||||||
|
<td v-if="row.departureTracks == 2" class="border-l">{{ row.departureSpeed || ' ' }}</td>
|
||||||
|
</tr> -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="p-1 border border-white">
|
||||||
|
<div class="flex flex-col h-full justify-between">
|
||||||
|
<div :class="{ 'font-bold': row.isMain }">
|
||||||
|
{{ row.pointName }}
|
||||||
|
<span v-if="row.stopType"> ; {{ row.stopType }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span>{{ row.pointKm }}</span>
|
||||||
|
<span>R1, PP</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="border border-white">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr class="text-center align-top">
|
||||||
|
<td class="border-r-[1px] border-r-white" :class="{ 'font-bold': row.stopTime > 0 }">
|
||||||
|
{{
|
||||||
|
(row.scheduledArrivalDate?.getTime() || 0) != (row.scheduledDepartureDate?.getTime() || 0)
|
||||||
|
? row.scheduledArrivalDate?.toLocaleTimeString('pl-PL', { hour: '2-digit', minute: '2-digit' })
|
||||||
|
: '|'
|
||||||
|
}}
|
||||||
|
</td>
|
||||||
|
<td width="30">{{ row.driveTime ? Math.floor(row.driveTime / 60000) : '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="text-center align-bottom">
|
||||||
|
<td class="border-r-[1px] border-r-white" :class="{ 'font-bold': row.stopTime > 0 }">
|
||||||
|
{{ row.scheduledDepartureDate?.toLocaleTimeString('pl-PL', { hour: '2-digit', minute: '2-digit' }) }}
|
||||||
|
</td>
|
||||||
|
<td width="30" class="font-bold">{{ row.stopTime || '' }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="p-0 text-center border border-white">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr class="border-b-[1px] border-b-white">
|
||||||
|
<td>{{ selectedTrain!.stockString.split(';')[0].split('-')[0] }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="border-b-[1px] border-b-white">
|
||||||
|
<td> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="p-0 text-center border border-white">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr class="border-b-[1px] border-b-white">
|
||||||
|
<td>{{ Math.floor(selectedTrain!.mass / 1000) }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ selectedTrain!.length }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-center border border-white">70</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { useGlobalStore } from './stores/global.store';
|
||||||
|
|
||||||
|
const additionalData = {
|
||||||
|
// Mijanki
|
||||||
|
passings: ['Stolnica Wielka'],
|
||||||
|
// SHP
|
||||||
|
shpSystems: [],
|
||||||
|
// 4-stawne SBL
|
||||||
|
sbl4: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
interface StopRow {
|
||||||
|
pointName: string;
|
||||||
|
pointKm: string;
|
||||||
|
isMain: boolean;
|
||||||
|
stopTime: number;
|
||||||
|
stopType: string;
|
||||||
|
scheduledArrivalDate: Date | null;
|
||||||
|
scheduledDepartureDate: Date | null;
|
||||||
|
realLine: string;
|
||||||
|
driveTime: number;
|
||||||
|
controlAbbrevs: string[];
|
||||||
|
additionalAbbrevs: string[];
|
||||||
|
|
||||||
|
sceneryName: string;
|
||||||
|
|
||||||
|
arrivalKm: string;
|
||||||
|
|
||||||
|
arrivalSpeed: number;
|
||||||
|
arrivalTracks: number;
|
||||||
|
|
||||||
|
departureKm: string;
|
||||||
|
|
||||||
|
departureSpeed: number;
|
||||||
|
departureTracks: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
data: () => ({
|
||||||
|
selectedTrainId: '',
|
||||||
|
globalStore: useGlobalStore(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.globalStore.setupData();
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
timetableTrains() {
|
||||||
|
return this.globalStore.activeData?.trains.filter((train) => train.timetable != undefined) ?? [];
|
||||||
|
},
|
||||||
|
|
||||||
|
selectedTrain() {
|
||||||
|
return this.timetableTrains.find((train) => train.id == this.selectedTrainId);
|
||||||
|
},
|
||||||
|
|
||||||
|
computedTimetable() {
|
||||||
|
if (!this.selectedTrain) return null;
|
||||||
|
|
||||||
|
const timetable = this.selectedTrain.timetable;
|
||||||
|
|
||||||
|
if (!timetable) return null;
|
||||||
|
|
||||||
|
const timetablePath = timetable.path.split(';').map((pathEl) => {
|
||||||
|
const [arrivalLine, scenery, departureLine] = pathEl.split(',');
|
||||||
|
const sceneryName = scenery.split(' ').slice(0, -1).join(' ');
|
||||||
|
|
||||||
|
const sceneryData = this.globalStore.sceneryData?.find((sc) => sc.name == sceneryName) ?? null;
|
||||||
|
const arrivalLineData = arrivalLine ? sceneryData?.routesInfo.find((rt) => rt.routeName == arrivalLine) ?? null : null;
|
||||||
|
const departureLineData = departureLine ? sceneryData?.routesInfo.find((rt) => rt.routeName == departureLine) ?? null : null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
sceneryName,
|
||||||
|
arrivalLine: arrivalLine ?? '',
|
||||||
|
arrivalLineData,
|
||||||
|
departureLine: departureLine ?? '',
|
||||||
|
departureLineData,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const stopRows: StopRow[] = [];
|
||||||
|
|
||||||
|
let currentPathIndex = 0;
|
||||||
|
let currentPath = timetablePath[0];
|
||||||
|
|
||||||
|
let lastDepartureTimestamp = 0;
|
||||||
|
|
||||||
|
let arrivalKm = 0,
|
||||||
|
arrivalSpeed = currentPath.departureLineData?.routeSpeed ?? 0,
|
||||||
|
arrivalTracks = currentPath.departureLineData?.routeTracks ?? 0;
|
||||||
|
|
||||||
|
let departureSpeed = currentPath.departureLineData?.routeSpeed ?? 0,
|
||||||
|
departureTracks = currentPath.departureLineData?.routeTracks ?? 2;
|
||||||
|
|
||||||
|
let checkEntryAsFirst = true;
|
||||||
|
|
||||||
|
for (const stop of timetable.stopList) {
|
||||||
|
if (stop.arrivalLine && stop.arrivalLine == currentPath.arrivalLine) {
|
||||||
|
arrivalKm = stop.stopDistance;
|
||||||
|
arrivalSpeed = currentPath.arrivalLineData?.routeSpeed ?? 0;
|
||||||
|
arrivalTracks = currentPath.arrivalLineData?.routeTracks ?? 2;
|
||||||
|
|
||||||
|
departureSpeed = arrivalSpeed;
|
||||||
|
departureTracks = arrivalTracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^<strong>|, (podg|po)$|^(!_, pe)$/.test(stop.stopName)) {
|
||||||
|
let rowData: StopRow = {
|
||||||
|
isMain: /^<strong>/.test(stop.stopName),
|
||||||
|
pointKm: stop.stopDistance.toFixed(3),
|
||||||
|
pointName: stop.stopNameRAW,
|
||||||
|
scheduledArrivalDate: stop.arrivalTimestamp ? new Date(stop.arrivalTimestamp) : null,
|
||||||
|
scheduledDepartureDate: stop.departureTimestamp ? new Date(stop.departureTimestamp) : null,
|
||||||
|
stopTime: stop.stopTime ?? 0,
|
||||||
|
stopType: stop.stopType,
|
||||||
|
sceneryName: currentPath.sceneryName,
|
||||||
|
realLine: '-',
|
||||||
|
driveTime: lastDepartureTimestamp ? stop.arrivalTimestamp - lastDepartureTimestamp : 0,
|
||||||
|
additionalAbbrevs: [],
|
||||||
|
controlAbbrevs: [],
|
||||||
|
|
||||||
|
arrivalKm: arrivalKm.toFixed(3),
|
||||||
|
departureKm: stop.stopDistance.toFixed(3),
|
||||||
|
|
||||||
|
arrivalSpeed: arrivalSpeed,
|
||||||
|
arrivalTracks: arrivalTracks,
|
||||||
|
|
||||||
|
departureSpeed: departureSpeed,
|
||||||
|
departureTracks: departureTracks,
|
||||||
|
};
|
||||||
|
|
||||||
|
arrivalKm = stop.stopDistance;
|
||||||
|
checkEntryAsFirst = false;
|
||||||
|
|
||||||
|
if (stop.departureTimestamp) lastDepartureTimestamp = stop.departureTimestamp;
|
||||||
|
|
||||||
|
stopRows.push(rowData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stop.departureLine && stop.departureLine == currentPath.departureLine) {
|
||||||
|
// Reverse search for last scenery checkpoint
|
||||||
|
for (let i = stopRows.length - 1; i > 0; i--) {
|
||||||
|
stopRows[i].departureTracks = currentPath.departureLineData?.routeTracks ?? 0;
|
||||||
|
|
||||||
|
if (stopRows[i].isMain || stopRows[i].pointName.endsWith(', podg')) {
|
||||||
|
stopRows[i].departureSpeed = currentPath.departureLineData?.routeSpeed ?? 0;
|
||||||
|
stopRows[i].departureTracks = currentPath.departureLineData?.routeTracks ?? 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stopRows[i].arrivalTracks = currentPath.departureLineData?.routeTracks ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPath = timetablePath[++currentPathIndex];
|
||||||
|
checkEntryAsFirst = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stopRows;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.srjp-table {
|
||||||
|
min-width: 750px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-bottom-border {
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
table {
|
||||||
|
page-break-inside: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 496 B |
@@ -0,0 +1,8 @@
|
|||||||
|
import { createApp } from 'vue';
|
||||||
|
import App from './App.vue';
|
||||||
|
import { createPinia } from 'pinia';
|
||||||
|
import './style.css'
|
||||||
|
|
||||||
|
const pinia = createPinia();
|
||||||
|
|
||||||
|
createApp(App).use(pinia).mount('#app');
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import httpClient from '../utils/http';
|
||||||
|
import type { ActiveDataResponse, SceneriesDataResponse } from '../types/api.types';
|
||||||
|
import type { ActiveData, SceneryData } from '../types/common.types';
|
||||||
|
|
||||||
|
export const useGlobalStore = defineStore('global', {
|
||||||
|
state: () => ({
|
||||||
|
activeData: null as ActiveData | null,
|
||||||
|
sceneryData: null as SceneryData[] | null,
|
||||||
|
}),
|
||||||
|
getters: {},
|
||||||
|
actions: {
|
||||||
|
async _fetchActiveData() {
|
||||||
|
try {
|
||||||
|
const response = (await httpClient.get<ActiveDataResponse>('/api/getActiveData')).data;
|
||||||
|
|
||||||
|
this.activeData = response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async _fetchSceneriesData() {
|
||||||
|
try {
|
||||||
|
const response = (await httpClient.get<SceneriesDataResponse>('/api/getSceneries')).data;
|
||||||
|
|
||||||
|
this.sceneryData = response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setupData() {
|
||||||
|
this._fetchActiveData();
|
||||||
|
this._fetchSceneriesData();
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
this._fetchActiveData();
|
||||||
|
}, 20000);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
:root {
|
||||||
|
color-scheme: dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
min-width: 320px;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
max-width: 1280px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
:root {
|
||||||
|
color-scheme: light;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import type { ActiveData, SceneryData } from './common.types';
|
||||||
|
|
||||||
|
export type ActiveDataResponse = ActiveData;
|
||||||
|
|
||||||
|
export type SceneriesDataResponse = SceneryData[];
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
export interface ActiveData {
|
||||||
|
trains: ActiveTrain[];
|
||||||
|
activeSceneries: ActiveScenery[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActiveTrain {
|
||||||
|
id: string;
|
||||||
|
trainNo: number;
|
||||||
|
mass: number;
|
||||||
|
speed: number;
|
||||||
|
length: number;
|
||||||
|
distance: number;
|
||||||
|
stockString: string;
|
||||||
|
driverName: string;
|
||||||
|
driverId: number;
|
||||||
|
driverIsSupporter: boolean;
|
||||||
|
driverLevel: number;
|
||||||
|
currentStationHash?: string;
|
||||||
|
currentStationName: string;
|
||||||
|
signal: string;
|
||||||
|
connectedTrack: string;
|
||||||
|
online: number;
|
||||||
|
lastSeen: number;
|
||||||
|
region: string;
|
||||||
|
isTimeout: boolean;
|
||||||
|
timetable?: ActiveTrainTimetable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActiveTrainTimetable {
|
||||||
|
SKR: boolean;
|
||||||
|
TWR: boolean;
|
||||||
|
hasDangerousCargo: boolean;
|
||||||
|
hasExtraDeliveries: boolean;
|
||||||
|
warningNotes: string;
|
||||||
|
category: string;
|
||||||
|
stopList: TimetableStop[];
|
||||||
|
route: string;
|
||||||
|
timetableId: number;
|
||||||
|
sceneries: string[];
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimetableStop {
|
||||||
|
stopName: string;
|
||||||
|
stopNameRAW: string;
|
||||||
|
stopType: string;
|
||||||
|
stopDistance: number;
|
||||||
|
pointId: string;
|
||||||
|
comments?: string;
|
||||||
|
mainStop: boolean;
|
||||||
|
arrivalLine?: string;
|
||||||
|
arrivalTimestamp: number;
|
||||||
|
arrivalRealTimestamp: number;
|
||||||
|
arrivalDelay: number;
|
||||||
|
departureLine?: string;
|
||||||
|
departureTimestamp: number;
|
||||||
|
departureRealTimestamp: number;
|
||||||
|
departureDelay: number;
|
||||||
|
beginsHere: boolean;
|
||||||
|
terminatesHere: boolean;
|
||||||
|
confirmed: number;
|
||||||
|
stopped: number;
|
||||||
|
stopTime?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActiveScenery {
|
||||||
|
dispatcherId: number;
|
||||||
|
dispatcherName: string;
|
||||||
|
dispatcherIsSupporter: boolean;
|
||||||
|
stationName: string;
|
||||||
|
stationHash: string;
|
||||||
|
region: string;
|
||||||
|
maxUsers: number;
|
||||||
|
currentUsers: number;
|
||||||
|
spawn: number;
|
||||||
|
lastSeen: number;
|
||||||
|
dispatcherExp: number;
|
||||||
|
nameFromHeader: string;
|
||||||
|
spawnString?: string;
|
||||||
|
networkConnectionString: string;
|
||||||
|
isOnline: number;
|
||||||
|
dispatcherRate: number;
|
||||||
|
dispatcherStatus: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SceneryData {
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt?: string;
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
SUP: boolean;
|
||||||
|
authors: string;
|
||||||
|
availability: string;
|
||||||
|
backupJSON: any;
|
||||||
|
checkpoints?: string;
|
||||||
|
controlType: string;
|
||||||
|
lines?: string;
|
||||||
|
project?: string;
|
||||||
|
reqLevel: number;
|
||||||
|
routes?: string;
|
||||||
|
routesInfo: SceneryRoute[];
|
||||||
|
signalType: string;
|
||||||
|
supportersOnly?: boolean;
|
||||||
|
url?: string;
|
||||||
|
projectUrl?: string;
|
||||||
|
hash?: string;
|
||||||
|
abbr: string;
|
||||||
|
hidden: boolean;
|
||||||
|
ASDEK: boolean;
|
||||||
|
hashHistory: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SceneryRoute {
|
||||||
|
routeName: string;
|
||||||
|
isElectric: boolean;
|
||||||
|
isInternal: boolean;
|
||||||
|
isRouteSBL: boolean;
|
||||||
|
routeSpeed: number;
|
||||||
|
routeLength: number;
|
||||||
|
routeTracks: number;
|
||||||
|
hidden?: boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const httpClient = axios.create({
|
||||||
|
baseURL: 'https://stacjownik.spythere.eu',
|
||||||
|
timeout: 3000,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default httpClient;
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
content: [],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
purge: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{ "path": "./tsconfig.app.json" },
|
||||||
|
{ "path": "./tsconfig.node.json" }
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||||
|
"target": "ES2022",
|
||||||
|
"lib": ["ES2023"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
|
// https://vite.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user