初始配置组件,密钥认证组件

This commit is contained in:
Jerry 2025-06-18 16:47:57 +08:00
parent ca6387f6dc
commit 8c71a4c83c
14 changed files with 281 additions and 30 deletions

View File

@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4"> <module type="PYTHON_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="Python" name="Python facet"> <facet type="Python" name="Python facet">
<configuration sdkName="Python 3.10" /> <configuration sdkName="Python 3.13" />
</facet> </facet>
</component> </component>
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
@ -11,5 +11,6 @@
</content> </content>
<orderEntry type="jdk" jdkName="Python 3.13" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="Python 3.13" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Python 3.13 interpreter library" level="application" />
</component> </component>
</module> </module>

View File

@ -25,4 +25,6 @@
- []自然语言解析命令 - []自然语言解析命令
- []下发配置到交换机 - []下发配置到交换机
- []流量预测 - []流量预测
- []图表显示 - []图表显示
172.17.99.208

View File

@ -1,6 +1,6 @@
import { Box, Image } from '@chakra-ui/react'; import { Box, Image } from '@chakra-ui/react';
import { motion } from 'framer-motion'; 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); const MotionBox = motion(Box);

View 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;

View File

@ -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;

View File

@ -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 MotionCard from '@/components/ui/MotionCard';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import FadeInWrapper from '@/components/system/layout/FadeInWrapper'; import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
@ -8,11 +8,17 @@ import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
* @returns {JSX.Element} * @returns {JSX.Element}
* @constructor * @constructor
*/ */
const DashboardCard = () => { const DashboardCard = ({ isConfigured }) => {
const navigate = useNavigate(); const navigate = useNavigate();
const handleClick = () => {
if (isConfigured) {
navigate('/dashboard');
} else {
}
};
return ( return (
<FadeInWrapper delay={0.4} yOffset={-5}> <FadeInWrapper delay={0.4} yOffset={-5}>
<MotionCard icon={manageIcon} text={'管理后台'} onClick={() => navigate('/dashboard')} /> <MotionCard icon={manageIcon} text={'管理后台'} onClick={() => handleClick()} />
</FadeInWrapper> </FadeInWrapper>
); );
}; };

View File

@ -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 MotionCard from '@/components/ui/MotionCard';
import FadeInWrapper from '@/components/system/layout/FadeInWrapper'; import FadeInWrapper from '@/components/system/layout/FadeInWrapper';

View File

@ -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 DashboardCard from '@/components/pages/welcome/DashboardCard';
import FadeInWrapper from '@/components/system/layout/FadeInWrapper'; 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} * @returns {JSX.Element}
* @constructor * @constructor
*/ */
const WelcomeContent = () => { 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 ( return (
<VStack spacing={10} py={200} align={'center'} px={4}> <>
<FadeInWrapper delay={0.2} yOffset={-5}> <VStack spacing={10} py={200} align={'center'} px={4}>
<Box textAlign={'center'}> <FadeInWrapper delay={0.2} yOffset={-5}>
<Heading size="6xl" fontWeight={'black'} color={'teal.300'}> <Box textAlign={'center'}>
智能网络交换机 <Heading size={'6xl'} fontWeight={'black'} color={'teal.300'}>
<br /> 智能网络交换机
管理系统 <br />
</Heading> 管理系统
</Box> </Heading>
</FadeInWrapper> </Box>
<FadeInWrapper delay={0.3} yOffset={-5}> </FadeInWrapper>
<Box textAlign={'center'}> <FadeInWrapper delay={0.3} yOffset={-5}>
<Text mt={6} fontSize={'2xl'} color={'gray.300'}> <Box textAlign={'center'}>
助力大型网络交换机配置及网络流量管理方便的管控网络让网络配置不再困难 <Text mt={6} fontSize={'2xl'} color={'gray.300'}>
</Text> 助力大型网络交换机配置及网络流量管理方便的管控网络让网络配置不再困难
</Box> </Text>
</FadeInWrapper> </Box>
<DashboardCard /> </FadeInWrapper>
</VStack>
<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}
/>
</>
); );
}; };

View File

@ -2,8 +2,8 @@ import { useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { Button, HStack } from '@chakra-ui/react'; import { Button, HStack } from '@chakra-ui/react';
import web from '@/resources/icon/web.svg'; import web from '@/resources/icon/pages/weclome/web.svg';
import githubIcon from '@/resources/welcome/image/github.svg'; import githubIcon from '@/resources/icon/pages/weclome/github.svg';
import FadeInWrapper from '@/components/system/layout/FadeInWrapper'; import FadeInWrapper from '@/components/system/layout/FadeInWrapper';
import MotionCard from '@/components/ui/MotionCard'; import MotionCard from '@/components/ui/MotionCard';

View 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

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 300 B

View File

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB