update
This commit is contained in:
@@ -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<Record<string, string>> {
|
||||
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<string, string> = {};
|
||||
settingsArray.forEach(setting => {
|
||||
settingsRecord[setting.key] = setting.value;
|
||||
@@ -45,9 +44,9 @@ export const settingsService = {
|
||||
* @param settings 包含多个设置项键值对的对象
|
||||
*/
|
||||
async setMultipleSettings(settings: Record<string, string>): Promise<void> {
|
||||
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<void> {
|
||||
await Promise.all([
|
||||
settingsRepository.setSetting('ipWhitelistEnabled', String(enabled)), // 将布尔值转换为字符串
|
||||
settingsRepository.setSetting('ipWhitelistEnabled', String(enabled)),
|
||||
settingsRepository.setSetting('ipWhitelist', whitelist),
|
||||
]);
|
||||
},
|
||||
|
||||
// +++ 新增:获取焦点切换顺序 +++
|
||||
/**
|
||||
* 获取焦点切换顺序
|
||||
* @returns 返回存储的焦点切换顺序数组,如果未设置或无效则返回默认顺序
|
||||
*/
|
||||
async getFocusSwitcherSequence(): Promise<string[]> {
|
||||
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<void> {
|
||||
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<boolean> {
|
||||
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<void> {
|
||||
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.');
|
||||
}
|
||||
} // *** 最后的方法后面不需要逗号 ***
|
||||
};
|
||||
|
||||
@@ -122,9 +122,57 @@ export const settingsController = {
|
||||
}
|
||||
},
|
||||
|
||||
// +++ 新增:获取导航栏可见性 +++
|
||||
/**
|
||||
* 获取导航栏可见性设置
|
||||
*/
|
||||
async getNavBarVisibility(req: Request, res: Response): Promise<void> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
try {
|
||||
|
||||
@@ -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 黑名单列表 (需要认证)
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
<template>
|
||||
<div id="app-container">
|
||||
<header v-if="!isWorkspaceRoute || isLayoutVisible"> <!-- *** 添加 v-if *** -->
|
||||
<!-- *** 修改 v-if 条件以使用 isHeaderVisible *** -->
|
||||
<header v-if="!isWorkspaceRoute || isHeaderVisible">
|
||||
<nav ref="navRef">
|
||||
<div class="nav-left"> <!-- Group left-aligned links -->
|
||||
<RouterLink to="/">{{ t('nav.dashboard') }}</RouterLink>
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, PropType } from 'vue'; // 导入 ref 和 computed
|
||||
import { ref, computed, PropType, onMounted, watch } from 'vue'; // 导入 ref, computed, onMounted, watch
|
||||
import { useI18n } from 'vue-i18n'; // 导入 i18n
|
||||
import { storeToRefs } from 'pinia'; // *** 重新导入 storeToRefs ***
|
||||
import { useRoute } from 'vue-router'; // 导入 useRoute
|
||||
import { storeToRefs } from 'pinia'; // 导入 storeToRefs
|
||||
import WorkspaceConnectionListComponent from './WorkspaceConnectionList.vue'; // 导入连接列表组件
|
||||
import { useSessionStore } from '../stores/session.store'; // 导入 session store
|
||||
import { useLayoutStore, type PaneName } from '../stores/layout.store'; // 导入布局 store 和类型
|
||||
// 导入会话状态类型
|
||||
import type { SessionTabInfoWithStatus } from '../stores/session.store'; // 导入更新后的类型
|
||||
// *** 假设 layoutStore 会有这些状态和方法 ***
|
||||
// import { useLayoutStore } from '../stores/layout.store';
|
||||
|
||||
// --- Setup ---
|
||||
const { t } = useI18n(); // 初始化 i18n
|
||||
const layoutStore = useLayoutStore(); // 初始化布局 store
|
||||
// const { isLayoutVisible } = storeToRefs(layoutStore); // *** 移除 isLayoutVisible ***
|
||||
// const route = useRoute(); // *** 移除 route ***
|
||||
const { isHeaderVisible } = storeToRefs(layoutStore); // 从 layout store 获取主导航栏可见状态
|
||||
const route = useRoute(); // 获取路由实例
|
||||
|
||||
// 定义 Props
|
||||
const props = defineProps({
|
||||
@@ -75,9 +78,51 @@ const openLayoutConfigurator = () => {
|
||||
emit('open-layout-configurator'); // 发出事件
|
||||
};
|
||||
|
||||
// --- Layout Visibility Logic ---
|
||||
// 移除布局可见性切换逻辑
|
||||
// --- End Layout Visibility Logic ---
|
||||
// --- Header Visibility Logic ---
|
||||
const isWorkspaceRoute = ref(route.path === '/workspace'); // 检查是否在 /workspace 路由
|
||||
|
||||
// 监视路由变化
|
||||
watch(() => route.path, (newPath) => {
|
||||
isWorkspaceRoute.value = newPath === '/workspace';
|
||||
if (isWorkspaceRoute.value) {
|
||||
// 进入 /workspace 时,不需要在这里加载 Header 状态,App.vue 会处理
|
||||
console.log('[TabBar] Entered /workspace route. Header toggle button is now active.');
|
||||
}
|
||||
});
|
||||
|
||||
// 组件挂载时检查一次
|
||||
onMounted(() => {
|
||||
isWorkspaceRoute.value = route.path === '/workspace';
|
||||
if (isWorkspaceRoute.value) {
|
||||
// 初始加载时,不需要在这里加载 Header 状态,App.vue 会处理
|
||||
console.log('[TabBar] Mounted on /workspace route. Header toggle button is now active.');
|
||||
}
|
||||
});
|
||||
|
||||
// 切换主导航栏可见性 (只在 workspace 路由下生效)
|
||||
const toggleHeader = () => {
|
||||
if (isWorkspaceRoute.value) {
|
||||
console.log('[TabBar] Toggling header visibility');
|
||||
// 调用 store action
|
||||
layoutStore.toggleHeaderVisibility();
|
||||
} else {
|
||||
console.log('[TabBar] Not on /workspace route, toggle ignored.');
|
||||
}
|
||||
};
|
||||
|
||||
// 计算属性,用于确定眼睛图标的类
|
||||
const eyeIconClass = computed(() => {
|
||||
// 默认显示眼睛图标,如果主导航栏不可见,则显示斜杠眼睛
|
||||
// 注意:这里假设 isHeaderVisible 为 true 时是可见的
|
||||
return isHeaderVisible.value ? 'fas fa-eye' : 'fas fa-eye-slash';
|
||||
});
|
||||
|
||||
// 计算属性,用于按钮的 title
|
||||
const toggleButtonTitle = computed(() => {
|
||||
// 调整 i18n key 和默认文本
|
||||
return isHeaderVisible.value ? t('header.hide', '隐藏顶部导航') : t('header.show', '显示顶部导航');
|
||||
});
|
||||
// --- End Header Visibility Logic ---
|
||||
|
||||
</script>
|
||||
|
||||
@@ -106,7 +151,15 @@ const openLayoutConfigurator = () => {
|
||||
</button>
|
||||
</div>
|
||||
<div class="action-buttons-container">
|
||||
<!-- 移除布局可见性切换按钮 -->
|
||||
<!-- Header Toggle Button (Only functional on /workspace) -->
|
||||
<button
|
||||
v-if="isWorkspaceRoute"
|
||||
class="action-button header-toggle-button"
|
||||
@click="toggleHeader"
|
||||
:title="toggleButtonTitle"
|
||||
>
|
||||
<i :class="eyeIconClass"></i>
|
||||
</button>
|
||||
<!-- Layout Configurator Button -->
|
||||
<button class="action-button layout-config-button" @click="openLayoutConfigurator" :title="t('layout.configure', '配置布局')"> <!-- 使用 t 函数 -->
|
||||
<i class="fas fa-th-large"></i> <!-- 恢复为田字格图标 -->
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref, computed, watch, type Ref, type ComputedRef } from 'vue';
|
||||
// 导入 axios 用于 API 调用
|
||||
import axios from 'axios';
|
||||
|
||||
// 定义所有可用面板的名称
|
||||
export type PaneName = 'connections' | 'terminal' | 'commandBar' | 'fileManager' | 'editor' | 'statusMonitor' | 'commandHistory' | 'quickCommands';
|
||||
@@ -93,7 +95,9 @@ export const useLayoutStore = defineStore('layout', () => {
|
||||
'editor', 'statusMonitor', 'commandHistory', 'quickCommands'
|
||||
]);
|
||||
// 新增:控制布局(Header/Footer)可见性的状态
|
||||
const isLayoutVisible: Ref<boolean> = ref(true);
|
||||
const isLayoutVisible: Ref<boolean> = ref(true); // 控制整体布局(Header/Footer)可见性
|
||||
// 新增:控制主导航栏(Header)可见性的状态
|
||||
const isHeaderVisible: Ref<boolean> = ref(true); // 默认可见
|
||||
|
||||
// --- 计算属性 ---
|
||||
// 计算当前布局中正在使用的面板
|
||||
@@ -176,6 +180,45 @@ export const useLayoutStore = defineStore('layout', () => {
|
||||
function toggleLayoutVisibility() {
|
||||
isLayoutVisible.value = !isLayoutVisible.value;
|
||||
console.log(`[Layout Store] 布局可见性切换为: ${isLayoutVisible.value}`);
|
||||
// 注意:这个状态目前不与后端同步
|
||||
}
|
||||
|
||||
// 新增 Action: 从后端加载主导航栏可见性设置
|
||||
async function loadHeaderVisibility() {
|
||||
console.log('[Layout Store] Attempting to load header visibility from backend...');
|
||||
try {
|
||||
// --- 调用后端 API (复用 nav-bar-visibility 接口) ---
|
||||
const response = await axios.get<{ visible: boolean }>('/api/v1/settings/nav-bar-visibility');
|
||||
if (response && typeof response.data.visible === 'boolean') {
|
||||
isHeaderVisible.value = response.data.visible;
|
||||
console.log(`[Layout Store] Header visibility loaded from backend: ${isHeaderVisible.value}`);
|
||||
} else {
|
||||
console.warn('[Layout Store] Invalid response from backend for header visibility, using default.');
|
||||
isHeaderVisible.value = true; // 默认值
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Layout Store] Failed to load header visibility from backend:', error);
|
||||
// 出错时使用默认值
|
||||
isHeaderVisible.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 新增 Action: 切换主导航栏可见性并同步到后端
|
||||
async function toggleHeaderVisibility() {
|
||||
const newValue = !isHeaderVisible.value;
|
||||
console.log(`[Layout Store] Toggling header visibility to: ${newValue}`);
|
||||
isHeaderVisible.value = newValue; // 立即更新 UI
|
||||
|
||||
try {
|
||||
// --- 调用后端 API (复用 nav-bar-visibility 接口) ---
|
||||
await axios.put('/api/v1/settings/nav-bar-visibility', { visible: newValue });
|
||||
console.log('[Layout Store] Header visibility saved to backend.');
|
||||
} catch (error) {
|
||||
console.error('[Layout Store] Failed to save header visibility to backend:', error);
|
||||
// 可选:如果保存失败,回滚状态?
|
||||
// isHeaderVisible.value = !newValue;
|
||||
// alert('Failed to save preference.'); // 或者通知用户
|
||||
}
|
||||
}
|
||||
// --- 持久化 ---
|
||||
// 监听 layoutTree 的变化,并自动保存到 localStorage
|
||||
@@ -217,5 +260,9 @@ export const useLayoutStore = defineStore('layout', () => {
|
||||
// 新增:暴露布局可见性状态和切换方法
|
||||
isLayoutVisible,
|
||||
toggleLayoutVisibility,
|
||||
// 新增:暴露主导航栏可见性状态和操作
|
||||
isHeaderVisible,
|
||||
loadHeaderVisibility,
|
||||
toggleHeaderVisibility,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ const commandHistoryStore = useCommandHistoryStore();
|
||||
const { sessionTabsWithStatus, activeSessionId, activeSession } = storeToRefs(sessionStore);
|
||||
const { shareFileEditorTabsBoolean } = storeToRefs(settingsStore);
|
||||
const { orderedTabs: globalEditorTabs, activeTabId: globalActiveEditorTabId } = storeToRefs(fileEditorStore);
|
||||
const { layoutTree } = storeToRefs(layoutStore); // 获取布局树
|
||||
const { layoutTree } = storeToRefs(layoutStore); // 只获取布局树
|
||||
|
||||
// --- 计算属性 (用于动态绑定编辑器 Props) ---
|
||||
// 这些计算属性现在需要传递给 LayoutRenderer
|
||||
@@ -61,6 +61,7 @@ const currentSearchTerm = ref(''); // 当前搜索的关键词
|
||||
onMounted(() => {
|
||||
console.log('[工作区视图] 组件已挂载。');
|
||||
// 确保布局已初始化 (layoutStore 内部会处理)
|
||||
// 确保布局已初始化 (layoutStore 内部会处理)
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -310,6 +311,7 @@ const handleCloseEditorTab = (tabId: string) => {
|
||||
|
||||
<template>
|
||||
<div class="workspace-view">
|
||||
<!-- TerminalTabBar 始终渲染 -->
|
||||
<TerminalTabBar
|
||||
:sessions="sessionTabsWithStatus"
|
||||
:active-session-id="activeSessionId"
|
||||
@@ -319,6 +321,7 @@ const handleCloseEditorTab = (tabId: string) => {
|
||||
@request-add-connection-from-popup="handleRequestAddConnection"
|
||||
/>
|
||||
|
||||
<!-- 移除 :class 绑定 -->
|
||||
<div class="main-content-area">
|
||||
<LayoutRenderer
|
||||
v-if="layoutTree"
|
||||
@@ -370,7 +373,7 @@ const handleCloseEditorTab = (tabId: string) => {
|
||||
display: flex;
|
||||
background-color: transparent;
|
||||
flex-direction: column;
|
||||
height: calc(100vh - 3.5rem); /* 保持原始高度计算 */
|
||||
height: calc(100vh); /* 恢复原始高度计算 (假设 header 固定高度为 3.5rem) */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user