Merge pull request #189 from safe1ine/main

支持配置连接地址
This commit is contained in:
Yoko
2025-07-31 18:39:09 +08:00
committed by GitHub
17 changed files with 681 additions and 50 deletions

View File

@@ -271,7 +271,7 @@ export const getGetSetting = (params: RequestParams = {}) =>
});
/**
* @description 更新系统设置
* @description 更新为增量更新,只传需要更新的字段
*
* @tags Admin
* @name PutUpdateSetting

View File

@@ -13,6 +13,9 @@
import request, { ContentType, RequestParams } from "./httpClient";
import {
DomainAcceptCompletionReq,
DomainCreateSecurityScanningReq,
DomainListSecurityScanningBriefResp,
DomainListSecurityScanningReq,
DomainModelListResp,
DomainReportReq,
WebResp,
@@ -146,3 +149,56 @@ export const postReport = (
format: "json",
...params,
});
/**
* @description 分页逻辑只支持用 next_token
*
* @tags OpenAIV1
* @name GetListSecurityScanning
* @summary 扫描任务列表
* @request GET:/v1/security/scanning
* @response `200` `(WebResp & {
data?: DomainListSecurityScanningBriefResp,
})` OK
*/
export const getListSecurityScanning = (
param: DomainListSecurityScanningReq,
params: RequestParams = {},
) =>
request<
WebResp & {
data?: DomainListSecurityScanningBriefResp;
}
>({
path: `/v1/security/scanning`,
method: "GET",
body: param,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 创建扫描任务
*
* @tags OpenAIV1
* @name PostCreateSecurityScanning
* @summary 创建扫描任务
* @request POST:/v1/security/scanning
* @response `200` `WebResp` OK
*/
export const postCreateSecurityScanning = (
param: DomainCreateSecurityScanningReq,
params: RequestParams = {},
) =>
request<WebResp>({
path: `/v1/security/scanning`,
method: "POST",
body: param,
type: ContentType.Json,
format: "json",
...params,
});

View File

@@ -0,0 +1,82 @@
/* eslint-disable */
/* tslint:disable */
// @ts-nocheck
/*
* ---------------------------------------------------------------
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
* ## ##
* ## AUTHOR: acacode ##
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
* ---------------------------------------------------------------
*/
import request, { ContentType, RequestParams } from "./httpClient";
import {
DomainListSecurityScanningResp,
DomainSecurityScanningRiskDetail,
GetSecurityScanningDetailParams,
GetSecurityScanningListParams,
WebResp,
} from "./types";
/**
* @description 获取扫描结果
*
* @tags Security Scanning
* @name GetSecurityScanningList
* @summary 获取扫描结果
* @request GET:/api/v1/security/scanning
* @response `200` `(WebResp & {
data?: DomainListSecurityScanningResp,
})` OK
* @response `401` `string` Unauthorized
*/
export const getSecurityScanningList = (
query: GetSecurityScanningListParams,
params: RequestParams = {},
) =>
request<
WebResp & {
data?: DomainListSecurityScanningResp;
}
>({
path: `/api/v1/security/scanning`,
method: "GET",
query: query,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 获取扫描风险详情
*
* @tags Security Scanning
* @name GetSecurityScanningDetail
* @summary 获取扫描风险详情
* @request GET:/api/v1/security/scanning/detail
* @response `200` `(WebResp & {
data?: (DomainSecurityScanningRiskDetail)[],
})` OK
* @response `401` `string` Unauthorized
*/
export const getSecurityScanningDetail = (
query: GetSecurityScanningDetailParams,
params: RequestParams = {},
) =>
request<
WebResp & {
data?: DomainSecurityScanningRiskDetail[];
}
>({
path: `/api/v1/security/scanning/detail`,
method: "GET",
query: query,
type: ContentType.Json,
format: "json",
...params,
});

View File

@@ -0,0 +1,82 @@
/* eslint-disable */
/* tslint:disable */
// @ts-nocheck
/*
* ---------------------------------------------------------------
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
* ## ##
* ## AUTHOR: acacode ##
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
* ---------------------------------------------------------------
*/
import request, { ContentType, RequestParams } from "./httpClient";
import {
DomainListSecurityScanningResp,
DomainSecurityScanningRiskDetail,
GetUserSecurityScanningDetailParams,
GetUserSecurityScanningListParams,
WebResp,
} from "./types";
/**
* @description 获取用户扫描结果
*
* @tags User Security Scanning
* @name GetUserSecurityScanningList
* @summary 获取用户扫描结果
* @request GET:/api/v1/user/security/scanning
* @response `200` `(WebResp & {
data?: DomainListSecurityScanningResp,
})` OK
* @response `401` `string` Unauthorized
*/
export const getUserSecurityScanningList = (
query: GetUserSecurityScanningListParams,
params: RequestParams = {},
) =>
request<
WebResp & {
data?: DomainListSecurityScanningResp;
}
>({
path: `/api/v1/user/security/scanning`,
method: "GET",
query: query,
type: ContentType.Json,
format: "json",
...params,
});
/**
* @description 获取用户扫描风险详情
*
* @tags User Security Scanning
* @name GetUserSecurityScanningDetail
* @summary 获取用户扫描风险详情
* @request GET:/api/v1/user/security/scanning/detail
* @response `200` `(WebResp & {
data?: (DomainSecurityScanningRiskDetail)[],
})` OK
* @response `401` `string` Unauthorized
*/
export const getUserSecurityScanningDetail = (
query: GetUserSecurityScanningDetailParams,
params: RequestParams = {},
) =>
request<
WebResp & {
data?: DomainSecurityScanningRiskDetail[];
}
>({
path: `/api/v1/user/security/scanning/detail`,
method: "GET",
query: query,
type: ContentType.Json,
format: "json",
...params,
});

View File

@@ -4,10 +4,12 @@ export * from './Cli'
export * from './Dashboard'
export * from './Model'
export * from './OpenAiv1'
export * from './SecurityScanning'
export * from './User'
export * from './UserDashboard'
export * from './UserManage'
export * from './UserRecord'
export * from './UserSecurityScanning'
export * from './WorkspaceFile'
export * from './types'

View File

@@ -40,6 +40,47 @@ export enum ConstsUserPlatform {
UserPlatformCustom = "custom",
}
export enum ConstsSecurityScanningStatus {
SecurityScanningStatusPending = "pending",
SecurityScanningStatusRunning = "running",
SecurityScanningStatusSuccess = "success",
SecurityScanningStatusFailed = "failed",
}
export enum ConstsSecurityScanningRiskLevel {
SecurityScanningRiskLevelSevere = "severe",
SecurityScanningRiskLevelCritical = "critical",
SecurityScanningRiskLevelSuggest = "suggest",
}
export enum ConstsSecurityScanningLanguage {
SecurityScanningLanguageCpp = "C/C++",
SecurityScanningLanguageJava = "Java",
SecurityScanningLanguagePython = "Python",
SecurityScanningLanguageJavaScript = "JavaScript",
SecurityScanningLanguageGo = "Go",
SecurityScanningLanguagePHP = "PHP",
SecurityScanningLanguageCS = "C#",
SecurityScanningLanguageSwift = "Swift",
SecurityScanningLanguageRuby = "Ruby",
SecurityScanningLanguageRust = "Rust",
SecurityScanningLanguageHTML = "HTML",
SecurityScanningLanguageObjectiveC = "Objective-C/C++",
SecurityScanningLanguageOCaml = "OCaml",
SecurityScanningLanguageKotlin = "Kotlin",
SecurityScanningLanguageScala = "Scala",
SecurityScanningLanguageSolidity = "Solidity",
SecurityScanningLanguageCOBOL = "COBOL",
SecurityScanningLanguageShell = "Shell",
SecurityScanningLanguageSQL = "SQL",
SecurityScanningLanguageFortran = "Fortran",
SecurityScanningLanguageDart = "Dart",
SecurityScanningLanguageGroovy = "Groovy",
SecurityScanningLanguageLua = "Lua",
SecurityScanningLanguageSecrets = "Secrets",
SecurityScanningLanguageIaC = "IaC",
}
export enum ConstsReportAction {
ReportActionAccept = "accept",
ReportActionSuggest = "suggest",
@@ -313,6 +354,13 @@ export interface DomainCreateModelReq {
show_name?: string;
}
export interface DomainCreateSecurityScanningReq {
/** 扫描语言 */
language?: ConstsSecurityScanningLanguage;
/** 项目目录 */
workspace?: string;
}
export interface DomainCreateWorkspaceFileReq {
/** 文件内容 */
content?: string;
@@ -504,6 +552,41 @@ export interface DomainListLoginHistoryResp {
total_count?: number;
}
export interface DomainListSecurityScanningBriefResp {
has_next_page?: boolean;
items?: DomainSecurityScanningBrief[];
next_token?: string;
total_count?: number;
}
export interface DomainListSecurityScanningReq {
/** 作者 */
author?: string;
/** 下一页标识 */
next_token?: string;
/**
* 分页
* @min 1
* @default 1
*/
page?: number;
/** 项目名称 */
project_name?: string;
/**
* 每页多少条记录
* @min 1
* @default 10
*/
size?: number;
}
export interface DomainListSecurityScanningResp {
has_next_page?: boolean;
items?: DomainSecurityScanningResult[];
next_token?: string;
total_count?: number;
}
export interface DomainListUserResp {
has_next_page?: boolean;
next_token?: string;
@@ -695,7 +778,57 @@ export interface DomainReportReq {
user_input?: string;
}
export interface DomainSecurityScanningBrief {
/** 创建时间 */
created_at?: number;
/** 报告url */
report_url?: string;
/** 扫描状态 */
status?: ConstsSecurityScanningStatus;
/** 项目目录 */
workspace?: string;
}
export interface DomainSecurityScanningResult {
/** 扫描开始时间 */
created_at?: number;
/** 扫描任务id */
id?: string;
/** 扫描任务 */
name?: string;
/** 项目名称 */
project_name?: string;
/** 风险结果 */
risk?: DomainSecurityScanningRiskResult;
/** 扫描状态 */
status?: ConstsSecurityScanningStatus;
/** 用户 */
user?: DomainUser;
}
export interface DomainSecurityScanningRiskDetail {
/** 风险描述 */
desc?: string;
/** 风险文件名 */
filename?: string;
/** 风险id */
id?: string;
/** 风险等级 */
level?: ConstsSecurityScanningRiskLevel;
}
export interface DomainSecurityScanningRiskResult {
/** 高危数 */
critical_count?: number;
/** 严重数 */
severe_count?: number;
/** 建议数 */
suggest_count?: number;
}
export interface DomainSetting {
/** base url 配置,为了支持前置代理 */
base_url?: string;
/** 创建时间 */
created_at?: number;
/** 自定义OAuth接入 */
@@ -829,6 +962,8 @@ export interface DomainUpdateModelReq {
}
export interface DomainUpdateSettingReq {
/** base url 配置,为了支持前置代理 */
base_url?: string;
/** 自定义OAuth配置 */
custom_oauth?: DomainCustomOAuthReq;
/** 钉钉OAuth配置 */
@@ -1230,6 +1365,32 @@ export interface GetGetTokenUsageParams {
model_type: "llm" | "coder" | "embedding" | "audio" | "reranker";
}
export interface GetSecurityScanningListParams {
/** 作者 */
author?: string;
/** 下一页标识 */
next_token?: string;
/**
* 分页
* @min 1
* @default 1
*/
page?: number;
/** 项目名称 */
project_name?: string;
/**
* 每页多少条记录
* @min 1
* @default 10
*/
size?: number;
}
export interface GetSecurityScanningDetailParams {
/** 扫描任务id */
id: string;
}
export interface GetUserChatInfoParams {
/** 对话记录ID */
id: string;
@@ -1384,6 +1545,32 @@ export interface GetUserOauthSignupOrInParams {
source: "plugin" | "browser";
}
export interface GetUserSecurityScanningListParams {
/** 作者 */
author?: string;
/** 下一页标识 */
next_token?: string;
/**
* 分页
* @min 1
* @default 1
*/
page?: number;
/** 项目名称 */
project_name?: string;
/**
* 每页多少条记录
* @min 1
* @default 10
*/
size?: number;
}
export interface GetUserSecurityScanningDetailParams {
/** 扫描任务id */
id: string;
}
export interface GetListWorkspaceFilesParams {
/** 编程语言筛选 */
language?: string;

View File

@@ -58,10 +58,10 @@ const ADMIN_MENUS = [
disabled: false,
},
{
label: '管理员',
value: '/admin',
pathname: 'admin',
icon: 'icon-guanliyuan1',
label: '通用设置',
value: '/general-setting',
pathname: 'general-setting',
icon: 'icon-setting',
show: true,
disabled: false,
},

View File

@@ -1,19 +0,0 @@
import React from 'react';
import LoginHistory from './loginHistory';
import AdminTable from './adminTable';
import { Grid2 as Grid, Stack } from '@mui/material';
const Admin = () => {
return (
<Grid container spacing={2} sx={{ height: '100%' }}>
<Grid size={6}>
<AdminTable />
</Grid>
<Grid size={6}>
<LoginHistory />
</Grid>
</Grid>
);
};
export default Admin;

View File

@@ -15,7 +15,7 @@ import {
Divider,
Stack,
} from '@mui/material';
import { Icon, message } from '@c-x/ui';
import { CusTabs, Icon, message } from '@c-x/ui';
// @ts-ignore
import { AestheticFluidBg } from '@/assets/jsm/AestheticFluidBg.module.js';
@@ -43,7 +43,7 @@ const StyledPaper = styled(Paper)(({ theme }) => ({
position: 'relative',
zIndex: 9,
padding: theme.spacing(4),
background: 'rgba(255, 255, 255, 0.85)',
background: 'rgba(240, 240, 240, 0.85)',
backdropFilter: 'blur(10px)',
width: 458,
borderRadius: theme.spacing(2),
@@ -133,6 +133,12 @@ const AuthPage = () => {
// 处理登录表单提交
const onSubmit = useCallback(
async (data: LoginFormData) => {
// 检查是否使用 admin 账户登录
if (data.username === 'admin') {
message.error('请使用研发成员的账户登录,本页面不支持管理员账户访问');
return;
}
setLoading(true);
setError(null);
@@ -344,6 +350,40 @@ const AuthPage = () => {
Monkey Code
</LogoTitle>
</LogoContainer>
<CusTabs
list={[
{ label: '研发成员', value: 'user' },
{ label: '管理员', value: 'admin', disabled: true},
]}
value={"user"}
sx={{
width: '100%',
mb: 4,
height: 40,
border: 'none',
padding: '4px',
'.MuiTab-root': {
width: '50%',
height: 32,
fontSize: 14,
'&.Mui-selected': {
color: 'text.primary',
fontWeight: 500,
},
},
'.MuiTabs-scroller': {
height: 32,
},
'.MuiTabs-indicator': {
borderRadius: '10px',
height: 32,
backgroundColor: '#fff',
},
bgcolor: 'rgba(255, 255, 255, 0.2)',
borderRadius: '10px',
}}
/>
{!loginSetting.disable_password_login && renderLoginForm()}
{oauthEnable && oauthLogin()}
</StyledPaper>

View File

@@ -12,7 +12,7 @@ type LoginHistory = NonNullable<
DomainListAdminLoginHistoryResp['login_histories']
>[number];
const LoginHistory = () => {
const AdminLoginHistory = () => {
const { data, loading } = useRequest(() => getAdminLoginHistory({}));
const columns: ColumnsType<LoginHistory> = [
{
@@ -55,9 +55,23 @@ const LoginHistory = () => {
direction='row'
justifyContent='space-between'
alignItems='center'
sx={{ mb: 2 }}
sx={{
mb: 2,
height: 32,
fontWeight: 'bold',
}}
>
<Box sx={{ fontWeight: 700, lineHeight: '36px' }}></Box>
<Box sx={{
'&::before': {
content: '""',
display: 'inline-block',
width: 4,
height: 12,
bgcolor: 'common.black',
borderRadius: '2px',
mr: 1,
},
}}></Box>
</Stack>
<Table
columns={columns}
@@ -71,4 +85,4 @@ const LoginHistory = () => {
);
};
export default LoginHistory;
export default AdminLoginHistory;

View File

@@ -151,7 +151,7 @@ const AddAdminModal = ({
);
};
const AdminTable = () => {
const AdminUser = () => {
const [open, setOpen] = useState(false);
const { data, loading, refresh } = useRequest(() => getListAdminUser({}));
const onDeleteAdmin = (data: DomainAdminUser) => {
@@ -187,19 +187,27 @@ const AdminTable = () => {
},
},
{
title: '最近活跃时间',
title: '加入时间',
dataIndex: 'created_at',
width: 140,
render: (text) => {
return dayjs.unix(text).fromNow();
},
},
{
title: '最近活跃',
dataIndex: 'last_active_at',
width: 140,
render: (text, record) => {
return <Stack direction='column'>
<Box sx={{ color: 'text.secondary' }}>{record.created_at ? dayjs.unix(record.created_at).fromNow() + '加入' : '加入时间未知'}</Box>
<Box sx={{ color: 'text.secondary' }}>{record.last_active_at ? dayjs.unix(record.last_active_at).fromNow() + '活跃' : '活跃时间未知'}</Box>
</Stack>
return record.last_active_at === 0
? '从未使用'
: dayjs.unix(text).fromNow();
},
},
{
title: '',
dataIndex: 'opt',
width: 200,
width: 100,
render: (_, record) => {
return (
<Button
@@ -215,14 +223,28 @@ const AdminTable = () => {
},
];
return (
<Card sx={{ height: '100%' }}>
<Card>
<Stack
direction='row'
justifyContent='space-between'
alignItems='center'
sx={{ mb: 2 }}
sx={{
mb: 2,
height: 32,
fontWeight: 'bold',
}}
>
<Box sx={{ fontWeight: 700, lineHeight: '36px' }}></Box>
<Box sx={{
'&::before': {
content: '""',
display: 'inline-block',
width: 4,
height: 12,
bgcolor: 'common.black',
borderRadius: '2px',
mr: 1,
},
}}></Box>
<Button
variant='contained'
color='primary'
@@ -249,4 +271,4 @@ const AdminTable = () => {
);
};
export default AdminTable;
export default AdminUser;

View File

@@ -0,0 +1,25 @@
import Card from '@/components/card';
import { Box, Stack } from "@mui/material"
import AdminUser from './adminUser';
import AdminLoginHistory from './adminLoginHistory';
const CardAdminUser = () => {
return <Card sx={{ p : 0, }}>
<Box sx={{
fontWeight: 'bold',
px: 2,
py: 1.5,
bgcolor: 'rgb(248, 249, 250)',
borderTopLeftRadius: '10px',
borderTopRightRadius: '10px',
}}></Box>
<Stack direction='column'>
<AdminUser />
<AdminLoginHistory />
</Stack>
</Card>
}
export default CardAdminUser;

View File

@@ -0,0 +1,122 @@
import Card from '@/components/card';
import { Box, Button, Stack, TextField } from "@mui/material"
import { message } from '@c-x/ui';
import { useEffect, useState } from "react"
import { getGetSetting, putUpdateSetting } from '@/api/Admin';
import { DomainUpdateSettingReq } from '@/api/types';
const CardServiceSettings = () => {
const [baseURL, setBaseURL] = useState('');
const [initialBaseURL, setInitialBaseURL] = useState('');
useEffect(() => {
const fetchInitialBaseURL = async () => {
try {
const response = await getGetSetting();
const initialValue = response.base_url || '';
setBaseURL(initialValue);
setInitialBaseURL(initialValue);
} catch (err: any) {
message.error('Failed to fetch initial base URL:', err);
// 如果获取失败,可以设置一个默认值或者保持空字符串
setBaseURL('');
setInitialBaseURL('');
}
};
fetchInitialBaseURL();
}, []);
const handleBaseURLChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setBaseURL(event.target.value);
};
const isValidURL = (url: string): boolean => {
try {
const parsedURL = new URL(url);
// Check if the protocol is either http or https
if (parsedURL.protocol !== 'http:' && parsedURL.protocol !== 'https:') {
return false;
}
// Check if the URL is a base URL (no path or only root path)
if (parsedURL.pathname !== '/' && parsedURL.pathname !== '') {
return false;
}
return true;
} catch (e) {
return false;
}
};
const handleSave = async () => {
// Check if the baseURL is valid before saving
if (baseURL && !isValidURL(baseURL)) {
message.error('请输入一个有效的 URL 地址');
return;
}
try {
const setting: DomainUpdateSettingReq = {
base_url: baseURL,
};
await putUpdateSetting(setting);
message.success('保存成功');
setInitialBaseURL(baseURL);
} catch (err: any) {
message.error('保存失败:', err);
}
};
const hasValueChanged = baseURL !== initialBaseURL;
return <Card sx={{p : 0, borderBottom: '1px solid #e0e0e0'}}>
<Box sx={{
fontWeight: 'bold',
px: 2,
py: 1.5,
bgcolor: 'rgb(248, 249, 250)',
borderTopLeftRadius: '10px',
borderTopRightRadius: '10px',
}}>MonkeyCode </Box>
<Stack direction='column'>
<Box sx={{ width: '100%' }}>
<Stack direction='row' alignItems={'center'} justifyContent={'space-between'} sx={{
m: 2,
height: 32,
fontWeight: 'bold',
}}>
<Box sx={{
'&::before': {
content: '""',
display: 'inline-block',
width: 4,
height: 12,
bgcolor: 'common.black',
borderRadius: '2px',
mr: 1,
},
}}>MonkeyCode </Box>
{hasValueChanged && <Button variant="contained" size="small" onClick={handleSave}></Button>}
</Stack>
<Box sx={{ m: 2 }}>
<TextField
fullWidth
value={baseURL}
onChange={handleBaseURLChange}
placeholder={baseURL ? '' : window.location.origin}
/>
<Box sx={{
mt: 1,
fontSize: '0.75rem',
color: '#FFA500',
fontWeight: 'normal'
}}>
VSCode MonkeyCode
</Box>
</Box>
</Box>
</Stack>
</Card>
}
export default CardServiceSettings;

View File

@@ -0,0 +1,18 @@
import CardServiceSettings from './components/cardServiceSettings';
import { Grid2 as Grid } from '@mui/material';
import CardAdminUser from './components/cardAdminUser';
const GeneralSetting = () => {
return (
<Grid container spacing={2} sx={{ height: '100%' }}>
<Grid size={6}>
<CardServiceSettings />
</Grid>
<Grid size={6}>
<CardAdminUser />
</Grid>
</Grid>
);
};
export default GeneralSetting;

View File

@@ -42,7 +42,7 @@ const StyledPaper = styled(Paper)(({ theme }) => ({
position: 'relative',
zIndex: 9,
padding: theme.spacing(4),
background: 'rgba(255, 255, 255, 0.85)',
background: 'rgba(240, 240, 240, 0.85)',
backdropFilter: 'blur(10px)',
width: 458,
borderRadius: theme.spacing(2),
@@ -209,8 +209,8 @@ const LoginPage = () => {
<CusTabs
list={[
{ label: '普通账号', value: 'user' },
{ label: '管理员账号', value: 'admin' },
{ label: '研发成员', value: 'user' },
{ label: '管理员', value: 'admin' },
]}
value={tab}
onChange={(value: TabType) => {

View File

@@ -266,7 +266,7 @@ const MemberManage = () => {
{
title: '加入时间',
dataIndex: 'created_at',
width: 120,
width: 140,
render: (text) => {
return dayjs.unix(text).fromNow();
},
@@ -274,7 +274,7 @@ const MemberManage = () => {
{
title: '最近活跃',
dataIndex: 'last_active_at',
width: 120,
width: 140,
render: (text, record) => {
return record.last_active_at === 0
? '从未使用'
@@ -284,7 +284,7 @@ const MemberManage = () => {
{
title: '',
dataIndex: 'action',
width: 100,
width: 80,
render: (_, record) => {
return (
<IconButton

View File

@@ -33,7 +33,7 @@ const Chat = LazyLoadable(lazy(() => import('@/pages/chat')));
const Completion = LazyLoadable(lazy(() => import('@/pages/completion')));
const Model = LazyLoadable(lazy(() => import('@/pages/model')));
const MemberManage = LazyLoadable(lazy(() => import('@/pages/memberManage')));
const Admin = LazyLoadable(lazy(() => import('@/pages/admin')));
const GeneralSetting = LazyLoadable(lazy(() => import('@/pages/generalSetting')));
const Invite = LazyLoadable(lazy(() => import('@/pages/invite')));
const Auth = LazyLoadable(lazy(() => import('@/pages/auth')));
const Login = LazyLoadable(lazy(() => import('@/pages/login')));
@@ -83,8 +83,8 @@ const routerConfig = [
element: <MemberManage />,
},
{
path: 'admin',
element: <Admin />,
path: 'general-setting',
element: <GeneralSetting />,
},
],
},