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