Prechádzať zdrojové kódy

feat(app): 添加 AdminLayout 组件

- 新增 AdminLayout 组件,用于管理后台布局
- 实现了侧边栏、顶部栏、内容区的基本布局结构
- 添加了通知和紧急报警的 Modal 组件
- 集成了 Ant Design 的多个组件,包括 Layout、Menu、Badge、Button、Switch、Modal 等
- 实现了暗黑模式切换功能
nahida 9 mesiacov pred
rodič
commit
b2d316e93e
2 zmenil súbory, kde vykonal 289 pridanie a 0 odobranie
  1. 2 0
      .gitignore
  2. 287 0
      app/(other)/test9/components/admin-layout.tsx

+ 2 - 0
.gitignore

@@ -39,3 +39,5 @@ yarn-error.log*
 # typescript
 *.tsbuildinfo
 next-env.d.ts
+
+.idea

+ 287 - 0
app/(other)/test9/components/admin-layout.tsx

@@ -0,0 +1,287 @@
+"use client"
+
+import type React from "react"
+import {useState} from "react"
+import {Badge, Button, Descriptions, Layout, List, Menu, Modal, Space, Switch, Tag} from "antd"
+import {
+  AlertOutlined,
+  BellOutlined,
+  CheckCircleOutlined,
+  ClockCircleOutlined,
+  DashboardOutlined,
+  DatabaseOutlined,
+  ExclamationCircleOutlined,
+  MenuFoldOutlined,
+  MenuUnfoldOutlined,
+  MonitorOutlined,
+  MoonOutlined,
+  SunOutlined,
+} from "@ant-design/icons"
+import globalMessage from "@/app/_modules/globalMessage";
+
+const { Header, Sider, Content } = Layout
+
+interface AdminLayoutProps {
+  children: React.ReactNode
+  activeKey?: string
+  onMenuSelect?: (key: string) => void
+}
+
+export default function AdminLayout({ children, activeKey = "dashboard", onMenuSelect }: AdminLayoutProps) {
+  const [collapsed, setCollapsed] = useState(false)
+  const [isDarkMode, setIsDarkMode] = useState(false)
+  const [notificationModalVisible, setNotificationModalVisible] = useState(false)
+  const [emergencyModalVisible, setEmergencyModalVisible] = useState(false)
+
+  const menuItems = [
+    { key: "dashboard", icon: <DashboardOutlined />, label: "系统概览" },
+    { key: "facilities", icon: <DatabaseOutlined />, label: "基础数据管理" },
+    { key: "devices", icon: <MonitorOutlined />, label: "监测设备管理" },
+    { key: "monitoring", icon: <MonitorOutlined />, label: "运行监测" },
+    { key: "alarms", icon: <AlertOutlined />, label: "监测报警" },
+  ]
+
+  const notifications = [
+    { id: 1, title: "设备维护提醒", content: "岳麓区泵站#001需要进行定期维护", time: "2024-01-15 14:30", type: "info", read: false },
+    { id: 2, title: "数据同步完成", content: "今日监测数据已成功同步至中央数据库", time: "2024-01-15 12:00", type: "success", read: true },
+    { id: 3, title: "系统更新通知", content: "监测系统将于今晚22:00进行版本更新", time: "2024-01-15 10:15", type: "warning", read: false },
+    { id: 4, title: "月度报告生成", content: "12月份供水监测月度报告已生成完成", time: "2024-01-14 16:45", type: "info", read: true },
+    { id: 5, title: "新设备接入", content: "五一大道新增3台流量监测设备已成功接入系统", time: "2024-01-14 09:20", type: "success", read: false },
+  ]
+
+  const emergencyAlarms = [
+    { id: 1, location: "湘江水源地取水口", type: "水质异常", level: "高", description: "检测到浊度超标,当前值:15.2 NTU,标准值:≤10 NTU", time: "2024-01-15 15:45", status: "处理中" },
+    { id: 2, location: "长沙第一水厂", type: "压力异常", level: "中", description: "出厂压力偏低,当前值:0.25 MPa,标准值:≥0.3 MPa", time: "2024-01-15 14:20", status: "待处理" },
+    { id: 3, location: "岳麓区主管网", type: "流量异常", level: "高", description: "检测到异常流量波动,疑似管道破裂", time: "2024-01-15 13:10", status: "已处理" },
+  ]
+
+  const getNotificationIcon = (type: string) => {
+    switch (type) {
+      case "success": return <CheckCircleOutlined style={{ color: "#52c41a" }} />
+      case "warning": return <ExclamationCircleOutlined style={{ color: "#faad14" }} />
+      default: return <ClockCircleOutlined style={{ color: "#1890ff" }} />
+    }
+  }
+
+  const getAlarmLevelColor = (level: string) => {
+    switch (level) {
+      case "高": return "red"
+      case "中": return "orange"
+      case "低": return "yellow"
+      default: return "default"
+    }
+  }
+
+  const getStatusColor = (status: string) => {
+    switch (status) {
+      case "已处理": return "green"
+      case "处理中": return "blue"
+      case "待处理": return "red"
+      default: return "default"
+    }
+  }
+
+
+  return (
+    <Layout hasSider className="h-screen">
+      {/* 固定侧边栏 */}
+      <Sider
+        trigger={null}
+        collapsible
+        collapsed={collapsed}
+        width={200}
+        className={`shadow-lg fixed left-0 top-0 z-50  transition-all duration-300 ${
+          isDarkMode ? "bg-gray-800" : "bg-white"
+        }`}
+        style={{ background: isDarkMode ? "#1f2937" : "#ffffff" }}
+      >
+        <div
+          className={`h-16 flex items-center justify-center border-b ${
+            isDarkMode ? "border-gray-700" : "border-gray-200"
+          }`}
+        >
+          <div className={`font-bold text-lg ${isDarkMode ? "text-white" : "text-gray-800"}`}>
+            {collapsed ? "供水" : "供水管网监测系统"}
+          </div>
+        </div>
+        <Menu
+          theme={isDarkMode ? "dark" : "light"}
+          mode="inline"
+          selectedKeys={[activeKey]}
+          items={menuItems}
+          onClick={({ key }) => onMenuSelect?.(key)}
+          style={{ background: "transparent", border: "none" }}
+          className="mt-4"
+        />
+      </Sider>
+
+      {/* 右侧内容区 */}
+      <Layout className="transition-all duration-300" >
+        <Header
+          className={`shadow-sm px-4 flex items-center justify-between fixed top-0 right-0 z-9999 transition-all duration-300 ${
+            isDarkMode ? "bg-gray-800 border-gray-700" : "bg-white border-gray-200"
+          }`}
+          style={{
+            width: `calc(100% - ${collapsed?"80px":"200px"})`,
+            background: isDarkMode ? "#111827" : "#f8f9fa",
+          }}
+        >
+          <div className="flex items-center">
+            <Button
+              type="text"
+              icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
+              onClick={() => setCollapsed(!collapsed)}
+              className={`text-lg transition-all duration-200 hover:scale-105 ${
+                isDarkMode ? "text-gray-300 hover:bg-gray-700" : "text-gray-600 hover:bg-gray-100"
+              }`}
+            />
+            <div className="ml-4">
+              <h1 className={`text-xl font-semibold ${isDarkMode ? "text-white" : "text-gray-800"}`}>
+                长沙市供水管网安全运行监测平台
+              </h1>
+            </div>
+          </div>
+          <Space size="large">
+            <div className="flex items-center space-x-2">
+              <SunOutlined className={isDarkMode ? "text-gray-400" : "text-yellow-500"} />
+              <Switch checked={isDarkMode} onChange={setIsDarkMode} size="small" />
+              <MoonOutlined className={isDarkMode ? "text-blue-400" : "text-gray-400"} />
+            </div>
+
+            <Badge count={5} size="small">
+              <Button
+                type="text"
+                icon={<BellOutlined />}
+                onClick={() => setNotificationModalVisible(true)}
+                className={isDarkMode ? "text-gray-300 hover:bg-gray-700" : "text-gray-600 hover:bg-gray-100"}
+              />
+            </Badge>
+
+            <Badge count={3} size="small">
+              <Button
+                type="primary"
+                danger
+                onClick={() => setEmergencyModalVisible(true)}
+                className="hover:scale-105 transition-transform duration-200 shadow-lg hover:shadow-xl"
+              >
+                紧急报警
+              </Button>
+            </Badge>
+          </Space>
+        </Header>
+
+        <Content
+          className={`p-6 pt-[80px] min-h-screen transition-all duration-300 ${
+            isDarkMode ? "bg-gray-900" : "bg-gray-50"
+          }`}
+        >
+          {children}
+        </Content>
+
+
+      </Layout>
+
+      {/* 系统通知 Modal */}
+      <Modal
+        title={
+          <div className="flex items-center">
+            <BellOutlined className="mr-2 text-blue-500" />
+            系统通知
+          </div>
+        }
+        open={notificationModalVisible}
+        onCancel={() => setNotificationModalVisible(false)}
+        footer={[
+          <Button key="close" onClick={() => setNotificationModalVisible(false)}>关闭</Button>,
+          <Button
+            key="markAll"
+            type="primary"
+            onClick={() => {
+              globalMessage.success("已标记所有通知为已读")
+              setNotificationModalVisible(false)
+            }}
+          >
+            全部标记为已读
+          </Button>,
+        ]}
+        width={600}
+      >
+        <List
+          dataSource={notifications}
+          renderItem={(item) => (
+            <List.Item
+              className={`transition-all duration-200 hover:bg-gray-50 rounded-lg p-2 ${
+                !item.read ? "bg-blue-50 border-l-4 border-blue-400" : ""
+              }`}
+            >
+              <List.Item.Meta
+                avatar={getNotificationIcon(item.type)}
+                title={
+                  <div className="flex items-center justify-between">
+                    <span className={!item.read ? "font-semibold" : ""}>{item.title}</span>
+                    {!item.read && <Tag color="blue">未读</Tag>}
+                  </div>
+                }
+                description={
+                  <div>
+                    <p className="mb-1">{item.content}</p>
+                    <span className="text-xs text-gray-400">{item.time}</span>
+                  </div>
+                }
+              />
+            </List.Item>
+          )}
+        />
+      </Modal>
+
+      {/* 紧急报警 Modal */}
+      <Modal
+        title={
+          <div className="flex items-center">
+            <ExclamationCircleOutlined className="mr-2 text-red-500" />
+            紧急报警处理
+          </div>
+        }
+        open={emergencyModalVisible}
+        onCancel={() => setEmergencyModalVisible(false)}
+        footer={[
+          <Button key="close" onClick={() => setEmergencyModalVisible(false)}>关闭</Button>,
+          <Button
+            key="handle"
+            type="primary"
+            danger
+            onClick={() => {
+              globalMessage.success("已派发处理任务给相关人员")
+              setEmergencyModalVisible(false)
+            }}
+          >
+            立即处理
+          </Button>,
+        ]}
+        width={800}
+      >
+        <List
+          dataSource={emergencyAlarms}
+          renderItem={(item) => (
+            <List.Item className="transition-all duration-200 hover:bg-gray-50 rounded-lg p-4 border border-gray-200 mb-3">
+              <div className="w-full">
+                <div className="flex items-center justify-between mb-3">
+                  <div className="flex items-center space-x-2">
+                    <Tag color={getAlarmLevelColor(item.level)}>{item.level}级报警</Tag>
+                    <Tag color={getStatusColor(item.status)}>{item.status}</Tag>
+                  </div>
+                  <span className="text-sm text-gray-500">{item.time}</span>
+                </div>
+                <Descriptions column={1} size="small">
+                  <Descriptions.Item label="报警位置">{item.location}</Descriptions.Item>
+                  <Descriptions.Item label="报警类型">{item.type}</Descriptions.Item>
+                  <Descriptions.Item label="详细描述">{item.description}</Descriptions.Item>
+                </Descriptions>
+              </div>
+            </List.Item>
+          )}
+        />
+      </Modal>
+    </Layout>
+  )
+}