Merge branch 'develop' into 'feature/gasht_submit'
# Conflicts: # src/components/dashboard/roadItems/operator/Actions/Create/Forms/GetItemInfo.jsx
This commit is contained in:
@@ -147,7 +147,7 @@ const CreateFormContent = ({ setOpen, onSubmit, is_gasht = false }) => {
|
||||
mode: "onBlur",
|
||||
context: { subItemsList, is_gasht },
|
||||
});
|
||||
const onSubmitBase = (data) => {
|
||||
const onSubmitBase = async (data) => {
|
||||
let result = { ...data };
|
||||
|
||||
if (result.before_image === null) {
|
||||
@@ -184,7 +184,7 @@ const CreateFormContent = ({ setOpen, onSubmit, is_gasht = false }) => {
|
||||
});
|
||||
delete result.cmms_machines;
|
||||
|
||||
onSubmit({
|
||||
await onSubmit({
|
||||
result,
|
||||
data: {
|
||||
...data,
|
||||
@@ -205,7 +205,8 @@ const CreateFormContent = ({ setOpen, onSubmit, is_gasht = false }) => {
|
||||
variant={`${isMobile ? "scrollable" : "fullWidth"}`}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-around",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
backgroundColor: "#efefef",
|
||||
}}
|
||||
@@ -253,7 +254,7 @@ const CreateFormContent = ({ setOpen, onSubmit, is_gasht = false }) => {
|
||||
<Button
|
||||
onClick={handlePrev}
|
||||
variant="outlined"
|
||||
color="error"
|
||||
color="secondary"
|
||||
size="large"
|
||||
startIcon={tabState === 0 ? <ExitToAppIcon /> : <KeyboardDoubleArrowRightIcon />}
|
||||
>
|
||||
|
||||
@@ -4,13 +4,7 @@ import GashtCreateContent from "./GashtCreateContent";
|
||||
const GashtCreate = ({ open, setOpen, mutate, rowId }) => {
|
||||
return (
|
||||
<Dialog open={open} fullWidth maxWidth="md">
|
||||
<DialogTitle>جستجوی مورد مشاهده شده در گشت راهداری و ترابری</DialogTitle>
|
||||
<GashtCreateContent mutate={mutate} setOpen={setOpen} />
|
||||
<DialogActions>
|
||||
<Button onClick={() => setOpen(false)} variant="outlined" color="primary" autoFocus>
|
||||
بستن
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,28 +1,46 @@
|
||||
import { Box, Button, DialogActions, DialogContent, Grid, Stack, Tab, Tabs } from "@mui/material";
|
||||
import { Box, Button, DialogActions, DialogContent, Tab, Tabs } from "@mui/material";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import * as yup from "yup";
|
||||
import MuiDatePicker from "@/core/components/MuiDatePicker";
|
||||
import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
|
||||
import FileCopyIcon from "@mui/icons-material/FileCopy";
|
||||
import InfoIcon from "@mui/icons-material/Info";
|
||||
import GetItemsForm from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/GetItemsForm";
|
||||
import GetSubItemsForm from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/GetSubItemsForm";
|
||||
import GetItemInfo from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/GetItemInfo";
|
||||
import ExitToAppIcon from "@mui/icons-material/ExitToApp";
|
||||
import KeyboardDoubleArrowRightIcon from "@mui/icons-material/KeyboardDoubleArrowRight";
|
||||
import BeenhereIcon from "@mui/icons-material/Beenhere";
|
||||
import StyledForm from "@/core/components/StyledForm";
|
||||
import React from "react";
|
||||
import { TabPanel } from "@mui/lab";
|
||||
import React, { useState } from "react";
|
||||
import SearchItemInfo from "./SearchItemInfo";
|
||||
import moment from "jalali-moment";
|
||||
import GetItemInfo from "./RowActions/GetItemInfo";
|
||||
|
||||
function TabPanel(props) {
|
||||
const { children, value, index } = props;
|
||||
return (
|
||||
<div role="tabpanel" hidden={value !== index}>
|
||||
{value === index && <Box>{children}</Box>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const defaultValues = {
|
||||
start_date: moment(new Date()).format("YYYY-MM-DD"),
|
||||
end_date: moment(new Date()).format("YYYY-MM-DD"),
|
||||
item_id: "",
|
||||
road_patrol_id: "",
|
||||
};
|
||||
|
||||
const defaultFilter = [
|
||||
{ value: `${defaultValues.item_id}`, datatype: "text", id: "item_id", fn: "equals" },
|
||||
{ value: `${defaultValues.road_patrol_id}`, datatype: "text", id: "road_patrol_id", fn: "equals" },
|
||||
{ value: `${defaultValues.start_date}`, datatype: "date", id: "roadPatrol.start_time", fn: "equals" },
|
||||
{ value: `${defaultValues.end_date}`, datatype: "date", id: "roadPatrol.end_time", fn: "equals" },
|
||||
];
|
||||
|
||||
const GashtCreateContent = ({ mutate, setOpen }) => {
|
||||
const defaultValues = {
|
||||
start_date: null,
|
||||
end_date: null,
|
||||
item_id: null,
|
||||
road_patrol_id: null,
|
||||
};
|
||||
const [tabState, setTabState] = useState(0);
|
||||
const [itemInfo, setItemInfo] = useState(null);
|
||||
const [submitCompleteForm, setSubmitCompleteForm] = useState(false);
|
||||
const [specialFilter, setSpecialFilter] = useState(defaultFilter);
|
||||
|
||||
const validationSchema = yup
|
||||
.object()
|
||||
@@ -36,6 +54,21 @@ const GashtCreateContent = ({ mutate, setOpen }) => {
|
||||
return (!!values.start_date && !!values.end_date) || !!values.item_id || !!values.road_patrol_id;
|
||||
});
|
||||
|
||||
const handleChangeTab = (event, newValue) => {
|
||||
setTabState(newValue);
|
||||
};
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const handlePrev = () => {
|
||||
if (tabState === 0) {
|
||||
handleClose();
|
||||
} else {
|
||||
setTabState(tabState - 1);
|
||||
}
|
||||
};
|
||||
|
||||
const {
|
||||
control,
|
||||
getValues,
|
||||
@@ -49,41 +82,53 @@ const GashtCreateContent = ({ mutate, setOpen }) => {
|
||||
resolver: yupResolver(validationSchema),
|
||||
mode: "onBlur",
|
||||
});
|
||||
const onSearchSubmit = async (data) => {
|
||||
setSpecialFilter([
|
||||
{ value: `${data.item_id}`, datatype: "text", id: "item_id", fn: "equals" },
|
||||
{ value: `${data.road_patrol_id}`, datatype: "text", id: "road_patrol_id", fn: "equals" },
|
||||
{ value: `${data.start_date}`, datatype: "date", id: "roadPatrol.start_time", fn: "equals" },
|
||||
{ value: `${data.end_date}`, datatype: "date", id: "roadPatrol.end_time", fn: "equals" },
|
||||
]);
|
||||
};
|
||||
return (
|
||||
<StyledForm onSubmit={handleSubmit(onSubmit)}>
|
||||
<>
|
||||
<Tabs
|
||||
allowScrollButtonsMobile
|
||||
value={tabState}
|
||||
onChange={handleChangeTab}
|
||||
variant={`${isMobile ? "scrollable" : "fullWidth"}`}
|
||||
variant="fullWidth"
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-around",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
backgroundColor: "#efefef",
|
||||
}}
|
||||
>
|
||||
<Tab icon={<InsertDriveFileIcon />} label="انتخاب آیتم" />
|
||||
<Tab disabled={tabState === 0} icon={<FileCopyIcon />} label="انتخاب موضوع مشاهده شده" />
|
||||
<Tab icon={<InsertDriveFileIcon />} label="انتخاب مورد مشاهده شده" />
|
||||
<Tab disabled={tabState === 0} icon={<FileCopyIcon />} label="اطلاعات مورد مشاهده شده" />
|
||||
</Tabs>
|
||||
<DialogContent dividers sx={{ overflowY: "auto", maxHeight: "70vh" }}>
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<TabPanel value={tabState} index={0}>
|
||||
<GetItemsForm
|
||||
setItemsList={setItemsList}
|
||||
setValue={setValue}
|
||||
watch={watch}
|
||||
tabState={tabState}
|
||||
setTabState={setTabState}
|
||||
/>
|
||||
<StyledForm onSubmit={handleSubmit(onSearchSubmit)}>
|
||||
<SearchItemInfo
|
||||
isSubmitting={isSubmitting}
|
||||
specialFilter={specialFilter}
|
||||
watch={watch}
|
||||
errors={errors}
|
||||
setValue={setValue}
|
||||
register={register}
|
||||
setTabState={setTabState}
|
||||
setItemInfo={setItemInfo}
|
||||
/>
|
||||
</StyledForm>
|
||||
</TabPanel>
|
||||
<TabPanel value={tabState} index={1}>
|
||||
<GetSubItemsForm
|
||||
setSubItemsList={setSubItemsList}
|
||||
setValue={setValue}
|
||||
watch={watch}
|
||||
tabState={tabState}
|
||||
setTabState={setTabState}
|
||||
<GetItemInfo
|
||||
mutate={mutate}
|
||||
setOpen={setOpen}
|
||||
setSubmitCompleteForm={setSubmitCompleteForm}
|
||||
itemInfo={itemInfo}
|
||||
/>
|
||||
</TabPanel>
|
||||
</Box>
|
||||
@@ -98,19 +143,21 @@ const GashtCreateContent = ({ mutate, setOpen }) => {
|
||||
>
|
||||
{tabState === 0 ? "بستن" : "مرحله قبل"}
|
||||
</Button>
|
||||
{tabState === 2 && (
|
||||
{tabState === 1 && (
|
||||
<Button
|
||||
variant="contained"
|
||||
size="large"
|
||||
disabled={isSubmitting}
|
||||
form={"CompleteItemForm"}
|
||||
type={"submit"}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size="large"
|
||||
disabled={submitCompleteForm}
|
||||
endIcon={<BeenhereIcon />}
|
||||
>
|
||||
{isSubmitting ? "در حال ثبت فعالیت" : "ثبت فعالیت"}
|
||||
{submitCompleteForm ? "درحال ثبت فعالیت..." : "ثبت فعالیت"}
|
||||
</Button>
|
||||
)}
|
||||
</DialogActions>
|
||||
</StyledForm>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default GashtCreateContent;
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
"use client";
|
||||
import { Box, Button, DialogActions, DialogContent, Stack } from "@mui/material";
|
||||
import React from "react";
|
||||
import dynamic from "next/dynamic";
|
||||
import MapLoading from "@/core/components/MapLayer/Loading";
|
||||
import ShowLocationMarker from "@/core/components/ShowLocationMarker";
|
||||
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
|
||||
loading: () => <MapLoading />,
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const LocationFormContent = ({ setOpenLocationDialog, start_lat, start_lng }) => {
|
||||
return (
|
||||
<>
|
||||
<DialogContent>
|
||||
<Box sx={{ width: "400px", height: "400px" }}>
|
||||
<MapLayer>
|
||||
<ShowLocationMarker start_lat={start_lat} start_lng={start_lng} />
|
||||
</MapLayer>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ justifyContent: "center", paddingBottom: 2, width: "100%" }}>
|
||||
<Button onClick={() => setOpenLocationDialog(false)} variant="contained" color="error">
|
||||
بستن
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LocationFormContent;
|
||||
@@ -0,0 +1,36 @@
|
||||
import React, { useState } from "react";
|
||||
import { Tooltip, IconButton, Dialog, DialogTitle } from "@mui/material";
|
||||
import ExploreIcon from "@mui/icons-material/Explore";
|
||||
import LocationFormContent from "./LocationFormContent";
|
||||
const LocationForm = ({ start_lat, start_lng }) => {
|
||||
const [openLocationDialog, setOpenLocationDialog] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="موقعیت">
|
||||
<IconButton color="primary" onClick={() => setOpenLocationDialog(true)}>
|
||||
<ExploreIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Dialog
|
||||
open={openLocationDialog}
|
||||
onClose={() => setOpenLocationDialog(false)}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
|
||||
},
|
||||
}}
|
||||
dir="rtl"
|
||||
maxWidth={"md"}
|
||||
>
|
||||
<DialogTitle>موقعیت</DialogTitle>
|
||||
<LocationFormContent
|
||||
start_lat={start_lat}
|
||||
start_lng={start_lng}
|
||||
setOpenLocationDialog={setOpenLocationDialog}
|
||||
/>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default LocationForm;
|
||||
@@ -0,0 +1,231 @@
|
||||
import { Button, DialogActions, Grid, Stack } from "@mui/material";
|
||||
import PreviousStatesInfo from "./PreviousStatesInfo";
|
||||
import NumberField from "@/core/components/NumberField";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import CarCode from "@/core/components/CarCode";
|
||||
import RahdarCode from "@/core/components/RahdarCode";
|
||||
import ImageUpload from "@/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/ImageUpload";
|
||||
import MuiDatePicker from "@/core/components/MuiDatePicker";
|
||||
import MuiTimePicker from "@/core/components/MuiTimePicker";
|
||||
import MapInfoTwoMarker from "@/core/components/MapInfoTwoMarker";
|
||||
import MapInfoOneMarker from "@/core/components/MapInfoOneMarker";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import StyledForm from "@/core/components/StyledForm";
|
||||
import { array, mixed, number, object, string } from "yup";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import BeenhereIcon from "@mui/icons-material/Beenhere";
|
||||
import React, { useEffect } from "react";
|
||||
import { CREATE_ROAD_ITEMS } from "@/core/utils/routes";
|
||||
|
||||
const CompleteItem = ({ subItem, itemInfo, setSubmitCompleteForm, mutate, setOpen }) => {
|
||||
const requestServer = useRequest({ notificationSuccess: true });
|
||||
|
||||
const defaultValues = {
|
||||
item_id: itemInfo?.item_id || null,
|
||||
sub_item_id: itemInfo?.sub_item_id || null,
|
||||
amount: "",
|
||||
activity_time: "",
|
||||
activity_date: "",
|
||||
before_image: null,
|
||||
after_image: null,
|
||||
cmms_machines: null,
|
||||
rahdaran_id: null,
|
||||
start_point: { lat: itemInfo?.start_lat || "", lng: itemInfo?.start_lon || "" },
|
||||
end_point: { lat: itemInfo?.end_lat || "", lng: itemInfo?.end_lon || "" },
|
||||
};
|
||||
|
||||
const validationSchema = object({
|
||||
item_id: number().required("نوع آیتم را مشخص کنید!"),
|
||||
sub_item_id: number().required("موضوع مشاهده شده را مشخص کنید!"),
|
||||
amount: string().required("وارد کردن مقدار الزامیست!"),
|
||||
cmms_machines: array().required("وارد کردن کد خودرو الزامیست!"),
|
||||
rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"), // بررسی حداقل یک آیتم,
|
||||
activity_time: string().required("لطفا زمان فعالیت را انتخاب کنید!"),
|
||||
activity_date: string().required("لطفاً تاریخ شروع فعالیت را انتخاب کنید!"),
|
||||
before_image: mixed()
|
||||
.nullable()
|
||||
.test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) {
|
||||
const { subItem } = this.options.context;
|
||||
const needsImage = subItem?.needs_image === 1;
|
||||
if (needsImage) {
|
||||
return !!value;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
after_image: mixed()
|
||||
.nullable()
|
||||
.test("after-image-required", "لطفا عکس بعد از اقدام را بارگذاری کنید!", function (value) {
|
||||
const { subItem } = this.options.context;
|
||||
const needsImage = subItem?.needs_image === 1;
|
||||
if (needsImage) {
|
||||
return !!value;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
start_point: mixed()
|
||||
.test("start-point-required", "لطفاً نقطه شروع را مشخص کنید!", function (value) {
|
||||
return !!value; // چک میکند که مقدار موجود است
|
||||
})
|
||||
.required("لطفاً نقطه شروع را مشخص کنید!"),
|
||||
end_point: mixed().test("end-point-required", "لطفاً نقطه پایان را مشخص کنید!", function (value) {
|
||||
const { subItem } = this.options.context;
|
||||
const needsEndPoint = subItem?.needs_end_point === 1;
|
||||
if (needsEndPoint) {
|
||||
return !!value; // چک میکند که مقدار موجود است
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
});
|
||||
|
||||
const {
|
||||
control,
|
||||
watch,
|
||||
getValues,
|
||||
register,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
resetField,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm({
|
||||
defaultValues,
|
||||
resolver: yupResolver(validationSchema),
|
||||
mode: "onBlur",
|
||||
context: { subItem },
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setSubmitCompleteForm(isSubmitting);
|
||||
}, [isSubmitting]);
|
||||
const onSubmit = async (data) => {
|
||||
let endPoint;
|
||||
let startPoint = `${data.start_point.lat},${data.start_point.lng}`;
|
||||
if (subItem.needs_end_point === 1) {
|
||||
endPoint = `${data.end_point.lat},${data.end_point.lng}`;
|
||||
}
|
||||
const formData = new FormData();
|
||||
data.after_image !== null && formData.append("after_image", data.after_image);
|
||||
data.before_image !== null && formData.append("before_image", data.before_image);
|
||||
subItem.needs_end_point === 1 && formData.append("end_point", endPoint);
|
||||
formData.append("start_point", startPoint);
|
||||
formData.append("activity_time", data.activity_time);
|
||||
formData.append("activity_date", data.activity_date);
|
||||
formData.append("amount", data.amount);
|
||||
formData.append("item_id", data.item_id);
|
||||
formData.append("sub_item_id", data.sub_item_id);
|
||||
data.cmms_machines.forEach((machine, index) => formData.append(`machines_id[${index}]`, machine.id));
|
||||
data.rahdaran_id.forEach((rahdar, index) => formData.append(`rahdaran_id[${index}]`, rahdar.id));
|
||||
|
||||
await requestServer(CREATE_ROAD_ITEMS, "post", {
|
||||
data: formData,
|
||||
})
|
||||
.then((response) => {
|
||||
mutate();
|
||||
setOpen(false);
|
||||
})
|
||||
.catch((error) => {});
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledForm onSubmit={handleSubmit(onSubmit)} id={"CompleteItemForm"}>
|
||||
<Stack spacing={2}>
|
||||
<Stack>
|
||||
<PreviousStatesInfo itemInfo={itemInfo} />
|
||||
</Stack>
|
||||
<Stack>
|
||||
<NumberField
|
||||
{...register("amount")}
|
||||
label={`مقدار (${subItem.unit})`}
|
||||
error={!!errors.amount}
|
||||
value={watch("amount")}
|
||||
type="text"
|
||||
size={"small"}
|
||||
unit={itemInfo.unit}
|
||||
inputProps={{
|
||||
inputMode: "number",
|
||||
min: 0,
|
||||
pattern: "[0-9]*",
|
||||
}}
|
||||
onChange={(event) => {
|
||||
if (!isNaN(event.target.value)) {
|
||||
setValue("amount", event.target.value);
|
||||
} else {
|
||||
setValue("amount", watch("amount"));
|
||||
}
|
||||
}}
|
||||
helperText={errors.amount ? errors.amount.message : null}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Controller
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<CarCode
|
||||
carCode={field.value || []}
|
||||
setCarCode={(value) => field.onChange(value || [])}
|
||||
error={error}
|
||||
multiple={true}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
name={"cmms_machines"}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Controller
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<RahdarCode
|
||||
rahdarsCode={field.value || []}
|
||||
setRahdarsCode={(value) => field.onChange(value || [])}
|
||||
error={error}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
name={"rahdaran_id"}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
{subItem.needs_image ? (
|
||||
<ImageUpload setValue={setValue} control={control} errors={errors} getValues={getValues} />
|
||||
) : null}
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<MuiDatePicker
|
||||
name="activity_date"
|
||||
error={errors.activity_date ? errors.activity_date.message : null}
|
||||
value={watch("activity_date")}
|
||||
placeholder={"تاریخ شروع فعالیت"}
|
||||
setFieldValue={setValue}
|
||||
helperText={errors.activity_date ? errors.activity_date.message : null}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<MuiTimePicker
|
||||
value={watch("activity_time")}
|
||||
name="activity_time"
|
||||
error={errors.activity_time ? errors.activity_time.message : null}
|
||||
placeholder={"زمان فعالیت"}
|
||||
setFieldValue={setValue}
|
||||
helperText={errors.activity_time ? errors.activity_time.message : null}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
<Stack>
|
||||
{subItem?.needs_end_point === 1 ? (
|
||||
<MapInfoTwoMarker setValue={setValue} errors={errors} />
|
||||
) : (
|
||||
<MapInfoOneMarker setValue={setValue} errors={errors} />
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</StyledForm>
|
||||
);
|
||||
};
|
||||
export default CompleteItem;
|
||||
@@ -0,0 +1,28 @@
|
||||
import { LinearProgress, Typography } from "@mui/material";
|
||||
import useRoadItemGetISubtems from "@/lib/hooks/useRoadItemGetISubtems";
|
||||
import CompleteItem from "./CompleteItem";
|
||||
|
||||
const GetItemInfo = ({ itemInfo, setSubmitCompleteForm, mutate, setOpen }) => {
|
||||
const { subItemsList, loadingSubItemsList, errorSubItemsList } = useRoadItemGetISubtems(itemInfo?.item_id);
|
||||
const subItem = subItemsList.find((SubItem) => SubItem.sub_item === itemInfo?.sub_item_id);
|
||||
return (
|
||||
<>
|
||||
{loadingSubItemsList ? (
|
||||
<LinearProgress />
|
||||
) : errorSubItemsList ? (
|
||||
<Typography color={"error.main"} textAlign={"center"}>
|
||||
خطا در دریافت اطلاعات!!!
|
||||
</Typography>
|
||||
) : (
|
||||
<CompleteItem
|
||||
setOpen={setOpen}
|
||||
mutate={mutate}
|
||||
setSubmitCompleteForm={setSubmitCompleteForm}
|
||||
subItem={subItem}
|
||||
itemInfo={itemInfo}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default GetItemInfo;
|
||||
@@ -0,0 +1,131 @@
|
||||
import { FormControl, FormHelperText, Grid } from "@mui/material";
|
||||
import UploadSystem from "@/core/components/UploadSystem";
|
||||
import { Controller } from "react-hook-form";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
const ImageUpload = ({ control, setValue, errors, getValues, beforeImage = null, afterImage = null }) => {
|
||||
const [beforeImg, setBeforeImg] = useState(beforeImage ? beforeImage : null);
|
||||
const [beforeFileType, setBeforeFileType] = useState(beforeImage ? "image/" : null);
|
||||
const [beforeFileName, setBeforeFileName] = useState(null);
|
||||
const [showBeforeImage, setShowBeforeImage] = useState(!beforeImage);
|
||||
|
||||
const [afterImg, setAfterImg] = useState(afterImage ? afterImage : null);
|
||||
const [afterFileType, setAfterFileType] = useState(afterImage ? "image/" : null);
|
||||
const [afterFileName, setAfterFileName] = useState(null);
|
||||
const [showAfterImage, setShowAfterImage] = useState(!afterImage);
|
||||
|
||||
useEffect(() => {
|
||||
if (getValues("before_image")) {
|
||||
setShowBeforeImage(false);
|
||||
setBeforeImg(getValues("before_image"));
|
||||
setBeforeFileType("image/");
|
||||
}
|
||||
if (getValues("after_image")) {
|
||||
setShowAfterImage(false);
|
||||
setAfterImg(getValues("after_image"));
|
||||
setAfterFileType("image/");
|
||||
}
|
||||
}, [getValues]);
|
||||
|
||||
const handleBeforeFileChange = (event) => {
|
||||
const uploadedFile = event.target?.files?.[0];
|
||||
if (uploadedFile) {
|
||||
const fileType = event.target?.files?.[0].type;
|
||||
const fileName = event.target?.files?.[0].name;
|
||||
setBeforeImg(URL.createObjectURL(uploadedFile));
|
||||
setBeforeFileType(fileType);
|
||||
setBeforeFileName(fileName);
|
||||
setValue("before_image", uploadedFile);
|
||||
setShowBeforeImage(false);
|
||||
}
|
||||
};
|
||||
const handleAfterFileChange = (event) => {
|
||||
const uploadedFile = event.target?.files?.[0];
|
||||
if (uploadedFile) {
|
||||
const fileType = event.target?.files?.[0].type;
|
||||
const fileName = event.target?.files?.[0].name;
|
||||
setAfterImg(URL.createObjectURL(uploadedFile));
|
||||
setAfterFileType(fileType);
|
||||
setAfterFileName(fileName);
|
||||
setValue("after_image", uploadedFile);
|
||||
setShowAfterImage(false);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Controller
|
||||
name="before_image"
|
||||
control={control}
|
||||
render={({ field: { value, onChange } }) => {
|
||||
return (
|
||||
<FormControl
|
||||
error={errors.before_image}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<FormHelperText sx={{ fontSize: "large" }} id="before_image">
|
||||
عکس قبل از اقدام
|
||||
</FormHelperText>
|
||||
<UploadSystem
|
||||
selectedImage={beforeImg}
|
||||
handleUploadChange={handleBeforeFileChange}
|
||||
fileType={beforeFileType}
|
||||
fileName={beforeFileName}
|
||||
setSelectedImage={setBeforeImg}
|
||||
imageSize={[250, 150]}
|
||||
setShowAddIcon={setShowBeforeImage}
|
||||
showAddIcon={showBeforeImage}
|
||||
/>
|
||||
<FormHelperText id="before_image">
|
||||
{errors.before_image ? errors.before_image.message : null}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Controller
|
||||
name="after_image"
|
||||
control={control}
|
||||
render={({ field: { value, onChange } }) => {
|
||||
return (
|
||||
<FormControl
|
||||
error={errors.before_image}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<FormHelperText sx={{ fontSize: "large" }} id="before_image">
|
||||
عکس بعد از اقدام
|
||||
</FormHelperText>
|
||||
<UploadSystem
|
||||
selectedImage={afterImg}
|
||||
handleUploadChange={handleAfterFileChange}
|
||||
fileType={afterFileType}
|
||||
fileName={afterFileName}
|
||||
setSelectedImage={setAfterImg}
|
||||
imageSize={[250, 150]}
|
||||
setShowAddIcon={setShowAfterImage}
|
||||
showAddIcon={showAfterImage}
|
||||
/>
|
||||
<FormHelperText id="after_image">
|
||||
{errors.after_image ? errors.after_image.message : null}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
export default ImageUpload;
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Box, Chip, Divider, Grid, Typography } from "@mui/material";
|
||||
import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
|
||||
import FileCopyIcon from "@mui/icons-material/FileCopy";
|
||||
|
||||
const PreviousStatesInfo = ({ itemInfo }) => {
|
||||
return (
|
||||
<Grid container spacing={2} sx={{ alignItems: "center", justifyContent: "space-around" }}>
|
||||
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Chip
|
||||
icon={<InsertDriveFileIcon />}
|
||||
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" }}>
|
||||
{itemInfo.item_name || "هیچ آیتمی انتخاب نشده است"}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={12} sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Chip
|
||||
icon={<FileCopyIcon />}
|
||||
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" }}>
|
||||
{itemInfo?.sub_item_name || "هیچ موضوعی انتخاب نشده است"}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
export default PreviousStatesInfo;
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import { Tooltip, IconButton } from "@mui/material";
|
||||
import UndoIcon from "@mui/icons-material/Undo";
|
||||
const SubItemForm = ({ row, setTabState, setItemInfo }) => {
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="انتخاب این مورد">
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
setTabState(1);
|
||||
setItemInfo(row.original);
|
||||
}}
|
||||
>
|
||||
<UndoIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default SubItemForm;
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Box } from "@mui/material";
|
||||
import SubItemForm from "./SubItemForm";
|
||||
|
||||
const RowActions = ({ row, mutate, setTabState, setItemInfo }) => {
|
||||
return (
|
||||
<Box sx={{ display: "flex", gap: 1 }}>
|
||||
<SubItemForm row={row} setTabState={setTabState} setItemInfo={setItemInfo} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
export default RowActions;
|
||||
@@ -0,0 +1,42 @@
|
||||
import { LinearProgress, Typography } from "@mui/material";
|
||||
import useRoadItemGetItems from "@/lib/hooks/useRoadItemGetItems";
|
||||
import React from "react";
|
||||
import SearchItems from "./SearchItems";
|
||||
import TableInfo from "./TableInfo";
|
||||
|
||||
const SearchItemInfo = ({
|
||||
watch,
|
||||
errors,
|
||||
setValue,
|
||||
register,
|
||||
specialFilter,
|
||||
setTabState,
|
||||
setItemInfo,
|
||||
isSubmitting,
|
||||
}) => {
|
||||
const { itemsList, loadingItemsList, errorItemsList } = useRoadItemGetItems();
|
||||
return (
|
||||
<>
|
||||
{loadingItemsList ? (
|
||||
<LinearProgress />
|
||||
) : errorItemsList ? (
|
||||
<Typography textAlign={"center"} color={"error.main"}>
|
||||
خطا در دریافت اطلاعات!!!
|
||||
</Typography>
|
||||
) : (
|
||||
<>
|
||||
<SearchItems
|
||||
isSubmitting={isSubmitting}
|
||||
register={register}
|
||||
setValue={setValue}
|
||||
errors={errors}
|
||||
watch={watch}
|
||||
itemsList={itemsList}
|
||||
/>
|
||||
<TableInfo specialFilter={specialFilter} setTabState={setTabState} setItemInfo={setItemInfo} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default SearchItemInfo;
|
||||
@@ -0,0 +1,96 @@
|
||||
import { Button, FormControl, FormHelperText, InputLabel, MenuItem, Select, Stack, TextField } from "@mui/material";
|
||||
import MuiDatePicker from "@/core/components/MuiDatePicker";
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
import React from "react";
|
||||
|
||||
const SearchItems = ({ setValue, itemsList, watch, errors, register, isSubmitting }) => {
|
||||
const disabledButton =
|
||||
(!!watch("start_date") && !!watch("end_date")) || !!watch("item_id") || !!watch("road_patrol_id");
|
||||
|
||||
return (
|
||||
<Stack display={"flex"} sx={{ pb: 2 }} direction={"row"} spacing={1} alignItems={"center"}>
|
||||
<Stack sx={{ flex: 2 }}>
|
||||
<MuiDatePicker
|
||||
name="start_date"
|
||||
error={errors.start_date ? errors.start_date.message : null}
|
||||
value={watch("start_date")}
|
||||
placeholder={"از تاریخ"}
|
||||
setFieldValue={setValue}
|
||||
helperText={errors.start_date ? errors.start_date.message : null}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack sx={{ flex: 2 }}>
|
||||
<MuiDatePicker
|
||||
name="end_date"
|
||||
minDate={watch("start_date")}
|
||||
error={errors.end_date ? errors.end_date.message : null}
|
||||
value={watch("end_date")}
|
||||
placeholder={"تا تاریخ"}
|
||||
setFieldValue={setValue}
|
||||
helperText={errors.end_date ? errors.end_date.message : null}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack sx={{ flex: 1.5 }}>
|
||||
<FormControl error={!!errors.item_id} size="small" fullWidth>
|
||||
<InputLabel id="demo-error-label">آیتم فعالیت</InputLabel>
|
||||
<Select
|
||||
labelId="demo-error-label"
|
||||
id="item_id"
|
||||
name="item_id"
|
||||
value={watch("item_id") || ""}
|
||||
label="آیتم فعالیت"
|
||||
onChange={(event) => setValue("item_id", event.target.value)}
|
||||
>
|
||||
<MenuItem value={""}>حذف</MenuItem>
|
||||
{itemsList.map((item) => (
|
||||
<MenuItem key={item.id} value={item.id}>
|
||||
{item.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{/*{errors.item_id ? (*/}
|
||||
{/* <FormHelperText>*/}
|
||||
{/* errors.item_id.message*/}
|
||||
{/* </FormHelperText>*/}
|
||||
{/*) : null}*/}
|
||||
</FormControl>
|
||||
</Stack>
|
||||
<Stack sx={{ flex: 1 }}>
|
||||
<TextField
|
||||
{...register("road_patrol_id")}
|
||||
label="کد یکتا گشت"
|
||||
error={!!errors.road_patrol_id}
|
||||
value={watch("road_patrol_id")}
|
||||
type="tel"
|
||||
size={"small"}
|
||||
inputProps={{
|
||||
inputMode: "number",
|
||||
min: 0,
|
||||
pattern: "[0-9]*",
|
||||
}}
|
||||
onChange={(event) => {
|
||||
if (!isNaN(event.target.value)) {
|
||||
setValue("road_patrol_id", event.target.value);
|
||||
} else {
|
||||
setValue("road_patrol_id", watch("road_patrol_id"));
|
||||
}
|
||||
}}
|
||||
helperText={errors.road_patrol_id ? errors.road_patrol_id.message : null}
|
||||
variant="outlined"
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="medium"
|
||||
type={"submit"}
|
||||
disabled={!disabledButton || isSubmitting}
|
||||
endIcon={<SearchIcon />}
|
||||
>
|
||||
{isSubmitting ? "درحال دریافت اطلاعات" : "جستجو"}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
export default SearchItems;
|
||||
@@ -0,0 +1,115 @@
|
||||
import { useMemo } from "react";
|
||||
import { Box, Stack } from "@mui/material";
|
||||
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
|
||||
import RowActions from "./RowActions";
|
||||
import { GET_OBSERVED_GASHT_LIST } from "@/core/utils/routes";
|
||||
import LocationForm from "./LocationForm";
|
||||
|
||||
const TableInfo = ({ specialFilter, setTabState, setItemInfo }) => {
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "road_patrol_id",
|
||||
header: "کد یکتا گشت",
|
||||
id: "road_patrol_id",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 50,
|
||||
},
|
||||
{
|
||||
accessorKey: "priority_fa",
|
||||
header: "اولویت",
|
||||
id: "priority_fa",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 80,
|
||||
},
|
||||
{
|
||||
accessorKey: "local_name",
|
||||
header: "نام محلی",
|
||||
id: "local_name",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "item_name",
|
||||
header: "نام ایتم",
|
||||
id: "item_name",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "sub_item_name",
|
||||
header: "موضوع مشاهده شده",
|
||||
id: "sub_item_name",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "location",
|
||||
header: "موقعیت", // Location
|
||||
id: "location",
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
datatype: "array",
|
||||
grow: false,
|
||||
size: 50,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
py: 0,
|
||||
"&:first-of-type": {
|
||||
borderLeft: "unset",
|
||||
},
|
||||
},
|
||||
},
|
||||
Cell: ({ renderedCellValue, row }) => {
|
||||
return (
|
||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||
<LocationForm start_lat={row.original.start_lat} start_lng={row.original.start_lon} />
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
|
||||
<DataTableWithAuth
|
||||
table_title={"لیست موارد مشاهده شده"}
|
||||
columns={columns}
|
||||
specialFilter={specialFilter}
|
||||
table_url={GET_OBSERVED_GASHT_LIST}
|
||||
page_name={"operator"}
|
||||
table_name={"Observed_Gasht_List"}
|
||||
enableRowActions
|
||||
positionActionsColumn={"last"}
|
||||
RowActions={(props) => (
|
||||
<RowActions {...props} setTabState={setTabState} setItemInfo={setItemInfo} />
|
||||
)}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default TableInfo;
|
||||
@@ -17,7 +17,11 @@ const ObservedGashtCreate = ({ mutate }) => {
|
||||
return (
|
||||
<>
|
||||
{isMobile ? (
|
||||
<IconButton aria-label="ثبت فعالیت" color="primary" onClick={handleOpen}>
|
||||
<IconButton
|
||||
aria-label="ثبت فعالیت برای موارد مشاهده شده در گشت راهداری"
|
||||
color="primary"
|
||||
onClick={handleOpen}
|
||||
>
|
||||
<AddRoadIcon sx={{ fontSize: "25px" }} />
|
||||
</IconButton>
|
||||
) : (
|
||||
|
||||
@@ -193,7 +193,7 @@ const OperatorList = () => {
|
||||
},
|
||||
{
|
||||
accessorKey: "cmms_machines",
|
||||
header: "کد خودرو", // Car ID
|
||||
header: "خودرو ها", // Car ID
|
||||
id: "cmmsMachines__machine_code",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
@@ -241,20 +241,17 @@ const OperatorList = () => {
|
||||
},
|
||||
},
|
||||
Cell: ({ renderedCellValue }) => {
|
||||
if (renderedCellValue) {
|
||||
return (
|
||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||
<RahdaranDialog rahdarLists={renderedCellValue} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
return <Typography variant="body2">بدون شخص</Typography>;
|
||||
return (
|
||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||
<RahdaranDialog rahdarLists={renderedCellValue} />
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ ثبت", // Register Date
|
||||
id: "created_at",
|
||||
accessorFn: (row) => moment(row.activity_date_time).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ فعالیت", // Start Date
|
||||
id: "activity_date_time",
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
@@ -263,9 +260,9 @@ const OperatorList = () => {
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => moment(row.activity_date_time).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ فعالیت", // Start Date
|
||||
id: "activity_date_time",
|
||||
accessorFn: (row) => moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ ثبت", // Register Date
|
||||
id: "created_at",
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
@@ -296,6 +293,7 @@ const OperatorList = () => {
|
||||
header: "توضیحات کارشناس", // Description
|
||||
id: "supervisor_description",
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
@@ -311,11 +309,14 @@ const OperatorList = () => {
|
||||
},
|
||||
},
|
||||
Cell: ({ renderedCellValue }) => {
|
||||
return (
|
||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||
<DescriptionForm description={renderedCellValue} />
|
||||
</Stack>
|
||||
);
|
||||
if (renderedCellValue) {
|
||||
return (
|
||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||
<DescriptionForm description={renderedCellValue} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
return <Typography variant="body2">بدون توضیحات</Typography>;
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -37,7 +37,7 @@ const DescriptionForm = ({ description }) => {
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Card sx={{ padding: 2, boxShadow: 3, borderRadius: 2 }}>
|
||||
<Card elevation={0}>
|
||||
<CardContent>
|
||||
<Typography variant="body2">{description || "هیچ توضیحی موجود نیست"} </Typography>
|
||||
</CardContent>
|
||||
|
||||
@@ -17,7 +17,7 @@ const EditFormContent = ({ setOpenEditDialog, onSubmit, defaultData }) => {
|
||||
rahdaran_id: defaultData?.rahdaran_id || null,
|
||||
};
|
||||
|
||||
const onSubmitBase = (data) => {
|
||||
const onSubmitBase = async (data) => {
|
||||
let result = { ...data };
|
||||
if (result.before_image === null) {
|
||||
delete result.before_image;
|
||||
@@ -53,7 +53,7 @@ const EditFormContent = ({ setOpenEditDialog, onSubmit, defaultData }) => {
|
||||
});
|
||||
delete result.cmms_machines;
|
||||
|
||||
onSubmit({
|
||||
await onSubmit({
|
||||
result,
|
||||
data: {
|
||||
...data,
|
||||
|
||||
@@ -159,7 +159,7 @@ const EditFormCreate = ({ defaultData, subItem, onSubmitBase, defaultValues, set
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setOpenEditDialog(false)} variant="outlined" color="primary" autoFocus>
|
||||
<Button onClick={() => setOpenEditDialog(false)} variant="outlined" color="secondary" autoFocus>
|
||||
بستن
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -25,7 +25,7 @@ const LocationFormContent = ({ setOpenLocationDialog, start_lat, start_lng, end_
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ justifyContent: "center", paddingBottom: 2, width: "100%" }}>
|
||||
<Button onClick={() => setOpenLocationDialog(false)} variant="contained" color="error">
|
||||
<Button onClick={() => setOpenLocationDialog(false)} variant="outlined" color="secondary">
|
||||
بستن
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
||||
@@ -8,7 +8,7 @@ const Toolbar = ({ table, filterData, mutate }) => {
|
||||
<Stack direction={"row"} spacing={2}>
|
||||
<PrintExcel table={table} filterData={filterData} />
|
||||
<OperatorCreate mutate={mutate} />
|
||||
{/*<ObservedGashtCreate mutate={mutate} />*/}
|
||||
<ObservedGashtCreate mutate={mutate} />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -28,10 +28,10 @@ const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => {
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ justifyContent: "center", paddingBottom: 2, width: "100%" }}>
|
||||
<Button onClick={() => setOpenDeleteDialog(false)} variant="contained" color="error">
|
||||
<Button onClick={() => setOpenDeleteDialog(false)} variant="outlined" color="secondary">
|
||||
خیر !
|
||||
</Button>
|
||||
<Button onClick={handleClick} variant="contained" color="primary" disabled={submitting}>
|
||||
<Button onClick={handleClick} variant="contained" color="error" disabled={submitting}>
|
||||
{submitting ? "درحال ارسال اطلاعات..." : "بله اطمینان دارم"}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
||||
@@ -25,7 +25,7 @@ const LocationFormContent = ({ setOpenLocationDialog, start_lat, start_lng, end_
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ justifyContent: "center", paddingBottom: 2, width: "100%" }}>
|
||||
<Button onClick={() => setOpenLocationDialog(false)} variant="contained" color="error">
|
||||
<Button onClick={() => setOpenLocationDialog(false)} variant="outlined" color="secondary">
|
||||
بستن
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
||||
@@ -257,7 +257,7 @@ const SupervisorList = () => {
|
||||
},
|
||||
{
|
||||
accessorKey: "cmms_machines",
|
||||
header: "کد خودرو", // Car ID
|
||||
header: "خودرو ها", // Car ID
|
||||
id: "cmmsMachines__machine_code",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
@@ -316,9 +316,9 @@ const SupervisorList = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ ثبت", // Register Date
|
||||
id: "created_at",
|
||||
accessorFn: (row) => moment(row.activity_date_time).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ فعالیت", // Start Date
|
||||
id: "activity_date_time",
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
@@ -327,9 +327,9 @@ const SupervisorList = () => {
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => moment(row.activity_date_time).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ فعالیت", // Start Date
|
||||
id: "activity_date_time",
|
||||
accessorFn: (row) => moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ ثبت", // Register Date
|
||||
id: "created_at",
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
|
||||
@@ -7,6 +7,8 @@ import { GET_ROAD_PATROL_OPERATOR_LIST } from "@/core/utils/routes";
|
||||
import moment from "jalali-moment";
|
||||
import RowActions from "./RowActions";
|
||||
import ReportForm from "./RowActions/ReportForm";
|
||||
import MachinesCodeDialog from "./RowActions/MachinesCodeForm";
|
||||
import RahdaranDialog from "./RowActions/RahdaranForm";
|
||||
|
||||
const OperatorList = () => {
|
||||
const columns = useMemo(
|
||||
@@ -23,31 +25,64 @@ const OperatorList = () => {
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "operator_name",
|
||||
header: "نام مامور",
|
||||
id: "operator_name",
|
||||
accessorKey: "cmms_machines",
|
||||
header: "خودرو", // Car ID
|
||||
id: "cmmsMachines__machine_code",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
filterMode: "contains",
|
||||
enableSorting: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
py: 0,
|
||||
"&:first-of-type": {
|
||||
borderLeft: "unset",
|
||||
},
|
||||
},
|
||||
},
|
||||
Cell: ({ renderedCellValue }) => {
|
||||
if (renderedCellValue) {
|
||||
return (
|
||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||
<MachinesCodeDialog machinesLists={renderedCellValue} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
return <Typography variant="body2">کد خودرویی وجود ندارد</Typography>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "officer_phone_number",
|
||||
header: "تلفن همراه",
|
||||
id: "officer_phone_number",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
},
|
||||
{
|
||||
accessorKey: "car_id",
|
||||
header: "کد خودرو",
|
||||
id: "car_id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
accessorKey: "rahdaran",
|
||||
header: "راهداران",
|
||||
id: "rahdaran",
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
datatype: "array",
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
py: 0,
|
||||
"&:first-of-type": {
|
||||
borderLeft: "unset",
|
||||
},
|
||||
},
|
||||
},
|
||||
Cell: ({ renderedCellValue }) => {
|
||||
if (renderedCellValue) {
|
||||
return (
|
||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||
<RahdaranDialog rahdarLists={renderedCellValue} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
return <Typography variant="body2">بدون شخص</Typography>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => moment(row.start_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { DialogContent, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material";
|
||||
import ShowPlak from "@/core/components/ShowPlak";
|
||||
|
||||
const MachinesCodeContent = ({ machinesLists }) => {
|
||||
return (
|
||||
<>
|
||||
<DialogContent>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
width: "100%",
|
||||
overflow: "hidden",
|
||||
"*::-webkit-scrollbar": {
|
||||
width: "0.5em",
|
||||
},
|
||||
"*::-webkit-scrollbar-thumb": {
|
||||
backgroundColor: "primary.main",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TableContainer sx={{ maxHeight: 600 }}>
|
||||
<Table stickyHeader sx={{ minWidth: 800 }}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>کد ماشین</TableCell>
|
||||
<TableCell>نام خودرو</TableCell>
|
||||
<TableCell>پلاک</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{machinesLists.map((machine) => {
|
||||
return (
|
||||
<TableRow
|
||||
key={machine.id}
|
||||
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
||||
>
|
||||
<TableCell>{machine.machine_code}</TableCell>
|
||||
<TableCell>{machine.car_name}</TableCell>
|
||||
<TableCell>
|
||||
{machine.plak_number ? (
|
||||
<ShowPlak plak_number={machine.plak_number} />
|
||||
) : null}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Paper>
|
||||
</DialogContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default MachinesCodeContent;
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material";
|
||||
import DirectionsCarIcon from "@mui/icons-material/DirectionsCar";
|
||||
import { useState } from "react";
|
||||
import MachinesCodeContent from "./MachinesCodeContent";
|
||||
|
||||
const MachinesCodeDialog = ({ machinesLists }) => {
|
||||
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="کد خودرو">
|
||||
<IconButton color="primary" onClick={() => setOpenMachinesCodeDialog(true)}>
|
||||
<DirectionsCarIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Dialog
|
||||
fullWidth
|
||||
open={openMachinesCodeDialog}
|
||||
onClose={() => setOpenMachinesCodeDialog(false)}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
|
||||
},
|
||||
}}
|
||||
dir="rtl"
|
||||
maxWidth={"md"}
|
||||
>
|
||||
<DialogTitle sx={{ fontSize: "large" }}>کد خودرو</DialogTitle>
|
||||
<MachinesCodeContent machinesLists={machinesLists} />
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => setOpenMachinesCodeDialog(false)}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
autoFocus
|
||||
>
|
||||
بستن
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default MachinesCodeDialog;
|
||||
@@ -0,0 +1,48 @@
|
||||
import { DialogContent, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material";
|
||||
|
||||
const RahdaranContent = ({ rahdarLists }) => {
|
||||
return (
|
||||
<>
|
||||
<DialogContent>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
width: "100%",
|
||||
overflow: "hidden",
|
||||
"*::-webkit-scrollbar": {
|
||||
width: "0.5em",
|
||||
},
|
||||
"*::-webkit-scrollbar-thumb": {
|
||||
backgroundColor: "primary.main",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TableContainer sx={{ maxHeight: 600 }}>
|
||||
<Table stickyHeader sx={{ minWidth: 800 }}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>کد راهدار</TableCell>
|
||||
<TableCell>نام</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{rahdarLists.map((rahdar) => {
|
||||
return (
|
||||
<TableRow
|
||||
key={rahdar.id}
|
||||
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
||||
>
|
||||
<TableCell>{rahdar.code}</TableCell>
|
||||
<TableCell>{rahdar.name}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Paper>
|
||||
</DialogContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default RahdaranContent;
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material";
|
||||
import GroupsIcon from "@mui/icons-material/Groups";
|
||||
import { useState } from "react";
|
||||
import RahdaranContent from "./RahdaranContent";
|
||||
|
||||
const RahdaranDialog = ({ rahdarLists }) => {
|
||||
const [openRahdaranDialog, setOpenRahdaranDialog] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="راهداران">
|
||||
<IconButton color="primary" onClick={() => setOpenRahdaranDialog(true)}>
|
||||
<GroupsIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Dialog
|
||||
fullWidth
|
||||
open={openRahdaranDialog}
|
||||
onClose={() => setOpenRahdaranDialog(false)}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
|
||||
},
|
||||
}}
|
||||
dir="rtl"
|
||||
maxWidth={"md"}
|
||||
>
|
||||
<DialogTitle sx={{ fontSize: "large" }}>لیست راهداران</DialogTitle>
|
||||
<RahdaranContent rahdarLists={rahdarLists} />
|
||||
<DialogActions>
|
||||
<Button onClick={() => setOpenRahdaranDialog(false)} variant="outlined" color="secondary" autoFocus>
|
||||
بستن
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default RahdaranDialog;
|
||||
@@ -0,0 +1,55 @@
|
||||
import { DialogContent, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material";
|
||||
import ShowPlak from "@/core/components/ShowPlak";
|
||||
|
||||
const MachinesCodeContent = ({ machinesLists }) => {
|
||||
return (
|
||||
<>
|
||||
<DialogContent>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
width: "100%",
|
||||
overflow: "hidden",
|
||||
"*::-webkit-scrollbar": {
|
||||
width: "0.5em",
|
||||
},
|
||||
"*::-webkit-scrollbar-thumb": {
|
||||
backgroundColor: "primary.main",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TableContainer sx={{ maxHeight: 600 }}>
|
||||
<Table stickyHeader sx={{ minWidth: 800 }}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>کد ماشین</TableCell>
|
||||
<TableCell>نام خودرو</TableCell>
|
||||
<TableCell>پلاک</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{machinesLists.map((machine) => {
|
||||
return (
|
||||
<TableRow
|
||||
key={machine.id}
|
||||
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
||||
>
|
||||
<TableCell>{machine.machine_code}</TableCell>
|
||||
<TableCell>{machine.car_name}</TableCell>
|
||||
<TableCell>
|
||||
{machine.plak_number ? (
|
||||
<ShowPlak plak_number={machine.plak_number} />
|
||||
) : null}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Paper>
|
||||
</DialogContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default MachinesCodeContent;
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material";
|
||||
import DirectionsCarIcon from "@mui/icons-material/DirectionsCar";
|
||||
import { useState } from "react";
|
||||
import MachinesCodeContent from "./MachinesCodeContent";
|
||||
|
||||
const MachinesCodeDialog = ({ machinesLists }) => {
|
||||
const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="کد خودرو">
|
||||
<IconButton color="primary" onClick={() => setOpenMachinesCodeDialog(true)}>
|
||||
<DirectionsCarIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Dialog
|
||||
fullWidth
|
||||
open={openMachinesCodeDialog}
|
||||
onClose={() => setOpenMachinesCodeDialog(false)}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
|
||||
},
|
||||
}}
|
||||
dir="rtl"
|
||||
maxWidth={"md"}
|
||||
>
|
||||
<DialogTitle sx={{ fontSize: "large" }}>کد خودرو</DialogTitle>
|
||||
<MachinesCodeContent machinesLists={machinesLists} />
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => setOpenMachinesCodeDialog(false)}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
autoFocus
|
||||
>
|
||||
بستن
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default MachinesCodeDialog;
|
||||
@@ -0,0 +1,48 @@
|
||||
import { DialogContent, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material";
|
||||
|
||||
const RahdaranContent = ({ rahdarLists }) => {
|
||||
return (
|
||||
<>
|
||||
<DialogContent>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
width: "100%",
|
||||
overflow: "hidden",
|
||||
"*::-webkit-scrollbar": {
|
||||
width: "0.5em",
|
||||
},
|
||||
"*::-webkit-scrollbar-thumb": {
|
||||
backgroundColor: "primary.main",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TableContainer sx={{ maxHeight: 600 }}>
|
||||
<Table stickyHeader sx={{ minWidth: 800 }}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>کد راهدار</TableCell>
|
||||
<TableCell>نام</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{rahdarLists.map((rahdar) => {
|
||||
return (
|
||||
<TableRow
|
||||
key={rahdar.id}
|
||||
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
||||
>
|
||||
<TableCell>{rahdar.code}</TableCell>
|
||||
<TableCell>{rahdar.name}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Paper>
|
||||
</DialogContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default RahdaranContent;
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material";
|
||||
import GroupsIcon from "@mui/icons-material/Groups";
|
||||
import { useState } from "react";
|
||||
import RahdaranContent from "./RahdaranContent";
|
||||
|
||||
const RahdaranDialog = ({ rahdarLists }) => {
|
||||
const [openRahdaranDialog, setOpenRahdaranDialog] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="راهداران">
|
||||
<IconButton color="primary" onClick={() => setOpenRahdaranDialog(true)}>
|
||||
<GroupsIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Dialog
|
||||
fullWidth
|
||||
open={openRahdaranDialog}
|
||||
onClose={() => setOpenRahdaranDialog(false)}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
|
||||
},
|
||||
}}
|
||||
dir="rtl"
|
||||
maxWidth={"md"}
|
||||
>
|
||||
<DialogTitle sx={{ fontSize: "large" }}>لیست راهداران</DialogTitle>
|
||||
<RahdaranContent rahdarLists={rahdarLists} />
|
||||
<DialogActions>
|
||||
<Button onClick={() => setOpenRahdaranDialog(false)} variant="outlined" color="secondary" autoFocus>
|
||||
بستن
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default RahdaranDialog;
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
import { useMemo } from "react";
|
||||
import { Box, Stack } from "@mui/material";
|
||||
import {Box, Stack, Typography} from "@mui/material";
|
||||
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
|
||||
import Toolbar from "./Toolbar";
|
||||
import { GET_ROAD_PATROL_SUPERVISOR_LIST } from "@/core/utils/routes";
|
||||
@@ -11,6 +11,8 @@ import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsT
|
||||
import useEdaratLists from "@/lib/hooks/useEdaratLists";
|
||||
import OfficerDescriptionForm from "./RowActions/OfficerDescription";
|
||||
import ReportForm from "./RowActions/ReportForm";
|
||||
import MachinesCodeDialog from "./RowActions/MachinesCodeForm";
|
||||
import RahdaranDialog from "./RowActions/RahdaranForm";
|
||||
|
||||
const OperatorList = () => {
|
||||
const columns = useMemo(
|
||||
@@ -93,31 +95,64 @@ const OperatorList = () => {
|
||||
Cell: ({ renderedCellValue, row }) => <>{row.original.edare_name}</>,
|
||||
},
|
||||
{
|
||||
accessorKey: "operator_name",
|
||||
header: "نام مامور",
|
||||
id: "operator_name",
|
||||
accessorKey: "cmms_machines",
|
||||
header: "خودرو", // Car ID
|
||||
id: "cmmsMachines__machine_code",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
filterMode: "contains",
|
||||
enableSorting: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
py: 0,
|
||||
"&:first-of-type": {
|
||||
borderLeft: "unset",
|
||||
},
|
||||
},
|
||||
},
|
||||
Cell: ({ renderedCellValue }) => {
|
||||
if (renderedCellValue) {
|
||||
return (
|
||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||
<MachinesCodeDialog machinesLists={renderedCellValue} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
return <Typography variant="body2">کد خودرویی وجود ندارد</Typography>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "officer_phone_number",
|
||||
header: "تلفن همراه",
|
||||
id: "officer_phone_number",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
},
|
||||
{
|
||||
accessorKey: "car_id",
|
||||
header: "کد خودرو",
|
||||
id: "car_id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
accessorKey: "rahdaran",
|
||||
header: "راهداران",
|
||||
id: "rahdaran",
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
datatype: "array",
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
py: 0,
|
||||
"&:first-of-type": {
|
||||
borderLeft: "unset",
|
||||
},
|
||||
},
|
||||
},
|
||||
Cell: ({ renderedCellValue }) => {
|
||||
if (renderedCellValue) {
|
||||
return (
|
||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||
<RahdaranDialog rahdarLists={renderedCellValue} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
return <Typography variant="body2">بدون شخص</Typography>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => moment(row.start_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
|
||||
@@ -1,30 +1,36 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, memo } from "react";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import { useEffect } from "react";
|
||||
import { ACTIVITY_LOG } from "@/core/utils/routes";
|
||||
|
||||
const ActivityCodeLog = ({ activity_code }) => {
|
||||
const ActivityCodeLog = memo(({ activity_code }) => {
|
||||
const requestServer = useRequest({ notificationShow: false });
|
||||
const [hasLogged, setHasLogged] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!activity_code) return;
|
||||
if (!activity_code || hasLogged) return;
|
||||
|
||||
const fetchSubItems = async () => {
|
||||
const controller = new AbortController();
|
||||
|
||||
const fetchActivityLog = async () => {
|
||||
try {
|
||||
await requestServer(ACTIVITY_LOG, "post", {
|
||||
data: {
|
||||
activityCode: activity_code,
|
||||
},
|
||||
data: { activityCode: activity_code },
|
||||
signal: controller.signal,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error); // Always helpful to log the error for debugging.
|
||||
}
|
||||
setHasLogged(true);
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
fetchSubItems();
|
||||
}, [activity_code, requestServer]);
|
||||
fetchActivityLog();
|
||||
|
||||
return null; // Ensure the component still renders something.
|
||||
};
|
||||
return () => {
|
||||
controller.abort();
|
||||
};
|
||||
}, [activity_code, hasLogged, requestServer]);
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
export default ActivityCodeLog;
|
||||
|
||||
@@ -23,6 +23,7 @@ const DataTable_Main = (props) => {
|
||||
table_title,
|
||||
RowActions,
|
||||
specific_data,
|
||||
specialFilter,
|
||||
} = props;
|
||||
const flatColumns = flattenArrayOfObjects(columns, "columns");
|
||||
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });
|
||||
@@ -33,29 +34,34 @@ const DataTable_Main = (props) => {
|
||||
};
|
||||
|
||||
const fetchUrl = useMemo(() => {
|
||||
const params = new URLSearchParams();
|
||||
params.set("start", `${pagination.pageIndex * pagination.pageSize}`);
|
||||
params.set("size", pagination.pageSize);
|
||||
const isValueEmpty = (value) => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.length === 0 || value.every((v) => v === "");
|
||||
}
|
||||
return value === "" || value === null || value === undefined;
|
||||
};
|
||||
if (specialFilter) {
|
||||
const filteredSpecialFilterData = Object.values(specialFilter).filter(
|
||||
(filter) => !isValueEmpty(filter.value)
|
||||
);
|
||||
params.set("filters", JSON.stringify(filteredSpecialFilterData || []));
|
||||
} else {
|
||||
const filteredFilterData = Object.values(filterData)
|
||||
.filter((filter) => !isValueEmpty(filter.value))
|
||||
.map(({ filterMode, id, ...rest }) => ({
|
||||
...rest,
|
||||
id: id.replace(/__/g, "."),
|
||||
fn: filterMode,
|
||||
}));
|
||||
|
||||
const filteredFilterData = Object.values(filterData)
|
||||
.filter((filter) => !isValueEmpty(filter.value))
|
||||
.map(({ filterMode, id, ...rest }) => ({
|
||||
...rest,
|
||||
id: id.replace(/__/g, "."),
|
||||
fn: filterMode,
|
||||
}));
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.set("start", `${pagination.pageIndex * pagination.pageSize}`);
|
||||
params.set("size", pagination.pageSize);
|
||||
params.set("filters", JSON.stringify(filteredFilterData.length === 0 ? [] : filteredFilterData));
|
||||
params.set("filters", JSON.stringify(filteredFilterData.length === 0 ? [] : filteredFilterData));
|
||||
}
|
||||
params.set("sorting", JSON.stringify(sortData));
|
||||
return `${table_url}?${params}`;
|
||||
}, [table_url, filterData, pagination, columns, sortData]);
|
||||
|
||||
}, [table_url, filterData, pagination, columns, sortData, specialFilter]);
|
||||
const fetcher = async (url) => {
|
||||
try {
|
||||
const response = await request(url);
|
||||
@@ -143,5 +149,4 @@ const DataTable_Main = (props) => {
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DataTable_Main;
|
||||
|
||||
@@ -23,8 +23,8 @@ const createCustomIcon = (size, iconUrl, labelText, color) => {
|
||||
</div>
|
||||
<div style="width: 5px; height: 20px; background: ${color}; margin: auto;border-bottom-left-radius: 50%; border-bottom-right-radius: 50%;"></div>
|
||||
</div>`,
|
||||
iconSize: [100, 50], // Adjust icon size to fit your content
|
||||
iconAnchor: [50, 25], // Adjust to position the marker correctly
|
||||
iconSize: [50, 50],
|
||||
iconAnchor: [25, 50],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ const createCustomIcon = (size, iconUrl, labelText, color) => {
|
||||
</div>
|
||||
<div style="width: 5px; height: 20px; background: ${color}; margin: auto;border-bottom-left-radius: 50%; border-bottom-right-radius: 50%;"></div>
|
||||
</div>`,
|
||||
iconSize: [100, 50], // Adjust icon size to fit your content
|
||||
iconAnchor: [50, 25], // Adjust to position the marker correctly
|
||||
iconSize: [50, 50],
|
||||
iconAnchor: [25, 50],
|
||||
});
|
||||
}
|
||||
return L.icon({
|
||||
@@ -111,6 +111,7 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
||||
setStartPosition({ lat: center.lat, lng: center.lng });
|
||||
setIsStartLocked(true);
|
||||
setStartIconColor("#1CAC66");
|
||||
map.panBy([25, 25])
|
||||
}
|
||||
},
|
||||
}}
|
||||
@@ -182,6 +183,13 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
||||
setEndPosition({ lat: center.lat, lng: center.lng });
|
||||
setIsEndLocked(true);
|
||||
setEndIconColor("#D13131");
|
||||
map.fitBounds(
|
||||
[
|
||||
startPosition,
|
||||
map.getCenter(),
|
||||
],
|
||||
{ paddingTopLeft: [16, 16], paddingBottomRight: [16, 16] }
|
||||
);
|
||||
}
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -59,9 +59,11 @@ function MuiDatePicker({ value, setFieldValue, name, minDate, maxDate, helperTex
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text" sx={{ color: error ? "#d32f2f" : "unset" }}>
|
||||
{helperText ? helperText : ""}
|
||||
</FormHelperText>
|
||||
{helperText ? (
|
||||
<FormHelperText id="component-helper-text" sx={{ color: error ? "#d32f2f" : "unset" }}>
|
||||
{helperText}
|
||||
</FormHelperText>
|
||||
) : null}
|
||||
</LocalizationProvider>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -64,9 +64,11 @@ function MuiTimePicker({ value, setFieldValue, name, minTime, maxTime, helperTex
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text" sx={{ color: error ? "#d32f2f" : "unset" }}>
|
||||
{helperText ? helperText : ""}
|
||||
</FormHelperText>
|
||||
{helperText ? (
|
||||
<FormHelperText id="component-helper-text" sx={{ color: error ? "#d32f2f" : "unset" }}>
|
||||
{helperText}
|
||||
</FormHelperText>
|
||||
) : null}
|
||||
</LocalizationProvider>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -2,16 +2,24 @@
|
||||
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { usePermissions } from "@/lib/hooks/usePermissions";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function WithPermission({ children, permission_name }) {
|
||||
const { data, error, isLoading } = usePermissions();
|
||||
const [cachedData, setCachedData] = useState(null);
|
||||
|
||||
if (error || isLoading || !data || !permission_name) {
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
setCachedData(data);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
if (error || isLoading || !cachedData || !permission_name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const hasPermission =
|
||||
permission_name.includes("all") || permission_name.some((permission) => data.includes(permission));
|
||||
permission_name.includes("all") || permission_name.some((permission) => cachedData.includes(permission));
|
||||
|
||||
if (!hasPermission) {
|
||||
return (
|
||||
|
||||
@@ -54,6 +54,7 @@ export const DELETE_BY_SUPERVISOR = api + "/api/v3/road_items/delete";
|
||||
export const RESTORE_BY_SUPERVISOR = api + "/api/v3/road_items/restore";
|
||||
export const GET_CAR_LIST_SEARCH = api + "/api/v3/cmms_machines/search";
|
||||
export const GET_RAHDARANS_LIST_SEARCH = api + "/api/v3/rahdaran/search";
|
||||
export const GET_OBSERVED_GASHT_LIST = api + "/api/v3/observed_items/filter";
|
||||
|
||||
// activity code log
|
||||
export const ACTIVITY_LOG = api + "/api/v3/profile/add_activity";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
import { createTheme } from "@mui/material";
|
||||
import { grey } from '@mui/material/colors';
|
||||
|
||||
const theme = createTheme({
|
||||
direction: "rtl",
|
||||
@@ -16,6 +17,9 @@ const theme = createTheme({
|
||||
main: "#015688",
|
||||
contrastText: "#fff",
|
||||
},
|
||||
secondary: {
|
||||
main: grey[700],
|
||||
}
|
||||
},
|
||||
components: {
|
||||
MuiBackdrop: {
|
||||
|
||||
@@ -14,5 +14,5 @@ export const usePermissions = () => {
|
||||
}
|
||||
};
|
||||
|
||||
return useSWR(GET_PERMISSIONS_ROUTE, fetcher, { keepPreviousData: true });
|
||||
return useSWR(GET_PERMISSIONS_ROUTE, fetcher, { keepPreviousData: true, dedupingInterval: 30000 });
|
||||
};
|
||||
|
||||
@@ -14,5 +14,5 @@ export const useSidebarBadge = () => {
|
||||
}
|
||||
};
|
||||
|
||||
return useSWR(GET_SIDEBAR_BADGE_ROUTE, fetcher, { keepPreviousData: true });
|
||||
return useSWR(GET_SIDEBAR_BADGE_ROUTE, fetcher, { keepPreviousData: true, dedupingInterval: 10000 });
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user