mirror of
https://github.com/Jerryplusy/AI-powered-switches.git
synced 2025-10-14 09:49:19 +00:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
2980489b5b
138
src/frontend/src/components/pages/config/DeviceConfigModal.jsx
Normal file
138
src/frontend/src/components/pages/config/DeviceConfigModal.jsx
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
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);
|
||||||
|
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;
|
@ -8,10 +8,12 @@ import {
|
|||||||
HStack,
|
HStack,
|
||||||
Portal,
|
Portal,
|
||||||
Select,
|
Select,
|
||||||
|
Spinner,
|
||||||
Text,
|
Text,
|
||||||
Textarea,
|
Textarea,
|
||||||
VStack,
|
VStack,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
import DocumentTitle from '@/components/system/pages/DocumentTitle';
|
import DocumentTitle from '@/components/system/pages/DocumentTitle';
|
||||||
import PageContainer from '@/components/system/PageContainer';
|
import PageContainer from '@/components/system/PageContainer';
|
||||||
import DashboardBackground from '@/components/system/pages/DashboardBackground';
|
import DashboardBackground from '@/components/system/pages/DashboardBackground';
|
||||||
@ -32,6 +34,9 @@ const ConfigPage = () => {
|
|||||||
const [editableConfig, setEditableConfig] = useState('');
|
const [editableConfig, setEditableConfig] = useState('');
|
||||||
const [applying, setApplying] = useState(false);
|
const [applying, setApplying] = useState(false);
|
||||||
const [hasParsed, setHasParsed] = useState(false);
|
const [hasParsed, setHasParsed] = useState(false);
|
||||||
|
const [isPeizhi, setisPeizhi] = useState(false);
|
||||||
|
const [isApplying, setIsApplying] = useState(false);
|
||||||
|
const [applyStatus, setApplyStatus] = useState([]);
|
||||||
|
|
||||||
const deviceCollection = createListCollection({
|
const deviceCollection = createListCollection({
|
||||||
items: devices.map((device) => ({
|
items: devices.map((device) => ({
|
||||||
@ -79,12 +84,12 @@ const ConfigPage = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await resultWrapper.unwrap();
|
let result = await resultWrapper.unwrap();
|
||||||
|
if (result?.data) {
|
||||||
if (result?.config) {
|
setParsedConfig(JSON.stringify(result.data));
|
||||||
setParsedConfig(result.config);
|
setEditableConfig(JSON.stringify(result.data));
|
||||||
setEditableConfig(result.config);
|
|
||||||
setHasParsed(true);
|
setHasParsed(true);
|
||||||
|
setisPeizhi(true);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('配置解析异常:', error);
|
console.error('配置解析异常:', error);
|
||||||
@ -105,10 +110,11 @@ const ConfigPage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setApplying(true);
|
setApplying(true);
|
||||||
|
setIsApplying(true);
|
||||||
try {
|
try {
|
||||||
const applyOperation = testMode
|
const applyOperation = testMode
|
||||||
? Common.sleep(1000).then(() => ({ success: true }))
|
? Common.sleep(1000).then(() => ({ success: true }))
|
||||||
: await api.applyConfig(selectedDevice, editableConfig);
|
: await api.applyConfig(selectedDevice, JSON.parse(editableConfig)?.config?.commands);
|
||||||
|
|
||||||
await Notification.promise({
|
await Notification.promise({
|
||||||
promise: applyOperation,
|
promise: applyOperation,
|
||||||
@ -139,7 +145,6 @@ const ConfigPage = () => {
|
|||||||
<Heading fontSize={'xl'} color={'teal.300'}>
|
<Heading fontSize={'xl'} color={'teal.300'}>
|
||||||
交换机配置中心
|
交换机配置中心
|
||||||
</Heading>
|
</Heading>
|
||||||
|
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
<Field.Label fontWeight={'bold'} mb={1} fontSize="sm">
|
<Field.Label fontWeight={'bold'} mb={1} fontSize="sm">
|
||||||
选择交换机设备
|
选择交换机设备
|
||||||
@ -175,21 +180,21 @@ const ConfigPage = () => {
|
|||||||
</Portal>
|
</Portal>
|
||||||
</Select.Root>
|
</Select.Root>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
|
|
||||||
<Field.Root>
|
<Field.Root>
|
||||||
<Field.Label fontWeight={'bold'} mb={1} fontSize="sm">
|
<Field.Label fontWeight={'bold'} mb={1} fontSize="sm">
|
||||||
配置指令输入
|
配置指令输入
|
||||||
</Field.Label>
|
</Field.Label>
|
||||||
<Textarea
|
<Textarea
|
||||||
rows={4}
|
rows={4}
|
||||||
placeholder={'例子:创建VLAN 10并配置IP 192.168.10.1/24并在端口1启用SSH访问"'}
|
placeholder={'例:创建VLAN 10并配置IP 192.168.10.1/24并在端口1启用SSH访问"'}
|
||||||
value={inputText}
|
value={inputText}
|
||||||
|
colorPalette={'teal'}
|
||||||
|
orientation={'vertical'}
|
||||||
onChange={(e) => setInputText(e.target.value)}
|
onChange={(e) => setInputText(e.target.value)}
|
||||||
bg={'whiteAlpha.200'}
|
bg={'whiteAlpha.200'}
|
||||||
size={'sm'}
|
size={'sm'}
|
||||||
/>
|
/>
|
||||||
</Field.Root>
|
</Field.Root>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
colorScheme={'teal'}
|
colorScheme={'teal'}
|
||||||
variant={'solid'}
|
variant={'solid'}
|
||||||
@ -199,29 +204,74 @@ const ConfigPage = () => {
|
|||||||
>
|
>
|
||||||
解析配置
|
解析配置
|
||||||
</Button>
|
</Button>
|
||||||
|
{isPeizhi && parsedConfig && (
|
||||||
|
<FadeInWrapper delay={0.2}>
|
||||||
|
<VStack spacing={4} align={'stretch'}>
|
||||||
|
{(() => {
|
||||||
|
let parsed;
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(editableConfig);
|
||||||
|
} catch (e) {
|
||||||
|
return <Text color={'red.300'}>配置 JSON 格式错误,无法解析</Text>;
|
||||||
|
}
|
||||||
|
|
||||||
{hasParsed && (
|
const config = parsed.config ? [parsed.config] : parsed;
|
||||||
<FadeInWrapper>
|
return config.map((cfg, idx) => (
|
||||||
<Box
|
<Box
|
||||||
|
key={idx}
|
||||||
p={4}
|
p={4}
|
||||||
bg={'whiteAlpha.100'}
|
bg={'whiteAlpha.100'}
|
||||||
borderRadius={'xl'}
|
borderRadius={'xl'}
|
||||||
border={'1px solid'}
|
border={'1px solid'}
|
||||||
borderColor={'whiteAlpha.300'}
|
borderColor={'whiteAlpha.300'}
|
||||||
>
|
>
|
||||||
<Text fontWeight={'bold'} mb={2} fontSize="sm">
|
<Text fontSize={'lg'} fontWeight={'bold'} mb={2}>
|
||||||
生成配置:
|
配置类型: {cfg.type}
|
||||||
</Text>
|
</Text>
|
||||||
<Textarea
|
|
||||||
value={JSON.stringify(editableConfig)}
|
|
||||||
rows={12}
|
|
||||||
onChange={(e) => setEditableConfig(e.target.value)}
|
|
||||||
fontFamily={'monospace'}
|
|
||||||
size={'sm'}
|
|
||||||
bg={'blackAlpha.200'}
|
|
||||||
whiteSpace="pre-wrap"
|
|
||||||
/>
|
|
||||||
|
|
||||||
|
{Object.entries(cfg).map(([key, value]) => {
|
||||||
|
if (key === 'type' || key === 'commands') return null;
|
||||||
|
return (
|
||||||
|
<Field.Root
|
||||||
|
key={key}
|
||||||
|
colorPalette={'teal'}
|
||||||
|
orientation={'vertical'}
|
||||||
|
mb={3}
|
||||||
|
>
|
||||||
|
<Field.Label fontSize={'sm'}>{key}</Field.Label>
|
||||||
|
<Textarea
|
||||||
|
size={'sm'}
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newVal = e.target.value;
|
||||||
|
const updated = JSON.parse(editableConfig);
|
||||||
|
updated.config[key] = newVal;
|
||||||
|
setEditableConfig(JSON.stringify(updated, null, 2));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Field.Root>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<Text fontWeight={'semibold'} mt={3} mb={2}>
|
||||||
|
配置命令:
|
||||||
|
</Text>
|
||||||
|
{cfg.commands?.map((cmd, i) => (
|
||||||
|
<Field.Root key={i} colorPalette={'teal'} orientation={'vertical'} mb={2}>
|
||||||
|
<Field.Label fontSize="sm">命令 {i + 1}</Field.Label>
|
||||||
|
<Textarea
|
||||||
|
size={'sm'}
|
||||||
|
fontFamily={'monospace'}
|
||||||
|
value={cmd}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newCmd = e.target.value;
|
||||||
|
const updated = JSON.parse(editableConfig);
|
||||||
|
updated.config.commands[i] = newCmd;
|
||||||
|
setEditableConfig(JSON.stringify(updated, null, 2));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Field.Root>
|
||||||
|
))}
|
||||||
<HStack mt={4} spacing={3} justify={'flex-end'}>
|
<HStack mt={4} spacing={3} justify={'flex-end'}>
|
||||||
<Button
|
<Button
|
||||||
variant={'outline'}
|
variant={'outline'}
|
||||||
@ -237,6 +287,21 @@ const ConfigPage = () => {
|
|||||||
>
|
>
|
||||||
重置为原始配置
|
重置为原始配置
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
size={'sm'}
|
||||||
|
variant={'outline'}
|
||||||
|
colorScheme={'gray'}
|
||||||
|
onClick={() => {
|
||||||
|
Notification.success({
|
||||||
|
title: `配置 ${cfg.type} 已保存`,
|
||||||
|
description: '修改已同步至内存配置',
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
保存当前配置
|
||||||
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
colorScheme={'teal'}
|
colorScheme={'teal'}
|
||||||
size={'sm'}
|
size={'sm'}
|
||||||
@ -248,6 +313,58 @@ const ConfigPage = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</HStack>
|
</HStack>
|
||||||
</Box>
|
</Box>
|
||||||
|
));
|
||||||
|
})()}
|
||||||
|
|
||||||
|
{
|
||||||
|
<FadeInWrapper delay={0.2}>
|
||||||
|
<VStack spacing={4} align={'stretch'}>
|
||||||
|
<Box
|
||||||
|
p={4}
|
||||||
|
bg={'whiteAlpha.100'}
|
||||||
|
borderRadius={'xl'}
|
||||||
|
border={'1px solid'}
|
||||||
|
borderColor={'whiteAlpha.300'}
|
||||||
|
>
|
||||||
|
<Text fontSize={'lg'} fontWeight={'bold'} mb={2}>
|
||||||
|
应用配置命令
|
||||||
|
</Text>
|
||||||
|
<Box>
|
||||||
|
{JSON.parse(editableConfig).config?.commands.map((command, index) => (
|
||||||
|
<HStack key={index} mb={2}>
|
||||||
|
<Text fontSize={'sm'} flex={1}>
|
||||||
|
{command}
|
||||||
|
</Text>
|
||||||
|
<Spinner
|
||||||
|
size={'sm'}
|
||||||
|
color={applyStatus[index] === 'success' ? 'green.500' : 'red.500'}
|
||||||
|
display={
|
||||||
|
applyStatus[index] === 'pending' ||
|
||||||
|
applyStatus[index] === 'in-progress'
|
||||||
|
? 'inline-block'
|
||||||
|
: 'none'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Text
|
||||||
|
color={applyStatus[index] === 'success' ? 'green.500' : 'red.500'}
|
||||||
|
ml={2}
|
||||||
|
>
|
||||||
|
{applyStatus[index] === 'success'
|
||||||
|
? '成功'
|
||||||
|
: applyStatus[index] === 'failed'
|
||||||
|
? '失败'
|
||||||
|
: applyStatus[index] === 'in-progress'
|
||||||
|
? '正在应用'
|
||||||
|
: ''}
|
||||||
|
</Text>
|
||||||
|
</HStack>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</VStack>
|
||||||
|
</FadeInWrapper>
|
||||||
|
}
|
||||||
|
</VStack>
|
||||||
</FadeInWrapper>
|
</FadeInWrapper>
|
||||||
)}
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
|
@ -19,6 +19,7 @@ import ConfigTool from '@/libs/config/ConfigTool';
|
|||||||
import Common from '@/libs/common';
|
import Common from '@/libs/common';
|
||||||
import switchIcon from '@/resources/icon/pages/devices/switch.png';
|
import switchIcon from '@/resources/icon/pages/devices/switch.png';
|
||||||
import Notification from '@/libs/system/Notification';
|
import Notification from '@/libs/system/Notification';
|
||||||
|
import DeviceConfigModal from '@/components/pages/config/DeviceConfigModal';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 交换机管理
|
* 交换机管理
|
||||||
@ -29,6 +30,8 @@ const DevicesPage = () => {
|
|||||||
const [devices, setDevices] = useState([]);
|
const [devices, setDevices] = useState([]);
|
||||||
const [editingIndex, setEditingIndex] = useState(null);
|
const [editingIndex, setEditingIndex] = useState(null);
|
||||||
const [editingName, setEditingName] = useState('');
|
const [editingName, setEditingName] = useState('');
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const [currentDevice, setCurrentDevice] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const config = ConfigTool.load();
|
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 (
|
return (
|
||||||
<DocumentTitle title={'交换机设备'}>
|
<DocumentTitle title={'交换机设备'}>
|
||||||
<DashboardBackground />
|
<DashboardBackground />
|
||||||
@ -124,6 +144,15 @@ const DevicesPage = () => {
|
|||||||
{'端口: '}
|
{'端口: '}
|
||||||
{device.ports.join(', ')}
|
{device.ports.join(', ')}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
size={'sm'}
|
||||||
|
colorPalette={'teal'}
|
||||||
|
mt={2}
|
||||||
|
onClick={() => handleOpenConfigModal(device)}
|
||||||
|
>
|
||||||
|
配置
|
||||||
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
@ -134,6 +163,15 @@ const DevicesPage = () => {
|
|||||||
</VStack>
|
</VStack>
|
||||||
</FadeInWrapper>
|
</FadeInWrapper>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
|
|
||||||
|
{isModalOpen && currentDevice && (
|
||||||
|
<DeviceConfigModal
|
||||||
|
isOpen={isModalOpen}
|
||||||
|
onClose={() => setIsModalOpen(false)}
|
||||||
|
onSave={handleSaveDeviceConfig}
|
||||||
|
device={currentDevice}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</DocumentTitle>
|
</DocumentTitle>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -41,22 +41,16 @@ export const api = {
|
|||||||
* @param text 文本
|
* @param text 文本
|
||||||
* @returns {Promise<axios.AxiosResponse<any>>}
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
*/
|
*/
|
||||||
//parseCommand: async (text) => await axios.post(buildUrl('/api/parse_command'), { command: text }),
|
parseCommand: (text) => axios.post(buildUrl('/api/parse_command'), { command: text }),
|
||||||
async parseCommand(text) {
|
|
||||||
const res = await axios.post(buildUrl('/api/parse_command', { command: text }));
|
|
||||||
if (res) {
|
|
||||||
return res;
|
|
||||||
} else return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用配置
|
* 应用配置
|
||||||
* @param switch_ip 交换机ip
|
* @param switch_ip 交换机ip
|
||||||
* @param config 配置
|
* @param commands 配置,为数组[]
|
||||||
* @returns {Promise<axios.AxiosResponse<any>>}
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
*/
|
*/
|
||||||
applyConfig: (switch_ip, config) =>
|
applyConfig: (switch_ip, commands) =>
|
||||||
axios.post(buildUrl('/api/apply_config'), { switch_ip, config }),
|
axios.post(buildUrl('/api/execute_cli_commands'), { switch_ip, commands }),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新基础URL
|
* 更新基础URL
|
||||||
|
Loading…
x
Reference in New Issue
Block a user