10 Commits

32 changed files with 289 additions and 188 deletions

View File

@@ -1,5 +1,5 @@
HOST="rms.witel.ir"
HOST_RMTO="rms.rmto.ir"
NEXT_PUBLIC_VERSION="1.8.8"
NEXT_PUBLIC_VERSION="1.9.0"
NEXT_PUBLIC_API_URL="https://rms.witel.ir"
NEXT_PUBLIC_MAPTILE_ENDPOINT="https://rmsmap.rmto.ir/141map"

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef } from "react";
import { useEffect, useRef, useState } from "react";
import { Marker, Polyline, useMap } from "react-leaflet";
import L from "leaflet";
import polyline from "@mapbox/polyline";
@@ -18,14 +18,24 @@ const ShowRoute = ({ area }) => {
});
};
useEffect(() => {
if (coords.length > 0) {
map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 });
}
}, [area]);
const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src);
const destIcon = createCustomIcon(defaultIconSize, DestIcon.src);
const [showRoute, setShowRoute] = useState(false);
useEffect(() => {
if (!coords.length) return;
setShowRoute(false);
map.flyToBounds(coords, {
padding: [50, 50],
duration: 1.5,
});
map.once("moveend", () => {
setShowRoute(true);
});
}, [area]);
if (!area) return null;
const coords = polyline.decode(area, 6);
@@ -36,7 +46,8 @@ const ShowRoute = ({ area }) => {
return (
<>
<Polyline positions={coords} color="#015688" weight={7} opacity={1} />
{showRoute && <Polyline positions={coords} color="#015688" weight={7} />}
<Marker position={sourcePosition} icon={sourceIcon} />
<Marker position={destPosition} icon={destIcon} />
</>

View File

@@ -6,107 +6,107 @@ import { Controller, useWatch } from "react-hook-form";
const MissionDates = ({ control }) => {
const type = useWatch({ control, name: "type" });
const start_date = useWatch({ control, name: "start_date" });
const end_date = useWatch({ control, name: "end_date" });
const start_time = useWatch({ control, name: "start_time" });
const end_time = useWatch({ control, name: "end_time" });
const startDateTime = makeDateTime(start_date, start_time);
const endDateTime = makeDateTime(end_date, end_time);
const now = new Date();
const startDateTime = start_date && start_time ? makeDateTime(start_date, start_time) : null;
const endDateTime = end_date && end_time ? makeDateTime(end_date, end_time) : null;
const isSameDay =
start_date && end_date && new Date(start_date).toDateString() === new Date(end_date).toDateString();
const isToday = start_date && new Date(start_date).toDateString() === now.toDateString();
return (
type && (
<>
<Grid item xs={12} sm={6}>
<Controller
control={control}
name={"start_date"}
render={({ field, fieldState: { error } }) => {
return (
<MuiDatePicker
name="start_date"
error={error}
value={field.value}
disableFuture={false}
minDate={now}
maxDate={end_date ?? null}
placeholder={"تاریخ شروع ماموریت را وارد کنید"}
label={"تاریخ شروع ماموریت"}
setFieldValue={(name, value) => field.onChange(value || [])}
helperText={error ? error.message : null}
/>
);
}}
name="start_date"
render={({ field, fieldState: { error } }) => (
<MuiDatePicker
name="start_date"
value={field.value}
error={error}
disableFuture={false}
minDate={now}
maxDate={end_date ?? null}
label="تاریخ شروع ماموریت"
placeholder="تاریخ شروع ماموریت را وارد کنید"
setFieldValue={(name, value) => field.onChange(value || null)}
helperText={error?.message}
/>
)}
/>
</Grid>
{type == 1 && (
<Grid item xs={12} sm={6}>
<Controller
control={control}
name={"start_time"}
render={({ field, fieldState: { error } }) => {
return (
<MuiTimePicker
name="start_time"
error={error}
value={field.value}
minTime={
start_date && new Date(start_date).toDateString() === now.toDateString()
? now
: null
}
maxTime={endDateTime ?? null}
placeholder={"زمان شروع ماموریت را وارد کنید"}
label={"زمان شروع ماموریت"}
setFieldValue={(name, value) => field.onChange(value || null)}
helperText={error ? error.message : null}
/>
);
}}
name="start_time"
render={({ field, fieldState: { error } }) => (
<MuiTimePicker
name="start_time"
value={field.value}
error={error}
minTime={isToday ? now : null}
maxTime={isSameDay && endDateTime ? endDateTime : null}
label="زمان شروع ماموریت"
placeholder="زمان شروع ماموریت را وارد کنید"
setFieldValue={(name, value) => field.onChange(value || null)}
helperText={error?.message}
/>
)}
/>
</Grid>
)}
<Grid item xs={12} sm={6}>
<Controller
control={control}
name={"end_date"}
render={({ field, fieldState: { error } }) => {
return (
<MuiDatePicker
name="end_date"
error={error}
value={field.value}
disableFuture={false}
minDate={start_date ? start_date : now}
placeholder={"تاریخ پایان ماموریت را وارد کنید"}
label={"تاریخ پایان ماموریت"}
setFieldValue={(name, value) => field.onChange(value || [])}
helperText={error ? error.message : null}
/>
);
}}
name="end_date"
render={({ field, fieldState: { error } }) => (
<MuiDatePicker
name="end_date"
value={field.value}
error={error}
disableFuture={false}
minDate={start_date || now}
label="تاریخ پایان ماموریت"
placeholder="تاریخ پایان ماموریت را وارد کنید"
setFieldValue={(name, value) => field.onChange(value || null)}
helperText={error?.message}
/>
)}
/>
</Grid>
{type == 1 && (
<Grid item xs={12} sm={6}>
<Controller
control={control}
name={"end_time"}
render={({ field, fieldState: { error } }) => {
return (
<MuiTimePicker
name="end_time"
error={error}
value={field.value}
minTime={startDateTime ?? null}
placeholder={"زمان پایان ماموریت را وارد کنید"}
label={"زمان پایان ماموریت"}
setFieldValue={(name, value) => field.onChange(value || null)}
helperText={error ? error.message : null}
/>
);
}}
name="end_time"
render={({ field, fieldState: { error } }) => (
<MuiTimePicker
name="end_time"
value={field.value}
error={error}
minTime={isSameDay && startDateTime ? startDateTime : null}
label="زمان پایان ماموریت"
placeholder="زمان پایان ماموریت را وارد کنید"
setFieldValue={(name, value) => field.onChange(value || null)}
helperText={error?.message}
/>
)}
/>
</Grid>
)}
@@ -114,4 +114,5 @@ const MissionDates = ({ control }) => {
)
);
};
export default MissionDates;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -50,7 +50,8 @@ const DriverReportsList = ({ data, specialFilter }) => {
},
];
}, []);
const cleanedData = specialFilter.filter((item) => !(item.id === "province_id" && item.value === "-1"));
const RowActionsWithRowData = (props) => <RowActions specialFilter={cleanedData} {...props} />;
return (
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
@@ -62,7 +63,7 @@ const DriverReportsList = ({ data, specialFilter }) => {
enablePagination={false}
specialFilter={specialFilter}
enableRowActions
RowActions={RowActions}
RowActions={RowActionsWithRowData}
/>
</Box>
);

View File

@@ -3,7 +3,7 @@ import { GET_DRIVER_DETAILS } from "@/core/utils/routes";
import { Box } from "@mui/material";
import { useMemo } from "react";
const DriverList = ({ row }) => {
const DriverList = ({ row, specialFilter }) => {
const columns = useMemo(
() => [
{
@@ -93,6 +93,7 @@ const DriverList = ({ row }) => {
<DataTableWithAuth
need_filter={true}
columns={columns}
specialFilter={specialFilter}
sorting={[{ id: "id", desc: true }]}
table_url={`${GET_DRIVER_DETAILS}/${row.driver_id}`}
page_name={"driverListReport"}

View File

@@ -2,14 +2,14 @@ import { Box, Button, DialogActions, DialogContent } from "@mui/material";
import { Stack } from "@mui/system";
import DriverList from "./DriverDetailsDialog/DriverList";
const DriverDetailsTable = ({ row, setOpenDriverDetails }) => {
const DriverDetailsTable = ({ row, setOpenDriverDetails, specialFilter }) => {
return (
<>
<DialogContent dividers>
<Box sx={{ flex: 1 }}>
<Stack spacing={3}>
<Stack spacing={2}>
<DriverList row={row} />
<DriverList specialFilter={specialFilter} row={row} />
</Stack>
</Stack>
</Box>

View File

@@ -3,7 +3,7 @@ import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material";
import { useState } from "react";
import DriverDetailsTable from "./Form";
const DriverDetails = ({ row }) => {
const DriverDetails = ({ row, specialFilter }) => {
const [openDriverDetails, setOpenDriverDetails] = useState(false);
return (
@@ -35,7 +35,11 @@ const DriverDetails = ({ row }) => {
</IconButton>
<DialogTitle>ریز گزارشات راننده</DialogTitle>
{openDriverDetails && (
<DriverDetailsTable row={row.original} setOpenDriverDetails={setOpenDriverDetails} />
<DriverDetailsTable
specialFilter={specialFilter}
row={row.original}
setOpenDriverDetails={setOpenDriverDetails}
/>
)}
</Dialog>
</>

View File

@@ -1,6 +1,6 @@
import DriverDetails from "./DriverDetails";
const RowActions = ({ row }) => {
return <DriverDetails row={row} />;
const RowActions = ({ row, specialFilter }) => {
return <DriverDetails specialFilter={specialFilter} row={row} />;
};
export default RowActions;

View File

@@ -27,8 +27,8 @@ const DriverReportsPage = () => {
};
const defaultFilter = [
{ value: `${defaultValues.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" },
{ value: `${defaultValues.from_date}`, datatype: "date", id: "from_date", fn: "between" },
{ value: `${defaultValues.date_to}`, datatype: "date", id: "date_to", fn: "between" },
{ value: `${defaultValues.from_date} 00:00:00`, datatype: "date", id: "start_time", fn: "greaterThan" },
{ value: `${defaultValues.date_to} 23:59:59`, datatype: "date", id: "finish_time", fn: "lessThan" },
];
const [specialFilter, setSpecialFilter] = useState(defaultFilter);
@@ -38,8 +38,8 @@ const DriverReportsPage = () => {
params.set("date_to", `${data.date_to} 23:59:59`);
setSpecialFilter([
{ value: `${data.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" },
{ value: `${data.from_date}`, datatype: "date", id: "from_date", fn: "between" },
{ value: `${data.date_to}`, datatype: "date", id: "date_to", fn: "between" },
{ value: `${data.from_date} 00:00:00`, datatype: "date", id: "start_time", fn: "greaterThan" },
{ value: `${data.date_to} 23:59:59`, datatype: "date", id: "finish_time", fn: "lessThan" },
]);
if (data.province_id === "-1") {
try {

View File

@@ -60,7 +60,8 @@ const MachinesReportsList = ({ data, specialFilter }) => {
},
];
}, []);
const cleanedData = specialFilter.filter((item) => !(item.id === "province_id" && item.value === "-1"));
const RowActionsWithRowData = (props) => <RowActions specialFilter={cleanedData} {...props} />;
return (
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
@@ -72,7 +73,7 @@ const MachinesReportsList = ({ data, specialFilter }) => {
enablePagination={false}
specialFilter={specialFilter}
enableRowActions
RowActions={RowActions}
RowActions={RowActionsWithRowData}
/>
</Box>
);

View File

@@ -3,7 +3,7 @@ import { GET_MACHINE_MISSIONS_DETAILS } from "@/core/utils/routes";
import { Box } from "@mui/material";
import { useMemo } from "react";
const MachineMissionsList = ({ row }) => {
const MachineMissionsList = ({ row, specialFilter }) => {
const columns = useMemo(
() => [
{
@@ -91,6 +91,7 @@ const MachineMissionsList = ({ row }) => {
<>
<Box sx={{ mt: 3 }}>
<DataTableWithAuth
specialFilter={specialFilter}
need_filter={true}
columns={columns}
sorting={[{ id: "id", desc: true }]}

View File

@@ -2,14 +2,14 @@ import { Box, Button, DialogActions, DialogContent } from "@mui/material";
import { Stack } from "@mui/system";
import MachineMissionsList from "./MachineMissionsDetailsDialog/MachineMissionsList";
const MachineMissionsDetailsTable = ({ row, setOpenMachineMissionsDetails }) => {
const MachineMissionsDetailsTable = ({ row, setOpenMachineMissionsDetails, specialFilter }) => {
return (
<>
<DialogContent dividers>
<Box sx={{ flex: 1 }}>
<Stack spacing={3}>
<Stack spacing={2}>
<MachineMissionsList row={row} />
<MachineMissionsList specialFilter={specialFilter} row={row} />
</Stack>
</Stack>
</Box>

View File

@@ -3,7 +3,7 @@ import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material";
import { useState } from "react";
import MachineMissionsDetailsTable from "./Form";
const MissionDetails = ({ row }) => {
const MissionDetails = ({ row, specialFilter }) => {
const [openMachineMissionsDetails, setOpenMachineMissionsDetails] = useState(false);
return (
@@ -36,6 +36,7 @@ const MissionDetails = ({ row }) => {
<DialogTitle>ریز گزارشات خودرو</DialogTitle>
{openMachineMissionsDetails && (
<MachineMissionsDetailsTable
specialFilter={specialFilter}
row={row.original}
setOpenMachineMissionsDetails={setOpenMachineMissionsDetails}
/>

View File

@@ -1,6 +1,6 @@
import MissionDetails from "./MissionDitails";
const RowActions = ({ row }) => {
return <MissionDetails row={row} />;
const RowActions = ({ row, specialFilter }) => {
return <MissionDetails specialFilter={specialFilter} row={row} />;
};
export default RowActions;

View File

@@ -27,8 +27,8 @@ const MachinesReportsPage = () => {
};
const defaultFilter = [
{ value: `${defaultValues.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" },
{ value: `${defaultValues.from_date}`, datatype: "date", id: "from_date", fn: "between" },
{ value: `${defaultValues.date_to}`, datatype: "date", id: "date_to", fn: "between" },
{ value: `${defaultValues.from_date} 00:00:00`, datatype: "date", id: "start_time", fn: "greaterThan" },
{ value: `${defaultValues.date_to} 23:59:59`, datatype: "date", id: "finish_time", fn: "lessThan" },
];
const [specialFilter, setSpecialFilter] = useState(defaultFilter);
@@ -38,8 +38,8 @@ const MachinesReportsPage = () => {
params.set("date_to", `${data.date_to} 23:59:59`);
setSpecialFilter([
{ value: `${data.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" },
{ value: `${data.from_date}`, datatype: "date", id: "from_date", fn: "between" },
{ value: `${data.date_to}`, datatype: "date", id: "date_to", fn: "between" },
{ value: `${data.from_date} 00:00:00`, datatype: "date", id: "start_time", fn: "greaterThan" },
{ value: `${data.date_to} 23:59:59`, datatype: "date", id: "finish_time", fn: "lessThan" },
]);
if (data.province_id === "-1") {
try {

View File

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

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef } from "react";
import { useEffect, useRef, useState } from "react";
import { Marker, Polyline, useMap } from "react-leaflet";
import L from "leaflet";
import polyline from "@mapbox/polyline";
@@ -18,14 +18,24 @@ const ShowRoute = ({ area }) => {
});
};
useEffect(() => {
if (coords.length > 0) {
map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 });
}
}, [area]);
const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src);
const destIcon = createCustomIcon(defaultIconSize, DestIcon.src);
const [showRoute, setShowRoute] = useState(false);
useEffect(() => {
if (!coords.length) return;
setShowRoute(false);
map.flyToBounds(coords, {
padding: [50, 50],
duration: 1.5,
});
map.once("moveend", () => {
setShowRoute(true);
});
}, [area]);
if (!area) return null;
const coords = polyline.decode(area, 6);
@@ -36,7 +46,8 @@ const ShowRoute = ({ area }) => {
return (
<>
<Polyline positions={coords} color="#015688" weight={7} opacity={1} />
{showRoute && <Polyline positions={coords} color="#015688" weight={7} />}
<Marker position={sourcePosition} icon={sourceIcon} />
<Marker position={destPosition} icon={destIcon} />
</>

View File

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

View File

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