Merge branch 'release/v0.15.0'
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
NEXT_PUBLIC_VERSION="0.14.0"
|
HOST="rms.witel.ir"
|
||||||
|
NEXT_PUBLIC_VERSION="0.15.0"
|
||||||
NEXT_PUBLIC_API_URL="https://rms.witel.ir"
|
NEXT_PUBLIC_API_URL="https://rms.witel.ir"
|
||||||
NEXT_PUBLIC_MAPTILE_ENDPOINT="https://rmsmap.rmto.ir/141map"
|
NEXT_PUBLIC_MAPTILE_ENDPOINT="https://rmsmap.rmto.ir/141map"
|
||||||
@@ -5,7 +5,7 @@ const nextConfig = {
|
|||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
protocol: 'https',
|
protocol: 'https',
|
||||||
hostname: 'rms.witel.ir',
|
hostname: process.env.HOST,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
import TestPage from "@/components/dashboard/carDetails";
|
|
||||||
import WithPermission from "@/core/middlewares/withPermission";
|
|
||||||
|
|
||||||
const Page = () => {
|
|
||||||
return (
|
|
||||||
<WithPermission permission_name={[""]}>
|
|
||||||
<TestPage />
|
|
||||||
</WithPermission>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Page;
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
import { Button, Collapse, DialogActions, DialogContent, Grid, Stack, TextField } from "@mui/material";
|
|
||||||
import MuiDatePicker from "@/core/components/MuiDatePicker";
|
|
||||||
import { useFormik } from "formik";
|
|
||||||
import moment from "jalali-moment";
|
|
||||||
import * as Yup from "yup";
|
|
||||||
import { useState } from "react";
|
|
||||||
import ApplicantRequestDetail from "@/core/components/ApplicantRequestDetail";
|
|
||||||
import DetailMap from "@/core/components/ApplicantRequestDetail/DetailMap";
|
|
||||||
import FlyToPolyline from "@/core/components/ApplicantRequestDetail/FlyToPolyline";
|
|
||||||
import { MapContainer } from "react-leaflet";
|
|
||||||
import dynamic from "next/dynamic";
|
|
||||||
import MapLoading from "@/core/components/MapLayer/Loading";
|
|
||||||
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
|
|
||||||
loading: () => <MapLoading />,
|
|
||||||
ssr: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fakeData = {
|
|
||||||
id: 1,
|
|
||||||
shomareh_darkhast: "2124",
|
|
||||||
ostan: "ostan",
|
|
||||||
shahr: "shahr",
|
|
||||||
shahrestan: "shahrestan",
|
|
||||||
bakhsh: "bakhsh",
|
|
||||||
roosta: "roosta",
|
|
||||||
tarikh_darkhast: "tarikh_darkhast",
|
|
||||||
sazman: "sazman",
|
|
||||||
masahat_zamin: "masahat_zamin",
|
|
||||||
masahat_tarh: "masahat_tarh",
|
|
||||||
gorooh_tarh: "gorooh_tarh",
|
|
||||||
onvane_tarh: "onvane_tarh",
|
|
||||||
address: "کرج - فلان جا - جنب پاساژ - نزدیک اونجا - اونور خیابون - زیر رو گذر - روی زیر گذر",
|
|
||||||
file_mosavab: "file",
|
|
||||||
polyline: [
|
|
||||||
[35.6892, 51.389],
|
|
||||||
[35.7074, 51.3929],
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const CarDetailsContent = ({ setOpenCarDialog }) => {
|
|
||||||
const [openCarDetailContent, setOpenCarDetailContent] = useState(false);
|
|
||||||
const initialValues = {
|
|
||||||
start_date: "",
|
|
||||||
end_date: "",
|
|
||||||
vehicle_code: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
|
||||||
start_date: Yup.string().required("تاریخ شروع الزامیست!!!"),
|
|
||||||
end_date: Yup.string()
|
|
||||||
.test("is-greater", "تاریخ اتمام نمیتواند کمتر از تاریخ شروع باشد", function (value) {
|
|
||||||
const { start_date } = this.parent; // Access other field values
|
|
||||||
if (!value || !start_date) return true; // Skip validation if either field is empty
|
|
||||||
return moment(value, "YYYY/MM/DD").isSameOrAfter(moment(start_date, "YYYY/MM/DD"));
|
|
||||||
})
|
|
||||||
.required("تاریخ اتمام الزامیست!!!"),
|
|
||||||
vehicle_code: Yup.mixed()
|
|
||||||
.test("is-number", "کد خودرو باید عدد باشد!!!", (value) => !isNaN(value))
|
|
||||||
.test("positive", "کد خودرو باید مثبت باشد!!!", (value) => value >= 0)
|
|
||||||
.required("کد خودرو الزامیست!!!"),
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleSubmit = async (values, props) => {
|
|
||||||
props.setSubmitting(true);
|
|
||||||
setOpenCarDetailContent(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const formik = useFormik({
|
|
||||||
initialValues,
|
|
||||||
validationSchema,
|
|
||||||
onSubmit: handleSubmit,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<DialogContent>
|
|
||||||
<Stack spacing={2} sx={{ my: 2 }}>
|
|
||||||
<Stack direction={"row"} spacing={2} sx={{ my: 2 }}>
|
|
||||||
<MuiDatePicker
|
|
||||||
formik={formik}
|
|
||||||
value={formik.values.start_date}
|
|
||||||
name={"start_date"}
|
|
||||||
error={formik.errors.start_date}
|
|
||||||
helperText={formik.touched.start_date && formik.errors.start_date}
|
|
||||||
touched={formik.touched.start_date}
|
|
||||||
onBlur={formik.handleBlur("start_date")}
|
|
||||||
/>
|
|
||||||
<MuiDatePicker
|
|
||||||
formik={formik}
|
|
||||||
name={"end_date"}
|
|
||||||
disabled={formik.values.start_date === ""}
|
|
||||||
value={formik.values.end_date}
|
|
||||||
error={formik.errors.end_date}
|
|
||||||
helperText={formik.touched.end_date && formik.errors.end_date}
|
|
||||||
touched={formik.touched.end_date}
|
|
||||||
onBlur={formik.handleBlur("end_date")}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
name="vehicle_code"
|
|
||||||
label={"کد خودرو"}
|
|
||||||
type="text"
|
|
||||||
inputProps={{
|
|
||||||
inputMode: "number",
|
|
||||||
min: 0,
|
|
||||||
pattern: "[0-9]*",
|
|
||||||
}}
|
|
||||||
variant="outlined"
|
|
||||||
value={formik.values.vehicle_code}
|
|
||||||
onChange={(event) => {
|
|
||||||
if (!isNaN(event.target.value)) {
|
|
||||||
formik.setFieldValue("vehicle_code", event.target.value);
|
|
||||||
} else {
|
|
||||||
formik.setFieldValue("vehicle_code", formik.values.vehicle_code);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
size={"small"}
|
|
||||||
error={formik.touched.vehicle_code && Boolean(formik.errors.vehicle_code)}
|
|
||||||
helperText={formik.touched.vehicle_code && formik.errors.vehicle_code}
|
|
||||||
onBlur={formik.handleBlur("vehicle_code")}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
<Stack>
|
|
||||||
<Button variant={"contained"} color={"primary"} onClick={formik.handleSubmit}>
|
|
||||||
نمایش اطلاعات
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
</Stack>
|
|
||||||
<Grid container spacing={2}>
|
|
||||||
<Grid item xs={12} sm={4}>
|
|
||||||
<Stack
|
|
||||||
direction="column"
|
|
||||||
sx={{ height: "100%", justifyContent: "start", alignItems: "center" }}
|
|
||||||
spacing={5}
|
|
||||||
>
|
|
||||||
<TextField
|
|
||||||
name="vehicle_code"
|
|
||||||
label={"مصرف سوخت خودرو"}
|
|
||||||
disabled
|
|
||||||
variant="outlined"
|
|
||||||
value={"5 لیتر"}
|
|
||||||
size={"small"}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
name="vehicle_code"
|
|
||||||
label={"مسافت پیموده شده"}
|
|
||||||
disabled
|
|
||||||
variant="outlined"
|
|
||||||
value={"54 کیلومتر"}
|
|
||||||
size={"small"}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
name="vehicle_code"
|
|
||||||
label={"زمان روشن بودن خودرو"}
|
|
||||||
disabled
|
|
||||||
variant="outlined"
|
|
||||||
value={"3 ساعت"}
|
|
||||||
size={"small"}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} sm={8}>
|
|
||||||
<MapLayer style={{ height: "400px", width: "100%" }}>
|
|
||||||
{/*<FlyToPolyline polyline={fakeData.polyline} />*/}
|
|
||||||
</MapLayer>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button variant={"outlined"} color={"warning"} onClick={() => setOpenCarDialog(false)}>
|
|
||||||
بستن
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export default CarDetailsContent;
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import PageTitle from "@/core/components/PageTitle";
|
|
||||||
import { Dialog, DialogTitle, IconButton, Stack, Tooltip } from "@mui/material";
|
|
||||||
import { useState } from "react";
|
|
||||||
import DriveEtaIcon from "@mui/icons-material/DriveEta";
|
|
||||||
import CarDetailsContent from "@/components/dashboard/carDetails/CarDetailsContent";
|
|
||||||
|
|
||||||
const TestPage = () => {
|
|
||||||
const [openCarDialog, setOpenCarDialog] = useState(false);
|
|
||||||
return (
|
|
||||||
<Stack spacing={1}>
|
|
||||||
<PageTitle title={"نمایش اطلاعات خودرو"} />
|
|
||||||
<>
|
|
||||||
<Tooltip title="نمایش اطلاعات خودرو">
|
|
||||||
<IconButton
|
|
||||||
color="primary"
|
|
||||||
onClick={() => {
|
|
||||||
setOpenCarDialog(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DriveEtaIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
<Dialog
|
|
||||||
onClose={() => setOpenCarDialog(false)}
|
|
||||||
fullWidth
|
|
||||||
open={openCarDialog}
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
maxWidth={"lg"}
|
|
||||||
>
|
|
||||||
<DialogTitle>نمایش اطلاعات خودرو</DialogTitle>
|
|
||||||
<CarDetailsContent setOpenCarDialog={setOpenCarDialog} />
|
|
||||||
</Dialog>
|
|
||||||
</>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export default TestPage;
|
|
||||||
@@ -27,10 +27,26 @@ function TabPanel(props) {
|
|||||||
|
|
||||||
const validationSchema = object({
|
const validationSchema = object({
|
||||||
item_id: number().required("نوع آیتم را مشخص کنید!"),
|
item_id: number().required("نوع آیتم را مشخص کنید!"),
|
||||||
sub_item_id: number().required("موضوع مشاهده شده را مشخص کنید!"),
|
sub_item_id: number().required("اقدام انجام شده را مشخص کنید!"),
|
||||||
amount: string().required("وارد کردن مقدار الزامیست!"),
|
amount: string().required("وارد کردن مقدار الزامیست!"),
|
||||||
cmms_machines: array().required("وارد کردن کد خودرو الزامیست!").min(1, "حداقل یک کد خودرو باید وارد شود!"),
|
cmms_machines: array()
|
||||||
rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"), // بررسی حداقل یک آیتم,
|
.test("cmms-machines-conditional", "وارد کردن کد خودرو الزامیست!", function (value) {
|
||||||
|
const { is_gasht } = this.options.context;
|
||||||
|
if (is_gasht) {
|
||||||
|
return true; // اگر is_gasht true باشد، این فیلد نیاز به اعتبارسنجی ندارد
|
||||||
|
}
|
||||||
|
return Array.isArray(value) && value.length > 0; // حداقل یک کد باید وجود داشته باشد
|
||||||
|
})
|
||||||
|
.min(1, "حداقل یک کد خودرو باید وارد شود!"), // پیام خطا برای زمانی که شرط تست برقرار باشد
|
||||||
|
rahdaran_id: array()
|
||||||
|
.test("rahdaran-id-conditional", "وارد کردن کد راهداران الزامیست!", function (value) {
|
||||||
|
const { is_gasht } = this.options.context;
|
||||||
|
if (is_gasht) {
|
||||||
|
return true; // اگر is_gasht true باشد، این فیلد نیاز به اعتبارسنجی ندارد
|
||||||
|
}
|
||||||
|
return Array.isArray(value) && value.length > 0; // حداقل یک کد باید وجود داشته باشد
|
||||||
|
})
|
||||||
|
.min(1, "حداقل یک کد راهدار باید وارد شود!"), // پیام خطا برای زمانی که شرط تست برقرار باشد
|
||||||
activity_time: string().test("activity-time-conditional", "لطفا زمان فعالیت را انتخاب کنید!", function (value) {
|
activity_time: string().test("activity-time-conditional", "لطفا زمان فعالیت را انتخاب کنید!", function (value) {
|
||||||
const { is_gasht } = this.options.context; // دسترسی به context
|
const { is_gasht } = this.options.context; // دسترسی به context
|
||||||
if (is_gasht) {
|
if (is_gasht) {
|
||||||
@@ -91,11 +107,14 @@ const CreateFormContent = ({ setOpen, onSubmit, is_gasht = false }) => {
|
|||||||
amount: "",
|
amount: "",
|
||||||
before_image: null,
|
before_image: null,
|
||||||
after_image: null,
|
after_image: null,
|
||||||
cmms_machines: null,
|
|
||||||
rahdaran_id: null,
|
|
||||||
start_point: "",
|
start_point: "",
|
||||||
end_point: "",
|
end_point: "",
|
||||||
...(!is_gasht && { activity_time: "", activity_date: "" }),
|
...(!is_gasht && {
|
||||||
|
activity_time: "",
|
||||||
|
activity_date: "",
|
||||||
|
cmms_machines: [],
|
||||||
|
rahdaran_id: [],
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const [tabState, setTabState] = useState(0);
|
const [tabState, setTabState] = useState(0);
|
||||||
@@ -175,17 +194,24 @@ const CreateFormContent = ({ setOpen, onSubmit, is_gasht = false }) => {
|
|||||||
result.start_point = `${result.start_point.lat},${result.start_point.lng}`;
|
result.start_point = `${result.start_point.lat},${result.start_point.lng}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.rahdaran_id.forEach((rahdar, index) => {
|
if (!is_gasht) {
|
||||||
result[`rahdaran_id[${index}]`] = rahdar.id;
|
result.rahdaran_id.forEach((rahdar, index) => {
|
||||||
});
|
result[`rahdaran_id[${index}]`] = rahdar.id;
|
||||||
delete result.rahdaran_id;
|
});
|
||||||
|
delete result.rahdaran_id;
|
||||||
|
|
||||||
result.cmms_machines.forEach((cmms_machine, index) => {
|
result.cmms_machines.forEach((cmms_machine, index) => {
|
||||||
result[`machines_id[${index}]`] = cmms_machine.id;
|
result[`machines_id[${index}]`] = cmms_machine.id;
|
||||||
});
|
});
|
||||||
delete result.cmms_machines;
|
delete result.cmms_machines;
|
||||||
|
|
||||||
result[`activity_time`] = format(new Date(result.activity_time), "HH:mm");
|
result[`activity_time`] = format(new Date(result.activity_time), "HH:mm");
|
||||||
|
} else {
|
||||||
|
delete result.rahdaran_id;
|
||||||
|
delete result.cmms_machines;
|
||||||
|
delete result.activity_date;
|
||||||
|
delete result.activity_time;
|
||||||
|
}
|
||||||
|
|
||||||
await onSubmit({
|
await onSubmit({
|
||||||
result,
|
result,
|
||||||
@@ -214,7 +240,7 @@ const CreateFormContent = ({ setOpen, onSubmit, is_gasht = false }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tab icon={<InsertDriveFileIcon />} label="انتخاب آیتم" />
|
<Tab icon={<InsertDriveFileIcon />} label="انتخاب آیتم" />
|
||||||
<Tab disabled={tabState === 0} icon={<FileCopyIcon />} label="انتخاب موضوع مشاهده شده" />
|
<Tab disabled={tabState === 0} icon={<FileCopyIcon />} label="انتخاب اقدام انجام شده" />
|
||||||
<Tab disabled={tabState === 0 || tabState === 1} icon={<InfoIcon />} label="اطلاعات فعالیت" />
|
<Tab disabled={tabState === 0 || tabState === 1} icon={<InfoIcon />} label="اطلاعات فعالیت" />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<DialogContent dividers sx={{ overflowY: "auto", maxHeight: "70vh" }}>
|
<DialogContent dividers sx={{ overflowY: "auto", maxHeight: "70vh" }}>
|
||||||
|
|||||||
@@ -43,37 +43,41 @@ const GetItemInfo = ({ register, itemsList, subItemsList, control, setValue, err
|
|||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Stack>
|
{!is_gasht && (
|
||||||
<Controller
|
<Stack>
|
||||||
control={control}
|
<Controller
|
||||||
render={({ field, fieldState: { error } }) => {
|
control={control}
|
||||||
return (
|
render={({ field, fieldState: { error } }) => {
|
||||||
<CarCode
|
return (
|
||||||
carCode={field.value || []}
|
<CarCode
|
||||||
setCarCode={(value) => field.onChange(value || [])}
|
carCode={field.value || []}
|
||||||
error={error}
|
setCarCode={(value) => field.onChange(value || [])}
|
||||||
multiple={true}
|
error={error}
|
||||||
/>
|
multiple={true}
|
||||||
);
|
/>
|
||||||
}}
|
);
|
||||||
name={"cmms_machines"}
|
}}
|
||||||
/>
|
name={"cmms_machines"}
|
||||||
</Stack>
|
/>
|
||||||
<Stack>
|
</Stack>
|
||||||
<Controller
|
)}
|
||||||
control={control}
|
{!is_gasht && (
|
||||||
render={({ field, fieldState: { error } }) => {
|
<Stack>
|
||||||
return (
|
<Controller
|
||||||
<RahdarCode
|
control={control}
|
||||||
rahdarsCode={field.value || []}
|
render={({ field, fieldState: { error } }) => {
|
||||||
setRahdarsCode={(value) => field.onChange(value || [])}
|
return (
|
||||||
error={error}
|
<RahdarCode
|
||||||
/>
|
rahdarsCode={field.value || []}
|
||||||
);
|
setRahdarsCode={(value) => field.onChange(value || [])}
|
||||||
}}
|
error={error}
|
||||||
name={"rahdaran_id"}
|
/>
|
||||||
/>
|
);
|
||||||
</Stack>
|
}}
|
||||||
|
name={"rahdaran_id"}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
<Stack>
|
<Stack>
|
||||||
{subItemsList.needs_image ? (
|
{subItemsList.needs_image ? (
|
||||||
<ImageUpload setValue={setValue} control={control} errors={errors} getValues={getValues} />
|
<ImageUpload setValue={setValue} control={control} errors={errors} getValues={getValues} />
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const GetSubItemsForm = ({ setValue, watch, setSubItemsList, tabState, setTabSta
|
|||||||
<>
|
<>
|
||||||
{errorSubItemsList ? (
|
{errorSubItemsList ? (
|
||||||
<Typography textAlign={"center"} color={"error"}>
|
<Typography textAlign={"center"} color={"error"}>
|
||||||
خطا در دریافت موضوع مشاهده شده
|
خطا در دریافت اقدام انجام شده
|
||||||
</Typography>
|
</Typography>
|
||||||
) : loadingSubItemsList ? (
|
) : loadingSubItemsList ? (
|
||||||
<LinearProgress />
|
<LinearProgress />
|
||||||
|
|||||||
@@ -27,14 +27,14 @@ const PreviousStatesInfo = ({ itemsList, subItemsList }) => {
|
|||||||
icon={<FileCopyIcon />}
|
icon={<FileCopyIcon />}
|
||||||
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" }}>
|
||||||
{subItemsList?.name || "هیچ موضوعی انتخاب نشده است"}
|
{subItemsList?.name || "هیچ اقدامی انتخاب نشده است"}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const OperatorCreateForm = ({ open, setOpen, mutate, rowId }) => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} fullWidth maxWidth="sm">
|
<Dialog open={open} fullWidth maxWidth="sm">
|
||||||
<CreateFormContent setOpen={setOpen} mutate={mutate} onSubmit={HandleSubmit} />
|
{open && <CreateFormContent setOpen={setOpen} mutate={mutate} onSubmit={HandleSubmit} />}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const OperatorCreate = ({ mutate }) => {
|
|||||||
ثبت فعالیت
|
ثبت فعالیت
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{open && <OperatorCreateForm open={open} setOpen={setOpen} mutate={mutate} />}
|
<OperatorCreateForm open={open} setOpen={setOpen} mutate={mutate} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ const GashtCreate = ({ open, setOpen, mutate, rowId }) => {
|
|||||||
const [tabState, setTabState] = useState(0);
|
const [tabState, setTabState] = useState(0);
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} fullWidth maxWidth={tabState === 0 ? "md" : "sm"}>
|
<Dialog open={open} fullWidth maxWidth={tabState === 0 ? "md" : "sm"}>
|
||||||
<GashtCreateContent mutate={mutate} setOpen={setOpen} setTabState={setTabState} tabState={tabState} />
|
{open && (
|
||||||
|
<GashtCreateContent mutate={mutate} setOpen={setOpen} setTabState={setTabState} tabState={tabState} />
|
||||||
|
)}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ const GashtCreateContent = ({ mutate, setOpen, tabState, setTabState }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tab icon={<InsertDriveFileIcon />} label="انتخاب مورد مشاهده شده" />
|
<Tab icon={<InsertDriveFileIcon />} label="انتخاب مورد مشاهده شده" />
|
||||||
<Tab disabled={tabState === 0} icon={<FileCopyIcon />} label="اطلاعات مورد مشاهده شده" />
|
<Tab disabled={tabState === 0} icon={<FileCopyIcon />} label="اطلاعات مورد اقدام شده" />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<DialogContent dividers sx={{ overflowY: "auto", maxHeight: "70vh" }}>
|
<DialogContent dividers sx={{ overflowY: "auto", maxHeight: "70vh" }}>
|
||||||
<Box sx={{ flex: 1 }}>
|
<Box sx={{ flex: 1 }}>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const CompleteItem = ({ subItem, itemInfo, setSubmitCompleteForm, mutate, setOpe
|
|||||||
|
|
||||||
const validationSchema = object({
|
const validationSchema = object({
|
||||||
item_id: number().required("نوع آیتم را مشخص کنید!"),
|
item_id: number().required("نوع آیتم را مشخص کنید!"),
|
||||||
sub_item_id: number().required("موضوع مشاهده شده را مشخص کنید!"),
|
sub_item_id: number().required("اقدام انجام شده را مشخص کنید!"),
|
||||||
amount: string().required("وارد کردن مقدار الزامیست!"),
|
amount: string().required("وارد کردن مقدار الزامیست!"),
|
||||||
cmms_machines: array().required("وارد کردن کد خودرو الزامیست!").min(1, "حداقل یک کد خودرو باید وارد شود!"),
|
cmms_machines: array().required("وارد کردن کد خودرو الزامیست!").min(1, "حداقل یک کد خودرو باید وارد شود!"),
|
||||||
rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"), // بررسی حداقل یک آیتم,
|
rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"), // بررسی حداقل یک آیتم,
|
||||||
|
|||||||
@@ -27,14 +27,14 @@ const PreviousStatesInfo = ({ itemInfo }) => {
|
|||||||
icon={<FileCopyIcon />}
|
icon={<FileCopyIcon />}
|
||||||
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" }}>
|
||||||
{itemInfo?.sub_item_name || "هیچ موضوعی انتخاب نشده است"}
|
{itemInfo?.sub_item_name || "هیچ اقدامی انتخاب نشده است"}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const TableInfo = ({ specialFilter, setTabState, setItemInfo }) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "sub_item_name",
|
accessorKey: "sub_item_name",
|
||||||
header: "موضوع مشاهده شده",
|
header: "مشاهده انجام شده",
|
||||||
id: "sub_item_name",
|
id: "sub_item_name",
|
||||||
enableColumnFilter: false,
|
enableColumnFilter: false,
|
||||||
datatype: "text",
|
datatype: "text",
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const ObservedGashtCreate = ({ mutate }) => {
|
|||||||
ثبت فعالیت برای موارد مشاهده شده در گشت راهداری
|
ثبت فعالیت برای موارد مشاهده شده در گشت راهداری
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{open && <GashtCreate open={open} setOpen={setOpen} mutate={mutate} />}
|
<GashtCreate open={open} setOpen={setOpen} mutate={mutate} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import MachinesCodeDialog from "./RowActions/MachinesCodeForm";
|
|||||||
|
|
||||||
const OperatorList = () => {
|
const OperatorList = () => {
|
||||||
const statusOptions = [
|
const statusOptions = [
|
||||||
|
{ value: "", label: "همه وضعیت ها" },
|
||||||
{ value: 0, label: "درحال بررسی" },
|
{ value: 0, label: "درحال بررسی" },
|
||||||
{ value: 1, label: "تایید" },
|
{ value: 1, label: "تایید" },
|
||||||
{ value: 2, label: "عدم تایید" },
|
{ value: 2, label: "عدم تایید" },
|
||||||
@@ -54,7 +55,7 @@ const OperatorList = () => {
|
|||||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
{ value: "", label: props.column.header },
|
{ value: "", label: "همه آیتم ها" },
|
||||||
...itemsList.map((item) => ({
|
...itemsList.map((item) => ({
|
||||||
value: item.id,
|
value: item.id,
|
||||||
label: item.name,
|
label: item.name,
|
||||||
@@ -76,7 +77,7 @@ const OperatorList = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "sub_item",
|
accessorKey: "sub_item",
|
||||||
header: "موضوع مشاهده شده",
|
header: "اقدام انجام شده",
|
||||||
id: "sub_item",
|
id: "sub_item",
|
||||||
enableColumnFilter: true,
|
enableColumnFilter: true,
|
||||||
datatype: "numeric",
|
datatype: "numeric",
|
||||||
@@ -99,7 +100,7 @@ const OperatorList = () => {
|
|||||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
{ value: "", label: props.column.header },
|
{ value: "", label: "همه اقدام ها" },
|
||||||
...subItemsList.map((item) => ({
|
...subItemsList.map((item) => ({
|
||||||
value: item.sub_item,
|
value: item.sub_item,
|
||||||
label: item.name,
|
label: item.name,
|
||||||
@@ -246,7 +247,7 @@ const OperatorList = () => {
|
|||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <Typography variant="body2">کد خودرویی وجود ندارد</Typography>;
|
return <Typography variant="body2">خودرویی وجود ندارد</Typography>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import React from "react";
|
|||||||
import useRoadItemGetISubtems from "@/lib/hooks/useRoadItemGetISubtems";
|
import useRoadItemGetISubtems from "@/lib/hooks/useRoadItemGetISubtems";
|
||||||
import EditFormCreate from "@/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormCreate";
|
import EditFormCreate from "@/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormCreate";
|
||||||
|
|
||||||
const EditFormContent = ({ setOpenEditDialog, onSubmit, defaultData }) => {
|
const EditFormContent = ({ setOpenEditDialog, onSubmit, defaultData, is_gasht }) => {
|
||||||
const { subItemsList, loadingSubItemsList, errorSubItemsList } = useRoadItemGetISubtems(defaultData?.item_id);
|
const { subItemsList, loadingSubItemsList, errorSubItemsList } = useRoadItemGetISubtems(defaultData?.item_id);
|
||||||
const subItem = subItemsList.find((SubItem) => SubItem.sub_item === defaultData?.sub_item_id);
|
const subItem = subItemsList.find((SubItem) => SubItem.sub_item === defaultData?.sub_item_id);
|
||||||
|
|
||||||
@@ -13,8 +13,10 @@ const EditFormContent = ({ setOpenEditDialog, onSubmit, defaultData }) => {
|
|||||||
amount: defaultData?.amount || null,
|
amount: defaultData?.amount || null,
|
||||||
start_point: defaultData?.start_point || { lat: "", lng: "" },
|
start_point: defaultData?.start_point || { lat: "", lng: "" },
|
||||||
end_point: defaultData?.end_point || { lat: "", lng: "" },
|
end_point: defaultData?.end_point || { lat: "", lng: "" },
|
||||||
cmms_machines: defaultData?.cmms_machines || null,
|
...(!is_gasht && {
|
||||||
rahdaran_id: defaultData?.rahdaran_id || null,
|
cmms_machines: defaultData?.cmms_machines || null,
|
||||||
|
rahdaran_id: defaultData?.rahdaran_id || null,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmitBase = async (data) => {
|
const onSubmitBase = async (data) => {
|
||||||
@@ -43,15 +45,20 @@ const EditFormContent = ({ setOpenEditDialog, onSubmit, defaultData }) => {
|
|||||||
result.start_point = `${result.start_point.lat},${result.start_point.lng}`;
|
result.start_point = `${result.start_point.lat},${result.start_point.lng}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.rahdaran_id.forEach((rahdar, index) => {
|
if (!is_gasht) {
|
||||||
result[`rahdaran_id[${index}]`] = rahdar.id;
|
result.rahdaran_id.forEach((rahdar, index) => {
|
||||||
});
|
result[`rahdaran_id[${index}]`] = rahdar.id;
|
||||||
delete result.rahdaran_id;
|
});
|
||||||
|
delete result.rahdaran_id;
|
||||||
|
|
||||||
result.cmms_machines.forEach((cmms_machine, index) => {
|
result.cmms_machines.forEach((cmms_machine, index) => {
|
||||||
result[`machines_id[${index}]`] = cmms_machine.id;
|
result[`machines_id[${index}]`] = cmms_machine.id;
|
||||||
});
|
});
|
||||||
delete result.cmms_machines;
|
delete result.cmms_machines;
|
||||||
|
} else {
|
||||||
|
delete result.rahdaran_id;
|
||||||
|
delete result.cmms_machines;
|
||||||
|
}
|
||||||
|
|
||||||
await onSubmit({
|
await onSubmit({
|
||||||
result,
|
result,
|
||||||
@@ -81,6 +88,7 @@ const EditFormContent = ({ setOpenEditDialog, onSubmit, defaultData }) => {
|
|||||||
defaultData={defaultData}
|
defaultData={defaultData}
|
||||||
defaultValues={defaultValues}
|
defaultValues={defaultValues}
|
||||||
setOpenEditDialog={setOpenEditDialog}
|
setOpenEditDialog={setOpenEditDialog}
|
||||||
|
is_gasht={is_gasht}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -13,8 +13,24 @@ import { array, mixed, object, string } from "yup";
|
|||||||
|
|
||||||
const validationSchema = object({
|
const validationSchema = object({
|
||||||
amount: string().required("وارد کردن مقدار الزامیست!"),
|
amount: string().required("وارد کردن مقدار الزامیست!"),
|
||||||
cmms_machines: array().required("وارد کردن کد خودرو الزامیست!").min(1, "حداقل یک کد خودرو باید وارد شود!"),
|
cmms_machines: array()
|
||||||
rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"),
|
.test("cmms-machines-conditional", "وارد کردن کد خودرو الزامیست!", function (value) {
|
||||||
|
const { is_gasht } = this.options.context;
|
||||||
|
if (is_gasht) {
|
||||||
|
return true; // اگر is_gasht true باشد، این فیلد نیاز به اعتبارسنجی ندارد
|
||||||
|
}
|
||||||
|
return Array.isArray(value) && value.length > 0; // حداقل یک کد باید وجود داشته باشد
|
||||||
|
})
|
||||||
|
.min(1, "حداقل یک کد خودرو باید وارد شود!"), // پیام خطا برای زمانی که شرط تست برقرار باشد
|
||||||
|
rahdaran_id: array()
|
||||||
|
.test("rahdaran-id-conditional", "وارد کردن کد راهداران الزامیست!", function (value) {
|
||||||
|
const { is_gasht } = this.options.context;
|
||||||
|
if (is_gasht) {
|
||||||
|
return true; // اگر is_gasht true باشد، این فیلد نیاز به اعتبارسنجی ندارد
|
||||||
|
}
|
||||||
|
return Array.isArray(value) && value.length > 0; // حداقل یک کد باید وجود داشته باشد
|
||||||
|
})
|
||||||
|
.min(1, "حداقل یک کد راهدار باید وارد شود!"),
|
||||||
before_image: mixed()
|
before_image: mixed()
|
||||||
.nullable()
|
.nullable()
|
||||||
.test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) {
|
.test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) {
|
||||||
@@ -50,7 +66,7 @@ const validationSchema = object({
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const EditFormCreate = ({ defaultData, subItem, onSubmitBase, defaultValues, setOpenEditDialog }) => {
|
const EditFormCreate = ({ defaultData, subItem, onSubmitBase, defaultValues, setOpenEditDialog, is_gasht }) => {
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
getValues,
|
getValues,
|
||||||
@@ -63,7 +79,7 @@ const EditFormCreate = ({ defaultData, subItem, onSubmitBase, defaultValues, set
|
|||||||
defaultValues,
|
defaultValues,
|
||||||
resolver: yupResolver(validationSchema),
|
resolver: yupResolver(validationSchema),
|
||||||
mode: "onBlur",
|
mode: "onBlur",
|
||||||
context: { subItem },
|
context: { subItem, is_gasht },
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -108,38 +124,42 @@ const EditFormCreate = ({ defaultData, subItem, onSubmitBase, defaultValues, set
|
|||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Stack>
|
{!is_gasht && (
|
||||||
<Controller
|
<Stack>
|
||||||
control={control}
|
<Controller
|
||||||
render={({ field, fieldState: { error } }) => {
|
control={control}
|
||||||
return (
|
render={({ field, fieldState: { error } }) => {
|
||||||
<CarCode
|
return (
|
||||||
carCode={field.value || []}
|
<CarCode
|
||||||
setCarCode={(value) => field.onChange(value || [])}
|
carCode={field.value || []}
|
||||||
inputValueDefault={defaultData?.cmms_machines}
|
setCarCode={(value) => field.onChange(value || [])}
|
||||||
multiple={true}
|
inputValueDefault={defaultData?.cmms_machines}
|
||||||
error={error} // اگر خطا وجود داشته باشد
|
multiple={true}
|
||||||
/>
|
error={error} // اگر خطا وجود داشته باشد
|
||||||
);
|
/>
|
||||||
}}
|
);
|
||||||
name={"cmms_machines"}
|
}}
|
||||||
/>
|
name={"cmms_machines"}
|
||||||
</Stack>
|
/>
|
||||||
<Stack>
|
</Stack>
|
||||||
<Controller
|
)}
|
||||||
control={control}
|
{!is_gasht && (
|
||||||
render={({ field, fieldState: { error } }) => {
|
<Stack>
|
||||||
return (
|
<Controller
|
||||||
<RahdarCode
|
control={control}
|
||||||
rahdarsCode={field.value || []}
|
render={({ field, fieldState: { error } }) => {
|
||||||
setRahdarsCode={(value) => field.onChange(value || [])}
|
return (
|
||||||
error={error}
|
<RahdarCode
|
||||||
/>
|
rahdarsCode={field.value || []}
|
||||||
);
|
setRahdarsCode={(value) => field.onChange(value || [])}
|
||||||
}}
|
error={error}
|
||||||
name={"rahdaran_id"}
|
/>
|
||||||
/>
|
);
|
||||||
</Stack>
|
}}
|
||||||
|
name={"rahdaran_id"}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
<Stack>
|
<Stack>
|
||||||
{subItem.needs_end_point === 1 ? (
|
{subItem.needs_end_point === 1 ? (
|
||||||
<MapInfoTwoMarker
|
<MapInfoTwoMarker
|
||||||
|
|||||||
@@ -1,41 +1,44 @@
|
|||||||
import { DialogContent, Paper, Stack, Typography, useTheme } from "@mui/material";
|
import { Box, DialogContent, Paper, Stack, Typography, useTheme } from "@mui/material";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
const ImageFormContent = ({ image, title }) => {
|
const ImageFormContent = ({ image, title }) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
<DialogContent>
|
<Stack
|
||||||
<Paper
|
spacing={2}
|
||||||
elevation={3}
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
sx={{
|
||||||
|
my: 2,
|
||||||
|
padding: 2,
|
||||||
|
borderRadius: "12px",
|
||||||
|
border: `1px solid ${theme.palette.primary.main}`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
sx={{
|
sx={{
|
||||||
padding: 2,
|
color: theme.palette.primary.dark,
|
||||||
borderRadius: "12px",
|
fontWeight: "bold",
|
||||||
border: `1px solid ${theme.palette.primary.main}`,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack spacing={2} alignItems="center" justifyContent="center">
|
{title}
|
||||||
<Typography
|
</Typography>
|
||||||
variant="h6"
|
<Box sx={{ width: "100%", position: "relative", aspectRatio: "16/9" }}>
|
||||||
sx={{
|
<Image
|
||||||
color: theme.palette.primary.dark,
|
src={image}
|
||||||
fontWeight: "bold",
|
alt="Image"
|
||||||
}}
|
fill={true}
|
||||||
>
|
loading="lazy"
|
||||||
{title}
|
style={{
|
||||||
</Typography>
|
objectFit: "contain",
|
||||||
<img
|
marginBottom: "16px",
|
||||||
src={image}
|
borderRadius: "12px",
|
||||||
alt="Image"
|
border: `1px solid ${theme.palette.divider}`,
|
||||||
style={{
|
}}
|
||||||
maxWidth: "100%",
|
/>
|
||||||
maxHeight: "200px",
|
</Box>
|
||||||
marginBottom: "16px",
|
</Stack>
|
||||||
borderRadius: "12px",
|
|
||||||
border: `1px solid ${theme.palette.divider}`,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</DialogContent>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default ImageFormContent;
|
export default ImageFormContent;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material";
|
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Paper, Tooltip } from "@mui/material";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import PhotoLibraryIcon from "@mui/icons-material/PhotoLibrary";
|
import PhotoLibraryIcon from "@mui/icons-material/PhotoLibrary";
|
||||||
import ImageFormContent from "./ImageFormContent";
|
import ImageFormContent from "./ImageFormContent";
|
||||||
@@ -22,14 +22,18 @@ const ImageDialog = ({ images }) => {
|
|||||||
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
|
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
dir="rtl"
|
maxWidth={"sm"}
|
||||||
maxWidth={"md"}
|
scroll="paper"
|
||||||
>
|
>
|
||||||
<DialogTitle sx={{ fontSize: "large" }}>تصاویر</DialogTitle>
|
<DialogTitle sx={{ fontSize: "large" }}>تصاویر</DialogTitle>
|
||||||
<ImageFormContent image={images[1]?.full_path_for_fast_react} title={"قبل از اقدام"} />
|
<DialogContent>
|
||||||
<ImageFormContent image={images[0]?.full_path_for_fast_react} title={"بعد از اقدام"} />
|
<Paper elevation={0}>
|
||||||
|
<ImageFormContent image={images[1]?.full_path_for_fast_react} title={"قبل از اقدام"} />
|
||||||
|
<ImageFormContent image={images[0]?.full_path_for_fast_react} title={"بعد از اقدام"} />
|
||||||
|
</Paper>
|
||||||
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={() => setOpenImageDialog(false)} variant="outlined" color="secondary" autoFocus>
|
<Button onClick={() => setOpenImageDialog(false)} variant="outlined" color="secondary">
|
||||||
بستن
|
بستن
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const MachinesCodeDialog = ({ machinesLists }) => {
|
|||||||
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
|
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tooltip title="کد خودرو">
|
<Tooltip title="خودرو ها">
|
||||||
<IconButton color="primary" onClick={() => setOpenMachinesCodeDialog(true)}>
|
<IconButton color="primary" onClick={() => setOpenMachinesCodeDialog(true)}>
|
||||||
<DirectionsCarIcon />
|
<DirectionsCarIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -24,7 +24,7 @@ const MachinesCodeDialog = ({ machinesLists }) => {
|
|||||||
dir="rtl"
|
dir="rtl"
|
||||||
maxWidth={"md"}
|
maxWidth={"md"}
|
||||||
>
|
>
|
||||||
<DialogTitle sx={{ fontSize: "large" }}>کد خودرو</DialogTitle>
|
<DialogTitle sx={{ fontSize: "large" }}>خودرو ها</DialogTitle>
|
||||||
<MachinesCodeContent machinesLists={machinesLists} />
|
<MachinesCodeContent machinesLists={machinesLists} />
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ const ReportLists = ({ itemsList, data }) => {
|
|||||||
data={data.data}
|
data={data.data}
|
||||||
page_name={"roadItemReportByItems"}
|
page_name={"roadItemReportByItems"}
|
||||||
table_name={"roadItemReportByItemsList"}
|
table_name={"roadItemReportByItemsList"}
|
||||||
|
enablePagination={false}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const SubItemsList = ({ data }) => {
|
|||||||
data={data.data}
|
data={data.data}
|
||||||
page_name={"roadItemReportBySubItems"}
|
page_name={"roadItemReportBySubItems"}
|
||||||
table_name={"roadItemReportBySubItemsList"}
|
table_name={"roadItemReportBySubItemsList"}
|
||||||
|
enablePagination={false}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const createColumns = (sub_items) => {
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
accessorKey: `sub_item_${sub_item.sub_item}_count`,
|
accessorKey: `sub_item_${sub_item.sub_item}_count`,
|
||||||
header: "تعداد",
|
header: "تعداد اقدام",
|
||||||
id: `sub_item_${sub_item.sub_item}_count`,
|
id: `sub_item_${sub_item.sub_item}_count`,
|
||||||
enableColumnFilter: false,
|
enableColumnFilter: false,
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
@@ -81,7 +81,7 @@ const createColumns = (sub_items) => {
|
|||||||
size: 50,
|
size: 50,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: "موارد مشاهده شده فعالیت روزانه",
|
header: "موارد اقدام شده فعالیت روزانه",
|
||||||
enableColumnFilter: false,
|
enableColumnFilter: false,
|
||||||
id: "subItems",
|
id: "subItems",
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
@@ -228,7 +228,7 @@ const SubItemsReports = () => {
|
|||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Stack spacing={1}>
|
<Stack spacing={1}>
|
||||||
<PageTitle title={"گزارش تعداد فعالیت ها به تفکیک موارد مشاهده شده"} />
|
<PageTitle title={"گزارش تعداد فعالیت ها به تفکیک موارد اقدام شده"} />
|
||||||
<SearchReportList
|
<SearchReportList
|
||||||
control={control}
|
control={control}
|
||||||
hasProvincesPermission={hasProvincesPermission}
|
hasProvincesPermission={hasProvincesPermission}
|
||||||
|
|||||||
@@ -40,10 +40,12 @@ const ConfirmContent = ({ rowId, mutate, setOpenConfirmDialog }) => {
|
|||||||
{...register("description")}
|
{...register("description")}
|
||||||
multiline
|
multiline
|
||||||
rows={8}
|
rows={8}
|
||||||
label="توضیحات کارشناس"
|
label="توضیحات و دلایل تأیید (اختیاری)"
|
||||||
|
placeholder="لطفاً علت تأیید خود را توضیح دهید"
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{ mt: 1 }}
|
sx={{ mt: 1 }}
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -59,7 +61,7 @@ const ConfirmContent = ({ rowId, mutate, setOpenConfirmDialog }) => {
|
|||||||
بستن
|
بستن
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleSubmit(onSubmit)} variant="contained" color="primary" disabled={isSubmitting}>
|
<Button onClick={handleSubmit(onSubmit)} variant="contained" color="primary" disabled={isSubmitting}>
|
||||||
{isSubmitting ? "درحال ارسال اطلاعات..." : "ثبت"}
|
{isSubmitting ? "درحال ثبت تایید..." : "ثبت تایید"}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const ConfirmForm = ({ rowId, mutate }) => {
|
|||||||
const [openConfirmDialog, setOpenConfirmDialog] = useState(false);
|
const [openConfirmDialog, setOpenConfirmDialog] = useState(false);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tooltip title="تایید">
|
<Tooltip title="تایید فعالیت">
|
||||||
<IconButton color="primary" onClick={() => setOpenConfirmDialog(true)}>
|
<IconButton color="primary" onClick={() => setOpenConfirmDialog(true)}>
|
||||||
<DoneIcon />
|
<DoneIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -20,7 +20,7 @@ const ConfirmForm = ({ rowId, mutate }) => {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>تایید</DialogTitle>
|
<DialogTitle>تایید فعالیت</DialogTitle>
|
||||||
<ConfirmContent mutate={mutate} rowId={rowId} setOpenConfirmDialog={setOpenConfirmDialog} />
|
<ConfirmContent mutate={mutate} rowId={rowId} setOpenConfirmDialog={setOpenConfirmDialog} />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => {
|
|||||||
<>
|
<>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<Stack alignItems="center" spacing={2}>
|
<Stack alignItems="center" spacing={2}>
|
||||||
<Typography textAlign="center" fontWeight="bold" fontSize="16px" mt={2}>
|
<Typography mt={2}>آیا از حذف فعالیت اطمینان دارید؟</Typography>
|
||||||
آیا از حذف فعالیت اطمینان دارید؟
|
|
||||||
</Typography>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions sx={{ justifyContent: "center", paddingBottom: 2, width: "100%" }}>
|
<DialogActions sx={{ justifyContent: "center", paddingBottom: 2, width: "100%" }}>
|
||||||
@@ -32,7 +30,7 @@ const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => {
|
|||||||
خیر !
|
خیر !
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleClick} variant="contained" color="error" disabled={submitting}>
|
<Button onClick={handleClick} variant="contained" color="error" disabled={submitting}>
|
||||||
{submitting ? "درحال ارسال اطلاعات..." : "بله اطمینان دارم"}
|
{submitting ? "درحال حذف..." : "بله اطمینان دارم"}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,41 +1,44 @@
|
|||||||
import { DialogContent, Paper, Stack, Typography, useTheme } from "@mui/material";
|
import { Box, DialogContent, Paper, Stack, Typography, useTheme } from "@mui/material";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
const ImageFormContent = ({ image, title }) => {
|
const ImageFormContent = ({ image, title }) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
<DialogContent>
|
<Stack
|
||||||
<Paper
|
spacing={2}
|
||||||
elevation={3}
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
sx={{
|
||||||
|
my: 2,
|
||||||
|
padding: 2,
|
||||||
|
borderRadius: "12px",
|
||||||
|
border: `1px solid ${theme.palette.primary.main}`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="h6"
|
||||||
sx={{
|
sx={{
|
||||||
padding: 2,
|
color: theme.palette.primary.dark,
|
||||||
borderRadius: "12px",
|
fontWeight: "bold",
|
||||||
border: `1px solid ${theme.palette.primary.main}`,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack spacing={2} alignItems="center" justifyContent="center">
|
{title}
|
||||||
<Typography
|
</Typography>
|
||||||
variant="h6"
|
<Box sx={{ width: "100%", position: "relative", aspectRatio: "16/9" }}>
|
||||||
sx={{
|
<Image
|
||||||
color: theme.palette.primary.dark,
|
src={image}
|
||||||
fontWeight: "bold",
|
alt="Image"
|
||||||
}}
|
fill={true}
|
||||||
>
|
loading="lazy"
|
||||||
{title}
|
style={{
|
||||||
</Typography>
|
objectFit: "contain",
|
||||||
<img
|
marginBottom: "16px",
|
||||||
src={image}
|
borderRadius: "12px",
|
||||||
alt="Image"
|
border: `1px solid ${theme.palette.divider}`,
|
||||||
style={{
|
}}
|
||||||
maxWidth: "100%",
|
/>
|
||||||
maxHeight: "200px",
|
</Box>
|
||||||
marginBottom: "16px",
|
</Stack>
|
||||||
borderRadius: "12px",
|
|
||||||
border: `1px solid ${theme.palette.divider}`,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
</DialogContent>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default ImageFormContent;
|
export default ImageFormContent;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material";
|
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Paper, Tooltip } from "@mui/material";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import PhotoLibraryIcon from "@mui/icons-material/PhotoLibrary";
|
import PhotoLibraryIcon from "@mui/icons-material/PhotoLibrary";
|
||||||
import ImageFormContent from "./ImageFormContent";
|
import ImageFormContent from "./ImageFormContent";
|
||||||
@@ -22,14 +22,18 @@ const ImageDialog = ({ images }) => {
|
|||||||
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
|
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
dir="rtl"
|
maxWidth={"sm"}
|
||||||
maxWidth={"md"}
|
scroll="paper"
|
||||||
>
|
>
|
||||||
<DialogTitle>تصاویر</DialogTitle>
|
<DialogTitle sx={{ fontSize: "large" }}>تصاویر</DialogTitle>
|
||||||
<ImageFormContent image={images[1].full_path_for_fast_react} title={"قبل از اقدام"} />
|
<DialogContent>
|
||||||
<ImageFormContent image={images[0].full_path_for_fast_react} title={"بعد از اقدام"} />
|
<Paper elevation={0}>
|
||||||
|
<ImageFormContent image={images[1]?.full_path_for_fast_react} title={"قبل از اقدام"} />
|
||||||
|
<ImageFormContent image={images[0]?.full_path_for_fast_react} title={"بعد از اقدام"} />
|
||||||
|
</Paper>
|
||||||
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={() => setOpenImageDialog(false)} variant="outlined" color="secondary" autoFocus>
|
<Button onClick={() => setOpenImageDialog(false)} variant="outlined" color="secondary">
|
||||||
بستن
|
بستن
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const MachinesCodeDialog = ({ machinesLists }) => {
|
|||||||
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
|
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tooltip title="کد خودرو">
|
<Tooltip title="خودرو ها">
|
||||||
<IconButton color="primary" onClick={() => setOpenMachinesCodeDialog(true)}>
|
<IconButton color="primary" onClick={() => setOpenMachinesCodeDialog(true)}>
|
||||||
<DirectionsCarIcon />
|
<DirectionsCarIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -24,7 +24,7 @@ const MachinesCodeDialog = ({ machinesLists }) => {
|
|||||||
dir="rtl"
|
dir="rtl"
|
||||||
maxWidth={"md"}
|
maxWidth={"md"}
|
||||||
>
|
>
|
||||||
<DialogTitle sx={{ fontSize: "large" }}>کد خودرو</DialogTitle>
|
<DialogTitle sx={{ fontSize: "large" }}>خودرو ها</DialogTitle>
|
||||||
<MachinesCodeContent machinesLists={machinesLists} />
|
<MachinesCodeContent machinesLists={machinesLists} />
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const RejectContent = ({ rowId, mutate, setOpenRejectDialog }) => {
|
|||||||
const requestServer = useRequest({ notificationSuccess: true });
|
const requestServer = useRequest({ notificationSuccess: true });
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
description: Yup.string().required("توضیحات الزامیست!!!"),
|
description: Yup.string().required("لطفاً توضیحات را وارد کنید."),
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -51,12 +51,14 @@ const RejectContent = ({ rowId, mutate, setOpenRejectDialog }) => {
|
|||||||
{...register("description")}
|
{...register("description")}
|
||||||
multiline
|
multiline
|
||||||
rows={8}
|
rows={8}
|
||||||
label="توضیحات کارشناس"
|
label="توضیحات و دلایل عدم تأیید"
|
||||||
|
placeholder="لطفاً علت عدم تأیید خود را توضیح دهید"
|
||||||
error={!!errors.description}
|
error={!!errors.description}
|
||||||
helperText={errors.description?.message}
|
helperText={errors.description?.message}
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{ mt: 1 }}
|
sx={{ mt: 1 }}
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -72,7 +74,7 @@ const RejectContent = ({ rowId, mutate, setOpenRejectDialog }) => {
|
|||||||
بستن
|
بستن
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleSubmit(onSubmit)} variant="contained" color="primary" disabled={isSubmitting}>
|
<Button onClick={handleSubmit(onSubmit)} variant="contained" color="primary" disabled={isSubmitting}>
|
||||||
{isSubmitting ? "درحال ارسال اطلاعات..." : "عدم تایید"}
|
{isSubmitting ? "درحال ثبت عدم تایید..." : "ثبت عدم تایید"}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const RejectForm = ({ rowId, mutate }) => {
|
|||||||
const [openRejectDialog, setOpenRejectDialog] = useState(false);
|
const [openRejectDialog, setOpenRejectDialog] = useState(false);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tooltip title="عدم تایید">
|
<Tooltip title="عدم تایید فعالیت">
|
||||||
<IconButton color="primary" onClick={() => setOpenRejectDialog(true)}>
|
<IconButton color="primary" onClick={() => setOpenRejectDialog(true)}>
|
||||||
<ClearIcon />
|
<ClearIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -20,7 +20,7 @@ const RejectForm = ({ rowId, mutate }) => {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>عدم تایید</DialogTitle>
|
<DialogTitle>عدم تایید فعالیت</DialogTitle>
|
||||||
<RejectContent mutate={mutate} rowId={rowId} setOpenRejectDialog={setOpenRejectDialog} />
|
<RejectContent mutate={mutate} rowId={rowId} setOpenRejectDialog={setOpenRejectDialog} />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { useAuth } from "@/lib/contexts/auth";
|
|||||||
|
|
||||||
const SupervisorList = () => {
|
const SupervisorList = () => {
|
||||||
const statusOptions = [
|
const statusOptions = [
|
||||||
|
{ value: "", label: "همه وضعیت ها" },
|
||||||
{ value: 0, label: "درحال بررسی" },
|
{ value: 0, label: "درحال بررسی" },
|
||||||
{ value: 1, label: "تایید" },
|
{ value: 1, label: "تایید" },
|
||||||
{ value: 2, label: "عدم تایید" },
|
{ value: 2, label: "عدم تایید" },
|
||||||
@@ -46,7 +47,7 @@ const SupervisorList = () => {
|
|||||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
{ value: "", label: props.column.header },
|
{ value: "", label: "کل کشور" },
|
||||||
...provinces.map((province) => ({
|
...provinces.map((province) => ({
|
||||||
value: province.id,
|
value: province.id,
|
||||||
label: province.name_fa,
|
label: province.name_fa,
|
||||||
@@ -106,7 +107,7 @@ const SupervisorList = () => {
|
|||||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
{ value: "", label: props.column.header },
|
{ value: "", label: "کل ادارات" },
|
||||||
...edaratList.map((edare) => ({
|
...edaratList.map((edare) => ({
|
||||||
value: edare.id,
|
value: edare.id,
|
||||||
label: edare.name_fa,
|
label: edare.name_fa,
|
||||||
@@ -155,7 +156,7 @@ const SupervisorList = () => {
|
|||||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
{ value: "", label: props.column.header },
|
{ value: "", label: "همه آیتم ها" },
|
||||||
...itemsList.map((item) => ({
|
...itemsList.map((item) => ({
|
||||||
value: item.id,
|
value: item.id,
|
||||||
label: item.name,
|
label: item.name,
|
||||||
@@ -177,7 +178,7 @@ const SupervisorList = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "sub_item",
|
accessorKey: "sub_item",
|
||||||
header: "موضوع مشاهده شده",
|
header: "اقدام انجام شده",
|
||||||
id: "sub_item",
|
id: "sub_item",
|
||||||
enableColumnFilter: true,
|
enableColumnFilter: true,
|
||||||
datatype: "numeric",
|
datatype: "numeric",
|
||||||
@@ -200,7 +201,7 @@ const SupervisorList = () => {
|
|||||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
{ value: "", label: props.column.header },
|
{ value: "", label: "همه اقدام ها" },
|
||||||
...subItemsList.map((item) => ({
|
...subItemsList.map((item) => ({
|
||||||
value: item.sub_item,
|
value: item.sub_item,
|
||||||
label: item.name,
|
label: item.name,
|
||||||
@@ -347,7 +348,7 @@ const SupervisorList = () => {
|
|||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <Typography variant="body2">کد خودرویی وجود ندارد</Typography>;
|
return <Typography variant="body2">خودرویی وجود ندارد</Typography>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const OperatorCreate = ({ mutate }) => {
|
|||||||
ثبت اقدام
|
ثبت اقدام
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{open && <CreatePatrol open={open} setOpen={setOpen} mutate={mutate} />}
|
<CreatePatrol open={open} setOpen={setOpen} mutate={mutate} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,75 +1,25 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
import dynamic from "next/dynamic";
|
|
||||||
import MapLoading from "@/core/components/MapLayer/Loading";
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
Card,
|
|
||||||
CardActions,
|
|
||||||
CardContent,
|
|
||||||
CardHeader,
|
|
||||||
Chip,
|
|
||||||
Divider,
|
|
||||||
IconButton,
|
|
||||||
Stack,
|
|
||||||
Typography,
|
|
||||||
} from "@mui/material";
|
|
||||||
import HandymanIcon from "@mui/icons-material/Handyman";
|
|
||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
import DirectionsCarIcon from "@mui/icons-material/DirectionsCar";
|
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 DesignServicesIcon from "@mui/icons-material/DesignServices";
|
|
||||||
import EditActionDuringPatrol from "./EditActionDuringPatrol";
|
import EditActionDuringPatrol from "./EditActionDuringPatrol";
|
||||||
|
|
||||||
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
|
|
||||||
loading: () => <MapLoading />,
|
|
||||||
ssr: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
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>}
|
||||||
subheader={action.data.sub_item_name}
|
subheader={action.data.sub_item_name}
|
||||||
/>
|
/>
|
||||||
<CardContent>
|
|
||||||
<Stack sx={{ gap: 1 }}>
|
|
||||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
|
||||||
<DesignServicesIcon />
|
|
||||||
<Typography variant="button">میزان فعالیت انجام شده:</Typography>
|
|
||||||
<Typography variant="button">
|
|
||||||
{action.data.amount}({action.data.unit_fa})
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Divider sx={{ mb: 1 }}>
|
|
||||||
<Chip size="small" label="خودرو ها" icon={<DirectionsCarIcon />} />
|
|
||||||
</Divider>
|
|
||||||
<Stack>
|
|
||||||
{action.data.cmms_machines.map((cmms_machine, index) => (
|
|
||||||
<Typography variant="button" key={index}>
|
|
||||||
{index + 1}: {cmms_machine.car_name}
|
|
||||||
</Typography>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Divider sx={{ mb: 1 }}>
|
|
||||||
<Chip size="small" label="راهداران" icon={<PersonIcon />} />
|
|
||||||
</Divider>
|
|
||||||
<Stack>
|
|
||||||
{action.data.rahdaran_id.map((rahdar, index) => (
|
|
||||||
<Typography variant="button" key={index}>
|
|
||||||
{index + 1}: {rahdar.name}
|
|
||||||
</Typography>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
</CardContent>
|
|
||||||
<CardActions disableSpacing>
|
<CardActions disableSpacing>
|
||||||
<Box>
|
<Box>
|
||||||
<IconButton aria-label="حذف فعالیت" color="error" onClick={deleteAction}>
|
<IconButton aria-label="حذف فعالیت" color="error" onClick={deleteAction}>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Box, Button, Divider, Grid, Typography } from "@mui/material";
|
|
||||||
import AddCircleIcon from "@mui/icons-material/AddCircle";
|
import AddCircleIcon from "@mui/icons-material/AddCircle";
|
||||||
import React, { useState } from "react";
|
import ExitToAppIcon from "@mui/icons-material/ExitToApp";
|
||||||
import ModalActionsDuringPatrol from "./ModalActionsDuringPatrol";
|
import { Box, Button, Chip, DialogActions, DialogContent, Divider, Grid, Stack, Typography } from "@mui/material";
|
||||||
|
import { useState } from "react";
|
||||||
import ActionInfo from "./ActionInfo";
|
import ActionInfo from "./ActionInfo";
|
||||||
import KeyboardDoubleArrowLeftIcon from "@mui/icons-material/KeyboardDoubleArrowLeft";
|
import ModalActionsDuringPatrol from "./ModalActionsDuringPatrol";
|
||||||
|
|
||||||
const ActionsDuringPatrol = ({ setValue, tabState, setTabState }) => {
|
const ActionsDuringPatrol = ({ allData, setAllData, handlePrev, setTabState }) => {
|
||||||
const [ActionsList, setActionsList] = useState([]);
|
const [actionsList, setActionsList] = useState(allData.observed_items);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const handleOpen = () => {
|
const handleOpen = () => {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
@@ -18,72 +18,77 @@ const ActionsDuringPatrol = ({ setValue, tabState, setTabState }) => {
|
|||||||
setActionsList((prev) => prev.filter((_, index) => index !== indexToRemove));
|
setActionsList((prev) => prev.filter((_, index) => index !== indexToRemove));
|
||||||
};
|
};
|
||||||
|
|
||||||
const SubmitActionDuringPatrol = () => {
|
const handleNext = (data) => {
|
||||||
setTabState(tabState + 1);
|
setAllData({ observed_items: data });
|
||||||
const resultItems = ActionsList.map((item) => item.result);
|
setTabState((s) => s + 1);
|
||||||
console.log("resultItems", resultItems);
|
|
||||||
setValue("observed_items", resultItems);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<>
|
||||||
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
<DialogContent dividers sx={{ display: "flex" }}>
|
||||||
<Typography variant="h6">لیست اقدامات حین گشت</Typography>
|
<Box sx={{ flex: 1 }}>
|
||||||
<Button
|
<Stack
|
||||||
onClick={handleOpen}
|
direction={"row"}
|
||||||
startIcon={<AddCircleIcon />}
|
justifyContent={"center"}
|
||||||
variant="outlined"
|
sx={{
|
||||||
sx={{ mb: 1, alignSelf: "end" }}
|
mt: 1,
|
||||||
>
|
mb: 2,
|
||||||
ثبت اقدام
|
}}
|
||||||
</Button>
|
|
||||||
<ModalActionsDuringPatrol open={open} setOpen={setOpen} setActionsList={setActionsList} />
|
|
||||||
</Box>
|
|
||||||
<Divider />
|
|
||||||
{ActionsList.length !== 0 ? (
|
|
||||||
<Grid
|
|
||||||
container
|
|
||||||
spacing={2}
|
|
||||||
sx={{
|
|
||||||
p: 1,
|
|
||||||
mt: 1,
|
|
||||||
maxHeight: "300px",
|
|
||||||
overflowY: "auto",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{ActionsList.map((action, index) => (
|
|
||||||
<Grid key={index} item xs={12} sm={6} lg={4}>
|
|
||||||
<ActionInfo
|
|
||||||
action={action}
|
|
||||||
setActionsList={setActionsList}
|
|
||||||
index={index}
|
|
||||||
deleteAction={() => deleteAction(index)}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
) : (
|
|
||||||
<Box sx={{ my: 5, width: "100%", textAlign: "center" }}>
|
|
||||||
<Typography variant="h6" sx={{ letterSpacing: "2px", color: "#606060" }}>
|
|
||||||
فعالیتی ثبت نکرده اید
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
<Box>
|
|
||||||
<Box sx={{ display: "flex", gap: 1, justifyContent: "center" }}>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
onClick={SubmitActionDuringPatrol}
|
|
||||||
disabled={ActionsList === []}
|
|
||||||
endIcon={<KeyboardDoubleArrowLeftIcon />}
|
|
||||||
sx={{ mt: 2 }}
|
|
||||||
>
|
>
|
||||||
نهایی کردن درخواست
|
<Button onClick={handleOpen} startIcon={<AddCircleIcon />} variant="outlined" sx={{ mb: 1 }}>
|
||||||
</Button>
|
ثبت اقدام انجام شده
|
||||||
|
</Button>
|
||||||
|
<ModalActionsDuringPatrol open={open} setOpen={setOpen} setActionsList={setActionsList} />
|
||||||
|
</Stack>
|
||||||
|
<Divider sx={{ my: 2, width: "100%" }}>
|
||||||
|
<Chip variant="outlined" label="لیست اقدامات حین گشت" />
|
||||||
|
</Divider>
|
||||||
|
{actionsList.length !== 0 ? (
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={2}
|
||||||
|
sx={{
|
||||||
|
p: 1,
|
||||||
|
mt: 1,
|
||||||
|
maxHeight: "400px",
|
||||||
|
overflowY: "auto",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{actionsList.map((action, index) => (
|
||||||
|
<Grid key={index} item xs={12} sm={6} lg={4}>
|
||||||
|
<ActionInfo
|
||||||
|
action={action}
|
||||||
|
setActionsList={setActionsList}
|
||||||
|
index={index}
|
||||||
|
deleteAction={() => deleteAction(index)}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
) : (
|
||||||
|
<Box sx={{ my: 5, width: "100%", textAlign: "center" }}>
|
||||||
|
<Typography variant="h6" sx={{ letterSpacing: "2px", color: "#606060" }}>
|
||||||
|
فعالیتی ثبت نکرده اید
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</DialogContent>
|
||||||
</Box>
|
<DialogActions sx={{ alignItems: "center", justifyContent: "center" }}>
|
||||||
|
<Button
|
||||||
|
onClick={handlePrev}
|
||||||
|
variant="outlined"
|
||||||
|
color="secondary"
|
||||||
|
size="large"
|
||||||
|
startIcon={<ExitToAppIcon />}
|
||||||
|
>
|
||||||
|
{"صفحه قبل"}
|
||||||
|
</Button>
|
||||||
|
<Button variant="contained" size="large" onClick={() => handleNext(actionsList)}>
|
||||||
|
{"تایید اقدامات و ادامه"}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,20 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useEffect, useState } from "react";
|
import ShowPlak from "@/core/components/ShowPlak";
|
||||||
|
import StyledForm from "@/core/components/StyledForm";
|
||||||
|
import { formatCounter } from "@/core/utils/formatCounter";
|
||||||
|
import { formatSecondsToHHMMSS } from "@/core/utils/formatSecondsToHHMMSS";
|
||||||
|
import { CREATE_PATROL, GET_OTP_TOKEN } from "@/core/utils/routes";
|
||||||
|
import useRequest from "@/lib/hooks/useRequest";
|
||||||
|
import { yupResolver } from "@hookform/resolvers/yup";
|
||||||
|
import ExitToAppIcon from "@mui/icons-material/ExitToApp";
|
||||||
|
import ForwardToInboxIcon from "@mui/icons-material/ForwardToInbox";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Chip,
|
Chip,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
Divider,
|
Divider,
|
||||||
FormControl,
|
FormControl,
|
||||||
Grid,
|
Grid,
|
||||||
@@ -14,39 +24,53 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
Typography,
|
Typography,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import BeenhereIcon from "@mui/icons-material/Beenhere";
|
|
||||||
import ForwardToInboxIcon from "@mui/icons-material/ForwardToInbox";
|
|
||||||
import { formatCounter } from "@/core/utils/formatCounter";
|
|
||||||
import useRequest from "@/lib/hooks/useRequest";
|
|
||||||
import { GET_OTP_TOKEN } from "@/core/utils/routes";
|
|
||||||
import moment from "jalali-moment";
|
import moment from "jalali-moment";
|
||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import * as yup from "yup";
|
||||||
|
|
||||||
const CompeleteRequest = ({ watch, isSubmitting, setValue, register }) => {
|
const schemaOtp = yup.object().shape({
|
||||||
const requestServer = useRequest({ auth: true });
|
phoneNumber: yup
|
||||||
|
.string()
|
||||||
|
.matches(/^09\d{9}$/, "شماره تماس باید با 09 شروع شود و 11 رقم باشد.")
|
||||||
|
.required("شماره تماس الزامی است."),
|
||||||
|
});
|
||||||
|
|
||||||
|
const schemaSend = yup.object().shape({
|
||||||
|
phoneNumber: yup
|
||||||
|
.string()
|
||||||
|
.matches(/^09\d{9}$/, "شماره تماس باید با 09 شروع شود و 11 رقم باشد.")
|
||||||
|
.required("شماره تماس الزامی است."),
|
||||||
|
code: yup.string().length(6).required("شماره تماس الزامی است."),
|
||||||
|
});
|
||||||
|
|
||||||
|
const CompeleteRequest = ({ allData, handlePrev, mutate, setOpen }) => {
|
||||||
|
const requestServer = useRequest();
|
||||||
const [delayPerRequest, setDelayPerRequest] = useState(false);
|
const [delayPerRequest, setDelayPerRequest] = useState(false);
|
||||||
const [phoneNumber, setPhoneNumber] = useState("");
|
|
||||||
const [validPhone, setValidPhone] = useState(false);
|
|
||||||
const [verificationCode, setVerificationCode] = useState("");
|
|
||||||
const [counter, setCounter] = useState(120);
|
const [counter, setCounter] = useState(120);
|
||||||
const [otpSended, setOtpSended] = useState(false);
|
const [otpSended, setOtpSended] = useState(false);
|
||||||
const [readyToVerify, setReadyToVerify] = useState(false);
|
|
||||||
|
|
||||||
const handleNumericInput = (e) => {
|
const defaultValuesOtp = {
|
||||||
e.target.value = e.target.value.replace(/[^0-9]/g, "");
|
phoneNumber: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const defaultValuesSend = {
|
||||||
if (phoneNumber.length === 11) {
|
phoneNumber: "",
|
||||||
setValidPhone(true);
|
code: "",
|
||||||
} else {
|
};
|
||||||
setValidPhone(false);
|
|
||||||
}
|
const {
|
||||||
if (verificationCode.length === 6 && phoneNumber.length === 11) {
|
handleSubmit: handleSubmitOtp,
|
||||||
setReadyToVerify(true);
|
register: registerOtp,
|
||||||
} else {
|
formState: { isSubmitting: isSubmittingOtp, isValid: isValidOtp },
|
||||||
setReadyToVerify(false);
|
} = useForm({ defaultValues: defaultValuesOtp, resolver: yupResolver(schemaOtp), mode: "onBlur" });
|
||||||
}
|
|
||||||
}, [phoneNumber, verificationCode]);
|
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) {
|
||||||
@@ -62,167 +86,265 @@ const CompeleteRequest = ({ watch, isSubmitting, setValue, register }) => {
|
|||||||
}
|
}
|
||||||
}, [counter, delayPerRequest]);
|
}, [counter, delayPerRequest]);
|
||||||
|
|
||||||
const sendOtp = () => {
|
const sendOtp = async (data) => {
|
||||||
if (!validPhone) return false;
|
try {
|
||||||
requestServer(`${GET_OTP_TOKEN}?phone_number=${phoneNumber}`, "get")
|
const response = await requestServer(`${GET_OTP_TOKEN}?phone_number=${data.phoneNumber}`, "get");
|
||||||
.then((response) => {
|
setOtpSended(true);
|
||||||
setOtpSended(true);
|
setDelayPerRequest(true);
|
||||||
setDelayPerRequest(true);
|
setValueSend("phoneNumber", data.phoneNumber);
|
||||||
})
|
} catch (error) {}
|
||||||
.catch(() => { });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sendData = useCallback(
|
||||||
|
async (data) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
allData.road_patrol_rahdaran_id.forEach((rahdar, index) =>
|
||||||
|
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}][duration]`, stop_point.duration);
|
||||||
|
formData.append(`stop_points[${index}][latitude]`, stop_point.latitude);
|
||||||
|
formData.append(`stop_points[${index}][longitude]`, stop_point.longitude);
|
||||||
|
formData.append(`stop_points[${index}][startDT]`, stop_point.startDT);
|
||||||
|
});
|
||||||
|
allData.observed_items.forEach((observed_item, index) => {
|
||||||
|
formData.append(`observed_items[${index}][instant_action]`, 1);
|
||||||
|
formData.append(`observed_items[${index}][local_name]`, "");
|
||||||
|
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);
|
||||||
|
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 (
|
||||||
<Stack>
|
<>
|
||||||
<Stack>
|
<DialogContent dividers sx={{ display: "flex" }}>
|
||||||
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
<Box sx={{ flex: 1 }}>
|
||||||
<Box>
|
<Stack>
|
||||||
<Typography sx={{ color: "#777777", fontWeight: 500 }} variant="body1">
|
|
||||||
{moment(watch("start_time")).locale("fa").format("YYYY/MM/DD | HH:mm")}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Typography sx={{ color: "#777777", fontWeight: 500 }} variant="body1">
|
|
||||||
{moment(watch("end_time")).locale("fa").format("YYYY/MM/DD | HH:mm")}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<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>{watch("vehicle_runtime")}</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<Chip label="میزان سوخت مصرفی" />
|
|
||||||
<Divider sx={{ flex: 1, mx: 2 }} />
|
|
||||||
<Typography>{watch("fuel_consumption")}</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<Chip label="تعداد نقاط توقف" />
|
|
||||||
<Divider sx={{ flex: 1, mx: 2 }} />
|
|
||||||
<Typography>{watch("stop_points").length}</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<Chip label="مسافت پیموده شده" />
|
|
||||||
<Divider sx={{ flex: 1, mx: 2 }} />
|
|
||||||
<Typography>{watch("distance")}</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<Chip label="تعداد فعالیت های حین گشت" />
|
|
||||||
<Divider sx={{ flex: 1, mx: 2 }} />
|
|
||||||
<Typography>{watch("observed_items").length}</Typography>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
<Grid container spacing={3} sx={{ alignItems: "start", my: 2 }}>
|
|
||||||
<Grid item xs={12} lg={6}>
|
|
||||||
<Divider>
|
<Divider>
|
||||||
<Chip label="خودرو گشت" />
|
<Chip label="اطلاعات گشت" variant="outlined" />
|
||||||
</Divider>
|
</Divider>
|
||||||
<Box sx={{ display: "flex", alignItems: "center", my: 1 }}>
|
<Grid container spacing={2} sx={{ alignItems: "start", my: 1 }}>
|
||||||
<Typography>کد</Typography>
|
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
|
||||||
<Divider sx={{ flex: 1, mx: 2 }} />
|
<Chip label="تاریخ و زمان شروع" />
|
||||||
<Typography>{watch("road_patrol_machines_id.machine_code")}</Typography>
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ display: "flex", alignItems: "center", my: 1 }}>
|
|
||||||
<Typography>نام</Typography>
|
|
||||||
<Divider sx={{ flex: 1, mx: 2 }} />
|
|
||||||
<Typography>{watch("road_patrol_machines_id.car_name")}</Typography>
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ display: "flex", alignItems: "center", my: 1 }}>
|
|
||||||
<Typography>پلاک</Typography>
|
|
||||||
<Divider sx={{ flex: 1, mx: 2 }} />
|
|
||||||
<Typography>{watch("road_patrol_machines_id.plak_number")}</Typography>
|
|
||||||
</Box>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} lg={6}>
|
|
||||||
<Divider>
|
|
||||||
<Chip label="راهدار / راهداران حاضر در گشت" />
|
|
||||||
</Divider>
|
|
||||||
{watch("road_patrol_rahdaran_id")?.map((rahdar, index) => (
|
|
||||||
<Box key={index} sx={{ display: "flex", alignItems: "center", my: 1 }}>
|
|
||||||
<Typography>نام و کد راهدار</Typography>
|
|
||||||
<Divider sx={{ flex: 1, mx: 2 }} />
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
<Typography>
|
<Typography>
|
||||||
{rahdar.name} | {rahdar.code}
|
{allData.start_time !== "" &&
|
||||||
|
moment(allData.start_time).locale("fa").format("YYYY/MM/DD | HH:mm")}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Grid>
|
||||||
))}
|
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
|
||||||
</Grid>
|
<Chip label="تاریخ و زمان پایان" />
|
||||||
</Grid>
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
<Box sx={{ display: "flex", gap: 2, my: 2, justifyContent: "space-around" }}>
|
<Typography>
|
||||||
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
|
{allData.start_time !== "" &&
|
||||||
<FormControl size="small" fullWidth variant="outlined">
|
moment(allData.start_time).locale("fa").format("YYYY/MM/DD | HH:mm")}
|
||||||
<InputLabel htmlFor="phone_number">شماره تلفن مامور گشت</InputLabel>
|
</Typography>
|
||||||
<OutlinedInput
|
</Grid>
|
||||||
id="phone_number"
|
</Grid>
|
||||||
label={"شماره تلفن مامور گشت"}
|
<Grid container spacing={2} sx={{ alignItems: "start", my: 1 }}>
|
||||||
disabled={delayPerRequest}
|
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
|
||||||
autoComplete="off"
|
<Chip label="مدت زمان روشن بودن خودرو" />
|
||||||
size="small"
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
fullWidth
|
<Typography>
|
||||||
{...register("phone_number")}
|
{allData.accOnDuration && formatSecondsToHHMMSS(allData.accOnDuration)}
|
||||||
value={phoneNumber}
|
</Typography>
|
||||||
onChange={(e) => setPhoneNumber(e.target.value)}
|
</Grid>
|
||||||
onInput={handleNumericInput}
|
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
|
||||||
type="text"
|
<Chip label="میزان سوخت مصرفی" />
|
||||||
inputProps={{
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
maxLength: 11,
|
<Typography>
|
||||||
}}
|
{allData.fuelConsumption && Math.round(allData.fuelConsumption * 10) / 10} لیتر
|
||||||
/>
|
</Typography>
|
||||||
</FormControl>
|
</Grid>
|
||||||
<Button
|
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
|
||||||
onClick={sendOtp}
|
<Chip label="تعداد نقاط توقف" />
|
||||||
disabled={!validPhone || delayPerRequest}
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
variant="contained"
|
<Typography>{allData.stopPoints && allData.stopPoints.length}</Typography>
|
||||||
color="success"
|
</Grid>
|
||||||
sx={{ textWrap: "nowrap", px: 4 }}
|
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
|
||||||
endIcon={<ForwardToInboxIcon />}
|
<Chip label="مسافت پیموده شده" />
|
||||||
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
|
<Typography>
|
||||||
|
{allData.mileage && (allData.mileage / 1000).toFixed(1)} کیلومتر
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<Chip label="تعداد فعالیت های حین گشت" />
|
||||||
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
|
<Typography>{allData.observed_items && allData.observed_items.length}</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid container spacing={3} sx={{ alignItems: "start", my: 2 }}>
|
||||||
|
<Grid item xs={12} lg={6}>
|
||||||
|
<Divider>
|
||||||
|
<Chip label="خودرو گشت" />
|
||||||
|
</Divider>
|
||||||
|
<Stack direction={"row"} sx={{ alignItems: "center", my: 1 }}>
|
||||||
|
<Chip label="کد خودرو" />
|
||||||
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
|
<Typography>
|
||||||
|
{allData.roadPatrolMachinesId && allData.roadPatrolMachinesId.machine_code}
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
<Stack direction={"row"} sx={{ alignItems: "center", my: 1 }}>
|
||||||
|
<Chip label="نام خودرو" />
|
||||||
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
|
<Typography>
|
||||||
|
{allData.roadPatrolMachinesId && allData.roadPatrolMachinesId.car_name}
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
<Stack direction={"row"} sx={{ alignItems: "center", my: 1 }}>
|
||||||
|
<Chip label="پلاک خودرو" />
|
||||||
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
|
<Box sx={{ fontSize: 11 }}>
|
||||||
|
{allData.roadPatrolMachinesId.plak_number &&
|
||||||
|
ShowPlak({ plak_number: allData.roadPatrolMachinesId.plak_number })}
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} lg={6}>
|
||||||
|
<Divider>
|
||||||
|
<Chip label="راهدار / راهداران حاضر در گشت" />
|
||||||
|
</Divider>
|
||||||
|
{allData.road_patrol_rahdaran_id.map((rahdar, index) => (
|
||||||
|
<Stack key={rahdar.code} direction={"row"} sx={{ alignItems: "center", my: 1 }}>
|
||||||
|
<Chip label={`نام و کد راهدار ${index + 1}`} />
|
||||||
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
|
<Box sx={{ fontSize: 11 }}>
|
||||||
|
<Typography>
|
||||||
|
{rahdar.name} | {rahdar.code}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Divider>
|
||||||
|
<Chip label="احراز هویت" variant="outlined" />
|
||||||
|
</Divider>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
gap: 2,
|
||||||
|
my: 2,
|
||||||
|
justifyContent: "space-around",
|
||||||
|
flexDirection: { xs: "column", md: "row" },
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{delayPerRequest ? formatCounter(counter) : "دریافت کد"}
|
<StyledForm onSubmit={handleSubmitOtp(sendOtp)}>
|
||||||
</Button>
|
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
|
||||||
</Box>
|
<FormControl size="small" fullWidth variant="outlined">
|
||||||
<Slide in={otpSended}>
|
<InputLabel htmlFor="phoneNumber">شماره تلفن مامور گشت</InputLabel>
|
||||||
<Box>
|
<OutlinedInput
|
||||||
<FormControl size="small" fullWidth variant="outlined" focused>
|
id="phoneNumber"
|
||||||
<InputLabel htmlFor="verification_code">کد پیامک شده</InputLabel>
|
label={"شماره تلفن مامور گشت"}
|
||||||
<OutlinedInput
|
disabled={delayPerRequest}
|
||||||
id="verification_code"
|
autoComplete="off"
|
||||||
label={"کد پیامک شده"}
|
size="small"
|
||||||
placeholder="------"
|
fullWidth
|
||||||
autoComplete="off"
|
{...registerOtp("phoneNumber")}
|
||||||
size="small"
|
type="text"
|
||||||
fullWidth
|
inputProps={{
|
||||||
{...register("verification_code")}
|
maxLength: 11,
|
||||||
value={verificationCode}
|
}}
|
||||||
onChange={(e) => setVerificationCode(e.target.value)}
|
/>
|
||||||
onInput={handleNumericInput}
|
</FormControl>
|
||||||
type="text"
|
<Button
|
||||||
inputProps={{
|
disabled={isSubmittingOtp || !isValidOtp || delayPerRequest}
|
||||||
maxLength: 6,
|
variant="contained"
|
||||||
inputMode: "numeric",
|
type="submit"
|
||||||
style: {
|
sx={{ textWrap: "nowrap", width: 200 }}
|
||||||
textAlign: "center",
|
endIcon={<ForwardToInboxIcon />}
|
||||||
letterSpacing: "10px",
|
>
|
||||||
},
|
{delayPerRequest
|
||||||
}}
|
? formatCounter(counter)
|
||||||
/>
|
: isSubmittingOtp
|
||||||
</FormControl>
|
? "درحال دریافت کد ..."
|
||||||
|
: "دریافت کد"}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</StyledForm>
|
||||||
|
<Slide in={otpSended}>
|
||||||
|
<StyledForm onSubmit={handleSubmitSend(sendData)} id="sendForm">
|
||||||
|
<Box>
|
||||||
|
<FormControl size="small" fullWidth variant="outlined">
|
||||||
|
<InputLabel htmlFor="code">کد تایید پیامک شده</InputLabel>
|
||||||
|
<OutlinedInput
|
||||||
|
id="code"
|
||||||
|
label={"کد تایید پیامک شده"}
|
||||||
|
placeholder="------"
|
||||||
|
autoComplete="off"
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
{...registerSend("code")}
|
||||||
|
type="text"
|
||||||
|
inputProps={{
|
||||||
|
maxLength: 6,
|
||||||
|
inputMode: "numeric",
|
||||||
|
style: {
|
||||||
|
textAlign: "center",
|
||||||
|
letterSpacing: "10px",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
|
</StyledForm>
|
||||||
|
</Slide>
|
||||||
</Box>
|
</Box>
|
||||||
</Slide>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</DialogContent>
|
||||||
<Button
|
<DialogActions sx={{ alignItems: "center", justifyContent: "center" }}>
|
||||||
variant="contained"
|
<Button
|
||||||
size="large"
|
onClick={handlePrev}
|
||||||
disabled={isSubmitting}
|
variant="outlined"
|
||||||
type={"submit"}
|
color="secondary"
|
||||||
form="patrol_form"
|
size="large"
|
||||||
endIcon={<BeenhereIcon />}
|
startIcon={<ExitToAppIcon />}
|
||||||
>
|
>
|
||||||
{isSubmitting ? "در حال ثبت فعالیت" : "ثبت فعالیت"}
|
{"صفحه قبل"}
|
||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
size="large"
|
||||||
|
type="submit"
|
||||||
|
form="sendForm"
|
||||||
|
disabled={isSubmittingSend || !isValidSend}
|
||||||
|
>
|
||||||
|
{isSubmittingSend ? "در حال ثبت ..." : "تایید نهایی و ثبت"}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { IconButton, InputAdornment } from "@mui/material";
|
||||||
|
import { ClearIcon, MobileDateTimePicker } from "@mui/x-date-pickers";
|
||||||
|
import moment from "jalali-moment";
|
||||||
|
import { useWatch } from "react-hook-form";
|
||||||
|
|
||||||
|
const DatePickerForEndTime = ({ field, fieldState: { error }, control }) => {
|
||||||
|
const startTime = useWatch({ control, name: "start_time" });
|
||||||
|
return (
|
||||||
|
<MobileDateTimePicker
|
||||||
|
value={field.value ? new Date(field.value) : null}
|
||||||
|
ampm={false}
|
||||||
|
name="تاریخ و ساعت پایان گشت"
|
||||||
|
closeOnSelect
|
||||||
|
minDateTime={startTime ? new Date(startTime) : null}
|
||||||
|
onChange={(end_time) => {
|
||||||
|
const date = new Date(end_time);
|
||||||
|
const formattedDate = moment(date).locale("en").format("YYYY-MM-DD HH:mm");
|
||||||
|
field.onChange(formattedDate);
|
||||||
|
}}
|
||||||
|
slotProps={{
|
||||||
|
textField: {
|
||||||
|
size: "small",
|
||||||
|
placeholder: "تاریخ و ساعت وارد کنید",
|
||||||
|
InputLabelProps: { shrink: true },
|
||||||
|
sx: { width: { xs: "100%", md: 200 } },
|
||||||
|
InputProps: {
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
field.onChange("");
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
color: "#bfbfbf",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "rgba(189, 189, 189, 0.1)",
|
||||||
|
color: "#363434",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ClearIcon />
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
label="تاریخ و ساعت پایان گشت"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default DatePickerForEndTime;
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { IconButton, InputAdornment } from "@mui/material";
|
||||||
|
import { ClearIcon, MobileDateTimePicker } from "@mui/x-date-pickers";
|
||||||
|
import moment from "jalali-moment";
|
||||||
|
import { useWatch } from "react-hook-form";
|
||||||
|
|
||||||
|
const DatePickerForStartTime = ({ field, fieldState: { error }, control }) => {
|
||||||
|
const endTime = useWatch({ control, name: "end_time" });
|
||||||
|
return (
|
||||||
|
<MobileDateTimePicker
|
||||||
|
value={field.value ? new Date(field.value) : null}
|
||||||
|
ampm={false}
|
||||||
|
name="تاریخ و ساعت شروع گشت"
|
||||||
|
closeOnSelect
|
||||||
|
maxDateTime={endTime ? new Date(endTime) : null}
|
||||||
|
onChange={(start_time) => {
|
||||||
|
const date = new Date(start_time);
|
||||||
|
const formattedDate = moment(date).locale("en").format("YYYY-MM-DD HH:mm");
|
||||||
|
field.onChange(formattedDate);
|
||||||
|
}}
|
||||||
|
slotProps={{
|
||||||
|
textField: {
|
||||||
|
size: "small",
|
||||||
|
placeholder: "تاریخ و ساعت وارد کنید",
|
||||||
|
InputLabelProps: { shrink: true },
|
||||||
|
sx: { width: { xs: "100%", md: 200 } },
|
||||||
|
InputProps: {
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
field.onChange("");
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
color: "#bfbfbf",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "rgba(189, 189, 189, 0.1)",
|
||||||
|
color: "#363434",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ClearIcon />
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
label="تاریخ و ساعت شروع گشت"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default DatePickerForStartTime;
|
||||||
@@ -48,7 +48,12 @@ const EditActionDuringPatrol = ({ action, index, setActionsList }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle>ویرایش اطلاعات</DialogTitle>
|
<DialogTitle>ویرایش اطلاعات</DialogTitle>
|
||||||
<EditFormContent setOpenEditDialog={setOpen} onSubmit={HandleSubmit} defaultData={action.data} />
|
<EditFormContent
|
||||||
|
setOpenEditDialog={setOpen}
|
||||||
|
onSubmit={HandleSubmit}
|
||||||
|
defaultData={action.data}
|
||||||
|
is_gasht={true}
|
||||||
|
/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,202 +1,179 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Box, Button, Chip, Divider, IconButton, InputAdornment, Stack } from "@mui/material";
|
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import CarCode from "@/core/components/CarCode";
|
import CarCode from "@/core/components/CarCode";
|
||||||
|
import StyledForm from "@/core/components/StyledForm";
|
||||||
|
import { GET_FMS_DATA as GET_VAHICLE_OPRATION } from "@/core/utils/routes";
|
||||||
|
import useRequest from "@/lib/hooks/useRequest";
|
||||||
|
import { yupResolver } from "@hookform/resolvers/yup";
|
||||||
|
import ExitToAppIcon from "@mui/icons-material/ExitToApp";
|
||||||
import SearchIcon from "@mui/icons-material/Search";
|
import SearchIcon from "@mui/icons-material/Search";
|
||||||
|
import { Box, Button, Chip, DialogActions, DialogContent, Divider, Stack } from "@mui/material";
|
||||||
|
import { LocalizationProvider } from "@mui/x-date-pickers";
|
||||||
import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali";
|
import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali";
|
||||||
import { faIR } from "@mui/x-date-pickers/locales";
|
import { faIR } from "@mui/x-date-pickers/locales";
|
||||||
import { LocalizationProvider, MobileDateTimePicker } from "@mui/x-date-pickers";
|
|
||||||
import ClearIcon from "@mui/icons-material/Clear";
|
|
||||||
import moment from "jalali-moment";
|
import moment from "jalali-moment";
|
||||||
import dynamic from "next/dynamic";
|
import { useState } from "react";
|
||||||
import MapLoading from "@/core/components/MapLayer/Loading";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { Controller } from "react-hook-form";
|
import * as yup from "yup";
|
||||||
import { GET_FMS_DATA } from "@/core/utils/routes";
|
import DatePickerForEndTime from "./DatePickerForEndTime";
|
||||||
import useRequest from "@/lib/hooks/useRequest";
|
import DatePickerForStartTime from "./DatePickerForStartTime";
|
||||||
import PatrolDetailInfo from "./PatrolDetailInfo";
|
import PatrolDetailInfo from "./PatrolDetailInfo";
|
||||||
import PatrolResultCodeErrors from "./PatrolResultCodeErrors";
|
import PatrolResultCodeErrors from "./PatrolResultCodeErrors";
|
||||||
|
|
||||||
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
|
const schema = yup.object().shape({
|
||||||
loading: () => <MapLoading />,
|
roadPatrolMachinesId: yup.object().required("خودرو الزامی است."),
|
||||||
ssr: false,
|
start_time: yup.string().required("زمان شروع الزامی است."),
|
||||||
|
end_time: yup.string().required("زمان پایان الزامی است."),
|
||||||
});
|
});
|
||||||
|
|
||||||
const PatrolDetail = ({ control, watch, setValue, tabState, setTabState }) => {
|
const PatrolDetail = ({ allData, setAllData, handlePrev, setTabState }) => {
|
||||||
const requestServer = useRequest({ notificationSuccess: true });
|
const defaultValues = {
|
||||||
const [patrolResultStatus, setPatrolResultStatus] = useState(null);
|
has_vehicle_operation: allData.has_vehicle_operation,
|
||||||
const [readyToRequest, setReadyToRequest] = useState(false);
|
roadPatrolMachinesId: allData.roadPatrolMachinesId,
|
||||||
const [patrolData, setPatrolData] = useState(null);
|
start_time: allData.start_time,
|
||||||
|
end_time: allData.end_time,
|
||||||
|
stopPoints: allData.stopPoints,
|
||||||
|
accOnDuration: allData.accOnDuration,
|
||||||
|
fuelConsumption: allData.fuelConsumption,
|
||||||
|
mileage: allData.mileage,
|
||||||
|
};
|
||||||
|
const requestServer = useRequest();
|
||||||
|
const [patrolResultStatus, setPatrolResultStatus] = useState(allData.resultCode);
|
||||||
|
const [patrolData, setPatrolData] = useState(defaultValues);
|
||||||
|
|
||||||
const requestPatrolInfo = async () => {
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
setValue,
|
||||||
|
formState: { isSubmitting, isValid },
|
||||||
|
} = useForm({ defaultValues, resolver: yupResolver(schema), mode: "onBlur" });
|
||||||
|
|
||||||
|
const requestPatrolInfo = async (data) => {
|
||||||
|
setPatrolResultStatus(1);
|
||||||
|
setPatrolData((pd) => ({ ...pd, has_vehicle_operation: false }));
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("machineCode", watch("road_patrol_machines_id").machine_code);
|
formData.append("machineCode", data.roadPatrolMachinesId.machine_code);
|
||||||
formData.append("startDT", moment(watch("start_time")).format("YYYY-MM-DDTHH:mm"));
|
formData.append("startDT", moment(data.start_time).format("YYYY-MM-DDTHH:mm"));
|
||||||
formData.append("endDT", moment(watch("end_time")).format("YYYY-MM-DDTHH:mm"));
|
formData.append("endDT", moment(data.end_time).format("YYYY-MM-DDTHH:mm"));
|
||||||
await requestServer(GET_FMS_DATA, "post", {
|
try {
|
||||||
data: formData,
|
const response = await requestServer(GET_VAHICLE_OPRATION, "post", {
|
||||||
})
|
data: formData,
|
||||||
.then((response) => {
|
});
|
||||||
const data = response.data.data;
|
const result = response.data.data;
|
||||||
setPatrolData({
|
setPatrolData({
|
||||||
...data,
|
...result,
|
||||||
roadPatrolMachinesId: watch("road_patrol_machines_id"),
|
roadPatrolMachinesId: data.roadPatrolMachinesId,
|
||||||
start_time: watch("start_time"),
|
start_time: data.start_time,
|
||||||
end_time: watch("end_time"),
|
end_time: data.end_time,
|
||||||
});
|
has_vehicle_operation: result.resultCode == 0,
|
||||||
setPatrolResultStatus(data.resultCode);
|
});
|
||||||
})
|
|
||||||
.catch((error) => {});
|
setValue("stopPoints", result.stopPoints);
|
||||||
|
setValue("accOnDuration", result.accOnDuration);
|
||||||
|
setValue("fuelConsumption", result.fuelConsumption);
|
||||||
|
setValue("mileage", result.mileage);
|
||||||
|
setValue("has_vehicle_operation", true);
|
||||||
|
setPatrolResultStatus(result.resultCode);
|
||||||
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const handleNext = (data) => {
|
||||||
const roadPatrolMachinesId = watch("road_patrol_machines_id");
|
setAllData(data);
|
||||||
const startTime = watch("start_time");
|
setTabState((s) => s + 1);
|
||||||
const endTime = watch("end_time");
|
};
|
||||||
|
|
||||||
const isReady = roadPatrolMachinesId !== null && startTime !== "" && endTime !== "";
|
|
||||||
setReadyToRequest(isReady);
|
|
||||||
}, [watch("road_patrol_machines_id"), watch("start_time"), watch("end_time")]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<>
|
||||||
sx={{
|
<DialogContent dividers sx={{ display: "flex", maxHeight: { xs: "500px", md: "100%" }, overflowY: "auto" }}>
|
||||||
display: "flex",
|
<Box sx={{ flex: 1 }}>
|
||||||
flexDirection: "column",
|
<Box
|
||||||
alignItems: "center",
|
sx={{
|
||||||
justifyContent: "center",
|
display: "flex",
|
||||||
my: 3,
|
flexDirection: "column",
|
||||||
}}
|
mt: 1,
|
||||||
>
|
mb: 2,
|
||||||
<Box sx={{ display: "flex", flexDirection: { xs: "column", lg: "row" }, gap: 2 }}>
|
|
||||||
<Stack sx={{ minWidth: "200px" }}>
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
render={({ field, fieldState: { error } }) => {
|
|
||||||
return (
|
|
||||||
<CarCode
|
|
||||||
carCode={field.value}
|
|
||||||
setCarCode={(value) => field.onChange(value)}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
name={"road_patrol_machines_id"}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
<Box sx={{ display: "flex", gap: 2 }}>
|
|
||||||
<LocalizationProvider
|
|
||||||
dateAdapter={AdapterDateFnsJalali}
|
|
||||||
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
|
|
||||||
>
|
>
|
||||||
<MobileDateTimePicker
|
<StyledForm onSubmit={handleSubmit(requestPatrolInfo)}>
|
||||||
value={watch("start_time") ? new Date(watch("start_time")) : null}
|
<Box
|
||||||
ampm={false}
|
sx={{
|
||||||
name="تاریخ و ساعت شروع گشت"
|
display: "flex",
|
||||||
closeOnSelect
|
flexDirection: { xs: "column", md: "row" },
|
||||||
maxDateTime={watch("end_time") ? new Date(watch("end_time")) : null}
|
rowGap: 2,
|
||||||
onChange={(start_time) => {
|
columnGap: 1,
|
||||||
const date = new Date(start_time);
|
}}
|
||||||
const formattedDate = moment(date).locale("en").format("YYYY-MM-DD HH:mm");
|
>
|
||||||
setValue("start_time", formattedDate);
|
<Stack sx={{ minWidth: "200px" }}>
|
||||||
}}
|
<Controller
|
||||||
slotProps={{
|
control={control}
|
||||||
textField: {
|
render={({ field, fieldState: { error } }) => {
|
||||||
size: "small",
|
return (
|
||||||
placeholder: "تاریخ و ساعت شروع گشت",
|
<CarCode
|
||||||
InputProps: {
|
carCode={field.value}
|
||||||
endAdornment: (
|
setCarCode={(value) => field.onChange(value)}
|
||||||
<InputAdornment position="end">
|
error={error}
|
||||||
<IconButton
|
/>
|
||||||
size="small"
|
);
|
||||||
onClick={(event) => {
|
}}
|
||||||
event.stopPropagation();
|
name={"roadPatrolMachinesId"}
|
||||||
setValue("start_time", "");
|
/>
|
||||||
}}
|
</Stack>
|
||||||
sx={{
|
<Box sx={{ display: "flex", gap: 1 }}>
|
||||||
color: "#bfbfbf",
|
<LocalizationProvider
|
||||||
"&:hover": {
|
dateAdapter={AdapterDateFnsJalali}
|
||||||
backgroundColor: "rgba(189, 189, 189, 0.1)",
|
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
|
||||||
color: "#363434",
|
>
|
||||||
},
|
<Controller
|
||||||
}}
|
control={control}
|
||||||
>
|
render={(props) => <DatePickerForStartTime {...props} control={control} />}
|
||||||
<ClearIcon />
|
name={"start_time"}
|
||||||
</IconButton>
|
/>
|
||||||
</InputAdornment>
|
<Controller
|
||||||
),
|
control={control}
|
||||||
},
|
render={(props) => <DatePickerForEndTime {...props} control={control} />}
|
||||||
},
|
name={"end_time"}
|
||||||
}}
|
/>
|
||||||
label="تاریخ و ساعت شروع گشت"
|
</LocalizationProvider>
|
||||||
/>
|
</Box>
|
||||||
<MobileDateTimePicker
|
<Button
|
||||||
value={watch("end_time") ? new Date(watch("end_time")) : null}
|
sx={{ flex: 1 }}
|
||||||
ampm={false}
|
variant="contained"
|
||||||
name="تاریخ و ساعت پایان گشت"
|
type="submit"
|
||||||
closeOnSelect
|
disabled={isSubmitting || !isValid}
|
||||||
minDateTime={watch("start_time") ? new Date(watch("start_time")) : null}
|
endIcon={<SearchIcon />}
|
||||||
onChange={(end_time) => {
|
>
|
||||||
const date = new Date(end_time);
|
{isSubmitting ? "درحال دریافت عملکرد خودرو ..." : "دریافت عملکرد خوردو"}
|
||||||
const formattedDate = moment(date).locale("en").format("YYYY-MM-DD HH:mm");
|
</Button>
|
||||||
setValue("end_time", formattedDate);
|
</Box>
|
||||||
}}
|
</StyledForm>
|
||||||
slotProps={{
|
<Divider sx={{ my: 2, width: "100%" }}>
|
||||||
textField: {
|
<Chip label="مشخصات گشت" variant="outlined" />
|
||||||
size: "small",
|
</Divider>
|
||||||
placeholder: "تاریخ و ساعت پایان گشت",
|
{patrolResultStatus !== 0 && <PatrolResultCodeErrors ResultCode={patrolResultStatus} />}
|
||||||
InputProps: {
|
<PatrolDetailInfo patrolData={patrolData} />
|
||||||
endAdornment: (
|
</Box>
|
||||||
<InputAdornment position="end">
|
|
||||||
<IconButton
|
|
||||||
size="small"
|
|
||||||
onClick={(event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
setValue("end_time", "");
|
|
||||||
}}
|
|
||||||
sx={{
|
|
||||||
color: "#bfbfbf",
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: "rgba(189, 189, 189, 0.1)",
|
|
||||||
color: "#363434",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ClearIcon />
|
|
||||||
</IconButton>
|
|
||||||
</InputAdornment>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
label="تاریخ و ساعت پایان گشت"
|
|
||||||
/>
|
|
||||||
</LocalizationProvider>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions sx={{ alignItems: "center", justifyContent: "center" }}>
|
||||||
|
<Button
|
||||||
|
onClick={handlePrev}
|
||||||
|
variant="outlined"
|
||||||
|
color="secondary"
|
||||||
|
size="large"
|
||||||
|
startIcon={<ExitToAppIcon />}
|
||||||
|
>
|
||||||
|
{"بستن"}
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={requestPatrolInfo}
|
size="large"
|
||||||
color="success"
|
disabled={!patrolData?.has_vehicle_operation}
|
||||||
disabled={!readyToRequest}
|
onClick={() => handleNext(patrolData)}
|
||||||
endIcon={<SearchIcon />}
|
|
||||||
>
|
>
|
||||||
درخواست اطلاعات
|
{"تایید مشخصات گشت و ادامه"}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</DialogActions>
|
||||||
<Divider sx={{ my: 2, width: "100%" }}>
|
</>
|
||||||
<Chip color="success" label="مشخصات گشت" />
|
|
||||||
</Divider>
|
|
||||||
{patrolResultStatus === 0 ? (
|
|
||||||
<PatrolDetailInfo
|
|
||||||
patrolData={patrolData}
|
|
||||||
tabState={tabState}
|
|
||||||
setTabState={setTabState}
|
|
||||||
setValue={setValue}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<PatrolResultCodeErrors ResultCode={patrolResultStatus} />
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,18 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Box, Button, Card, CardActions, CardContent, Chip, Divider, 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 />,
|
||||||
@@ -27,111 +41,109 @@ const MapItemViewBound = ({ patrolData, bound }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (bound.length !== 0) {
|
if (bound.length !== 0) {
|
||||||
map.fitBounds(bound, { paddingTopLeft: [16, 16], paddingBottomRight: [16, 130] });
|
map.fitBounds(bound, { paddingTopLeft: [64, 64], paddingBottomRight: [64, 64] });
|
||||||
}
|
}
|
||||||
}, [bound]);
|
}, [bound]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{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, tabState, setTabState, setValue }) => {
|
const PatrolDetailInfo = ({ patrolData }) => {
|
||||||
const bound = patrolData.stopPoints.map((point) => [point.latitude, point.longitude]);
|
const bound = patrolData?.stopPoints
|
||||||
|
? patrolData?.stopPoints.map((point) => [point.latitude, point.longitude])
|
||||||
const SendPatrolInfo = () => {
|
: [];
|
||||||
setValue("vehicle_runtime", patrolData.accOnDuration);
|
|
||||||
setValue("fuel_consumption", patrolData.fuelConsumption);
|
|
||||||
setValue("distance", patrolData.mileage);
|
|
||||||
setValue("stop_points", patrolData.stopPoints);
|
|
||||||
setTabState(tabState + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slide in={true} sx={{ width: "100%" }}>
|
<Fade in={patrolData?.has_vehicle_operation} sx={{ width: "100%" }}>
|
||||||
<Card>
|
<Card elevation={0}>
|
||||||
<CardContent
|
<CardContent
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: { xs: "column", lg: "row" },
|
flexDirection: { xs: "column", lg: "row" },
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-around",
|
||||||
gap: { xs: 2, lg: 0 },
|
gap: { xs: 2, lg: 0 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack sx={{ minWidth: { xs: "100%", lg: "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" }}>
|
||||||
<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 }}>
|
<Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
|
||||||
{patrolData.roadPatrolMachinesId.car_name}
|
{patrolData?.roadPatrolMachinesId?.car_name}
|
||||||
</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={<QrCode2Icon />} />
|
<Chip size="small" label="کد خودرو" icon={<QrCode2Icon />} />
|
||||||
<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.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 }}>
|
||||||
{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 }}>
|
||||||
{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} لیتر
|
||||||
</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={<ShareLocationIcon />} />
|
<Chip size="small" label="تعداد توقف در مسیر" icon={<ShareLocationIcon />} />
|
||||||
<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.stopPoints.length} مورد
|
{patrolData?.stopPoints?.length} مورد
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Divider orientation="vertical" flexItem />
|
<Divider orientation="vertical" flexItem />
|
||||||
<Stack spacing={1} sx={{ height: "300px", width: { xs: "100%", lg: "350px" } }}>
|
<Stack spacing={1} sx={{ height: "300px", width: { xs: "100%", md: "350px" } }}>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
p: 1,
|
p: 1,
|
||||||
@@ -149,28 +161,17 @@ const PatrolDetailInfo = ({ patrolData, tabState, setTabState, setValue }) => {
|
|||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MapLayer position={bound}>
|
{bound.length > 0 && (
|
||||||
<MapItemViewBound patrolData={patrolData} bound={bound} />
|
<MapLayer position={bound}>
|
||||||
</MapLayer>
|
<MapItemViewBound patrolData={patrolData} bound={bound} />
|
||||||
|
</MapLayer>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardActions sx={{ alignItems: "center", justifyContent: "center" }}>
|
|
||||||
<Box sx={{ display: "flex", gap: 1 }}>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
onClick={SendPatrolInfo}
|
|
||||||
endIcon={<KeyboardDoubleArrowLeftIcon />}
|
|
||||||
sx={{ mt: 2 }}
|
|
||||||
>
|
|
||||||
تایید اطلاعات و رفتن به مرحله بعد
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</CardActions>
|
|
||||||
</Card>
|
</Card>
|
||||||
</Slide>
|
</Fade>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Box, DialogContent, Tab, Tabs, useMediaQuery } from "@mui/material";
|
|
||||||
import { useTheme } from "@emotion/react";
|
import { useTheme } from "@emotion/react";
|
||||||
import React, { useEffect, useState } from "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 PatrolTimeLine from "./PatrolTimeLine";
|
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 ActionsDuringPatrol from "./ActionsDurigPatrol";
|
||||||
|
import CompeleteRequest from "./CompeleteRequest";
|
||||||
import PatrolDetail from "./PatrolDetail";
|
import PatrolDetail from "./PatrolDetail";
|
||||||
import SuperVisorsDetail from "./SuperVisorsDetail";
|
import SuperVisorsDetail from "./SuperVisorsDetail";
|
||||||
import ActionsDuringPatrol from "./ActionsDurigPatrol";
|
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import StyledForm from "@/core/components/StyledForm";
|
|
||||||
import useRequest from "@/lib/hooks/useRequest";
|
|
||||||
import CompeleteRequest from "./CompeleteRequest";
|
|
||||||
|
|
||||||
function TabPanel(props) {
|
function TabPanel(props) {
|
||||||
const { children, value, index } = props;
|
const { children, value, index } = props;
|
||||||
@@ -27,21 +24,32 @@ function TabPanel(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
road_patrol_rahdaran_id: null,
|
has_vehicle_operation: false,
|
||||||
road_patrol_machines_id: null,
|
road_patrol_rahdaran_id: [],
|
||||||
|
roadPatrolMachinesId: null,
|
||||||
start_time: "",
|
start_time: "",
|
||||||
end_time: "",
|
end_time: "",
|
||||||
stop_points: null,
|
stopPoints: null,
|
||||||
vehicle_runtime: "",
|
accOnDuration: "",
|
||||||
fuel_consumption: "",
|
fuelConsumption: "",
|
||||||
distance: "",
|
mileage: "",
|
||||||
observed_items: null,
|
observed_items: [],
|
||||||
phone_number: "",
|
phone_number: "",
|
||||||
otp_token: "",
|
otp_token: "",
|
||||||
|
resultCode: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const reducer = (state, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case "changeData":
|
||||||
|
return { ...state, ...action.data };
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const PatrolForms = ({ mutate, setOpen }) => {
|
const PatrolForms = ({ mutate, setOpen }) => {
|
||||||
const requestServer = useRequest({ notificationSuccess: true });
|
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"));
|
||||||
const [tabState, setTabState] = useState(0);
|
const [tabState, setTabState] = useState(0);
|
||||||
@@ -57,123 +65,68 @@ const PatrolForms = ({ mutate, setOpen }) => {
|
|||||||
}
|
}
|
||||||
}, [tabState]);
|
}, [tabState]);
|
||||||
|
|
||||||
const {
|
const handlePrev = useCallback(() => {
|
||||||
control,
|
if (tabState == 0) {
|
||||||
watch,
|
setOpen(false);
|
||||||
getValues,
|
}
|
||||||
register,
|
setTabState((s) => s - 1);
|
||||||
handleSubmit,
|
}, [tabState]);
|
||||||
setValue,
|
|
||||||
resetField,
|
|
||||||
formState: { isSubmitting },
|
|
||||||
} = useForm({
|
|
||||||
defaultValues,
|
|
||||||
mode: "onBlur",
|
|
||||||
});
|
|
||||||
|
|
||||||
const onSubmit = async (data) => {
|
|
||||||
console.log("data", data);
|
|
||||||
// const formData = new FormData();
|
|
||||||
// data.road_patrol_rahdaran_id.forEach((rahdar, index) => formData.append(`road_patrol_rahdaran_id[${index}]`, rahdar.id));
|
|
||||||
// formData.append(`road_patrol_machines_id[0]`, data.road_patrol_machines_id.id)
|
|
||||||
// data.stop_points.forEach((stop_point, index) => formData.append(`stop_points[${index}]`, stop_point))
|
|
||||||
// data.observed_items.forEach((observed_item, index) => {
|
|
||||||
// formData.append(`observed_items[${index}][instant_action]`, 1);
|
|
||||||
// formData.append(`observed_items[${index}][local_name]`, "");
|
|
||||||
// formData.append(`observed_items[${index}][start_point]`, observed_item.start_point);
|
|
||||||
// formData.append(`observed_items[${index}][start_point]`, observed_item.end_point);
|
|
||||||
// formData.append(`observed_items[${index}][amount]`, observed_item.amount);
|
|
||||||
// formData.append(`observed_items[${index}][before_image]`, observed_item.before_image);
|
|
||||||
// formData.append(`observed_items[${index}][after_image]`, observed_item.after_image);
|
|
||||||
// observed_item.cmms_machines.forEach((machine) => formData.append(`observed_items[${index}][cmms_machines][]`, machine.id))
|
|
||||||
// observed_item.rahdaran_id.forEach((rahdar) => formData.append(`observed_items[${index}][rahdaran_id][]`, rahdar.id))
|
|
||||||
// formData.append(`observed_items[${index}][sub_item_id]`, observed_item.sub_item_id);
|
|
||||||
// })
|
|
||||||
// formData.append("start_time", data.start_time);
|
|
||||||
// formData.append("end_time", data.end_time);
|
|
||||||
// formData.append("vehicle_runtime", data.vehicle_runtime);
|
|
||||||
// formData.append("fuel_consumption", +data.fuel_consumption);
|
|
||||||
// formData.append("distance", data.distance);
|
|
||||||
// formData.append("description", "");
|
|
||||||
// formData.append("phone_number", data.phone_number);
|
|
||||||
// formData.append("verification_code", data.verification_code);
|
|
||||||
// if (data.phone_number !== "" && data.verification_code !== "") {
|
|
||||||
// try {
|
|
||||||
// await requestServer(CREATE_PATROL, "post", {
|
|
||||||
// data: formData,
|
|
||||||
// });
|
|
||||||
// mutate();
|
|
||||||
// setOpen(false);
|
|
||||||
// } catch (error) {
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// console.log("error phone number")
|
|
||||||
// }
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledForm onSubmit={handleSubmit(onSubmit)} id="patrol_form">
|
<>
|
||||||
<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>
|
||||||
<DialogContent dividers sx={{ display: "flex" }}>
|
</Tabs>
|
||||||
<Box sx={{ flex: 1 }}>
|
</DialogHeader>
|
||||||
<TabPanel value={tabState} index={0}>
|
<TabPanel value={tabState} index={0}>
|
||||||
<PatrolDetail
|
<PatrolDetail
|
||||||
control={control}
|
allData={allData}
|
||||||
setValue={setValue}
|
setAllData={(data) => {
|
||||||
watch={watch}
|
dispatch({ type: "changeData", data });
|
||||||
tabState={tabState}
|
}}
|
||||||
setTabState={setTabState}
|
handlePrev={handlePrev}
|
||||||
/>
|
setTabState={setTabState}
|
||||||
</TabPanel>
|
/>
|
||||||
<TabPanel value={tabState} index={1}>
|
</TabPanel>
|
||||||
<SuperVisorsDetail
|
<TabPanel value={tabState} index={1}>
|
||||||
control={control}
|
<SuperVisorsDetail
|
||||||
setValue={setValue}
|
allData={allData}
|
||||||
watch={watch}
|
setAllData={(data) => {
|
||||||
tabState={tabState}
|
dispatch({ type: "changeData", data });
|
||||||
setTabState={setTabState}
|
}}
|
||||||
/>
|
handlePrev={handlePrev}
|
||||||
</TabPanel>
|
setTabState={setTabState}
|
||||||
<TabPanel value={tabState} index={2}>
|
/>
|
||||||
<ActionsDuringPatrol
|
</TabPanel>
|
||||||
watch={watch}
|
<TabPanel value={tabState} index={2}>
|
||||||
setValue={setValue}
|
<ActionsDuringPatrol
|
||||||
tabState={tabState}
|
allData={allData}
|
||||||
setTabState={setTabState}
|
setAllData={(data) => {
|
||||||
/>
|
dispatch({ type: "changeData", data });
|
||||||
</TabPanel>
|
}}
|
||||||
<TabPanel value={tabState} index={3}>
|
handlePrev={handlePrev}
|
||||||
<CompeleteRequest
|
setTabState={setTabState}
|
||||||
register={register}
|
/>
|
||||||
setValue={setValue}
|
</TabPanel>
|
||||||
watch={watch}
|
<TabPanel value={tabState} index={3}>
|
||||||
isSubmitting={isSubmitting}
|
<CompeleteRequest allData={allData} handlePrev={handlePrev} mutate={mutate} setOpen={setOpen} />
|
||||||
/>
|
</TabPanel>
|
||||||
</TabPanel>
|
</>
|
||||||
</Box>
|
|
||||||
{!isMobile && (
|
|
||||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<PatrolTimeLine tabState={tabState} />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</DialogContent>
|
|
||||||
</StyledForm>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default PatrolForms;
|
export default PatrolForms;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import React from "react";
|
|||||||
|
|
||||||
const PatrolResultCodeErrors = ({ ResultCode }) => {
|
const PatrolResultCodeErrors = ({ ResultCode }) => {
|
||||||
const errorMessages = {
|
const errorMessages = {
|
||||||
|
[1]: "درحال دریافت عملکرد خودرو ...",
|
||||||
[-1]: "نام کاربری یا کلمه عبور صحیح نمیباشد",
|
[-1]: "نام کاربری یا کلمه عبور صحیح نمیباشد",
|
||||||
[-2]: "ردیاب به خودرو انتخابی متصل نیست",
|
[-2]: "ردیاب به خودرو انتخابی متصل نیست",
|
||||||
[-3]: "کاربر دسترسی لازم به اطلاعات خودرو انتخابی را ندارد",
|
[-3]: "کاربر دسترسی لازم به اطلاعات خودرو انتخابی را ندارد",
|
||||||
@@ -14,8 +15,11 @@ const PatrolResultCodeErrors = ({ ResultCode }) => {
|
|||||||
const message = errorMessages[ResultCode] || "ابتدا اطلاعات بالا را تکمیل نمایید";
|
const message = errorMessages[ResultCode] || "ابتدا اطلاعات بالا را تکمیل نمایید";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ my: 5 }}>
|
<Box sx={{ my: 5, textAlign: "center" }}>
|
||||||
<Typography variant="h6" sx={{ letterSpacing: "2px", color: ResultCode ? "error.main" : "#606060" }}>
|
<Typography
|
||||||
|
variant="h6"
|
||||||
|
sx={{ letterSpacing: "2px", color: ResultCode && ResultCode != 1 ? "error.main" : "#606060" }}
|
||||||
|
>
|
||||||
{message}
|
{message}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -8,11 +8,13 @@ import React from "react";
|
|||||||
const SuperVisorInfo = ({ superVisor, deleteSuperVisor }) => {
|
const SuperVisorInfo = ({ superVisor, deleteSuperVisor }) => {
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
elevation={3}
|
elevation={0}
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
|
border: 1,
|
||||||
|
borderColor: "divider",
|
||||||
px: 1,
|
px: 1,
|
||||||
py: 1,
|
py: 1,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,138 +1,144 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Box, Button, Chip, Divider, Grid, Stack, Typography } from "@mui/material";
|
|
||||||
import SaveAltIcon from "@mui/icons-material/SaveAlt";
|
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import RahdarCode from "@/core/components/RahdarCode";
|
|
||||||
import SuperVisorInfo from "@/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorInfo";
|
import SuperVisorInfo from "@/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorInfo";
|
||||||
import KeyboardDoubleArrowRightIcon from "@mui/icons-material/KeyboardDoubleArrowRight";
|
import RahdarCode from "@/core/components/RahdarCode";
|
||||||
import KeyboardDoubleArrowLeftIcon from "@mui/icons-material/KeyboardDoubleArrowLeft";
|
import StyledForm from "@/core/components/StyledForm";
|
||||||
import { Controller } from "react-hook-form";
|
import { yupResolver } from "@hookform/resolvers/yup";
|
||||||
|
import ExitToAppIcon from "@mui/icons-material/ExitToApp";
|
||||||
|
import { Box, Button, Chip, DialogActions, DialogContent, Divider, Fade, Grid, Stack, Typography } from "@mui/material";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
import * as yup from "yup";
|
||||||
|
|
||||||
const SuperVisorsDetail = ({ control, watch, setValue, tabState, setTabState }) => {
|
const schema = yup.object().shape({
|
||||||
const [SuperVisorList, setSuperVisorList] = useState([]);
|
road_patrol_rahdaran_id: yup.object().required("راهدار الزامی است."),
|
||||||
const [readyToRequest, setReadyToRequest] = useState(false);
|
});
|
||||||
|
|
||||||
const requestPatrolInfo = () => {
|
const SuperVisorsDetail = ({ allData, setAllData, handlePrev, setTabState }) => {
|
||||||
setSuperVisorList((prev) => [...prev, watch("road_patrol_rahdaran_id")]);
|
const [SuperVisorList, setSuperVisorList] = useState(allData.road_patrol_rahdaran_id);
|
||||||
setReadyToRequest(false);
|
|
||||||
setValue("road_patrol_rahdaran_id", null);
|
const defaultValues = {
|
||||||
|
road_patrol_rahdaran_id: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
reset,
|
||||||
|
setValue,
|
||||||
|
formState: { isSubmitting, isValid },
|
||||||
|
} = useForm({ defaultValues, resolver: yupResolver(schema), mode: "onBlur" });
|
||||||
|
|
||||||
|
const requestPatrolInfo = (data) => {
|
||||||
|
setSuperVisorList((prev) => [...prev, data.road_patrol_rahdaran_id]);
|
||||||
|
reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteSuperVisor = (id) => {
|
const deleteSuperVisor = (id) => {
|
||||||
setSuperVisorList((prev) => prev.filter((superVisor) => superVisor.id !== id));
|
setSuperVisorList((prev) => prev.filter((superVisor) => superVisor.id !== id));
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const handleNext = (data) => {
|
||||||
setReadyToRequest(watch("road_patrol_rahdaran_id") != null);
|
setAllData({ road_patrol_rahdaran_id: data });
|
||||||
}, [watch("road_patrol_rahdaran_id")]);
|
setTabState((s) => s + 1);
|
||||||
|
|
||||||
const SendSuperVisor = () => {
|
|
||||||
setValue("road_patrol_rahdaran_id", SuperVisorList);
|
|
||||||
setTabState(tabState + 1);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<>
|
||||||
sx={{
|
<DialogContent dividers sx={{ display: "flex" }}>
|
||||||
display: "flex",
|
<Box sx={{ flex: 1 }}>
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
my: 3,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Grid container sx={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
|
|
||||||
<Grid
|
|
||||||
item
|
|
||||||
xs={6}
|
|
||||||
sx={{ display: "flex", alignItems: "center", flexDirection: { xs: "column", lg: "row" }, gap: 2 }}
|
|
||||||
>
|
|
||||||
<Stack sx={{ minWidth: "250px" }}>
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
render={({ field, fieldState: { error } }) => {
|
|
||||||
return (
|
|
||||||
<RahdarCode
|
|
||||||
rahdarsCode={field.value}
|
|
||||||
setRahdarsCode={(value) => field.onChange(value)}
|
|
||||||
error={error}
|
|
||||||
multiple={false}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
name={"road_patrol_rahdaran_id"}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
onClick={requestPatrolInfo}
|
|
||||||
color="success"
|
|
||||||
sx={{ textWrap: "nowrap", px: 3 }}
|
|
||||||
disabled={!readyToRequest}
|
|
||||||
endIcon={<SaveAltIcon />}
|
|
||||||
>
|
|
||||||
ثبت راهدار
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
<Divider sx={{ my: 2, width: "100%" }}>
|
|
||||||
<Chip color="success" variant="outlined" label="لیست راهداران انتخاب شده" />
|
|
||||||
</Divider>
|
|
||||||
{SuperVisorList.length !== 0 ? (
|
|
||||||
<>
|
|
||||||
<Grid
|
|
||||||
container
|
|
||||||
spacing={2}
|
|
||||||
sx={{
|
|
||||||
p: 1,
|
|
||||||
mt: 1,
|
|
||||||
maxHeight: "300px",
|
|
||||||
overflowY: "auto",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{SuperVisorList.map((superVisor) => (
|
|
||||||
<Grid key={superVisor.id} item xs={12} sm={6} lg={4}>
|
|
||||||
<SuperVisorInfo superVisor={superVisor} deleteSuperVisor={deleteSuperVisor} />
|
|
||||||
</Grid>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
gap: 1,
|
flexDirection: "column",
|
||||||
mt: 2,
|
mt: 1,
|
||||||
width: "100%",
|
mb: 2,
|
||||||
justifyContent: "center",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<StyledForm onSubmit={handleSubmit(requestPatrolInfo)}>
|
||||||
variant="outlined"
|
<Stack direction={{ xs: "column", sm: "row" }} justifyContent={"center"} spacing={2}>
|
||||||
color="error"
|
<Stack sx={{ minWidth: "250px" }}>
|
||||||
startIcon={<KeyboardDoubleArrowRightIcon />}
|
<Controller
|
||||||
sx={{ mt: 2 }}
|
control={control}
|
||||||
>
|
render={({ field, fieldState: { error } }) => {
|
||||||
بازگشت
|
return (
|
||||||
</Button>
|
<RahdarCode
|
||||||
<Button
|
rahdarsCode={field.value}
|
||||||
variant="contained"
|
setRahdarsCode={(value) => field.onChange(value)}
|
||||||
color="primary"
|
error={error}
|
||||||
onClick={SendSuperVisor}
|
multiple={false}
|
||||||
endIcon={<KeyboardDoubleArrowLeftIcon />}
|
/>
|
||||||
sx={{ mt: 2 }}
|
);
|
||||||
>
|
}}
|
||||||
تایید اطلاعات و رفتن به مرحله بعد
|
name={"road_patrol_rahdaran_id"}
|
||||||
</Button>
|
/>
|
||||||
|
</Stack>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
type="submit"
|
||||||
|
sx={{ textWrap: "nowrap", px: 3 }}
|
||||||
|
disabled={isSubmitting || !isValid}
|
||||||
|
>
|
||||||
|
افزودن راهدار
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</StyledForm>
|
||||||
|
<Divider sx={{ my: 2, width: "100%" }}>
|
||||||
|
<Chip variant="outlined" label="لیست راهداران" />
|
||||||
|
</Divider>
|
||||||
|
{SuperVisorList.length === 0 && (
|
||||||
|
<Box sx={{ my: 4, width: "100%", textAlign: "center" }}>
|
||||||
|
<Typography variant="h6" sx={{ letterSpacing: "2px", color: "#606060" }}>
|
||||||
|
ابتدا اطلاعات بالا را تکمیل نمایید
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
<Fade in={SuperVisorList.length !== 0} sx={{ width: "100%" }}>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={2}
|
||||||
|
sx={{
|
||||||
|
p: 1,
|
||||||
|
mt: 2,
|
||||||
|
minHeight: 150,
|
||||||
|
maxHeight: 300,
|
||||||
|
overflowY: "auto",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{SuperVisorList.length !== 0 &&
|
||||||
|
SuperVisorList.map((superVisor) => (
|
||||||
|
<Grid key={superVisor.id} item xs={12} sm={6} lg={4}>
|
||||||
|
<SuperVisorInfo
|
||||||
|
superVisor={superVisor}
|
||||||
|
deleteSuperVisor={deleteSuperVisor}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Fade>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Box sx={{ my: 5, width: "100%", textAlign: "center" }}>
|
|
||||||
<Typography variant="h6" sx={{ letterSpacing: "2px", color: "#606060" }}>
|
|
||||||
ابتدا اطلاعات بالا را تکمیل نمایید
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
</DialogContent>
|
||||||
</Box>
|
<DialogActions sx={{ alignItems: "center", justifyContent: "center" }}>
|
||||||
|
<Button
|
||||||
|
onClick={handlePrev}
|
||||||
|
variant="outlined"
|
||||||
|
color="secondary"
|
||||||
|
size="large"
|
||||||
|
startIcon={<ExitToAppIcon />}
|
||||||
|
>
|
||||||
|
{"صفحه قبل"}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
size="large"
|
||||||
|
disabled={SuperVisorList.length === 0}
|
||||||
|
onClick={() => handleNext(SuperVisorList)}
|
||||||
|
>
|
||||||
|
{"تایید راهداران و ادامه"}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import PatrolForms from "./PatrolForms";
|
|||||||
|
|
||||||
const CreatePatrol = ({ open, setOpen, mutate }) => {
|
const CreatePatrol = ({ open, setOpen, mutate }) => {
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} fullWidth maxWidth="lg">
|
<Dialog open={open} fullWidth maxWidth="md">
|
||||||
<PatrolForms setOpen={setOpen} mutate={mutate} />
|
{open && <PatrolForms setOpen={setOpen} mutate={mutate} />}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,10 +43,10 @@ const OperatorList = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Cell: ({ renderedCellValue }) => {
|
Cell: ({ renderedCellValue, row }) => {
|
||||||
return (
|
return (
|
||||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||||
<MachinePerformanceForm />
|
<MachinePerformanceForm row={row} />
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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 || ""} کیلومتر
|
{(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" }}>
|
||||||
|
|||||||
@@ -3,34 +3,15 @@ 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 = () => {
|
const MachinePerformanceForm = ({ row }) => {
|
||||||
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
|
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
|
||||||
const machineData = {
|
const machineData = {
|
||||||
cmms_machine_code: 245,
|
cmms_machine_code: row.original?.cmms_machines[0]?.machine_code,
|
||||||
resultCode: 0,
|
resultCode: 0,
|
||||||
mileage: 17645,
|
mileage: row.original?.distance,
|
||||||
accOnDuration: 3599,
|
accOnDuration: row.original?.vehicle_runtime,
|
||||||
fuelConsumption: 6.1757503,
|
fuelConsumption: row.original?.fuel_consumption,
|
||||||
stopPoints: [
|
stopPoints: row.original?.stop_points,
|
||||||
{
|
|
||||||
startDT: "2024-12-23T13:55:40",
|
|
||||||
duration: 114,
|
|
||||||
latitude: 37.521317,
|
|
||||||
longitude: 46.103584,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startDT: "2024-12-23T14:31:11",
|
|
||||||
duration: 14,
|
|
||||||
latitude: 37.566532,
|
|
||||||
longitude: 46.17688,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startDT: "2024-12-23T14:35:36",
|
|
||||||
duration: 55,
|
|
||||||
latitude: 37.569958,
|
|
||||||
longitude: 46.18166,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { Tooltip, IconButton } from "@mui/material";
|
import { GET_ROAD_PATROL_OPERATOR_REPORT } from "@/core/utils/routes";
|
||||||
import PrintIcon from "@mui/icons-material/Print";
|
import PrintIcon from "@mui/icons-material/Print";
|
||||||
|
import { IconButton, Tooltip } from "@mui/material";
|
||||||
|
|
||||||
const ReportForm = ({ rowId }) => {
|
const ReportForm = ({ rowId }) => {
|
||||||
const reportUrl = `https://rms.rmto.ir/v2/road_patrols/operator/report/${rowId}`;
|
|
||||||
return (
|
return (
|
||||||
<Tooltip title="گزارش" arrow placement="right">
|
<Tooltip title="گزارش" arrow placement="right">
|
||||||
<IconButton
|
<IconButton
|
||||||
color="primary"
|
color="primary"
|
||||||
component="a"
|
component="a"
|
||||||
href={reportUrl}
|
href={`${GET_ROAD_PATROL_OPERATOR_REPORT}/${rowId}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
sx={{ textTransform: "unset", alignSelf: "center" }}
|
sx={{ textTransform: "unset", alignSelf: "center" }}
|
||||||
|
|||||||
@@ -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 || ""} کیلومتر
|
{(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,62 +69,59 @@ 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>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<Chip
|
||||||
|
icon={<PinDropIcon />}
|
||||||
|
label={
|
||||||
|
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
|
||||||
|
طول جغرافیایی
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
|
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
|
||||||
|
{selectedPoint ? selectedPoint.longitude : "نقطه مورد نظر را انتخاب کنید"}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<Chip
|
||||||
|
icon={<PinDropIcon />}
|
||||||
|
label={
|
||||||
|
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
|
||||||
|
عرض جغرافیایی
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
|
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
|
||||||
|
{selectedPoint ? selectedPoint.latitude : "نقطه مورد نظر را انتخاب کنید"}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<Chip
|
||||||
|
icon={<AccessAlarmsIcon />}
|
||||||
|
label={
|
||||||
|
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
|
||||||
|
مدت زمان توقف
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Divider sx={{ flex: 1, mx: 2 }} />
|
||||||
|
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
|
||||||
|
{selectedPoint
|
||||||
|
? `${formatSecondsToHHMMSS(selectedPoint.duration)} ثانیه`
|
||||||
|
: "نقطه مورد نظر را انتخاب کنید"}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{selectedPoint && (
|
|
||||||
<>
|
|
||||||
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<Chip
|
|
||||||
icon={<PinDropIcon />}
|
|
||||||
label={
|
|
||||||
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
|
|
||||||
طول جغرافیایی
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Divider sx={{ flex: 1, mx: 2 }} />
|
|
||||||
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
|
|
||||||
{selectedPoint.longitude || ""}
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<Chip
|
|
||||||
icon={<PinDropIcon />}
|
|
||||||
label={
|
|
||||||
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
|
|
||||||
عرض جغرافیایی
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Divider sx={{ flex: 1, mx: 2 }} />
|
|
||||||
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
|
|
||||||
{selectedPoint.latitude || ""}
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<Chip
|
|
||||||
icon={<AccessAlarmsIcon />}
|
|
||||||
label={
|
|
||||||
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.700" }}>
|
|
||||||
مدت زمان توقف
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Divider sx={{ flex: 1, mx: 2 }} />
|
|
||||||
<Typography variant="body2" sx={{ fontWeight: 600, color: "grey.800" }}>
|
|
||||||
{selectedPoint.duration || ""} ثانیه
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,34 +3,15 @@ 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 = () => {
|
const MachinePerformanceForm = ({ row }) => {
|
||||||
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
|
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
|
||||||
const machineData = {
|
const machineData = {
|
||||||
cmms_machine_code: 245,
|
cmms_machine_code: row.original?.cmms_machines[0]?.machine_code,
|
||||||
resultCode: 0,
|
resultCode: 0,
|
||||||
mileage: 17645,
|
mileage: row.original?.distance,
|
||||||
accOnDuration: 3599,
|
accOnDuration: row.original?.vehicle_runtime,
|
||||||
fuelConsumption: 6.1757503,
|
fuelConsumption: row.original?.fuel_consumption,
|
||||||
stopPoints: [
|
stopPoints: row.original?.stop_points,
|
||||||
{
|
|
||||||
startDT: "2024-12-23T13:55:40",
|
|
||||||
duration: 114,
|
|
||||||
latitude: 37.521317,
|
|
||||||
longitude: 46.103584,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startDT: "2024-12-23T14:31:11",
|
|
||||||
duration: 14,
|
|
||||||
latitude: 37.566532,
|
|
||||||
longitude: 46.17688,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startDT: "2024-12-23T14:35:36",
|
|
||||||
duration: 55,
|
|
||||||
latitude: 37.569958,
|
|
||||||
longitude: 46.18166,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { Tooltip, IconButton } from "@mui/material";
|
import { GET_ROAD_PATROL_SUPERVISOR_REPORT } from "@/core/utils/routes";
|
||||||
import PrintIcon from "@mui/icons-material/Print";
|
import PrintIcon from "@mui/icons-material/Print";
|
||||||
|
import { IconButton, Tooltip } from "@mui/material";
|
||||||
|
|
||||||
const ReportForm = ({ rowId }) => {
|
const ReportForm = ({ rowId }) => {
|
||||||
const reportUrl = `https://rms.rmto.ir/v2/road_patrols/operator/report/${rowId}`;
|
|
||||||
return (
|
return (
|
||||||
<Tooltip title="گزارش" arrow placement="right">
|
<Tooltip title="گزارش" arrow placement="right">
|
||||||
<IconButton
|
<IconButton
|
||||||
color="primary"
|
color="primary"
|
||||||
component="a"
|
component="a"
|
||||||
href={reportUrl}
|
href={`${GET_ROAD_PATROL_SUPERVISOR_REPORT}/${rowId}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
sx={{ textTransform: "unset", alignSelf: "center" }}
|
sx={{ textTransform: "unset", alignSelf: "center" }}
|
||||||
|
|||||||
@@ -147,9 +147,9 @@ const SupervisorList = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Cell: () => (
|
Cell: ({ row }) => (
|
||||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||||
<MachinePerformanceForm />
|
<MachinePerformanceForm row={row} />
|
||||||
</Stack>
|
</Stack>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,36 +10,37 @@ const CarCode = ({ carCode, setCarCode, inputValueDefault = "", error, multiple
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const requestServer = useRequest();
|
const requestServer = useRequest();
|
||||||
|
|
||||||
const fetchCarCodes = (inputValue, controller) => {
|
|
||||||
const debouncer = debounce((query) => {
|
|
||||||
if (!query || query?.length < 3) {
|
|
||||||
setOptions([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setLoading(true);
|
|
||||||
requestServer(`${GET_CAR_LIST_SEARCH}?machine_code=${query}`, "get", {
|
|
||||||
requestOptions: { signal: controller.signal },
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
const combinedArray = carCode ? [...carCode, ...response.data.data] : [...response.data.data];
|
|
||||||
const uniqueArray = Array.from(new Map(combinedArray.map((item) => [item.id, item])).values());
|
|
||||||
setOptions(uniqueArray || []);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setOptions([]);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
debouncer(inputValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const fetchCarCodes = (inputValue, controller) => {
|
||||||
|
const debouncer = debounce((query) => {
|
||||||
|
if (!query || query?.length < 3) {
|
||||||
|
setOptions([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setLoading(true);
|
||||||
|
requestServer(`${GET_CAR_LIST_SEARCH}?machine_code=${query}`, "get", {
|
||||||
|
requestOptions: { signal: controller.signal },
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
const combinedArray = carCode ? [...carCode, ...response.data.data] : [...response.data.data];
|
||||||
|
const uniqueArray = Array.from(new Map(combinedArray.map((item) => [item.id, item])).values());
|
||||||
|
setOptions(uniqueArray || []);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setOptions([]);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
debouncer(inputValue);
|
||||||
|
};
|
||||||
|
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
fetchCarCodes(inputValue, controller);
|
fetchCarCodes(inputValue, controller);
|
||||||
return () => controller.abort();
|
return () => controller.abort();
|
||||||
}, [inputValue]);
|
}, [inputValue]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
multiple={multiple}
|
multiple={multiple}
|
||||||
@@ -50,7 +51,7 @@ const CarCode = ({ carCode, setCarCode, inputValueDefault = "", error, multiple
|
|||||||
}}
|
}}
|
||||||
inputValue={inputValue}
|
inputValue={inputValue}
|
||||||
onInputChange={(event, newInputValue) => {
|
onInputChange={(event, newInputValue) => {
|
||||||
setInputValue(newInputValue || ""); // Prevent inputValue from being null or undefined
|
setInputValue(newInputValue || "");
|
||||||
}}
|
}}
|
||||||
options={options}
|
options={options}
|
||||||
getOptionLabel={(option) => {
|
getOptionLabel={(option) => {
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ const DataTable_Main = (props) => {
|
|||||||
}
|
}
|
||||||
params.set("sorting", JSON.stringify(sortData));
|
params.set("sorting", JSON.stringify(sortData));
|
||||||
return `${table_url}?${params}`;
|
return `${table_url}?${params}`;
|
||||||
}, [table_url, filterData, pagination, columns, sortData, specialFilter]);
|
}, [table_url, filterData, pagination, sortData, specialFilter]);
|
||||||
|
|
||||||
const fetcher = async (url) => {
|
const fetcher = async (url) => {
|
||||||
try {
|
try {
|
||||||
const response = await request(url);
|
const response = await request(url);
|
||||||
|
|||||||
@@ -84,16 +84,12 @@ function FilterBody({ columns, drawerState, setDrawerState }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<>
|
||||||
open={drawerState}
|
|
||||||
onClose={() => setDrawerState(false)}
|
|
||||||
sx={{ overflowY: "hidden", display: "flex", flexDirection: "column", height: "100%", zIndex: "1300" }}
|
|
||||||
>
|
|
||||||
<FilterHeader setDrawerState={setDrawerState} />
|
<FilterHeader setDrawerState={setDrawerState} />
|
||||||
{Object.keys(filterData).length > 0 && (
|
{Object.keys(filterData).length > 0 && (
|
||||||
<ScrollBox>
|
<ScrollBox>
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
<Box sx={{ px: 1, py: 2 }}>
|
<Box sx={{ px: 1, py: 3 }}>
|
||||||
{columns.map((column) =>
|
{columns.map((column) =>
|
||||||
column.enableColumnFilter ? (
|
column.enableColumnFilter ? (
|
||||||
column.dependencyId ? (
|
column.dependencyId ? (
|
||||||
@@ -144,7 +140,7 @@ function FilterBody({ columns, drawerState, setDrawerState }) {
|
|||||||
</form>
|
</form>
|
||||||
</ScrollBox>
|
</ScrollBox>
|
||||||
)}
|
)}
|
||||||
</Drawer>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Box, IconButton, Typography } from "@mui/material";
|
|
||||||
import CancelIcon from "@mui/icons-material/Cancel";
|
import CancelIcon from "@mui/icons-material/Cancel";
|
||||||
import FilterAltIcon from "@mui/icons-material/FilterAlt";
|
import FilterAltIcon from "@mui/icons-material/FilterAlt";
|
||||||
|
import { Box, IconButton, Typography } from "@mui/material";
|
||||||
|
|
||||||
function FilterHeader({ setDrawerState }) {
|
function FilterHeader({ setDrawerState }) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -30,6 +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",
|
||||||
error: error,
|
error: error,
|
||||||
placeholder: placeholder,
|
placeholder: placeholder,
|
||||||
InputProps: {
|
InputProps: {
|
||||||
@@ -60,9 +61,9 @@ function MuiDatePicker({ label, value, setFieldValue, name, minDate, maxDate, he
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<FormHelperText id="component-helper-text" sx={{ ml: 2, color: error ? "#d32f2f" : "unset" }}>
|
{/* <FormHelperText id="component-helper-text" variant="caption" sx={{ ml: 2, color: error ? "#d32f2f" : "unset", fontWeight: 'bold' }}>
|
||||||
{helperText ? helperText : ""}
|
{helperText ? helperText : ""}
|
||||||
</FormHelperText>
|
</FormHelperText> */}
|
||||||
</LocalizationProvider>
|
</LocalizationProvider>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,46 +1,28 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { FormControl, FormHelperText, InputLabel, MenuItem, OutlinedInput, Select, Typography } from "@mui/material";
|
import { FormControl, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material";
|
||||||
import { useEffect, useMemo } from "react";
|
function CustomSelect({ column, filterParameters, handleChange }) {
|
||||||
|
|
||||||
function CustomSelect({ column, dependencyFieldValue, filterParameters, defaultFilterTranslation, handleChange }) {
|
|
||||||
const columnSelectOption = useMemo(() => {
|
|
||||||
return column?.columnSelectOption?.(dependencyFieldValue) || [];
|
|
||||||
}, [dependencyFieldValue]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const isValidValue = columnSelectOption.some((option) => option.value === filterParameters.value);
|
|
||||||
if (!isValidValue) {
|
|
||||||
handleChange({ ...filterParameters, value: "" });
|
|
||||||
}
|
|
||||||
}, [columnSelectOption, filterParameters.value, handleChange]);
|
|
||||||
|
|
||||||
const isValidValue = columnSelectOption.some((option) => option.value === filterParameters.value);
|
|
||||||
const selectedValue = isValidValue ? filterParameters.value : "";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormControl fullWidth sx={{ marginY: 1 }}>
|
<FormControl fullWidth sx={{ marginY: 1 }} size="small">
|
||||||
<InputLabel id={`label${column.id}`}>{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}
|
||||||
name={`${column.id}.value`}
|
name={`${column.id}.value`}
|
||||||
value={selectedValue}
|
value={filterParameters.value}
|
||||||
input={<OutlinedInput label={column.header} />}
|
input={<OutlinedInput label={column.header} />}
|
||||||
|
size="small"
|
||||||
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
|
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
|
||||||
|
displayEmpty
|
||||||
>
|
>
|
||||||
<MenuItem value="">{column.header}</MenuItem>
|
{column.columnSelectOption().map((option) => (
|
||||||
{columnSelectOption.map((option) => (
|
|
||||||
<MenuItem key={option.value} value={option.value}>
|
<MenuItem key={option.value} value={option.value}>
|
||||||
{option.label}
|
{option.label}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
<FormHelperText>
|
|
||||||
<Typography variant="button" sx={{ color: "#155175" }}>
|
|
||||||
نوع فیلتر: {defaultFilterTranslation}
|
|
||||||
</Typography>
|
|
||||||
</FormHelperText>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,15 +12,19 @@ function CustomSelectByDependency({
|
|||||||
columnSelectOption,
|
columnSelectOption,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<FormControl fullWidth sx={{ marginY: 1 }}>
|
<FormControl fullWidth sx={{ my: 1 }} size="small">
|
||||||
<InputLabel id={`label${column.id}`}>{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}
|
||||||
name={`${column.id}.value`}
|
name={`${column.id}.value`}
|
||||||
value={value}
|
value={value}
|
||||||
|
size="small"
|
||||||
input={<OutlinedInput label={column.header} />}
|
input={<OutlinedInput label={column.header} />}
|
||||||
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
|
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
|
||||||
|
displayEmpty
|
||||||
>
|
>
|
||||||
{columnSelectOption.map((option) => (
|
{columnSelectOption.map((option) => (
|
||||||
<MenuItem key={option.value} value={option.value}>
|
<MenuItem key={option.value} value={option.value}>
|
||||||
@@ -28,11 +32,11 @@ function CustomSelectByDependency({
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
<FormHelperText>
|
{/* <FormHelperText>
|
||||||
<Typography variant="button" sx={{ color: "#155175" }}>
|
<Typography variant="caption" sx={{ color: "#155175", fontWeight: 'bold' }}>
|
||||||
نوع فیلتر: {defaultFilterTranslation}
|
نوع فیلتر: {defaultFilterTranslation}
|
||||||
</Typography>
|
</Typography>
|
||||||
</FormHelperText>
|
</FormHelperText> */}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ function CustomSelectMultiple({ column, filterParameters, defaultFilterTranslati
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormControl fullWidth sx={{ marginY: 1 }}>
|
<FormControl fullWidth sx={{ marginY: 1 }} size="small">
|
||||||
<InputLabel htmlFor="uncontrolled-native" id={`label${column.id}`}>
|
<InputLabel htmlFor="uncontrolled-native" id={`label${column.id}`}>
|
||||||
{column.header}
|
{column.header}
|
||||||
</InputLabel>
|
</InputLabel>
|
||||||
@@ -30,6 +30,7 @@ function CustomSelectMultiple({ column, filterParameters, defaultFilterTranslati
|
|||||||
id={column.id}
|
id={column.id}
|
||||||
value={filterParameters.value}
|
value={filterParameters.value}
|
||||||
multiple
|
multiple
|
||||||
|
size="small"
|
||||||
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
|
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
|
||||||
renderValue={(selected) => (
|
renderValue={(selected) => (
|
||||||
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 0.5 }}>
|
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 0.5 }}>
|
||||||
@@ -39,6 +40,7 @@ function CustomSelectMultiple({ column, filterParameters, defaultFilterTranslati
|
|||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
input={<OutlinedInput label={column.header} />}
|
input={<OutlinedInput label={column.header} />}
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
>
|
>
|
||||||
{columnSelectOption.map((option) => (
|
{columnSelectOption.map((option) => (
|
||||||
<MenuItem key={option.value} value={option.value}>
|
<MenuItem key={option.value} value={option.value}>
|
||||||
@@ -46,11 +48,11 @@ function CustomSelectMultiple({ column, filterParameters, defaultFilterTranslati
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
<FormHelperText>
|
{/* <FormHelperText>
|
||||||
<Typography variant="button" sx={{ color: "#155175" }}>
|
<Typography variant="caption" sx={{ color: "#155175", fontWeight: 'bold' }}>
|
||||||
نوع فیلتر: {defaultFilterTranslation}
|
نوع فیلتر: {defaultFilterTranslation}
|
||||||
</Typography>
|
</Typography>
|
||||||
</FormHelperText>
|
</FormHelperText> */}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ function CustomTextField({
|
|||||||
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
|
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
fullWidth
|
fullWidth
|
||||||
helperText={
|
// helperText={
|
||||||
<Typography variant="button" sx={{ color: "#155175" }}>
|
// <Typography variant="caption" sx={{ color: "#155175", fontWeight: 'bold' }}>
|
||||||
نوع فیلتر: {defaultFilterTranslation}
|
// نوع فیلتر: {defaultFilterTranslation}
|
||||||
</Typography>
|
// </Typography>
|
||||||
}
|
// }
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="normal"
|
size="small"
|
||||||
sx={{ marginY: 1 }}
|
sx={{ my: 1 }}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end" sx={{ cursor: "pointer" }} onClick={handleOpenFilterBox}>
|
<InputAdornment position="end" sx={{ cursor: "pointer" }} onClick={handleOpenFilterBox}>
|
||||||
@@ -33,6 +33,7 @@ function CustomTextField({
|
|||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ 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="button" sx={{ color: "#155175" }}>
|
<Typography variant="caption" sx={{ color: "#155175", fontWeight: "bold" }}>
|
||||||
نوع فیلتر: {defaultFilterTranslation}
|
نوع فیلتر: {defaultFilterTranslation}
|
||||||
</Typography>
|
</Typography>
|
||||||
}
|
}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="normal"
|
size="small"
|
||||||
sx={{ marginY: 1, marginRight: 1 }}
|
sx={{ my: 1, marginRight: 1 }}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
id={`${column.id}.value[1]`}
|
id={`${column.id}.value[1]`}
|
||||||
@@ -45,8 +45,8 @@ function CustomTextFieldRange({
|
|||||||
value={filterParameters.value[1]}
|
value={filterParameters.value[1]}
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="normal"
|
size="small"
|
||||||
sx={{ marginY: 1 }}
|
sx={{ my: 1 }}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end" sx={{ cursor: "pointer" }} onClick={handleOpenFilterBox}>
|
<InputAdornment position="end" sx={{ cursor: "pointer" }} onClick={handleOpenFilterBox}>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import FilterButton from "@/core/components/DataTable/filter/FilterButton";
|
import FilterButton from "@/core/components/DataTable/filter/FilterButton";
|
||||||
import FilterBody from "@/core/components/DataTable/filter/FilterBody";
|
import FilterBody from "@/core/components/DataTable/filter/FilterBody";
|
||||||
|
import { Drawer } from "@mui/material";
|
||||||
|
|
||||||
function FilterColumn({ columns, user_id, page_name, table_name }) {
|
function FilterColumn({ columns, user_id, page_name, table_name }) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
@@ -9,7 +10,11 @@ function FilterColumn({ columns, user_id, page_name, table_name }) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FilterButton drawerState={open} setDrawerState={setOpen} />
|
<FilterButton drawerState={open} setDrawerState={setOpen} />
|
||||||
{open && (
|
<Drawer
|
||||||
|
open={open}
|
||||||
|
onClose={() => setOpen(false)}
|
||||||
|
sx={{ overflowY: "hidden", display: "flex", flexDirection: "column", height: "100%", zIndex: "1300" }}
|
||||||
|
>
|
||||||
<FilterBody
|
<FilterBody
|
||||||
columns={columns}
|
columns={columns}
|
||||||
drawerState={open}
|
drawerState={open}
|
||||||
@@ -18,7 +23,7 @@ function FilterColumn({ columns, user_id, page_name, table_name }) {
|
|||||||
page_name={page_name}
|
page_name={page_name}
|
||||||
table_name={table_name}
|
table_name={table_name}
|
||||||
/>
|
/>
|
||||||
)}
|
</Drawer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,8 +122,8 @@ const MapInteraction = ({ setValue, startLat, startLng }) => {
|
|||||||
zIndex: 1000,
|
zIndex: 1000,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button variant="contained" onClick={handleUnlockMarker}>
|
<Button variant="contained" color="warning" onClick={handleUnlockMarker}>
|
||||||
ویرایش
|
تغییر مکان
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
|||||||
{ lat: startLat, lng: startLng },
|
{ lat: startLat, lng: startLng },
|
||||||
{ lat: endLat, lng: endLng },
|
{ lat: endLat, lng: endLng },
|
||||||
],
|
],
|
||||||
{ paddingTopLeft: [16, 16], paddingBottomRight: [16, 130] }
|
{ paddingTopLeft: [64, 64], paddingBottomRight: [64, 64] }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, [startLat, map, endLng]);
|
}, [startLat, map, endLng]);
|
||||||
@@ -142,7 +142,7 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
|||||||
zIndex: 1000,
|
zIndex: 1000,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button variant={"contained"} onClick={handleUnlockStart}>
|
<Button variant={"contained"} color="warning" onClick={handleUnlockStart}>
|
||||||
ویرایش نقطه شروع
|
ویرایش نقطه شروع
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -184,8 +184,8 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
|||||||
setIsEndLocked(true);
|
setIsEndLocked(true);
|
||||||
setEndIconColor("#D13131");
|
setEndIconColor("#D13131");
|
||||||
map.fitBounds([startPosition, map.getCenter()], {
|
map.fitBounds([startPosition, map.getCenter()], {
|
||||||
paddingTopLeft: [16, 16],
|
paddingTopLeft: [64, 64],
|
||||||
paddingBottomRight: [16, 16],
|
paddingBottomRight: [64, 64],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -202,7 +202,7 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
|||||||
zIndex: 1000,
|
zIndex: 1000,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button variant={"contained"} onClick={handleUnlockEnd}>
|
<Button variant={"contained"} color="warning" onClick={handleUnlockEnd}>
|
||||||
ویرایش نقاط
|
ویرایش نقاط
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const ChangePass = ({ open, setOpen }) => {
|
|||||||
<LoadingButton
|
<LoadingButton
|
||||||
loading={loading}
|
loading={loading}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="error"
|
color="secondary"
|
||||||
size="large"
|
size="large"
|
||||||
onClick={handleCloseForm}
|
onClick={handleCloseForm}
|
||||||
>
|
>
|
||||||
@@ -38,7 +38,7 @@ const ChangePass = ({ open, setOpen }) => {
|
|||||||
loadingPosition="end"
|
loadingPosition="end"
|
||||||
endIcon={<SaveIcon />}
|
endIcon={<SaveIcon />}
|
||||||
>
|
>
|
||||||
ثبت
|
تغییر
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const Update = ({ open, setOpen }) => {
|
|||||||
<Form handleCloseForm={handleCloseForm} setLoading={setLoading} />
|
<Form handleCloseForm={handleCloseForm} setLoading={setLoading} />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button autoFocus variant="outlined" color="error" size="large" onClick={handleCloseForm}>
|
<Button variant="outlined" color="secondary" size="large" onClick={handleCloseForm}>
|
||||||
بستن
|
بستن
|
||||||
</Button>
|
</Button>
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
@@ -35,7 +35,7 @@ const Update = ({ open, setOpen }) => {
|
|||||||
loadingPosition="end"
|
loadingPosition="end"
|
||||||
endIcon={<SaveIcon />}
|
endIcon={<SaveIcon />}
|
||||||
>
|
>
|
||||||
ثبت
|
ویرایش
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -11,34 +11,34 @@ const RahdarCode = ({ rahdarsCode, setRahdarsCode, error, multiple = true }) =>
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const requestServer = useRequest();
|
const requestServer = useRequest();
|
||||||
|
|
||||||
const fetchRahdarCodes = (inputValue, controller) => {
|
|
||||||
const debouncer = debounce((query) => {
|
|
||||||
if ((query || "").length < 3) {
|
|
||||||
setOptions([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setLoading(true);
|
|
||||||
requestServer(`${GET_RAHDARANS_LIST_SEARCH}?code=${query}`, "get", {
|
|
||||||
requestOptions: { signal: controller.signal },
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
const combinedArray = rahdarsCode
|
|
||||||
? [...rahdarsCode, ...response.data.data]
|
|
||||||
: [...response.data.data];
|
|
||||||
const uniqueArray = Array.from(new Map(combinedArray.map((item) => [item.id, item])).values());
|
|
||||||
setOptions(uniqueArray || []);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setOptions([]);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
debouncer(inputValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const fetchRahdarCodes = (inputValue, controller) => {
|
||||||
|
const debouncer = debounce((query) => {
|
||||||
|
if ((query || "").length < 3) {
|
||||||
|
setOptions([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setLoading(true);
|
||||||
|
requestServer(`${GET_RAHDARANS_LIST_SEARCH}?code=${query}`, "get", {
|
||||||
|
requestOptions: { signal: controller.signal },
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
const combinedArray = rahdarsCode
|
||||||
|
? [...rahdarsCode, ...response.data.data]
|
||||||
|
: [...response.data.data];
|
||||||
|
const uniqueArray = Array.from(new Map(combinedArray.map((item) => [item.id, item])).values());
|
||||||
|
setOptions(uniqueArray || []);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setOptions([]);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
debouncer(inputValue);
|
||||||
|
};
|
||||||
|
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
fetchRahdarCodes(inputValue, controller);
|
fetchRahdarCodes(inputValue, controller);
|
||||||
return () => controller.abort();
|
return () => controller.abort();
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
10
src/core/utils/formatSecondsToHHMMSS.js
Normal file
10
src/core/utils/formatSecondsToHHMMSS.js
Normal 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")}`;
|
||||||
|
};
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
const api = process.env.NEXT_PUBLIC_API_URL;
|
||||||
|
|
||||||
export const headerMenu = [
|
export const headerMenu = [
|
||||||
{
|
{
|
||||||
title: "تصادفات",
|
title: "تصادفات",
|
||||||
@@ -5,7 +7,7 @@ export const headerMenu = [
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
title: "تصادفات روزانه",
|
title: "تصادفات روزانه",
|
||||||
href: "https://rms.witel.ir/v2/daily_accidents/create",
|
href: api + "/v2/daily_accidents/create",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@@ -16,11 +18,11 @@ export const headerMenu = [
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
title: "گزارش محوری",
|
title: "گزارش محوری",
|
||||||
href: "https://rms.witel.ir/v2/axis_reports",
|
href: api + "/v2/axis_reports",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "هوش تجاری (BI)",
|
title: "هوش تجاری (BI)",
|
||||||
href: "https://rms.witel.ir/v2/axis_reports",
|
href: api + "/v2/axis_reports",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@@ -31,17 +33,17 @@ export const headerMenu = [
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
title: "پراکندگی بر روی نقشه راهدارخانه ها",
|
title: "پراکندگی بر روی نقشه راهدارخانه ها",
|
||||||
href: "https://rms.witel.ir/v2/map?type=rahdar",
|
href: api + "/v2/map?type=rahdar",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "راهدارخانه ها",
|
title: "راهدارخانه ها",
|
||||||
href: "https://rms.witel.ir/v2/rahdari_points",
|
href: api + "/v2/rahdari_points",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
title: "ممیزی ماشین آلات راهداری کشور",
|
title: "ممیزی ماشین آلات راهداری کشور",
|
||||||
href: "https://rms.witel.ir/cmms-audit",
|
href: api + "/cmms-audit",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@@ -52,7 +54,7 @@ export const headerMenu = [
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
title: "تحقیق و توسعه",
|
title: "تحقیق و توسعه",
|
||||||
href: "https://rms.witel.ir/RandD",
|
href: api + "/RandD",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "سامانه مدیریت یکپارچه زیرساخت های راه (PMS,BMS,SMS)",
|
title: "سامانه مدیریت یکپارچه زیرساخت های راه (PMS,BMS,SMS)",
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ export const pageMenu = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "roadItemManagmentReportItems",
|
id: "roadItemManagmentReportItems",
|
||||||
label: "تعداد و حجم فعالیت ها به تفکیک موارد مشاهده شده",
|
label: "تعداد و حجم فعالیت ها به تفکیک موارد اقدام شده",
|
||||||
type: "page",
|
type: "page",
|
||||||
route: "/dashboard/road-items/reports/sub-items-report",
|
route: "/dashboard/road-items/reports/sub-items-report",
|
||||||
permissions: [
|
permissions: [
|
||||||
|
|||||||
@@ -30,10 +30,12 @@ export const UPDATE_AZMAYESH_TYPE = api + "/api/v3/azmayesh_types/update";
|
|||||||
|
|
||||||
//road patrol
|
//road patrol
|
||||||
export const GET_ROAD_PATROL_OPERATOR_LIST = api + "/api/v3/road_patrols/operator_index";
|
export const GET_ROAD_PATROL_OPERATOR_LIST = api + "/api/v3/road_patrols/operator_index";
|
||||||
export const EXPORT_ROAD_PATROL_OPERATOR_LIST = "https://rms.witel.ir/v2/road_patrols/operator/cartable/report";
|
export const EXPORT_ROAD_PATROL_OPERATOR_LIST = api + "/v2/road_patrols/operator/cartable/report";
|
||||||
export const GET_ROAD_PATROL_SUPERVISOR_LIST = api + "/api/v3/road_patrols/supervisor_index";
|
export const GET_ROAD_PATROL_SUPERVISOR_LIST = api + "/api/v3/road_patrols/supervisor_index";
|
||||||
export const EXPORT_ROAD_PATROL_SUPERVISOR_LIST = "https://rms.witel.ir/v2/road_patrols/supervisor/cartable/report";
|
export const EXPORT_ROAD_PATROL_SUPERVISOR_LIST = api + "/v2/road_patrols/supervisor/cartable/report";
|
||||||
export const DELETE_ROAD_PATROL_SUPERVISOR = api + "/api/v3/road_patrols/delete";
|
export const DELETE_ROAD_PATROL_SUPERVISOR = api + "/api/v3/road_patrols/delete";
|
||||||
|
export const GET_ROAD_PATROL_OPERATOR_REPORT = api + "/v2/road_patrols/operator/report";
|
||||||
|
export const GET_ROAD_PATROL_SUPERVISOR_REPORT = api + "/v2/road_patrols/supervisor/report";
|
||||||
export const CREATE_PATROL = api + "/api/v3/road_patrols/store";
|
export const CREATE_PATROL = api + "/api/v3/road_patrols/store";
|
||||||
export const GET_FMS_DATA = api + "/api/v3/fms_vehicle/get_activity";
|
export const GET_FMS_DATA = api + "/api/v3/fms_vehicle/get_activity";
|
||||||
export const GET_OTP_TOKEN = api + "/v2/get_otp_token";
|
export const GET_OTP_TOKEN = api + "/v2/get_otp_token";
|
||||||
@@ -45,9 +47,9 @@ export const GET_ROAD_ITEMS_SUPERVISOR_LIST = api + "/api/v3/road_items/supervis
|
|||||||
export const EXPORT_ROAD_ITEMS_SUPERVISOR_LIST = api + "/api/v3/road_items/supervisor_report";
|
export const EXPORT_ROAD_ITEMS_SUPERVISOR_LIST = api + "/api/v3/road_items/supervisor_report";
|
||||||
export const GET_ROAD_ITEMS_OPERATOR_LIST = api + "/api/v3/road_items/operator_index";
|
export const GET_ROAD_ITEMS_OPERATOR_LIST = api + "/api/v3/road_items/operator_index";
|
||||||
export const EXPORT_ROAD_ITEMS_OPERATOR_LIST = api + "/api/v3/road_items/operator_report";
|
export const EXPORT_ROAD_ITEMS_OPERATOR_LIST = api + "/api/v3/road_items/operator_report";
|
||||||
export const GET_ROAD_ITEMS_ITEM = "https://rms.witel.ir/v2/items";
|
export const GET_ROAD_ITEMS_ITEM = api + "/v2/items";
|
||||||
export const GET_ROAD_ITEMS_SUB_ITEM = "https://rms.witel.ir/v2/sub_items";
|
export const GET_ROAD_ITEMS_SUB_ITEM = api + "/v2/sub_items";
|
||||||
export const GET_EDARAT_LISTS = "https://rms.witel.ir/public/contents/edarate_shahri_by_province";
|
export const GET_EDARAT_LISTS = api + "/public/contents/edarate_shahri_by_province";
|
||||||
export const CREATE_ROAD_ITEMS = api + "/api/v3/road_items/store";
|
export const CREATE_ROAD_ITEMS = api + "/api/v3/road_items/store";
|
||||||
export const UPDATE_ROAD_ITEMS = api + "/api/v3/road_items/update";
|
export const UPDATE_ROAD_ITEMS = api + "/api/v3/road_items/update";
|
||||||
export const VERIFY_BY_SUPERVISOR = api + "/api/v3/road_items/verify_by_supervisor";
|
export const VERIFY_BY_SUPERVISOR = api + "/api/v3/road_items/verify_by_supervisor";
|
||||||
|
|||||||
Reference in New Issue
Block a user