fix: Update map with tables fixes

This commit is contained in:
2025-07-09 18:56:18 +03:00
parent 78800ee2ae
commit e2547cb571
87 changed files with 5392 additions and 1410 deletions

View File

@@ -6,19 +6,23 @@ import {
MenuItem,
FormControl,
InputLabel,
// Typography,
Typography,
Box,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
} from "@mui/material";
import { LanguageSwitcher } from "@widgets";
import { MediaViewer } from "@widgets";
import { observer } from "mobx-react-lite";
import { ArrowLeft, Loader2, Save } from "lucide-react";
import { ArrowLeft, Loader2, Save, Plus } from "lucide-react";
import { useEffect, useState } 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 } from "@shared";
import { languageStore, SelectArticleModal, SelectMediaDialog } from "@shared";
export const RouteCreatePage = observer(() => {
const navigate = useNavigate();
@@ -33,7 +37,12 @@ export const RouteCreatePage = observer(() => {
const [turn, setTurn] = useState("");
const [centerLat, setCenterLat] = useState("");
const [centerLng, setCenterLng] = useState("");
const [videoPreview, setVideoPreview] = useState<string>("");
const [isLoading, setIsLoading] = useState(false);
const [isSelectArticleDialogOpen, setIsSelectArticleDialogOpen] =
useState(false);
const [isSelectVideoDialogOpen, setIsSelectVideoDialogOpen] = useState(false);
const [isVideoPreviewOpen, setIsVideoPreviewOpen] = useState(false);
const { language } = languageStore;
useEffect(() => {
@@ -78,6 +87,25 @@ export const RouteCreatePage = observer(() => {
}
};
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);
@@ -126,6 +154,8 @@ export const RouteCreatePage = observer(() => {
center_latitude,
center_longitude,
path,
video_preview:
videoPreview && videoPreview !== "" ? videoPreview : undefined,
};
await routeStore.createRoute(newRoute);
@@ -139,9 +169,13 @@ export const RouteCreatePage = observer(() => {
}
};
// Получаем название выбранной статьи для отображения
const selectedArticle = articlesStore.articleList.ru.data.find(
(article) => article.id === Number(governorAppeal)
);
return (
<Paper className="w-full h-full p-3 flex flex-col gap-10">
<LanguageSwitcher />
<div className="flex items-center gap-4">
<button
className="flex items-center gap-2"
@@ -184,9 +218,11 @@ export const RouteCreatePage = observer(() => {
onChange={(e) => setRouteNumber(e.target.value)}
/>
<TextField
className="w-full"
label="Координаты маршрута"
multiline
className="w-full max-h-[300px] overflow-y-scroll"
minRows={4}
minRows={2}
maxRows={10}
value={routeCoords}
onChange={(e) => {
const newValue = e.target.value;
@@ -209,10 +245,25 @@ export const RouteCreatePage = observer(() => {
helperText={
typeof validateCoordinates(routeCoords) === "string"
? validateCoordinates(routeCoords)
: "Введите координаты в формате: широта долгота (можно использовать запятые или пробелы)"
: "Формат: широта долгота"
}
placeholder="55.7558 37.6173
55.7539 37.6208"
placeholder="55.7558 37.6173&#10;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",
},
}}
/>
<TextField
className="w-full"
@@ -221,24 +272,75 @@ export const RouteCreatePage = observer(() => {
value={govRouteNumber}
onChange={(e) => setGovRouteNumber(e.target.value)}
/>
<FormControl fullWidth required>
<InputLabel>Обращение губернатора</InputLabel>
<Select
value={governorAppeal}
label="Обращение губернатора"
onChange={(e) => setGovernorAppeal(e.target.value as string)}
disabled={articlesStore.articleList.ru.data.length === 0}
>
<MenuItem value="">Не выбрано</MenuItem>
{articlesStore.articleList.ru.data.map(
(a: (typeof articlesStore.articleList.ru.data)[number]) => (
<MenuItem key={a.id} value={a.id}>
{a.heading}
</MenuItem>
)
)}
</Select>
</FormControl>
{/* Заменяем Select на кнопку для выбора статьи */}
<Box className="flex flex-col gap-2">
<label className="text-sm font-medium text-gray-700">
Обращение к пассажирам
</label>
<Box className="flex gap-2">
<TextField
className="flex-1"
value={selectedArticle?.heading || "Статья не выбрана"}
placeholder="Выберите статью"
disabled
sx={{
"& .MuiInputBase-input": {
color: selectedArticle ? "inherit" : "#999",
},
}}
/>
<Button
variant="outlined"
onClick={() => setIsSelectArticleDialogOpen(true)}
startIcon={<Plus size={16} />}
sx={{ minWidth: "auto", px: 2 }}
>
Выбрать
</Button>
</Box>
</Box>
{/* Селектор видео превью */}
<Box className="flex flex-col gap-2">
<label className="text-sm font-medium text-gray-700">
Видео превью
</label>
<Box className="flex gap-2">
<Typography
variant="body1"
onClick={handleVideoPreviewClick}
component="span"
className="flex-1"
sx={{
color:
videoPreview && videoPreview !== "" ? "inherit" : "#999",
cursor:
videoPreview && videoPreview !== "" ? "pointer" : "default",
border: "1px solid #ccc",
borderRadius: "4px",
padding: "16.5px 14px",
display: "flex",
alignItems: "center",
minHeight: "56px",
backgroundColor: "#fff",
}}
>
{videoPreview && videoPreview !== ""
? "Видео выбрано"
: "Видео не выбрано"}
</Typography>
<Button
variant="outlined"
onClick={() => setIsSelectVideoDialogOpen(true)}
startIcon={<Plus size={16} />}
sx={{ minWidth: "auto", px: 2 }}
>
Выбрать
</Button>
</Box>
</Box>
<FormControl fullWidth required>
<InputLabel>Прямой/обратный маршрут</InputLabel>
<Select
@@ -298,6 +400,49 @@ export const RouteCreatePage = observer(() => {
</Button>
</div>
</div>
{/* Модальное окно выбора статьи */}
<SelectArticleModal
open={isSelectArticleDialogOpen}
onClose={() => setIsSelectArticleDialogOpen(false)}
onSelectArticle={handleArticleSelect}
/>
{/* Модальное окно выбора видео */}
<SelectMediaDialog
open={isSelectVideoDialogOpen}
onClose={() => setIsSelectVideoDialogOpen(false)}
onSelectMedia={handleVideoSelect}
mediaType={2}
/>
{/* Модальное окно предпросмотра видео */}
{videoPreview && videoPreview !== "" && (
<Dialog
open={isVideoPreviewOpen}
onClose={() => setIsVideoPreviewOpen(false)}
maxWidth="md"
fullWidth
>
<DialogTitle>Предпросмотр видео</DialogTitle>
<DialogContent>
<Box className="flex justify-center items-center p-4">
<MediaViewer
media={{
id: videoPreview,
media_type: 2,
filename: "video_preview",
}}
/>
</Box>
</DialogContent>
<DialogActions>
<Button onClick={() => setIsVideoPreviewOpen(false)}>
Закрыть
</Button>
</DialogActions>
</Dialog>
)}
</Paper>
);
});