Files
web-Iot/tmpp7zw7soq.tsx

543 lines
16 KiB
TypeScript
Raw Permalink Normal View History

2026-08-12 11:29:44 +08:00
import React, { useState, useRef, useEffect } from 'react';
import {
Table,
Input,
Button,
Form,
Select,
Space,
Tag,
Modal,
Card,
Typography,
InputNumber,
Row,
Col,
App,
Divider,
} from 'antd';
import {
SearchOutlined,
ReloadOutlined,
PlusOutlined,
EditOutlined,
DeleteOutlined,
EyeOutlined,
ExclamationCircleOutlined,
} from '@ant-design/icons';
import {
getErrorListApi,
addErrorApi,
updateErrorApi,
deleteErrorApi,
getErrorDetailApi,
getErrorListAllApi
} from '@/api/systemSetting';
import utils from '@/lib/utils';
import { errorLevelOptions, errorSourceOptions, CompareEnumOptions } from '@/lib/utils';
import { useSelector } from 'react-redux';
import { RootState } from '@/src/store';
import { useTranslation } from 'react-i18next';
const { TextArea } = Input;
const { Text, Title } = Typography;
const { Option } = Select;
const AntdCard = Card as any;
export default function ErrorManagement() {
const { t } = useTranslation();
const { userInfo } = useSelector((state: RootState) => state.user);
const { stationId, currentStation } = useSelector((state: RootState) => state.station);
const { modal } = App.useApp();
const [form] = Form.useForm();
const [searchForm] = Form.useForm();
const [loading, setLoading] = useState(false);
const [errorList, setErrorList] = useState([]);
const [total, setTotal] = useState(0);
const [params, setParams] = useState({
errorCode: '',
errorName: '',
errorSource: '',
errorLevel: '',
orgId: currentStation?.orgId || '',
siteId: stationId || '',
});
const [modalVisible, setModalVisible] = useState(false);
const [modalType, setModalType] = useState<'add' | 'edit' | 'view'>('add');
const [currentRecord, setCurrentRecord] = useState<any>(null);
// 监听对比类型,判断是否是区间
const compareTypeWatch = Form.useWatch('compareType', form);
// 获取错误列表
const fetchErrorList = async () => {
setLoading(true);
try {
const requestParams = {
...params,
siteId: stationId || '',
};
const realParams = Object.fromEntries(
Object.entries(requestParams).filter(([_, val]) => val !== '')
);
const res = await getErrorListAllApi(realParams);
if (res.code === 200) {
setErrorList(res.rows || []);
setTotal(res.total || res.rows?.length || 0);
}
} catch (err) {
utils.message.error(t('systemSetting.getErrorListFailed'));
} finally {
setLoading(false);
}
};
useEffect(() => {
setParams(prev => ({
...prev,
siteId: stationId || ''
}));
}, [stationId]);
useEffect(() => {
fetchErrorList();
}, [params]);
// 打开弹窗
// 打开弹窗
const openModal = (type: 'add' | 'edit' | 'view', record?: any) => {
setModalType(type);
setCurrentRecord(record);
setModalVisible(true);
form.resetFields();
if (type === 'edit' || type === 'view') {
const fillData = { ...record };
// 区间规则拆分 compareValues 回填 min/max
const targetEnum = CompareEnumOptions.find(e => e.value === record.compareType);
if (targetEnum?.range && record.compareValues) {
const valArr = record.compareValues.split(',');
fillData.rangeMin = valArr[0];
fillData.rangeMax = valArr[1];
}
form.setFieldsValue(fillData);
}
};
// 保存错误(字段映射适配后端实体)
const handleSave = async (values: any) => {
console.log('提交表单数据', values);
//return;
// 组装后端需要的实体字段
const submitData = {
id: modalType == 'edit' ? currentRecord.id : undefined,
// 原有基础字段
errorCode: values.errorCode,
errorName: values.errorName,
errorSource: values.errorSource,
errorLevel: values.errorLevel,
errorDescription: values.errorDescription,
suggestion: values.suggestion,
// 新增校验规则字段
field: values.field,
compareType: values.compareType,
orgId: currentStation?.orgId || '',
siteId: stationId || '',
// 区间/普通值统一拼接逗号字符串传给 compareValues
compareValues: values.rangeMin && values.rangeMax
? `${values.rangeMin},${values.rangeMax}`
: values.compareValues || '',
};
console.log('提交表单数据', submitData);
try {
// 真实接口
const res = await addErrorApi(submitData);
if (res.code === 200) {
utils.message.success(modalType == 'edit' ? t('common.editSuccess') : t('common.addSuccess'));
setModalVisible(false);
fetchErrorList();
} else {
utils.message.error(res.msg || t('systemSetting.operationFailed'));
}
} catch (err) {
utils.message.error(t('systemSetting.operationFailed'));
}
};
// 删除错误
const handleDelete = (record: any) => {
modal.confirm({
title: t('common.confirmDelete'),
content: t('systemSetting.confirmDeleteError', { name: record.errorName }),
icon: <ExclamationCircleOutlined />,
okText: t('common.ok'),
cancelText: t('common.cancel'),
onOk: async () => {
try {
// 真实接口
const data = {
ids: [record.id]
}
console.log('删除请求参数', data);
const res = await deleteErrorApi(data.ids);
if (res.code == 200) {
utils.message.success(t('common.deleteSuccess'));
fetchErrorList();
} else {
utils.message.error(res.msg || t('common.deleteFail'));
}
} catch (err) {
utils.message.error(t('common.deleteFail'));
}
},
});
};
// 搜索
const handleSearch = () => {
searchForm.validateFields().then(values => {
setParams({
...params,
...values,
});
});
};
// 重置
const handleReset = () => {
searchForm.resetFields();
setParams({
errorCode: '',
errorName: '',
errorSource: '',
errorLevel: '',
});
};
// 标签颜色方法(原有不变)
const getTypeColor = (type: string) => {
const colorMap: Record<string, string> = {
ROBOT: 'blue',
DEVICE: 'green',
SYSTEM: 'purple',
COMMUNICATION: 'orange',
SENSOR: 'cyan',
OTHER: 'default',
};
return colorMap[type] || 'default';
};
const getSeverityColor = (severity: string) => {
const colorMap: Record<string, string> = {
MINOR: 'default',
NORMAL: 'blue',
SERIOUS: 'orange',
CRITICAL: 'red',
};
return colorMap[severity] || 'default';
};
const getStatusColor = (status: string) => {
const colorMap: Record<string, string> = {
PENDING: 'orange',
PROCESSING: 'blue',
RESOLVED: 'green',
IGNORED: 'default',
};
return colorMap[status] || 'default';
};
// 表格列(完全不变)
const columns = [
{
title: t('systemSetting.errorCode'),
dataIndex: 'errorCode',
key: 'errorCode',
width: 150,
fixed: 'left' as const,
},
{
title: t('systemSetting.errorName'),
dataIndex: 'errorName',
key: 'errorName',
width: 200,
},
{
title: t('systemSetting.errorSourceLabel'),
dataIndex: 'errorSource',
key: 'errorSource',
width: 120,
render: (text: string) => {
const typeObj = errorSourceOptions.find(t => t.value === text);
return <Tag color={getTypeColor(text)}>{typeObj?.label || text}</Tag>;
},
},
{
title: t('systemSetting.errorLevelLabel'),
dataIndex: 'errorLevel',
key: 'errorLevel',
width: 100,
render: (text: string) => {
const severityObj = errorLevelOptions.find(t => t.value === text);
return <Tag color={getSeverityColor(text)}>{severityObj?.label || text}</Tag>;
},
},
{
title: t('systemSetting.checkField'),
dataIndex: 'field',
key: 'field',
width: 130,
},
{
title: t('systemSetting.compareRule'),
dataIndex: 'compareType',
key: 'compareType',
width: 140,
render: (val) => {
const item = CompareEnumOptions.find(o => o.value === val);
return item?.label || val;
},
},
{
title: t('systemSetting.compareValueCol'),
dataIndex: 'compareValues',
key: 'compareValues',
width: 140,
},
{
title: t('common.description'),
dataIndex: 'errorDescription',
key: 'errorDescription',
ellipsis: true,
},
{
title: t('aiAnalysis.suggestion'),
dataIndex: 'suggestion',
key: 'suggestion',
width: 180,
},
{
title: t('roles.actions'),
key: 'action',
width: 300,
fixed: 'right' as const,
render: (_: any, record: any) => (
<Space>
<Button
type="link"
size="small"
icon={<EyeOutlined />}
onClick={() => openModal('view', record)}
>{t('common.view')}</Button>
<Button
type="link"
size="small"
icon={<EditOutlined />}
onClick={() => openModal('edit', record)}
>{t('common.edit')}</Button>
<Button
type="link"
size="small"
danger
icon={<DeleteOutlined />}
onClick={() => handleDelete(record)}
>{t('common.delete')}</Button>
</Space>
),
},
];
return (
<div style={{ padding: '0px 0px', background: '#f5f7fa', minHeight: 'calc(100vh - 120px)' }}>
<AntdCard style={{ borderRadius: 8 }}>
{/* 搜索区域完全不变 */}
<Form form={searchForm} layout="inline" style={{ marginBottom: 0 }}>
<Form.Item name="errorCode" label={t("systemSetting.errorCode")}>
<Input placeholder={t("systemSetting.pleaseInputErrorCode")} style={{ width: 150 }} allowClear />
</Form.Item>
<Form.Item name="errorName" label={t("systemSetting.errorName")}>
<Input placeholder={t("systemSetting.pleaseInputErrorName")} style={{ width: 150 }} allowClear />
</Form.Item>
<Form.Item name="errorSource" label={t("systemSetting.errorSourceLabel")}>
<Select placeholder={t("systemSetting.pleaseSelectSource")} style={{ width: 120 }} allowClear >
{errorSourceOptions.map(option => (
<Option key={option.value} value={option.value}>{option.label}</Option>
))}
</Select>
</Form.Item>
<Form.Item name="errorLevel" label={t("systemSetting.errorLevelLabel")}>
<Select placeholder={t("systemSetting.pleaseSelectLevel")} style={{ width: 120 }} allowClear >
{errorLevelOptions.map(option => (
<Option key={option.value} value={option.value}>{option.label}</Option>
))}
</Select>
</Form.Item>
<Form.Item>
<Space>
<Button type="primary" icon={<SearchOutlined />} onClick={handleSearch}>{t('common.search2')}</Button>
<Button icon={<ReloadOutlined />} onClick={handleReset}>{t('common.reset')}</Button>
<Button type="primary" icon={<PlusOutlined />} onClick={() => openModal('add')}>{t('common.addNew')}</Button>
</Space>
</Form.Item>
</Form>
<Table
rowKey="id"
columns={columns}
dataSource={errorList}
loading={loading}
scroll={{ x: 1600, y: 1200 }}
pagination={{
current: params.pageNum,
pageSize: params.pageSize,
total: total,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `${t('common.total')} ${total} ${t('common.items')}`,
onChange: (page, pageSize) => {
setParams({ ...params, pageNum: page, pageSize });
},
}}
/>
</AntdCard>
{/* 新增/编辑/查看弹窗(核心优化区域) */}
<Modal
title={
modalType === 'add'
? t('systemSetting.addErrorRule')
: modalType === 'edit'
? t('systemSetting.editErrorRule')
: t('systemSetting.viewErrorRuleDetail')
}
open={modalVisible}
onCancel={() => {
setModalVisible(false);
form.resetFields();
}}
width={780}
footer={
modalType === 'view'
? [
<Button key="close" onClick={() => setModalVisible(false)}>{t('common.close')}</Button>
]
: [
<div style={{ margin: '8px 0 24px 0' }}></div>,
<Button key="cancel" onClick={() => {
setModalVisible(false);
form.resetFields();
}}>{t('common.cancel')}</Button>,
<Button key="submit" type="primary" onClick={() => form.submit()}>{t('common.save')}</Button>
]
}
>
<Divider style={{ margin: '8px 0 16px 0' }} />
<Form
form={form}
layout="vertical"
onFinish={handleSave}
disabled={modalType === 'view'}
>
{/* 第一行:基础编码名称 */}
<Row gutter={16}>
<Col span={12}>
<Form.Item label={t("systemSetting.errorCode")} name="errorCode" rules={[{ required: true, message: t("systemSetting.pleaseInputErrorCode") }]}>
<Input placeholder={t("systemSetting.errorCodePlaceholder")} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label={t("systemSetting.errorName")} name="errorName" rules={[{ required: true, message: t("systemSetting.pleaseInputErrorName") }]}>
<Input placeholder={t("systemSetting.pleaseInputErrorName")} />
</Form.Item>
</Col>
</Row>
{/* 第二行:来源、等级、校验字段 */}
<Row gutter={16}>
<Col span={8}>
<Form.Item label={t("systemSetting.errorSourceLabel")} name="errorSource" rules={[{ required: true, message: t("systemSetting.pleaseSelectErrorSource") }]}>
<Select placeholder={t('common.pleaseSelect')}>
{errorSourceOptions.map(option => (
<Option key={option.value} value={option.value}>{option.label}</Option>
))}
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label={t("systemSetting.errorLevelLabel")} name="errorLevel" rules={[{ required: true, message: t("systemSetting.pleaseSelectErrorLevel") }]}>
<Select placeholder={t('common.pleaseSelect')}>
{errorLevelOptions.map(option => (
<Option key={option.value} value={option.value}>{option.label}</Option>
))}
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label={t("systemSetting.checkField")} name="field" rules={[{ required: true, message: t("systemSetting.pleaseInputCheckField") }]}>
<Input placeholder={t("systemSetting.checkFieldPlaceholder")} />
</Form.Item>
</Col>
</Row>
{/* 第三行:对比类型 + 对比值(自动切换单输入/区间双输入) */}
<Row gutter={16}>
<Col span={8}>
<Form.Item label={t("systemSetting.compareRule")} name="compareType" rules={[{ required: true, message: t("systemSetting.pleaseSelectCompareRule") }]}>
<Select placeholder={t("systemSetting.pleaseSelectCompareRule")}>
{CompareEnumOptions.map(item => (
<Option key={item.value} value={item.value}>{item.label} ({item.symbol})</Option>
))}
</Select>
</Form.Item>
</Col>
{/* 区间类型:BETWEEN / NOT_BETWEEN 显示两个输入框 */}
{CompareEnumOptions.find(o => o.value === compareTypeWatch)?.range ? (
<>
<Col span={8}>
<Form.Item label={t("systemSetting.rangeMin")} name="rangeMin" rules={[{ required: true, message: t("systemSetting.pleaseInputMinValue") }]}>
<InputNumber style={{ width: '100%' }} placeholder={t("systemSetting.minValuePlaceholder")} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label={t("systemSetting.rangeMax")} name="rangeMax" rules={[{ required: true, message: t("systemSetting.pleaseInputMaxValue") }]}>
<InputNumber style={{ width: '100%' }} placeholder={t("systemSetting.maxValuePlaceholder")} />
</Form.Item>
</Col>
</>
) : (
<Col span={16}>
<Form.Item label={t("systemSetting.compareValueLabel")} name="compareValues" rules={[{ required: true, message: t("systemSetting.pleaseInputCompareValue") }]}>
<Input placeholder={t("systemSetting.compareValuePlaceholder")} />
</Form.Item>
</Col>
)}
</Row>
{/* 错误描述 */}
<Form.Item label={t("systemSetting.errorDesc")} name="errorDescription">
<TextArea rows={3} placeholder={t("systemSetting.errorDescPlaceholder")} showCount maxLength={500} />
</Form.Item>
{/* 处理建议 */}
<Form.Item label={t('aiAnalysis.suggestion')} name="suggestion">
<TextArea rows={3} placeholder={t("systemSetting.suggestionPlaceholder")} showCount maxLength={500} />
</Form.Item>
</Form>
</Modal>
</div>
);
}