feat: 添加前端页面和业务说明书

refactor(server): 重构服务层代码结构
feat(server): 添加基础设施、跨境电商、AI决策等核心服务
docs: 完善前端业务说明书和开发进度文档
style: 格式化代码和文档
This commit is contained in:
2026-03-18 19:12:38 +08:00
parent c932a67be2
commit 6d0d2b6157
140 changed files with 23859 additions and 5833 deletions

View File

@@ -0,0 +1,221 @@
import React, { useState, useEffect } from 'react';
import { Table, Button, Input, Select, DatePicker, message } from 'antd';
import { SearchOutlined, FilterOutlined, ExportOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
const { Option } = Select;
const { RangePicker } = DatePicker;
const { Search } = Input;
interface Transaction {
id: string;
transactionId: string;
amount: number;
type: 'income' | 'expense';
category: string;
description: string;
date: string;
status: 'completed' | 'pending' | 'failed';
}
const Transactions: React.FC = () => {
const navigate = useNavigate();
const [transactions, setTransactions] = useState<Transaction[]>([]);
const [loading, setLoading] = useState(false);
const [filters, setFilters] = useState({
type: '',
category: '',
status: '',
search: '',
dateRange: null as any,
});
useEffect(() => {
fetchTransactions();
}, [filters]);
const fetchTransactions = async () => {
setLoading(true);
// 模拟API调用
setTimeout(() => {
const mockTransactions: Transaction[] = [
{
id: '1',
transactionId: 'TRX-2026-001',
amount: 10000,
type: 'income',
category: 'Sales',
description: 'Product sales',
date: '2026-03-15',
status: 'completed',
},
{
id: '2',
transactionId: 'TRX-2026-002',
amount: 5000,
type: 'expense',
category: 'Suppliers',
description: 'Supplier payment',
date: '2026-03-16',
status: 'completed',
},
{
id: '3',
transactionId: 'TRX-2026-003',
amount: 2000,
type: 'expense',
category: 'Marketing',
description: 'Ad spend',
date: '2026-03-17',
status: 'completed',
},
{
id: '4',
transactionId: 'TRX-2026-004',
amount: 15000,
type: 'income',
category: 'Sales',
description: 'Product sales',
date: '2026-03-18',
status: 'pending',
},
];
setTransactions(mockTransactions);
setLoading(false);
}, 500);
};
const handleExport = () => {
message.success('交易记录已导出');
};
const columns = [
{
title: '交易ID',
dataIndex: 'transactionId',
key: 'transactionId',
},
{
title: '金额',
dataIndex: 'amount',
key: 'amount',
render: (amount: number, record: Transaction) => (
<span style={{ color: record.type === 'income' ? '#3f8600' : '#cf1322' }}>
{record.type === 'income' ? '+' : '-'}$${amount.toFixed(2)}
</span>
),
},
{
title: '类型',
dataIndex: 'type',
key: 'type',
render: (type: string) => {
return type === 'income' ? '收入' : '支出';
},
},
{
title: '分类',
dataIndex: 'category',
key: 'category',
},
{
title: '描述',
dataIndex: 'description',
key: 'description',
},
{
title: '日期',
dataIndex: 'date',
key: 'date',
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
render: (status: string) => {
const statusMap = {
completed: '已完成',
pending: '待处理',
failed: '失败',
};
return statusMap[status] || status;
},
},
];
return (
<div className="transactions">
<div className="page-header">
<h1></h1>
<Button
type="primary"
icon={<ExportOutlined />}
onClick={handleExport}
>
</Button>
</div>
<div className="filter-section" style={{ marginBottom: 24, display: 'flex', gap: 16, flexWrap: 'wrap' }}>
<Search
placeholder="搜索交易ID或描述"
style={{ width: 300 }}
onChange={(e) => setFilters({ ...filters, search: e.target.value })}
/>
<Select
placeholder="类型"
style={{ width: 120 }}
onChange={(value) => setFilters({ ...filters, type: value })}
>
<Option value=""></Option>
<Option value="income"></Option>
<Option value="expense"></Option>
</Select>
<Select
placeholder="分类"
style={{ width: 120 }}
onChange={(value) => setFilters({ ...filters, category: value })}
>
<Option value=""></Option>
<Option value="Sales"></Option>
<Option value="Suppliers"></Option>
<Option value="Marketing"></Option>
<Option value="Shipping"></Option>
</Select>
<Select
placeholder="状态"
style={{ width: 120 }}
onChange={(value) => setFilters({ ...filters, status: value })}
>
<Option value=""></Option>
<Option value="completed"></Option>
<Option value="pending"></Option>
<Option value="failed"></Option>
</Select>
<RangePicker
style={{ width: 300 }}
onChange={(dates) => setFilters({ ...filters, dateRange: dates })}
/>
<Button
icon={<FilterOutlined />}
onClick={fetchTransactions}
>
</Button>
</div>
<Table
columns={columns}
dataSource={transactions}
loading={loading}
rowKey="id"
pagination={{
pageSize: 10,
showSizeChanger: true,
}}
/>
</div>
);
};
export default Transactions;