import React, { useState } from 'react'; import { useParams } from 'react-router-dom'; import { useQuery } from '@tanstack/react-query'; import { Card, Table, Tag, Typography, Space, Select, Tooltip, Badge, Drawer, Descriptions, Button, Alert, Row, Col, Statistic, } from 'antd'; import { SwapOutlined, WarningOutlined, LinkOutlined, EyeOutlined, ArrowUpOutlined, ArrowDownOutlined, } from '@ant-design/icons'; import type { ColumnsType } from 'antd/es/table'; import type { TransactionRecord, SourceApp } from '../../types'; import { fetchTransactions } from '../../services/api'; const appTag: Record = { wechat: { label: '微信', color: 'green' }, alipay: { label: '支付宝', color: 'blue' }, bank: { label: '银行', color: 'purple' }, digital_wallet: { label: '数字钱包', color: 'orange' }, other: { label: '其他', color: 'default' }, }; const Transactions: React.FC = () => { const { id = '1' } = useParams(); const [filterDuplicate, setFilterDuplicate] = useState('all'); const [detail, setDetail] = useState(null); const { data: txData } = useQuery({ queryKey: ['transactions', id], queryFn: () => fetchTransactions(id), }); const allTransactions = txData?.items ?? []; const data = filterDuplicate === 'all' ? allTransactions : filterDuplicate === 'unique' ? allTransactions.filter((t) => !t.isDuplicate) : allTransactions.filter((t) => t.isDuplicate); const totalOut = allTransactions .filter((t) => t.direction === 'out' && !t.isDuplicate) .reduce((s, t) => s + t.amount, 0); const totalIn = allTransactions .filter((t) => t.direction === 'in' && !t.isDuplicate) .reduce((s, t) => s + t.amount, 0); const duplicateCount = allTransactions.filter((t) => t.isDuplicate).length; const transitCount = allTransactions.filter((t) => t.isTransit).length; const columns: ColumnsType = [ { title: '交易时间', dataIndex: 'tradeTime', width: 170, sorter: (a, b) => a.tradeTime.localeCompare(b.tradeTime), defaultSortOrder: 'ascend', }, { title: '来源', dataIndex: 'sourceApp', width: 100, render: (app: SourceApp) => ( {appTag[app].label} ), }, { title: '金额(元)', dataIndex: 'amount', width: 140, align: 'right', render: (v: number, r) => ( {r.direction === 'out' ? '-' : '+'}¥{v.toLocaleString('zh-CN', { minimumFractionDigits: 2 })} ), }, { title: '方向', dataIndex: 'direction', width: 70, align: 'center', render: (d: string) => d === 'out' ? ( ) : ( ), }, { title: '对方', dataIndex: 'counterpartyName', ellipsis: true, }, { title: '备注', dataIndex: 'remark', width: 120, ellipsis: true, }, { title: '标记', width: 130, render: (_, r) => ( {r.isDuplicate && ( 重复 )} {r.isTransit && ( 中转 )} {!r.isDuplicate && !r.isTransit && ( 有效 )} ), }, { title: '置信度', dataIndex: 'confidence', width: 80, align: 'center', render: (v: number) => ( = 0.9 ? '#52c41a' : v >= 0.8 ? '#faad14' : '#ff4d4f'} text={`${(v * 100).toFixed(0)}%`} /> ), }, { title: '操作', width: 80, render: (_, r) => ( ), }, ]; return (
} /> } /> {duplicateCount > 0 && ( )} 交易明细 {allTransactions.length} 笔 } extra={