import React, { useState, useEffect } from 'react'; import { Table, Tag, Spin, Alert, Typography, Card, Button, Modal, Descriptions } from 'antd'; import { useRequest } from 'umi'; const { Title, Text } = Typography; interface BillingRecord { id: string; merchantId: string; totalAmount: number; status: string; createdAt: Date; paidAt?: Date; } interface BillingItem { id: string; billingId: string; feature: string; amount: number; quantity: number; unitPrice: number; } const statusColorMap: Record = { pending: 'orange', paid: 'green' }; const statusTextMap: Record = { pending: '待支付', paid: '已支付' }; const featureMap: Record = { AI_OPTIMIZE: 'AI优化', ADS_AUTO: '自动广告', SYNC_INVENTORY: '库存同步', CALCULATE_PROFIT: '利润计算' }; export default function Billing() { const [bills, setBills] = useState([]); const [loading, setLoading] = useState(true); const [selectedBill, setSelectedBill] = useState(null); const [billItems, setBillItems] = useState([]); const [itemsLoading, setItemsLoading] = useState(false); const [modalVisible, setModalVisible] = useState(false); // 获取账单列表 const { run: fetchBills } = useRequest(async () => { try { // 从本地存储获取merchantId(实际应用中应该从认证信息中获取) const merchantId = localStorage.getItem('merchantId') || 'anonymous'; const response = await fetch(`/api/billing?merchantId=${merchantId}`); const data = await response.json(); setBills(data.list || []); } catch (error) { console.error('Error fetching bills:', error); } finally { setLoading(false); } }, { manual: true }); // 获取账单明细 const { run: fetchBillItems } = useRequest(async (billingId: string) => { try { setItemsLoading(true); const response = await fetch(`/api/billing/items?billingId=${billingId}`); const data = await response.json(); setBillItems(data.list || []); } catch (error) { console.error('Error fetching bill items:', error); } finally { setItemsLoading(false); } }, { manual: true }); // 初始加载账单列表 useEffect(() => { fetchBills(); }, [fetchBills]); // 查看账单明细 const handleViewDetails = async (bill: BillingRecord) => { setSelectedBill(bill); await fetchBillItems(bill.id); setModalVisible(true); }; // 标记账单为已支付 const handleMarkAsPaid = async (bill: BillingRecord) => { try { const response = await fetch(`/api/billing/paid`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ billingId: bill.id }) }); if (response.ok) { // 刷新账单列表 fetchBills(); } } catch (error) { console.error('Error marking bill as paid:', error); } }; // 列定义 const columns = [ { title: '账单ID', dataIndex: 'id', key: 'id', ellipsis: true, }, { title: '总金额', dataIndex: 'totalAmount', key: 'totalAmount', render: (amount: number) => `$${amount.toFixed(2)}`, }, { title: '状态', dataIndex: 'status', key: 'status', render: (status: string) => ( {statusTextMap[status]} ), }, { title: '创建时间', dataIndex: 'createdAt', key: 'createdAt', render: (date: Date) => new Date(date).toLocaleString(), }, { title: '支付时间', dataIndex: 'paidAt', key: 'paidAt', render: (date: Date) => date ? new Date(date).toLocaleString() : '-', }, { title: '操作', key: 'action', render: (_: any, record: BillingRecord) => (
{record.status === 'pending' && ( )}
), }, ]; // 计算总金额 const totalAmount = bills.reduce((sum, bill) => sum + bill.totalAmount, 0); const pendingAmount = bills.filter(bill => bill.status === 'pending').reduce((sum, bill) => sum + bill.totalAmount, 0); return (
账单管理 ${totalAmount.toFixed(2)} ${pendingAmount.toFixed(2)} ${(totalAmount - pendingAmount).toFixed(2)} {bills.length} {loading ? (
) : bills.length === 0 ? ( ) : ( )} {/* 账单明细 modal */} setModalVisible(false)} footer={[ ]} width={800} > {selectedBill && (
{selectedBill.id} ${selectedBill.totalAmount.toFixed(2)} {statusTextMap[selectedBill.status]} {new Date(selectedBill.createdAt).toLocaleString()} {selectedBill.paidAt ? new Date(selectedBill.paidAt).toLocaleString() : '-'} 明细列表 {itemsLoading ? ( ) : billItems.length === 0 ? ( ) : (
featureMap[feature] || feature, }, { title: '数量', dataIndex: 'quantity', }, { title: '单价', dataIndex: 'unitPrice', render: (price: number) => `$${price.toFixed(2)}`, }, { title: '金额', dataIndex: 'amount', render: (amount: number) => `$${amount.toFixed(2)}`, }, ]} dataSource={billItems} pagination={false} /> )} )} ); }