"use client" import {useCallback, useEffect, useState} from "react" import dynamic from "next/dynamic" import { Badge, Button, Card, Checkbox, Col, DatePicker, Dropdown, Form, Input, Layout, Menu, Modal, Progress, Row, Select, Space, Statistic, Switch, Table, Tabs, Tag, } from "antd" // 为避免未定义错误,添加缺失的图标导入 import { BarChartOutlined, BellOutlined, BlockOutlined, CheckOutlined, DashboardOutlined, DownOutlined, EnvironmentOutlined, ExportOutlined, FilterOutlined, LineChartOutlined, MonitorOutlined, PieChartOutlined, ReloadOutlined, SearchOutlined, SettingOutlined, UserOutlined, VideoCameraOutlined, WarningOutlined, } from "@ant-design/icons" import MonitoringCharts from "./components/MonitoringCharts" import AlarmPanel from "./components/AlarmPanel" import VideoMonitoring from "./components/VideoMonitoring" import DataManagement from "./components/DataManagement" import globalMessage from "@/app/_modules/globalMessage" import GisMapBaidu from "@/components/gisMapBaidu"; const { RangePicker } = DatePicker const MapView = dynamic(() => import("./components/MapView"), { ssr: false, loading: () =>
地图加载中...
, }) const { Header, Sider, Content } = Layout const { Option } = Select const { TabPane } = Tabs export default function DrainageMonitoringSystem() { const [selectedMenu, setSelectedMenu] = useState("dashboard") const [collapsed, setCollapsed] = useState(false) const [videoModalVisible, setVideoModalVisible] = useState(false) const [currentTime, setCurrentTime] = useState("") const [notifications, setNotifications] = useState([ { id: 1, message: "人民路积水点液位超过阈值", time: "2分钟前", type: "warning" }, { id: 2, message: "第一泵站设备离线", time: "15分钟前", type: "error" }, ]) const [autoRefresh, setAutoRefresh] = useState(true) const [videoSettingsModal, setVideoSettingsModal] = useState(false) // 只在客户端更新时间,避免服务端和客户端渲染不一致 useEffect(() => { const updateTime = () => { const now = new Date() const hours = now.getHours().toString().padStart(2, "0") const minutes = now.getMinutes().toString().padStart(2, "0") const seconds = now.getSeconds().toString().padStart(2, "0") setCurrentTime(`${hours}:${minutes}:${seconds}`) } updateTime() const interval = setInterval(updateTime, 1000) return () => clearInterval(interval) }, []) // 自动刷新数据 useEffect(() => { let interval: NodeJS.Timeout | null = null if (autoRefresh) { interval = setInterval(() => { // 这里可以添加刷新数据的逻辑 console.log("自动刷新数据") }, 30000) // 30秒刷新一次 } return () => { if (interval) clearInterval(interval) } }, [autoRefresh]) const menuItems = [ { key: "dashboard", icon: , label: "综合监控", }, { key: "data-management", icon: , label: "基础数据管理", }, { key: "real-time-monitoring", icon: , label: "实时监测", }, { key: "alarm-warning", icon: , label: "监测报警", }, { key: "video-monitoring", icon: , label: "视频监测", }, ] const handleButtonClick = (action: string) => { globalMessage.success(`${action} 操作已执行`) } const renderContent = () => { switch (selectedMenu) { case "dashboard": return case "data-management": return case "real-time-monitoring": return case "alarm-warning": return case "video-monitoring": return ( setVideoModalVisible(true)} onButtonClick={handleButtonClick} onRefreshVideos={() => console.log("刷新视频列表")} onVideoSettings={() => setVideoSettingsModal(true)} /> ) default: return } } const notificationMenu = { items: [ { key: 'notification-header', label: (

通知

), }, ...notifications.map(notification => ({ key: `notification-${notification.id}`, label: (
{notification.message} {notification.time}
), })), { key: 'notification-footer', label: (
), } ] } return (

排水管网安全运行监测子系统

管理员 {/* 使用 suppressHydrationWarning 忽略时间显示的 hydration 警告 */} {currentTime}
setSelectedMenu(key)} items={menuItems} className="border-r-0 h-full bg-gray-50" /> {renderContent()} setVideoModalVisible(false)} width={1200} footer={[ , ]} > setVideoSettingsModal(false)} width={600} footer={[ , ]} > ) } function VideoSettingsForm() { const [form] = Form.useForm() const onFinish = (values: any) => { console.log('视频设置:', values) } return (
自动录像 移动侦测 夜视功能
) } function DashboardContent({ onButtonClick, autoRefresh, setAutoRefresh }: { onButtonClick: (action: string) => void, autoRefresh: boolean, setAutoRefresh: (value: boolean) => void }) { const [deviceStats, setDeviceStats] = useState({ total: 1234, online: 1180, alarms: 23, waterPoints: 156 }) const [timeRange, setTimeRange] = useState<[string, string]>(['今天', '']) // 模拟数据更新 const updateStats = useCallback(() => { setDeviceStats(prev => ({ total: prev.total, online: prev.online + Math.floor(Math.random() * 3) - 1, alarms: Math.max(0, prev.alarms + Math.floor(Math.random() * 3) - 1), waterPoints: prev.waterPoints })) }, []) useEffect(() => { if (autoRefresh) { const interval = setInterval(updateStats, 10000) return () => clearInterval(interval) } }, [autoRefresh, updateStats]) const timeRangeOptions = [ { label: '今天', value: 'today' }, { label: '昨天', value: 'yesterday' }, { label: '最近7天', value: '7days' }, { label: '最近30天', value: '30days' }, ] const handleTimeRangeChange = (value: string) => { setTimeRange([value, '']) onButtonClick(`切换时间范围到${value}`) } return (
{/* 控制面板 */ }
时间范围:
自动刷新:
onButtonClick(`执行导出操作: ${key}`) }} >
{/* 统计卡片 */} onButtonClick("查看设备总数详情")} >
在线率: {Math.round((deviceStats.online / deviceStats.total) * 100)}%
onButtonClick("查看在线设备详情")} >
正常 {deviceStats.total - deviceStats.online} 台离线
onButtonClick("查看当前报警详情")} > 0 ? "#cf1322" : "#1890ff" }} suffix="条" />
0 ? "error" : "success"} text={deviceStats.alarms > 0 ? "有报警" : "无报警"} />
onButtonClick("查看易积水点详情")} >
5 ? "error" : "warning"}> {deviceStats.alarms > 5 ? "高风险" : "中风险"}
{/* 地图和图表 */} } > }, { key: 'bar', label: '柱状图', icon: }, { key: 'pie', label: '饼图', icon: }, ], onClick: ({ key }) => onButtonClick(`切换图表类型: ${key}`) }} > } > {/* 报警信息 */} onButtonClick("查看全部报警")}> 查看更多 } >
) } function RealTimeMonitoring({ onButtonClick }: { onButtonClick: (action: string) => void }) { const [filterStatus, setFilterStatus] = useState(null) const [filterType, setFilterType] = useState(null) const [searchText, setSearchText] = useState("") const deviceData = [ { key: "1", deviceId: "FL001", deviceName: "主干道流量计", deviceType: "流量计", status: "online", currentValue: "2.5 m³/s", threshold: "3.0 m³/s", lastUpdate: "2024-01-15 14:29:30", }, { key: "2", deviceId: "LV002", deviceName: "积水点液位计", deviceType: "液位计", status: "alarm", currentValue: "0.8 m", threshold: "0.5 m", lastUpdate: "2024-01-15 14:29:25", }, { key: "3", deviceId: "PS001", deviceName: "第一泵站", deviceType: "泵站", status: "offline", currentValue: "-", threshold: "-", lastUpdate: "2024-01-15 14:25:10", }, { key: "4", deviceId: "LV003", deviceName: "商业区液位计", deviceType: "液位计", status: "online", currentValue: "0.2 m", threshold: "0.5 m", lastUpdate: "2024-01-15 14:29:35", }, ] const filteredData = deviceData.filter(device => { const matchesStatus = !filterStatus || device.status === filterStatus const matchesType = !filterType || device.deviceType === filterType const matchesSearch = !searchText || device.deviceId.toLowerCase().includes(searchText.toLowerCase()) || device.deviceName.toLowerCase().includes(searchText.toLowerCase()) return matchesStatus && matchesType && matchesSearch }) const clearFilters = () => { setFilterStatus(null) setFilterType(null) setSearchText("") } return (
} value={searchText} onChange={e => setSearchText(e.target.value)} style={{ width: 200 }} />
a.deviceId.localeCompare(b.deviceId), }, { title: "设备名称", dataIndex: "deviceName", key: "deviceName", sorter: (a, b) => a.deviceName.localeCompare(b.deviceName), }, { title: "设备类型", dataIndex: "deviceType", key: "deviceType", filters: [ { text: '流量计', value: '流量计' }, { text: '液位计', value: '液位计' }, { text: '泵站', value: '泵站' }, ], onFilter: (value, record) => record.deviceType === value, }, { title: "运行状态", dataIndex: "status", key: "status", filters: [ { text: '在线', value: 'online' }, { text: '离线', value: 'offline' }, { text: '报警', value: 'alarm' }, ], onFilter: (value, record) => record.status === value, render: (status: string) => ( ), }, { title: "当前值", dataIndex: "currentValue", key: "currentValue", sorter: (a, b) => { const aVal = parseFloat(a.currentValue) || 0 const bVal = parseFloat(b.currentValue) || 0 return aVal - bVal }, }, { title: "报警阈值", dataIndex: "threshold", key: "threshold" }, { title: "最后更新", dataIndex: "lastUpdate", key: "lastUpdate", sorter: (a, b) => a.lastUpdate.localeCompare(b.lastUpdate), }, { title: "操作", key: "action", render: (_, record) => ( onButtonClick(`${key === 'repair' ? '维修派单' : key === 'history' ? '查看历史数据' : '设备设置'}: ${record.deviceName}`) }} > ), }, ]} dataSource={filteredData} pagination={{ pageSize: 10, showSizeChanger: true, showQuickJumper: true, }} scroll={{ x: 'max-content' }} /> onButtonClick("刷新积水地图")} > 刷新 } > onButtonClick("刷新管网地图")} > 刷新 } > ) } function VideoMonitoringContent({ onVideoClick, onButtonClick, onRefreshVideos, onVideoSettings }: { onVideoClick: () => void; onButtonClick: (action: string) => void; onRefreshVideos: () => void; onVideoSettings: () => void; }) { const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid') const [selectedVideos, setSelectedVideos] = useState([]) const videoData = [ { id: 1, name: "人民路积水点监控", status: "online", location: "人民路与南京路交叉口" }, { id: 2, name: "第一泵站监控", status: "online", location: "城东泵站" }, { id: 3, name: "主干道管网监控", status: "offline", location: "淮海路主干管网" }, { id: 4, name: "南京路积水点监控", status: "online", location: "南京路商业区" }, { id: 5, name: "第二泵站监控", status: "alarm", location: "城西泵站" }, { id: 6, name: "商业区管网监控", status: "online", location: "中心商业区" }, { id: 7, name: "学校区域监控", status: "online", location: "第一中学附近" }, { id: 8, name: "住宅区监控", status: "offline", location: "阳光小区" }, ] const toggleVideoSelection = (id: number) => { setSelectedVideos(prev => prev.includes(id) ? prev.filter(videoId => videoId !== id) : [...prev, id] ) } const selectAllVideos = () => { setSelectedVideos(videoData.map(video => video.id)) } const clearVideoSelection = () => { setSelectedVideos([]) } return (
} >
{selectedVideos.length > 0 && ( 已选择 {selectedVideos.length} 个视频 )}
{viewMode === 'grid' ? (
{videoData.map((video) => ( toggleVideoSelection(video.id)} >
{video.name} {selectedVideos.includes(video.id) && ( )}
{video.location}
{video.status === "online" ? "在线" : video.status === "alarm" ? "报警" : "离线"}
))}
) : (
( toggleVideoSelection(record.id)} /> ), }, { title: '监控点名称', dataIndex: 'name', key: 'name', }, { title: '位置', dataIndex: 'location', key: 'location', }, { title: '状态', dataIndex: 'status', key: 'status', render: (status: string) => ( ), }, { title: '操作', key: 'action', render: (_, record) => ( ), }, ]} rowSelection={{ selectedRowKeys: selectedVideos, onChange: (selectedRowKeys) => { setSelectedVideos(selectedRowKeys.map(key => Number(key))) }, }} /> )} ) } function AlarmList({ onButtonClick }: { onButtonClick: (action: string) => void }) { const [alarmData] = useState([ { key: "1", time: "2024-01-15 14:25:30", device: "LV002", location: "人民路积水点", level: "高", message: "液位超过报警阈值", status: "未处理", }, { key: "2", time: "2024-01-15 14:20:15", device: "FL001", location: "主干道流量计", level: "中", message: "流量异常波动", status: "处理中", }, { key: "3", time: "2024-01-15 14:15:45", device: "PS001", location: "第一泵站", level: "高", message: "设备离线", status: "未处理", }, { key: "4", time: "2024-01-15 14:10:20", device: "LV003", location: "商业区液位计", level: "低", message: "电池电量低", status: "已处理", }, ]) const [filteredAlarms, setFilteredAlarms] = useState(alarmData) const [statusFilter, setStatusFilter] = useState(null) useEffect(() => { if (statusFilter) { setFilteredAlarms(alarmData.filter(alarm => alarm.status === statusFilter)) } else { setFilteredAlarms(alarmData) } }, [statusFilter, alarmData]) return (
a.time.localeCompare(b.time), }, { title: "设备编号", dataIndex: "device", key: "device" }, { title: "位置", dataIndex: "location", key: "location" }, { title: "报警级别", dataIndex: "level", key: "level", filters: [ { text: '高', value: '高' }, { text: '中', value: '中' }, { text: '低', value: '低' }, ], onFilter: (value, record) => record.level === value, render: (level: string) => ( ), }, { title: "报警信息", dataIndex: "message", key: "message" }, { title: "处理状态", dataIndex: "status", key: "status", filters: [ { text: '未处理', value: '未处理' }, { text: '处理中', value: '处理中' }, { text: '已处理', value: '已处理' }, ], onFilter: (value, record) => record.status === value, render: (status: string) => ( ), }, { title: "操作", key: "action", render: (_, record) => ( {record.status !== "已处理" && ( )} ), }, ]} dataSource={filteredAlarms} pagination={{ pageSize: 5, showSizeChanger: true, showQuickJumper: true, }} size="small" /> ) }