Files
d8d-vite-starter/src/client/admin/pages/pages_alert_notify_config.tsx
D8D Developer b9a3c991d0 update
2025-06-27 01:56:30 +00:00

511 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
);
};