import React, { useState, useEffect } from 'react'
import { Layout, Menu, theme, Button, Space, Dropdown, message, Drawer, Avatar, Modal, Form, Input, Badge, Tooltip } from 'antd'
import {
DashboardOutlined,
DesktopOutlined,
TeamOutlined,
BellOutlined,
InfoCircleOutlined,
BookOutlined,
MenuOutlined,
LogoutOutlined,
UserOutlined,
DownOutlined,
UserSwitchOutlined,
KeyOutlined,
MessageOutlined
} from '@ant-design/icons'
import axios from 'axios'
import Login from './pages/Login'
import Weather from './components/Weather'
import Dashboard from './pages/Dashboard'
import DeviceManagement from './pages/DeviceManagement'
import PersonnelManagement from './pages/PersonnelManagement'
import NotificationManagement from './pages/NotificationManagement'
import AccountManagement from './pages/AccountManagement'
import Messages from './pages/Messages'
import About from './pages/About'
import Guide from './pages/Guide'
import Download from './pages/Download'
const { Header, Sider, Content } = Layout
// 移动端检测 Hook
function useIsMobile() {
const [isMobile, setIsMobile] = useState(window.innerWidth < 768)
useEffect(() => {
const onResize = () => setIsMobile(window.innerWidth < 768)
window.addEventListener('resize', onResize)
return () => window.removeEventListener('resize', onResize)
}, [])
return isMobile
}
function App() {
const isMobile = useIsMobile()
const [collapsed, setCollapsed] = useState(false)
const [drawerVisible, setDrawerVisible] = useState(false)
const [currentPage, setCurrentPage] = useState('dashboard')
const [user, setUser] = useState(null)
const [checkingAuth, setCheckingAuth] = useState(true)
const [pwdModalVisible, setPwdModalVisible] = useState(false)
const [pwdForm] = Form.useForm()
const [unreadTotal, setUnreadTotal] = useState(0)
const {
token: { colorBgContainer, borderRadiusLG }
} = theme.useToken()
// 初始化时恢复登录态
useEffect(() => {
const token = localStorage.getItem('token')
const savedUser = localStorage.getItem('user')
if (token && savedUser) {
axios.get('/api/auth/me')
.then(res => {
if (res.data.success) setUser(res.data.data)
else handleLogout(false)
})
.catch(() => handleLogout(false))
.finally(() => setCheckingAuth(false))
} else {
setCheckingAuth(false)
}
// 监听登录过期
const onExpired = () => handleLogout(false)
window.addEventListener('auth-expired', onExpired)
return () => window.removeEventListener('auth-expired', onExpired)
}, [])
// 轮询消息未读总数(侧边栏徽标)
useEffect(() => {
if (!user) return
const fetchUnread = () => {
axios.get('/api/chat/conversations')
.then(res => {
if (res.data.success) {
setUnreadTotal(res.data.data.reduce((s, c) => s + (c.unread || 0), 0))
}
})
.catch(() => {})
}
fetchUnread()
const timer = setInterval(fetchUnread, 10000)
return () => clearInterval(timer)
}, [user?.id])
const handleLogin = (userData) => {
setUser(userData)
setCurrentPage('dashboard')
}
const handleLogout = async (callApi = true) => {
if (callApi) {
try { await axios.post('/api/auth/logout') } catch (err) { /* ignore */ }
}
localStorage.removeItem('token')
localStorage.removeItem('user')
setUser(null)
message.success('已安全退出')
}
const getGreeting = () => {
const hour = new Date().getHours()
if (hour < 6) return '晚上好'
if (hour < 9) return '早上好'
if (hour < 12) return '上午好'
if (hour < 14) return '中午好'
if (hour < 18) return '下午好'
return '晚上好'
}
const menuItems = [
{ key: 'dashboard', icon: