mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 05:18:11 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a34eef098b | |||
| 97a829a21c | |||
| 83444f64d0 | |||
| c2f7eef146 | |||
| 3c78af4dc0 | |||
| fc7a9be9dd | |||
| 3c3a114a38 | |||
| fe6972c1f8 | |||
| 08b9b72dcd | |||
| c90be042e7 | |||
| 430a05ab38 |
+2
-1
@@ -15,12 +15,13 @@ pnpm-debug.log*
|
|||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.idea
|
.idea
|
||||||
|
.vscode
|
||||||
*.suo
|
*.suo
|
||||||
*.ntvs*
|
*.ntvs*
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
.vscode/settings.json
|
node_modules
|
||||||
|
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json.schemastore.org/prettierrc",
|
|
||||||
"tabWidth": 2,
|
|
||||||
"singleQuote": true,
|
|
||||||
"printWidth": 100,
|
|
||||||
"trailingComma": "none"
|
|
||||||
}
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"recommendations": ["Vue.volar", "esbenp.prettier-vscode"]
|
|
||||||
}
|
|
||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stacjownik",
|
"name": "stacjownik",
|
||||||
"version": "1.35.0",
|
"version": "1.33.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -26,12 +26,12 @@
|
|||||||
"vue-router": "^4.4.0"
|
"vue-router": "^4.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node24": "^24.0.4",
|
"@types/node": "^24.3.1",
|
||||||
"@types/node": "^24.12.0",
|
|
||||||
"@types/showdown": "^2.0.6",
|
"@types/showdown": "^2.0.6",
|
||||||
"@vite-pwa/assets-generator": "^1.0.0",
|
"@vite-pwa/assets-generator": "^1.0.0",
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@vue/tsconfig": "^0.8.1",
|
"@vue/tsconfig": "^0.8.1",
|
||||||
|
"axios": "^1.9.0",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.5.4",
|
||||||
"vite": "^7.1.4",
|
"vite": "^7.1.4",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
+6
-9
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
import { version } from '../package.json';
|
import { version } from '../package.json';
|
||||||
import { Status } from './typings/common';
|
import { Status } from './typings/common';
|
||||||
@@ -113,15 +114,11 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const releaseData = await (
|
||||||
'https://api.github.com/repos/Spythere/stacjownik/releases/latest'
|
await axios.get('https://api.github.com/repos/Spythere/stacjownik/releases/latest')
|
||||||
);
|
).data;
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!releaseData) return;
|
||||||
throw new Error('Failed to fetch release data from repository!');
|
|
||||||
}
|
|
||||||
|
|
||||||
const releaseData = await response.json();
|
|
||||||
|
|
||||||
this.store.appUpdate = {
|
this.store.appUpdate = {
|
||||||
version,
|
version,
|
||||||
@@ -133,7 +130,7 @@ export default defineComponent({
|
|||||||
(storageVersion != '' && storageVersion != version && this.isOnProductionHost) ||
|
(storageVersion != '' && storageVersion != version && this.isOnProductionHost) ||
|
||||||
import.meta.env.VITE_UPDATE_TEST === 'test';
|
import.meta.env.VITE_UPDATE_TEST === 'test';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(`Wystąpił błąd podczas pobierania danych z API GitHuba: ${error}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageManager.setStringValue(STORAGE_VERSION_KEY, version);
|
StorageManager.setStringValue(STORAGE_VERSION_KEY, version);
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<Card :is-open="isUpdateCardOpen" @toggle-card="toggleCard(false)">
|
<Card :is-open="isUpdateCardOpen" @toggle-card="toggleCard(false)">
|
||||||
<div class="content" tabindex="0" ref="content">
|
<div class="content" tabindex="0" ref="content">
|
||||||
<h1 class="content-title">
|
<h1 class="content-title"><i class="fa-solid fa-wand-sparkles"></i> {{ $t('update.title') }}</h1>
|
||||||
<i class="fa-solid fa-wand-sparkles"></i> {{ $t('update.title') }}
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div class="features-body" v-if="htmlChangelog != ''" v-html="htmlChangelog"></div>
|
<div class="features-body" v-if="htmlChangelog != ''" v-html="htmlChangelog"></div>
|
||||||
<div class="no-features" v-else>{{ $t('update.no-data') }}</div>
|
<div class="no-features" v-else>{{ $t('update.no-data') }}</div>
|
||||||
@@ -89,27 +87,13 @@ export default defineComponent({
|
|||||||
|
|
||||||
::v-deep(h2) {
|
::v-deep(h2) {
|
||||||
padding: 0.5em 0;
|
padding: 0.5em 0;
|
||||||
|
border-bottom: 1px solid #aaa;
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
height: 2px;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #aaa;
|
|
||||||
margin-top: 0.25em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::v-deep(h3) {
|
|
||||||
padding-bottom: 0.25em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep(ul) {
|
::v-deep(ul) {
|
||||||
list-style: disc;
|
list-style: disc;
|
||||||
|
padding: 0.5em 1.5em;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
padding: 0 1.5em;
|
|
||||||
|
|
||||||
padding-bottom: 0.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
|||||||
@@ -1,325 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="driver-propositions">
|
|
||||||
<h3>{{ t('trains.number-propositions-header') }}</h3>
|
|
||||||
|
|
||||||
<div class="categories-select">
|
|
||||||
<button
|
|
||||||
v-for="(category, i) in availableCategories"
|
|
||||||
class="btn btn--option btn--action"
|
|
||||||
@click="selectCategory(i)"
|
|
||||||
:class="{ checked: i == chosenCategoryIndex }"
|
|
||||||
>
|
|
||||||
{{ category }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="numberPropositions.length > 0" class="propositions-numbers">
|
|
||||||
<div v-if="chosenCategory">
|
|
||||||
<b>{{ chosenCategory }} </b> -
|
|
||||||
{{ t(`categories.${chosenCategory.slice(0, 2)}`) }}
|
|
||||||
({{ t(`categories.${chosenCategory.slice(2)}`) }})
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="chosenCategoryRules">
|
|
||||||
<span v-if="chosenCategoryRules[0]"
|
|
||||||
>{{ t('trains.number-propositions-third-number') }}
|
|
||||||
<b class="text--primary">{{ chosenCategoryRules[0] }}</b> •
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
>{{
|
|
||||||
t('trains.number-propositions-last-nums', {
|
|
||||||
count: chosenCategoryRules[1].length
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
<b class="text--primary">{{ chosenCategoryRules[1] }}</b> -
|
|
||||||
<b class="text--primary">{{ chosenCategoryRules[2] }}</b></span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-top: 0.5em">
|
|
||||||
<b>{{ t('trains.number-propositions-title') }} </b>
|
|
||||||
<i>{{ numberPropositions.join(', ') }}</i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="no-propositions" v-else>{{ t('trains.number-propositions-empty') }}</div>
|
|
||||||
|
|
||||||
<div class="cargo-warnings" v-if="getCargoWarnings.size > 0">
|
|
||||||
<hr />
|
|
||||||
<h3>{{ t('cargo-warnings.title') }}</h3>
|
|
||||||
|
|
||||||
<div class="warnings-container">
|
|
||||||
<div
|
|
||||||
v-for="warning in getCargoWarnings"
|
|
||||||
class="train-badge"
|
|
||||||
:class="`${warning.split('-')[0]}`"
|
|
||||||
>
|
|
||||||
{{ t('cargo-warnings.' + warning) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, computed, PropType, watch, onMounted } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { Train } from '../../typings/common';
|
|
||||||
import rulesJSON from '../../data/trainNumberRules.json';
|
|
||||||
import { useApiStore } from '../../store/apiStore';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
const apiStore = useApiStore();
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
chosenTrain: {
|
|
||||||
type: Object as PropType<Train>,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const emits = defineEmits(['selectCategory']);
|
|
||||||
|
|
||||||
const chosenCategoryIndex = ref(0);
|
|
||||||
|
|
||||||
const numberPropositions = ref<string[]>([]);
|
|
||||||
const chosenCategoryRules = ref<any[]>([]);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
computed(() => props.chosenTrain.trainNo),
|
|
||||||
() => {
|
|
||||||
chosenCategoryIndex.value = 0;
|
|
||||||
generateNumberPropositions();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
generateNumberPropositions();
|
|
||||||
});
|
|
||||||
|
|
||||||
function generateNumberPropositions() {
|
|
||||||
const categoryCode = chosenCategory.value?.slice(0, 2);
|
|
||||||
const trainNoStr = props.chosenTrain.trainNo.toString();
|
|
||||||
|
|
||||||
// Get category rules
|
|
||||||
const rules = categoryCode
|
|
||||||
? ((rulesJSON.categoriesRules as any)[categoryCode] as any[])
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
if (!categoryCode || !rules) {
|
|
||||||
numberPropositions.value.length = 0;
|
|
||||||
chosenCategoryRules.value.length = 0;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [thirdNumber, minRange, maxRange] = rules;
|
|
||||||
|
|
||||||
const propositionsArr: string[] = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
let generatedNumStr = '';
|
|
||||||
|
|
||||||
generatedNumStr += trainNoStr[0] ?? Math.floor(Math.random() * 10);
|
|
||||||
generatedNumStr += trainNoStr[1] ?? Math.floor(Math.random() * 10);
|
|
||||||
|
|
||||||
// Third number
|
|
||||||
generatedNumStr += thirdNumber ?? '';
|
|
||||||
|
|
||||||
// Remaining numbers
|
|
||||||
const rangeNums = minRange?.length ?? 3;
|
|
||||||
|
|
||||||
const randRange = Math.floor(
|
|
||||||
Math.random() * (Number(maxRange) - Number(minRange)) + Number(minRange)
|
|
||||||
).toString();
|
|
||||||
|
|
||||||
const leadingZeros = new Array(Math.abs(randRange.toString().length - rangeNums))
|
|
||||||
.fill('0')
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
generatedNumStr += `${leadingZeros}${randRange}`;
|
|
||||||
|
|
||||||
const isNumberTaken =
|
|
||||||
apiStore.activeData?.trains?.some((t) => t.trainNo.toString() == generatedNumStr) ?? false;
|
|
||||||
|
|
||||||
if (!isNumberTaken) {
|
|
||||||
propositionsArr.push(generatedNumStr);
|
|
||||||
} else {
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Number(randRange) > Number(maxRange)) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
numberPropositions.value = propositionsArr;
|
|
||||||
chosenCategoryRules.value = rules;
|
|
||||||
}
|
|
||||||
|
|
||||||
const chosenCategory = computed(() => {
|
|
||||||
return availableCategories.value[chosenCategoryIndex.value];
|
|
||||||
});
|
|
||||||
|
|
||||||
const getCargoWarnings = computed(() => {
|
|
||||||
const stockList = props.chosenTrain.stockList;
|
|
||||||
|
|
||||||
let warnings: Set<string> = new Set();
|
|
||||||
|
|
||||||
stockList.forEach((stockVehicle) => {
|
|
||||||
const [vehicleName, vehicleCargo] = stockVehicle.split(':');
|
|
||||||
|
|
||||||
if (vehicleName.startsWith('WB117')) warnings.add(vehicleCargo ? 'twr-un1965' : 'tn-un1965');
|
|
||||||
else if (vehicleName.startsWith('445Rb'))
|
|
||||||
warnings.add(vehicleCargo ? 'tn-un1202' : 'tn-un1202-empty');
|
|
||||||
else if (vehicleName.startsWith('EDK80')) warnings.add('pn-edk80');
|
|
||||||
|
|
||||||
if (vehicleCargo) {
|
|
||||||
if (vehicleCargo.startsWith('wt_20')) warnings.add('pn-innofreight');
|
|
||||||
else if (/^(tank|vehicles_01|truck)/.test(vehicleCargo)) warnings.add('pn-military');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return warnings;
|
|
||||||
});
|
|
||||||
|
|
||||||
const availableCategories = computed(() => {
|
|
||||||
const stockList = props.chosenTrain.stockList;
|
|
||||||
const headVehicle = stockList[0]?.split('-')[0] ?? '';
|
|
||||||
|
|
||||||
let availableCategories: string[] = [];
|
|
||||||
let categoryTraction = 'E';
|
|
||||||
|
|
||||||
let vehicleTypesSet = new Set<string>();
|
|
||||||
let wagonsNamesSet = new Set<string>();
|
|
||||||
let cargoNamesSet = new Set<string>();
|
|
||||||
|
|
||||||
for (const stockName of stockList) {
|
|
||||||
const [vehicleName, ...cargoList] = stockName.split(':');
|
|
||||||
|
|
||||||
const vehicleData = apiStore.vehiclesData?.vehicles.find((v) => v.name == vehicleName);
|
|
||||||
|
|
||||||
if (!vehicleData) continue;
|
|
||||||
|
|
||||||
vehicleTypesSet.add(vehicleData.type);
|
|
||||||
|
|
||||||
if (vehicleData.type.startsWith('wagon-')) wagonsNamesSet.add(vehicleData.name.split('_')[0]);
|
|
||||||
|
|
||||||
if (cargoList !== undefined) cargoList.forEach((c) => cargoNamesSet.add(c.split('_')[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
let vehicleTypesArr = [...vehicleTypesSet];
|
|
||||||
let wagonsNamesArr = [...wagonsNamesSet];
|
|
||||||
|
|
||||||
// Traction
|
|
||||||
if (vehicleTypesArr[0] == 'loco-electric') categoryTraction = 'E';
|
|
||||||
else if (vehicleTypesArr[0] == 'loco-diesel') categoryTraction = 'S';
|
|
||||||
else if (vehicleTypesArr[0] == 'unit-electric') categoryTraction = 'J';
|
|
||||||
else categoryTraction = 'M';
|
|
||||||
|
|
||||||
// EMU / DMU - M*, R*, P*
|
|
||||||
if (vehicleTypesArr.length == 1 && (categoryTraction == 'J' || categoryTraction == 'M')) {
|
|
||||||
availableCategories.push('MO', 'MP', 'MM', 'RO', 'RP', 'RA', 'RM', 'PW');
|
|
||||||
}
|
|
||||||
// Only locos (up to 3) - LT, LP, LS
|
|
||||||
else if (stockList.length <= 3 && vehicleTypesArr.every((v) => v.startsWith('loco-'))) {
|
|
||||||
if (/^(EU|ET|201E|4E|SU|ST|M62|CTLR4C)/.test(headVehicle)) availableCategories.push('LT');
|
|
||||||
if (/^(EU|EP|SU|SP)/.test(headVehicle)) availableCategories.push('LP');
|
|
||||||
if (/^(SM)/.test(headVehicle)) availableCategories.push('LS');
|
|
||||||
}
|
|
||||||
// Only locos (more than 3) - TH
|
|
||||||
else if (stockList.length > 3 && vehicleTypesArr.every((v) => v.startsWith('loco-'))) {
|
|
||||||
availableCategories.push('TH');
|
|
||||||
}
|
|
||||||
// Loco(s) + passenger only wagons - M*, R*, E*, P*
|
|
||||||
else if (vehicleTypesArr.every((v) => v.startsWith('loco-') || v == 'wagon-passenger')) {
|
|
||||||
availableCategories.push('EI', 'EC', 'EN', 'MO', 'MP', 'MM', 'RO', 'RP', 'RA', 'RM', 'PW');
|
|
||||||
}
|
|
||||||
// Loco(s) + cargo only / mixed wagons - T*, Z*
|
|
||||||
else {
|
|
||||||
if (wagonsNamesArr.every((v) => /^(627Z|412Z)/.test(v)))
|
|
||||||
availableCategories.push('TC', 'TD', 'TS');
|
|
||||||
else if (stockList.slice(1).every((v) => /PKPE/.test(v))) {
|
|
||||||
availableCategories.push('ZU', 'ZN');
|
|
||||||
} else if (wagonsNamesArr.length < 3 || cargoNamesSet.size < 3) {
|
|
||||||
availableCategories.push('TM', 'TG', 'TS', 'TK');
|
|
||||||
} else {
|
|
||||||
availableCategories.push('TN', 'TR', 'TS', 'TK');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return availableCategories.map((c) => `${c}${categoryTraction}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
function selectCategory(i: number) {
|
|
||||||
chosenCategoryIndex.value = i;
|
|
||||||
generateNumberPropositions();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@use '../../styles/responsive';
|
|
||||||
@use '../../styles/badge';
|
|
||||||
|
|
||||||
.driver-propositions {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
padding: 0.5em;
|
|
||||||
background-color: #111;
|
|
||||||
}
|
|
||||||
|
|
||||||
.categories-select {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.5em;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
bottom: calc(-0.5em);
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 2px;
|
|
||||||
background-color: #aaa;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.propositions-numbers {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-propositions {
|
|
||||||
margin-top: 1em;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cargo-warnings {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin: 0.5em 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.warnings-container {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include responsive.smallScreen {
|
|
||||||
.driver-propositions {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.categories-select {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.warnings-container {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -4,18 +4,63 @@
|
|||||||
|
|
||||||
<!-- Train action buttons -->
|
<!-- Train action buttons -->
|
||||||
<div class="train-stock-actions">
|
<div class="train-stock-actions">
|
||||||
<button class="btn btn--action" @click="copyStockToClipboard()">
|
<button class="btn btn--action" style="margin: 1em 0" @click="copyStockToClipboard()">
|
||||||
<i class="fa-regular fa-copy"></i> {{ i18n.t('trains.stock-copy') }}
|
<i class="fa-regular fa-copy"></i> {{ i18n.t('trains.stock-copy') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="btn btn--action" @click="toggleNumberPropositions()">
|
<button class="btn btn--action" style="margin: 1em 0" @click="toggleNumberPropositions()">
|
||||||
<i class="fa-regular fa-lightbulb"></i> {{ i18n.t('trains.number-propositions') }}
|
<i class="fa-regular fa-lightbulb"></i> {{ i18n.t('trains.number-propositions') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Proposed numbers container -->
|
<!-- Proposed numbers container -->
|
||||||
<transition name="view-anim">
|
<transition name="view-anim" class="propositions-container">
|
||||||
<DriverPropositions :chosenTrain="chosenTrain" v-if="arePropositionsVisible" />
|
<div v-if="arePropositionsVisible">
|
||||||
|
<h3 style="margin-bottom: 0.5em">{{ i18n.t('trains.number-propositions-header') }}</h3>
|
||||||
|
|
||||||
|
<div class="categories-select">
|
||||||
|
<button
|
||||||
|
v-for="(category, i) in availableCategories"
|
||||||
|
class="btn btn--option btn--action"
|
||||||
|
@click="selectCategory(i)"
|
||||||
|
:class="{ checked: i == chosenCategoryIndex }"
|
||||||
|
>
|
||||||
|
{{ category }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="numberPropositions.length > 0" class="propositions-numbers">
|
||||||
|
<div v-if="chosenCategory">
|
||||||
|
<b>{{ chosenCategory }} </b> -
|
||||||
|
{{ i18n.t(`categories.${chosenCategory.slice(0, 2)}`) }}
|
||||||
|
({{ i18n.t(`categories.${chosenCategory.slice(2)}`) }})
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="chosenCategoryRules">
|
||||||
|
<span v-if="chosenCategoryRules[0]"
|
||||||
|
>{{ i18n.t('trains.number-propositions-third-number') }}
|
||||||
|
<b class="text--primary">{{ chosenCategoryRules[0] }}</b> •
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
>{{
|
||||||
|
i18n.t('trains.number-propositions-last-nums', {
|
||||||
|
count: chosenCategoryRules[1].length
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
<b class="text--primary">{{ chosenCategoryRules[1] }}</b> -
|
||||||
|
<b class="text--primary">{{ chosenCategoryRules[2] }}</b></span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 0.5em">
|
||||||
|
<b>{{ i18n.t('trains.number-propositions-title') }} </b>
|
||||||
|
<i>{{ numberPropositions.join(', ') }}</i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="no-propositions" v-else>{{ i18n.t('trains.number-propositions-empty') }}</div>
|
||||||
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<StockList :trainStockList="chosenTrain.stockList" :key="chosenTrain.id" :showPreviews="true" />
|
<StockList :trainStockList="chosenTrain.stockList" :key="chosenTrain.id" :showPreviews="true" />
|
||||||
@@ -27,15 +72,25 @@
|
|||||||
import { PropType, ref } from 'vue';
|
import { PropType, ref } from 'vue';
|
||||||
import { Train } from '../../typings/common';
|
import { Train } from '../../typings/common';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useApiStore } from '../../store/apiStore';
|
||||||
|
|
||||||
import StockList from '../Global/StockList.vue';
|
import StockList from '../Global/StockList.vue';
|
||||||
import TrainSchedule from '../TrainsView/TrainSchedule.vue';
|
import TrainSchedule from '../TrainsView/TrainSchedule.vue';
|
||||||
import TrainInfo from '../TrainsView/TrainInfo.vue';
|
import TrainInfo from '../TrainsView/TrainInfo.vue';
|
||||||
import DriverPropositions from './DriverPropositions.vue';
|
|
||||||
|
import rulesJSON from '../../data/trainNumberRules.json';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { watch } from 'vue';
|
||||||
|
|
||||||
|
const apiStore = useApiStore();
|
||||||
|
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const arePropositionsVisible = ref(false);
|
const arePropositionsVisible = ref(false);
|
||||||
|
const chosenCategoryIndex = ref(0);
|
||||||
|
|
||||||
|
const numberPropositions = ref<string[]>([]);
|
||||||
|
const chosenCategoryRules = ref<any[]>([]);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
chosenTrain: {
|
chosenTrain: {
|
||||||
@@ -64,7 +119,153 @@ function copyStockToClipboard() {
|
|||||||
|
|
||||||
function toggleNumberPropositions() {
|
function toggleNumberPropositions() {
|
||||||
arePropositionsVisible.value = !arePropositionsVisible.value;
|
arePropositionsVisible.value = !arePropositionsVisible.value;
|
||||||
|
|
||||||
|
if (arePropositionsVisible.value) generateNumberPropositions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selectCategory(i: number) {
|
||||||
|
chosenCategoryIndex.value = i;
|
||||||
|
|
||||||
|
generateNumberPropositions();
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateNumberPropositions() {
|
||||||
|
const categoryCode = chosenCategory.value?.slice(0, 2);
|
||||||
|
const trainNoStr = props.chosenTrain.trainNo.toString();
|
||||||
|
|
||||||
|
// Get category rules
|
||||||
|
const rules = categoryCode
|
||||||
|
? ((rulesJSON.categoriesRules as any)[categoryCode] as any[])
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (!categoryCode || !rules) {
|
||||||
|
numberPropositions.value.length = 0;
|
||||||
|
chosenCategoryRules.value.length = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [thirdNumber, minRange, maxRange] = rules;
|
||||||
|
|
||||||
|
const propositionsArr: string[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
let generatedNumStr = '';
|
||||||
|
|
||||||
|
generatedNumStr += trainNoStr.at(0) ?? Math.floor(Math.random() * 10);
|
||||||
|
generatedNumStr += trainNoStr.at(1) ?? Math.floor(Math.random() * 10);
|
||||||
|
|
||||||
|
// Third number
|
||||||
|
generatedNumStr += thirdNumber ?? '';
|
||||||
|
|
||||||
|
// Remaining numbers
|
||||||
|
const rangeNums = minRange?.length ?? 3;
|
||||||
|
|
||||||
|
const randRange = Math.floor(
|
||||||
|
Math.random() * (Number(maxRange) - Number(minRange)) + Number(minRange)
|
||||||
|
).toString();
|
||||||
|
|
||||||
|
const leadingZeros = new Array(Math.abs(randRange.toString().length - rangeNums))
|
||||||
|
.fill('0')
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
generatedNumStr += `${leadingZeros}${randRange}`;
|
||||||
|
|
||||||
|
const isNumberTaken =
|
||||||
|
apiStore.activeData?.trains?.some((t) => t.trainNo.toString() == generatedNumStr) ?? false;
|
||||||
|
|
||||||
|
if (!isNumberTaken) {
|
||||||
|
propositionsArr.push(generatedNumStr);
|
||||||
|
} else {
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Number(randRange) > Number(maxRange)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
numberPropositions.value = propositionsArr;
|
||||||
|
chosenCategoryRules.value = rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chosenCategory = computed(() => {
|
||||||
|
return availableCategories.value.at(chosenCategoryIndex.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
const availableCategories = computed(() => {
|
||||||
|
const stockList = props.chosenTrain.stockList;
|
||||||
|
const headVehicle = stockList.at(0)?.split('-')[0] ?? '';
|
||||||
|
|
||||||
|
let availableCategories: string[] = [];
|
||||||
|
let categoryTraction = 'E';
|
||||||
|
|
||||||
|
let vehicleTypesSet = new Set<string>();
|
||||||
|
let wagonsNamesSet = new Set<string>();
|
||||||
|
let cargoNamesSet = new Set<string>();
|
||||||
|
|
||||||
|
for (const stockName of stockList) {
|
||||||
|
const [vehicleName, ...cargoList] = stockName.split(':');
|
||||||
|
|
||||||
|
const vehicleData = apiStore.vehiclesData?.vehicles.find((v) => v.name == vehicleName);
|
||||||
|
|
||||||
|
if (!vehicleData) continue;
|
||||||
|
|
||||||
|
vehicleTypesSet.add(vehicleData.type);
|
||||||
|
|
||||||
|
if (vehicleData.type.startsWith('wagon-')) wagonsNamesSet.add(vehicleData.name.split('_')[0]);
|
||||||
|
|
||||||
|
if (cargoList !== undefined) cargoList.forEach((c) => cargoNamesSet.add(c.split('_')[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
let vehicleTypesArr = [...vehicleTypesSet];
|
||||||
|
let wagonsNamesArr = [...wagonsNamesSet];
|
||||||
|
|
||||||
|
// Traction
|
||||||
|
if (vehicleTypesArr[0] == 'loco-electric') categoryTraction = 'E';
|
||||||
|
else if (vehicleTypesArr[0] == 'loco-diesel') categoryTraction = 'S';
|
||||||
|
else if (vehicleTypesArr[0] == 'unit-electric') categoryTraction = 'J';
|
||||||
|
else categoryTraction = 'M';
|
||||||
|
|
||||||
|
// EMU / DMU - M*, R*, P*
|
||||||
|
if (vehicleTypesArr.length == 1 && (categoryTraction == 'J' || categoryTraction == 'M')) {
|
||||||
|
availableCategories.push('MO', 'MP', 'MM', 'RO', 'RP', 'RA', 'RM', 'PW');
|
||||||
|
}
|
||||||
|
// Only locos (up to 3) - LT, LP, LS
|
||||||
|
else if (stockList.length <= 3 && vehicleTypesArr.every((v) => v.startsWith('loco-'))) {
|
||||||
|
if (/^(EU|ET|201E|4E|SU|ST|M62|CTLR4C)/.test(headVehicle)) availableCategories.push('LT');
|
||||||
|
if (/^(EU|EP|SU|SP)/.test(headVehicle)) availableCategories.push('LP');
|
||||||
|
if (/^(SM)/.test(headVehicle)) availableCategories.push('LS');
|
||||||
|
}
|
||||||
|
// Only locos (more than 3) - TH
|
||||||
|
else if (stockList.length > 3 && vehicleTypesArr.every((v) => v.startsWith('loco-'))) {
|
||||||
|
availableCategories.push('TH');
|
||||||
|
}
|
||||||
|
// Loco(s) + passenger only wagons - M*, R*, E*, P*
|
||||||
|
else if (vehicleTypesArr.every((v) => v.startsWith('loco-') || v == 'wagon-passenger')) {
|
||||||
|
availableCategories.push('EI', 'EC', 'EN', 'MO', 'MP', 'MM', 'RO', 'RP', 'RA', 'RM', 'PW');
|
||||||
|
}
|
||||||
|
// Loco(s) + cargo only / mixed wagons - T*, Z*
|
||||||
|
else {
|
||||||
|
if (wagonsNamesArr.every((v) => /^(627Z|412Z)/.test(v)))
|
||||||
|
availableCategories.push('TC', 'TD', 'TS');
|
||||||
|
else if (stockList.slice(1).every((v) => /PKPE/.test(v))) {
|
||||||
|
availableCategories.push('ZU', 'ZN');
|
||||||
|
} else if (wagonsNamesArr.length < 3 || cargoNamesSet.size < 3) {
|
||||||
|
availableCategories.push('TM', 'TG', 'TS', 'TK');
|
||||||
|
} else {
|
||||||
|
availableCategories.push('TN', 'TR', 'TS', 'TK');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return availableCategories.map((c) => `${c}${categoryTraction}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
computed(() => `${props.chosenTrain.trainNo}`),
|
||||||
|
() => {
|
||||||
|
chosenCategoryIndex.value = 0;
|
||||||
|
generateNumberPropositions();
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -78,13 +279,49 @@ function toggleNumberPropositions() {
|
|||||||
|
|
||||||
.train-stock-actions {
|
.train-stock-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.propositions-container {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
padding: 0.5em;
|
||||||
|
background-color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.categories-select {
|
||||||
|
display: inline-flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
margin: 1em 0;
|
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: calc(-0.5em);
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #aaa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.propositions-numbers {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-propositions {
|
||||||
|
margin-top: 1em;
|
||||||
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include responsive.smallScreen {
|
@include responsive.smallScreen {
|
||||||
.train-stock-actions {
|
.propositions-container {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.categories-select {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
:images="images"
|
:images="images"
|
||||||
:image-fallbacks="imagesFallbacks"
|
:image-fallbacks="imagesFallbacks"
|
||||||
:show-previews="showPreviews"
|
:show-previews="showPreviews"
|
||||||
:thumbnail-size="thumbnailSize"
|
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -26,8 +25,7 @@ export default defineComponent({
|
|||||||
props: {
|
props: {
|
||||||
trainStockList: { type: Array as PropType<string[]>, required: true },
|
trainStockList: { type: Array as PropType<string[]>, required: true },
|
||||||
tractionOnly: { type: Boolean, required: false },
|
tractionOnly: { type: Boolean, required: false },
|
||||||
showPreviews: { type: Boolean },
|
showPreviews: { type: Boolean }
|
||||||
thumbnailSize: { type: Number }
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<img
|
<img
|
||||||
v-for="(thumbnailImage, imageIndex) in images"
|
v-for="(thumbnailImage, imageIndex) in images"
|
||||||
:src="`https://stacjownik.spythere.eu/static/thumbnails/${thumbnailImage}.png`"
|
:src="`https://stacjownik.spythere.eu/static/thumbnails/${thumbnailImage}.png`"
|
||||||
:height="thumbnailSize || 70"
|
height="70"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
:data-crosshair-cursor="showPreviews"
|
:data-crosshair-cursor="showPreviews"
|
||||||
:data-tooltip-type="showPreviews ? 'VehiclePreviewTooltip' : ''"
|
:data-tooltip-type="showPreviews ? 'VehiclePreviewTooltip' : ''"
|
||||||
@@ -28,8 +28,7 @@ const props = defineProps({
|
|||||||
vehicleString: { type: String, required: true },
|
vehicleString: { type: String, required: true },
|
||||||
images: { type: Object as PropType<string[]>, required: true },
|
images: { type: Object as PropType<string[]>, required: true },
|
||||||
imageFallbacks: { type: Object as PropType<string[]>, required: true },
|
imageFallbacks: { type: Object as PropType<string[]>, required: true },
|
||||||
showPreviews: { type: Boolean },
|
showPreviews: { type: Boolean }
|
||||||
thumbnailSize: { type: Number }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const thumbRef = ref(null) as Ref<HTMLElement | null>;
|
const thumbRef = ref(null) as Ref<HTMLElement | null>;
|
||||||
@@ -68,7 +67,7 @@ function onImageLoad() {
|
|||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
font-size: 0.8em;
|
font-size: 0.85em;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0.25em 0;
|
padding: 0.25em 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,7 @@
|
|||||||
</b>
|
</b>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
v-if="isCreator(entry.dispatcherName)"
|
v-if="apiStore.donatorsData.includes(entry.dispatcherName)"
|
||||||
data-tooltip-type="CreatorTooltip"
|
|
||||||
:data-tooltip-content="$t('donations.creator-message')"
|
|
||||||
>
|
|
||||||
<router-link
|
|
||||||
class="text--creator"
|
|
||||||
:to="`/journal/dispatchers?search-dispatcher=${entry.dispatcherName}`"
|
|
||||||
>
|
|
||||||
{{ entry.dispatcherName }}
|
|
||||||
</router-link>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
v-else-if="apiStore.donatorsData.includes(entry.dispatcherName)"
|
|
||||||
data-tooltip-type="DonatorTooltip"
|
data-tooltip-type="DonatorTooltip"
|
||||||
:data-tooltip-content="$t('donations.dispatcher-message')"
|
:data-tooltip-content="$t('donations.dispatcher-message')"
|
||||||
>
|
>
|
||||||
@@ -135,7 +122,6 @@ import styleMixin from '../../../mixins/styleMixin';
|
|||||||
import { useApiStore } from '../../../store/apiStore';
|
import { useApiStore } from '../../../store/apiStore';
|
||||||
import StationStatusBadge from '../../Global/StationStatusBadge.vue';
|
import StationStatusBadge from '../../Global/StationStatusBadge.vue';
|
||||||
import FlagIcon from '../../Global/FlagIcon.vue';
|
import FlagIcon from '../../Global/FlagIcon.vue';
|
||||||
import { isCreator } from '../../../utils/userUtils';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -148,7 +134,7 @@ export default defineComponent({
|
|||||||
emits: ['toggleShowExtraInfo'],
|
emits: ['toggleShowExtraInfo'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return { regions, apiStore: useApiStore(), isCreator };
|
return { regions, apiStore: useApiStore() };
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -269,9 +269,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
this.searchTimeout = window.setTimeout(async () => {
|
this.searchTimeout = window.setTimeout(async () => {
|
||||||
try {
|
try {
|
||||||
const suggestions: string[] = await this.apiStore.client.get(
|
const suggestions: string[] = await (
|
||||||
`api/get${type}Suggestions?name=${value}`
|
await this.apiStore.client!.get(`api/get${type}Suggestions?name=${value}`)
|
||||||
);
|
).data;
|
||||||
|
|
||||||
this[`${type}Suggestions`] = suggestions;
|
this[`${type}Suggestions`] = suggestions;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -336,17 +336,10 @@ export default defineComponent({
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 1fr auto;
|
grid-template-rows: 1fr auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
max-height: calc(100% - 4.5em);
|
max-height: 530px;
|
||||||
top: 3.5em;
|
|
||||||
padding: 1em 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.options_content {
|
.options_content {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 0 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options_actions {
|
|
||||||
padding: 0 1em;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -64,18 +64,10 @@ function navigateToProfile() {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@use '../../styles/dropdown';
|
@use '../../styles/dropdown';
|
||||||
@use '../../styles/dropdown-filters';
|
@use '../../styles/dropdown-filters';
|
||||||
@use '../../styles/responsive';
|
|
||||||
|
|
||||||
.dropdown_wrapper {
|
.dropdown_wrapper {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: 0;
|
right: 0;
|
||||||
max-width: 700px;
|
max-width: 700px;
|
||||||
top: 3.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include responsive.smallScreen {
|
|
||||||
.dropdown_wrapper {
|
|
||||||
top: 6.25em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -201,20 +201,22 @@ const driverRouteLocation = computed<RouteLocationRaw | null>(() => {
|
|||||||
|
|
||||||
async function fetchTimetableDetails() {
|
async function fetchTimetableDetails() {
|
||||||
try {
|
try {
|
||||||
const responseData = await apiStore.client.get<API.TimetableHistory.Response>(
|
const responseData = await apiStore.client!.get<API.TimetableHistory.Response>(
|
||||||
'api/getTimetables',
|
'api/getTimetables',
|
||||||
{
|
{
|
||||||
timetableId: props.timetableEntry.id,
|
params: {
|
||||||
returnType: 'detailed'
|
timetableId: props.timetableEntry.id,
|
||||||
|
returnType: 'detailed'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!responseData || responseData.length != 1) {
|
if (!responseData || responseData.data.length != 1) {
|
||||||
timetableDetails.value = null;
|
timetableDetails.value = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
timetableDetails.value = responseData[0];
|
timetableDetails.value = responseData.data[0];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// this.dataStatus = Status.Data.Error;
|
// this.dataStatus = Status.Data.Error;
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|||||||
@@ -59,17 +59,7 @@
|
|||||||
</strong>
|
</strong>
|
||||||
|
|
||||||
<router-link
|
<router-link
|
||||||
v-if="isCreator(timetable.driverName)"
|
v-if="apiStore.donatorsData.includes(timetable.driverName)"
|
||||||
class="text--creator"
|
|
||||||
data-tooltip-type="CreatorTooltip"
|
|
||||||
:data-tooltip-content="$t('donations.creator-message')"
|
|
||||||
:to="`/journal/timetables?search-driver=${timetable.driverName}`"
|
|
||||||
>
|
|
||||||
<strong>{{ timetable.driverName }}</strong>
|
|
||||||
</router-link>
|
|
||||||
|
|
||||||
<router-link
|
|
||||||
v-else-if="apiStore.donatorsData.includes(timetable.driverName)"
|
|
||||||
class="text--donator"
|
class="text--donator"
|
||||||
data-tooltip-type="DonatorTooltip"
|
data-tooltip-type="DonatorTooltip"
|
||||||
:data-tooltip-content="$t('donations.driver-message')"
|
:data-tooltip-content="$t('donations.driver-message')"
|
||||||
@@ -125,7 +115,6 @@ import styleMixin from '../../../mixins/styleMixin';
|
|||||||
import { useApiStore } from '../../../store/apiStore';
|
import { useApiStore } from '../../../store/apiStore';
|
||||||
import trainCategoryMixin from '../../../mixins/trainCategoryMixin';
|
import trainCategoryMixin from '../../../mixins/trainCategoryMixin';
|
||||||
import FlagIcon from '../../Global/FlagIcon.vue';
|
import FlagIcon from '../../Global/FlagIcon.vue';
|
||||||
import { isCreator } from '../../../utils/userUtils';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { FlagIcon },
|
components: { FlagIcon },
|
||||||
@@ -133,8 +122,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
apiStore: useApiStore(),
|
apiStore: useApiStore()
|
||||||
isCreator
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ export namespace Journal {
|
|||||||
| 'search-issuedFrom'
|
| 'search-issuedFrom'
|
||||||
| 'search-terminatingAt'
|
| 'search-terminatingAt'
|
||||||
| 'search-via'
|
| 'search-via'
|
||||||
| 'select-categoryCode'
|
| 'select-categoryCode';
|
||||||
| 'search-headUnit';
|
|
||||||
|
|
||||||
export type TimetableSearchType = {
|
export type TimetableSearchType = {
|
||||||
[key in TimetableSearchKey]: string;
|
[key in TimetableSearchKey]: string;
|
||||||
|
|||||||
@@ -5,10 +5,7 @@
|
|||||||
<ProfilePlayerAvatar :playerTD2Info="playerTD2Info" />
|
<ProfilePlayerAvatar :playerTD2Info="playerTD2Info" />
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2
|
<h2 class="player-name-header" :class="{ 'text--donator': isPlayerDonator }">
|
||||||
class="player-name-header"
|
|
||||||
:class="{ 'text--donator': isPlayerDonator, 'text--creator': isPlayerCreator }"
|
|
||||||
>
|
|
||||||
<a :href="`https://td2.info.pl/profile/?u=${route.query.playerId}`" target="_blank">
|
<a :href="`https://td2.info.pl/profile/?u=${route.query.playerId}`" target="_blank">
|
||||||
<img
|
<img
|
||||||
v-if="isPlayerDonator"
|
v-if="isPlayerDonator"
|
||||||
@@ -235,7 +232,6 @@ import { useApiStore } from '../../store/apiStore';
|
|||||||
import StationStatusBadge from '../Global/StationStatusBadge.vue';
|
import StationStatusBadge from '../Global/StationStatusBadge.vue';
|
||||||
import ProfilePlayerAvatar from './ProfilePlayerAvatar.vue';
|
import ProfilePlayerAvatar from './ProfilePlayerAvatar.vue';
|
||||||
import { getRegionNameById } from '../../utils/regionUtils';
|
import { getRegionNameById } from '../../utils/regionUtils';
|
||||||
import { isCreator } from '../../utils/userUtils';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@@ -261,8 +257,6 @@ const isPlayerDonator = computed(() =>
|
|||||||
props.playerName ? apiStore.donatorsData.includes(props.playerName) : false
|
props.playerName ? apiStore.donatorsData.includes(props.playerName) : false
|
||||||
);
|
);
|
||||||
|
|
||||||
const isPlayerCreator = computed(() => (props.playerName ? isCreator(props.playerName) : false));
|
|
||||||
|
|
||||||
const activeDispatches = computed(() => {
|
const activeDispatches = computed(() => {
|
||||||
if (!props.playerName) return [];
|
if (!props.playerName) return [];
|
||||||
if (!apiStore.activeData || !apiStore.activeData.activeSceneries) return [];
|
if (!apiStore.activeData || !apiStore.activeData.activeSceneries) return [];
|
||||||
|
|||||||
@@ -127,8 +127,9 @@ export default defineComponent({
|
|||||||
this.station?.name || this.onlineScenery?.name
|
this.station?.name || this.onlineScenery?.name
|
||||||
}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
}&countFrom=${countFrom}&countLimit=${countLimit}`;
|
||||||
|
|
||||||
const historyAPIData: API.DispatcherHistory.Response =
|
const historyAPIData: API.DispatcherHistory.Response = await (
|
||||||
await this.apiStore.client.get(requestString);
|
await this.apiStore.client!.get(requestString)
|
||||||
|
).data;
|
||||||
|
|
||||||
this.dataStatus = Status.Data.Loaded;
|
this.dataStatus = Status.Data.Loaded;
|
||||||
return historyAPIData;
|
return historyAPIData;
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ import { useRoute, useRouter } from 'vue-router';
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const prevPath = ref('/');
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
prevPath.value = (route.meta['prevPath'] as string) ?? '/';
|
||||||
|
});
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
station: {
|
station: {
|
||||||
type: Object as PropType<Station>
|
type: Object as PropType<Station>
|
||||||
@@ -40,7 +46,7 @@ defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function onReturnButtonClick() {
|
function onReturnButtonClick() {
|
||||||
router.push('/');
|
router.push(prevPath.value);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -9,16 +9,9 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<router-link class="dispatcher-name" :to="`/profile?playerId=${onlineScenery.dispatcherId}`">
|
<router-link class="dispatcher-name" :to="`/profile?playerId=${onlineScenery.dispatcherId}`">
|
||||||
<span
|
|
||||||
class="text--creator"
|
|
||||||
v-if="isCreator(onlineScenery.dispatcherName)"
|
|
||||||
:title="$t('donations.creator-message')"
|
|
||||||
>
|
|
||||||
{{ onlineScenery.dispatcherName }}
|
|
||||||
</span>
|
|
||||||
<span
|
<span
|
||||||
class="text--donator"
|
class="text--donator"
|
||||||
v-else-if="apiStore.donatorsData.includes(onlineScenery.dispatcherName)"
|
v-if="apiStore.donatorsData.includes(onlineScenery.dispatcherName)"
|
||||||
:title="$t('donations.dispatcher-message')"
|
:title="$t('donations.dispatcher-message')"
|
||||||
>
|
>
|
||||||
{{ onlineScenery.dispatcherName }}
|
{{ onlineScenery.dispatcherName }}
|
||||||
@@ -58,7 +51,6 @@ import StationStatusBadge from '../../Global/StationStatusBadge.vue';
|
|||||||
import { ActiveScenery } from '../../../typings/common';
|
import { ActiveScenery } from '../../../typings/common';
|
||||||
import { useApiStore } from '../../../store/apiStore';
|
import { useApiStore } from '../../../store/apiStore';
|
||||||
import FlagIcon from '../../Global/FlagIcon.vue';
|
import FlagIcon from '../../Global/FlagIcon.vue';
|
||||||
import { isCreator } from '../../../utils/userUtils';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [styleMixin, dateMixin, routerMixin],
|
mixins: [styleMixin, dateMixin, routerMixin],
|
||||||
@@ -66,8 +58,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
apiStore: useApiStore(),
|
apiStore: useApiStore()
|
||||||
isCreator
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="info-routes" v-if="station.generalInfo">
|
<section class="info-routes" v-if="station.generalInfo">
|
||||||
<div class="routes one-way" v-if="singleRoutesAvailable.length > 0">
|
<div class="routes one-way" v-if="oneWayRoutes.length > 0">
|
||||||
<button
|
<button
|
||||||
class="routes-btn"
|
class="routes-btn"
|
||||||
@click="toggleRoutesVisibility('single')"
|
@click="toggleRoutesVisibility('single')"
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<ul class="routes-list">
|
<ul class="routes-list">
|
||||||
<li v-for="route in singleRoutesFiltered" :key="route.routeName">
|
<li v-for="route in oneWayRoutes" :key="route.routeName">
|
||||||
<span :class="{ 'no-catenary': !route.isElectric, internal: route.isInternal }">
|
<span :class="{ 'no-catenary': !route.isElectric, internal: route.isInternal }">
|
||||||
{{ route.routeName }}</span
|
{{ route.routeName }}</span
|
||||||
>
|
>
|
||||||
@@ -24,17 +24,10 @@
|
|||||||
</span>
|
</span>
|
||||||
<span v-if="route.isRouteSBL" class="sbl">SBL</span>
|
<span v-if="route.isRouteSBL" class="sbl">SBL</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li v-if="singleRoutesFiltered.length == 0">
|
|
||||||
<span class="routes-hidden">
|
|
||||||
<i class="fa-solid fa-eye-slash"></i>
|
|
||||||
{{ $t('scenery.routes-hidden') }}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="routes two-way" v-if="doubleRoutesAvailable.length > 0">
|
<div class="routes two-way" v-if="twoWayRoutes.length > 0">
|
||||||
<button
|
<button
|
||||||
class="routes-btn"
|
class="routes-btn"
|
||||||
@click="toggleRoutesVisibility('double')"
|
@click="toggleRoutesVisibility('double')"
|
||||||
@@ -46,7 +39,7 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<ul class="routes-list">
|
<ul class="routes-list">
|
||||||
<li v-for="route in doubleRoutesFiltered" :key="route.routeName">
|
<li v-for="route in twoWayRoutes" :key="route.routeName">
|
||||||
<span :class="{ 'no-catenary': !route.isElectric, internal: route.isInternal }">
|
<span :class="{ 'no-catenary': !route.isElectric, internal: route.isInternal }">
|
||||||
{{ route.routeName }}
|
{{ route.routeName }}
|
||||||
</span>
|
</span>
|
||||||
@@ -61,13 +54,6 @@
|
|||||||
</span>
|
</span>
|
||||||
<span v-if="route.isRouteSBL" class="sbl">SBL</span>
|
<span v-if="route.isRouteSBL" class="sbl">SBL</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li v-if="doubleRoutesFiltered.length == 0">
|
|
||||||
<span class="routes-hidden">
|
|
||||||
<i class="fa-solid fa-eye-slash"></i>
|
|
||||||
{{ $t('scenery.routes-hidden') }}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -116,32 +102,20 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
singleRoutesAvailable() {
|
oneWayRoutes() {
|
||||||
return (
|
return (
|
||||||
this.station.generalInfo?.routes.single
|
this.station.generalInfo?.routes.single
|
||||||
.filter((r) => !r.hidden)
|
.filter((r) => !r.isInternal || r.isInternal == this.showInternalSingleRoutes)
|
||||||
.sort((r1, r2) => r1.routeName.localeCompare(r2.routeName)) ?? []
|
.sort((r1, r2) => r1.routeName.localeCompare(r2.routeName)) ?? []
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
doubleRoutesAvailable() {
|
twoWayRoutes() {
|
||||||
return (
|
return (
|
||||||
this.station.generalInfo?.routes.double
|
this.station.generalInfo?.routes.double
|
||||||
.filter((r) => !r.hidden)
|
.filter((r) => !r.isInternal || r.isInternal == this.showInternalDoubleRoutes)
|
||||||
.sort((r1, r2) => r1.routeName.localeCompare(r2.routeName)) ?? []
|
.sort((r1, r2) => r1.routeName.localeCompare(r2.routeName)) ?? []
|
||||||
);
|
);
|
||||||
},
|
|
||||||
|
|
||||||
singleRoutesFiltered() {
|
|
||||||
return this.singleRoutesAvailable.filter(
|
|
||||||
(r) => this.showInternalSingleRoutes || !r.isInternal
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
doubleRoutesFiltered() {
|
|
||||||
return this.doubleRoutesAvailable.filter(
|
|
||||||
(r) => this.showInternalDoubleRoutes || !r.isInternal
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -180,6 +154,11 @@ ul.routes-list {
|
|||||||
|
|
||||||
li {
|
li {
|
||||||
margin: 0.5em 0.25em;
|
margin: 0.5em 0.25em;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
|
||||||
& > span {
|
& > span {
|
||||||
padding: 0.2em;
|
padding: 0.2em;
|
||||||
@@ -203,16 +182,11 @@ ul.routes-list {
|
|||||||
background-color: #303030;
|
background-color: #303030;
|
||||||
color: #cfcfcf;
|
color: #cfcfcf;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.sbl {
|
&.sbl {
|
||||||
color: var(--clr-primary);
|
color: var(--clr-primary);
|
||||||
background-color: #404040;
|
background-color: #404040;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.routes-hidden {
|
|
||||||
background-color: #4b4b4b;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
border-radius: 0 0.5em 0.5em 0;
|
border-radius: 0 0.5em 0.5em 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,7 @@
|
|||||||
<i
|
<i
|
||||||
v-if="
|
v-if="
|
||||||
train.timetableData != undefined &&
|
train.timetableData != undefined &&
|
||||||
train.lastSeen <= Date.now() - 60000 &&
|
(train.lastSeen <= Date.now() - 60000 || !train.online)
|
||||||
!train.online
|
|
||||||
"
|
"
|
||||||
class="fa-solid fa-user-slash"
|
class="fa-solid fa-user-slash"
|
||||||
style="color: lightcoral"
|
style="color: lightcoral"
|
||||||
|
|||||||
@@ -210,7 +210,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="item-stock-list" v-if="showStockThumbnails">
|
<div class="item-stock-list" v-if="showStockThumbnails">
|
||||||
<StockList :trainStockList="row.train.stockList" :thumbnailSize="45" />
|
<StockList :trainStockList="row.train.stockList" />
|
||||||
</div>
|
</div>
|
||||||
</router-link>
|
</router-link>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
@@ -348,7 +348,7 @@ const tabliceZbiorczeHref = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const pragotronHref = computed(() => {
|
const pragotronHref = computed(() => {
|
||||||
let url = `https://pragotron-td2.spythere.eu/board?name=${props.station!.name}®ion=${mainStore.region.id}`;
|
let url = `https://pragotron-td2.web.app/board?name=${props.station!.name}®ion=${mainStore.region.id}`;
|
||||||
if (props.chosenCheckpoint) url += `&checkpoint=${props.chosenCheckpoint}`;
|
if (props.chosenCheckpoint) url += `&checkpoint=${props.chosenCheckpoint}`;
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
|
|||||||
@@ -149,12 +149,11 @@ export default defineComponent({
|
|||||||
requestFilters['returnType'] = 'short';
|
requestFilters['returnType'] = 'short';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response: API.TimetableHistory.ResponseShort = await this.apiStore.client.get(
|
const response: API.TimetableHistory.ResponseShort = await (
|
||||||
'api/getTimetables',
|
await this.apiStore.client!.get('api/getTimetables', {
|
||||||
requestFilters
|
params: requestFilters
|
||||||
);
|
})
|
||||||
|
).data;
|
||||||
console.log(response);
|
|
||||||
|
|
||||||
this.historyList = response;
|
this.historyList = response;
|
||||||
|
|
||||||
|
|||||||
@@ -1,213 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="scenery-top-list">
|
|
||||||
<h2 class="header">{{ t('scenery.top-list.header') }}</h2>
|
|
||||||
|
|
||||||
<div class="top-actions">
|
|
||||||
<div class="actions-modes">
|
|
||||||
<button
|
|
||||||
v-for="mode in availableModes"
|
|
||||||
:class="`btn btn--option ${mode == currentListMode ? 'checked' : ''}`"
|
|
||||||
@click="selectListMode(mode)"
|
|
||||||
>
|
|
||||||
{{ t(`scenery.top-list.mode-${mode}`) }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="actions-scopes">
|
|
||||||
<button
|
|
||||||
v-for="scope in availableScopes"
|
|
||||||
:class="`btn btn--option ${scope == currentListScope ? 'checked' : ''}`"
|
|
||||||
@click="selectListScope(scope)"
|
|
||||||
>
|
|
||||||
{{ t(`scenery.top-list.scope-${scope}`) }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="rating-list-wrapper">
|
|
||||||
<Loading v-if="listState == Status.Data.Loading" />
|
|
||||||
<div v-else-if="listState == Status.Data.Error">Ups, coś poszło nie tak...</div>
|
|
||||||
|
|
||||||
<ul v-else-if="bestScoreList.length > 0">
|
|
||||||
<li v-for="(value, i) in bestScoreList">
|
|
||||||
<div>
|
|
||||||
{{ t('ordinal', { count: i + 1 }) }} {{ t('scenery.top-list.place') }} -
|
|
||||||
<router-link :to="`/profile?playerId=${value.dispatcherId}`">{{
|
|
||||||
value.dispatcherName
|
|
||||||
}}</router-link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<b class="text--primary" v-if="currentListMode == 'dutyCount'">{{
|
|
||||||
t('scenery.top-list.duty-count', value.value)
|
|
||||||
}}</b>
|
|
||||||
|
|
||||||
<b class="text--primary" v-else-if="currentListMode == 'dispatcherRating'">{{
|
|
||||||
t('scenery.top-list.dispatcher-rating', value.value)
|
|
||||||
}}</b>
|
|
||||||
|
|
||||||
<b class="text--primary" v-else>
|
|
||||||
{{ t('scenery.top-list.duration') }}
|
|
||||||
{{ humanizeDuration(value.value) }}
|
|
||||||
</b>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div v-else class="no-data">
|
|
||||||
<span v-if="currentListScope == 'name'">{{ t('scenery.top-list.no-data-general') }}</span>
|
|
||||||
<span v-else>{{ t('scenery.top-list.no-data-current-hash') }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { onActivated, PropType, ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { useApiStore } from '../../store/apiStore';
|
|
||||||
import { Station, ActiveScenery, Status } from '../../typings/common';
|
|
||||||
import Loading from '../Global/Loading.vue';
|
|
||||||
import { humanizeDuration } from '../../composables/time';
|
|
||||||
|
|
||||||
interface SceneryBestScoreItem {
|
|
||||||
dispatcherName: string;
|
|
||||||
dispatcherId: number;
|
|
||||||
value: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const apiStore = useApiStore();
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'SceneryTopList'
|
|
||||||
});
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
station: {
|
|
||||||
type: Object as PropType<Station>
|
|
||||||
},
|
|
||||||
|
|
||||||
onlineScenery: {
|
|
||||||
type: Object as PropType<ActiveScenery>
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const availableModes = ['dutyCount', 'dispatcherRating', 'dutyDuration'] as const;
|
|
||||||
const availableScopes = ['name', 'hash'] as const;
|
|
||||||
|
|
||||||
type ListMode = (typeof availableModes)[number];
|
|
||||||
type ListScope = (typeof availableScopes)[number];
|
|
||||||
|
|
||||||
const currentListMode = ref<ListMode>('dutyCount');
|
|
||||||
const currentListScope = ref<ListScope>('name');
|
|
||||||
|
|
||||||
const listState = ref<Status.Data>(Status.Data.Loading);
|
|
||||||
|
|
||||||
const bestScoreList = ref<SceneryBestScoreItem[]>([]);
|
|
||||||
|
|
||||||
onActivated(() => {
|
|
||||||
fetchTopDispatchersList();
|
|
||||||
});
|
|
||||||
|
|
||||||
function selectListMode(mode: ListMode) {
|
|
||||||
currentListMode.value = mode;
|
|
||||||
fetchTopDispatchersList();
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectListScope(scope: ListScope) {
|
|
||||||
currentListScope.value = scope;
|
|
||||||
fetchTopDispatchersList();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchTopDispatchersList() {
|
|
||||||
const searchedStationValue =
|
|
||||||
currentListScope.value == 'name'
|
|
||||||
? props.station?.name
|
|
||||||
: apiStore.sceneryData.find((sc) => sc.name == props.station!.name)?.hash;
|
|
||||||
|
|
||||||
bestScoreList.value = [];
|
|
||||||
|
|
||||||
if (!searchedStationValue) {
|
|
||||||
listState.value = Status.Data.Loaded;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
listState.value = Status.Data.Loading;
|
|
||||||
|
|
||||||
const response: SceneryBestScoreItem[] = await apiStore.client.get(`api/getSceneryBestScores`, {
|
|
||||||
[currentListScope.value]: searchedStationValue,
|
|
||||||
type: currentListMode.value,
|
|
||||||
countLimit: 40
|
|
||||||
});
|
|
||||||
|
|
||||||
bestScoreList.value = response;
|
|
||||||
listState.value = Status.Data.Loaded;
|
|
||||||
} catch (error) {
|
|
||||||
listState.value = Status.Data.Error;
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.scenery-top-list {
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: auto auto 1fr;
|
|
||||||
overflow: hidden;
|
|
||||||
gap: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-actions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.5em 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions-modes,
|
|
||||||
.actions-scopes {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.5em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rating-list-wrapper {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rating-list-wrapper > ul {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.65em;
|
|
||||||
padding-right: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rating-list-wrapper > ul > li {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
padding: 0.25em;
|
|
||||||
background-color: #2b2b2b;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
line-height: 1.5em;
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-data {
|
|
||||||
padding: 1em 0.5em;
|
|
||||||
font-size: 1.1em;
|
|
||||||
background-color: #333;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -18,31 +18,23 @@ export function getTrainStopStatus(
|
|||||||
return StopStatus.TERMINATED;
|
return StopStatus.TERMINATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == sceneryName) {
|
||||||
!stopInfo.terminatesHere &&
|
|
||||||
stopInfo.confirmed &&
|
|
||||||
currentStationName.startsWith(sceneryName)
|
|
||||||
) {
|
|
||||||
return StopStatus.DEPARTED;
|
return StopStatus.DEPARTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != sceneryName) {
|
||||||
!stopInfo.terminatesHere &&
|
|
||||||
stopInfo.confirmed &&
|
|
||||||
!currentStationName.startsWith(sceneryName)
|
|
||||||
) {
|
|
||||||
return StopStatus.DEPARTED_AWAY;
|
return StopStatus.DEPARTED_AWAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentStationName.startsWith(sceneryName) && !stopInfo.stopped) {
|
if (currentStationName == sceneryName && !stopInfo.stopped) {
|
||||||
return StopStatus.ONLINE;
|
return StopStatus.ONLINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentStationName.startsWith(sceneryName) && stopInfo.stopped) {
|
if (currentStationName == sceneryName && stopInfo.stopped) {
|
||||||
return StopStatus.STOPPED;
|
return StopStatus.STOPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currentStationName.startsWith(sceneryName)) {
|
if (currentStationName != sceneryName) {
|
||||||
return StopStatus.ARRIVING;
|
return StopStatus.ARRIVING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -278,10 +278,6 @@ export default defineComponent({
|
|||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown_wrapper {
|
|
||||||
top: 2.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include responsive.smallScreen {
|
@include responsive.smallScreen {
|
||||||
.stats-title {
|
.stats-title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -290,9 +286,5 @@ export default defineComponent({
|
|||||||
.filter-button > span {
|
.filter-button > span {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-data {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="station_table" @scroll="onScroll" ref="tableRef">
|
<section class="station_table">
|
||||||
<Loading
|
<Loading
|
||||||
v-if="apiStore.dataStatuses.connection == Status.Loading && filteredStationList.length == 0"
|
v-if="apiStore.dataStatuses.connection == Status.Loading && filteredStationList.length == 0"
|
||||||
/>
|
/>
|
||||||
@@ -131,16 +131,7 @@
|
|||||||
<td class="station-dispatcher-name">
|
<td class="station-dispatcher-name">
|
||||||
<span v-if="station.onlineInfo?.dispatcherName">
|
<span v-if="station.onlineInfo?.dispatcherName">
|
||||||
<b
|
<b
|
||||||
v-if="isCreator(station.onlineInfo.dispatcherName)"
|
v-if="apiStore.donatorsData.includes(station.onlineInfo.dispatcherName)"
|
||||||
data-tooltip-type="CreatorTooltip"
|
|
||||||
:data-tooltip-content="$t('donations.creator-message')"
|
|
||||||
>
|
|
||||||
<img src="/images/icon-creator.png" alt="creator icon" />
|
|
||||||
<span class="text--creator"> {{ station.onlineInfo.dispatcherName }}</span>
|
|
||||||
</b>
|
|
||||||
|
|
||||||
<b
|
|
||||||
v-else-if="apiStore.donatorsData.includes(station.onlineInfo.dispatcherName)"
|
|
||||||
data-tooltip-type="DonatorTooltip"
|
data-tooltip-type="DonatorTooltip"
|
||||||
:data-tooltip-content="$t('donations.dispatcher-message')"
|
:data-tooltip-content="$t('donations.dispatcher-message')"
|
||||||
>
|
>
|
||||||
@@ -362,7 +353,6 @@ import { ActiveSorter, HeadIdsType, headIconsIds, headIds } from './typings';
|
|||||||
import { filterStations, sortStations } from './utils';
|
import { filterStations, sortStations } from './utils';
|
||||||
import { getLanguageNameById } from '../../utils/languageUtils';
|
import { getLanguageNameById } from '../../utils/languageUtils';
|
||||||
import FlagIcon from '../Global/FlagIcon.vue';
|
import FlagIcon from '../Global/FlagIcon.vue';
|
||||||
import { isCreator } from '../../utils/userUtils';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
emits: ['toggleDonationCard'],
|
emits: ['toggleDonationCard'],
|
||||||
@@ -373,9 +363,7 @@ export default defineComponent({
|
|||||||
data: () => ({
|
data: () => ({
|
||||||
headIconsIds,
|
headIconsIds,
|
||||||
headIds,
|
headIds,
|
||||||
scrollTop: 0,
|
getChangedFilters
|
||||||
getChangedFilters,
|
|
||||||
isCreator
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
@@ -403,10 +391,6 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
activated() {
|
|
||||||
(this.$refs['tableRef'] as HTMLElement).scrollTop = this.scrollTop;
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
getSceneryRoute(station: Station) {
|
getSceneryRoute(station: Station) {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
@@ -447,10 +431,6 @@ export default defineComponent({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
return JSON.stringify(usersTrains);
|
return JSON.stringify(usersTrains);
|
||||||
},
|
|
||||||
|
|
||||||
onScroll(e: Event) {
|
|
||||||
this.scrollTop = (e.target as HTMLElement).scrollTop;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -633,8 +613,8 @@ tbody tr {
|
|||||||
|
|
||||||
.station-dispatcher-name {
|
.station-dispatcher-name {
|
||||||
img {
|
img {
|
||||||
max-height: 1.3em;
|
max-width: 1.35em;
|
||||||
vertical-align: text-top;
|
vertical-align: text-bottom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="tooltip-content">
|
|
||||||
<img src="/images/icon-creator.png" alt="creator icon" />
|
|
||||||
<b class="text--creator"> {{ tooltipStore.content }}</b>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useTooltipStore } from '../../store/tooltipStore';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
tooltipStore: useTooltipStore()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.tooltip-content {
|
|
||||||
padding: 0.5em;
|
|
||||||
border-radius: 0.25em;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
background-color: #333;
|
|
||||||
box-shadow: 0 0 10px 2px #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
vertical-align: text-bottom;
|
|
||||||
height: 1.25em;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tooltip-content">
|
<div class="tooltip-content">
|
||||||
<img src="/images/icon-diamond.svg" alt="donator diamond icon" />
|
<img src="/images/icon-diamond.svg" alt="donator diamond icon" />
|
||||||
<b class="text--donator"> {{ tooltipStore.content }}</b>
|
<span>{{ tooltipStore.content }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -20,6 +20,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.tooltip-content {
|
.tooltip-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
border-radius: 0.25em;
|
border-radius: 0.25em;
|
||||||
|
|
||||||
@@ -30,7 +35,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
vertical-align: text-bottom;
|
vertical-align: middle;
|
||||||
height: 1.25em;
|
height: 1em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -8,13 +8,12 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useTooltipStore } from '../../store/tooltipStore';
|
import { useTooltipStore } from '../../store/tooltipStore';
|
||||||
import DonatorTooltip from './DonatorTooltip.vue';
|
import DonatorTooltip from './DonatorTooltip.vue';
|
||||||
import CreatorTooltip from './CreatorTooltip.vue';
|
|
||||||
import VehiclePreviewTooltip from './VehiclePreviewTooltip.vue';
|
import VehiclePreviewTooltip from './VehiclePreviewTooltip.vue';
|
||||||
import BaseTooltip from './BaseTooltip.vue';
|
import BaseTooltip from './BaseTooltip.vue';
|
||||||
import SpawnsTooltip from './SpawnsTooltip.vue';
|
import SpawnsTooltip from './SpawnsTooltip.vue';
|
||||||
import UsersTooltip from './UsersTooltip.vue';
|
import UsersTooltip from './UsersTooltip.vue';
|
||||||
import HtmlTooltip from './HtmlTooltip.vue';
|
import HtmlTooltip from './HtmlTooltip.vue';
|
||||||
import TrainInfoTooltip from './TrainInfoTooltip.vue';
|
import TrainInfoTooltip from "./TrainInfoTooltip.vue";
|
||||||
|
|
||||||
const BOX_PADDING_PX = 20;
|
const BOX_PADDING_PX = 20;
|
||||||
|
|
||||||
@@ -26,8 +25,7 @@ export default defineComponent({
|
|||||||
SpawnsTooltip,
|
SpawnsTooltip,
|
||||||
UsersTooltip,
|
UsersTooltip,
|
||||||
HtmlTooltip,
|
HtmlTooltip,
|
||||||
TrainInfoTooltip,
|
TrainInfoTooltip
|
||||||
CreatorTooltip
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
@@ -56,21 +56,12 @@
|
|||||||
</b>
|
</b>
|
||||||
|
|
||||||
<b
|
<b
|
||||||
v-if="isCreator(train.driverName)"
|
v-if="apiStore.donatorsData.includes(train.driverName)"
|
||||||
data-tooltip-type="CreatorTooltip"
|
|
||||||
:data-tooltip-content="$t('donations.creator-message')"
|
|
||||||
>
|
|
||||||
<img src="/images/icon-creator.png" alt="creator icon" />
|
|
||||||
<span class="text--creator"> {{ train.driverName }}</span>
|
|
||||||
</b>
|
|
||||||
|
|
||||||
<b
|
|
||||||
v-else-if="apiStore.donatorsData.includes(train.driverName)"
|
|
||||||
data-tooltip-type="DonatorTooltip"
|
data-tooltip-type="DonatorTooltip"
|
||||||
:data-tooltip-content="$t('donations.driver-message')"
|
:data-tooltip-content="$t('donations.driver-message')"
|
||||||
>
|
>
|
||||||
|
<span class="text--donator">{{ train.driverName }} </span>
|
||||||
<img src="/images/icon-diamond.svg" alt="donator diamond icon" />
|
<img src="/images/icon-diamond.svg" alt="donator diamond icon" />
|
||||||
<span class="text--donator"> {{ train.driverName }}</span>
|
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
<span v-else>{{ train.driverName }}</span>
|
<span v-else>{{ train.driverName }}</span>
|
||||||
@@ -213,7 +204,6 @@ import trainCategoryMixin from '../../mixins/trainCategoryMixin';
|
|||||||
import ProgressBar from '../Global/ProgressBar.vue';
|
import ProgressBar from '../Global/ProgressBar.vue';
|
||||||
import StockList from '../Global/StockList.vue';
|
import StockList from '../Global/StockList.vue';
|
||||||
import FlagIcon from '../Global/FlagIcon.vue';
|
import FlagIcon from '../Global/FlagIcon.vue';
|
||||||
import { isCreator } from '../../utils/userUtils';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
mixins: [trainInfoMixin, styleMixin, trainCategoryMixin],
|
mixins: [trainInfoMixin, styleMixin, trainCategoryMixin],
|
||||||
@@ -232,8 +222,7 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
store: useMainStore(),
|
store: useMainStore(),
|
||||||
apiStore: useApiStore(),
|
apiStore: useApiStore()
|
||||||
isCreator
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -289,6 +278,8 @@ export default defineComponent({
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
gap: 0.25em;
|
||||||
|
|
||||||
background-color: #1a1a1a;
|
background-color: #1a1a1a;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
}
|
}
|
||||||
@@ -367,6 +358,8 @@ export default defineComponent({
|
|||||||
.status-badges {
|
.status-badges {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
margin-left: 0.25em;
|
||||||
|
|
||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
@@ -379,7 +372,7 @@ export default defineComponent({
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
padding: 0.25em 0;
|
padding: 0.5em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-distance {
|
.progress-distance {
|
||||||
|
|||||||
@@ -210,10 +210,6 @@ export default defineComponent({
|
|||||||
@use '../../styles/dropdown';
|
@use '../../styles/dropdown';
|
||||||
@use '../../styles/dropdown-filters';
|
@use '../../styles/dropdown-filters';
|
||||||
|
|
||||||
.dropdown_wrapper {
|
|
||||||
top: 2.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search_content > div {
|
.search_content > div {
|
||||||
margin: 0.5em auto;
|
margin: 0.5em auto;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,10 +250,9 @@ h3 {
|
|||||||
|
|
||||||
.dropdown_wrapper {
|
.dropdown_wrapper {
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
top: 2.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@include responsive.smallScreen {
|
@include responsive.smallScreen{
|
||||||
.no-data {
|
.no-data {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|||||||
-23
@@ -1,23 +0,0 @@
|
|||||||
export class HttpClient {
|
|
||||||
constructor(private readonly baseURL: string) {}
|
|
||||||
|
|
||||||
async get<T>(url: string, params?: Record<string, any>): Promise<T> {
|
|
||||||
const absoluteURL = new URL(this.baseURL + '/' + url);
|
|
||||||
|
|
||||||
if (params) {
|
|
||||||
Object.keys(params).forEach((key) => {
|
|
||||||
if (params[key] === undefined) return;
|
|
||||||
|
|
||||||
absoluteURL.searchParams.append(key, params[key]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await fetch(absoluteURL);
|
|
||||||
|
|
||||||
if (!data.ok) {
|
|
||||||
throw new Error(`Cannot fetch ${absoluteURL}: ${data.statusText}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data.json();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-36
@@ -9,43 +9,9 @@ const i18n = createI18n({
|
|||||||
warnHtmlMessage: false,
|
warnHtmlMessage: false,
|
||||||
fallbackLocale: 'pl',
|
fallbackLocale: 'pl',
|
||||||
|
|
||||||
pluralizationRules: {
|
|
||||||
en: {
|
|
||||||
ordinal: (ctx: { named: (arg0: string) => number }) => {
|
|
||||||
const number = ctx.named('count');
|
|
||||||
|
|
||||||
const suffixes: Record<number, string> = {
|
|
||||||
1: 'st',
|
|
||||||
2: 'nd',
|
|
||||||
3: 'rd'
|
|
||||||
};
|
|
||||||
const suffix = suffixes[number % 10] || 'th';
|
|
||||||
|
|
||||||
return `${number}${suffix}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
messages: {
|
messages: {
|
||||||
en: {
|
en: enLang,
|
||||||
...enLang,
|
pl: plLang
|
||||||
ordinal: (ctx: { named: (arg0: string) => number }) => {
|
|
||||||
const number = ctx.named('count');
|
|
||||||
|
|
||||||
const suffixes: Record<number, string> = {
|
|
||||||
1: 'st',
|
|
||||||
2: 'nd',
|
|
||||||
3: 'rd'
|
|
||||||
};
|
|
||||||
const suffix = suffixes[number % 10] || 'th';
|
|
||||||
|
|
||||||
return `${number}${suffix}`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
pl: {
|
|
||||||
...plLang,
|
|
||||||
ordinal: '{count}.'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
enableLegacy: false
|
enableLegacy: false
|
||||||
});
|
});
|
||||||
|
|||||||
+6
-36
@@ -42,8 +42,7 @@
|
|||||||
"action-paypal": "DONATE WITH PAYPAL",
|
"action-paypal": "DONATE WITH PAYPAL",
|
||||||
"action-buycoffee": "BUY ME A COFFEE!",
|
"action-buycoffee": "BUY ME A COFFEE!",
|
||||||
"dispatcher-message": "Dispatcher supporting the Stacjownik project!",
|
"dispatcher-message": "Dispatcher supporting the Stacjownik project!",
|
||||||
"driver-message": "Driver supporting the Stacjownik project!",
|
"driver-message": "Driver supporting the Stacjownik project!"
|
||||||
"creator-message": "Creator of the Stacjownik project"
|
|
||||||
},
|
},
|
||||||
"warnings": {
|
"warnings": {
|
||||||
"TWR": "Train with high risk cargo",
|
"TWR": "Train with high risk cargo",
|
||||||
@@ -200,7 +199,6 @@
|
|||||||
"search-date-from": "Date (UTC+2 / CEST)",
|
"search-date-from": "Date (UTC+2 / CEST)",
|
||||||
"search-date-to": "Date (UTC+2 / CEST)",
|
"search-date-to": "Date (UTC+2 / CEST)",
|
||||||
"select-categoryCode": "Train category",
|
"select-categoryCode": "Train category",
|
||||||
"search-headUnit": "Traction unit (e.g. EP09, ET22-401)",
|
|
||||||
"sort-mass": "mass",
|
"sort-mass": "mass",
|
||||||
"sort-speed": "speed",
|
"sort-speed": "speed",
|
||||||
"sort-length": "length",
|
"sort-length": "length",
|
||||||
@@ -439,25 +437,15 @@
|
|||||||
"driver-not-found-others": "Player {driver} is online as:",
|
"driver-not-found-others": "Player {driver} is online as:",
|
||||||
"driver-not-found-return": "RETURN TO THE MAIN SITE",
|
"driver-not-found-return": "RETURN TO THE MAIN SITE",
|
||||||
"stock-copy": "COPY THE STOCK",
|
"stock-copy": "COPY THE STOCK",
|
||||||
"number-propositions": "NUMBER & WARNINGS SUGGESTIONS",
|
"number-propositions": "PROPOSE NUMBER",
|
||||||
"stock-clipboard-success": "Successfully copied the railway stock in a text form to your clipboard!",
|
"stock-clipboard-success": "Successfully copied the railway stock in a text form to your clipboard!",
|
||||||
"stock-clipboard-failure": "Oops! Something happened and the railway stock couldn't be copied to your clipboard! :/",
|
"stock-clipboard-failure": "Oops! Something happened and the railway stock couldn't be copied to your clipboard! :/",
|
||||||
"number-propositions-header": "Generate number examples for a train category:",
|
"number-propositions-header": "Generate number examples for selected category:",
|
||||||
"number-propositions-third-number": "Third digit:",
|
"number-propositions-third-number": "Third digit:",
|
||||||
"number-propositions-last-nums": "{count} last digits from the range of:",
|
"number-propositions-last-nums": "{count} last digits from the range of:",
|
||||||
"number-propositions-title": "Propositions:",
|
"number-propositions-title": "Propositions:",
|
||||||
"number-propositions-empty": "No propositions available for the chosen category! :/"
|
"number-propositions-empty": "No propositions available for the chosen category! :/"
|
||||||
},
|
},
|
||||||
"cargo-warnings": {
|
|
||||||
"title": "Additional cargo warnings:",
|
|
||||||
"pn-innofreight": "PN: Innofreight C45: exceeded gauge",
|
|
||||||
"twr-un1965": "TWR: UN1965 (LPG)",
|
|
||||||
"tn-un1965": "TN: unclean tanks after UN1965",
|
|
||||||
"tn-un1202": "TN: UN1202 (diesel fuel)",
|
|
||||||
"tn-un1202-empty": "TN: unclean tanks after UN1202",
|
|
||||||
"pn-military": "PN: military transport",
|
|
||||||
"pn-edk80": "PN: EDK80 railway crane"
|
|
||||||
},
|
|
||||||
"train-stats": {
|
"train-stats": {
|
||||||
"stats-button": "STATISTICS",
|
"stats-button": "STATISTICS",
|
||||||
"title": "ONLINE TRAINS STATS",
|
"title": "ONLINE TRAINS STATS",
|
||||||
@@ -570,7 +558,7 @@
|
|||||||
"no-users": "NO ACTIVE PLAYERS",
|
"no-users": "NO ACTIVE PLAYERS",
|
||||||
"no-spawns": "NO OPEN SPAWNS",
|
"no-spawns": "NO OPEN SPAWNS",
|
||||||
"no-scenery": "Oops! This scenery doesn't exist!",
|
"no-scenery": "Oops! This scenery doesn't exist!",
|
||||||
"return-btn": "BACK TO SCENERIES",
|
"return-btn": "BACK TO THE MAIN SITE",
|
||||||
"history-btn": "View the dispatcher history",
|
"history-btn": "View the dispatcher history",
|
||||||
"info-btn": "Return to the scenery view",
|
"info-btn": "Return to the scenery view",
|
||||||
"authors-title": "Scenery author | Scenery authors",
|
"authors-title": "Scenery author | Scenery authors",
|
||||||
@@ -580,12 +568,10 @@
|
|||||||
"additional-tools-title": "Additional tools",
|
"additional-tools-title": "Additional tools",
|
||||||
"one-way-routes": "Single track routes",
|
"one-way-routes": "Single track routes",
|
||||||
"two-way-routes": "Double track routes",
|
"two-way-routes": "Double track routes",
|
||||||
"routes-hidden": "Hidden internal routes",
|
|
||||||
"no-data": "No available data about this scenery",
|
"no-data": "No available data about this scenery",
|
||||||
"option-active-timetables": "Active timetables",
|
"option-active-timetables": "Active timetables",
|
||||||
"option-timetables-history": "Timetables history PL1",
|
"option-timetables-history": "Timetables history PL1",
|
||||||
"option-dispatchers-history": "Dispatchers history PL1",
|
"option-dispatchers-history": "Dispatchers history PL1",
|
||||||
"option-top-list": "Scenery records",
|
|
||||||
"btn-show-timetable-thumbnails": "Show rolling stock thumbnails",
|
"btn-show-timetable-thumbnails": "Show rolling stock thumbnails",
|
||||||
"btn-hide-timetable-thumbnails": "Hide rolling stock thumbnails",
|
"btn-hide-timetable-thumbnails": "Hide rolling stock thumbnails",
|
||||||
"timetable-includesScenery": "ALL TIMETABLES",
|
"timetable-includesScenery": "ALL TIMETABLES",
|
||||||
@@ -598,30 +584,14 @@
|
|||||||
"dispatcher-rate": "Rate:",
|
"dispatcher-rate": "Rate:",
|
||||||
"dispatcher-status-changes": "Status changes:",
|
"dispatcher-status-changes": "Status changes:",
|
||||||
"req-level": "all dispatcher levels | dispatcher level {lvl} required | dispatcher level {lvl} required",
|
"req-level": "all dispatcher levels | dispatcher level {lvl} required | dispatcher level {lvl} required",
|
||||||
"history-list-empty": "No saved scenery history!",
|
"history-list-empty": "No recorded scenery history!",
|
||||||
"forum-topic": "Scenery's forum topic",
|
"forum-topic": "Scenery's forum topic",
|
||||||
"gnr-link": "Train orders generator",
|
"gnr-link": "Train orders generator",
|
||||||
"pragotron-link": "Timetable pallet board",
|
"pragotron-link": "Timetable pallet board",
|
||||||
"tablice-link": "Timetable summary board <br> (by Thundo)",
|
"tablice-link": "Timetable summary board <br> (by Thundo)",
|
||||||
"bottom-info": "Show full history in the Journal tab",
|
"bottom-info": "Show full history in the Journal tab",
|
||||||
"btn-show-internal-routes": "Show internal routes",
|
"btn-show-internal-routes": "Show internal routes",
|
||||||
"btn-hide-internal-routes": "Hide internal routes",
|
"btn-hide-internal-routes": "Hide internal routes"
|
||||||
"top-list": {
|
|
||||||
"header": "RECORDS ON THE SCENERY (PL1)",
|
|
||||||
"mode-dutyCount": "DUTIES",
|
|
||||||
"mode-dispatcherRating": "RATING",
|
|
||||||
"mode-dutyDuration": "DUTY DURATION",
|
|
||||||
"scope-name": "GENERAL",
|
|
||||||
"scope-hash": "CURRENT HASH",
|
|
||||||
|
|
||||||
"place": "place",
|
|
||||||
"dispatcher-rating": "Rating: {n}",
|
|
||||||
"duty-count": "No duties | 1 duty | Duties: {n}",
|
|
||||||
"duration": "Duration:",
|
|
||||||
|
|
||||||
"no-data-general": "No best scores for this scenery on the PL1 server!",
|
|
||||||
"no-data-current-hash": "No best scores for the current scenery hash on the PL1 server!"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"availability": {
|
"availability": {
|
||||||
"title": "Availability",
|
"title": "Availability",
|
||||||
|
|||||||
+5
-35
@@ -42,8 +42,7 @@
|
|||||||
"action-paypal": "PRZELEJ PAYPALEM",
|
"action-paypal": "PRZELEJ PAYPALEM",
|
||||||
"action-buycoffee": "POSTAW KAWĘ!",
|
"action-buycoffee": "POSTAW KAWĘ!",
|
||||||
"dispatcher-message": "Dyżurny wspierający projekt Stacjownika!",
|
"dispatcher-message": "Dyżurny wspierający projekt Stacjownika!",
|
||||||
"driver-message": "Maszynista wspierający projekt Stacjownika!",
|
"driver-message": "Maszynista wspierający projekt Stacjownika!"
|
||||||
"creator-message": "Twórca projektu Stacjownik"
|
|
||||||
},
|
},
|
||||||
"warnings": {
|
"warnings": {
|
||||||
"TWR": "Pociąg z towarami niebezpiecznymi wysokiego ryzyka",
|
"TWR": "Pociąg z towarami niebezpiecznymi wysokiego ryzyka",
|
||||||
@@ -197,7 +196,6 @@
|
|||||||
"search-date-from": "Data (UTC+2 / CEST)",
|
"search-date-from": "Data (UTC+2 / CEST)",
|
||||||
"search-date-to": "Data (UTC+2 / CEST)",
|
"search-date-to": "Data (UTC+2 / CEST)",
|
||||||
"select-categoryCode": "Kategoria pociągu",
|
"select-categoryCode": "Kategoria pociągu",
|
||||||
"search-headUnit": "Pojazd trakcyjny (np. EP09, ET22-137)",
|
|
||||||
"sort-routeDistance": "kilometraż",
|
"sort-routeDistance": "kilometraż",
|
||||||
"sort-allStopsCount": "stacje",
|
"sort-allStopsCount": "stacje",
|
||||||
"sort-beginDate": "data",
|
"sort-beginDate": "data",
|
||||||
@@ -426,25 +424,15 @@
|
|||||||
"driver-not-found-others": "Gracz {driver} jest online jako:",
|
"driver-not-found-others": "Gracz {driver} jest online jako:",
|
||||||
"driver-not-found-return": "WRÓĆ NA STRONĘ GŁÓWNĄ",
|
"driver-not-found-return": "WRÓĆ NA STRONĘ GŁÓWNĄ",
|
||||||
"stock-copy": "SKOPIUJ SKŁAD",
|
"stock-copy": "SKOPIUJ SKŁAD",
|
||||||
"number-propositions": "PROPOZYCJE NUMERÓW I UWAG",
|
"number-propositions": "ZAPROPONUJ NUMER",
|
||||||
"stock-clipboard-success": "Pomyślnie skopiowano skład w postaci tekstowej do schowka!",
|
"stock-clipboard-success": "Pomyślnie skopiowano skład w postaci tekstowej do schowka!",
|
||||||
"stock-clipboard-failure": "Ups! Nie udało się skopiować składu do schowka! :/",
|
"stock-clipboard-failure": "Ups! Nie udało się skopiować składu do schowka! :/",
|
||||||
"number-propositions-header": "Wygeneruj propozycje numerów dla pociągu kategorii:",
|
"number-propositions-header": "Wygeneruj propozycje numerów dla kategorii pociągu:",
|
||||||
"number-propositions-third-number": "Trzecia cyfra:",
|
"number-propositions-third-number": "Trzecia cyfra:",
|
||||||
"number-propositions-last-nums": "{count} ostatnie cyfry z przedziału:",
|
"number-propositions-last-nums": "{count} ostatnie cyfry z przedziału:",
|
||||||
"number-propositions-title": "Propozycje:",
|
"number-propositions-title": "Propozycje:",
|
||||||
"number-propositions-empty": "Brak propozycji dla wybranej kategorii! :/"
|
"number-propositions-empty": "Brak propozycji dla wybranej kategorii! :/"
|
||||||
},
|
},
|
||||||
"cargo-warnings": {
|
|
||||||
"title": "Dodatkowe uwagi przewozowe:",
|
|
||||||
"pn-innofreight": "PN: Innofreight C45: przekroczona skrajnia",
|
|
||||||
"twr-un1965": "TWR: UN1965 (LPG)",
|
|
||||||
"tn-un1965": "TN: brudne cysterny po UN1965",
|
|
||||||
"tn-un1202": "TN: UN1202 (olej napędowy)",
|
|
||||||
"tn-un1202-empty": "TN: brudne cysterny po UN1202",
|
|
||||||
"pn-military": "PN: transport wojskowy",
|
|
||||||
"pn-edk80": "PN: żuraw kolejowy EDK80"
|
|
||||||
},
|
|
||||||
"train-stats": {
|
"train-stats": {
|
||||||
"stats-button": "STATYSTYKI",
|
"stats-button": "STATYSTYKI",
|
||||||
"title": "STATYSTYKI AKTYWNYCH POCIĄGÓW",
|
"title": "STATYSTYKI AKTYWNYCH POCIĄGÓW",
|
||||||
@@ -556,7 +544,7 @@
|
|||||||
"no-users": "BRAK AKTYWNYCH GRACZY",
|
"no-users": "BRAK AKTYWNYCH GRACZY",
|
||||||
"no-spawns": "BRAK OTWARTYCH SPAWNÓW",
|
"no-spawns": "BRAK OTWARTYCH SPAWNÓW",
|
||||||
"no-scenery": "Ups! Ta sceneria nie istnieje!",
|
"no-scenery": "Ups! Ta sceneria nie istnieje!",
|
||||||
"return-btn": "POWRÓT DO SCENERII",
|
"return-btn": "POWRÓT DO STRONY GŁÓWNEJ",
|
||||||
"history-btn": "Przejdź do widoku historii dyżurnych ruchu",
|
"history-btn": "Przejdź do widoku historii dyżurnych ruchu",
|
||||||
"info-btn": "Wróć do widoku scenerii",
|
"info-btn": "Wróć do widoku scenerii",
|
||||||
"authors-title": "Autor scenerii | Autorzy scenerii",
|
"authors-title": "Autor scenerii | Autorzy scenerii",
|
||||||
@@ -566,12 +554,10 @@
|
|||||||
"additional-tools-title": "Dodatkowe narzędzia",
|
"additional-tools-title": "Dodatkowe narzędzia",
|
||||||
"one-way-routes": "Szlaki jednotorowe",
|
"one-way-routes": "Szlaki jednotorowe",
|
||||||
"two-way-routes": "Szlaki dwutorowe",
|
"two-way-routes": "Szlaki dwutorowe",
|
||||||
"routes-hidden": "Ukryto szlaki wewnętrzne",
|
|
||||||
"no-data": "Brak informacji o tej scenerii",
|
"no-data": "Brak informacji o tej scenerii",
|
||||||
"option-active-timetables": "Aktywne rozkłady jazdy",
|
"option-active-timetables": "Aktywne rozkłady jazdy",
|
||||||
"option-timetables-history": "Historia rozkładów PL1",
|
"option-timetables-history": "Historia rozkładów PL1",
|
||||||
"option-dispatchers-history": "Historia dyżurów PL1",
|
"option-dispatchers-history": "Historia dyżurów PL1",
|
||||||
"option-top-list": "Rekordy scenerii",
|
|
||||||
"btn-show-timetable-thumbnails": "Pokazuj podglądy składów",
|
"btn-show-timetable-thumbnails": "Pokazuj podglądy składów",
|
||||||
"btn-hide-timetable-thumbnails": "Ukrywaj podglądy składów",
|
"btn-hide-timetable-thumbnails": "Ukrywaj podglądy składów",
|
||||||
"timetable-includesScenery": "WSZYSTKIE RJ",
|
"timetable-includesScenery": "WSZYSTKIE RJ",
|
||||||
@@ -591,23 +577,7 @@
|
|||||||
"tablice-link": "Tablica informacyjna zbiorcza <br> (autorstwa Thundo)",
|
"tablice-link": "Tablica informacyjna zbiorcza <br> (autorstwa Thundo)",
|
||||||
"bottom-info": "Pokaż pełną historię w zakładce Dziennika",
|
"bottom-info": "Pokaż pełną historię w zakładce Dziennika",
|
||||||
"btn-show-internal-routes": "Pokazuj szlaki wewnętrzne",
|
"btn-show-internal-routes": "Pokazuj szlaki wewnętrzne",
|
||||||
"btn-hide-internal-routes": "Ukrywaj szlaki wewnętrzne",
|
"btn-hide-internal-routes": "Ukrywaj szlaki wewnętrzne"
|
||||||
"top-list": {
|
|
||||||
"header": "REKORDY NA SCENERII (PL1)",
|
|
||||||
"mode-dutyCount": "DYŻURY",
|
|
||||||
"mode-dispatcherRating": "OCENA",
|
|
||||||
"mode-dutyDuration": "CZAS DYŻURU",
|
|
||||||
"scope-name": "OGÓLNIE",
|
|
||||||
"scope-hash": "OBECNY HASH",
|
|
||||||
|
|
||||||
"place": "miejsce",
|
|
||||||
"dispatcher-rating": "Ocena: {n}",
|
|
||||||
"duty-count": "Brak dyżurów | 1 dyżur | Dyżury: {n}",
|
|
||||||
"duration": "Czas:",
|
|
||||||
|
|
||||||
"no-data-general": "Brak zapisanych rekordów scenerii na serwerze PL1!",
|
|
||||||
"no-data-current-hash": "Brak zapisanych rekordów scenerii z obecnym hashem na serwerze PL1!"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"availability": {
|
"availability": {
|
||||||
"title": "Dostępność",
|
"title": "Dostępność",
|
||||||
|
|||||||
@@ -94,14 +94,14 @@ export const initFilters = {
|
|||||||
minTwoWayCatenary: 0,
|
minTwoWayCatenary: 0,
|
||||||
minTwoWayInt: 0,
|
minTwoWayInt: 0,
|
||||||
minTwoWayCatenaryInt: 0,
|
minTwoWayCatenaryInt: 0,
|
||||||
maxOneWay: 10,
|
maxOneWay: 5,
|
||||||
maxOneWayCatenary: 10,
|
maxOneWayCatenary: 5,
|
||||||
maxOneWayInt: 20,
|
maxOneWayInt: 5,
|
||||||
maxOneWayCatenaryInt: 20,
|
maxOneWayCatenaryInt: 5,
|
||||||
maxTwoWay: 10,
|
maxTwoWay: 5,
|
||||||
maxTwoWayCatenary: 10,
|
maxTwoWayCatenary: 5,
|
||||||
maxTwoWayInt: 20,
|
maxTwoWayInt: 5,
|
||||||
maxTwoWayCatenaryInt: 20,
|
maxTwoWayCatenaryInt: 5,
|
||||||
authors: '',
|
authors: '',
|
||||||
projects: '',
|
projects: '',
|
||||||
lines: ''
|
lines: ''
|
||||||
@@ -122,62 +122,62 @@ export const sliderGroups: SliderGroup[] = [
|
|||||||
|
|
||||||
export const sliderGroupsOptions: Record<SliderGroup, SliderOptions[]> = {
|
export const sliderGroupsOptions: Record<SliderGroup, SliderOptions[]> = {
|
||||||
vMax: [
|
vMax: [
|
||||||
{ id: 'minVmax', minRange: 0, maxRange: 200, step: 20 },
|
{ id: 'minVmax', minRange: 0, maxRange: 200, step: 10 },
|
||||||
{ id: 'maxVmax', minRange: 0, maxRange: 200, step: 20 }
|
{ id: 'maxVmax', minRange: 0, maxRange: 200, step: 10 }
|
||||||
],
|
],
|
||||||
level: [
|
level: [
|
||||||
{ id: 'minLevel', minRange: 0, maxRange: 20, step: 1 },
|
{ id: 'minLevel', minRange: 0, maxRange: 20, step: 1 },
|
||||||
{ id: 'maxLevel', minRange: 0, maxRange: 20, step: 1 }
|
{ id: 'maxLevel', minRange: 0, maxRange: 20, step: 1 }
|
||||||
],
|
],
|
||||||
routeOneWay: [
|
routeOneWay: [
|
||||||
{ id: 'minOneWay', minRange: 0, maxRange: 10, step: 1 },
|
{ id: 'minOneWay', minRange: 0, maxRange: 5, step: 1 },
|
||||||
{ id: 'maxOneWay', minRange: 0, maxRange: 10, step: 1 }
|
{ id: 'maxOneWay', minRange: 0, maxRange: 5, step: 1 }
|
||||||
],
|
],
|
||||||
routeOneWayCatenary: [
|
routeOneWayCatenary: [
|
||||||
{ id: 'minOneWayCatenary', minRange: 0, maxRange: 10, step: 1 },
|
{ id: 'minOneWayCatenary', minRange: 0, maxRange: 5, step: 1 },
|
||||||
{ id: 'maxOneWayCatenary', minRange: 0, maxRange: 10, step: 1 }
|
{ id: 'maxOneWayCatenary', minRange: 0, maxRange: 5, step: 1 }
|
||||||
],
|
],
|
||||||
routeOneWayInternal: [
|
routeOneWayInternal: [
|
||||||
{ id: 'minOneWayInt', minRange: 0, maxRange: 20, step: 1 },
|
{ id: 'minOneWayInt', minRange: 0, maxRange: 5, step: 1 },
|
||||||
{ id: 'maxOneWayInt', minRange: 0, maxRange: 20, step: 1 }
|
{ id: 'maxOneWayInt', minRange: 0, maxRange: 5, step: 1 }
|
||||||
],
|
],
|
||||||
routeOneWayInternalCatenary: [
|
routeOneWayInternalCatenary: [
|
||||||
{
|
{
|
||||||
id: 'minOneWayCatenaryInt',
|
id: 'minOneWayCatenaryInt',
|
||||||
minRange: 0,
|
minRange: 0,
|
||||||
maxRange: 20,
|
maxRange: 5,
|
||||||
step: 1
|
step: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'maxOneWayCatenaryInt',
|
id: 'maxOneWayCatenaryInt',
|
||||||
minRange: 0,
|
minRange: 0,
|
||||||
maxRange: 20,
|
maxRange: 5,
|
||||||
step: 1
|
step: 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
routeTwoWay: [
|
routeTwoWay: [
|
||||||
{ id: 'minTwoWay', minRange: 0, maxRange: 10, step: 1 },
|
{ id: 'minTwoWay', minRange: 0, maxRange: 5, step: 1 },
|
||||||
{ id: 'maxTwoWay', minRange: 0, maxRange: 10, step: 1 }
|
{ id: 'maxTwoWay', minRange: 0, maxRange: 5, step: 1 }
|
||||||
],
|
],
|
||||||
routeTwoWayCatenary: [
|
routeTwoWayCatenary: [
|
||||||
{ id: 'minTwoWayCatenary', minRange: 0, maxRange: 10, step: 1 },
|
{ id: 'minTwoWayCatenary', minRange: 0, maxRange: 5, step: 1 },
|
||||||
{ id: 'maxTwoWayCatenary', minRange: 0, maxRange: 10, step: 1 }
|
{ id: 'maxTwoWayCatenary', minRange: 0, maxRange: 5, step: 1 }
|
||||||
],
|
],
|
||||||
routeTwoWayInternal: [
|
routeTwoWayInternal: [
|
||||||
{ id: 'minTwoWayInt', minRange: 0, maxRange: 20, step: 1 },
|
{ id: 'minTwoWayInt', minRange: 0, maxRange: 5, step: 1 },
|
||||||
{ id: 'maxTwoWayInt', minRange: 0, maxRange: 20, step: 1 }
|
{ id: 'maxTwoWayInt', minRange: 0, maxRange: 5, step: 1 }
|
||||||
],
|
],
|
||||||
routeTwoWayInternalCatenary: [
|
routeTwoWayInternalCatenary: [
|
||||||
{
|
{
|
||||||
id: 'minTwoWayCatenaryInt',
|
id: 'minTwoWayCatenaryInt',
|
||||||
minRange: 0,
|
minRange: 0,
|
||||||
maxRange: 20,
|
maxRange: 5,
|
||||||
step: 1
|
step: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'maxTwoWayCatenaryInt',
|
id: 'maxTwoWayCatenaryInt',
|
||||||
minRange: 0,
|
minRange: 0,
|
||||||
maxRange: 20,
|
maxRange: 5,
|
||||||
step: 1
|
step: 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
+32
-24
@@ -2,20 +2,7 @@ import { defineStore } from 'pinia';
|
|||||||
import { API } from '../typings/api';
|
import { API } from '../typings/api';
|
||||||
import { Status } from '../typings/common';
|
import { Status } from '../typings/common';
|
||||||
import { StationJSONData } from './typings';
|
import { StationJSONData } from './typings';
|
||||||
import { HttpClient } from '../http';
|
import axios, { AxiosInstance } from 'axios';
|
||||||
|
|
||||||
let baseURL = 'https://stacjownik.spythere.eu';
|
|
||||||
|
|
||||||
switch (import.meta.env.VITE_API_MODE) {
|
|
||||||
case 'development':
|
|
||||||
baseURL = 'http://localhost:3001';
|
|
||||||
break;
|
|
||||||
case 'mocking':
|
|
||||||
baseURL = 'http://localhost:3123';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useApiStore = defineStore('apiStore', {
|
export const useApiStore = defineStore('apiStore', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
@@ -38,13 +25,30 @@ export const useApiStore = defineStore('apiStore', {
|
|||||||
nextUpdateTime: 0,
|
nextUpdateTime: 0,
|
||||||
nextDataCheckTime: 0,
|
nextDataCheckTime: 0,
|
||||||
|
|
||||||
client: new HttpClient(baseURL),
|
client: undefined as AxiosInstance | undefined,
|
||||||
|
|
||||||
activeDataScheduler: undefined as number | undefined
|
activeDataScheduler: undefined as number | undefined
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
async setupAPIData() {
|
async setupAPIData() {
|
||||||
|
let baseURL = 'https://stacjownik.spythere.eu';
|
||||||
|
|
||||||
|
switch (import.meta.env.VITE_API_MODE) {
|
||||||
|
case 'development':
|
||||||
|
baseURL = 'http://localhost:3001';
|
||||||
|
break;
|
||||||
|
case 'mocking':
|
||||||
|
baseURL = 'http://localhost:3123';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client = axios.create({
|
||||||
|
baseURL
|
||||||
|
});
|
||||||
|
|
||||||
this.connectToAPI();
|
this.connectToAPI();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -78,9 +82,9 @@ export const useApiStore = defineStore('apiStore', {
|
|||||||
if (!this.activeData) this.dataStatuses.connection = Status.Data.Loading;
|
if (!this.activeData) this.dataStatuses.connection = Status.Data.Loading;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.client.get<API.ActiveData.Response>('api/getActiveData');
|
const response = await this.client!.get<API.ActiveData.Response>('api/getActiveData');
|
||||||
|
|
||||||
this.activeData = response;
|
this.activeData = response.data;
|
||||||
this.dataStatuses.connection = Status.Data.Loaded;
|
this.dataStatuses.connection = Status.Data.Loaded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.dataStatuses.connection = Status.Data.Error;
|
this.dataStatuses.connection = Status.Data.Error;
|
||||||
@@ -90,9 +94,9 @@ export const useApiStore = defineStore('apiStore', {
|
|||||||
|
|
||||||
async fetchDonatorsData() {
|
async fetchDonatorsData() {
|
||||||
try {
|
try {
|
||||||
const response = await this.client.get<API.Donators.Response>('api/getDonators');
|
const response = await this.client!.get<API.Donators.Response>('api/getDonators');
|
||||||
|
|
||||||
this.donatorsData = response;
|
this.donatorsData = response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Ups! Wystąpił błąd podczas pobierania informacji o donatorach:', error);
|
console.error('Ups! Wystąpił błąd podczas pobierania informacji o donatorach:', error);
|
||||||
}
|
}
|
||||||
@@ -100,7 +104,9 @@ export const useApiStore = defineStore('apiStore', {
|
|||||||
|
|
||||||
async fetchStationsGeneralInfo() {
|
async fetchStationsGeneralInfo() {
|
||||||
try {
|
try {
|
||||||
const sceneryData = await this.client.get<StationJSONData[]>(`api/getSceneries`);
|
const sceneryData: StationJSONData[] = (
|
||||||
|
await this.client!.get<StationJSONData[]>(`api/getSceneries`)
|
||||||
|
).data;
|
||||||
|
|
||||||
this.dataStatuses.sceneries = Status.Data.Loaded;
|
this.dataStatuses.sceneries = Status.Data.Loaded;
|
||||||
this.sceneryData = sceneryData;
|
this.sceneryData = sceneryData;
|
||||||
@@ -112,10 +118,10 @@ export const useApiStore = defineStore('apiStore', {
|
|||||||
|
|
||||||
async fetchVehiclesInfo() {
|
async fetchVehiclesInfo() {
|
||||||
try {
|
try {
|
||||||
const response = await this.client.get<API.VehiclesData.Response>('api/getVehiclesData');
|
const response = await this.client!.get<API.VehiclesData.Response>('api/getVehiclesData');
|
||||||
|
|
||||||
this.vehiclesData = response;
|
this.vehiclesData = response.data;
|
||||||
this.dataStatuses.vehicles = response ? Status.Data.Loaded : Status.Data.Warning;
|
this.dataStatuses.vehicles = response.data ? Status.Data.Loaded : Status.Data.Warning;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.dataStatuses.vehicles = Status.Data.Error;
|
this.dataStatuses.vehicles = Status.Data.Error;
|
||||||
console.error('Ups! Wystąpił błąd podczas pobierania informacji o pojazdach:', error);
|
console.error('Ups! Wystąpił błąd podczas pobierania informacji o pojazdach:', error);
|
||||||
@@ -124,7 +130,9 @@ export const useApiStore = defineStore('apiStore', {
|
|||||||
|
|
||||||
async fetchDailyStats() {
|
async fetchDailyStats() {
|
||||||
try {
|
try {
|
||||||
const res = await this.client.get<API.DailyStats.Response>('api/getDailyStats');
|
const res: API.DailyStats.Response = await (
|
||||||
|
await this.client!.get('api/getDailyStats')
|
||||||
|
).data;
|
||||||
|
|
||||||
this.dailyStatsData = res;
|
this.dailyStatsData = res;
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ export const tooltipKeys = [
|
|||||||
'SpawnsTooltip',
|
'SpawnsTooltip',
|
||||||
'UsersTooltip',
|
'UsersTooltip',
|
||||||
'HtmlTooltip',
|
'HtmlTooltip',
|
||||||
'TrainInfoTooltip',
|
'TrainInfoTooltip'
|
||||||
'CreatorTooltip'
|
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type TooltipType = (typeof tooltipKeys)[number];
|
export type TooltipType = (typeof tooltipKeys)[number];
|
||||||
|
|||||||
@@ -85,6 +85,7 @@
|
|||||||
padding: 0.1em 0.3em;
|
padding: 0.1em 0.3em;
|
||||||
border-radius: 0.2em;
|
border-radius: 0.2em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
&.twr {
|
&.twr {
|
||||||
background-color: var(--clr-twr);
|
background-color: var(--clr-twr);
|
||||||
@@ -150,4 +151,4 @@
|
|||||||
&.active {
|
&.active {
|
||||||
background-color: lightblue;
|
background-color: lightblue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,14 +78,14 @@ h1.option-title {
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 1em;
|
margin-top: 0.5em;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include responsive.smallScreen {
|
@include responsive.smallScreen{
|
||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
.dropdown_wrapper {
|
.dropdown_wrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: calc(100% + 0.5em);
|
||||||
|
|
||||||
background-color: var(--clr-bg3);
|
background-color: var(--clr-bg3);
|
||||||
box-shadow: 0 0 5px 1px var(--clr-primary);
|
box-shadow: 0 0 5px 1px var(--clr-primary);
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 550px;
|
max-width: 550px;
|
||||||
|
|
||||||
|
max-height: 750px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
|
|||||||
@@ -217,19 +217,6 @@ ul {
|
|||||||
text-shadow: #f050ff 0 0 10px;
|
text-shadow: #f050ff 0 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--creator {
|
|
||||||
color: var(--clr-primary);
|
|
||||||
color: transparent;
|
|
||||||
|
|
||||||
background: var(--clr-primary);
|
|
||||||
background: linear-gradient(90deg, gold 30%, #ffffff 70%);
|
|
||||||
background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
|
|
||||||
text-shadow: gold 0 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--discord {
|
&--discord {
|
||||||
color: var(--clr-donator);
|
color: var(--clr-donator);
|
||||||
color: transparent;
|
color: transparent;
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|
||||||
padding: 1em 0;
|
padding: 1em 0;
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.journal_refreshed-date {
|
.journal_refreshed-date {
|
||||||
@@ -57,6 +57,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn--load-data {
|
.btn--load-data {
|
||||||
@@ -67,7 +68,7 @@
|
|||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include responsive.smallScreen {
|
@include responsive.smallScreen{
|
||||||
.journal_top-bar {
|
.journal_top-bar {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
|
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
|
margin-right: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-input {
|
&-input {
|
||||||
@@ -60,4 +61,4 @@
|
|||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
padding-right: 0.5em;
|
padding-right: 0.5em;
|
||||||
}
|
}
|
||||||
+1
-3
@@ -253,10 +253,8 @@ export namespace API {
|
|||||||
pn?: number;
|
pn?: number;
|
||||||
tn?: number;
|
tn?: number;
|
||||||
|
|
||||||
headUnitName?: string;
|
|
||||||
headUnitType?: string;
|
|
||||||
|
|
||||||
returnType?: 'all' | 'short' | 'detailed';
|
returnType?: 'all' | 'short' | 'detailed';
|
||||||
|
|
||||||
sortBy?: Journal.TimetableSorter['id'];
|
sortBy?: Journal.TimetableSorter['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
export function isCreator(name: string) {
|
|
||||||
return /(spythere|kowbojyt)/.test(name.toLowerCase());
|
|
||||||
}
|
|
||||||
@@ -217,10 +217,9 @@ export default defineComponent({
|
|||||||
this.scrollDataLoaded = false;
|
this.scrollDataLoaded = false;
|
||||||
this.currentQueryParams['countFrom'] = this.historyList.length;
|
this.currentQueryParams['countFrom'] = this.historyList.length;
|
||||||
|
|
||||||
const responseData: API.DispatcherHistory.Response = await await this.apiStore.client.get(
|
const responseData: API.DispatcherHistory.Response = await (
|
||||||
`api/getDispatchers`,
|
await this.apiStore.client!.get(`api/getDispatchers`, { params: this.currentQueryParams })
|
||||||
this.currentQueryParams
|
).data;
|
||||||
);
|
|
||||||
|
|
||||||
if (!responseData) return;
|
if (!responseData) return;
|
||||||
|
|
||||||
@@ -277,10 +276,9 @@ export default defineComponent({
|
|||||||
this.currentQueryParams = queryParams;
|
this.currentQueryParams = queryParams;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const responseData: API.DispatcherHistory.Response = await this.apiStore.client.get(
|
const responseData: API.DispatcherHistory.Response = await (
|
||||||
`api/getDispatchers`,
|
await this.apiStore.client!.get(`api/getDispatchers`, { params: this.currentQueryParams })
|
||||||
this.currentQueryParams
|
).data;
|
||||||
);
|
|
||||||
|
|
||||||
if (!responseData) {
|
if (!responseData) {
|
||||||
this.dataStatus = Status.Data.Error;
|
this.dataStatus = Status.Data.Error;
|
||||||
|
|||||||
@@ -173,9 +173,8 @@ export default defineComponent({
|
|||||||
'search-issuedFrom': '',
|
'search-issuedFrom': '',
|
||||||
'search-via': '',
|
'search-via': '',
|
||||||
'search-terminatingAt': '',
|
'search-terminatingAt': '',
|
||||||
'search-headUnit': '',
|
'select-categoryCode': '',
|
||||||
'search-date-from': '',
|
'search-date-from': ''
|
||||||
'select-categoryCode': ''
|
|
||||||
} as Journal.TimetableSearchType);
|
} as Journal.TimetableSearchType);
|
||||||
|
|
||||||
const countFromIndex = ref(0);
|
const countFromIndex = ref(0);
|
||||||
@@ -278,10 +277,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
this.currentQueryParams['countFrom'] = this.timetableHistory.length;
|
this.currentQueryParams['countFrom'] = this.timetableHistory.length;
|
||||||
|
|
||||||
const responseData: API.TimetableHistory.Response = await this.apiStore.client.get(
|
const responseData: API.TimetableHistory.Response = await (
|
||||||
'api/getTimetables',
|
await this.apiStore.client!.get('api/getTimetables', {
|
||||||
this.currentQueryParams
|
params: this.currentQueryParams
|
||||||
);
|
})
|
||||||
|
).data;
|
||||||
|
|
||||||
if (!responseData) return;
|
if (!responseData) return;
|
||||||
|
|
||||||
@@ -297,8 +297,6 @@ export default defineComponent({
|
|||||||
async fetchHistoryData() {
|
async fetchHistoryData() {
|
||||||
this.extraInfoIndexes.length = 0;
|
this.extraInfoIndexes.length = 0;
|
||||||
|
|
||||||
const queryParams: API.TimetableHistory.QueryParams = {};
|
|
||||||
|
|
||||||
const driverName = this.searchersValues['search-driver'].trim() || undefined;
|
const driverName = this.searchersValues['search-driver'].trim() || undefined;
|
||||||
const trainNo = this.searchersValues['search-train'].trim() || undefined;
|
const trainNo = this.searchersValues['search-train'].trim() || undefined;
|
||||||
const authorName = this.searchersValues['search-dispatcher'].trim() || undefined;
|
const authorName = this.searchersValues['search-dispatcher'].trim() || undefined;
|
||||||
@@ -308,7 +306,6 @@ export default defineComponent({
|
|||||||
const via = this.searchersValues['search-via'].trim() || undefined;
|
const via = this.searchersValues['search-via'].trim() || undefined;
|
||||||
const terminatingAt = this.searchersValues['search-terminatingAt'].trim() || undefined;
|
const terminatingAt = this.searchersValues['search-terminatingAt'].trim() || undefined;
|
||||||
const categoryCode = this.searchersValues['select-categoryCode'].trim() || undefined;
|
const categoryCode = this.searchersValues['select-categoryCode'].trim() || undefined;
|
||||||
const headUnit = this.searchersValues['search-headUnit'].trim() || undefined;
|
|
||||||
|
|
||||||
let dateFromISO: string | undefined = undefined;
|
let dateFromISO: string | undefined = undefined;
|
||||||
let dateToISO: string | undefined = undefined;
|
let dateToISO: string | undefined = undefined;
|
||||||
@@ -324,6 +321,8 @@ export default defineComponent({
|
|||||||
dateToISO = dateTo.toISOString();
|
dateToISO = dateTo.toISOString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const queryParams: API.TimetableHistory.QueryParams = {};
|
||||||
|
|
||||||
this.filterList
|
this.filterList
|
||||||
.filter((f) => f.isActive)
|
.filter((f) => f.isActive)
|
||||||
.forEach((f) => {
|
.forEach((f) => {
|
||||||
@@ -395,27 +394,17 @@ export default defineComponent({
|
|||||||
queryParams['sortBy'] =
|
queryParams['sortBy'] =
|
||||||
this.sorterActive.id != 'timetableId' ? this.sorterActive.id : undefined;
|
this.sorterActive.id != 'timetableId' ? this.sorterActive.id : undefined;
|
||||||
|
|
||||||
// Head unit params
|
|
||||||
if (headUnit) {
|
|
||||||
const [headUnitName, headUnitNumber] = headUnit.split('-');
|
|
||||||
|
|
||||||
if (headUnitNumber && !isNaN(Number(headUnitNumber))) {
|
|
||||||
queryParams['headUnitName'] = `${headUnitName}-${headUnitNumber}`;
|
|
||||||
} else {
|
|
||||||
queryParams['headUnitType'] = headUnitName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (JSON.stringify(this.currentQueryParams) != JSON.stringify(queryParams))
|
if (JSON.stringify(this.currentQueryParams) != JSON.stringify(queryParams))
|
||||||
this.dataStatus = Status.Data.Loading;
|
this.dataStatus = Status.Data.Loading;
|
||||||
|
|
||||||
this.currentQueryParams = queryParams;
|
this.currentQueryParams = queryParams;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const responseData: API.TimetableHistory.ResponseShort = await this.apiStore.client.get(
|
const responseData: API.TimetableHistory.ResponseShort = await (
|
||||||
'api/getTimetables',
|
await this.apiStore.client!.get('api/getTimetables', {
|
||||||
this.currentQueryParams
|
params: this.currentQueryParams
|
||||||
);
|
})
|
||||||
|
).data;
|
||||||
|
|
||||||
if (!responseData) {
|
if (!responseData) {
|
||||||
this.dataStatus = Status.Data.Error;
|
this.dataStatus = Status.Data.Error;
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import Loading from '../components/Global/Loading.vue';
|
|||||||
import ProfileSummary from '../components/PlayerProfileView/ProfileSummary.vue';
|
import ProfileSummary from '../components/PlayerProfileView/ProfileSummary.vue';
|
||||||
import ProfileRecentStats from '../components/PlayerProfileView/ProfileRecentStats.vue';
|
import ProfileRecentStats from '../components/PlayerProfileView/ProfileRecentStats.vue';
|
||||||
import ProfileHistoryList from '../components/PlayerProfileView/ProfileHistoryList.vue';
|
import ProfileHistoryList from '../components/PlayerProfileView/ProfileHistoryList.vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -70,28 +71,29 @@ onDeactivated(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function fetchPlayerInfo(playerId: number) {
|
async function fetchPlayerInfo(playerId: number) {
|
||||||
return apiStore.client.get<API.PlayerInfo.Data>('api/getPlayerInfo', {
|
return apiStore.client!.get<API.PlayerInfo.Data>('api/getPlayerInfo', {
|
||||||
playerId
|
params: {
|
||||||
|
playerId
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchPlayerJournal(playerId: number) {
|
async function fetchPlayerJournal(playerId: number) {
|
||||||
return apiStore.client.get<API.PlayerJournal.Data>('api/getPlayerJournal', {
|
return apiStore.client!.get<API.PlayerJournal.Data>('api/getPlayerJournal', {
|
||||||
playerId,
|
params: {
|
||||||
dateScope: '30d'
|
playerId,
|
||||||
|
dateScope: '30d'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchPlayerTd2Info(playerName: string): Promise<Td2API.UsersInfoByName.Response> {
|
async function fetchPlayerTd2Info(playerName: string) {
|
||||||
const response = await fetch(
|
return axios.get<Td2API.UsersInfoByName.Response>('https://api.td2.info.pl', {
|
||||||
`https://api.td2.info.pl?method=getUsersInfoByName&name=${playerName}`
|
params: {
|
||||||
);
|
method: 'getUsersInfoByName',
|
||||||
|
name: playerName
|
||||||
if (!response.ok) {
|
}
|
||||||
throw new Error('fetchPlayerTd2Info: could not fetch data');
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return response.json();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchPlayerData() {
|
async function fetchPlayerData() {
|
||||||
@@ -114,21 +116,23 @@ async function fetchPlayerData() {
|
|||||||
const playerInfoResp = await fetchPlayerInfo(playerId.value);
|
const playerInfoResp = await fetchPlayerInfo(playerId.value);
|
||||||
|
|
||||||
playerName.value =
|
playerName.value =
|
||||||
playerInfoResp.driverStats.driverName || playerInfoResp.dispatcherStats.dispatcherName || '';
|
playerInfoResp.data.driverStats.driverName ||
|
||||||
|
playerInfoResp.data.dispatcherStats.dispatcherName ||
|
||||||
|
'';
|
||||||
|
|
||||||
if (!playerName.value) {
|
if (!playerName.value) {
|
||||||
router.push('/');
|
router.push('/');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playerInfo.value = playerName.value ? playerInfoResp : undefined;
|
playerInfo.value = playerName.value ? playerInfoResp.data : undefined;
|
||||||
playerInfoStatus.value = Status.Data.Loaded;
|
playerInfoStatus.value = Status.Data.Loaded;
|
||||||
|
|
||||||
if (playerName.value) {
|
if (playerName.value) {
|
||||||
const playerTD2InfoResp = await fetchPlayerTd2Info(playerName.value);
|
const playerTD2InfoResp = await fetchPlayerTd2Info(playerName.value);
|
||||||
|
|
||||||
if (playerTD2InfoResp.success && playerTD2InfoResp.message.length == 1) {
|
if (playerTD2InfoResp.data.success && playerTD2InfoResp.data.message.length == 1) {
|
||||||
playerTD2Info.value = playerTD2InfoResp.message[0];
|
playerTD2Info.value = playerTD2InfoResp.data.message[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -140,7 +144,7 @@ async function fetchPlayerData() {
|
|||||||
try {
|
try {
|
||||||
const playerJournalResp = await fetchPlayerJournal(playerId.value);
|
const playerJournalResp = await fetchPlayerJournal(playerId.value);
|
||||||
|
|
||||||
playerJournal.value = playerJournalResp;
|
playerJournal.value = playerJournalResp.data;
|
||||||
playerJournalStatus.value = Status.Data.Loaded;
|
playerJournalStatus.value = Status.Data.Loaded;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
playerJournal.value = undefined;
|
playerJournal.value = undefined;
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ import SceneryDispatchersHistory from '../components/SceneryView/SceneryDispatch
|
|||||||
|
|
||||||
import { useApiStore } from '../store/apiStore';
|
import { useApiStore } from '../store/apiStore';
|
||||||
import { Status } from '../typings/common';
|
import { Status } from '../typings/common';
|
||||||
import SceneryTopList from '../components/SceneryView/SceneryTopList.vue';
|
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -90,10 +89,6 @@ const viewModes = [
|
|||||||
{
|
{
|
||||||
id: 'scenery.option-dispatchers-history',
|
id: 'scenery.option-dispatchers-history',
|
||||||
component: SceneryDispatchersHistory
|
component: SceneryDispatchersHistory
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'scenery.option-top-list',
|
|
||||||
component: SceneryTopList
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -189,7 +184,7 @@ function setViewMode(componentName: string) {
|
|||||||
|
|
||||||
background-color: #181818;
|
background-color: #181818;
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
padding: 1em;
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scenery-left {
|
.scenery-left {
|
||||||
|
|||||||
@@ -116,10 +116,13 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@use '../styles/responsive';
|
@use '../styles/responsive';
|
||||||
|
|
||||||
|
.trains-view {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.trains_wrapper {
|
.trains_wrapper {
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
max-width: var(--max-container-width);
|
max-width: var(--max-container-width);
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.trains_topbar {
|
.trains_topbar {
|
||||||
@@ -127,6 +130,7 @@ export default defineComponent({
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
|
||||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
|
||||||
"exclude": ["src/**/__tests__/*"],
|
|
||||||
"compilerOptions": {
|
|
||||||
"noUncheckedIndexedAccess": false,
|
|
||||||
"verbatimModuleSyntax": null,
|
|
||||||
|
|
||||||
"paths": {
|
|
||||||
"@/*": ["./src/*"]
|
|
||||||
},
|
|
||||||
|
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+18
-5
@@ -1,11 +1,24 @@
|
|||||||
{
|
{
|
||||||
"files": [],
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"sourceMap": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
|
||||||
|
"lib": ["ESNext", "DOM"],
|
||||||
|
"types": ["vite/client", "vite-plugin-pwa/client"],
|
||||||
|
"skipLibCheck": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "./tsconfig.node.json"
|
"path": "./tsconfig.node.json"
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.app.json"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-9
@@ -1,12 +1,9 @@
|
|||||||
// TSConfig for modules that run in Node.js environment via either transpilation or type-stripping.
|
|
||||||
{
|
{
|
||||||
"extends": "@tsconfig/node24/tsconfig.json",
|
|
||||||
"include": ["vite.config.*", "eslint.config.*"],
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "preserve",
|
"composite": true,
|
||||||
"moduleResolution": "bundler",
|
"module": "nodenext",
|
||||||
"types": ["node", "vite/client", "vite-plugin-pwa/client"],
|
"moduleResolution": "nodenext",
|
||||||
"noEmit": true,
|
"allowSyntheticDefaultImports": true
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
|
},
|
||||||
}
|
"include": ["vite.config.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-7
@@ -1,7 +1,7 @@
|
|||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import vue from '@vitejs/plugin-vue';
|
import vue from '@vitejs/plugin-vue';
|
||||||
import { VitePWA } from 'vite-plugin-pwa';
|
import { VitePWA } from 'vite-plugin-pwa';
|
||||||
import { fileURLToPath } from 'node:url';
|
import path from 'path';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
server: { port: 5123, open: false },
|
server: { port: 5123, open: false },
|
||||||
@@ -14,7 +14,7 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
'@': path.resolve(__dirname, 'src')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
@@ -29,13 +29,10 @@ export default defineConfig({
|
|||||||
{
|
{
|
||||||
urlPattern:
|
urlPattern:
|
||||||
/^https:\/\/stacjownik.spythere.eu\/api\/(getVehiclesData|getDonators|getSceneries)/i,
|
/^https:\/\/stacjownik.spythere.eu\/api\/(getVehiclesData|getDonators|getSceneries)/i,
|
||||||
handler: 'StaleWhileRevalidate',
|
handler: 'CacheFirst',
|
||||||
options: {
|
options: {
|
||||||
cacheName: 'stacjownik-api-cache',
|
cacheName: 'stacjownik-api-cache',
|
||||||
cacheableResponse: { statuses: [0, 200] },
|
cacheableResponse: { statuses: [0, 200] }
|
||||||
expiration: {
|
|
||||||
maxAgeSeconds: 3600
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user