Explorar el Código

feat(test8): 添加异常报警管理功能

- 实现了异常报警的展示、处理和详情查看功能
- 包含报警概览、趋势图、筛选控件等模块
- 使用 Ant Design 组件库进行界面设计
- 添加模拟数据和统计信息
- 实现了报警状态的动态更新和全局消息提示
nahida hace 9 meses
padre
commit
54c050fbb4
Se han modificado 1 ficheros con 478 adiciones y 0 borrados
  1. 478 0
      app/(other)/test8/components/abnormal-alarm.tsx

+ 478 - 0
app/(other)/test8/components/abnormal-alarm.tsx

@@ -0,0 +1,478 @@
+"use client"
+
+import {useEffect, useState} from "react"
+import {
+  Alert,
+  Button,
+  Card,
+  Col,
+  Descriptions,
+  Form,
+  Input,
+  Modal,
+  Row,
+  Select,
+  Space,
+  Table,
+  Tag,
+  Timeline,
+} from "antd"
+import {BellOutlined, CheckCircleOutlined, EditOutlined, EyeOutlined} from "@ant-design/icons"
+import {Line} from "@ant-design/plots"
+import globalMessage from "@/app/_modules/globalMessage";
+
+const { Option } = Select
+const { TextArea } = Input
+
+// 模拟报警数据
+const mockAlarmData = [
+  {
+    id: "A001",
+    title: "解放路段压力异常报警",
+    type: "压力异常",
+    level: "高",
+    location: "解放路调压站",
+    deviceId: "D001",
+    deviceName: "压力监测器001",
+    value: 0.52,
+    threshold: 0.45,
+    unit: "MPa",
+    status: "未处理",
+    createTime: "2024-01-15 14:30:25",
+    updateTime: "2024-01-15 14:30:25",
+    handler: null,
+    handleTime: null,
+    description: "管网压力超出安全阈值,可能存在安全隐患",
+    solution: null,
+  },
+  {
+    id: "A002",
+    title: "人民路段流量异常报警",
+    type: "流量异常",
+    level: "中",
+    location: "人民路段",
+    deviceId: "D002",
+    deviceName: "流量监测器002",
+    value: 4200,
+    threshold: 3500,
+    unit: "m³/h",
+    status: "处理中",
+    createTime: "2024-01-15 13:45:10",
+    updateTime: "2024-01-15 14:15:30",
+    handler: "张三",
+    handleTime: "2024-01-15 14:15:30",
+    description: "流量超出正常范围,需要检查管网状态",
+    solution: "正在检查管网连接状态,预计30分钟内完成",
+  },
+  {
+    id: "A003",
+    title: "建设路段泄漏报警",
+    type: "泄漏检测",
+    level: "高",
+    location: "建设路北段",
+    deviceId: "D004",
+    deviceName: "泄漏检测器004",
+    value: 0.08,
+    threshold: 0.05,
+    unit: "ppm",
+    status: "已处理",
+    createTime: "2024-01-15 12:20:15",
+    updateTime: "2024-01-15 13:45:20",
+    handler: "李四",
+    handleTime: "2024-01-15 12:25:15",
+    description: "检测到燃气泄漏,浓度超标",
+    solution: "已完成管线检修,泄漏点已修复,监测数据恢复正常",
+  },
+]
+
+// 模拟报警统计数据
+const mockAlarmStats = [
+  { time: "00:00", count: 2 },
+  { time: "04:00", count: 1 },
+  { time: "08:00", count: 3 },
+  { time: "12:00", count: 5 },
+  { time: "16:00", count: 2 },
+  { time: "20:00", count: 1 },
+]
+
+export default function AbnormalAlarm() {
+  const [isModalVisible, setIsModalVisible] = useState(false)
+  const [isDetailModalVisible, setIsDetailModalVisible] = useState(false)
+  const [selectedAlarm, setSelectedAlarm] = useState(null)
+  const [form] = Form.useForm()
+  const [alarmData, setAlarmData] = useState(mockAlarmData)
+
+  // 模拟实时报警更新
+  useEffect(() => {
+    const interval = setInterval(() => {
+      // 模拟新报警
+      if (Math.random() < 0.1) {
+        const newAlarm = {
+          id: `A${Date.now()}`,
+          title: "新报警事件",
+          type: "压力异常",
+          level: "中",
+          location: "测试路段",
+          deviceId: "D999",
+          deviceName: "测试设备",
+          value: 0.48,
+          threshold: 0.45,
+          unit: "MPa",
+          status: "未处理",
+          createTime: new Date().toLocaleString(),
+          updateTime: new Date().toLocaleString(),
+          handler: null,
+          handleTime: null,
+          description: "模拟报警事件",
+          solution: null,
+        }
+        setAlarmData((prev) => [newAlarm, ...prev])
+        globalMessage.warning("收到新报警!")
+      }
+    }, 30000) // 30秒检查一次
+
+    return () => clearInterval(interval)
+  }, [])
+
+  const handleView = (record: any) => {
+    setSelectedAlarm(record)
+    setIsDetailModalVisible(true)
+  }
+
+  const handleProcess = (record: any) => {
+    setSelectedAlarm(record)
+    form.setFieldsValue({
+      handler: "当前用户",
+      solution: "",
+    })
+    setIsModalVisible(true)
+  }
+
+  const handleModalOk = () => {
+    form.validateFields().then((values) => {
+      const updatedData = alarmData.map((item) =>
+        item.id === selectedAlarm?.id
+          ? {
+              ...item,
+              status: "处理中",
+              handler: values.handler,
+              handleTime: new Date().toLocaleString(),
+              updateTime: new Date().toLocaleString(),
+              solution: values.solution,
+            }
+          : item,
+      )
+      setAlarmData(updatedData)
+      globalMessage.success("报警处理成功")
+      setIsModalVisible(false)
+      form.resetFields()
+    })
+  }
+
+  const handleComplete = (id: string) => {
+    const updatedData = alarmData.map((item) =>
+      item.id === id
+        ? {
+            ...item,
+            status: "已处理",
+            updateTime: new Date().toLocaleString(),
+          }
+        : item,
+    )
+    setAlarmData(updatedData)
+    globalMessage.success("报警已标记为完成")
+  }
+
+  const getStatusColor = (status: string) => {
+    switch (status) {
+      case "未处理":
+        return "red"
+      case "处理中":
+        return "orange"
+      case "已处理":
+        return "green"
+      default:
+        return "default"
+    }
+  }
+
+  const getLevelColor = (level: string) => {
+    switch (level) {
+      case "高":
+        return "red"
+      case "中":
+        return "orange"
+      case "低":
+        return "blue"
+      default:
+        return "default"
+    }
+  }
+
+  const columns = [
+    { title: "报警编号", dataIndex: "id", key: "id", width: 100 },
+    { title: "报警标题", dataIndex: "title", key: "title", width: 200 },
+    { title: "报警类型", dataIndex: "type", key: "type", width: 120 },
+    {
+      title: "报警等级",
+      dataIndex: "level",
+      key: "level",
+      width: 100,
+      render: (level: string) => <Tag color={getLevelColor(level)}>{level}</Tag>,
+    },
+    { title: "位置", dataIndex: "location", key: "location", width: 150 },
+    { title: "设备名称", dataIndex: "deviceName", key: "deviceName", width: 150 },
+    {
+      title: "异常值",
+      key: "value",
+      width: 120,
+      render: (_, record: any) => `${record.value} ${record.unit}`,
+    },
+    {
+      title: "阈值",
+      key: "threshold",
+      width: 120,
+      render: (_, record: any) => `${record.threshold} ${record.unit}`,
+    },
+    {
+      title: "状态",
+      dataIndex: "status",
+      key: "status",
+      width: 100,
+      render: (status: string) => <Tag color={getStatusColor(status)}>{status}</Tag>,
+    },
+    { title: "创建时间", dataIndex: "createTime", key: "createTime", width: 180 },
+    { title: "处理人", dataIndex: "handler", key: "handler", width: 100 },
+    {
+      title: "操作",
+      key: "action",
+      width: 200,
+      fixed: "right",
+      render: (_, record) => (
+        <Space>
+          <Button type="link" icon={<EyeOutlined />} onClick={() => handleView(record)}>
+            查看
+          </Button>
+          {record.status === "未处理" && (
+            <Button type="link" icon={<EditOutlined />} onClick={() => handleProcess(record)}>
+              处理
+            </Button>
+          )}
+          {record.status === "处理中" && (
+            <Button type="link" onClick={() => handleComplete(record.id)}>
+              完成
+            </Button>
+          )}
+        </Space>
+      ),
+    },
+  ]
+
+  const lineConfig = {
+    data: mockAlarmStats,
+    xField: "time",
+    yField: "count",
+    color: "#f5222d",
+    point: {
+      size: 5,
+      shape: "diamond",
+    },
+    area: {
+      style: {
+        fill: "l(270) 0:#ffffff 0.5:#ffccc7 1:#f5222d",
+        fillOpacity: 0.3,
+      },
+    },
+  }
+
+  const unhandledCount = alarmData.filter((item) => item.status === "未处理").length
+  const processingCount = alarmData.filter((item) => item.status === "处理中").length
+  const handledCount = alarmData.filter((item) => item.status === "已处理").length
+
+  return (
+    <div className="p-6">
+      <Card title="异常报警管理">
+        {/* 报警概览 */}
+        <Row gutter={16} className="mb-6">
+          <Col span={6}>
+            <Card size="small">
+              <div className="text-center">
+                <div className="text-2xl font-bold text-red-600">{unhandledCount}</div>
+                <div className="text-gray-600">未处理报警</div>
+              </div>
+            </Card>
+          </Col>
+          <Col span={6}>
+            <Card size="small">
+              <div className="text-center">
+                <div className="text-2xl font-bold text-orange-600">{processingCount}</div>
+                <div className="text-gray-600">处理中</div>
+              </div>
+            </Card>
+          </Col>
+          <Col span={6}>
+            <Card size="small">
+              <div className="text-center">
+                <div className="text-2xl font-bold text-green-600">{handledCount}</div>
+                <div className="text-gray-600">已处理</div>
+              </div>
+            </Card>
+          </Col>
+          <Col span={6}>
+            <Card size="small">
+              <div className="text-center">
+                <div className="text-2xl font-bold text-blue-600">{alarmData.length}</div>
+                <div className="text-gray-600">报警总数</div>
+              </div>
+            </Card>
+          </Col>
+        </Row>
+
+        {/* 紧急报警提醒 */}
+        {unhandledCount > 0 && (
+          <Alert
+            message={`当前有 ${unhandledCount} 个未处理报警`}
+            description="请及时处理高等级报警,确保系统安全运行"
+            type="error"
+            icon={<BellOutlined />}
+            showIcon
+            className="mb-6"
+          />
+        )}
+
+        {/* 报警趋势图 */}
+        <Row gutter={16} className="mb-6">
+          <Col span={24}>
+            <Card title="24小时报警趋势" size="small">
+              <Line {...lineConfig} height={200} />
+            </Card>
+          </Col>
+        </Row>
+
+        {/* 筛选控件 */}
+        <div className="mb-4">
+          <Space>
+            <Select placeholder="报警类型" style={{ width: 120 }}>
+              <Option value="pressure">压力异常</Option>
+              <Option value="flow">流量异常</Option>
+              <Option value="temperature">温度异常</Option>
+              <Option value="leak">泄漏检测</Option>
+            </Select>
+            <Select placeholder="报警等级" style={{ width: 120 }}>
+              <Option value="high">高</Option>
+              <Option value="medium">中</Option>
+              <Option value="low">低</Option>
+            </Select>
+            <Select placeholder="处理状态" style={{ width: 120 }}>
+              <Option value="unhandled">未处理</Option>
+              <Option value="processing">处理中</Option>
+              <Option value="handled">已处理</Option>
+            </Select>
+          </Space>
+        </div>
+
+        {/* 报警列表 */}
+        <Table
+          columns={columns}
+          dataSource={alarmData}
+          rowKey="id"
+          pagination={{ pageSize: 10 }}
+          scroll={{ x: 1600 }}
+          rowClassName={(record) => (record.status === "未处理" && record.level === "高" ? "bg-red-50" : "")}
+        />
+
+        {/* 处理模态框 */}
+        <Modal
+          title="处理报警"
+          open={isModalVisible}
+          onOk={handleModalOk}
+          onCancel={() => setIsModalVisible(false)}
+          width={600}
+        >
+          <Form form={form} layout="vertical">
+            <Form.Item name="handler" label="处理人" rules={[{ required: true }]}>
+              <Input />
+            </Form.Item>
+            <Form.Item name="solution" label="处理方案" rules={[{ required: true }]}>
+              <TextArea rows={4} placeholder="请输入处理方案..." />
+            </Form.Item>
+          </Form>
+        </Modal>
+
+        {/* 详情查看模态框 */}
+        <Modal
+          title="报警详情"
+          open={isDetailModalVisible}
+          onCancel={() => setIsDetailModalVisible(false)}
+          footer={[
+            <Button key="close" onClick={() => setIsDetailModalVisible(false)}>
+              关闭
+            </Button>,
+          ]}
+          width={800}
+        >
+          {selectedAlarm && (
+            <div>
+              <Descriptions column={2} bordered>
+                <Descriptions.Item label="报警编号">{selectedAlarm.id}</Descriptions.Item>
+                <Descriptions.Item label="报警标题">{selectedAlarm.title}</Descriptions.Item>
+                <Descriptions.Item label="报警类型">{selectedAlarm.type}</Descriptions.Item>
+                <Descriptions.Item label="报警等级">
+                  <Tag color={getLevelColor(selectedAlarm.level)}>{selectedAlarm.level}</Tag>
+                </Descriptions.Item>
+                <Descriptions.Item label="位置">{selectedAlarm.location}</Descriptions.Item>
+                <Descriptions.Item label="设备名称">{selectedAlarm.deviceName}</Descriptions.Item>
+                <Descriptions.Item label="异常值">
+                  {selectedAlarm.value} {selectedAlarm.unit}
+                </Descriptions.Item>
+                <Descriptions.Item label="阈值">
+                  {selectedAlarm.threshold} {selectedAlarm.unit}
+                </Descriptions.Item>
+                <Descriptions.Item label="状态">
+                  <Tag color={getStatusColor(selectedAlarm.status)}>{selectedAlarm.status}</Tag>
+                </Descriptions.Item>
+                <Descriptions.Item label="创建时间">{selectedAlarm.createTime}</Descriptions.Item>
+                <Descriptions.Item label="处理人">{selectedAlarm.handler || "未分配"}</Descriptions.Item>
+                <Descriptions.Item label="处理时间">{selectedAlarm.handleTime || "未处理"}</Descriptions.Item>
+              </Descriptions>
+
+              <div className="mt-4">
+                <h4 className="font-medium mb-2">报警描述</h4>
+                <div className="p-3 bg-gray-50 rounded">{selectedAlarm.description}</div>
+              </div>
+
+              {selectedAlarm.solution && (
+                <div className="mt-4">
+                  <h4 className="font-medium mb-2">处理方案</h4>
+                  <div className="p-3 bg-blue-50 rounded">{selectedAlarm.solution}</div>
+                </div>
+              )}
+
+              <div className="mt-4">
+                <h4 className="font-medium mb-2">处理时间线</h4>
+                <Timeline>
+                  <Timeline.Item color="red" dot={<BellOutlined />}>
+                    <div>报警触发</div>
+                    <div className="text-gray-500 text-sm">{selectedAlarm.createTime}</div>
+                  </Timeline.Item>
+                  {selectedAlarm.handleTime && (
+                    <Timeline.Item color="orange" dot={<EditOutlined />}>
+                      <div>开始处理 - {selectedAlarm.handler}</div>
+                      <div className="text-gray-500 text-sm">{selectedAlarm.handleTime}</div>
+                    </Timeline.Item>
+                  )}
+                  {selectedAlarm.status === "已处理" && (
+                    <Timeline.Item color="green" dot={<CheckCircleOutlined />}>
+                      <div>处理完成</div>
+                      <div className="text-gray-500 text-sm">{selectedAlarm.updateTime}</div>
+                    </Timeline.Item>
+                  )}
+                </Timeline>
+              </div>
+            </div>
+          )}
+        </Modal>
+      </Card>
+    </div>
+  )
+}