Ver código fonte

feat(app): 添加关键指标实时监测功能

- 实现了压力、流量、温度、泄漏等关键指标的实时监测和展示
- 添加了实时数据更新、历史趋势分析、设备监测状态等功能
- 使用了EChart组件进行数据可视化- 集成了Ant Design组件库,实现了美观的界面布局
nahida 9 meses atrás
pai
commit
cb142b53a2

+ 438 - 0
app/(other)/test8/components/key-indicators-monitoring.tsx

@@ -0,0 +1,438 @@
+"use client"
+
+import {useEffect, useState} from "react"
+import {Alert, Card, Col, DatePicker, Row, Select, Space, Statistic, Table, Tag} from "antd"
+import EChart from "@/components/echarts"
+import {ArrowDownOutlined, ArrowUpOutlined, WarningOutlined} from "@ant-design/icons"
+
+const { RangePicker } = DatePicker
+const { Option } = Select
+
+// 模拟实时监测数据
+const mockRealTimeData = {
+  pressure: {
+    current: 0.42,
+    normal: [0.35, 0.45],
+    status: "normal",
+    trend: "up",
+    change: 0.02,
+  },
+  flow: {
+    current: 2850,
+    normal: [2000, 3500],
+    status: "normal",
+    trend: "down",
+    change: -150,
+  },
+  temperature: {
+    current: 18.5,
+    normal: [15, 25],
+    status: "normal",
+    trend: "stable",
+    change: 0.1,
+  },
+  leakage: {
+    current: 0.02,
+    normal: [0, 0.05],
+    status: "warning",
+    trend: "up",
+    change: 0.01,
+  },
+}
+
+// 模拟历史趋势数据
+const mockTrendData = [
+  { time: "00:00", pressure: 0.38, flow: 2200, temperature: 16.2, leakage: 0.01 },
+  { time: "02:00", pressure: 0.39, flow: 2100, temperature: 16.8, leakage: 0.01 },
+  { time: "04:00", pressure: 0.41, flow: 2300, temperature: 17.2, leakage: 0.015 },
+  { time: "06:00", pressure: 0.43, flow: 2800, temperature: 18.1, leakage: 0.018 },
+  { time: "08:00", pressure: 0.42, flow: 3200, temperature: 18.5, leakage: 0.02 },
+  { time: "10:00", pressure: 0.41, flow: 3100, temperature: 18.8, leakage: 0.022 },
+  { time: "12:00", pressure: 0.4, flow: 2900, temperature: 19.2, leakage: 0.019 },
+  { time: "14:00", pressure: 0.42, flow: 2850, temperature: 18.5, leakage: 0.02 },
+]
+
+// 模拟设备监测数据
+const mockDeviceData = [
+  {
+    id: "D001",
+    name: "解放路压力监测点",
+    type: "压力监测",
+    value: 0.42,
+    unit: "MPa",
+    status: "正常",
+    lastUpdate: "2024-01-15 14:30:25",
+    location: "解放路调压站",
+  },
+  {
+    id: "D002",
+    name: "人民路流量监测点",
+    type: "流量监测",
+    value: 2850,
+    unit: "m³/h",
+    status: "正常",
+    lastUpdate: "2024-01-15 14:30:20",
+    location: "人民路段",
+  },
+  {
+    id: "D003",
+    name: "建设路温度监测点",
+    type: "温度监测",
+    value: 18.5,
+    unit: "°C",
+    status: "正常",
+    lastUpdate: "2024-01-15 14:30:15",
+    location: "建设路段",
+  },
+  {
+    id: "D004",
+    name: "解放路泄漏检测点",
+    type: "泄漏检测",
+    value: 0.02,
+    unit: "ppm",
+    status: "预警",
+    lastUpdate: "2024-01-15 14:30:30",
+    location: "解放路北段",
+  },
+]
+
+export default function KeyIndicatorsMonitoring() {
+  const [selectedIndicator, setSelectedIndicator] = useState("pressure")
+  const [realTimeData, setRealTimeData] = useState(mockRealTimeData)
+
+  // 模拟实时数据更新
+  useEffect(() => {
+    const interval = setInterval(() => {
+      setRealTimeData((prev) => ({
+        ...prev,
+        pressure: {
+          ...prev.pressure,
+          current: +(prev.pressure.current + (Math.random() - 0.5) * 0.02).toFixed(3),
+        },
+        flow: {
+          ...prev.flow,
+          current: Math.round(prev.flow.current + (Math.random() - 0.5) * 100),
+        },
+        temperature: {
+          ...prev.temperature,
+          current: +(prev.temperature.current + (Math.random() - 0.5) * 0.5).toFixed(1),
+        },
+        leakage: {
+          ...prev.leakage,
+          current: +(prev.leakage.current + (Math.random() - 0.5) * 0.005).toFixed(3),
+        },
+      }))
+    }, 5000)
+
+    return () => clearInterval(interval)
+  }, [])
+
+  const getStatusColor = (status: string) => {
+    switch (status) {
+      case "normal":
+        return "#52c41a"
+      case "warning":
+        return "#faad14"
+      case "danger":
+        return "#f5222d"
+      default:
+        return "#1890ff"
+    }
+  }
+
+  const getTrendIcon = (trend: string, change: number) => {
+    if (trend === "up") {
+      return <ArrowUpOutlined style={{ color: change > 0 ? "#f5222d" : "#52c41a" }} />
+    } else if (trend === "down") {
+      return <ArrowDownOutlined style={{ color: change < 0 ? "#f5222d" : "#52c41a" }} />
+    }
+    return null
+  }
+
+  const gaugeOption = {
+    series: [
+      {
+        type: "gauge",
+        startAngle: 180,
+        endAngle: 0,
+        center: ["50%", "75%"],
+        radius: "90%",
+        min: 0,
+        max: 1,
+        splitNumber: 8,
+        axisLine: {
+          lineStyle: {
+            width: 6,
+            color: [
+              [0.25, "#FF6E76"],
+              [0.5, "#FDDD60"],
+              [0.75, "#58D9F9"],
+              [1, "#7CFFB2"],
+            ],
+          },
+        },
+        pointer: {
+          icon: "path://M12.8,0.7l12,40.1H0.7L12.8,0.7z",
+          length: "12%",
+          width: 20,
+          offsetCenter: [0, "-60%"],
+          itemStyle: {
+            color: "auto",
+          },
+        },
+        axisTick: {
+          length: 12,
+          lineStyle: {
+            color: "auto",
+            width: 2,
+          },
+        },
+        splitLine: {
+          length: 20,
+          lineStyle: {
+            color: "auto",
+            width: 5,
+          },
+        },
+        axisLabel: {
+          color: "#464646",
+          fontSize: 20,
+          distance: -60,
+          rotate: "tangential",
+          formatter: (value: number) => {
+            if (value === 0.875) {
+              return "A+"
+            } else if (value === 0.625) {
+              return "A"
+            } else if (value === 0.375) {
+              return "B"
+            } else if (value === 0.125) {
+              return "C"
+            }
+            return ""
+          },
+        },
+        title: {
+          offsetCenter: [0, "-10%"],
+          fontSize: 20,
+        },
+        detail: {
+          fontSize: 30,
+          offsetCenter: [0, "-35%"],
+          valueAnimation: true,
+          formatter: (value: number) => Math.round(value * 100) / 100,
+          color: "inherit",
+        },
+        data: [
+          {
+            value: realTimeData.pressure.current,
+            name: "压力 (MPa)",
+          },
+        ],
+      },
+    ],
+  }
+
+  const getIndicatorName = (indicator: string) => {
+    const names = {
+      pressure: "压力",
+      flow: "流量",
+      temperature: "温度",
+      leakage: "泄漏",
+    }
+    return names[indicator as keyof typeof names] || indicator
+  }
+
+  const areaOption = {
+    title: { text: `${getIndicatorName(selectedIndicator)}趋势`, left: "center" },
+    tooltip: { trigger: "axis" },
+    grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true },
+    xAxis: {
+      type: "category",
+      data: mockTrendData.map((item) => item.time),
+    },
+    yAxis: { type: "value" },
+    series: [
+      {
+        type: "line",
+        data: mockTrendData.map((item) => item[selectedIndicator as keyof typeof item]),
+        smooth: true,
+        areaStyle: {
+          color: {
+            type: "linear",
+            x: 0,
+            y: 0,
+            x2: 0,
+            y2: 1,
+            colorStops: [
+              {
+                offset: 0,
+                color: "rgba(24, 144, 255, 0.8)",
+              },
+              {
+                offset: 1,
+                color: "rgba(24, 144, 255, 0.1)",
+              },
+            ],
+          },
+        },
+        itemStyle: { color: "#1890ff" },
+      },
+    ],
+  }
+
+  const deviceColumns = [
+    { title: "设备编号", dataIndex: "id", key: "id", width: 100 },
+    { title: "设备名称", dataIndex: "name", key: "name", width: 200 },
+    { title: "监测类型", dataIndex: "type", key: "type", width: 120 },
+    {
+      title: "当前值",
+      dataIndex: "value",
+      key: "value",
+      width: 100,
+      render: (value: number, record: any) => `${value} ${record.unit}`,
+    },
+    {
+      title: "状态",
+      dataIndex: "status",
+      key: "status",
+      width: 100,
+      render: (status: string) => {
+        const colorMap = { 正常: "green", 预警: "orange", 异常: "red" }
+        return <Tag color={colorMap[status as keyof typeof colorMap]}>{status}</Tag>
+      },
+    },
+    { title: "位置", dataIndex: "location", key: "location", width: 150 },
+    { title: "更新时间", dataIndex: "lastUpdate", key: "lastUpdate", width: 180 },
+  ]
+
+  return (
+    <div className="p-6">
+      <Card title="关键指标实时监测">
+        {/* 实时指标概览 */}
+        <Row gutter={16} className="mb-6">
+          <Col span={6}>
+            <Card size="small" className="text-center">
+              <Statistic
+                title="管网压力"
+                value={realTimeData.pressure.current}
+                suffix="MPa"
+                valueStyle={{ color: getStatusColor(realTimeData.pressure.status) }}
+                prefix={getTrendIcon(realTimeData.pressure.trend, realTimeData.pressure.change)}
+              />
+              <div className="text-xs text-gray-500 mt-2">
+                正常范围: {realTimeData.pressure.normal[0]} - {realTimeData.pressure.normal[1]} MPa
+              </div>
+            </Card>
+          </Col>
+          <Col span={6}>
+            <Card size="small" className="text-center">
+              <Statistic
+                title="流量监测"
+                value={realTimeData.flow.current}
+                suffix="m³/h"
+                valueStyle={{ color: getStatusColor(realTimeData.flow.status) }}
+                prefix={getTrendIcon(realTimeData.flow.trend, realTimeData.flow.change)}
+              />
+              <div className="text-xs text-gray-500 mt-2">
+                正常范围: {realTimeData.flow.normal[0]} - {realTimeData.flow.normal[1]} m³/h
+              </div>
+            </Card>
+          </Col>
+          <Col span={6}>
+            <Card size="small" className="text-center">
+              <Statistic
+                title="温度监测"
+                value={realTimeData.temperature.current}
+                suffix="°C"
+                valueStyle={{ color: getStatusColor(realTimeData.temperature.status) }}
+                prefix={getTrendIcon(realTimeData.temperature.trend, realTimeData.temperature.change)}
+              />
+              <div className="text-xs text-gray-500 mt-2">
+                正常范围: {realTimeData.temperature.normal[0]} - {realTimeData.temperature.normal[1]} °C
+              </div>
+            </Card>
+          </Col>
+          <Col span={6}>
+            <Card size="small" className="text-center">
+              <Statistic
+                title="泄漏检测"
+                value={realTimeData.leakage.current}
+                suffix="ppm"
+                valueStyle={{ color: getStatusColor(realTimeData.leakage.status) }}
+                prefix={getTrendIcon(realTimeData.leakage.trend, realTimeData.leakage.change)}
+              />
+              <div className="text-xs text-gray-500 mt-2">
+                安全范围: {realTimeData.leakage.normal[0]} - {realTimeData.leakage.normal[1]} ppm
+              </div>
+            </Card>
+          </Col>
+        </Row>
+
+        {/* 预警信息 */}
+        {realTimeData.leakage.status === "warning" && (
+          <Alert
+            message="泄漏预警"
+            description="解放路北段检测到燃气泄漏浓度超标,请及时处理"
+            type="warning"
+            icon={<WarningOutlined />}
+            showIcon
+            className="mb-6"
+          />
+        )}
+
+        {/* 图表展示 */}
+        <Row gutter={16} className="mb-6">
+          <Col span={12}>
+            <Card title="压力监测仪表" size="small">
+              <EChart option={gaugeOption} style={{ height: 300 }} />
+            </Card>
+          </Col>
+          <Col span={12}>
+            <Card
+              title="指标趋势分析"
+              size="small"
+              extra={
+                <Select value={selectedIndicator} onChange={setSelectedIndicator} style={{ width: 120 }}>
+                  <Option value="pressure">压力</Option>
+                  <Option value="flow">流量</Option>
+                  <Option value="temperature">温度</Option>
+                  <Option value="leakage">泄漏</Option>
+                </Select>
+              }
+            >
+              <EChart option={areaOption} style={{ height: 300 }} />
+            </Card>
+          </Col>
+        </Row>
+
+        {/* 设备监测状态 */}
+        <Card title="设备监测状态" size="small">
+          <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="normal">正常</Option>
+                <Option value="warning">预警</Option>
+                <Option value="error">异常</Option>
+              </Select>
+              <RangePicker showTime />
+            </Space>
+          </div>
+          <Table
+            columns={deviceColumns}
+            dataSource={mockDeviceData}
+            rowKey="id"
+            pagination={{ pageSize: 10 }}
+            size="small"
+          />
+        </Card>
+      </Card>
+    </div>
+  )
+}