Merge branch 'feature/province_reports' into 'develop'

Feature/province reports

See merge request witel-front-end/crm-app!47
This commit is contained in:
AmirHossein Mahmoodi
2025-08-16 05:45:59 +00:00
16 changed files with 757 additions and 7 deletions

View File

@@ -0,0 +1,16 @@
import ProvinceCumulativeCallsReportPage from "@/components/dashboard/provinceReports/ProvinceCumulativeCallsReport";
import WithPermission from "@/core/middlewares/withPermission";
export const metadata = {
title: "گزارشات",
};
const Page = () => {
return (
<WithPermission permission_name={["all"]}>
<ProvinceCumulativeCallsReportPage />
</WithPermission>
);
};
export default Page;

View File

@@ -0,0 +1,16 @@
import ProvinceDetailedLogsReportPage from "@/components/dashboard/provinceReports/ProvinceDetailedLogsReport";
import WithPermission from "@/core/middlewares/withPermission";
export const metadata = {
title: "ریز گزارشات",
};
const Page = () => {
return (
<WithPermission permission_name={["all"]}>
<ProvinceDetailedLogsReportPage />
</WithPermission>
);
};
export default Page;

View File

@@ -0,0 +1,16 @@
import ProvincePeopleMessagesReportPage from "@/components/dashboard/provinceReports/ProvincePeopleMessagesReport";
import WithPermission from "@/core/middlewares/withPermission";
export const metadata = {
title: "گزارش پیام‌ها",
};
const Page = () => {
return (
<WithPermission permission_name={["all"]}>
<ProvincePeopleMessagesReportPage />
</WithPermission>
);
};
export default Page;

View File

@@ -0,0 +1,16 @@
import ProvinceOperatorPerformanceReportPage from "@/components/dashboard/provinceReports/ProvinceOperatorPerformanceReport";
import WithPermission from "@/core/middlewares/withPermission";
export const metadata = {
title: "عملکرد کارشناسان",
};
const Page = () => {
return (
<WithPermission permission_name={["all"]}>
<ProvinceOperatorPerformanceReportPage />
</WithPermission>
);
};
export default Page;

View File

