mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 05:18:11 +00:00
Cleanup i restrukturyzacja widoku scenerii
This commit is contained in:
@@ -1,189 +1,49 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scenery-info">
|
<div class="scenery-info">
|
||||||
<div class="info-header">
|
<!-- info header -->
|
||||||
<div class="scenery-name">
|
<scenery-info-header :station="station" />
|
||||||
<div v-if="station.generalInfo?.project" style="color: salmon; font-size: 0.6em; line-height: 0.7em;">
|
|
||||||
{{ station.generalInfo.project }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a v-if="station.generalInfo?.url" :href="station.generalInfo.url" target="_blank" rel="noopener noreferrer">{{
|
|
||||||
station.name
|
|
||||||
}}</a>
|
|
||||||
|
|
||||||
<span v-else>{{ station.name }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="scenery-hash" v-if="station.onlineInfo?.hash">#{{ station.onlineInfo.hash }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<section v-if="!timetableOnly">
|
<section v-if="!timetableOnly">
|
||||||
<div class="info-stats" :class="!station.onlineInfo ? 'no-stats' : ''">
|
<!-- info stats -->
|
||||||
<span class="likes">
|
<scenery-info-stats :station="station" />
|
||||||
<img :src="likeIcon" alt="icon-like" />
|
<!-- info icons -->
|
||||||
<span>{{ station.onlineInfo?.dispatcherRate || '0' }}</span>
|
<scenery-info-icons :station="station" />
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="users">
|
|
||||||
<img :src="userIcon" alt="icon-user" />
|
|
||||||
<span>{{ station.onlineInfo?.currentUsers || '0' }}</span>
|
|
||||||
/
|
|
||||||
<span>{{ station.onlineInfo?.maxUsers || '0' }}</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="spawns">
|
|
||||||
<img :src="spawnIcon" alt="icon-spawn" />
|
|
||||||
<span>{{ station.onlineInfo?.spawns.length || '0' }}</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="schedules">
|
|
||||||
<img :src="timetableIcon" alt="icon-timetable" />
|
|
||||||
<span>
|
|
||||||
<span style="color: #eee">{{ station.onlineInfo?.scheduledTrains?.length || '0' }}</span>
|
|
||||||
/
|
|
||||||
<span style="color: #bbb"
|
|
||||||
>{{ station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed).length || '0' }}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info-brief">
|
|
||||||
<img
|
|
||||||
v-if="station.generalInfo?.controlType"
|
|
||||||
:src="require(`@/assets/icon-${station.generalInfo.controlType}.svg`)"
|
|
||||||
:alt="station.generalInfo.controlType"
|
|
||||||
:title="$t('desc.control-type') + $t(`controls.${station.generalInfo.controlType}`)"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<img
|
|
||||||
v-if="station.generalInfo?.signalType"
|
|
||||||
:src="require(`@/assets/icon-${station.generalInfo.signalType}.svg`)"
|
|
||||||
:alt="station.generalInfo.signalType"
|
|
||||||
:title="$t('desc.signals-type') + $t(`signals.${station.generalInfo.signalType}`)"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<img
|
|
||||||
v-if="station.generalInfo && station.generalInfo.SBL !== ''"
|
|
||||||
:src="SBLIcon"
|
|
||||||
:alt="$t('desc.SBL') + `${station.generalInfo.SBL}`"
|
|
||||||
:title="$t('desc.SBL') + `${station.generalInfo.SBL}`"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<img
|
|
||||||
v-if="station.generalInfo && station.generalInfo.TWB !== ''"
|
|
||||||
:src="TWBIcon"
|
|
||||||
alt="two way route blockade"
|
|
||||||
:title="
|
|
||||||
`${
|
|
||||||
station.generalInfo.TWB === 'TAK' ? $t('desc.TWB-all') : $t('desc.TWB-routes') + station.generalInfo.TWB
|
|
||||||
}`
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<img v-if="station.generalInfo?.default" :src="td2Icon" alt="default scenery" :title="$t('desc.default')" />
|
|
||||||
|
|
||||||
<img
|
|
||||||
v-if="station.generalInfo?.nonPublic"
|
|
||||||
:src="lockIcon"
|
|
||||||
alt="non public scenery"
|
|
||||||
:title="$t('desc.non-public')"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<img
|
|
||||||
v-if="station.generalInfo?.unavailable"
|
|
||||||
:src="unavailableIcon"
|
|
||||||
alt="icon unavailable"
|
|
||||||
:title="$t('desc.unavailable')"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<img
|
|
||||||
v-if="station.generalInfo && station.generalInfo.lines != ''"
|
|
||||||
:src="realIcon"
|
|
||||||
alt="real scenery"
|
|
||||||
:title="`${$t('desc.real')} ${station.generalInfo.lines}`"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<img v-if="!station.generalInfo" :src="unknownIcon" alt="icon-unknown" :title="$t('desc.unknown')" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info-dispatcher">
|
|
||||||
<div class="dispatcher" v-if="station.onlineInfo">
|
|
||||||
<span
|
|
||||||
class="dispatcher_level"
|
|
||||||
:style="calculateExpStyle(station.onlineInfo.dispatcherExp, station.onlineInfo.dispatcherIsSupporter)"
|
|
||||||
>
|
|
||||||
{{ station.onlineInfo.dispatcherExp > 1 ? station.onlineInfo.dispatcherExp : 'L' }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="dispatcher_name">{{ station.onlineInfo.dispatcherName }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span class="status-badge" v-if="station.onlineInfo" :class="station.onlineInfo.statusID">
|
|
||||||
{{ $t(`status.${station.onlineInfo.statusID}`) }}
|
|
||||||
{{ station.onlineInfo.statusID == 'online' ? station.onlineInfo.statusTimeString : '' }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="status-badge free" v-else>
|
|
||||||
{{ $t('status.free') }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<!-- info dispatcher -->
|
||||||
|
<scenery-info-dispatcher :station="station" />
|
||||||
|
|
||||||
<div class="info-lists">
|
<div class="info-lists">
|
||||||
<div class="user-list">
|
<!-- user list -->
|
||||||
<h3 class="user-header">
|
<scenery-info-user-list :station="station" />
|
||||||
{{ $t('scenery.users') }}
|
|
||||||
<img :src="userIcon" alt="icon-user" />
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<div
|
<!-- spawn list -->
|
||||||
v-for="(train, i) in computedStationTrains"
|
<scenery-info-spawn-list :station="station" />
|
||||||
class="user"
|
|
||||||
:class="train.stopStatus"
|
|
||||||
:key="train.trainNo + i"
|
|
||||||
tabindex="0"
|
|
||||||
@click="() => navigateToTrain(train.trainNo)"
|
|
||||||
@keydown="(e) => { if(e.keyCode == 13) navigateToTrain(train.trainNo) }"
|
|
||||||
>
|
|
||||||
<span class="user_train">{{ train.trainNo }}</span>
|
|
||||||
<span class="user_name">{{ train.driverName }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="user offline" v-if="!computedStationTrains || computedStationTrains.length == 0">
|
|
||||||
{{ $t('scenery.no-users') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="spawn-list">
|
|
||||||
<h3 class="spawn-header">
|
|
||||||
{{ $t('scenery.spawns') }}
|
|
||||||
<img :src="spawnIcon" alt="icon-spawn" />
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<span v-if="station.onlineInfo">
|
|
||||||
<span
|
|
||||||
class="spawn"
|
|
||||||
v-for="(spawn, i) in station.onlineInfo.spawns"
|
|
||||||
:key="spawn.spawnName + station.onlineInfo?.dispatcherName + i"
|
|
||||||
>
|
|
||||||
<span class="spawn_name">{{ spawn.spawnName }}</span>
|
|
||||||
<span class="spawn_length">{{ spawn.spawnLength }}m</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="spawn none" v-if="!station.onlineInfo || station.onlineInfo.spawns.length == 0"
|
|
||||||
>{{ $t('scenery.no-spawns') }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Station from '@/scripts/interfaces/Station';
|
|
||||||
import styleMixin from '@/mixins/styleMixin';
|
|
||||||
import { computed, defineComponent } from '@vue/runtime-core';
|
import { computed, defineComponent } from '@vue/runtime-core';
|
||||||
|
|
||||||
|
import SceneryInfoDispatcher from './SceneryInfo/SceneryInfoDispatcher.vue';
|
||||||
|
import SceneryInfoIcons from './SceneryInfo/SceneryInfoIcons.vue';
|
||||||
|
import SceneryInfoStats from './SceneryInfo/SceneryInfoStats.vue';
|
||||||
|
import SceneryInfoHeader from './SceneryInfo/SceneryInfoHeader.vue';
|
||||||
|
import SceneryInfoUserList from './SceneryInfo/SceneryInfoUserList.vue';
|
||||||
|
import SceneryInfoSpawnList from './SceneryInfo/SceneryInfoSpawnList.vue';
|
||||||
|
|
||||||
|
import Station from '@/scripts/interfaces/Station';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
SceneryInfoDispatcher,
|
||||||
|
SceneryInfoIcons,
|
||||||
|
SceneryInfoStats,
|
||||||
|
SceneryInfoHeader,
|
||||||
|
SceneryInfoUserList,
|
||||||
|
SceneryInfoSpawnList,
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
station: {
|
station: {
|
||||||
type: Object as () => Station,
|
type: Object as () => Station,
|
||||||
@@ -192,63 +52,13 @@ export default defineComponent({
|
|||||||
|
|
||||||
timetableOnly: Boolean,
|
timetableOnly: Boolean,
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [styleMixin],
|
|
||||||
|
|
||||||
data: () => ({
|
|
||||||
likeIcon: require('@/assets/icon-like.svg'),
|
|
||||||
spawnIcon: require('@/assets/icon-spawn.svg'),
|
|
||||||
timetableIcon: require('@/assets/icon-timetable.svg'),
|
|
||||||
userIcon: require('@/assets/icon-user.svg'),
|
|
||||||
|
|
||||||
SBLIcon: require('@/assets/icon-SBL.svg'),
|
|
||||||
TWBIcon: require('@/assets/icon-2way-block.svg'),
|
|
||||||
td2Icon: require('@/assets/icon-td2.svg'),
|
|
||||||
lockIcon: require('@/assets/icon-lock.svg'),
|
|
||||||
unavailableIcon: require('@/assets/icon-unavailable.svg'),
|
|
||||||
unknownIcon: require('@/assets/icon-unknown.svg'),
|
|
||||||
|
|
||||||
realIcon: require('@/assets/icon-real.svg'),
|
|
||||||
}),
|
|
||||||
|
|
||||||
setup(props) {
|
|
||||||
const computedStationTrains = computed(() => {
|
|
||||||
if (!props.station) return [];
|
|
||||||
if (!props.station.onlineInfo) return [];
|
|
||||||
if (!props.station.onlineInfo.stationTrains) return [];
|
|
||||||
|
|
||||||
return props.station.onlineInfo.stationTrains.map((train) => {
|
|
||||||
const scheduledTrainStatus = props.station.onlineInfo?.scheduledTrains?.find(
|
|
||||||
(st) => st.trainNo === train.trainNo
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...train,
|
|
||||||
stopStatus: scheduledTrainStatus?.stopStatus || 'no-timetable',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return { computedStationTrains };
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
navigateToTrain(trainNo: number) {
|
|
||||||
this.$router.push({
|
|
||||||
name: 'TrainsView',
|
|
||||||
query: { train: trainNo.toString() },
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss">
|
||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
@import '../../styles/user_badge.scss';
|
|
||||||
@import '../../styles/variables.scss';
|
|
||||||
|
|
||||||
h3 {
|
h3.section-header {
|
||||||
margin: 0.5em 0;
|
margin: 0.5em 0;
|
||||||
padding: 0.3em;
|
padding: 0.3em;
|
||||||
|
|
||||||
@@ -264,123 +74,14 @@ h3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info-lists {
|
||||||
&-header {
|
display: flex;
|
||||||
padding: 2em 1em;
|
|
||||||
|
|
||||||
& > .scenery-name {
|
align-items: center;
|
||||||
font-weight: bold;
|
flex-direction: column;
|
||||||
color: $accentCol;
|
|
||||||
|
|
||||||
font-size: 3.5em;
|
|
||||||
|
|
||||||
text-transform: uppercase;
|
|
||||||
|
|
||||||
@include smallScreen() {
|
|
||||||
font-size: 2.75em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .scenery-hash {
|
|
||||||
line-height: 0.8em;
|
|
||||||
color: #aaa;
|
|
||||||
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-stats {
|
|
||||||
padding: 1rem 0;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
font-size: 1.65em;
|
|
||||||
|
|
||||||
&.no-stats {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
margin: 0.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.likes,
|
|
||||||
.spawns {
|
|
||||||
color: $accentCol;
|
|
||||||
}
|
|
||||||
|
|
||||||
span > img {
|
|
||||||
width: 1.2em;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-brief {
|
|
||||||
padding: 1em 0;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 3.5em;
|
|
||||||
margin: 0 0.5em;
|
|
||||||
|
|
||||||
border: 2px solid #4e4e4e;
|
|
||||||
border-radius: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-dispatcher {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
.dispatcher {
|
|
||||||
font-size: 2em;
|
|
||||||
|
|
||||||
&_level {
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 0.3em;
|
|
||||||
background: firebrick;
|
|
||||||
|
|
||||||
border-radius: 0.1em;
|
|
||||||
|
|
||||||
width: 1.5em;
|
|
||||||
height: 1.5em;
|
|
||||||
line-height: 1.5em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
&_name {
|
|
||||||
margin-right: 1em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-badge {
|
|
||||||
font-size: 1.2em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-lists {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
& > .user-list {
|
|
||||||
ul {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user,
|
.badge {
|
||||||
.spawn {
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -394,68 +95,18 @@ h3 {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 0.2em 0.4em;
|
padding: 0.2em 0.4em;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.user {
|
&-none {
|
||||||
cursor: pointer;
|
font-weight: 600;
|
||||||
|
|
||||||
&_train {
|
padding: 0.2em 0.4em;
|
||||||
color: black;
|
|
||||||
background-color: $no-timetable;
|
|
||||||
|
|
||||||
transition: background-color 200ms;
|
|
||||||
-ms-transition: background-color 200ms;
|
|
||||||
-webkit-transition: background-color 200ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.no-timetable .user_train {
|
|
||||||
background-color: $no-timetable;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.departed > &_train {
|
|
||||||
background-color: $departed;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.stopped > &_train {
|
|
||||||
background-color: $stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.online > &_train {
|
|
||||||
background-color: $online;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.terminated > &_train {
|
|
||||||
background-color: $terminated;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disconnected > &_train {
|
|
||||||
background-color: $disconnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.offline {
|
|
||||||
background: firebrick;
|
background: firebrick;
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.spawn {
|
text-align: center;
|
||||||
&_length {
|
|
||||||
background: $accentCol;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.spawn.none,
|
@include smallScreen() {
|
||||||
.user.offline {
|
font-size: 1em;
|
||||||
font-weight: 600;
|
}
|
||||||
|
|
||||||
padding: 0.2em 0.4em;
|
|
||||||
background: firebrick;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
@include smallScreen() {
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<section class="info-dispatcher">
|
||||||
|
<div class="dispatcher" v-if="station.onlineInfo">
|
||||||
|
<span
|
||||||
|
class="dispatcher_level"
|
||||||
|
:style="calculateExpStyle(station.onlineInfo.dispatcherExp, station.onlineInfo.dispatcherIsSupporter)"
|
||||||
|
>
|
||||||
|
{{ station.onlineInfo.dispatcherExp > 1 ? station.onlineInfo.dispatcherExp : 'L' }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="dispatcher_name">{{ station.onlineInfo.dispatcherName }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="status-badge" v-if="station.onlineInfo" :class="station.onlineInfo.statusID">
|
||||||
|
{{ $t(`status.${station.onlineInfo.statusID}`) }}
|
||||||
|
{{ station.onlineInfo.statusID == 'online' ? station.onlineInfo.statusTimeString : '' }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="status-badge free" v-else>
|
||||||
|
{{ $t('status.free') }}
|
||||||
|
</span>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
import styleMixin from '@/mixins/styleMixin';
|
||||||
|
import Station from '@/scripts/interfaces/Station';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
mixins: [styleMixin],
|
||||||
|
props: {
|
||||||
|
station: {
|
||||||
|
type: Object as () => Station,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data: () => ({
|
||||||
|
icons: {
|
||||||
|
spawn: require('@/assets/icon-spawn.svg'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.info-dispatcher {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.dispatcher {
|
||||||
|
font-size: 2em;
|
||||||
|
|
||||||
|
&_level {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 0.3em;
|
||||||
|
background: firebrick;
|
||||||
|
|
||||||
|
border-radius: 0.1em;
|
||||||
|
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_name {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<section class="info-header">
|
||||||
|
<div class="scenery-name">
|
||||||
|
<div v-if="station.generalInfo?.project" style="color: salmon; font-size: 0.6em; line-height: 0.7em;">
|
||||||
|
{{ station.generalInfo.project }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a v-if="station.generalInfo?.url" :href="station.generalInfo.url" target="_blank" rel="noopener noreferrer">{{
|
||||||
|
station.name
|
||||||
|
}}</a>
|
||||||
|
|
||||||
|
<span v-else>{{ station.name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="scenery-hash" v-if="station.onlineInfo?.hash">#{{ station.onlineInfo.hash }}</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
import Station from '@/scripts/interfaces/Station';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
station: {
|
||||||
|
type: Object as () => Station,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../../styles/variables.scss';
|
||||||
|
@import '../../../styles/responsive.scss';
|
||||||
|
|
||||||
|
|
||||||
|
.info-header {
|
||||||
|
padding: 2em 1em;
|
||||||
|
|
||||||
|
& > .scenery-name {
|
||||||
|
font-weight: bold;
|
||||||
|
color: $accentCol;
|
||||||
|
|
||||||
|
font-size: 3.5em;
|
||||||
|
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
@include smallScreen() {
|
||||||
|
font-size: 2.75em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .scenery-hash {
|
||||||
|
line-height: 0.8em;
|
||||||
|
color: #aaa;
|
||||||
|
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<section class="info-icons">
|
||||||
|
<img
|
||||||
|
v-if="station.generalInfo?.controlType"
|
||||||
|
:src="require(`@/assets/icon-${station.generalInfo.controlType}.svg`)"
|
||||||
|
:alt="station.generalInfo.controlType"
|
||||||
|
:title="$t('desc.control-type') + $t(`controls.${station.generalInfo.controlType}`)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<img
|
||||||
|
v-if="station.generalInfo?.signalType"
|
||||||
|
:src="require(`@/assets/icon-${station.generalInfo.signalType}.svg`)"
|
||||||
|
:alt="station.generalInfo.signalType"
|
||||||
|
:title="$t('desc.signals-type') + $t(`signals.${station.generalInfo.signalType}`)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<img
|
||||||
|
v-if="station.generalInfo && station.generalInfo.SBL !== ''"
|
||||||
|
:src="icons.SBL"
|
||||||
|
:alt="$t('desc.SBL') + `${station.generalInfo.SBL}`"
|
||||||
|
:title="$t('desc.SBL') + `${station.generalInfo.SBL}`"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<img
|
||||||
|
v-if="station.generalInfo && station.generalInfo.TWB !== ''"
|
||||||
|
:src="icons.TWB"
|
||||||
|
alt="two way route blockade"
|
||||||
|
:title="
|
||||||
|
`${station.generalInfo.TWB === 'TAK' ? $t('desc.TWB-all') : $t('desc.TWB-routes') + station.generalInfo.TWB}`
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<img v-if="station.generalInfo?.default" :src="icons.td2" alt="default scenery" :title="$t('desc.default')" />
|
||||||
|
|
||||||
|
<img
|
||||||
|
v-if="station.generalInfo?.nonPublic"
|
||||||
|
:src="icons.lock"
|
||||||
|
alt="non public scenery"
|
||||||
|
:title="$t('desc.non-public')"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<img
|
||||||
|
v-if="station.generalInfo?.unavailable"
|
||||||
|
:src="icons.unavailable"
|
||||||
|
alt="icon unavailable"
|
||||||
|
:title="$t('desc.unavailable')"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<img
|
||||||
|
v-if="station.generalInfo && station.generalInfo.lines != ''"
|
||||||
|
:src="icons.real"
|
||||||
|
alt="real scenery"
|
||||||
|
:title="`${$t('desc.real')} ${station.generalInfo.lines}`"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<img v-if="!station.generalInfo" :src="icons.unknown" alt="icon-unknown" :title="$t('desc.unknown')" />
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
import Station from '@/scripts/interfaces/Station';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
station: {
|
||||||
|
type: Object as () => Station,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data: () => ({
|
||||||
|
icons: {
|
||||||
|
SBL: require('@/assets/icon-SBL.svg'),
|
||||||
|
TWB: require('@/assets/icon-2way-block.svg'),
|
||||||
|
td2: require('@/assets/icon-td2.svg'),
|
||||||
|
lock: require('@/assets/icon-lock.svg'),
|
||||||
|
unavailable: require('@/assets/icon-unavailable.svg'),
|
||||||
|
unknown: require('@/assets/icon-unknown.svg'),
|
||||||
|
|
||||||
|
real: require('@/assets/icon-real.svg'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.info-icons {
|
||||||
|
padding: 1em 0;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 3.5em;
|
||||||
|
margin: 0 0.5em;
|
||||||
|
|
||||||
|
border: 2px solid #4e4e4e;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<section class="info-spawn-list">
|
||||||
|
<h3 class="spawn-header section-header">
|
||||||
|
{{ $t('scenery.spawns') }}
|
||||||
|
<img :src="icons.spawn" alt="icon-spawn" />
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<span v-if="station.onlineInfo">
|
||||||
|
<span
|
||||||
|
class="badge spawn"
|
||||||
|
v-for="(spawn, i) in station.onlineInfo.spawns"
|
||||||
|
:key="spawn.spawnName + station.onlineInfo?.dispatcherName + i"
|
||||||
|
>
|
||||||
|
<span class="spawn_name">{{ spawn.spawnName }}</span>
|
||||||
|
<span class="spawn_length">{{ spawn.spawnLength }}m</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="badge spawn badge-none" v-if="!station.onlineInfo || station.onlineInfo.spawns.length == 0"
|
||||||
|
>{{ $t('scenery.no-spawns') }}
|
||||||
|
</span>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Station from '@/scripts/interfaces/Station';
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
station: {
|
||||||
|
type: Object as () => Station,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data: () => ({
|
||||||
|
icons: {
|
||||||
|
spawn: require('@/assets/icon-spawn.svg'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../../styles/variables.scss';
|
||||||
|
|
||||||
|
.spawn {
|
||||||
|
&_length {
|
||||||
|
background: $accentCol;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
<template>
|
||||||
|
<section class="info-stats" :class="!station.onlineInfo ? 'no-stats' : ''">
|
||||||
|
<span class="likes">
|
||||||
|
<img :src="icons.like" alt="icon-like" />
|
||||||
|
<span>{{ station.onlineInfo?.dispatcherRate || '0' }}</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="users">
|
||||||
|
<img :src="icons.user" alt="icon-user" />
|
||||||
|
<span>{{ station.onlineInfo?.currentUsers || '0' }}</span>
|
||||||
|
/
|
||||||
|
<span>{{ station.onlineInfo?.maxUsers || '0' }}</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="spawns">
|
||||||
|
<img :src="icons.spawn" alt="icon-spawn" />
|
||||||
|
<span>{{ station.onlineInfo?.spawns.length || '0' }}</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="schedules">
|
||||||
|
<img :src="icons.timetable" alt="icon-timetable" />
|
||||||
|
<span>
|
||||||
|
<span style="color: #eee">{{ station.onlineInfo?.scheduledTrains?.length || '0' }}</span>
|
||||||
|
/
|
||||||
|
<span style="color: #bbb"
|
||||||
|
>{{ station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed).length || '0' }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
import Station from '@/scripts/interfaces/Station';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
station: {
|
||||||
|
type: Object as () => Station,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data: () => ({
|
||||||
|
icons: {
|
||||||
|
like: require('@/assets/icon-like.svg'),
|
||||||
|
timetable: require('@/assets/icon-timetable.svg'),
|
||||||
|
user: require('@/assets/icon-user.svg'),
|
||||||
|
spawn: require('@/assets/icon-spawn.svg'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../../styles/variables.scss';
|
||||||
|
|
||||||
|
.info-stats {
|
||||||
|
padding: 1rem 0;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
font-size: 1.65em;
|
||||||
|
|
||||||
|
&.no-stats {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
margin: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.likes,
|
||||||
|
.spawns {
|
||||||
|
color: $accentCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
span > img {
|
||||||
|
width: 1.2em;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
<template>
|
||||||
|
<section class="info-user-list">
|
||||||
|
<h3 class="user-header section-header">
|
||||||
|
{{ $t('scenery.users') }}
|
||||||
|
<img :src="icons.user" alt="icon-user" />
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-for="(train, i) in computedStationTrains"
|
||||||
|
class="badge user"
|
||||||
|
:class="train.stopStatus"
|
||||||
|
:key="train.trainNo + i"
|
||||||
|
tabindex="0"
|
||||||
|
@click="() => navigateToTrain(train.trainNo)"
|
||||||
|
@keydown.enter="navigateToTrain(train.trainNo)"
|
||||||
|
>
|
||||||
|
<span class="user_train">{{ train.trainNo }}</span>
|
||||||
|
<span class="user_name">{{ train.driverName }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="badge user badge-none" v-if="!computedStationTrains || computedStationTrains.length == 0">
|
||||||
|
{{ $t('scenery.no-users') }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Station from '@/scripts/interfaces/Station';
|
||||||
|
import { computed, defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
station: {
|
||||||
|
type: Object as () => Station,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props) {
|
||||||
|
const computedStationTrains = computed(() => {
|
||||||
|
if (!props.station) return [];
|
||||||
|
if (!props.station.onlineInfo) return [];
|
||||||
|
if (!props.station.onlineInfo.stationTrains) return [];
|
||||||
|
|
||||||
|
return props.station.onlineInfo.stationTrains.map((train) => {
|
||||||
|
const scheduledTrainStatus = props.station.onlineInfo?.scheduledTrains?.find(
|
||||||
|
(st) => st.trainNo === train.trainNo
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...train,
|
||||||
|
stopStatus: scheduledTrainStatus?.stopStatus || 'no-timetable',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return { computedStationTrains };
|
||||||
|
},
|
||||||
|
|
||||||
|
data: () => ({
|
||||||
|
icons: {
|
||||||
|
user: require('@/assets/icon-user.svg'),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
navigateToTrain(trainNo: number) {
|
||||||
|
this.$router.push({
|
||||||
|
name: 'TrainsView',
|
||||||
|
query: { train: trainNo.toString() },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
$no-timetable: #aaa;
|
||||||
|
$departed: springgreen;
|
||||||
|
$stopped: #ffa600;
|
||||||
|
$online: gold;
|
||||||
|
$terminated: red;
|
||||||
|
$disconnected: slategray;
|
||||||
|
|
||||||
|
.info-user-list {
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&_train {
|
||||||
|
color: black;
|
||||||
|
background-color: $no-timetable;
|
||||||
|
|
||||||
|
transition: background-color 200ms;
|
||||||
|
-ms-transition: background-color 200ms;
|
||||||
|
-webkit-transition: background-color 200ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no-timetable .user_train {
|
||||||
|
background-color: $no-timetable;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.departed > &_train {
|
||||||
|
background-color: $departed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.stopped > &_train {
|
||||||
|
background-color: $stopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.online > &_train {
|
||||||
|
background-color: $online;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.terminated > &_train {
|
||||||
|
background-color: $terminated;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disconnected > &_train {
|
||||||
|
background-color: $disconnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.offline {
|
||||||
|
background: firebrick;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -35,11 +35,7 @@
|
|||||||
:key="i + 1"
|
:key="i + 1"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@click="navigateToTrain(scheduledTrain.trainNo)"
|
@click="navigateToTrain(scheduledTrain.trainNo)"
|
||||||
@keydown="
|
@keydown.enter="navigateToTrain(scheduledTrain.trainNo)"
|
||||||
(e) => {
|
|
||||||
if (e.keyCode == 13) navigateToTrain(scheduledTrain.trainNo);
|
|
||||||
}
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<span class="timetable-general">
|
<span class="timetable-general">
|
||||||
<span class="general-info">
|
<span class="general-info">
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
v-for="(station, i) in stations"
|
v-for="(station, i) in stations"
|
||||||
:key="i + station.name"
|
:key="i + station.name"
|
||||||
@click="() => setScenery(station.name)"
|
@click="() => setScenery(station.name)"
|
||||||
@keydown="(e) => { if(e.keyCode == 13) setScenery(station.name) }"
|
@keydown.enter="setScenery(station.name)"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<td
|
<td
|
||||||
|
|||||||
@@ -18,17 +18,9 @@
|
|||||||
v-for="(train, i) in computedTrains"
|
v-for="(train, i) in computedTrains"
|
||||||
:key="i"
|
:key="i"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@keydown="
|
@keydown.enter="changeScheduleShowState(train.timetableData?.timetableId)"
|
||||||
(e) => {
|
|
||||||
if (e.keyCode == 13) changeScheduleShowState(train.timetableData?.timetableId);
|
:ref="el => registerReference(el, train.timetableData?.timetableId)"
|
||||||
}
|
|
||||||
"
|
|
||||||
:ref="
|
|
||||||
(el) => {
|
|
||||||
if (!train.timetableData) return;
|
|
||||||
elList[train.timetableData.timetableId] = el;
|
|
||||||
}
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<div class="wrapper" @click="changeScheduleShowState(train.timetableData?.timetableId)">
|
<div class="wrapper" @click="changeScheduleShowState(train.timetableData?.timetableId)">
|
||||||
<span class="info">
|
<span class="info">
|
||||||
@@ -268,6 +260,10 @@ export default defineComponent({
|
|||||||
}, 10);
|
}, 10);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
registerReference(el: HTMLElement, timetableId: number | undefined) {
|
||||||
|
if(timetableId) this.elList[timetableId] = el;
|
||||||
|
},
|
||||||
|
|
||||||
focusOnTrain(trainNoStr: string) {
|
focusOnTrain(trainNoStr: string) {
|
||||||
const timetableId = this.computedTrains.find((train) => train.trainNo == Number(trainNoStr))?.timetableData
|
const timetableId = this.computedTrains.find((train) => train.trainNo == Number(trainNoStr))?.timetableData
|
||||||
?.timetableId;
|
?.timetableId;
|
||||||
@@ -335,7 +331,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import '../../styles/responsive.scss';
|
@import '../../styles/responsive.scss';
|
||||||
@import '../../styles/user_badge.scss';
|
|
||||||
|
|
||||||
.unfold {
|
.unfold {
|
||||||
&-leave-active,
|
&-leave-active,
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
$no-timetable: #aaa;
|
|
||||||
$departed: springgreen;
|
|
||||||
$stopped: #ffa600;
|
|
||||||
$online: gold;
|
|
||||||
$terminated: red;
|
|
||||||
$disconnected: slategray;
|
|
||||||
|
|
||||||
|
|
||||||
.user-badge {
|
|
||||||
border: 2px solid white;
|
|
||||||
z-index: 4;
|
|
||||||
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
|
|
||||||
border-radius: 0.7em;
|
|
||||||
padding: 0.3em 0.5em;
|
|
||||||
font-size: 0.95em;
|
|
||||||
|
|
||||||
&.borderless {
|
|
||||||
border: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.no-timetable {
|
|
||||||
border: 2px solid $no-timetable;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: $no-timetable;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.departed {
|
|
||||||
border: 2px solid $departed;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.stopped {
|
|
||||||
border: 2px solid $stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.online {
|
|
||||||
border: 2px solid $online;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.terminated {
|
|
||||||
border: 2px solid $terminated;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disconnected {
|
|
||||||
border: 1px solid $disconnected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user