Jelajahi Sumber

feat(test11): 新增窨井盖安全运行监测子系统页面

- 添加了 ManholeMonitoringSystem 组件,包含设备管理、GIS地图、实时监测、报警管理等功能模块
- 实现了设备列表展示、地图可视化、实时数据图表、报警记录管理等核心功能- 集成了 EChart、MapView 等组件用于数据展示和地图渲染
- 优化了页面布局和样式,提高了用户体验
nahida 9 bulan lalu
induk
melakukan
42877f0a47
2 mengubah file dengan 1017 tambahan dan 0 penghapusan
  1. 231 0
      app/(other)/test10/components/VideoMonitoring.tsx
  2. 786 0
      app/(other)/test11/page.tsx

+ 231 - 0
app/(other)/test10/components/VideoMonitoring.tsx

@@ -0,0 +1,231 @@
+"use client"
+
+import {useState} from "react"
+import dynamic from "next/dynamic"
+import {Button, Card, Checkbox, Col, Input, Row, Select, Space, Tabs} from "antd"
+import {FullscreenOutlined, PlayCircleOutlined, SearchOutlined} from "@ant-design/icons"
+
+const MapView = dynamic(() => import("./MapView"), {
+  ssr: false,
+  loading: () => <div className="flex items-center justify-center h-full">地图加载中...</div>,
+})
+
+const { Option } = Select
+const { TabPane } = Tabs
+
+export default function VideoMonitoring() {
+  const [selectedVideos, setSelectedVideos] = useState<string[]>([])
+  const [viewMode, setViewMode] = useState<"1" | "4">("4")
+
+  // 模拟视频数据
+  const videoData = [
+    {
+      id: "V001",
+      name: "人民路积水点监控",
+      type: "积水点",
+      location: "人民路与南京路交叉口",
+      status: "online",
+      associatedDevice: "LV002",
+    },
+    {
+      id: "V002",
+      name: "第一泵站监控",
+      type: "泵站",
+      location: "城东泵站",
+      status: "online",
+      associatedDevice: "PS001",
+    },
+    {
+      id: "V003",
+      name: "主干道管网监控",
+      type: "管网",
+      location: "淮海路主干管网",
+      status: "online",
+      associatedDevice: "FL001",
+    },
+    {
+      id: "V004",
+      name: "南京路积水点监控",
+      type: "积水点",
+      location: "南京路商业区",
+      status: "offline",
+      associatedDevice: "LV003",
+    },
+  ]
+
+  const handleVideoSelect = (videoId: string, checked: boolean) => {
+    if (checked) {
+      setSelectedVideos([...selectedVideos, videoId])
+    } else {
+      setSelectedVideos(selectedVideos.filter((id) => id !== videoId))
+    }
+  }
+
+  const renderVideoGrid = () => {
+    const gridCols = viewMode === "1" ? 1 : viewMode === "4" ? 2 : 3
+    const selectedVideoData = videoData.filter((video) => selectedVideos.includes(video.id))
+
+    return (
+      <div className={`grid grid-cols-${gridCols} gap-4 h-96`}>
+        {selectedVideoData.slice(0, Number.parseInt(viewMode)).map((video) => (
+          <Card
+            key={video.id}
+            title={video.name}
+            size="small"
+            className="h-full"
+            extra={
+              <Space>
+                <Button size="small" icon={<PlayCircleOutlined />} />
+                <Button size="small" icon={<FullscreenOutlined />} />
+              </Space>
+            }
+          >
+            <div className="bg-gray-800 h-full flex items-center justify-center text-white">
+              {video.status === "online" ? (
+                <div className="text-center">
+                  <PlayCircleOutlined className="text-4xl mb-2" />
+                  <div>视频监控画面</div>
+                  <div className="text-sm text-gray-300">{video.location}</div>
+                </div>
+              ) : (
+                <div className="text-center text-gray-400">
+                  <div>设备离线</div>
+                  <div className="text-sm">{video.location}</div>
+                </div>
+              )}
+            </div>
+          </Card>
+        ))}
+
+        {/* 填充空白格子 */}
+        {Array.from({ length: Number.parseInt(viewMode) - selectedVideoData.length }).map((_, index) => (
+          <Card key={`empty-${index}`} className="h-full">
+            <div className="bg-gray-100 h-full flex items-center justify-center text-gray-400">
+              <div className="text-center">
+                <div>请选择视频</div>
+              </div>
+            </div>
+          </Card>
+        ))}
+      </div>
+    )
+  }
+
+  return (
+    <div className="space-y-6">
+      <Tabs defaultActiveKey="batch-monitoring">
+        <TabPane tab="视频批量监控" key="batch-monitoring">
+          <Row gutter={[16, 16]}>
+            <Col span={6}>
+              <Card title="视频列表" className="h-full overflow-auto">
+                <div className="mb-4">
+                  <Space direction="vertical" className="w-full">
+                    <Input placeholder="搜索视频" prefix={<SearchOutlined />} />
+                    <Select placeholder="视频类型" className="w-full">
+                      <Option value="waterlogging">积水点</Option>
+                      <Option value="pump">泵站</Option>
+                      <Option value="pipeline">管网</Option>
+                    </Select>
+                  </Space>
+                </div>
+
+                <div className="space-y-2">
+                  {videoData.map((video) => (
+                    <div key={video.id} className="flex items-center space-x-2 p-2 border rounded">
+                      <Checkbox
+                        checked={selectedVideos.includes(video.id)}
+                        onChange={(e) => handleVideoSelect(video.id, e.target.checked)}
+                      />
+                      <div className="flex-1">
+                        <div className="font-medium text-sm">{video.name}</div>
+                        <div className="text-xs text-gray-500">{video.location}</div>
+                        <div className="text-xs">
+                          <span
+                            className={`inline-block w-2 h-2 rounded-full mr-1 ${
+                              video.status === "online" ? "bg-green-500" : "bg-gray-400"
+                            }`}
+                          />
+                          {video.status === "online" ? "在线" : "离线"}
+                        </div>
+                      </div>
+                    </div>
+                  ))}
+                </div>
+              </Card>
+            </Col>
+
+            <Col span={18}>
+              <Card
+                title="视频监控"
+                extra={
+                  <Space>
+                    <span>显示模式:</span>
+                    <Select value={viewMode} onChange={setViewMode} style={{ width: 80 }}>
+                      <Option value="1">1画面</Option>
+                      <Option value="4">4画面</Option>
+                    </Select>
+                  </Space>
+                }
+              >
+                {renderVideoGrid()}
+              </Card>
+            </Col>
+          </Row>
+        </TabPane>
+
+        <TabPane tab="视频地图" key="video-map">
+          <Card title="监测视频 GIS " className="h-96">
+            <MapView type="overview" />
+          </Card>
+        </TabPane>
+
+        <TabPane tab="设备关联" key="device-association">
+          <Card title="设备关联管理">
+            <div className="mb-4">
+              <Space>
+                <Input placeholder="设备编号" prefix={<SearchOutlined />} />
+                <Select placeholder="设备类型" style={{ width: 120 }}>
+                  <Option value="flow">流量计</Option>
+                  <Option value="level">液位计</Option>
+                  <Option value="pump">泵站</Option>
+                </Select>
+                <Button type="primary" icon={<SearchOutlined />}>
+                  查询
+                </Button>
+              </Space>
+            </div>
+
+            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
+              {videoData.map((video) => (
+                <Card key={video.id} size="small">
+                  <div className="space-y-2">
+                    <div>
+                      <strong>视频:</strong> {video.name}
+                    </div>
+                    <div>
+                      <strong>关联设备:</strong> {video.associatedDevice}
+                    </div>
+                    <div>
+                      <strong>位置:</strong> {video.location}
+                    </div>
+                    <div>
+                      <strong>状态:</strong>
+                      <span className={`ml-1 ${video.status === "online" ? "text-green-600" : "text-gray-400"}`}>
+                        {video.status === "online" ? "在线" : "离线"}
+                      </span>
+                    </div>
+                    <div className="pt-2">
+                      <Button size="small" type="primary">
+                        查看视频
+                      </Button>
+                    </div>
+                  </div>
+                </Card>
+              ))}
+            </div>
+          </Card>
+        </TabPane>
+      </Tabs>
+    </div>
+  )
+}

