import React, { useState, useEffect } from 'react' import { Table, Button, Card, Row, Col, Statistic, Select, message, Spin, Progress } from 'antd' import { BarChartOutlined, DollarOutlined, ShoppingOutlined } from '@ant-design/icons' import type { ColumnsType } from 'antd/es/table' // ==================== 类型定义 ==================== interface Project { id: number name: string code: string contract_amount: number } interface CostSummary { project_name: string contract_amount: number purchase_cost: { total: number by_category: Record } payment_cost: number total_cost: number profit: number } // ==================== 组件 ==================== const ProjectCostPage: React.FC = () => { // 状态 const [projects, setProjects] = useState([]) const [selectedProjectId, setSelectedProjectId] = useState(null) const [costSummary, setCostSummary] = useState(null) const [loading, setLoading] = useState(false) // ==================== 数据加载 ==================== const fetchProjects = async () => { try { const response = await fetch('/api/projects') const data = await response.json() if (data.success) { setProjects(data.data) } } catch (error) { console.error('获取项目列表失败:', error) } } const fetchCostSummary = async (projectId: number) => { setLoading(true) try { const response = await fetch(`/api/projects/${projectId}/cost-summary`) const data = await response.json() if (data.success) { setCostSummary(data.data) } else { message.error('获取成本统计失败') setCostSummary(null) } } catch (error) { console.error('获取成本统计失败:', error) message.error('获取成本统计失败') setCostSummary(null) } finally { setLoading(false) } } useEffect(() => { fetchProjects() }, []) useEffect(() => { if (selectedProjectId) { fetchCostSummary(selectedProjectId) } else { setCostSummary(null) } }, [selectedProjectId]) // ==================== 渲染 ==================== return (
{loading ? (
) : costSummary ? ( <> } valueStyle={{ color: '#1890ff' }} /> } valueStyle={{ color: '#faad14' }} /> } valueStyle={{ color: '#fa8c16' }} /> } valueStyle={{ color: costSummary.profit >= 0 ? '#52c41a' : '#ff4d4f' }} />
合同金额 {(costSummary.contract_amount || 0).toFixed(2)}
采购成本 {(costSummary.purchase_cost.total || 0).toFixed(2)}
0 ? Math.min((costSummary.purchase_cost.total / costSummary.contract_amount) * 100, 100) : 0} status="normal" strokeColor="#faad14" />
付款支出 {(costSummary.payment_cost || 0).toFixed(2)}
0 ? Math.min((costSummary.payment_cost / costSummary.contract_amount) * 100, 100) : 0} status="normal" strokeColor="#fa8c16" />
总成本 {costSummary.total_cost.toFixed(2)}
0 ? Math.min((costSummary.total_cost / costSummary.contract_amount) * 100, 100) : 0} status="normal" strokeColor={costSummary.profit >= 0 ? '#52c41a' : '#ff4d4f'} />
{Object.keys(costSummary.purchase_cost.by_category).length > 0 ? (
{Object.entries(costSummary.purchase_cost.by_category).map(([category, amount]) => { const categoryMap: Record = { material: '材料', equipment: '设备', pole: '电杆', other: '其他' } return (
{categoryMap[category] || category} {(amount || 0).toFixed(2)}
0 ? (amount / costSummary.purchase_cost.total) * 100 : 0} status="normal" />
) })}
) : (
暂无采购成本数据
)}
) : (
请选择项目查看成本统计
)}
) } export default ProjectCostPage