mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 05:18:11 +00:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5ffc63a815 | |||
| 87f7ff58e8 | |||
| 8b6944a8e5 | |||
| cfeeb8fddd | |||
| 89f7fd3c53 | |||
| 86259988c9 | |||
| 7b5ef18ad6 | |||
| d784042691 | |||
| d0e482aa4f | |||
| 3bf1db52b4 | |||
| 8e713a5c6e | |||
| af6eb35b67 | |||
| 1e6ab1c2d1 | |||
| fd4849bd5e | |||
| bc0f4c5d3f | |||
| 8909a0cd40 | |||
| a2602aeefe | |||
| 37ad9b2787 | |||
| 0b4ad679b3 | |||
| dd0d7897cf | |||
| 1453dbda01 | |||
| 4af856b833 | |||
| 182b46a377 | |||
| bb5fc395d2 | |||
| a91a00f88a | |||
| c8d481a952 |
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "stacjownik",
|
||||
"version": "1.30.2",
|
||||
"version": "1.30.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
<template>
|
||||
<section class="info-header">
|
||||
<button
|
||||
class="btn btn-return"
|
||||
:title="$t('scenery.return-btn')"
|
||||
@click="onReturnButtonClick"
|
||||
>
|
||||
<img src="/images/icon-back.svg" alt="return button" />
|
||||
</button>
|
||||
|
||||
<a class="scenery-name" :href="station?.generalInfo?.url" target="_blank">
|
||||
{{ stationName.replace(/_/g, ' ') }}
|
||||
</a>
|
||||
@@ -12,39 +20,64 @@
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, PropType, ref } from 'vue';
|
||||
import { ActiveScenery, Station } from '../../typings/common';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
station: {
|
||||
type: Object as PropType<Station>
|
||||
},
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
stationName: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
const prevPath = ref('/');
|
||||
|
||||
onlineScenery: {
|
||||
type: Object as PropType<ActiveScenery>
|
||||
}
|
||||
onMounted(() => {
|
||||
prevPath.value = (route.meta['prevPath'] as string) ?? '/';
|
||||
});
|
||||
|
||||
defineProps({
|
||||
station: {
|
||||
type: Object as PropType<Station>
|
||||
},
|
||||
|
||||
stationName: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
onlineScenery: {
|
||||
type: Object as PropType<ActiveScenery>
|
||||
}
|
||||
});
|
||||
|
||||
function onReturnButtonClick() {
|
||||
router.push(prevPath.value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use '../../styles/responsive';
|
||||
@use 'sass:color';
|
||||
|
||||
.info-header {
|
||||
margin-top: 1em;
|
||||
.btn-return {
|
||||
$bgColor: #2b2b2b;
|
||||
background-color: $bgColor;
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
img {
|
||||
width: 2em;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: color.adjust($color: $bgColor, $lightness: 15%);
|
||||
}
|
||||
}
|
||||
|
||||
.scenery-name {
|
||||
font-weight: bold;
|
||||
font-size: 3em;
|
||||
|
||||
text-align: center;
|
||||
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
@@ -58,4 +91,10 @@ export default defineComponent({
|
||||
color: #aaa;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
@include responsive.smallScreen {
|
||||
.scenery-name {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
{{ route.routeName }}
|
||||
</span>
|
||||
<span v-if="route.routeSpeed" class="speed">{{ route.routeSpeed }}</span>
|
||||
<span v-if="route.routeSpeedExit" class="speed">| {{ route.routeSpeedExit }}</span>
|
||||
<span v-if="route.routeLength" class="length">
|
||||
{{ (route.routeLength / 1000).toFixed(1) + 'km' }}
|
||||
</span>
|
||||
|
||||
@@ -18,7 +18,11 @@
|
||||
:key="train.id"
|
||||
:data-status="status"
|
||||
>
|
||||
<router-link :to="train.driverRouteLocation">
|
||||
<router-link
|
||||
:to="train.driverRouteLocation"
|
||||
data-tooltip-type="TrainInfoTooltip"
|
||||
:data-tooltip-content="train.id"
|
||||
>
|
||||
<span class="user_train"> {{ train.trainNo }}</span>
|
||||
<span class="user_name">
|
||||
{{ train.driverName }}
|
||||
|
||||
@@ -93,19 +93,59 @@
|
||||
<span class="timetable-general">
|
||||
<span class="general-info">
|
||||
<div class="info-train">
|
||||
<b
|
||||
<!-- Cargo warnings & details badges -->
|
||||
<span
|
||||
class="train-badge twr"
|
||||
v-if="row.train.timetableData!.twr"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="getCategoryExplanation(row.train.timetableData!.category)"
|
||||
class="text--primary tooltip-help"
|
||||
:data-tooltip-content="$t('warnings.TWR')"
|
||||
>
|
||||
{{ row.train.timetableData!.category }}
|
||||
</b>
|
||||
<span> </span>
|
||||
<b>{{ row.train.trainNo }}</b>
|
||||
<span> • </span>
|
||||
<span>{{ row.train.driverName }}</span>
|
||||
TWR
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="train-badge tn"
|
||||
v-if="row.train.timetableData!.hasDangerousCargo"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="$t('warnings.TN')"
|
||||
>
|
||||
TN
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="train-badge pn"
|
||||
v-if="row.train.timetableData!.hasExtraDeliveries"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="$t('warnings.PN')"
|
||||
>
|
||||
PN
|
||||
</span>
|
||||
|
||||
<!-- Train info -->
|
||||
<span
|
||||
data-tooltip-type="TrainInfoTooltip"
|
||||
:data-tooltip-content="row.train.id"
|
||||
class="tooltip-help"
|
||||
>
|
||||
<b class="text--primary">
|
||||
{{ row.train.timetableData!.category }}
|
||||
</b>
|
||||
|
||||
<b> {{ row.train.trainNo }}</b>
|
||||
•
|
||||
{{ row.train.driverName }}
|
||||
|
||||
<i
|
||||
class="fa-solid fa-user-slash"
|
||||
style="color: salmon"
|
||||
v-if="!row.train.online && row.train.lastSeen <= Date.now() - 60000"
|
||||
></i>
|
||||
</span>
|
||||
|
||||
<!-- Train stop comments -->
|
||||
<span
|
||||
v-if="row.checkpointStop.comments"
|
||||
class="stop-comments-icon"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="row.checkpointStop.comments"
|
||||
>
|
||||
@@ -205,7 +245,7 @@ import { useMainStore } from '../../store/mainStore';
|
||||
import { useApiStore } from '../../store/apiStore';
|
||||
import ScheduledTrainStatus from './ScheduledTrainStatus.vue';
|
||||
import { SceneryTimetableRow } from './typings';
|
||||
import { ActiveScenery, Station } from '../../typings/common';
|
||||
import { ActiveScenery, Station, TooltipTrainInfo, Train } from '../../typings/common';
|
||||
import { getTrainStopStatus, stopStatusPriority } from './utils';
|
||||
|
||||
export default defineComponent({
|
||||
@@ -352,6 +392,7 @@ export default defineComponent({
|
||||
<style lang="scss" scoped>
|
||||
@use '../../styles/responsive';
|
||||
@use '../../styles/animations';
|
||||
@use '../../styles/badge';
|
||||
|
||||
.scenery-timetable {
|
||||
height: 100%;
|
||||
@@ -468,21 +509,32 @@ export default defineComponent({
|
||||
|
||||
.general-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.info-number {
|
||||
color: var(--clr-primary);
|
||||
}
|
||||
.info-train {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25em;
|
||||
}
|
||||
|
||||
.info-route {
|
||||
width: 100%;
|
||||
}
|
||||
.info-train > .train-badge {
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 0.9em;
|
||||
vertical-align: middle;
|
||||
margin: 0 0.25em;
|
||||
}
|
||||
.info-number {
|
||||
color: var(--clr-primary);
|
||||
}
|
||||
|
||||
.info-route {
|
||||
width: 100%;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
.stop-comments-icon > img {
|
||||
width: 1.3em;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.schedule {
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
<template>
|
||||
<div class="general-status">
|
||||
<span
|
||||
<router-link
|
||||
v-if="computedScheduledTrain.stationNameHref"
|
||||
:to="`/scenery?station=${computedScheduledTrain.stationNameHref}`"
|
||||
:class="computedScheduledTrain.status"
|
||||
data-tooltip-type="HtmlTooltip"
|
||||
:data-tooltip-content="computedScheduledTrain.stopStatusDescription"
|
||||
@click.prevent="() => {}"
|
||||
v-html="computedScheduledTrain.stopStatusIndicator"
|
||||
>
|
||||
{{ computedScheduledTrain.stopStatusIndicator }}
|
||||
</span>
|
||||
</router-link>
|
||||
|
||||
<span
|
||||
v-else
|
||||
:class="computedScheduledTrain.status"
|
||||
v-html="computedScheduledTrain.stopStatusIndicator"
|
||||
></span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -28,66 +33,65 @@ export default defineComponent({
|
||||
computedScheduledTrain() {
|
||||
const { status, prevElement, currentElement, nextElement } = this.sceneryTimetableRow;
|
||||
|
||||
const prevDepartureIndicator = prevElement?.departureRouteExt
|
||||
? `(${prevElement.departureRouteExt}) ${prevElement.stationName}`
|
||||
: '---';
|
||||
|
||||
const nextArrivalIndicator = nextElement?.arrivalRouteExt
|
||||
? `(${nextElement.arrivalRouteExt}) ${nextElement.stationName}`
|
||||
: `${currentElement.stationName}`;
|
||||
|
||||
let stopStatusDescription = '',
|
||||
stopStatusIndicator = '';
|
||||
let stopStatusIndicator = '';
|
||||
let stationNameHref = '';
|
||||
|
||||
switch (status) {
|
||||
case StopStatus.ARRIVING:
|
||||
stopStatusIndicator = `${this.$t('timetables.from')}: ${prevDepartureIndicator}`;
|
||||
stopStatusDescription = this.$t('timetables.desc-arriving', {
|
||||
prevStationName: prevElement?.stationName ?? '',
|
||||
prevDepartureLine: prevElement?.departureRouteExt ?? ''
|
||||
});
|
||||
if (prevElement) {
|
||||
stopStatusIndicator = this.$t('timetables.desc-arriving', {
|
||||
prevStationName: prevElement?.stationName ?? '',
|
||||
prevDepartureLine: prevElement?.departureRouteExt ?? ''
|
||||
});
|
||||
|
||||
stationNameHref = prevElement?.stationName ?? '';
|
||||
} else {
|
||||
stopStatusIndicator = this.$t('timetables.desc-beginning');
|
||||
}
|
||||
break;
|
||||
|
||||
case StopStatus.ONLINE:
|
||||
case StopStatus.STOPPED:
|
||||
stopStatusIndicator = nextElement?.arrivalRouteExt
|
||||
? `${this.$t('timetables.to')}: ${nextArrivalIndicator}`
|
||||
: `${this.$t('timetables.desc-end')}`;
|
||||
stopStatusDescription = nextElement?.arrivalRouteExt
|
||||
? this.$t(`timetables.desc-${status}`, {
|
||||
nextStationName: nextElement?.stationName,
|
||||
nextArrivalLine: nextElement?.arrivalRouteExt
|
||||
})
|
||||
: '';
|
||||
: this.$t(`timetables.desc-end`);
|
||||
|
||||
stationNameHref = nextElement?.stationName ?? '';
|
||||
|
||||
break;
|
||||
|
||||
case StopStatus.DEPARTED:
|
||||
stopStatusIndicator = `${this.$t('timetables.to')}: ${nextArrivalIndicator}`;
|
||||
|
||||
if (!nextElement?.stationName) {
|
||||
stopStatusDescription = this.$t('timetables.desc-departed-ends', {
|
||||
stopStatusIndicator = this.$t('timetables.desc-departed-ends', {
|
||||
nextStationName: currentElement.stationName
|
||||
});
|
||||
|
||||
stationNameHref = nextElement?.stationName ?? '';
|
||||
} else {
|
||||
stopStatusDescription = this.$t('timetables.desc-departed', {
|
||||
stopStatusIndicator = this.$t('timetables.desc-departed', {
|
||||
nextStationName: nextElement?.stationName ?? currentElement.stationName,
|
||||
nextArrivalLine: nextElement?.arrivalRouteExt
|
||||
});
|
||||
|
||||
stationNameHref = nextElement?.stationName ?? '';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case StopStatus.DEPARTED_AWAY:
|
||||
stopStatusIndicator = `${this.$t('timetables.to')}: ${nextArrivalIndicator}`;
|
||||
stopStatusDescription = this.$t('timetables.desc-departed-away', {
|
||||
stopStatusIndicator = this.$t('timetables.desc-departed-away', {
|
||||
nextStationName: nextElement?.stationName,
|
||||
nextArrivalLine: nextElement?.arrivalRouteExt
|
||||
});
|
||||
|
||||
stationNameHref = nextElement?.stationName ?? '';
|
||||
break;
|
||||
|
||||
case StopStatus.TERMINATED:
|
||||
stopStatusIndicator = `X ${this.$t('timetables.desc-terminated')}`;
|
||||
stopStatusDescription = this.$t('timetables.desc-terminated');
|
||||
stopStatusIndicator = this.$t('timetables.desc-terminated');
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -95,10 +99,18 @@ export default defineComponent({
|
||||
}
|
||||
return {
|
||||
...this.sceneryTimetableRow,
|
||||
stopStatusDescription,
|
||||
stationNameHref,
|
||||
stopStatusIndicator
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
navigateToScenery(sceneryName?: string) {
|
||||
if (!sceneryName) return;
|
||||
|
||||
this.$router.push(`/scenery?station=${sceneryName}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -106,34 +118,29 @@ export default defineComponent({
|
||||
<style lang="scss" scoped>
|
||||
.general-status {
|
||||
margin-top: 0.5em;
|
||||
cursor: help;
|
||||
|
||||
span.arriving {
|
||||
& > .arriving {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
span.departed {
|
||||
& > .departed {
|
||||
color: lime;
|
||||
font-weight: bold;
|
||||
|
||||
&-away {
|
||||
font-weight: bold;
|
||||
color: #5ecc5e;
|
||||
}
|
||||
}
|
||||
|
||||
span.stopped {
|
||||
& > .stopped {
|
||||
color: #ffa600;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span.online {
|
||||
& > .online {
|
||||
color: gold;
|
||||
}
|
||||
|
||||
span.terminated {
|
||||
& > .terminated {
|
||||
color: salmon;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
class="header-image"
|
||||
:class="headerName"
|
||||
>
|
||||
<span class="header_wrapper">
|
||||
<img
|
||||
:src="`/images/icon-${headerName}.svg`"
|
||||
:alt="headerName"
|
||||
:title="$t(`sceneries.headers.${headerName}`)"
|
||||
/>
|
||||
<span
|
||||
class="header_wrapper"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="$t(`sceneries.headers.${headerName}`)"
|
||||
>
|
||||
<img :src="`/images/icon-${headerName}.svg`" :alt="headerName" />
|
||||
|
||||
<img
|
||||
class="sort-icon"
|
||||
@@ -76,37 +76,49 @@
|
||||
station.generalInfo.availability != 'nonPublic' &&
|
||||
station.generalInfo.availability != 'unavailable'
|
||||
"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="`${$t(`sceneries.info.${station.generalInfo.availability}`)} (${$t(
|
||||
'sceneries.info.req-level',
|
||||
{ lvl: station.generalInfo.reqLevel },
|
||||
station.generalInfo.reqLevel
|
||||
)})`"
|
||||
:style="calculateExpStyle(station.generalInfo.reqLevel)"
|
||||
>
|
||||
{{ station.generalInfo.reqLevel >= 2 ? station.generalInfo.reqLevel : 'L' }}
|
||||
</span>
|
||||
|
||||
<span v-else-if="station.generalInfo.availability == 'abandoned'">
|
||||
<img
|
||||
src="/images/icon-abandoned.svg"
|
||||
alt="non-public"
|
||||
:title="$t('sceneries.info.abandoned')"
|
||||
/>
|
||||
<span
|
||||
v-else-if="station.generalInfo.availability == 'abandoned'"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="$t('sceneries.info.abandoned')"
|
||||
>
|
||||
<img src="/images/icon-abandoned.svg" alt="non-public" />
|
||||
</span>
|
||||
|
||||
<span v-else-if="station.generalInfo.availability == 'nonPublic'">
|
||||
<img
|
||||
src="/images/icon-lock.svg"
|
||||
alt="non-public"
|
||||
:title="$t('sceneries.info.non-public')"
|
||||
/>
|
||||
<span
|
||||
v-else-if="station.generalInfo.availability == 'nonPublic'"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="$t('sceneries.info.non-public')"
|
||||
>
|
||||
<img src="/images/icon-lock.svg" alt="non-public" />
|
||||
</span>
|
||||
|
||||
<span v-else>
|
||||
<img
|
||||
src="/images/icon-unavailable.svg"
|
||||
alt="unavailable"
|
||||
:title="$t('sceneries.info.unavailable')"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="$t('sceneries.info.unavailable')"
|
||||
>
|
||||
<img src="/images/icon-unavailable.svg" alt="unavailable" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span v-else> ? </span>
|
||||
<span
|
||||
v-else
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="$t('sceneries.info.unknown')"
|
||||
>
|
||||
?
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="station-status">
|
||||
@@ -153,7 +165,8 @@
|
||||
<span
|
||||
v-if="station.generalInfo.routes.singleElectrifiedNames.length != 0"
|
||||
class="track catenary"
|
||||
:title="`${$t('sceneries.info.single-track-routes-catenary')}${
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="`${$t('sceneries.info.single-track-routes-catenary')}${
|
||||
station.generalInfo.routes.singleElectrifiedNames.length
|
||||
}`"
|
||||
>
|
||||
@@ -163,7 +176,8 @@
|
||||
<span
|
||||
v-if="station.generalInfo.routes.singleOtherNames.length != 0"
|
||||
class="track no-catenary"
|
||||
:title="`${$t('sceneries.info.single-track-routes-other')}${
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="`${$t('sceneries.info.single-track-routes-other')}${
|
||||
station.generalInfo.routes.singleOtherNames.length
|
||||
}`"
|
||||
>
|
||||
@@ -177,7 +191,8 @@
|
||||
<span
|
||||
v-if="station.generalInfo.routes.doubleElectrifiedNames.length != 0"
|
||||
class="track catenary"
|
||||
:title="`${$t('sceneries.info.double-track-routes-catenary')}${
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="`${$t('sceneries.info.double-track-routes-catenary')}${
|
||||
station.generalInfo.routes.doubleElectrifiedNames.length
|
||||
}`"
|
||||
>
|
||||
@@ -187,7 +202,8 @@
|
||||
<span
|
||||
v-if="station.generalInfo.routes.doubleOtherNames.length != 0"
|
||||
class="track no-catenary"
|
||||
:title="`${$t('sceneries.info.double-track-routes-other')}${
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="`${$t('sceneries.info.double-track-routes-other')}${
|
||||
station.generalInfo.routes.doubleOtherNames.length
|
||||
}`"
|
||||
>
|
||||
@@ -201,7 +217,8 @@
|
||||
v-if="station.generalInfo?.signalType"
|
||||
class="scenery-icon icon-info"
|
||||
:class="station.generalInfo?.controlType.replace('+', '-')"
|
||||
:title="
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="
|
||||
$t('sceneries.info.control-type') +
|
||||
$t(`controls.${station.generalInfo?.controlType}`)
|
||||
"
|
||||
@@ -214,7 +231,8 @@
|
||||
class="icon-info"
|
||||
:src="`/images/icon-${station.generalInfo.signalType}.svg`"
|
||||
:alt="station.generalInfo.signalType"
|
||||
:title="
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="
|
||||
$t('sceneries.info.signals-type') + $t(`signals.${station.generalInfo.signalType}`)
|
||||
"
|
||||
/>
|
||||
@@ -224,7 +242,8 @@
|
||||
class="icon-info"
|
||||
src="/images/icon-SUP.svg"
|
||||
alt="SUP (RASP-UZK)"
|
||||
:title="$t('sceneries.info.SUP')"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="$t('sceneries.info.SUP')"
|
||||
/>
|
||||
|
||||
<img
|
||||
@@ -232,7 +251,8 @@
|
||||
class="icon-info"
|
||||
src="/images/icon-ASDEK.svg"
|
||||
alt="dSAT ASDEK"
|
||||
:title="$t('sceneries.info.ASDEK')"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="$t('sceneries.info.ASDEK')"
|
||||
/>
|
||||
|
||||
<img
|
||||
@@ -240,7 +260,8 @@
|
||||
class="icon-info"
|
||||
src="/images/icon-unknown.svg"
|
||||
alt="icon-unknown"
|
||||
:title="$t('sceneries.info.unknown')"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="$t('sceneries.info.unknown')"
|
||||
/>
|
||||
</td>
|
||||
|
||||
@@ -248,7 +269,7 @@
|
||||
class="station-users"
|
||||
:class="{ inactive: !station.onlineInfo }"
|
||||
data-tooltip-type="UsersTooltip"
|
||||
:data-tooltip-content="JSON.stringify(station.onlineInfo?.stationTrains ?? [])"
|
||||
:data-tooltip-content="getUsersTooltipContent(station.onlineInfo?.stationTrains ?? [])"
|
||||
>
|
||||
<span class="text--primary">{{
|
||||
station.onlineInfo?.stationTrains?.length ?? '-'
|
||||
@@ -318,7 +339,7 @@ import dateMixin from '../../mixins/dateMixin';
|
||||
import styleMixin from '../../mixins/styleMixin';
|
||||
import { useApiStore } from '../../store/apiStore';
|
||||
import { useMainStore } from '../../store/mainStore';
|
||||
import { Station, Status } from '../../typings/common';
|
||||
import { Station, Status, TooltipUserTrain, Train } from '../../typings/common';
|
||||
import { useTooltipStore } from '../../store/tooltipStore';
|
||||
import { getChangedFilters } from '../../managers/stationFilterManager';
|
||||
import { ActiveSorter, HeadIdsType, headIconsIds, headIds } from './typings';
|
||||
@@ -394,6 +415,15 @@ export default defineComponent({
|
||||
else this.activeSorter.dir = 1;
|
||||
|
||||
this.activeSorter.headerName = headerName;
|
||||
},
|
||||
|
||||
getUsersTooltipContent(stationTrains: Train[]): string {
|
||||
const usersTrains: TooltipUserTrain[] = stationTrains.map((train) => ({
|
||||
driverName: train.driverName,
|
||||
trainNo: train.trainNo
|
||||
}));
|
||||
|
||||
return JSON.stringify(usersTrains);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@ import BaseTooltip from './BaseTooltip.vue';
|
||||
import SpawnsTooltip from './SpawnsTooltip.vue';
|
||||
import UsersTooltip from './UsersTooltip.vue';
|
||||
import HtmlTooltip from './HtmlTooltip.vue';
|
||||
import TrainInfoTooltip from "./TrainInfoTooltip.vue";
|
||||
|
||||
const BOX_PADDING_PX = 20;
|
||||
|
||||
@@ -23,7 +24,8 @@ export default defineComponent({
|
||||
BaseTooltip,
|
||||
SpawnsTooltip,
|
||||
UsersTooltip,
|
||||
HtmlTooltip
|
||||
HtmlTooltip,
|
||||
TrainInfoTooltip
|
||||
},
|
||||
|
||||
data() {
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div class="tooltip-content">
|
||||
<span v-if="trainInfo">
|
||||
<b v-if="trainInfo.timetableData" style="text-transform: uppercase">
|
||||
<span class="text--primary">{{ trainInfo.timetableData.category }}</span>
|
||||
{{ getCategoryExplanation(trainInfo.timetableData.category) }}
|
||||
</b>
|
||||
|
||||
<div class="text--primary">
|
||||
<b>{{ trainInfo.stockList[0] }}</b> • {{ trainInfo.length }}m •
|
||||
{{ (trainInfo.mass / 1000).toFixed(2) }}t
|
||||
</div>
|
||||
|
||||
<div class="text--grayed">
|
||||
{{ displayTrainPosition(trainInfo) }} - {{ trainInfo.speed }}km/h
|
||||
<span v-if="!trainInfo.online" style="color: salmon">
|
||||
- offline {{ lastSeenMessage(trainInfo.lastSeen) }}</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<div></div>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { useTooltipStore } from '../../store/tooltipStore';
|
||||
import trainCategoryMixin from '../../mixins/trainCategoryMixin';
|
||||
import trainInfoMixin from '../../mixins/trainInfoMixin';
|
||||
import { useMainStore } from '../../store/mainStore';
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [trainCategoryMixin, trainInfoMixin],
|
||||
|
||||
data: () => ({
|
||||
tooltipStore: useTooltipStore(),
|
||||
mainStore: useMainStore()
|
||||
}),
|
||||
|
||||
computed: {
|
||||
trainInfo() {
|
||||
if (this.tooltipStore.content == '') return null;
|
||||
|
||||
// Passed "content" string should be the desired train's ID
|
||||
return this.mainStore.trainList.find((t) => t.id === this.tooltipStore.content);
|
||||
},
|
||||
|
||||
lastSceneryStatus() {
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tooltip-content {
|
||||
padding: 0.25em 0.5em;
|
||||
border-radius: 0.25em;
|
||||
|
||||
width: 100%;
|
||||
background-color: #1f1f1f;
|
||||
box-shadow: 0 0 5px 2px #aaa;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 1em;
|
||||
}
|
||||
</style>
|
||||
@@ -10,7 +10,7 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { useTooltipStore } from '../../store/tooltipStore';
|
||||
import { Train } from '../../typings/common';
|
||||
import { TooltipUserTrain } from '../../typings/common';
|
||||
|
||||
export default defineComponent({
|
||||
data() {
|
||||
@@ -23,7 +23,7 @@ export default defineComponent({
|
||||
trains() {
|
||||
if (this.tooltipStore.content == '') return [];
|
||||
|
||||
const parsedTrains = JSON.parse(this.tooltipStore.content) as Train[];
|
||||
const parsedTrains = JSON.parse(this.tooltipStore.content) as TooltipUserTrain[];
|
||||
return (parsedTrains ?? []).sort((a, b) => a.trainNo - b.trainNo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,10 @@
|
||||
{{ $t('trains.scenery-offline') }}
|
||||
</div>
|
||||
|
||||
<div v-if="!train.online" class="train-badge offline">
|
||||
<div
|
||||
v-if="!train.online && train.lastSeen >= Date.now() - 60000"
|
||||
class="train-badge offline"
|
||||
>
|
||||
<i class="fa-solid fa-user-slash"></i>
|
||||
Offline {{ lastSeenMessage(train.lastSeen) }}
|
||||
</div>
|
||||
|
||||
@@ -30,17 +30,20 @@
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
<select
|
||||
class="search-input"
|
||||
name="active-trains"
|
||||
id="active-trains"
|
||||
v-model="searchedDriver"
|
||||
>
|
||||
<option value="">{{ $t('options.select-driver') }}</option>
|
||||
<datalist id="search-active-driver">
|
||||
<option v-for="driverName in activeDriverNames" :value="driverName">
|
||||
{{ driverName }}
|
||||
</option>
|
||||
</select>
|
||||
</datalist>
|
||||
|
||||
<input
|
||||
class="search-input"
|
||||
list="search-active-driver"
|
||||
name="search-active-driver"
|
||||
id="search-active-driver"
|
||||
:placeholder="$t(`options.search-driver`)"
|
||||
v-model="searchedDriver"
|
||||
/>
|
||||
|
||||
<button class="btn btn--action search-exit" @click="onInputClear('driver')">
|
||||
<img src="/images/icon-exit.svg" alt="Trains search clear icon" />
|
||||
|
||||
@@ -57,7 +57,14 @@
|
||||
<span>{{ stop.departureLine }}</span>
|
||||
|
||||
<span v-if="stop.departureLineInfo">
|
||||
<span> | {{ stop.departureLineInfo.routeSpeed }}</span>
|
||||
<span>
|
||||
|
|
||||
{{
|
||||
stop.departureLineInfo.routeSpeedExit
|
||||
? `${stop.departureLineInfo.routeSpeedExit} (${stop.departureLineInfo.routeSpeed})`
|
||||
: stop.departureLineInfo.routeSpeed
|
||||
}}</span
|
||||
>
|
||||
|
||||
<img
|
||||
:src="
|
||||
@@ -85,13 +92,13 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="stop.sceneryName != scheduleStops[i + 1]?.sceneryName"
|
||||
v-if="stop.nextPointRef && stop.sceneryName != stop.nextPointRef.sceneryName"
|
||||
class="scenery-change-name"
|
||||
>
|
||||
<span>{{ scheduleStops[i + 1].sceneryName }}</span>
|
||||
<span>{{ stop.nextPointRef.sceneryName }}</span>
|
||||
|
||||
<i
|
||||
v-if="!scheduleStops[i + 1].isSceneryOnline"
|
||||
v-if="!stop.nextPointRef.isSceneryOnline"
|
||||
class="fa-solid fa-ban fa-sm"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="$t('app.tooltip-scenery-offline')"
|
||||
@@ -101,30 +108,33 @@
|
||||
|
||||
<div
|
||||
class="scenery-route"
|
||||
v-if="stop.sceneryName != scheduleStops[i + 1]?.sceneryName"
|
||||
v-if="stop.nextPointRef && stop.sceneryName != stop.nextPointRef.sceneryName"
|
||||
>
|
||||
<span> {{ scheduleStops[i + 1].arrivalLine }}</span>
|
||||
<span> {{ stop.nextPointRef.arrivalLine }}</span>
|
||||
|
||||
<span v-if="scheduleStops[i + 1].arrivalLineInfo">
|
||||
<span> | {{ scheduleStops[i + 1].arrivalLineInfo!.routeSpeed }} </span>
|
||||
<span v-if="stop.nextPointRef.arrivalLineInfo">
|
||||
<span> | {{ stop.nextPointRef.arrivalLineInfo!.routeSpeed }}</span>
|
||||
<span v-if="stop.nextPointRef.arrivalLineInfo!.routeSpeedExit"
|
||||
>({{ stop.nextPointRef.arrivalLineInfo!.routeSpeedExit }})</span
|
||||
>
|
||||
|
||||
<img
|
||||
:src="
|
||||
scheduleStops[i + 1].arrivalLineInfo?.isElectric
|
||||
stop.nextPointRef.arrivalLineInfo?.isElectric
|
||||
? '/images/icon-catenary.svg'
|
||||
: '/images/icon-we4a.png'
|
||||
"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
:data-tooltip-content="
|
||||
$t(
|
||||
`trains.${!scheduleStops[i + 1].arrivalLineInfo?.isElectric ? 'no-' : ''}catenary-tooltip`
|
||||
`trains.${!stop.nextPointRef.arrivalLineInfo?.isElectric ? 'no-' : ''}catenary-tooltip`
|
||||
)
|
||||
"
|
||||
width="14"
|
||||
/>
|
||||
|
||||
<img
|
||||
v-if="scheduleStops[i + 1].arrivalLineInfo!.isRouteSBL"
|
||||
v-if="stop.nextPointRef.arrivalLineInfo!.isRouteSBL"
|
||||
src="/images/icon-sbl-transparent.svg"
|
||||
width="14"
|
||||
data-tooltip-type="BaseTooltip"
|
||||
@@ -228,7 +238,7 @@ export default defineComponent({
|
||||
departureLineInfo = pathData.departureLineData;
|
||||
}
|
||||
|
||||
for (const stop of followingStops) {
|
||||
followingStops.forEach((stop, i) => {
|
||||
let isExternal = false;
|
||||
|
||||
if (stop.arrivalLine === currentPath.arrivalRouteExt) {
|
||||
@@ -287,7 +297,9 @@ export default defineComponent({
|
||||
status: stop.confirmed ? 'confirmed' : stop.stopped ? 'stopped' : 'unconfirmed',
|
||||
|
||||
sceneryName: currentPath.stationName,
|
||||
isSceneryOnline: pathData?.isOnline ?? false
|
||||
isSceneryOnline: pathData?.isOnline ?? false,
|
||||
|
||||
nextPointRef: null
|
||||
};
|
||||
|
||||
if (internalRouteInfo) {
|
||||
@@ -309,6 +321,11 @@ export default defineComponent({
|
||||
|
||||
stopRows.push(rowData);
|
||||
|
||||
// Assign this row data object to the last one as reference
|
||||
if (i != 0) {
|
||||
stopRows[i - 1].nextPointRef = rowData;
|
||||
}
|
||||
|
||||
if (stop.departureLine === currentPath.departureRouteExt) {
|
||||
// Reverse search for last scenery checkpoint
|
||||
if (pathData?.departureLineData) {
|
||||
@@ -328,7 +345,7 @@ export default defineComponent({
|
||||
currentPath = timetablePath[++currentPathIndex];
|
||||
pathData = this.getPathSceneryData(currentPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return stopRows;
|
||||
},
|
||||
|
||||
@@ -196,4 +196,6 @@ export interface TrainSchedulePoint {
|
||||
isSBL: boolean;
|
||||
sceneryName: string | null;
|
||||
isSceneryOnline: boolean;
|
||||
|
||||
nextPointRef: TrainSchedulePoint | null;
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
"TRE", "TRS",
|
||||
"TSE", "TSS",
|
||||
"THE", "THS",
|
||||
"LPE",
|
||||
"LPE", "LPS",
|
||||
"LTE", "LTS",
|
||||
"LSS",
|
||||
"LZE", "LZS",
|
||||
|
||||
+23
-20
@@ -84,7 +84,7 @@
|
||||
"categories": {
|
||||
"EI": "domestic express",
|
||||
"EC": "international express",
|
||||
"EN": "domestic night express",
|
||||
"EN": "international night express",
|
||||
"MP": "intervoivodeship bullet",
|
||||
"MO": "intervoivodeship regio",
|
||||
"MM": "international bullet",
|
||||
@@ -337,18 +337,20 @@
|
||||
},
|
||||
"info": {
|
||||
"control-type": "Control type: ",
|
||||
"signals-type": "Signals type: ",
|
||||
"SBL": "This scenery has automatic block signalling (ABS/SBL) system on following routes: ",
|
||||
"signals-type": "Signalling type: ",
|
||||
"SBL": "A scenery with automatic block signalling (ABS/SBL) on routes: ",
|
||||
"SUP": "Requires the SUP program (level crossing remote control)",
|
||||
"ASDEK": "Requires the ASDEK program (defect detection of moving rolling stock)",
|
||||
"ASDEK": "ASDEK program available (defect detection of moving rolling stock)",
|
||||
"TWB-all": "This scenery has two-way route blockade on all routes",
|
||||
"TWB-routes": "This scenery has two-way route blockade on following routes: ",
|
||||
"default": "This scenery is available by default",
|
||||
"non-public": "This scenery is not public",
|
||||
"unavailable": "This scenery is unavailable",
|
||||
"abandoned": "This scenery is no longer supported by its creators",
|
||||
"unknown": "This scenery isn't recognizable right now",
|
||||
"real": "Scenery with real lines: ",
|
||||
"default": "Scenery available in game package",
|
||||
"nonDefault": "Sceneria available to download from forum site",
|
||||
"req-level": "all dispatcher levels | requries {lvl} dispatcher lvl | requires {lvl} dispatcher lvl",
|
||||
"non-public": "Non-public scenery",
|
||||
"unavailable": "Unavailable scenery",
|
||||
"abandoned": "Abandoned scenery",
|
||||
"unknown": "Unknown scenery",
|
||||
"real": "Scenery with real Polish routes: ",
|
||||
"double-track-routes-catenary": "Electrified double-track routes count: ",
|
||||
"single-track-routes-catenary": "Electrified single-track routes count: ",
|
||||
"double-track-routes-other": "Not electrified double-track routes count: ",
|
||||
@@ -543,7 +545,7 @@
|
||||
"no-users": "NO ACTIVE PLAYERS",
|
||||
"no-spawns": "NO OPEN SPAWNS",
|
||||
"no-scenery": "Oops! This scenery doesn't exist!",
|
||||
"return-btn": "Return",
|
||||
"return-btn": "BACK TO THE LAST SITE",
|
||||
"history-btn": "View the dispatcher history",
|
||||
"info-btn": "Return to the scenery view",
|
||||
"authors-title": "Scenery author | Scenery authors",
|
||||
@@ -589,15 +591,16 @@
|
||||
"terminated": "Timetable terminated",
|
||||
"begins": "BEGINS HERE",
|
||||
"terminates": "TERMINATES\nHERE",
|
||||
"from": "FROM",
|
||||
"to": "TO",
|
||||
"desc-arriving": "The train is not here yet.\nIt's going to come from: <b>{prevStationName} (route {prevDepartureLine})</b>",
|
||||
"desc-online": "The train is at the station.\nIt's going to leave to: <b>{nextStationName} (route {nextArrivalLine})</b>",
|
||||
"desc-stopped": "The train is at the station and is stopped.\nIt's going to leave towards: <b>{nextStationName} (route {nextArrivalLine})</b>",
|
||||
"desc-next-arrival": "Leaves towards: <b>{nextStationName} (route {nextArrivalLine})</b>",
|
||||
"desc-departed": "The train is at the station and it's been departed.\nLeaves towards: <b>{nextStationName} (route {nextArrivalLine})</b>",
|
||||
"desc-departed-ends": "The train is at the station and it's been departed.\nLeaves towards station: <b>{nextStationName}</b>",
|
||||
"desc-departed-away": "The train has been departed to:\n<b>{nextStationName} (route {nextArrivalLine})</b>",
|
||||
"from": "Arrives from",
|
||||
"to": "Departs to",
|
||||
"desc-beginning": "Outside scenery / begins here",
|
||||
"desc-arriving": "Arrives from: <b><u>{prevStationName} ({prevDepartureLine})</u></b>",
|
||||
"desc-online": "On scenery / direction: <b><u>{nextStationName} ({nextArrivalLine})</u></b>",
|
||||
"desc-stopped": "On scenery - stopped / direction: <b><u>{nextStationName} ({nextArrivalLine})</u></b>",
|
||||
"desc-next-arrival": "On scenery / direction: <b><u>{nextStationName} ({nextArrivalLine})</u></b>",
|
||||
"desc-departed": "On scenery / departed to: <b><u>{nextStationName} ({nextArrivalLine})</u></b>",
|
||||
"desc-departed-ends": "On scenery / departed to: <b><u>{nextStationName}</u></b>",
|
||||
"desc-departed-away": "Departed to: <b><u>{nextStationName} ({nextArrivalLine})</u></b>",
|
||||
"desc-end": "The train terminates here",
|
||||
"desc-terminated": "The train has been terminated"
|
||||
},
|
||||
|
||||
+16
-13
@@ -81,7 +81,7 @@
|
||||
"categories": {
|
||||
"EI": "ekspres krajowy",
|
||||
"EC": "ekspres międzynarodowy",
|
||||
"EN": "ekspres krajowy nocny",
|
||||
"EN": "ekspres międzynarodowy nocny",
|
||||
"MP": "międzywojewódzki pospieszny",
|
||||
"MO": "międzywojewódzki osobowy",
|
||||
"MM": "międzynarodowy pospieszny",
|
||||
@@ -338,8 +338,10 @@
|
||||
"signals-type": "Sygnalizacja: ",
|
||||
"SBL": "Sceneria posiada SBL na szlakach: ",
|
||||
"SUP": "Wymaga programu SUP do kontroli systemu RASP-UZK",
|
||||
"ASDEK": "Wymaga programu ASDEK do detekcji stanów awaryjnych taboru w ruchu",
|
||||
"ASDEK": "Dostępny program ASDEK do detekcji stanów awaryjnych taboru w ruchu",
|
||||
"default": "Sceneria dostępna domyślnie w paczce z grą",
|
||||
"nonDefault": "Sceneria dostępna do pobrania ze strony forum",
|
||||
"req-level": "ogólnodostępna | od {lvl} poz. DR | od {lvl} poz. DR",
|
||||
"non-public": "Sceneria niepubliczna",
|
||||
"unavailable": "Sceneria niedostępna",
|
||||
"abandoned": "Sceneria wycofana z rozgrywki",
|
||||
@@ -529,7 +531,7 @@
|
||||
"no-users": "BRAK AKTYWNYCH GRACZY",
|
||||
"no-spawns": "BRAK OTWARTYCH SPAWNÓW",
|
||||
"no-scenery": "Ups! Ta sceneria nie istnieje!",
|
||||
"return-btn": "Powrót",
|
||||
"return-btn": "POWRÓT DO POPRZEDNIEJ STRONY",
|
||||
"history-btn": "Przejdź do widoku historii dyżurnych ruchu",
|
||||
"info-btn": "Wróć do widoku scenerii",
|
||||
"authors-title": "Autor scenerii | Autorzy scenerii",
|
||||
@@ -575,17 +577,18 @@
|
||||
"terminated": "Rozkład jazdy zakończony",
|
||||
"begins": "ROZPOCZYNA\nBIEG",
|
||||
"terminates": "KOŃCZY BIEG",
|
||||
"from": "Z",
|
||||
"to": "DO",
|
||||
"desc-arriving": "Pociągu nie ma jeszcze na tej scenerii.\nPrzyjedzie z: <b>{prevStationName} (szlak {prevDepartureLine})</b>",
|
||||
"desc-online": "Pociąg jest na tej scenerii.\nOdjedzie w kierunku: <b>{nextStationName} (szlak {nextArrivalLine})</b>",
|
||||
"desc-stopped": "Pociąg jest na tej scenerii i odbywa postój.\nOdjedzie w kierunku: <b>{nextStationName} (szlak {nextArrivalLine})</b>",
|
||||
"desc-next-arrival": "Odjeżdża do:\n<b>{nextStationName} (szlak {nextArrivalLine})</b>",
|
||||
"desc-departed": "Pociąg jest na tej scenerii i został odprawiony.\nOdjeżdża w kierunku: <b>{nextStationName} (szlak {nextArrivalLine})</b>",
|
||||
"desc-departed-ends": "Pociąg jest na tej scenerii i został odprawiony.\nOdjechał w kierunku stacji: <b>{nextStationName}</b>",
|
||||
"desc-departed-away": "Pociąg został odprawiony i odjechał do:\n<b>{nextStationName} (szlak {nextArrivalLine})</b>",
|
||||
"from": "Przyjedzie z",
|
||||
"to": "Odjeżdża do",
|
||||
"desc-beginning": "Poza scenerią / rozpoczyna bieg",
|
||||
"desc-arriving": "Przyjedzie z: <b><u>{prevStationName} ({prevDepartureLine})</u></b>",
|
||||
"desc-online": "Na scenerii / kierunek: <b><u>{nextStationName} ({nextArrivalLine})</u></b>",
|
||||
"desc-stopped": "Na scenerii - postój / kierunek: <b><u>{nextStationName} ({nextArrivalLine})</u></b>",
|
||||
"desc-next-arrival": "Na scenerii / kierunek: <b><u>{nextStationName} ({nextArrivalLine})</u></b>",
|
||||
"desc-departed": "Na scenerii / odprawiony do: <b><u>{nextStationName} ({nextArrivalLine})</u></b>",
|
||||
"desc-departed-ends": "Na scenerii / odprawiony do: <b><u>{nextStationName}</u></b>",
|
||||
"desc-departed-away": "Odprawiony do: <b><u>{nextStationName} ({nextArrivalLine})</u></b>",
|
||||
"desc-end": "Pociąg kończy bieg",
|
||||
"desc-terminated": "Pociąg skończył bieg"
|
||||
"desc-terminated": "Pociąg zakończył bieg"
|
||||
},
|
||||
"history": {
|
||||
"title": "DZIENNIK ROZKŁADÓW JAZDY"
|
||||
|
||||
+5
-2
@@ -36,7 +36,10 @@ const routes: Array<RouteRecordRaw> = [
|
||||
props: (route) => ({
|
||||
region: route.query.region,
|
||||
station: route.query.station
|
||||
})
|
||||
}),
|
||||
beforeEnter: (to, from) => {
|
||||
to.meta['prevPath'] = from.fullPath;
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/journal',
|
||||
@@ -72,7 +75,7 @@ const router = createRouter({
|
||||
from.query['view'] === undefined &&
|
||||
!savedPosition
|
||||
)
|
||||
return { el: `.scenery-left`, behavior: 'instant', top: 3 };
|
||||
return { el: `.app_main`, behavior: 'instant', top: -13 };
|
||||
|
||||
if (savedPosition) return savedPosition;
|
||||
},
|
||||
|
||||
@@ -8,7 +8,8 @@ export const tooltipKeys = [
|
||||
'VehiclePreviewTooltip',
|
||||
'SpawnsTooltip',
|
||||
'UsersTooltip',
|
||||
'HtmlTooltip'
|
||||
'HtmlTooltip',
|
||||
'TrainInfoTooltip'
|
||||
] as const;
|
||||
|
||||
export type TooltipType = (typeof tooltipKeys)[number];
|
||||
@@ -33,6 +34,7 @@ export const useTooltipStore = defineStore('tooltipStore', {
|
||||
this.content = '';
|
||||
},
|
||||
|
||||
// Tooltip handler reading attributes of DOM elements
|
||||
handle(e: MouseEvent) {
|
||||
const targetEl = e
|
||||
.composedPath()
|
||||
@@ -44,6 +46,7 @@ export const useTooltipStore = defineStore('tooltipStore', {
|
||||
return;
|
||||
}
|
||||
|
||||
// Tooltip content is a string but may be parsed to objects / html in corresponding tooltip type components
|
||||
const tooltipType = targetEl.getAttribute('data-tooltip-type');
|
||||
const tooltipContent = targetEl.getAttribute('data-tooltip-content');
|
||||
|
||||
|
||||
@@ -297,48 +297,6 @@ a.a-button {
|
||||
}
|
||||
}
|
||||
|
||||
.return-btn {
|
||||
display: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
position: fixed;
|
||||
right: 2.5rem;
|
||||
bottom: 4rem;
|
||||
|
||||
z-index: 100;
|
||||
|
||||
width: 3.5rem;
|
||||
|
||||
font-size: 3rem;
|
||||
|
||||
background-color: #555;
|
||||
outline: 3px solid #222;
|
||||
color: white;
|
||||
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #3c3c3c;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 1.3em;
|
||||
}
|
||||
|
||||
@include responsive.smallScreen {
|
||||
bottom: 1em;
|
||||
right: 0;
|
||||
left: 50%;
|
||||
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
// Basic tooltip
|
||||
[data-tooltip] {
|
||||
cursor: help;
|
||||
|
||||
@@ -142,6 +142,7 @@ export interface StationRoutesInfo {
|
||||
isRouteSBL: boolean;
|
||||
routeLength: number;
|
||||
routeSpeed: number;
|
||||
routeSpeedExit?: number;
|
||||
routeTracks: number;
|
||||
hidden?: boolean;
|
||||
realLineNo?: number;
|
||||
@@ -252,3 +253,25 @@ export interface VehicleCargo {
|
||||
id: string;
|
||||
weight: number;
|
||||
}
|
||||
|
||||
export interface TooltipUserTrain {
|
||||
driverName: string;
|
||||
trainNo: number;
|
||||
}
|
||||
|
||||
export interface TooltipTrainInfo {
|
||||
mass: number;
|
||||
length: number;
|
||||
speed: number;
|
||||
signal: string;
|
||||
distance: number;
|
||||
connectedTrack: string;
|
||||
trainNo: number;
|
||||
driverName: string;
|
||||
driverLevel: number;
|
||||
currentStationName: string;
|
||||
currentStationHash: string;
|
||||
headVehicleName: string;
|
||||
stockCount: number;
|
||||
trainTimetableCategory?: string;
|
||||
}
|
||||
|
||||
+74
-128
@@ -2,12 +2,6 @@
|
||||
<div class="scenery-view">
|
||||
<div class="scenery-wrapper" ref="card-wrapper">
|
||||
<div class="scenery-left">
|
||||
<div class="scenery-actions">
|
||||
<button class="back-btn" :title="$t('scenery.return-btn')" @click="onReturnButtonClick">
|
||||
<img src="/images/icon-back.svg" alt="return button" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<SceneryHeader
|
||||
:stationName="station"
|
||||
:station="stationInfo"
|
||||
@@ -23,8 +17,8 @@
|
||||
v-for="(viewMode, i) in viewModes"
|
||||
:key="i"
|
||||
class="btn btn--option"
|
||||
:class="{ checked: currentMode == viewMode.component }"
|
||||
@click="setViewMode(viewMode.component)"
|
||||
:class="{ checked: currentMode == viewMode.component.name }"
|
||||
@click="setViewMode(viewMode.component.name!)"
|
||||
>
|
||||
{{ $t(viewMode.id) }}
|
||||
</button>
|
||||
@@ -32,17 +26,17 @@
|
||||
|
||||
<div
|
||||
v-if="
|
||||
apiStore.dataStatuses.sceneries == Status.Loading ||
|
||||
apiStore.dataStatuses.connection == Status.Loading
|
||||
apiStore.dataStatuses.sceneries == Status.Data.Loading ||
|
||||
apiStore.dataStatuses.connection == Status.Data.Loading
|
||||
"
|
||||
></div>
|
||||
|
||||
<keep-alive v-else>
|
||||
<component
|
||||
:is="currentMode"
|
||||
:is="currentViewComponent"
|
||||
:onlineScenery="onlineSceneryInfo"
|
||||
:station="stationInfo"
|
||||
:key="currentMode"
|
||||
:key="currentViewComponent.name"
|
||||
></component>
|
||||
</keep-alive>
|
||||
</div>
|
||||
@@ -50,141 +44,93 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import routerMixin from '../mixins/routerMixin';
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useMainStore } from '../store/mainStore';
|
||||
|
||||
import SceneryInfo from '../components/SceneryView/SceneryInfo.vue';
|
||||
import SceneryHeader from '../components/SceneryView/SceneryHeader.vue';
|
||||
|
||||
import SceneryTimetable from '../components/SceneryView/SceneryTimetable.vue';
|
||||
import SceneryTimetablesHistory from '../components/SceneryView/SceneryTimetablesHistory.vue';
|
||||
import SceneryDispatchersHistory from '../components/SceneryView/SceneryDispatchersHistory.vue';
|
||||
import ActionButton from '../components/Global/ActionButton.vue';
|
||||
import { Status } from '../typings/common';
|
||||
|
||||
import { useApiStore } from '../store/apiStore';
|
||||
import { Status } from '../typings/common';
|
||||
|
||||
enum SceneryViewMode {
|
||||
'TIMETABLES_ACTIVE',
|
||||
'TIMETABLES_HISTORY',
|
||||
'SCENERY_HISTORY'
|
||||
}
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SceneryView',
|
||||
|
||||
components: {
|
||||
SceneryInfo,
|
||||
SceneryTimetable,
|
||||
ActionButton,
|
||||
SceneryHeader,
|
||||
SceneryTimetablesHistory,
|
||||
SceneryDispatchersHistory
|
||||
const props = defineProps({
|
||||
region: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
|
||||
props: {
|
||||
region: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
|
||||
station: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
mixins: [routerMixin],
|
||||
|
||||
data: () => ({
|
||||
store: useMainStore(),
|
||||
apiStore: useApiStore(),
|
||||
|
||||
viewModes: [
|
||||
{
|
||||
id: 'scenery.option-active-timetables',
|
||||
component: 'SceneryTimetable'
|
||||
},
|
||||
{
|
||||
id: 'scenery.option-timetables-history',
|
||||
component: 'SceneryTimetablesHistory'
|
||||
},
|
||||
{
|
||||
id: 'scenery.option-dispatchers-history',
|
||||
component: 'SceneryDispatchersHistory'
|
||||
}
|
||||
],
|
||||
sceneryViewMode: SceneryViewMode,
|
||||
selectedCheckpoint: '',
|
||||
currentViewCompontent: 'SceneryTimetable',
|
||||
onlineFrom: -1,
|
||||
Status: Status.Data
|
||||
}),
|
||||
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
|
||||
const isComponentVisible = computed(() => route.path === '/scenery');
|
||||
|
||||
return {
|
||||
isComponentVisible
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
currentMode() {
|
||||
return this.$route.query.view?.toString() ?? 'SceneryTimetable';
|
||||
},
|
||||
|
||||
stationInfo() {
|
||||
return this.store.stationList.find(
|
||||
(station) => station.name === this.station?.toString().replace(/_/g, ' ')
|
||||
);
|
||||
},
|
||||
|
||||
onlineSceneryInfo() {
|
||||
return this.store.activeSceneryList.find(
|
||||
(scenery) =>
|
||||
scenery.name === this.station?.toString().replace(/_/g, ' ') &&
|
||||
scenery.region == this.store.region.id
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setViewMode(componentName: string) {
|
||||
this.$router.push({
|
||||
path: this.$route.path,
|
||||
query: {
|
||||
...this.$route.query,
|
||||
view: componentName
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
loadSelectedCheckpoint() {
|
||||
if (!this.stationInfo?.generalInfo?.checkpoints) return;
|
||||
if (this.stationInfo.generalInfo.checkpoints.length == 0) return;
|
||||
this.selectedCheckpoint = this.stationInfo.generalInfo.checkpoints[0];
|
||||
},
|
||||
|
||||
onReturnButtonClick() {
|
||||
this.$router.back();
|
||||
}
|
||||
station: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const store = useMainStore();
|
||||
const apiStore = useApiStore();
|
||||
|
||||
const viewModes = [
|
||||
{
|
||||
id: 'scenery.option-active-timetables',
|
||||
component: SceneryTimetable
|
||||
},
|
||||
{
|
||||
id: 'scenery.option-timetables-history',
|
||||
component: SceneryTimetablesHistory
|
||||
},
|
||||
{
|
||||
id: 'scenery.option-dispatchers-history',
|
||||
component: SceneryDispatchersHistory
|
||||
}
|
||||
];
|
||||
|
||||
const currentMode = computed(() => {
|
||||
return route.query.view?.toString() ?? 'SceneryTimetable';
|
||||
});
|
||||
|
||||
const currentViewComponent = computed(() => {
|
||||
return (
|
||||
viewModes.find((mode) => mode.component.name == currentMode.value)?.component ??
|
||||
SceneryTimetable
|
||||
);
|
||||
});
|
||||
|
||||
const stationInfo = computed(() => {
|
||||
return store.stationList.find(
|
||||
(station) => station.name === props.station?.toString().replace(/_/g, ' ')
|
||||
);
|
||||
});
|
||||
|
||||
const onlineSceneryInfo = computed(() => {
|
||||
return store.activeSceneryList.find(
|
||||
(scenery) =>
|
||||
scenery.name === props.station?.toString().replace(/_/g, ' ') &&
|
||||
scenery.region == store.region.id
|
||||
);
|
||||
});
|
||||
|
||||
function setViewMode(componentName: string) {
|
||||
router.push({
|
||||
path: route.path,
|
||||
query: {
|
||||
...route.query,
|
||||
view: componentName
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use '../styles/responsive';
|
||||
|
||||
button.back-btn {
|
||||
img {
|
||||
width: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.scenery {
|
||||
&-view {
|
||||
display: flex;
|
||||
|
||||
@@ -3202,7 +3202,7 @@ sharp@*, sharp@^0.33.5:
|
||||
|
||||
showdown@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz"
|
||||
resolved "https://registry.yarnpkg.com/showdown/-/showdown-2.1.0.tgz#1251f5ed8f773f0c0c7bfc8e6fd23581f9e545c5"
|
||||
integrity sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==
|
||||
dependencies:
|
||||
commander "^9.0.0"
|
||||
|
||||
Reference in New Issue
Block a user