feat: 迭代

This commit is contained in:
2026-05-27 18:58:39 +08:00
parent 716a55744e
commit 9baf5f29f7
44 changed files with 928 additions and 2903 deletions
@@ -8,17 +8,18 @@ const { TabPane } = Tabs;
interface Account {
id: number;
userId?: number;
merchantId?: number;
user_id?: number;
merchant_id?: number;
userName?: string;
merchantName?: string;
balance: number;
frozenAmount: number;
availableAmount: number;
totalIncome: number;
totalExpense: number;
account_name?: string;
balance: number | string;
frozen_balance: number | string;
total_income: number | string;
total_expense: number | string;
status: string;
createdAt: string;
created_at: string;
updated_at: string;
}
const Accounts: React.FC = () => {
@@ -52,8 +53,10 @@ const Accounts: React.FC = () => {
res = await getMerchantAccounts(queryParams);
}
setAccounts(res.data.items);
setPagination({ ...pagination, total: res.data.total, ...params });
// 后端返回的是数组,不是分页对象
const data = Array.isArray(res.data) ? res.data : (res.data.items || res.data.list || []);
setAccounts(data);
setPagination({ ...pagination, total: data.length, ...params });
} catch (error) {
console.error('获取账户列表失败', error);
} finally {
@@ -77,40 +80,48 @@ const Accounts: React.FC = () => {
key: 'id',
width: 80,
},
{
title: '账户名称',
dataIndex: 'account_name',
key: 'account_name',
width: 150,
},
{
title: '账户余额',
dataIndex: 'balance',
key: 'balance',
width: 120,
render: (balance: number) => `¥${balance.toFixed(2)}`,
render: (balance: number | string) => `¥${Number(balance).toFixed(2)}`,
},
{
title: '冻结金额',
dataIndex: 'frozenAmount',
key: 'frozenAmount',
dataIndex: 'frozen_balance',
key: 'frozen_balance',
width: 120,
render: (amount: number) => `¥${amount.toFixed(2)}`,
render: (amount: number | string) => `¥${Number(amount).toFixed(2)}`,
},
{
title: '可用余额',
dataIndex: 'availableAmount',
key: 'availableAmount',
width: 120,
render: (amount: number) => `¥${amount.toFixed(2)}`,
render: (record: Account) => {
const available = Number(record.balance) - Number(record.frozen_balance);
return `¥${available.toFixed(2)}`;
},
},
{
title: '累计收入',
dataIndex: 'totalIncome',
key: 'totalIncome',
dataIndex: 'total_income',
key: 'total_income',
width: 120,
render: (amount: number) => <span style={{ color: '#52c41a' }}>¥{amount.toFixed(2)}</span>,
render: (amount: number | string) => <span style={{ color: '#52c41a' }}>¥{Number(amount).toFixed(2)}</span>,
},
{
title: '累计支出',
dataIndex: 'totalExpense',
key: 'totalExpense',
dataIndex: 'total_expense',
key: 'total_expense',
width: 120,
render: (amount: number) => <span style={{ color: '#ff4d4f' }}>¥{amount.toFixed(2)}</span>,
render: (amount: number | string) => <span style={{ color: '#ff4d4f' }}>¥{Number(amount).toFixed(2)}</span>,
},
{
title: '状态',
@@ -125,9 +136,10 @@ const Accounts: React.FC = () => {
},
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
dataIndex: 'created_at',
key: 'created_at',
width: 180,
render: (date: string) => formatDateTime(date),
},
];
@@ -140,8 +152,8 @@ const Accounts: React.FC = () => {
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
dataIndex: 'user_id',
key: 'user_id',
width: 100,
},
{
@@ -155,21 +167,23 @@ const Accounts: React.FC = () => {
dataIndex: 'balance',
key: 'balance',
width: 120,
render: (balance: number) => `¥${balance.toFixed(2)}`,
render: (balance: number | string) => `¥${Number(balance).toFixed(2)}`,
},
{
title: '冻结金额',
dataIndex: 'frozenAmount',
key: 'frozenAmount',
dataIndex: 'frozen_balance',
key: 'frozen_balance',
width: 120,
render: (amount: number) => `¥${amount.toFixed(2)}`,
render: (amount: number | string) => `¥${Number(amount).toFixed(2)}`,
},
{
title: '可用余额',
dataIndex: 'availableAmount',
key: 'availableAmount',
width: 120,
render: (amount: number) => `¥${amount.toFixed(2)}`,
render: (record: Account) => {
const available = Number(record.balance) - Number(record.frozen_balance);
return `¥${available.toFixed(2)}`;
},
},
{
title: '状态',
@@ -184,9 +198,10 @@ const Accounts: React.FC = () => {
},
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
dataIndex: 'created_at',
key: 'created_at',
width: 180,
render: (date: string) => formatDateTime(date),
},
];
@@ -199,8 +214,8 @@ const Accounts: React.FC = () => {
},
{
title: '商家ID',
dataIndex: 'merchantId',
key: 'merchantId',
dataIndex: 'merchant_id',
key: 'merchant_id',
width: 100,
},
{
@@ -214,21 +229,23 @@ const Accounts: React.FC = () => {
dataIndex: 'balance',
key: 'balance',
width: 120,
render: (balance: number) => `¥${balance.toFixed(2)}`,
render: (balance: number | string) => `¥${Number(balance).toFixed(2)}`,
},
{
title: '冻结金额',
dataIndex: 'frozenAmount',
key: 'frozenAmount',
dataIndex: 'frozen_balance',
key: 'frozen_balance',
width: 120,
render: (amount: number) => `¥${amount.toFixed(2)}`,
render: (amount: number | string) => `¥${Number(amount).toFixed(2)}`,
},
{
title: '可用余额',
dataIndex: 'availableAmount',
key: 'availableAmount',
width: 120,
render: (amount: number) => `¥${amount.toFixed(2)}`,
render: (record: Account) => {
const available = Number(record.balance) - Number(record.frozen_balance);
return `¥${available.toFixed(2)}`;
},
},
{
title: '状态',
@@ -243,9 +260,10 @@ const Accounts: React.FC = () => {
},
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
dataIndex: 'created_at',
key: 'created_at',
width: 180,
render: (date: string) => formatDateTime(date),
},
];
@@ -24,11 +24,13 @@ interface FinancialOverview {
interface Transaction {
id: number;
type: string;
transaction_no: string;
direction: 'income' | 'expense';
amount: number;
balance: number;
description: string;
createdAt: string;
balance_after: number;
transaction_type: string;
remark: string;
created_at: string;
}
const FinanceDashboard: React.FC = () => {
@@ -54,7 +56,7 @@ const FinanceDashboard: React.FC = () => {
setLoading(true);
try {
const res = await getPlatformTransactions({ page: 1, pageSize: 10 });
setRecentTransactions(res.data.items);
setRecentTransactions(res.data.list || res.data.items || []);
} catch (error) {
console.error('获取最近交易失败', error);
} finally {
@@ -65,21 +67,21 @@ const FinanceDashboard: React.FC = () => {
const columns: ColumnsType<Transaction> = [
{
title: '交易时间',
dataIndex: 'createdAt',
key: 'createdAt',
dataIndex: 'created_at',
key: 'created_at',
width: 180,
},
{
title: '交易类型',
dataIndex: 'type',
key: 'type',
dataIndex: 'direction',
key: 'direction',
width: 120,
render: (type: string) => {
render: (direction: string) => {
const typeMap: Record<string, { text: string; color: string }> = {
income: { text: '收入', color: 'green' },
expense: { text: '支出', color: 'red' },
};
const config = typeMap[type] || { text: type, color: 'default' };
const config = typeMap[direction] || { text: direction, color: 'default' };
return <Tag color={config.color}>{config.text}</Tag>;
},
},
@@ -88,23 +90,23 @@ const FinanceDashboard: React.FC = () => {
dataIndex: 'amount',
key: 'amount',
width: 120,
render: (amount: number, record: Transaction) => (
<span style={{ color: record.type === 'income' ? '#52c41a' : '#ff4d4f' }}>
{record.type === 'income' ? '+' : '-'}¥{amount.toFixed(2)}
render: (amount: number | string, record: Transaction) => (
<span style={{ color: record.direction === 'income' ? '#52c41a' : '#ff4d4f' }}>
{record.direction === 'income' ? '+' : '-'}¥{Number(amount).toFixed(2)}
</span>
),
},
{
title: '余额',
dataIndex: 'balance',
key: 'balance',
dataIndex: 'balance_after',
key: 'balance_after',
width: 120,
render: (balance: number) => `¥${balance.toFixed(2)}`,
render: (balance: number | string) => `¥${Number(balance).toFixed(2)}`,
},
{
title: '说明',
dataIndex: 'description',
key: 'description',
dataIndex: 'remark',
key: 'remark',
},
];
@@ -44,7 +44,7 @@ const PlatformTransactions: React.FC = () => {
fetchFn: async (params) => {
const res = await getPlatformTransactions(params);
return {
list: res.data.items,
list: res.data.list || res.data.items || [],
total: res.data.total,
page: params.page || 1,
pageSize: params.pageSize || 20,
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react';
import { Card, Row, Col, Statistic, Descriptions, Button, Space, Modal, Form, InputNumber, Input, message, Select } from 'antd';
import { WalletOutlined, ArrowUpOutlined, ArrowDownOutlined, DollarOutlined, ExportOutlined } from '@ant-design/icons';
import { WalletOutlined, ArrowUpOutlined, ArrowDownOutlined, DollarOutlined, ExportOutlined, HistoryOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
import { getPlatformAccounts, createPlatformWithdrawal, getBankCards } from '@/api/finance';
import { formatMoney, formatDateTime } from '@rent/shared-utils';
@@ -28,6 +29,7 @@ interface BankCard {
}
const PlatformWallet: React.FC = () => {
const navigate = useNavigate();
const [account, setAccount] = useState<PlatformAccount | null>(null);
const [loading, setLoading] = useState(false);
const [withdrawModalVisible, setWithdrawModalVisible] = useState(false);
@@ -266,6 +268,9 @@ const PlatformWallet: React.FC = () => {
<div style={{ marginTop: 24, textAlign: 'right' }}>
<Space>
<Button icon={<HistoryOutlined />} onClick={() => navigate('/finance/platform-withdrawals')}>
</Button>
<Button type="primary" icon={<ExportOutlined />} onClick={handleWithdraw}>
</Button>
@@ -9,20 +9,20 @@ import { useModal } from '@/hooks/useModal';
interface PlatformWithdrawal {
id: number;
withdrawal_no: string;
account_id: number;
withdrawNo: string;
accountId: number;
amount: number;
bank_account: string;
bank_name: string;
account_name: string;
bankAccount: string;
bankName: string;
accountName: string;
status: 'pending' | 'approved' | 'rejected' | 'paid' | 'failed';
remark?: string;
reject_reason?: string;
reviewer_id?: number;
reviewed_at?: string;
payment_no?: string;
paid_at?: string;
created_at: string;
rejectReason?: string;
reviewerId?: number;
reviewedAt?: string;
paymentNo?: string;
paidAt?: string;
createdAt: string;
}
const statusConfig = {
@@ -54,7 +54,7 @@ const PlatformWithdrawals: React.FC = () => {
fetchFn: async (params) => {
const res = await getPlatformWithdrawals(params);
return {
list: res.data.items,
list: res.data.list || res.data.items || [],
total: res.data.total,
page: params.page || 1,
pageSize: params.pageSize || 20,
@@ -133,8 +133,8 @@ const PlatformWithdrawals: React.FC = () => {
const columns: ColumnsType<PlatformWithdrawal> = [
{
title: '提现单号',
dataIndex: 'withdrawal_no',
key: 'withdrawal_no',
dataIndex: 'withdrawNo',
key: 'withdrawNo',
width: 180,
fixed: 'left',
},
@@ -149,21 +149,22 @@ const PlatformWithdrawals: React.FC = () => {
},
{
title: '收款账户',
dataIndex: 'bank_account',
key: 'bank_account',
dataIndex: 'bankAccount',
key: 'bankAccount',
width: 180,
},
{
title: '开户银行',
dataIndex: 'bank_name',
key: 'bank_name',
dataIndex: 'bankName',
key: 'bankName',
width: 150,
},
{
title: '账户名称',
dataIndex: 'account_name',
key: 'account_name',
dataIndex: 'accountName',
key: 'accountName',
width: 120,
render: (name: string) => name || '-',
},
{
title: '状态',
@@ -177,22 +178,22 @@ const PlatformWithdrawals: React.FC = () => {
},
{
title: '申请时间',
dataIndex: 'created_at',
key: 'created_at',
dataIndex: 'createdAt',
key: 'createdAt',
width: 180,
render: (date: string) => formatDateTime(date),
},
{
title: '审核时间',
dataIndex: 'reviewed_at',
key: 'reviewed_at',
dataIndex: 'reviewedAt',
key: 'reviewedAt',
width: 180,
render: (date: string) => (date ? formatDateTime(date) : '-'),
},
{
title: '打款时间',
dataIndex: 'paid_at',
key: 'paid_at',
dataIndex: 'paidAt',
key: 'paidAt',
width: 180,
render: (date: string) => (date ? formatDateTime(date) : '-'),
},
@@ -298,15 +299,15 @@ const PlatformWithdrawals: React.FC = () => {
>
{detailModal.data && (
<Descriptions column={1} bordered>
<Descriptions.Item label="提现单号">{detailModal.data.withdrawal_no}</Descriptions.Item>
<Descriptions.Item label="提现单号">{detailModal.data.withdrawNo}</Descriptions.Item>
<Descriptions.Item label="提现金额">
<span style={{ fontSize: 18, fontWeight: 'bold', color: '#ff4d4f' }}>
{formatMoney(detailModal.data.amount)}
</span>
</Descriptions.Item>
<Descriptions.Item label="收款账户">{detailModal.data.bank_account}</Descriptions.Item>
<Descriptions.Item label="开户银行">{detailModal.data.bank_name}</Descriptions.Item>
<Descriptions.Item label="账户名称">{detailModal.data.account_name}</Descriptions.Item>
<Descriptions.Item label="收款账户">{detailModal.data.bankAccount}</Descriptions.Item>
<Descriptions.Item label="开户银行">{detailModal.data.bankName}</Descriptions.Item>
<Descriptions.Item label="账户名称">{detailModal.data.accountName || '-'}</Descriptions.Item>
<Descriptions.Item label="状态">
<Tag color={statusConfig[detailModal.data.status].color}>
{statusConfig[detailModal.data.status].text}
@@ -315,20 +316,20 @@ const PlatformWithdrawals: React.FC = () => {
{detailModal.data.remark && (
<Descriptions.Item label="备注">{detailModal.data.remark}</Descriptions.Item>
)}
{detailModal.data.reject_reason && (
{detailModal.data.rejectReason && (
<Descriptions.Item label="拒绝原因">
<span style={{ color: '#ff4d4f' }}>{detailModal.data.reject_reason}</span>
<span style={{ color: '#ff4d4f' }}>{detailModal.data.rejectReason}</span>
</Descriptions.Item>
)}
{detailModal.data.payment_no && (
<Descriptions.Item label="打款流水号">{detailModal.data.payment_no}</Descriptions.Item>
{detailModal.data.paymentNo && (
<Descriptions.Item label="打款流水号">{detailModal.data.paymentNo}</Descriptions.Item>
)}
<Descriptions.Item label="申请时间">{formatDateTime(detailModal.data.created_at)}</Descriptions.Item>
{detailModal.data.reviewed_at && (
<Descriptions.Item label="审核时间">{formatDateTime(detailModal.data.reviewed_at)}</Descriptions.Item>
<Descriptions.Item label="申请时间">{formatDateTime(detailModal.data.createdAt)}</Descriptions.Item>
{detailModal.data.reviewedAt && (
<Descriptions.Item label="审核时间">{formatDateTime(detailModal.data.reviewedAt)}</Descriptions.Item>
)}
{detailModal.data.paid_at && (
<Descriptions.Item label="打款时间">{formatDateTime(detailModal.data.paid_at)}</Descriptions.Item>
{detailModal.data.paidAt && (
<Descriptions.Item label="打款时间">{formatDateTime(detailModal.data.paidAt)}</Descriptions.Item>
)}
</Descriptions>
)}
@@ -13,6 +13,7 @@ import {
confirmMerchantWithdrawal
} from '@/api/finance';
import type { ColumnsType } from 'antd/es/table';
import { formatDateTime } from '@rent/shared-utils';
import dayjs from 'dayjs';
interface Withdrawal {
@@ -73,7 +74,7 @@ const Withdrawals: React.FC = () => {
res = await getPlatformWithdrawals(queryParams);
}
setWithdrawals(res.data.items || []);
setWithdrawals(res.data.list || res.data.items || []);
setPagination({ ...pagination, total: res.data.total || 0, ...params });
} catch (error) {
message.error('获取提现记录失败');
@@ -179,22 +180,22 @@ const Withdrawals: React.FC = () => {
dataIndex: 'amount',
key: 'amount',
width: 120,
render: (amount: number) => `¥${amount.toFixed(2)}`,
render: (amount: number | string) => `¥${Number(amount).toFixed(2)}`,
},
{
title: '手续费',
dataIndex: 'fee',
key: 'fee',
width: 100,
render: (fee: number) => `¥${fee.toFixed(2)}`,
render: (fee: number | string) => `¥${Number(fee).toFixed(2)}`,
},
{
title: '到账金额',
dataIndex: 'actualAmount',
key: 'actualAmount',
width: 120,
render: (actualAmount: number) => (
<span style={{ fontWeight: 'bold', color: '#52c41a' }}>¥{actualAmount.toFixed(2)}</span>
render: (actualAmount: number | string) => (
<span style={{ fontWeight: 'bold', color: '#52c41a' }}>¥{Number(actualAmount).toFixed(2)}</span>
),
},
{
@@ -230,6 +231,7 @@ const Withdrawals: React.FC = () => {
dataIndex: 'createdAt',
key: 'createdAt',
width: 180,
render: (date: string) => formatDateTime(date),
},
{
title: '操作',