import { Button, Paper, TextField, Select, MenuItem, FormControl, InputLabel, Typography, Box, Dialog, DialogTitle, DialogContent, DialogActions, } from "@mui/material"; import { MediaViewer, VideoPreviewCard } from "@widgets"; import { observer } from "mobx-react-lite"; import { ArrowLeft, Copy, Save, Plus } from "lucide-react"; import { useEffect, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { carrierStore } from "../../../shared/store/CarrierStore"; import { articlesStore } from "../../../shared/store/ArticlesStore"; import { routeStore, languageStore, ArticleSelectOrCreateDialog, SelectMediaDialog, UploadMediaDialog, } from "@shared"; import { toast } from "react-toastify"; import { stationsStore } from "@shared"; import { LinkedItems } from "../LinekedStations"; export const RouteEditPage = observer(() => { const navigate = useNavigate(); const { id } = useParams(); const { editRouteData, copyRouteAction } = routeStore; const [isLoading, setIsLoading] = useState(false); const [isSelectArticleDialogOpen, setIsSelectArticleDialogOpen] = useState(false); const [isSelectVideoDialogOpen, setIsSelectVideoDialogOpen] = useState(false); const [isVideoPreviewOpen, setIsVideoPreviewOpen] = useState(false); const [isUploadVideoDialogOpen, setIsUploadVideoDialogOpen] = useState(false); const [fileToUpload, setFileToUpload] = useState(null); const { language } = languageStore; const [coordinates, setCoordinates] = useState(""); useEffect(() => { const fetchData = async () => { const response = await routeStore.getRoute(Number(id)); routeStore.setEditRouteData(response); languageStore.setLanguage("ru"); }; fetchData(); }, []); useEffect(() => { const fetchData = async () => { carrierStore.getCarriers(language); stationsStore.getStations(); articlesStore.getArticleList(); }; 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 () => { // Валидация обязательных полей if (!editRouteData.route_name?.trim()) { toast.error("Заполните название маршрута"); return; } if (!editRouteData.carrier_id) { toast.error("Выберите перевозчика"); return; } if (!editRouteData.route_number?.trim()) { toast.error("Заполните номер маршрута"); return; } if (!editRouteData.route_sys_number?.trim()) { toast.error("Заполните номер маршрута в Говорящем Городе"); return; } if (!editRouteData.governor_appeal) { toast.error("Выберите статью для обращения к пассажирам"); return; } const validationResult = validateCoordinates(coordinates); if (validationResult !== true) { toast.error(validationResult); return; } // Валидация масштабов if ( editRouteData.scale_min !== null && editRouteData.scale_min !== undefined && editRouteData.scale_max !== null && editRouteData.scale_max !== undefined && editRouteData.scale_min > editRouteData.scale_max ) { toast.error("Максимальный масштаб не может быть меньше минимального"); return; } if ( editRouteData.scale_min === 0 || editRouteData.scale_max === 0 || editRouteData.scale_min === null || editRouteData.scale_max === null ) { toast.error("Масштабы не могут быть равны 0"); setIsLoading(false); return; } setIsLoading(true); try { await routeStore.editRoute(Number(id)); toast.success("Маршрут успешно сохранен"); } catch (error) { console.error(error); toast.error("Произошла ошибка при сохранении маршрута"); } finally { 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 "Неверный формат координат"; } }; const handleCopy = async () => { await copyRouteAction(Number(id)); toast.success("Маршрут успешно скопирован"); }; const handleArticleSelect = (articleId: number) => { routeStore.setEditRouteData({ governor_appeal: articleId, }); setIsSelectArticleDialogOpen(false); // Обновляем список статей после создания новой articlesStore.getArticleList(); }; const handleVideoSelect = (media: { id: string; filename: string; media_name?: string; media_type: number; }) => { routeStore.setEditRouteData({ video_preview: media.id, }); setIsSelectVideoDialogOpen(false); }; const handleVideoFileSelect = (file?: File) => { if (file) { setFileToUpload(file); setIsUploadVideoDialogOpen(true); } else { setIsSelectVideoDialogOpen(true); } }; const handleVideoUpload = (media: { id: string; filename: string; media_name?: string; media_type: number; }) => { routeStore.setEditRouteData({ video_preview: media.id, }); setIsUploadVideoDialogOpen(false); setFileToUpload(null); }; const handleVideoPreviewClick = () => { if (editRouteData.video_preview && editRouteData.video_preview !== "") { setIsVideoPreviewOpen(true); } }; // Получаем название выбранной статьи для отображения const selectedArticle = articlesStore.articleList.ru.data.find( (article) => article.id === editRouteData.governor_appeal ); return (
routeStore.setEditRouteData({ route_name: e.target.value, }) } /> Выберите перевозчика routeStore.setEditRouteData({ route_number: e.target.value, }) } /> { 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" 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", }, }} /> routeStore.setEditRouteData({ route_sys_number: e.target.value, }) } /> Прямой/обратный маршрут { const value = e.target.value === "" ? null : parseFloat(e.target.value); routeStore.setEditRouteData({ scale_min: value, }); // Если максимальный масштаб стал меньше минимального, обновляем его if ( value !== null && editRouteData.scale_max !== null && editRouteData.scale_max !== undefined && value > editRouteData.scale_max ) { routeStore.setEditRouteData({ scale_max: value, }); } }} required /> routeStore.setEditRouteData({ scale_max: e.target.value === "" ? null : parseFloat(e.target.value), }) } error={ editRouteData.scale_min !== null && editRouteData.scale_min !== undefined && editRouteData.scale_max !== null && editRouteData.scale_max !== undefined && editRouteData.scale_max < editRouteData.scale_min } helperText={ editRouteData.scale_min !== null && editRouteData.scale_min !== undefined && editRouteData.scale_max !== null && editRouteData.scale_max !== undefined && editRouteData.scale_max < editRouteData.scale_min ? "Максимальный масштаб не может быть меньше минимального" : "" } /> routeStore.setEditRouteData({ rotate: e.target.value === "" ? null : parseFloat(e.target.value), }) } /> routeStore.setEditRouteData({ center_latitude: e.target.value, }) } /> routeStore.setEditRouteData({ center_longitude: e.target.value, }) } /> Обращение к пассажирам { routeStore.setEditRouteData({ video_preview: "" }); }} onSelectVideoClick={handleVideoFileSelect} className="w-full" /> { routeStore.getRoute(Number(id)); }} routeDirection={editRouteData.route_direction} />
setIsSelectArticleDialogOpen(false)} onSelectArticle={handleArticleSelect} /> setIsSelectVideoDialogOpen(false)} onSelectMedia={handleVideoSelect} mediaType={2} /> setIsVideoPreviewOpen(false)} maxWidth="md" fullWidth > Предпросмотр видео {editRouteData.video_preview && ( )} { setIsUploadVideoDialogOpen(false); setFileToUpload(null); }} hardcodeType="video_preview" contextObjectName={editRouteData.route_name || "Маршрут"} contextType="sight" initialFile={fileToUpload || undefined} afterUpload={handleVideoUpload} />
); });