Files
WhiteNightsAdminPanel/src/shared/store/RouteStore/index.ts
2026-05-07 13:08:33 +03:00

256 lines
6.9 KiB
TypeScript

import { makeAutoObservable, runInAction } from "mobx";
import {
authInstance,
languageInstance,
languageStore,
isMediaIdEmpty,
} from "@shared";
export type Route = {
route_name: string;
carrier: string;
carrier_id: number;
center_latitude: number;
center_longitude: number;
governor_appeal: number;
id: number;
icon: string;
path: number[][];
rotate: number;
route_direction: boolean;
route_number: string;
route_sys_number: string;
scale_max: number;
scale_min: number;
video_preview: string;
video_timer: number;
};
class RouteStore {
routes: {
data: Route[];
loaded: boolean;
} = {
data: [],
loaded: false,
};
route: Record<string, Route> = {};
constructor() {
makeAutoObservable(this);
}
getRoutes = async () => {
if (this.routes.loaded) return;
const response = await authInstance.get("/route");
runInAction(() => {
this.routes = {
data: response.data,
loaded: true,
};
});
};
createRoute = async (route: any): Promise<number> => {
const response = await authInstance.post("/route", route);
const id = response.data.id;
runInAction(() => {
this.route[id] = { ...route, id };
this.routes.data = [...this.routes.data, { ...route, id }];
});
return id;
};
deleteRoute = async (id: number) => {
await authInstance.delete(`/route/${id}`);
runInAction(() => {
this.routes = {
data: this.routes.data.filter((route) => route.id !== id),
loaded: true,
};
});
};
routeStations: Record<string, any[]> = {};
getRoute = async (id: number) => {
if (this.route[id]) return this.route[id];
const response = await authInstance.get(`/route/${id}`);
const stations = await authInstance.get(`/route/${id}/station`);
runInAction(() => {
this.route[id] = response.data;
this.routeStations[id] = stations.data;
});
return response.data;
};
setRouteStations = (routeId: number, stationId: number, data: any) => {
this.routeStations[routeId] = this.routeStations[routeId]?.map((station) =>
station.id === stationId ? { ...station, ...data } : station
);
};
saveRouteStations = async (routeId: number, stationId: number) => {
const { language } = languageStore;
const stationResponse = await languageInstance(language).get(
`/station/${stationId}`
);
const fullStationData = stationResponse.data;
// Получаем отредактированные данные из локального кеша
const editedStationData = this.routeStations[routeId]?.find(
(station) => station.id === stationId
);
const dataToSend: any = {
station_id: stationId,
offset_x: editedStationData?.offset_x ?? fullStationData.offset_x ?? 0,
offset_y: editedStationData?.offset_y ?? fullStationData.offset_y ?? 0,
align: editedStationData?.align ?? fullStationData.align ?? 0,
transfers: fullStationData.transfers || {},
};
await authInstance.patch(`/route/${routeId}/station`, dataToSend);
// Обновляем локальный кеш после успешного сохранения
runInAction(() => {
if (this.routeStations[routeId]) {
this.routeStations[routeId] = this.routeStations[routeId].map(
(station) =>
station.id === stationId
? {
...station,
...dataToSend,
}
: station
);
}
});
};
editRouteData = {
route_name: "",
carrier: "",
carrier_id: 0,
center_latitude: "",
center_longitude: "",
governor_appeal: 0,
id: 0,
icon: "",
path: [] as number[][],
rotate: 0,
route_direction: false,
route_number: "",
route_sys_number: "",
scale_max: 0,
scale_min: 0,
video_preview: "" as string | undefined,
video_timer: 420,
};
setEditRouteData = (data: any) => {
this.editRouteData = { ...this.editRouteData, ...data };
};
editRoute = async (id: number) => {
if (
!this.editRouteData.video_preview ||
isMediaIdEmpty(this.editRouteData.video_preview)
) {
delete this.editRouteData.video_preview;
}
if (!this.editRouteData.icon || isMediaIdEmpty(this.editRouteData.icon)) {
delete (this.editRouteData as any).icon;
}
const dataToSend: any = {
...this.editRouteData,
route_name: (this.editRouteData.route_name || "").trim(),
route_number: (this.editRouteData.route_number || "").trim(),
route_sys_number: (this.editRouteData.route_sys_number || "").trim(),
center_latitude: parseFloat(this.editRouteData.center_latitude),
center_longitude: parseFloat(this.editRouteData.center_longitude),
};
if (
this.editRouteData.governor_appeal === 0 ||
!this.editRouteData.governor_appeal
) {
dataToSend.governor_appeal = null;
}
const response = await authInstance.patch(`/route/${id}`, dataToSend);
runInAction(() => {
this.route[id] = response.data;
this.routes.data = this.routes.data.map((route) =>
route.id === id ? response.data : route
);
});
};
copyRouteAction = async (id: number) => {
const response = await authInstance.post(`/route/${id}/copy`);
runInAction(() => {
this.routes.data = [...this.routes.data, response.data];
});
};
sightCounts: Map<number, number> = new Map();
stationCounts: Map<number, number> = new Map();
countsLoading = false;
loadCounts = async (routeIds: number[]) => {
if (routeIds.length === 0) return;
runInAction(() => {
this.countsLoading = true;
});
const batchSize = 20;
for (let i = 0; i < routeIds.length; i += batchSize) {
const batch = routeIds.slice(i, i + batchSize);
const results = await Promise.allSettled(
batch.flatMap((id) => [
authInstance.get(`/route/${id}/sight/count`).then((res) => ({ id, type: "sight", data: res.data })),
authInstance.get(`/route/${id}/station/count`).then((res) => ({ id, type: "station", data: res.data })),
])
);
runInAction(() => {
for (const result of results) {
if (result.status === "fulfilled") {
const { id, type, data } = result.value;
let count = 0;
if (typeof data === "number") {
count = data;
} else if (data && typeof data === "object") {
count = Object.values(data).reduce((sum: number, v: any) => sum + (Number(v) || 0), 0);
}
if (type === "sight") this.sightCounts.set(id, count);
else this.stationCounts.set(id, count);
}
}
});
}
runInAction(() => {
this.countsLoading = false;
});
};
selectedStationId = 0;
setSelectedStationId = (id: number) => {
this.selectedStationId = id;
};
}
export const routeStore = new RouteStore();