511 lines
15 KiB
TypeScript
511 lines
15 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
||
import {
|
||
Button, Table, Space,
|
||
Form, Input, Select, message, Modal, Badge,
|
||
Popconfirm, Tag, Card
|
||
} from 'antd';
|
||
import 'dayjs/locale/zh-cn';
|
||
import type { InferResponseType, InferRequestType } from 'hono/client';
|
||
// 从share/types.ts导入所有类型,包括MapMode
|
||
|
||
import {
|
||
AlertLevel, NotifyType,
|
||
AlertLevelNameMap,
|
||
NotifyTypeNameMap,
|
||
} from '@/share/monitorTypes';
|
||
|
||
import {
|
||
EnableStatus, EnableStatusNameMap,
|
||
} from '@/share/types';
|
||
|
||
import { getEnumOptions } from '../utils';
|
||
|
||
import { deviceInstancesClient, userClient, alertNotifyConfigClient } from '@/client/api';
|
||
|
||
// 定义类型
|
||
type AlertNotifyConfig = InferResponseType<typeof alertNotifyConfigClient.$get, 200>['data'][0];
|
||
type CreateAlertNotifyConfigRequest = InferRequestType<typeof alertNotifyConfigClient.$post>['json'];
|
||
type UpdateAlertNotifyConfigRequest = InferRequestType<typeof alertNotifyConfigClient[':id']['$put']>['json'];
|
||
type DeviceInstance = InferResponseType<typeof deviceInstancesClient.$get, 200>['data'][0];
|
||
type User = InferResponseType<typeof userClient.$get, 200>['data'][0];
|
||
|
||
|
||
// 告警通知配置页面
|
||
export const AlertNotifyConfigPage = () => {
|
||
const [loading, setLoading] = useState(false);
|
||
const [configData, setConfigData] = useState<AlertNotifyConfig[]>([]);
|
||
const [pagination, setPagination] = useState({
|
||
current: 1,
|
||
pageSize: 10,
|
||
total: 0,
|
||
});
|
||
const [deviceOptions, setDeviceOptions] = useState<{label: string, value: number}[]>([]);
|
||
const [userOptions, setUserOptions] = useState<{label: string, value: number}[]>([]);
|
||
const [modalVisible, setModalVisible] = useState(false);
|
||
const [modalTitle, setModalTitle] = useState('新增告警通知配置');
|
||
const [currentRecord, setCurrentRecord] = useState<AlertNotifyConfig | null>(null);
|
||
const [formRef] = Form.useForm();
|
||
const [modalForm] = Form.useForm<CreateAlertNotifyConfigRequest>();
|
||
|
||
useEffect(() => {
|
||
fetchDeviceOptions();
|
||
fetchUserOptions();
|
||
fetchConfigData();
|
||
}, [pagination.current, pagination.pageSize]);
|
||
|
||
const fetchDeviceOptions = async () => {
|
||
try {
|
||
const res = await deviceInstancesClient.$get({
|
||
query:{
|
||
pageSize: 500
|
||
}
|
||
});
|
||
if (res.status === 200) {
|
||
const data = await res.json();
|
||
const options = data.data.map((device) => ({
|
||
label: device.zichanInfo?.assetName || `设备${device.id}`,
|
||
value: device.id
|
||
}));
|
||
setDeviceOptions(options);
|
||
} else {
|
||
const data = await res.json();
|
||
throw new Error(data.message || '获取设备列表失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('获取设备列表失败:', error);
|
||
message.error(error instanceof Error ? error.message : '获取设备列表失败');
|
||
}
|
||
};
|
||
|
||
const fetchUserOptions = async () => {
|
||
try {
|
||
const res = await userClient.$get({
|
||
query: {
|
||
pageSize: 100
|
||
}
|
||
});
|
||
if (res.status === 200) {
|
||
const data = await res.json();
|
||
const options = data.data.map((user) => ({
|
||
label: user.nickname || user.username,
|
||
value: user.id
|
||
}));
|
||
setUserOptions(options);
|
||
} else {
|
||
const data = await res.json();
|
||
throw new Error(data.message || '获取用户列表失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('获取用户列表失败:', error);
|
||
message.error(error instanceof Error ? error.message : '获取用户列表失败');
|
||
}
|
||
};
|
||
|
||
const fetchConfigData = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const values = formRef.getFieldsValue();
|
||
const params = {
|
||
page: pagination.current,
|
||
pageSize: pagination.pageSize,
|
||
deviceId: values.deviceId,
|
||
alertLevel: values.alertLevel,
|
||
notifyType: values.notifyType,
|
||
isEnabled: values.isEnabled,
|
||
};
|
||
|
||
const res = await alertNotifyConfigClient.$get({
|
||
query: params
|
||
});
|
||
|
||
if (res.status === 200) {
|
||
const data = await res.json();
|
||
setConfigData(data.data || []);
|
||
setPagination({
|
||
...pagination,
|
||
total: data.pagination?.total || 0,
|
||
});
|
||
} else {
|
||
const data = await res.json();
|
||
throw new Error(data.message || '获取告警通知配置失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('获取告警通知配置失败:', error);
|
||
message.error(error instanceof Error ? error.message : '获取告警通知配置失败');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const handleSearch = (values: any) => {
|
||
setPagination({
|
||
...pagination,
|
||
current: 1,
|
||
});
|
||
fetchConfigData();
|
||
};
|
||
|
||
const handleTableChange = (newPagination: any) => {
|
||
setPagination({
|
||
...pagination,
|
||
current: newPagination.current,
|
||
pageSize: newPagination.pageSize,
|
||
});
|
||
};
|
||
|
||
const handleAdd = () => {
|
||
setModalTitle('新增告警通知配置');
|
||
setCurrentRecord(null);
|
||
modalForm.resetFields();
|
||
setModalVisible(true);
|
||
};
|
||
|
||
const handleEdit = (record: AlertNotifyConfig) => {
|
||
setModalTitle('编辑告警通知配置');
|
||
setCurrentRecord(record);
|
||
|
||
// 将用户ID列表转为数组
|
||
const formData = {
|
||
...record,
|
||
notifyUsers: record.notifyUsers || [],
|
||
deviceId: record.deviceId,
|
||
alertLevel: record.alertLevel,
|
||
notifyType: record.notifyType,
|
||
notifyTemplate: record.notifyTemplate,
|
||
isEnabled: record.isEnabled,
|
||
};
|
||
|
||
modalForm.setFieldsValue(formData);
|
||
setModalVisible(true);
|
||
};
|
||
|
||
const handleDelete = async (id: number) => {
|
||
try {
|
||
const res = await alertNotifyConfigClient[':id'].$delete({
|
||
param: { id: id }
|
||
});
|
||
|
||
if (res.status === 200) {
|
||
message.success('删除成功');
|
||
fetchConfigData();
|
||
} else {
|
||
const data = await res.json();
|
||
throw new Error(data.message || '删除失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('删除失败:', error);
|
||
message.error(error instanceof Error ? error.message : '删除失败');
|
||
}
|
||
};
|
||
|
||
const handleModalSubmit = async () => {
|
||
try {
|
||
const values = await modalForm.validateFields();
|
||
|
||
// 根据通知类型处理提交数据
|
||
const submitData = {
|
||
...values,
|
||
notifyUsers: values.notifyType === NotifyType.SMS ? [] : values.notifyUsers,
|
||
};
|
||
|
||
if (currentRecord) {
|
||
// 更新
|
||
const res = await alertNotifyConfigClient[':id'].$put({
|
||
param: { id: currentRecord.id },
|
||
json: submitData
|
||
});
|
||
|
||
if (res.status === 200) {
|
||
message.success('更新成功');
|
||
setModalVisible(false);
|
||
fetchConfigData();
|
||
} else {
|
||
const data = await res.json();
|
||
throw new Error(data.message || '更新失败');
|
||
}
|
||
} else {
|
||
// 新增
|
||
const res = await alertNotifyConfigClient.$post({
|
||
json: submitData
|
||
});
|
||
|
||
if (res.status === 200) {
|
||
message.success('添加成功');
|
||
setModalVisible(false);
|
||
fetchConfigData();
|
||
} else {
|
||
const data = await res.json();
|
||
throw new Error(data.message || '添加失败');
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('操作失败:', error);
|
||
message.error(error instanceof Error ? error.message : '操作失败');
|
||
}
|
||
};
|
||
|
||
const alertLevelOptions = getEnumOptions(AlertLevel, AlertLevelNameMap);
|
||
|
||
const notifyTypeOptions = getEnumOptions(NotifyType, NotifyTypeNameMap);
|
||
|
||
const enableStatusOptions = getEnumOptions(EnableStatus, EnableStatusNameMap);
|
||
|
||
const getAlertLevelTag = (level: AlertLevel) => {
|
||
switch (level) {
|
||
case AlertLevel.MINOR:
|
||
return <Tag color="blue">次要</Tag>;
|
||
case AlertLevel.NORMAL:
|
||
return <Tag color="green">一般</Tag>;
|
||
case AlertLevel.IMPORTANT:
|
||
return <Tag color="orange">重要</Tag>;
|
||
case AlertLevel.URGENT:
|
||
return <Tag color="red">紧急</Tag>;
|
||
default:
|
||
return <Tag>未知</Tag>;
|
||
}
|
||
};
|
||
|
||
const columns = [
|
||
{
|
||
title: '配置ID',
|
||
dataIndex: 'id',
|
||
key: 'id',
|
||
width: 80,
|
||
},
|
||
{
|
||
title: '设备',
|
||
dataIndex: 'deviceId',
|
||
key: 'deviceId',
|
||
render: (id: number) => {
|
||
const device = deviceOptions.find(opt => opt.value === id);
|
||
return device ? device.label : id;
|
||
},
|
||
},
|
||
{
|
||
title: '告警等级',
|
||
dataIndex: 'alertLevel',
|
||
key: 'alertLevel',
|
||
render: (level: AlertLevel) => getAlertLevelTag(level),
|
||
},
|
||
{
|
||
title: '通知类型',
|
||
dataIndex: 'notifyType',
|
||
key: 'notifyType',
|
||
render: (type: NotifyType) => NotifyTypeNameMap[type] || type,
|
||
},
|
||
{
|
||
title: '通知模板',
|
||
dataIndex: 'notifyTemplate',
|
||
key: 'notifyTemplate',
|
||
ellipsis: true,
|
||
},
|
||
{
|
||
title: '通知用户',
|
||
dataIndex: 'notifyUsers',
|
||
key: 'notifyUsers',
|
||
render: (users: number[]) => {
|
||
if (!users || users.length === 0) return '无';
|
||
|
||
return users.map(id => {
|
||
const user = userOptions.find(opt => opt.value === id);
|
||
return user ? user.label : id;
|
||
}).join(', ');
|
||
},
|
||
},
|
||
{
|
||
title: '状态',
|
||
dataIndex: 'isEnabled',
|
||
key: 'isEnabled',
|
||
render: (status: EnableStatus) => (
|
||
status === EnableStatus.ENABLED ?
|
||
<Badge status="success" text="启用" /> :
|
||
<Badge status="default" text="禁用" />
|
||
),
|
||
},
|
||
{
|
||
title: '操作',
|
||
key: 'action',
|
||
render: (_: any, record: AlertNotifyConfig) => (
|
||
<Space size="middle">
|
||
<Button size="small" type="primary" onClick={() => handleEdit(record)}>
|
||
编辑
|
||
</Button>
|
||
<Popconfirm
|
||
title="确定删除此配置?"
|
||
onConfirm={() => handleDelete(record.id)}
|
||
okText="确定"
|
||
cancelText="取消"
|
||
>
|
||
<Button size="small" danger>
|
||
删除
|
||
</Button>
|
||
</Popconfirm>
|
||
</Space>
|
||
),
|
||
},
|
||
];
|
||
|
||
return (
|
||
<div>
|
||
<Card title="告警通知配置" style={{ marginBottom: 16 }}>
|
||
<Form
|
||
form={formRef}
|
||
layout="inline"
|
||
onFinish={handleSearch}
|
||
style={{ marginBottom: 16 }}
|
||
>
|
||
<Form.Item name="deviceId" label="设备">
|
||
<Select
|
||
placeholder="选择设备"
|
||
style={{ width: 200 }}
|
||
allowClear
|
||
options={deviceOptions}
|
||
/>
|
||
</Form.Item>
|
||
<Form.Item name="alertLevel" label="告警等级">
|
||
<Select
|
||
placeholder="选择告警等级"
|
||
style={{ width: 120 }}
|
||
allowClear
|
||
options={alertLevelOptions}
|
||
/>
|
||
</Form.Item>
|
||
<Form.Item name="notifyType" label="通知类型">
|
||
<Select
|
||
placeholder="选择通知类型"
|
||
style={{ width: 120 }}
|
||
allowClear
|
||
options={notifyTypeOptions}
|
||
/>
|
||
</Form.Item>
|
||
<Form.Item name="isEnabled" label="状态">
|
||
<Select
|
||
placeholder="选择状态"
|
||
style={{ width: 100 }}
|
||
allowClear
|
||
options={enableStatusOptions}
|
||
/>
|
||
</Form.Item>
|
||
<Form.Item>
|
||
<Button type="primary" htmlType="submit">
|
||
查询
|
||
</Button>
|
||
</Form.Item>
|
||
<Form.Item>
|
||
<Button type="primary" onClick={handleAdd}>
|
||
新增
|
||
</Button>
|
||
</Form.Item>
|
||
</Form>
|
||
|
||
<Table
|
||
columns={columns}
|
||
dataSource={configData}
|
||
rowKey="id"
|
||
pagination={pagination}
|
||
loading={loading}
|
||
onChange={handleTableChange}
|
||
/>
|
||
</Card>
|
||
|
||
<Modal
|
||
title={modalTitle}
|
||
open={modalVisible}
|
||
onOk={handleModalSubmit}
|
||
onCancel={() => setModalVisible(false)}
|
||
width={600}
|
||
>
|
||
<Form
|
||
form={modalForm}
|
||
layout="vertical"
|
||
>
|
||
<Form.Item
|
||
name="deviceId"
|
||
label="设备"
|
||
rules={[{ required: true, message: '请选择设备' }]}
|
||
>
|
||
<Select
|
||
placeholder="选择设备"
|
||
options={deviceOptions}
|
||
/>
|
||
</Form.Item>
|
||
|
||
<Form.Item
|
||
name="alertLevel"
|
||
label="告警等级"
|
||
rules={[{ required: true, message: '请选择告警等级' }]}
|
||
>
|
||
<Select
|
||
placeholder="选择告警等级"
|
||
options={alertLevelOptions}
|
||
/>
|
||
</Form.Item>
|
||
|
||
<Form.Item
|
||
name="notifyType"
|
||
label="通知类型"
|
||
rules={[{ required: true, message: '请选择通知类型' }]}
|
||
>
|
||
<Select
|
||
placeholder="选择通知类型"
|
||
options={notifyTypeOptions}
|
||
onChange={(value) => {
|
||
if (value === NotifyType.SMS) {
|
||
modalForm.setFieldsValue({ notifyUsers: [] });
|
||
}
|
||
}}
|
||
/>
|
||
</Form.Item>
|
||
|
||
<Form.Item
|
||
name="notifyTemplate"
|
||
label="通知模板"
|
||
rules={[{ required: true, message: '请输入通知模板' }]}
|
||
>
|
||
<Input.TextArea rows={3} placeholder="输入通知模板,可使用{{变量}}格式插入动态内容" />
|
||
</Form.Item>
|
||
|
||
<Form.Item
|
||
noStyle
|
||
shouldUpdate={(prevValues, currentValues) => prevValues.notifyType !== currentValues.notifyType}
|
||
>
|
||
{({ getFieldValue }) =>
|
||
getFieldValue('notifyType') === NotifyType.SMS ? (
|
||
<Form.Item
|
||
name="phone"
|
||
label="手机号码"
|
||
rules={[{ required: true, message: '请输入手机号码' }]}
|
||
>
|
||
<Input placeholder="请输入接收短信的手机号码" />
|
||
</Form.Item>
|
||
) : (
|
||
<Form.Item
|
||
name="notifyUsers"
|
||
label="通知用户"
|
||
rules={[{ required: true, message: '请选择通知用户' }]}
|
||
>
|
||
<Select
|
||
placeholder="选择通知用户"
|
||
mode="multiple"
|
||
options={userOptions}
|
||
/>
|
||
</Form.Item>
|
||
)
|
||
}
|
||
</Form.Item>
|
||
|
||
<Form.Item
|
||
name="isEnabled"
|
||
label="状态"
|
||
initialValue={EnableStatus.ENABLED}
|
||
>
|
||
<Select
|
||
placeholder="选择状态"
|
||
options={enableStatusOptions}
|
||
/>
|
||
</Form.Item>
|
||
</Form>
|
||
</Modal>
|
||
</div>
|
||
);
|
||
}; |