From ecced23bf448d1abcc6848477d34412e585efc20 Mon Sep 17 00:00:00 2001 From: baslani Date: Mon, 26 Jan 2026 16:30:14 +0330 Subject: [PATCH] implemented violations reports page --- .../reports/missionsReports/page.js | 2 +- .../reports/violationsReports/page.js | 19 ++- .../violationsReports/ExcelPrint/index.jsx | 77 ++++++++++ .../Search/FromDateController.jsx | 27 ++++ .../Search/SearchReportField.jsx | 44 ++++++ .../Search/SelectProvince.jsx | 45 ++++++ .../Search/ToDateController.jsx | 30 ++++ .../violationsReports/Search/index.jsx | 16 ++ .../reports/violationsReports/Toolbar.jsx | 11 ++ .../ViolationsReportsList.jsx | 101 +++++++++++++ .../reports/violationsReports/index.jsx | 141 ++++++++++++++++++ src/core/utils/routes.js | 22 +-- 12 files changed, 521 insertions(+), 14 deletions(-) create mode 100644 src/components/dashboard/roadMissions/reports/violationsReports/ExcelPrint/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/violationsReports/Search/FromDateController.jsx create mode 100644 src/components/dashboard/roadMissions/reports/violationsReports/Search/SearchReportField.jsx create mode 100644 src/components/dashboard/roadMissions/reports/violationsReports/Search/SelectProvince.jsx create mode 100644 src/components/dashboard/roadMissions/reports/violationsReports/Search/ToDateController.jsx create mode 100644 src/components/dashboard/roadMissions/reports/violationsReports/Search/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/violationsReports/Toolbar.jsx create mode 100644 src/components/dashboard/roadMissions/reports/violationsReports/ViolationsReportsList.jsx create mode 100644 src/components/dashboard/roadMissions/reports/violationsReports/index.jsx diff --git a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/missionsReports/page.js b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/missionsReports/page.js index 30c499c..7a6bc58 100644 --- a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/missionsReports/page.js +++ b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/missionsReports/page.js @@ -1,7 +1,7 @@ import WithPermission from "@/core/middlewares/withPermission"; import MissionsReportPage from "@/components/dashboard/roadMissions/reports/missionsReports"; export const metadata = { - title: "کارتابل گزارش ماموریت ها", + title: "کارتابل گزارش ترددها", }; const Page = () => { return ( diff --git a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/violationsReports/page.js b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/violationsReports/page.js index 6084a35..6aa2483 100644 --- a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/violationsReports/page.js +++ b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/violationsReports/page.js @@ -1,3 +1,18 @@ -export default function ViolationReportsPage() { - return
ViolationReportsPage
; +import ViolationsReportsPage from "@/components/dashboard/roadMissions/reports/violationsReports"; +import WithPermission from "@/core/middlewares/withPermission"; + +export const metadata = { + title: "کارتابل گزارش تخلفات", +}; + +export default function Page() { + return ( + + + + ); } diff --git a/src/components/dashboard/roadMissions/reports/violationsReports/ExcelPrint/index.jsx b/src/components/dashboard/roadMissions/reports/violationsReports/ExcelPrint/index.jsx new file mode 100644 index 0000000..b7487f6 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/violationsReports/ExcelPrint/index.jsx @@ -0,0 +1,77 @@ +"use client"; +import { + EXPORT_MISSIONS_REPORT_VIOLATION_COUNTRY_EXCEL_ACTIVITY, + EXPORT_MISSIONS_REPORT_VIOLATION_PROVINCE_EXCEL_ACTIVITY, +} from "@/core/utils/routes"; +import useRequest from "@/lib/hooks/useRequest"; +import { useTheme } from "@emotion/react"; +import DescriptionIcon from "@mui/icons-material/Description"; +import { Button, CircularProgress, IconButton, useMediaQuery } from "@mui/material"; +import FileSaver from "file-saver"; +import moment from "jalali-moment"; +import { useMemo, useState } from "react"; + +const PrintExcel = ({ table, filterData }) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down("sm")); + const [loading, setLoading] = useState(false); + const requestServer = useRequest({ notificationSuccess: true }); + const activeFilters = Object.entries(filterData).reduce((acc, [key, filter]) => { + if (filter.value) { + acc.push({ id: filter.id, value: filter.value }); + } + return acc; + }, []); + + const filterParams = useMemo(() => { + const params = new URLSearchParams(); + activeFilters.length > 0 && + activeFilters.map((filter, index) => { + params.set(`${filter.id}`, filter.value); + }); + return params; + }, [activeFilters]); + + const clickHandler = () => { + setLoading(true); + const CountryOrProvince = activeFilters.find((item) => item.id === "province_id"); + const requestUrl = + CountryOrProvince.value === "-1" + ? EXPORT_MISSIONS_REPORT_VIOLATION_COUNTRY_EXCEL_ACTIVITY + : EXPORT_MISSIONS_REPORT_VIOLATION_PROVINCE_EXCEL_ACTIVITY; + requestServer(`${requestUrl}?${filterParams}`, "get", { + requestOptions: { responseType: "blob" }, + }) + .then((response) => { + const filename = `خروجی کارتابل گزارشات گشت راهداری تاریخ_${moment().format("jYYYY_jMM_jDD")}.xlsx`; + FileSaver.saveAs(response.data, filename); + }) + .catch(() => {}) + .finally(() => { + setLoading(false); + }); + }; + + return ( + <> + {isMobile ? ( + + + + ) : ( + + )} + + ); +}; +export default PrintExcel; diff --git a/src/components/dashboard/roadMissions/reports/violationsReports/Search/FromDateController.jsx b/src/components/dashboard/roadMissions/reports/violationsReports/Search/FromDateController.jsx new file mode 100644 index 0000000..490ee7b --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/violationsReports/Search/FromDateController.jsx @@ -0,0 +1,27 @@ +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller } from "react-hook-form"; + +const FromDateController = ({ control }) => { + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default FromDateController; diff --git a/src/components/dashboard/roadMissions/reports/violationsReports/Search/SearchReportField.jsx b/src/components/dashboard/roadMissions/reports/violationsReports/Search/SearchReportField.jsx new file mode 100644 index 0000000..bde2a4c --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/violationsReports/Search/SearchReportField.jsx @@ -0,0 +1,44 @@ +import SearchIcon from "@mui/icons-material/Search"; +import { Button, Grid } from "@mui/material"; +import { Controller } from "react-hook-form"; +import FromDateController from "./FromDateController"; +import SelectProvince from "./SelectProvince"; +import ToDateController from "./ToDateController"; + +const SearchReportField = ({ control, hasProvincesPermission }) => { + return ( + + + + + + + + {hasProvincesPermission && ( + + + + )} + + ( + + )} + /> + + + ); +}; + +export default SearchReportField; diff --git a/src/components/dashboard/roadMissions/reports/violationsReports/Search/SelectProvince.jsx b/src/components/dashboard/roadMissions/reports/violationsReports/Search/SelectProvince.jsx new file mode 100644 index 0000000..2b24d67 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/violationsReports/Search/SelectProvince.jsx @@ -0,0 +1,45 @@ +import useProvinces from "@/lib/hooks/useProvince"; +import { FormControl, FormHelperText, InputLabel, MenuItem, Select } from "@mui/material"; +import { Controller } from "react-hook-form"; + +const SelectProvince = ({ control }) => { + const { provinces, loadingProvinces, errorProvinces } = useProvinces(); + return ( + ( + + استان + + {error && {error.message}} + + )} + /> + ); +}; +export default SelectProvince; diff --git a/src/components/dashboard/roadMissions/reports/violationsReports/Search/ToDateController.jsx b/src/components/dashboard/roadMissions/reports/violationsReports/Search/ToDateController.jsx new file mode 100644 index 0000000..2dd7263 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/violationsReports/Search/ToDateController.jsx @@ -0,0 +1,30 @@ +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller, useWatch } from "react-hook-form"; + +const ToDateController = ({ control }) => { + const minDate = useWatch({ control, name: "from_date" }); + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default ToDateController; diff --git a/src/components/dashboard/roadMissions/reports/violationsReports/Search/index.jsx b/src/components/dashboard/roadMissions/reports/violationsReports/Search/index.jsx new file mode 100644 index 0000000..63d4a61 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/violationsReports/Search/index.jsx @@ -0,0 +1,16 @@ +import StyledForm from "@/core/components/StyledForm"; +import SearchReportField from "./SearchReportField"; + +const SearchReportList = ({ handleSubmit, onSearchSubmit, control, hasProvincesPermission }) => { + return ( + <> + + + + + ); +}; +export default SearchReportList; diff --git a/src/components/dashboard/roadMissions/reports/violationsReports/Toolbar.jsx b/src/components/dashboard/roadMissions/reports/violationsReports/Toolbar.jsx new file mode 100644 index 0000000..0f726c7 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/violationsReports/Toolbar.jsx @@ -0,0 +1,11 @@ +import { Box } from "@mui/material"; +import PrintExcel from "./ExcelPrint"; + +const Toolbar = ({ table, filterData, mutate }) => { + return ( + + + + ); +}; +export default Toolbar; diff --git a/src/components/dashboard/roadMissions/reports/violationsReports/ViolationsReportsList.jsx b/src/components/dashboard/roadMissions/reports/violationsReports/ViolationsReportsList.jsx new file mode 100644 index 0000000..62b848b --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/violationsReports/ViolationsReportsList.jsx @@ -0,0 +1,101 @@ +"use client"; +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import { Box } from "@mui/material"; +import { useEffect, useMemo } from "react"; +import Toolbar from "./Toolbar"; + +const ViolationsReportsList = ({ data, specialFilter }) => { + useEffect(() => { + console.log(data); + }, [data]); + const columns = useMemo(() => { + return [ + { + accessorKey: "edare_name", + header: "اداره کل", + id: "edare_name", + enableColumnFilter: false, + enableSorting: false, + datatype: "text", + grow: false, + size: 50, + }, + { + accessorKey: "total", + header: "کل تخلفات", + id: "total", + enableColumnFilter: false, + enableSorting: false, + datatype: "numeric", + grow: false, + size: 50, + }, + { + accessorKey: "done", + header: "اقدام شده", + id: "done", + enableColumnFilter: false, + enableSorting: false, + datatype: "numeric", + grow: false, + size: 50, + }, + { + accessorKey: "undone", + header: "اقدام نشده", + id: "un_done", + enableColumnFilter: false, + enableSorting: false, + datatype: "numeric", + grow: false, + size: 50, + }, + { + accessorKey: "gps", + header: "GPS", + id: "gps", + enableColumnFilter: false, + enableSorting: false, + datatype: "numeric", + grow: false, + size: 50, + }, + { + accessorKey: "herasat", + header: "ثبت حراست", + id: "herasat", + enableColumnFilter: false, + enableSorting: false, + datatype: "numeric", + grow: false, + size: 50, + }, + { + accessorKey: "mil_gps", + header: "کیلومتر GPS", + id: "mil_gps", + enableColumnFilter: false, + enableSorting: false, + datatype: "numeric", + grow: false, + size: 50, + }, + ]; + }, []); + + return ( + + + + ); +}; + +export default ViolationsReportsList; diff --git a/src/components/dashboard/roadMissions/reports/violationsReports/index.jsx b/src/components/dashboard/roadMissions/reports/violationsReports/index.jsx new file mode 100644 index 0000000..c2fcd77 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/violationsReports/index.jsx @@ -0,0 +1,141 @@ +"use client"; +import PageTitle from "@/core/components/PageTitle"; +import { + GET_MISSIONS_REPORT_VIOLATION_COUNTRY_ACTIVITY, + GET_MISSIONS_REPORT_VIOLATION_PROVINCE_ACTIVITY, +} from "@/core/utils/routes"; +import { useAuth } from "@/lib/contexts/auth"; +import { usePermissions } from "@/lib/hooks/usePermissions"; +import useRequest from "@/lib/hooks/useRequest"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { LinearProgress, Stack } from "@mui/material"; +import moment from "jalali-moment"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import * as yup from "yup"; +import ViolationsReportsList from "./ViolationsReportsList"; +import SearchReportList from "./Search"; + +const ViolationsReportsPage = () => { + const [data, setData] = useState(null); + const { data: userPermissions } = usePermissions(); + const { user } = useAuth(); + const requestServer = useRequest(); + // const hasProvincesPermission = userPermissions?.includes("mission-report-country"); + + const defaultValues = { + from_date: moment(new Date()).format("YYYY-MM-DD"), + date_to: moment(new Date()).format("YYYY-MM-DD"), + province_id: user.province_id || "-1", + }; + 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" }, + ]; + const [specialFilter, setSpecialFilter] = useState(defaultFilter); + + const onSearchSubmit = async (data) => { + const params = new URLSearchParams(); + params.set("from_date", `${data.from_date}`); + params.set("date_to", `${data.date_to}`); + 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" }, + ]); + if (data.province_id === "-1") { + try { + // params.set("province_id", `${data.province_id}`); + const response = await requestServer(`${GET_MISSIONS_REPORT_VIOLATION_COUNTRY_ACTIVITY}?${params}`); + const result = response.data.data; + const nationalReportForItem = result.activities.find((report) => report.province_id === "-1"); + const nationalReport = { + edare_name: "کل کشور", + ...nationalReportForItem, + }; + + setData({ + data: [ + nationalReport, + ...result.provinces.map((province) => { + const filteredReports = result.activities.find( + (report) => report.province_id == province.id + ); + return { + ...filteredReports, + edare_name: province.name_fa, + }; + }), + ], + filters: data, + }); + } catch (e) {} + } else { + try { + params.set("province_id", `${data.province_id}`); + const response = await requestServer(`${GET_MISSIONS_REPORT_VIOLATION_PROVINCE_ACTIVITY}?${params}`); + const result = response.data.data; + + const nationalReportForItem = result.activities.find((report) => report.city_id === "-1"); + + const nationalReport = { + ...nationalReportForItem, + edare_name: "کل استان", + }; + setData({ + data: [ + nationalReport, + ...result.city.map((city) => { + const filteredReports = result.activities.find((report) => report.city_id == city.id); + return { + edare_name: city.name_fa, + ...filteredReports, + }; + }), + ], + filters: data, + }); + } catch (e) {} + } + }; + + useEffect(() => { + if (!userPermissions) return; + onSearchSubmit(defaultValues); + }, [userPermissions]); + + const validationSchema = yup.object().shape({ + from_date: yup + .string() + .required("تاریخ شروع الزامی است!") + .matches(/^\d{4}-\d{2}-\d{2}$/, "تاریخ شروع الزامی است!") + .test("is-valid-date", "تاریخ شروع معتبر نیست!", (value) => moment(value, "YYYY-MM-DD", true).isValid()), + date_to: yup + .string() + .required("تاریخ پایان الزامی است!") + .matches(/^\d{4}-\d{2}-\d{2}$/, "تاریخ پایان الزامی است!") + .test("is-valid-date", "تاریخ پایان معتبر نیست!", (value) => moment(value, "YYYY-MM-DD", true).isValid()), + province_id: yup.string().nullable(), + }); + + const { control, handleSubmit } = useForm({ + defaultValues, + resolver: yupResolver(validationSchema), + mode: "all", + }); + + return ( + + + + {!data ? : } + + ); +}; +export default ViolationsReportsPage; diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js index 2c51a51..8f38aef 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -47,23 +47,23 @@ export const GET_COUNTRY_ACTIVITY_REPORT = api + "/api/v3/missions/report/countr export const EXPORT_COUNTRY_ROAD_PATROL_REPORTS = api + "/api/v3/road_patrols/report/country_activity_excel"; export const EXPORT_PROVINCE_ROAD_PATROL_REPORTS = api + "/api/v3/road_patrols/report/province_activity_excel"; -export const GET_MISSIONS_REPORT_VIOLATION_COUNTRY_ACTIVITY = - api + "/api/v3/missions/report_violation/country_activity"; -export const GET_MISSIONS_REPORT_VIOLATION_PROVINCE_ACTIVITY = - api + "/api/v3/missions/report_violation/province_activity"; -export const EXPORT_MISSIONS_REPORT_VIOLATION_COUNTRY_ACTIVITY = - api + "/api/v3/missions/report_violation/country_excel_activity"; -export const EXPORT_MISSIONS_REPORT_VIOLATION_PROVINCE_ACTIVITY = - api + "/api/v3/missions/report_violation/province_excel_activity"; - export const GET_MISSIONS_REPORT_TARADOD_COUNTRY_ACTIVITY = "http://192.168.1.132:8000" + "/api/v3/missions/report_taradod/country_activity"; export const GET_MISSIONS_REPORT_TARADOD_PROVINCE_ACTIVITY = "http://192.168.1.132:8000" + "/api/v3/missions/report_taradod/province_activity"; export const EXPORT_MISSIONS_REPORT_TARADOD_COUNTRY_EXCEL_ACTIVITY = - api + "/api/v3/missions/report_taradod/country_excel_activity"; + "http://192.168.1.132:8000" + "/api/v3/missions/report_taradod/country_excel_activity"; export const EXPORT_MISSIONS_REPORT_TARADOD_PROVINCE_EXCEL_ACTIVITY = - api + "/api/v3/missions/report_taradod/province_excel_activity"; + "http://192.168.1.132:8000" + "/api/v3/missions/report_taradod/province_excel_activity"; + +export const GET_MISSIONS_REPORT_VIOLATION_COUNTRY_ACTIVITY = + "http://192.168.1.132:8000" + "/api/v3/missions/report_violation/country_activity"; +export const GET_MISSIONS_REPORT_VIOLATION_PROVINCE_ACTIVITY = + "http://192.168.1.132:8000" + "/api/v3/missions/report_violation/province_activity"; +export const EXPORT_MISSIONS_REPORT_VIOLATION_COUNTRY_EXCEL_ACTIVITY = + "http://192.168.1.132:8000" + "/api/v3/missions/report_violation/country_excel_activity"; +export const EXPORT_MISSIONS_REPORT_VIOLATION_PROVINCE_EXCEL_ACTIVITY = + "http://192.168.1.132:8000" + "/api/v3/missions/report_violation/province_excel_activity"; // road items export const GET_ROAD_ITEMS_SUPERVISOR_LIST = api + "/api/v3/road_items/supervisor";