Kolumna z aktywnymi RJ dla scenerii - W.I.P.

This commit is contained in:
2020-08-29 02:11:01 +02:00
parent dc70bd8a38
commit 5f48c4688f
8 changed files with 149 additions and 563 deletions
+5 -4
View File
@@ -57,18 +57,19 @@ import Clock from "@/components/App/Clock.vue";
components: { Error, Loading, Clock },
})
export default class App extends Vue {
@Getter("getStationList") stations;
@Getter("getOnlineInfo") onlineInfo;
@Action("initStations") initStations;
@Action("fetchOnlineStations") fetchStations;
errorMessage: string = "";
@Action("fetchOnlineStations") fetchStations;
@Action("fetchTrainsData") fetchTrainsData;
async mounted() {
this.initStations();
this.fetchTrainsData();
setInterval(this.fetchStations, 5000);
setInterval(this.fetchStations, 15000);
setInterval(this.fetchTrainsData, 10000);
}
}
</script>
+38 -13
View File
@@ -118,12 +118,10 @@
>{{station.routes.oneWay.noCatenary}}</span>
</td>
<!-- <td
class="active-timetables"
@click="() => showScheduledTrains(station)"
>{{station.scheduledTrains.length}}</td>-->
<td class="active-timetables">0</td>
</tr>
</table>
<div class="no-stations" v-if="stations.length == 0">Ups! Brak stacji do wyświetlenia!</div>
</div>
</section>
</template>
@@ -152,7 +150,6 @@ export default class StationTable extends styleMixin {
@Prop() readonly setFocusedStation!: () => void;
@Getter("trainsDataList") trains!: Train[];
@Getter("trainsDataState") state!: number;
icons: { ascSVG; descSVG } = { ascSVG, descSVG };
sorterActive: { index: number; dir: number } = { index: 0, dir: 1 };
@@ -166,7 +163,7 @@ export default class StationTable extends styleMixin {
["Maszyniści"],
["Informacje", "ogólne"],
["Szlaki", "2tor | 1tor"],
// ["Aktywne RJ"],
["Aktywne RJ"],
];
changeSorter(index: number) {
@@ -179,12 +176,28 @@ export default class StationTable extends styleMixin {
this.sorterActive.index = index;
}
get test() {
return this.trains;
}
get scheduledTrains() {
return this.stations.reduce((acc, station) => {
if (!acc[station.stationName]) acc[station.stationName] = [];
showScheduledTrains(station) {
console.log(station.scheduledTrains);
this.trains
.filter((train) => !train.noTimetable)
.forEach((train) => {
const found = train.stopPoints!.find(
(sp: any) =>
(station.stationName.includes(sp.pointNameRAW) ||
station.stationName.includes(sp.pointNameRAW.split(" ")[0])) &&
!acc[station.stationName].find((t) => t === train.trainNo)
// !acc[station.stationName].find((t) => t.trainNo === train.trainNo)
);
if (!found) return acc;
acc[station.stationName].push(train.trainNo);
});
return acc;
}, {});
}
get computedStations() {
@@ -235,10 +248,24 @@ export default class StationTable extends styleMixin {
@import "../../styles/variables.scss";
@import "../../styles/global.scss";
.station-table {
font-size: calc(0.6rem + 0.3vw);
}
.separator {
border-left: 3px solid #b3b3b3;
}
.no-stations {
text-align: center;
font-size: 1.5em;
padding: 1rem;
margin: 1rem 0;
background: #333;
}
.table {
&-wrapper {
overflow: auto;
@@ -247,8 +274,6 @@ export default class StationTable extends styleMixin {
white-space: nowrap;
border-collapse: collapse;
font-size: calc(0.6rem + 0.3vw);
@include smallScreen() {
font-size: 0.6rem;
}
+2 -2
View File
@@ -140,7 +140,7 @@ export default class TrainSorter extends Vue {
z-index: 5;
width: 100%;
background-color: rgba(#333, 0.85);
background-color: rgba(#222, 0.95);
overflow: hidden;
max-height: 0;
@@ -150,7 +150,7 @@ export default class TrainSorter extends Vue {
opacity: 1;
}
transition: all 250ms ease-in;
transition: all 150ms ease-in;
}
.option {
+1
View File
@@ -19,4 +19,5 @@ export default interface Train {
locoURL: string;
locoType: string;
routeDistance: number;
stopPoints?: [];
}
-474
View File
@@ -1,474 +0,0 @@
import { VuexModule, Module, Mutation, Action } from "vuex-module-decorators";
import axios from "axios";
import data from "@/data/stations.json";
import Station from "@/scripts/interfaces/Station";
enum ConnState {
Loading = 0,
Error = 1,
Connected = 2,
}
const apiURLS = {
stationDataURL: "https://api.td2.info.pl:9640/?method=getStationsOnline",
trainDataURL: "https://api.td2.info.pl:9640/?method=getTrainsOnline",
dispatcherDataURL:
"https://api.td2.info.pl:9640/?method=readFromSWDR&value=getDispatcherStatusList%3B1",
};
interface TimetableResponseData {
stopPoints:
| {
arrivalTime: string;
arrivalDelay: number;
departureTime: string;
departureDelay: number;
pointNameRAW: string;
}[]
| [];
trainInfo: {
timetableId: number;
trainCategoryCode: string;
};
}
interface OnlineStationsResponseData {
stationName: string;
stationHash: string;
maxUsers: number;
currentUsers: number;
spawnString: string;
dispatcherRate: number;
dispatcherName: string;
dispatcherExp: number;
dispatcherId: number;
region: string;
isOnline: number;
}
let onlineStationsData: OnlineStationsResponseData[];
let onlineDispatchersData: [string, string, number, number][];
let onlineTrainsData: {
isOnline: number;
region: string;
trainNo: number;
station: { stationName: string };
}[];
const queryStations = (async () => {
return (await axios.get(apiURLS.stationDataURL)).data.message;
})();
const queryTrains = (async () => {
return await (await axios.get(apiURLS.trainDataURL)).data.message;
})();
const queryDisptachers = (async () => {
return await (await axios.get(apiURLS.dispatcherDataURL)).data.message;
})();
const queryTimetableData = async (
trainNo: number
): Promise<TimetableResponseData> =>
(
await axios.get(
`https://api.td2.info.pl:9640/?method=readFromSWDR&value=getTimetable%3B${trainNo}%3Beu`
)
).data.message;
async function getScheduledTrains(stationName: string) {
let scheduledTrains: any[] = [];
for (let train of onlineTrainsData) {
if (train.region !== "eu" || !train.isOnline) continue;
const timetable = await queryTimetableData(train.trainNo);
if (!timetable.trainInfo) continue;
const stop = timetable.stopPoints.find((point) => {
return (
stationName.toLowerCase().includes(point.pointNameRAW.toLowerCase()) ||
stationName
.toLowerCase()
.includes(point.pointNameRAW.toLowerCase().split(" ")[0]) ||
stationName
.toLowerCase()
.includes(point.pointNameRAW.toLowerCase().split(",")[0])
);
});
if (!stop) continue;
scheduledTrains.push({
arrivalTime: stop?.arrivalTime,
departureTime: stop?.departureTime,
trainCategory: timetable.trainInfo?.trainCategoryCode,
trainNo: train.trainNo,
});
}
return scheduledTrains;
}
@Module
class Store extends VuexModule {
private trainCount: number = 0;
private stationCount: number = 0;
private connectionState: ConnState = ConnState.Loading;
private stations: Station[] = [];
// private scheduledTrains: {
// trainNo: number;
// trainCategory: string;
// arrivalTime: string;
// departureTime: string;
// }[] = [];
private filteredStations: {}[] = [];
private filterInitStates = {
default: false,
notDefault: false,
nonPublic: false,
SPK: false,
SCS: false,
ręczne: false,
mechaniczne: false,
współczesna: false,
kształtowa: false,
historyczna: false,
mieszana: false,
minLevel: 0,
minOneWayCatenary: 0,
minOneWay: 0,
minTwoWayCatenary: 0,
minTwoWay: 0,
"no-1track": false,
"no-2track": false,
free: true,
occupied: false,
ending: false,
} as const;
private filters: any = { ...this.filterInitStates };
get getStationCount(): number {
return this.stationCount;
}
get getTrainCount(): number {
return this.trainCount;
}
get getStations() {
return this.filteredStations;
}
get getAllStations() {
return this.stations;
}
get getFilters() {
return this.filters;
}
get getConnectionState() {
return this.connectionState;
}
@Action
public setFilter(payload: { filterName: string; value: number | boolean }) {
this.context.commit("mutateFilter", payload);
this.context.commit("filterStations");
}
@Action
public resetFilters() {
this.context.commit("resetFilterList");
this.context.commit("filterStations");
}
@Action
public initStations() {
this.context.commit("loadAllStations");
this.context.dispatch("fetchStations");
setInterval(() => this.context.dispatch("fetchStations"), 10000);
}
@Action
private fetchStations() {
Promise.all([queryStations, queryTrains, queryDisptachers])
.then(async (response) => {
onlineStationsData = response[0];
onlineTrainsData = response[1];
onlineDispatchersData = response[2];
const updatedStations = await Promise.all(
onlineStationsData
.filter((station) => station.region === "eu" && station.isOnline)
.map(async (station) => {
const stationStatus = onlineDispatchersData.find(
(status) =>
status[0] == station.stationHash && status[1] == "eu"
);
let statusLabel = "";
let statusTimestamp = -1;
if (!stationStatus) statusLabel = "NIEZALOGOWANY";
else {
let statusCode = stationStatus[2];
statusTimestamp = stationStatus[3];
statusLabel = "NIEDOSTĘPNY";
switch (statusCode) {
case 0:
if (statusTimestamp - Date.now() > 21000000)
statusLabel = "BEZ LIMITU";
else
statusLabel =
"DO " +
new Date(statusTimestamp).toLocaleTimeString("en-US", {
hour12: false,
hour: "2-digit",
minute: "2-digit",
});
break;
case 1:
statusLabel = "Z/W";
break;
case 2:
if (statusTimestamp == 0) statusLabel = "KOŃCZY";
break;
case 3:
statusLabel = "BRAK MIEJSCA";
break;
default:
break;
}
}
const trains = onlineTrainsData.filter(
(train) =>
train.region === "eu" &&
train.isOnline &&
train.station.stationName === station.stationName
);
const stationData = data.find(
(s) => s.stationName === station.stationName
) || { stationName: station.stationName, stationURL: "" };
// let scheduledTrains = await getScheduledTrains(
// station.stationName
// );
let scheduledTrains: any[] = [];
return {
...stationData,
stationHash: station.stationHash,
maxUsers: station.maxUsers,
currentUsers: station.currentUsers,
spawnString:
station.spawnString &&
station.spawnString
.split(";")
.map((v) =>
v.split(",")[6] ? v.split(",")[6] : v.split(",")[0]
),
dispatcherName: station.dispatcherName,
dispatcherRate: station.dispatcherRate,
dispatcherId: station.dispatcherId,
dispatcherExp: station.dispatcherExp,
occupiedTo: statusLabel,
statusTimestamp,
trains,
scheduledTrains,
};
})
);
// const scheduled = await testLoad();
// for (let stationName in scheduled) {
// let t = updatedStations.find(
// (updated) => updated.stationName === stationName
// );
// if (!t) continue;
// t.scheduledTrains = scheduled[stationName];
// }
this.context.commit("updateStations", {
updatedStations,
trainCount: onlineTrainsData.filter(
(train) => train.isOnline && train.region === "eu"
).length,
});
this.context.commit("filterStations");
this.context.commit("setConnState", ConnState.Connected);
})
.catch((err) => {
this.context.commit("setConnState", ConnState.Error);
});
}
@Mutation
private filterStations() {
this.filteredStations = this.stations.filter((station) => {
if ((station.nonPublic || !station.reqLevel) && this.filters["nonPublic"])
return false;
if (!station.reqLevel || station.reqLevel == "-1") return true;
if (
station.online &&
station.occupiedTo == "KOŃCZY" &&
this.filters["ending"]
)
return false;
if (station.online && this.filters["occupied"]) return false;
if (!station.online && this.filters["free"]) return false;
if (station.default && this.filters["default"]) return false;
if (!station.default && this.filters["notDefault"]) return false;
if (station.reqLevel < this.filters["minLevel"]) return false;
if (
this.filters["no-1track"] &&
(station.routes.oneWay.catenary != 0 ||
station.routes.oneWay.noCatenary != 0)
)
return false;
if (
this.filters["no-2track"] &&
(station.routes.twoWay.catenary != 0 ||
station.routes.twoWay.noCatenary != 0)
)
return false;
if (station.routes.oneWay.catenary < this.filters["minOneWayCatenary"])
return false;
if (station.routes.oneWay.noCatenary < this.filters["minOneWay"])
return false;
if (station.routes.twoWay.catenary < this.filters["minTwoWayCatenary"])
return false;
if (station.routes.twoWay.noCatenary < this.filters["minTwoWay"])
return false;
if (this.filters[station.controlType]) return false;
if (this.filters[station.signalType]) return false;
if (this.filters["SPK"] && station.controlType.includes("SPK"))
return false;
if (this.filters["SCS"] && station.controlType.includes("SCS"))
return false;
if (
this.filters["mechaniczne"] &&
station.controlType.includes("mechaniczne")
)
return false;
if (this.filters["ręczne"] && station.controlType.includes("ręczne"))
return false;
return true;
});
}
@Mutation
private loadAllStations() {
this.stations = data.map((stationData) => ({
stationProject: "",
spawnString: "",
stationHash: "",
maxUsers: 0,
currentUsers: 0,
dispatcherName: "",
dispatcherRate: 0,
dispatcherExp: -1,
dispatcherId: 0,
online: false,
occupiedTo: "WOLNA",
statusTimestamp: 0,
scheduledTrains: [],
...stationData,
}));
}
@Mutation
private updateStations({ updatedStations, trainCount }) {
for (let i = 0; i < this.stations.length; i++) {
const toUpdate: any = updatedStations.find(
(updated: any) => updated.stationName === this.stations[i].stationName
);
if (!toUpdate) {
this.stations[i].online = false;
this.stations[i].occupiedTo = "WOLNA";
this.stations[i].statusTimestamp = -1;
this.stations[i].dispatcherExp = -1;
continue;
}
this.stations[i] = { ...this.stations[i], ...toUpdate };
this.stations[i].online = true;
updatedStations = updatedStations.filter(
(updated: any) => updated.stationName !== this.stations[i].stationName
);
}
// Dodawanie do listy online potencjalnych scenerii niewpisanych do bazy
updatedStations.forEach((updated: any) => {
const toUpdate: any = this.stations.find(
(station) => station.stationName === updated.stationName
);
if (!toUpdate) {
this.stations.push({ ...updated, online: true, reqLevel: "-1" });
}
});
// Aktualizacja liczników
this.stationCount = this.stations.filter(
(station) => station.online
).length;
this.trainCount = trainCount;
}
@Mutation
private mutateFilter(payload: {
filterName: string;
value: number | boolean;
}) {
this.filters[payload.filterName] = payload.value;
}
@Mutation
private resetFilterList() {
this.filters = { ...this.filterInitStates };
}
@Mutation
private setConnState(state: ConnState) {
this.connectionState = state;
}
}
export default Store;
+56 -55
View File
@@ -50,6 +50,7 @@ interface TimetableData {
skr: boolean;
sceneries: string[];
routeDistance: number;
stopPoints?: {}[];
}
const getTimetableURL = (trainNo: number) =>
@@ -79,65 +80,65 @@ export default class TrainsModule extends VuexModule {
let onlineTrainsData: TrainData[] = trainDataResponse.data.message;
return await Promise.all(
onlineTrainsData
.filter((train) => train.isOnline)
.map(async (train) => {
const timetableResponseData: TimetableResponseData | null = (
await axios.get(getTimetableURL(train.trainNo))
).data.message;
onlineTrainsData.map(async (train) => {
const timetableResponseData: TimetableResponseData | null = (
await axios.get(getTimetableURL(train.trainNo))
).data.message;
let timetableData: TimetableData | null = null;
let timetableData: TimetableData | null = null;
if (timetableResponseData && timetableResponseData.trainInfo) {
const routeDistance: number =
timetableResponseData.stopPoints[
timetableResponseData.stopPoints.length - 1
].pointDistance;
if (timetableResponseData && timetableResponseData.trainInfo) {
const routeDistance: number =
timetableResponseData.stopPoints[
timetableResponseData.stopPoints.length - 1
].pointDistance;
timetableData = {
...timetableResponseData.trainInfo,
routeDistance,
};
}
const locoType = train.dataCon.split(";")
? train.dataCon.split(";")[0]
: train.dataCon;
const stopPoints = timetableResponseData?.stopPoints.reduce(
(acc, point) => {
if (point.pointName.includes("strong")) {
acc.push(point.pointNameRAW);
}
return acc;
},
[] as string[]
);
return {
driverId: train.driverId,
driverName: train.driverName,
trainNo: train.trainNo,
currentStationName: train.station.stationName,
mass: train.dataMass,
length: train.dataLength,
speed: train.dataSpeed,
distance: train.dataDistance,
signal: train.dataSignal,
connectedTrack: train.dataSceneryConnection,
locoType,
locoURL: getLocoURL(locoType),
noTimetable: timetableData == null,
route: timetableData && timetableData.route,
timetableId: timetableData && timetableData.timetableId,
category: timetableData && timetableData.trainCategoryCode,
routeDistance: (timetableData && timetableData.routeDistance) || 0,
sceneries: stopPoints,
TWR: timetableData && timetableData.twr,
SKR: timetableData && timetableData.skr,
timetableData = {
...timetableResponseData.trainInfo,
routeDistance,
stopPoints: timetableResponseData.stopPoints,
};
})
}
const locoType = train.dataCon.split(";")
? train.dataCon.split(";")[0]
: train.dataCon;
const stopPoints = timetableResponseData?.stopPoints.reduce(
(acc, point) => {
if (point.pointName.includes("strong")) {
acc.push(point.pointNameRAW);
}
return acc;
},
[] as string[]
);
return {
driverId: train.driverId,
driverName: train.driverName,
trainNo: train.trainNo,
currentStationName: train.station.stationName,
mass: train.dataMass,
length: train.dataLength,
speed: train.dataSpeed,
distance: train.dataDistance,
signal: train.dataSignal,
connectedTrack: train.dataSceneryConnection,
locoType,
locoURL: getLocoURL(locoType),
noTimetable: timetableData == null,
route: timetableData?.route,
timetableId: timetableData?.timetableId,
category: timetableData?.trainCategoryCode,
routeDistance: timetableData?.routeDistance || 0,
sceneries: stopPoints,
stopPoints: timetableData?.stopPoints,
TWR: timetableData?.twr,
SKR: timetableData?.skr,
};
})
);
}
+3 -3
View File
@@ -6,7 +6,6 @@
<transition name="card-anim">
<StationCard v-if="focusedStationInfo" :stationInfo="focusedStationInfo" :exit="closeCard" />
</transition>
<!-- <div class="info" v-if="stations.length == 0">Ups! Brak stacji do wyświetlenia!</div> -->
<div class="stations-wrapper" v-if="connectionState == 2">
<div class="stations-body">
@@ -22,6 +21,9 @@ import { Vue, Component } from "vue-property-decorator";
import { Getter, Action } from "vuex-class";
import Station from "@/scripts/interfaces/Station";
import Train from "@/scripts/interfaces/Train";
import inputData from "@/data/options.json";
import Loading from "@/components/App/Loading.vue";
import Error from "@/components/App/Error.vue";
@@ -30,8 +32,6 @@ import StationTable from "@/components/StationsView/StationTable.vue";
import StationCard from "@/components/StationsView/StationCard.vue";
import Options from "@/components/StationsView/Options.vue";
import inputData from "@/data/options.json";
enum ConnState {
Loading = 0,
Error = 1,
+44 -12
View File
@@ -7,12 +7,28 @@
<TrainSorter :trainList="computedTrains" @changeSorter="changeSorter" />
<div class="search train">
<div class="search-title title">Szukaj składu</div>
<input class="search-input" v-model="searchedTrain" />
<div class="search-box">
<input class="search-input" v-model="searchedTrain" />
<img
class="search-exit"
:src="exitIcon"
alt="exit-icon"
@click="() => searchedTrain = ''"
/>
</div>
</div>
<div class="search driver">
<div class="search-title title">Szukaj maszynisty</div>
<input class="search-input" v-model="searchedDriver" />
<div class="search-box">
<input class="search-input" v-model="searchedDriver" />
<img
class="search-exit"
:src="exitIcon"
alt="exit-icon"
@click="() => searchedDriver = ''"
/>
</div>
</div>
</div>
@@ -48,7 +64,10 @@ import axios from "axios";
},
})
export default class TrainsView extends Vue {
exitIcon = require("@/assets/icon-exit.svg");
@Getter("trainsDataList") trains!: Train[];
@Getter("trainsDataState") connectionState;
@Action("fetchTrainsData") fetchTrainsData;
@@ -70,7 +89,9 @@ export default class TrainsView extends Vue {
? train.trainNo.toString().includes(this.searchedTrain)
: true) &&
(this.searchedDriver.length > 0
? train.driverName.includes(this.searchedDriver)
? train.driverName
.toLowerCase()
.includes(this.searchedDriver.toLowerCase())
: true)
)
.sort((a, b) => {
@@ -107,12 +128,6 @@ export default class TrainsView extends Vue {
return 0;
});
}
mounted() {
this.fetchTrainsData();
setInterval(this.fetchTrainsData, 5000);
}
}
</script>
@@ -142,17 +157,34 @@ export default class TrainsView extends Vue {
}
.search {
&-input {
&-box {
position: relative;
background: #333;
border: none;
border-radius: 0.5em;
min-width: 150px;
}
&-input {
border: none;
padding: 0.5rem 1rem;
margin: 0;
font-size: 1em;
min-width: 150px;
min-width: 85%;
}
&-exit {
position: absolute;
cursor: pointer;
top: 50%;
right: 10px;
transform: translateY(-50%);
width: 1em;
}
}
}