mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 21:38:13 +00:00
feature: stations stats
This commit is contained in:
@@ -29,11 +29,6 @@
|
|||||||
<img src="/images/icon-dispatcher.svg" alt="icon dispatcher" />
|
<img src="/images/icon-dispatcher.svg" alt="icon dispatcher" />
|
||||||
<span class="text--primary">{{ onlineDispatchersCount }}</span>
|
<span class="text--primary">{{ onlineDispatchersCount }}</span>
|
||||||
|
|
||||||
<!-- <span class="g-tooltip">
|
|
||||||
<b class="text--primary">{{ factorU }}U</b>
|
|
||||||
<div class="content">Test</div>
|
|
||||||
</span> -->
|
|
||||||
|
|
||||||
<span class="text--grayed"> / </span>
|
<span class="text--grayed"> / </span>
|
||||||
<span class="text--primary">{{ onlineTrainsCount }}</span>
|
<span class="text--primary">{{ onlineTrainsCount }}</span>
|
||||||
<img src="/images/icon-train.svg" alt="icon train" />
|
<img src="/images/icon-train.svg" alt="icon train" />
|
||||||
@@ -103,12 +98,6 @@ export default defineComponent({
|
|||||||
return this.store.activeSceneryList.filter(
|
return this.store.activeSceneryList.filter(
|
||||||
(scenery) => scenery.region == this.store.region.id && scenery.dispatcherId != -1
|
(scenery) => scenery.region == this.store.region.id && scenery.dispatcherId != -1
|
||||||
).length;
|
).length;
|
||||||
},
|
|
||||||
|
|
||||||
factorU() {
|
|
||||||
return this.onlineDispatchersCount == 0
|
|
||||||
? '-'
|
|
||||||
: (this.onlineTrainsCount / this.onlineDispatchersCount).toFixed(2);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: { StatusIndicator, Clock, RegionDropdown }
|
components: { StatusIndicator, Clock, RegionDropdown }
|
||||||
|
|||||||
@@ -405,13 +405,6 @@ export default defineComponent({
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.g-tooltip > .content {
|
|
||||||
z-index: 100;
|
|
||||||
color: white;
|
|
||||||
|
|
||||||
left: 110%;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 1.1em;
|
width: 1.1em;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ export default defineComponent({
|
|||||||
$rowCol: #424242;
|
$rowCol: #424242;
|
||||||
|
|
||||||
.station_table {
|
.station_table {
|
||||||
height: 90vh;
|
height: calc(100vh - 150px);
|
||||||
min-height: 550px;
|
min-height: 550px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
<template>
|
||||||
|
<div class="stations-stats">
|
||||||
|
<div class="separator" />
|
||||||
|
<div>
|
||||||
|
Współczynnik Ugla
|
||||||
|
<a
|
||||||
|
href="https://td2.info.pl/dyskusje/wspolczynnik-ugla-czy-to-ma-sens/msg81011/#msg81011"
|
||||||
|
target="_blank"
|
||||||
|
data-tooltip="(?) Współczynnik ruchu na serwerze (liczba maszynistów online dzielona na liczbę dyżurnych ruchu)"
|
||||||
|
>(?)</a
|
||||||
|
>:
|
||||||
|
<b :style="calculateFactorStyle()">
|
||||||
|
{{ uFactor.toFixed(2) }}
|
||||||
|
</b>
|
||||||
|
| Średnia liczba rozkładów jazdy na dyżurnego:
|
||||||
|
<b>{{ avgTimetableCount.toFixed(2) }}</b>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Dostępne szlaki 1-torowe:
|
||||||
|
<b>{{ trackCount.oneWayElectric }}</b> (zelektr.) /
|
||||||
|
<b>{{ trackCount.oneWayOther }}</b> (niezelektr.) | Dostępne szlaki 2-torowe:
|
||||||
|
<b>{{ trackCount.twoWayElectric }}</b> (zelektr.) /
|
||||||
|
<b>{{ trackCount.twoWayOther }}</b> (niezelektr.) | Otwarte spawny:
|
||||||
|
<b>{{ spawnCount.passenger }}</b> - PAS / <b>{{ spawnCount.freight }}</b> - TOW /
|
||||||
|
<b>{{ spawnCount.loco }}</b> - LUZ / <b>{{ spawnCount.all }}</b> - ALL
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { useMainStore } from '../../store/mainStore';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
mainStore: useMainStore()
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
calculateFactorStyle() {
|
||||||
|
if (this.uFactor == 0) return '';
|
||||||
|
|
||||||
|
const norm = this.uFactor == 0 ? 1 : Math.max(Math.min(1 / this.uFactor / 2, 1), 0);
|
||||||
|
const lerp = 120 * norm;
|
||||||
|
|
||||||
|
return `color: hsl(${lerp}, 100%, 60%)`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
uFactor() {
|
||||||
|
const activeDispatchers = this.mainStore.activeSceneryList.filter(
|
||||||
|
(scenery) => scenery.region == this.mainStore.region.id && scenery.dispatcherId != -1
|
||||||
|
);
|
||||||
|
|
||||||
|
const activeTrains = this.mainStore.trainList.filter(
|
||||||
|
(train) => train.region == this.mainStore.region.id
|
||||||
|
);
|
||||||
|
|
||||||
|
return activeDispatchers.length != 0 ? activeTrains.length / activeDispatchers.length : 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
avgTimetableCount() {
|
||||||
|
const scheduledTrainsTotal = this.mainStore.activeSceneryList.reduce<number>((acc, sc) => {
|
||||||
|
if (sc.region != this.mainStore.region.id) return acc;
|
||||||
|
|
||||||
|
acc += sc.scheduledTrainCount.all;
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
return this.mainStore.activeSceneryList.length != 0
|
||||||
|
? scheduledTrainsTotal / this.mainStore.activeSceneryList.length
|
||||||
|
: 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
trackCount() {
|
||||||
|
return this.mainStore.allStationInfo
|
||||||
|
.filter(
|
||||||
|
(st) =>
|
||||||
|
st.onlineInfo?.dispatcherId != -1 &&
|
||||||
|
st.onlineInfo?.region == this.mainStore.region.id &&
|
||||||
|
st.generalInfo?.routes
|
||||||
|
)
|
||||||
|
.reduce(
|
||||||
|
(acc, st) => {
|
||||||
|
[...st.generalInfo!.routes.single, ...st.generalInfo!.routes.double].forEach((r) => {
|
||||||
|
if (r.isInternal) return;
|
||||||
|
|
||||||
|
const keyName: keyof typeof acc = `${r.routeTracks == 2 ? 'twoWay' : 'oneWay'}${r.isElectric ? 'Electric' : 'Other'}`;
|
||||||
|
|
||||||
|
acc[keyName] += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{ oneWayElectric: 0, oneWayOther: 0, twoWayElectric: 0, twoWayOther: 0 }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
spawnCount() {
|
||||||
|
return this.mainStore.activeSceneryList.reduce(
|
||||||
|
(acc, scenery) => {
|
||||||
|
scenery.spawns.forEach((spawn) => {
|
||||||
|
if (/EZT|POS|OSOB/i.test(spawn.spawnName)) acc['passenger'] += 1;
|
||||||
|
if (/TOW/i.test(spawn.spawnName)) acc['freight'] += 1;
|
||||||
|
if (/LUZ/i.test(spawn.spawnName)) acc['loco'] += 1;
|
||||||
|
if (/ALL/i.test(spawn.spawnName)) acc['all'] += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{ passenger: 0, freight: 0, loco: 0, all: 0 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.separator {
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stations-stats {
|
||||||
|
text-align: center;
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-factor-low='true'] {
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-factor-mediocre='true'] {
|
||||||
|
color: lightgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-factor-high='true'] {
|
||||||
|
color: greenyellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-factor-highest='true'] {
|
||||||
|
color: rgb(22, 245, 22);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -32,10 +32,7 @@ export const useMainStore = defineStore('mainStore', {
|
|||||||
modalLastClickedTarget: null,
|
modalLastClickedTarget: null,
|
||||||
|
|
||||||
mousePos: { x: 0, y: 0 },
|
mousePos: { x: 0, y: 0 },
|
||||||
popUpData: { key: null, content: '' },
|
popUpData: { key: null, content: '' }
|
||||||
|
|
||||||
stations: [] as Station[],
|
|
||||||
trainsOnline: [] as Train[]
|
|
||||||
}) as MainStoreState,
|
}) as MainStoreState,
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ export interface MainStoreState {
|
|||||||
modalLastClickedTarget: EventTarget | null;
|
modalLastClickedTarget: EventTarget | null;
|
||||||
mousePos: { x: number; y: number };
|
mousePos: { x: number; y: number };
|
||||||
popUpData: { key: PopUpType | null; content: string };
|
popUpData: { key: PopUpType | null; content: string };
|
||||||
stations: Station[];
|
|
||||||
trainsOnline: Train[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StationJSONData {
|
export interface StationJSONData {
|
||||||
|
|||||||
@@ -298,3 +298,23 @@ a.a-button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Basic tooltip
|
||||||
|
[data-tooltip]:hover::after,
|
||||||
|
[data-tooltip]:focus::after {
|
||||||
|
position: absolute;
|
||||||
|
transform: translate(10px, -50%);
|
||||||
|
|
||||||
|
content: attr(data-tooltip);
|
||||||
|
color: white;
|
||||||
|
background-color: #171717;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
padding: 0.5em;
|
||||||
|
margin: 0 0.25em;
|
||||||
|
max-width: 300px;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-tooltip] {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,13 +22,7 @@
|
|||||||
<Donation :isModalOpen="isDonationModalOpen" @toggleModal="toggleDonationModal" />
|
<Donation :isModalOpen="isDonationModalOpen" @toggleModal="toggleDonationModal" />
|
||||||
<StationTable @toggleDonationModal="toggleDonationModal" />
|
<StationTable @toggleDonationModal="toggleDonationModal" />
|
||||||
|
|
||||||
<div class="stations-stats">
|
<StationsStats />
|
||||||
<hr style="margin: 0.5em 0" />
|
|
||||||
Średnia liczba rozkładów jazdy na dyżurnego: <b>{{ avgTimetableCount }}</b> | Dostępne
|
|
||||||
szlaki 1-torowe: <b>{{ oneWayTracks }}</b> (zelektr.) / <b>{{ 0 }}</b> (spalinowe) |
|
|
||||||
Dostępne szlaki 2-torowe: <b>{{ 0 }}</b> (zelektr.) / <b>{{ 0 }}</b> (spalinowe) | Otwarte
|
|
||||||
spawny: <b>{{ 0 }}</b> (PAS.) / <b>{{ 0 }}</b> (TOW.) / <b>{{ 0 }}</b> (LUZ.)
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
@@ -40,56 +34,28 @@ import StationFilterCard from '../components/StationsView/StationFilterCard.vue'
|
|||||||
import { useStationFiltersStore } from '../store/stationFiltersStore';
|
import { useStationFiltersStore } from '../store/stationFiltersStore';
|
||||||
import { useMainStore } from '../store/mainStore';
|
import { useMainStore } from '../store/mainStore';
|
||||||
import Donation from '../components/Global/Donation.vue';
|
import Donation from '../components/Global/Donation.vue';
|
||||||
|
import StationsStats from '../components/StationsView/StationsStats.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
StationTable,
|
StationTable,
|
||||||
StationFilterCard,
|
StationFilterCard,
|
||||||
|
StationsStats,
|
||||||
Donation
|
Donation
|
||||||
},
|
},
|
||||||
|
|
||||||
data: () => ({
|
data: () => ({
|
||||||
filterCardOpen: false,
|
filterCardOpen: false,
|
||||||
modalHidden: true,
|
isDonationModalOpen: false,
|
||||||
STORAGE_KEY: 'options_saved',
|
|
||||||
focusedStationName: '',
|
|
||||||
filterStore: useStationFiltersStore(),
|
|
||||||
store: useMainStore(),
|
|
||||||
|
|
||||||
isDonationModalOpen: false
|
filterStore: useStationFiltersStore(),
|
||||||
|
store: useMainStore()
|
||||||
}),
|
}),
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.filterStore.setupFilters();
|
this.filterStore.setupFilters();
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
|
||||||
avgTimetableCount() {
|
|
||||||
const scheduledTrainsTotal = this.store.activeSceneryList.reduce<number>((acc, sc) => {
|
|
||||||
if (sc.region != 'eu') return acc;
|
|
||||||
|
|
||||||
acc += sc.scheduledTrainCount.all;
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
return (
|
|
||||||
this.store.activeSceneryList.length != 0
|
|
||||||
? scheduledTrainsTotal / this.store.activeSceneryList.length
|
|
||||||
: 0
|
|
||||||
).toFixed(2);
|
|
||||||
},
|
|
||||||
|
|
||||||
oneWayTracks() {
|
|
||||||
// return this.computedStationList
|
|
||||||
// .filter((st) => st.onlineInfo && st.generalInfo?.routes.single)
|
|
||||||
// .map((st) => st.generalInfo!.routes.single.map((r) => r.routeName))
|
|
||||||
// .join(', ');
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
toggleDonationModal(value: boolean) {
|
toggleDonationModal(value: boolean) {
|
||||||
this.isDonationModalOpen = value;
|
this.isDonationModalOpen = value;
|
||||||
@@ -102,30 +68,6 @@ export default defineComponent({
|
|||||||
@import '../styles/variables.scss';
|
@import '../styles/variables.scss';
|
||||||
@import '../styles/responsive.scss';
|
@import '../styles/responsive.scss';
|
||||||
|
|
||||||
@keyframes blinkAnim {
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.indicator-anim {
|
|
||||||
&-enter-active,
|
|
||||||
&-leave-active {
|
|
||||||
transition: all 0.25s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-enter,
|
|
||||||
&-leave-to {
|
|
||||||
transform: translateY(100%);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.stations-view {
|
.stations-view {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -148,11 +90,6 @@ export default defineComponent({
|
|||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stations-stats {
|
|
||||||
text-align: center;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn-donation {
|
button.btn-donation {
|
||||||
$btnColor: #254069;
|
$btnColor: #254069;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user