fix: Hot bug fix

This commit is contained in:
2025-06-15 20:38:48 +03:00
parent 481385c2f4
commit 32a7cb44d1
24 changed files with 900 additions and 250 deletions

View File

@@ -35,11 +35,49 @@ export const RouteCreatePage = observer(() => {
const [centerLng, setCenterLng] = useState("");
const [isLoading, setIsLoading] = useState(false);
const { language } = languageStore;
useEffect(() => {
carrierStore.getCarriers(language);
articlesStore.getArticleList();
}, [language]);
const validateCoordinates = (value: string) => {
try {
const lines = value.trim().split("\n");
const coordinates = lines.map((line) => {
const [lat, lon] = line
.trim()
.split(/[\s,]+/)
.map(Number);
return [lat, lon];
});
if (coordinates.length === 0) {
return "Введите хотя бы одну пару координат";
}
if (
!coordinates.every(
(point) => Array.isArray(point) && point.length === 2
)
) {
return "Каждая строка должна содержать две координаты";
}
if (
!coordinates.every((point) =>
point.every((coord) => !isNaN(coord) && typeof coord === "number")
)
) {
return "Координаты должны быть числами";
}
return true;
} catch {
return "Неверный формат координат";
}
};
const handleCreateRoute = async () => {
try {
setIsLoading(true);
@@ -52,16 +90,24 @@ export const RouteCreatePage = observer(() => {
const center_latitude = centerLat ? Number(centerLat) : undefined;
const center_longitude = centerLng ? Number(centerLng) : undefined;
const route_direction = direction === "forward";
const validationResult = validateCoordinates(routeCoords);
if (validationResult !== true) {
toast.error(validationResult);
return;
}
// Координаты маршрута как массив массивов чисел
const path = routeCoords
.trim()
.split("\n")
.map((line) =>
line
.split(" ")
.map((coord) => Number(coord.trim()))
.filter((n) => !isNaN(n))
)
.filter((arr) => arr.length === 2);
.map((line) => {
const [lat, lon] = line
.trim()
.split(/[\s,]+/)
.map(Number);
return [lat, lon];
});
// Собираем объект маршрута
const newRoute: Partial<Route> = {
@@ -141,9 +187,33 @@ export const RouteCreatePage = observer(() => {
className="w-full"
label="Координаты маршрута"
multiline
minRows={3}
minRows={4}
value={routeCoords}
onChange={(e) => setRouteCoords(e.target.value)}
onChange={(e) => {
const newValue = e.target.value;
setRouteCoords(newValue);
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
const lines = routeCoords.split("\n");
const lastLine = lines[lines.length - 1];
// Если мы на последней строке и она не пустая
if (lastLine && lastLine.trim()) {
e.preventDefault();
const newValue = routeCoords + "\n";
setRouteCoords(newValue);
}
}
}}
error={validateCoordinates(routeCoords) !== true}
helperText={
typeof validateCoordinates(routeCoords) === "string"
? validateCoordinates(routeCoords)
: "Введите координаты в формате: широта долгота (можно использовать запятые или пробелы)"
}
placeholder="55.7558 37.6173
55.7539 37.6208"
/>
<TextField
className="w-full"

View File

@@ -27,6 +27,8 @@ export const RouteEditPage = observer(() => {
const { editRouteData } = routeStore;
const [isLoading, setIsLoading] = useState(false);
const { language } = languageStore;
const [coordinates, setCoordinates] = useState<string>("");
useEffect(() => {
const fetchData = async () => {
const response = await routeStore.getRoute(Number(id));
@@ -37,6 +39,15 @@ export const RouteEditPage = observer(() => {
fetchData();
}, [id, language]);
useEffect(() => {
if (editRouteData.path && editRouteData.path.length > 0) {
const formattedPath = editRouteData.path
.map((coords) => coords.join(" "))
.join("\n");
setCoordinates(formattedPath);
}
}, [editRouteData.path]);
const handleSave = async () => {
setIsLoading(true);
await routeStore.editRoute(Number(id));
@@ -44,6 +55,43 @@ export const RouteEditPage = observer(() => {
setIsLoading(false);
};
const validateCoordinates = (value: string) => {
try {
const lines = value.trim().split("\n");
const coordinates = lines.map((line) => {
const [lat, lon] = line
.trim()
.split(/[\s,]+/)
.map(Number);
return [lat, lon];
});
if (coordinates.length === 0) {
return "Введите хотя бы одну пару координат";
}
if (
!coordinates.every(
(point) => Array.isArray(point) && point.length === 2
)
) {
return "Каждая строка должна содержать две координаты";
}
if (
!coordinates.every((point) =>
point.every((coord) => !isNaN(coord) && typeof coord === "number")
)
) {
return "Координаты должны быть числами";
}
return true;
} catch {
return "Неверный формат координат";
}
};
return (
<Paper className="w-full h-full p-3 flex flex-col gap-10">
<LanguageSwitcher />
@@ -105,15 +153,46 @@ export const RouteEditPage = observer(() => {
className="w-full"
label="Координаты маршрута"
multiline
minRows={3}
value={editRouteData.path.map((p) => p.join(" ")).join("\n") || ""}
onChange={(e) =>
routeStore.setEditRouteData({
path: e.target.value
.split("\n")
.map((line) => line.split(" ").map(Number)),
})
minRows={4}
value={coordinates}
onChange={(e) => {
const newValue = e.target.value;
setCoordinates(newValue);
const validationResult = validateCoordinates(newValue);
if (validationResult === true) {
const lines = newValue.trim().split("\n");
const path = lines.map((line) => {
const [lat, lon] = line
.trim()
.split(/[\s,]+/)
.map(Number);
return [lat, lon];
});
routeStore.setEditRouteData({ path });
}
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
const lines = coordinates.split("\n");
const lastLine = lines[lines.length - 1];
// Если мы на последней строке и она не пустая
if (lastLine && lastLine.trim()) {
e.preventDefault();
const newValue = coordinates + "\n";
setCoordinates(newValue);
}
}
}}
error={validateCoordinates(coordinates) !== true}
helperText={
typeof validateCoordinates(coordinates) === "string"
? validateCoordinates(coordinates)
: "Введите координаты в формате: широта долгота (можно использовать запятые или пробелы)"
}
placeholder="55.7558 37.6173
55.7539 37.6208"
/>
<TextField
className="w-full"

View File

@@ -1,5 +1,5 @@
import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid";
import { languageStore, routeStore } from "@shared";
import { carrierStore, languageStore, routeStore } from "@shared";
import { useEffect, useState } from "react";
import { observer } from "mobx-react-lite";
import { Map, Pencil, Trash2, Minus } from "lucide-react";
@@ -9,6 +9,7 @@ import { LanguageSwitcher } from "@widgets";
export const RouteListPage = observer(() => {
const { routes, getRoutes, deleteRoute } = routeStore;
const { carriers, getCarriers } = carrierStore;
const navigate = useNavigate();
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isBulkDeleteModalOpen, setIsBulkDeleteModalOpen] = useState(false);
@@ -17,19 +18,27 @@ export const RouteListPage = observer(() => {
const { language } = languageStore;
useEffect(() => {
getRoutes();
const fetchData = async () => {
await getCarriers("ru");
await getCarriers("en");
await getCarriers("zh");
await getRoutes();
};
fetchData();
}, [language]);
const columns: GridColDef[] = [
{
field: "carrier",
field: "carrier_id",
headerName: "Перевозчик",
width: 250,
renderCell: (params: GridRenderCellParams) => {
return (
<div className="w-full h-full flex items-center">
{params.value ? (
params.value
carriers[language].data.find(
(carrier) => carrier.id == params.value
)?.short_name
) : (
<Minus size={20} className="text-red-500" />
)}
@@ -105,7 +114,7 @@ export const RouteListPage = observer(() => {
const rows = routes.data.map((route) => ({
id: route.id,
carrier: route.carrier,
carrier_id: route.carrier_id,
route_number: route.route_number,
route_direction: route.route_direction ? "Прямой" : "Обратный",
}));