@@ -0,0 +1,200 @@
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import { GET_PROVINCE_CUMULATIVE_CALLS_DAILY_REPORT } from "@/core/utils/routes";
import { Box } from "@mui/material";
import moment from "jalali-moment";
import { useMemo } from "react";
export default function DataTable() {
const columns = useMemo(() => [
{
header: "تاریخ",
id: "date",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
Cell: ({ row }) => (row.original.d ? moment(row.original.d).locale("fa").format("yyyy/MM/DD") : <>-</>),
},
{
accessorKey: "total",
header: "تمامی تماس ها",
id: "total",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
header: "تماس با تهران",
id: "call_to_tehran",
enableColumnFilter: false,
enableSorting: false,
grow: false,
size: 50,
columns: [
{
accessorKey: "teh4",
header: "کلید 4",
id: "teh4",
enableColumnFilter: true,
datatype: "integer",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "teh5",
header: "کلید 5",
id: "teh5",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
],
},
{
header: "تماس با اپراتور استانی",
id: "call_to_ostan",
enableColumnFilter: false,
enableSorting: false,
grow: false,
size: 50,
columns: [
{
accessorKey: "ok",
header: "موفق",
id: "ok",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "fail",
header: "جواب داده نشده",
id: "fail",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "nok",
header: "نا موفق",
id: "nok",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "os4",
header: "کلید 4",
id: "os4",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "os5",
header: "کلید 5",
id: "os5",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "dnd",
header: "dnd",
id: "dnd",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "trans",
header: "انتقال تماس",
id: "trans",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
],
},
{
accessorKey: "b10",
header: "تماس بالای 10 ثانیه",
id: "b10",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "avg",
header: "میانگین تماس ها",
id: "avg",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
Cell: ({ row }) => <>{row.original.avg ? row.original.avg : <>-</>}</>,
},
]);
return (
<>
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
need_filter={true}
columns={columns}
table_url={GET_PROVINCE_CUMULATIVE_CALLS_DAILY_REPORT}
page_name={"provinceCumulativeCallsReportPage"}
table_name={"provinceCumulativeCallsReportList"}
positionActionsColumn={"last"}
/>
</Box>
</>
);
}

View File

@@ -0,0 +1,14 @@
"use client";
import PageTitle from "@/core/components/PageTitle";
import { Stack } from "@mui/material";
import DataTable from "./DataTable";
export default function ProvinceCumulativeCallsReportPage() {
return (
<Stack spacing={1}>
<PageTitle title={"گزارشات تجمعی"} />
<DataTable />
</Stack>
);
}

View File

@@ -0,0 +1,103 @@
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import { GET_PROVINCE_DETAILED_LOGS_REPORT } from "@/core/utils/routes";
import { Box } from "@mui/material";
import moment from "jalali-moment";
import { useMemo } from "react";
export default function DataTable() {
const columns = useMemo(() => [
{
header: "تاریخ",
id: "date",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
Cell: ({ row }) => {
const dateTime = row.original.calldate;
if (!dateTime) return <>-</>;
const date = dateTime.split(" ")[0];
const persianDate = moment(date).locale("fa").format("YYYY-MM-DD") || "";
return <>{persianDate}</>;
},
},
{
header: "ساعت",
id: "time",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
Cell: ({ row }) => {
const dateTime = row.original.calldate;
if (!dateTime) return <>-</>;
const time = dateTime.split(" ")[1] || "";
return <>{time}</>;
},
},
{
accessorKey: "src",
header: "شماره تماس گیرنده",
id: "src",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "dst",
header: "مقصد تماس",
id: "dst",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "disposition",
header: "وضعیت پاسخگویی",
id: "disposition",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "duration",
header: "مدت زمان تماس",
id: "duration",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
]);
return (
<>
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
need_filter={true}
columns={columns}
table_url={GET_PROVINCE_DETAILED_LOGS_REPORT}
page_name={"provinceDetailedLogsReportPage"}
table_name={"provinceDetailedLogsReportList"}
positionActionsColumn={"last"}
/>
</Box>
</>
);
}

View File

@@ -0,0 +1,14 @@
"use client";
import PageTitle from "@/core/components/PageTitle";
import { Stack } from "@mui/material";
import DataTable from "./DataTable";
export default function ProvinceDetailedLogsReportPage() {
return (
<Stack spacing={1}>
<PageTitle title={"ریز گزارش ها"} />
<DataTable />
</Stack>
);
}

View File

@@ -0,0 +1,101 @@
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import { GET_PROVINCE_OPERATORS_PERFORMANCE_TOTAL_REPORT } from "@/core/utils/routes";
import { Box } from "@mui/material";
import { useMemo } from "react";
export default function DataTableCumulative() {
const columns = useMemo(() => [
{
accessorKey: "dst",
header: "کد یکتای کارشناس",
id: "dst",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "total",
header: "تعداد کل تماس ها",
id: "total",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "ok",
header: "تماس های موفق",
id: "ok",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "fail",
header: "تماس های جواب داده نشده",
id: "fail",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "nok",
header: "تماس های ناموفق",
id: "nok",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "b10",
header: "تماس های بالای 10 ثانیه",
id: "b10",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "dnd",
header: "dnd",
id: "dnd",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
]);
return (
<>
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
need_filter={true}
columns={columns}
table_url={GET_PROVINCE_OPERATORS_PERFORMANCE_TOTAL_REPORT}
page_name={"provinceOperatorPerformanceCumulativeReportPage"}
table_name={"provinceOperatorPerformanceCumulativeReportList"}
positionActionsColumn={"last"}
/>
</Box>
</>
);
}

View File

@@ -0,0 +1,113 @@
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import { GET_PROVINCE_OPERATORS_PERFORMANCE_DAILY_REPORT } from "@/core/utils/routes";
import { Box } from "@mui/material";
import moment from "jalali-moment";
import { useMemo } from "react";
export default function DataTableDaily() {
const columns = useMemo(() => [
{
header: "تاریخ",
id: "date",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
Cell: ({ row }) => (row.original.d ? moment(row.original.d).locale("fa").format("yyyy/MM/DD") : <>-</>),
},
{
accessorKey: "dst",
header: "کد یکتای کارشناس",
id: "dst",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "total",
header: "تعداد کل تماس ها",
id: "total",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "ok",
header: "تماس های موفق",
id: "ok",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "fail",
header: "تماس های جواب داده نشده",
id: "fail",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "nok",
header: "تماس های ناموفق",
id: "nok",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "b10",
header: "تماس های بالای 10 ثانیه",
id: "b10",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
{
accessorKey: "dnd",
header: "dnd",
id: "dnd",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
grow: false,
size: 100,
},
]);
return (
<>
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
need_filter={true}
columns={columns}
table_url={GET_PROVINCE_OPERATORS_PERFORMANCE_DAILY_REPORT}
page_name={"provinceOperatorPerformanceDailyReportPage"}
table_name={"provinceOperatorPerformanceDailyReportList"}
positionActionsColumn={"last"}
/>
</Box>
</>
);
}

View File

@@ -0,0 +1,17 @@
"use client";
import PageTitle from "@/core/components/PageTitle";
import { Stack } from "@mui/material";
import DataTableCumulative from "./DataTableCumulative";
import DataTableDaily from "./DataTableDaily";
export default function ProvinceOperatorPerformanceReportPage() {
return (
<Stack spacing={1}>
<PageTitle title={"گزارش تجمعی عملکرد کارشناسان"} />
<DataTableCumulative />
<PageTitle title={"گزارش روزانه عملکرد کارشناسان"} />
<DataTableDaily />
</Stack>
);
}

View File

@@ -0,0 +1,59 @@
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import { GET_PROVINCE_PEOPLE_MESSAGES_REPORT } from "@/core/utils/routes";
import { Box } from "@mui/material";
import { useMemo } from "react";
export default function DataTable() {
const columns = useMemo(() => [
{
header: "تعداد",
id: "count",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
Cell: ({ row }) => <>{row.original.nl + row.original.l}</>,
},
{
accessorKey: "l",
header: "تماس های شنیده شده",
id: "l",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
{
accessorKey: "nl",
header: "تماس های شنیده نشده",
id: "nl",
enableColumnFilter: true,
datatype: "text",
filterMode: "equals",
sortDescFirst: false,
columnFilterModeOptions: ["equals", "contains"],
grow: false,
size: 100,
},
]);
return (
<>
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
need_filter={true}
columns={columns}
table_url={GET_PROVINCE_PEOPLE_MESSAGES_REPORT}
page_name={"provincePeopleMessagesReportPage"}
table_name={"provincePeopleMessagesReportList"}
positionActionsColumn={"last"}
/>
</Box>
</>
);
}

View File

@@ -0,0 +1,14 @@
"use client";
import PageTitle from "@/core/components/PageTitle";
import { Stack } from "@mui/material";
import DataTable from "./DataTable";
export default function ProvincePeopleMessagesReportPage() {
return (
<Stack spacing={1}>
<PageTitle title={"گزارش وضعیت پیام های مردمی"} />
<DataTable />
</Stack>
);
}

View File

@@ -1,15 +1,17 @@
import { Settings } from "@mui/icons-material";
import AssessmentIcon from "@mui/icons-material/Assessment";
import SupervisedUserCircleIcon from "@mui/icons-material/SupervisedUserCircle";
import VerifiedUserIcon from "@mui/icons-material/VerifiedUser";
import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard";
import ContentPasteSearchIcon from "@mui/icons-material/ContentPasteSearch";
import MarkEmailReadIcon from "@mui/icons-material/MarkEmailRead";
import PointOfSaleIcon from "@mui/icons-material/PointOfSale";
import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard";
import StarIcon from "@mui/icons-material/Star";
import SupervisedUserCircleIcon from "@mui/icons-material/SupervisedUserCircle";
import SupervisorAccountIcon from "@mui/icons-material/SupervisorAccount";
import ThreePIcon from "@mui/icons-material/ThreeP";
import TtyIcon from "@mui/icons-material/Tty";
import VerifiedUserIcon from "@mui/icons-material/VerifiedUser";
import VoiceChatIcon from "@mui/icons-material/VoiceChat";
import ZoomInMapIcon from "@mui/icons-material/ZoomInMap";
import StarIcon from "@mui/icons-material/Star";
import MarkEmailReadIcon from "@mui/icons-material/MarkEmailRead";
import TtyIcon from "@mui/icons-material/Tty";
export const pageMenu = [
{
@@ -61,6 +63,48 @@ export const pageMenu = [
},
],
},
{
id: "province-reports",
label: "گزارش ها",
type: "menu",
icon: <AssessmentIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true,
permissions: ["all"],
Subitems: [
{
id: "province-calls-report",
label: "تجمعی",
type: "page",
icon: <ZoomInMapIcon sx={{ width: "inherit", height: "inherit" }} />,
route: "/dashboard/province-reports/province-calls-report",
permissions: ["all"],
},
{
id: "province-messages-reports",
label: "تجمعی پیام‌های مردمی",
type: "page",
icon: <MarkEmailReadIcon sx={{ width: "inherit", height: "inherit" }} />,
route: "/dashboard/province-reports/province-messages-report",
permissions: ["all"],
},
{
id: "province-detailed-reports",
label: "ریز گزارش ها",
type: "page",
icon: <ContentPasteSearchIcon sx={{ width: "inherit", height: "inherit" }} />,
route: "/dashboard/province-reports/province-detailed-report",
permissions: ["all"],
},
{
id: "province-operators-performance-reports",
label: "عملکرد کارشناسان",
type: "page",
icon: <SupervisorAccountIcon sx={{ width: "inherit", height: "inherit" }} />,
route: "/dashboard/province-reports/province-operators-performance-report",
permissions: ["all"],
},
],
},
{
id: "systemManagment",
label: "مدیریت سامانه",

View File

@@ -25,3 +25,10 @@ export const GET_COUNTRY_KEYPRESS_REPORT = api + "/cumulative_keypress_stats";
export const GET_SYSTEM_MESSAGES_SUPERVISOR = api + "/system_messages/supervisor";
export const GET_SYSTEM_MESSAGES_OPERATOR = api + "/system_messages/operator";
// export const GET_PROVINCE_CUMULATIVE_CALLS_TOTAL_REPORT = api + "/report/cumulative_total";
export const GET_PROVINCE_CUMULATIVE_CALLS_DAILY_REPORT = api + "/report/cumulative";
export const GET_PROVINCE_PEOPLE_MESSAGES_REPORT = api + "/report/people_messages";
export const GET_PROVINCE_DETAILED_LOGS_REPORT = api + "/report/detailed_logs";
export const GET_PROVINCE_OPERATORS_PERFORMANCE_DAILY_REPORT = api + "/report/operator_performance_daily";
export const GET_PROVINCE_OPERATORS_PERFORMANCE_TOTAL_REPORT = api + "/report/operator_performance_total";

View File

@@ -91,7 +91,7 @@ const DataTableProvider = ({ children, user_id, page_name, table_name, columns,
};
}
return acc;
}, {});
}, []);
const getHideValues = (columns) => {
return columns.reduce((acc, column) => {