working on faaliat information
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
NEXT_PUBLIC_VERSION="0.11.1"
|
||||
NEXT_PUBLIC_VERSION="0.12.0"
|
||||
NEXT_PUBLIC_API_URL="https://rms.witel.ir"
|
||||
NEXT_PUBLIC_MAPTILE_ENDPOINT="https://rmsmap.rmto.ir/141map"
|
||||
@@ -8,6 +8,7 @@ import { GET_AZMAYESH_LIST } from "@/core/utils/routes";
|
||||
import ShowLocation from "./ShowLocation";
|
||||
import moment from "jalali-moment";
|
||||
import RowActions from "./RowActions";
|
||||
import ShowSampleOfAzmayesh from "./RowActions/ShowSampleOfAzmayesh";
|
||||
|
||||
const AzmayeshList = () => {
|
||||
const columns = useMemo(
|
||||
@@ -19,6 +20,16 @@ const AzmayeshList = () => {
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterMode: "notEquals",
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "province_name",
|
||||
header: "استان",
|
||||
id: "province_name",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterMode: "notEquals",
|
||||
},
|
||||
{
|
||||
accessorKey: "azmayesh_type_name",
|
||||
@@ -28,6 +39,14 @@ const AzmayeshList = () => {
|
||||
datatype: "text",
|
||||
filterMode: "notEquals",
|
||||
},
|
||||
{
|
||||
accessorKey: "contract_subitem_id",
|
||||
header: "کد یکتا پروژه",
|
||||
id: "contract_subitem_id",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
},
|
||||
{
|
||||
accessorKey: "project_name",
|
||||
header: "پروژه",
|
||||
@@ -37,13 +56,24 @@ const AzmayeshList = () => {
|
||||
filterMode: "equals",
|
||||
},
|
||||
{
|
||||
accessorKey: "lat",
|
||||
accessorKey: "location",
|
||||
header: "نمایش مختصات",
|
||||
id: "lat",
|
||||
id: "location",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
enableSorting: false,
|
||||
filterMode: "equals",
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
py: 0,
|
||||
"&:first-of-type": {
|
||||
borderLeft: "unset",
|
||||
},
|
||||
},
|
||||
},
|
||||
Cell: ({ row }) => <ShowLocation lat={row.original.lat} lng={row.original.lng} />,
|
||||
},
|
||||
{
|
||||
@@ -101,6 +131,8 @@ const AzmayeshList = () => {
|
||||
enableColumnFilter: false,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
grow: false,
|
||||
size: 100,
|
||||
Cell: ({ renderedCellValue }) => (
|
||||
<Typography variant="body2">
|
||||
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("YYYY/MM/DD") : "-"}
|
||||
@@ -114,6 +146,8 @@ const AzmayeshList = () => {
|
||||
enableColumnFilter: false,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
grow: false,
|
||||
size: 100,
|
||||
Cell: ({ renderedCellValue }) => (
|
||||
<Typography variant="body2">
|
||||
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("YYYY/MM/DD") : "-"}
|
||||
@@ -127,12 +161,35 @@ const AzmayeshList = () => {
|
||||
enableColumnFilter: false,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
grow: false,
|
||||
size: 100,
|
||||
Cell: ({ renderedCellValue }) => (
|
||||
<Typography variant="body2">
|
||||
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("HH:mm | YYYY/MM/DD") : "-"}
|
||||
</Typography>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "samples",
|
||||
header: "نمونه ها",
|
||||
id: "samples",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
enableSorting: false,
|
||||
filterMode: "equals",
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
py: 0,
|
||||
"&:first-of-type": {
|
||||
borderLeft: "unset",
|
||||
},
|
||||
},
|
||||
},
|
||||
Cell: ({ row }) => <ShowSampleOfAzmayesh rowData={row.original} />,
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { Marker, useMapEvents } from "react-leaflet";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import AzmayeshIcon from "@/assets/images/examine_marker.png";
|
||||
import AzmayeshActiveIcon from "@/assets/images/examine_marker_active.png";
|
||||
import {
|
||||
Alert,
|
||||
Box,
|
||||
Button,
|
||||
FormControl,
|
||||
@@ -14,6 +15,7 @@ import {
|
||||
OutlinedInput,
|
||||
Stack,
|
||||
Tooltip,
|
||||
Zoom,
|
||||
useMediaQuery,
|
||||
} from "@mui/material";
|
||||
import NewReleasesIcon from "@mui/icons-material/NewReleases";
|
||||
@@ -21,9 +23,12 @@ import VerifiedIcon from "@mui/icons-material/Verified";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { useTheme } from "@emotion/react";
|
||||
|
||||
const MAX_ZOOM_FOR_MARKER = 13;
|
||||
|
||||
const CandUChooseLocation = ({ mapBoxData, setMapBoxData }) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
const [enableSend, setEnableSend] = useState(false);
|
||||
|
||||
const mapAzmayeshMarker = useRef();
|
||||
const defaultIconSize = [35, 35];
|
||||
@@ -38,6 +43,7 @@ const CandUChooseLocation = ({ mapBoxData, setMapBoxData }) => {
|
||||
|
||||
const map = useMapEvents({
|
||||
move(e) {
|
||||
setEnableSend(e.target.getZoom() > MAX_ZOOM_FOR_MARKER);
|
||||
if (!mapBoxData) {
|
||||
mapAzmayeshMarker.current.setLatLng(e.target.getCenter());
|
||||
}
|
||||
@@ -52,22 +58,24 @@ const CandUChooseLocation = ({ mapBoxData, setMapBoxData }) => {
|
||||
mapAzmayeshMarker.current.setIcon(createCustomIcon(defaultIconSize, AzmayeshIcon.src));
|
||||
}
|
||||
},
|
||||
zoom(e) {
|
||||
setEnableSend(e.target.getZoom() > MAX_ZOOM_FOR_MARKER);
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (mapAzmayeshMarker.current) {
|
||||
const newIcon = mapBoxData
|
||||
? createCustomIcon([45, 45], AzmayeshActiveIcon.src)
|
||||
: createCustomIcon(defaultIconSize, AzmayeshIcon.src);
|
||||
mapAzmayeshMarker.current.setIcon(newIcon);
|
||||
}
|
||||
if (!mapAzmayeshMarker.current) return;
|
||||
if (mapBoxData) {
|
||||
mapAzmayeshMarker.current.setIcon(createCustomIcon([45, 45], AzmayeshActiveIcon.src));
|
||||
mapAzmayeshMarker.current.setLatLng(mapBoxData);
|
||||
map.flyTo(mapBoxData, 14);
|
||||
map.setView(mapBoxData, 14);
|
||||
} else {
|
||||
mapAzmayeshMarker.current.setIcon(createCustomIcon(defaultIconSize, AzmayeshIcon.src));
|
||||
}
|
||||
}, [mapBoxData]);
|
||||
}, [mapBoxData, mapAzmayeshMarker.current]);
|
||||
|
||||
const handleMarkerClick = () => {
|
||||
if (!enableSend) return;
|
||||
if (!mapBoxData) {
|
||||
setMapBoxData({
|
||||
lat: mapAzmayeshMarker.current.getLatLng().lat,
|
||||
@@ -86,93 +94,118 @@ const CandUChooseLocation = ({ mapBoxData, setMapBoxData }) => {
|
||||
position={map.getCenter()}
|
||||
ref={mapAzmayeshMarker}
|
||||
eventHandlers={{ click: handleMarkerClick }}
|
||||
icon={createCustomIcon(defaultIconSize, AzmayeshIcon.src)}
|
||||
icon={L.divIcon({ className: "" })}
|
||||
/>
|
||||
<Box
|
||||
<Stack
|
||||
direction={"row"}
|
||||
justifyContent={"center"}
|
||||
sx={{
|
||||
zIndex: "400",
|
||||
width: "100%",
|
||||
position: "absolute",
|
||||
background: "#ffffff94",
|
||||
p: 2,
|
||||
borderRadius: "10px",
|
||||
boxShadow: "rgba(0, 0, 0, 0.24) 0px 3px 8px",
|
||||
bottom: "5px",
|
||||
left: "10px",
|
||||
right: isMobile ? "10px" : "",
|
||||
top: 0,
|
||||
left: 0,
|
||||
}}
|
||||
>
|
||||
<Stack sx={{ gap: 2 }}>
|
||||
<Tooltip title="با کلیک بر روی مارکر، محل آزمایش را انتخاب کنید" arrow>
|
||||
<FormControl size="small" variant="outlined">
|
||||
<InputLabel sx={{ color: mapBoxData ? "success.main" : "" }} htmlFor="lat">
|
||||
طول جغرافیایی
|
||||
</InputLabel>
|
||||
<OutlinedInput
|
||||
id="lat"
|
||||
type="text"
|
||||
size="small"
|
||||
readOnly
|
||||
sx={{
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: mapBoxData ? "success.main" : "",
|
||||
},
|
||||
color: mapBoxData ? "success.main" : "",
|
||||
}}
|
||||
value={mapBoxData ? `${mapBoxData.lat}` : ""}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
{mapBoxData ? (
|
||||
<VerifiedIcon color="success" />
|
||||
) : (
|
||||
<NewReleasesIcon color="error" />
|
||||
)}
|
||||
</InputAdornment>
|
||||
}
|
||||
label="طول جغرافیایی"
|
||||
/>
|
||||
</FormControl>
|
||||
</Tooltip>
|
||||
<Tooltip title="با کلیک بر روی مارکر، محل آزمایش را انتخاب کنید" arrow>
|
||||
<FormControl size="small" variant="outlined">
|
||||
<InputLabel sx={{ color: mapBoxData ? "success.main" : "" }} htmlFor="lng">
|
||||
عرض جغرافیایی
|
||||
</InputLabel>
|
||||
<OutlinedInput
|
||||
id="lng"
|
||||
type="text"
|
||||
size="small"
|
||||
readOnly
|
||||
sx={{
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: mapBoxData ? "success.main" : "",
|
||||
},
|
||||
color: mapBoxData ? "success.main" : "",
|
||||
}}
|
||||
value={mapBoxData ? `${mapBoxData.lng}` : ""}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
{mapBoxData ? (
|
||||
<VerifiedIcon color="success" />
|
||||
) : (
|
||||
<NewReleasesIcon color="error" />
|
||||
)}
|
||||
</InputAdornment>
|
||||
}
|
||||
label="عرض جغرافیایی"
|
||||
/>
|
||||
</FormControl>
|
||||
</Tooltip>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={!mapBoxData}
|
||||
startIcon={<EditIcon />}
|
||||
onClick={handleEditLocation}
|
||||
>
|
||||
ویرایش مختصات
|
||||
</Button>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Zoom in={!enableSend}>
|
||||
<Alert sx={{ mt: 1, py: 0.5, px: 2, borderRadius: 2, border: 1 }} icon={false} color={"warning"}>
|
||||
برای ثبت محل آزمایش، لطفاً نقشه را بیشتر زوم کنید.
|
||||
</Alert>
|
||||
</Zoom>
|
||||
</Stack>
|
||||
<Stack
|
||||
direction={"row"}
|
||||
sx={{
|
||||
zIndex: "400",
|
||||
width: "100%",
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
background: "#ffffff94",
|
||||
flex: isMobile ? 1 : "",
|
||||
m: 1,
|
||||
p: 2,
|
||||
borderRadius: 2,
|
||||
boxShadow: "rgba(0, 0, 0, 0.24) 0px 3px 8px",
|
||||
}}
|
||||
>
|
||||
<Stack sx={{ gap: 2 }}>
|
||||
<Tooltip title="با کلیک بر روی مارکر، محل آزمایش را انتخاب کنید" arrow>
|
||||
<FormControl size="small" variant="outlined">
|
||||
<InputLabel sx={{ color: mapBoxData ? "success.main" : "" }} htmlFor="lat">
|
||||
طول جغرافیایی
|
||||
</InputLabel>
|
||||
<OutlinedInput
|
||||
id="lat"
|
||||
type="text"
|
||||
size="small"
|
||||
readOnly
|
||||
sx={{
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: mapBoxData ? "success.main" : "",
|
||||
},
|
||||
color: mapBoxData ? "success.main" : "",
|
||||
}}
|
||||
value={mapBoxData ? `${mapBoxData.lat}` : ""}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
{mapBoxData ? (
|
||||
<VerifiedIcon color="success" />
|
||||
) : (
|
||||
<NewReleasesIcon color="error" />
|
||||
)}
|
||||
</InputAdornment>
|
||||
}
|
||||
label="طول جغرافیایی"
|
||||
/>
|
||||
</FormControl>
|
||||
</Tooltip>
|
||||
<Tooltip title="با کلیک بر روی مارکر، محل آزمایش را انتخاب کنید" arrow>
|
||||
<FormControl size="small" variant="outlined">
|
||||
<InputLabel sx={{ color: mapBoxData ? "success.main" : "" }} htmlFor="lng">
|
||||
عرض جغرافیایی
|
||||
</InputLabel>
|
||||
<OutlinedInput
|
||||
id="lng"
|
||||
type="text"
|
||||
size="small"
|
||||
readOnly
|
||||
sx={{
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: mapBoxData ? "success.main" : "",
|
||||
},
|
||||
color: mapBoxData ? "success.main" : "",
|
||||
}}
|
||||
value={mapBoxData ? `${mapBoxData.lng}` : ""}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
{mapBoxData ? (
|
||||
<VerifiedIcon color="success" />
|
||||
) : (
|
||||
<NewReleasesIcon color="error" />
|
||||
)}
|
||||
</InputAdornment>
|
||||
}
|
||||
label="عرض جغرافیایی"
|
||||
/>
|
||||
</FormControl>
|
||||
</Tooltip>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={!mapBoxData}
|
||||
startIcon={<EditIcon />}
|
||||
onClick={handleEditLocation}
|
||||
>
|
||||
ویرایش مختصات
|
||||
</Button>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -66,6 +66,11 @@ const CandUGeneralInfo = ({ control, register, setValue, errors }) => {
|
||||
label="نوع آزمایش"
|
||||
/>
|
||||
)}
|
||||
renderOption={(props, option) => (
|
||||
<li {...props} key={option.id}>
|
||||
{option.name}
|
||||
</li>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<FormHelperText id="azmayesh_type_id">
|
||||
@@ -122,6 +127,23 @@ const CandUGeneralInfo = ({ control, register, setValue, errors }) => {
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<FormControl error={!!errors.contract_subitem_id} size="small" fullWidth variant="outlined">
|
||||
<InputLabel htmlFor="contract_subitem_id">کد یکتا پروژه</InputLabel>
|
||||
<OutlinedInput
|
||||
id="contract_subitem_id"
|
||||
label={"کد یکتا پروژه"}
|
||||
autoComplete="off"
|
||||
{...register("contract_subitem_id")}
|
||||
size="small"
|
||||
fullWidth
|
||||
type="text"
|
||||
/>
|
||||
<FormHelperText id="contract_subitem_id">
|
||||
{errors.contract_subitem_id ? errors.contract_subitem_id.message : null}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<FormControl error={!!errors.project_name} size="small" fullWidth variant="outlined">
|
||||
<InputLabel htmlFor="project_name">پروژه</InputLabel>
|
||||
@@ -252,6 +274,7 @@ const CandUGeneralInfo = ({ control, register, setValue, errors }) => {
|
||||
onChange={(newValue) => {
|
||||
onChange(newValue);
|
||||
}}
|
||||
closeOnSelect
|
||||
slotProps={{
|
||||
textField: {
|
||||
size: "small",
|
||||
@@ -305,6 +328,7 @@ const CandUGeneralInfo = ({ control, register, setValue, errors }) => {
|
||||
onChange={(newValue) => {
|
||||
onChange(newValue);
|
||||
}}
|
||||
closeOnSelect
|
||||
slotProps={{
|
||||
textField: {
|
||||
size: "small",
|
||||
|
||||
@@ -33,6 +33,7 @@ function TabPanel(props) {
|
||||
const validationSchema = object({
|
||||
azmayesh_type_id: string().required("نوع آزمایش را مشخص کنید!"),
|
||||
province_id: string().required("استان را وارد کنید!"),
|
||||
contract_subitem_id: string().required("کد یکتا پروژه را وارد کنید!"),
|
||||
project_name: string().required("عنوان پروژه را وارد کنید!"),
|
||||
employer: string().required("کارفرما را وارد کنید!"),
|
||||
consultant: string().required("مشاور را وارد کنید!"),
|
||||
@@ -46,7 +47,7 @@ const validationSchema = object({
|
||||
|
||||
const CandUAzmayesh = ({ setOpen, mutate, updateInfo, rowId }) => {
|
||||
const theme = useTheme();
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest({ notificationSuccess: true });
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
const [tabState, setTabState] = useState(0);
|
||||
const [mapBoxData, setMapBoxData] = useState(updateInfo ? { lat: updateInfo.lat, lng: updateInfo.lng } : null);
|
||||
@@ -72,6 +73,7 @@ const CandUAzmayesh = ({ setOpen, mutate, updateInfo, rowId }) => {
|
||||
azmayesh_type_name: updateInfo ? updateInfo.azmayesh_type_name : "",
|
||||
province_id: updateInfo ? updateInfo.province_id : "",
|
||||
province_name: updateInfo ? updateInfo.province_name : "",
|
||||
contract_subitem_id: updateInfo ? updateInfo.contract_subitem_id : "",
|
||||
project_name: updateInfo ? updateInfo.project_name : "",
|
||||
employer: updateInfo ? updateInfo.employer : "",
|
||||
consultant: updateInfo ? updateInfo.consultant : "",
|
||||
@@ -88,7 +90,7 @@ const CandUAzmayesh = ({ setOpen, mutate, updateInfo, rowId }) => {
|
||||
register,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { isSubmitting, errors, touchedFields },
|
||||
formState: { isSubmitting, errors },
|
||||
} = useForm({ defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur" });
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
@@ -99,6 +101,7 @@ const CandUAzmayesh = ({ setOpen, mutate, updateInfo, rowId }) => {
|
||||
formData.append("azmayesh_type_name", data.azmayesh_type_name);
|
||||
formData.append("province_id", data.province_id);
|
||||
formData.append("province_name", data.province_name);
|
||||
formData.append("contract_subitem_id", data.contract_subitem_id);
|
||||
formData.append("project_name", data.project_name);
|
||||
formData.append("employer", data.employer);
|
||||
formData.append("consultant", data.consultant);
|
||||
@@ -109,14 +112,13 @@ const CandUAzmayesh = ({ setOpen, mutate, updateInfo, rowId }) => {
|
||||
formData.append("request_date", moment(new Date(data.request_date)).format("YYYY-MM-DD"));
|
||||
formData.append("report_date", moment(new Date(data.report_date)).format("YYYY-MM-DD"));
|
||||
|
||||
requestServer(updateInfo ? `${UPDATE_AZMAYESH}/${rowId}` : CREATE_AZMAYESH, "post", {
|
||||
data: formData,
|
||||
})
|
||||
.then(() => {
|
||||
mutate();
|
||||
handleClose();
|
||||
})
|
||||
.catch(() => {});
|
||||
try {
|
||||
await requestServer(updateInfo ? `${UPDATE_AZMAYESH}/${rowId}` : CREATE_AZMAYESH, "post", {
|
||||
data: formData,
|
||||
});
|
||||
mutate();
|
||||
handleClose();
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -6,7 +6,7 @@ import { GET_AZMAYESH_LIST } from "@/core/utils/routes";
|
||||
import CandUAzmayesh from "@/components/dashboard/azmayesh/Forms/CandUAzmayesh";
|
||||
|
||||
const AzmayeshUpdate = ({ rowId, mutate }) => {
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest();
|
||||
const [openUpdateDialog, setOpenUpdateDialog] = useState(false);
|
||||
const [updateInfo, setUpdateInfo] = useState(null);
|
||||
const [loadingOpen, setLoadingOpen] = useState(false);
|
||||
|
||||
@@ -14,7 +14,7 @@ import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import { DELETE_AZMAYESH } from "@/core/utils/routes";
|
||||
|
||||
const DeleteAzmayesh = ({ rowId, mutate }) => {
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest({ notificationSuccess: true });
|
||||
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useTheme } from "@emotion/react";
|
||||
import CandUSampleOfAzmayesh from "@/components/dashboard/azmayesh/RowActions/ShowSampleOfAzmayesh/Forms/CandUSampleOfAzmayesh";
|
||||
|
||||
const AddSampleToAzmayesh = ({ azmayeshTypeId, mutate, rowId }) => {
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest();
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
const [sampleInfo, setSampleInfo] = useState(null);
|
||||
|
||||
@@ -15,10 +15,10 @@ const CandUSampleOfAzmayesh = ({
|
||||
isUpdate,
|
||||
azmayesh_id,
|
||||
}) => {
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest({ notificationSuccess: true });
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const handleSubmit = () => {
|
||||
const handleSubmit = async () => {
|
||||
const data = {};
|
||||
setIsSubmitting(true);
|
||||
const formData = new FormData();
|
||||
@@ -27,17 +27,20 @@ const CandUSampleOfAzmayesh = ({
|
||||
data[key] = value;
|
||||
});
|
||||
formData.append("data", JSON.stringify(data));
|
||||
requestServer(isUpdate ? `${UPDATE_SAMPLE_OF_AZMAYESH}/${rowId}` : `${ADD_SAMPLE_TO_AZMAYESH}`, "post", {
|
||||
data: formData,
|
||||
})
|
||||
.then(() => {
|
||||
mutate();
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
setOpenSampleDialog(false);
|
||||
setIsSubmitting(false);
|
||||
});
|
||||
try {
|
||||
await requestServer(
|
||||
isUpdate ? `${UPDATE_SAMPLE_OF_AZMAYESH}/${rowId}` : `${ADD_SAMPLE_TO_AZMAYESH}`,
|
||||
"post",
|
||||
{
|
||||
data: formData,
|
||||
}
|
||||
);
|
||||
mutate();
|
||||
setOpenSampleDialog(false);
|
||||
setIsSubmitting(false);
|
||||
} catch (error) {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ const CandUSampleOfAzmayesh = ({
|
||||
isUpdate,
|
||||
azmayesh_id,
|
||||
}) => {
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest({ notificationSuccess: true });
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const handleSubmit = () => {
|
||||
|
||||
@@ -14,7 +14,7 @@ import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import { DELETE_SAMPLE_LIST } from "@/core/utils/routes";
|
||||
|
||||
const DeleteSample = ({ rowId, mutate }) => {
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest({ notificationSuccess: true });
|
||||
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import CandUSampleOfAzmayesh from "@/components/dashboard/azmayesh/RowActions/Sh
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
|
||||
const UpdateSample = ({ azmayeshTypeId, mutate, rowId, azmayesh_id }) => {
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest();
|
||||
const [sampleInfo, setSampleInfo] = useState(null);
|
||||
const [openUpdateSampleDialog, setOpenUpdateSampleDialog] = useState(false);
|
||||
const [defaultValues, setDefaultValues] = useState({});
|
||||
|
||||
@@ -24,10 +24,12 @@ const ShowSampleList = ({ sampleInfo, rowData }) => {
|
||||
id: "id",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
...sampleInfo.map((item) => ({
|
||||
accessorKey: item.id.toString(),
|
||||
header: item.name,
|
||||
header: item.unit ? `${item.name} (${item.unit})` : item.name,
|
||||
id: item.id.toString(),
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
@@ -38,6 +40,8 @@ const ShowSampleList = ({ sampleInfo, rowData }) => {
|
||||
id: "updated_at",
|
||||
enableColumnFilter: false,
|
||||
datatype: "date",
|
||||
grow: false,
|
||||
size: 100,
|
||||
Cell: ({ renderedCellValue }) => (
|
||||
<Typography variant="body2">
|
||||
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("HH:mm | YYYY/MM/DD") : "-"}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, Dialog, DialogActions, DialogContent, IconButton, Tooltip } from "@mui/material";
|
||||
import { Box, Button, Dialog, DialogActions, DialogContent, IconButton, Tooltip } from "@mui/material";
|
||||
import AssignmentIcon from "@mui/icons-material/Assignment";
|
||||
import { useState } from "react";
|
||||
import ShowSampleList from "./ShowSampleList";
|
||||
@@ -6,7 +6,7 @@ import { GET_AZMAYESH_SAMPLE_FIELDS } from "@/core/utils/routes";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
|
||||
const ShowSampleOfAzmayesh = ({ rowData }) => {
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest();
|
||||
const [openShowSampleDialog, setOpenShowSampleDialog] = useState(false);
|
||||
const [sampleInfo, setSampleInfo] = useState(null);
|
||||
const handleGetSampleFields = () => {
|
||||
@@ -20,7 +20,7 @@ const ShowSampleOfAzmayesh = ({ rowData }) => {
|
||||
});
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ display: "flex", justifyContent: "center" }}>
|
||||
<Tooltip title="نمایش نمونه های آزمایش" arrow placement="right">
|
||||
<IconButton
|
||||
color="primary"
|
||||
@@ -30,7 +30,7 @@ const ShowSampleOfAzmayesh = ({ rowData }) => {
|
||||
<AssignmentIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Dialog maxWidth="md" fullWidth open={openShowSampleDialog}>
|
||||
<Dialog maxWidth="lg" fullWidth open={openShowSampleDialog}>
|
||||
<DialogContent>
|
||||
<ShowSampleList rowData={rowData} sampleInfo={sampleInfo} />
|
||||
</DialogContent>
|
||||
@@ -40,7 +40,7 @@ const ShowSampleOfAzmayesh = ({ rowData }) => {
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
export default ShowSampleOfAzmayesh;
|
||||
|
||||
@@ -7,7 +7,6 @@ const RowActions = ({ row, mutate }) => {
|
||||
return (
|
||||
<Box sx={{ display: "flex", gap: 1 }}>
|
||||
<AzmayeshUpdate mutate={mutate} rowId={row.getValue("id")} />
|
||||
<ShowSampleOfAzmayesh rowData={row.original} />
|
||||
<DeleteAzmayesh mutate={mutate} rowId={row.getValue("id")} />
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -42,9 +42,8 @@ const validationSchema = object({
|
||||
});
|
||||
|
||||
const FormAndRequest = ({ setOpen, mutate, rowId, updateInfo }) => {
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest({ notificationSuccess: true });
|
||||
const [selectedListItem, setSelectedListItem] = useState(null);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
@@ -68,7 +67,7 @@ const FormAndRequest = ({ setOpen, mutate, rowId, updateInfo }) => {
|
||||
handleSubmit,
|
||||
setValue,
|
||||
watch,
|
||||
formState: { errors },
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm({ defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur" });
|
||||
|
||||
const { fields, append, remove } = useFieldArray({
|
||||
@@ -90,25 +89,22 @@ const FormAndRequest = ({ setOpen, mutate, rowId, updateInfo }) => {
|
||||
};
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
setIsSubmitting(true);
|
||||
const formData = new FormData();
|
||||
formData.append("name", data.name);
|
||||
data.fields.map((field, index) => {
|
||||
formData.append(`fields[${index}][name]`, field.name);
|
||||
formData.append(`fields[${index}][unit]`, field.unit);
|
||||
if (field.unit !== "") formData.append(`fields[${index}][unit]`, field.unit);
|
||||
formData.append(`fields[${index}][type]`, field.type);
|
||||
if (field.options.length !== 0) formData.append(`fields[${index}][option]`, JSON.stringify(field.options));
|
||||
});
|
||||
|
||||
requestServer(updateInfo ? `${UPDATE_AZMAYESH_TYPE}/${rowId}` : ADD_AZMAYESH_TYPE, "post", {
|
||||
data: formData,
|
||||
})
|
||||
.then(() => {
|
||||
mutate();
|
||||
handleClose();
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => setIsSubmitting(false));
|
||||
try {
|
||||
await requestServer(updateInfo ? `${UPDATE_AZMAYESH_TYPE}/${rowId}` : ADD_AZMAYESH_TYPE, "post", {
|
||||
data: formData,
|
||||
});
|
||||
mutate();
|
||||
handleClose();
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useState } from "react";
|
||||
import { DELETE_AZMAYESH_TYPE_LIST } from "@/core/utils/routes";
|
||||
|
||||
const DeleteAzmayeshType = ({ rowId, mutate }) => {
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest({ notificationSuccess: true });
|
||||
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import useRequest from "@/lib/hooks/useRequest";
|
||||
import CandUAzmayeshType from "@/components/dashboard/azmayeshType/Forms/CandUAzmayeshType";
|
||||
|
||||
const UpdateAzmayeshType = ({ rowId, mutate }) => {
|
||||
const requestServer = useRequest({ auth: true });
|
||||
const requestServer = useRequest();
|
||||
const [openUpdateDialog, setOpenUpdateDialog] = useState(false);
|
||||
const [updateInfo, setUpdateInfo] = useState(null);
|
||||
const [loadingOpen, setLoadingOpen] = useState(false);
|
||||
|
||||
@@ -57,7 +57,7 @@ const RoadSafetyFormContext = ({ rowId, mutate, setOpenRoadSafetyForm }) => {
|
||||
setOpenRoadSafetyForm(false);
|
||||
mutate();
|
||||
})
|
||||
.catch(() => { });
|
||||
.catch(() => {});
|
||||
};
|
||||
return (
|
||||
<StyledForm onSubmit={handleSubmit(onSubmit)}>
|
||||
|
||||
@@ -50,7 +50,7 @@ const ReferFormContext = ({ setOpenReferDialog, rowId, mutate }) => {
|
||||
setOpenReferDialog(false);
|
||||
mutate();
|
||||
})
|
||||
.catch(() => { });
|
||||
.catch(() => {});
|
||||
};
|
||||
return (
|
||||
<StyledForm onSubmit={handleSubmit(onSubmit)}>
|
||||
|
||||
@@ -57,7 +57,7 @@ const RoadSafetyFormContext = ({ rowId, mutate, setOpenRoadSafetyForm }) => {
|
||||
setOpenRoadSafetyForm(false);
|
||||
mutate();
|
||||
})
|
||||
.catch(() => { });
|
||||
.catch(() => {});
|
||||
};
|
||||
return (
|
||||
<StyledForm onSubmit={handleSubmit(onSubmit)}>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import React, { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { array, mixed, object, string } from "yup";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import { Box, Button, DialogActions, DialogContent, Tab, Tabs, useMediaQuery } from "@mui/material";
|
||||
import React, {useState} from "react";
|
||||
import {useForm} from "react-hook-form";
|
||||
import {yupResolver} from "@hookform/resolvers/yup";
|
||||
import {array, mixed, object, string} from "yup";
|
||||
import {useTheme} from "@emotion/react";
|
||||
import {Box, Button, DialogActions, DialogContent, Tab, Tabs, useMediaQuery} from "@mui/material";
|
||||
import StyledForm from "@/core/components/StyledForm";
|
||||
import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
|
||||
import FileCopyIcon from "@mui/icons-material/FileCopy";
|
||||
@@ -15,10 +14,9 @@ import BeenhereIcon from "@mui/icons-material/Beenhere";
|
||||
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 { CREATE_ROAD_ITEMS } from "@/core/utils/routes";
|
||||
|
||||
function TabPanel(props) {
|
||||
const { children, value, index } = props;
|
||||
const {children, value, index} = props;
|
||||
return (
|
||||
<div role="tabpanel" hidden={value !== index}>
|
||||
{value === index && <Box>{children}</Box>}
|
||||
@@ -34,7 +32,7 @@ const defaultValues = {
|
||||
start_date: "",
|
||||
before_image: null,
|
||||
after_image: null,
|
||||
cmms_machine_id: null,
|
||||
cmms_machines: null,
|
||||
rahdaran_id: null,
|
||||
start_point: "",
|
||||
end_point: "",
|
||||
@@ -43,14 +41,14 @@ const validationSchema = object({
|
||||
itemId: string().required("نوع آیتم را مشخص کنید!"),
|
||||
itemSubId: string().required("موضوع مشاهده شده را مشخص کنید!"),
|
||||
amount: string().required("وارد کردن مقدار الزامیست!"),
|
||||
cmms_machine_id: object().required("وارد کردن کد خودرو الزامیست!"),
|
||||
cmms_machines: array().required("وارد کردن کد خودرو الزامیست!"),
|
||||
rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"), // بررسی حداقل یک آیتم,
|
||||
action_date: string().required("لطفا زمان فعالیت را انتخاب کنید!"),
|
||||
start_date: string().required("لطفاً تاریخ شروع فعالیت را انتخاب کنید!"),
|
||||
before_image: mixed()
|
||||
.nullable()
|
||||
.test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) {
|
||||
const { subItemsList } = this.options.context;
|
||||
const {subItemsList} = this.options.context;
|
||||
const needsImage = subItemsList?.needs_image === 1;
|
||||
if (needsImage) {
|
||||
return !!value;
|
||||
@@ -60,7 +58,7 @@ const validationSchema = object({
|
||||
after_image: mixed()
|
||||
.nullable()
|
||||
.test("after-image-required", "لطفا عکس بعد از اقدام را بارگذاری کنید!", function (value) {
|
||||
const { subItemsList } = this.options.context;
|
||||
const {subItemsList} = this.options.context;
|
||||
const needsImage = subItemsList?.needs_image === 1;
|
||||
if (needsImage) {
|
||||
return !!value;
|
||||
@@ -73,7 +71,7 @@ const validationSchema = object({
|
||||
})
|
||||
.required("لطفاً نقطه شروع را مشخص کنید!"),
|
||||
end_point: mixed().test("end-point-required", "لطفاً نقطه پایان را مشخص کنید!", function (value) {
|
||||
const { subItemsList } = this.options.context;
|
||||
const {subItemsList} = this.options.context;
|
||||
const needsEndPoint = subItemsList?.needs_end_point === 1;
|
||||
if (needsEndPoint) {
|
||||
return !!value; // چک میکند که مقدار موجود است
|
||||
@@ -82,12 +80,11 @@ const validationSchema = object({
|
||||
}),
|
||||
});
|
||||
|
||||
const CreateFormContent = ({ setOpen, mutate, rowId }) => {
|
||||
const CreateFormContent = ({setOpen, onSubmit}) => {
|
||||
const [tabState, setTabState] = useState(0);
|
||||
const [itemsList, setItemsList] = useState();
|
||||
const [subItemsList, setSubItemsList] = useState([]);
|
||||
const theme = useTheme();
|
||||
const requestServer = useRequest({ notificationSuccess: true });
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
@@ -98,6 +95,20 @@ const CreateFormContent = ({ setOpen, mutate, rowId }) => {
|
||||
};
|
||||
|
||||
const handlePrev = () => {
|
||||
if (tabState === 2) {
|
||||
const fieldsToReset = [
|
||||
"amount",
|
||||
"action_date",
|
||||
"start_date",
|
||||
"before_image",
|
||||
"after_image",
|
||||
"cmms_machines",
|
||||
"rahdaran_id",
|
||||
"start_point",
|
||||
"end_point",
|
||||
];
|
||||
fieldsToReset.forEach((field) => resetField(field));
|
||||
}
|
||||
if (tabState === 0) {
|
||||
handleClose();
|
||||
} else {
|
||||
@@ -111,40 +122,15 @@ const CreateFormContent = ({ setOpen, mutate, rowId }) => {
|
||||
register,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { errors, isSubmitting },
|
||||
resetField,
|
||||
formState: {errors, isSubmitting},
|
||||
} = useForm({
|
||||
defaultValues,
|
||||
resolver: yupResolver(validationSchema),
|
||||
mode: "onBlur",
|
||||
context: { subItemsList },
|
||||
context: {subItemsList},
|
||||
});
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
console.log(data);
|
||||
let endPoint;
|
||||
let startPoint = `${data.start_point.lat},${data.start_point.lng}`;
|
||||
data.end_point !== "" && (endPoint = `${data.end_point.lat},${data.end_point.lng}`);
|
||||
const formData = new FormData();
|
||||
data.rahdaran_id.map((rahdar, index) => formData.append(`rahdaran_id[${index}]`, rahdar.id));
|
||||
formData.append("item_id", data.itemId);
|
||||
formData.append("sub_item_id", data.itemSubId);
|
||||
formData.append("amount", data.amount);
|
||||
formData.append("activity_time", data.action_date);
|
||||
formData.append("activity_date", data.start_date);
|
||||
formData.append("cmms_machine_id", data.cmms_machine_id.id);
|
||||
data.before_image !== null && formData.append("before_image", data.before_image);
|
||||
data.after_image !== null && formData.append("after_image", data.after_image);
|
||||
data.start_point !== "" && formData.append("start_point", startPoint);
|
||||
data.end_point !== "" && formData.append("end_point", endPoint);
|
||||
requestServer(CREATE_ROAD_ITEMS, "post", {
|
||||
data: formData,
|
||||
})
|
||||
.then((response) => {
|
||||
mutate();
|
||||
setOpen(false);
|
||||
})
|
||||
.catch((error) => {});
|
||||
};
|
||||
return (
|
||||
<StyledForm onSubmit={handleSubmit(onSubmit)}>
|
||||
<Tabs
|
||||
@@ -159,12 +145,12 @@ const CreateFormContent = ({ setOpen, mutate, rowId }) => {
|
||||
backgroundColor: "#efefef",
|
||||
}}
|
||||
>
|
||||
<Tab icon={<InsertDriveFileIcon />} label="انتخاب آیتم" />
|
||||
<Tab disabled={tabState === 0} icon={<FileCopyIcon />} label="انتخاب موضوع مشاهده شده" />
|
||||
<Tab disabled={tabState === 0 || tabState === 1} icon={<InfoIcon />} label="اطلاعات فعالیت" />
|
||||
<Tab icon={<InsertDriveFileIcon/>} label="انتخاب آیتم"/>
|
||||
<Tab disabled={tabState === 0} icon={<FileCopyIcon/>} label="انتخاب موضوع مشاهده شده"/>
|
||||
<Tab disabled={tabState === 0 || tabState === 1} icon={<InfoIcon/>} label="اطلاعات فعالیت"/>
|
||||
</Tabs>
|
||||
<DialogContent dividers sx={{ overflowY: "auto", maxHeight: "70vh" }}>
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<DialogContent dividers sx={{overflowY: "auto", maxHeight: "70vh"}}>
|
||||
<Box sx={{flex: 1}}>
|
||||
<TabPanel value={tabState} index={0}>
|
||||
<GetItemsForm
|
||||
setItemsList={setItemsList}
|
||||
@@ -197,13 +183,13 @@ const CreateFormContent = ({ setOpen, mutate, rowId }) => {
|
||||
</TabPanel>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ alignItems: "center", justifyContent: "center" }}>
|
||||
<DialogActions sx={{alignItems: "center", justifyContent: "center"}}>
|
||||
<Button
|
||||
onClick={handlePrev}
|
||||
variant="outlined"
|
||||
color="error"
|
||||
size="large"
|
||||
startIcon={tabState === 0 ? <ExitToAppIcon /> : <KeyboardDoubleArrowRightIcon />}
|
||||
startIcon={tabState === 0 ? <ExitToAppIcon/> : <KeyboardDoubleArrowRightIcon/>}
|
||||
>
|
||||
{tabState === 0 ? "بستن" : "مرحله قبل"}
|
||||
</Button>
|
||||
@@ -213,7 +199,7 @@ const CreateFormContent = ({ setOpen, mutate, rowId }) => {
|
||||
size="large"
|
||||
disabled={isSubmitting}
|
||||
type={"submit"}
|
||||
endIcon={<BeenhereIcon />}
|
||||
endIcon={<BeenhereIcon/>}
|
||||
>
|
||||
{isSubmitting ? "در حال ثبت فعالیت" : "ثبت فعالیت"}
|
||||
</Button>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Controller } from "react-hook-form";
|
||||
import CarCode from "@/core/components/CarCode";
|
||||
import RahdarCode from "@/core/components/RahdarCode";
|
||||
import PreviousStatesInfo from "./PreviousStatesInfo";
|
||||
import NumberField from "@/core/components/NumberField";
|
||||
|
||||
const GetItemInfo = ({ register, itemsList, subItemsList, control, setValue, errors, watch, getValues }) => {
|
||||
return (
|
||||
@@ -16,12 +17,14 @@ const GetItemInfo = ({ register, itemsList, subItemsList, control, setValue, err
|
||||
<PreviousStatesInfo itemsList={itemsList} subItemsList={subItemsList} />
|
||||
</Stack>
|
||||
<Stack>
|
||||
<TextField
|
||||
<NumberField
|
||||
{...register("amount")}
|
||||
label={`مقدار (${subItemsList.unit})`}
|
||||
error={!!errors.amount}
|
||||
value={watch("amount")}
|
||||
type="text"
|
||||
size={"small"}
|
||||
unit={subItemsList.unit}
|
||||
inputProps={{
|
||||
inputMode: "number",
|
||||
min: 0,
|
||||
@@ -45,13 +48,14 @@ const GetItemInfo = ({ register, itemsList, subItemsList, control, setValue, err
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<CarCode
|
||||
carCode={field.value || null}
|
||||
setCarCode={(value) => field.onChange(value || null)}
|
||||
carCode={field.value || []}
|
||||
setCarCode={(value) => field.onChange(value || [])}
|
||||
error={error}
|
||||
multiple={true}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
name={"cmms_machine_id"}
|
||||
name={"cmms_machines"}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
|
||||
@@ -1,11 +1,40 @@
|
||||
"use client";
|
||||
import { Dialog } from "@mui/material";
|
||||
import {Dialog} from "@mui/material";
|
||||
import CreateFormContent from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/CreateFormContent";
|
||||
import {CREATE_ROAD_ITEMS} from "@/core/utils/routes";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
|
||||
const OperatorCreateForm = ({ open, setOpen, mutate, rowId }) => {
|
||||
const OperatorCreateForm = ({open, setOpen, mutate, rowId}) => {
|
||||
const requestServer = useRequest({notificationSuccess: true});
|
||||
const HandleSubmit = async (data) => {
|
||||
let endPoint;
|
||||
let startPoint = `${data.start_point.lat},${data.start_point.lng}`;
|
||||
data.end_point !== "" && (endPoint = `${data.end_point.lat},${data.end_point.lng}`);
|
||||
const formData = new FormData();
|
||||
data.rahdaran_id.map((rahdar, index) => formData.append(`rahdaran_id[${index}]`, rahdar.id));
|
||||
formData.append("item_id", data.itemId);
|
||||
formData.append("sub_item_id", data.itemSubId);
|
||||
formData.append("amount", data.amount);
|
||||
formData.append("activity_time", data.action_date);
|
||||
formData.append("activity_date", data.start_date);
|
||||
data.cmms_machines.map((machine, index) => formData.append(`machines_id[${index}]`, machine.id));
|
||||
data.before_image !== null && formData.append("before_image", data.before_image);
|
||||
data.after_image !== null && formData.append("after_image", data.after_image);
|
||||
data.start_point !== "" && formData.append("start_point", startPoint);
|
||||
data.end_point !== "" && formData.append("end_point", endPoint);
|
||||
await requestServer(CREATE_ROAD_ITEMS, "post", {
|
||||
data: formData,
|
||||
})
|
||||
.then((response) => {
|
||||
mutate();
|
||||
setOpen(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Dialog open={open} fullWidth maxWidth="sm">
|
||||
<CreateFormContent setOpen={setOpen} mutate={mutate} rowId={rowId} />
|
||||
<CreateFormContent setOpen={setOpen} onSubmit={HandleSubmit}/>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ const PrintExcel = ({ table, filterData }) => {
|
||||
const filename = `خروجی کارتابل فعالیت روزانه تاریخ_${moment().format("jYYYY_jMM_jDD")}.xlsx`;
|
||||
FileSaver.saveAs(response.data, filename);
|
||||
})
|
||||
.catch(() => { })
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
|
||||
@@ -1,16 +1,26 @@
|
||||
"use client";
|
||||
import { useMemo } from "react";
|
||||
import { Box, Stack, Typography } from "@mui/material";
|
||||
import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
|
||||
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
|
||||
import Toolbar from "./Toolbar";
|
||||
import { GET_ROAD_ITEMS_OPERATOR_LIST } from "@/core/utils/routes";
|
||||
import useRoadItemGetSubItems from "@/lib/hooks/useRoadItemGetISubtems";
|
||||
import useRoadItemGetItems from "@/lib/hooks/useRoadItemGetItems";
|
||||
import { Box, Stack, Typography } from "@mui/material";
|
||||
import moment from "jalali-moment";
|
||||
import { useMemo } from "react";
|
||||
import RowActions from "./RowActions";
|
||||
import LocationForm from "./RowActions/LocationForm";
|
||||
import ImageDialog from "./RowActions/ImageForm";
|
||||
import LocationForm from "./RowActions/LocationForm";
|
||||
import RahdaranDialog from "./RowActions/RahdaranForm";
|
||||
import Toolbar from "./Toolbar";
|
||||
import DescriptionForm from "./RowActions/DescriptionForm";
|
||||
import MachinesCodeDialog from "./RowActions/MachinesCodeForm";
|
||||
|
||||
const OperatorList = () => {
|
||||
const statusOptions = [
|
||||
{ value: 0, label: "درحال بررسی" },
|
||||
{ value: 1, label: "تایید" },
|
||||
{ value: 2, label: "عدم تایید" },
|
||||
];
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
@@ -21,24 +31,78 @@ const OperatorList = () => {
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "item_fa",
|
||||
header: "آیتم فعالیت",
|
||||
id: "item_fa",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
datatype: "numeric",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
ColumnSelectComponent: (props) => {
|
||||
const { itemsList, loadingItemsList, errorItemsList } = useRoadItemGetItems();
|
||||
|
||||
const getColumnSelectOptions = () => {
|
||||
if (loadingItemsList) {
|
||||
return [{ value: "loading", label: "در حال بارگذاری..." }];
|
||||
}
|
||||
if (errorItemsList) {
|
||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||
}
|
||||
return [
|
||||
{ value: "", label: props.column.header },
|
||||
...itemsList.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name,
|
||||
})),
|
||||
];
|
||||
};
|
||||
|
||||
const columnSelectOption = getColumnSelectOptions();
|
||||
|
||||
return <CustomSelectByDependency {...props} columnSelectOption={columnSelectOption} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "sub_item_fa",
|
||||
header: "موضوع مشاهده شده", // Observed Subject
|
||||
header: "موضوع مشاهده شده",
|
||||
id: "sub_item_fa",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
datatype: "numeric",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
dependencyId: "item_fa",
|
||||
ColumnSelectComponent: (props) => {
|
||||
const { subItemsList, loadingSubItemsList, errorSubItemsList } = useRoadItemGetSubItems(
|
||||
props.dependencyFieldValue.value
|
||||
);
|
||||
|
||||
const getColumnSelectOptions = () => {
|
||||
if (props.dependencyFieldValue.value === "") {
|
||||
return [{ value: "empty", label: "ابتدا آیتم فعالیت را انتخاب کنید" }];
|
||||
}
|
||||
if (loadingSubItemsList) {
|
||||
return [{ value: "loading", label: "در حال بارگذاری..." }];
|
||||
}
|
||||
if (errorSubItemsList) {
|
||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||
}
|
||||
return [
|
||||
{ value: "", label: props.column.header },
|
||||
...subItemsList.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name,
|
||||
})),
|
||||
];
|
||||
};
|
||||
|
||||
const columnSelectOption = getColumnSelectOptions();
|
||||
|
||||
return <CustomSelectByDependency {...props} columnSelectOption={columnSelectOption} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "value",
|
||||
@@ -48,11 +112,17 @@ const OperatorList = () => {
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 120,
|
||||
Cell: ({ renderedCellValue, row }) => {
|
||||
return (
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Typography variant="body2">{row.original.sub_item_data}</Typography>
|
||||
<Typography variant="body2">{`(${row.original.unit_fa})`}</Typography>
|
||||
<Stack direction="row" alignItems="center" spacing={0.5}>
|
||||
<Typography sx={{ margin: 1 }} component="span">
|
||||
{(row.original.sub_item_data / 1).toLocaleString()}
|
||||
</Typography>
|
||||
<Typography component="span" variant="caption">
|
||||
{`(${row.original.unit_fa})`}
|
||||
</Typography>
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
@@ -64,6 +134,8 @@ const OperatorList = () => {
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
datatype: "array",
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
@@ -95,6 +167,8 @@ const OperatorList = () => {
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
datatype: "array",
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
@@ -118,14 +192,35 @@ const OperatorList = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "cmms_machine_code",
|
||||
accessorKey: "cmms_machines",
|
||||
header: "کد خودرو", // Car ID
|
||||
id: "cmms_machine_code",
|
||||
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: "rahdaran",
|
||||
@@ -134,6 +229,8 @@ const OperatorList = () => {
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
datatype: "array",
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
@@ -162,6 +259,8 @@ const OperatorList = () => {
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => moment(row.activity_date_time).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
@@ -171,25 +270,53 @@ const OperatorList = () => {
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "status_fa",
|
||||
accessorKey: "status",
|
||||
header: "وضعیت", // Status
|
||||
id: "status_fa",
|
||||
id: "status",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
datatype: "numeric",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: true,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
columnSelectOption: () => {
|
||||
return statusOptions.map((status) => ({
|
||||
value: status.value,
|
||||
label: status.label,
|
||||
}));
|
||||
},
|
||||
Cell: ({ renderedCellValue, row }) => <>{row.original.status_fa}</>,
|
||||
},
|
||||
{
|
||||
accessorKey: "supervisor_description",
|
||||
header: "توضیحات", // Description
|
||||
header: "توضیحات کارشناس", // Description
|
||||
id: "supervisor_description",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 70,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
py: 0,
|
||||
"&:first-of-type": {
|
||||
borderLeft: "unset",
|
||||
},
|
||||
},
|
||||
},
|
||||
Cell: ({ renderedCellValue }) => {
|
||||
return (
|
||||
<Stack alignItems={"center"} justifyContent={"center"}>
|
||||
<DescriptionForm description={renderedCellValue} />
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
[]
|
||||
@@ -202,7 +329,7 @@ const OperatorList = () => {
|
||||
need_filter={true}
|
||||
columns={columns}
|
||||
sorting={[
|
||||
{ id: "status_fa", desc: true },
|
||||
{ id: "status", desc: true },
|
||||
{ id: "id", desc: true },
|
||||
]}
|
||||
table_url={GET_ROAD_ITEMS_OPERATOR_LIST}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { Dialog, DialogContent, DialogTitle, IconButton, Tooltip, Typography, Card, CardContent } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
import RemoveRedEyeIcon from "@mui/icons-material/RemoveRedEye";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
|
||||
const DescriptionForm = ({ description }) => {
|
||||
const [openOfficerDescriptionDialog, setOpenOfficerDescriptionDialog] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="توضیحات کارشناس">
|
||||
<IconButton color="primary" onClick={() => setOpenOfficerDescriptionDialog(true)}>
|
||||
<RemoveRedEyeIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Dialog
|
||||
open={openOfficerDescriptionDialog}
|
||||
onClose={() => setOpenOfficerDescriptionDialog(false)}
|
||||
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",
|
||||
borderRadius: 2,
|
||||
padding: 1,
|
||||
},
|
||||
}}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
dir="rtl"
|
||||
>
|
||||
<DialogTitle sx={{ display: "flex", justifyContent: "space-between", padding: "16px 24px" }}>
|
||||
<Typography variant="body1" sx={{ fontWeight: "bold", fontSize: "large" }}>
|
||||
توضیحات کارشناس
|
||||
</Typography>
|
||||
<IconButton onClick={() => setOpenOfficerDescriptionDialog(false)} size="small">
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Card sx={{ padding: 2, boxShadow: 3, borderRadius: 2 }}>
|
||||
<CardContent>
|
||||
<Typography variant="body2">{description || "هیچ توضیحی موجود نیست"} </Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DescriptionForm;
|
||||
@@ -0,0 +1,29 @@
|
||||
import { LinearProgress, Typography } from "@mui/material";
|
||||
import EditFormContent from "./EditFormContent";
|
||||
import useRoadItemGetISubtems from "@/lib/hooks/useRoadItemGetISubtems";
|
||||
|
||||
const EditController = ({ rowId, mutate, setOpenEditDialog, row }) => {
|
||||
const { subItemsList, loadingSubItemsList, errorSubItemsList } = useRoadItemGetISubtems(row.original?.item);
|
||||
const subItem = subItemsList.find((SubItem) => SubItem.sub_item === row.original?.sub_item);
|
||||
|
||||
return (
|
||||
<>
|
||||
{errorSubItemsList ? (
|
||||
<Typography color={"error"} textAlign={"center"}>
|
||||
خطا در دریافت اطلاعات!!!
|
||||
</Typography>
|
||||
) : loadingSubItemsList ? (
|
||||
<LinearProgress />
|
||||
) : (
|
||||
<EditFormContent
|
||||
subItem={subItem}
|
||||
rowId={rowId}
|
||||
row={row}
|
||||
mutate={mutate}
|
||||
setOpenEditDialog={setOpenEditDialog}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default EditController;
|
||||
@@ -12,10 +12,11 @@ import { UPDATE_ROAD_ITEMS } from "@/core/utils/routes";
|
||||
import CarCode from "@/core/components/CarCode";
|
||||
import RahdarCode from "@/core/components/RahdarCode";
|
||||
import useRoadItemGetISubtems from "@/lib/hooks/useRoadItemGetISubtems";
|
||||
import NumberField from "@/core/components/NumberField";
|
||||
|
||||
const validationSchema = object({
|
||||
amount: string().required("وارد کردن مقدار الزامیست!"),
|
||||
cmms_machine_id: object().required("وارد کردن کد خودرو الزامیست!"),
|
||||
cmms_machines: array().required("وارد کردن کد خودرو الزامیست!"),
|
||||
rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"),
|
||||
before_image: mixed()
|
||||
.nullable()
|
||||
@@ -59,7 +60,7 @@ const EditFormContent = ({ row, mutate, setOpenEditDialog, rowId, subItem }) =>
|
||||
amount: row.original.sub_item_data || null,
|
||||
start_point: { lat: row.original.start_lat || "", lng: row.original.start_lng || "" },
|
||||
end_point: { lat: row.original.end_lat || "", lng: row.original.end_lng || "" },
|
||||
cmms_machine_id: row.original.cmms_machine,
|
||||
cmms_machines: row.original.cmms_machines || null,
|
||||
rahdaran_id: row.original.rahdaran || null,
|
||||
};
|
||||
const requestServer = useRequest();
|
||||
@@ -91,12 +92,12 @@ const EditFormContent = ({ row, mutate, setOpenEditDialog, rowId, subItem }) =>
|
||||
data.after_image !== defaultValues.after_image &&
|
||||
formData.append("after_image", data.after_image);
|
||||
formData.append("amount", data.amount);
|
||||
formData.append("cmms_machine_id", data.cmms_machine_id.id);
|
||||
data.cmms_machines.map((machine, index) => formData.append(`machines_id[${index}]`, machine.id));
|
||||
data.rahdaran_id.map((rahdar, index) => formData.append(`rahdaran_id[${index}]`, rahdar.id));
|
||||
formData.append("start_point", startPoint);
|
||||
subItem.needs_end_point === 1 && formData.append("end_point", endPoint);
|
||||
|
||||
requestServer(`${UPDATE_ROAD_ITEMS}/${rowId}`, "post", {
|
||||
await requestServer(`${UPDATE_ROAD_ITEMS}/${rowId}`, "post", {
|
||||
notificationSuccess: true,
|
||||
data: formData,
|
||||
})
|
||||
@@ -104,8 +105,9 @@ const EditFormContent = ({ row, mutate, setOpenEditDialog, rowId, subItem }) =>
|
||||
mutate();
|
||||
setOpenEditDialog(false);
|
||||
})
|
||||
.catch((err) => { });
|
||||
.catch((err) => {});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledForm onSubmit={handleSubmit(onSubmit)}>
|
||||
@@ -124,11 +126,14 @@ const EditFormContent = ({ row, mutate, setOpenEditDialog, rowId, subItem }) =>
|
||||
) : null}
|
||||
</Stack>
|
||||
<Stack>
|
||||
<TextField
|
||||
<NumberField
|
||||
{...register("amount")}
|
||||
label={`مقدار (${row.original.unit_fa})`}
|
||||
label={`مقدار (${subItem.unit})`}
|
||||
error={!!errors.amount}
|
||||
value={watch("amount")}
|
||||
type="text"
|
||||
size={"small"}
|
||||
unit={subItem.unit}
|
||||
inputProps={{
|
||||
inputMode: "number",
|
||||
min: 0,
|
||||
@@ -141,7 +146,6 @@ const EditFormContent = ({ row, mutate, setOpenEditDialog, rowId, subItem }) =>
|
||||
setValue("amount", watch("amount"));
|
||||
}
|
||||
}}
|
||||
error={!!errors.amount}
|
||||
helperText={errors.amount ? errors.amount.message : null}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
@@ -153,14 +157,15 @@ const EditFormContent = ({ row, mutate, setOpenEditDialog, rowId, subItem }) =>
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<CarCode
|
||||
carCode={field.value || null}
|
||||
setCarCode={(value) => field.onChange(value || "")}
|
||||
inputValueDefault={row.original.cmms_machine_code}
|
||||
carCode={field.value || []}
|
||||
setCarCode={(value) => field.onChange(value || [])}
|
||||
inputValueDefault={row.original.cmms_machines}
|
||||
multiple={true}
|
||||
error={error} // اگر خطا وجود داشته باشد
|
||||
/>
|
||||
);
|
||||
}}
|
||||
name={"cmms_machine_id"}
|
||||
name={"cmms_machines"}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { Dialog, DialogTitle, IconButton, LinearProgress, Tooltip, Typography } from "@mui/material";
|
||||
import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
import BorderColorIcon from "@mui/icons-material/BorderColor";
|
||||
import EditFormContent from "@/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormContent";
|
||||
import useRoadItemGetISubtems from "@/lib/hooks/useRoadItemGetISubtems";
|
||||
import EditController from "./EditController";
|
||||
|
||||
const EditForm = ({ row, mutate, rowId }) => {
|
||||
const [openEditDialog, setOpenEditDialog] = useState(false);
|
||||
const { subItemsList, loadingSubItemsList, errorSubItemsList } = useRoadItemGetISubtems(row.original?.item);
|
||||
const subItem = subItemsList.find((subItem) => subItem.sub_item === row.original?.sub_item);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="ویرایش اطلاعات" arrow placement="right">
|
||||
@@ -32,21 +30,7 @@ const EditForm = ({ row, mutate, rowId }) => {
|
||||
}}
|
||||
>
|
||||
<DialogTitle>ویرایش اطلاعات</DialogTitle>
|
||||
{errorSubItemsList ? (
|
||||
<Typography color={"error"} textAlign={"center"}>
|
||||
خطا در دریافت اطلاعات!!!
|
||||
</Typography>
|
||||
) : loadingSubItemsList ? (
|
||||
<LinearProgress />
|
||||
) : (
|
||||
<EditFormContent
|
||||
subItem={subItem}
|
||||
rowId={rowId}
|
||||
row={row}
|
||||
mutate={mutate}
|
||||
setOpenEditDialog={setOpenEditDialog}
|
||||
/>
|
||||
)}
|
||||
<EditController setOpenEditDialog={setOpenEditDialog} rowId={rowId} row={row} mutate={mutate} />
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
@@ -28,7 +28,7 @@ const ConfirmContent = ({ rowId, mutate, setOpenConfirmDialog }) => {
|
||||
mutate();
|
||||
setOpenConfirmDialog(false);
|
||||
})
|
||||
.catch(() => { });
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -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;
|
||||
@@ -36,7 +36,7 @@ const RejectContent = ({ rowId, mutate, setOpenRejectDialog }) => {
|
||||
mutate();
|
||||
setOpenRejectDialog(false);
|
||||
})
|
||||
.catch(() => { })
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
reset();
|
||||
});
|
||||
|
||||
@@ -8,8 +8,19 @@ import RowActions from "./RowActions";
|
||||
import LocationForm from "./RowActions/LocationForm";
|
||||
import ImageDialog from "./RowActions/ImageForm";
|
||||
import RahdaranDialog from "./RowActions/RahdaranForm";
|
||||
import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
|
||||
import useProvinces from "@/lib/hooks/useProvince";
|
||||
import useRoadItemGetItems from "@/lib/hooks/useRoadItemGetItems";
|
||||
import useRoadItemGetSubItems from "@/lib/hooks/useRoadItemGetISubtems";
|
||||
import useEdaratLists from "@/lib/hooks/useEdaratLists";
|
||||
import MachinesCodeDialog from "./RowActions/MachinesCodeForm";
|
||||
|
||||
const SupervisorList = () => {
|
||||
const statusOptions = [
|
||||
{ value: 0, label: "درحال بررسی" },
|
||||
{ value: 1, label: "تایید" },
|
||||
{ value: 2, label: "عدم تایید" },
|
||||
];
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
@@ -21,42 +32,141 @@ const SupervisorList = () => {
|
||||
filterMode: "equals",
|
||||
sortDescFirst: false,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "province_fa",
|
||||
accessorKey: "province_id",
|
||||
header: "استان", // Province
|
||||
id: "province_fa",
|
||||
id: "province_id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
datatype: "numeric",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 130,
|
||||
ColumnSelectComponent: (props) => {
|
||||
const { provinces, errorProvinces, loadingProvinces } = useProvinces();
|
||||
const getColumnSelectOptions = () => {
|
||||
if (loadingProvinces) {
|
||||
return [{ value: "loading", label: "در حال بارگذاری..." }];
|
||||
}
|
||||
if (errorProvinces) {
|
||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||
}
|
||||
return [
|
||||
{ value: "", label: props.column.header },
|
||||
...provinces.map((province) => ({
|
||||
value: province.id,
|
||||
label: province.name_fa,
|
||||
})),
|
||||
];
|
||||
};
|
||||
const columnSelectOption = getColumnSelectOptions();
|
||||
return <CustomSelectByDependency {...props} columnSelectOption={columnSelectOption} />;
|
||||
},
|
||||
Cell: ({ renderedCellValue, row }) => <>{row.original.province_fa}</>,
|
||||
},
|
||||
{
|
||||
accessorKey: "edarat_name",
|
||||
accessorKey: "edarat_id",
|
||||
header: "اداره", // Office
|
||||
id: "edarat_name",
|
||||
id: "edarat_id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
datatype: "numeric",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
dependencyId: "province_id",
|
||||
grow: false,
|
||||
size: 120,
|
||||
ColumnSelectComponent: (props) => {
|
||||
const { edaratList, loadingEdaratList, errorEdaratList } = useEdaratLists(
|
||||
props.dependencyFieldValue.value
|
||||
);
|
||||
|
||||
const getColumnSelectOptions = () => {
|
||||
if (props.dependencyFieldValue.value === "") {
|
||||
return [{ value: "empty", label: "ابتدا استان را انتخاب کنید" }];
|
||||
}
|
||||
if (loadingEdaratList) {
|
||||
return [{ value: "loading", label: "در حال بارگذاری..." }];
|
||||
}
|
||||
if (errorEdaratList) {
|
||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||
}
|
||||
return [
|
||||
{ value: "", label: props.column.header },
|
||||
...edaratList.map((edare) => ({
|
||||
value: edare.id,
|
||||
label: edare.name_fa,
|
||||
})),
|
||||
];
|
||||
};
|
||||
const columnSelectOption = getColumnSelectOptions();
|
||||
return <CustomSelectByDependency {...props} columnSelectOption={columnSelectOption} />;
|
||||
},
|
||||
Cell: ({ renderedCellValue, row }) => <>{row.original.edarat_name}</>,
|
||||
},
|
||||
{
|
||||
accessorKey: "item_fa",
|
||||
header: "آیتم فعالیت",
|
||||
id: "item_fa",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
datatype: "numeric",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
ColumnSelectComponent: (props) => {
|
||||
const { itemsList, loadingItemsList, errorItemsList } = useRoadItemGetItems();
|
||||
const getColumnSelectOptions = () => {
|
||||
if (loadingItemsList) {
|
||||
return [{ value: "loading", label: "در حال بارگذاری..." }];
|
||||
}
|
||||
if (errorItemsList) {
|
||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||
}
|
||||
return [
|
||||
{ value: "", label: props.column.header },
|
||||
...itemsList.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name,
|
||||
})),
|
||||
];
|
||||
};
|
||||
const columnSelectOption = getColumnSelectOptions();
|
||||
return <CustomSelectByDependency {...props} columnSelectOption={columnSelectOption} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "sub_item_fa",
|
||||
header: "موضوع مشاهده شده", // Observed Subject
|
||||
header: "موضوع مشاهده شده",
|
||||
id: "sub_item_fa",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
datatype: "numeric",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
dependencyId: "item_fa",
|
||||
ColumnSelectComponent: (props) => {
|
||||
const { subItemsList, loadingSubItemsList, errorSubItemsList } = useRoadItemGetSubItems(
|
||||
props.dependencyFieldValue.value
|
||||
);
|
||||
const getColumnSelectOptions = () => {
|
||||
if (props.dependencyFieldValue.value === "") {
|
||||
return [{ value: "empty", label: "ابتدا آیتم فعالیت را انتخاب کنید" }];
|
||||
}
|
||||
if (loadingSubItemsList) {
|
||||
return [{ value: "loading", label: "در حال بارگذاری..." }];
|
||||
}
|
||||
if (errorSubItemsList) {
|
||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||
}
|
||||
return [
|
||||
{ value: "", label: props.column.header },
|
||||
...subItemsList.map((item) => ({
|
||||
value: item.id,
|
||||
label: item.name,
|
||||
})),
|
||||
];
|
||||
};
|
||||
const columnSelectOption = getColumnSelectOptions();
|
||||
return <CustomSelectByDependency {...props} columnSelectOption={columnSelectOption} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "value",
|
||||
@@ -65,12 +175,18 @@ const SupervisorList = () => {
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
grow: false,
|
||||
size: 120,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
Cell: ({ renderedCellValue, row }) => {
|
||||
return (
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Typography variant="body2">{row.original.sub_item_data}</Typography>
|
||||
<Typography variant="body2">{`(${row.original.unit_fa})`}</Typography>
|
||||
<Stack direction="row" alignItems="center" spacing={0.5}>
|
||||
<Typography sx={{ margin: 1 }} component="span">
|
||||
{(row.original.sub_item_data / 1).toLocaleString()}
|
||||
</Typography>
|
||||
<Typography component="span" variant="caption">
|
||||
{`(${row.original.unit_fa})`}
|
||||
</Typography>
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
@@ -82,6 +198,8 @@ const SupervisorList = () => {
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
datatype: "array",
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
@@ -113,6 +231,8 @@ const SupervisorList = () => {
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
datatype: "array",
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
@@ -136,14 +256,35 @@ const SupervisorList = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "cmms_machine_code",
|
||||
accessorKey: "cmms_machines",
|
||||
header: "کد خودرو", // Car ID
|
||||
id: "cmms_machine_code",
|
||||
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: "rahdaran",
|
||||
@@ -152,6 +293,8 @@ const SupervisorList = () => {
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
datatype: "array",
|
||||
grow: false,
|
||||
size: 100,
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
borderLeft: "1px solid #e1e1e1",
|
||||
@@ -180,6 +323,8 @@ const SupervisorList = () => {
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => moment(row.activity_date_time).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
@@ -189,25 +334,26 @@ const SupervisorList = () => {
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "status_fa",
|
||||
accessorKey: "status",
|
||||
header: "وضعیت", // Status
|
||||
id: "status_fa",
|
||||
id: "status",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
datatype: "numeric",
|
||||
filterMode: "equals",
|
||||
sortDescFirst: true,
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
},
|
||||
{
|
||||
accessorKey: "supervisor_description",
|
||||
header: "توضیحات", // Description
|
||||
id: "supervisor_description",
|
||||
enableColumnFilter: false,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
columnSelectOption: () => {
|
||||
return statusOptions.map((status) => ({
|
||||
value: status.value,
|
||||
label: status.label,
|
||||
}));
|
||||
},
|
||||
Cell: ({ renderedCellValue, row }) => <>{row.original.status_fa}</>,
|
||||
},
|
||||
],
|
||||
[]
|
||||
@@ -220,7 +366,7 @@ const SupervisorList = () => {
|
||||
need_filter={true}
|
||||
columns={columns}
|
||||
sorting={[
|
||||
{ id: "status_fa", desc: false },
|
||||
{ id: "status", desc: false },
|
||||
{ id: "id", desc: true },
|
||||
]}
|
||||
table_url={GET_ROAD_ITEMS_SUPERVISOR_LIST}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
"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 EditIcon from "@mui/icons-material/Edit";
|
||||
import moment from "jalali-moment";
|
||||
import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
|
||||
import WatchLaterIcon from '@mui/icons-material/WatchLater';
|
||||
|
||||
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
|
||||
loading: () => <MapLoading/>,
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const ActionInfo = ({action, deleteAction}) => {
|
||||
console.log("action", action)
|
||||
return (
|
||||
<Card sx={{maxWidth: 300}}>
|
||||
<CardHeader
|
||||
avatar={
|
||||
<HandymanIcon color="primary" sx={{width: "30px", height: "30px"}}/>
|
||||
}
|
||||
title={"متن تست"}
|
||||
subheader={"ساب آیتم تست"}
|
||||
/>
|
||||
<CardContent>
|
||||
<Stack sx={{gap: 2}}>
|
||||
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}>
|
||||
<Chip size="small" label="تاریخ" icon={<CalendarMonthIcon/>}/>
|
||||
<Divider sx={{flex: 1, mx: 2}}/>
|
||||
<Typography sx={{fontSize: "12px", fontWeight: 500, textDecoration: "underline"}}>
|
||||
{moment(action.start_date).locale("fa").format("YYYY/MM/DD")}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}>
|
||||
<Chip size="small" label="ساعت" icon={<WatchLaterIcon/>}/>
|
||||
<Divider sx={{flex: 1, mx: 2}}/>
|
||||
<Typography sx={{fontSize: "12px", fontWeight: 500, textDecoration: "underline"}}>
|
||||
{action.action_date}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
<CardActions disableSpacing>
|
||||
<IconButton aria-label="حذف فعالیت" color="error">
|
||||
<DeleteIcon/>
|
||||
</IconButton>
|
||||
<IconButton aria-label="ویرایش فعالیت" color="primary">
|
||||
<EditIcon/>
|
||||
</IconButton>
|
||||
</CardActions>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionInfo;
|
||||
@@ -0,0 +1,58 @@
|
||||
"use client";
|
||||
|
||||
import {Box, Button, Divider, Grid, Typography} from "@mui/material";
|
||||
import AddCircleIcon from '@mui/icons-material/AddCircle';
|
||||
import React, {useState} from "react";
|
||||
import ModalActionsDuringPatrol from "./ModalActionsDuringPatrol";
|
||||
import ActionInfo from "./ActionInfo";
|
||||
|
||||
const ActionsDuringPatrol = ({tabState, setTabState}) => {
|
||||
const [ActionsList, setActionsList] = useState([]);
|
||||
const [open, setOpen] = useState(false);
|
||||
const handleOpen = () => {
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const deleteAction = (indexToRemove) => {
|
||||
setActionsList((prev) => prev.filter((_, index) => index !== indexToRemove));
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}>
|
||||
<Typography variant="h6">لیست اقدامات حین گشت</Typography>
|
||||
<Button onClick={handleOpen} startIcon={<AddCircleIcon/>} variant="outlined"
|
||||
sx={{mb: 1, alignSelf: "end"}}>
|
||||
ثبت اقدام
|
||||
</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}
|
||||
deleteAction={() => deleteAction(index)}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
:
|
||||
<Box sx={{my: 5, width: "100%", textAlign: "center"}}>
|
||||
<Typography variant="h6" sx={{letterSpacing: "2px", color: "#606060"}}>
|
||||
فعالیتی ثبت نکرده اید
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionsDuringPatrol;
|
||||
@@ -0,0 +1,17 @@
|
||||
import CreateFormContent from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/CreateFormContent";
|
||||
import {Dialog} from "@mui/material";
|
||||
|
||||
const ModalActionsDuringPatrol = ({open, setOpen, setActionsList}) => {
|
||||
|
||||
const HandleSubmit = async (data) => {
|
||||
setActionsList((prev) => [...prev, data]);
|
||||
setOpen(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} fullWidth maxWidth="sm">
|
||||
<CreateFormContent setOpen={setOpen} onSubmit={HandleSubmit}/>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
export default ModalActionsDuringPatrol;
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
CardActions,
|
||||
CardContent,
|
||||
Chip,
|
||||
Divider,
|
||||
@@ -243,6 +244,18 @@ const PatrolDetail = ({tabState, setTabState}) => {
|
||||
</Box>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
<CardActions sx={{alignItems: "center", justifyContent: "center"}}>
|
||||
<Box sx={{display: "flex", gap: 1}}>
|
||||
<Button variant="outlined" color="error"
|
||||
startIcon={<KeyboardDoubleArrowRightIcon/>} sx={{mt: 2}}>
|
||||
بازگشت
|
||||
</Button>
|
||||
<Button variant="contained" color="primary" onClick={() => setTabState(tabState + 1)}
|
||||
endIcon={<KeyboardDoubleArrowLeftIcon/>} sx={{mt: 2}}>
|
||||
تایید اطلاعات و رفتن به مرحله بعد
|
||||
</Button>
|
||||
</Box>
|
||||
</CardActions>
|
||||
</Card>
|
||||
</Slide> :
|
||||
<Box sx={{my: 5}}>
|
||||
@@ -250,16 +263,6 @@ const PatrolDetail = ({tabState, setTabState}) => {
|
||||
ابتدا اطلاعات بالا را تکمیل نمایید
|
||||
</Typography>
|
||||
</Box>}
|
||||
<Box sx={{display: "flex", gap: 1}}>
|
||||
<Button variant="outlined" color="error"
|
||||
startIcon={<KeyboardDoubleArrowRightIcon/>} sx={{mt: 2}}>
|
||||
بازگشت
|
||||
</Button>
|
||||
<Button variant="contained" color="primary" onClick={() => setTabState(tabState + 1)}
|
||||
endIcon={<KeyboardDoubleArrowLeftIcon/>} sx={{mt: 2}}>
|
||||
تایید اطلاعات و رفتن به مرحله بعد
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -11,7 +11,8 @@ import VerifiedIcon from '@mui/icons-material/Verified';
|
||||
import PatrolTimeLine from "./PatrolTimeLine";
|
||||
import PhoneValidation from "./PhoneValidation";
|
||||
import PatrolDetail from "./PatrolDetail";
|
||||
import SuperVisorsDetail from "@/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorsDetail";
|
||||
import SuperVisorsDetail from "./SuperVisorsDetail";
|
||||
import ActionsDuringPatrol from "./ActionsDurigPatrol";
|
||||
|
||||
function TabPanel(props) {
|
||||
const {children, value, index} = props;
|
||||
@@ -72,7 +73,7 @@ const PatrolForms = () => {
|
||||
<SuperVisorsDetail tabState={tabState} setTabState={setTabState}/>
|
||||
</TabPanel>
|
||||
<TabPanel value={tabState} index={3}>
|
||||
<>eghdamat heine gasht</>
|
||||
<ActionsDuringPatrol tabState={tabState} setTabState={setTabState}/>
|
||||
</TabPanel>
|
||||
<TabPanel value={tabState} index={4}>
|
||||
<>taiidie</>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import {Box, Card, IconButton, Stack, Typography} from "@mui/material";
|
||||
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import React from "react";
|
||||
|
||||
const SuperVisorInfo = ({superVisor, deleteSuperVisor}) => {
|
||||
return (
|
||||
<Card elevation={3} sx={{
|
||||
display: "flex", alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
px: 1, py: 1,
|
||||
}}>
|
||||
<Box sx={{display: "flex"}}>
|
||||
<AccountCircleIcon color="primary" sx={{width: "50px", height: "50px"}}/>
|
||||
<Stack sx={{ml: 1, justifyContent: "center"}}>
|
||||
<Typography variant="body1"
|
||||
sx={{letterSpacing: "1px", fontWeight: 500}}>{superVisor.name}</Typography>
|
||||
<Typography variant="caption">کد راهدار: {superVisor.code}</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Box>
|
||||
<IconButton color="error" onClick={() => deleteSuperVisor(superVisor.id)}><DeleteIcon/></IconButton>
|
||||
</Box>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default SuperVisorInfo;
|
||||
@@ -1,21 +1,32 @@
|
||||
"use client";
|
||||
|
||||
import {Box, Button, Card, Chip, Divider, IconButton, TextField, Typography} from "@mui/material";
|
||||
import {Box, Button, Chip, Divider, Grid, Typography} from "@mui/material";
|
||||
import SaveAltIcon from '@mui/icons-material/SaveAlt';
|
||||
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import React, {useState} from "react";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import RahdarCode from "@/core/components/RahdarCode";
|
||||
import SuperVisorInfo from "@/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorInfo";
|
||||
import KeyboardDoubleArrowRightIcon from "@mui/icons-material/KeyboardDoubleArrowRight";
|
||||
import KeyboardDoubleArrowLeftIcon from "@mui/icons-material/KeyboardDoubleArrowLeft";
|
||||
|
||||
const SuperVisorsDetail = ({tabState, setTabState}) => {
|
||||
const [patrolFounded, setPatrolFounded] = useState(false);
|
||||
const [SuperVisorList, setSuperVisorList] = useState([]);
|
||||
const [rahdarsCode, setRahdarsCode] = useState(null);
|
||||
const [readyToRequest, setReadyToRequest] = useState(false);
|
||||
|
||||
const requestPatrolInfo = () => {
|
||||
setPatrolFounded(true)
|
||||
setReadyToRequest(false)
|
||||
setSuperVisorList((prev) => [...prev, rahdarsCode]);
|
||||
setReadyToRequest(false);
|
||||
setRahdarsCode(null);
|
||||
}
|
||||
|
||||
const deleteSuperVisor = (id) => {
|
||||
setSuperVisorList((prev) => prev.filter((superVisor) => superVisor.id !== id));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setReadyToRequest(rahdarsCode != null);
|
||||
}, [rahdarsCode]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
@@ -26,69 +37,77 @@ const SuperVisorsDetail = ({tabState, setTabState}) => {
|
||||
my: 3
|
||||
}}
|
||||
>
|
||||
<Box sx={{display: "flex", flexDirection: {xs: "column", lg: "row"}, gap: 2}}>
|
||||
<Box sx={{minWidth: "200px"}}>
|
||||
{/*<RahdarCode rahdarsCode={rahdarsCode} setRahdarsCode={setRahdarsCode}/>*/}
|
||||
<TextField
|
||||
id="outlined-required"
|
||||
label="کد راهدار"
|
||||
size="small"
|
||||
/>
|
||||
</Box>
|
||||
<Button variant="contained" onClick={requestPatrolInfo}
|
||||
color="success"
|
||||
disabled={!readyToRequest}
|
||||
endIcon={<SaveAltIcon/>}
|
||||
>
|
||||
ثبت راهدار
|
||||
</Button>
|
||||
</Box>
|
||||
<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}}>
|
||||
<RahdarCode rahdarsCode={rahdarsCode} setRahdarsCode={setRahdarsCode} multiple={false}/>
|
||||
<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>
|
||||
<Box sx={{
|
||||
width: "100%",
|
||||
p: 1,
|
||||
maxHeight: "300px",
|
||||
overflowY: "auto"
|
||||
}}>
|
||||
<Card sx={{
|
||||
display: "flex", alignItems: "center",
|
||||
justifyContent: "space-between", width: "100%",
|
||||
px: 2, py: 1, my: 2,
|
||||
background: "#f7f7f7"
|
||||
}}>
|
||||
<Box sx={{display: "flex"}}>
|
||||
<AccountCircleIcon color="primary" sx={{width: "50px", height: "50px"}}/>
|
||||
<Box sx={{ml: 1}}>
|
||||
<Typography variant="h6" sx={{letterSpacing: "1px"}}>محمد حسین</Typography>
|
||||
<Typography variant="caption">کد راهدار: 893</Typography>
|
||||
</Box>
|
||||
{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
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: 1,
|
||||
mt: 2,
|
||||
width: "100%",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
startIcon={<KeyboardDoubleArrowRightIcon/>}
|
||||
sx={{mt: 2}}
|
||||
>
|
||||
بازگشت
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => setTabState(tabState + 1)}
|
||||
endIcon={<KeyboardDoubleArrowLeftIcon/>}
|
||||
sx={{mt: 2}}
|
||||
>
|
||||
تایید اطلاعات و رفتن به مرحله بعد
|
||||
</Button>
|
||||
</Box>
|
||||
<Box>
|
||||
<IconButton color="error"><DeleteIcon/></IconButton>
|
||||
</Box>
|
||||
</Card>
|
||||
<Card sx={{
|
||||
display: "flex", width: "100%",
|
||||
alignItems: "center", justifyContent: "space-between",
|
||||
px: 2, py: 1, my: 2,
|
||||
background: "#f7f7f7"
|
||||
}}>
|
||||
<Box sx={{display: "flex"}}>
|
||||
<AccountCircleIcon color="primary" sx={{width: "50px", height: "50px"}}/>
|
||||
<Box sx={{ml: 1}}>
|
||||
<Typography variant="h6" sx={{letterSpacing: "1px"}}>حسین تقی</Typography>
|
||||
<Typography variant="caption">کد راهدار: 123</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<IconButton color="error"><DeleteIcon/></IconButton>
|
||||
</Box>
|
||||
</Card>
|
||||
</Box>
|
||||
</>
|
||||
) : (
|
||||
<Box sx={{my: 5, width: "100%", textAlign: "center"}}>
|
||||
<Typography variant="h6" sx={{letterSpacing: "2px", color: "#606060"}}>
|
||||
ابتدا اطلاعات بالا را تکمیل نمایید
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default SuperVisorsDetail;
|
||||
export default SuperVisorsDetail;
|
||||
|
||||
@@ -18,6 +18,8 @@ const OperatorList = () => {
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "operator_name",
|
||||
@@ -29,9 +31,9 @@ const OperatorList = () => {
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
},
|
||||
{
|
||||
accessorKey: "phone_number",
|
||||
accessorKey: "officer_phone_number",
|
||||
header: "تلفن همراه",
|
||||
id: "phone_number",
|
||||
id: "officer_phone_number",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
@@ -47,46 +49,37 @@ const OperatorList = () => {
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
},
|
||||
{
|
||||
accessorKey: "start_date",
|
||||
accessorFn: (row) => moment(row.start_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ شروع",
|
||||
id: "start_date",
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
Cell: ({ renderedCellValue }) => (
|
||||
<Typography variant="body2">
|
||||
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("YYYY/MM/DD") : "-"}
|
||||
</Typography>
|
||||
),
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "end_date",
|
||||
accessorFn: (row) => moment(row.end_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ پایان",
|
||||
id: "end_date",
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
Cell: ({ renderedCellValue }) => (
|
||||
<Typography variant="body2">
|
||||
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("YYYY/MM/DD") : "-"}
|
||||
</Typography>
|
||||
),
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "register_date",
|
||||
accessorFn: (row) => moment(row.register_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ ثبت",
|
||||
id: "register_date",
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
Cell: ({ renderedCellValue }) => (
|
||||
<Typography variant="body2">
|
||||
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("YYYY/MM/DD") : "-"}
|
||||
</Typography>
|
||||
),
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
],
|
||||
[]
|
||||
@@ -99,6 +92,7 @@ const OperatorList = () => {
|
||||
table_title={"عملیات"}
|
||||
need_filter={true}
|
||||
columns={columns}
|
||||
sorting={[{ id: "id", desc: true }]}
|
||||
table_url={GET_ROAD_PATROL_OPERATOR_LIST}
|
||||
page_name={"operator"}
|
||||
table_name={"operatorList"}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Tooltip, IconButton } from "@mui/material";
|
||||
import PrintIcon from "@mui/icons-material/Print";
|
||||
|
||||
const ReportForm = ({ rowId }) => {
|
||||
const reportUrl = "https://rms.rmto.ir/v2/road_patrols/operator/report/97314"; // TODO replace id here
|
||||
const reportUrl = "https://rms.rmto.ir/v2/road_patrols/operator/report/96872"; // TODO replace id here
|
||||
|
||||
return (
|
||||
<Tooltip title="گزارش" arrow placement="right">
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Tooltip, IconButton } from "@mui/material";
|
||||
import PrintIcon from "@mui/icons-material/Print";
|
||||
|
||||
const ReportForm = ({ rowId }) => {
|
||||
const reportUrl = "https://rms.rmto.ir/v2/road_patrols/operator/report/541938"; // TODO replace id here
|
||||
const reportUrl = "https://rms.rmto.ir/v2/road_patrols/operator/report/96872"; // TODO replace id here
|
||||
|
||||
return (
|
||||
<Tooltip title="گزارش" arrow placement="right">
|
||||
|
||||
@@ -7,10 +7,11 @@ import { GET_ROAD_PATROL_SUPERVISOR_LIST } from "@/core/utils/routes";
|
||||
import moment from "jalali-moment";
|
||||
import RowActions from "./RowActions";
|
||||
import useProvinces from "@/lib/hooks/useProvince";
|
||||
import useRoadItemGetItems from "@/lib/hooks/useRoadItemGetItems";
|
||||
import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
|
||||
import useEdaratLists from "@/lib/hooks/useEdaratLists";
|
||||
|
||||
const OperatorList = () => {
|
||||
const { provinces, errorProvinces, loadingProvinces } = useProvinces();
|
||||
const citiesListApi = "https://rms.rmto.ir/public/contents/edarate_shahri_by_province";
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
@@ -21,44 +22,74 @@ const OperatorList = () => {
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "province",
|
||||
accessorKey: "province_id",
|
||||
header: "استان",
|
||||
id: "province",
|
||||
id: "province_id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "numeric",
|
||||
filterMode: "equals",
|
||||
columnSelectOption: () => {
|
||||
if (loadingProvinces) {
|
||||
return [{ value: "", label: "در حال بارگذاری..." }];
|
||||
}
|
||||
|
||||
if (errorProvinces) {
|
||||
return [{ value: "", label: "خطا در بارگذاری" }];
|
||||
}
|
||||
|
||||
return provinces.map((province) => ({
|
||||
value: province.id,
|
||||
label: province.name_fa,
|
||||
}));
|
||||
ColumnSelectComponent: (props) => {
|
||||
const { provinces, errorProvinces, loadingProvinces } = useProvinces();
|
||||
const getColumnSelectOptions = () => {
|
||||
if (loadingProvinces) {
|
||||
return [{ value: "loading", label: "در حال بارگذاری..." }];
|
||||
}
|
||||
if (errorProvinces) {
|
||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||
}
|
||||
return [
|
||||
{ value: "", label: props.column.header },
|
||||
...provinces.map((province) => ({
|
||||
value: province.id,
|
||||
label: province.name_fa,
|
||||
})),
|
||||
];
|
||||
};
|
||||
const columnSelectOption = getColumnSelectOptions();
|
||||
return <CustomSelectByDependency {...props} columnSelectOption={columnSelectOption} />;
|
||||
},
|
||||
Cell: ({ renderedCellValue, row }) => <>{row.original.province_fa}</>,
|
||||
},
|
||||
{
|
||||
accessorKey: "office",
|
||||
accessorKey: "edare_id",
|
||||
header: "اداره",
|
||||
id: "office",
|
||||
id: "edare_id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "numeric",
|
||||
filterMode: "equals",
|
||||
dependencyId: "province",
|
||||
columnSelectOption: (dependencyField) => {
|
||||
if (dependencyField.value === "") {
|
||||
return [{ value: "", label: "ابتدا استان را انتخاب کنید" }];
|
||||
}
|
||||
|
||||
return [{ value: dependencyField.value, label: dependencyField.value }];
|
||||
dependencyId: "province_id",
|
||||
grow: false,
|
||||
size: 120,
|
||||
ColumnSelectComponent: (props) => {
|
||||
const { edaratList, loadingEdaratList, errorEdaratList } = useEdaratLists(
|
||||
props.dependencyFieldValue.value
|
||||
);
|
||||
const getColumnSelectOptions = () => {
|
||||
if (props.dependencyFieldValue.value === "") {
|
||||
return [{ value: "empty", label: "ابتدا استان را انتخاب کنید" }];
|
||||
}
|
||||
if (loadingEdaratList) {
|
||||
return [{ value: "loading", label: "در حال بارگذاری..." }];
|
||||
}
|
||||
if (errorEdaratList) {
|
||||
return [{ value: "error", label: "خطا در بارگذاری" }];
|
||||
}
|
||||
return [
|
||||
{ value: "", label: props.column.header },
|
||||
...edaratList.map((edare) => ({
|
||||
value: edare.id,
|
||||
label: edare.name_fa,
|
||||
})),
|
||||
];
|
||||
};
|
||||
const columnSelectOption = getColumnSelectOptions();
|
||||
return <CustomSelectByDependency {...props} columnSelectOption={columnSelectOption} />;
|
||||
},
|
||||
Cell: ({ renderedCellValue, row }) => <>{row.original.edare_name}</>,
|
||||
},
|
||||
{
|
||||
accessorKey: "operator_name",
|
||||
@@ -70,9 +101,9 @@ const OperatorList = () => {
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
},
|
||||
{
|
||||
accessorKey: "phone_number",
|
||||
accessorKey: "officer_phone_number",
|
||||
header: "تلفن همراه",
|
||||
id: "phone_number",
|
||||
id: "officer_phone_number",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
@@ -88,49 +119,40 @@ const OperatorList = () => {
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
},
|
||||
{
|
||||
accessorKey: "start_date",
|
||||
accessorFn: (row) => moment(row.start_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ شروع",
|
||||
id: "start_date",
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
Cell: ({ renderedCellValue }) => (
|
||||
<Typography variant="body2">
|
||||
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("YYYY/MM/DD") : "-"}
|
||||
</Typography>
|
||||
),
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "end_date",
|
||||
accessorFn: (row) => moment(row.end_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ پایان",
|
||||
id: "end_date",
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
Cell: ({ renderedCellValue }) => (
|
||||
<Typography variant="body2">
|
||||
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("YYYY/MM/DD") : "-"}
|
||||
</Typography>
|
||||
),
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorKey: "register_date",
|
||||
accessorFn: (row) => moment(row.register_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ ثبت",
|
||||
id: "register_date",
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterMode: "equals",
|
||||
columnFilterModeOptions: ["equals", "contains"],
|
||||
Cell: ({ renderedCellValue }) => (
|
||||
<Typography variant="body2">
|
||||
{renderedCellValue ? moment(renderedCellValue).locale("fa").format("YYYY/MM/DD") : "-"}
|
||||
</Typography>
|
||||
),
|
||||
grow: false,
|
||||
size: 100,
|
||||
},
|
||||
],
|
||||
[provinces]
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -140,6 +162,7 @@ const OperatorList = () => {
|
||||
table_title={"ارزیابی"}
|
||||
need_filter={true}
|
||||
columns={columns}
|
||||
sorting={[{ id: "id", desc: true }]}
|
||||
table_url={GET_ROAD_PATROL_SUPERVISOR_LIST}
|
||||
page_name={"supervisor"}
|
||||
table_name={"supervisorList"}
|
||||
|
||||
@@ -4,11 +4,12 @@ import useRequest from "@/lib/hooks/useRequest";
|
||||
import { debounce } from "@mui/material/utils";
|
||||
import { GET_CAR_LIST_SEARCH } from "@/core/utils/routes";
|
||||
|
||||
const CarCode = ({ carCode, setCarCode, inputValueDefault = "", error }) => {
|
||||
const CarCode = ({ carCode, setCarCode, inputValueDefault = "", error, multiple = false }) => {
|
||||
const [inputValue, setInputValue] = useState(inputValueDefault);
|
||||
const [options, setOptions] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const requestServer = useRequest();
|
||||
|
||||
const fetchCarCodes = (inputValue, controller) => {
|
||||
const debouncer = debounce((query) => {
|
||||
if (!query || query?.length < 3) {
|
||||
@@ -40,20 +41,32 @@ const CarCode = ({ carCode, setCarCode, inputValueDefault = "", error }) => {
|
||||
|
||||
return (
|
||||
<Autocomplete
|
||||
multiple={multiple}
|
||||
value={carCode}
|
||||
size="small"
|
||||
onChange={(event, newValue) => {
|
||||
setCarCode(newValue || null); // Set an empty string if no value is selected
|
||||
setCarCode(multiple ? newValue || [] : newValue || null);
|
||||
}}
|
||||
inputValue={inputValue}
|
||||
onInputChange={(event, newInputValue) => {
|
||||
setInputValue(newInputValue || ""); // Prevent inputValue from being null or undefined
|
||||
}}
|
||||
options={options}
|
||||
getOptionLabel={(option) => (typeof option === "string" ? option : option.machine_code)}
|
||||
getOptionLabel={(option) => {
|
||||
if (typeof option === "string") return option;
|
||||
const { machine_code, car_name, plak_number } = option;
|
||||
let label = `${machine_code || ""}`;
|
||||
if (car_name) {
|
||||
label += ` | ${car_name}`;
|
||||
}
|
||||
if (plak_number) {
|
||||
label += ` | ${plak_number}`;
|
||||
}
|
||||
return label;
|
||||
}}
|
||||
isOptionEqualToValue={(option, value) => {
|
||||
if (!value) return false; // Handle null/undefined values
|
||||
if (value === "") return option.machine_code === ""; // Handle empty string case
|
||||
if (!value) return false;
|
||||
if (value === "") return option.machine_code === "";
|
||||
return option.machine_code === (value?.machine_code || value);
|
||||
}}
|
||||
loading={loading}
|
||||
@@ -65,8 +78,8 @@ const CarCode = ({ carCode, setCarCode, inputValueDefault = "", error }) => {
|
||||
{...params}
|
||||
label="کد خودرو"
|
||||
fullWidth
|
||||
error={!!error} // نمایش خطا
|
||||
helperText={error?.message} // پیام خطا
|
||||
error={!!error}
|
||||
helperText={error?.message}
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
endAdornment: (
|
||||
|
||||
@@ -42,8 +42,9 @@ const DataTable_Main = (props) => {
|
||||
|
||||
const filteredFilterData = Object.values(filterData)
|
||||
.filter((filter) => !isValueEmpty(filter.value))
|
||||
.map(({ filterMode, ...rest }) => ({
|
||||
.map(({ filterMode, id, ...rest }) => ({
|
||||
...rest,
|
||||
id: id.replace(/__/g, "."),
|
||||
fn: filterMode,
|
||||
}));
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Controller, useWatch } from "react-hook-form";
|
||||
import FilterBodyField from "./FilterBodyField";
|
||||
|
||||
const FilterBodyController = ({ column, control, reset, errors }) => {
|
||||
const dependencyField = useWatch({ control, name: column?.dependencyId });
|
||||
const dependencyField = useWatch({ control, name: column.dependencyId });
|
||||
|
||||
return (
|
||||
<Controller
|
||||
@@ -14,7 +14,7 @@ const FilterBodyController = ({ column, control, reset, errors }) => {
|
||||
filterParameters={value}
|
||||
handleChange={onChange}
|
||||
handleBlur={onBlur}
|
||||
dependencyFieldValue={dependencyField || null}
|
||||
dependencyFieldValue={column.dependencyId ? dependencyField : null}
|
||||
resetForm={() => reset()}
|
||||
errors={errors}
|
||||
/>
|
||||
|
||||
@@ -54,10 +54,13 @@ function FilterBodyField({
|
||||
return <CustomTextFieldRange {...commonProps} />;
|
||||
}
|
||||
if (filterParameters.filterMode === "equals") {
|
||||
return <CustomSelect {...commonProps} />;
|
||||
return column.ColumnSelectComponent ? (
|
||||
<column.ColumnSelectComponent {...commonProps} />
|
||||
) : (
|
||||
<CustomSelect {...commonProps} />
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case "date":
|
||||
if (filterParameters.filterMode === "equals") {
|
||||
return <CustomDatePicker {...commonProps} />;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
"use client";
|
||||
|
||||
import { FormControl, FormHelperText, InputLabel, MenuItem, OutlinedInput, Select, Typography } from "@mui/material";
|
||||
import { useCallback, useEffect } from "react";
|
||||
|
||||
function CustomSelectByDependency({
|
||||
column,
|
||||
filterParameters,
|
||||
defaultFilterTranslation,
|
||||
handleChange,
|
||||
columnSelectOption,
|
||||
}) {
|
||||
const isValidValue = columnSelectOption.some((option) => option.value === filterParameters.value);
|
||||
|
||||
const handleInvalidValue = useCallback(() => {
|
||||
if (!isValidValue && filterParameters.value !== "") {
|
||||
handleChange({ ...filterParameters, value: columnSelectOption[0]?.value || "" });
|
||||
}
|
||||
}, [isValidValue, filterParameters, handleChange, columnSelectOption]);
|
||||
|
||||
useEffect(() => {
|
||||
handleInvalidValue();
|
||||
}, [handleInvalidValue]);
|
||||
|
||||
const selectedValue = isValidValue ? filterParameters.value : columnSelectOption[0]?.value || "";
|
||||
|
||||
return (
|
||||
<FormControl fullWidth sx={{ marginY: 1 }}>
|
||||
<InputLabel id={`label${column.id}`}>{column.header}</InputLabel>
|
||||
<Select
|
||||
labelId={`label${column.id}`}
|
||||
id={column.id}
|
||||
name={`${column.id}.value`}
|
||||
value={selectedValue}
|
||||
input={<OutlinedInput label={column.header} />}
|
||||
onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
|
||||
>
|
||||
{columnSelectOption.map((option) => (
|
||||
<MenuItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
<Typography variant="button" sx={{ color: "#155175" }}>
|
||||
نوع فیلتر: {defaultFilterTranslation}
|
||||
</Typography>
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
||||
|
||||
export default CustomSelectByDependency;
|
||||
@@ -9,14 +9,16 @@ function FilterColumn({ columns, user_id, page_name, table_name }) {
|
||||
return (
|
||||
<>
|
||||
<FilterButton drawerState={open} setDrawerState={setOpen} />
|
||||
<FilterBody
|
||||
columns={columns}
|
||||
drawerState={open}
|
||||
setDrawerState={setOpen}
|
||||
user_id={user_id}
|
||||
page_name={page_name}
|
||||
table_name={table_name}
|
||||
/>
|
||||
{open && (
|
||||
<FilterBody
|
||||
columns={columns}
|
||||
drawerState={open}
|
||||
setDrawerState={setOpen}
|
||||
user_id={user_id}
|
||||
page_name={page_name}
|
||||
table_name={table_name}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import useDataTable from "@/lib/hooks/useDataTable";
|
||||
|
||||
function ResetStorage({ user_id, page_name, table_name }) {
|
||||
const { resetAction } = useTableSetting();
|
||||
const { isDirty } = useDataTable();
|
||||
const { isAnyDirty } = useDataTable();
|
||||
const reset = () => {
|
||||
resetAction(user_id, page_name, table_name);
|
||||
};
|
||||
@@ -14,7 +14,7 @@ function ResetStorage({ user_id, page_name, table_name }) {
|
||||
return (
|
||||
<Tooltip title="بازنشانی اطلاعات">
|
||||
<IconButton onClick={reset} aria-label="reset table data">
|
||||
{isDirty ? (
|
||||
{isAnyDirty ? (
|
||||
<Badge
|
||||
anchorOrigin={{
|
||||
vertical: "top",
|
||||
|
||||
@@ -9,13 +9,14 @@ const InputType = ({ itemInfo, defaultValues, setDefaultValues }) => {
|
||||
[itemInfo.id]: value,
|
||||
}));
|
||||
};
|
||||
const label = itemInfo.unit ? `${itemInfo.name} (${itemInfo.unit})` : itemInfo.name;
|
||||
|
||||
return (
|
||||
<FormControl size="small" fullWidth variant="outlined">
|
||||
<InputLabel htmlFor={itemInfo.id}>{itemInfo.name}</InputLabel>
|
||||
<InputLabel htmlFor={itemInfo.id}>{label}</InputLabel>
|
||||
<OutlinedInput
|
||||
id={itemInfo.id}
|
||||
label={itemInfo.name}
|
||||
label={label}
|
||||
autoComplete="off"
|
||||
size="small"
|
||||
fullWidth
|
||||
|
||||
@@ -9,15 +9,15 @@ const SelectType = ({ itemInfo, defaultValues, setDefaultValues }) => {
|
||||
[itemInfo.id]: newValue,
|
||||
}));
|
||||
};
|
||||
|
||||
const label = itemInfo.unit ? `${itemInfo.name} (${itemInfo.unit})` : itemInfo.name;
|
||||
return (
|
||||
<FormControl size="small" fullWidth variant="outlined">
|
||||
<InputLabel id={itemInfo.id}>{itemInfo.name}</InputLabel>
|
||||
<InputLabel id={itemInfo.id}>{label}</InputLabel>
|
||||
<Select
|
||||
labelId={itemInfo.id}
|
||||
id={itemInfo.id}
|
||||
value={defaultValues[itemInfo.id] || ""}
|
||||
label={itemInfo.name}
|
||||
label={label}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<MenuItem value="">{itemInfo.name}</MenuItem>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from "react";
|
||||
import { Marker, useMapEvents } from "react-leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import L from "leaflet";
|
||||
import { Box, Button, Typography } from "@mui/material";
|
||||
import { Alert, Box, Button, Stack, Typography, Zoom } from "@mui/material";
|
||||
import dynamic from "next/dynamic";
|
||||
import MapLoading from "@/core/components/MapLayer/Loading";
|
||||
import HereIcon from "@/assets/images/examine_marker_active.png";
|
||||
@@ -40,9 +40,11 @@ const createCustomIcon = (size, iconUrl, labelText) => {
|
||||
popupAnchor: [0, -size[1]],
|
||||
});
|
||||
};
|
||||
const MAX_ZOOM_FOR_MARKER = 13;
|
||||
|
||||
const MapInteraction = ({ setValue, startLat, startLng }) => {
|
||||
const [isMarkerLocked, setIsMarkerLocked] = useState(!!(startLat && startLng)); // وضعیت قفل مارکر
|
||||
const [enableSend, setEnableSend] = useState(false);
|
||||
const [markerPosition, setMarkerPosition] = useState(
|
||||
startLat && startLng ? { lat: startLat, lng: startLng } : null
|
||||
);
|
||||
@@ -50,11 +52,13 @@ const MapInteraction = ({ setValue, startLat, startLng }) => {
|
||||
|
||||
const map = useMapEvents({
|
||||
move(e) {
|
||||
setEnableSend(e.target.getZoom() > MAX_ZOOM_FOR_MARKER);
|
||||
if (!isMarkerLocked && markerRef.current) {
|
||||
markerRef.current.setLatLng(e.target.getCenter());
|
||||
}
|
||||
},
|
||||
zoom(e) {
|
||||
setEnableSend(e.target.getZoom() > MAX_ZOOM_FOR_MARKER);
|
||||
if (!isMarkerLocked && markerRef.current) {
|
||||
markerRef.current.setLatLng(e.target.getCenter());
|
||||
}
|
||||
@@ -69,6 +73,7 @@ const MapInteraction = ({ setValue, startLat, startLng }) => {
|
||||
}, [startLat, startLng, map]);
|
||||
|
||||
const handleMarkerClick = () => {
|
||||
if (!enableSend) return;
|
||||
if (!isMarkerLocked) {
|
||||
const center = map.getCenter();
|
||||
setValue("start_point", { lat: center.lat.toString(), lng: center.lng.toString() });
|
||||
@@ -93,6 +98,23 @@ const MapInteraction = ({ setValue, startLat, startLng }) => {
|
||||
click: handleMarkerClick,
|
||||
}}
|
||||
/>
|
||||
<Stack
|
||||
direction={"row"}
|
||||
justifyContent={"center"}
|
||||
sx={{
|
||||
zIndex: "400",
|
||||
width: "100%",
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
}}
|
||||
>
|
||||
<Zoom in={!enableSend}>
|
||||
<Alert sx={{ mt: 1, py: 0.5, px: 2, borderRadius: 2, border: 1 }} icon={false} color={"warning"}>
|
||||
برای ثبت محل فعالیت، لطفاً نقشه را بیشتر زوم کنید.
|
||||
</Alert>
|
||||
</Zoom>
|
||||
</Stack>
|
||||
{isMarkerLocked && (
|
||||
<Box
|
||||
sx={{
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from "react";
|
||||
import { Marker, useMapEvents } from "react-leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import L from "leaflet";
|
||||
import { Box, Button, Typography } from "@mui/material";
|
||||
import { Alert, Box, Button, Stack, Typography, Zoom } from "@mui/material";
|
||||
import dynamic from "next/dynamic";
|
||||
import MapLoading from "@/core/components/MapLayer/Loading";
|
||||
import EndIcon from "@/assets/images/examine_marker_active.png";
|
||||
@@ -40,17 +40,20 @@ const createCustomIcon = (size, iconUrl, labelText) => {
|
||||
popupAnchor: [0, -size[1]],
|
||||
});
|
||||
};
|
||||
const MAX_ZOOM_FOR_MARKER = 13;
|
||||
|
||||
const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
||||
const [isStartLocked, setIsStartLocked] = useState(!!(startLat && startLng)); // وضعیت قفل نقطه آغاز
|
||||
const [isEndLocked, setIsEndLocked] = useState(!!(endLat && endLng)); // وضعیت قفل نقطه پایان
|
||||
const [startPosition, setStartPosition] = useState(startLat && startLng ? { lat: startLat, lng: startLng } : null);
|
||||
const [endPosition, setEndPosition] = useState(endLat && endLng ? { lat: endLat, lng: endLng } : null);
|
||||
const [enableSend, setEnableSend] = useState(false);
|
||||
const startRef = useRef();
|
||||
const endRef = useRef();
|
||||
|
||||
const map = useMapEvents({
|
||||
move(e) {
|
||||
setEnableSend(e.target.getZoom() > MAX_ZOOM_FOR_MARKER);
|
||||
if (!isStartLocked && startRef.current) {
|
||||
startRef.current.setLatLng(e.target.getCenter());
|
||||
} else if (isStartLocked && !isEndLocked && endRef.current) {
|
||||
@@ -58,6 +61,7 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
||||
}
|
||||
},
|
||||
zoom(e) {
|
||||
setEnableSend(e.target.getZoom() > MAX_ZOOM_FOR_MARKER);
|
||||
if (!isStartLocked && startRef.current) {
|
||||
startRef.current.setLatLng(e.target.getCenter());
|
||||
} else if (isStartLocked && !isEndLocked && endRef.current) {
|
||||
@@ -101,6 +105,7 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
||||
icon={createCustomIcon([35, 35], StartIcon.src, "نقطه شروع")}
|
||||
eventHandlers={{
|
||||
click: () => {
|
||||
if (!enableSend) return;
|
||||
if (!isStartLocked) {
|
||||
const center = map.getCenter();
|
||||
setValue("start_point", { lat: center.lat.toString(), lng: center.lng.toString() });
|
||||
@@ -110,6 +115,23 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Stack
|
||||
direction={"row"}
|
||||
justifyContent={"center"}
|
||||
sx={{
|
||||
zIndex: "400",
|
||||
width: "100%",
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
}}
|
||||
>
|
||||
<Zoom in={!enableSend}>
|
||||
<Alert sx={{ mt: 1, py: 0.5, px: 2, borderRadius: 2, border: 1 }} icon={false} color={"warning"}>
|
||||
برای ثبت محل فعالیت، لطفاً نقشه را بیشتر زوم کنید.
|
||||
</Alert>
|
||||
</Zoom>
|
||||
</Stack>
|
||||
{isStartLocked && !isEndLocked && (
|
||||
<Box
|
||||
sx={{
|
||||
@@ -125,21 +147,45 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
||||
</Box>
|
||||
)}
|
||||
{isStartLocked && (
|
||||
<Marker
|
||||
position={endPosition || map.getCenter()}
|
||||
ref={endRef}
|
||||
icon={createCustomIcon([35, 35], EndIcon.src, "نقطه پایان")}
|
||||
eventHandlers={{
|
||||
click: () => {
|
||||
if (!isEndLocked) {
|
||||
const center = map.getCenter();
|
||||
setValue("end_point", { lat: center.lat.toString(), lng: center.lng.toString() });
|
||||
setEndPosition({ lat: center.lat, lng: center.lng });
|
||||
setIsEndLocked(true);
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
<Stack
|
||||
direction={"row"}
|
||||
justifyContent={"center"}
|
||||
sx={{
|
||||
zIndex: "400",
|
||||
width: "100%",
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
}}
|
||||
>
|
||||
<Zoom in={!enableSend}>
|
||||
<Alert
|
||||
sx={{ mt: 1, py: 0.5, px: 2, borderRadius: 2, border: 1 }}
|
||||
icon={false}
|
||||
color={"warning"}
|
||||
>
|
||||
برای ثبت محل فعالیت، لطفاً نقشه را بیشتر زوم کنید.
|
||||
</Alert>
|
||||
</Zoom>
|
||||
</Stack>
|
||||
<Marker
|
||||
position={endPosition || map.getCenter()}
|
||||
ref={endRef}
|
||||
icon={createCustomIcon([35, 35], EndIcon.src, "نقطه پایان")}
|
||||
eventHandlers={{
|
||||
click: () => {
|
||||
if (!enableSend) return;
|
||||
if (!isEndLocked) {
|
||||
const center = map.getCenter();
|
||||
setValue("end_point", { lat: center.lat.toString(), lng: center.lng.toString() });
|
||||
setEndPosition({ lat: center.lat, lng: center.lng });
|
||||
setIsEndLocked(true);
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{isEndLocked && (
|
||||
<Box
|
||||
|
||||
29
src/core/components/NumberField.jsx
Normal file
29
src/core/components/NumberField.jsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import LtrTextField from "@/core/components/LtrTextField";
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
|
||||
const NumberField = React.forwardRef((props, ref) => {
|
||||
return (
|
||||
<LtrTextField
|
||||
{...props}
|
||||
ref={ref}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<Stack direction="row" alignItems="center" spacing={0.5}>
|
||||
<Typography sx={{ margin: 1 }} component="span">
|
||||
{(props.value / 1).toLocaleString()}
|
||||
</Typography>
|
||||
<Typography component="span" variant="caption">
|
||||
{props.unit}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
NumberField.displayName = "NumberField";
|
||||
export default NumberField;
|
||||
@@ -5,7 +5,7 @@ import useRequest from "@/lib/hooks/useRequest";
|
||||
import { debounce } from "@mui/material/utils";
|
||||
import { GET_RAHDARANS_LIST_SEARCH } from "@/core/utils/routes";
|
||||
|
||||
const RahdarCode = ({ rahdarsCode, setRahdarsCode, error }) => {
|
||||
const RahdarCode = ({ rahdarsCode, setRahdarsCode, error, multiple = true }) => {
|
||||
const [inputValue, setInputValue] = useState(""); // مدیریت مقدار تایپشده
|
||||
const [options, setOptions] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -42,11 +42,11 @@ const RahdarCode = ({ rahdarsCode, setRahdarsCode, error }) => {
|
||||
|
||||
return (
|
||||
<Autocomplete
|
||||
multiple // قابلیت انتخاب چندگانه
|
||||
multiple={multiple} // قابلیت انتخاب چندگانه داینامیک
|
||||
value={rahdarsCode} // آرایه موارد انتخابشده
|
||||
size="small"
|
||||
onChange={(event, newValue) => {
|
||||
setRahdarsCode(newValue || []); // بهروزرسانی موارد انتخابشده
|
||||
setRahdarsCode(multiple ? newValue || [] : newValue || null); // مدیریت حالت چندگانه و تکگانه
|
||||
}}
|
||||
inputValue={inputValue} // مقدار تایپشده
|
||||
onInputChange={(event, newInputValue) => {
|
||||
@@ -86,5 +86,4 @@ const RahdarCode = ({ rahdarsCode, setRahdarsCode, error }) => {
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default RahdarCode;
|
||||
|
||||
62
src/core/components/ShowPlak.jsx
Normal file
62
src/core/components/ShowPlak.jsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { Stack } from "@mui/material";
|
||||
|
||||
const ShowPlak = ({ plak_number }) => {
|
||||
const processPlak = (plak_number) => {
|
||||
const parts = plak_number.match(/^([\u0600-\u06FF]+)(\d+)-(\d+)([^\d]*)(\d+)$/);
|
||||
if (!parts) return {};
|
||||
|
||||
return {
|
||||
region: parts[1], // "ايران"
|
||||
mainNumber: parts[2], // "13"
|
||||
serial: parts[3], // "189"
|
||||
letter: parts[4], // "الف"
|
||||
number: parts[5], // "15"
|
||||
};
|
||||
};
|
||||
const plakParts = processPlak(plak_number);
|
||||
|
||||
return (
|
||||
<Stack sx={{ border: 1, borderColor: "divider", borderRadius: 1, maxWidth: "150px" }} direction={"row"}>
|
||||
<Stack
|
||||
sx={{
|
||||
borderRight: 1,
|
||||
borderColor: "divider",
|
||||
textAlign: "center",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{plakParts.region} {plakParts.mainNumber}
|
||||
</Stack>
|
||||
<Stack spacing={1} direction={"row"} sx={{ width: "100%" }}>
|
||||
<Stack
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
width: "100%",
|
||||
px: 1,
|
||||
}}
|
||||
>
|
||||
{plakParts.serial}
|
||||
</Stack>
|
||||
<Stack
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
width: "100%",
|
||||
pl: 1,
|
||||
}}
|
||||
>
|
||||
{plakParts.letter}
|
||||
</Stack>
|
||||
<Stack
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
width: "100%",
|
||||
px: 1,
|
||||
}}
|
||||
>
|
||||
{plakParts.number}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
export default ShowPlak;
|
||||
@@ -124,13 +124,6 @@ export const pageMenu = [
|
||||
hasSubitems: true,
|
||||
badges: ["road_items.operation_cnt"],
|
||||
Subitems: [
|
||||
{
|
||||
id: "roadItemManagmentOparationCreate",
|
||||
label: "ثبت فعالیت",
|
||||
type: "page",
|
||||
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/operator/create",
|
||||
permissions: ["create-road-item"],
|
||||
},
|
||||
{
|
||||
id: "roadItemManagmentOparationCartable",
|
||||
label: "کارتابل",
|
||||
@@ -186,7 +179,7 @@ export const pageMenu = [
|
||||
id: "roadPatrolManagmentSupervisorCartable",
|
||||
label: "کارتابل",
|
||||
type: "page",
|
||||
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/supervisor/cartable",
|
||||
route: "/dashboard/road-patrols/supervisor",
|
||||
permissions: [
|
||||
"show-road-patrol-supervise-cartable",
|
||||
"show-road-patrol-supervise-cartable-province",
|
||||
|
||||
@@ -29,9 +29,9 @@ export const ADD_AZMAYESH_TYPE = api + "/api/v3/azmayesh_types/store";
|
||||
export const UPDATE_AZMAYESH_TYPE = api + "/api/v3/azmayesh_types/update";
|
||||
|
||||
//road patrol
|
||||
export const GET_ROAD_PATROL_OPERATOR_LIST = "/v3/api/fake-road-patrol/operator";
|
||||
export const GET_ROAD_PATROL_OPERATOR_LIST = api + "/api/v3/road_patrols/operator_index";
|
||||
export const EXPORT_ROAD_PATROL_OPERATOR_LIST = "https://rms.rmto.ir/v2/road_patrols/operator/cartable/report";
|
||||
export const GET_ROAD_PATROL_SUPERVISOR_LIST = "/v3/api/fake-road-patrol/supervisor";
|
||||
export const GET_ROAD_PATROL_SUPERVISOR_LIST = api + "/api/v3/road_patrols/supervisor_index";
|
||||
export const EXPORT_ROAD_PATROL_SUPERVISOR_LIST = "https://rms.rmto.ir/v2/road_patrols/supervisor/cartable/report";
|
||||
export const GET_OTP_TOKEN = "fake/api";
|
||||
export const VERIFY_OTP = "fake/api";
|
||||
@@ -43,6 +43,7 @@ export const GET_ROAD_ITEMS_OPERATOR_LIST = api + "/api/v3/road_items/operator_i
|
||||
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_SUB_ITEM = "https://rms.witel.ir/v2/sub_items";
|
||||
export const GET_EDARAT_LISTS = "https://rms.witel.ir/public/contents/edarate_shahri_by_province";
|
||||
export const CREATE_ROAD_ITEMS = api + "/api/v3/road_items/store";
|
||||
export const UPDATE_ROAD_ITEMS = api + "/api/v3/road_items/update";
|
||||
export const VERIFY_BY_SUPERVISOR = api + "/api/v3/road_items/verify_by_supervisor";
|
||||
|
||||
@@ -18,14 +18,23 @@ const DataTableProvider = ({ children, user_id, page_name, table_name, columns,
|
||||
const [initHide, setInitHide] = useState({});
|
||||
const [hideData, setHideData] = useState({});
|
||||
const [isDirty, setIsDirty] = useState(false);
|
||||
const [isAnyDirty, setIsAnyDirty] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let hasAnyConflict = false;
|
||||
const hasConflict =
|
||||
JSON.stringify(hideData) !== JSON.stringify(initHide) ||
|
||||
JSON.stringify(sortData) !== JSON.stringify(initSort) ||
|
||||
JSON.stringify(filterData) !== JSON.stringify(initFilter);
|
||||
|
||||
const CheckFilterValues = Object.values(filterData).every((innerObject) => innerObject.value === "");
|
||||
const CheckHideValues = Object.values(hideData).every((value) => value === true);
|
||||
|
||||
hasAnyConflict =
|
||||
!CheckHideValues || JSON.stringify(sortData) !== JSON.stringify(initialSort) || !CheckFilterValues;
|
||||
|
||||
setIsDirty(hasConflict);
|
||||
setIsAnyDirty(hasAnyConflict);
|
||||
}, [hideData, sortData, filterData, initHide, initSort, initFilter]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -136,7 +145,7 @@ const DataTableProvider = ({ children, user_id, page_name, table_name, columns,
|
||||
|
||||
return (
|
||||
<DataTableContext.Provider
|
||||
value={{ filterData, setFilterData, sortData, setSortData, hideData, setHideData, isDirty }}
|
||||
value={{ filterData, setFilterData, sortData, setSortData, hideData, setHideData, isDirty, isAnyDirty }}
|
||||
>
|
||||
{children}
|
||||
</DataTableContext.Provider>
|
||||
|
||||
@@ -2,9 +2,9 @@ import { useContext } from "react";
|
||||
import { DataTableContext } from "@/lib/contexts/DataTable";
|
||||
|
||||
const useTableSetting = () => {
|
||||
const { filterData, setFilterData, sortData, setSortData, hideData, setHideData, isDirty } =
|
||||
const { filterData, setFilterData, sortData, setSortData, hideData, setHideData, isDirty, isAnyDirty } =
|
||||
useContext(DataTableContext);
|
||||
return { filterData, setFilterData, sortData, setSortData, hideData, setHideData, isDirty };
|
||||
return { filterData, setFilterData, sortData, setSortData, hideData, setHideData, isDirty, isAnyDirty };
|
||||
};
|
||||
|
||||
export default useTableSetting;
|
||||
|
||||
62
src/lib/hooks/useEdaratLists.js
Normal file
62
src/lib/hooks/useEdaratLists.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import { useEffect, useReducer } from "react";
|
||||
import { GET_EDARAT_LISTS } from "@/core/utils/routes";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
|
||||
const ACTIONS = {
|
||||
LOADING: "loading",
|
||||
SUCCESS: "success",
|
||||
ERROR: "error",
|
||||
RESET: "reset",
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
data: [],
|
||||
loading: true,
|
||||
error: null,
|
||||
};
|
||||
|
||||
function reducer(state, action) {
|
||||
switch (action.type) {
|
||||
case ACTIONS.LOADING:
|
||||
return { ...state, loading: true, error: null };
|
||||
case ACTIONS.SUCCESS:
|
||||
return { ...state, loading: false, data: action.payload };
|
||||
case ACTIONS.ERROR:
|
||||
return { ...state, loading: false, error: action.payload };
|
||||
case ACTIONS.RESET:
|
||||
return { ...initialState, loading: false };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
const useEdaratLists = (id) => {
|
||||
const requestServer = useRequest({ notificationShow: false });
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
useEffect(() => {
|
||||
if (!id) {
|
||||
dispatch({ type: ACTIONS.RESET });
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchEdaratLists = async () => {
|
||||
dispatch({ type: ACTIONS.LOADING });
|
||||
try {
|
||||
const response = await requestServer(`${GET_EDARAT_LISTS}/${id}`);
|
||||
dispatch({ type: ACTIONS.SUCCESS, payload: response.data.data });
|
||||
} catch (error) {
|
||||
dispatch({ type: ACTIONS.ERROR, payload: error });
|
||||
}
|
||||
};
|
||||
|
||||
fetchEdaratLists();
|
||||
}, [id]);
|
||||
|
||||
return {
|
||||
edaratList: state.data,
|
||||
loadingEdaratList: state.loading,
|
||||
errorEdaratList: state.error,
|
||||
};
|
||||
};
|
||||
|
||||
export default useEdaratLists;
|
||||
@@ -10,7 +10,7 @@ const defaultOptions = {
|
||||
},
|
||||
notificationShow: true,
|
||||
notificationSuccess: false,
|
||||
notificationFailed: true
|
||||
notificationFailed: true,
|
||||
};
|
||||
|
||||
const useRequest = (initOptions) => {
|
||||
|
||||
@@ -1,29 +1,62 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useReducer } from "react";
|
||||
import { GET_ROAD_ITEMS_SUB_ITEM } from "@/core/utils/routes";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
|
||||
const useRoadItemGetItems = (id) => {
|
||||
const requestServer = useRequest();
|
||||
const [subItemsList, setSubItemsList] = useState([]);
|
||||
const [loadingSubItemsList, setLoadingSubItemsList] = useState(true);
|
||||
const [errorSubItemsList, setErrorSubItemsList] = useState(null);
|
||||
const ACTIONS = {
|
||||
LOADING: "loading",
|
||||
SUCCESS: "success",
|
||||
ERROR: "error",
|
||||
RESET: "reset",
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
data: [],
|
||||
loading: true,
|
||||
error: null,
|
||||
};
|
||||
|
||||
function reducer(state, action) {
|
||||
switch (action.type) {
|
||||
case ACTIONS.LOADING:
|
||||
return { ...state, loading: true, error: null };
|
||||
case ACTIONS.SUCCESS:
|
||||
return { ...state, loading: false, data: action.payload };
|
||||
case ACTIONS.ERROR:
|
||||
return { ...state, loading: false, error: action.payload };
|
||||
case ACTIONS.RESET:
|
||||
return { ...initialState, loading: false };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
const useRoadItemGetItems = (id) => {
|
||||
const requestServer = useRequest({ notificationShow: false });
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
useEffect(() => {
|
||||
if (!id) {
|
||||
dispatch({ type: ACTIONS.RESET });
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchSubItems = async () => {
|
||||
dispatch({ type: ACTIONS.LOADING });
|
||||
try {
|
||||
const response = await requestServer(`${GET_ROAD_ITEMS_SUB_ITEM}/${id}`);
|
||||
setSubItemsList(response.data.data);
|
||||
setLoadingSubItemsList(false);
|
||||
} catch (e) {
|
||||
setErrorSubItemsList(e);
|
||||
setLoadingSubItemsList(false);
|
||||
dispatch({ type: ACTIONS.SUCCESS, payload: response.data.data });
|
||||
} catch (error) {
|
||||
dispatch({ type: ACTIONS.ERROR, payload: error });
|
||||
}
|
||||
};
|
||||
|
||||
fetchSubItems();
|
||||
}, []);
|
||||
}, [id]);
|
||||
|
||||
return { subItemsList, loadingSubItemsList, errorSubItemsList };
|
||||
return {
|
||||
subItemsList: state.data,
|
||||
loadingSubItemsList: state.loading,
|
||||
errorSubItemsList: state.error,
|
||||
};
|
||||
};
|
||||
|
||||
export default useRoadItemGetItems;
|
||||
|
||||
@@ -14,6 +14,7 @@ const useRoadItemGetItems = () => {
|
||||
const response = await requestServer(`${GET_ROAD_ITEMS_ITEM}`);
|
||||
setItemsList(response.data.data);
|
||||
setLoadingItemsList(false);
|
||||
setErrorItemsList(false);
|
||||
} catch (e) {
|
||||
setErrorItemsList(e);
|
||||
setLoadingItemsList(false);
|
||||
|
||||
Reference in New Issue
Block a user