import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { Card, Row, Col, Statistic, Table, DatePicker, Select, Space, Tag, message } from 'antd'; import { BarChartOutlined, PieChartOutlined, RiseOutlined, FallOutlined, ClockCircleOutlined, CheckCircleOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; import axios from 'axios'; import dayjs from 'dayjs'; const { RangePicker } = DatePicker; const { Option } = Select; const getStatusColor = (status) => { const colors = { pending: 'orange', assigned: 'blue', in_progress: 'processing', completed: 'green', closed: 'default' }; return colors[status] || 'default'; }; const getStatusText = (status) => { const texts = { pending: '待处理', assigned: '已分配', in_progress: '处理中', completed: '已完成', closed: '已关闭' }; return texts[status] || status; }; const getPriorityColor = (priority) => { const colors = { low: 'green', medium: 'orange', high: 'red', urgent: 'magenta' }; return colors[priority] || 'default'; }; const getPriorityText = (priority) => { const texts = { low: '低', medium: '中', high: '高', urgent: '紧急' }; return texts[priority] || priority; }; function TicketStatistics() { const [loading, setLoading] = useState(true); const [dateRange, setDateRange] = useState([ dayjs().subtract(30, 'days'), dayjs() ]); const [statistics, setStatistics] = useState({ total: 0, pending: 0, inProgress: 0, completed: 0, closed: 0, avgProcessingTime: 0, byCategory: [], byPriority: [], byStatus: [], byDevice: [], trend: [] }); const fetchStatistics = useCallback(async () => { try { setLoading(true); const params = { startDate: dateRange[0].format('YYYY-MM-DD'), endDate: dateRange[1].format('YYYY-MM-DD') }; const response = await axios.get('/api/tickets/statistics', { params }); setStatistics(response.data); } catch (error) { message.error('获取统计数据失败'); console.error('获取统计数据失败:', error); } finally { setLoading(false); } }, [dateRange]); useEffect(() => { fetchStatistics(); }, [fetchStatistics]); const handleDateChange = useCallback((dates) => { if (dates) { setDateRange(dates); } }, []); const getStatusColor = (status) => { const colors = { pending: 'orange', assigned: 'blue', in_progress: 'processing', completed: 'green', closed: 'default' }; return colors[status] || 'default'; }; const getStatusText = (status) => { const texts = { pending: '待处理', assigned: '已分配', in_progress: '处理中', completed: '已完成', closed: '已关闭' }; return texts[status] || status; }; const getPriorityColor = (priority) => { const colors = { low: 'green', medium: 'orange', high: 'red', urgent: 'magenta' }; return colors[priority] || 'default'; }; const getPriorityText = (priority) => { const texts = { low: '低', medium: '中', high: '高', urgent: '紧急' }; return texts[priority] || priority; }; const statusColumns = useMemo(() => [ { title: '状态', dataIndex: 'status', key: 'status', width: 120, render: (status) => ( {getStatusText(status)} ) }, { title: '工单数量', dataIndex: 'count', key: 'count', width: 120, render: (count) => }, { title: '占比', dataIndex: 'percentage', key: 'percentage', width: 120, render: (pct) => ( 30 ? '#ff4d4f' : '#52c41a' }}> {pct !== undefined && pct !== null ? `${pct.toFixed(1)}%` : '-'} ) } ], []); const categoryColumns = useMemo(() => [ { title: '故障分类', dataIndex: 'category', key: 'category', width: 150 }, { title: '工单数量', dataIndex: 'count', key: 'count', width: 120, render: (count) => }, { title: '占比', dataIndex: 'percentage', key: 'percentage', width: 100, render: (pct) => `${pct !== undefined && pct !== null ? pct.toFixed(1) : 0}%` }, { title: '已完成', dataIndex: 'completed', key: 'completed', width: 100, render: (count) => {count} }, { title: '平均处理时间(小时)', dataIndex: 'avgTime', key: 'avgTime', width: 150, render: (time) => time !== undefined && time !== null ? time.toFixed(1) : '-' } ], []); const priorityColumns = useMemo(() => [ { title: '优先级', dataIndex: 'priority', key: 'priority', width: 100, render: (priority) => ( {getPriorityText(priority)} ) }, { title: '工单数量', dataIndex: 'count', key: 'count', width: 120, render: (count) => }, { title: '已完成', dataIndex: 'completed', key: 'completed', width: 100, render: (count) => {count} }, { title: '平均处理时间(小时)', dataIndex: 'avgTime', key: 'avgTime', width: 150, render: (time) => time !== undefined && time !== null ? time.toFixed(1) : '-' } ], []); const deviceColumns = useMemo(() => [ { title: '设备名称', dataIndex: 'deviceName', key: 'deviceName', width: 180 }, { title: '故障次数', dataIndex: 'count', key: 'count', width: 100, render: (count) => {count} }, { title: '最后故障时间', dataIndex: 'lastFaultTime', key: 'lastFaultTime', width: 160, render: (text) => text ? dayjs(text).format('YYYY-MM-DD HH:mm') : '-' }, { title: '设备类型', dataIndex: 'deviceType', key: 'deviceType', width: 100 } ], []); const simpleBarData = [ { name: '待处理', value: statistics.pending }, { name: '处理中', value: statistics.inProgress }, { name: '已完成', value: statistics.completed }, { name: '已关闭', value: statistics.closed } ]; return (
} > } valueStyle={{ color: '#1890ff' }} /> } valueStyle={{ color: '#fa8c16' }} /> } valueStyle={{ color: '#52c41a' }} /> } valueStyle={{ color: '#722ed1' }} precision={1} /> } valueStyle={{ color: '#eb2f96' }} /> } valueStyle={{ color: '#8c8c8c' }} /> 0 ? ((statistics.completed / statistics.total) * 100).toFixed(1) : 0} suffix="%" prefix={} valueStyle={{ color: '#ff4d4f' }} /> 0 ? ((statistics.inProgress / statistics.total) * 100).toFixed(1) : 0} suffix="%" prefix={} valueStyle={{ color: '#52c41a' }} />
text ? dayjs(text).format('YYYY-MM-DD') : '-' }, { title: '新建工单', dataIndex: 'created', key: 'created', width: 100, render: (count) => {count} }, { title: '已完成', dataIndex: 'completed', key: 'completed', width: 100, render: (count) => {count} }, { title: '关闭工单', dataIndex: 'closed', key: 'closed', width: 100, render: (count) => {count} }, { title: '当日处理中', dataIndex: 'inProgress', key: 'inProgress', width: 120, render: (count) => {count} }, { title: '新增待处理', dataIndex: 'pending', key: 'pending', width: 120, render: (count) => {count} } ]} dataSource={statistics.trend} rowKey="date" pagination={{ pageSize: 10 }} size="small" /> ); } export default React.memo(TicketStatistics);