diff --git a/src/assets/svg/login-avatars.svg b/src/assets/svg/login-avatars.svg deleted file mode 100644 index d235c32..0000000 --- a/src/assets/svg/login-avatars.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/assets/svg/login-background.svg b/src/assets/svg/login-background.svg deleted file mode 100644 index ca0269d..0000000 --- a/src/assets/svg/login-background.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/assets/svg/next-login-bg.svg b/src/assets/svg/next-login-bg.svg deleted file mode 100644 index a7c3bad..0000000 --- a/src/assets/svg/next-login-bg.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/components/AppSvgIcon.tsx b/src/components/AppSvgIcon.tsx index 18d73e9..67f6485 100644 --- a/src/components/AppSvgIcon.tsx +++ b/src/components/AppSvgIcon.tsx @@ -2,8 +2,26 @@ import React from "react"; import { SvgIcon, type SvgIconProps } from "@mui/material"; import logger from "@/utils/logger"; -// 使用 import.meta.glob 预加载所有 SVG 文件 -const svgModules = import.meta.glob('/src/assets/svg/**/*.svg', { +// 按目录分别预加载 SVG 文件,实现按需加载 +const llmSvgModules = import.meta.glob('/src/assets/svg/llm/*.svg', { + query: '?react', + import: 'default', + eager: false +}); + +const chunkSvgModules = import.meta.glob('/src/assets/svg/chunk-method/*.svg', { + query: '?react', + import: 'default', + eager: false +}); + +const fileSvgModules = import.meta.glob('/src/assets/svg/file-icon/*.svg', { + query: '?react', + import: 'default', + eager: false +}); + +const commonSvgModules = import.meta.glob('/src/assets/svg/*.svg', { query: '?react', import: 'default', eager: false @@ -27,8 +45,22 @@ const getPointPath = (point: AppSvgIconProps['point']) => { return '' } +// 根据类型获取对应的模块映射 +const getSvgModules = (point: AppSvgIconProps['point']) => { + switch (point) { + case 'llm': + return llmSvgModules; + case 'chunk': + return chunkSvgModules; + case 'file': + return fileSvgModules; + default: + return commonSvgModules; + } +} + /** - * 通用 SVG 图标组件 + * 通用 SVG 图标组件 - 优化版本,支持按需加载 * */ export default function AppSvgIcon(props: AppSvgIconProps) { @@ -46,8 +78,10 @@ export default function AppSvgIcon(props: AppSvgIconProps) { setLoading(true); const iconPath = `/src/assets/svg${pointPath}/${name}.svg`; - // 使用预定义的模块映射 + // 根据类型获取对应的模块映射 + const svgModules = getSvgModules(point); const moduleLoader = svgModules[iconPath]; + if (moduleLoader) { const iconModule = await moduleLoader(); setIcon(() => iconModule as React.FC>); @@ -63,10 +97,11 @@ export default function AppSvgIcon(props: AppSvgIconProps) { }; loadIcon(); - }, [name, pointPath]); + }, [name, pointPath, point]); if (loading) { - return null; // 或者返回一个加载占位符 + // 返回一个简单的占位符,避免布局跳动 + return ; } if (!Icon) { diff --git a/src/components/Layout/Header.tsx b/src/components/Layout/Header.tsx index 8846fd6..88586eb 100644 --- a/src/components/Layout/Header.tsx +++ b/src/components/Layout/Header.tsx @@ -20,6 +20,7 @@ import { import LanguageSwitcher from '../LanguageSwitcher'; import { useAuth } from '@/hooks/login-hooks'; import { useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; const Header = () => { const { userInfo, logout } = useAuth(); @@ -27,6 +28,8 @@ const Header = () => { const open = Boolean(anchorEl); const navigate = useNavigate(); + const {t} = useTranslation(); + const handleAvatarClick = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); }; @@ -193,14 +196,14 @@ const Header = () => { - 个人资料 + {t('setting.personalProfile')} {/* 模型配置 */} navigate('/setting/models')} sx={{ py: 1 }}> - 模型配置 + {t('setting.modelSettings')} @@ -209,7 +212,7 @@ const Header = () => { - 退出登录 + {t('setting.logout')} diff --git a/src/pages/setting/hooks/useModelDialogs.ts b/src/pages/setting/hooks/useModelDialogs.ts index 1d24cd7..8e7a77c 100644 --- a/src/pages/setting/hooks/useModelDialogs.ts +++ b/src/pages/setting/hooks/useModelDialogs.ts @@ -161,7 +161,7 @@ export const useApiKeyDialog = (onSuccess?: () => void) => { }; // Ollama 对话框管理 -export const useOllamaDialog = () => { +export const useOllamaDialog = (onSuccess?: () => void) => { const dialogState = useDialogState(); const showMessage = useMessage(); @@ -179,6 +179,11 @@ export const useOllamaDialog = () => { }); showMessage.success('Ollama 模型添加成功'); dialogState.closeDialog(); + + // 调用成功回调 + if (onSuccess) { + onSuccess(); + } } catch (error) { logger.error('Ollama 模型添加失败:', error); showMessage.error('Ollama 模型添加失败'); @@ -186,7 +191,7 @@ export const useOllamaDialog = () => { } finally { dialogState.setLoading(false); } - }, [dialogState, showMessage]); + }, [dialogState, showMessage, onSuccess]); return { ...dialogState, @@ -340,7 +345,7 @@ export const useSystemModelSetting = (onSuccess?: () => void) => { // 统一的模型对话框管理器 export const useModelDialogs = (onSuccess?: () => void) => { const apiKeyDialog = useApiKeyDialog(onSuccess); - const ollamaDialog = useOllamaDialog(); + const ollamaDialog = useOllamaDialog(onSuccess); const configurationDialog = useConfigurationDialog(onSuccess); const systemDialog = useSystemModelSetting(onSuccess); const deleteOps = useDeleteOperations(onSuccess); diff --git a/src/pages/setting/models.tsx b/src/pages/setting/models.tsx index 935ec29..93e3cec 100644 --- a/src/pages/setting/models.tsx +++ b/src/pages/setting/models.tsx @@ -88,6 +88,28 @@ function ModelsPage() { return filterFactory || []; }, [llmFactory, myLlm]); + const showAddModel = (factoryName: string) => { + const configurationFactories: LLMFactory[] = [ + LLM_FACTORY_LIST.AzureOpenAI, + LLM_FACTORY_LIST.Bedrock, + LLM_FACTORY_LIST.BaiduYiYan, + LLM_FACTORY_LIST.FishAudio, + LLM_FACTORY_LIST.GoogleCloud, + LLM_FACTORY_LIST.TencentCloud, + LLM_FACTORY_LIST.TencentHunYuan, + LLM_FACTORY_LIST.XunFeiSpark, + LLM_FACTORY_LIST.VolcEngine, + ] + + const fN = factoryName as LLMFactory; + if (!fN) { + return false; + } + + return LocalLlmFactories.includes(fN) || + configurationFactories.includes(fN); + } + // 处理配置模型工厂 const handleConfigureFactory = useCallback((factory: IFactory) => { if (factory == null) { @@ -126,7 +148,31 @@ function ModelsPage() { if (factoryName == null) { return; } - modelDialogs.apiKeyDialog.openApiKeyDialog(factoryName); + const factoryN = factoryName as LLMFactory; + const configurationFactories: LLMFactory[] = [ + LLM_FACTORY_LIST.AzureOpenAI, + LLM_FACTORY_LIST.Bedrock, + LLM_FACTORY_LIST.BaiduYiYan, + LLM_FACTORY_LIST.FishAudio, + LLM_FACTORY_LIST.GoogleCloud, + LLM_FACTORY_LIST.TencentCloud, + LLM_FACTORY_LIST.TencentHunYuan, + LLM_FACTORY_LIST.XunFeiSpark, + LLM_FACTORY_LIST.VolcEngine, + ] + if (LocalLlmFactories.includes(factoryN)) { + // local llm + modelDialogs.ollamaDialog.openDialog({ + llm_factory: factoryN, + }, true); + } else if (configurationFactories.includes(factoryN)) { + // custom configuration llm + modelDialogs.configurationDialog.openConfigurationDialog(factoryN); + } else { + // llm set api + modelDialogs.apiKeyDialog.openApiKeyDialog(factoryN, {}, true); + } + logger.debug('handleEditLlmFactory', factoryN); }, []); const dialog = useDialog(); @@ -247,7 +293,7 @@ function ModelsPage() { variant='contained' color='primary' startIcon={} onClick={() => handleEditLlmFactory(factoryName)} > - {t('setting.edit')} + { showAddModel(factoryName) ? t('setting.addModel') : t('setting.edit')}