import { Button, Paper, TextField, Select, MenuItem, FormControl, InputLabel, Typography, Box, Dialog, DialogTitle, DialogContent, DialogActions, } from "@mui/material"; import { MediaViewer } from "@widgets"; import { observer } from "mobx-react-lite"; import { ArrowLeft, Loader2, Save, Plus } from "lucide-react"; import { useEffect, useState, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { toast } from "react-toastify"; import { carrierStore } from "../../../shared/store/CarrierStore"; import { articlesStore } from "../../../shared/store/ArticlesStore"; import { Route, routeStore } from "../../../shared/store/RouteStore"; import { languageStore, SelectArticleModal, SelectMediaDialog, selectedCityStore, } from "@shared"; export const RouteCreatePage = observer(() => { const navigate = useNavigate(); const [carrier, setCarrier] = useState(""); const [routeNumber, setRouteNumber] = useState(""); const [routeCoords, setRouteCoords] = useState(""); const [govRouteNumber, setGovRouteNumber] = useState(""); const [governorAppeal, setGovernorAppeal] = useState(""); const [direction, setDirection] = useState("backward"); const [scaleMin, setScaleMin] = useState(""); const [scaleMax, setScaleMax] = useState(""); const [turn, setTurn] = useState(""); const [centerLat, setCenterLat] = useState(""); const [centerLng, setCenterLng] = useState(""); const [videoPreview, setVideoPreview] = useState(""); const [isLoading, setIsLoading] = useState(false); const [isSelectArticleDialogOpen, setIsSelectArticleDialogOpen] = useState(false); const [isSelectVideoDialogOpen, setIsSelectVideoDialogOpen] = useState(false); const [isVideoPreviewOpen, setIsVideoPreviewOpen] = useState(false); const { language } = languageStore; useEffect(() => { carrierStore.getCarriers(language); articlesStore.getArticleList(); }, [language]); // Фильтруем перевозчиков только из выбранного города const filteredCarriers = useMemo(() => { const carriers = carrierStore.carriers[language as keyof typeof carrierStore.carriers] .data || []; if (!selectedCityStore.selectedCityId) { return carriers; } return carriers.filter( (carrier: any) => carrier.city_id === selectedCityStore.selectedCityId ); }, [carrierStore.carriers, language, selectedCityStore.selectedCityId]); 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 handleArticleSelect = (articleId: number) => { setGovernorAppeal(articleId.toString()); setIsSelectArticleDialogOpen(false); }; const handleVideoSelect = (media: { id: string; filename: string; media_name?: string; media_type: number; }) => { setVideoPreview(media.id); setIsSelectVideoDialogOpen(false); }; const handleVideoPreviewClick = () => { setIsVideoPreviewOpen(true); }; const handleCreateRoute = async () => { try { setIsLoading(true); // Преобразуем значения в нужные типы const carrier_id = Number(carrier); const governor_appeal = Number(governorAppeal); const scale_min = scaleMin ? Number(scaleMin) : undefined; const scale_max = scaleMax ? Number(scaleMax) : undefined; const rotate = turn ? Number(turn) : undefined; 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) => { const [lat, lon] = line .trim() .split(/[\s,]+/) .map(Number); return [lat, lon]; }); // Собираем объект маршрута const newRoute: Partial = { carrier: carrierStore.carriers[ language as keyof typeof carrierStore.carriers ].data?.find((c: any) => c.id === carrier_id)?.full_name || "", carrier_id, route_number: routeNumber, route_sys_number: govRouteNumber, governor_appeal, route_direction, scale_min, scale_max, rotate, center_latitude, center_longitude, path, video_preview: videoPreview && videoPreview !== "" ? videoPreview : undefined, }; await routeStore.createRoute(newRoute); toast.success("Маршрут успешно создан"); navigate(-1); } catch (error) { console.error(error); toast.error("Произошла ошибка при создании маршрута"); } finally { setIsLoading(false); } }; // Получаем название выбранной статьи для отображения const selectedArticle = articlesStore.articleList.ru.data.find( (article) => article.id === Number(governorAppeal) ); return (
Выберите перевозчика setRouteNumber(e.target.value)} /> { 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" sx={{ "& .MuiInputBase-root": { maxHeight: "500px", overflow: "auto", }, "& .MuiInputBase-input": { fontFamily: "monospace", fontSize: "0.8rem", lineHeight: "1.2", padding: "8px 12px", }, "& .MuiFormHelperText-root": { fontSize: "0.75rem", marginTop: "2px", }, }} /> setGovRouteNumber(e.target.value)} /> {/* Заменяем Select на кнопку для выбора статьи */} {/* Селектор видеозаставки */} {videoPreview && videoPreview !== "" ? "Видео выбрано" : "Видео не выбрано"} {videoPreview && videoPreview !== "" && ( { e.stopPropagation(); setVideoPreview(""); }} sx={{ cursor: "pointer", color: "#999", "&:hover": { color: "#666", }, }} > × )} Прямой/обратный маршрут setScaleMin(e.target.value)} /> setScaleMax(e.target.value)} /> setTurn(e.target.value)} /> setCenterLat(e.target.value)} /> setCenterLng(e.target.value)} />
{/* Модальное окно выбора статьи */} setIsSelectArticleDialogOpen(false)} onSelectArticle={handleArticleSelect} /> {/* Модальное окно выбора видео */} setIsSelectVideoDialogOpen(false)} onSelectMedia={handleVideoSelect} mediaType={2} /> {/* Модальное окно предпросмотра видео */} {videoPreview && videoPreview !== "" && ( setIsVideoPreviewOpen(false)} maxWidth="md" fullWidth > Предпросмотр видео )}
); });