256 lines
6.9 KiB
TypeScript
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();
|