Feature/change style road patrol new

This commit is contained in:
AmirHossein Mahmoodi
2025-01-26 14:00:57 +00:00
parent 2d9d116877
commit caa816c8aa
27 changed files with 363 additions and 275 deletions

View File

@@ -18,13 +18,11 @@ const OperatorCreateForm = ({ open, setOpen, mutate, rowId }) => {
mutate(); mutate();
setOpen(false); setOpen(false);
}) })
.catch((error) => { }); .catch((error) => {});
}; };
return ( return (
<Dialog open={open} fullWidth maxWidth="sm"> <Dialog open={open} fullWidth maxWidth="sm">
{open && ( {open && <CreateFormContent setOpen={setOpen} mutate={mutate} onSubmit={HandleSubmit} />}
<CreateFormContent setOpen={setOpen} mutate={mutate} onSubmit={HandleSubmit} />
)}
</Dialog> </Dialog>
); );
}; };

View File

@@ -120,8 +120,8 @@ const OperatorList = () => {
props.dependencyFieldValue.value === "" props.dependencyFieldValue.value === ""
? "empty" ? "empty"
: loadingSubItemsList : loadingSubItemsList
? "loading" ? "loading"
: props.filterParameters.value : props.filterParameters.value
} }
columnSelectOption={getColumnSelectOptions} columnSelectOption={getColumnSelectOptions}
/> />

View File

@@ -127,8 +127,8 @@ const SupervisorList = () => {
props.dependencyFieldValue?.value === "" props.dependencyFieldValue?.value === ""
? "empty" ? "empty"
: loadingEdaratList : loadingEdaratList
? "loading" ? "loading"
: props.filterParameters.value : props.filterParameters.value
} }
columnSelectOption={getColumnSelectOptions} columnSelectOption={getColumnSelectOptions}
/> />
@@ -221,8 +221,8 @@ const SupervisorList = () => {
props.dependencyFieldValue.value === "" props.dependencyFieldValue.value === ""
? "empty" ? "empty"
: loadingSubItemsList : loadingSubItemsList
? "loading" ? "loading"
: props.filterParameters.value : props.filterParameters.value
} }
columnSelectOption={getColumnSelectOptions} columnSelectOption={getColumnSelectOptions}
/> />

View File

