import React, { useState, useEffect, useCallback } from 'react';
import {
Table,
Button,
Modal,
Form,
Input,
Select,
message,
Card,
Space,
Tag,
Tooltip,
Typography,
Pagination,
Popconfirm,
Row,
Col,
Badge,
Avatar,
Statistic,
} from 'antd';
import {
PlusOutlined,
EditOutlined,
DeleteOutlined,
SearchOutlined,
ReloadOutlined,
InboxOutlined,
ClockCircleOutlined,
UploadOutlined,
ExclamationCircleOutlined,
} from '@ant-design/icons';
import axios from 'axios';
import { deviceAPI } from '../api';
const { Title, Text, Paragraph } = Typography;
const { Option } = Select;
const { TextArea } = Input;
const IdleDeviceManagement = () => {
const [idleDevices, setIdleDevices] = useState([]);
const [loading, setLoading] = useState(false);
const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 });
const [searchKeyword, setSearchKeyword] = useState('');
const [sourceTypeFilter, setSourceTypeFilter] = useState('all');
const [isModalVisible, setIsModalVisible] = useState(false);
const [isShelveModalVisible, setIsShelveModalVisible] = useState(false);
const [editingDevice, setEditingDevice] = useState(null);
const [shelvingDevice, setShelvingDevice] = useState(null);
const [form] = Form.useForm();
const [shelveForm] = Form.useForm();
const [racks, setRacks] = useState([]);
const [rooms, setRooms] = useState([]);
const [selectedRoomId, setSelectedRoomId] = useState(null);
const [selectedShelveRoomId, setSelectedShelveRoomId] = useState(null);
const [shelvePositionConflict, setShelvePositionConflict] = useState(null);
const [shelveSelectedRackId, setShelveSelectedRackId] = useState(null);
const fetchIdleDevices = useCallback(async () => {
setLoading(true);
try {
const params = {
page: pagination.current,
pageSize: pagination.pageSize,
keyword: searchKeyword,
sourceType: sourceTypeFilter,
};
const response = await axios.get('/api/idle-devices', { params });
setIdleDevices(response.data.idleDevices || []);
setPagination(prev => ({
...prev,
total: response.data.total || 0,
}));
} catch (error) {
message.error('获取空闲设备列表失败');
} finally {
setLoading(false);
}
}, [pagination.current, pagination.pageSize, searchKeyword, sourceTypeFilter]);
const fetchRacks = async () => {
try {
const response = await axios.get('/api/racks/all');
setRacks(response.data.racks || []);
} catch (error) {
console.error('获取机柜列表失败', error);
}
};
const fetchRooms = async () => {
try {
const response = await axios.get('/api/rooms', { params: { pageSize: 100 } });
setRooms(response.data.rooms || []);
} catch (error) {
console.error('获取机房列表失败', error);
}
};
useEffect(() => {
fetchIdleDevices();
}, [fetchIdleDevices]);
useEffect(() => {
fetchRacks();
fetchRooms();
}, []);
const handleAdd = () => {
setEditingDevice(null);
setSelectedRoomId(null);
form.resetFields();
setIsModalVisible(true);
};
const handleEdit = record => {
setEditingDevice(record);
let roomId = null;
if (record.rackId && record.Rack) {
roomId = record.Rack.roomId;
setSelectedRoomId(roomId);
}
form.setFieldsValue({
name: record.name,
type: record.type,
model: record.model,
serialNumber: record.serialNumber,
powerConsumption: record.powerConsumption,
idleReason: record.idleReason,
warehouseId: record.warehouseId,
roomId: roomId,
rackId: record.rackId,
position: record.position,
description: record.description,
});
setIsModalVisible(true);
};
const handleDelete = async deviceId => {
try {
await axios.delete(`/api/idle-devices/${deviceId}`);
message.success('删除成功');
fetchIdleDevices();
} catch (error) {
message.error(error.response?.data?.error || '删除失败');
}
};
const handleShelve = record => {
setShelvingDevice(record);
setShelvePositionConflict(null);
setShelveSelectedRackId(null);
let roomId = null;
if (record.rackId) {
const rack = racks.find(r => r.rackId === record.rackId);
if (rack) {
roomId = rack.roomId;
}
}
setSelectedShelveRoomId(roomId);
shelveForm.setFieldsValue({
name: record.name,
type: record.type,
model: record.model,
serialNumber: record.serialNumber,
height: record.height || 1,
powerConsumption: record.powerConsumption,
roomId: roomId,
rackId: record.rackId,
position: null,
description: record.description,
});
if (record.rackId) {
setShelveSelectedRackId(record.rackId);
}
setIsShelveModalVisible(true);
};
const checkShelvePositionConflict = async (rackId, position, height) => {
if (!rackId || !position) {
setShelvePositionConflict(null);
return;
}
try {
console.log('检查U位冲突:', { rackId, position, height, deviceId: shelvingDevice?.deviceId });
const result = await deviceAPI.checkPosition(rackId, { position, height: height || 1 });
console.log('U位检查结果:', result);
if (!result.available) {
setShelvePositionConflict(result.reason);
} else {
setShelvePositionConflict(null);
}
} catch (error) {
console.error('检查U位冲突失败:', error);
setShelvePositionConflict(null);
}
};
const handleShelveRackChange = value => {
setShelveSelectedRackId(value);
const position = shelveForm.getFieldValue('position');
const height = shelveForm.getFieldValue('height');
if (position) {
checkShelvePositionConflict(value, position, height);
} else {
setShelvePositionConflict(null);
}
};
const handleShelvePositionChange = e => {
const value = e.target.value ? parseInt(e.target.value) : null;
const height = shelveForm.getFieldValue('height');
if (shelveSelectedRackId && value) {
checkShelvePositionConflict(shelveSelectedRackId, value, height);
} else {
setShelvePositionConflict(null);
}
};
const handleShelveHeightChange = e => {
const value = e.target.value ? parseInt(e.target.value) : null;
const position = shelveForm.getFieldValue('position');
if (shelveSelectedRackId && position) {
checkShelvePositionConflict(shelveSelectedRackId, position, value);
} else {
setShelvePositionConflict(null);
}
};
const handleShelveSubmit = async () => {
try {
const values = await shelveForm.validateFields();
if (shelvePositionConflict) {
message.error('存在U位冲突,请重新选择上架位置');
return;
}
const submitData = {
name: values.name,
type: values.type,
model: values.model,
serialNumber: values.serialNumber,
height: values.height || 1,
powerConsumption: values.powerConsumption || 0,
rackId: values.rackId,
position: values.position,
description: values.description || '',
};
await axios.put(`/api/idle-devices/${shelvingDevice.deviceId}/shelve`, submitData);
message.success('设备上架成功');
setIsShelveModalVisible(false);
fetchIdleDevices();
} catch (error) {
message.error(error.response?.data?.error || '上架失败');
}
};
const handleSubmit = async () => {
try {
const values = await form.validateFields();
const submitData = { ...values };
if (submitData.warehouseId) {
submitData.rackId = null;
submitData.position = null;
submitData.sourceType = 'warehouse';
} else if (submitData.rackId) {
submitData.warehouseId = null;
submitData.sourceType = 'rack';
}
if (editingDevice) {
await axios.put(`/api/idle-devices/${editingDevice.deviceId}`, submitData);
message.success('更新成功');
} else {
const response = await axios.post('/api/idle-devices', submitData);
message.success(`添加成功,设备ID:${response.data.deviceId}`);
}
setIsModalVisible(false);
fetchIdleDevices();
} catch (error) {
message.error(error.response?.data?.error || '操作失败');
}
};
const getIdleDays = idleDate => {
if (!idleDate) return 0;
const diff = new Date() - new Date(idleDate);
return Math.floor(diff / (1000 * 60 * 60 * 24));
};
const columns = [
{
title: '序号',
key: 'index',
width: 60,
align: 'center',
render: (_, __, index) => (