初始配置组件,密钥认证组件
3
.idea/AI-powered-switches.iml
generated
@ -2,7 +2,7 @@
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="Python" name="Python facet">
|
||||
<configuration sdkName="Python 3.10" />
|
||||
<configuration sdkName="Python 3.13" />
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
@ -11,5 +11,6 @@
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.13" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Python 3.13 interpreter library" level="application" />
|
||||
</component>
|
||||
</module>
|
@ -25,4 +25,6 @@
|
||||
- []自然语言解析命令
|
||||
- []下发配置到交换机
|
||||
- []流量预测
|
||||
- []图表显示
|
||||
- []图表显示
|
||||
|
||||
172.17.99.208
|
@ -1,6 +1,6 @@
|
||||
import { Box, Image } from '@chakra-ui/react';
|
||||
import { motion } from 'framer-motion';
|
||||
import image from '@/resources/welcome/image/background.png';
|
||||
import image from '@/resources/image/welcome/background.png';
|
||||
|
||||
const MotionBox = motion(Box);
|
||||
|
||||
|
18
src/frontend/src/components/pages/welcome/ConfigureCard.jsx
Normal file
@ -0,0 +1,18 @@
|
||||
import MotionCard from '@/components/ui/MotionCard';
|
||||
import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
|
||||
import configIcon from '@/resources/icon/pages/weclome/config.svg';
|
||||
|
||||
/**
|
||||
* 连接配置卡片组件
|
||||
* @param onClick 点击事件
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
const ConfigureCard = ({ onClick }) => {
|
||||
return (
|
||||
<FadeInWrapper delay={0.4} yOffset={-5}>
|
||||
<MotionCard icon={configIcon} text={'连接配置'} onClick={onClick} />
|
||||
</FadeInWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfigureCard;
|
@ -0,0 +1,183 @@
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Box,
|
||||
Dialog,
|
||||
DialogBackdrop,
|
||||
DialogPositioner,
|
||||
DialogContent,
|
||||
DialogCloseTrigger,
|
||||
DialogHeader,
|
||||
DialogBody,
|
||||
DialogFooter,
|
||||
Field,
|
||||
Input,
|
||||
Portal,
|
||||
Stack,
|
||||
} from '@chakra-ui/react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { IoClose } from 'react-icons/io5';
|
||||
import { FiCheck } from 'react-icons/fi';
|
||||
|
||||
const MotionBox = motion(Box);
|
||||
const defaultConfig = {
|
||||
backendUrl: '',
|
||||
authKey: '',
|
||||
};
|
||||
|
||||
const ConnectionConfigModal = ({ isOpen, onClose, onSave }) => {
|
||||
const [config, setConfig] = useState(defaultConfig);
|
||||
const [saved, setSaved] = useState(false);
|
||||
const backendRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const savedData = localStorage.getItem('connection-config');
|
||||
if (savedData) {
|
||||
setConfig(JSON.parse(savedData));
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setConfig((prev) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
localStorage.setItem('connection-config', JSON.stringify(config));
|
||||
onSave(config);
|
||||
setSaved(true);
|
||||
setTimeout(() => {
|
||||
setSaved(false);
|
||||
onClose();
|
||||
}, 1200);
|
||||
};
|
||||
|
||||
const handleClear = () => {
|
||||
localStorage.removeItem('connection-config');
|
||||
setConfig(defaultConfig);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog.Root open={isOpen} onClose={onClose} initialFocusEl={() => backendRef.current}>
|
||||
<Portal>
|
||||
<DialogBackdrop backdropFilter={'blur(8px) hue-rotate(0deg)'} bg={'rgba(0, 0, 0, 0.3)'} />
|
||||
<DialogPositioner>
|
||||
<MotionBox
|
||||
as={DialogContent}
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.8 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
bg={'whiteAlpha.100'}
|
||||
backdropFilter={'blur(12px)'}
|
||||
border={'1px solid'}
|
||||
borderColor={'whiteAlpha.300'}
|
||||
>
|
||||
<DialogHeader color={'white'}>地址配置</DialogHeader>
|
||||
<DialogCloseTrigger asChild>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
borderColor={'whiteAlpha.500'}
|
||||
color={'white'}
|
||||
size={'sm'}
|
||||
position={'absolute'}
|
||||
top={3}
|
||||
right={3}
|
||||
onClick={onClose}
|
||||
>
|
||||
<IoClose size={20} color={'white'} />
|
||||
</Button>
|
||||
</DialogCloseTrigger>
|
||||
|
||||
<DialogBody>
|
||||
<Stack gap="4">
|
||||
<Field.Root>
|
||||
<Field.Label color={'white'}>后端连接地址</Field.Label>
|
||||
<Input
|
||||
ref={backendRef}
|
||||
name={'backendUrl'}
|
||||
value={config.backendUrl}
|
||||
onChange={handleChange}
|
||||
placeholder={'http://127.0.0.1:8000'}
|
||||
bg={'whiteAlpha.200'}
|
||||
color={'white'}
|
||||
/>
|
||||
</Field.Root>
|
||||
<Field.Root>
|
||||
<Field.Label color={'white'}>连接密钥</Field.Label>
|
||||
<Input
|
||||
name={'authKey'}
|
||||
type={'password'}
|
||||
value={config.authKey}
|
||||
onChange={handleChange}
|
||||
placeholder={'123456'}
|
||||
bg={'whiteAlpha.200'}
|
||||
color={'white'}
|
||||
/>
|
||||
</Field.Root>
|
||||
</Stack>
|
||||
</DialogBody>
|
||||
|
||||
<DialogFooter justifyContent={'space-between'}>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
borderColor={'whiteAlpha.500'}
|
||||
color={'white'}
|
||||
onClick={handleClear}
|
||||
>
|
||||
清除配置
|
||||
</Button>
|
||||
|
||||
<Stack direction={'row'} spacing={3}>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
borderColor={'whiteAlpha.500'}
|
||||
color={'white'}
|
||||
onClick={onClose}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant={'outline'}
|
||||
borderColor={'whiteAlpha.500'}
|
||||
color={'white'}
|
||||
onClick={handleSave}
|
||||
isDisabled={saved}
|
||||
position={'relative'}
|
||||
width={'80px'}
|
||||
>
|
||||
<AnimatePresence initial={false} mode={'wait'}>
|
||||
{saved ? (
|
||||
<motion.div
|
||||
key={'saved'}
|
||||
initial={{ opacity: 0, scale: 0.5 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.5 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<FiCheck size={20} color={'lightgreen'} />
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
key={'save'}
|
||||
initial={{ opacity: 0, scale: 0.5 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.5 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
保存
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</Button>
|
||||
</Stack>
|
||||
</DialogFooter>
|
||||
</MotionBox>
|
||||
</DialogPositioner>
|
||||
</Portal>
|
||||
</Dialog.Root>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConnectionConfigModal;
|
@ -1,4 +1,4 @@
|
||||
import manageIcon from '@/resources/welcome/image/setting.svg';
|
||||
import manageIcon from '@/resources/icon/pages/weclome/setting.svg';
|
||||
import MotionCard from '@/components/ui/MotionCard';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
|
||||
@ -8,11 +8,17 @@ import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const DashboardCard = () => {
|
||||
const DashboardCard = ({ isConfigured }) => {
|
||||
const navigate = useNavigate();
|
||||
const handleClick = () => {
|
||||
if (isConfigured) {
|
||||
navigate('/dashboard');
|
||||
} else {
|
||||
}
|
||||
};
|
||||
return (
|
||||
<FadeInWrapper delay={0.4} yOffset={-5}>
|
||||
<MotionCard icon={manageIcon} text={'管理后台'} onClick={() => navigate('/dashboard')} />
|
||||
<MotionCard icon={manageIcon} text={'管理后台'} onClick={() => handleClick()} />
|
||||
</FadeInWrapper>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import githubIcon from '@/resources/welcome/image/github.svg';
|
||||
import githubIcon from '@/resources/icon/pages/weclome/github.svg';
|
||||
import MotionCard from '@/components/ui/MotionCard';
|
||||
import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
|
||||
|
||||
|
@ -1,33 +1,73 @@
|
||||
import { Box, Heading, Text, VStack } from '@chakra-ui/react';
|
||||
import { Box, Heading, Text, VStack, HStack } from '@chakra-ui/react';
|
||||
import DashboardCard from '@/components/pages/welcome/DashboardCard';
|
||||
import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
|
||||
import { useState, useEffect } from 'react';
|
||||
import ConnectionConfigModal from '@/components/pages/welcome/ConnectionConfigModal';
|
||||
import ConfigureCard from '@/components/pages/welcome/ConfigureCard';
|
||||
|
||||
/**
|
||||
* 欢迎文字
|
||||
* 欢迎页面内容
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const WelcomeContent = () => {
|
||||
const [showConfigModal, setShowConfigModal] = useState(false);
|
||||
const [isConfigured, setIsConfigured] = useState(false);
|
||||
//const [showAlert, setShowAlert] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const saved = localStorage.getItem('connection-config');
|
||||
if (saved) {
|
||||
setIsConfigured(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleSave = () => {
|
||||
setIsConfigured(true);
|
||||
//setShowAlert(false);
|
||||
};
|
||||
|
||||
const handleConfigureClick = () => {
|
||||
if (!isConfigured) {
|
||||
//setShowAlert(true);
|
||||
}
|
||||
setShowConfigModal(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<VStack spacing={10} py={200} align={'center'} px={4}>
|
||||
<FadeInWrapper delay={0.2} yOffset={-5}>
|
||||
<Box textAlign={'center'}>
|
||||
<Heading size="6xl" fontWeight={'black'} color={'teal.300'}>
|
||||
智能网络交换机
|
||||
<br />
|
||||
管理系统
|
||||
</Heading>
|
||||
</Box>
|
||||
</FadeInWrapper>
|
||||
<FadeInWrapper delay={0.3} yOffset={-5}>
|
||||
<Box textAlign={'center'}>
|
||||
<Text mt={6} fontSize={'2xl'} color={'gray.300'}>
|
||||
助力大型网络交换机配置及网络流量管理,方便的管控网络,让网络配置不再困难
|
||||
</Text>
|
||||
</Box>
|
||||
</FadeInWrapper>
|
||||
<DashboardCard />
|
||||
</VStack>
|
||||
<>
|
||||
<VStack spacing={10} py={200} align={'center'} px={4}>
|
||||
<FadeInWrapper delay={0.2} yOffset={-5}>
|
||||
<Box textAlign={'center'}>
|
||||
<Heading size={'6xl'} fontWeight={'black'} color={'teal.300'}>
|
||||
智能网络交换机
|
||||
<br />
|
||||
管理系统
|
||||
</Heading>
|
||||
</Box>
|
||||
</FadeInWrapper>
|
||||
<FadeInWrapper delay={0.3} yOffset={-5}>
|
||||
<Box textAlign={'center'}>
|
||||
<Text mt={6} fontSize={'2xl'} color={'gray.300'}>
|
||||
助力大型网络交换机配置及网络流量管理,方便的管控网络,让网络配置不再困难
|
||||
</Text>
|
||||
</Box>
|
||||
</FadeInWrapper>
|
||||
|
||||
<FadeInWrapper delay={0.4} yOffset={-5}>
|
||||
<HStack spacing={6}>
|
||||
<DashboardCard isConfigured={isConfigured} />
|
||||
<ConfigureCard onClick={handleConfigureClick} />
|
||||
</HStack>
|
||||
</FadeInWrapper>
|
||||
</VStack>
|
||||
|
||||
<ConnectionConfigModal
|
||||
isOpen={showConfigModal}
|
||||
onClose={() => setShowConfigModal(false)}
|
||||
onSave={handleSave}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -2,8 +2,8 @@ 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 web from '@/resources/icon/web.svg';
|
||||
import githubIcon from '@/resources/welcome/image/github.svg';
|
||||
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';
|
||||
import MotionCard from '@/components/ui/MotionCard';
|
||||
|
||||
|
1
src/frontend/src/resources/icon/pages/weclome/config.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 512 512"><path fill="none" stroke="#2EE2E5" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M262.29 192.31a64 64 0 1 0 57.4 57.4a64.13 64.13 0 0 0-57.4-57.4M416.39 256a154 154 0 0 1-1.53 20.79l45.21 35.46a10.81 10.81 0 0 1 2.45 13.75l-42.77 74a10.81 10.81 0 0 1-13.14 4.59l-44.9-18.08a16.11 16.11 0 0 0-15.17 1.75A164.5 164.5 0 0 1 325 400.8a15.94 15.94 0 0 0-8.82 12.14l-6.73 47.89a11.08 11.08 0 0 1-10.68 9.17h-85.54a11.11 11.11 0 0 1-10.69-8.87l-6.72-47.82a16.07 16.07 0 0 0-9-12.22a155 155 0 0 1-21.46-12.57a16 16 0 0 0-15.11-1.71l-44.89 18.07a10.81 10.81 0 0 1-13.14-4.58l-42.77-74a10.8 10.8 0 0 1 2.45-13.75l38.21-30a16.05 16.05 0 0 0 6-14.08c-.36-4.17-.58-8.33-.58-12.5s.21-8.27.58-12.35a16 16 0 0 0-6.07-13.94l-38.19-30A10.81 10.81 0 0 1 49.48 186l42.77-74a10.81 10.81 0 0 1 13.14-4.59l44.9 18.08a16.11 16.11 0 0 0 15.17-1.75A164.5 164.5 0 0 1 187 111.2a15.94 15.94 0 0 0 8.82-12.14l6.73-47.89A11.08 11.08 0 0 1 213.23 42h85.54a11.11 11.11 0 0 1 10.69 8.87l6.72 47.82a16.07 16.07 0 0 0 9 12.22a155 155 0 0 1 21.46 12.57a16 16 0 0 0 15.11 1.71l44.89-18.07a10.81 10.81 0 0 1 13.14 4.58l42.77 74a10.8 10.8 0 0 1-2.45 13.75l-38.21 30a16.05 16.05 0 0 0-6.05 14.08c.33 4.14.55 8.3.55 12.47"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 300 B After Width: | Height: | Size: 300 B |
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.5 MiB |