| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- "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>
- )
- }
|