无人机 管理 绑定逻辑

This commit is contained in:
mmc
2026-05-25 13:06:38 +08:00
parent f86e4a2800
commit 62cce4ec0e
2 changed files with 178 additions and 2 deletions

View File

@@ -139,7 +139,25 @@ export function changeCameraPlane(data) {
})
}
//直播心跳
// 绑定无人机
export function bindDrone(data) {
return request({
url: '/iot/UAV/bind',
method: 'post',
data
})
}
// 解绑无人机
export function unbindDrone(data) {
return request({
url: '/iot/UAV/unbind',
method: 'post',
data
})
}
// 直播心跳
export function postLiveHeartbeat(data) {
return request({

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import {
Table,
Input,
@@ -12,6 +12,10 @@ import {
Tabs,
Card,
InputNumber,
Checkbox,
Tooltip,
Row,
Col,
} from 'antd';
import {
SearchOutlined,
@@ -19,8 +23,14 @@ import {
PlusOutlined,
EditOutlined,
DeleteOutlined,
LinkOutlined,
DisconnectOutlined,
} from '@ant-design/icons';
import SerialNumGenerate from "./SerialNumGenerate"
import { getPlaneDeviceList, bindDrone, unbindDrone } from '@/api/device';
import { useSelector } from 'react-redux';
import { RootState } from '@/src/store';
import utils from '@/lib/utils';
// 模拟数据
const allDeviceList = [
@@ -54,6 +64,101 @@ export default function DeviceManagementPage() {
const [loading, setLoading] = useState(false);
const [deviceList, setDeviceList] = useState(allDeviceList);
// 无人机相关状态
const { userInfo } = useSelector((state: RootState) => state.user);
const [droneList, setDroneList] = useState([]);
const [bindModalVisible, setBindModalVisible] = useState(false);
const [bindForm] = Form.useForm();
const [selectedDroneKeys, setSelectedDroneKeys] = useState([]);
const fetchDroneList = async () => {
setLoading(true);
try {
const res: any = await getPlaneDeviceList();
if (res.code == 200) {
setDroneList(res?.data?.detail || []);
}
} catch (err) {
utils.message.error('获取无人机列表失败');
} finally {
setLoading(false);
}
};
useEffect(() => {
if (activeTab === 'drone') {
fetchDroneList();
}
}, [activeTab]);
const handleBind = async (values) => {
try {
const payload = {
siteId: values.siteId,
orgId: values.orgId,
userId: values.userId || userInfo?.userId,
sns: values.sns.split(',').map(s => s.trim()),
};
const res: any = await bindDrone(payload);
if (res.code === 200) {
utils.message.success('绑定成功');
setBindModalVisible(false);
bindForm.resetFields();
fetchDroneList();
} else {
utils.message.error(res.msg || '绑定失败');
}
} catch (err) {
utils.message.error('操作异常');
}
};
const handleUnbind = (sns, type) => {
const typeText = { 1: '人员', 2: '场站', 3: '组织' }[type];
Modal.confirm({
title: '确认解绑',
content: `确定要为选中的无人机清除${typeText}绑定吗?`,
onOk: async () => {
try {
const res: any = await unbindDrone({ sns, type });
if (res.code === 200) {
utils.message.success('解绑成功');
fetchDroneList();
setSelectedDroneKeys([]);
} else {
utils.message.error(res.msg || '解绑失败');
}
} catch (err) {
utils.message.error('操作异常');
}
}
});
};
const droneColumns = [
{ title: '设备名称', dataIndex: 'drone_callsign', key: 'name' },
{ title: 'SN码', dataIndex: 'device_sn', key: 'sn' },
{ title: '网关SN', dataIndex: 'gateway_sn', key: 'gsn' },
{ title: '状态', dataIndex: 'onlineStatus', key: 'status', render: s => <Tag color={s === 1 ? 'green' : 'default'}>{s === 1 ? '在线' : '离线'}</Tag> },
{
title: '操作',
key: 'action',
render: (_, record) => (
<Space>
<Tooltip title="清除人员绑定">
<Button size="small" icon={<DisconnectOutlined />} onClick={() => handleUnbind([record.device_sn], 1)}>人</Button>
</Tooltip>
<Tooltip title="清除场站绑定">
<Button size="small" icon={<DisconnectOutlined />} onClick={() => handleUnbind([record.device_sn], 2)}>场</Button>
</Tooltip>
<Tooltip title="清除组织绑定">
<Button size="small" icon={<DisconnectOutlined />} onClick={() => handleUnbind([record.device_sn], 3)}>组</Button>
</Tooltip>
</Space>
),
},
];
// 根据 Tab 过滤数据
const filteredByTab = deviceList.filter(tabs.find(t => t.key === activeTab)?.filter || (() => false));
@@ -149,12 +254,65 @@ export default function DeviceManagementPage() {
<Tabs.TabPane key="all" tab="设备管理" />
<Tabs.TabPane key="camera" tab="摄像头管理" />
<Tabs.TabPane key="smart" tab="智能装备" />
<Tabs.TabPane key="drone" tab="无人机管理" />
<Tabs.TabPane key="serialGenerate" tab="机器人生成" />
</Tabs>
{/* ====================== 判断显示内容 ====================== */}
{activeTab === 'serialGenerate' ? (
<SerialNumGenerate />
) : activeTab === 'drone' ? (
<>
<div style={{ marginBottom: 16 }}>
<Space>
<Button type="primary" icon={<LinkOutlined />} onClick={() => setBindModalVisible(true)}>绑定无人机</Button>
<Button disabled={selectedDroneKeys.length === 0} onClick={() => handleUnbind(selectedDroneKeys, 1)}>批量解绑(人)</Button>
<Button disabled={selectedDroneKeys.length === 0} onClick={() => handleUnbind(selectedDroneKeys, 2)}>批量解绑(场)</Button>
<Button disabled={selectedDroneKeys.length === 0} onClick={() => handleUnbind(selectedDroneKeys, 3)}>批量解绑(组)</Button>
</Space>
</div>
<Table
rowSelection={{
selectedRowKeys: selectedDroneKeys,
onChange: setSelectedDroneKeys,
}}
rowKey="device_sn"
columns={droneColumns}
dataSource={droneList}
loading={loading}
pagination={{ showSizeChanger: true, showTotal: t => `共 ${t} 条` }}
/>
<Modal
title="绑定无人机"
open={bindModalVisible}
onCancel={() => setBindModalVisible(false)}
onOk={() => bindForm.submit()}
width={500}
>
<Form form={bindForm} layout="vertical" onFinish={handleBind} initialValues={{ userId: userInfo?.userId }}>
<Form.Item label="无人机 SN (多个用逗号隔开)" name="sns" rules={[{ required: true, message: '请输入 SN' }]}>
<Input.TextArea placeholder="例如: SN001, SN002" rows={3} />
</Form.Item>
<Row gutter={16}>
<Col span={12}>
<Form.Item label="场站 ID (siteId)" name="siteId" rules={[{ required: true, message: '请输入场站 ID' }]}>
<InputNumber style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="组织 ID (orgId)" name="orgId" rules={[{ required: true, message: '请输入组织 ID' }]}>
<InputNumber style={{ width: '100%' }} />
</Form.Item>
</Col>
</Row>
<Form.Item label="用户 ID (userId)" name="userId">
<InputNumber style={{ width: '100%' }} />
</Form.Item>
</Form>
</Modal>
</>
) : (
// 显示原来的设备列表
<>