From 9d10fefaca47a266fed9d54a609da9e05329b5be Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Mon, 1 Dec 2025 11:05:50 +0330 Subject: [PATCH 1/4] add map to toll house --- .env.example | 1 + next.config.mjs | 4 + .../infrastructure/map/loading.jsx | 7 + .../infrastructure/map/page.js | 16 ++ .../tollHouse/ShowProjectArea/ShowBound.jsx | 29 +++ .../tollHouse/ShowProjectArea/index.jsx | 69 ++++++ .../tollHouse/TollHouseList.jsx | 23 ++ .../tollHouseMap/ClusterSwitch/index.jsx | 25 ++ .../tollHouseMap/Filter/index.jsx | 44 ++++ .../tollHouseMap/Legend/index.jsx | 35 +++ .../DialogInfoItem/ContentInfoItem.jsx | 71 ++++++ .../PointsOnMap/DialogInfoItem/index.jsx | 51 ++++ .../tollHouseMap/PointsOnMap/index.jsx | 79 ++++++ .../infrastructure/tollHouseMap/index.jsx | 231 ++++++++++++++++++ src/core/utils/headerMenu.js | 2 +- src/core/utils/routes.js | 1 + 16 files changed, 687 insertions(+), 1 deletion(-) create mode 100644 src/app/(withAuth)/(dashboardLayout)/infrastructure/map/loading.jsx create mode 100644 src/app/(withAuth)/(dashboardLayout)/infrastructure/map/page.js create mode 100644 src/components/infrastructure/tollHouse/ShowProjectArea/ShowBound.jsx create mode 100644 src/components/infrastructure/tollHouse/ShowProjectArea/index.jsx create mode 100644 src/components/infrastructure/tollHouseMap/ClusterSwitch/index.jsx create mode 100644 src/components/infrastructure/tollHouseMap/Filter/index.jsx create mode 100644 src/components/infrastructure/tollHouseMap/Legend/index.jsx create mode 100644 src/components/infrastructure/tollHouseMap/PointsOnMap/DialogInfoItem/ContentInfoItem.jsx create mode 100644 src/components/infrastructure/tollHouseMap/PointsOnMap/DialogInfoItem/index.jsx create mode 100644 src/components/infrastructure/tollHouseMap/PointsOnMap/index.jsx create mode 100644 src/components/infrastructure/tollHouseMap/index.jsx diff --git a/.env.example b/.env.example index 8368bd5..d6c1f1b 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,5 @@ HOST="rms.witel.ir" +HOST_RMTO="rms.rmto.ir" NEXT_PUBLIC_VERSION="1.8.3" NEXT_PUBLIC_API_URL="https://rms.witel.ir" NEXT_PUBLIC_MAPTILE_ENDPOINT="https://rmsmap.rmto.ir/141map" \ No newline at end of file diff --git a/next.config.mjs b/next.config.mjs index e33199c..ac3621e 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -7,6 +7,10 @@ const nextConfig = { protocol: 'https', hostname: process.env.HOST, }, + { + protocol: 'https', + hostname: process.env.HOST_RMTO, + }, ], }, }; diff --git a/src/app/(withAuth)/(dashboardLayout)/infrastructure/map/loading.jsx b/src/app/(withAuth)/(dashboardLayout)/infrastructure/map/loading.jsx new file mode 100644 index 0000000..4535a8d --- /dev/null +++ b/src/app/(withAuth)/(dashboardLayout)/infrastructure/map/loading.jsx @@ -0,0 +1,7 @@ +"use client"; +import PageLoading from "@/core/components/PageLoading"; + +const Loading = () => { + return ; +}; +export default Loading; diff --git a/src/app/(withAuth)/(dashboardLayout)/infrastructure/map/page.js b/src/app/(withAuth)/(dashboardLayout)/infrastructure/map/page.js new file mode 100644 index 0000000..a4cad6b --- /dev/null +++ b/src/app/(withAuth)/(dashboardLayout)/infrastructure/map/page.js @@ -0,0 +1,16 @@ +import WithPermission from "@/core/middlewares/withPermission"; +import TollHouseMapPage from "@/components/infrastructure/tollHouseMap"; + +export const metadata = { + title: "پراکندگی بر روی نقشه راهدارخانه ها", +}; + +const Page = () => { + return ( + + + + ); +}; + +export default Page; diff --git a/src/components/infrastructure/tollHouse/ShowProjectArea/ShowBound.jsx b/src/components/infrastructure/tollHouse/ShowProjectArea/ShowBound.jsx new file mode 100644 index 0000000..24db476 --- /dev/null +++ b/src/components/infrastructure/tollHouse/ShowProjectArea/ShowBound.jsx @@ -0,0 +1,29 @@ +import { useEffect, useRef } from "react"; +import { FeatureGroup, useMap } from "react-leaflet"; + +const ShowBound = ({ bound }) => { + const map = useMap(); + const featureRef = useRef(null); + + const safeFitBounds = (layer) => { + if (!layer || !map) return; + try { + const latLngs = layer.getLatLngs(); + map.fitBounds(latLngs, { + paddingTopLeft: [20, 20], + paddingBottomRight: [20, 20], + }); + } catch (e) { + console.warn("fitBounds failed:", e); + } + }; + + useEffect(() => { + bound?.editing?.disable(); + featureRef.current.addLayer(bound); + safeFitBounds(bound); + }, []); + + return ; +}; +export default ShowBound; diff --git a/src/components/infrastructure/tollHouse/ShowProjectArea/index.jsx b/src/components/infrastructure/tollHouse/ShowProjectArea/index.jsx new file mode 100644 index 0000000..202ef61 --- /dev/null +++ b/src/components/infrastructure/tollHouse/ShowProjectArea/index.jsx @@ -0,0 +1,69 @@ +const { IconButton, Tooltip, Box, Dialog, DialogTitle, Typography, DialogContent } = require("@mui/material"); +import MapLayer from "@/core/components/MapLayer"; +import CloseIcon from "@mui/icons-material/Close"; +import LayersIcon from "@mui/icons-material/Layers"; +import L from "leaflet"; +import { useMemo, useState } from "react"; +import ShowBound from "./ShowBound"; + +const ShowProjectArea = ({ primaryArea }) => { + const [openShowAreaDialog, setOpenShowAreaDialog] = useState(false); + const bound = useMemo(() => { + const coordinates = Object.values(primaryArea.coordinates); + + const latLngCoords = coordinates.map(([lat, lng]) => [ + parseFloat(lng), + parseFloat(lat), + ]); + + return primaryArea.type === "polygon" + ? L.polygon(latLngCoords, { color: "#ff5555" }) + : L.polyline(latLngCoords); + }, [primaryArea]); + + + return ( + + + setOpenShowAreaDialog(true)}> + + + + setOpenShowAreaDialog(false)} + PaperProps={{ + sx: { + transition: "all .3s", + boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", + borderRadius: 2, + padding: 1, + }, + }} + maxWidth="sm" + fullWidth + dir="rtl" + > + + + محدوده طرح + + setOpenShowAreaDialog(false)} size="small"> + + + + + + + + + + + + + + + ); +}; + +export default ShowProjectArea; diff --git a/src/components/infrastructure/tollHouse/TollHouseList.jsx b/src/components/infrastructure/tollHouse/TollHouseList.jsx index 11536b8..e8e6d2f 100644 --- a/src/components/infrastructure/tollHouse/TollHouseList.jsx +++ b/src/components/infrastructure/tollHouse/TollHouseList.jsx @@ -13,6 +13,7 @@ import { usePermissions } from "@/lib/hooks/usePermissions"; import LocationForm from "./RowActions/LocationForm"; import ImageDialog from "./RowActions/ImageForm"; import { useAuth } from "@/lib/contexts/auth"; +import ShowProjectArea from "./ShowProjectArea"; const statusOptions = [ { value: "", label: "همه وضعیت ها" }, @@ -225,6 +226,28 @@ const TollHouseList = () => { ); }, }, + { + accessorKey: "area", + header: "نمایش محدوده طرح", + id: "area", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + sortDescFirst: false, + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + Cell: ({ row }) => + row.original.area ? ( + + + + ) : ( + "-" + ), + }, { accessorKey: "phone", header: "تلفن راهدارخانه", diff --git a/src/components/infrastructure/tollHouseMap/ClusterSwitch/index.jsx b/src/components/infrastructure/tollHouseMap/ClusterSwitch/index.jsx new file mode 100644 index 0000000..e8fac87 --- /dev/null +++ b/src/components/infrastructure/tollHouseMap/ClusterSwitch/index.jsx @@ -0,0 +1,25 @@ +import DoneIcon from "@mui/icons-material/Done"; +import { Chip, Tooltip, Zoom } from "@mui/material"; + +const ClusterSwitch = ({ isCluster, setCluster, disabled, max }) => { + return ( + + + setCluster((c) => !c)} + sx={{ borderRadius: 1 }} + icon={ + + + + } + /> + + + ); +}; +export default ClusterSwitch; diff --git a/src/components/infrastructure/tollHouseMap/Filter/index.jsx b/src/components/infrastructure/tollHouseMap/Filter/index.jsx new file mode 100644 index 0000000..3cbbe5d --- /dev/null +++ b/src/components/infrastructure/tollHouseMap/Filter/index.jsx @@ -0,0 +1,44 @@ +"use client"; +import { Box, Button, Drawer } from "@mui/material"; +import FilterListIcon from "@mui/icons-material/FilterList"; +import { useCallback, useState } from "react"; +import FilterDrawer from "@/core/components/FilterDrawer"; + +const drawerSx = { + overflowY: "hidden", + display: "flex", + flexDirection: "column", + height: "100%", + zIndex: "1300", +}; + +const boxSx = { + width: { xs: 300, sm: 450 }, +}; + +const Filter = ({ filterData, setFilterData }) => { + const [open, setOpen] = useState(false); + + const openDrawer = useCallback(() => setOpen(true), []); + const closeDrawer = useCallback(() => setOpen(false), []); + + return ( + <> + + + + {open && ( + + )} + + + + ); +}; +export default Filter; diff --git a/src/components/infrastructure/tollHouseMap/Legend/index.jsx b/src/components/infrastructure/tollHouseMap/Legend/index.jsx new file mode 100644 index 0000000..b6f5936 --- /dev/null +++ b/src/components/infrastructure/tollHouseMap/Legend/index.jsx @@ -0,0 +1,35 @@ +import { Box, Stack, Typography } from "@mui/material"; + +const Legend = () => { + return ( + + + theme.palette.success.main, + background: (theme) => theme.palette.success.light, + }} + /> + فعال + + + theme.palette.error.main, + background: (theme) => theme.palette.error.light, + }} + /> + غیرفعال + + + ); +}; +export default Legend; diff --git a/src/components/infrastructure/tollHouseMap/PointsOnMap/DialogInfoItem/ContentInfoItem.jsx b/src/components/infrastructure/tollHouseMap/PointsOnMap/DialogInfoItem/ContentInfoItem.jsx new file mode 100644 index 0000000..5061fe9 --- /dev/null +++ b/src/components/infrastructure/tollHouseMap/PointsOnMap/DialogInfoItem/ContentInfoItem.jsx @@ -0,0 +1,71 @@ +import { Box, Chip, Divider, Stack, Typography } from "@mui/material"; +import moment from "jalali-moment"; +import Image from "next/image"; + +const ContentInfoItem = ({ data }) => { + return ( + + + + + {data.id !== "" && data.id} + + + + + + {data.province_name !== "" && data.province_name} + + + + + + + {data.type_fa !== "" && data.type_fa} + + + + + + + {data.status === "1" ? "فعال" : "غیرفعال"} + + + + + + + recognize_picture + + + + + + recognize_picture_second + + + + + ); +}; +export default ContentInfoItem; diff --git a/src/components/infrastructure/tollHouseMap/PointsOnMap/DialogInfoItem/index.jsx b/src/components/infrastructure/tollHouseMap/PointsOnMap/DialogInfoItem/index.jsx new file mode 100644 index 0000000..232c2a4 --- /dev/null +++ b/src/components/infrastructure/tollHouseMap/PointsOnMap/DialogInfoItem/index.jsx @@ -0,0 +1,51 @@ +import DialogLoading from "@/core/components/DialogLoading"; +import { GET_TOLL_HOUSE_DETAILS } from "@/core/utils/routes"; +import useRequest from "@/lib/hooks/useRequest"; +import { Button, DialogActions, DialogContent, DialogTitle } from "@mui/material"; +import { useEffect, useState } from "react"; +import ContentInfoItem from "./ContentInfoItem"; + +const DialogInfoItem = ({ selectedId, closeDialog }) => { + const request = useRequest(); + const [loading, setLoading] = useState(true); + const [data, setData] = useState(null); + + useEffect(() => { + const controller = new AbortController(); + + const fetchItem = async () => { + setLoading(true); + setData(null); + try { + const response = await request(`${GET_TOLL_HOUSE_DETAILS}/${selectedId}`, "get", { + signal: controller.signal, + }); + setData(response.data.data); + } catch (error) { + } finally { + setLoading(false); + } + }; + + fetchItem(); + + return () => { + controller.abort(); + }; + }, [selectedId]); + + return ( + <> + جزئیات فعالیت + + {loading ? : data && } + + + + + + ); +}; +export default DialogInfoItem; diff --git a/src/components/infrastructure/tollHouseMap/PointsOnMap/index.jsx b/src/components/infrastructure/tollHouseMap/PointsOnMap/index.jsx new file mode 100644 index 0000000..e0b3f16 --- /dev/null +++ b/src/components/infrastructure/tollHouseMap/PointsOnMap/index.jsx @@ -0,0 +1,79 @@ +import { Dialog, useTheme } from "@mui/material"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { CircleMarker, useMap } from "react-leaflet"; +import MarkerClusterGroup from "react-leaflet-markercluster"; +import DialogInfoItem from "./DialogInfoItem"; + +const PointsOnMap = ({ data, isCluster }) => { + const map = useMap(); + const theme = useTheme(); + const [selectedId, setSelectedId] = useState(null); + const [open, setOpen] = useState(false); + + const openDialog = useCallback(() => setOpen(true), []); + const closeDialog = useCallback(() => setOpen(false), []); + + const getMarkerColor = (status) => { + if (status === 1) return theme.palette.warning.main; + if (status === 2) return theme.palette.error.main; + return theme.palette.success.main; + }; + + const markers = useMemo(() => { + return data.map(({ id, lat, lng, step }) => ( + { + openDialog(); + setSelectedId(id); + }, + }} + color={getMarkerColor(Number(status))} + /> + )); + + }, [data, theme]); + + useEffect(() => { + if (data.length === 0) return; + + const bounds = L.latLngBounds( + data.map(({ lat, lng }) => { + return L.latLng(Number(lat), Number(lng)); + }) + ); + + map.flyToBounds(bounds, { duration: 0.7 }); + }, [data]); + + + const createClusterCustomIcon = (cluster) => { + const count = cluster.getChildCount(); + return L.divIcon({ + html: `
${count}
`, + className: "custom-marker-cluster", + iconSize: L.point(40, 40, true), + }); + }; + + if (data.length === 0) return null; + + return ( + <> + {isCluster ? ( + + {markers} + + ) : ( + markers + )} + + {open && } + + + ); +}; +export default PointsOnMap; diff --git a/src/components/infrastructure/tollHouseMap/index.jsx b/src/components/infrastructure/tollHouseMap/index.jsx new file mode 100644 index 0000000..2177397 --- /dev/null +++ b/src/components/infrastructure/tollHouseMap/index.jsx @@ -0,0 +1,231 @@ +"use client"; +import LoadingHardPage from "@/core/components/LoadingHardPage"; +import MapLoading from "@/core/components/MapLayer/Loading"; +import isArrayEmpty from "@/core/utils/isArrayEmpty"; +import { GET_TOLL_HOUSE_MAP } from "@/core/utils/routes"; +import useRequest from "@/lib/hooks/useRequest"; +import { Box, Stack } from "@mui/material"; +import dynamic from "next/dynamic"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import ClusterSwitch from "./ClusterSwitch"; +import Filter from "./Filter"; +import Legend from "./Legend"; +import PointsOnMap from "./PointsOnMap"; +import DataTableFilterDataStructure from "@/core/utils/DataTableFilterDataStructure"; +import useProvinces from "@/lib/hooks/useProvince"; +import CustomSelectByDependency from "@/core/components/FilterDrawer/fieldsType/CustomSelectByDependency"; +import useEdaratLists from "@/lib/hooks/useEdaratLists"; +const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { + loading: () => , + ssr: false, +}); +const typeOptions = [ + { value: "", label: "همه نوع ها" }, + { value: 0, label: "فصلی" }, + { value: 1, label: "دائمی" }, + { value: 2, label: "موقت" }, +]; + +const MAX_POINTS = 1000; + +const containerStyles = { + width: "100%", + height: "100%", + p: 1, + border: "1px dashed", + borderColor: "divider", + borderRadius: 1, +}; + +const controlBarStyles = { + p: 1, + background: "#fff", +}; + +const RoadSafetyReportMap = () => { + const defaultValues = useMemo( + () => [ + { + header: "استان", + id: "province_id", + filterMode: "equals", + datatype: "numeric", + value: "", + enable: true, + SelectComponent: (props) => { + const { provinces, errorProvinces, loadingProvinces } = useProvinces(); + const getSelectOptions = useMemo(() => { + if (loadingProvinces) { + return [{ value: "loading", label: "در حال بارگذاری..." }]; + } + if (errorProvinces) { + return [{ value: "error", label: "خطا در بارگذاری" }]; + } + return [ + { value: "", label: "کل کشور" }, + ...provinces.map((province) => ({ + value: province.id, + label: province.name_fa, + })), + ]; + }, [provinces, errorProvinces, loadingProvinces]); + return ( + + ); + }, + }, + { + eader: "اداره", + id: "edare_shahri_id", + filterMode: "equals", + datatype: "numeric", + dependencyId: "province_id", + value: "", + enable: true, + SelectComponent: (props) => { + const { edaratList, loadingEdaratList, errorEdaratList } = useEdaratLists( + props.dependencyFieldValue.value + ); + const [prevDependency, setPrevDependency] = useState(props.dependencyFieldValue.value); + + const getSelectOptions = useMemo(() => { + if (props.dependencyFieldValue.value === "") { + return [{ value: "empty", label: "ابتدا استان را انتخاب کنید" }]; + } + if (loadingEdaratList) { + return [{ value: "loading", label: "در حال بارگذاری..." }]; + } + if (errorEdaratList) { + return [{ value: "error", label: "خطا در بارگذاری" }]; + } + return [ + { value: "", label: "کل ادارات" }, + ...edaratList.map((edare) => ({ + value: edare.id, + label: edare.name_fa, + })), + ]; + }, [edaratList, loadingEdaratList, errorEdaratList]); + useEffect(() => { + if (prevDependency === props.dependencyFieldValue?.value) return; + props.handleChange({ ...props.filterParameters, value: "" }); + setPrevDependency(props.dependencyFieldValue?.value); + }, [props.dependencyFieldValue?.value]); + return ( + + ); + }, + }, + { + header: "نوع", + id: "type", + filterMode: "equals", + datatype: "numeric", + value: "", + enable: true, + selectOption: () => { + return typeOptions.map((status) => ({ + value: status.value, + label: status.label, + })); + }, + }, + ], + [] + ); + const requestServer = useRequest(); + const [filterData, setFilterData] = useState( + defaultValues.reduce((acc, item) => { + acc[item.id] = item; + return acc; + }, {}) + ); + const [isCluster, setCluster] = useState(false); + const [data, setData] = useState([]); + const [isLoading, setLoading] = useState(true); + + const buildQueryParams = useCallback(() => { + const params = new URLSearchParams(); + const filters = DataTableFilterDataStructure(filterData, isArrayEmpty); + params.set("filters", JSON.stringify(filters || [])); + return params.toString(); + }, [filterData]); + + useEffect(() => { + const fetchData = async () => { + try { + setLoading(true); + const params = new URLSearchParams(); + const filters = DataTableFilterDataStructure(filterData, isArrayEmpty); + params.set("filters", JSON.stringify(filters || [])); + const query = params.toString(); + const response = await requestServer(`${GET_TOLL_HOUSE_MAP}?${query}`); + const fetchedData = response?.data?.data || []; + + if (fetchedData.length > MAX_POINTS) { + setCluster(true); + } + setData(fetchedData); + } catch (error) { + console.log(error); + } finally { + setLoading(false); + } + }; + + fetchData(); + }, [filterData, buildQueryParams]); + + return ( + + + + + MAX_POINTS} + max={MAX_POINTS} + /> + + + + + + + + + + + {isLoading && ( + + + + )} + + + + + ); +}; +export default RoadSafetyReportMap; diff --git a/src/core/utils/headerMenu.js b/src/core/utils/headerMenu.js index 6faa5fa..dcadc5e 100644 --- a/src/core/utils/headerMenu.js +++ b/src/core/utils/headerMenu.js @@ -33,7 +33,7 @@ export const headerMenu = [ [ { title: "پراکندگی بر روی نقشه راهدارخانه ها", - href: api + "/v2/map?type=rahdar", + href: "/infrastructure/map", }, { title: "راهدارخانه ها", diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js index 7e23042..11cf9b4 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -210,6 +210,7 @@ export const GET_TOLL_HOUSE_DETAILS = api + "/api/v3/road_maintenance_station"; export const DELETE_TOLL_HOUSE_ITEM = api + "/api/v3/road_maintenance_station"; export const UPDATE_TOLL_HOUSE_ITEM = api + "/api/v3/road_maintenance_station"; export const GET_TOLL_HOUSE_IMAGES = api + "/api/v3/road_maintenance_station/images"; +export const GET_TOLL_HOUSE_MAP = api + "/api/v3/road_maintenance_station/map"; // road missions export const GET_ROAD_MISSIONS_OPERATOR_LIST = api + "/api/v3/missions/request_portal"; From 15106d02c0c8d575ab17257c4f5b93bc305e2672 Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Mon, 1 Dec 2025 11:08:53 +0330 Subject: [PATCH 2/4] build and format --- .../infrastructure/tollHouse/ShowProjectArea/index.jsx | 6 +----- src/components/infrastructure/tollHouse/TollHouseList.jsx | 6 ++---- .../infrastructure/tollHouseMap/PointsOnMap/index.jsx | 2 -- src/components/infrastructure/tollHouseMap/index.jsx | 4 ++-- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/components/infrastructure/tollHouse/ShowProjectArea/index.jsx b/src/components/infrastructure/tollHouse/ShowProjectArea/index.jsx index 202ef61..250cd52 100644 --- a/src/components/infrastructure/tollHouse/ShowProjectArea/index.jsx +++ b/src/components/infrastructure/tollHouse/ShowProjectArea/index.jsx @@ -11,17 +11,13 @@ const ShowProjectArea = ({ primaryArea }) => { const bound = useMemo(() => { const coordinates = Object.values(primaryArea.coordinates); - const latLngCoords = coordinates.map(([lat, lng]) => [ - parseFloat(lng), - parseFloat(lat), - ]); + const latLngCoords = coordinates.map(([lat, lng]) => [parseFloat(lng), parseFloat(lat)]); return primaryArea.type === "polygon" ? L.polygon(latLngCoords, { color: "#ff5555" }) : L.polyline(latLngCoords); }, [primaryArea]); - return ( diff --git a/src/components/infrastructure/tollHouse/TollHouseList.jsx b/src/components/infrastructure/tollHouse/TollHouseList.jsx index e8e6d2f..dc115ec 100644 --- a/src/components/infrastructure/tollHouse/TollHouseList.jsx +++ b/src/components/infrastructure/tollHouse/TollHouseList.jsx @@ -238,11 +238,9 @@ const TollHouseList = () => { grow: false, size: 100, Cell: ({ row }) => - row.original.area ? ( + row.original.area ? ( - + ) : ( "-" diff --git a/src/components/infrastructure/tollHouseMap/PointsOnMap/index.jsx b/src/components/infrastructure/tollHouseMap/PointsOnMap/index.jsx index e0b3f16..05b4d03 100644 --- a/src/components/infrastructure/tollHouseMap/PointsOnMap/index.jsx +++ b/src/components/infrastructure/tollHouseMap/PointsOnMap/index.jsx @@ -34,7 +34,6 @@ const PointsOnMap = ({ data, isCluster }) => { color={getMarkerColor(Number(status))} /> )); - }, [data, theme]); useEffect(() => { @@ -49,7 +48,6 @@ const PointsOnMap = ({ data, isCluster }) => { map.flyToBounds(bounds, { duration: 0.7 }); }, [data]); - const createClusterCustomIcon = (cluster) => { const count = cluster.getChildCount(); return L.divIcon({ diff --git a/src/components/infrastructure/tollHouseMap/index.jsx b/src/components/infrastructure/tollHouseMap/index.jsx index 2177397..f7b5a86 100644 --- a/src/components/infrastructure/tollHouseMap/index.jsx +++ b/src/components/infrastructure/tollHouseMap/index.jsx @@ -122,8 +122,8 @@ const RoadSafetyReportMap = () => { props.dependencyFieldValue?.value === "" ? "empty" : loadingEdaratList - ? "loading" - : props.filterParameters.value + ? "loading" + : props.filterParameters.value } selectOption={getSelectOptions} /> From 7c197c2bf0d21a3cca30818ee0b90c90cbe78d80 Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Mon, 1 Dec 2025 13:05:54 +0330 Subject: [PATCH 3/4] add km to control panel --- .../StartMission/StartMissionContent.jsx | 24 ++++++++++++++++ .../RowActions/Allocation/Form/index.jsx | 28 ++++--------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/components/dashboard/roadMissions/control/RowActions/StartMission/StartMissionContent.jsx b/src/components/dashboard/roadMissions/control/RowActions/StartMission/StartMissionContent.jsx index c7f516d..72fc54b 100644 --- a/src/components/dashboard/roadMissions/control/RowActions/StartMission/StartMissionContent.jsx +++ b/src/components/dashboard/roadMissions/control/RowActions/StartMission/StartMissionContent.jsx @@ -11,6 +11,7 @@ const StartMissionContent = ({ rowId, mutate, setOpenStartMissionDialog }) => { const validationSchema = object().shape({ code: string().length(6, "کد خروج باید 6 رقم باشد").required("لطفاً کد خروج را وارد کنید."), + km: string().required("لطفاً کیلومتر را وارد کنید."), }); const { @@ -20,6 +21,7 @@ const StartMissionContent = ({ rowId, mutate, setOpenStartMissionDialog }) => { } = useForm({ defaultValues: { code: "", + km : "" }, resolver: yupResolver(validationSchema), mode: "all", @@ -29,6 +31,7 @@ const StartMissionContent = ({ rowId, mutate, setOpenStartMissionDialog }) => { requestServer(`${START_MISSION}/${rowId}`, "post", { data: { code: values.code, + km: values.km, }, hasSidebarUpdate: true, }) @@ -69,6 +72,27 @@ const StartMissionContent = ({ rowId, mutate, setOpenStartMissionDialog }) => { )} /> + + ( + { + if (isNaN(Number(e.target.value))) return; + field.onChange(e.target.value) + }} + size="small" + fullWidth + label="کیلومتر خودرو / ساعت کار" + InputLabelProps={{ shrink: true }} + /> + )} + /> + diff --git a/src/components/dashboard/roadMissions/transportation/RowActions/Allocation/Form/index.jsx b/src/components/dashboard/roadMissions/transportation/RowActions/Allocation/Form/index.jsx index f5d4395..eb591e8 100644 --- a/src/components/dashboard/roadMissions/transportation/RowActions/Allocation/Form/index.jsx +++ b/src/components/dashboard/roadMissions/transportation/RowActions/Allocation/Form/index.jsx @@ -22,16 +22,14 @@ const AllocationForm = ({ row, mutate, setOpenAllocationDialog }) => { const requestServer = useRequest({ notificationSuccess: true }); const [machine, setMachine] = useState(); const [driver, setDriver] = useState(); - const [kilometer, setKilometer] = useState(); const [isSubmitting, setIsSubmitting] = useState(false); - const handleSubmit = async (_machine, _driver, _kilometer) => { + const handleSubmit = async (_machine, _driver) => { setIsSubmitting(true); await requestServer(`${ALLOCATE_REQUEST_MISSION}/${row.id}`, "post", { data: { - machines: [_machine.id], + machines: _machine.id, driver: _driver.id, - km: kilometer, }, hasSidebarUpdate: true, }) @@ -110,23 +108,7 @@ const AllocationForm = ({ row, mutate, setOpenAllocationDialog }) => { )} )} - {driver && ( - - { - if (isNaN(Number(e.target.value))) return; - setKilometer(e.target.value); - }} - size="small" - fullWidth - label="کیلومتر خودرو" - InputLabelProps={{ shrink: true }} - /> - - )} + @@ -208,10 +190,10 @@ const AllocationForm = ({ row, mutate, setOpenAllocationDialog }) => {