diff --git a/frontend/src/api/initialization/index.ts b/frontend/src/api/initialization/index.ts
index 66591c797..c42f1483b 100644
--- a/frontend/src/api/initialization/index.ts
+++ b/frontend/src/api/initialization/index.ts
@@ -19,6 +19,7 @@ export interface InitializationConfig {
modelName: string;
baseUrl: string;
apiKey?: string;
+ enabled: boolean;
};
multimodal: {
enabled: boolean;
diff --git a/frontend/src/assets/img/user-green.svg b/frontend/src/assets/img/user-green.svg
new file mode 100644
index 000000000..6685b1b68
--- /dev/null
+++ b/frontend/src/assets/img/user-green.svg
@@ -0,0 +1,4 @@
+
diff --git a/frontend/src/assets/img/user.svg b/frontend/src/assets/img/user.svg
new file mode 100644
index 000000000..1e26d1ed4
--- /dev/null
+++ b/frontend/src/assets/img/user.svg
@@ -0,0 +1,4 @@
+
diff --git a/frontend/src/components/menu.vue b/frontend/src/components/menu.vue
index ede1d29ba..afb55ca59 100644
--- a/frontend/src/components/menu.vue
+++ b/frontend/src/components/menu.vue
@@ -201,24 +201,19 @@ let knowledgeIcon = ref('zhishiku-green.svg');
let prefixIcon = ref('prefixIcon.svg');
let settingIcon = ref('setting.svg');
let logoutIcon = ref('logout.svg');
-let tenantIcon = ref('setting.svg'); // 暂时使用setting图标
+let tenantIcon = ref('user.svg'); // 使用专门的用户图标
let pathPrefix = ref(route.name)
const getIcon = (path) => {
fileAddIcon.value = path == 'knowledgeBase' ? 'file-add-green.svg' : 'file-add.svg';
knowledgeIcon.value = path == 'knowledgeBase' ? 'zhishiku-green.svg' : 'zhishiku.svg';
prefixIcon.value = path == 'creatChat' ? 'prefixIcon-green.svg' : path == 'knowledgeBase' ? 'prefixIcon-grey.svg' : 'prefixIcon.svg';
settingIcon.value = path == 'settings' ? 'setting-green.svg' : 'setting.svg';
- tenantIcon.value = path == 'tenant' ? 'setting-green.svg' : 'setting.svg'; // 暂时使用setting图标
+ tenantIcon.value = path == 'tenant' ? 'user-green.svg' : 'user.svg'; // 使用专门的用户图标
logoutIcon.value = 'logout.svg';
}
getIcon(route.name)
const gotopage = (path) => {
pathPrefix.value = path;
- // 如果是系统设置,跳转到初始化配置页面
- if (path === 'settings') {
- router.push('/initialization');
- return;
- }
// 处理退出登录
if (path === 'logout') {
authStore.logout();
diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts
index f0a4b4a6c..f1fee0765 100644
--- a/frontend/src/router/index.ts
+++ b/frontend/src/router/index.ts
@@ -62,9 +62,9 @@ const router = createRouter({
{
path: "settings",
name: "settings",
- component: () => import("../views/settings/Settings.vue"),
- meta: { requiresInit: true }
- },
+ component: () => import("../views/settings/SystemSettings.vue"),
+ meta: { requiresInit: true }
+ },
],
},
],
diff --git a/frontend/src/views/initialization/InitializationConfig.vue b/frontend/src/views/initialization/InitializationConfig.vue
index 8a82a71df..fa26650bc 100644
--- a/frontend/src/views/initialization/InitializationConfig.vue
+++ b/frontend/src/views/initialization/InitializationConfig.vue
@@ -2,29 +2,20 @@
-
-
@@ -941,26 +931,6 @@ const imageUpload = ref(null);
// Embedding 维度检测状态
const embeddingDimDetecting = ref(false);
-// 左侧导航区段
-type Section = { id: string; label: string };
-const sections: Section[] = [
- { id: 'ollama', label: 'Ollama 服务' },
- { id: 'llm', label: 'LLM 模型' },
- { id: 'embedding', label: 'Embedding 模型' },
- { id: 'rerank', label: 'Rerank 配置' },
- { id: 'multimodal', label: '多模态配置' },
- { id: 'docsplit', label: '文档分割' },
- { id: 'submit', label: '完成配置' },
-];
-
-const activeSectionId = ref
('ollama');
-const goToSection = (id: string) => {
- const el = document.getElementById(`section-${id}`);
- if (el) {
- el.scrollIntoView({ behavior: 'smooth', block: 'start' });
- activeSectionId.value = id;
- }
-};
// 退出登录
const handleLogout = () => {
@@ -968,19 +938,6 @@ const handleLogout = () => {
router.replace('/login');
};
-// 监听滚动,高亮当前区块
-const onScroll = () => {
- const order = ['ollama','llm','embedding','rerank','multimodal','docsplit','submit'];
- for (const id of order) {
- const el = document.getElementById(`section-${id}`);
- if (!el) continue;
- const rect = el.getBoundingClientRect();
- if (rect.top <= 120 && rect.bottom >= 120) {
- activeSectionId.value = id;
- break;
- }
- }
-};
// 配置回填
const loadCurrentConfig = async () => {
@@ -1004,8 +961,8 @@ const loadCurrentConfig = async () => {
if (config.rerank) {
Object.assign(formData.rerank, config.rerank);
}
- formData.storageType = config.multimodal.storageType;
if (config.multimodal) {
+ formData.storageType = config.multimodal.storageType || 'minio';
formData.multimodal.enabled = config.multimodal.enabled || false;
if (config.multimodal.vlm) {
Object.assign(formData.multimodal.vlm, config.multimodal.vlm);
@@ -1014,11 +971,14 @@ const loadCurrentConfig = async () => {
formData.multimodal.vlm.interfaceType = 'ollama';
}
}
- if (config.multimodal.storageType === 'cos') {
+ if (config.multimodal.storageType === 'cos' && config.multimodal.cos) {
Object.assign(formData.multimodal.cos, config.multimodal.cos);
- } else if (config.multimodal.storageType === 'minio') {
+ } else if (config.multimodal.storageType === 'minio' && config.multimodal.minio) {
Object.assign(formData.multimodal.minio, config.multimodal.minio);
}
+ } else {
+ // 如果没有多模态配置,设置默认存储类型
+ formData.storageType = 'minio';
}
if (config.documentSplitting) {
Object.assign(formData.documentSplitting, config.documentSplitting);
@@ -1351,8 +1311,6 @@ onUnmounted(() => {
clearTimeout(submitDebounceTimer.value);
submitDebounceTimer.value = null;
}
-
- window.removeEventListener('scroll', onScroll);
});
// 事件处理
@@ -1740,6 +1698,23 @@ const handleSubmit = async () => {
// 调用初始化API
const payload: any = JSON.parse(JSON.stringify(formData));
+
+ // 确保存储类型在正确的位置,并只保留选中的存储配置
+ if (payload.multimodal && payload.storageType) {
+ payload.multimodal.storageType = payload.storageType;
+
+ // 根据选择的存储类型,只保留对应的配置,删除其他存储配置
+ if (payload.storageType === 'cos') {
+ // 保留COS配置,删除MinIO配置
+ delete payload.multimodal.minio;
+ } else if (payload.storageType === 'minio') {
+ // 保留MinIO配置,删除COS配置
+ delete payload.multimodal.cos;
+ }
+
+ delete payload.storageType; // 删除顶级的storageType字段
+ }
+
await initializeSystem(payload);
const successMessage = isUpdateMode.value ? '配置更新成功!' : '系统初始化成功!';
@@ -1777,9 +1752,6 @@ onMounted(async () => {
// 检查已配置模型状态
await checkAllConfiguredModels();
-
- // 绑定滚动监听,用于左侧导航高亮
- window.addEventListener('scroll', onScroll, { passive: true });
});
const onRerankChange = () => {
@@ -2347,144 +2319,75 @@ const detectEmbeddingDimension = async () => {
diff --git a/frontend/src/views/settings/SystemSettings.vue b/frontend/src/views/settings/SystemSettings.vue
new file mode 100644
index 000000000..730b3d04f
--- /dev/null
+++ b/frontend/src/views/settings/SystemSettings.vue
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
diff --git a/frontend/src/views/tenant/TenantInfo.vue b/frontend/src/views/tenant/TenantInfo.vue
index 6379b154d..1890cb26c 100644
--- a/frontend/src/views/tenant/TenantInfo.vue
+++ b/frontend/src/views/tenant/TenantInfo.vue
@@ -311,11 +311,11 @@ onMounted(() => {
.tenant-info-container {
padding: 20px;
background-color: #fff;
- border-radius: 8px;
- margin: 0 20px 20px 20px;
- height: calc(100vh - 40px);
+ margin: 0 20px 0 20px;
+ height: calc(100vh);
overflow-y: auto;
box-sizing: border-box;
+ flex: 1;
}
.tenant-header {
@@ -363,7 +363,7 @@ onMounted(() => {
.api-key-content,
.storage-content,
.doc-content {
-// padding: 16px 0;
+ margin-top: 0;
}
.api-key-input {
diff --git a/internal/handler/initialization.go b/internal/handler/initialization.go
index 07078a401..b74fd5580 100644
--- a/internal/handler/initialization.go
+++ b/internal/handler/initialization.go
@@ -83,9 +83,7 @@ func NewInitializationHandler(
// InitializationRequest 初始化请求结构
type InitializationRequest struct {
- // 前端传入的存储类型:cos 或 minio
- StorageType string `json:"storageType"`
- LLM struct {
+ LLM struct {
Source string `json:"source" binding:"required"`
ModelName string `json:"modelName" binding:"required"`
BaseURL string `json:"baseUrl"`
@@ -115,7 +113,8 @@ type InitializationRequest struct {
APIKey string `json:"apiKey"`
InterfaceType string `json:"interfaceType"` // "ollama" or "openai"
} `json:"vlm,omitempty"`
- COS *struct {
+ StorageType string `json:"storageType"`
+ COS *struct {
SecretID string `json:"secretId"`
SecretKey string `json:"secretKey"`
Region string `json:"region"`
@@ -210,7 +209,7 @@ func (h *InitializationHandler) Initialize(c *gin.Context) {
// 验证多模态配置
if req.Multimodal.Enabled {
- storageType := strings.ToLower(req.StorageType)
+ storageType := strings.ToLower(req.Multimodal.StorageType)
if req.Multimodal.VLM == nil {
logger.Error(ctx, "Multimodal enabled but missing VLM configuration")
c.Error(errors.NewBadRequestError("启用多模态时需要配置VLM信息"))
@@ -502,11 +501,11 @@ func (h *InitializationHandler) Initialize(c *gin.Context) {
InterfaceType: req.Multimodal.VLM.InterfaceType,
},
}
- switch req.StorageType {
+ switch req.Multimodal.StorageType {
case "cos":
if req.Multimodal.COS != nil {
kb.StorageConfig = types.StorageConfig{
- Provider: req.StorageType,
+ Provider: req.Multimodal.StorageType,
BucketName: req.Multimodal.COS.BucketName,
AppID: req.Multimodal.COS.AppID,
PathPrefix: req.Multimodal.COS.PathPrefix,
@@ -518,7 +517,7 @@ func (h *InitializationHandler) Initialize(c *gin.Context) {
case "minio":
if req.Multimodal.Minio != nil {
kb.StorageConfig = types.StorageConfig{
- Provider: req.StorageType,
+ Provider: req.Multimodal.StorageType,
BucketName: req.Multimodal.Minio.BucketName,
PathPrefix: req.Multimodal.Minio.PathPrefix,
SecretID: os.Getenv("MINIO_ACCESS_KEY_ID"),
@@ -560,11 +559,11 @@ func (h *InitializationHandler) Initialize(c *gin.Context) {
APIKey: req.Multimodal.VLM.APIKey,
InterfaceType: req.Multimodal.VLM.InterfaceType,
}
- switch req.StorageType {
+ switch req.Multimodal.StorageType {
case "cos":
if req.Multimodal.COS != nil {
kb.StorageConfig = types.StorageConfig{
- Provider: req.StorageType,
+ Provider: req.Multimodal.StorageType,
SecretID: req.Multimodal.COS.SecretID,
SecretKey: req.Multimodal.COS.SecretKey,
Region: req.Multimodal.COS.Region,
@@ -576,7 +575,7 @@ func (h *InitializationHandler) Initialize(c *gin.Context) {
case "minio":
if req.Multimodal.Minio != nil {
kb.StorageConfig = types.StorageConfig{
- Provider: req.StorageType,
+ Provider: req.Multimodal.StorageType,
BucketName: req.Multimodal.Minio.BucketName,
PathPrefix: req.Multimodal.Minio.PathPrefix,
SecretID: os.Getenv("MINIO_ACCESS_KEY_ID"),