+ 786 - 0
app/(other)/test11/page.tsx

@@ -0,0 +1,786 @@
+"use client"
+
+import {useState} from "react"
+import {
+  Alert,
+  Badge,
+  Button,
+  Card,
+  Col,
+  Form,
+  Input,
+  Layout,
+  Menu,
+  message,
+  Modal,
+  Row,
+  Select,
+  Space,
+  Statistic,
+  Table,
+  Tabs,
+  Tag,
+} from "antd"
+import {
+  AlertOutlined,
+  BarChartOutlined,
+  DashboardOutlined,
+  EditOutlined,
+  EnvironmentOutlined,
+  EyeOutlined,
+  PlusOutlined,
+  SettingOutlined,
+} from "@ant-design/icons"
+import dynamic from "next/dynamic"
+import EChart from "@/components/echarts"
+
+const { Header, Sider, Content } = Layout
+const { TabPane } = Tabs
+const { Option } = Select
+
+// 动态导入地图组件避免SSR问题
+const MapView = dynamic(() => import("./components/map-view"), { ssr: false })
+
+export default function ManholeMonitoringSystem() {
+  const [selectedMenu, setSelectedMenu] = useState("dashboard")
+  const [deviceModalVisible, setDeviceModalVisible] = useState(false)
+  const [selectedDevice, setSelectedDevice] = useState(null)
+  const [addDeviceModalVisible, setAddDeviceModalVisible] = useState(false)
+  const [editDeviceModalVisible, setEditDeviceModalVisible] = useState(false)
+  const [editingDevice, setEditingDevice] = useState(null)
+  const [devices, setDevices] = useState([
+    {
+      id: 1,
+      name: "设备001",
+      type: "智能井盖",
+      status: "normal",
+      location: "朝阳区建国路",
+      lat: 39.9042,
+      lng: 116.4074,
+      battery: 85,
+      signal: 90,
+    },
+    {
+      id: 2,
+      name: "设备002",
+      type: "智能井盖",
+      status: "warning",
+      location: "海淀区中关村",
+      lat: 39.9826,
+      lng: 116.3186,
+      battery: 45,
+      signal: 75,
+    },
+    {
+      id: 3,
+      name: "设备003",
+      type: "智能井盖",
+      status: "error",
+      location: "西城区金融街",
+      lat: 39.926,
+      lng: 116.3663,
+      battery: 20,
+      signal: 60,
+    },
+    {
+      id: 4,
+      name: "设备004",
+      type: "智能井盖",
+      status: "normal",
+      location: "东城区王府井",
+      lat: 39.9097,
+      lng: 116.4109,
+      battery: 92,
+      signal: 95,
+    },
+    {
+      id: 5,
+      name: "设备005",
+      type: "智能井盖",
+      status: "maintenance",
+      location: "丰台区丽泽",
+      lat: 39.8584,
+      lng: 116.3135,
+      battery: 78,
+      signal: 80,
+    },
+  ])
+  const [alerts, setAlerts] = useState([
+    {
+      id: 1,
+      deviceName: "设备002",
+      type: "位移异常",
+      level: "warning",
+      time: "2024-01-15 14:30:25",
+      location: "海淀区中关村",
+      status: "pending", // pending, processed, ignored
+    },
+    {
+      id: 2,
+      deviceName: "设备003",
+      type: "电池电压低",
+      level: "error",
+      time: "2024-01-15 14:25:10",
+      location: "西城区金融街",
+      status: "pending",
+    },
+    {
+      id: 3,
+      deviceName: "设备001",
+      type: "震动异常",
+      level: "info",
+      time: "2024-01-15 14:20:15",
+      location: "朝阳区建国路",
+      status: "processed",
+    },
+  ])
+
+  const [addDeviceForm] = Form.useForm()
+  const [editDeviceForm] = Form.useForm()
+
+  const handleAddDevice = (values: any) => {
+    const newDevice = {
+      id: devices.length + 1,
+      name: values.name,
+      type: values.type,
+      status: values.status,
+      location: values.location,
+      lat: Number.parseFloat(values.lat),
+      lng: Number.parseFloat(values.lng),
+      battery: Number.parseInt(values.battery),
+      signal: Number.parseInt(values.signal),
+    }
+    setDevices([...devices, newDevice])
+    setAddDeviceModalVisible(false)
+    addDeviceForm.resetFields()
+    message.success("设备添加成功!")
+  }
+
+  const handleEditDevice = (values: any) => {
+    const updatedDevices = devices.map((device) =>
+      device.id === editingDevice.id
+        ? {
+          ...device,
+          ...values,
+          lat: Number.parseFloat(values.lat),
+          lng: Number.parseFloat(values.lng),
+          battery: Number.parseInt(values.battery),
+          signal: Number.parseInt(values.signal),
+        }
+        : device,
+    )
+    setDevices(updatedDevices)
+    setEditDeviceModalVisible(false)
+    setEditingDevice(null)
+    editDeviceForm.resetFields()
+    message.success("设备信息更新成功!")
+  }
+
+  const openEditModal = (device: any) => {
+    setEditingDevice(device)
+    editDeviceForm.setFieldsValue(device)
+    setEditDeviceModalVisible(true)
+  }
+
+  const handleProcessAlert = (alertId: number) => {
+    const updatedAlerts = alerts.map((alert) => (alert.id === alertId ? { ...alert, status: "processed" } : alert))
+    setAlerts(updatedAlerts)
+    message.success("报警已处理!")
+  }
+
+  const handleIgnoreAlert = (alertId: number) => {
+    const updatedAlerts = alerts.map((alert) => (alert.id === alertId ? { ...alert, status: "ignored" } : alert))
+    setAlerts(updatedAlerts)
+    message.success("报警已忽略!")
+  }
+
+  // 设备状态统计
+  const deviceStats = {
+    total: devices.length,
+    normal: devices.filter((d) => d.status === "normal").length,
+    warning: devices.filter((d) => d.status === "warning").length,
+    error: devices.filter((d) => d.status === "error").length,
+    maintenance: devices.filter((d) => d.status === "maintenance").length,
+  }
+
+  // 区域分布图表配置
+  const regionChartOption = {
+    title: { text: "设备区域分布", left: "center" },
+    tooltip: { trigger: "item" },
+    series: [
+      {
+        type: "pie",
+        radius: "50%",
+        data: [
+          { value: 1, name: "朝阳区" },
+          { value: 1, name: "海淀区" },
+          { value: 1, name: "西城区" },
+          { value: 1, name: "东城区" },
+          { value: 1, name: "丰台区" },
+        ],
+      },
+    ],
+  }
+
+  // 设备状态分布图表配置
+  const statusChartOption = {
+    title: { text: "设备状态分布", left: "center" },
+    tooltip: { trigger: "item" },
+    series: [
+      {
+        type: "pie",
+        radius: "50%",
+        data: [
+          { value: deviceStats.normal, name: "正常", itemStyle: { color: "#52c41a" } },
+          { value: deviceStats.warning, name: "告警", itemStyle: { color: "#faad14" } },
+          { value: deviceStats.error, name: "故障", itemStyle: { color: "#f5222d" } },
+          { value: deviceStats.maintenance, name: "维修中", itemStyle: { color: "#722ed1" } },
+        ],
+      },
+    ],
+  }
+
+  // 实时监测数据图表配置
+  const monitoringChartOption = {
+    title: { text: "实时监测数据趋势", left: "center" },
+    tooltip: { trigger: "axis" },
+    legend: { data: ["倾斜角度", "位移距离", "震动强度"], top: 30 },
+    xAxis: {
+      type: "category",
+      data: ["00:00", "04:00", "08:00", "12:00", "16:00", "20:00"],
+    },
+    yAxis: { type: "value" },
+    series: [
+      {
+        name: "倾斜角度",
+        type: "line",
+        data: [2.1, 2.3, 2.0, 2.5, 2.8, 2.4],
+        itemStyle: { color: "#1890ff" },
+      },
+      {
+        name: "位移距离",
+        type: "line",
+        data: [0.5, 0.7, 0.4, 0.9, 1.2, 0.8],
+        itemStyle: { color: "#52c41a" },
+      },
+      {
+        name: "震动强度",
+        type: "line",
+        data: [15, 18, 12, 22, 28, 20],
+        itemStyle: { color: "#faad14" },
+      },
+    ],
+  }
+
+  const deviceColumns = [
+    { title: "设备编号", dataIndex: "name", key: "name" },
+    { title: "设备类型", dataIndex: "type", key: "type" },
+    {
+      title: "运维状态",
+      dataIndex: "status",
+      key: "status",
+      render: (status: string) => {
+        const statusMap = {
+          normal: { color: "success", text: "正常" },
+          warning: { color: "warning", text: "告警" },
+          error: { color: "error", text: "故障" },
+          maintenance: { color: "processing", text: "维修中" },
+        }
+        const config = statusMap[status as keyof typeof statusMap]
+        return <Badge status={config.color as any} text={config.text} />
+      },
+    },
+    { title: "所在位置", dataIndex: "location", key: "location" },
+    {
+      title: "电池电量",
+      dataIndex: "battery",
+      key: "battery",
+      render: (battery: number) => `${battery}%`,
+    },
+    {
+      title: "信号强度",
+      dataIndex: "signal",
+      key: "signal",
+      render: (signal: number) => `${signal}%`,
+    },
+    {
+      title: "操作",
+      key: "action",
+      render: (_, record: any) => (
+        <Space>
+          <Button
+            type="link"
+            icon={<EyeOutlined />}
+            onClick={() => {
+              setSelectedDevice(record)
+              setDeviceModalVisible(true)
+            }}
+          >
+            查看
+          </Button>
+          <Button type="link" icon={<EditOutlined />} onClick={() => openEditModal(record)}>
+            编辑
+          </Button>
+        </Space>
+      ),
+    },
+  ]
+
+  const alertColumns = [
+    { title: "设备名称", dataIndex: "deviceName", key: "deviceName" },
+    { title: "报警类型", dataIndex: "type", key: "type" },
+    {
+      title: "报警级别",
+      dataIndex: "level",
+      key: "level",
+      render: (level: string) => {
+        const levelMap = {
+          info: { color: "blue", text: "信息" },
+          warning: { color: "orange", text: "警告" },
+          error: { color: "red", text: "严重" },
+        }
+        const config = levelMap[level as keyof typeof levelMap]
+        return <Tag color={config.color}>{config.text}</Tag>
+      },
+    },
+    { title: "报警时间", dataIndex: "time", key: "time" },
+    { title: "设备位置", dataIndex: "location", key: "location" },
+    {
+      title: "状态",
+      dataIndex: "status",
+      key: "status",
+      render: (status: string) => {
+        const statusMap = {
+          pending: { color: "orange", text: "待处理" },
+          processed: { color: "green", text: "已处理" },
+          ignored: { color: "gray", text: "已忽略" },
+        }
+        const config = statusMap[status as keyof typeof statusMap]
+        return <Tag color={config.color}>{config.text}</Tag>
+      },
+    },
+    {
+      title: "操作",
+      key: "action",
+      render: (_, record: any) => (
+        <Space>
+          {record.status === "pending" && (
+            <>
+              <Button type="link" onClick={() => handleProcessAlert(record.id)}>
+                处理
+              </Button>
+              <Button type="link" onClick={() => handleIgnoreAlert(record.id)}>
+                忽略
+              </Button>
+            </>
+          )}
+          {record.status !== "pending" && <span className="text-gray-400">已处理</span>}
+        </Space>
+      ),
+    },
+  ]
+
+  const renderContent = () => {
+    switch (selectedMenu) {
+      case "dashboard":
+        return (
+          <div className="space-y-6">
+            {/* 统计卡片 */}
+            <Row gutter={16}>
+              <Col span={6}>
+                <Card>
+                  <Statistic title="设备总数" value={deviceStats.total} valueStyle={{ color: "#1890ff" }} />
+                </Card>
+              </Col>
+              <Col span={6}>
+                <Card>
+                  <Statistic title="正常设备" value={deviceStats.normal} valueStyle={{ color: "#52c41a" }} />
+                </Card>
+              </Col>
+              <Col span={6}>
+                <Card>
+                  <Statistic title="告警设备" value={deviceStats.warning} valueStyle={{ color: "#faad14" }} />
+                </Card>
+              </Col>
+              <Col span={6}>
+                <Card>
+                  <Statistic title="故障设备" value={deviceStats.error} valueStyle={{ color: "#f5222d" }} />
+                </Card>
+              </Col>
+            </Row>
+
+            {/* 图表展示 */}
+            <Row gutter={16}>
+              <Col span={12}>
+                <Card title="设备区域分布">
+                  <EChart option={regionChartOption} />
+                </Card>
+              </Col>
+              <Col span={12}>
+                <Card title="设备状态分布">
+                  <EChart option={statusChartOption} />
+                </Card>
+              </Col>
+            </Row>
+
+            {/* 实时监测趋势 */}
+            <Card title="实时监测数据趋势">
+              <EChart option={monitoringChartOption} />
+            </Card>
+          </div>
+        )
+
+      case "devices":
+        return (
+          <div className="space-y-6">
+            <Card
+              title="监测设备台账"
+              extra={
+                <Button type="primary" icon={<PlusOutlined />} onClick={() => setAddDeviceModalVisible(true)}>
+                  添加设备
+                </Button>
+              }
+            >
+              <Table columns={deviceColumns} dataSource={devices} rowKey="id" pagination={{ pageSize: 10 }} />
+            </Card>
+          </div>
+        )
+
+      case "map":
+        return (
+          <div className="space-y-6">
+            <Card title="监测设备 GIS 一张图">
+              <div style={{ height: "600px" }}>
+                <MapView devices={devices} />
+              </div>
+            </Card>
+          </div>
+        )
+
+      case "monitoring":
+        return (
+          <div className="space-y-6">
+            <Row gutter={16}>
+              <Col span={24}>
+                <Alert
+                  message="实时监测状态"
+                  description="系统正在实时监测所有窨井盖设备状态,包括开启、位移、倾斜、震动、溢水等情况"
+                  type="info"
+                  showIcon
+                  className="mb-4"
+                />
+              </Col>
+            </Row>
+
+            <Tabs defaultActiveKey="realtime">
+              <TabPane tab="实时监测" key="realtime">
+                <Row gutter={16}>
+                  <Col span={24}>
+                    <Card title="实时监测一张图">
+                      <div style={{ height: "500px" }}>
+                        <MapView devices={devices} showRealTimeData />
+                      </div>
+                    </Card>
+                  </Col>
+                </Row>
+              </TabPane>
+
+              <TabPane tab="监测数据" key="data">
+                <Card title="实时监测数据">
+                  <EChart option={monitoringChartOption} />
+                </Card>
+              </TabPane>
+            </Tabs>
+          </div>
+        )
+
+      case "alerts":
+        return (
+          <div className="space-y-6">
+            <Row gutter={16}>
+              <Col span={6}>
+                <Card>
+                  <Statistic title="今日告警" value={alerts.length} valueStyle={{ color: "#f5222d" }} />
+                </Card>
+              </Col>
+              <Col span={6}>
+                <Card>
+                  <Statistic
+                    title="待处理"
+                    value={alerts.filter((a) => a.status === "pending").length}
+                    valueStyle={{ color: "#faad14" }}
+                  />
+                </Card>
+              </Col>
+              <Col span={6}>
+                <Card>
+                  <Statistic
+                    title="已处理"
+                    value={alerts.filter((a) => a.status === "processed").length}
+                    valueStyle={{ color: "#52c41a" }}
+                  />
+                </Card>
+              </Col>
+              <Col span={6}>
+                <Card>
+                  <Statistic
+                    title="已忽略"
+                    value={alerts.filter((a) => a.status === "ignored").length}
+                    valueStyle={{ color: "#d9d9d9" }}
+                  />
+                </Card>
+              </Col>
+            </Row>
+
+            <Card title="监测报警记录">
+              <Table columns={alertColumns} dataSource={alerts} rowKey="id" pagination={{ pageSize: 10 }} />
+            </Card>
+          </div>
+        )
+
+      default:
+        return <div>页面开发中...</div>
+    }
+  }
+
+  return (
+    <Layout className="min-h-screen">
+      <Header className="bg-blue-600 text-white" style={{backgroundColor:'white'}}>
+        <div className="flex items-center justify-between">
+          <h1 className="text-xl font-bold">窨井盖安全运行监测子系统</h1>
+          <div className="text-sm">当前时间: {new Date().toLocaleString("zh-CN")}</div>
+        </div>
+      </Header>
+
+      <Layout>
+        <Sider width={200} className="bg-white">
+          <Menu
+            mode="inline"
+            selectedKeys={[selectedMenu]}
+            onClick={({ key }) => setSelectedMenu(key)}
+            className="h-full border-r"
+          >
+            <Menu.Item key="dashboard" icon={<DashboardOutlined />}>
+              监控面板
+            </Menu.Item>
+            <Menu.Item key="devices" icon={<SettingOutlined />}>
+              设备管理
+            </Menu.Item>
+            <Menu.Item key="map" icon={<EnvironmentOutlined />}>
+              GIS地图
+            </Menu.Item>
+            <Menu.Item key="monitoring" icon={<BarChartOutlined />}>
+              实时监测
+            </Menu.Item>
+            <Menu.Item key="alerts" icon={<AlertOutlined />}>
+              报警管理
+            </Menu.Item>
+          </Menu>
+        </Sider>
+
+        <Layout className="p-6">
+          <Content className="bg-gray-50 min-h-full">{renderContent()}</Content>
+        </Layout>
+      </Layout>
+
+      {/* 设备详情弹窗 */}
+      <Modal
+        title="设备详情"
+        open={deviceModalVisible}
+        onCancel={() => setDeviceModalVisible(false)}
+        footer={null}
+        width={600}
+      >
+        {selectedDevice && (
+          <div className="space-y-4">
+            <Row gutter={16}>
+              <Col span={12}>
+                <div>
+                  <strong>设备编号:</strong> {selectedDevice.name}
+                </div>
+              </Col>
+              <Col span={12}>
+                <div>
+                  <strong>设备类型:</strong> {selectedDevice.type}
+                </div>
+              </Col>
+            </Row>
+            <Row gutter={16}>
+              <Col span={12}>
+                <div>
+                  <strong>所在位置:</strong> {selectedDevice.location}
+                </div>
+              </Col>
+              <Col span={12}>
+                <div>
+                  <strong>运维状态:</strong>
+                  <Badge
+                    status={selectedDevice.status === "normal" ? "success" : "error"}
+                    text={selectedDevice.status === "normal" ? "正常" : "异常"}
+                  />
+                </div>
+              </Col>
+            </Row>
+            <Row gutter={16}>
+              <Col span={12}>
+                <div>
+                  <strong>电池电量:</strong> {selectedDevice.battery}%
+                </div>
+              </Col>
+              <Col span={12}>
+                <div>
+                  <strong>信号强度:</strong> {selectedDevice.signal}%
+                </div>
+              </Col>
+            </Row>
+          </div>
+        )}
+      </Modal>
+
+      {/* 添加设备弹窗 */}
+      <Modal
+        title="添加设备"
+        open={addDeviceModalVisible}
+        onCancel={() => {
+          setAddDeviceModalVisible(false)
+          addDeviceForm.resetFields()
+        }}
+        onOk={() => addDeviceForm.submit()}
+        width={600}
+      >
+        <Form form={addDeviceForm} layout="vertical" onFinish={handleAddDevice}>
+          <Row gutter={16}>
+            <Col span={12}>
+              <Form.Item name="name" label="设备编号" rules={[{ required: true, message: "请输入设备编号" }]}>
+                <Input placeholder="请输入设备编号" />
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item name="type" label="设备类型" rules={[{ required: true, message: "请选择设备类型" }]}>
+                <Select placeholder="请选择设备类型">
+                  <Option value="智能井盖">智能井盖</Option>
+                  <Option value="传感器">传感器</Option>
+                  <Option value="监控设备">监控设备</Option>
+                </Select>
+              </Form.Item>
+            </Col>
+          </Row>
+          <Row gutter={16}>
+            <Col span={12}>
+              <Form.Item name="status" label="运维状态" rules={[{ required: true, message: "请选择运维状态" }]}>
+                <Select placeholder="请选择运维状态">
+                  <Option value="normal">正常</Option>
+                  <Option value="warning">告警</Option>
+                  <Option value="error">故障</Option>
+                  <Option value="maintenance">维修中</Option>
+                </Select>
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item name="location" label="所在位置" rules={[{ required: true, message: "请输入所在位置" }]}>
+                <Input placeholder="请输入所在位置" />
+              </Form.Item>
+            </Col>
+          </Row>
+          <Row gutter={16}>
+            <Col span={12}>
+              <Form.Item name="lat" label="纬度" rules={[{ required: true, message: "请输入纬度" }]}>
+                <Input placeholder="请输入纬度" type="number" step="0.000001" />
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item name="lng" label="经度" rules={[{ required: true, message: "请输入经度" }]}>
+                <Input placeholder="请输入经度" type="number" step="0.000001" />
+              </Form.Item>
+            </Col>
+          </Row>
+          <Row gutter={16}>
+            <Col span={12}>
+              <Form.Item name="battery" label="电池电量(%)" rules={[{ required: true, message: "请输入电池电量" }]}>
+                <Input placeholder="请输入电池电量" type="number" min="0" max="100" />
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item name="signal" label="信号强度(%)" rules={[{ required: true, message: "请输入信号强度" }]}>
+                <Input placeholder="请输入信号强度" type="number" min="0" max="100" />
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </Modal>
+
+      {/* 编辑设备弹窗 */}
+      <Modal
+        title="编辑设备"
+        open={editDeviceModalVisible}
+        onCancel={() => {
+          setEditDeviceModalVisible(false)
+          setEditingDevice(null)
+          editDeviceForm.resetFields()
+        }}
+        onOk={() => editDeviceForm.submit()}
+        width={600}
+      >
+        <Form form={editDeviceForm} layout="vertical" onFinish={handleEditDevice}>
+          <Row gutter={16}>
+            <Col span={12}>
+              <Form.Item name="name" label="设备编号" rules={[{ required: true, message: "请输入设备编号" }]}>
+                <Input placeholder="请输入设备编号" />
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item name="type" label="设备类型" rules={[{ required: true, message: "请选择设备类型" }]}>
+                <Select placeholder="请选择设备类型">
+                  <Option value="智能井盖">智能井盖</Option>
+                  <Option value="传感器">传感器</Option>
+                  <Option value="监控设备">监控设备</Option>
+                </Select>
+              </Form.Item>
+            </Col>
+          </Row>
+          <Row gutter={16}>
+            <Col span={12}>
+              <Form.Item name="status" label="运维状态" rules={[{ required: true, message: "请选择运维状态" }]}>
+                <Select placeholder="请选择运维状态">
+                  <Option value="normal">正常</Option>
+                  <Option value="warning">告警</Option>
+                  <Option value="error">故障</Option>
+                  <Option value="maintenance">维修中</Option>
+                </Select>
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item name="location" label="所在位置" rules={[{ required: true, message: "请输入所在位置" }]}>
+                <Input placeholder="请输入所在位置" />
+              </Form.Item>
+            </Col>
+          </Row>
+          <Row gutter={16}>
+            <Col span={12}>
+              <Form.Item name="lat" label="纬度" rules={[{ required: true, message: "请输入纬度" }]}>
+                <Input placeholder="请输入纬度" type="number" step="0.000001" />
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item name="lng" label="经度" rules={[{ required: true, message: "请输入经度" }]}>
+                <Input placeholder="请输入经度" type="number" step="0.000001" />
+              </Form.Item>
+            </Col>
+          </Row>
+          <Row gutter={16}>
+            <Col span={12}>
+              <Form.Item name="battery" label="电池电量(%)" rules={[{ required: true, message: "请输入电池电量" }]}>
+                <Input placeholder="请输入电池电量" type="number" min="0" max="100" />
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item name="signal" label="信号强度(%)" rules={[{ required: true, message: "请输入信号强度" }]}>
+                <Input placeholder="请输入信号强度" type="number" min="0" max="100" />
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </Modal>
+    </Layout>
+  )
+}