通知策略和告警联系人

main
zjlnb666 1 month ago
parent 0e0d128bb5
commit 46e5c81d84

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

@ -1,7 +1,339 @@
import {Button, Card, Col, DatePicker, Form, Input, Row, Select, Space} from "antd";
import styles from "./HistoryAlarms.less";
import Title from "@/pages/homepage/compontent/title";
import {SearchOutlined} from "@ant-design/icons";
import TableWithPagination from "@/components/assetmangement/table";
import React, {useState} from "react";
const { Option } = Select;
const { RangePicker } = DatePicker;
const columns = [
{
title: '序号',
dataIndex: 'serialNumber',
key: 'serialNumber',
},
{
title: '告警级别',
dataIndex: 'alarmLevel',
key: 'alarmLevel',
render: (text) => {
const colorMap = {
'紧急': '#ff4d4f',
'严重': '#fa8c16',
'警告': '#faad14',
'提示': '#52c41a'
};
return <span style={{ color: colorMap[text] || '#000' }}>{text}</span>;
}
},
{
title: '设备名称',
dataIndex: 'deviceName',
key: 'deviceName',
},
{
title: '设备类型',
dataIndex: 'deviceType',
key: 'deviceType',
},
{
title: '告警类别',
dataIndex: 'alarmType',
key: 'alarmType',
},
{
title: '规划时间',
dataIndex: 'planTime',
key: 'planTime',
},
{
title: '处理时间',
dataIndex: 'handleTime',
key: 'handleTime',
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
render: (text) => {
const statusColor = {
'未处理': '#FFBC00',
'已处理': '#2C9E9D',
'已忽略': '#666666'
};
return <span style={{ color: statusColor[text] || '#000' }}>{text}</span>;
}
},
{
title: '处理人',
dataIndex: 'handler',
key: 'handler',
},
{
title: '操作',
key: 'operations',
render: (_, record) => {
if(record.status === '已处理'){
return (
<div>
<Button type={"link"} style={{color:'#2C9E9D'}}>处理</Button>
<Button type={"link"} style={{color:'#2C9E9D'}}>详情</Button>
<Button type={"link"} style={{color:'#006665'}}>追溯</Button>
</div>
)
}else if(record.status === '未处理'){
return (
<div>
<Button type={"link"} style={{color: '#2C9E9D'}}>处理</Button>
<Button type={"link"} style={{color: '#006665'}}>确认</Button>
<Button type={"link"} style={{color: '#999999'}}>忽略</Button>
</div>
)
}else if(record.status === '已忽略'){
return (
<div>
<Button type={"link"} style={{color:'#2C9E9D'}}>详情</Button>
<Button type={"link"} style={{color:'#FF826D'}}>取消忽略</Button>
</div>
)
}
},
},
]
const mockData = [
{
key: '1',
serialNumber: 'ALM-1001',
alarmLevel: '紧急',
deviceName: '核心服务器 A',
deviceType: '服务器',
alarmType: 'CPU 使用率>96%',
planTime: '2025-10-30',
handleTime: '2025-10-25',
status: '已处理',
handler: '政府',
},
{
key: '2',
serialNumber: 'ALM-1002',
alarmLevel: '严重',
deviceName: '工业网关 B',
deviceType: '网关',
alarmType: '系统配置 > 分钟',
planTime: '2025-10-30',
handleTime: '2025-10-24',
status: '已处理',
handler: '马明',
},
{
key: '3',
serialNumber: 'ALM-1003',
alarmLevel: '警告',
deviceName: '温度传感器 G',
deviceType: '传感器',
alarmType: '温度>40℃',
planTime: '2025-10-30',
handleTime: '--',
status: '未处理',
handler: '--',
},
{
key: '4',
serialNumber: 'ALM-1004',
alarmLevel: '提示',
deviceName: '温控器输入 D',
deviceType: '摄像头',
alarmType: '温度报警/远程控制',
planTime: '2025-10-30',
handleTime: '2025-10-22',
status: '已忽略',
handler: '赵小强',
},
{
key: '5',
serialNumber: 'ALM-1005',
alarmLevel: '紧急',
deviceName: '存储节点 E',
deviceType: '服务器',
alarmType: '温度报警/报警>90%',
planTime: '2025-10-30',
handleTime: '2025-10-21',
status: '已处理',
handler: '冯玉洁',
},
{
key: '6',
serialNumber: 'ALM-1006',
alarmLevel: '严重',
deviceName: '边缘网关 F',
deviceType: '网关',
alarmType: '网络安全等级>20%',
planTime: '2025-10-30',
handleTime: '2025-10-20',
status: '已处理',
handler: '王文忠',
},
{
key: '7',
serialNumber: 'ALM-1007',
alarmLevel: '警告',
deviceName: '温度传感器 G',
deviceType: '传感器',
alarmType: '温度>60%',
planTime: '2025-10-30',
handleTime: '--',
status: '未处理',
handler: '--',
},
];
const HistoryAlarmsData = ()=>{
const [form] = Form.useForm();
const [dataSource, setDataSource] = useState(mockData);
const [selectedRows, setSelectedRows] = useState([]);
const [paginationProps, setPaginationProps] = useState({
total: mockData.length,
defaultPageSize: 10,
pageSizeOptions: ['10', '20', '50', '100']
});
// 定义fetchData函数方便后续对接接口
const fetchData = async (page, pageSize) => {
try {
// 这里可以替换为实际的API调用
// const response = await api.getServiceTickets({ page, pageSize, ...searchParams });
// return response.data;
// 模拟API调用
const startIndex = (page - 1) * pageSize;
const endIndex = startIndex + pageSize;
return mockData.slice(startIndex, endIndex);
} catch (error) {
console.error('获取工单列表失败:', error);
return [];
}
};
// 处理行选择
const handleRowSelection = (selectedRowKeys, selectedRows) => {
setSelectedRows(selectedRows);
};
// 搜索
const handleSearch = (values) => {
console.log('搜索条件:', values);
// 这里可以添加实际的搜索逻辑
};
// 重置
const handleReset = () => {
form.resetFields();
};
// 新增工单
const handleAdd = () => {
console.log('新增工单');
// 这里可以添加实际的新增工单逻辑
};
// 导入工单
const handleImport = () => {
console.log('导入工单');
// 这里可以添加实际的导入工单逻辑
};
// 导出工单
const handleExport = () => {
console.log('导出工单');
// 这里可以添加实际的导出工单逻辑
};
// 打印工单
const handlePrint = () => {
console.log('打印工单');
// 这里可以添加实际的打印工单逻辑
};
// 删除工单
const handleDelete = () => {
console.log('删除工单');
// 这里可以添加实际的删除工单逻辑
};
return (
<div>
历史告警
<div style={{padding: 20,}}>
{/* 查询条件区域 */}
<Card className={styles.card} bordered={false} bodyStyle={{paddingTop: 20}}>
<Row>
<Col span={12}>
<Title title="查询条件" className={styles.title}/>
</Col>
<Col span={12} style={{textAlign: 'right'}}>
<Space>
<Button icon={<SearchOutlined/>} htmlType="submit"
className={styles['search-button']}>查询</Button>
<Button onClick={handleReset} className={styles['reset-button']}>重置</Button>
</Space>
</Col>
</Row>
<Form form={form} layout="inline" onFinish={handleSearch}>
<Form.Item name="applicant" label="申请人">
<Input placeholder="设备名称、分组ID"/>
</Form.Item>
<Form.Item name="type" label="告警级别">
<Select placeholder="全部" style={{width: 132}}>
<Option value="设备维修">设备维修</Option>
<Option value="设备安装">设备安装</Option>
<Option value="设备巡检">设备巡检</Option>
<Option value="设备更换">设备更换</Option>
</Select>
</Form.Item>
<Form.Item name="status" label="设备类型">
<Select placeholder="请选择状态" style={{width: 132}}>
<Option value="待处理">待处理</Option>
<Option value="处理中">处理中</Option>
<Option value="已完成">已完成</Option>
<Option value="已取消">已取消</Option>
</Select>
</Form.Item>
<Form.Item name="applyTime" label="时间范围">
<RangePicker style={{width: 240}}/>
</Form.Item>
</Form>
</Card>
{/* 工单列表区域 */}
<Card className={styles.card} bordered={false} bodyStyle={{paddingTop: 0}}>
<Title title="工单列表" className={styles.title}/>
<div className={styles.toolbar}>
<div className={styles['button-group']}>
<Space size={'large'}>
<Button onClick={handleImport} className={styles['search-button']}>
批量确认
</Button>
<Button onClick={handleExport} className={styles['reset-button']}>
批量忽略
</Button>
<Button onClick={handleDelete} className={styles['del-button']}>
导出告警
</Button>
</Space>
</div>
</div>
<TableWithPagination
columns={columns}
dataSource={dataSource}
fetchData={fetchData}
paginationProps={paginationProps}
rowSelection={true}
tableStyle={{marginTop: 16}}
rowKey="id"
isPagination={true}
/>
</Card>
</div>
)
}

