460 lines
12 KiB
TypeScript
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;
|