From bc50e572cbb5e5fd815eff597fbd34688517408a Mon Sep 17 00:00:00 2001 From: Baobhan Sith <80159437+Heavrnl@users.noreply.github.com> Date: Sun, 20 Apr 2025 01:22:41 +0800 Subject: [PATCH] update --- .../backend/src/services/settings.service.ts | 87 ++++++++++++------- .../src/settings/settings.controller.ts | 52 ++++++++++- .../backend/src/settings/settings.routes.ts | 5 ++ packages/frontend/src/App.vue | 8 +- .../src/components/TerminalTabBar.vue | 69 +++++++++++++-- packages/frontend/src/stores/layout.store.ts | 49 ++++++++++- packages/frontend/src/views/WorkspaceView.vue | 7 +- 7 files changed, 233 insertions(+), 44 deletions(-) diff --git a/packages/backend/src/services/settings.service.ts b/packages/backend/src/services/settings.service.ts index f196b5f..8a104b8 100644 --- a/packages/backend/src/services/settings.service.ts +++ b/packages/backend/src/services/settings.service.ts @@ -2,19 +2,18 @@ import { settingsRepository, Setting } from '../repositories/settings.repository // +++ 定义默认的焦点切换顺序 +++ const DEFAULT_FOCUS_SEQUENCE = ["quickCommandsSearch", "commandHistorySearch", "fileManagerSearch", "commandInput", "terminalSearch"]; -const FOCUS_SEQUENCE_KEY = 'focusSwitcherSequence'; // +++ 定义设置键常量 +++ +const FOCUS_SEQUENCE_KEY = 'focusSwitcherSequence'; // 焦点切换顺序设置键 +const NAV_BAR_VISIBLE_KEY = 'navBarVisible'; // 导航栏可见性设置键 export const settingsService = { - // ... (getAllSettings, getSetting, setSetting, setMultipleSettings, deleteSetting, getIpWhitelistSettings, updateIpWhitelistSettings, getFocusSwitcherSequence 保持不变) ... - /** * 获取所有设置项 - * @returns 返回包含所有设置项的数组 + * @returns 返回包含所有设置项的键值对记录 */ async getAllSettings(): Promise> { - console.log('[Service] Calling repository.getAllSettings...'); // 添加日志 + console.log('[Service] Calling repository.getAllSettings...'); const settingsArray = await settingsRepository.getAllSettings(); - console.log('[Service] Got settings array from repository:', JSON.stringify(settingsArray)); // 添加日志 + console.log('[Service] Got settings array from repository:', JSON.stringify(settingsArray)); const settingsRecord: Record = {}; settingsArray.forEach(setting => { settingsRecord[setting.key] = setting.value; @@ -45,9 +44,9 @@ export const settingsService = { * @param settings 包含多个设置项键值对的对象 */ async setMultipleSettings(settings: Record): Promise { - console.log('[Service] Calling repository.setMultipleSettings with:', JSON.stringify(settings)); // 添加日志 + console.log('[Service] Calling repository.setMultipleSettings with:', JSON.stringify(settings)); await settingsRepository.setMultipleSettings(settings); - console.log('[Service] Finished repository.setMultipleSettings.'); // 添加日志 + console.log('[Service] Finished repository.setMultipleSettings.'); }, /** @@ -66,8 +65,8 @@ export const settingsService = { const enabledStr = await settingsRepository.getSetting('ipWhitelistEnabled'); const whitelist = await settingsRepository.getSetting('ipWhitelist'); return { - enabled: enabledStr === 'true', // 将字符串 'true' 转换为布尔值 - whitelist: whitelist ?? '', // 如果为 null 则返回空字符串 + enabled: enabledStr === 'true', + whitelist: whitelist ?? '', }; }, @@ -78,26 +77,24 @@ export const settingsService = { */ async updateIpWhitelistSettings(enabled: boolean, whitelist: string): Promise { await Promise.all([ - settingsRepository.setSetting('ipWhitelistEnabled', String(enabled)), // 将布尔值转换为字符串 + settingsRepository.setSetting('ipWhitelistEnabled', String(enabled)), settingsRepository.setSetting('ipWhitelist', whitelist), ]); }, - // +++ 新增:获取焦点切换顺序 +++ /** * 获取焦点切换顺序 * @returns 返回存储的焦点切换顺序数组,如果未设置或无效则返回默认顺序 */ async getFocusSwitcherSequence(): Promise { - console.log(`[Service] Attempting to get setting for key: ${FOCUS_SEQUENCE_KEY}`); // +++ 添加日志 +++ + console.log(`[Service] Attempting to get setting for key: ${FOCUS_SEQUENCE_KEY}`); try { const sequenceJson = await settingsRepository.getSetting(FOCUS_SEQUENCE_KEY); - console.log(`[Service] Raw value from repository for ${FOCUS_SEQUENCE_KEY}:`, sequenceJson); // +++ 添加日志 +++ + console.log(`[Service] Raw value from repository for ${FOCUS_SEQUENCE_KEY}:`, sequenceJson); if (sequenceJson) { const sequence = JSON.parse(sequenceJson); - // 基本验证:确保它是一个数组并且包含字符串 if (Array.isArray(sequence) && sequence.every(item => typeof item === 'string')) { - console.log('[Service] Fetched and validated focus switcher sequence:', JSON.stringify(sequence)); // +++ 更新日志 +++ + console.log('[Service] Fetched and validated focus switcher sequence:', JSON.stringify(sequence)); return sequence; } else { console.warn('[Service] Invalid focus switcher sequence format found in settings. Returning default.'); @@ -106,33 +103,65 @@ export const settingsService = { console.log('[Service] No focus switcher sequence found in settings. Returning default.'); } } catch (error) { - console.error(`[Service] Error parsing focus switcher sequence from settings (key: ${FOCUS_SEQUENCE_KEY}):`, error); // +++ 更新日志 +++ + console.error(`[Service] Error parsing focus switcher sequence from settings (key: ${FOCUS_SEQUENCE_KEY}):`, error); } - // 如果发生错误或未找到/无效,返回默认值 - console.log('[Service] Returning default focus sequence:', JSON.stringify(DEFAULT_FOCUS_SEQUENCE)); // +++ 添加日志 +++ - return [...DEFAULT_FOCUS_SEQUENCE]; // 返回默认值的副本 + console.log('[Service] Returning default focus sequence:', JSON.stringify(DEFAULT_FOCUS_SEQUENCE)); + return [...DEFAULT_FOCUS_SEQUENCE]; }, - // +++ 新增:设置焦点切换顺序 +++ /** * 设置焦点切换顺序 * @param sequence 要保存的焦点切换顺序数组 */ async setFocusSwitcherSequence(sequence: string[]): Promise { - console.log('[Service] setFocusSwitcherSequence called with:', JSON.stringify(sequence)); // +++ 添加日志 +++ - // 基本验证 + console.log('[Service] setFocusSwitcherSequence called with:', JSON.stringify(sequence)); if (!Array.isArray(sequence) || !sequence.every(item => typeof item === 'string')) { console.error('[Service] Attempted to save invalid focus switcher sequence format:', sequence); - throw new Error('Invalid sequence format provided.'); // 抛出错误阻止保存无效数据 + throw new Error('Invalid sequence format provided.'); } try { const sequenceJson = JSON.stringify(sequence); - console.log(`[Service] Attempting to save setting. Key: ${FOCUS_SEQUENCE_KEY}, Value: ${sequenceJson}`); // +++ 添加日志 +++ + console.log(`[Service] Attempting to save setting. Key: ${FOCUS_SEQUENCE_KEY}, Value: ${sequenceJson}`); await settingsRepository.setSetting(FOCUS_SEQUENCE_KEY, sequenceJson); - console.log(`[Service] Successfully saved setting for key: ${FOCUS_SEQUENCE_KEY}`); // +++ 添加日志 +++ + console.log(`[Service] Successfully saved setting for key: ${FOCUS_SEQUENCE_KEY}`); } catch (error) { - console.error(`[Service] Error calling settingsRepository.setSetting for key ${FOCUS_SEQUENCE_KEY}:`, error); // +++ 更新日志 +++ - throw new Error('Failed to save focus switcher sequence.'); // 重新抛出错误 + console.error(`[Service] Error calling settingsRepository.setSetting for key ${FOCUS_SEQUENCE_KEY}:`, error); + throw new Error('Failed to save focus switcher sequence.'); } - }, + }, // *** 确保这里有逗号 *** + + /** + * 获取导航栏可见性设置 + * @returns 返回导航栏是否可见 (boolean),如果未设置则默认为 true + */ + async getNavBarVisibility(): Promise { + console.log(`[Service] Attempting to get setting for key: ${NAV_BAR_VISIBLE_KEY}`); + try { + const visibleStr = await settingsRepository.getSetting(NAV_BAR_VISIBLE_KEY); + console.log(`[Service] Raw value from repository for ${NAV_BAR_VISIBLE_KEY}:`, visibleStr); + // 如果设置存在且值为 'false',则返回 false,否则都返回 true (包括未设置的情况) + return visibleStr !== 'false'; + } catch (error) { + console.error(`[Service] Error getting nav bar visibility setting (key: ${NAV_BAR_VISIBLE_KEY}):`, error); + // 出错时返回默认值 true + return true; + } + }, // *** 确保这里有逗号 *** + + /** + * 设置导航栏可见性 + * @param visible 是否可见 (boolean) + */ + async setNavBarVisibility(visible: boolean): Promise { + console.log(`[Service] setNavBarVisibility called with: ${visible}`); + try { + const visibleStr = String(visible); // 将布尔值转换为 'true' 或 'false' + console.log(`[Service] Attempting to save setting. Key: ${NAV_BAR_VISIBLE_KEY}, Value: ${visibleStr}`); + await settingsRepository.setSetting(NAV_BAR_VISIBLE_KEY, visibleStr); + console.log(`[Service] Successfully saved setting for key: ${NAV_BAR_VISIBLE_KEY}`); + } catch (error) { + console.error(`[Service] Error calling settingsRepository.setSetting for key ${NAV_BAR_VISIBLE_KEY}:`, error); + throw new Error('Failed to save nav bar visibility setting.'); + } + } // *** 最后的方法后面不需要逗号 *** }; diff --git a/packages/backend/src/settings/settings.controller.ts b/packages/backend/src/settings/settings.controller.ts index 11d86a3..23907a8 100644 --- a/packages/backend/src/settings/settings.controller.ts +++ b/packages/backend/src/settings/settings.controller.ts @@ -122,9 +122,57 @@ export const settingsController = { } }, + // +++ 新增:获取导航栏可见性 +++ + /** + * 获取导航栏可见性设置 + */ + async getNavBarVisibility(req: Request, res: Response): Promise { + try { + console.log('[Controller] Received request to get nav bar visibility.'); + const isVisible = await settingsService.getNavBarVisibility(); + console.log(`[Controller] Sending nav bar visibility to client: ${isVisible}`); + res.json({ visible: isVisible }); // 返回包含 visible 键的对象 + } catch (error: any) { + console.error('[Controller] 获取导航栏可见性时出错:', error); + res.status(500).json({ message: '获取导航栏可见性失败', error: error.message }); + } + }, - /** - * 获取 IP 黑名单列表 (分页) + // +++ 新增:设置导航栏可见性 +++ + /** + * 设置导航栏可见性 + */ + async setNavBarVisibility(req: Request, res: Response): Promise { + console.log('[Controller] Received request to set nav bar visibility.'); + try { + const { visible } = req.body; + console.log('[Controller] Request body visible:', visible); + + // 输入验证 + if (typeof visible !== 'boolean') { + console.warn('[Controller] Invalid visible format received:', visible); + res.status(400).json({ message: '无效的请求体,"visible" 必须是一个布尔值' }); + return; + } + + console.log('[Controller] Calling settingsService.setNavBarVisibility...'); + await settingsService.setNavBarVisibility(visible); + console.log('[Controller] settingsService.setNavBarVisibility completed successfully.'); + + // 记录审计日志 (可选) + // console.log('[Controller] Logging audit action: NAV_BAR_VISIBILITY_UPDATED'); + // auditLogService.logAction('NAV_BAR_VISIBILITY_UPDATED', { visible }); + + console.log('[Controller] Sending success response.'); + res.status(200).json({ message: '导航栏可见性已成功更新' }); + } catch (error: any) { + console.error('[Controller] 设置导航栏可见性时出错:', error); + res.status(500).json({ message: '设置导航栏可见性失败', error: error.message }); + } + }, + + /** + * 获取 IP 黑名单列表 (分页) */ async getIpBlacklist(req: Request, res: Response): Promise { try { diff --git a/packages/backend/src/settings/settings.routes.ts b/packages/backend/src/settings/settings.routes.ts index f8763c1..26d4ac9 100644 --- a/packages/backend/src/settings/settings.routes.ts +++ b/packages/backend/src/settings/settings.routes.ts @@ -17,6 +17,11 @@ router.get('/focus-switcher-sequence', settingsController.getFocusSwitcherSequen // PUT /api/v1/settings/focus-switcher-sequence - 更新焦点切换顺序 router.put('/focus-switcher-sequence', settingsController.setFocusSwitcherSequence); +// +++ 新增:导航栏可见性路由 +++ +// GET /api/v1/settings/nav-bar-visibility - 获取导航栏可见性 +router.get('/nav-bar-visibility', settingsController.getNavBarVisibility); +// PUT /api/v1/settings/nav-bar-visibility - 更新导航栏可见性 +router.put('/nav-bar-visibility', settingsController.setNavBarVisibility); // --- IP 黑名单管理路由 --- // GET /api/v1/settings/ip-blacklist - 获取 IP 黑名单列表 (需要认证) diff --git a/packages/frontend/src/App.vue b/packages/frontend/src/App.vue index fa424e2..92c42ec 100644 --- a/packages/frontend/src/App.vue +++ b/packages/frontend/src/App.vue @@ -26,7 +26,7 @@ const focusSwitcherStore = useFocusSwitcherStore(); // +++ 实例化焦点切换 const { isAuthenticated } = storeToRefs(authStore); const { showPopupFileEditorBoolean } = storeToRefs(settingsStore); const { isStyleCustomizerVisible } = storeToRefs(appearanceStore); -const { isLayoutVisible } = storeToRefs(layoutStore); +const { isLayoutVisible, isHeaderVisible } = storeToRefs(layoutStore); // 添加 isHeaderVisible const { isConfiguratorVisible: isFocusSwitcherVisible } = storeToRefs(focusSwitcherStore); const route = useRoute(); @@ -54,6 +54,9 @@ onMounted(() => { // +++ 添加全局 Alt 键监听器 +++ window.addEventListener('keydown', handleGlobalKeyDown); + + // +++ 加载 Header 可见性状态 +++ + layoutStore.loadHeaderVisibility(); }); // +++ 添加卸载钩子以移除监听器 +++ @@ -221,7 +224,8 @@ const isElementVisibleAndFocusable = (element: HTMLElement): boolean => {