fix: Fix errors

This commit is contained in:
2025-10-10 08:40:39 +03:00
parent c50ccb3a0c
commit cdb96dfb8b
17 changed files with 139 additions and 25 deletions

View File

@@ -46,6 +46,7 @@ export const ArticleListPage = observer(() => {
{ {
field: "actions", field: "actions",
headerName: "Действия", headerName: "Действия",
sortable: false,
renderCell: (params: GridRenderCellParams) => { renderCell: (params: GridRenderCellParams) => {
return ( return (

View File

@@ -88,6 +88,7 @@ export const CarrierListPage = observer(() => {
headerName: "Действия", headerName: "Действия",
headerAlign: "center", headerAlign: "center",
width: 200, width: 200,
sortable: false,
renderCell: (params: GridRenderCellParams) => { renderCell: (params: GridRenderCellParams) => {
return ( return (

View File

@@ -93,6 +93,7 @@ export const CityListPage = observer(() => {
align: "center", align: "center",
headerAlign: "center", headerAlign: "center",
width: 200, width: 200,
sortable: false,
renderCell: (params: GridRenderCellParams) => { renderCell: (params: GridRenderCellParams) => {
return ( return (
<div className="flex h-full gap-7 justify-center items-center"> <div className="flex h-full gap-7 justify-center items-center">

View File

@@ -50,6 +50,7 @@ export const CountryListPage = observer(() => {
align: "center", align: "center",
headerAlign: "center", headerAlign: "center",
width: 200, width: 200,
sortable: false,
renderCell: (params: GridRenderCellParams) => { renderCell: (params: GridRenderCellParams) => {
return ( return (
<div className="flex h-full gap-7 justify-center items-center"> <div className="flex h-full gap-7 justify-center items-center">

View File

@@ -132,6 +132,7 @@ interface ApiStation {
longitude: number; longitude: number;
city_id: number; city_id: number;
created_at?: string; created_at?: string;
updated_at?: string;
} }
interface ApiSight { interface ApiSight {
@@ -142,9 +143,16 @@ interface ApiSight {
longitude: number; longitude: number;
city_id: number; city_id: number;
created_at?: string; created_at?: string;
updated_at?: string;
} }
export type SortType = "name_asc" | "name_desc" | "date_asc" | "date_desc"; export type SortType =
| "name_asc"
| "name_desc"
| "created_asc"
| "created_desc"
| "updated_asc"
| "updated_desc";
class MapStore { class MapStore {
constructor() { constructor() {
@@ -179,7 +187,7 @@ class MapStore {
return sorted.sort((a, b) => a.name.localeCompare(b.name)); return sorted.sort((a, b) => a.name.localeCompare(b.name));
case "name_desc": case "name_desc":
return sorted.sort((a, b) => b.name.localeCompare(a.name)); return sorted.sort((a, b) => b.name.localeCompare(a.name));
case "date_asc": case "created_asc":
return sorted.sort((a, b) => { return sorted.sort((a, b) => {
if ( if (
"created_at" in a && "created_at" in a &&
@@ -195,7 +203,7 @@ class MapStore {
// Фоллбэк: сортировка по ID, если дата недоступна // Фоллбэк: сортировка по ID, если дата недоступна
return a.id - b.id; return a.id - b.id;
}); });
case "date_desc": case "created_desc":
return sorted.sort((a, b) => { return sorted.sort((a, b) => {
if ( if (
"created_at" in a && "created_at" in a &&
@@ -211,6 +219,32 @@ class MapStore {
// Фоллбэк: сортировка по ID, если дата недоступна // Фоллбэк: сортировка по ID, если дата недоступна
return b.id - a.id; return b.id - a.id;
}); });
case "updated_asc":
return sorted.sort((a, b) => {
const aUpdated =
("updated_at" in a && a.updated_at) ||
("created_at" in a && a.created_at);
const bUpdated =
("updated_at" in b && b.updated_at) ||
("created_at" in b && b.created_at);
if (typeof aUpdated === "string" && typeof bUpdated === "string") {
return new Date(aUpdated).getTime() - new Date(bUpdated).getTime();
}
return a.id - b.id;
});
case "updated_desc":
return sorted.sort((a, b) => {
const aUpdated =
("updated_at" in a && a.updated_at) ||
("created_at" in a && a.created_at);
const bUpdated =
("updated_at" in b && b.updated_at) ||
("created_at" in b && b.created_at);
if (typeof aUpdated === "string" && typeof bUpdated === "string") {
return new Date(bUpdated).getTime() - new Date(aUpdated).getTime();
}
return b.id - a.id;
});
default: default:
return sorted; return sorted;
} }
@@ -626,6 +660,7 @@ class MapService {
private selectedIds: Set<string | number> = new Set(); private selectedIds: Set<string | number> = new Set();
private onSelectionChange: ((ids: Set<string | number>) => void) | null = private onSelectionChange: ((ids: Set<string | number>) => void) | null =
null; null;
private isCreating: boolean = false;
// Styles // Styles
private defaultStyle: Style; private defaultStyle: Style;
@@ -1397,6 +1432,21 @@ class MapService {
const feature = event.feature as Feature<Geometry>; const feature = event.feature as Feature<Geometry>;
const fType = this.currentDrawingFeatureType; const fType = this.currentDrawingFeatureType;
if (!fType) return; if (!fType) return;
// Проверяем, не идет ли уже процесс создания
if (this.isCreating) {
toast.warning("Дождитесь завершения создания предыдущего объекта.");
// Удаляем созданный объект из источника
const sourceForDrawing =
type === "Point" ? this.pointSource : this.lineSource;
setTimeout(() => {
if (sourceForDrawing.hasFeature(feature as any)) {
sourceForDrawing.removeFeature(feature as any);
}
}, 0);
return;
}
feature.set("featureType", fType); feature.set("featureType", fType);
let resourceName: string; let resourceName: string;
@@ -1483,6 +1533,13 @@ class MapService {
public finishDrawing(): void { public finishDrawing(): void {
if (!this.currentInteraction) return; if (!this.currentInteraction) return;
// Блокируем завершение рисования, если идет процесс создания
if (this.isCreating) {
toast.warning("Дождитесь завершения создания предыдущего объекта.");
return;
}
try { try {
this.currentInteraction.finishDrawing(); this.currentInteraction.finishDrawing();
} catch (e) { } catch (e) {
@@ -1830,6 +1887,22 @@ class MapService {
const featureType = feature.get("featureType") as FeatureType; const featureType = feature.get("featureType") as FeatureType;
if (!featureType || !this.map) return; if (!featureType || !this.map) return;
// Проверяем, не идет ли уже процесс создания
if (this.isCreating) {
toast.warning("Дождитесь завершения создания предыдущего объекта.");
// Удаляем незавершенный объект с карты
if (feature.getGeometry()?.getType() === "LineString") {
if (this.lineSource.hasFeature(feature as Feature<LineString>))
this.lineSource.removeFeature(feature as Feature<LineString>);
} else {
if (this.pointSource.hasFeature(feature as Feature<Point>))
this.pointSource.removeFeature(feature as Feature<Point>);
}
return;
}
this.isCreating = true;
const geoJSONFormat = new GeoJSON({ const geoJSONFormat = new GeoJSON({
dataProjection: "EPSG:4326", dataProjection: "EPSG:4326",
featureProjection: this.map.getView().getProjection().getCode(), featureProjection: this.map.getView().getProjection().getCode(),
@@ -1890,6 +1963,8 @@ class MapService {
if (this.pointSource.hasFeature(feature as Feature<Point>)) if (this.pointSource.hasFeature(feature as Feature<Point>))
this.pointSource.removeFeature(feature as Feature<Point>); this.pointSource.removeFeature(feature as Feature<Point>);
} }
} finally {
this.isCreating = false;
} }
} }
} }
@@ -2153,7 +2228,7 @@ const MapSightbar: React.FC<MapSightbarProps> = observer(
(a.get("name") as string) || "" (a.get("name") as string) || ""
) )
); );
case "date_asc": case "created_asc":
return sorted.sort((a, b) => { return sorted.sort((a, b) => {
const aDate = a.get("created_at") const aDate = a.get("created_at")
? new Date(a.get("created_at")) ? new Date(a.get("created_at"))
@@ -2163,7 +2238,7 @@ const MapSightbar: React.FC<MapSightbarProps> = observer(
: new Date(0); : new Date(0);
return aDate.getTime() - bDate.getTime(); return aDate.getTime() - bDate.getTime();
}); });
case "date_desc": case "created_desc":
return sorted.sort((a, b) => { return sorted.sort((a, b) => {
const aDate = a.get("created_at") const aDate = a.get("created_at")
? new Date(a.get("created_at")) ? new Date(a.get("created_at"))
@@ -2173,6 +2248,34 @@ const MapSightbar: React.FC<MapSightbarProps> = observer(
: new Date(0); : new Date(0);
return bDate.getTime() - aDate.getTime(); return bDate.getTime() - aDate.getTime();
}); });
case "updated_asc":
return sorted.sort((a, b) => {
const aDate = a.get("updated_at")
? new Date(a.get("updated_at"))
: a.get("created_at")
? new Date(a.get("created_at"))
: new Date(0);
const bDate = b.get("updated_at")
? new Date(b.get("updated_at"))
: b.get("created_at")
? new Date(b.get("created_at"))
: new Date(0);
return aDate.getTime() - bDate.getTime();
});
case "updated_desc":
return sorted.sort((a, b) => {
const aDate = a.get("updated_at")
? new Date(a.get("updated_at"))
: a.get("created_at")
? new Date(a.get("created_at"))
: new Date(0);
const bDate = b.get("updated_at")
? new Date(b.get("updated_at"))
: b.get("created_at")
? new Date(b.get("created_at"))
: new Date(0);
return bDate.getTime() - aDate.getTime();
});
default: default:
return sorted; return sorted;
} }
@@ -2305,6 +2408,10 @@ const MapSightbar: React.FC<MapSightbarProps> = observer(
> >
<option value="name_asc">Имя </option> <option value="name_asc">Имя </option>
<option value="name_desc">Имя </option> <option value="name_desc">Имя </option>
<option value="created_asc">Дата создания </option>
<option value="created_desc">Дата создания </option>
<option value="updated_asc">Дата обновления </option>
<option value="updated_desc">Дата обновления </option>
</select> </select>
</div> </div>
), ),
@@ -2333,6 +2440,10 @@ const MapSightbar: React.FC<MapSightbarProps> = observer(
> >
<option value="name_asc">Имя </option> <option value="name_asc">Имя </option>
<option value="name_desc">Имя </option> <option value="name_desc">Имя </option>
<option value="created_asc">Дата создания </option>
<option value="created_desc">Дата создания </option>
<option value="updated_asc">Дата обновления </option>
<option value="updated_desc">Дата обновления </option>
</select> </select>
</div> </div>
), ),

View File

@@ -69,6 +69,7 @@ export const MediaListPage = observer(() => {
width: 200, width: 200,
align: "center", align: "center",
headerAlign: "center", headerAlign: "center",
sortable: false,
renderCell: (params: GridRenderCellParams) => { renderCell: (params: GridRenderCellParams) => {
return ( return (

View File

@@ -90,6 +90,7 @@ export const RouteListPage = observer(() => {
width: 250, width: 250,
align: "center", align: "center",
headerAlign: "center", headerAlign: "center",
sortable: false,
renderCell: (params: GridRenderCellParams) => { renderCell: (params: GridRenderCellParams) => {
return ( return (
<div className="flex h-full gap-7 justify-center items-center"> <div className="flex h-full gap-7 justify-center items-center">

View File

@@ -54,16 +54,16 @@ export function InfiniteCanvas({
const lastOriginalRotation = useRef<number | undefined>(undefined); const lastOriginalRotation = useRef<number | undefined>(undefined);
useEffect(() => { useEffect(() => {
const canvas = applicationRef?.app?.canvas; if (!applicationRef?.app?.canvas) return;
if (!canvas) return;
const canvas = applicationRef.app.canvas;
const canvasRect = canvas.getBoundingClientRect(); const canvasRect = canvas.getBoundingClientRect();
const canvasLeft = canvasRect.left; const canvasLeft = canvasRect.left;
const canvasTop = canvasRect.top; const canvasTop = canvasRect.top;
const centerX = window.innerWidth / 2 - canvasLeft; const centerX = window.innerWidth / 2 - canvasLeft;
const centerY = window.innerHeight / 2 - canvasTop; const centerY = window.innerHeight / 2 - canvasTop;
setScreenCenter({ x: centerX, y: centerY }); setScreenCenter({ x: centerX, y: centerY });
}, [applicationRef?.app?.canvas, setScreenCenter]); }, [applicationRef?.app, setScreenCenter]);
const handlePointerDown = (e: FederatedMouseEvent) => { const handlePointerDown = (e: FederatedMouseEvent) => {
setIsPointerDown(true); setIsPointerDown(true);

View File

@@ -101,7 +101,6 @@ export function RightSidebar() {
} }
if (!routeData) { if (!routeData) {
console.error("routeData is null");
return null; return null;
} }

View File

@@ -166,7 +166,7 @@ export const RouteMap = observer(() => {
return ( return (
<div style={{ width: "100%", height: "100%" }} ref={parentRef}> <div style={{ width: "100%", height: "100%" }} ref={parentRef}>
<LanguageSwitcher /> <LanguageSwitcher />
<Application resizeTo={parentRef} background="#fff"> <Application resizeTo={parentRef} background="#fff" preference="webgl">
<InfiniteCanvas> <InfiniteCanvas>
<TravelPath points={points} /> <TravelPath points={points} />
{stationData[language].map((obj, index) => ( {stationData[language].map((obj, index) => (

View File

@@ -73,6 +73,7 @@ export const SightListPage = observer(() => {
headerName: "Действия", headerName: "Действия",
align: "center", align: "center",
headerAlign: "center", headerAlign: "center",
sortable: false,
renderCell: (params: GridRenderCellParams) => { renderCell: (params: GridRenderCellParams) => {
return ( return (

View File

@@ -2,23 +2,16 @@ import { Button, TextField } from "@mui/material";
import { snapshotStore } from "@shared"; import { snapshotStore } from "@shared";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { ArrowLeft, Loader2, Save } from "lucide-react"; import { ArrowLeft, Loader2, Save } from "lucide-react";
import { useEffect, useState } from "react"; import { useState } from "react";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
export const SnapshotCreatePage = observer(() => { export const SnapshotCreatePage = observer(() => {
const { id } = useParams(); const { createSnapshot } = snapshotStore;
const { getSnapshot, createSnapshot } = snapshotStore;
const navigate = useNavigate(); const navigate = useNavigate();
const [name, setName] = useState(""); const [name, setName] = useState("");
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
(async () => {
await getSnapshot(id as string);
})();
}, [id]);
return ( return (
<div className="w-full h-[400px] flex justify-center items-center"> <div className="w-full h-[400px] flex justify-center items-center">
<div className="w-full h-full p-3 flex flex-col gap-10"> <div className="w-full h-full p-3 flex flex-col gap-10">

View File

@@ -43,6 +43,7 @@ export const SnapshotListPage = observer(() => {
headerName: "Действия", headerName: "Действия",
width: 300, width: 300,
headerAlign: "center", headerAlign: "center",
sortable: false,
renderCell: (params: GridRenderCellParams) => { renderCell: (params: GridRenderCellParams) => {
return ( return (

View File

@@ -6,7 +6,7 @@ import {
selectedCityStore, selectedCityStore,
cityStore, cityStore,
} from "@shared"; } from "@shared";
import { useEffect, useState, useMemo } from "react"; import { useEffect, useState } from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { Eye, Pencil, Trash2, Minus } from "lucide-react"; import { Eye, Pencil, Trash2, Minus } from "lucide-react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
@@ -91,6 +91,7 @@ export const StationListPage = observer(() => {
width: 140, width: 140,
align: "center", align: "center",
headerAlign: "center", headerAlign: "center",
sortable: false,
renderCell: (params: GridRenderCellParams) => { renderCell: (params: GridRenderCellParams) => {
return ( return (
@@ -116,7 +117,7 @@ export const StationListPage = observer(() => {
]; ];
// Фильтрация станций по выбранному городу // Фильтрация станций по выбранному городу
const filteredStations = useMemo(() => { const filteredStations = () => {
const { selectedCityId } = selectedCityStore; const { selectedCityId } = selectedCityStore;
if (!selectedCityId) { if (!selectedCityId) {
return stationLists[language].data; return stationLists[language].data;
@@ -124,9 +125,9 @@ export const StationListPage = observer(() => {
return stationLists[language].data.filter( return stationLists[language].data.filter(
(station: any) => station.city_id === selectedCityId (station: any) => station.city_id === selectedCityId
); );
}, [stationLists, language, selectedCityStore.selectedCityId]); };
const rows = filteredStations.map((station: any) => ({ const rows = filteredStations().map((station: any) => ({
id: station.id, id: station.id,
name: station.name, name: station.name,
system_name: station.system_name, system_name: station.system_name,

View File

@@ -83,6 +83,7 @@ export const UserListPage = observer(() => {
flex: 1, flex: 1,
align: "center", align: "center",
headerAlign: "center", headerAlign: "center",
sortable: false,
renderCell: (params: GridRenderCellParams) => { renderCell: (params: GridRenderCellParams) => {
return ( return (

View File

@@ -102,6 +102,7 @@ export const VehicleListPage = observer(() => {
width: 200, width: 200,
align: "center", align: "center",
headerAlign: "center", headerAlign: "center",
sortable: false,
renderCell: (params: GridRenderCellParams) => { renderCell: (params: GridRenderCellParams) => {
return ( return (

File diff suppressed because one or more lines are too long