edit missions pages

This commit is contained in:
2025-12-28 11:10:07 +03:30
parent d9bff30085
commit a4a0312073
19 changed files with 1169 additions and 479 deletions

View File

@@ -9,7 +9,7 @@ const Page = () => {
<>
<WithPermission
permission_name={[
"manage-control-unit",
"manage-control-unit-province",
"manage-control-unit-city",
"manage-control-unit-country",
"manage-control-unit-station",

View File

@@ -9,7 +9,7 @@ const Page = () => {
<>
<WithPermission
permission_name={[
"manage-transportation-unit-country",
"manage-transportation-unit-province",
"manage-transportation-unit-city",
"manage-transportation-unit-country",
"manage-transportation-unit-station",

View File

@@ -2,18 +2,15 @@
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import { GET_RAHDARAN_TABLE_LIST } from "@/core/utils/routes";
import { Box } from "@mui/material";
import { useEffect, useMemo, useState } from "react";
import { useMemo } from "react";
import RowActions from "./RowActions";
import Toolbar from "./Toolbar";
import { useAuth } from "@/lib/contexts/auth";
import useProvinces from "@/lib/hooks/useProvince";
import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
import useEdaratLists from "@/lib/hooks/useEdaratLists";
import { usePermissions } from "@/lib/hooks/usePermissions";
const RahdaranList = () => {
const { data: userPermissions } = usePermissions();
const { user } = useAuth();
const hasCountryPermission = userPermissions?.includes("manage-rahdaran-country");
const columns = useMemo(() => {
const provinceColumn = {
@@ -66,63 +63,6 @@ const RahdaranList = () => {
size: 100,
},
...(hasCountryPermission ? [provinceColumn] : []),
{
header: "اداره",
id: "edareh_shahri_id",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
dependencyId: hasCountryPermission ? "province_id" : null,
grow: false,
size: 120,
ColumnSelectComponent: (props) => {
const { edaratList, loadingEdaratList, errorEdaratList } = useEdaratLists(
hasCountryPermission ? props.dependencyFieldValue.value : user.province_id
);
const [prevDependency, setPrevDependency] = useState(
hasCountryPermission ? props.dependencyFieldValue.value : user.province_id
);
const getColumnSelectOptions = useMemo(() => {
if (hasCountryPermission && props.dependencyFieldValue.value === "") {
return [{ value: "empty", label: "ابتدا استان را انتخاب کنید" }];
}
if (loadingEdaratList) {
return [{ value: "loading", label: "در حال بارگذاری..." }];
}
if (errorEdaratList) {
return [{ value: "error", label: "خطا در بارگذاری" }];
}
return [
{ value: "", label: "کل ادارات" },
...edaratList.map((edare) => ({
value: edare.id,
label: edare.name_fa,
})),
];
}, [edaratList, loadingEdaratList, errorEdaratList]);
useEffect(() => {
if (hasCountryPermission) return;
if (prevDependency === props.dependencyFieldValue?.value) return;
props.handleChange({ ...props.filterParameters, value: "" });
setPrevDependency(props.dependencyFieldValue?.value);
}, [props.dependencyFieldValue?.value, hasCountryPermission]);
return (
<CustomSelectByDependency
{...props}
value={
props.dependencyFieldValue?.value === ""
? "empty"
: loadingEdaratList
? "loading"
: props.filterParameters.value
}
columnSelectOption={getColumnSelectOptions}
/>
);
},
Cell: ({ renderedCellValue, row }) => <>{row.original.edareh_shahri_name}</>,
},
{
accessorKey: "name",
header: "نام و نام خانوادگی",

View File

@@ -12,8 +12,6 @@ import { Box, Stack, Typography } from "@mui/material";
import moment from "jalali-moment";
import { useEffect, useMemo, useState } from "react";
import ImageDialog from "../operator/RowActions/ImageForm";
import MachinesCodeDialog from "../operator/RowActions/MachinesCodeForm";
import RahdaranDialog from "../operator/RowActions/RahdaranForm";
import RowActions from "./RowActions";
import LocationForm from "./RowActions/LocationForm";
import Toolbar from "./Toolbar";
@@ -364,7 +362,7 @@ const SupervisorList = () => {
label: status.label,
}));
},
Cell: ({ renderedCellValue, row }) => <>{row.original.status_fa}</>,
Cell: ({ row }) => <>{row.original.status_fa}</>,
},
];
}, [hasCountryPermission]);

View File

@@ -7,10 +7,50 @@ import { useMemo } from "react";
import MachinesDialog from "./RowActions/Machines";
import RowActions from "./RowActions";
import RahdaranDialog from "./RowActions/Rahdaran";
import useProvinces from "@/lib/hooks/useProvince";
import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
import useCities from "@/lib/hooks/useCities";
const ControlList = () => {
const columns = useMemo(
() => [
const columns = useMemo(() => {
const dynamicColumns = {
header: "استان",
id: "province_id",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 130,
ColumnSelectComponent: (props) => {
const { provinces, errorProvinces, loadingProvinces } = useProvinces();
const getColumnSelectOptions = useMemo(() => {
if (loadingProvinces) {
return [{ value: "loading", label: "در حال بارگذاری..." }];
}
if (errorProvinces) {
return [{ value: "error", label: "خطا در بارگذاری" }];
}
return [
{ value: "", label: "کل کشور" },
...provinces.map((province) => ({
value: province.id,
label: province.name_fa,
})),
];
}, [provinces, errorProvinces, loadingProvinces]);
return (
<CustomSelectByDependency
{...props}
value={loadingProvinces ? "loading" : props.filterParameters.value}
columnSelectOption={getColumnSelectOptions}
/>
);
},
Cell: ({ renderedCellValue, row }) => {
return <>{row.original.province_name}</>;
},
};
return [
{
accessorKey: "id",
header: "کد یکتا",
@@ -22,6 +62,63 @@ const ControlList = () => {
grow: false,
size: 100,
},
...[dynamicColumns],
{
header: "شهر",
id: "city_id",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
dependencyId: "province_id",
grow: false,
size: 120,
ColumnSelectComponent: (props) => {
const { cityList, loadingCityList, errorCityList } = useCities(props.dependencyFieldValue.value);
const getColumnSelectOptions = useMemo(() => {
if (props.dependencyFieldValue.value === "") {
return [{ value: "empty", label: "ابتدا استان را انتخاب کنید" }];
}
if (loadingCityList) {
return [{ value: "loading", label: "در حال بارگذاری..." }];
}
if (errorCityList) {
return [{ value: "error", label: "خطا در بارگذاری" }];
}
return [
{ value: "", label: "کل ادارات" },
...cityList.map((edare) => ({
value: edare.id,
label: edare.name_fa,
})),
];
}, [cityList, loadingCityList, errorCityList]);
return (
<CustomSelectByDependency
{...props}
value={
props.dependencyFieldValue?.value === ""
? "empty"
: loadingCityList
? "loading"
: props.filterParameters.value
}
columnSelectOption={getColumnSelectOptions}
/>
);
},
Cell: ({ row }) => <>{row.original.city_name}</>,
},
{
accessorKey: "station_name",
header: "راهدارخانه",
id: "station_name",
enableColumnFilter: false,
datatype: "text",
filterMode: "equals",
grow: false,
size: 100,
},
{
accessorFn: (row) =>
row.type == 1
@@ -113,9 +210,8 @@ const ControlList = () => {
grow: false,
size: 100,
},
],
[]
);
];
}, []);
return (
<>

View File

@@ -2,6 +2,8 @@ import LtrTextField from "@/core/components/LtrTextField";
import { Close, Edit } from "@mui/icons-material";
import { Button, Dialog, IconButton, Stack } from "@mui/material";
import { useState } from "react";
import { Controller } from "react-hook-form";
import CarCode from "@/core/components/CarCode";
const MachinesDialog = ({ setMachine, mode, machineCode, setShowMachineCodeDialog }) => {
const [openMachinesDialog, setOpenMachinesDialog] = useState(false);
@@ -33,23 +35,14 @@ const MachinesDialog = ({ setMachine, mode, machineCode, setShowMachineCodeDialo
</IconButton>
{openMachinesDialog && (
<Stack sx={{ p: 4, mt: 2 }} spacing={2}>
<LtrTextField
label={`کد خودرو`}
value={machineCode || ""}
type="text"
size={"small"}
inputProps={{
placeholder: "کد خودرو را وارد کنید",
inputMode: "numeric",
min: 0,
pattern: "[0-9]*",
}}
onChange={(event) => {
setMachine(event.target.value);
}}
variant="outlined"
fullWidth
/>
<Stack sx={{ minWidth: "200px" }}>
<CarCode
carCode={machineCode}
setCarCode={(value) => {
setMachine(value.machine_code);
}}
/>
</Stack>
<Button
onClick={() => {
setShowMachineCodeDialog(true);

View File

@@ -13,281 +13,382 @@ import MachinesDialog from "./RowActions/Machines";
import Toolbar from "./Toolbar";
import RahdaranDialog from "./RowActions/Rahdaran";
import DescriptionDialog from "@/components/dashboard/roadMissions/operator/RowActions/DescriptionDialog";
import useProvinces from "@/lib/hooks/useProvince";
import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
import useCities from "@/lib/hooks/useCities";
const OperatorList = () => {
const columns = useMemo(
() => [
{
accessorKey: "id",
header: "کد یکتا",
id: "id",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "code",
header: "کد خروج",
id: "code",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
accessorKey: "state_name",
header: "وضعیت",
id: "state_name",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
accessorKey: "explanation",
header: "موضوع",
id: "explanation",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
accessorKey: "category_id",
header: "نوع",
id: "category_id",
() =>{
const dynamicColumns = {
header: "استان",
id: "province_id",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
sortDescFirst: true,
grow: false,
size: 100,
columnSelectOption: () => {
return missionCategoryTypes.map((category) => ({
value: category.id,
label: category.name_fa,
}));
},
Cell: ({ row }) => row.original.category_name,
},
{
accessorKey: "zone",
header: "محدوده",
id: "zone",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
sortDescFirst: true,
grow: false,
size: 100,
columnSelectOption: () => {
return missionRegions.map((region) => ({
value: region.id,
label: region.name_fa,
}));
},
Cell: ({ row }) => row.original.zone_fa,
},
{
accessorKey: "type",
header: "نوع زمانبندی",
id: "type",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
sortDescFirst: true,
grow: false,
size: 100,
columnSelectOption: () => {
return missionTypes.map((type) => ({
value: type.id,
label: type.name_fa,
}));
},
Cell: ({ row }) => row.original.type_fa,
},
{
accessorFn: (row) =>
row.type == 1
? moment(row.start_date).locale("fa").format("HH:mm | yyyy/MM/DD")
: moment(row.start_date).locale("fa").format("yyyy/MM/DD"),
header: "تاریخ شروع",
id: "start_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorFn: (row) =>
row.type == 1
? moment(row.end_date).locale("fa").format("HH:mm | yyyy/MM/DD")
: moment(row.end_date).locale("fa").format("yyyy/MM/DD"),
header: "تاریخ پایان",
id: "end_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorKey: "end_point",
header: "مقصد",
id: "end_point",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
header: "منطقه عملیاتی",
id: "area",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
muiTableBodyCellProps: {
sx: {
borderLeft: "1px solid #e1e1e1",
py: 0,
"&:first-of-type": {
borderLeft: "unset",
},
},
},
Cell: ({ row }) =>
row.original.area ? (
<Stack alignItems={"center"} justifyContent={"center"}>
<ShowArea area={row.original.area} />
</Stack>
) : (
"-"
),
},
{
header: "خودرو",
id: "cmmsMachines__machine_code",
enableColumnFilter: true,
datatype: "text",
filterMode: "contains",
enableSorting: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
muiTableBodyCellProps: {
sx: {
borderLeft: "1px solid #e1e1e1",
py: 0,
"&:first-of-type": {
borderLeft: "unset",
},
},
size: 130,
ColumnSelectComponent: (props) => {
const { provinces, errorProvinces, loadingProvinces } = useProvinces();
const getColumnSelectOptions = useMemo(() => {
if (loadingProvinces) {
return [{ value: "loading", label: "در حال بارگذاری..." }];
}
if (errorProvinces) {
return [{ value: "error", label: "خطا در بارگذاری" }];
}
return [
{ value: "", label: "کل کشور" },
...provinces.map((province) => ({
value: province.id,
label: province.name_fa,
})),
];
}, [provinces, errorProvinces, loadingProvinces]);
return (
<CustomSelectByDependency
{...props}
value={loadingProvinces ? "loading" : props.filterParameters.value}
columnSelectOption={getColumnSelectOptions}
/>
);
},
Cell: ({ renderedCellValue, row }) => {
return (
<Stack alignItems={"center"} justifyContent={"center"}>
<MachinesDialog rowId={row.original.id} />
</Stack>
);
return <>{row.original.province_name}</>;
},
},
{
header: "افراد",
id: "rahdaran__code",
enableColumnFilter: true,
enableSorting: false,
datatype: "text",
filterMode: "contains",
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
muiTableBodyCellProps: {
sx: {
borderLeft: "1px solid #e1e1e1",
py: 0,
"&:first-of-type": {
borderLeft: "unset",
};
return [
{
accessorKey: "id",
header: "کد یکتا",
id: "id",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "code",
header: "کد خروج",
id: "code",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
...[dynamicColumns],
{
header: "شهر",
id: "city_id",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
dependencyId: "province_id",
grow: false,
size: 120,
ColumnSelectComponent: (props) => {
const { cityList, loadingCityList, errorCityList } = useCities(
props.dependencyFieldValue.value
);
const getColumnSelectOptions = useMemo(() => {
if (props.dependencyFieldValue.value === "") {
return [{ value: "empty", label: "ابتدا استان را انتخاب کنید" }];
}
if (loadingCityList) {
return [{ value: "loading", label: "در حال بارگذاری..." }];
}
if (errorCityList) {
return [{ value: "error", label: "خطا در بارگذاری" }];
}
return [
{ value: "", label: "کل ادارات" },
...cityList.map((edare) => ({
value: edare.id,
label: edare.name_fa,
})),
];
}, [cityList, loadingCityList, errorCityList]);
return (
<CustomSelectByDependency
{...props}
value={
props.dependencyFieldValue?.value === ""
? "empty"
: loadingCityList
? "loading"
: props.filterParameters.value
}
columnSelectOption={getColumnSelectOptions}
/>
);
},
Cell: ({ row }) => <>{row.original.city_name}</>,
},
{
accessorKey: "station_name",
header: "راهدارخانه",
id: "station_name",
enableColumnFilter: false,
datatype: "text",
filterMode: "equals",
grow: false,
size: 100,
},
{
accessorKey: "state_name",
header: "وضعیت",
id: "state_name",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
accessorKey: "explanation",
header: "موضوع",
id: "explanation",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
accessorKey: "category_id",
header: "نوع",
id: "category_id",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
sortDescFirst: true,
grow: false,
size: 100,
columnSelectOption: () => {
return missionCategoryTypes.map((category) => ({
value: category.id,
label: category.name_fa,
}));
},
Cell: ({ row }) => row.original.category_name,
},
{
accessorKey: "zone",
header: "محدوده",
id: "zone",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
sortDescFirst: true,
grow: false,
size: 100,
columnSelectOption: () => {
return missionRegions.map((region) => ({
value: region.id,
label: region.name_fa,
}));
},
Cell: ({ row }) => row.original.zone_fa,
},
{
accessorKey: "type",
header: "نوع زمانبندی",
id: "type",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
sortDescFirst: true,
grow: false,
size: 100,
columnSelectOption: () => {
return missionTypes.map((type) => ({
value: type.id,
label: type.name_fa,
}));
},
Cell: ({ row }) => row.original.type_fa,
},
{
accessorFn: (row) =>
row.type == 1
? moment(row.start_date).locale("fa").format("HH:mm | yyyy/MM/DD")
: moment(row.start_date).locale("fa").format("yyyy/MM/DD"),
header: "تاریخ شروع",
id: "start_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorFn: (row) =>
row.type == 1
? moment(row.end_date).locale("fa").format("HH:mm | yyyy/MM/DD")
: moment(row.end_date).locale("fa").format("yyyy/MM/DD"),
header: "تاریخ پایان",
id: "end_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorKey: "end_point",
header: "مقصد",
id: "end_point",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
header: "منطقه عملیاتی",
id: "area",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
muiTableBodyCellProps: {
sx: {
borderLeft: "1px solid #e1e1e1",
py: 0,
"&:first-of-type": {
borderLeft: "unset",
},
},
},
Cell: ({ row }) =>
row.original.area ? (
<Stack alignItems={"center"} justifyContent={"center"}>
<ShowArea area={row.original.area} />
</Stack>
) : (
"-"
),
},
Cell: ({ row }) => {
return (
<Stack alignItems={"center"} justifyContent={"center"}>
<RahdaranDialog rowId={row.original.id} />
</Stack>
);
},
},
{
header: "دلیل رد درخواست",
id: "description",
enableColumnFilter: false,
enableSorting: false,
datatype: "text",
filterMode: "contains",
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
muiTableBodyCellProps: {
sx: {
borderLeft: "1px solid #e1e1e1",
py: 0,
"&:first-of-type": {
borderLeft: "unset",
{
header: "خودرو",
id: "cmmsMachines__machine_code",
enableColumnFilter: true,
datatype: "text",
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, row }) => {
return (
<Stack alignItems={"center"} justifyContent={"center"}>
<MachinesDialog rowId={row.original.id} />
</Stack>
);
},
},
Cell: ({ row }) => {
return (
<Stack alignItems={"center"} justifyContent={"center"}>
<DescriptionDialog description={row.original.description} />
</Stack>
);
{
header: "افراد",
id: "rahdaran__code",
enableColumnFilter: true,
enableSorting: false,
datatype: "text",
filterMode: "contains",
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
muiTableBodyCellProps: {
sx: {
borderLeft: "1px solid #e1e1e1",
py: 0,
"&:first-of-type": {
borderLeft: "unset",
},
},
},
Cell: ({ row }) => {
return (
<Stack alignItems={"center"} justifyContent={"center"}>
<RahdaranDialog rowId={row.original.id} />
</Stack>
);
},
},
},
{
accessorFn: (row) =>
row.start_time ? moment(row.start_time).locale("fa").format("HH:mm | yyyy/MM/DD") : null,
header: "تاریخ خروج",
id: "start_time",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorFn: (row) =>
row.finish_time ? moment(row.finish_time).locale("fa").format("HH:mm | yyyy/MM/DD") : null,
header: "تاریخ ورود",
id: "finish_time",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorFn: (row) => moment(row.request_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
header: "تاریخ ثبت",
id: "request_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
],
{
header: "دلیل رد درخواست",
id: "description",
enableColumnFilter: false,
enableSorting: false,
datatype: "text",
filterMode: "contains",
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
muiTableBodyCellProps: {
sx: {
borderLeft: "1px solid #e1e1e1",
py: 0,
"&:first-of-type": {
borderLeft: "unset",
},
},
},
Cell: ({ row }) => {
return (
<Stack alignItems={"center"} justifyContent={"center"}>
<DescriptionDialog description={row.original.description} />
</Stack>
);
},
},
{
accessorFn: (row) =>
row.start_time ? moment(row.start_time).locale("fa").format("HH:mm | yyyy/MM/DD") : null,
header: "تاریخ خروج",
id: "start_time",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorFn: (row) =>
row.finish_time ? moment(row.finish_time).locale("fa").format("HH:mm | yyyy/MM/DD") : null,
header: "تاریخ ورود",
id: "finish_time",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorFn: (row) => moment(row.request_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
header: "تاریخ ثبت",
id: "request_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
];
},
[]
);

View File

@@ -8,150 +8,250 @@ import ShowArea from "./Actions/showArea";
import RowActions from "./RowActions";
import { missionRegions } from "@/core/utils/missionRegions";
import { missionTypes } from "@/core/utils/missionTypes";
import useProvinces from "@/lib/hooks/useProvince";
import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
import useCities from "@/lib/hooks/useCities";
const TransportationList = () => {
const columns = useMemo(
() => [
{
accessorKey: "id",
header: "کد یکتا",
id: "id",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "state_name",
header: "وضعیت",
id: "state_name",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
accessorKey: "explanation",
header: "موضوع",
id: "explanation",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
accessorKey: "zone",
header: "محدوده",
id: "zone",
() => {
const dynamicColumns = {
header: "استان",
id: "province_id",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
sortDescFirst: true,
grow: false,
size: 100,
columnSelectOption: () => {
return missionRegions.map((region) => ({
value: region.id,
label: region.name_fa,
}));
size: 130,
ColumnSelectComponent: (props) => {
const { provinces, errorProvinces, loadingProvinces } = useProvinces();
const getColumnSelectOptions = useMemo(() => {
if (loadingProvinces) {
return [{ value: "loading", label: "در حال بارگذاری..." }];
}
if (errorProvinces) {
return [{ value: "error", label: "خطا در بارگذاری" }];
}
return [
{ value: "", label: "کل کشور" },
...provinces.map((province) => ({
value: province.id,
label: province.name_fa,
})),
];
}, [provinces, errorProvinces, loadingProvinces]);
return (
<CustomSelectByDependency
{...props}
value={loadingProvinces ? "loading" : props.filterParameters.value}
columnSelectOption={getColumnSelectOptions}
/>
);
},
Cell: ({ row }) => row.original.zone_fa,
},
{
accessorKey: "type",
header: "نوع زمانبندی",
id: "type",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
sortDescFirst: true,
grow: false,
size: 100,
columnSelectOption: () => {
return missionTypes.map((type) => ({
value: type.id,
label: type.name_fa,
}));
Cell: ({ renderedCellValue, row }) => {
return <>{row.original.province_name}</>;
},
Cell: ({ row }) => row.original.type_fa,
},
{
accessorFn: (row) =>
row.type == 1
? moment(row.start_date).locale("fa").format("HH:mm | yyyy/MM/DD")
: moment(row.start_date).locale("fa").format("yyyy/MM/DD"),
header: "تاریخ شروع",
id: "start_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorFn: (row) =>
row.type == 1
? moment(row.end_date).locale("fa").format("HH:mm | yyyy/MM/DD")
: moment(row.end_date).locale("fa").format("yyyy/MM/DD"),
header: "تاریخ پایان",
id: "end_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorKey: "end_point",
header: "مقصد",
id: "end_point",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
header: "منطقه عملیاتی",
id: "area",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
muiTableBodyCellProps: {
sx: {
borderLeft: "1px solid #e1e1e1",
py: 0,
"&:first-of-type": {
borderLeft: "unset",
};
return [
{
accessorKey: "id",
header: "کد یکتا",
id: "id",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "state_name",
header: "وضعیت",
id: "state_name",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
...[dynamicColumns],
{
header: "شهر",
id: "city_id",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
dependencyId: "province_id",
grow: false,
size: 120,
ColumnSelectComponent: (props) => {
const { cityList, loadingCityList, errorCityList } = useCities(
props.dependencyFieldValue.value
);
const getColumnSelectOptions = useMemo(() => {
if (props.dependencyFieldValue.value === "") {
return [{ value: "empty", label: "ابتدا استان را انتخاب کنید" }];
}
if (loadingCityList) {
return [{ value: "loading", label: "در حال بارگذاری..." }];
}
if (errorCityList) {
return [{ value: "error", label: "خطا در بارگذاری" }];
}
return [
{ value: "", label: "کل ادارات" },
...cityList.map((edare) => ({
value: edare.id,
label: edare.name_fa,
})),
];
}, [cityList, loadingCityList, errorCityList]);
return (
<CustomSelectByDependency
{...props}
value={
props.dependencyFieldValue?.value === ""
? "empty"
: loadingCityList
? "loading"
: props.filterParameters.value
}
columnSelectOption={getColumnSelectOptions}
/>
);
},
Cell: ({ row }) => <>{row.original.city_name}</>,
},
{
accessorKey: "station_name",
header: "راهدارخانه",
id: "station_name",
enableColumnFilter: false,
datatype: "text",
filterMode: "equals",
grow: false,
size: 100,
},
{
accessorKey: "explanation",
header: "موضوع",
id: "explanation",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
accessorKey: "zone",
header: "محدوده",
id: "zone",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
sortDescFirst: true,
grow: false,
size: 100,
columnSelectOption: () => {
return missionRegions.map((region) => ({
value: region.id,
label: region.name_fa,
}));
},
Cell: ({ row }) => row.original.zone_fa,
},
{
accessorKey: "type",
header: "نوع زمانبندی",
id: "type",
enableColumnFilter: true,
datatype: "numeric",
filterMode: "equals",
sortDescFirst: true,
grow: false,
size: 100,
columnSelectOption: () => {
return missionTypes.map((type) => ({
value: type.id,
label: type.name_fa,
}));
},
Cell: ({ row }) => row.original.type_fa,
},
{
accessorFn: (row) =>
row.type == 1
? moment(row.start_date).locale("fa").format("HH:mm | yyyy/MM/DD")
: moment(row.start_date).locale("fa").format("yyyy/MM/DD"),
header: "تاریخ شروع",
id: "start_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorFn: (row) =>
row.type == 1
? moment(row.end_date).locale("fa").format("HH:mm | yyyy/MM/DD")
: moment(row.end_date).locale("fa").format("yyyy/MM/DD"),
header: "تاریخ پایان",
id: "end_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
{
accessorKey: "end_point",
header: "مقصد",
id: "end_point",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
},
{
header: "منطقه عملیاتی",
id: "area",
enableColumnFilter: false,
datatype: "numeric",
filterMode: "equals",
grow: false,
size: 100,
muiTableBodyCellProps: {
sx: {
borderLeft: "1px solid #e1e1e1",
py: 0,
"&:first-of-type": {
borderLeft: "unset",
},
},
},
Cell: ({ row }) =>
row.original.area ? (
<Stack alignItems={"center"} justifyContent={"center"}>
<ShowArea area={row.original.area} />
</Stack>
) : (
"-"
),
},
Cell: ({ row }) =>
row.original.area ? (
<Stack alignItems={"center"} justifyContent={"center"}>
<ShowArea area={row.original.area} />
</Stack>
) : (
"-"
),
},
{
accessorFn: (row) => moment(row.request_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
header: "تاریخ ثبت",
id: "request_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
],
{
accessorFn: (row) => moment(row.request_date).locale("fa").format("HH:mm | yyyy/MM/DD"),
header: "تاریخ ثبت",
id: "request_date",
enableColumnFilter: true,
datatype: "date",
filterMode: "between",
grow: false,
size: 100,
},
];},
[]
);

View File

@@ -0,0 +1,54 @@
import { Button, DialogActions, DialogContent, Stack } from "@mui/material";
import { Controller, useForm } from "react-hook-form";
import CarCode from "@/core/components/CarCode";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import StyledForm from "@/core/components/StyledForm";
const schema = yup.object().shape({
machinesId: yup.object().required("کد خودرو الزامی است."),
});
const CreateViolationForm = ({ setOpenMachinesDialog, defaultValues, onSubmitBase }) => {
const {
control,
handleSubmit,
formState: { isSubmitting },
} = useForm({ defaultValues, resolver: yupResolver(schema), mode: "all" });
const handleOnSubmit = async (data) => {
await onSubmitBase(data);
};
return (
<>
<StyledForm onSubmit={handleSubmit(handleOnSubmit)}>
<DialogContent>
<Stack sx={{ minWidth: "200px" }}>
<Controller
control={control}
render={({ field, fieldState: { error } }) => {
return (
<CarCode
carCode={field.value}
setCarCode={(value) => field.onChange(value)}
error={error}
/>
);
}}
name={"machinesId"}
/>
</Stack>
</DialogContent>
<DialogActions sx={{ alignItems: "center", justifyContent: "end" }}>
<Button onClick={() => setOpenMachinesDialog(false)} variant="outlined" color="secondary" size="large">
{"بستن"}
</Button>
<Button variant="contained" disabled={isSubmitting} size="large" type={"submit"}>
{"تایید"}
</Button>
</DialogActions>
</StyledForm>
</>
);
};
export default CreateViolationForm

View File

@@ -0,0 +1,39 @@
import { DialogTitle } from "@mui/material";
import { DialogHeader } from "next/dist/client/components/react-dev-overlay/internal/components/Dialog";
import useRequest from "@/lib/hooks/useRequest";
import { CREATE_VIOLATION } from "@/core/utils/routes";
import CreateViolationForm from "@/components/dashboard/roadMissions/violations/Actions/CreateViolation/Form/CreateForm";
const ViolationForm = ({ setOpenMachinesDialog, mutate, openMachinesDialog }) => {
const requestServer = useRequest({ notificationSuccess: true });
const defaultValues = {
machinesId: null,
};
const submitForm = async (result) => {
await requestServer(CREATE_VIOLATION, "post", {
data: {
machine_code: result.machinesId.machine_code,
},
})
.then((response) => {
setOpenMachinesDialog(false);
mutate();
})
.catch((error) => {});
};
return (
<>
<DialogHeader>
<DialogTitle>ثبت تخلف</DialogTitle>
</DialogHeader>
<CreateViolationForm
setOpenMachinesDialog={setOpenMachinesDialog}
defaultValues={defaultValues}
onSubmitBase={submitForm}
/>
</>
);
};
export default ViolationForm;

View File

@@ -0,0 +1,50 @@
import { AddCircle, Close } from "@mui/icons-material";
import { Button, Dialog, IconButton, Tooltip } from "@mui/material";
import { useState } from "react";
import ViolationForm from "./Form";
const CreateViolation = ({ mutate }) => {
const [openMachinesDialog, setOpenMachinesDialog] = useState(false);
return (
<>
<Tooltip title="ثبت تخلف" arrow placement="left">
<Button
size={"small"}
variant="contained"
color="primary"
startIcon={<AddCircle />}
onClick={() => setOpenMachinesDialog(true)}
>
ثبت تخلف
</Button>
</Tooltip>
<Dialog open={openMachinesDialog} fullWidth maxWidth="sm">
<IconButton
aria-label="close"
onClick={() => setOpenMachinesDialog(false)}
sx={(theme) => ({
position: "absolute",
right: 8,
top: 8,
zIndex: 50,
color: theme.palette.grey[500],
})}
>
<Close />
</IconButton>
{openMachinesDialog && (
<ViolationForm
openMachinesDialog={openMachinesDialog}
setOpenMachinesDialog={setOpenMachinesDialog}
mutate={mutate}
/>
)}
</Dialog>
</>
);
};
export default CreateViolation;

View File

@@ -0,0 +1,51 @@
import { EDIT_VIOLATION } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest";
import { DialogTitle } from "@mui/material";
import { DialogHeader } from "next/dist/client/components/react-dev-overlay/internal/components/Dialog";
import EditViolationForm from "./EditViolationForm";
import moment from "jalali-moment";
const EditController = ({ rowId, mutate, setOpen }) => {
const requestServer = useRequest({ notificationSuccess: true });
const defaultData = {
start_date: null,
start_time: null,
end_date: null,
end_time: null,
};
const handleSubmit = async (result) => {
const payload = {};
if (result.start_date && result.start_time) {
payload.enter_time = `${result.start_date} ${moment(result.start_time).format("HH:mm")}`;
}
if (result.end_date && result.end_time) {
payload.exit_time = `${result.end_date} ${moment(result.end_time).format("HH:mm")}`;
}
await requestServer(`${EDIT_VIOLATION}/${rowId}`, "post", {
data: payload,
})
.then(() => {
mutate();
setOpen(false);
})
.catch(() => {});
};
return (
<>
<DialogHeader>
<DialogTitle>ثبت تردد</DialogTitle>
</DialogHeader>
<EditViolationForm
setOpenMachinesDialog={setOpen}
defaultValues={defaultData}
onSubmitBase={handleSubmit}
/>
</>
);
};
export default EditController;

View File

@@ -0,0 +1,95 @@
import { 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";
export const schema = yup
.object({
start_date: yup.string().nullable(),
start_time: yup.string().nullable(),
end_date: yup.string().nullable(),
end_time: yup.string().nullable(),
})
.test("valid-dates", function (values) {
if (!values) return false;
const hasStartDate = !!values.start_date;
const hasStartTime = !!values.start_time;
const hasEndDate = !!values.end_date;
const hasEndTime = !!values.end_time;
if (hasStartDate !== hasStartTime) {
return this.createError({
message: "تاریخ و زمان شروع باید هر دو وارد شوند",
});
}
if (hasEndDate !== hasEndTime) {
return this.createError({
message: "تاریخ و زمان پایان باید هر دو وارد شوند",
});
}
if (!((hasStartDate && hasStartTime) || (hasEndDate && hasEndTime))) {
return this.createError({
message: "حداقل تاریخ و زمان شروع یا پایان باید مشخص شود",
});
}
return true;
});
const EditViolationForm = ({ setOpenMachinesDialog, defaultValues, onSubmitBase }) => {
const {
control,
handleSubmit,
formState: { isSubmitting, errors },
} = useForm({ defaultValues, resolver: yupResolver(schema), mode: "all" });
const handleOnSubmit = async (data) => {
await onSubmitBase(data);
};
return (
<>
<StyledForm onSubmit={handleSubmit(handleOnSubmit)}>
<DialogContent dividers>
<Box sx={{ flex: 1 }}>
<Stack>
<Grid container spacing={2}>
<MissionDates control={control} />
</Grid>
{errors?.[""]?.message && (
<Box
sx={{
color: "error.main",
textAlign: "center",
mb: 2,
fontSize: 14,
}}
>
{errors?.[""]?.message}
</Box>
)}
</Stack>
</Box>
</DialogContent>
<DialogActions sx={{ alignItems: "center", justifyContent: "center" }}>
<Button
onClick={() => setOpenMachinesDialog(false)}
variant="outlined"
color="secondary"
size="large"
>
{"بستن"}
</Button>
<Button disabled={isSubmitting} variant="contained" size="large" type="submit">
ثبت
</Button>
</DialogActions>
</StyledForm>
</>
);
};
export default EditViolationForm

View File

@@ -0,0 +1,99 @@
import MuiDatePicker from "@/core/components/MuiDatePicker";
import MuiTimePicker from "@/core/components/MuiTimePicker";
import { makeDateTime } from "@/core/utils/makeDateTime";
import { Grid } from "@mui/material";
import { Controller, useWatch } from "react-hook-form";
const MissionDates = ({ control }) => {
const start_date = useWatch({ control, name: "start_date" });
const end_date = useWatch({ control, name: "end_date" });
const now = new Date();
return (
<>
<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}
maxDate={end_date ?? null}
placeholder={"تاریخ شروع ماموریت را وارد کنید"}
label={"تاریخ شروع ماموریت"}
setFieldValue={(name, value) => field.onChange(value || [])}
helperText={error ? error.message : null}
/>
);
}}
/>
</Grid>
<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}
views={["hours"]}
placeholder={"زمان شروع ماموریت را وارد کنید"}
label={"زمان شروع ماموریت"}
setFieldValue={(name, value) => field.onChange(value || null)}
helperText={error ? error.message : null}
/>
);
}}
/>
</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}
/>
);
}}
/>
</Grid>
<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}
views={["hours"]}
placeholder={"زمان پایان ماموریت را وارد کنید"}
label={"زمان پایان ماموریت"}
setFieldValue={(name, value) => field.onChange(value || null)}
helperText={error ? error.message : null}
/>
);
}}
/>
</Grid>
</>
);
};
export default MissionDates;

View File

@@ -0,0 +1,51 @@
import CloseIcon from "@mui/icons-material/Close";
import { Dialog, IconButton, Tooltip } from "@mui/material";
import { useState } from "react";
import BookmarkAddIcon from "@mui/icons-material/BookmarkAdd";
import EditController from "./EditController";
const EditViolation = ({ mutate, row, rowId }) => {
const [open, setOpen] = useState(false);
return (
<>
<Tooltip title="ثبت تردد" arrow placement="right">
<IconButton
color="primary"
sx={{ textTransform: "unset", alignSelf: "center" }}
onClick={() => {
setOpen(true);
}}
>
<BookmarkAddIcon />
</IconButton>
</Tooltip>
<Dialog
fullWidth
open={open}
maxWidth={"xs"}
PaperProps={{
sx: {
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
},
}}
>
<IconButton
aria-label="close"
onClick={() => setOpen(false)}
sx={(theme) => ({
position: "absolute",
right: 8,
top: 8,
zIndex: 50,
color: theme.palette.grey[500],
})}
>
<CloseIcon />
</IconButton>
{open && <EditController setOpen={setOpen} rowId={rowId} row={row} mutate={mutate} />}
</Dialog>
</>
);
};
export default EditViolation;

View File

@@ -1,7 +1,15 @@
import CreateWithoutProcess from "../Actions/CreateWithoutProcess";
import EditViolation from "../Actions/EditViolation";
const RowActions = ({ row, mutate }) => {
const canEdit = row.original.status === 0 && row.original.type === 1;
return canEdit && <CreateWithoutProcess row={row} mutate={mutate} />;
return (
<>
{!row.original.mileage &&
<EditViolation row={row} mutate={mutate} rowId={row.getValue("id")} />}
{canEdit && <CreateWithoutProcess row={row} mutate={mutate} />}
</>
);
};
export default RowActions;

View File

@@ -0,0 +1,11 @@
import { Stack } from "@mui/material";
import CreateViolation from "./Actions/CreateViolation";
const Toolbar = ({ mutate }) => {
return (
<Stack direction={"row"} spacing={1}>
<CreateViolation mutate={mutate} />
</Stack>
);
};
export default Toolbar;

View File

@@ -5,6 +5,7 @@ import { Box } from "@mui/material";
import moment from "jalali-moment";
import { useMemo } from "react";
import RowActions from "./RowActions";
import Toolbar from "./Toolbar";
const ViolationsList = () => {
const columns = useMemo(
@@ -68,6 +69,7 @@ const ViolationsList = () => {
<DataTableWithAuth
need_filter={true}
columns={columns}
TableToolbar={Toolbar}
sorting={[{ id: "id", desc: true }]}
table_url={GET_ROAD_MISSIONS_VIOLATIONS_LIST}
page_name={"roadMissionsOperator"}

View File

@@ -231,6 +231,8 @@ export const FINISH_MISSION = api + "/api/v3/missions/control_unit/finish";
export const GET_ROAD_MISSIONS_VIOLATIONS_LIST = api + "/api/v3/missions/violation_management";
export const GET_MISSION_PROVINCE_ACTIVITY_REPORT = api + "/api/v3/missions/report/country_activity";
export const GET_MISSION_CITY_ACTIVITY_REPORT = api + "/api/v3/missions/report/country_activity";
export const CREATE_VIOLATION = api + "/api/v3/missions/violation_management";
export const EDIT_VIOLATION = api + "/api/v3/missions/violation_management";
export const GET_MACHINES_TABLE_LIST = api + "/api/v3/cmms_machines";