2026-01-18 14:32:49 +03:30
|
|
|
|
import {
|
|
|
|
|
|
Button,
|
|
|
|
|
|
Card,
|
|
|
|
|
|
IconButton,
|
|
|
|
|
|
List,
|
|
|
|
|
|
ListItemButton,
|
|
|
|
|
|
ListItemIcon,
|
|
|
|
|
|
ListItemText,
|
|
|
|
|
|
Popover,
|
|
|
|
|
|
Tooltip,
|
|
|
|
|
|
} from "@mui/material";
|
|
|
|
|
|
import { useContext, useEffect, useState } from "react";
|
|
|
|
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
|
|
|
|
// import { slaughterGetCars } from "../../services/slaughter-get-cars";
|
|
|
|
|
|
// import { slaughterDeleteCar } from "../../services/slaughter-delete-car";
|
|
|
|
|
|
import { Grid } from "../../../../components/grid/Grid";
|
|
|
|
|
|
import { SPACING } from "../../../../data/spacing";
|
|
|
|
|
|
// import { SlaughterNewCar } from "../slaughter-new-car/SlaughterNewCar";
|
|
|
|
|
|
// import { ProvinceRegisterCar } from "../province-register-car/ProvinceRegisterCar";
|
|
|
|
|
|
import { provinceGetCars } from "../../services/province-get-cars";
|
|
|
|
|
|
import {
|
|
|
|
|
|
DRAWER,
|
|
|
|
|
|
LOADING_END,
|
|
|
|
|
|
LOADING_START,
|
|
|
|
|
|
} from "../../../../lib/redux/slices/appSlice";
|
|
|
|
|
|
import { ProvinceRegisterCarForm } from "../province-register-car-form/ProvinceRegisterCarForm";
|
|
|
|
|
|
import { provinceRemoveCar } from "../../services/province-remove-car";
|
|
|
|
|
|
import { AppContext } from "../../../../contexts/AppContext";
|
|
|
|
|
|
import { ProvinceAllocateCarsForm } from "../province-allocate-cars-form/ProvinceAllocateCarsForm";
|
|
|
|
|
|
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
|
|
|
|
|
import { ManageCarState } from "../manage-car-state/ManageCarState";
|
|
|
|
|
|
import axios from "axios";
|
|
|
|
|
|
import { RiFileExcel2Fill } from "react-icons/ri";
|
|
|
|
|
|
import TuneIcon from "@mui/icons-material/Tune";
|
|
|
|
|
|
import LocalShippingIcon from "@mui/icons-material/LocalShipping";
|
|
|
|
|
|
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
|
|
|
|
|
|
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
|
|
|
|
|
|
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
|
|
|
|
|
import { provinceCarsDashboardService } from "../../services/province-cars-dashboard";
|
|
|
|
|
|
|
|
|
|
|
|
export const ProvinceManageCars = () => {
|
|
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
|
const [dataTable, setDataTable] = useState([]);
|
|
|
|
|
|
const [openNotif] = useContext(AppContext);
|
|
|
|
|
|
const { provinceCars } = useSelector((state) => state.provinceSlice);
|
|
|
|
|
|
// const userInfo = useSelector((state) => state.userSlice);
|
|
|
|
|
|
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
2026-01-18 16:03:27 +03:30
|
|
|
|
|
2026-01-18 14:32:49 +03:30
|
|
|
|
useEffect(() => {
|
2026-01-18 16:03:27 +03:30
|
|
|
|
dispatch(provinceGetCars());
|
|
|
|
|
|
}, []);
|
2026-01-18 14:32:49 +03:30
|
|
|
|
|
|
|
|
|
|
const [dashboardData, setDashboardData] = useState([]);
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2026-01-18 16:03:27 +03:30
|
|
|
|
dispatch(provinceCarsDashboardService()).then((r) => {
|
2026-01-18 14:32:49 +03:30
|
|
|
|
setDashboardData(r.payload.data);
|
|
|
|
|
|
});
|
2026-01-18 16:03:27 +03:30
|
|
|
|
}, [dispatch, provinceCars]);
|
2026-01-18 14:32:49 +03:30
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
const d = provinceCars?.map((item, i) => {
|
|
|
|
|
|
let carIdentity = "-";
|
|
|
|
|
|
if (item.type === "rental") {
|
|
|
|
|
|
carIdentity = "اجاره ای";
|
|
|
|
|
|
} else if (item.type === "exclusive") {
|
|
|
|
|
|
carIdentity = "اختصاصی";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// const handleDisable =
|
|
|
|
|
|
// getRoleFromUrl() === "ProvinceOperator" ||
|
|
|
|
|
|
// getRoleFromUrl() === "SuperAdmin" ||
|
|
|
|
|
|
// getRoleFromUrl() === "AdminX"
|
|
|
|
|
|
// ? false
|
|
|
|
|
|
// : true;
|
|
|
|
|
|
|
|
|
|
|
|
const killhouseList =
|
|
|
|
|
|
item.type === "rental"
|
|
|
|
|
|
? "همه کشتارگاه ها/کشتارکن ها"
|
|
|
|
|
|
: item?.killHouseList?.map((killHouse, index) => {
|
|
|
|
|
|
const separator =
|
|
|
|
|
|
index + 1 === item.killHouseList.length ? "" : " - ";
|
|
|
|
|
|
return killHouse?.killHouseName + separator;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
|
i + 1,
|
|
|
|
|
|
item.typeCar,
|
|
|
|
|
|
carIdentity,
|
|
|
|
|
|
item.pelak,
|
|
|
|
|
|
item.capocity,
|
|
|
|
|
|
parseInt(item.healthCode),
|
|
|
|
|
|
// Number(item.healthCode),
|
|
|
|
|
|
item.driverName,
|
|
|
|
|
|
item.driverMobile,
|
|
|
|
|
|
killhouseList,
|
|
|
|
|
|
<ManageCarState key={item.key} item={item} />,
|
|
|
|
|
|
<CarActions
|
|
|
|
|
|
key={`car-action-${item.key}`}
|
|
|
|
|
|
item={item}
|
|
|
|
|
|
openNotif={openNotif}
|
|
|
|
|
|
/>,
|
|
|
|
|
|
];
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
setDataTable(d);
|
|
|
|
|
|
}, [provinceCars, dispatch, openNotif]);
|
|
|
|
|
|
|
|
|
|
|
|
const [tableDataCol] = useState([
|
|
|
|
|
|
"ردیف",
|
|
|
|
|
|
"مدل خودرو",
|
|
|
|
|
|
"ماهیت",
|
|
|
|
|
|
"پلاک",
|
|
|
|
|
|
"ظرفیت",
|
|
|
|
|
|
"کد بهداشتی",
|
|
|
|
|
|
"نام راننده",
|
|
|
|
|
|
"موبایل راننده",
|
|
|
|
|
|
"کشتارگاه ها/کشتارکن ها",
|
|
|
|
|
|
"وضعیت",
|
|
|
|
|
|
"عملیات",
|
|
|
|
|
|
]);
|
|
|
|
|
|
return (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<Grid
|
|
|
|
|
|
container
|
|
|
|
|
|
alignItems="center"
|
|
|
|
|
|
justifyContent="space-between"
|
|
|
|
|
|
gap={SPACING.SMALL}
|
|
|
|
|
|
xs={12}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
variant="contained"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
dispatch(
|
|
|
|
|
|
DRAWER({
|
|
|
|
|
|
right: !(window.innerWidth <= 600),
|
|
|
|
|
|
bottom: window.innerWidth <= 600,
|
|
|
|
|
|
title: "افزودن خودرو",
|
|
|
|
|
|
content: <ProvinceRegisterCarForm />,
|
|
|
|
|
|
})
|
|
|
|
|
|
);
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
افزودن خودرو
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<Tooltip title="خروجی اکسل">
|
|
|
|
|
|
<a
|
|
|
|
|
|
href={`${
|
|
|
|
|
|
axios.defaults.baseURL
|
2026-01-18 16:03:27 +03:30
|
|
|
|
}car_province_excel/?key=${userKey}&role=${getRoleFromUrl()}`}
|
2026-01-18 14:32:49 +03:30
|
|
|
|
rel="noreferrer"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Button color="success">
|
|
|
|
|
|
<RiFileExcel2Fill size={32} />
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
<Card sx={{ width: "100%" }}>
|
2026-01-18 16:03:27 +03:30
|
|
|
|
<Grid container mt={2} mb={4} isDashboard>
|
2026-01-18 14:32:49 +03:30
|
|
|
|
<ResponsiveTable
|
|
|
|
|
|
noPagination
|
|
|
|
|
|
isDashboard
|
|
|
|
|
|
columns={[
|
|
|
|
|
|
"تعداد خودرو ها",
|
|
|
|
|
|
"اختصاصی",
|
|
|
|
|
|
"اجاره ای",
|
|
|
|
|
|
"فعال",
|
|
|
|
|
|
"غیر فعال",
|
|
|
|
|
|
"معلق",
|
|
|
|
|
|
]}
|
|
|
|
|
|
data={[
|
|
|
|
|
|
[
|
|
|
|
|
|
dashboardData?.total?.toLocaleString(),
|
|
|
|
|
|
dashboardData?.exclusive?.toLocaleString(),
|
|
|
|
|
|
dashboardData?.rental?.toLocaleString(),
|
|
|
|
|
|
dashboardData?.active?.toLocaleString(),
|
|
|
|
|
|
dashboardData?.inactive?.toLocaleString(),
|
|
|
|
|
|
dashboardData?.suspended?.toLocaleString(),
|
|
|
|
|
|
],
|
|
|
|
|
|
]}
|
|
|
|
|
|
title={"خلاصه اطلاعات"}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Grid>
|
|
|
|
|
|
|
|
|
|
|
|
<ResponsiveTable
|
|
|
|
|
|
paginated
|
|
|
|
|
|
title="خودروها"
|
|
|
|
|
|
columns={tableDataCol}
|
|
|
|
|
|
data={dataTable}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
</Grid>
|
|
|
|
|
|
</>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const CarActions = ({ item, openNotif }) => {
|
|
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
|
const [anchorEl, setAnchorEl] = useState(null);
|
|
|
|
|
|
|
|
|
|
|
|
const handleDisable = !(
|
|
|
|
|
|
getRoleFromUrl() === "ProvinceOperator" ||
|
|
|
|
|
|
getRoleFromUrl() === "SuperAdmin" ||
|
|
|
|
|
|
getRoleFromUrl() === "AdminX"
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const hasForbiddenKillhouse = item.killHouseList?.some(
|
|
|
|
|
|
(killItem) => !killItem.allowState
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const hasAccess = !handleDisable || !hasForbiddenKillhouse;
|
|
|
|
|
|
const isRental = item.type === "rental";
|
|
|
|
|
|
|
|
|
|
|
|
const open = Boolean(anchorEl);
|
|
|
|
|
|
const id = open ? `province-cars-popover-${item.key}` : undefined;
|
|
|
|
|
|
|
|
|
|
|
|
const closePopover = () => setAnchorEl(null);
|
|
|
|
|
|
|
|
|
|
|
|
const handleAllocate = () => {
|
|
|
|
|
|
closePopover();
|
|
|
|
|
|
dispatch(
|
|
|
|
|
|
DRAWER({
|
|
|
|
|
|
right: !(window.innerWidth <= 600),
|
|
|
|
|
|
bottom: window.innerWidth <= 600,
|
|
|
|
|
|
title: "تخصیص/حذف کشتارگاه",
|
|
|
|
|
|
content: (
|
|
|
|
|
|
<ProvinceAllocateCarsForm
|
|
|
|
|
|
driverKey={item.key}
|
|
|
|
|
|
killHouseList={item.killHouseList}
|
|
|
|
|
|
/>
|
|
|
|
|
|
),
|
|
|
|
|
|
})
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleEdit = () => {
|
|
|
|
|
|
closePopover();
|
|
|
|
|
|
dispatch(
|
|
|
|
|
|
DRAWER({
|
|
|
|
|
|
right: !(window.innerWidth <= 600),
|
|
|
|
|
|
bottom: window.innerWidth <= 600,
|
|
|
|
|
|
title: "ویرایش خودرو",
|
|
|
|
|
|
content: (
|
|
|
|
|
|
<ProvinceRegisterCarForm
|
|
|
|
|
|
first_name={item.firstName}
|
|
|
|
|
|
pelak={item.pelak}
|
|
|
|
|
|
city_name={item.city}
|
|
|
|
|
|
type_car={item.typeCar}
|
|
|
|
|
|
last_name={item.lastName}
|
|
|
|
|
|
capocity={item.capocity}
|
|
|
|
|
|
health_code={item.healthCode}
|
|
|
|
|
|
driver_mobile={item.driverMobile}
|
|
|
|
|
|
driverKey={item?.key}
|
|
|
|
|
|
type={item?.type}
|
|
|
|
|
|
/>
|
|
|
|
|
|
),
|
|
|
|
|
|
})
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleDelete = () => {
|
|
|
|
|
|
closePopover();
|
|
|
|
|
|
dispatch(LOADING_START());
|
|
|
|
|
|
dispatch(provinceRemoveCar(item.key)).then((r) => {
|
|
|
|
|
|
if (r.error) {
|
|
|
|
|
|
if (r.error.message.includes("403")) {
|
|
|
|
|
|
openNotif({
|
|
|
|
|
|
vertical: "top",
|
|
|
|
|
|
horizontal: "center",
|
|
|
|
|
|
msg: "امکان حذف بدلیل تخصیص بار فعال به خودرو وجود ندارد!",
|
|
|
|
|
|
severity: "error",
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
openNotif({
|
|
|
|
|
|
vertical: "top",
|
|
|
|
|
|
horizontal: "center",
|
|
|
|
|
|
msg: "مشکلی پیش آمده است!",
|
|
|
|
|
|
severity: "error",
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
dispatch(DRAWER({ right: false, bottom: false, content: null }));
|
|
|
|
|
|
dispatch(provinceGetCars());
|
|
|
|
|
|
openNotif({
|
|
|
|
|
|
vertical: "top",
|
|
|
|
|
|
horizontal: "center",
|
|
|
|
|
|
msg: "عملیات با موفقیت انجام شد.",
|
|
|
|
|
|
severity: "success",
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
dispatch(LOADING_END());
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const actionsDisabled = !hasAccess || (handleDisable && isRental);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<IconButton
|
|
|
|
|
|
aria-describedby={id}
|
|
|
|
|
|
color="primary"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
onClick={(event) => setAnchorEl(event.currentTarget)}
|
|
|
|
|
|
disabled={!hasAccess}
|
|
|
|
|
|
>
|
|
|
|
|
|
<TuneIcon />
|
|
|
|
|
|
</IconButton>
|
|
|
|
|
|
<Popover
|
|
|
|
|
|
id={id}
|
|
|
|
|
|
anchorEl={anchorEl}
|
|
|
|
|
|
open={open}
|
|
|
|
|
|
onClose={closePopover}
|
|
|
|
|
|
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
|
|
|
|
|
|
transformOrigin={{ vertical: "top", horizontal: "left" }}
|
|
|
|
|
|
disableRestoreFocus
|
|
|
|
|
|
PaperProps={{ sx: { p: 2 } }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<List sx={{ py: 0 }}>
|
|
|
|
|
|
<ListItemButton onClick={handleAllocate} disabled={actionsDisabled}>
|
|
|
|
|
|
<ListItemIcon>
|
|
|
|
|
|
<LocalShippingIcon
|
|
|
|
|
|
fontSize="small"
|
|
|
|
|
|
color={actionsDisabled ? "disabled" : "primary"}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</ListItemIcon>
|
|
|
|
|
|
<ListItemText
|
|
|
|
|
|
primary="تخصیص به کشتارگاه"
|
|
|
|
|
|
primaryTypographyProps={{
|
|
|
|
|
|
variant: "body2",
|
|
|
|
|
|
color: actionsDisabled ? "text.secondary" : "primary",
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</ListItemButton>
|
|
|
|
|
|
<ListItemButton onClick={handleEdit} disabled={actionsDisabled}>
|
|
|
|
|
|
<ListItemIcon>
|
|
|
|
|
|
<EditOutlinedIcon
|
|
|
|
|
|
fontSize="small"
|
|
|
|
|
|
color={actionsDisabled ? "disabled" : "primary"}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</ListItemIcon>
|
|
|
|
|
|
<ListItemText
|
|
|
|
|
|
primary="ویرایش"
|
|
|
|
|
|
primaryTypographyProps={{
|
|
|
|
|
|
variant: "body2",
|
|
|
|
|
|
color: actionsDisabled ? "text.secondary" : "primary",
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</ListItemButton>
|
|
|
|
|
|
<ListItemButton onClick={handleDelete} disabled={actionsDisabled}>
|
|
|
|
|
|
<ListItemIcon>
|
|
|
|
|
|
<DeleteOutlineIcon
|
|
|
|
|
|
fontSize="small"
|
|
|
|
|
|
color={actionsDisabled ? "disabled" : "error"}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</ListItemIcon>
|
|
|
|
|
|
<ListItemText
|
|
|
|
|
|
primary="حذف"
|
|
|
|
|
|
primaryTypographyProps={{
|
|
|
|
|
|
variant: "body2",
|
|
|
|
|
|
color: actionsDisabled ? "text.secondary" : "error",
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</ListItemButton>
|
|
|
|
|
|
</List>
|
|
|
|
|
|
</Popover>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|