添加api调用模块

This commit is contained in:
Jerry 2025-06-20 13:34:15 +08:00
parent a528009674
commit ae8786f297
5 changed files with 87 additions and 23 deletions

View File

@ -28,7 +28,7 @@ const FeatureCard = ({ title, description, buttonText, to, disabled }) => (
{description} {description}
</Text> </Text>
<Button <Button
colorScheme={'blue'} colorPalette={'blue'}
variant={'solid'} variant={'solid'}
isDisabled={disabled} isDisabled={disabled}
onClick={() => { onClick={() => {

View File

@ -9,8 +9,10 @@ import MotionCard from '@/components/ui/MotionCard';
const navItems = [ const navItems = [
{ label: '面板', path: '/dashboard' }, { label: '面板', path: '/dashboard' },
{ label: '网络', path: '/dashboard/network' }, { label: '网络扫描', path: '/dashboard/scan' },
{ label: '交换机', path: '/dashboard/switch' }, { label: '交换机设备', path: '/dashboard/devices' },
{ label: '交换机配置', path: '/dashboard/config' },
{ label: '流量监控', path: '/dashboard/watch' },
]; ];
/** /**

View File

@ -95,7 +95,7 @@ export const NotificationProvider = ({ children }) => {
<Text mt={2}>{item.description}</Text> <Text mt={2}>{item.description}</Text>
{item.button && ( {item.button && (
<Button <Button
colorScheme={'whiteAlpha'} colorPalette={'whiteAlpha'}
size={'sm'} size={'sm'}
mt={3} mt={3}
onClick={item.button.onClick} onClick={item.button.onClick}

View File

@ -8,6 +8,11 @@ import FeatureCard from '@/components/pages/dashboard/FeatureCard';
import StatCard from '@/components/pages/dashboard/StatCard'; import StatCard from '@/components/pages/dashboard/StatCard';
import { useNotification } from '@/libs/system/Notification'; import { useNotification } from '@/libs/system/Notification';
/**
* 控制台
* @returns {JSX.Element}
* @constructor
*/
const Dashboard = () => { const Dashboard = () => {
const [stats, setStats] = useState({ const [stats, setStats] = useState({
totalDevices: 0, totalDevices: 0,
@ -15,7 +20,7 @@ const Dashboard = () => {
lastScan: '', lastScan: '',
}); });
const [networkStatus, setNetworkStatus] = useState('idle'); // idle | loading | ok | fail const [networkStatus, setNetworkStatus] = useState('loading'); // loading | ok | fail
const notify = useNotification(); const notify = useNotification();
const checkBackend = useCallback(async () => { const checkBackend = useCallback(async () => {
@ -39,7 +44,6 @@ const Dashboard = () => {
const timer = setTimeout(() => { const timer = setTimeout(() => {
checkBackend(); checkBackend();
}, 3000); }, 3000);
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, [checkBackend]); }, [checkBackend]);
@ -92,35 +96,42 @@ const Dashboard = () => {
{'网络健康状态'} {'网络健康状态'}
</Text> </Text>
<HStack spacing={4}> <HStack spacing={4}>
{networkStatus === 'idle' && (
<Badge colorScheme={'gray'} variant={'solid'} p={2} borderRadius={'lg'}>
{'等待检测'}
</Badge>
)}
{networkStatus === 'loading' && ( {networkStatus === 'loading' && (
<Badge colorScheme={'gray'} variant={'solid'} p={2} borderRadius={'lg'}> <Badge
colorScheme={'gray'}
variant={'surface'}
p={2}
borderRadius={'lg'}
colorPalette={'blue'}
>
<Spinner size="sm" mr={2} /> {'检测网络中...'} <Spinner size="sm" mr={2} /> {'检测网络中...'}
</Badge> </Badge>
)} )}
{networkStatus === 'ok' && ( {networkStatus === 'ok' && (
<Badge colorScheme={'green'} variant={'solid'} p={2} borderRadius={'lg'}> <Badge
colorScheme={'green'}
variant={'surface'}
p={2}
borderRadius={'lg'}
colorPalette={'green'}
>
{'网络连接正常'} {'网络连接正常'}
</Badge> </Badge>
)} )}
{networkStatus === 'fail' && ( {networkStatus === 'fail' && (
<Badge colorScheme={'red'} variant={'solid'} p={2} borderRadius={'lg'}> <Badge colorPalette={'red'} variant={'surface'} p={2} borderRadius={'lg'}>
{'无法连接后端'} {'无法连接后端'}
</Badge> </Badge>
)} )}
<Badge colorScheme={'blue'} variant={'solid'} p={2} borderRadius={'lg'}> <Badge colorPalette={'blue'} variant={'surface'} p={2} borderRadius={'lg'}>
{'交换机正常运行'} {'交换机正常运行'}
</Badge> </Badge>
<Badge colorScheme={'yellow'} variant={'solid'} p={2} borderRadius={'lg'}> <Badge colorPalette={'yellow'} variant={'surface'} p={2} borderRadius={'lg'}>
{'流量监控启动'} {'流量监控启动'}
</Badge> </Badge>
</HStack> </HStack>
<Button mt={4} onClick={checkBackend} colorScheme={'teal'}> <Button mt={4} onClick={checkBackend} colorPalette={'teal'} variant={'outline'}>
{'重新检测'} {'重新检测'}
</Button> </Button>
</Box> </Box>
@ -132,25 +143,25 @@ const Dashboard = () => {
title={'网络扫描'} title={'网络扫描'}
description={'快速扫描指定子网,发现可用设备,展示设备 IP/MAC 和开放端口信息'} description={'快速扫描指定子网,发现可用设备,展示设备 IP/MAC 和开放端口信息'}
buttonText={'立即扫描'} buttonText={'立即扫描'}
to={'/scan'} to={'/dashboard/scan'}
/> />
<FeatureCard <FeatureCard
title={'设备管理'} title={'设备管理'}
description={'查看已记录的交换机设备信息,未来支持编辑、备注、批量管理'} description={'查看已记录的交换机设备信息,未来支持编辑、备注、批量管理'}
buttonText={'管理设备'} buttonText={'管理设备'}
to={'/devices'} to={'/dashboard/devices'}
/> />
<FeatureCard <FeatureCard
title={'命令配置'} title={'命令配置'}
description={'输入自然语言命令,自动生成设备配置,支持一键应用到交换机'} description={'输入自然语言命令,自动生成设备配置,支持一键应用到交换机'}
buttonText={'前往配置'} buttonText={'前往配置'}
to={'/config'} to={'/dashboard/config'}
/> />
<FeatureCard <FeatureCard
title={'流量监控'} title={'流量监控'}
description={'未来将支持实时监控每台设备上下行带宽,帮助掌握网络流量变化'} description={'未来将支持实时监控每台设备上下行带宽,帮助掌握网络流量变化'}
buttonText={'敬请期待'} buttonText={'前往查看'}
disabled to={'dashboard/watch'}
/> />
</SimpleGrid> </SimpleGrid>
</FadeInWrapper> </FadeInWrapper>

View File

@ -0,0 +1,51 @@
/**
* 获取config
* @returns {any|null}
*/
export const getConfig = () => {
const cfg = localStorage.getItem('connection-config');
return cfg ? JSON.parse(cfg) : null;
};
/**
* 获取后端url
* @returns {string}
*/
export const getBaseUrl = () => {
const cfg = getConfig();
return cfg?.backendUrl || '';
};
/**
* fetchUrl
* @param path 路径
* @param options 选项
* @returns {Promise<any>}
*/
const fetchWithBase = async (path, options = {}) => {
const base = getBaseUrl();
const res = await fetch(`${base}${path}`, options);
return res.json();
};
/**
* api模块
* @type {{test: (function(): Promise<*>), scan: (function(*): Promise<*>), listDevices: (function(): Promise<*>), parseCommand: (function(*): Promise<*>), applyConfig: (function(*, *): Promise<*>)}}
*/
export const api = {
test: () => fetchWithBase('/api/test'),
scan: (subnet) => fetchWithBase(`/api/scan_network?subnet=${encodeURIComponent(subnet)}`),
listDevices: () => fetchWithBase('/api/list_devices'),
parseCommand: (text) =>
fetchWithBase('/api/parse_command', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ command: text }),
}),
applyConfig: (switch_ip, config) =>
fetchWithBase('/api/apply_config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ switch_ip, config }),
}),
};