@ -0,0 +1,48 @@
.search-button{
background-image: url('../../assets/img/assetmangement1.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: #fff;
border-radius: 4px;
height: 36px;
border-color:#d9d9d9 ;
}
.reset-button{
background-image: url('../../assets/img/assetmangement2.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: rgba(0, 102, 101, 1);
border-radius: 4px;
height: 36px;
border-color:#d9d9d9 ;
}
.del-button{
background-image: url('../../assets/img/assetmangement3.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: #000;
border-radius: 4px;
height: 36px;
width:88px;
border-color:#d9d9d9 ;
background-color: #E5B7B733;
}
.card {
margin-bottom: 16px;
background-color: #fff;
// box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
border-radius: 8px;
}
.title {
margin-bottom: 20px;
}
.toolbar {
margin-bottom: 16px;
display: flex;
align-items: center;
justify-content: space-between;
}

@ -1,7 +1,330 @@
const ImplementWarnings = ()=>{
import {Button, Card, Col, DatePicker, Form, Input, Row, Select, Space} from "antd";
import styles from './ImplementWarnings.less';
import Title from "@/pages/homepage/compontent/title";
import {PlusOutlined, SearchOutlined} from "@ant-design/icons";
import React, {useState} from "react";
import TableWithPagination from "@/components/assetmangement/table";
const { Option } = Select;
const { RangePicker } = DatePicker;
// 模拟数据
const mockData = [
{
key: '1',
alarmId: 'ALM-001',
alarmLevel: '紧急',
deviceName: '核心服务器 A',
deviceType: '服务器',
alarmType: 'CPU 使用率>96%',
triggerTime: '2025-10-30',
status: '未处理',
operations: ['处理', '确认']
},
{
key: '2',
alarmId: 'ALM-002',
alarmLevel: '严重',
deviceName: '工业网关 B',
deviceType: '网关',
alarmType: '离线超过 5 分钟',
triggerTime: '2025-10-30',
status: '未处理',
operations: ['处理', '确认']
},
{
key: '3',
alarmId: 'ALM-003',
alarmLevel: '警告',
deviceName: '遥感传感器 C',
deviceType: '传感器',
alarmType: '遥测>40℃',
triggerTime: '2025-10-30',
status: '已确认',
operations: ['处理', '详情']
},
{
key: '4',
alarmId: 'ALM-004',
alarmLevel: '提示',
deviceName: '园区摄像头 D',
deviceType: '摄像头',
alarmType: '画面模糊(AI识别)',
triggerTime: '2025-10-30',
status: '已忽略',
operations: ['详情', '取消忽略']
},
{
key: '5',
alarmId: 'ALM-005',
alarmLevel: '紧急',
deviceName: '存储节点 E',
deviceType: '服务器',
alarmType: '磁盘使用率>90%',
triggerTime: '2025-10-30',
status: '未处理',
operations: ['处理', '确认']
},
{
key: '6',
alarmId: 'ALM-006',
alarmLevel: '严重',
deviceName: '边缘网关 F',
deviceType: '网关',
alarmType: '网络丢包率>30%',
triggerTime: '2025-10-30',
status: '未处理',
operations: ['处理', '确认']
},
{
key: '7',
alarmId: 'ALM-007',
alarmLevel: '警告',
deviceName: '遥感传感器 G',
deviceType: '传感器',
alarmType: '遥测>80%',
triggerTime: '2025-10-30',
status: '未处理',
operations: ['处理', '确认']
},
];
// 表格列配置
const columns = [
{
title: '告警 ID',
dataIndex: 'alarmId',
key: 'alarmId',
width: 100,
},
{
title: '告警级别',
dataIndex: 'alarmLevel',
key: 'alarmLevel',
width: 100,
render: (text) => {
const colorMap = {
'紧急': '#ff4d4f',
'严重': '#fa8c16',
'警告': '#faad14',
'提示': '#52c41a'
};
return <span style={{ color: colorMap[text] || '#000' }}>{text}</span>;
}
},
{
title: '设备名称',
dataIndex: 'deviceName',
key: 'deviceName',
width: 120,
},
{
title: '设备类型',
dataIndex: 'deviceType',
key: 'deviceType',
width: 100,
},
{
title: '告警类型',
dataIndex: 'alarmType',
key: 'alarmType',
width: 150,
},
{
title: '触发时间',
dataIndex: 'triggerTime',
key: 'triggerTime',
width: 120,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
render: (text) => {
const statusColor = {
'未处理': '#FFBC00',
'已确认': '#2C9E9D',
'已忽略': '#666666'
};
return <span style={{ color: statusColor[text] || '#000' }}>{text}</span>;
}
},
{
title: '操作',
key: 'operations',
width: 200,
align: 'center',
render: (_, record) => {
if(record.status === '已确认'){
return (
<div>
<Button type={"link"} style={{color:'#2C9E9D'}}>处理</Button>
<Button type={"link"} style={{color:'#2C9E9D'}}>详情</Button>
<Button type={"link"} style={{color:'#006665'}}>追溯</Button>
</div>
)
}else if(record.status === '未处理'){
return (
<div>
<Button type={"link"} style={{color: '#2C9E9D'}}>处理</Button>
<Button type={"link"} style={{color: '#006665'}}>确认</Button>
<Button type={"link"} style={{color: '#999999'}}>忽略</Button>
</div>
)
}else if(record.status === '已忽略'){
return (
<div>
<Button type={"link"} style={{color:'#2C9E9D'}}>详情</Button>
<Button type={"link"} style={{color:'#FF826D'}}>取消忽略</Button>
</div>
)
}
},
},
];
const ImplementWarnings = () => {
const [form] = Form.useForm();
const [dataSource, setDataSource] = useState(mockData);
const [selectedRows, setSelectedRows] = useState([]);
const [paginationProps, setPaginationProps] = useState({
total: mockData.length,
defaultPageSize: 10,
pageSizeOptions: ['10', '20', '50', '100']
});
// 定义fetchData函数方便后续对接接口
const fetchData = async (page, pageSize) => {
try {
// 这里可以替换为实际的API调用
// const response = await api.getServiceTickets({ page, pageSize, ...searchParams });
// return response.data;
// 模拟API调用
const startIndex = (page - 1) * pageSize;
const endIndex = startIndex + pageSize;
return mockData.slice(startIndex, endIndex);
} catch (error) {
console.error('获取工单列表失败:', error);
return [];
}
};
// 处理行选择
const handleRowSelection = (selectedRowKeys, selectedRows) => {
setSelectedRows(selectedRows);
};
// 搜索
const handleSearch = (values) => {
console.log('搜索条件:', values);
// 这里可以添加实际的搜索逻辑
};
// 重置
const handleReset = () => {
form.resetFields();
};
// 新增工单
const handleAdd = () => {
console.log('新增工单');
// 这里可以添加实际的新增工单逻辑
};
// 导入工单
const handleImport = () => {
console.log('导入工单');
// 这里可以添加实际的导入工单逻辑
};
// 导出工单
const handleExport = () => {
console.log('导出工单');
// 这里可以添加实际的导出工单逻辑
};
// 打印工单
const handlePrint = () => {
console.log('打印工单');
// 这里可以添加实际的打印工单逻辑
};
// 删除工单
const handleDelete = () => {
console.log('删除工单');
// 这里可以添加实际的删除工单逻辑
};
return (
<div>
实时告警
<div style={{padding:20,}}>
{/* 查询条件区域 */}
<Card className={styles.card} bordered={false} bodyStyle={{ paddingTop: 20 }}>
<Row >
<Col span={12}>
<Title title="查询条件" className={styles.title} />
</Col>
<Col span={12} style={{ textAlign: 'right' }}>
<Space>
<Button icon={<SearchOutlined />} htmlType="submit" className={styles['search-button']}>查询</Button>
<Button onClick={handleReset} className={styles['reset-button']}>重置</Button>
</Space>
</Col>
</Row>
<Form form={form} layout="inline" onFinish={handleSearch}>
<Form.Item name="applicant" label="申请人">
<Input placeholder="设备名称、告警ID" />
</Form.Item>
<Form.Item name="type" label="告警级别">
<Select placeholder="全部" style={{width:132}}>
<Option value="设备维修">设备维修</Option>
<Option value="设备安装">设备安装</Option>
<Option value="设备巡检">设备巡检</Option>
<Option value="设备更换">设备更换</Option>
</Select>
</Form.Item>
<Form.Item name="status" label="设备类型">
<Select placeholder="请选择状态" style={{width:132}}>
<Option value="待处理">待处理</Option>
<Option value="处理中">处理中</Option>
<Option value="已完成">已完成</Option>
<Option value="已取消">已取消</Option>
</Select>
</Form.Item>
<Form.Item name="applyTime" label="时间范围">
<RangePicker style={{ width: 240 }} />
</Form.Item>
</Form>
</Card>
{/* 工单列表区域 */}
<Card className={styles.card} bordered={false} bodyStyle={{ paddingTop: 0 }}>
<Title title="工单列表" className={styles.title} />
<div className={styles.toolbar}>
<div className={styles['button-group']}>
<Space size={'large'}>
<Button onClick={handleImport} className={styles['search-button']}>
批量确认
</Button>
<Button onClick={handleExport} className={styles['reset-button']}>
批量忽略
</Button>
<Button onClick={handleDelete} className={styles['del-button']}>
导出告警
</Button>
</Space>
</div>
</div>
<TableWithPagination
columns={columns}
dataSource={dataSource}
fetchData={fetchData}
paginationProps={paginationProps}
rowSelection={true }
tableStyle={{ marginTop: 16 }}
rowKey="id"
isPagination={true}
/>
</Card>
</div>
)
}

@ -0,0 +1,48 @@
.search-button{
background-image: url('../../assets/img/assetmangement1.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: #fff;
border-radius: 4px;
height: 36px;
border-color:#d9d9d9 ;
}
.reset-button{
background-image: url('../../assets/img/assetmangement2.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: rgba(0, 102, 101, 1);
border-radius: 4px;
height: 36px;
border-color:#d9d9d9 ;
}
.del-button{
background-image: url('../../assets/img/assetmangement3.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: #000;
border-radius: 4px;
height: 36px;
width:88px;
border-color:#d9d9d9 ;
background-color: #E5B7B733;
}
.card {
margin-bottom: 16px;
background-color: #fff;
// box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
border-radius: 8px;
}
.title {
margin-bottom: 20px;
}
.toolbar {
margin-bottom: 16px;
display: flex;
align-items: center;
justify-content: space-between;
}

@ -1,7 +1,37 @@
import React, { useMemo, useState } from 'react';
import { Button, Checkbox, Divider, Tabs } from 'antd';
import styles from './Policy.less'
import ListOfStrategies from "@/pages/alarmcenter_policy/component/listOfStrategies/ListOfStrategies";
const items =[
{
label: `策略列表`,
key: '策略列表',
children: <ListOfStrategies/>,
},
{
label: `场景化配置`,
key: '场景化配置',
children: `Content of tab 2`,
},
{
label: `联系人分组管理`,
key: '联系人分组管理',
children: `Content of tab 3`,
},
{
label: `模板管理`,
key: '模板管理',
children: `Content of tab 4`,
},
]
const Policy = ()=>{
const [activeKey, setActiveKey] = useState('策略列表');
return (
<div>
通知策略和告警联系人
<div style={{borderTopLeftRadius:16}}>
<Tabs className={styles['tabs']} tabBarExtraContent={{left: <div className={styles['title']}><span>{activeKey}</span></div>}} items={items}
onChange={(key) => setActiveKey(key)} />
</div>
)
}

@ -0,0 +1,58 @@
.title{
position: relative;
font-size: 20px;
font-weight: 400;
color: #fff;
border-top-left-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
height: 54px;
width: 298px;
z-index: 2;
background-color: #ffffff4d;
background-image: url("@/assets/img/titleBg.png");
background-position: -57px -6px;
span{
margin-left: -30px;
}
}
.tabs{
:global(.ant-tabs-nav){
border: 1px solid;
border-image-source: linear-gradient(96.54deg, #FFFFFF -0.94%, rgba(255, 255, 255, 0) 25.28%, rgba(167, 229, 228, 0) 59.69%, #A7E5E4 79.76%);
border-image-slice: 1;
backdrop-filter: blur(3.4000000953674316px);
box-shadow: 1px 2px 5px 0px #00666540;
}
:global(.ant-tabs-nav-list){
align-items: center;
}
:global(.ant-tabs-tab){
color:#006665;
padding: 0;
background: #38939233;
border: 1px solid;
border-image-source: linear-gradient(97.32deg, #FFFFFF 11.3%, rgba(255, 255, 255, 0) 32.07%, rgba(0, 143, 142, 0) 72.22%, #0E5A4B 85.54%);
border-image-slice: 1;
height:36px;
transform:skew(-45deg);
margin-left: 20px;
&:hover{
color:#006665;
}
}
:global(.ant-tabs-tab-btn){
color:#006665 !important;
padding: 0 20px;
transform:skew(45deg);
}
:global(.ant-tabs-ink-bar){
display: none;
}
}

@ -0,0 +1,230 @@
import Title from "@/pages/homepage/compontent/title";
import {Button, Col, Row, Space, Switch, Tag} from "antd";
import styles from './ListOfStrategies.less'
import {EditOutlined, FileTextOutlined, PlusOutlined, StopOutlined} from "@ant-design/icons";
import TableWithPagination from "@/components/assetmangement/table";
const ListOfStrategies = ()=>{
const dataSource = [
{
key: '1',
strategyId: 'STR-001',
strategyName: '设备故障紧急通知',
scenario: '设备故障场景',
contactGroup: '运维组(系统失效)',
notificationMethod: '短信 + APP 推送',
status: '启用',
},
{
key: '2',
strategyId: 'STR-002',
strategyName: '系统性能异常通知',
scenario: '系统性能场景',
contactGroup: '系统管理员组',
notificationMethod: '邮件(每 30 分钟重复)',
status: '启用',
},
{
key: '3',
strategyId: 'STR-003',
strategyName: '安全漏洞报警通知',
scenario: '安全漏洞场景',
contactGroup: '研发组 + 运维组',
notificationMethod: '短信 + 邮件 + 电话',
status: '启用',
},
{
key: '4',
strategyId: 'STR-004',
strategyName: '设备监控异常通知',
scenario: '设备监控场景',
contactGroup: '运维组(中优先级)',
notificationMethod: 'APP 推送',
status: '启用',
},
{
key: '5',
strategyId: 'STR-005',
strategyName: '环境监测异常通知',
scenario: '环境监测场景',
contactGroup: '运维组(低优先级)',
notificationMethod: '邮件',
status: '启用',
},
{
key: '6',
strategyId: 'STR-006',
strategyName: '月度监控总站通知',
scenario: '周期性场景',
contactGroup: '管理层组',
notificationMethod: '邮件(空对发送)',
status: '启用',
},
{
key: '7',
strategyId: 'STR-007',
strategyName: '紧急安全事件通知',
scenario: '重大安全场景',
contactGroup: '高管组 + 技术专家组',
notificationMethod: '电话 + 短信 + APP 推送',
status: '启用',
},
];
const columns = [
{
title: '策略 ID',
dataIndex: 'strategyId',
key: 'strategyId',
width: 120,
fixed: 'left',
sorter: (a, b) => a.strategyId.localeCompare(b.strategyId),
},
{
title: '策略名称',
dataIndex: 'strategyName',
key: 'strategyName',
width: 180,
ellipsis: true,
},
{
title: '适用场景',
dataIndex: 'scenario',
key: 'scenario',
width: 150,
filters: [
{ text: '设备故障场景', value: '设备故障场景' },
{ text: '系统性能场景', value: '系统性能场景' },
{ text: '安全漏洞场景', value: '安全漏洞场景' },
{ text: '设备监控场景', value: '设备监控场景' },
{ text: '环境监测场景', value: '环境监测场景' },
{ text: '周期性场景', value: '周期性场景' },
{ text: '重大安全场景', value: '重大安全场景' },
],
onFilter: (value, record) => record.scenario === value,
},
{
title: '联系人组',
dataIndex: 'contactGroup',
key: 'contactGroup',
width: 200,
ellipsis: true,
render: (text) => {
const groups = text.split(' + ');
return groups.map((group, index) => (
<Tag key={index} color="blue" style={{ margin: '2px' }}>
{group}
</Tag>
));
},
},
{
title: '通知方式组合',
dataIndex: 'notificationMethod',
key: 'notificationMethod',
width: 200,
render: (text) => {
const methods = text.split(' + ');
const colors = {
'短信': 'green',
'邮件': 'orange',
'电话': 'red',
'APP 推送': 'purple',
};
return methods.map((method, index) => {
let methodText = method;
let color = 'default';
// 提取基础方法名称
for (const key in colors) {
if (method.includes(key)) {
methodText = key;
color = colors[key];
break;
}
}
return (
<Tag key={index} color={color} style={{ margin: '2px' }}>
{method}
</Tag>
);
});
},
},
{
title: '启用状态',
dataIndex: 'status',
key: 'status',
width: 120,
render: (text, record) => (
<Space>
<Tag color={text === '启用' ? 'success' : 'default'}>
{text}
</Tag>
<Switch
checked={text === '启用'}
onChange={(checked) => {
// 这里处理状态切换逻辑
console.log(`切换策略 ${record.strategyId} 状态为: ${checked ? '启用' : '禁用'}`);
}}
size="small"
/>
</Space>
),
},
{
title: '操作',
key: 'action',
width: 240,
fixed: 'right',
align:'center',
render: (_, record) => (
<Space size="small">
<Button
type="link"
style={{color:'#2C9E9D'}}
icon={<EditOutlined />}
// onClick={() => handleEdit(record)}
>
编辑
</Button>
<Button
type="link"
style={{color:'#FF826D'}}
icon={<StopOutlined />}
// onClick={() => handleDisable(record)}
// danger
>
禁用
</Button>
<Button
type="link"
style={{color:'#FF8800'}}
icon={<FileTextOutlined />}
// onClick={() => handleTemplate(record)}
>
模板化
</Button>
</Space>
),
},
];
return(
<div style={{padding:'0 20px'}}>
<Title title={'策略列表'}/>
<Row style={{marginTop:'20px'}} justify={'space-between'}>
<Col>
<Button className={styles['search-button']} style={{marginRight:'30px'}}>导入策略</Button>
<Button className={styles['reset-button']}>导出策略</Button>
</Col>
<Col>
<Button className={styles['reset-button' ]} style={{marginRight:'30px'}}>模板管理</Button>
<Button icon={<PlusOutlined />} className={styles['search-button']}>新增策略</Button>
</Col>
</Row>
<Row style={{marginTop:'20px'}} >
<TableWithPagination rowSelection={true} dataSource={dataSource} columns={columns}></TableWithPagination>
</Row>
</div>
)
}
export default ListOfStrategies

@ -0,0 +1,32 @@
.search-button{
background-image: url('../../../../assets/img/assetmangement1.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: #fff;
border-radius: 4px;
height: 36px;
border-color:#d9d9d9 ;
}
.reset-button{
background-image: url('../../../../assets/img/assetmangement2.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: rgba(0, 102, 101, 1);
border-radius: 4px;
height: 36px;
border-color:#d9d9d9 ;
}
.del-button{
background-image: url('../../../../assets/img/assetmangement3.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: #000;
border-radius: 4px;
height: 36px;
width:88px;
border-color:#d9d9d9 ;
background-color: #E5B7B733;
}

@ -1,7 +1,523 @@
import {Button, Col, Form, Input, Row, Select, Space, DatePicker, Radio, Tag, Badge} from "antd";
import Title from "@/pages/homepage/compontent/title";
import styles from "./RuleConfiguration.less";
import {PlusOutlined, SearchOutlined} from "@ant-design/icons";
import React from "react";
import TableWithPagination from "@/components/assetmangement/table";
const {RangePicker} = DatePicker;
const OptimizationTable=()=>{
const columns=[
{
title: '现有规则 ID',
dataIndex: 'id',
key: 'id',
},
{
title: '优化建议',
dataIndex: 'suggest',
key: 'suggest',
},
{
title: '预期效果',
dataIndex: 'effect',
key: 'effect',
},
{
title: '操作',
dataIndex: 'operation',
key: 'operation',
fixed:'right',
render:(_,record)=>{
return(
<Space>
<Button type={"link"} style={{color:'#2C9E9D'}} size="small">确认优化</Button>
<Button type={'link'} style={{color:'#999999'}} size="small">忽略</Button>
</Space>
)
}
}
]
const dataSource = [
{
id: 'ALM-RO02',
suggest: '建议将温度阈值从 40℃调整为 42℃',
effect: '减少 15% 误报',
},
{
id: 'ALM-RO04',
suggest: '建议增加磁盘>90%的持续时间为2分钟',
effect: '减少临时波动误报',
},
];
return(
<>
<TableWithPagination
columns={columns}
dataSource={dataSource}
pagination={{
total: dataSource.length,
pageSize: 5,
}}
isPagination={false}
/>
</>
)
}
const HistoryTable=()=>{
const columns=[
{
title:'优化时间',
dataIndex:'optimizationTime',
key:'optimizationTime',
},
{
title:'规则 ID',
dataIndex:'ruleId',
key:'ruleId',
},
{
title:'原配置',
dataIndex:'originalConfig',
key:'originalConfig',
},
{
title:'优化后配置',
dataIndex:'optimizationConfig',
key:'optimizationConfig',
},
{
title:'优化效果',
dataIndex:'optimizationEffect',
key:'optimizationEffect',
}
]
const dataSource=[
{
optimizationTime:'2023-10-10 10:00:00',
ruleId:'ALM-RO02',
originalConfig:'CPU>95%5分钟',
optimizationConfig:'温度阈值从 40℃调整为 42℃',
optimizationEffect:'减少 15% 误报',
},
{
optimizationTime:'2023-10-11 10:00:00',
ruleId:'ALM-RO04',
originalConfig:'离线3分钟',
optimizationConfig:'增加磁盘>90%的持续时间为2分钟',
optimizationEffect:'减少临时波动误报',
},
]
return (
<>
<TableWithPagination
columns={columns}
dataSource={dataSource}
pagination={{
total: dataSource.length,
pageSize: 5,
}}
isPagination={false}
/>
</>
)
}
const RuleConfiguration = ()=>{
const [form] = Form.useForm();
const columns = [
{
title: '告警 ID',
dataIndex: 'id',
key: 'id',
fixed: 'left', // 固定在左侧
width: 120,
},
{
title: '规则名称',
dataIndex: 'ruleName',
key: 'ruleName',
},
{
title: '设备类型',
dataIndex: 'deviceType',
key: 'deviceType',
},
{
title: '告警类型',
dataIndex: 'alarmType',
key: 'alarmType',
},
{
title: '触发条件简述',
dataIndex: 'triggerCondition',
key: 'triggerCondition',
width: 200,
},
{
title: '告警级别',
dataIndex: 'level',
key: 'level',
render: (text) => {
const colorMap = {
'紧急': 'red',
'严重': 'volcano',
'警告': 'orange',
'提示': 'green',
};
return <Tag color={colorMap[text] || 'default'}>{text}</Tag>;
},
},
{
title: '周期',
dataIndex: 'cycle',
key: 'cycle',
},
{
title: '通知方式',
dataIndex: 'notification',
key: 'notification',
},
{
title: '启用状态',
dataIndex: 'status',
key: 'status',
render: (text) => (
<Badge status={text === '启用' ? 'success' : 'default'} text={text} />
),
},
{
title: 'AI优化标记',
dataIndex: 'aiOptimized',
key: 'aiOptimized',
render: (text) => (
<Tag color={text === '已优化' ? 'green' : text === '未优化' ? 'red' : 'default'}>
{text}
</Tag>
),
},
{
title: '操作',
key: 'action',
fixed: 'right', // 固定在右侧
width: 180,
align:'center',
render: (_, record) => (
<Space>
<Button style={{color:'#006665'}} type="link" size="small" onClick={() => handleEdit(record)}>
编辑
</Button>
<Button type="link" size="small" danger onClick={() => handleDelete(record)}>
删除
</Button>
<Button style={{color:'#006665'}} type="link" size="small" onClick={() => handleCopy(record)}>
复制
</Button>
</Space>
),
},
];
const dataSource = [
{
key: '1',
id: 'ALM-H001',
ruleName: '服务器 CPU 高负载',
deviceType: '服务器',
alarmType: '性能告警',
triggerCondition: 'CPU>95% 持续5分钟',
level: '紧急',
cycle: '实时检测',
notification: '短信 +平台',
status: '启用',
aiOptimized: '已优化',
},
{
key: '2',
id: 'ALM-H002',
ruleName: '温度传感器超限',
deviceType: '传感器',
alarmType: '环境告警',
triggerCondition: '温度>40℃ 或 <0℃',
level: '严重',
cycle: '5 分钟检测',
notification: '邮件 +平台',
status: '启用',
aiOptimized: '未优化',
},
{
key: '3',
id: 'ALM-H003',
ruleName: '网关离线告警',
deviceType: '网关',
alarmType: '连接告警',
triggerCondition: '离线超过 3 分钟',
level: '警告',
cycle: '实时检测',
notification: '短信 +平台',
status: '禁用',
aiOptimized: '已优化',
},
{
key: '4',
id: 'ALM-H004',
ruleName: '磁盘使用率告警',
deviceType: '服务器',
alarmType: '存储告警',
triggerCondition: '磁盘>90%',
level: '提示',
cycle: '10 分钟检测',
notification: '平台通知',
status: '启用',
aiOptimized: '未优化',
},
{
key: '5',
id: 'ALM-H005',
ruleName: '网络丢包率高',
deviceType: '网关',
alarmType: '网络告警',
triggerCondition: '丢包率>30% 持续1分钟',
level: '紧急',
cycle: '实时检测',
notification: '平台通知',
status: '启用',
aiOptimized: '已优化',
},
{
key: '6',
id: 'ALM-H006',
ruleName: '摄像头画面异常',
deviceType: '摄像头',
alarmType: 'AI 识别告警',
triggerCondition: '画面模糊/遮挡(A识别)',
level: '严重',
cycle: '实时检测',
notification: '平台通知',
status: '启用',
aiOptimized: '已优化',
},
{
key: '7',
id: 'ALM-H007',
ruleName: '湿度传感器超限',
deviceType: '传感器',
alarmType: '环境告警',
triggerCondition: '湿度>85% 持续2分钟',
level: '警告',
cycle: '5 分钟检测',
notification: '邮件',
status: '启用',
aiOptimized: '未优化',
},
];
// 重置
const handleReset = () => {
form.resetFields();
};
// 搜索
const handleSearch = (values) => {
console.log('搜索条件:', values);
// 这里可以添加实际的搜索逻辑
};
const handleEdit = (record) => {
console.log('编辑:', record);
// 这里可以添加实际的编辑逻辑
};
// 删除
const handleDelete = (record) => {
console.log('删除:', record);
// 这里可以添加实际的删除逻辑
};
// 复制
const handleCopy = (record) => {
console.log('复制:', record);
// 这里可以添加实际的复制逻辑
};
return (
<div>
告警规则配置
<div style={{backgroundColor:'#f0f7f7',height:'100%',overflowX:'hidden'}}>
<Row gutter={20} style={{height:'100%'}}>
<Col span={16} style={{height:'100%'}}>
<div style={{width:'100%',height:'100%',backgroundColor:'#fff',padding:20,borderRadius:8}}>
<Row style={{marginBottom: 20}}>
<Col span={12}>
<Title title="查询条件" className={styles.title}/>
</Col>
<Col span={12} style={{textAlign: 'right'}}>
<Space>
<Button icon={<SearchOutlined/>} htmlType="submit"
className={styles['search-button']}>查询</Button>
<Button onClick={handleReset} className={styles['reset-button']}>重置</Button>
</Space>
</Col>
</Row>
<Form form={form} layout="inline" onFinish={handleSearch} style={{borderBottom:'1px solid #eeeeee',paddingBottom:20}}>
<Form.Item name="type" label="设备类型">
<Select placeholder="全部" style={{width: 132}}>
<Option value="设备维修">设备维修</Option>
<Option value="设备安装">设备安装</Option>
<Option value="设备巡检">设备巡检</Option>
<Option value="设备更换">设备更换</Option>
</Select>
</Form.Item>
<Form.Item name="status" label="规则状态">
<Select placeholder="全部" style={{width: 132}}>
<Option value="设备维修">设备维修</Option>
<Option value="设备安装">设备安装</Option>
<Option value="设备巡检">设备巡检</Option>
<Option value="设备更换">设备更换</Option>
</Select>
</Form.Item>
<Form.Item name="level" label="告警级别">
<Select placeholder="请选择状态" style={{width: 132}}>
<Option value="待处理">待处理</Option>
<Option value="处理中">处理中</Option>
<Option value="已完成">已完成</Option>
<Option value="已取消">已取消</Option>
</Select>
</Form.Item>
<Form.Item name="applyTime" label="是否AI优化">
<Radio.Group
defaultValue={1}
options={[
{ value: 1, label: '是' },
{ value: 2, label: '否' },
{ value: 3, label: '全部' },
]}
>
</Radio.Group>
</Form.Item>
</Form>
<Row>
<div style={{width:'100%',paddingTop:20}}>
<Title title="规则列表" />
<Row gutter={20} justify="space-between" style={{marginTop:20,}}>
<Col>
<Button className={styles['search-button']} style={{marginRight:30}}>导入规则</Button>
<Button className={styles['reset-button']}>导出规则</Button>
</Col>
<Col>
<Button className={styles['reset-button']} style={{marginRight:30}}>AI推荐模板</Button>
<Button icon={<PlusOutlined/>} className={styles['search-button']}>新增规则</Button>
</Col>
</Row>
<Row style={{marginTop:20}}>
<TableWithPagination columns={columns} dataSource={dataSource} rowSelection={true}></TableWithPagination>
</Row>
</div>
</Row>
</div>
</Col>
<Col span={8} style={{height:'100%'}}>
<div style={{ backgroundColor: '#fff',padding:20 , borderRadius:8}}>
<Row justify="space-between">
<Col>
<Title title="AI推荐规则" />
</Col>
<Col>
<Button className={styles['search-button']} style={{marginRight:30}}>AI智能优化</Button>
<Button className={styles['reset-button']}>AI推荐规则</Button>
</Col>
</Row>
<Row style={{marginTop:20}} gutter={10} >
<Col span={12} >
<div className={styles['form-item']}>
<Row gutter={[0,20]}>
<Col className={styles['form-item-label']} span={10}>
推荐规则ID
</Col>
<Col className={styles['form-item-content']} span={14}>
REC-RO01
</Col>
<Col className={styles['form-item-label']} span={9}>
设备类型
</Col>
<Col className={styles['form-item-content']} span={15}>
传感器
</Col>
<Col className={styles['form-item-label']} span={9}>
告警类型
</Col>
<Col className={styles['form-item-content']} span={15}>
湿度告警
</Col>
<Col className={styles['form-item-label']} span={9}>
触发条件
</Col>
<Col className={styles['form-item-content']} span={15}>
湿度85% 持续3分钟
</Col>
<Col className={styles['form-item-label']} span={9}>
推荐理由
</Col>
<Col className={styles['form-item-content']} span={15}>
历史湿度85% 时设备故障概率提升 40%
</Col>
</Row>
<Row style={{marginTop:20}}>
<Col offset={9} span={15} style={{display:'flex',justifyContent:"space-around"}}>
<Button className={styles['search-button']}>启用</Button>
<Button className={styles['reset-button']}>忽略</Button>
</Col>
</Row>
</div>
</Col>
<Col span={12} >
<div className={styles['form-item']}>
<Row gutter={[0,20]}>
<Col className={styles['form-item-label']} span={10}>
推荐规则ID
</Col>
<Col className={styles['form-item-content']} span={14}>
REC-RO02
</Col>
<Col className={styles['form-item-label']} span={9}>
设备类型
</Col>
<Col className={styles['form-item-content']} span={15}>
服务器
</Col>
<Col className={styles['form-item-label']} span={9}>
告警类型
</Col>
<Col className={styles['form-item-content']} span={15}>
内存告警
</Col>
<Col className={styles['form-item-label']} span={9}>
触发条件
</Col>
<Col className={styles['form-item-content']} span={15}>
内存85% 持续 10 分钟
</Col>
<Col className={styles['form-item-label']} span={9}>
推荐理由
</Col>
<Col className={styles['form-item-content']} span={15}>
原阈值 80% 误报率高调整后精准度提升 25%
</Col>
</Row>
<Row style={{marginTop:20}}>
<Col offset={9} span={15} style={{display:'flex',justifyContent:"space-around"}}>
<Button className={styles['search-button']}>启用</Button>
<Button className={styles['reset-button']}>忽略</Button>
</Col>
</Row>
</div>
</Col>
</Row>
<Row style={{marginTop:20}}>
<Title title="优化建议" style={{marginBottom:20}} ></Title>
<OptimizationTable></OptimizationTable>
</Row>
<Row style={{marginTop:20}}>
<Title title="AI 优化历史" style={{marginBottom:20}} ></Title>
<HistoryTable></HistoryTable>
</Row>
</div>
</Col>
</Row>
</div>
)
}

@ -0,0 +1,93 @@
.search-button{
background-image: url('../../assets/img/assetmangement1.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: #fff;
border-radius: 4px;
height: 36px;
border-color:#d9d9d9 ;
}
.reset-button{
background-image: url('../../assets/img/assetmangement2.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: rgba(0, 102, 101, 1);
border-radius: 4px;
height: 36px;
border-color:#d9d9d9 ;
}
.del-button{
background-image: url('../../assets/img/assetmangement3.png');
background-repeat: no-repeat;
background-size: cover;
background-position:center;
color: #000;
border-radius: 4px;
height: 36px;
width:88px;
border-color:#d9d9d9 ;
background-color: #E5B7B733;
}
.card {
margin-bottom: 16px;
background-color: #fff;
// box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
border-radius: 8px;
}
.title {
margin-bottom: 20px;
}
.toolbar {
margin-bottom: 16px;
display: flex;
align-items: center;
justify-content: space-between;
}
.form-item{
position: relative;
background-color: #ffffff4d;
border-radius:4px;
padding: 10px ;
height:100%;
&::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
border-radius: 10px; /* 比主元素大边框宽度 */
background: linear-gradient(45deg,
#fafafa, #fdfdfd, #f7f7f7, #f6f6f6,
#f6f6f6, #f7f7f7, #fdfdfd, #fafafa);
z-index: 0;
}
/* 白色背景层,裁剪出边框 */
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 8px;
background-color: #ffffff4d;
z-index: 1;
}
.form-item-label{
font-size: 14px;
font-weight: 500;
color: #999999;
}
.form-item-content{
font-size: 14px;
font-weight: 500;
color: #000000D9;
}
}

@ -6,7 +6,9 @@ export default (props)=>{
fontFamily: '"PingFang SC", -apple-system, BlinkMacSystemFont, "Microsoft YaHei", "Segoe UI", Roboto, sans-serif',
fontWeight: '500',
fontSize: '20px',
lineHeight: '100%'
lineHeight: '100%',
display:'flex',
alignItems:'center'
}}
className={props.className}
>

Loading…
Cancel
Save