restrukturyzacja storów

This commit is contained in:
2023-12-09 16:18:23 +01:00
parent 59f4a0cb66
commit 39c3cf2329
34 changed files with 301 additions and 305 deletions
+1 -1
View File
@@ -31,7 +31,7 @@
// CONTAINER
.app_container {
display: grid;
grid-template-rows: auto minmax(100vh, 1fr) auto;
grid-template-rows: auto 1fr auto;
grid-template-columns: 100%;
min-height: 100vh;
+7 -7
View File
@@ -39,12 +39,13 @@ import Clock from './components/App/Clock.vue';
import packageInfo from '.././package.json';
import { regions } from './data/options.json';
import { useStore } from './store/mainStore';
import { useMainStore } from './store/mainStore';
import StatusIndicator from './components/App/StatusIndicator.vue';
import TrainModal from './components/Global/TrainModal.vue';
import AppHeader from './components/App/AppHeader.vue';
import axios from 'axios';
import StorageManager from './managers/storageManager';
import { useApiStore } from './store/apiStore';
export default defineComponent({
components: {
@@ -56,7 +57,8 @@ export default defineComponent({
data: () => ({
VERSION: packageInfo.version,
store: useStore(),
store: useMainStore(),
apiStore: useApiStore(),
currentLang: 'pl',
releaseURL: '',
@@ -65,17 +67,15 @@ export default defineComponent({
created() {
this.loadLang();
this.store.setupAPI();
this.apiStore.setupAPI();
this.store.isOffline = !window.navigator.onLine;
window.addEventListener('offline', () => {
this.store.isOffline = true;
this.apiStore.activeData = undefined;
this.store.activeData.activeSceneries = [];
this.store.activeData.trains = [];
this.store.setStatuses();
this.apiStore.setDataStatuses();
});
window.addEventListener('online', () => {
+2 -2
View File
@@ -68,7 +68,7 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import StatusIndicator from './StatusIndicator.vue';
import Clock from './Clock.vue';
import RegionDropdown from '../Global/RegionDropdown.vue';
@@ -84,7 +84,7 @@ export default defineComponent({
setup() {
return {
store: useStore()
store: useMainStore()
};
},
+6 -5
View File
@@ -194,9 +194,9 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { StoreState } from '../../store/typings';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import { Status } from '../../typings/common';
import { useApiStore } from '../../store/apiStore';
export default defineComponent({
data() {
@@ -221,10 +221,11 @@ export default defineComponent({
},
setup() {
const store = useStore();
const store = useMainStore();
const apiStore = useApiStore();
return {
dataStatus: store.dataStatuses,
dataStatus: apiStore.dataStatuses,
store
};
},
@@ -233,7 +234,7 @@ export default defineComponent({
dataStatus: {
deep: true,
handler(statuses: StoreState['dataStatuses']) {
handler(statuses: any) {
const connectionStatus = statuses.connection;
const sceneryDataStatus = statuses.sceneries;
const trainsDataStatus = statuses.trains;
+2 -2
View File
@@ -12,7 +12,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
export default defineComponent({
emits: ['toggleModal'],
@@ -23,7 +23,7 @@ export default defineComponent({
data() {
return {
store: useStore()
store: useMainStore()
};
},
+2 -2
View File
@@ -30,7 +30,7 @@
<script lang="ts">
import { defineComponent, Ref, ref } from 'vue';
import { regions as regionsJSON } from '../../data/options.json';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
interface Item {
id: string;
@@ -41,7 +41,7 @@ interface Item {
export default defineComponent({
data() {
return {
store: useStore(),
store: useMainStore(),
selectedItemIndex: 0,
listOpen: false
};
+4 -4
View File
@@ -50,8 +50,8 @@
<script lang="ts">
import { PropType, defineComponent } from 'vue';
import { useStore } from '../../store/mainStore';
import { API } from '../../typings/api';
import { useApiStore } from '../../store/apiStore';
export default defineComponent({
props: {
@@ -63,15 +63,15 @@ export default defineComponent({
data() {
return {
store: useStore()
apiStore: useApiStore()
};
},
methods: {
onImageError(event: Event, stockName: string) {
const fallbackName =
Object.keys(this.store.rollingStockData!.info).find((type) => {
return this.store.rollingStockData!.info[type as keyof API.RollingStock.Info].find(
Object.keys(this.apiStore.rollingStockData!.info).find((type) => {
return this.apiStore.rollingStockData!.info[type as keyof API.RollingStock.Info].find(
(v) => v[0] === stockName.split(':')[0]
);
}) || 'vehicle-unknown';
+5 -5
View File
@@ -16,8 +16,8 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { useStore } from '../../store/mainStore';
import { API } from '../../typings/api';
import { useApiStore } from '../../store/apiStore';
export default defineComponent({
props: {
@@ -34,7 +34,7 @@ export default defineComponent({
data() {
return {
store: useStore(),
apiStore: useApiStore(),
isNotFound: false,
isLoaded: false
};
@@ -50,11 +50,11 @@ export default defineComponent({
},
stockType() {
if (!this.store.rollingStockData) return 'vehicle-unknown';
if (!this.apiStore.rollingStockData) return 'vehicle-unknown';
return (
Object.keys(this.store.rollingStockData.info).find((type) => {
return this.store.rollingStockData?.info[type as keyof API.RollingStock.Info].find(
Object.keys(this.apiStore.rollingStockData.info).find((type) => {
return this.apiStore.rollingStockData?.info[type as keyof API.RollingStock.Info].find(
(v) => v[0] === this.name.split(':')[0]
);
}) || 'vehicle-unknown'
@@ -53,7 +53,7 @@
import axios from 'axios';
import { defineComponent } from 'vue';
import { URLs } from '../../scripts/utils/apiURLs';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import Loading from '../Global/Loading.vue';
import { API } from '../../typings/api';
@@ -61,7 +61,7 @@ export default defineComponent({
components: { Loading },
setup() {
const store = useStore();
const store = useMainStore();
return {
store
@@ -193,7 +193,7 @@ export default defineComponent({
if (this.intervalId != -1) return;
this.intervalId = setInterval(this.fetchDailyTimetableStats, 60000);
this.intervalId = window.setInterval(this.fetchDailyTimetableStats, 60000);
},
stopFetchingDailyStats() {
@@ -125,7 +125,7 @@
import { defineComponent, PropType } from 'vue';
import dateMixin from '../../mixins/dateMixin';
import styleMixin from '../../mixins/styleMixin';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import Loading from '../Global/Loading.vue';
import { regions } from '../../data/options.json';
import AddDataButton from '../Global/AddDataButton.vue';
@@ -160,7 +160,7 @@ export default defineComponent({
data() {
return {
Status,
store: useStore(),
store: useMainStore(),
regions
};
},
@@ -55,7 +55,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import { Status } from '../../typings/common';
export default defineComponent({
@@ -63,7 +63,7 @@ export default defineComponent({
data() {
return {
store: useStore(),
store: useMainStore(),
Status: Status
};
}
@@ -114,7 +114,7 @@ import axios from 'axios';
import { defineComponent, inject, PropType } from 'vue';
import keyMixin from '../../mixins/keyMixin';
import { URLs } from '../../scripts/utils/apiURLs';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import { Journal } from './typings';
import { API } from '../../typings/api';
import { Status } from '../../typings/common';
@@ -158,7 +158,7 @@ export default defineComponent({
dispatcherSuggestions: [] as string[],
searchTimeout: 0,
store: useStore(),
store: useMainStore(),
JournalFilterSection: Journal.FilterSection
};
@@ -238,7 +238,7 @@ export default defineComponent({
window.clearTimeout(this.searchTimeout);
this.searchTimeout = setTimeout(async () => {
this.searchTimeout = window.setTimeout(async () => {
try {
const suggestions: string[] = await (
await axios.get(`${URLs.stacjownikAPI}/api/get${type}Suggestions?name=${value}`)
+2 -2
View File
@@ -28,14 +28,14 @@
<script setup lang="ts">
import { computed, onMounted, reactive, Ref, ref, watch } from 'vue';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import JournalDailyStats from './JournalDailyStats.vue';
import JournalDriverStats from './JournalDriverStats.vue';
import StorageManager from '../../managers/storageManager';
export type JournalStatsTab = 'journal-driver-stats' | 'journal-daily-stats';
const store = useStore();
const store = useMainStore();
const currentStatsTab: Ref<JournalStatsTab | null> = ref(null);
let data = reactive({
@@ -42,7 +42,7 @@ import { defineComponent, PropType } from 'vue';
import Loading from '../../Global/Loading.vue';
import AddDataButton from '../../Global/AddDataButton.vue';
import TimetableHistoryList from './TimetableHistoryList.vue';
import { useStore } from '../../../store/mainStore';
import { useMainStore } from '../../../store/mainStore';
import { Status } from '../../../typings/common';
import { API } from '../../../typings/api';
@@ -71,7 +71,7 @@ export default defineComponent({
data() {
return {
Status,
store: useStore()
store: useMainStore()
};
}
});
@@ -48,7 +48,7 @@
<transition-group name="list-anim">
<div
style="padding-bottom: 5em"
v-if="store.dataStatuses.trains == 0 && computedScheduledTrains.length == 0"
v-if="apiStore.dataStatuses.trains == 0 && computedScheduledTrains.length == 0"
key="list-loading"
>
<Loading />
@@ -187,10 +187,11 @@ import Loading from '../Global/Loading.vue';
import dateMixin from '../../mixins/dateMixin';
import routerMixin from '../../mixins/routerMixin';
import Station from '../../scripts/interfaces/Station';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import modalTrainMixin from '../../mixins/modalTrainMixin';
import ScheduledTrainStatus from './ScheduledTrainStatus.vue';
import { OnlineScenery } from '../../store/typings';
import { useApiStore } from '../../store/apiStore';
export default defineComponent({
name: 'SceneryTimetable',
@@ -224,7 +225,8 @@ export default defineComponent({
const route = useRoute();
const currentURL = computed(() => `${location.origin}${route.fullPath}`);
const store = useStore();
const apiStore = useApiStore();
const mainStore = useMainStore();
const chosenCheckpoint = ref(
props.station?.generalInfo?.checkpoints?.length == 0
@@ -235,7 +237,8 @@ export default defineComponent({
return {
currentURL,
chosenCheckpoint,
store
apiStore,
mainStore
};
},
@@ -256,7 +259,7 @@ export default defineComponent({
(train) =>
train.checkpointName.toLocaleLowerCase() ==
(this.chosenCheckpoint || this.station!.name).toLocaleLowerCase() &&
train.region == this.store.region.id
train.region == this.mainStore.region.id
)
.sort((a, b) => {
if (a.stopStatusID > b.stopStatusID) return 1;
@@ -139,7 +139,7 @@ import { defineComponent, inject } from 'vue';
import keyMixin from '../../mixins/keyMixin';
import routerMixin from '../../mixins/routerMixin';
import { useStationFiltersStore } from '../../store/stationFiltersStore';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import FilterOption from './FilterOption.vue';
import StorageManager from '../../managers/storageManager';
@@ -163,7 +163,7 @@ export default defineComponent({
setup() {
const isVisible = inject('isFilterCardVisible');
const store = useStore();
const store = useMainStore();
const filterStore = useStationFiltersStore();
return {
+9 -6
View File
@@ -116,7 +116,7 @@
<td class="station_dispatcher-name">
<span v-if="station.onlineInfo?.dispatcherName">
<b
v-if="store.donatorsData.includes(station.onlineInfo.dispatcherName)"
v-if="apiStore.donatorsData.includes(station.onlineInfo.dispatcherName)"
:title="$t('donations.dispatcher-message')"
@click.stop="openDonationModal"
>
@@ -294,11 +294,12 @@ import stationInfoMixin from '../../mixins/stationInfoMixin';
import styleMixin from '../../mixins/styleMixin';
import Station from '../../scripts/interfaces/Station';
import { useStationFiltersStore } from '../../store/stationFiltersStore';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import Loading from '../Global/Loading.vue';
import { HeadIdsTypes, headIconsIds, headIds } from '../../scripts/data/stationHeaderNames';
import StationStatusBadge from '../Global/StationStatusBadge.vue';
import { Status } from '../../typings/common';
import { useApiStore } from '../../store/apiStore';
export default defineComponent({
props: {
@@ -325,17 +326,19 @@ export default defineComponent({
},
setup() {
const store = useStore();
const mainStore = useMainStore();
const apiStore = useApiStore();
const stationFiltersStore = useStationFiltersStore();
const isDataLoaded = computed(() => {
return store.dataStatuses.sceneries != Status.Data.Loading;
return apiStore.dataStatuses.sceneries != Status.Data.Loading;
});
return {
isDataLoaded,
stationFiltersStore,
store
mainStore,
apiStore
};
},
@@ -357,7 +360,7 @@ export default defineComponent({
openDonationModal(e: Event) {
this.$emit('toggleDonationModal', true);
this.store.modalLastClickedTarget = e.target;
this.mainStore.modalLastClickedTarget = e.target;
},
openForumSite(e: Event, url: string | undefined) {
+5 -3
View File
@@ -35,7 +35,7 @@
<div class="train-driver">
<b
v-if="store.donatorsData.includes(train.driverName)"
v-if="apiStore.donatorsData.includes(train.driverName)"
:title="$t('donations.driver-message')"
>
{{ train.driverName }}
@@ -126,7 +126,8 @@ import trainInfoMixin from '../../mixins/trainInfoMixin';
import Train from '../../scripts/interfaces/Train';
import ProgressBar from '../Global/ProgressBar.vue';
import TrainThumbnail from '../Global/TrainThumbnail.vue';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import { useApiStore } from '../../store/apiStore';
export default defineComponent({
mixins: [trainInfoMixin, styleMixin],
@@ -145,7 +146,8 @@ export default defineComponent({
data() {
return {
store: useStore()
store: useMainStore(),
apiStore: useApiStore()
};
}
});
+2 -2
View File
@@ -72,7 +72,7 @@
import { computed, defineComponent, PropType } from 'vue';
import dateMixin from '../../mixins/dateMixin';
import Train from '../../scripts/interfaces/Train';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import StopDate from '../Global/StopDate.vue';
import StockList from '../Global/StockList.vue';
import { TrainStop } from '../../store/typings';
@@ -92,7 +92,7 @@ export default defineComponent({
setup(props) {
return {
store: useStore(),
store: useMainStore(),
lastConfirmed: computed(() => {
return props.train.timetableData!.followingStops.findIndex(
+6 -4
View File
@@ -16,7 +16,7 @@
<hr style="margin: 0.5em 0" />
<div v-if="store.dataStatuses.trains == Status.Loaded && regionTrains.length > 0">
<div v-if="apiStore.dataStatuses.trains == Status.Loaded && regionTrains.length > 0">
<div class="top-list general">
<transition-group tag="ul" name="stats-anim">
<li class="badge" key="timetable-count">
@@ -88,7 +88,7 @@
</div>
</div>
<div v-else-if="store.dataStatuses.trains != Status.Loaded">
<div v-else-if="apiStore.dataStatuses.trains != Status.Loaded">
{{ $t('train-stats.stats-loading') }}
</div>
@@ -102,8 +102,9 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import { Status } from '../../typings/common';
import { useApiStore } from '../../store/apiStore';
interface ITop {
name: string;
@@ -127,7 +128,8 @@ export default defineComponent({
data() {
return {
showOptions: false,
store: useStore(),
store: useMainStore(),
apiStore: useApiStore(),
Status: Status.Data
};
},
+9 -6
View File
@@ -1,16 +1,16 @@
<template>
<transition name="status-anim" mode="out-in" tag="div" class="train-table">
<div :key="store.dataStatuses.trains">
<div :key="apiStore.dataStatuses.trains">
<div class="table-info" key="offline" v-if="store.isOffline">
{{ $t('app.offline') }}
</div>
<Loading v-else-if="trains.length == 0 && store.dataStatuses.trains == 0" key="loading" />
<Loading v-else-if="trains.length == 0 && apiStore.dataStatuses.trains == 0" key="loading" />
<div
class="table-info"
key="no-trains"
v-else-if="trains.length == 0 && store.dataStatuses.trains != 0"
v-else-if="trains.length == 0 && apiStore.dataStatuses.trains != 0"
>
{{ $t('trains.no-trains') }}
</div>
@@ -35,10 +35,11 @@
import { defineComponent, inject, PropType, Ref } from 'vue';
import modalTrainMixin from '../../mixins/modalTrainMixin';
import Train from '../../scripts/interfaces/Train';
import { useStore } from '../../store/mainStore';
import { useMainStore } from '../../store/mainStore';
import Loading from '../Global/Loading.vue';
import TrainInfo from './TrainInfo.vue';
import { Status } from '../../typings/common';
import { useApiStore } from '../../store/apiStore';
export default defineComponent({
components: { Loading, TrainInfo },
@@ -53,7 +54,8 @@ export default defineComponent({
mixins: [modalTrainMixin],
setup() {
const store = useStore();
const store = useMainStore();
const apiStore = useApiStore();
const searchedTrain = inject('searchedTrain') as Ref<string>;
const searchedDriver = inject('searchedDriver') as Ref<string>;
@@ -61,6 +63,7 @@ export default defineComponent({
searchedTrain,
searchedDriver,
store,
apiStore,
sorterActive: inject('sorterActive') as {
id: string | number;
dir: number;
@@ -72,7 +75,7 @@ export default defineComponent({
dataStatus() {
if (this.store.isOffline) return Status.Data.Offline;
if (this.trains.length == 0 && this.store.dataStatuses.trains == Status.Data.Loading)
if (this.trains.length == 0 && this.apiStore.dataStatuses.trains == Status.Data.Loading)
return Status.Data.Loading;
return Status.Data.Loaded;
+10
View File
@@ -0,0 +1,10 @@
import axios from 'axios';
const http = axios.create({
baseURL:
import.meta.env.VITE_API_MODE === 'development'
? 'http://localhost:3001'
: 'https://stacjownik.spythere.eu'
});
export default http;
+3 -3
View File
@@ -1,16 +1,16 @@
import { defineComponent } from 'vue';
import { useStore } from '../store/mainStore';
import { useApiStore } from '../store/apiStore';
export default defineComponent({
data() {
return {
store: useStore()
apiStore: useApiStore()
};
},
methods: {
isDonator(name: string) {
return this.store.donatorsData.includes(name);
return this.apiStore.donatorsData.includes(name);
}
}
});
+2 -2
View File
@@ -1,10 +1,10 @@
import { defineComponent } from 'vue';
import { useStore } from '../store/mainStore';
import { useMainStore } from '../store/mainStore';
export default defineComponent({
data() {
return {
store: useStore()
store: useMainStore()
};
},
+114
View File
@@ -0,0 +1,114 @@
import { defineStore } from 'pinia';
import http from '../http';
import { API } from '../typings/api';
import axios from 'axios';
import { Status } from '../typings/common';
import { StationJSONData } from './typings';
export const useApiStore = defineStore('apiStore', {
state: () => ({
dataStatuses: {
connection: Status.Data.Loading,
sceneries: Status.Data.Loading,
timetables: Status.Data.Loading,
dispatchers: Status.Data.Loading,
trains: Status.Data.Loading
},
activeData: undefined as API.ActiveData.Response | undefined,
rollingStockData: undefined as API.RollingStock.Response | undefined,
donatorsData: [] as API.Donators.Response,
sceneryData: [] as StationJSONData[]
}),
actions: {
async setupAPI() {
// Static data
this.fetchStockInfoData();
this.fetchDonatorsData();
this.fetchStationsGeneralInfo();
this.scheduleFetchActiveData();
},
async setDataStatuses() {
if (!this.activeData?.activeSceneries) {
this.dataStatuses.sceneries = Status.Data.Error;
this.dataStatuses.trains = Status.Data.Error;
this.dataStatuses.dispatchers = Status.Data.Error;
return;
}
this.dataStatuses.sceneries = Status.Data.Loaded;
this.dataStatuses.trains = !this.activeData.trains ? Status.Data.Warning : Status.Data.Loaded;
this.dataStatuses.dispatchers = Status.Data.Loaded;
},
async fetchDonatorsData() {
try {
const response = await http.get<API.Donators.Response>('api/getDonators');
this.donatorsData = response.data;
} catch (error) {
console.error('Ups! Wystąpił błąd podczas pobierania informacji o donatorach:', error);
}
},
async fetchStockInfoData() {
try {
this.rollingStockData = (
await axios.get<API.RollingStock.Response>(
'https://raw.githubusercontent.com/Spythere/api/main/td2/data/stockInfo.json'
)
).data;
} catch (error) {
console.error('Ups! Wystąpił błąd podczas pobierania informacji o taborze z API:', error);
}
},
async scheduleFetchActiveData() {
if (import.meta.env.VITE_API_MODE === 'mock') {
const mockActiveData = await import('../data/mockActiveData.json');
this.dataStatuses.connection = Status.Data.Loaded;
this.activeData = mockActiveData;
this.setDataStatuses();
console.warn('Stacjownik działa w trybie mockowania danych z WS');
return;
}
try {
const data = (await http.get<API.ActiveData.Response>('api/getActiveData')).data;
this.activeData = data;
this.dataStatuses.connection = Status.Data.Loaded;
this.setDataStatuses();
} catch (error) {
this.dataStatuses.connection = Status.Data.Error;
console.error('Wystąpił błąd podczas pobierania danych online z API!');
} finally {
setTimeout(
() => {
this.scheduleFetchActiveData();
},
~~(1000 * (Math.random() * (25 - 20) + 25))
);
}
},
async fetchStationsGeneralInfo() {
const sceneryData: StationJSONData[] = (await http.get<StationJSONData[]>('api/getSceneries'))
.data;
if (!sceneryData) {
this.dataStatuses.sceneries = Status.Data.Error;
return;
}
this.sceneryData = sceneryData;
}
}
});
+71 -183
View File
@@ -1,37 +1,20 @@
import axios from 'axios';
import { defineStore } from 'pinia';
import StationRoutes from '../scripts/interfaces/StationRoutes';
import Train from '../scripts/interfaces/Train';
import { URLs } from '../scripts/utils/apiURLs';
import { parseSpawns, getScheduledTrains, getStationTrains } from './utils';
import { OnlineScenery, ScheduledTrain, StationJSONData, StoreState } from './typings';
import { OnlineScenery, ScheduledTrain, StoreState } from './typings';
import { API } from '../typings/api';
import { Status } from '../typings/common';
import Station from '../scripts/interfaces/Station';
import { useApiStore } from './apiStore';
import { API } from '../typings/api';
const API_INTERVAL_MS = 20000;
export const useStore = defineStore('store', {
export const useMainStore = defineStore('store', {
state: () =>
({
activeData: {} as unknown,
rollingStockData: undefined,
donatorsData: [],
stationList: [],
regionOnlineCounters: [],
routesList: [],
sceneryData: [],
lastDispatcherStatuses: [],
region: { id: 'eu', value: 'PL1' },
trainCount: 0,
stationCount: 0,
isOffline: false,
dispatcherStatsName: '',
@@ -43,29 +26,15 @@ export const useStore = defineStore('store', {
chosenModalTrainId: undefined,
dataStatuses: {
connection: Status.Data.Loading,
sceneries: Status.Data.Loading,
timetables: Status.Data.Loading,
dispatchers: Status.Data.Loading,
trains: Status.Data.Loading
},
blockScroll: false,
listenerLaunched: false,
modalLastClickedTarget: null,
tooltip: {
content: '',
visible: false,
x: 0,
y: 0
}
modalLastClickedTarget: null
}) as StoreState,
getters: {
trainList(): Train[] {
return (this.activeData?.trains ?? [])
const apiStore = useApiStore();
return (apiStore.activeData?.trains ?? [])
.filter((train) => train.timetable || train.online)
.map((train) => {
const stock = train.stockString.split(';');
@@ -116,10 +85,12 @@ export const useStore = defineStore('store', {
},
onlineSceneryList(state): OnlineScenery[] {
if (state.isOffline) return [];
if (!state.activeData?.activeSceneries) return [];
const apiStore = useApiStore();
return state.activeData?.activeSceneries.reduce((list, scenery) => {
if (state.isOffline) return [];
if (!apiStore.activeData?.activeSceneries) return [];
return apiStore.activeData?.activeSceneries.reduce((list, scenery) => {
if (scenery.isOnline !== 1 && Date.now() - scenery.lastSeen > 1000 * 60 * 2) return list;
if (scenery.dispatcherStatus == Status.ActiveDispatcher.UNKNOWN) return list;
@@ -178,13 +149,67 @@ export const useStore = defineStore('store', {
return list;
}, [] as OnlineScenery[]);
},
stationList(): Station[] {
const apiStore = useApiStore();
return apiStore.sceneryData.map((scenery) => {
return {
name: scenery.name,
generalInfo: {
...scenery,
authors: scenery.authors?.split(',').map((a) => a.trim()),
routes:
scenery.routesInfo.reduce(
(acc, route) => {
const propName: keyof StationRoutes = `${
route.routeTracks == 2 ? 'twoWay' : 'oneWay'
}${route.isElectric ? '' : 'No'}CatenaryRouteNames`;
acc[route.routeTracks == 2 ? 'twoWay' : 'oneWay'].push({
name: route.routeName,
SBL: route.isRouteSBL,
TWB: false,
catenary: route.isElectric,
isInternal: route.isInternal,
tracks: route.routeTracks,
length: route.routeLength,
speed: route.routeSpeed
});
if (!route.isInternal) acc[propName].push(route.routeName);
if (route.isRouteSBL) acc['sblRouteNames'].push(route.routeName);
return acc;
},
{
oneWay: [],
twoWay: [],
sblRouteNames: [],
oneWayCatenaryRouteNames: [],
oneWayNoCatenaryRouteNames: [],
twoWayCatenaryRouteNames: [],
twoWayNoCatenaryRouteNames: []
} as StationRoutes
) || {},
checkpoints: scenery.checkpoints
? scenery.checkpoints
.split(';')
.map((sub) => ({ checkpointName: sub, scheduledTrains: [] }))
: []
}
};
});
}
},
actions: {
async processStationsOnlineInfo() {
if (!this.activeData.activeSceneries) return;
async processStationsOnlineInfo(activeData: API.ActiveData.Response) {
if (!activeData.activeSceneries) return;
const onlineSceneries = this.activeData.activeSceneries.reduce((acc, scenery) => {
const onlineSceneries = activeData.activeSceneries.reduce((acc, scenery) => {
const savedStation = this.stationList.find((st) => scenery.stationName === st.name);
if (scenery.isOnline !== 1 && Date.now() - scenery.lastSeen > 1000 * 60 * 2) return acc;
@@ -266,146 +291,9 @@ export const useStore = defineStore('store', {
)
.forEach((station) => (station.onlineInfo = undefined));
},
async fetchStationsGeneralInfo() {
const sceneryData: StationJSONData[] = await (
await axios.get(`${URLs.stacjownikAPI}/api/getSceneries`)
).data;
if (!sceneryData) {
this.dataStatuses.sceneries = Status.Data.Error;
return;
}
this.stationList = sceneryData.map((scenery) => {
return {
name: scenery.name,
generalInfo: {
...scenery,
authors: scenery.authors?.split(',').map((a) => a.trim()),
routes:
scenery.routesInfo.reduce(
(acc, route) => {
const propName: keyof StationRoutes = `${
route.routeTracks == 2 ? 'twoWay' : 'oneWay'
}${route.isElectric ? '' : 'No'}CatenaryRouteNames`;
acc[route.routeTracks == 2 ? 'twoWay' : 'oneWay'].push({
name: route.routeName,
SBL: route.isRouteSBL,
TWB: false,
catenary: route.isElectric,
isInternal: route.isInternal,
tracks: route.routeTracks,
length: route.routeLength,
speed: route.routeSpeed
});
if (!route.isInternal) acc[propName].push(route.routeName);
if (route.isRouteSBL) acc['sblRouteNames'].push(route.routeName);
return acc;
},
{
oneWay: [],
twoWay: [],
sblRouteNames: [],
oneWayCatenaryRouteNames: [],
oneWayNoCatenaryRouteNames: [],
twoWayCatenaryRouteNames: [],
twoWayNoCatenaryRouteNames: []
} as StationRoutes
) || {},
checkpoints: scenery.checkpoints
? scenery.checkpoints
.split(';')
.map((sub) => ({ checkpointName: sub, scheduledTrains: [] }))
: []
}
};
});
},
async fetchActiveData() {
if (import.meta.env.VITE_APP_API_MODE === 'mock') {
const mockActiveData = await import('../data/mockActiveData.json');
this.dataStatuses.connection = Status.Data.Loaded;
this.activeData = mockActiveData;
this.setStatuses();
console.warn('Stacjownik działa w trybie mockowania danych z WS');
return;
}
try {
const data = (
await axios.get<API.ActiveData.Response>(`${URLs.stacjownikAPI}/api/getActiveData`)
).data;
this.activeData = data;
this.dataStatuses.connection = Status.Data.Loaded;
this.setStatuses();
} catch (error) {
this.dataStatuses.connection = Status.Data.Error;
console.error('Wystąpił błąd podczas pobierania danych online z API!');
}
},
async setupAPI() {
this.fetchActiveData();
setInterval(() => {
this.fetchActiveData();
}, API_INTERVAL_MS);
this.fetchStockInfoData();
this.fetchDonatorsData();
this.fetchStationsGeneralInfo();
},
async changeRegion(region: StoreState['region']) {
this.region = region;
},
async fetchStockInfoData() {
try {
this.rollingStockData = (
await axios.get<API.RollingStock.Response>(
'https://raw.githubusercontent.com/Spythere/api/main/td2/data/stockInfo.json'
)
).data;
} catch (error) {
console.error('Ups! Wystąpił błąd podczas pobierania informacji o taborze z API:', error);
}
},
async fetchDonatorsData() {
try {
const response = await axios.get<API.Donators.Response>(
`${URLs.stacjownikAPI}/api/getDonators`
);
if (response.data) this.donatorsData = response.data;
} catch (error) {
console.error('Ups! Wystąpił błąd podczas pobierania informacji o donatorach:', error);
}
},
async setStatuses() {
if (!this.activeData.activeSceneries) {
this.dataStatuses.sceneries = Status.Data.Error;
this.dataStatuses.trains = Status.Data.Error;
this.dataStatuses.dispatchers = Status.Data.Error;
return;
}
this.dataStatuses.sceneries = Status.Data.Loaded;
this.dataStatuses.trains = !this.activeData.trains ? Status.Data.Warning : Status.Data.Loaded;
this.dataStatuses.dispatchers = Status.Data.Loaded;
}
}
});
+2 -2
View File
@@ -1,6 +1,6 @@
import { defineStore } from 'pinia';
import inputData from '../data/options.json';
import { useStore } from './mainStore';
import { useMainStore } from './mainStore';
import { filterStations, sortStations } from '../scripts/utils/filterUtils';
import { HeadIdsTypes } from '../scripts/data/stationHeaderNames';
import StorageManager from '../managers/storageManager';
@@ -70,7 +70,7 @@ export const useStationFiltersStore = defineStore('stationFiltersStore', {
},
filteredStationList: (state) => {
const store = useStore();
const store = useMainStore();
const savedStationNames = store.stationList.map((s) => s.name);
const onlineUnsavedStations = store.onlineSceneryList
-33
View File
@@ -11,24 +11,7 @@ export interface RegionCounters {
}
export interface StoreState {
stationList: Station[];
activeData: API.ActiveData.Response;
rollingStockData?: API.RollingStock.Response;
donatorsData: API.Donators.Response;
regionOnlineCounters: RegionCounters[];
lastDispatcherStatuses: {
hash: string;
statusTimestamp: number;
statusID: Status.ActiveDispatcher;
}[];
sceneryData: any[][];
region: { id: string; value: string };
trainCount: number;
stationCount: number;
isOffline: boolean;
@@ -41,24 +24,8 @@ export interface StoreState {
chosenModalTrainId?: string;
dataStatuses: {
connection: Status.Data;
sceneries: Status.Data;
timetables: Status.Data;
dispatchers: Status.Data;
trains: Status.Data;
};
listenerLaunched: boolean;
blockScroll: boolean;
modalLastClickedTarget: EventTarget | null;
tooltip: {
visible: boolean;
x: number;
y: number;
content: string;
};
}
export interface StationRoutesInfo {
+2 -2
View File
@@ -36,7 +36,7 @@ import axios from 'axios';
import JournalOptions from '../components/JournalView/JournalOptions.vue';
import { URLs } from '../scripts/utils/apiURLs';
import { useStore } from '../store/mainStore';
import { useMainStore } from '../store/mainStore';
import JournalDispatchersList from '../components/JournalView/JournalDispatchersList.vue';
import JournalHeader from '../components/JournalView/JournalHeader.vue';
@@ -105,7 +105,7 @@ export default defineComponent({
const scrollElement: Ref<HTMLElement | null> = ref(null);
return {
store: useStore(),
store: useMainStore(),
sorterActive,
searchersValues,
+2 -2
View File
@@ -46,7 +46,7 @@ import JournalStats from '../components/JournalView/JournalStats.vue';
import JournalHeader from '../components/JournalView/JournalHeader.vue';
import { URLs } from '../scripts/utils/apiURLs';
import { useStore } from '../store/mainStore';
import { useMainStore } from '../store/mainStore';
import { LocationQuery } from 'vue-router';
@@ -194,7 +194,7 @@ export default defineComponent({
scrollElement,
store: useStore()
store: useMainStore()
};
},
+7 -4
View File
@@ -42,8 +42,8 @@
<div
v-if="
store.dataStatuses.sceneries == Status.Loading ||
store.dataStatuses.trains == Status.Loading
apiStore.dataStatuses.sceneries == Status.Loading ||
apiStore.dataStatuses.trains == Status.Loading
"
></div>
@@ -64,7 +64,7 @@
import { computed, defineComponent } from 'vue';
import { useRoute } from 'vue-router';
import routerMixin from '../mixins/routerMixin';
import { useStore } from '../store/mainStore';
import { useMainStore } from '../store/mainStore';
import SceneryInfo from '../components/SceneryView/SceneryInfo.vue';
import SceneryHeader from '../components/SceneryView/SceneryHeader.vue';
@@ -73,6 +73,7 @@ import SceneryTimetablesHistory from '../components/SceneryView/SceneryTimetable
import SceneryDispatchersHistory from '../components/SceneryView/SceneryDispatchersHistory.vue';
import ActionButton from '../components/Global/ActionButton.vue';
import { Status } from '../typings/common';
import { useApiStore } from '../store/apiStore';
enum SceneryViewMode {
'TIMETABLES_ACTIVE',
@@ -107,7 +108,9 @@ export default defineComponent({
mixins: [routerMixin],
data: () => ({
store: useStore(),
store: useMainStore(),
apiStore: useApiStore(),
viewModes: [
{
id: 'scenery.option-active-timetables',
+2 -2
View File
@@ -21,7 +21,7 @@ import { defineComponent } from 'vue';
import StationTable from '../components/StationsView/StationTable.vue';
import StationFilterCard from '../components/StationsView/StationFilterCard.vue';
import { useStationFiltersStore } from '../store/stationFiltersStore';
import { useStore } from '../store/mainStore';
import { useMainStore } from '../store/mainStore';
import Donation from '../components/Global/Donation.vue';
export default defineComponent({
@@ -37,7 +37,7 @@ export default defineComponent({
STORAGE_KEY: 'options_saved',
focusedStationName: '',
filterStore: useStationFiltersStore(),
store: useStore(),
store: useMainStore(),
isDonationModalOpen: false
}),
+2 -2
View File
@@ -21,7 +21,7 @@ import TrainOptions from '../components/TrainsView/TrainOptions.vue';
import TrainTable from '../components/TrainsView/TrainTable.vue';
import modalTrainMixin from '../mixins/modalTrainMixin';
import Train from '../scripts/interfaces/Train';
import { useStore } from '../store/mainStore';
import { useMainStore } from '../store/mainStore';
import { TrainFilter, trainFilters } from '../components/TrainsView/typings';
import { filteredTrainList } from '../managers/trainFilterManager';
import TrainStats from '../components/TrainsView/TrainStats.vue';
@@ -58,7 +58,7 @@ export default defineComponent({
}),
setup() {
const store = useStore();
const store = useMainStore();
const initTrainFilters = [...trainFilters.map((f) => ({ ...f }))];
const sorterActive = reactive({ id: 'routeDistance', dir: -1 });