This commit is contained in:
2026-06-18 22:07:50 +03:30
parent d4b6d85cb5
commit 13c6de66b3
12 changed files with 236 additions and 1 deletions
+81
View File
@@ -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 (
<div className='mt-5'>
<div className='flex justify-between items-center'>
<h1 className='text-lg font-light'>{t('submenu.orders_daily_report')}</h1>
<Button
className='w-fit px-4'
isloading={isExporting}
disabled={isLoading}
onClick={handleExportExcel}
>
<div className='flex items-center gap-2'>
<DocumentDownload size={18} color='#fff' />
<span>خروجی Excel</span>
</div>
</Button>
</div>
<div className='mt-8'>
<Filters
fields={filterFields}
onChange={handleFiltersChange}
initialValues={filters}
showClearButton
/>
</div>
<Table<DailyOrderReportItem & RowDataType>
columns={columns}
data={reportItems as (DailyOrderReportItem & RowDataType)[]}
isloading={isLoading}
/>
</div>
);
};
export default DailyOrderReport;
@@ -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' },
],
},
], []);
};
@@ -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<DailyOrderReportItem>[] => {
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),
},
];
};
@@ -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),
});
};
@@ -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<FilterValues>({
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,
};
};
+22 -1
View File
@@ -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<GetDailyOrderReportResponse>(
'/admin/orders/report/by-day',
{ params }
);
return data;
};
+8
View File
@@ -234,3 +234,11 @@ export interface FoodOrderReportItem extends RowDataType {
}
export type GetFoodOrderReportResponse = IResponse<FoodOrderReportItem[]>;
export interface DailyOrderReportItem extends RowDataType {
date: string;
orderCount: number;
totalAmount: number;
}
export type GetDailyOrderReportResponse = IResponse<DailyOrderReportItem[]>;
@@ -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);
};