2 Commits

Author SHA1 Message Date
e66af994af build and format 2026-06-15 11:19:39 +03:30
1e0d3dcf0e add end_km to violations 2026-06-15 11:16:34 +03:30
16 changed files with 147 additions and 78 deletions

View File

@@ -2,7 +2,7 @@ import { Close } from "@mui/icons-material";
import { Dialog, DialogTitle, IconButton } from "@mui/material";
import ViolationsList from "./ViolationsList";
const ViolationsDialog = ({ open, setOpen, mutate, row }) => {
const ViolationsDialog = ({ open, setOpen, mutate }) => {
return (
<Dialog open={open} fullWidth maxWidth="xs">
<IconButton
@@ -19,7 +19,7 @@ const ViolationsDialog = ({ open, setOpen, mutate, row }) => {
<Close />
</IconButton>
<DialogTitle>تخلفات</DialogTitle>
{open && <ViolationsList setOpen={setOpen} />}
{open && <ViolationsList setOpen={setOpen} mutate={mutate} />}
</Dialog>
);
};

View File

@@ -20,10 +20,7 @@ const MachineAndDriver = ({ setTabState, allData, setAllData, handlePrev }) => {
<>
<Typography variant="body2">راننده</Typography>
<Divider sx={{ flex: 1 }} />
<Chip
label={driver ? `${driver.code} | ${driver.name}` : "راننده ای انتخاب نشده"}
size="small"
/>
<Chip label={driver ? `${driver.name}` : "راننده ای انتخاب نشده"} size="small" />
<Divider sx={{ flex: 1 }} />
<DriversDialog setDriver={setDriver} mode={"edit"} />
</>

View File

@@ -25,17 +25,17 @@ const RahdaranList = ({ rahdaran, setRahdaran }) => {
my: 1,
}}
>
<Stack direction={"row"} spacing={1}>
<Stack direction={"row"} sx={{ display: "flex", alignItems: "center" }} spacing={1}>
<AccountCircle color="primary" sx={{ width: "32px", height: "32px" }} />
<Stack>
<Stack direction={"row"} spacing={0.5}>
<Typography variant="caption">نام و نام خانوادگی:</Typography>
<Typography variant="body2">{rahdar.name}</Typography>
</Stack>
<Stack direction={"row"} spacing={0.5}>
<Typography variant="caption">کدملی:</Typography>
<Typography variant="body2">{rahdar.code}</Typography>
</Stack>
{/*<Stack direction={"row"} spacing={0.5}>*/}
{/* <Typography variant="caption">کدملی:</Typography>*/}
{/* <Typography variant="body2">-</Typography> /!*{rahdar.code}*!/*/}
{/*</Stack>*/}
</Stack>
</Stack>
<IconButton color="error" onClick={() => handleRemove(index)}>

View File

@@ -5,7 +5,7 @@ import { Dialog, IconButton, Tooltip } from "@mui/material";
import { useState } from "react";
import CreateForm from "./Form";
const MissionCorrection = ({ row, mutate }) => {
const MissionCorrection = ({ row, mutate, baseMutate }) => {
const [submitting, setSubmitting] = useState(false);
const requestServer = useRequest({ notificationSuccess: true });
const [open, setOpen] = useState(false);
@@ -31,6 +31,7 @@ const MissionCorrection = ({ row, mutate }) => {
})
.then((response) => {
mutate();
baseMutate();
setOpen(false);
})
.catch((error) => {})

View File

@@ -1,9 +1,9 @@
import MissionCorrection from "./MissionCorrection";
export default function RowActions({ row, mutate }) {
export default function RowActions({ row, mutate, baseMutate }) {
return (
<>
<MissionCorrection row={row} mutate={mutate} />
<MissionCorrection row={row} mutate={mutate} baseMutate={baseMutate} />
</>
);
}

View File

@@ -7,7 +7,7 @@ import useCities from "@/lib/hooks/useCities";
import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
import useProvinces from "@/lib/hooks/useProvince";
const ViolationsList = ({ setOpen }) => {
const ViolationsList = ({ setOpen, mutate }) => {
const columns = useMemo(() => {
const dynamicColumns = {
header: "استان",
@@ -132,7 +132,7 @@ const ViolationsList = ({ setOpen }) => {
table_name={"operatorViolationsList"}
enableRowActions
positionActionsColumn={"first"}
RowActions={(props) => <RowActions {...props} setOpen={setOpen} />}
RowActions={(props) => <RowActions {...props} setOpen={setOpen} baseMutate={mutate} />}
/>
</Box>
</>

View File

@@ -4,7 +4,7 @@ import ViolationsDialog from "./Dialog";
import theme from "@/core/utils/theme";
import RemoveRoadIcon from "@mui/icons-material/RemoveRoad";
const OperatorViolations = ({ row, mutate }) => {
const OperatorViolations = ({ mutate }) => {
const [open, setOpen] = useState(false);
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
return (
@@ -26,7 +26,7 @@ const OperatorViolations = ({ row, mutate }) => {
</Button>
)}
</Tooltip>
<ViolationsDialog open={open} setOpen={setOpen} mutate={mutate} row={row} />
<ViolationsDialog open={open} setOpen={setOpen} mutate={mutate} />
</>
);
};

View File

@@ -8,6 +8,7 @@ import { ExitToApp } from "@mui/icons-material";
import { Box, Button, DialogActions, DialogContent, Grid, Stack } from "@mui/material";
import { Controller, useForm } from "react-hook-form";
import { object, string } from "yup";
import LtrTextField from "@/core/components/LtrTextField";
const validationSchema = object({
explanation: string().required("موضوع را مشخص کنید!"),
@@ -125,6 +126,29 @@ const GetItemInfo = ({ allData, setAllData, handlePrev, setTabState }) => {
}}
/>
</Grid>
<Grid item xs={12} sm={12}>
<Stack>
<Controller
control={control}
name={"end_km"}
render={({ field, fieldState: { error } }) => (
<LtrTextField
autoComplete="off"
type="tel"
value={field.value}
onChange={(e) => {
if (isNaN(Number(e.target.value))) return;
field.onChange(e.target.value);
}}
size="small"
fullWidth
label="کیلومتر خودرو / ساعت کار"
InputLabelProps={{ shrink: true }}
/>
)}
/>
</Stack>
</Grid>
</Grid>
</Stack>
</Box>

View File

@@ -60,6 +60,11 @@ const Verify = ({ allData, handlePrev, submitForm, submitting }) => {
<Divider sx={{ flex: 1 }} />
<Chip size="small" label={allData.end_point} />
</Stack>
<Stack direction={"row"} alignItems={"center"} spacing={1}>
<Typography variant="body2">کیلومتر خودرو / ساعت کار</Typography>
<Divider sx={{ flex: 1 }} />
<Chip size="small" label={allData.end_km} />
</Stack>
<Stack direction={"row"} alignItems={"center"} spacing={1}>
<Typography variant="body2">تاریخ شروع ماموریت</Typography>
<Divider sx={{ flex: 1 }} />

View File

@@ -25,8 +25,6 @@ const reducer = (state, action) => {
};
const CreateForm = ({ defaultValues, submitForm, setOpen, submitting, oldBound }) => {
console.log("defaultValues", defaultValues);
const [allData, dispatch] = useReducer(reducer, defaultValues);
const [tabState, setTabState] = useState(0);
const handleClose = () => {

View File

@@ -18,6 +18,7 @@ const DialogAdd = ({ mutate, setOpen, oldBound, rahdaran, machine, row }) => {
driver: row.original.driver_id,
zone: result.region,
type: result.type,
end_km: result.end_km,
...(result.type == 1
? {
end_date: `${result.end_date} ${moment(result.end_time).format("HH:mm")}`,
@@ -54,6 +55,7 @@ const DialogAdd = ({ mutate, setOpen, oldBound, rahdaran, machine, row }) => {
rahdaran: rahdaran.filter((r) => !r.is_driver),
bound_type: "polyline",
type: "",
end_km: "",
end_date: "",
end_time: null,
end_point: "",

View File

@@ -3,61 +3,75 @@ import useRequest from "@/lib/hooks/useRequest";
import DialogLoading from "@/core/components/DialogLoading";
import CreateForm from "../../../Actions/Create/Form";
import moment from "jalali-moment";
import L from "leaflet";
import polyline from "@mapbox/polyline";
import { GET_RAHDARAN_BY_ID, UPDATE_REQUEST_MISSION } from "@/core/utils/routes";
const EditController = ({ row, mutate, openEditDialog, setOpenEditDialog }) => {
const latLngs = useMemo(() => {
return row.original.area.coordinates.map(([lng, lat]) => [lat, lng]);
}, [row.original.area.coordinates]);
const bound = useMemo(
() => (row.original.area.type === "polygon" ? L.polygon(latLngs) : L.polyline(latLngs)),
[row.original.area.type, latLngs]
);
const [submitting, setSubmitting] = useState(false);
const [rahdaran, setRahdaran] = useState(null);
const [rahdaranLoading, setRahdaranLoading] = useState(true);
const requestServer = useRequest();
const locations = useMemo(() => {
if (!row.original.encoded_route) return [];
const decoded = polyline.decode(row.original.encoded_route, 6);
if (decoded.length === 0) return [];
return [
{
lat: decoded[0][0],
lon: decoded[0][1],
},
{
lat: decoded[decoded.length - 1][0],
lon: decoded[decoded.length - 1][1],
},
];
}, [row.original.encoded_route]);
useEffect(() => {
setRahdaranLoading(true);
requestServer(`${GET_RAHDARAN_BY_ID}/${row.original.id}`, "get")
.then((response) => {
setRahdaran(response.data.data);
setRahdaranLoading(false);
})
.catch((e) => {
.catch(() => {})
.finally(() => {
setRahdaranLoading(false);
});
}, [row.original.id]);
const submitForm = async (result) => {
setSubmitting(true);
const latlngs = result.bound.getLatLngs();
const normalized = result.bound_type === "polygon" ? latlngs : [latlngs];
const area = normalized.map((ring) => ring.map(({ lat, lng }) => [lat, lng]));
await requestServer(`${UPDATE_REQUEST_MISSION}/${row.original.id}`, "post", {
data: {
explanation: result.explanation,
category_id: result.category_id,
...(result.category_id == 3
? {
road_observed_id: result.road_observed_id,
}
: {}),
area: {
type: result.bound_type,
coordinates: area[0],
},
...(result.rahdaran.length != 0 ? { rahdaran: result.rahdaran.map((r) => r.id) } : {}),
encoded_route: result.area,
...(result.rahdaran.length !== 0
? {
rahdaran: result.rahdaran.map((r) => r.id),
}
: {}),
requested_machines: result.requested_machines,
type: result.type,
zone: result.region,
end_point: result.end_point,
...(result.type == 1
? {
start_date: `${result.start_date} ${moment(result.start_time).format("HH:mm")}`,
@@ -71,46 +85,51 @@ const EditController = ({ row, mutate, openEditDialog, setOpenEditDialog }) => {
hasSidebarUpdate: true,
notificationSuccess: true,
})
.then((response) => {
.then(() => {
mutate();
setOpenEditDialog(false);
})
.catch((error) => {})
.catch(() => {})
.finally(() => {
setSubmitting(false);
});
};
return (
<>
{rahdaranLoading ? (
<DialogLoading />
) : (
<CreateForm
defaultValues={{
explanation: row.original.explanation,
category_id: row.original.category_id,
road_observed_id: row.original.category_id == 3 ? row.original.road_observed[0].id : "",
rahdaran: rahdaran.filter((r) => !r.isDriver),
requested_machines: row.original.requested_machines,
bound: bound,
bound_type: row.original.area.type,
type: row.original.type,
start_date: moment(row.original.start_date).format("YYYY-MM-DD"),
start_time: moment(row.original.start_date).toDate(),
end_date: moment(row.original.end_date).format("YYYY-MM-DD"),
end_time: moment(row.original.end_date).toDate(),
end_point: row.original.end_point,
region: row.original.zone,
}}
submitForm={submitForm}
submitting={submitting}
open={openEditDialog}
setOpen={setOpenEditDialog}
mutate={mutate}
/>
)}
</>
return rahdaranLoading ? (
<DialogLoading />
) : (
<CreateForm
defaultValues={{
explanation: row.original.explanation,
category_id: row.original.category_id,
road_observed_id: row.original.category_id == 3 ? (row.original.road_observed?.[0]?.id ?? "") : "",
rahdaran: rahdaran.filter((r) => !r.isDriver),
requested_machines: row.original.requested_machines,
area: row.original.encoded_route,
locations,
type: row.original.type,
start_date: moment(row.original.start_date).format("YYYY-MM-DD"),
start_time: moment(row.original.start_date).toDate(),
end_date: moment(row.original.end_date).format("YYYY-MM-DD"),
end_time: moment(row.original.end_date).toDate(),
end_point: row.original.end_point,
region: row.original.zone,
}}
submitForm={submitForm}
submitting={submitting}
open={openEditDialog}
setOpen={setOpenEditDialog}
mutate={mutate}
/>
);
};
export default EditController;

View File

@@ -7,7 +7,7 @@ const Toolbar = ({ table, filterData, mutate }) => {
return (
<Stack direction={"row"} spacing={1}>
<Create mutate={mutate} />
<OperatorViolations />
<OperatorViolations mutate={mutate} />
{/*<CreateWithoutProcess mutate={mutate} />*/}
</Stack>
);

View File

@@ -78,7 +78,6 @@ const MachinesList = ({ machineType, setMachine, setOpenMachinesDialog }) => {
columns={columns}
specialFilter={[
{ value: machineType, datatype: "text", id: "car_type", fn: "equals" },
{ value: 1, datatype: "numeric", id: "status", fn: "equals" },
{
value: city_id ? city_id : province_id,
datatype: "numeric",

View File

@@ -11,6 +11,7 @@ const EditController = ({ rowId, mutate, setOpen, row }) => {
const defaultData = {
end_date: endDate,
end_km: "",
end_time: row?.original?.enter_time ? new Date(row.original.enter_time) : null,
};
const handleSubmit = async (result) => {
@@ -19,6 +20,7 @@ const EditController = ({ rowId, mutate, setOpen, row }) => {
if (result.end_date && result.end_time) {
payload.enter_time = `${result.end_date} ${moment(result.end_time).format("HH:mm")}`;
}
payload.end_km = result.end_km;
await requestServer(`${EDIT_VIOLATION}/${rowId}`, "post", {
data: payload,

View File

@@ -1,9 +1,10 @@
import { useForm } from "react-hook-form";
import { Controller, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import StyledForm from "@/core/components/StyledForm";
import { Box, Button, DialogActions, DialogContent, Grid, Stack } from "@mui/material";
import MissionDates from "./MissionDates";
import * as yup from "yup";
import LtrTextField from "@/core/components/LtrTextField";
export const schema = yup
.object({
@@ -55,7 +56,7 @@ const EditViolationForm = ({ setOpenMachinesDialog, defaultValues, onSubmitBase
<>
<StyledForm onSubmit={handleSubmit(handleOnSubmit)}>
<DialogContent dividers>
<Box sx={{ flex: 1 }}>
<Stack spacing={2} sx={{ flex: 1 }}>
<Stack>
<Grid container spacing={2}>
<MissionDates control={control} />
@@ -73,7 +74,28 @@ const EditViolationForm = ({ setOpenMachinesDialog, defaultValues, onSubmitBase
</Box>
)}
</Stack>
</Box>
<Stack>
<Controller
control={control}
name={"end_km"}
render={({ field, fieldState: { error } }) => (
<LtrTextField
autoComplete="off"
type="tel"
value={field.value}
onChange={(e) => {
if (isNaN(Number(e.target.value))) return;
field.onChange(e.target.value);
}}
size="small"
fullWidth
label="کیلومتر خودرو / ساعت کار"
InputLabelProps={{ shrink: true }}
/>
)}
/>
</Stack>
</Stack>
</DialogContent>
<DialogActions sx={{ alignItems: "center", justifyContent: "center" }}>
<Button