Files
WhiteNightsAdminPanel/src/pages/MapPage/mapStore.ts

253 lines
7.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { languageInstance } from "@shared";
import { makeAutoObservable } from "mobx";
interface ApiRoute {
id: number;
route_number: string;
path: [number, number][];
}
interface ApiStation {
id: number;
name: string;
latitude: number;
longitude: number;
}
interface ApiSight {
id: number;
name: string;
description: string;
latitude: number;
longitude: number;
}
// Допуск для сравнения координат, чтобы избежать ошибок с точностью чисел.
const COORDINATE_PRECISION_TOLERANCE = 1e-9;
// Вспомогательная функция, обновленная для сравнения с допуском.
const arePathsEqual = (
path1: [number, number][],
path2: [number, number][]
): boolean => {
if (path1.length !== path2.length) {
return false;
}
for (let i = 0; i < path1.length; i++) {
if (
Math.abs(path1[i][0] - path2[i][0]) > COORDINATE_PRECISION_TOLERANCE ||
Math.abs(path1[i][1] - path2[i][1]) > COORDINATE_PRECISION_TOLERANCE
) {
return false;
}
}
return true;
};
class MapStore {
constructor() {
makeAutoObservable(this);
}
routes: ApiRoute[] = [];
stations: ApiStation[] = [];
sights: ApiSight[] = [];
getRoutes = async () => {
const response = await languageInstance("ru").get("/route");
const routesIds = response.data.map((route: any) => route.id);
for (const id of routesIds) {
const route = await languageInstance("ru").get(`/route/${id}`);
this.routes.push({
id: route.data.id,
route_number: route.data.route_number,
path: route.data.path,
});
}
const mappedRoutes: ApiRoute[] = response.data.map((route: any) => ({
id: route.id,
route_number: route.route_number,
path: route.path,
}));
this.routes = mappedRoutes.sort((a, b) =>
a.route_number.localeCompare(b.route_number)
);
};
getStations = async () => {
const stations = await languageInstance("ru").get("/station");
this.stations = stations.data.map((station: any) => ({
id: station.id,
name: station.name,
latitude: station.latitude,
longitude: station.longitude,
}));
};
getSights = async () => {
const sights = await languageInstance("ru").get("/sight");
this.sights = sights.data.map((sight: any) => ({
id: sight.id,
name: sight.name,
description: sight.description,
latitude: sight.latitude,
longitude: sight.longitude,
}));
};
deleteRecourse = async (recourse: string, id: number) => {
await languageInstance("ru").delete(`/${recourse}/${id}`);
if (recourse === "route") {
this.routes = this.routes.filter((route) => route.id !== id);
} else if (recourse === "station") {
this.stations = this.stations.filter((station) => station.id !== id);
} else if (recourse === "sight") {
this.sights = this.sights.filter((sight) => sight.id !== id);
}
};
handleSave = async (json: string) => {
const newSights: any[] = [];
const newRoutes: any[] = [];
const newStations: any[] = [];
const updatedSights: any[] = [];
const updatedRoutes: any[] = [];
const updatedStations: any[] = [];
const parsedJSON = JSON.parse(json);
for (const feature of parsedJSON.features) {
const { geometry, properties, id } = feature;
const idParts = String(id).split("-");
if (idParts.length > 1) {
const featureType = idParts[0];
const numericId = parseInt(idParts[1], 10);
if (isNaN(numericId)) continue;
if (featureType === "station") {
const originalStation = this.stations.find((s) => s.id === numericId);
if (!originalStation) continue;
const currentStation = {
name: properties.name || "",
latitude: geometry.coordinates[1],
longitude: geometry.coordinates[0],
};
// ИЗМЕНЕНИЕ: Сравнение координат с допуском
if (
originalStation.name !== currentStation.name ||
Math.abs(originalStation.latitude - currentStation.latitude) >
COORDINATE_PRECISION_TOLERANCE ||
Math.abs(originalStation.longitude - currentStation.longitude) >
COORDINATE_PRECISION_TOLERANCE
) {
updatedStations.push({ id: numericId, ...currentStation });
}
} else if (featureType === "route") {
const originalRoute = this.routes.find((r) => r.id === numericId);
if (!originalRoute) continue;
const currentRoute = {
route_number: properties.name || "",
path: geometry.coordinates,
};
// ИЗМЕНЕНИЕ: Используется новая функция arePathsEqual с допуском
if (
originalRoute.route_number !== currentRoute.route_number ||
!arePathsEqual(originalRoute.path, currentRoute.path)
) {
updatedRoutes.push({ id: numericId, ...currentRoute });
}
} else if (featureType === "sight") {
const originalSight = this.sights.find((s) => s.id === numericId);
if (!originalSight) continue;
const currentSight = {
name: properties.name || "",
description: properties.description || "",
latitude: geometry.coordinates[1],
longitude: geometry.coordinates[0],
};
// ИЗМЕНЕНИЕ: Сравнение координат с допуском
if (
originalSight.name !== currentSight.name ||
originalSight.description !== currentSight.description ||
Math.abs(originalSight.latitude - currentSight.latitude) >
COORDINATE_PRECISION_TOLERANCE ||
Math.abs(originalSight.longitude - currentSight.longitude) >
COORDINATE_PRECISION_TOLERANCE
) {
updatedSights.push({ id: numericId, ...currentSight });
}
}
} else {
if (properties.featureType === "station") {
newStations.push({
name: properties.name || "",
latitude: geometry.coordinates[1],
longitude: geometry.coordinates[0],
});
} else if (properties.featureType === "route") {
newRoutes.push({
route_number: properties.name || "",
path: geometry.coordinates,
});
} else if (properties.featureType === "sight") {
newSights.push({
name: properties.name || "",
description: properties.description || "",
latitude: geometry.coordinates[1],
longitude: geometry.coordinates[0],
});
}
}
}
const requests: Promise<any>[] = [];
newStations.forEach((data) =>
requests.push(languageInstance("ru").post("/station", data))
);
newRoutes.forEach((data) =>
requests.push(languageInstance("ru").post("/route", data))
);
newSights.forEach((data) =>
requests.push(languageInstance("ru").post("/sight", data))
);
updatedStations.forEach(({ id, ...data }) =>
requests.push(languageInstance("ru").patch(`/station/${id}`, data))
);
updatedRoutes.forEach(({ id, ...data }) =>
requests.push(languageInstance("ru").patch(`/route/${id}`, data))
);
updatedSights.forEach(({ id, ...data }) =>
requests.push(languageInstance("ru").patch(`/sight/${id}`, data))
);
if (requests.length === 0) {
return;
}
try {
await Promise.all(requests);
await Promise.all([
this.getRoutes(),
this.getStations(),
this.getSights(),
]);
} catch (error) {
console.error("Ошибка при сохранении данных:", error);
throw error;
}
};
}
export default new MapStore();