Dodano historię dyżurów do widoku scenerii

This commit is contained in:
2022-01-10 03:12:08 +01:00
parent 9c66afc9de
commit 53842ec3be
5 changed files with 184 additions and 76 deletions
@@ -31,12 +31,11 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
@import '../../../styles/variables.scss';
@import '../../../styles/responsive.scss';
@import '../../styles/variables.scss';
@import '../../styles/responsive.scss';
.info-header {
padding: 2em 1em;
padding-top: 2em;
& > .scenery-name {
font-weight: bold;
+118 -16
View File
@@ -3,10 +3,29 @@
<h2>HISTORIA DYŻURÓW</h2>
<ul>
<li v-for="(dispatcher, i) in dispatcherHistory" :key="i">
{{ dispatcher.dispatcherName }}
&nbsp;
{{ timestampToString(dispatcher.dispatcherFrom) }}
<li v-for="(timeline, i) in dispatcherTimeline" :key="i">
<h3
@click="toggleTimeline(i)"
@keydown.enter="toggleTimeline(i)"
@keydown.space="toggleTimeline(i)"
tabindex="0"
>
{{ timeline.date }} <img :src="icons.descArrow" alt="" />
</h3>
<span v-if="timeline.showTimeline">
<div v-for="dispatcher in timeline.dispatchers" :key="dispatcher.dispatcherFrom">
<span>
<span class="dispatcher-from text--primary">
{{ timestampToString(dispatcher.dispatcherFrom, true) }}
</span>
>
<span class="dispatcher-to text--primary"> {{ timestampToString(dispatcher.dispatcherTo, true) }}</span>
</span>
<b>{{ dispatcher.dispatcherName }}</b>
</div>
</span>
</li>
</ul>
</div>
@@ -16,6 +35,12 @@
import axios from 'axios';
import { defineComponent } from 'vue';
interface DispatcherTimeline {
date: string;
dispatchers: DispatcherHistory[];
showTimeline: boolean;
}
interface DispatcherHistory {
dispatcherName: string;
dispatcherId: number;
@@ -38,15 +63,17 @@ interface HistoryResultAPI {
errorMessage?: any;
}
const PROD_MODE = true;
const API_URL = PROD_MODE
? 'https://stacjownik-api-di22o.ondigitalocean.app/api/getSceneryHistory'
: 'http://localhost:3001/api/getTimetables';
const API_URL = 'https://stacjownik-api-di22o.ondigitalocean.app/api/getSceneryHistory';
export default defineComponent({
data: () => ({
dispatcherHistory: [] as DispatcherHistory[],
dispatcherTimeline: [] as DispatcherTimeline[],
icons: {
ascArrow: require('@/assets/icon-arrow-asc.svg'),
descArrow: require('@/assets/icon-arrow-desc.svg'),
},
}),
props: {
name: {
@@ -62,18 +89,42 @@ export default defineComponent({
try {
const apiResult: HistoryResultAPI = (await axios.get(`${API_URL}?name=${this.name}`)).data;
if (!apiResult.errorMessage) this.dispatcherHistory = apiResult.result.dispatcherHistory;
if (!apiResult.errorMessage) {
this.dispatcherHistory = apiResult.result.dispatcherHistory;
this.dispatcherTimeline = this.dispatcherHistory
.reduce((acc, dispatcher) => {
const dateStr = new Date(dispatcher.dispatcherFrom).toLocaleDateString('pl-PL').replace(/\./g, '/');
const timelineDay = acc.find((timeline) => timeline.date == dateStr) || {
date: dateStr,
dispatchers: [],
showTimeline: false,
};
timelineDay.dispatchers.push(dispatcher);
if (!acc.find((timeline) => timeline.date == dateStr)) acc.push(timelineDay);
return acc;
}, [] as DispatcherTimeline[])
.reverse();
}
} catch (error) {
console.error(error);
console.error(error);
}
},
methods: {
timestampToString: (timestamp: number): string =>
toggleTimeline(index: number) {
this.dispatcherTimeline[index].showTimeline = !this.dispatcherTimeline[index].showTimeline;
},
timestampToString: (timestamp: number, timeOnly = false): string =>
new Date(timestamp).toLocaleTimeString('pl-PL', {
day: '2-digit',
month: '2-digit',
year: '2-digit',
day: timeOnly ? undefined : '2-digit',
month: timeOnly ? undefined : '2-digit',
year: timeOnly ? undefined : '2-digit',
hour: '2-digit',
minute: '2-digit',
}),
@@ -81,4 +132,55 @@ export default defineComponent({
});
</script>
<style scoped></style>
<style lang="scss" scoped>
.scenery-history {
max-height: 600px;
overflow-y: scroll;
}
ul {
margin-top: 1em;
}
li {
margin: 1em 0;
h3 {
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
background: #444;
padding: 0.5em;
margin: 0 auto 0.5em auto;
max-width: 700px;
img {
width: 1.3em;
vertical-align: middle;
margin-left: 0.5em;
}
&:focus {
outline: 1px solid white;
}
}
div {
padding: 0.5em 0;
margin: 0.5em auto;
background-color: #444;
border-radius: 0.5em;
display: grid;
grid-template-columns: repeat(2, 1fr);
max-width: 400px;
}
}
</style>
+1 -6
View File
@@ -1,8 +1,5 @@
<template>
<div class="scenery-info">
<!-- info header -->
<scenery-info-header :station="station" />
<section v-if="!timetableOnly">
<!-- info stats -->
<scenery-info-stats :station="station" />
@@ -24,12 +21,11 @@
</template>
<script lang="ts">
import { computed, defineComponent } from '@vue/runtime-core';
import { 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';
@@ -40,7 +36,6 @@ export default defineComponent({
SceneryInfoDispatcher,
SceneryInfoIcons,
SceneryInfoStats,
SceneryInfoHeader,
SceneryInfoUserList,
SceneryInfoSpawnList,
},
@@ -17,6 +17,7 @@
<span class="stop-name">
<span v-html="stop.stopName"></span>
<img v-if="stop.comments" :src="icons.warning" :title="`${$t('trains.comment')}: ${stop.comments}`">
{{ decodeURIComponent(stop.comments) }}
</span>
<span class="stop-date">
<span
+61 -50
View File
@@ -1,80 +1,83 @@
<template>
<div class="scenery-view">
<div
class="scenery-offline"
v-if="!stationInfo && isDataLoaded && isComponentVisible"
>
<div>{{ $t("scenery.no-scenery") }}</div>
<div class="scenery-offline" v-if="!stationInfo && isDataLoaded && isComponentVisible">
<div>{{ $t('scenery.no-scenery') }}</div>
<action-button>
<router-link to="/">{{ $t("scenery.return-btn") }}</router-link>
<router-link to="/">{{ $t('scenery.return-btn') }}</router-link>
</action-button>
</div>
<div class="scenery-wrapper" v-if="stationInfo">
<!-- <button class="history-btn btn btn--image">
<img :src="icons.history" alt="History icon">
</button> -->
<SceneryInfo :station="stationInfo" :timetableOnly="timetableOnly" />
<div class="scenery-wrapper" v-if="stationInfo" ref="card-wrapper">
<!-- <scenery-info-header :station="stationInfo" /> -->
<SceneryHeader :station="stationInfo" />
<div v-if="viewMode == 'info'">
<button v-if="!timetableOnly" class="history-btn btn btn--image" @click="setCardViewMode('history')" title="Widok historii dyżurnych ruchu">
<img :src="icons.history" alt="History icon" />
</button>
<SceneryInfo :station="stationInfo" :timetableOnly="timetableOnly" />
<SceneryTimetable :station="stationInfo" :timetableOnly="timetableOnly" />
</div>
<div v-else-if="viewMode == 'history'">
<button class="history-btn btn btn--image" @click="setCardViewMode('info')">
<img :src="icons.user" alt="History icon" />
</button>
<SceneryHistory :name="stationInfo.name" />
</div>
<SceneryTimetable
:station="stationInfo"
:timetableOnly="timetableOnly"
/>
<!-- <SceneryHistory :name="stationInfo.name" /> -->
</div>
</div>
</template>
<script lang="ts">
import { StoreData } from "@/scripts/interfaces/StoreData";
import { DataStatus } from "@/scripts/enums/DataStatus";
import { StoreData } from '@/scripts/interfaces/StoreData';
import { DataStatus } from '@/scripts/enums/DataStatus';
import SceneryInfo from "@/components/SceneryView/SceneryInfo.vue";
import SceneryTimetable from "@/components/SceneryView/SceneryTimetable.vue";
import SceneryHistory from "@/components/SceneryView/SceneryHistory.vue"
import SceneryInfo from '@/components/SceneryView/SceneryInfo.vue';
import SceneryTimetable from '@/components/SceneryView/SceneryTimetable.vue';
import SceneryHistory from '@/components/SceneryView/SceneryHistory.vue';
import SceneryHeader from "@/components/SceneryView/SceneryHeader.vue";
import ActionButton from "@/components/Global/ActionButton.vue";
import ActionButton from '@/components/Global/ActionButton.vue';
import { computed, ComputedRef, defineComponent } from "@vue/runtime-core";
import { useStore } from "@/store";
import { GETTERS } from "@/constants/storeConstants";
import { useRoute } from "vue-router";
import { computed, ComputedRef, defineComponent } from '@vue/runtime-core';
import { useStore } from '@/store';
import { GETTERS } from '@/constants/storeConstants';
import { useRoute } from 'vue-router';
export default defineComponent({
components: { SceneryInfo, SceneryTimetable, SceneryHistory, ActionButton },
components: { SceneryInfo, SceneryTimetable, SceneryHistory, ActionButton, SceneryHeader },
data: () => ({
icons: {
history: require("@/assets/icon-history.svg")
}
history: require('@/assets/icon-history.svg'),
user: require('@/assets/icon-user.svg'),
},
cardHeight: 0,
viewMode: 'info',
}),
setup() {
const route = useRoute();
const store = useStore();
const data: ComputedRef<StoreData> = computed(
() => store.getters[GETTERS.allData]
);
const data: ComputedRef<StoreData> = computed(() => store.getters[GETTERS.allData]);
const timetableOnly = computed(() =>
route.query["timetable_only"] == "1" ? true : false
);
const timetableOnly = computed(() => (route.query['timetable_only'] == '1' ? true : false));
const isComponentVisible = computed(() => route.path === "/scenery");
const isComponentVisible = computed(() => route.path === '/scenery');
const isDataLoaded = computed(
() => data.value.dataConnectionStatus === DataStatus.Loaded
);
const isDataLoaded = computed(() => data.value.dataConnectionStatus === DataStatus.Loaded);
const stationInfo = computed(() =>
data.value.stationList.find(
(station) =>
station.name ===
route.query.station?.toString().replace(/_/g, " ")
)
data.value.stationList.find((station) => station.name === route.query.station?.toString().replace(/_/g, ' '))
);
return {
@@ -85,12 +88,22 @@ export default defineComponent({
stationInfo,
};
},
methods: {
setCardViewMode(mode: string) {
this.viewMode = mode;
},
},
mounted() {
this.cardHeight = (this.$refs['card-wrapper'] as HTMLElement).getBoundingClientRect().height;
}
});
</script>
<style lang="scss" scoped>
@import "../styles/responsive.scss";
@import "../styles/variables.scss";
@import '../styles/responsive.scss';
@import '../styles/variables.scss';
$sceneryBgCol: #333;
@@ -148,7 +161,5 @@ button.history-btn {
img {
width: 2em;
}
}
</style>
</style>