Jelajahi Sumber

refactor(test): 重构测试页面并添加新功能

- 修改了 test5 页面的卡片标题
- 新增了 test10 页面,包含以下功能:
  -基于 Ant Design 的综合监控系统界面
  - 实时监测、报警预警、视频监控等功能模块  - 丰富的数据展示组件和交互逻辑
nahida 9 bulan lalu
induk
melakukan
abd00c1350
2 mengubah file dengan 1225 tambahan dan 1 penghapusan
  1. 1224 0
      app/(other)/test10/page.tsx
  2. 1 1
      app/(other)/test5/page.tsx

+ 1224 - 0
app/(other)/test10/page.tsx

@@ -0,0 +1,1224 @@
+"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"
+
+const { RangePicker } = DatePicker
+const MapView = dynamic(() => import("./components/MapView"), {
+  ssr: false,
+  loading: () => <div className="flex items-center justify-center h-full">地图加载中...</div>,
+})
+
+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: <DashboardOutlined />,
+      label: "综合监控",
+    },
+    {
+      key: "data-management",
+      icon: <EnvironmentOutlined />,
+      label: "基础数据管理",
+    },
+    {
+      key: "real-time-monitoring",
+      icon: <MonitorOutlined />,
+      label: "实时监测",
+    },
+    {
+      key: "alarm-warning",
+      icon: <WarningOutlined />,
+      label: "监测报警",
+    },
+    {
+      key: "video-monitoring",
+      icon: <VideoCameraOutlined />,
+      label: "视频监测",
+    },
+  ]
+
+  const handleButtonClick = (action: string) => {
+    globalMessage.success(`${action} 操作已执行`)
+  }
+
+  const renderContent = () => {
+    switch (selectedMenu) {
+      case "dashboard":
+        return <DashboardContent onButtonClick={handleButtonClick} autoRefresh={autoRefresh} setAutoRefresh={setAutoRefresh} />
+      case "data-management":
+        return <DataManagement onButtonClick={handleButtonClick} />
+      case "real-time-monitoring":
+        return <RealTimeMonitoring onButtonClick={handleButtonClick} />
+      case "alarm-warning":
+        return <AlarmPanel onButtonClick={handleButtonClick} />
+      case "video-monitoring":
+        return (
+          <VideoMonitoringContent 
+            onVideoClick={() => setVideoModalVisible(true)} 
+            onButtonClick={handleButtonClick}
+            onRefreshVideos={() => console.log("刷新视频列表")}
+            onVideoSettings={() => setVideoSettingsModal(true)}
+          />
+        )
+      default:
+        return <DashboardContent onButtonClick={handleButtonClick} autoRefresh={autoRefresh} setAutoRefresh={setAutoRefresh} />
+    }
+  }
+
+  const notificationMenu = {
+    items: [
+      {
+        key: 'notification-header',
+        label: (
+          <div className="flex justify-between items-center">
+            <h4 className="font-bold">通知</h4>
+            <Button type="link" size="small">清除所有</Button>
+          </div>
+        ),
+      },
+      ...notifications.map(notification => ({
+        key: `notification-${notification.id}`,
+        label: (
+          <div className="p-2 hover:bg-gray-50">
+            <div className="flex justify-between">
+              <span className={notification.type === "warning" ? "text-orange-500" : "text-red-500"}>
+                {notification.message}
+              </span>
+              <span className="text-gray-400 text-sm">{notification.time}</span>
+            </div>
+          </div>
+        ),
+      })),
+      {
+        key: 'notification-footer',
+        label: (
+          <div className="text-center">
+            <Button type="link">查看全部通知</Button>
+          </div>
+        ),
+      }
+    ]
+  }
+
+  return (
+    <Layout className="h-screen">
+      <Header className="bg-gray-50 border-b border-gray-200 px-4 flex items-center justify-between" style={{ background: "#f8f9fa" }}>
+        <div className="flex items-center space-x-4">
+          <h1 className="text-xl font-bold m-0 text-gray-800">排水管网安全运行监测子系统</h1>
+        </div>
+        <div className="flex items-center space-x-4 text-gray-600">
+          <Dropdown menu={notificationMenu} trigger={["click"]}>
+            <Badge count={notifications.length} size="small">
+              <BellOutlined className="text-lg cursor-pointer" />
+            </Badge>
+          </Dropdown>
+          <span>管理员</span>
+          {/* 使用 suppressHydrationWarning 忽略时间显示的 hydration 警告 */}
+          <span suppressHydrationWarning>{currentTime}</span>
+          <UserOutlined className="text-lg" />
+        </div>
+      </Header>
+
+      <Layout className="flex-1">
+        <Sider
+          collapsible
+          collapsed={collapsed}
+          onCollapse={setCollapsed}
+          className="bg-gray-50 border-r border-gray-200 h-full"
+          width={200}
+        >
+          <Menu
+            mode="inline"
+            selectedKeys={[selectedMenu]}
+            onClick={({ key }) => setSelectedMenu(key)}
+            items={menuItems}
+            className="border-r-0 h-full bg-gray-50"
+          />
+        </Sider>
+
+        <Content className="p-6 bg-white overflow-auto">{renderContent()}</Content>
+      </Layout>
+
+      <Modal
+        title="视频监控"
+        open={videoModalVisible}
+        onCancel={() => setVideoModalVisible(false)}
+        width={1200}
+        footer={[
+          <Button key="close" onClick={() => setVideoModalVisible(false)}>
+            关闭
+          </Button>,
+        ]}
+      >
+        <VideoMonitoring onButtonClick={handleButtonClick} />
+      </Modal>
+
+      <Modal
+        title="视频设置"
+        open={videoSettingsModal}
+        onCancel={() => setVideoSettingsModal(false)}
+        width={600}
+        footer={[
+          <Button key="cancel" onClick={() => setVideoSettingsModal(false)}>
+            取消
+          </Button>,
+          <Button key="submit" type="primary" onClick={() => {
+            setVideoSettingsModal(false)
+            globalMessage.success("视频设置已保存")
+          }}>
+            保存
+          </Button>
+        ]}
+      >
+        <VideoSettingsForm />
+      </Modal>
+    </Layout>
+  )
+}
+
+function VideoSettingsForm() {
+  const [form] = Form.useForm()
+  
+  const onFinish = (values: any) => {
+    console.log('视频设置:', values)
+  }
+
+  return (
+    <Form
+      form={form}
+      layout="vertical"
+      onFinish={onFinish}
+      initialValues={{
+        quality: 'high',
+        autoRecord: false,
+        motionDetection: true,
+        nightVision: true,
+        resolution: '1080p',
+      }}
+    >
+      <Form.Item name="quality" label="视频质量">
+        <Select>
+          <Option value="low">低</Option>
+          <Option value="medium">中</Option>
+          <Option value="high">高</Option>
+          <Option value="ultra">超高清</Option>
+        </Select>
+      </Form.Item>
+      
+      <Form.Item name="resolution" label="分辨率">
+        <Select>
+          <Option value="720p">720p</Option>
+          <Option value="1080p">1080p</Option>
+          <Option value="2k">2K</Option>
+          <Option value="4k">4K</Option>
+        </Select>
+      </Form.Item>
+      
+      <Form.Item name="autoRecord" valuePropName="checked">
+        <Checkbox>自动录像</Checkbox>
+      </Form.Item>
+      
+      <Form.Item name="motionDetection" valuePropName="checked">
+        <Checkbox>移动侦测</Checkbox>
+      </Form.Item>
+      
+      <Form.Item name="nightVision" valuePropName="checked">
+        <Checkbox>夜视功能</Checkbox>
+      </Form.Item>
+      
+      <Form.Item name="storagePath" label="录像存储路径">
+        <Input placeholder="请输入存储路径" />
+      </Form.Item>
+    </Form>
+  )
+}
+
+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 (
+    <div className="space-y-6">
+      {/* 控制面板 */
+      }
+      <Card size="small">
+        <div className="flex flex-wrap items-center justify-between gap-4">
+          <div className="flex items-center space-x-2">
+            <span>时间范围:</span>
+            <Select 
+              defaultValue="today" 
+              onChange={handleTimeRangeChange}
+              size="small"
+            >
+              {timeRangeOptions.map(option => (
+                <Option key={option.value} value={option.value}>{option.label}</Option>
+              ))}
+            </Select>
+            <RangePicker size="small" />
+          </div>
+          
+          <div className="flex items-center space-x-4">
+            <div className="flex items-center space-x-2">
+              <span>自动刷新:</span>
+              <Switch 
+                checked={autoRefresh} 
+                onChange={setAutoRefresh} 
+                size="small"
+              />
+            </div>
+            <Button 
+              icon={<ReloadOutlined />} 
+              onClick={() => {
+                updateStats()
+                onButtonClick("手动刷新数据")
+              }}
+              size="small"
+            >
+              刷新
+            </Button>
+            <Dropdown
+              menu={{
+                items: [
+                  { key: 'export-excel', label: '导出为Excel' },
+                  { key: 'export-pdf', label: '导出为PDF' },
+                  { key: 'export-image', label: '导出为图片' },
+                ],
+                onClick: ({ key }) => onButtonClick(`执行导出操作: ${key}`)
+              }}
+            >
+              <Button icon={<ExportOutlined />} size="small">
+                导出 <DownOutlined />
+              </Button>
+            </Dropdown>
+          </div>
+        </div>
+      </Card>
+
+      {/* 统计卡片 */}
+      <Row gutter={[16, 16]}>
+        <Col span={6}>
+          <Card
+            className="hover:shadow-md transition-shadow cursor-pointer"
+            onClick={() => onButtonClick("查看设备总数详情")}
+          >
+            <Statistic 
+              title="监测设备总数" 
+              value={deviceStats.total} 
+              valueStyle={{ color: "#3f8600" }} 
+              suffix="台" 
+            />
+            <div className="mt-2">
+              <Progress 
+                percent={Math.round((deviceStats.online / deviceStats.total) * 100)} 
+                size="small" 
+                status="normal" 
+              />
+              <div className="text-xs text-gray-500 mt-1">
+                在线率: {Math.round((deviceStats.online / deviceStats.total) * 100)}%
+              </div>
+            </div>
+          </Card>
+        </Col>
+        <Col span={6}>
+          <Card
+            className="hover:shadow-md transition-shadow cursor-pointer"
+            onClick={() => onButtonClick("查看在线设备详情")}
+          >
+            <Statistic 
+              title="在线设备" 
+              value={deviceStats.online} 
+              valueStyle={{ color: "#1890ff" }} 
+              suffix="台" 
+            />
+            <div className="mt-2 flex items-center">
+              <Tag color="success">正常</Tag>
+              <span className="text-xs text-gray-500 ml-2">
+                {deviceStats.total - deviceStats.online} 台离线
+              </span>
+            </div>
+          </Card>
+        </Col>
+        <Col span={6}>
+          <Card
+            className="hover:shadow-md transition-shadow cursor-pointer"
+            onClick={() => onButtonClick("查看当前报警详情")}
+          >
+            <Statistic 
+              title="当前报警" 
+              value={deviceStats.alarms} 
+              valueStyle={{ color: deviceStats.alarms > 0 ? "#cf1322" : "#1890ff" }} 
+              suffix="条" 
+            />
+            <div className="mt-2">
+              <Badge 
+                status={deviceStats.alarms > 0 ? "error" : "success"} 
+                text={deviceStats.alarms > 0 ? "有报警" : "无报警"} 
+              />
+            </div>
+          </Card>
+        </Col>
+        <Col span={6}>
+          <Card
+            className="hover:shadow-md transition-shadow cursor-pointer"
+            onClick={() => onButtonClick("查看易积水点详情")}
+          >
+            <Statistic 
+              title="易积水点" 
+              value={deviceStats.waterPoints} 
+              valueStyle={{ color: "#722ed1" }} 
+              suffix="个" 
+            />
+            <div className="mt-2 flex items-center">
+              <Tag color={deviceStats.alarms > 5 ? "error" : "warning"}>
+                {deviceStats.alarms > 5 ? "高风险" : "中风险"}
+              </Tag>
+            </div>
+          </Card>
+        </Col>
+      </Row>
+
+      {/* 地图和图表 */}
+      <Row gutter={[16, 16]}>
+        <Col span={16}>
+          <Card 
+            title="GIS 一张图" 
+            className="h-96"
+            extra={
+              <Space>
+                <Button size="small" icon={<SettingOutlined />} onClick={() => onButtonClick("地图设置")}>
+                  设置
+                </Button>
+              </Space>
+            }
+          >
+            <MapView />
+          </Card>
+        </Col>
+        <Col span={8}>
+          <Card 
+            title="实时监测数据" 
+            className="h-96"
+            extra={
+              <Dropdown
+                menu={{
+                  items: [
+                    { key: 'line', label: '折线图', icon: <LineChartOutlined /> },
+                    { key: 'bar', label: '柱状图', icon: <BarChartOutlined /> },
+                    { key: 'pie', label: '饼图', icon: <PieChartOutlined /> },
+                  ],
+                  onClick: ({ key }) => onButtonClick(`切换图表类型: ${key}`)
+                }}
+              >
+                <Button size="small" icon={<BarChartOutlined />}>
+                  图表类型 <DownOutlined />
+                </Button>
+              </Dropdown>
+            }
+          >
+            <MonitoringCharts />
+          </Card>
+        </Col>
+      </Row>
+
+      {/* 报警信息 */}
+      <Card 
+        title="最新报警信息"
+        extra={
+          <Button type="link" onClick={() => onButtonClick("查看全部报警")}>
+            查看更多
+          </Button>
+        }
+      >
+        <AlarmList onButtonClick={onButtonClick} />
+      </Card>
+    </div>
+  )
+}
+
+function RealTimeMonitoring({ onButtonClick }: { onButtonClick: (action: string) => void }) {
+  const [filterStatus, setFilterStatus] = useState<string | null>(null)
+  const [filterType, setFilterType] = useState<string | null>(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 (
+    <div className="space-y-6">
+      <Card title="设备运行实时监测">
+        <div className="mb-4">
+          <Space wrap>
+            <Input 
+              placeholder="搜索设备编号或名称" 
+              prefix={<SearchOutlined />} 
+              value={searchText}
+              onChange={e => setSearchText(e.target.value)}
+              style={{ width: 200 }}
+            />
+            <Select 
+              placeholder="设备类型" 
+              style={{ width: 120 }}
+              value={filterType}
+              onChange={setFilterType}
+              allowClear
+            >
+              <Option value="流量计">流量计</Option>
+              <Option value="液位计">液位计</Option>
+              <Option value="泵站">泵站</Option>
+            </Select>
+            <Select 
+              placeholder="运行状态" 
+              style={{ width: 120 }}
+              value={filterStatus}
+              onChange={setFilterStatus}
+              allowClear
+            >
+              <Option value="online">在线</Option>
+              <Option value="offline">离线</Option>
+              <Option value="alarm">报警</Option>
+            </Select>
+            <Button 
+              icon={<FilterOutlined />} 
+              onClick={clearFilters}
+            >
+              清除筛选
+            </Button>
+            <Button 
+              type="primary" 
+              icon={<SearchOutlined />} 
+              onClick={() => onButtonClick("查询设备")}
+            >
+              查询
+            </Button>
+            <Button 
+              icon={<ExportOutlined />} 
+              onClick={() => onButtonClick("导出数据")}
+            >
+              导出
+            </Button>
+            <Button 
+              icon={<ReloadOutlined />} 
+              onClick={() => onButtonClick("刷新数据")}
+            >
+              刷新
+            </Button>
+          </Space>
+        </div>
+
+        <Table
+          columns={[
+            { 
+              title: "设备编号", 
+              dataIndex: "deviceId", 
+              key: "deviceId",
+              sorter: (a, b) => 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) => (
+                <Badge
+                  status={status === "online" ? "success" : status === "offline" ? "default" : "error"}
+                  text={status === "online" ? "在线" : status === "offline" ? "离线" : "报警"}
+                />
+              ),
+            },
+            { 
+              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) => (
+                <Space>
+                  <Button 
+                    size="small" 
+                    onClick={() => onButtonClick(`查看设备详情: ${record.deviceName}`)}
+                  >
+                    详情
+                  </Button>
+                  <Button 
+                    size="small" 
+                    onClick={() => onButtonClick(`设备定位: ${record.deviceName}`)}
+                  >
+                    定位
+                  </Button>
+                  <Dropdown
+                    menu={{
+                      items: [
+                        { key: 'repair', label: '维修派单' },
+                        { key: 'history', label: '历史数据' },
+                        { key: 'settings', label: '设备设置' },
+                      ],
+                      onClick: ({ key }) => onButtonClick(`${key === 'repair' ? '维修派单' : key === 'history' ? '查看历史数据' : '设备设置'}: ${record.deviceName}`)
+                    }}
+                  >
+                    <Button size="small">
+                      更多 <DownOutlined />
+                    </Button>
+                  </Dropdown>
+                </Space>
+              ),
+            },
+          ]}
+          dataSource={filteredData}
+          pagination={{ 
+            pageSize: 10,
+            showSizeChanger: true,
+            showQuickJumper: true,
+          }}
+          scroll={{ x: 'max-content' }}
+        />
+      </Card>
+
+      <Row gutter={[16, 16]}>
+        <Col span={12}>
+          <Card 
+            title="积水情况 GIS 一张图"
+            extra={
+              <Button 
+                size="small" 
+                onClick={() => onButtonClick("刷新积水地图")}
+              >
+                刷新
+              </Button>
+            }
+          >
+            <MapView type="waterlogging" />
+          </Card>
+        </Col>
+        <Col span={12}>
+          <Card 
+            title="管网运行情况 GIS 一张图"
+            extra={
+              <Button 
+                size="small" 
+                onClick={() => onButtonClick("刷新管网地图")}
+              >
+                刷新
+              </Button>
+            }
+          >
+            <MapView type="pipeline" />
+          </Card>
+        </Col>
+      </Row>
+    </div>
+  )
+}
+
+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<number[]>([])
+
+  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 (
+    <div className="space-y-6">
+      <Card 
+        title="视频监控概览"
+        extra={
+          <Space>
+            <Button 
+              icon={viewMode === 'grid' ? <LineChartOutlined /> : <BlockOutlined />} 
+              onClick={() => setViewMode(viewMode === 'grid' ? 'list' : 'grid')}
+            >
+              {viewMode === 'grid' ? '列表视图' : '网格视图'}
+            </Button>
+          </Space>
+        }
+      >
+        <div className="mb-4">
+          <Space wrap>
+            <Button 
+              type="primary" 
+              onClick={onVideoClick}
+              icon={<VideoCameraOutlined />}
+            >
+              打开视频监控
+            </Button>
+            <Button 
+              icon={<ReloadOutlined />} 
+              onClick={() => {
+                onRefreshVideos()
+                globalMessage.success("视频列表已刷新")
+              }}
+            >
+              刷新列表
+            </Button>
+            <Button 
+              icon={<SettingOutlined />} 
+              onClick={() => {
+                onVideoSettings()
+              }}
+            >
+              视频设置
+            </Button>
+            <Button 
+              onClick={selectAllVideos}
+            >
+              全选
+            </Button>
+            <Button 
+              onClick={clearVideoSelection}
+            >
+              清除选择
+            </Button>
+            {selectedVideos.length > 0 && (
+              <span className="text-gray-500">
+                已选择 {selectedVideos.length} 个视频
+              </span>
+            )}
+          </Space>
+        </div>
+        
+        {viewMode === 'grid' ? (
+          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
+            {videoData.map((video) => (
+              <Card 
+                key={video.id} 
+                size="small" 
+                className={`cursor-pointer hover:shadow-md transition-all ${
+                  selectedVideos.includes(video.id) ? 'ring-2 ring-blue-500' : ''
+                }`}
+                onClick={() => toggleVideoSelection(video.id)}
+              >
+                <div className="aspect-video bg-gray-200 flex items-center justify-center relative">
+                  <VideoCameraOutlined className="text-2xl text-gray-400" />
+                  <div className="absolute top-2 right-2">
+                    <Badge 
+                      status={video.status === "online" ? "success" : video.status === "alarm" ? "error" : "default"} 
+                    />
+                  </div>
+                </div>
+                <div className="mt-2">
+                  <div className="font-medium text-sm flex justify-between">
+                    <span>{video.name}</span>
+                    {selectedVideos.includes(video.id) && (
+                      <CheckOutlined className="text-blue-500" />
+                    )}
+                  </div>
+                  <div className="text-xs text-gray-500">{video.location}</div>
+                  <div className="text-xs">
+                    <span className={
+                      video.status === "online" 
+                        ? "text-green-600" 
+                        : video.status === "alarm" 
+                          ? "text-red-600" 
+                          : "text-gray-400"
+                    }>
+                      {video.status === "online" ? "在线" : video.status === "alarm" ? "报警" : "离线"}
+                    </span>
+                  </div>
+                </div>
+              </Card>
+            ))}
+          </div>
+        ) : (
+          <Table
+            dataSource={videoData}
+            columns={[
+              {
+                title: '选择',
+                key: 'selection',
+                render: (_, record) => (
+                  <Checkbox
+                    checked={selectedVideos.includes(record.id)}
+                    onChange={() => toggleVideoSelection(record.id)}
+                  />
+                ),
+              },
+              {
+                title: '监控点名称',
+                dataIndex: 'name',
+                key: 'name',
+              },
+              {
+                title: '位置',
+                dataIndex: 'location',
+                key: 'location',
+              },
+              {
+                title: '状态',
+                dataIndex: 'status',
+                key: 'status',
+                render: (status: string) => (
+                  <Badge
+                    status={status === "online" ? "success" : status === "alarm" ? "error" : "default"}
+                    text={status === "online" ? "在线" : status === "alarm" ? "报警" : "离线"}
+                  />
+                ),
+              },
+              {
+                title: '操作',
+                key: 'action',
+                render: (_, record) => (
+                  <Space>
+                    <Button 
+                      size="small" 
+                      type="primary"
+                      onClick={(e) => {
+                        e.stopPropagation()
+                        onVideoClick()
+                      }}
+                    >
+                      查看
+                    </Button>
+                    <Button 
+                      size="small"
+                      onClick={(e) => {
+                        e.stopPropagation()
+                        onButtonClick(`查看视频详情: ${record.name}`)
+                      }}
+                    >
+                      详情
+                    </Button>
+                  </Space>
+                ),
+              },
+            ]}
+            rowSelection={{
+              selectedRowKeys: selectedVideos,
+              onChange: (selectedRowKeys) => {
+                setSelectedVideos(selectedRowKeys.map(key => Number(key)))
+              },
+            }}
+          />
+        )}
+      </Card>
+    </div>
+  )
+}
+
+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<string | null>(null)
+
+  useEffect(() => {
+    if (statusFilter) {
+      setFilteredAlarms(alarmData.filter(alarm => alarm.status === statusFilter))
+    } else {
+      setFilteredAlarms(alarmData)
+    }
+  }, [statusFilter, alarmData])
+
+  return (
+    <div>
+      <div className="mb-4 flex justify-between">
+        <Space>
+          <Select
+            placeholder="处理状态"
+            style={{ width: 120 }}
+            onChange={setStatusFilter}
+            allowClear
+            value={statusFilter}
+          >
+            <Option value="未处理">未处理</Option>
+            <Option value="处理中">处理中</Option>
+            <Option value="已处理">已处理</Option>
+          </Select>
+          <Button onClick={() => setStatusFilter(null)}>清除筛选</Button>
+        </Space>
+        <Button type="primary" onClick={() => onButtonClick("刷新报警列表")}>
+          刷新
+        </Button>
+      </div>
+      <Table
+        columns={[
+          { 
+            title: "报警时间", 
+            dataIndex: "time", 
+            key: "time",
+            sorter: (a, b) => 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) => (
+              <Badge 
+                color={level === "高" ? "red" : level === "中" ? "orange" : "blue"} 
+                text={level} 
+              />
+            ),
+          },
+          { 
+            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) => (
+              <Badge
+                status={status === "未处理" ? "error" : status === "处理中" ? "processing" : "success"}
+                text={status}
+              />
+            ),
+          },
+          {
+            title: "操作",
+            key: "action",
+            render: (_, record) => (
+              <Space>
+                <Button 
+                  size="small" 
+                  onClick={() => onButtonClick(`查看报警详情: ${record.device}`)}
+                >
+                  详情
+                </Button>
+                {record.status !== "已处理" && (
+                  <Button 
+                    size="small" 
+                    type="primary"
+                    onClick={() => onButtonClick(`处理报警: ${record.device}`)}
+                  >
+                    处理
+                  </Button>
+                )}
+              </Space>
+            ),
+          },
+        ]}
+        dataSource={filteredAlarms}
+        pagination={{
+          pageSize: 5,
+          showSizeChanger: true,
+          showQuickJumper: true,
+        }}
+        size="small"
+      />
+    </div>
+  )
+}

+ 1 - 1
app/(other)/test5/page.tsx

@@ -928,7 +928,7 @@ export default function Page() {
                       </Row>
                     </Card>
 
-                    <Card title="一张图(示意)">
+                    <Card title="(示意)">
                       <div className="relative w-full h-[380px] rounded-md overflow-hidden bg-slate-100">
                         <img
                           src="/images/city-map.png"