Files
web-Iot/src/components/SystemSetting/WorkOrderSettingsManagement.tsx
2026-08-12 11:29:44 +08:00

460 lines
12 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import {
Card,
Row,
Col,
Button,
Form,
Input,
Select,
Switch,
Space,
Typography,
Table,
Modal,
InputNumber,
message,
Tag,
App
} from 'antd';
import {
PlusOutlined,
ReloadOutlined,
EditOutlined,
DeleteOutlined
} from '@ant-design/icons';
import {
getWorkOrderModelListApi,
addWorkOrderModelApi,
deleteWorkOrderModelApi,
} from '../../api/systemSetting';
import { getSiteDevice, getRobotRouteList, getWayLine, getSiteUAVList } from '../../api/device';
import { useSelector } from 'react-redux';
import { RootState } from '@/src/store';
import utils, { workOrderTypeOptions, getWorkOrderTypeText, errorLevelOptions, LEVEL_TAG_COLOR } from '@/lib/utils';
import { useTranslation } from 'react-i18next';
const { TabPane } = Typography;
const { Option } = Select;
// 工单模型管理子组件
const WorkOrderModelManagement: React.FC = () => {
const { t } = useTranslation();
const [form] = Form.useForm();
const [list, setList] = useState([]);
const [loading, setLoading] = useState(false);
const [modalVisible, setModalVisible] = useState(false);
const [editingItem, setEditingItem] = useState<any>(null);
const { stationId, currentStation } = useSelector((state: RootState) => state.station);
const { userInfo } = useSelector((state: RootState) => state.user);
const { modal } = App.useApp();
// 设备和预设路径数据
const [deviceOptions, setDeviceOptions] = useState([]);
const [routeOptions, setRouteOptions] = useState([]);
const [waylineOptions, setWaylineOptions] = useState([]);
// 当前选择的设备类型
const [selectedDeviceType, setSelectedDeviceType] = useState<'robot' | 'uav' | null>(null);
// 批量多选
const [selectedRowKeys, setSelectedRowKeys] = useState<(string | number)[]>([]);
// 获取设备列表(分组显示机器人和无人机)
const fetchDeviceList = async () => {
try {
// 获取机器人列表
const robotRes = await getSiteDevice({
siteId: stationId,
pageSize: 9999,
pageNum: 1,
orgId: currentStation?.orgId
});
// 获取无人机列表
const uavRes = await getSiteUAVList(stationId);
const robotOptions = [];
if (robotRes.code === 200) {
const robots = robotRes.rows || [];
robotOptions.push({
label: t('devices.robot'),
title: t('devices.robot'),
options: robots.map((item: any) => ({
label: item.deviceAlias || item.serialNumber,
value: item.serialNumber,
type: 'robot'
}))
});
}
const uavOptions = [];
if (uavRes.code === 200) {
const uavs = uavRes.rows || [];
uavOptions.push({
label: t('constants.uav'),
title: t('constants.uav'),
options: uavs.map((item: any) => ({
label: item.drone_callsign,
value: item.device_sn,
type: 'uav'
}))
});
}
setDeviceOptions([...robotOptions, ...uavOptions]);
} catch (e) {
console.error('获取设备列表失败', e);
}
};
// 获取预设路径列表(机器人)
const fetchRouteList = async () => {
try {
const res = await getRobotRouteList({ siteId: stationId });
if (res.code === 200) {
const routes = res.data || [];
setRouteOptions(
routes.map((item: any) => ({
label: item.workName,
value: item.id
}))
);
}
} catch (e) {
console.error('获取预设路径失败', e);
}
};
// 获取无人机航线列表
const fetchWaylineList = async () => {
try {
const res = await getWayLine();
if (res.code === 0) {
const waylines = res?.data?.list || [];
setWaylineOptions(
waylines.map((item: any) => ({
label: item.name,
value: item.id
}))
);
}
} catch (e) {
console.error('获取无人机航线失败', e);
}
};
// 获取数据
const fetchList = async () => {
setLoading(true);
const data = {
siteId: stationId || '',
}
try {
const res = await getWorkOrderModelListApi(data);
if (res.code === 200) {
setList(res.rows || []);
// 刷新后清空选中
setSelectedRowKeys([]);
}
} catch (e) {
utils.message.error('获取工单模型列表失败');
setList([]);
} finally {
setLoading(false);
}
};
useEffect(() => {
if (stationId) {
fetchList();
fetchDeviceList();
fetchRouteList();
fetchWaylineList();
}
}, [stationId]);
const handleAdd = () => {
const { t } = useTranslation();
setEditingItem(null);
form.resetFields();
setSelectedDeviceType(null);
setModalVisible(true);
};
const handleEdit = (record: any) => {
setEditingItem(record);
form.setFieldsValue(record);
// 判断当前编辑的设备类型
if (record.waylineId) {
setSelectedDeviceType('uav');
} else if (record.routeId) {
setSelectedDeviceType('robot');
}
setModalVisible(true);
};
// 处理设备选择变化
const handleDeviceChange = (value, option) => {
console.log('handleDeviceChange value:', value, 'option:', option);
if (option) {
setSelectedDeviceType(option.type);
// 清空路径选择
form.setFieldValue('routeId', undefined);
form.setFieldValue('waylineId', undefined);
}
};
// 单条删除
const handleDelete = (id: string | number) => {
modal.confirm({
title: '确认删除',
content: '您确定要删除这条工单模型吗?',
okText: t('common.ok'),
cancelText: t('common.cancel'),
onOk: async () => {
try {
const res = await deleteWorkOrderModelApi([id]);
if (res.code === 200) {
message.success(t('common.deleteSuccess'));
fetchList();
}
} catch (e) {
message.error(t('common.deleteFail'));
}
}
});
};
// 批量删除
const handleBatchDelete = () => {
if (!selectedRowKeys.length) {
message.warning('请先勾选要删除的数据');
return;
}
modal.confirm({
title: '批量删除确认',
content: `您确定要删除选中的 ${selectedRowKeys.length} 条工单模型吗?删除后不可恢复!`,
okText: t('common.ok'),
cancelText: t('common.cancel'),
danger: true,
onOk: async () => {
try {
const res = await deleteWorkOrderModelApi(selectedRowKeys);
if (res.code === 200) {
message.success('批量删除成功');
fetchList();
}
} catch (e) {
message.error('批量删除失败');
}
}
});
};
const handleSave = async (values: any) => {
try {
let res;
const payload = {
...values,
siteId: stationId,
deviceId: values.deviceId,
// 根据设备类型设置对应的路径字段
routeId: selectedDeviceType === 'robot' ? values.routeId : undefined,
waylineId: selectedDeviceType === 'uav' ? values.waylineId : undefined,
orgId: currentStation?.orgId || '',
};
if (editingItem) {
res = await addWorkOrderModelApi({ ...payload, id: editingItem.id });
} else {
res = await addWorkOrderModelApi(payload);
}
if (res.code === 200 && res.data == true) {
message.success(editingItem ? '更新成功' : t('common.addSuccess'));
setModalVisible(false);
form.resetFields();
fetchList();
}
} catch (e) {
message.error(t('common.saveFail'));
}
};
// 辅助函数:获取所有设备的选项(展开分组)
const getAllDeviceOptions = () => {
const result = [];
deviceOptions.forEach((group: any) => {
if (group.options) {
group.options.forEach((opt: any) => {
result.push(opt);
});
}
});
return result;
};
const columns = [
{ title: '工单名称', dataIndex: 'orderName', key: 'orderName' },
{
title: t('workOrder.orderType'),
dataIndex: 'orderType',
key: 'orderType',
render: getWorkOrderTypeText
},
{
title: '错误等级',
dataIndex: 'errorLevel',
key: 'errorLevel',
render: (val) => {
const color = LEVEL_TAG_COLOR[val] || 'default';
const text = { 1: '轻微', 2: t('constants.general'), 3: t('constants.critical') }[val] || val;
return <Tag color={color}>{text}</Tag>;
}
},
{
title: '设备',
dataIndex: 'deviceId',
key: 'deviceId',
render: (val) => {
const allDevices = getAllDeviceOptions();
const device = allDevices.find(d => d.value === val);
return device ? device.label : val;
}
},
{
title: '路径/航线',
dataIndex: 'routeId',
key: 'routeId',
render: (val, record) => {
if (record.waylineId) {
const wayline = waylineOptions.find(w => w.value === record.waylineId);
return wayline ? wayline.label : record.waylineId;
}
const route = routeOptions.find(r => r.value === val);
return route ? route.label : val;
}
},
{
title: '自动生成任务',
dataIndex: 'autoGenerateTask',
key: 'autoGenerateTask',
render: (val: boolean) => val ? '是' : '否'
},
{
title: t('roles.actions'),
key: 'action',
render: (_: any, record: any) => (
<Space>
<Button type="link" onClick={() => handleEdit(record)}>{t('roles.edit')}</Button>
<Button type="link" danger onClick={() => handleDelete(record.id)}>{t('roles.delete')}</Button>
</Space>
)
}
];
// 表格多选配置
const rowSelection = {
selectedRowKeys,
onChange: (keys: (string | number)[]) => setSelectedRowKeys(keys),
};
return (
<div>
<Card>
<Space style={{ marginBottom: 16 }}>
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>新增工单模型</Button>
<Button icon={<ReloadOutlined />} onClick={fetchList}>{t('common.refresh')}</Button>
<Button
danger
icon={<DeleteOutlined />}
onClick={handleBatchDelete}
disabled={selectedRowKeys.length === 0}
>
批量删除{selectedRowKeys.length ? `(${selectedRowKeys.length})` : ''}
</Button>
</Space>
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={list}
rowKey="id"
loading={loading}
pagination={false}
/>
</Card>
<Modal
title={editingItem ? '编辑工单模型' : '新增工单模型'}
open={modalVisible}
onCancel={() => setModalVisible(false)}
footer={null}
width={600}
>
<Form form={form} layout="vertical" onFinish={handleSave}>
<Form.Item label="工单名称" name="orderName" rules={[{ required: true, message: '请输入工单名称' }]}>
<Input placeholder="请输入工单名称" />
</Form.Item>
<Form.Item label={t('workOrder.orderType')} name="orderType" rules={[{ required: true, message: t('workOrder.pleaseSelectType') }]}>
<Select placeholder={t('workOrder.pleaseSelectType')} options={workOrderTypeOptions} />
</Form.Item>
<Form.Item label="错误等级" name="errorLevel" rules={[{ required: true, message: '请选择错误等级' }]}>
<Select placeholder="请选择错误等级" options={errorLevelOptions} />
</Form.Item>
<Form.Item label="设备" name="deviceId" rules={[{ required: true, message: '请选择设备' }]}>
<Select
placeholder="请选择设备"
options={deviceOptions}
onChange={handleDeviceChange}
labelInValue={false}
/>
</Form.Item>
{/* 根据设备类型显示不同的路径选择 */}
{selectedDeviceType === 'robot' && (
<Form.Item label="预设路径" name="routeId" rules={[{ required: true, message: '请选择预设路径' }]}>
<Select placeholder="请选择预设路径" options={routeOptions} />
</Form.Item>
)}
{selectedDeviceType === 'uav' && (
<Form.Item label="无人机航线" name="waylineId" rules={[{ required: true, message: '请选择无人机航线' }]}>
<Select placeholder="请选择无人机航线" options={waylineOptions} />
</Form.Item>
)}
{/*<Form.Item label="自动生成任务" name="autoGenerateTask" valuePropName="checked">
<Switch />
</Form.Item>*/}
<Form.Item>
<Space>
<Button type="primary" htmlType="submit">{t('common.save')}</Button>
<Button onClick={() => setModalVisible(false)}>{t('common.cancel')}</Button>
</Space>
</Form.Item>
</Form>
</Modal>
</div>
);
};
const WorkOrderSettingsManagement: React.FC = () => {
const [activeSubTab, setActiveSubTab] = useState('model');
return (
<div style={{ padding: 0 }}>
{activeSubTab === 'model' && <WorkOrderModelManagement />}
</div>
);
};
export default WorkOrderSettingsManagement;