mirror of
https://github.com/Jerryplusy/AI-powered-switches.git
synced 2025-10-14 01:39:18 +00:00
feat:交换机可配置username和password
This commit is contained in:
parent
8d1889bba7
commit
6ce1c89d8c
141
src/frontend/src/components/pages/config/DeviceConfigModal.jsx
Normal file
141
src/frontend/src/components/pages/config/DeviceConfigModal.jsx
Normal file
@ -0,0 +1,141 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Box,
|
||||
Dialog,
|
||||
DialogBackdrop,
|
||||
DialogPositioner,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogBody,
|
||||
DialogFooter,
|
||||
Field,
|
||||
Input,
|
||||
Stack,
|
||||
} from '@chakra-ui/react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { FiCheck } from 'react-icons/fi';
|
||||
import Notification from '@/libs/system/Notification';
|
||||
|
||||
const MotionBox = motion(Box);
|
||||
|
||||
/**
|
||||
* 设备配置弹窗
|
||||
* @param isOpen 是否打开
|
||||
* @param onClose 关闭弹窗
|
||||
* @param onSave 保存修改
|
||||
* @param device 当前设备
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const DeviceConfigModal = ({ isOpen, onClose, onSave, device }) => {
|
||||
const [username, setUsername] = useState(device.username || '');
|
||||
const [password, setPassword] = useState(device.password || '');
|
||||
const [saved, setSaved] = useState(false);
|
||||
|
||||
const handleSave = () => {
|
||||
const updatedDevice = { ...device, username, password };
|
||||
onSave(updatedDevice);
|
||||
setSaved(true);
|
||||
setTimeout(() => {
|
||||
setSaved(false);
|
||||
Notification.success({
|
||||
title: '设备配置已保存!',
|
||||
});
|
||||
onClose();
|
||||
}, 1200);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog.Root open={isOpen} onClose={onClose}>
|
||||
<DialogBackdrop />
|
||||
<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>交换机设备配置</DialogHeader>
|
||||
|
||||
<DialogBody>
|
||||
<Stack gap={4}>
|
||||
<Field.Root>
|
||||
<Field.Label>交换机用户名</Field.Label>
|
||||
<Input
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
placeholder={'请输入设备用户名'}
|
||||
bg={'whiteAlpha.200'}
|
||||
/>
|
||||
</Field.Root>
|
||||
|
||||
<Field.Root>
|
||||
<Field.Label>交换机密码</Field.Label>
|
||||
<Input
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
placeholder={'请输入设备密码'}
|
||||
bg={'whiteAlpha.200'}
|
||||
type={'password'}
|
||||
/>
|
||||
</Field.Root>
|
||||
</Stack>
|
||||
</DialogBody>
|
||||
|
||||
<DialogFooter justifyContent={'space-between'}>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
borderColor={'whiteAlpha.500'}
|
||||
color={'white'}
|
||||
onClick={onClose}
|
||||
_hover={{ bg: 'rgba(0, 0, 255, 0.3)' }}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant={'outline'}
|
||||
borderColor={'whiteAlpha.500'}
|
||||
color={'white'}
|
||||
onClick={handleSave}
|
||||
isDisabled={saved}
|
||||
width={'80px'}
|
||||
position={'relative'}
|
||||
_hover={{ bg: 'rgba(0, 0, 255, 0.3)' }}
|
||||
>
|
||||
{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>
|
||||
)}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</MotionBox>
|
||||
</DialogPositioner>
|
||||
</Dialog.Root>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeviceConfigModal;
|
@ -34,7 +34,6 @@ const ConfigPage = () => {
|
||||
const [editableConfig, setEditableConfig] = useState('');
|
||||
const [applying, setApplying] = useState(false);
|
||||
const [hasParsed, setHasParsed] = useState(false);
|
||||
const [conmmand, setConmmand] = useState([]);
|
||||
const [isPeizhi, setisPeizhi] = useState(false);
|
||||
const [isApplying, setIsApplying] = useState(false);
|
||||
const [applyStatus, setApplyStatus] = useState([]);
|
||||
@ -90,10 +89,6 @@ const ConfigPage = () => {
|
||||
setParsedConfig(JSON.stringify(result.data));
|
||||
setEditableConfig(JSON.stringify(result.data));
|
||||
setHasParsed(true);
|
||||
result = result.data;
|
||||
if (result.config && Array.isArray(result.config.commands)) {
|
||||
setConmmand(result.config.commands);
|
||||
}
|
||||
setisPeizhi(true);
|
||||
}
|
||||
} catch (error) {
|
||||
@ -119,7 +114,7 @@ const ConfigPage = () => {
|
||||
try {
|
||||
const applyOperation = testMode
|
||||
? Common.sleep(1000).then(() => ({ success: true }))
|
||||
: await api.applyConfig(selectedDevice, conmmand);
|
||||
: await api.applyConfig(selectedDevice, JSON.parse(editableConfig)?.config?.commands);
|
||||
|
||||
await Notification.promise({
|
||||
promise: applyOperation,
|
||||
@ -150,7 +145,6 @@ const ConfigPage = () => {
|
||||
<Heading fontSize={'xl'} color={'teal.300'}>
|
||||
交换机配置中心
|
||||
</Heading>
|
||||
|
||||
<Field.Root>
|
||||
<Field.Label fontWeight={'bold'} mb={1} fontSize="sm">
|
||||
选择交换机设备
|
||||
@ -186,7 +180,6 @@ const ConfigPage = () => {
|
||||
</Portal>
|
||||
</Select.Root>
|
||||
</Field.Root>
|
||||
|
||||
<Field.Root>
|
||||
<Field.Label fontWeight={'bold'} mb={1} fontSize="sm">
|
||||
配置指令输入
|
||||
@ -202,7 +195,6 @@ const ConfigPage = () => {
|
||||
size={'sm'}
|
||||
/>
|
||||
</Field.Root>
|
||||
|
||||
<Button
|
||||
colorScheme={'teal'}
|
||||
variant={'solid'}
|
||||
@ -212,7 +204,6 @@ const ConfigPage = () => {
|
||||
>
|
||||
解析配置
|
||||
</Button>
|
||||
|
||||
{isPeizhi && parsedConfig && (
|
||||
<FadeInWrapper delay={0.2}>
|
||||
<VStack spacing={4} align={'stretch'}>
|
||||
@ -256,7 +247,6 @@ const ConfigPage = () => {
|
||||
const updated = JSON.parse(editableConfig);
|
||||
updated.config[key] = newVal;
|
||||
setEditableConfig(JSON.stringify(updated, null, 2));
|
||||
setConmmand(updated);
|
||||
}}
|
||||
/>
|
||||
</Field.Root>
|
||||
|
@ -19,6 +19,7 @@ import ConfigTool from '@/libs/config/ConfigTool';
|
||||
import Common from '@/libs/common';
|
||||
import switchIcon from '@/resources/icon/pages/devices/switch.png';
|
||||
import Notification from '@/libs/system/Notification';
|
||||
import DeviceConfigModal from '@/components/pages/config/DeviceConfigModal';
|
||||
|
||||
/**
|
||||
* 交换机管理
|
||||
@ -29,6 +30,8 @@ const DevicesPage = () => {
|
||||
const [devices, setDevices] = useState([]);
|
||||
const [editingIndex, setEditingIndex] = useState(null);
|
||||
const [editingName, setEditingName] = useState('');
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [currentDevice, setCurrentDevice] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const config = ConfigTool.load();
|
||||
@ -53,6 +56,23 @@ const DevicesPage = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleOpenConfigModal = (device) => {
|
||||
setCurrentDevice(device);
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
|
||||
const handleSaveDeviceConfig = (updatedDevice) => {
|
||||
const updatedDevices = devices.map((device) =>
|
||||
device.ip === updatedDevice.ip ? updatedDevice : device
|
||||
);
|
||||
setDevices(updatedDevices);
|
||||
ConfigTool.save({ ...ConfigTool.load(), devices: updatedDevices });
|
||||
Notification.success({
|
||||
title: '设备配置已保存!',
|
||||
});
|
||||
setIsModalOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<DocumentTitle title={'交换机设备'}>
|
||||
<DashboardBackground />
|
||||
@ -124,6 +144,15 @@ const DevicesPage = () => {
|
||||
{'端口: '}
|
||||
{device.ports.join(', ')}
|
||||
</Text>
|
||||
|
||||
<Button
|
||||
size={'sm'}
|
||||
colorPalette={'teal'}
|
||||
mt={2}
|
||||
onClick={() => handleOpenConfigModal(device)}
|
||||
>
|
||||
配置
|
||||
</Button>
|
||||
</Box>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
@ -134,6 +163,15 @@ const DevicesPage = () => {
|
||||
</VStack>
|
||||
</FadeInWrapper>
|
||||
</PageContainer>
|
||||
|
||||
{isModalOpen && currentDevice && (
|
||||
<DeviceConfigModal
|
||||
isOpen={isModalOpen}
|
||||
onClose={() => setIsModalOpen(false)}
|
||||
onSave={handleSaveDeviceConfig}
|
||||
device={currentDevice}
|
||||
/>
|
||||
)}
|
||||
</DocumentTitle>
|
||||
);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user