From 13c6de66b36df38bc2981df17ae93f115c35dd8d Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Thu, 18 Jun 2026 22:07:50 +0330 Subject: [PATCH] report --- src/config/Pages.ts | 1 + src/langs/fa.json | 1 + src/pages/orders/DailyOrderReport.tsx | 81 +++++++++++++++++++ .../DailyOrderReportFiltersFields.tsx | 28 +++++++ .../DailyOrderReportTableColumns.tsx | 23 ++++++ .../orders/hooks/useDailyOrderReportData.ts | 10 +++ .../hooks/useDailyOrderReportFilters.ts | 37 +++++++++ src/pages/orders/service/OrderService.ts | 23 +++++- src/pages/orders/types/Types.ts | 8 ++ .../utils/exportDailyOrderReportExcel.ts | 18 +++++ src/router/Main.tsx | 2 + src/shared/components/OrdersSubMenu.tsx | 5 ++ 12 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 src/pages/orders/DailyOrderReport.tsx create mode 100644 src/pages/orders/components/DailyOrderReportFiltersFields.tsx create mode 100644 src/pages/orders/components/DailyOrderReportTableColumns.tsx create mode 100644 src/pages/orders/hooks/useDailyOrderReportData.ts create mode 100644 src/pages/orders/hooks/useDailyOrderReportFilters.ts create mode 100644 src/pages/orders/utils/exportDailyOrderReportExcel.ts diff --git a/src/config/Pages.ts b/src/config/Pages.ts index f018ee0..ba2b4dd 100644 --- a/src/config/Pages.ts +++ b/src/config/Pages.ts @@ -26,6 +26,7 @@ export const Pages = { add: "/orders/add", detail: "/orders/detail/", foodReport: "/orders/report/by-food", + dailyReport: "/orders/report/by-day", }, customers: { list: "/customers/list", diff --git a/src/langs/fa.json b/src/langs/fa.json index a502903..a631a7e 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -98,6 +98,7 @@ "categories": "دسته بندی ها", "orders_list": "لیست سفارشات", "orders_food_report": "گزارش فروش به تفکیک غذا", + "orders_daily_report": "گزارش فروش روزانه", "add_order": "افزودن سفارش", "discount_list": "لیست تخفیف", "add_discount": "افزودن تخفیف", diff --git a/src/pages/orders/DailyOrderReport.tsx b/src/pages/orders/DailyOrderReport.tsx new file mode 100644 index 0000000..69af019 --- /dev/null +++ b/src/pages/orders/DailyOrderReport.tsx @@ -0,0 +1,81 @@ +import { type FC, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { DocumentDownload } from 'iconsax-react'; +import Table from '@/components/Table'; +import Filters from '@/components/Filters'; +import Button from '@/components/Button'; +import { useGetDailyOrderReport } from './hooks/useDailyOrderReportData'; +import { useDailyOrderReportFilters } from './hooks/useDailyOrderReportFilters'; +import { getDailyOrderReportTableColumns } from './components/DailyOrderReportTableColumns'; +import { useDailyOrderReportFiltersFields } from './components/DailyOrderReportFiltersFields'; +import { getDailyOrderReport } from './service/OrderService'; +import { exportDailyOrderReportExcel } from './utils/exportDailyOrderReportExcel'; +import type { DailyOrderReportItem } from './types/Types'; +import type { RowDataType } from '@/components/types/TableTypes'; + +const DailyOrderReport: FC = () => { + const { t } = useTranslation('global'); + const { filters, apiParams, handleFiltersChange } = useDailyOrderReportFilters(); + const { data: reportData, isLoading } = useGetDailyOrderReport(apiParams); + const [isExporting, setIsExporting] = useState(false); + + const columns = getDailyOrderReportTableColumns(); + const filterFields = useDailyOrderReportFiltersFields(); + + const reportItems = useMemo(() => { + return (reportData?.data || []).map((item) => ({ + ...item, + id: item.date, + })); + }, [reportData?.data]); + + const handleExportExcel = async () => { + setIsExporting(true); + try { + const response = await getDailyOrderReport(apiParams); + const items = (response?.data || []).map((item) => ({ + ...item, + id: item.date, + })); + exportDailyOrderReportExcel(items); + } finally { + setIsExporting(false); + } + }; + + return ( +
+
+

{t('submenu.orders_daily_report')}

+ +
+ +
+ +
+ + + columns={columns} + data={reportItems as (DailyOrderReportItem & RowDataType)[]} + isloading={isLoading} + /> +
+ ); +}; + +export default DailyOrderReport; diff --git a/src/pages/orders/components/DailyOrderReportFiltersFields.tsx b/src/pages/orders/components/DailyOrderReportFiltersFields.tsx new file mode 100644 index 0000000..09ea415 --- /dev/null +++ b/src/pages/orders/components/DailyOrderReportFiltersFields.tsx @@ -0,0 +1,28 @@ +import { useMemo } from 'react'; +import type { FieldType } from '@/components/Filters'; + +export const useDailyOrderReportFiltersFields = (): FieldType[] => { + return useMemo(() => [ + { + type: 'datetime', + name: 'from', + placeholder: 'از تاریخ', + }, + { + type: 'datetime', + name: 'to', + placeholder: 'تا تاریخ', + }, + { + type: 'select', + name: 'sortBy', + placeholder: 'مرتب‌سازی', + defaultValue: 'date', + options: [ + { label: 'تاریخ', value: 'date' }, + { label: 'مبلغ کل', value: 'totalAmount' }, + { label: 'تعداد سفارش', value: 'orderCount' }, + ], + }, + ], []); +}; diff --git a/src/pages/orders/components/DailyOrderReportTableColumns.tsx b/src/pages/orders/components/DailyOrderReportTableColumns.tsx new file mode 100644 index 0000000..1193477 --- /dev/null +++ b/src/pages/orders/components/DailyOrderReportTableColumns.tsx @@ -0,0 +1,23 @@ +import type { ColumnType } from '@/components/types/TableTypes'; +import type { DailyOrderReportItem } from '../types/Types'; +import { formatDateShort, formatFaNumber, formatPrice } from '@/helpers/func'; + +export const getDailyOrderReportTableColumns = (): ColumnType[] => { + return [ + { + key: 'date', + title: 'تاریخ', + render: (item: DailyOrderReportItem) => formatDateShort(item.date), + }, + { + key: 'orderCount', + title: 'تعداد سفارش', + render: (item: DailyOrderReportItem) => formatFaNumber(item.orderCount), + }, + { + key: 'totalAmount', + title: 'مبلغ کل', + render: (item: DailyOrderReportItem) => formatPrice(item.totalAmount), + }, + ]; +}; diff --git a/src/pages/orders/hooks/useDailyOrderReportData.ts b/src/pages/orders/hooks/useDailyOrderReportData.ts new file mode 100644 index 0000000..68a811a --- /dev/null +++ b/src/pages/orders/hooks/useDailyOrderReportData.ts @@ -0,0 +1,10 @@ +import { useQuery } from '@tanstack/react-query'; +import * as api from '../service/OrderService'; +import type { GetDailyOrderReportParams } from '../service/OrderService'; + +export const useGetDailyOrderReport = (params?: GetDailyOrderReportParams) => { + return useQuery({ + queryKey: ['daily-order-report', params], + queryFn: () => api.getDailyOrderReport(params), + }); +}; diff --git a/src/pages/orders/hooks/useDailyOrderReportFilters.ts b/src/pages/orders/hooks/useDailyOrderReportFilters.ts new file mode 100644 index 0000000..1ef1549 --- /dev/null +++ b/src/pages/orders/hooks/useDailyOrderReportFilters.ts @@ -0,0 +1,37 @@ +import { useState, useMemo } from 'react'; +import type { FilterValues } from '@/components/Filters'; +import type { GetDailyOrderReportParams } from '../service/OrderService'; + +export const useDailyOrderReportFilters = () => { + const [filters, setFilters] = useState({ + sortBy: 'date', + }); + + const apiParams = useMemo(() => { + const params: GetDailyOrderReportParams = {}; + + if (filters.from) { + params.from = filters.from as string; + } + + if (filters.to) { + params.to = filters.to as string; + } + + if (filters.sortBy) { + params.sortBy = filters.sortBy as GetDailyOrderReportParams['sortBy']; + } + + return params; + }, [filters]); + + const handleFiltersChange = (newFilters: FilterValues) => { + setFilters(newFilters); + }; + + return { + filters, + apiParams, + handleFiltersChange, + }; +}; diff --git a/src/pages/orders/service/OrderService.ts b/src/pages/orders/service/OrderService.ts index 0156037..3fcf7f8 100644 --- a/src/pages/orders/service/OrderService.ts +++ b/src/pages/orders/service/OrderService.ts @@ -1,5 +1,10 @@ import axios from "@/config/axios"; -import type { GetOrdersResponse, GetOrderByIdResponse, GetFoodOrderReportResponse } from "../types/Types"; +import type { + GetOrdersResponse, + GetOrderByIdResponse, + GetFoodOrderReportResponse, + GetDailyOrderReportResponse, +} from "../types/Types"; export interface GetOrdersParams { page?: number; @@ -98,3 +103,19 @@ export const getFoodOrderReport = async ( ); return data; }; + +export interface GetDailyOrderReportParams { + from?: string; + to?: string; + sortBy?: 'date' | 'totalAmount' | 'orderCount'; +} + +export const getDailyOrderReport = async ( + params?: GetDailyOrderReportParams +) => { + const { data } = await axios.get( + '/admin/orders/report/by-day', + { params } + ); + return data; +}; diff --git a/src/pages/orders/types/Types.ts b/src/pages/orders/types/Types.ts index 2234496..e2178cf 100644 --- a/src/pages/orders/types/Types.ts +++ b/src/pages/orders/types/Types.ts @@ -234,3 +234,11 @@ export interface FoodOrderReportItem extends RowDataType { } export type GetFoodOrderReportResponse = IResponse; + +export interface DailyOrderReportItem extends RowDataType { + date: string; + orderCount: number; + totalAmount: number; +} + +export type GetDailyOrderReportResponse = IResponse; diff --git a/src/pages/orders/utils/exportDailyOrderReportExcel.ts b/src/pages/orders/utils/exportDailyOrderReportExcel.ts new file mode 100644 index 0000000..e69c3ce --- /dev/null +++ b/src/pages/orders/utils/exportDailyOrderReportExcel.ts @@ -0,0 +1,18 @@ +import * as XLSX from 'xlsx'; +import type { DailyOrderReportItem } from '../types/Types'; +import { formatDateShort } from '@/helpers/func'; + +export const exportDailyOrderReportExcel = (items: DailyOrderReportItem[]) => { + const rows = items.map((item) => ({ + تاریخ: formatDateShort(item.date), + 'تعداد سفارش': item.orderCount, + 'مبلغ کل': item.totalAmount, + })); + + const worksheet = XLSX.utils.json_to_sheet(rows); + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, 'گزارش فروش روزانه'); + + const fileName = `daily-order-report-${new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-')}.xlsx`; + XLSX.writeFile(workbook, fileName); +}; diff --git a/src/router/Main.tsx b/src/router/Main.tsx index 1e51732..ccf814e 100644 --- a/src/router/Main.tsx +++ b/src/router/Main.tsx @@ -16,6 +16,7 @@ import CreateCustomer from '@/pages/customers/Create' import OrdersList from '@/pages/orders/List' import OrderDetails from '@/pages/orders/Details' import FoodOrderReport from '@/pages/orders/FoodOrderReport' +import DailyOrderReport from '@/pages/orders/DailyOrderReport' import CommentsList from '@/pages/comments/List' import CommentsDetails from '@/pages/comments/Details' import ScheduleList from '@/pages/schedule/List' @@ -73,6 +74,7 @@ const MainRouter: FC = () => { } /> } /> } /> + } /> } /> } /> } /> diff --git a/src/shared/components/OrdersSubMenu.tsx b/src/shared/components/OrdersSubMenu.tsx index 4e6ce56..2997f88 100644 --- a/src/shared/components/OrdersSubMenu.tsx +++ b/src/shared/components/OrdersSubMenu.tsx @@ -38,6 +38,11 @@ const OrdersSubMenu: FC = () => { isActive={isActive('report/by-food')} link={Pages.orders.foodReport} /> + {/*