import { ReloadOutlined, SearchOutlined } from '@ant-design/icons' import { useQuery } from '@tanstack/react-query' import { Alert, Button, Card, Col, Form, Row, Select, Space, Statistic, Table, Tag, Typography, } from 'antd' import type { TableColumnsType } from 'antd' import { useState } from 'react' import { AdminRangePicker } from '@/components/admin/AdminDatePicker' import PageHeader from '@/components/admin/PageHeader' import dayjs from '@/lib/dayjs' import { fetchAdminFinanceSummary, fetchAdminFinanceTransactions, type AdminFinanceDateType, } from '@/services/admin' import type { AdminFinanceChannelDailyItem, AdminFinanceDailyItem, AdminFinanceTransaction, } from '@/types/admin/finance' import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination' import { formatAdminDateTime } from '@/utils/admin-time' import { formatMoney } from './panels/shared' type FinanceFilterForm = { dateRange?: unknown; dateType?: AdminFinanceDateType } const CATEGORY_OPTIONS = [ { value: '', label: '全部账目' }, { value: 'order_paid', label: '订单收款' }, { value: 'order_refund', label: '订单退款' }, { value: 'worker_reward', label: '打手报酬' }, { value: 'withdraw_paid', label: '打手提现' }, { value: 'recharge', label: '打手充值' }, { value: 'worker_recovery', label: '打手资金回收' }, { value: 'after_sales_refund', label: '售后追缴退还' }, ] export default function AdminFinancePage() { const [form] = Form.useForm() const [filters, setFilters] = useState<{ dateFrom: string dateTo: string dateType: AdminFinanceDateType }>({ dateFrom: '', dateTo: '', dateType: 'occurred' }) const [category, setCategory] = useState('') const [channel, setChannel] = useState('') const [channelSummaryFilter, setChannelSummaryFilter] = useState('') const [page, setPage] = useState(1) const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE) const summaryQuery = useQuery({ queryKey: ['admin-finance-summary', filters], queryFn: () => fetchAdminFinanceSummary(filters), }) const transactionsQuery = useQuery({ queryKey: ['admin-finance-transactions', filters, category, page, pageSize], queryFn: () => fetchAdminFinanceTransactions({ ...filters, category: category || undefined, channel: channel || undefined, page, pageSize, }), }) const overview = summaryQuery.data?.data.overview const daily = summaryQuery.data?.data.daily || [] const channelDaily = (summaryQuery.data?.data.channelDaily || []).filter( (item) => !channelSummaryFilter || item.channel === channelSummaryFilter, ) const transactionData = transactionsQuery.data?.data function applyFilters(values: FinanceFilterForm) { const range = Array.isArray(values.dateRange) ? values.dateRange : [] const dateFrom = range[0] && dayjs(range[0]).isValid() ? dayjs(range[0]).format('YYYY-MM-DD HH:mm:ss') : '' const dateTo = range[1] && dayjs(range[1]).isValid() ? dayjs(range[1]).second(59).format('YYYY-MM-DD HH:mm:ss') : '' setPage(1) setFilters({ dateFrom, dateTo, dateType: values.dateType || 'occurred' }) } function resetFilters() { form.resetFields() setCategory('') setChannel('') setChannelSummaryFilter('') setPage(1) setFilters({ dateFrom: '', dateTo: '', dateType: 'occurred' }) } const dailyColumns: TableColumnsType = [ { title: '日期', dataIndex: 'date', width: 120 }, { title: '支付订单', dataIndex: 'paidOrderCount', width: 100 }, { title: '收款', dataIndex: 'paidAmount', render: formatMoney }, { title: '退款', dataIndex: 'refundAmount', render: formatMoney }, { title: '打手报酬', dataIndex: 'workerRewardAmount', render: formatMoney }, { title: '已提现', dataIndex: 'withdrawAmount', render: formatMoney }, { title: '充值入账', dataIndex: 'rechargeAmount', render: formatMoney }, { title: '售后退还', dataIndex: 'afterSalesRefundAmount', render: formatMoney }, { title: '净现金流', dataIndex: 'netCashFlow', render: (value: number) => ( = 0 ? 'success' : 'danger'}> {formatMoney(value)} ), }, ] const transactionColumns: TableColumnsType = [ { title: '发生时间', dataIndex: 'occurredAt', width: 180, render: (value) => formatAdminDateTime(value), }, { title: '类型', dataIndex: 'label', width: 150, render: (value: string, row) => ( {value} ), }, { title: '渠道', dataIndex: 'channel', width: 150 }, { title: '金额', dataIndex: 'amount', width: 140, render: (value: number, row) => ( {row.direction === 'in' ? '+' : '-'} {formatMoney(value)} ), }, { title: '来源编号', dataIndex: 'sourceId', width: 110 }, { title: '关联单号/渠道', dataIndex: 'referenceNo', render: (value: string) => value || '-', }, ] return (
form={form} layout="inline" className="filter-form" onFinish={applyFilters} > item.channel)), ).map((value) => ({ value, label: value }))} onChange={(value) => setChannelSummaryFilter(value || '')} /> 按日期、渠道和账目类型汇总 } > rowKey={(row) => `${row.date}-${row.channel}-${row.category}`} loading={summaryQuery.isLoading} dataSource={channelDaily} pagination={false} columns={[ { title: '日期', dataIndex: 'date', width: 120 }, { title: '渠道', dataIndex: 'channel', width: 180 }, { title: '账目类型', dataIndex: 'category', width: 150, render: formatFinanceCategory }, { title: '笔数', dataIndex: 'count', width: 90 }, { title: '金额', dataIndex: 'amount', render: formatMoney }, ]} scroll={{ x: 760 }} /> item.channel)), ).map((value) => ({ value, label: value }))} onChange={(value) => { setChannel(value || '') setPage(1) }} /> } > rowKey={(row) => `${row.category}-${row.sourceId}-${row.occurredAt}`} loading={transactionsQuery.isLoading} dataSource={transactionData?.items || []} columns={transactionColumns} pagination={buildAdminTablePagination({ current: transactionData?.pagination.page || page, pageSize: transactionData?.pagination.pageSize || pageSize, total: transactionData?.pagination.total || 0, onChange: (nextPage, nextPageSize) => { setPage(nextPage) setPageSize(nextPageSize) }, })} scroll={{ x: 780 }} />
) } function formatFinanceCategory(value: string) { return CATEGORY_OPTIONS.find((item) => item.value === value)?.label || value || '-' } function FinanceStatistic({ title, value }: { title: string; value: number }) { return ( ) }