package api import ( "fmt" "u-desk/internal/service" ) // ConfigAPI 配置 API type ConfigAPI struct { configService *service.ConfigService } // NewConfigAPI 创建配置 API 实例 func NewConfigAPI() (*ConfigAPI, error) { configService, err := service.NewConfigService() if err != nil { return nil, err } return &ConfigAPI{ configService: configService, }, nil } // GetAppConfigResponse 获取应用配置响应 type GetAppConfigResponse struct { Tabs []AppTabDefinition `json:"tabs"` VisibleTabs []string `json:"visibleTabs"` DefaultTab string `json:"defaultTab"` } // AppTabDefinition 应用 Tab 定义(前端格式) type AppTabDefinition struct { Key string `json:"key"` Title string `json:"title"` Visible bool `json:"visible"` Enabled bool `json:"enabled"` } // SaveAppConfigRequest 保存应用配置请求(前端格式) type SaveAppConfigRequest struct { Tabs []AppTabDefinition `json:"tabs"` VisibleTabs []string `json:"visibleTabs"` DefaultTab string `json:"defaultTab"` } // GetAppConfig 获取应用配置 func (api *ConfigAPI) GetAppConfig() (map[string]interface{}, error) { tabConfig, err := api.configService.GetTabConfig() if err != nil { return map[string]interface{}{ "success": false, "message": fmt.Sprintf("获取配置失败: %v", err), }, err } // 转换为前端格式 tabs := make([]AppTabDefinition, len(tabConfig.AvailableTabs)) visibleTabSet := make(map[string]bool) for _, key := range tabConfig.VisibleTabs { visibleTabSet[key] = true } for i, tab := range tabConfig.AvailableTabs { tabs[i] = AppTabDefinition{ Key: tab.Key, Title: tab.Title, Visible: visibleTabSet[tab.Key], Enabled: tab.Enabled, } } return map[string]interface{}{ "success": true, "data": GetAppConfigResponse{ Tabs: tabs, VisibleTabs: tabConfig.VisibleTabs, DefaultTab: tabConfig.DefaultTab, }, }, nil } // SaveAppConfig 保存应用配置 func (api *ConfigAPI) SaveAppConfig(req SaveAppConfigRequest) (map[string]interface{}, error) { // 验证:至少保留一个可见 Tab if len(req.VisibleTabs) < 1 { return map[string]interface{}{ "success": false, "message": "至少需要保留一个可见的 Tab", }, fmt.Errorf("至少需要保留一个可见的 Tab") } // 验证:默认 Tab 必须在可见列表中 defaultTabExists := false for _, key := range req.VisibleTabs { if key == req.DefaultTab { defaultTabExists = true break } } if !defaultTabExists { return map[string]interface{}{ "success": false, "message": "默认 Tab 必须在可见列表中", }, fmt.Errorf("默认 Tab 必须在可见列表中") } // 转换为服务层格式 availableTabs := make([]service.TabDefinition, len(req.Tabs)) for i, tab := range req.Tabs { availableTabs[i] = service.TabDefinition{ Key: tab.Key, Title: tab.Title, Enabled: tab.Enabled, } } tabConfig := &service.TabConfig{ AvailableTabs: availableTabs, VisibleTabs: req.VisibleTabs, DefaultTab: req.DefaultTab, } // 保存配置 if err := api.configService.SaveTabConfig(tabConfig); err != nil { return map[string]interface{}{ "success": false, "message": fmt.Sprintf("保存配置失败: %v", err), }, err } return map[string]interface{}{ "success": true, "message": "配置保存成功", "data": nil, }, nil } // MigrateTabConfig 迁移旧配置(device 移除 + openclaw-manager 重命名) func (api *ConfigAPI) MigrateTabConfig() error { config, _ := api.configService.GetTabConfig() if config == nil { return nil } needMigrate := false // 检查是否包含需要迁移的旧 key for _, tab := range config.AvailableTabs { if tab.Key == "device" || tab.Key == "openclaw-manager" { needMigrate = true break } } if !needMigrate { return nil } // 映射:旧 key → 新 key(不需要的移除) keyMap := map[string]string{ "openclaw-manager": "version", // "device": "" // 直接过滤 } newTabs := make([]service.TabDefinition, 0, len(config.AvailableTabs)) newVisible := make([]string, 0, len(config.VisibleTabs)) seenKeys := map[string]bool{} for _, tab := range config.AvailableTabs { newKey, shouldRename := keyMap[tab.Key] if shouldRename { if newKey == "" { continue // 移除(如 device) } if seenKeys[newKey] { continue // 避免重复 } seenKeys[newKey] = true newTabs = append(newTabs, service.TabDefinition{Key: newKey, Title: tab.Title, Enabled: tab.Enabled}) } else { newTabs = append(newTabs, tab) } } for _, key := range config.VisibleTabs { if newKey, ok := keyMap[key]; ok { if newKey != "" && !seenKeys[newKey] { newVisible = append(newVisible, newKey) } // newKey == "" 时跳过(如 device) } else { newVisible = append(newVisible, key) } } defaultTab := config.DefaultTab if newKey, ok := keyMap[defaultTab]; ok && newKey != "" { defaultTab = newKey } if defaultTab == "device" { defaultTab = "file-system" } return api.configService.SaveTabConfig(&service.TabConfig{ AvailableTabs: newTabs, VisibleTabs: newVisible, DefaultTab: defaultTab, }) }