From a528009674b06c4574cf1d815ea469b137c70628 Mon Sep 17 00:00:00 2001 From: Jerry Date: Thu, 19 Jun 2025 18:45:10 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=9A=E7=9F=A5hook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/App.jsx | 2 + .../layout/github/GithubTransitionCard.jsx | 8 +- src/frontend/src/index.js | 5 +- src/frontend/src/libs/keep | 0 src/frontend/src/libs/system/Notification.jsx | 113 ++++++++++++++++++ src/frontend/src/pages/Dashboard.jsx | 75 +++++++++--- 6 files changed, 182 insertions(+), 21 deletions(-) delete mode 100644 src/frontend/src/libs/keep create mode 100644 src/frontend/src/libs/system/Notification.jsx diff --git a/src/frontend/src/App.jsx b/src/frontend/src/App.jsx index 5140139..4eb355c 100644 --- a/src/frontend/src/App.jsx +++ b/src/frontend/src/App.jsx @@ -1,9 +1,11 @@ import { BrowserRouter, Routes, Route } from 'react-router-dom'; import AppShell from '@/components/system/layout/AppShell'; import buildRoutes from '@/constants/routes/routes'; +import { useEffect } from 'react'; const App = () => { const isProd = process.env.NODE_ENV === 'production'; + useEffect(() => {}, []); return ( diff --git a/src/frontend/src/components/system/layout/github/GithubTransitionCard.jsx b/src/frontend/src/components/system/layout/github/GithubTransitionCard.jsx index f8bb143..cdca96f 100644 --- a/src/frontend/src/components/system/layout/github/GithubTransitionCard.jsx +++ b/src/frontend/src/components/system/layout/github/GithubTransitionCard.jsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { AnimatePresence, motion } from 'framer-motion'; -import { Button, HStack } from '@chakra-ui/react'; +import { Box, Button, HStack } from '@chakra-ui/react'; import web from '@/resources/icon/pages/weclome/web.svg'; import githubIcon from '@/resources/icon/pages/weclome/github.svg'; import FadeInWrapper from '@/components/system/layout/FadeInWrapper'; @@ -31,10 +31,10 @@ const GithubTransitionCard = () => { }, 400); return () => clearTimeout(timer); }, [isDashboard]); - + const MotionBox = motion(Box); return ( - { )} - + ); }; diff --git a/src/frontend/src/index.js b/src/frontend/src/index.js index d021c8d..d22913e 100644 --- a/src/frontend/src/index.js +++ b/src/frontend/src/index.js @@ -2,10 +2,13 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import App from '@/App'; import { Provider } from '@/components/ui/provider'; +import { NotificationProvider } from '@/libs/system/Notification'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( - + + + ); diff --git a/src/frontend/src/libs/keep b/src/frontend/src/libs/keep deleted file mode 100644 index e69de29..0000000 diff --git a/src/frontend/src/libs/system/Notification.jsx b/src/frontend/src/libs/system/Notification.jsx new file mode 100644 index 0000000..2a9c91a --- /dev/null +++ b/src/frontend/src/libs/system/Notification.jsx @@ -0,0 +1,113 @@ +import React, { createContext, useContext, useState, useCallback } from 'react'; +import { Box, Alert, Button, Icon, Text } from '@chakra-ui/react'; +import { AnimatePresence, motion } from 'framer-motion'; +import { AiOutlineInfoCircle, AiFillWarning } from 'react-icons/ai'; + +const NotificationContext = createContext(null); + +/** + * 通知hook + * @returns {null} + */ +export const useNotification = () => useContext(NotificationContext); + +/** + * 通知根组件 + * @param children + * @returns {JSX.Element} + * @constructor + */ +export const NotificationProvider = ({ children }) => { + const [notifications, setNotifications] = useState([]); + + const addNotification = useCallback((notification) => { + const id = Date.now() + Math.random(); + setNotifications((prev) => [...prev, { ...notification, id }]); + + setTimeout(() => { + setNotifications((prev) => prev.filter((n) => n.id !== id)); + }, 3000); + }, []); + + const notify = { + info: ({ title, description, button }) => + addNotification({ + type: 'info', + title, + description, + button, + }), + error: ({ title, description, button }) => + addNotification({ + type: 'error', + title, + description, + button, + }), + }; + + const MotionBox = motion(Box); + + return ( + + {children} + + + {notifications.map((item) => ( + + + + + + {item.title} + + + {item.description} + {item.button && ( + + )} + + + ))} + + + + ); +}; diff --git a/src/frontend/src/pages/Dashboard.jsx b/src/frontend/src/pages/Dashboard.jsx index c1187c9..2607542 100644 --- a/src/frontend/src/pages/Dashboard.jsx +++ b/src/frontend/src/pages/Dashboard.jsx @@ -1,17 +1,13 @@ -import React, { useEffect, useState } from 'react'; -import { Box, Text, VStack, HStack, SimpleGrid, Badge } from '@chakra-ui/react'; +import React, { useEffect, useState, useCallback } from 'react'; +import { Box, Text, VStack, HStack, SimpleGrid, Badge, Button, Spinner } from '@chakra-ui/react'; import DocumentTitle from '@/components/system/pages/DocumentTitle'; import PageContainer from '@/components/system/PageContainer'; import DashboardBackground from '@/components/system/pages/DashboardBackground'; import FadeInWrapper from '@/components/system/layout/FadeInWrapper'; import FeatureCard from '@/components/pages/dashboard/FeatureCard'; import StatCard from '@/components/pages/dashboard/StatCard'; +import { useNotification } from '@/libs/system/Notification'; -/** - * 控制台页面 - * @returns {JSX.Element} - * @constructor - */ const Dashboard = () => { const [stats, setStats] = useState({ totalDevices: 0, @@ -19,7 +15,33 @@ const Dashboard = () => { lastScan: '', }); - useEffect(() => {}, []); + const [networkStatus, setNetworkStatus] = useState('idle'); // idle | loading | ok | fail + const notify = useNotification(); + + const checkBackend = useCallback(async () => { + setNetworkStatus('loading'); + try { + const res = await fetch('/api/test'); + if (res.ok) { + setNetworkStatus('ok'); + notify.info({ title: '成功连接至后端服务!' }); + } else { + setNetworkStatus('fail'); + notify.error({ title: '后端服务响应异常!' }); + } + } catch (err) { + setNetworkStatus('fail'); + notify.error({ title: '无法连接到后端服务!' }); + } + }, [notify]); + + useEffect(() => { + const timer = setTimeout(() => { + checkBackend(); + }, 3000); + + return () => clearTimeout(timer); + }, [checkBackend]); return ( @@ -38,10 +60,10 @@ const Dashboard = () => { _hover={{ transform: 'translateY(-4px)' }} > - {`欢迎使用智能交换机管理系统`} + {'欢迎使用智能交换机管理系统'} - {`实时监控您的网络设备状态,快速配置并掌控全局网络环境`} + {'实时监控您的网络设备状态,快速配置并掌控全局网络环境'} @@ -67,19 +89,40 @@ const Dashboard = () => { _hover={{ transform: 'translateY(-4px)' }} > - {`网络健康状态`} + {'网络健康状态'} - - {`网络连接正常`} - + {networkStatus === 'idle' && ( + + {'等待检测'} + + )} + {networkStatus === 'loading' && ( + + {'检测网络中...'} + + )} + {networkStatus === 'ok' && ( + + {'网络连接正常'} + + )} + {networkStatus === 'fail' && ( + + {'无法连接后端'} + + )} - {`交换机正常运行`} + {'交换机正常运行'} - {`流量监控未启动`} + {'流量监控未启动'} + +