import React, { useEffect, useMemo, useState } from 'react';
import {
Table,
Button,
Input,
Space,
Modal,
Form,
Select,
App,
Tooltip,
Switch,
Badge,
Typography,
Tag,
Row,
Col,
} from 'antd';
import {
PlusOutlined,
DeleteOutlined,
EditOutlined,
SearchOutlined,
SyncOutlined,
MonitorOutlined,
ReloadOutlined,
LinkOutlined,
WifiOutlined,
CheckCircleOutlined,
SafetyCertificateOutlined,
} from '@ant-design/icons';
import apiClient from '../../utils/apiClient';
import { buildApiUrl, API_ENDPOINTS } from '../../config/api';
import AdminModuleShell from '../../components/AdminModuleShell';
import StatusTag from '../../components/StatusTag';
const { Text } = Typography;
const { TextArea } = Input;
const ONLINE_MINUTES = 10;
const TerminalManagement = () => {
const { message, modal } = App.useApp();
const [form] = Form.useForm();
const [terminals, setTerminals] = useState([]);
const [terminalTypes, setTerminalTypes] = useState([]);
const [loading, setLoading] = useState(true);
const [keyword, setKeyword] = useState('');
const [filterType, setFilterType] = useState('all');
const [filterStatus, setFilterStatus] = useState('all');
const [filterActivation, setFilterActivation] = useState('all');
const [showModal, setShowModal] = useState(false);
const [isEditing, setIsEditing] = useState(false);
const [selectedTerminal, setSelectedTerminal] = useState(null);
useEffect(() => {
fetchTerminalTypes();
fetchTerminals();
}, []);
const fetchTerminalTypes = async () => {
try {
const response = await apiClient.get(buildApiUrl(API_ENDPOINTS.DICT_DATA.BY_TYPE('client_platform')), {
params: { parent_code: 'TERMINAL' },
});
if (response.code === '200') {
setTerminalTypes(response.data.items || []);
}
} catch (error) {
console.error('Failed to fetch terminal types:', error);
}
};
const fetchTerminals = async () => {
setLoading(true);
try {
const response = await apiClient.get(buildApiUrl(API_ENDPOINTS.TERMINALS.LIST), {
params: { page: 1, size: 10000 },
});
if (response.code === '200') {
setTerminals(response.data.items || []);
}
} catch {
message.error('获取终端列表失败');
} finally {
setLoading(false);
}
};
const handleOpenModal = (terminal = null) => {
if (terminal) {
setIsEditing(true);
setSelectedTerminal(terminal);
form.setFieldsValue({
...terminal,
status: terminal.status === 1,
});
} else {
setIsEditing(false);
setSelectedTerminal(null);
form.resetFields();
form.setFieldsValue({
terminal_type: terminalTypes[0]?.dict_code,
status: true,
});
}
setShowModal(true);
};
const handleSave = async () => {
try {
const values = await form.validateFields();
const payload = {
...values,
status: values.status ? 1 : 0,
};
if (isEditing) {
await apiClient.put(buildApiUrl(API_ENDPOINTS.TERMINALS.UPDATE(selectedTerminal.id)), payload);
message.success('终端更新成功');
} else {
await apiClient.post(buildApiUrl(API_ENDPOINTS.TERMINALS.CREATE), payload);
message.success('终端创建成功');
}
setShowModal(false);
fetchTerminals();
} catch (error) {
if (!error.errorFields) {
message.error('保存失败');
}
}
};
const handleDelete = (item) => {
modal.confirm({
title: '删除终端',
content: `确定要删除 IMEI 为 ${item.imei} 的终端吗?`,
okText: '确定',
okType: 'danger',
onOk: async () => {
try {
await apiClient.delete(buildApiUrl(API_ENDPOINTS.TERMINALS.DELETE(item.id)));
message.success('删除成功');
fetchTerminals();
} catch {
message.error('删除失败');
}
},
});
};
const handleToggleStatus = async (item, checked) => {
try {
const newStatus = checked ? 1 : 0;
await apiClient.post(buildApiUrl(API_ENDPOINTS.TERMINALS.STATUS(item.id)), null, {
params: { status: newStatus },
});
setTerminals((prev) => prev.map((terminal) => (
terminal.id === item.id ? { ...terminal, status: newStatus } : terminal
)));
message.success(`已${newStatus === 1 ? '启用' : '停用'}终端`);
} catch {
message.error('状态更新失败');
}
};
const getTerminalTypeLabel = (code) => (
terminalTypes.find((terminalType) => terminalType.dict_code === code)?.label_cn || code
);
const isOnline = (lastOnlineAt) => {
if (!lastOnlineAt) return false;
const diffMs = Date.now() - new Date(lastOnlineAt).getTime();
return diffMs >= 0 && diffMs <= ONLINE_MINUTES * 60 * 1000;
};
const filteredTerminals = useMemo(() => terminals.filter((terminal) => {
if (filterType !== 'all' && terminal.terminal_type !== filterType) {
return false;
}
if (filterStatus !== 'all' && terminal.status !== Number.parseInt(filterStatus, 10)) {
return false;
}
if (filterActivation === 'activated' && terminal.is_activated !== 1) {
return false;
}
if (filterActivation === 'pending' && terminal.is_activated === 1) {
return false;
}
if (!keyword) {
return true;
}
const query = keyword.toLowerCase();
return [
terminal.imei,
terminal.terminal_name,
terminal.current_username,
terminal.current_user_caption,
terminal.mac_address,
terminal.ip_address,
].some((field) => String(field || '').toLowerCase().includes(query));
}), [terminals, filterType, filterStatus, filterActivation, keyword]);
const activeCount = useMemo(() => terminals.filter((terminal) => terminal.status === 1).length, [terminals]);
const activatedCount = useMemo(() => terminals.filter((terminal) => terminal.is_activated === 1).length, [terminals]);
const onlineCount = useMemo(() => terminals.filter((terminal) => isOnline(terminal.last_online_at)).length, [terminals]);
const columns = [
{
title: 'IMEI',
dataIndex: 'imei',
key: 'imei',
width: 160,
render: (text) =>