feat: 添加工单统计自动刷新功能并优化设备选择逻辑

refactor(工单管理): 重构设备选择表单并优化UI体验

fix(工单统计): 修复每日完成工单统计不准确的问题

perf(后端): 添加批量导出接口优化大数据量查询性能

chore: 添加react-transition-group依赖支持动画效果

feat(设备管理): 添加设备全量查询接口支持导出功能

style(工单管理): 优化表单布局和样式提升用户体验

refactor(工单字段): 优化字段管理组件处理空值情况

fix(机柜管理): 修复机柜列表查询接口参数问题

docs: 移除不再使用的工单字段管理页面
This commit is contained in:
zhang1106
2026-03-24 17:10:38 +08:00
parent 1b898814ed
commit 4e8d9be864
13 changed files with 1559 additions and 367 deletions
+55 -5
View File
@@ -1,5 +1,5 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { Card, Row, Col, Statistic, Table, DatePicker, Select, Space, Tag, message } from 'antd';
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { Card, Row, Col, Statistic, Table, DatePicker, Select, Space, Tag, message, Button, Switch, Tooltip } from 'antd';
import {
BarChartOutlined,
PieChartOutlined,
@@ -8,6 +8,8 @@ import {
ClockCircleOutlined,
CheckCircleOutlined,
ExclamationCircleOutlined,
ReloadOutlined,
SyncOutlined,
} from '@ant-design/icons';
import axios from 'axios';
import dayjs from 'dayjs';
@@ -15,6 +17,8 @@ import dayjs from 'dayjs';
const { RangePicker } = DatePicker;
const { Option } = Select;
const REFRESH_INTERVAL = 30000;
const getStatusColor = status => {
const colors = {
pending: 'orange',
@@ -59,7 +63,9 @@ const getPriorityText = priority => {
function TicketStatistics() {
const [loading, setLoading] = useState(true);
const [autoRefresh, setAutoRefresh] = useState(false);
const [dateRange, setDateRange] = useState([dayjs().subtract(30, 'days'), dayjs()]);
const [lastUpdateTime, setLastUpdateTime] = useState(null);
const [statistics, setStatistics] = useState({
total: 0,
pending: 0,
@@ -74,16 +80,21 @@ function TicketStatistics() {
trend: [],
});
const fetchStatistics = useCallback(async () => {
const timerRef = useRef(null);
const fetchStatistics = useCallback(async (isManual = false) => {
try {
setLoading(true);
if (isManual) {
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 });
const response = await axios.get('/api/tickets/stats', { params });
setStatistics(response.data);
setLastUpdateTime(new Date());
} catch (error) {
message.error('获取统计数据失败');
console.error('获取统计数据失败:', error);
@@ -96,12 +107,34 @@ function TicketStatistics() {
fetchStatistics();
}, [fetchStatistics]);
useEffect(() => {
if (autoRefresh) {
timerRef.current = setInterval(() => {
fetchStatistics();
}, REFRESH_INTERVAL);
} else {
if (timerRef.current) {
clearInterval(timerRef.current);
timerRef.current = null;
}
}
return () => {
if (timerRef.current) {
clearInterval(timerRef.current);
}
};
}, [autoRefresh, fetchStatistics]);
const handleDateChange = useCallback(dates => {
if (dates) {
setDateRange(dates);
}
}, []);
const handleManualRefresh = useCallback(() => {
fetchStatistics(true);
}, [fetchStatistics]);
const getStatusColor = status => {
const colors = {
pending: 'orange',
@@ -296,6 +329,23 @@ function TicketStatistics() {
title="工单统计报表"
extra={
<Space>
<Tooltip title={lastUpdateTime ? `最后更新: ${dayjs(lastUpdateTime).format('HH:mm:ss')}` : '尚未更新'}>
<span style={{ fontSize: 12, color: '#888', marginRight: 8 }}>
{lastUpdateTime && `更新于 ${dayjs(lastUpdateTime).format('HH:mm:ss')}`}
</span>
</Tooltip>
<Tooltip title="自动刷新(每30秒)">
<Switch
checked={autoRefresh}
onChange={setAutoRefresh}
checkedChildren={<SyncOutlined spin={autoRefresh} />}
unCheckedChildren={<SyncOutlined />}
size="small"
/>
</Tooltip>
<Button icon={<ReloadOutlined />} onClick={handleManualRefresh} size="small">
刷新
</Button>
<RangePicker value={dateRange} onChange={handleDateChange} allowClear={false} />
</Space>
}