diff --git a/src/assets/img/headerBg.png b/src/assets/img/headerBg.png new file mode 100644 index 0000000..46f623c Binary files /dev/null and b/src/assets/img/headerBg.png differ diff --git a/src/assets/img/titleBg.png b/src/assets/img/titleBg.png new file mode 100644 index 0000000..cd98e6e Binary files /dev/null and b/src/assets/img/titleBg.png differ diff --git a/src/pages/alarmcenter_historyAlarms/HistoryAlarms.js b/src/pages/alarmcenter_historyAlarms/HistoryAlarms.js index c87750e..add456c 100644 --- a/src/pages/alarmcenter_historyAlarms/HistoryAlarms.js +++ b/src/pages/alarmcenter_historyAlarms/HistoryAlarms.js @@ -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 {text}; + } + }, + { + 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 {text}; + } + }, + { + title: '处理人', + dataIndex: 'handler', + key: 'handler', + }, + { + title: '操作', + key: 'operations', + render: (_, record) => { + if(record.status === '已处理'){ + return ( +
+ + + +
+ ) + }else if(record.status === '未处理'){ + return ( +
+ + + +
+ ) + }else if(record.status === '已忽略'){ + return ( +
+ + +
+ ) + } + }, + }, +] + +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 ( -
- 历史告警 +
+ {/* 查询条件区域 */} + + + + + </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> ) } diff --git a/src/pages/alarmcenter_historyAlarms/HistoryAlarms.less b/src/pages/alarmcenter_historyAlarms/HistoryAlarms.less index e69de29..d65bddc 100644 --- a/src/pages/alarmcenter_historyAlarms/HistoryAlarms.less +++ b/src/pages/alarmcenter_historyAlarms/HistoryAlarms.less @@ -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; +} diff --git a/src/pages/alarmcenter_implementWarnings/ImplementWarnings.js b/src/pages/alarmcenter_implementWarnings/ImplementWarnings.js index 9d754f3..18169bc 100644 --- a/src/pages/alarmcenter_implementWarnings/ImplementWarnings.js +++ b/src/pages/alarmcenter_implementWarnings/ImplementWarnings.js @@ -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> ) } diff --git a/src/pages/alarmcenter_implementWarnings/ImplementWarnings.less b/src/pages/alarmcenter_implementWarnings/ImplementWarnings.less index e69de29..d65bddc 100644 --- a/src/pages/alarmcenter_implementWarnings/ImplementWarnings.less +++ b/src/pages/alarmcenter_implementWarnings/ImplementWarnings.less @@ -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; +} diff --git a/src/pages/alarmcenter_policy/Policy.js b/src/pages/alarmcenter_policy/Policy.js index 72ab12a..42e5a08 100644 --- a/src/pages/alarmcenter_policy/Policy.js +++ b/src/pages/alarmcenter_policy/Policy.js @@ -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> ) } diff --git a/src/pages/alarmcenter_policy/Policy.less b/src/pages/alarmcenter_policy/Policy.less index e69de29..5b2d2c8 100644 --- a/src/pages/alarmcenter_policy/Policy.less +++ b/src/pages/alarmcenter_policy/Policy.less @@ -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; + } +} diff --git a/src/pages/alarmcenter_policy/component/listOfStrategies/ListOfStrategies.js b/src/pages/alarmcenter_policy/component/listOfStrategies/ListOfStrategies.js new file mode 100644 index 0000000..dadf191 --- /dev/null +++ b/src/pages/alarmcenter_policy/component/listOfStrategies/ListOfStrategies.js @@ -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 diff --git a/src/pages/alarmcenter_policy/component/listOfStrategies/ListOfStrategies.less b/src/pages/alarmcenter_policy/component/listOfStrategies/ListOfStrategies.less new file mode 100644 index 0000000..9302f41 --- /dev/null +++ b/src/pages/alarmcenter_policy/component/listOfStrategies/ListOfStrategies.less @@ -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; +} diff --git a/src/pages/alarmcenter_ruleConfiguration/RuleConfiguration.js b/src/pages/alarmcenter_ruleConfiguration/RuleConfiguration.js index 935a048..fb0d5bd 100644 --- a/src/pages/alarmcenter_ruleConfiguration/RuleConfiguration.js +++ b/src/pages/alarmcenter_ruleConfiguration/RuleConfiguration.js @@ -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}} > + + + + + + +
+ +
) } diff --git a/src/pages/alarmcenter_ruleConfiguration/RuleConfiguration.less b/src/pages/alarmcenter_ruleConfiguration/RuleConfiguration.less index e69de29..8622f7e 100644 --- a/src/pages/alarmcenter_ruleConfiguration/RuleConfiguration.less +++ b/src/pages/alarmcenter_ruleConfiguration/RuleConfiguration.less @@ -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; + } +} diff --git a/src/pages/homepage/compontent/title.js b/src/pages/homepage/compontent/title.js index bd4cf81..97e82eb 100644 --- a/src/pages/homepage/compontent/title.js +++ b/src/pages/homepage/compontent/title.js @@ -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} >