@@ -1,27 +1,20 @@
"use client"; "use client";
import DeleteIcon from "@mui/icons-material/Delete"; import DeleteIcon from "@mui/icons-material/Delete";
import DesignServicesIcon from "@mui/icons-material/DesignServices";
import DirectionsCarIcon from "@mui/icons-material/DirectionsCar";
import HandymanIcon from "@mui/icons-material/Handyman"; import HandymanIcon from "@mui/icons-material/Handyman";
import PersonIcon from "@mui/icons-material/Person"; import { Box, Card, CardActions, CardHeader, IconButton, Typography } from "@mui/material";
import {
Box,
Card,
CardActions,
CardContent,
CardHeader,
Chip,
Divider,
IconButton,
Stack,
Typography,
} from "@mui/material";
import EditActionDuringPatrol from "./EditActionDuringPatrol"; import EditActionDuringPatrol from "./EditActionDuringPatrol";
const ActionInfo = ({ action, setActionsList, index, deleteAction }) => { const ActionInfo = ({ action, setActionsList, index, deleteAction }) => {
return ( return (
<Card sx={{ maxWidth: 300 }}> <Card
elevation={0}
sx={{
maxWidth: 300,
border: 1,
borderColor: "divider",
}}
>
<CardHeader <CardHeader
avatar={<HandymanIcon color="primary" sx={{ width: "30px", height: "30px" }} />} avatar={<HandymanIcon color="primary" sx={{ width: "30px", height: "30px" }} />}
title={<Typography sx={{ fontSize: "14px", fontWeight: 500 }}>{action.data.item_name}</Typography>} title={<Typography sx={{ fontSize: "14px", fontWeight: 500 }}>{action.data.item_name}</Typography>}

View File

@@ -20,7 +20,7 @@ const ActionsDuringPatrol = ({ allData, setAllData, handlePrev, setTabState }) =
const handleNext = (data) => { const handleNext = (data) => {
setAllData({ observed_items: data }); setAllData({ observed_items: data });
setTabState(s => s + 1); setTabState((s) => s + 1);
}; };
return ( return (
@@ -28,19 +28,14 @@ const ActionsDuringPatrol = ({ allData, setAllData, handlePrev, setTabState }) =
<DialogContent dividers sx={{ display: "flex" }}> <DialogContent dividers sx={{ display: "flex" }}>
<Box sx={{ flex: 1 }}> <Box sx={{ flex: 1 }}>
<Stack <Stack
direction={'row'} direction={"row"}
justifyContent={'center'} justifyContent={"center"}
sx={{ sx={{
mt: 1, mt: 1,
mb: 2, mb: 2,
}} }}
> >
<Button <Button onClick={handleOpen} startIcon={<AddCircleIcon />} variant="outlined" sx={{ mb: 1 }}>
onClick={handleOpen}
startIcon={<AddCircleIcon />}
variant="outlined"
sx={{ mb: 1 }}
>
ثبت اقدام انجام شده ثبت اقدام انجام شده
</Button> </Button>
<ModalActionsDuringPatrol open={open} setOpen={setOpen} setActionsList={setActionsList} /> <ModalActionsDuringPatrol open={open} setOpen={setOpen} setActionsList={setActionsList} />
@@ -78,7 +73,7 @@ const ActionsDuringPatrol = ({ allData, setAllData, handlePrev, setTabState }) =
</Box> </Box>
)} )}
</Box> </Box>
</DialogContent > </DialogContent>
<DialogActions sx={{ alignItems: "center", justifyContent: "center" }}> <DialogActions sx={{ alignItems: "center", justifyContent: "center" }}>
<Button <Button
onClick={handlePrev} onClick={handlePrev}
@@ -89,11 +84,7 @@ const ActionsDuringPatrol = ({ allData, setAllData, handlePrev, setTabState }) =
> >
{"صفحه قبل"} {"صفحه قبل"}
</Button> </Button>
<Button <Button variant="contained" size="large" onClick={() => handleNext(actionsList)}>
variant="contained"
size="large"
onClick={() => handleNext(actionsList)}
>
{"تایید اقدامات و ادامه"} {"تایید اقدامات و ادامه"}
</Button> </Button>
</DialogActions> </DialogActions>

View File

@@ -1,7 +1,9 @@
"use client"; "use client";
import ShowPlak from "@/core/components/ShowPlak";
import StyledForm from "@/core/components/StyledForm"; import StyledForm from "@/core/components/StyledForm";
import { formatCounter } from "@/core/utils/formatCounter"; import { formatCounter } from "@/core/utils/formatCounter";
import { formatSecondsToHHMMSS } from "@/core/utils/formatSecondsToHHMMSS";
import { CREATE_PATROL, GET_OTP_TOKEN } from "@/core/utils/routes"; import { CREATE_PATROL, GET_OTP_TOKEN } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest"; import useRequest from "@/lib/hooks/useRequest";
import { yupResolver } from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
@@ -39,10 +41,7 @@ const schemaSend = yup.object().shape({
.string() .string()
.matches(/^09\d{9}$/, "شماره تماس باید با 09 شروع شود و 11 رقم باشد.") .matches(/^09\d{9}$/, "شماره تماس باید با 09 شروع شود و 11 رقم باشد.")
.required("شماره تماس الزامی است."), .required("شماره تماس الزامی است."),
code: yup code: yup.string().length(6).required("شماره تماس الزامی است."),
.string()
.length(6)
.required("شماره تماس الزامی است."),
}); });
const CompeleteRequest = ({ allData, handlePrev, mutate, setOpen }) => { const CompeleteRequest = ({ allData, handlePrev, mutate, setOpen }) => {
@@ -52,17 +51,26 @@ const CompeleteRequest = ({ allData, handlePrev, mutate, setOpen }) => {
const [otpSended, setOtpSended] = useState(false); const [otpSended, setOtpSended] = useState(false);
const defaultValuesOtp = { const defaultValuesOtp = {
phoneNumber: '' phoneNumber: "",
} };
const defaultValuesSend = { const defaultValuesSend = {
phoneNumber: '', phoneNumber: "",
code: '' code: "",
} };
const { handleSubmit: handleSubmitOtp, register: registerOtp, formState: { isSubmitting: isSubmittingOtp, isValid: isValidOtp } } = useForm({ defaultValues: defaultValuesOtp, resolver: yupResolver(schemaOtp), mode: 'onBlur' }) const {
handleSubmit: handleSubmitOtp,
register: registerOtp,
formState: { isSubmitting: isSubmittingOtp, isValid: isValidOtp },
} = useForm({ defaultValues: defaultValuesOtp, resolver: yupResolver(schemaOtp), mode: "onBlur" });
const { handleSubmit: handleSubmitSend, setValue: setValueSend, register: registerSend, formState: { isSubmitting: isSubmittingSend, isValid: isValidSend } } = useForm({ defaultValues: defaultValuesSend, resolver: yupResolver(schemaSend), mode: 'onBlur' }) const {
handleSubmit: handleSubmitSend,
setValue: setValueSend,
register: registerSend,
formState: { isSubmitting: isSubmittingSend, isValid: isValidSend },
} = useForm({ defaultValues: defaultValuesSend, resolver: yupResolver(schemaSend), mode: "onBlur" });
useEffect(() => { useEffect(() => {
if (counter === 0) { if (counter === 0) {
@@ -80,82 +88,102 @@ const CompeleteRequest = ({ allData, handlePrev, mutate, setOpen }) => {
const sendOtp = async (data) => { const sendOtp = async (data) => {
try { try {
const response = await requestServer(`${GET_OTP_TOKEN}?phone_number=${data.phoneNumber}`, "get") const response = await requestServer(`${GET_OTP_TOKEN}?phone_number=${data.phoneNumber}`, "get");
setOtpSended(true) setOtpSended(true);
setDelayPerRequest(true); setDelayPerRequest(true);
setValueSend("phoneNumber", data.phoneNumber) setValueSend("phoneNumber", data.phoneNumber);
} catch (error) { } catch (error) {}
}
}; };
const sendData = useCallback(async (data) => { const sendData = useCallback(
console.log(allData); async (data) => {
const formData = new FormData();
const formData = new FormData(); allData.road_patrol_rahdaran_id.forEach((rahdar, index) =>
allData.road_patrol_rahdaran_id.forEach((rahdar, index) => formData.append(`road_patrol_rahdaran_id[${index}]`, rahdar.id)); formData.append(`road_patrol_rahdaran_id[${index}]`, rahdar.id)
formData.append(`road_patrol_machines_id[0]`, allData.roadPatrolMachinesId.id) );
allData.stopPoints.forEach((stop_point, index) => formData.append(`stop_points[${index}]`, stop_point)) formData.append(`road_patrol_machines_id[0]`, allData.roadPatrolMachinesId.id);
allData.observed_items.forEach((observed_item, index) => { allData.stopPoints.forEach((stop_point, index) => {
formData.append(`observed_items[${index}][instant_action]`, 1); formData.append(`stop_points[${index}][duration]`, stop_point.duration);
formData.append(`observed_items[${index}][local_name]`, ""); formData.append(`stop_points[${index}][latitude]`, stop_point.latitude);
formData.append(`observed_items[${index}][start_point]`, observed_item.result.start_point); formData.append(`stop_points[${index}][longitude]`, stop_point.longitude);
formData.append(`observed_items[${index}][end_point]`, observed_item.result.end_point); formData.append(`stop_points[${index}][startDT]`, stop_point.startDT);
formData.append(`observed_items[${index}][amount]`, observed_item.result.amount);
formData.append(`observed_items[${index}][before_image]`, observed_item.result.before_image);
formData.append(`observed_items[${index}][after_image]`, observed_item.result.after_image);
formData.append(`observed_items[${index}][item_id]`, observed_item.result.item_id);
formData.append(`observed_items[${index}][sub_item_id]`, observed_item.result.sub_item_id);
formData.append(`observed_items[${index}][road_item_machines_id][]`, allData.roadPatrolMachinesId.id)
allData.road_patrol_rahdaran_id.forEach((rahdar, index) => formData.append(`observed_items[${index}][road_item_rahdaran_id][]`, rahdar.id));
})
formData.append("start_time", allData.start_time);
formData.append("end_time", allData.end_time);
formData.append("vehicle_runtime", allData.accOnDuration);
formData.append("fuel_consumption", +allData.fuelConsumption);
formData.append("distance", allData.mileage);
// formData.append("description", "");
formData.append("phone_number", data.phoneNumber);
formData.append("verification_code", data.code);
try {
await requestServer(CREATE_PATROL, "post", {
data: formData,
}); });
mutate(); allData.observed_items.forEach((observed_item, index) => {
setOpen(false); formData.append(`observed_items[${index}][instant_action]`, 1);
} catch (error) { formData.append(`observed_items[${index}][local_name]`, "");
console.log(error); formData.append(`observed_items[${index}][start_point]`, observed_item.result.start_point);
formData.append(`observed_items[${index}][end_point]`, observed_item.result.end_point);
} formData.append(`observed_items[${index}][amount]`, observed_item.result.amount);
}, [allData]) formData.append(`observed_items[${index}][before_image]`, observed_item.result.before_image);
formData.append(`observed_items[${index}][after_image]`, observed_item.result.after_image);
formData.append(`observed_items[${index}][item_id]`, observed_item.result.item_id);
formData.append(`observed_items[${index}][sub_item_id]`, observed_item.result.sub_item_id);
formData.append(`observed_items[${index}][road_item_machines_id][]`, allData.roadPatrolMachinesId.id);
allData.road_patrol_rahdaran_id.forEach((rahdar, index) =>
formData.append(`observed_items[${index}][road_item_rahdaran_id][]`, rahdar.id)
);
});
formData.append("start_time", allData.start_time);
formData.append("end_time", allData.end_time);
formData.append("vehicle_runtime", allData.accOnDuration);
formData.append("fuel_consumption", +allData.fuelConsumption);
formData.append("distance", allData.mileage);
// formData.append("description", "");
formData.append("phone_number", data.phoneNumber);
formData.append("verification_code", data.code);
try {
await requestServer(CREATE_PATROL, "post", {
data: formData,
});
mutate();
setOpen(false);
} catch (error) {
console.log(error);
}
},
[allData]
);
return ( return (
<> <>
<DialogContent dividers sx={{ display: "flex" }}> <DialogContent dividers sx={{ display: "flex" }}>
<Box sx={{ flex: 1 }}> <Box sx={{ flex: 1 }}>
<Stack> <Stack>
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}> <Divider>
<Box> <Chip label="اطلاعات گشت" variant="outlined" />
<Typography sx={{ color: "#777777", fontWeight: 500 }} variant="body1"> </Divider>
{allData.start_time !== '' && moment(allData.start_time).locale("fa").format("YYYY/MM/DD | HH:mm")} <Grid container spacing={2} sx={{ alignItems: "start", my: 1 }}>
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Chip label="تاریخ و زمان شروع" />
<Divider sx={{ flex: 1, mx: 2 }} />
<Typography>
{allData.start_time !== "" &&
moment(allData.start_time).locale("fa").format("YYYY/MM/DD | HH:mm")}
</Typography> </Typography>
</Box> </Grid>
<Box> <Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Typography sx={{ color: "#777777", fontWeight: 500 }} variant="body1"> <Chip label="تاریخ و زمان پایان" />
{allData.end_time !== '' && moment(allData.end_time).locale("fa").format("YYYY/MM/DD | HH:mm")} <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>
{allData.start_time !== "" &&
moment(allData.start_time).locale("fa").format("YYYY/MM/DD | HH:mm")}
</Typography> </Typography>
</Box> </Grid>
</Box> </Grid>
<Grid container spacing={2} sx={{ alignItems: "start", my: 1 }}> <Grid container spacing={2} sx={{ alignItems: "start", my: 1 }}>
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}> <Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Chip label="مدت زمان روشن بودن خودرو" /> <Chip label="مدت زمان روشن بودن خودرو" />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{allData.accOnDuration && allData.accOnDuration}</Typography> <Typography>
{allData.accOnDuration && formatSecondsToHHMMSS(allData.accOnDuration)}
</Typography>
</Grid> </Grid>
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}> <Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Chip label="میزان سوخت مصرفی" /> <Chip label="میزان سوخت مصرفی" />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{allData.fuelConsumption && allData.fuelConsumption}</Typography> <Typography>
{allData.fuelConsumption && Math.round(allData.fuelConsumption * 10) / 10} لیتر
</Typography>
</Grid> </Grid>
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}> <Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Chip label="تعداد نقاط توقف" /> <Chip label="تعداد نقاط توقف" />
@@ -165,7 +193,9 @@ const CompeleteRequest = ({ allData, handlePrev, mutate, setOpen }) => {
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}> <Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Chip label="مسافت پیموده شده" /> <Chip label="مسافت پیموده شده" />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{allData.mileage && allData.mileage}</Typography> <Typography>
{allData.mileage && (allData.mileage / 1000).toFixed(1)} کیلومتر
</Typography>
</Grid> </Grid>
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}> <Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Chip label="تعداد فعالیت های حین گشت" /> <Chip label="تعداد فعالیت های حین گشت" />
@@ -178,38 +208,58 @@ const CompeleteRequest = ({ allData, handlePrev, mutate, setOpen }) => {
<Divider> <Divider>
<Chip label="خودرو گشت" /> <Chip label="خودرو گشت" />
</Divider> </Divider>
<Box sx={{ display: "flex", alignItems: "center", my: 1 }}> <Stack direction={"row"} sx={{ alignItems: "center", my: 1 }}>
<Typography>کد</Typography> <Chip label="کد خودرو" />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{allData.roadPatrolMachinesId && allData.roadPatrolMachinesId.machine_code}</Typography> <Typography>
</Box> {allData.roadPatrolMachinesId && allData.roadPatrolMachinesId.machine_code}
<Box sx={{ display: "flex", alignItems: "center", my: 1 }}> </Typography>
<Typography>نام</Typography> </Stack>
<Stack direction={"row"} sx={{ alignItems: "center", my: 1 }}>
<Chip label="نام خودرو" />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{allData.roadPatrolMachinesId && allData.roadPatrolMachinesId.car_name}</Typography> <Typography>
</Box> {allData.roadPatrolMachinesId && allData.roadPatrolMachinesId.car_name}
<Box sx={{ display: "flex", alignItems: "center", my: 1 }}> </Typography>
<Typography>پلاک</Typography> </Stack>
<Stack direction={"row"} sx={{ alignItems: "center", my: 1 }}>
<Chip label="پلاک خودرو" />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{allData.roadPatrolMachinesId && allData.roadPatrolMachinesId.plak_number}</Typography> <Box sx={{ fontSize: 11 }}>
</Box> {allData.roadPatrolMachinesId.plak_number &&
ShowPlak({ plak_number: allData.roadPatrolMachinesId.plak_number })}
</Box>
</Stack>
</Grid> </Grid>
<Grid item xs={12} lg={6}> <Grid item xs={12} lg={6}>
<Divider> <Divider>
<Chip label="راهدار / راهداران حاضر در گشت" /> <Chip label="راهدار / راهداران حاضر در گشت" />
</Divider> </Divider>
{allData.road_patrol_rahdaran_id.map((rahdar, index) => ( {allData.road_patrol_rahdaran_id.map((rahdar, index) => (
<Box key={index} sx={{ display: "flex", alignItems: "center", my: 1 }}> <Stack key={rahdar.code} direction={"row"} sx={{ alignItems: "center", my: 1 }}>
<Typography>نام و کد راهدار</Typography> <Chip label={`نام و کد راهدار ${index + 1}`} />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography> <Box sx={{ fontSize: 11 }}>
{rahdar.name} | {rahdar.code} <Typography>
</Typography> {rahdar.name} | {rahdar.code}
</Box> </Typography>
</Box>
</Stack>
))} ))}
</Grid> </Grid>
</Grid> </Grid>
<Box sx={{ display: "flex", gap: 2, my: 2, justifyContent: "space-around", flexDirection: { xs: 'column', md: 'row' } }}> <Divider>
<Chip label="احراز هویت" variant="outlined" />
</Divider>
<Box
sx={{
display: "flex",
gap: 2,
my: 2,
justifyContent: "space-around",
flexDirection: { xs: "column", md: "row" },
}}
>
<StyledForm onSubmit={handleSubmitOtp(sendOtp)}> <StyledForm onSubmit={handleSubmitOtp(sendOtp)}>
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}> <Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<FormControl size="small" fullWidth variant="outlined"> <FormControl size="small" fullWidth variant="outlined">
@@ -235,7 +285,11 @@ const CompeleteRequest = ({ allData, handlePrev, mutate, setOpen }) => {
sx={{ textWrap: "nowrap", width: 200 }} sx={{ textWrap: "nowrap", width: 200 }}
endIcon={<ForwardToInboxIcon />} endIcon={<ForwardToInboxIcon />}
> >
{delayPerRequest ? formatCounter(counter) : isSubmittingOtp ? 'درحال دریافت کد ...' : "دریافت کد"} {delayPerRequest
? formatCounter(counter)
: isSubmittingOtp
? "درحال دریافت کد ..."
: "دریافت کد"}
</Button> </Button>
</Box> </Box>
</StyledForm> </StyledForm>
@@ -269,7 +323,7 @@ const CompeleteRequest = ({ allData, handlePrev, mutate, setOpen }) => {
</Box> </Box>
</Stack> </Stack>
</Box> </Box>
</DialogContent > </DialogContent>
<DialogActions sx={{ alignItems: "center", justifyContent: "center" }}> <DialogActions sx={{ alignItems: "center", justifyContent: "center" }}>
<Button <Button
onClick={handlePrev} onClick={handlePrev}

View File

@@ -4,7 +4,7 @@ import moment from "jalali-moment";
import { useWatch } from "react-hook-form"; import { useWatch } from "react-hook-form";
const DatePickerForEndTime = ({ field, fieldState: { error }, control }) => { const DatePickerForEndTime = ({ field, fieldState: { error }, control }) => {
const startTime = useWatch({ control, name: "start_time" }) const startTime = useWatch({ control, name: "start_time" });
return ( return (
<MobileDateTimePicker <MobileDateTimePicker
value={field.value ? new Date(field.value) : null} value={field.value ? new Date(field.value) : null}
@@ -22,7 +22,7 @@ const DatePickerForEndTime = ({ field, fieldState: { error }, control }) => {
size: "small", size: "small",
placeholder: "تاریخ و ساعت وارد کنید", placeholder: "تاریخ و ساعت وارد کنید",
InputLabelProps: { shrink: true }, InputLabelProps: { shrink: true },
sx: { width: { xs: '100%', md: 200 } }, sx: { width: { xs: "100%", md: 200 } },
InputProps: { InputProps: {
endAdornment: ( endAdornment: (
<InputAdornment position="end"> <InputAdornment position="end">
@@ -50,5 +50,5 @@ const DatePickerForEndTime = ({ field, fieldState: { error }, control }) => {
label="تاریخ و ساعت پایان گشت" label="تاریخ و ساعت پایان گشت"
/> />
); );
} };
export default DatePickerForEndTime export default DatePickerForEndTime;

View File

@@ -4,7 +4,7 @@ import moment from "jalali-moment";
import { useWatch } from "react-hook-form"; import { useWatch } from "react-hook-form";
const DatePickerForStartTime = ({ field, fieldState: { error }, control }) => { const DatePickerForStartTime = ({ field, fieldState: { error }, control }) => {
const endTime = useWatch({ control, name: "end_time" }) const endTime = useWatch({ control, name: "end_time" });
return ( return (
<MobileDateTimePicker <MobileDateTimePicker
value={field.value ? new Date(field.value) : null} value={field.value ? new Date(field.value) : null}
@@ -22,7 +22,7 @@ const DatePickerForStartTime = ({ field, fieldState: { error }, control }) => {
size: "small", size: "small",
placeholder: "تاریخ و ساعت وارد کنید", placeholder: "تاریخ و ساعت وارد کنید",
InputLabelProps: { shrink: true }, InputLabelProps: { shrink: true },
sx: { width: { xs: '100%', md: 200 } }, sx: { width: { xs: "100%", md: 200 } },
InputProps: { InputProps: {
endAdornment: ( endAdornment: (
<InputAdornment position="end"> <InputAdornment position="end">
@@ -50,5 +50,5 @@ const DatePickerForStartTime = ({ field, fieldState: { error }, control }) => {
label="تاریخ و ساعت شروع گشت" label="تاریخ و ساعت شروع گشت"
/> />
); );
} };
export default DatePickerForStartTime export default DatePickerForStartTime;

View File

@@ -48,7 +48,12 @@ const EditActionDuringPatrol = ({ action, index, setActionsList }) => {
}} }}
> >
<DialogTitle>ویرایش اطلاعات</DialogTitle> <DialogTitle>ویرایش اطلاعات</DialogTitle>
<EditFormContent setOpenEditDialog={setOpen} onSubmit={HandleSubmit} defaultData={action.data} is_gasht={true} /> <EditFormContent
setOpenEditDialog={setOpen}
onSubmit={HandleSubmit}
defaultData={action.data}
is_gasht={true}
/>
</Dialog> </Dialog>
</> </>
); );

View File

@@ -21,15 +21,9 @@ import PatrolDetailInfo from "./PatrolDetailInfo";
import PatrolResultCodeErrors from "./PatrolResultCodeErrors"; import PatrolResultCodeErrors from "./PatrolResultCodeErrors";
const schema = yup.object().shape({ const schema = yup.object().shape({
roadPatrolMachinesId: yup roadPatrolMachinesId: yup.object().required("خودرو الزامی است."),
.object() start_time: yup.string().required("زمان شروع الزامی است."),
.required("خودرو الزامی است."), end_time: yup.string().required("زمان پایان الزامی است."),
start_time: yup
.string()
.required("زمان شروع الزامی است."),
end_time: yup
.string()
.required("زمان پایان الزامی است.")
}); });
const PatrolDetail = ({ allData, setAllData, handlePrev, setTabState }) => { const PatrolDetail = ({ allData, setAllData, handlePrev, setTabState }) => {
@@ -47,12 +41,16 @@ const PatrolDetail = ({ allData, setAllData, handlePrev, setTabState }) => {
const [patrolResultStatus, setPatrolResultStatus] = useState(allData.resultCode); const [patrolResultStatus, setPatrolResultStatus] = useState(allData.resultCode);
const [patrolData, setPatrolData] = useState(defaultValues); const [patrolData, setPatrolData] = useState(defaultValues);
const {
const { control, handleSubmit, setValue, formState: { isSubmitting, isValid } } = useForm({ defaultValues, resolver: yupResolver(schema), mode: 'onBlur' }) control,
handleSubmit,
setValue,
formState: { isSubmitting, isValid },
} = useForm({ defaultValues, resolver: yupResolver(schema), mode: "onBlur" });
const requestPatrolInfo = async (data) => { const requestPatrolInfo = async (data) => {
setPatrolResultStatus(1) setPatrolResultStatus(1);
setPatrolData(pd => ({ ...pd, has_vehicle_operation: false })) setPatrolData((pd) => ({ ...pd, has_vehicle_operation: false }));
const formData = new FormData(); const formData = new FormData();
formData.append("machineCode", data.roadPatrolMachinesId.machine_code); formData.append("machineCode", data.roadPatrolMachinesId.machine_code);
formData.append("startDT", moment(data.start_time).format("YYYY-MM-DDTHH:mm")); formData.append("startDT", moment(data.start_time).format("YYYY-MM-DDTHH:mm"));
@@ -60,46 +58,51 @@ const PatrolDetail = ({ allData, setAllData, handlePrev, setTabState }) => {
try { try {
const response = await requestServer(GET_VAHICLE_OPRATION, "post", { const response = await requestServer(GET_VAHICLE_OPRATION, "post", {
data: formData, data: formData,
}) });
const result = response.data.data; const result = response.data.data;
setPatrolData({ setPatrolData({
...result, ...result,
roadPatrolMachinesId: data.roadPatrolMachinesId, roadPatrolMachinesId: data.roadPatrolMachinesId,
start_time: data.start_time, start_time: data.start_time,
end_time: data.end_time, end_time: data.end_time,
has_vehicle_operation: result.resultCode == 0 has_vehicle_operation: result.resultCode == 0,
}); });
setValue('stopPoints', result.stopPoints) setValue("stopPoints", result.stopPoints);
setValue('accOnDuration', result.accOnDuration) setValue("accOnDuration", result.accOnDuration);
setValue('fuelConsumption', result.fuelConsumption) setValue("fuelConsumption", result.fuelConsumption);
setValue('mileage', result.mileage) setValue("mileage", result.mileage);
setValue('has_vehicle_operation', true) setValue("has_vehicle_operation", true);
setPatrolResultStatus(result.resultCode); setPatrolResultStatus(result.resultCode);
} catch (error) { } catch (error) {}
}
}; };
const handleNext = (data) => { const handleNext = (data) => {
setAllData(data); setAllData(data);
setTabState(s => s + 1) setTabState((s) => s + 1);
} };
return ( return (
<> <>
<DialogContent dividers sx={{ display: "flex" }}> <DialogContent dividers sx={{ display: "flex", maxHeight: { xs: "500px", md: "100%" }, overflowY: "auto" }}>
<Box sx={{ flex: 1 }}> <Box sx={{ flex: 1 }}>
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
mt: 1, mt: 1,
mb: 2 mb: 2,
}} }}
> >
<StyledForm onSubmit={handleSubmit(requestPatrolInfo)}> <StyledForm onSubmit={handleSubmit(requestPatrolInfo)}>
<Box sx={{ display: "flex", flexDirection: { xs: "column", md: "row" }, rowGap: 2, columnGap: 1 }}> <Box
sx={{
display: "flex",
flexDirection: { xs: "column", md: "row" },
rowGap: 2,
columnGap: 1,
}}
>
<Stack sx={{ minWidth: "200px" }}> <Stack sx={{ minWidth: "200px" }}>
<Controller <Controller
control={control} control={control}
@@ -139,19 +142,15 @@ const PatrolDetail = ({ allData, setAllData, handlePrev, setTabState }) => {
disabled={isSubmitting || !isValid} disabled={isSubmitting || !isValid}
endIcon={<SearchIcon />} endIcon={<SearchIcon />}
> >
{isSubmitting ? "درحال دریافت عملکرد خودرو ..." : 'دریافت عملکرد خوردو'} {isSubmitting ? "درحال دریافت عملکرد خودرو ..." : "دریافت عملکرد خوردو"}
</Button> </Button>
</Box> </Box>
</StyledForm> </StyledForm>
<Divider sx={{ my: 2, width: "100%" }}> <Divider sx={{ my: 2, width: "100%" }}>
<Chip label="مشخصات گشت" variant="outlined" /> <Chip label="مشخصات گشت" variant="outlined" />
</Divider> </Divider>
{patrolResultStatus !== 0 && ( {patrolResultStatus !== 0 && <PatrolResultCodeErrors ResultCode={patrolResultStatus} />}
<PatrolResultCodeErrors ResultCode={patrolResultStatus} /> <PatrolDetailInfo patrolData={patrolData} />
)}
<PatrolDetailInfo
patrolData={patrolData}
/>
</Box> </Box>
</Box> </Box>
</DialogContent> </DialogContent>

View File

@@ -1,6 +1,18 @@
"use client"; "use client";
import { Box, Button, Card, CardActions, CardContent, Chip, Divider, Fade, Slide, Stack, Typography } from "@mui/material"; import {
Box,
Button,
Card,
CardActions,
CardContent,
Chip,
Divider,
Fade,
Slide,
Stack,
Typography,
} from "@mui/material";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import MapLoading from "@/core/components/MapLayer/Loading"; import MapLoading from "@/core/components/MapLayer/Loading";
@@ -16,6 +28,8 @@ import QrCode2Icon from "@mui/icons-material/QrCode2";
import moment from "jalali-moment"; import moment from "jalali-moment";
import PatrolMapFeatures from "./PatrolMapFeatures"; import PatrolMapFeatures from "./PatrolMapFeatures";
import { useMap } from "react-leaflet"; import { useMap } from "react-leaflet";
import { formatSecondsToHHMMSS } from "@/core/utils/formatSecondsToHHMMSS";
import ShowPlak from "@/core/components/ShowPlak";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading />, loading: () => <MapLoading />,
@@ -33,17 +47,20 @@ const MapItemViewBound = ({ patrolData, bound }) => {
return ( return (
<> <>
{patrolData?.stopPoints && patrolData.stopPoints.map((stopPoint, index) => ( {patrolData?.stopPoints &&
<React.Fragment key={index}> patrolData.stopPoints.map((stopPoint, index) => (
<PatrolMapFeatures stopPoint={stopPoint} /> <React.Fragment key={index}>
</React.Fragment> <PatrolMapFeatures stopPoint={stopPoint} />
))} </React.Fragment>
))}
</> </>
); );
}; };
const PatrolDetailInfo = ({ patrolData }) => { const PatrolDetailInfo = ({ patrolData }) => {
const bound = patrolData?.stopPoints ? patrolData?.stopPoints.map((point) => [point.latitude, point.longitude]) : [] const bound = patrolData?.stopPoints
? patrolData?.stopPoints.map((point) => [point.latitude, point.longitude])
: [];
return ( return (
<Fade in={patrolData?.has_vehicle_operation} sx={{ width: "100%" }}> <Fade in={patrolData?.has_vehicle_operation} sx={{ width: "100%" }}>
@@ -57,12 +74,12 @@ const PatrolDetailInfo = ({ patrolData }) => {
gap: { xs: 2, lg: 0 }, gap: { xs: 2, lg: 0 },
}} }}
> >
<Stack sx={{ minWidth: { xs: "100%", md: "300px" }, gap: 2 }}> <Stack sx={{ minWidth: { xs: "100%", md: "350px" }, gap: 2 }}>
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="مدت زمان روشن بودن خودرو" icon={<ElectricCarIcon />} /> <Chip size="small" label="مدت زمان روشن بودن خودرو" icon={<ElectricCarIcon />} />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{ fontSize: "13px", fontWeight: 400 }}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{Math.floor(patrolData?.accOnDuration / 60)} دقیقه {formatSecondsToHHMMSS(patrolData?.accOnDuration)}
</Typography> </Typography>
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
@@ -79,36 +96,39 @@ const PatrolDetailInfo = ({ patrolData }) => {
{patrolData?.roadPatrolMachinesId?.machine_code} {patrolData?.roadPatrolMachinesId?.machine_code}
</Typography> </Typography>
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}> <Box sx={{ display: "flex", alignItems: "center" }}>
<Chip size="small" label="پلاک خودرو" icon={<DirectionsCarFilledIcon />} /> <Chip size="small" label="پلاک خودرو" icon={<DirectionsCarFilledIcon />} />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{ fontSize: "13px", fontWeight: 400 }}> <Box sx={{ fontSize: 11 }}>
{patrolData?.roadPatrolMachinesId?.plak_number} {patrolData?.roadPatrolMachinesId?.plak_number &&
</Typography> ShowPlak({ plak_number: patrolData?.roadPatrolMachinesId?.plak_number })}
</Box>
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="زمان شروع گشت" icon={<QueryBuilderIcon />} /> <Chip size="small" label="زمان شروع گشت" icon={<QueryBuilderIcon />} />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{ fontSize: "13px", fontWeight: 400 }}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{patrolData?.start_time !== '' && moment(patrolData?.start_time).locale("fa").format("HH:mm | YYYY/MM/DD")} {patrolData?.start_time !== "" &&
moment(patrolData?.start_time).locale("fa").format("HH:mm | YYYY/MM/DD")}
</Typography> </Typography>
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="زمان پایان گشت" icon={<WatchLaterIcon />} /> <Chip size="small" label="زمان پایان گشت" icon={<WatchLaterIcon />} />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{ fontSize: "13px", fontWeight: 400 }}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{patrolData?.end_time !== '' && moment(patrolData?.end_time).locale("fa").format("HH:mm | YYYY/MM/DD")} {patrolData?.end_time !== "" &&
moment(patrolData?.end_time).locale("fa").format("HH:mm | YYYY/MM/DD")}
</Typography> </Typography>
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="مسافت" icon={<AddRoadIcon />} /> <Chip size="small" label="مسافت پیموده شده" icon={<AddRoadIcon />} />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{ fontSize: "13px", fontWeight: 400 }}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{(patrolData?.mileage / 1000).toFixed(1)} کیلومتر {(patrolData?.mileage / 1000).toFixed(1)} کیلومتر
</Typography> </Typography>
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="میزان مصرف سوخت" icon={<LocalGasStationIcon />} /> <Chip size="small" label="میزان سوخت مصرفی" icon={<LocalGasStationIcon />} />
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{ fontSize: "13px", fontWeight: 400 }}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{Math.round(patrolData?.fuelConsumption * 10) / 10} لیتر {Math.round(patrolData?.fuelConsumption * 10) / 10} لیتر
@@ -150,7 +170,6 @@ const PatrolDetailInfo = ({ patrolData }) => {
</Box> </Box>
</Stack> </Stack>
</CardContent> </CardContent>
</Card> </Card>
</Fade> </Fade>
); );

View File

@@ -1,17 +1,17 @@
"use client"; "use client";
import useRequest from "@/lib/hooks/useRequest";
import { useTheme } from "@emotion/react"; import { useTheme } from "@emotion/react";
import TaxiAlertIcon from "@mui/icons-material/TaxiAlert";
import EngineeringIcon from "@mui/icons-material/Engineering"; import EngineeringIcon from "@mui/icons-material/Engineering";
import HandymanIcon from "@mui/icons-material/Handyman"; import HandymanIcon from "@mui/icons-material/Handyman";
import TaxiAlertIcon from "@mui/icons-material/TaxiAlert";
import VerifiedIcon from "@mui/icons-material/Verified"; import VerifiedIcon from "@mui/icons-material/Verified";
import { Box, Tab, Tabs, useMediaQuery } from "@mui/material"; import { Box, Tab, Tabs, useMediaQuery } from "@mui/material";
import { DialogHeader } from "next/dist/client/components/react-dev-overlay/internal/components/Dialog";
import { useCallback, useEffect, useReducer, useState } from "react"; import { useCallback, useEffect, useReducer, useState } from "react";
import PatrolDetail from "./PatrolDetail";
import SuperVisorsDetail from "./SuperVisorsDetail";
import ActionsDuringPatrol from "./ActionsDurigPatrol"; import ActionsDuringPatrol from "./ActionsDurigPatrol";
import CompeleteRequest from "./CompeleteRequest"; import CompeleteRequest from "./CompeleteRequest";
import PatrolDetail from "./PatrolDetail";
import SuperVisorsDetail from "./SuperVisorsDetail";
function TabPanel(props) { function TabPanel(props) {
const { children, value, index } = props; const { children, value, index } = props;
@@ -41,17 +41,14 @@ const defaultValues = {
const reducer = (state, action) => { const reducer = (state, action) => {
switch (action.type) { switch (action.type) {
case 'changeData': case "changeData":
return { ...state, ...action.data } return { ...state, ...action.data };
default: default:
return state; return state;
} }
};
}
const PatrolForms = ({ mutate, setOpen }) => { const PatrolForms = ({ mutate, setOpen }) => {
const requestServer = useRequest({ notificationSuccess: true });
const [allData, dispatch] = useReducer(reducer, defaultValues); const [allData, dispatch] = useReducer(reducer, defaultValues);
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("md")); const isMobile = useMediaQuery(theme.breakpoints.down("md"));
@@ -72,33 +69,36 @@ const PatrolForms = ({ mutate, setOpen }) => {
if (tabState == 0) { if (tabState == 0) {
setOpen(false); setOpen(false);
} }
setTabState(s => s - 1) setTabState((s) => s - 1);
}, [tabState]) }, [tabState]);
return ( return (
<> <>
<Tabs <DialogHeader>
allowScrollButtonsMobile <Tabs
value={tabState} allowScrollButtonsMobile
onChange={handleChangeTab} value={tabState}
variant={`${isMobile ? "scrollable" : "fullWidth"}`} onChange={handleChangeTab}
sx={{ variant={`${isMobile ? "scrollable" : "fullWidth"}`}
display: "flex", sx={{
justifyContent: "space-around", display: "flex",
width: "100%", justifyContent: "space-around",
backgroundColor: "#efefef", width: "100%",
}} backgroundColor: "#efefef",
> }}
<Tab disabled={!(activeUpTo >= 0)} icon={<TaxiAlertIcon />} label="مشخصات گشت"></Tab> >
<Tab disabled={!(activeUpTo >= 1)} icon={<EngineeringIcon />} label="مشخصات راهداران"></Tab> <Tab disabled={!(activeUpTo >= 0)} icon={<TaxiAlertIcon />} label="مشخصات گشت"></Tab>
<Tab disabled={!(activeUpTo >= 2)} icon={<HandymanIcon />} label="اقدامات حین گشت"></Tab> <Tab disabled={!(activeUpTo >= 1)} icon={<EngineeringIcon />} label="مشخصات راهداران"></Tab>
<Tab disabled={!(activeUpTo >= 3)} icon={<VerifiedIcon />} label="بررسی نهایی و ثبت"></Tab> <Tab disabled={!(activeUpTo >= 2)} icon={<HandymanIcon />} label="اقدامات حین گشت"></Tab>
</Tabs> <Tab disabled={!(activeUpTo >= 3)} icon={<VerifiedIcon />} label="بررسی نهایی و ثبت"></Tab>
</Tabs>
</DialogHeader>
<TabPanel value={tabState} index={0}> <TabPanel value={tabState} index={0}>
<PatrolDetail <PatrolDetail
allData={allData} allData={allData}
setAllData={(data) => { dispatch({ type: 'changeData', data }) }} setAllData={(data) => {
dispatch({ type: "changeData", data });
}}
handlePrev={handlePrev} handlePrev={handlePrev}
setTabState={setTabState} setTabState={setTabState}
/> />
@@ -106,7 +106,9 @@ const PatrolForms = ({ mutate, setOpen }) => {
<TabPanel value={tabState} index={1}> <TabPanel value={tabState} index={1}>
<SuperVisorsDetail <SuperVisorsDetail
allData={allData} allData={allData}
setAllData={(data) => { dispatch({ type: 'changeData', data }) }} setAllData={(data) => {
dispatch({ type: "changeData", data });
}}
handlePrev={handlePrev} handlePrev={handlePrev}
setTabState={setTabState} setTabState={setTabState}
/> />
@@ -114,18 +116,15 @@ const PatrolForms = ({ mutate, setOpen }) => {
<TabPanel value={tabState} index={2}> <TabPanel value={tabState} index={2}>
<ActionsDuringPatrol <ActionsDuringPatrol
allData={allData} allData={allData}
setAllData={(data) => { dispatch({ type: 'changeData', data }) }} setAllData={(data) => {
dispatch({ type: "changeData", data });
}}
handlePrev={handlePrev} handlePrev={handlePrev}
setTabState={setTabState} setTabState={setTabState}
/> />
</TabPanel> </TabPanel>
<TabPanel value={tabState} index={3}> <TabPanel value={tabState} index={3}>
<CompeleteRequest <CompeleteRequest allData={allData} handlePrev={handlePrev} mutate={mutate} setOpen={setOpen} />
allData={allData}
handlePrev={handlePrev}
mutate={mutate}
setOpen={setOpen}
/>
</TabPanel> </TabPanel>
</> </>
); );

View File

@@ -15,8 +15,11 @@ const PatrolResultCodeErrors = ({ ResultCode }) => {
const message = errorMessages[ResultCode] || "ابتدا اطلاعات بالا را تکمیل نمایید"; const message = errorMessages[ResultCode] || "ابتدا اطلاعات بالا را تکمیل نمایید";
return ( return (
<Box sx={{ my: 5, textAlign: 'center' }}> <Box sx={{ my: 5, textAlign: "center" }}>
<Typography variant="h6" sx={{ letterSpacing: "2px", color: ResultCode && ResultCode != 1 ? "error.main" : "#606060" }}> <Typography
variant="h6"
sx={{ letterSpacing: "2px", color: ResultCode && ResultCode != 1 ? "error.main" : "#606060" }}
>
{message} {message}
</Typography> </Typography>
</Box> </Box>

View File

@@ -14,7 +14,7 @@ const SuperVisorInfo = ({ superVisor, deleteSuperVisor }) => {
alignItems: "center", alignItems: "center",
justifyContent: "space-between", justifyContent: "space-between",
border: 1, border: 1,
borderColor: 'divider', borderColor: "divider",
px: 1, px: 1,
py: 1, py: 1,
}} }}

View File

@@ -11,9 +11,7 @@ import { Controller, useForm } from "react-hook-form";
import * as yup from "yup"; import * as yup from "yup";
const schema = yup.object().shape({ const schema = yup.object().shape({
road_patrol_rahdaran_id: yup road_patrol_rahdaran_id: yup.object().required("راهدار الزامی است."),
.object()
.required("راهدار الزامی است."),
}); });
const SuperVisorsDetail = ({ allData, setAllData, handlePrev, setTabState }) => { const SuperVisorsDetail = ({ allData, setAllData, handlePrev, setTabState }) => {
@@ -23,11 +21,17 @@ const SuperVisorsDetail = ({ allData, setAllData, handlePrev, setTabState }) =>
road_patrol_rahdaran_id: null, road_patrol_rahdaran_id: null,
}; };
const { control, handleSubmit, reset, setValue, formState: { isSubmitting, isValid } } = useForm({ defaultValues, resolver: yupResolver(schema), mode: 'onBlur' }) const {
control,
handleSubmit,
reset,
setValue,
formState: { isSubmitting, isValid },
} = useForm({ defaultValues, resolver: yupResolver(schema), mode: "onBlur" });
const requestPatrolInfo = (data) => { const requestPatrolInfo = (data) => {
setSuperVisorList((prev) => [...prev, data.road_patrol_rahdaran_id]); setSuperVisorList((prev) => [...prev, data.road_patrol_rahdaran_id]);
reset() reset();
}; };
const deleteSuperVisor = (id) => { const deleteSuperVisor = (id) => {
@@ -36,8 +40,8 @@ const SuperVisorsDetail = ({ allData, setAllData, handlePrev, setTabState }) =>
const handleNext = (data) => { const handleNext = (data) => {
setAllData({ road_patrol_rahdaran_id: data }); setAllData({ road_patrol_rahdaran_id: data });
setTabState(s => s + 1) setTabState((s) => s + 1);
} };
return ( return (
<> <>
@@ -48,11 +52,11 @@ const SuperVisorsDetail = ({ allData, setAllData, handlePrev, setTabState }) =>
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
mt: 1, mt: 1,
mb: 2 mb: 2,
}} }}
> >
<StyledForm onSubmit={handleSubmit(requestPatrolInfo)}> <StyledForm onSubmit={handleSubmit(requestPatrolInfo)}>
<Stack direction={{ xs: "column", sm: 'row' }} justifyContent={'center'} spacing={2}> <Stack direction={{ xs: "column", sm: "row" }} justifyContent={"center"} spacing={2}>
<Stack sx={{ minWidth: "250px" }}> <Stack sx={{ minWidth: "250px" }}>
<Controller <Controller
control={control} control={control}
@@ -101,16 +105,20 @@ const SuperVisorsDetail = ({ allData, setAllData, handlePrev, setTabState }) =>
overflowY: "auto", overflowY: "auto",
}} }}
> >
{SuperVisorList.length !== 0 && SuperVisorList.map((superVisor) => ( {SuperVisorList.length !== 0 &&
<Grid key={superVisor.id} item xs={12} sm={6} lg={4}> SuperVisorList.map((superVisor) => (
<SuperVisorInfo superVisor={superVisor} deleteSuperVisor={deleteSuperVisor} /> <Grid key={superVisor.id} item xs={12} sm={6} lg={4}>
</Grid> <SuperVisorInfo
))} superVisor={superVisor}
deleteSuperVisor={deleteSuperVisor}
/>
</Grid>
))}
</Grid> </Grid>
</Fade> </Fade>
</Box> </Box>
</Box> </Box>
</DialogContent > </DialogContent>
<DialogActions sx={{ alignItems: "center", justifyContent: "center" }}> <DialogActions sx={{ alignItems: "center", justifyContent: "center" }}>
<Button <Button
onClick={handlePrev} onClick={handlePrev}

View File

@@ -6,9 +6,7 @@ import PatrolForms from "./PatrolForms";
const CreatePatrol = ({ open, setOpen, mutate }) => { const CreatePatrol = ({ open, setOpen, mutate }) => {
return ( return (
<Dialog open={open} fullWidth maxWidth="md"> <Dialog open={open} fullWidth maxWidth="md">
{open && ( {open && <PatrolForms setOpen={setOpen} mutate={mutate} />}
<PatrolForms setOpen={setOpen} mutate={mutate} />
)}
</Dialog> </Dialog>
); );
}; };

View File

@@ -3,6 +3,7 @@ import AccessAlarmsIcon from "@mui/icons-material/AccessAlarms";
import PinDropIcon from "@mui/icons-material/PinDrop"; import PinDropIcon from "@mui/icons-material/PinDrop";
import LocalGasStationIcon from "@mui/icons-material/LocalGasStation"; import LocalGasStationIcon from "@mui/icons-material/LocalGasStation";
import DirectionsCarIcon from "@mui/icons-material/DirectionsCar"; import DirectionsCarIcon from "@mui/icons-material/DirectionsCar";
import { formatSecondsToHHMMSS } from "@/core/utils/formatSecondsToHHMMSS";
const StopsInfo = ({ selectedPoint, staticData }) => { const StopsInfo = ({ selectedPoint, staticData }) => {
return ( return (
@@ -13,7 +14,7 @@ const StopsInfo = ({ selectedPoint, staticData }) => {
icon={<DirectionsCarIcon />} icon={<DirectionsCarIcon />}
label={ label={
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
کد ماشین کد خودرو
</Typography> </Typography>
} }
/> />
@@ -29,14 +30,14 @@ const StopsInfo = ({ selectedPoint, staticData }) => {
icon={<LocalGasStationIcon />} icon={<LocalGasStationIcon />}
label={ label={
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
مصرف سوخت میزان سوخت مصرفی
</Typography> </Typography>
} }
/> />
</Box> </Box>
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
{staticData.fuelConsumption || ""} لیتر {Math.round(patrolData?.fuelConsumption * 10) / 10} لیتر
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}> <Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
@@ -45,14 +46,14 @@ const StopsInfo = ({ selectedPoint, staticData }) => {
icon={<DirectionsCarIcon />} icon={<DirectionsCarIcon />}
label={ label={
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
مسافت طیشده مسافت پیموده شده
</Typography> </Typography>
} }
/> />
</Box> </Box>
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
{staticData.mileage.toLocaleString() || ""} متر {(patrolData?.mileage / 1000).toFixed(1)} کیلومتر
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}> <Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
@@ -68,7 +69,7 @@ const StopsInfo = ({ selectedPoint, staticData }) => {
</Box> </Box>
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
{(staticData.accOnDuration / 60)?.toFixed(2) || ""} دقیقه {formatSecondsToHHMMSS(patrolData?.accOnDuration)}
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}> <Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>

View File

@@ -3,7 +3,7 @@ import DirectionsCarIcon from "@mui/icons-material/DirectionsCar";
import MachinePerformanceContent from "./MachinePerformanceContent"; import MachinePerformanceContent from "./MachinePerformanceContent";
import { useState } from "react"; import { useState } from "react";
const MachinePerformanceForm = ({row}) => { const MachinePerformanceForm = ({ row }) => {
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false); const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
const machineData = { const machineData = {
cmms_machine_code: row.original?.cmms_machines[0]?.machine_code, cmms_machine_code: row.original?.cmms_machines[0]?.machine_code,

View File

@@ -3,6 +3,8 @@ import AccessAlarmsIcon from "@mui/icons-material/AccessAlarms";
import PinDropIcon from "@mui/icons-material/PinDrop"; import PinDropIcon from "@mui/icons-material/PinDrop";
import LocalGasStationIcon from "@mui/icons-material/LocalGasStation"; import LocalGasStationIcon from "@mui/icons-material/LocalGasStation";
import DirectionsCarIcon from "@mui/icons-material/DirectionsCar"; import DirectionsCarIcon from "@mui/icons-material/DirectionsCar";
import { formatSecondsToHHMMSS } from "@/core/utils/formatSecondsToHHMMSS";
const StopsInfo = ({ selectedPoint, staticData }) => { const StopsInfo = ({ selectedPoint, staticData }) => {
return ( return (
<Grid container spacing={3} direction="row" sx={{ justifyContent: "space-between", alignItems: "center" }}> <Grid container spacing={3} direction="row" sx={{ justifyContent: "space-between", alignItems: "center" }}>
@@ -12,7 +14,7 @@ const StopsInfo = ({ selectedPoint, staticData }) => {
icon={<DirectionsCarIcon />} icon={<DirectionsCarIcon />}
label={ label={
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
کد ماشین کد خودرو
</Typography> </Typography>
} }
/> />
@@ -28,14 +30,14 @@ const StopsInfo = ({ selectedPoint, staticData }) => {
icon={<LocalGasStationIcon />} icon={<LocalGasStationIcon />}
label={ label={
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
مصرف سوخت میزان سوخت مصرفی
</Typography> </Typography>
} }
/> />
</Box> </Box>
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
{staticData.fuelConsumption || ""} لیتر {Math.round(staticData?.fuelConsumption * 10) / 10} لیتر
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}> <Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
@@ -44,14 +46,14 @@ const StopsInfo = ({ selectedPoint, staticData }) => {
icon={<DirectionsCarIcon />} icon={<DirectionsCarIcon />}
label={ label={
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
مسافت طیشده مسافت پیموده شده
</Typography> </Typography>
} }
/> />
</Box> </Box>
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
{staticData.mileage.toLocaleString() || ""} متر {(staticData?.mileage / 1000).toFixed(1)} کیلومتر
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}> <Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
@@ -67,7 +69,7 @@ const StopsInfo = ({ selectedPoint, staticData }) => {
</Box> </Box>
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
{(staticData.accOnDuration / 60)?.toFixed(2) || ""} دقیقه {formatSecondsToHHMMSS(staticData?.accOnDuration)}
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}> <Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
@@ -115,7 +117,9 @@ const StopsInfo = ({ selectedPoint, staticData }) => {
</Box> </Box>
<Divider sx={{ flex: 1, mx: 2 }} /> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}> <Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
{selectedPoint ? `${selectedPoint.duration} ثانیه` : "نقطه مورد نظر را انتخاب کنید"} {selectedPoint
? `${formatSecondsToHHMMSS(selectedPoint.duration)} ثانیه`
: "نقطه مورد نظر را انتخاب کنید"}
</Typography> </Typography>
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -3,7 +3,7 @@ import DirectionsCarIcon from "@mui/icons-material/DirectionsCar";
import MachinePerformanceContent from "./MachinePerformanceContent"; import MachinePerformanceContent from "./MachinePerformanceContent";
import { useState } from "react"; import { useState } from "react";
const MachinePerformanceForm = ({row}) => { const MachinePerformanceForm = ({ row }) => {
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false); const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
const machineData = { const machineData = {
cmms_machine_code: row.original?.cmms_machines[0]?.machine_code, cmms_machine_code: row.original?.cmms_machines[0]?.machine_code,

View File

@@ -147,7 +147,7 @@ const SupervisorList = () => {
}, },
}, },
}, },
Cell: ({row}) => ( Cell: ({ row }) => (
<Stack alignItems={"center"} justifyContent={"center"}> <Stack alignItems={"center"} justifyContent={"center"}>
<MachinePerformanceForm row={row} /> <MachinePerformanceForm row={row} />
</Stack> </Stack>

View File

@@ -30,7 +30,7 @@ function MuiDatePicker({ label, value, setFieldValue, name, minDate, maxDate, he
maxDate={maxDate ? new Date(maxDate) : null} maxDate={maxDate ? new Date(maxDate) : null}
slotProps={{ slotProps={{
textField: { textField: {
size: 'small', size: "small",
error: error, error: error,
placeholder: placeholder, placeholder: placeholder,
InputProps: { InputProps: {

View File

@@ -2,10 +2,11 @@
import { FormControl, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material"; import { FormControl, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material";
function CustomSelect({ column, filterParameters, handleChange }) { function CustomSelect({ column, filterParameters, handleChange }) {
return ( return (
<FormControl fullWidth sx={{ marginY: 1 }} size="small"> <FormControl fullWidth sx={{ marginY: 1 }} size="small">
<InputLabel id={`label${column.id}`} shrink>{column.header}</InputLabel> <InputLabel id={`label${column.id}`} shrink>
{column.header}
</InputLabel>
<Select <Select
labelId={`label${column.id}`} labelId={`label${column.id}`}
id={column.id} id={column.id}
@@ -17,7 +18,9 @@ function CustomSelect({ column, filterParameters, handleChange }) {
displayEmpty displayEmpty
> >
{column.columnSelectOption().map((option) => ( {column.columnSelectOption().map((option) => (
<MenuItem key={option.value} value={option.value}>{option.label}</MenuItem> <MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))} ))}
</Select> </Select>
</FormControl> </FormControl>

View File

@@ -13,7 +13,9 @@ function CustomSelectByDependency({
}) { }) {
return ( return (
<FormControl fullWidth sx={{ my: 1 }} size="small"> <FormControl fullWidth sx={{ my: 1 }} size="small">
<InputLabel id={`label${column.id}`} shrink>{column.header}</InputLabel> <InputLabel id={`label${column.id}`} shrink>
{column.header}
</InputLabel>
<Select <Select
labelId={`label${column.id}`} labelId={`label${column.id}`}
id={column.id} id={column.id}

View File

@@ -24,7 +24,7 @@ function CustomTextFieldRange({
fullWidth fullWidth
error={touched?.[`${column.id}`]?.value && Boolean(errors?.[`${column.id}`]?.value)} error={touched?.[`${column.id}`]?.value && Boolean(errors?.[`${column.id}`]?.value)}
helperText={ helperText={
<Typography variant="caption" sx={{ color: "#155175", fontWeight: 'bold' }}> <Typography variant="caption" sx={{ color: "#155175", fontWeight: "bold" }}>
نوع فیلتر: {defaultFilterTranslation} نوع فیلتر: {defaultFilterTranslation}
</Typography> </Typography>
} }

View File

@@ -16,13 +16,14 @@ const ShowPlak = ({ plak_number }) => {
const plakParts = processPlak(plak_number); const plakParts = processPlak(plak_number);
return ( return (
<Stack sx={{ border: 1, borderColor: "divider", borderRadius: 1, maxWidth: "150px" }} direction={"row"}> <Stack sx={{ border: 1, borderColor: "divider", borderRadius: 1 }} direction={"row"}>
<Stack <Stack
sx={{ sx={{
borderRight: 1, borderRight: 1,
borderColor: "divider", borderColor: "divider",
textAlign: "center", textAlign: "center",
width: "100%", width: "100%",
px: 1,
}} }}
> >
{plakParts.region} {plakParts.mainNumber} {plakParts.region} {plakParts.mainNumber}

View File

@@ -0,0 +1,10 @@
import moment from "jalali-moment";
export const formatSecondsToHHMMSS = (seconds) => {
const duration = moment.duration(seconds, "seconds");
const hours = Math.floor(duration.asHours());
const minutes = duration.minutes();
const secs = duration.seconds();
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}:${String(secs).padStart(2, "0")}`;
};