import React, { useState, useEffect } from 'react'; import { Card, Row, Col, Statistic, Table, Tag, DatePicker, Space, Select, Progress, message } from 'antd'; import { InboxOutlined, ExportOutlined, WarningOutlined, DollarOutlined, ShoppingCartOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; import axios from 'axios'; import dayjs from 'dayjs'; const { RangePicker } = DatePicker; function ConsumableStatistics() { const [summary, setSummary] = useState({ total: 0, lowStock: 0, totalValue: 0, byCategory: [] }); const [lowStockItems, setLowStockItems] = useState([]); const [stats, setStats] = useState({ inCount: 0, outCount: 0, inQuantity: 0, outQuantity: 0, recentRecords: [] }); const [loading, setLoading] = useState(true); const [dateRange, setDateRange] = useState([]); const fetchSummary = async () => { try { const response = await axios.get('/api/consumables/statistics/summary'); setSummary(response.data); } catch (error) { message.error('获取统计信息失败'); } }; const fetchLowStock = async () => { try { const response = await axios.get('/api/consumables/low-stock'); setLowStockItems(response.data); } catch (error) { message.error('获取低库存信息失败'); } }; const fetchInOutStats = async () => { try { const params = {}; if (dateRange && dateRange.length === 2) { params.startDate = dateRange[0].toISOString(); params.endDate = dateRange[1].toISOString(); } const response = await axios.get('/api/consumable-records/statistics', { params }); setStats(response.data); } catch (error) { message.error('获取出入库统计失败'); } }; useEffect(() => { fetchSummary(); fetchLowStock(); fetchInOutStats(); }, []); useEffect(() => { fetchInOutStats(); }, [dateRange]); const lowStockColumns = [ { title: '耗材名称', dataIndex: 'name', key: 'name', width: 150 }, { title: '分类', dataIndex: 'category', key: 'category', width: 120 }, { title: '当前库存', dataIndex: 'currentStock', key: 'currentStock', width: 100, render: (value) => ( {value} ) }, { title: '最小库存', dataIndex: 'minStock', key: 'minStock', width: 100 }, { title: '单位', dataIndex: 'unit', key: 'unit', width: 80 }, { title: '库存充足率', key: 'rate', width: 150, render: (_, record) => { const rate = Math.min(100, Math.round((record.currentStock / record.maxStock) * 100)); const status = rate < 30 ? 'exception' : rate < 60 ? 'active' : 'success'; return ; } }, { title: '供应商', dataIndex: 'supplier', key: 'supplier', width: 150, render: (value) => value || '-' } ]; const recentColumns = [ { title: '时间', dataIndex: 'createdAt', key: 'createdAt', width: 180, render: (date) => dayjs(date).format('YYYY-MM-DD HH:mm:ss') }, { title: '耗材名称', dataIndex: ['Consumable', 'name'], key: 'consumableName', width: 150 }, { title: '类型', dataIndex: 'type', key: 'type', width: 100, render: (type) => ( {type === 'in' ? '入库' : '出库'} ) }, { title: '数量', dataIndex: 'quantity', key: 'quantity', width: 100, render: (value, record) => ( {record.type === 'in' ? '+' : '-'}{value} ) }, { title: '操作人', dataIndex: 'operator', key: 'operator', width: 120 }, { title: '原因', dataIndex: 'reason', key: 'reason', width: 150, render: (value) => value || '-' } ]; return (
} /> 0 ? '#ff4d4f' : '#52c41a' }} />} valueStyle={{ color: summary.lowStock > 0 ? '#ff4d4f' : '#52c41a' }} /> } precision={2} /> = 0 ? '#52c41a' : '#ff4d4f' }} />} valueStyle={{ color: stats.inQuantity - stats.outQuantity >= 0 ? '#52c41a' : '#ff4d4f' }} /> }> } />
+{stats.inQuantity}
} />
-{stats.outQuantity}
{summary.byCategory?.map(item => ( ))}
低库存预警} extra={{lowStockItems.length}项} >
); } export default ConsumableStatistics;