Merge branch 'develop' of https://github.com/witelgroup/RMS-front-end into feature/mission_report

This commit is contained in:
2025-12-21 08:57:01 +03:30
11 changed files with 69 additions and 87 deletions

View File

@@ -3,8 +3,12 @@ import { Box } from "@mui/material";
import { useMemo } from "react"; import { useMemo } from "react";
import RowActions from "./RowActions"; import RowActions from "./RowActions";
import { GET_MACHINES_TABLE_LIST } from "@/core/utils/routes"; import { GET_MACHINES_TABLE_LIST } from "@/core/utils/routes";
import { useAuth } from "@/lib/contexts/auth";
const MachinesList = ({ machineType, setMachine, setOpenMachinesDialog }) => { const MachinesList = ({ machineType, setMachine, setOpenMachinesDialog }) => {
const {
user: { city_id },
} = useAuth();
const columns = useMemo( const columns = useMemo(
() => [ () => [
{ {
@@ -40,7 +44,11 @@ const MachinesList = ({ machineType, setMachine, setOpenMachinesDialog }) => {
need_filter={true} need_filter={true}
table_title="لیست خودرو ها" table_title="لیست خودرو ها"
columns={columns} columns={columns}
specialFilter={[{ value: machineType, datatype: "text", id: "car_type", fn: "equals" }]} specialFilter={[
{ value: machineType, datatype: "text", id: "car_type", fn: "equals" },
{ value: 1, datatype: "numeric", id: "status", fn: "equals" },
{ value: city_id, datatype: "numeric", id: "city_id", fn: "equals" },
]}
sorting={[{ id: "id", desc: true }]} sorting={[{ id: "id", desc: true }]}
table_url={GET_MACHINES_TABLE_LIST} table_url={GET_MACHINES_TABLE_LIST}
page_name={"roadMissionsTransportation"} page_name={"roadMissionsTransportation"}

View File

@@ -1,18 +1,17 @@
import MapLayer from "@/core/components/MapLayer"; import MapLayer from "@/core/components/MapLayer";
import { machineType } from "@/core/utils/machineTypes";
import { missionRegions } from "@/core/utils/missionRegions";
import { missionTypes } from "@/core/utils/missionTypes";
import { ALLOCATE_REQUEST_MISSION } from "@/core/utils/routes"; import { ALLOCATE_REQUEST_MISSION } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest"; import useRequest from "@/lib/hooks/useRequest";
import { Box, Button, Chip, DialogActions, DialogContent, Divider, Paper, Typography } from "@mui/material"; import { Box, Button, Chip, DialogActions, DialogContent, Divider, Paper, Typography } from "@mui/material";
import { Stack } from "@mui/system"; import { Stack } from "@mui/system";
import moment from "jalali-moment";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import ShowBound from "../../../Actions/showBound"; import ShowBound from "../../../Actions/showBound";
import Reject from "./Reject";
import { missionRegions } from "@/core/utils/missionRegions";
import { machineType } from "@/core/utils/machineTypes";
import { missionTypes } from "@/core/utils/missionTypes";
import moment from "jalali-moment";
import MachinesDialog from "./MachinesDialog";
import DriversDialog from "./DriversDialog"; import DriversDialog from "./DriversDialog";
import LtrTextField from "@/core/components/LtrTextField"; import MachinesDialog from "./MachinesDialog";
import Reject from "./Reject";
const AllocationForm = ({ row, mutate, setOpenAllocationDialog }) => { const AllocationForm = ({ row, mutate, setOpenAllocationDialog }) => {
const bound = useMemo( const bound = useMemo(
() => () =>
@@ -56,7 +55,7 @@ const AllocationForm = ({ row, mutate, setOpenAllocationDialog }) => {
</Typography> </Typography>
<Divider sx={{ flex: 1 }} /> <Divider sx={{ flex: 1 }} />
<Chip <Chip
label={machineType.find((mt) => mt.id == row.requested_machines[0]).name_fa} label={machineType.find((mt) => mt.id == row.requested_machines?.[0])?.name_fa}
/> />
</Stack> </Stack>
<Stack direction={"row"} alignItems={"center"} spacing={1}> <Stack direction={"row"} alignItems={"center"} spacing={1}>

View File

@@ -103,9 +103,6 @@ const GetItemInfo = ({ allData, setAllData, handlePrev, setTabState }) => {
)} )}
/> />
</Grid> </Grid>
<Grid item xs={12} sm={6}>
<FastReactCode control={control} />
</Grid>
<Grid item xs={12} sm={6}> <Grid item xs={12} sm={6}>
<Controller <Controller
control={control} control={control}

View File

@@ -3,7 +3,7 @@ import { Button, Dialog, DialogTitle, IconButton } from "@mui/material";
import { useState } from "react"; import { useState } from "react";
import DriversSearch from "./DriversSearch"; import DriversSearch from "./DriversSearch";
const DriversDialog = ({ setDriver, mode }) => { const DriversDialog = ({ setDriver, mode = "" }) => {
const [openDriversDialog, setOpenDriversDialog] = useState(false); const [openDriversDialog, setOpenDriversDialog] = useState(false);
return ( return (
<> <>

View File

@@ -1,10 +1,8 @@
import { Box, Button, Chip, DialogActions, DialogContent, Divider, Stack, Typography } from "@mui/material"; import { Box, Button, Chip, DialogActions, DialogContent, Divider, Stack, Typography } from "@mui/material";
import DriversDialog from "./DriversDialog";
import { useState } from "react"; import { useState } from "react";
import MachinesDialog from "./MachinesDialog"; import DriversDialog from "./DriversDialog";
const MachineAndDriver = ({ setTabState, allData, setAllData, handlePrev }) => { const MachineAndDriver = ({ setTabState, allData, setAllData, handlePrev }) => {
const [machine, setMachine] = useState(allData.machine);
const [driver, setDriver] = useState(allData.driver); const [driver, setDriver] = useState(allData.driver);
const handleNext = (data) => { const handleNext = (data) => {
@@ -18,43 +16,21 @@ const MachineAndDriver = ({ setTabState, allData, setAllData, handlePrev }) => {
<Box sx={{ flex: 1 }}> <Box sx={{ flex: 1 }}>
<Stack sx={{ my: 1 }} spacing={2}> <Stack sx={{ my: 1 }} spacing={2}>
<Stack direction={"row"} alignItems={"center"} spacing={1}> <Stack direction={"row"} alignItems={"center"} spacing={1}>
{machine ? ( {driver ? (
<> <>
<Typography variant="body2">خودرو</Typography> <Typography variant="body2">راننده</Typography>
<Divider sx={{ flex: 1 }} /> <Divider sx={{ flex: 1 }} />
<Chip <Chip
label={ label={driver ? `${driver.code} | ${driver.name}` : "راننده ای انتخاب نشده"}
machine
? `${machine.machine_code} | ${machine.car_name}`
: "خودرویی انتخاب نشده"
}
size="small" size="small"
/> />
<Divider sx={{ flex: 1 }} /> <Divider sx={{ flex: 1 }} />
<MachinesDialog setMachine={setMachine} mode={"edit"} /> <DriversDialog setDriver={setDriver} mode={"edit"} />
</> </>
) : ( ) : (
<MachinesDialog setMachine={setMachine} /> <DriversDialog setDriver={setDriver} />
)} )}
</Stack> </Stack>
{machine && (
<Stack direction={"row"} alignItems={"center"} spacing={1}>
{driver ? (
<>
<Typography variant="body2">راننده</Typography>
<Divider sx={{ flex: 1 }} />
<Chip
label={driver ? `${driver.code} | ${driver.name}` : "راننده ای انتخاب نشده"}
size="small"
/>
<Divider sx={{ flex: 1 }} />
<DriversDialog setDriver={setDriver} mode={"edit"} />
</>
) : (
<DriversDialog setDriver={setDriver} />
)}
</Stack>
)}
</Stack> </Stack>
</Box> </Box>
</DialogContent> </DialogContent>
@@ -62,12 +38,7 @@ const MachineAndDriver = ({ setTabState, allData, setAllData, handlePrev }) => {
<Button onClick={handlePrev} variant="outlined" color="secondary" size="large"> <Button onClick={handlePrev} variant="outlined" color="secondary" size="large">
{"مرحله قبلی"} {"مرحله قبلی"}
</Button> </Button>
<Button <Button variant="contained" disabled={!driver} size="large" onClick={() => handleNext({ driver })}>
variant="contained"
disabled={!machine || !driver}
size="large"
onClick={() => handleNext({ machine, driver })}
>
مرحله بعد مرحله بعد
</Button> </Button>
</DialogActions> </DialogActions>

View File

@@ -79,16 +79,9 @@ const Verify = ({ allData, handlePrev, submitForm, submitting }) => {
</Stack> </Stack>
<Stack spacing={1}> <Stack spacing={1}>
<Divider> <Divider>
<Chip color="primary" variant="outlined" label="خودرو و راننده" /> <Chip color="primary" variant="outlined" label=" راننده" />
</Divider> </Divider>
<Stack direction={"row"} alignItems={"center"} spacing={1}>
<Typography variant="body2">خودرو</Typography>
<Divider sx={{ flex: 1 }} />
<Chip
size="small"
label={`${allData.machine.machine_code} | ${allData.machine.car_name}`}
/>
</Stack>
<Stack direction={"row"} alignItems={"center"} spacing={1}> <Stack direction={"row"} alignItems={"center"} spacing={1}>
<Typography variant="body2">راننده</Typography> <Typography variant="body2">راننده</Typography>
<Divider sx={{ flex: 1 }} /> <Divider sx={{ flex: 1 }} />

View File

@@ -1,4 +1,4 @@
import { AccessTime, Engineering, InsertDriveFile, LocalShipping, Route, Verified } from "@mui/icons-material"; import { AccessTime, Engineering, InsertDriveFile, Route, Verified, Person } from "@mui/icons-material";
import { Box, Tab, Tabs } from "@mui/material"; import { Box, Tab, Tabs } from "@mui/material";
import { useReducer, useState } from "react"; import { useReducer, useState } from "react";
import Area from "./Area"; import Area from "./Area";
@@ -62,7 +62,7 @@ const CreateForm = ({ defaultValues, submitForm, setOpen, submitting }) => {
<Tab icon={<InsertDriveFile />} label="مشخصات" /> <Tab icon={<InsertDriveFile />} label="مشخصات" />
<Tab disabled={tabState < 1} icon={<AccessTime />} label="زمانبندی" /> <Tab disabled={tabState < 1} icon={<AccessTime />} label="زمانبندی" />
<Tab disabled={tabState < 2} icon={<Route />} label="منطقه عملیاتی" /> <Tab disabled={tabState < 2} icon={<Route />} label="منطقه عملیاتی" />
<Tab disabled={tabState < 3} icon={<LocalShipping />} label="خودرو و راننده" /> <Tab disabled={tabState < 3} icon={<Person />} label="راننده" />
<Tab disabled={tabState < 4} icon={<Engineering />} label="همراهان" /> <Tab disabled={tabState < 4} icon={<Engineering />} label="همراهان" />
<Tab disabled={tabState < 5} icon={<Verified />} label="بررسی نهایی" /> <Tab disabled={tabState < 5} icon={<Verified />} label="بررسی نهایی" />
</Tabs> </Tabs>

View File

@@ -1,16 +1,14 @@
import { REQUEST_MISSION_WITHOUT_PROCESS } from "@/core/utils/routes"; import { REQUEST_MISSION_WITHOUT_PROCESS } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest"; import useRequest from "@/lib/hooks/useRequest";
import { AddCircle, AddCircleOutline, Close } from "@mui/icons-material"; import { AddCircleOutline, Close } from "@mui/icons-material";
import { Button, Dialog, IconButton, useMediaQuery, useTheme } from "@mui/material"; import { Dialog, IconButton, Tooltip } from "@mui/material";
import moment from "jalali-moment"; import moment from "jalali-moment";
import { useState } from "react"; import { useState } from "react";
import CreateForm from "./Form"; import CreateForm from "./Form";
const CreateWithoutProcess = ({ mutate }) => { const CreateWithoutProcess = ({ row, mutate }) => {
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
const requestServer = useRequest({ notificationSuccess: true }); const requestServer = useRequest({ notificationSuccess: true });
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const handleOpen = () => { const handleOpen = () => {
@@ -25,15 +23,10 @@ const CreateWithoutProcess = ({ mutate }) => {
? bound.map((ring) => ring.map((latlng) => [latlng.lat, latlng.lng]))[0] ? bound.map((ring) => ring.map((latlng) => [latlng.lat, latlng.lng]))[0]
: bound.map((latlng) => [latlng.lat, latlng.lng]); : bound.map((latlng) => [latlng.lat, latlng.lng]);
await requestServer(REQUEST_MISSION_WITHOUT_PROCESS, "post", { await requestServer(`${REQUEST_MISSION_WITHOUT_PROCESS}/${row.original.id}`, "post", {
data: { data: {
explanation: result.explanation, explanation: result.explanation,
category_id: result.category_id, category_id: result.category_id,
...(result.category_id == 3
? {
road_observed_id: result.road_observed_id,
}
: {}),
area: { area: {
type: result.bound_type, type: result.bound_type,
coordinates: area, coordinates: area,
@@ -43,7 +36,6 @@ const CreateWithoutProcess = ({ mutate }) => {
end_point: result.end_point, end_point: result.end_point,
start_date: `${result.start_date} ${moment(result.start_time).format("HH:mm")}`, start_date: `${result.start_date} ${moment(result.start_time).format("HH:mm")}`,
end_date: `${result.end_date} ${moment(result.end_time).format("HH:mm")}`, end_date: `${result.end_date} ${moment(result.end_time).format("HH:mm")}`,
machines: [result.machine.id],
driver: result.driver.id, driver: result.driver.id,
}, },
hasSidebarUpdate: true, hasSidebarUpdate: true,
@@ -60,21 +52,12 @@ const CreateWithoutProcess = ({ mutate }) => {
return ( return (
<> <>
{isMobile ? ( <Tooltip title="تصحیح ماموریت" arrow placement="left">
<IconButton aria-label="تصحیح ماموریت" color="primary" onClick={handleOpen}> <IconButton aria-label="تصحیح ماموریت" color="primary" onClick={handleOpen}>
<AddCircleOutline sx={{ fontSize: "25px" }} /> <AddCircleOutline sx={{ fontSize: "25px" }} />
</IconButton> </IconButton>
) : ( </Tooltip>
<Button
size={"small"}
variant="contained"
color="primary"
startIcon={<AddCircle />}
onClick={handleOpen}
>
تصحیح ماموریت
</Button>
)}
<Dialog open={open} fullWidth maxWidth="sm"> <Dialog open={open} fullWidth maxWidth="sm">
<IconButton <IconButton
aria-label="close" aria-label="close"
@@ -104,7 +87,6 @@ const CreateWithoutProcess = ({ mutate }) => {
end_time: null, end_time: null,
end_point: "", end_point: "",
region: "", region: "",
machine: null,
driver: null, driver: null,
}} }}
submitForm={submitForm} submitForm={submitForm}

View File

@@ -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 <FeatureGroup ref={featureRef} />;
};
export default ShowBound;

View File

@@ -1,4 +1,7 @@
import CreateWithoutProcess from "../Actions/CreateWithoutProcess";
const RowActions = ({ row, mutate }) => { const RowActions = ({ row, mutate }) => {
return <></>; const canEdit = row.original.status === 0 && row.original.type === 1;
return canEdit && <CreateWithoutProcess row={row} mutate={mutate} />;
}; };
export default RowActions; export default RowActions;

View File

@@ -217,7 +217,7 @@ export const GET_ROAD_MISSIONS_OPERATOR_LIST = api + "/api/v3/missions/request_p
export const GET_ROAD_MISSIONS_TRANSPORTATION_LIST = api + "/api/v3/missions/transportation_unit"; export const GET_ROAD_MISSIONS_TRANSPORTATION_LIST = api + "/api/v3/missions/transportation_unit";
export const GET_ROAD_MISSIONS_CONTROL_LIST = api + "/api/v3/missions/control_unit"; export const GET_ROAD_MISSIONS_CONTROL_LIST = api + "/api/v3/missions/control_unit";
export const REQUEST_MISSION = api + "/api/v3/missions/request_portal"; export const REQUEST_MISSION = api + "/api/v3/missions/request_portal";
export const REQUEST_MISSION_WITHOUT_PROCESS = api + "/api/v3/missions/request_portal/no_process"; export const REQUEST_MISSION_WITHOUT_PROCESS = api + "/api/v3/missions/violation_management/no_process";
export const REQUEST_MISSION_CONTINUE_MISSION = api + "/api/v3/missions/request_portal/continue"; export const REQUEST_MISSION_CONTINUE_MISSION = api + "/api/v3/missions/request_portal/continue";
export const UPDATE_REQUEST_MISSION = api + "/api/v3/missions/request_portal"; export const UPDATE_REQUEST_MISSION = api + "/api/v3/missions/request_portal";
export const DELETE_REQUEST_MISSION = api + "/api/v3/missions/request_portal"; export const DELETE_REQUEST_MISSION = api + "/api/v3/missions/request_portal";