diff --git a/packages/backend/src/repositories/appearance.repository.ts b/packages/backend/src/repositories/appearance.repository.ts index a11c248..a3e81b4 100644 --- a/packages/backend/src/repositories/appearance.repository.ts +++ b/packages/backend/src/repositories/appearance.repository.ts @@ -19,6 +19,7 @@ const mapRowsToAppearanceSettings = (rows: DbAppearanceSettingsRow[]): Appearanc const settings: Partial = {}; let latestUpdatedAt = 0; let terminalBackgroundEnabledFound = false; // 标记是否在数据库中找到该设置 + let terminalBackgroundOverlayOpacityFound = false; // 标记是否找到蒙版透明度设置 for (const row of rows) { // 更新 latestUpdatedAt @@ -51,7 +52,11 @@ const mapRowsToAppearanceSettings = (rows: DbAppearanceSettingsRow[]): Appearanc break; case 'terminalBackgroundEnabled': settings.terminalBackgroundEnabled = row.value === 'true'; // 将 'true'/'false' 字符串转为 boolean - terminalBackgroundEnabledFound = true; // 标记已找到 + terminalBackgroundEnabledFound = true; + break; + case 'terminalBackgroundOverlayOpacity': + settings.terminalBackgroundOverlayOpacity = parseFloat(row.value); + terminalBackgroundOverlayOpacityFound = true; break; } } @@ -70,6 +75,9 @@ const mapRowsToAppearanceSettings = (rows: DbAppearanceSettingsRow[]): Appearanc terminalBackgroundEnabled: terminalBackgroundEnabledFound ? settings.terminalBackgroundEnabled // 使用数据库找到的值 (true 或 false) : defaults.terminalBackgroundEnabled, // 否则使用默认值 (true) + terminalBackgroundOverlayOpacity: terminalBackgroundOverlayOpacityFound + ? settings.terminalBackgroundOverlayOpacity // 使用数据库找到的值 + : defaults.terminalBackgroundOverlayOpacity, // 否则使用默认值 updatedAt: latestUpdatedAt || defaults.updatedAt, // 使用最新的更新时间,否则使用默认时间戳 }; }; @@ -86,6 +94,7 @@ const getDefaultAppearanceSettings = (): Omit => { terminalBackgroundImage: undefined, pageBackgroundImage: undefined, terminalBackgroundEnabled: true, // 默认启用 + terminalBackgroundOverlayOpacity: 0.5, // 默认蒙版透明度 updatedAt: Date.now(), // 提供默认时间戳 }; }; @@ -110,7 +119,8 @@ export const ensureDefaultSettingsExist = async (db: sqlite3.Database): Promise< { key: 'editorFontSize', value: defaults.editorFontSize }, { key: 'terminalBackgroundImage', value: defaults.terminalBackgroundImage ?? '' }, // 数据库中使用空字符串 { key: 'pageBackgroundImage', value: defaults.pageBackgroundImage ?? '' }, // 数据库中使用空字符串 - { key: 'terminalBackgroundEnabled', value: defaults.terminalBackgroundEnabled }, // 新增 + { key: 'terminalBackgroundEnabled', value: defaults.terminalBackgroundEnabled }, + { key: 'terminalBackgroundOverlayOpacity', value: defaults.terminalBackgroundOverlayOpacity }, // 新增 ]; try { diff --git a/packages/backend/src/services/appearance.service.ts b/packages/backend/src/services/appearance.service.ts index aa232ed..bfb602f 100644 --- a/packages/backend/src/services/appearance.service.ts +++ b/packages/backend/src/services/appearance.service.ts @@ -9,7 +9,12 @@ import * as terminalThemeRepository from '../repositories/terminal-theme.reposit * @returns Promise */ export const getSettings = async (): Promise => { - return appearanceRepository.getAppearanceSettings(); + const settings = await appearanceRepository.getAppearanceSettings(); + // 为 terminalBackgroundOverlayOpacity 提供默认值 + if (settings.terminalBackgroundOverlayOpacity === undefined || settings.terminalBackgroundOverlayOpacity === null) { + settings.terminalBackgroundOverlayOpacity = 0.5; // 默认透明度为 0.5 + } + return settings; }; /** @@ -64,6 +69,15 @@ export const updateSettings = async (settingsDto: UpdateAppearanceDto): Promise< settingsDto.editorFontSize = size; } + // 验证 terminalBackgroundOverlayOpacity (如果提供了) + if (settingsDto.terminalBackgroundOverlayOpacity !== undefined && settingsDto.terminalBackgroundOverlayOpacity !== null) { + const opacity = Number(settingsDto.terminalBackgroundOverlayOpacity); + if (isNaN(opacity) || opacity < 0 || opacity > 1) { + throw new Error(`无效的终端背景蒙版透明度: ${settingsDto.terminalBackgroundOverlayOpacity}。必须是一个 0 到 1 之间的数字。`); + } + settingsDto.terminalBackgroundOverlayOpacity = opacity; // 确保类型正确 + } + // TODO: 如果实现了背景图片上传,这里需要处理文件路径或 URL 的验证/保存逻辑 return appearanceRepository.updateAppearanceSettings(settingsDto); diff --git a/packages/backend/src/types/appearance.types.ts b/packages/backend/src/types/appearance.types.ts index a3146a2..d568f99 100644 --- a/packages/backend/src/types/appearance.types.ts +++ b/packages/backend/src/types/appearance.types.ts @@ -17,6 +17,7 @@ export interface AppearanceSettings { pageBackgroundImage?: string; // 页面背景图片 URL 或路径 editorFontSize?: number; // 编辑器字体大小 (px) terminalBackgroundEnabled?: boolean; // 终端背景是否启用 + terminalBackgroundOverlayOpacity?: number; // 终端背景蒙版透明度 (0-1) updatedAt?: number; } diff --git a/packages/backend/src/types/settings.types.ts b/packages/backend/src/types/settings.types.ts index 70350cf..ee80ab0 100644 --- a/packages/backend/src/types/settings.types.ts +++ b/packages/backend/src/types/settings.types.ts @@ -66,7 +66,7 @@ export interface UpdateCaptchaSettingsDto { export interface AppSettings { sidebar?: SidebarConfig; captcha?: CaptchaSettings; - showStatusMonitorIpAddress?: boolean; // 新增:是否在状态监视器中显示IP地址 + showStatusMonitorIpAddress?: boolean; // 是否在状态监视器中显示IP地址 // 可以添加其他设置模块,例如: // security?: SecuritySettings; // general?: GeneralSettings; diff --git a/packages/frontend/src/components/StyleCustomizer.vue b/packages/frontend/src/components/StyleCustomizer.vue index 13460c9..771eed3 100644 --- a/packages/frontend/src/components/StyleCustomizer.vue +++ b/packages/frontend/src/components/StyleCustomizer.vue @@ -22,7 +22,8 @@ const { terminalBackgroundImage, - isTerminalBackgroundEnabled, + isTerminalBackgroundEnabled, + currentTerminalBackgroundOverlayOpacity, // 从 store 解构 } = storeToRefs(appearanceStore); @@ -34,7 +35,8 @@ const editableEditorFontSize = ref(14); const editableUiThemeString = ref(''); const themeParseError = ref(null); -const localTerminalBackgroundEnabled = ref(true); +const localTerminalBackgroundEnabled = ref(true); +const editableTerminalBackgroundOverlayOpacity = ref(0.5); // 本地编辑状态,默认 0.5 // 终端主题管理相关状态 const isEditingTheme = ref(false); // 是否正在编辑某个主题 @@ -95,7 +97,9 @@ const initializeEditableState = () => { editableTerminalFontSize.value = currentTerminalFontSize.value; editableEditorFontSize.value = currentEditorFontSize.value; // <-- 新增 localTerminalBackgroundEnabled.value = isTerminalBackgroundEnabled.value; // <-- 重新添加:在此处初始化 + editableTerminalBackgroundOverlayOpacity.value = currentTerminalBackgroundOverlayOpacity.value; // 初始化蒙版透明度 console.log(`[StyleCustomizer initializeEditableState] Initializing localTerminalBackgroundEnabled to: ${localTerminalBackgroundEnabled.value} (from store: ${isTerminalBackgroundEnabled.value})`); // 添加日志 + console.log(`[StyleCustomizer initializeEditableState] Initializing editableTerminalBackgroundOverlayOpacity to: ${editableTerminalBackgroundOverlayOpacity.value} (from store: ${currentTerminalBackgroundOverlayOpacity.value})`); // 新增日志 uploadError.value = null; importError.value = null; saveThemeError.value = null; @@ -135,7 +139,9 @@ watch([ const oldActiveThemeId = oldVals ? oldVals[1] : null; // 仅当非编辑状态时,或活动终端主题ID变化时,或 UI 主题/终端背景启用状态设置本身发生变化时 (例如重置或外部更改),才重新初始化 - const settingsChanged = newSettings?.customUiTheme !== oldSettings?.customUiTheme || newSettings?.terminalBackgroundEnabled !== oldSettings?.terminalBackgroundEnabled; // 检查相关设置是否变化 + const settingsChanged = newSettings?.customUiTheme !== oldSettings?.customUiTheme || + newSettings?.terminalBackgroundEnabled !== oldSettings?.terminalBackgroundEnabled || + newSettings?.terminalBackgroundOverlayOpacity !== oldSettings?.terminalBackgroundOverlayOpacity; // 检查相关设置是否变化 if (!isEditingTheme.value || newActiveThemeId !== oldActiveThemeId || settingsChanged) { console.log(`[StyleCustomizer Watch] Triggering re-initialization. isEditing: ${isEditingTheme.value}, themeIdChanged: ${newActiveThemeId !== oldActiveThemeId}, settingsChanged: ${settingsChanged}`); // 添加日志 initializeEditableState(); // 调用修改后的初始化函数 @@ -150,6 +156,7 @@ watch([ editableTerminalFontSize.value = newSettings?.terminalFontSize || 14; editableEditorFontSize.value = newSettings?.editorFontSize || 14; // <-- 新增同步 // localTerminalBackgroundEnabled.value = newSettings?.terminalBackgroundEnabled ?? true; // <-- 移除此行,避免冲突 + // editableTerminalBackgroundOverlayOpacity.value = newSettings?.terminalBackgroundOverlayOpacity ?? 0.5; // 在 initializeEditableState 中处理 } }, { deep: true }); @@ -165,6 +172,14 @@ watch(isTerminalBackgroundEnabled, (newValue) => { } }); // 移除单独监听 isTerminalBackgroundEnabled 的 watcher + +// 监听 store 中 currentTerminalBackgroundOverlayOpacity 的变化,以同步本地状态 +watch(currentTerminalBackgroundOverlayOpacity, (newValue) => { + if (editableTerminalBackgroundOverlayOpacity.value !== newValue) { + console.log(`[StyleCustomizer Watch currentTerminalBackgroundOverlayOpacity] Store changed to ${newValue}, updating local state.`); + editableTerminalBackgroundOverlayOpacity.value = newValue; + } +}); const emit = defineEmits(['close']); @@ -791,6 +806,22 @@ const handleToggleTerminalBackground = async () => { } }; +// 保存终端背景蒙版透明度 +const handleSaveTerminalBackgroundOverlayOpacity = async () => { + try { + const opacity = Number(editableTerminalBackgroundOverlayOpacity.value); + if (isNaN(opacity) || opacity < 0 || opacity > 1) { + alert(t('styleCustomizer.errorInvalidOpacityValue')); // 需要添加翻译 "无效的透明度值,必须在0到1之间" + return; + } + await appearanceStore.setTerminalBackgroundOverlayOpacity(opacity); + alert(t('styleCustomizer.terminalBgOverlayOpacitySaved')); // 需要添加翻译 "终端背景蒙版透明度已保存" + } catch (error: any) { + console.error("保存终端背景蒙版透明度失败:", error); + alert(t('styleCustomizer.terminalBgOverlayOpacitySaveFailed', { message: error.message })); // 需要添加翻译 "终端背景蒙版透明度保存失败" + } +}; + // Removed handlePageOpacityChange and handleTerminalOpacityChange functions // --- 辅助函数 --- @@ -1188,14 +1219,39 @@ const handleFocusAndSelect = (event: FocusEvent) => {
-
- {{ t('styleCustomizer.noBackground') }} +
+ +
+ {{ t('styleCustomizer.noBackground') }}
+ + +
+ +
+ + {{ editableTerminalBackgroundOverlayOpacity.toFixed(2) }} + +
+ +
{{ t('styleCustomizer.terminalBgDisabled', '终端背景功能已禁用。') }} diff --git a/packages/frontend/src/components/Terminal.vue b/packages/frontend/src/components/Terminal.vue index 57a68bd..78ddb94 100644 --- a/packages/frontend/src/components/Terminal.vue +++ b/packages/frontend/src/components/Terminal.vue @@ -23,7 +23,8 @@ const props = defineProps<{ const emitWorkspaceEvent = useWorkspaceEventEmitter(); // +++ 获取事件发射器 +++ -const terminalRef = ref(null); // 终端容器的引用 +const terminalRef = ref(null); // xterm 挂载点的引用 (内部容器) +const terminalOuterWrapperRef = ref(null); // 最外层容器的引用,用于背景图 let terminal: Terminal | null = null; let fitAddon: FitAddon | null = null; let searchAddon: SearchAddon | null = null; // *** 添加 searchAddon 变量 *** @@ -40,7 +41,8 @@ const { currentTerminalFontFamily, terminalBackgroundImage, currentTerminalFontSize, - isTerminalBackgroundEnabled + isTerminalBackgroundEnabled, + currentTerminalBackgroundOverlayOpacity, // 获取蒙版透明度 } = storeToRefs(appearanceStore); // --- Settings Store --- @@ -85,7 +87,8 @@ const debouncedEmitResize = debounce((term: Terminal) => { // 立即执行 Fit 并发送 Resize 的函数 const fitAndEmitResizeNow = (term: Terminal) => { - if (!term || !terminalRef.value) return; // 添加 terminalRef.value 检查 + // terminalRef 现在指向内部容器,检查它即可 + if (!term || !terminalRef.value) return; try { // 确保容器可见且有尺寸 if (terminalRef.value.offsetHeight > 0 && terminalRef.value.offsetWidth > 0) { @@ -98,6 +101,7 @@ const fitAndEmitResizeNow = (term: Terminal) => { // 使用 nextTick 确保 fit() 的效果已反映,再触发 resize nextTick(() => { // 再次检查终端实例是否仍然存在 + // terminalRef 现在指向内部容器 if (terminal && terminalRef.value) { console.log(`[Terminal ${props.sessionId}] Triggering window resize event after immediate fit.`); window.dispatchEvent(new Event('resize')); @@ -160,6 +164,7 @@ const removeContextMenuListener = () => { // 初始化终端 onMounted(() => { + // xterm 挂载到 terminalRef (内部容器) if (terminalRef.value) { terminal = new Terminal({ cursorBlink: true, @@ -198,8 +203,9 @@ onMounted(() => { }); // 监听终端大小变化 (通过 ResizeObserver) - 主要处理浏览器窗口大小变化等 + // ResizeObserver 观察内部容器 terminalRef if (terminalRef.value) { - observedElement = terminalRef.value; // +++ Store the element to be observed +++ + observedElement = terminalRef.value; resizeObserver = new ResizeObserver((entries) => { // Only process if the terminal is active if (!props.isActive || !terminal) return; @@ -242,6 +248,7 @@ onMounted(() => { nextTick(() => { setTimeout(() => { // Re-check if still active and terminal exists + // 检查内部容器 terminalRef if (props.isActive && terminal && terminalRef.value && terminalRef.value.offsetHeight > 0) { fitAndEmitResizeNow(terminal); // Also ensure focus when becoming active @@ -445,7 +452,7 @@ onMounted(() => { }); - // 重新添加鼠标滚轮缩放功能 + // 重新添加鼠标滚轮缩放功能到内部容器 terminalRef if (terminalRef.value) { terminalRef.value.addEventListener('wheel', (event: WheelEvent) => { // // 只在按下Ctrl键时才触发缩放 @@ -534,9 +541,9 @@ onBeforeUnmount(() => { // 确保在卸载时移除右键监听器 removeContextMenuListener(); - if (terminalRef.value) { - - } + // terminalRef 是内部容器,不需要特别处理 + // if (terminalRef.value) { + // } }); // 暴露 write 方法给父组件 (可选) const write = (data: string | Uint8Array) => { @@ -572,60 +579,40 @@ defineExpose({ write, findNext, findPrevious, clearSearch, clear }); // 暴露 c // --- 应用终端背景 --- const applyTerminalBackground = () => { - if (terminalRef.value) { - // 首先检查背景功能是否启用 + // 背景应用到 terminalOuterWrapperRef + if (terminalOuterWrapperRef.value) { if (!isTerminalBackgroundEnabled.value) { - // 如果禁用,则移除背景并返回 nextTick(() => { - if (terminalRef.value) { - terminalRef.value.style.backgroundImage = 'none'; - terminalRef.value.classList.remove('has-terminal-background'); + if (terminalOuterWrapperRef.value) { + terminalOuterWrapperRef.value.style.backgroundImage = 'none'; + terminalOuterWrapperRef.value.classList.remove('has-terminal-background'); } }); console.log(`[Terminal ${props.sessionId}] 终端背景已禁用,移除背景。`); - return; // 提前退出 + return; } - // 如果启用,再检查是否有背景图片 if (terminalBackgroundImage.value) { - // --- 修改开始 --- - // 使用环境变量获取后端基础 URL - const backendUrl = import.meta.env.VITE_API_BASE_URL || ''; // 提供一个默认空字符串以防万一 + const backendUrl = import.meta.env.VITE_API_BASE_URL || ''; const imagePath = terminalBackgroundImage.value; - console.log(`[Terminal applyTerminalBackground] backendUrl: "${backendUrl}", imagePath: "${imagePath}"`); // 详细日志 const fullImageUrl = `${backendUrl}${imagePath}`; - console.log(`[Terminal applyTerminalBackground] fullImageUrl: "${fullImageUrl}"`); // 打印完整 URL - // --- 修改结束 --- - // --- 使用 nextTick 包装样式应用 --- nextTick(() => { - if (terminalRef.value) { // 再次检查 ref 是否存在 - terminalRef.value.style.backgroundImage = `url(${fullImageUrl})`; - terminalRef.value.style.backgroundSize = 'cover'; // Or 'contain', 'auto', etc. - terminalRef.value.style.backgroundPosition = 'center'; - terminalRef.value.style.backgroundRepeat = 'no-repeat'; - // 添加 CSS 类 - terminalRef.value.classList.add('has-terminal-background'); + if (terminalOuterWrapperRef.value) { + terminalOuterWrapperRef.value.style.backgroundImage = `url(${fullImageUrl})`; + terminalOuterWrapperRef.value.style.backgroundSize = 'cover'; + terminalOuterWrapperRef.value.style.backgroundPosition = 'center'; + terminalOuterWrapperRef.value.style.backgroundRepeat = 'no-repeat'; + terminalOuterWrapperRef.value.classList.add('has-terminal-background'); } }); - // 应用透明度: 通过设置背景色实现,需要 xterm 的 allowTransparency: true - // 注意:这会影响整个终端的背景,包括文本后的背景 - // 一个常见的做法是设置一个稍微透明的背景色,让图片透出来 - // 例如,将 xterm 主题的 background 设置为 rgba(r, g, b, opacity) - // 这里我们简单设置容器的 opacity,但这会影响文本!更好的方法是修改主题。 - // 另一种方法是用伪元素做背景层。 - // 为了简单起见,我们暂时只设置背景图,透明度让用户在主题中调整 background 的 alpha 值。 - // terminalRef.value.style.opacity = terminalBackgroundOpacity.value.toString(); // 不推荐直接设置 opacity console.log(`[Terminal ${props.sessionId}] 应用终端背景图片: ${terminalBackgroundImage.value}`); } else { - // --- 使用 nextTick 包装样式移除 --- nextTick(() => { - if (terminalRef.value) { // 再次检查 ref 是否存在 - terminalRef.value.style.backgroundImage = 'none'; - // 移除 CSS 类 - terminalRef.value.classList.remove('has-terminal-background'); + if (terminalOuterWrapperRef.value) { + terminalOuterWrapperRef.value.style.backgroundImage = 'none'; + terminalOuterWrapperRef.value.classList.remove('has-terminal-background'); } }); - // terminalRef.value.style.opacity = '1'; // 移除背景时恢复不透明 console.log(`[Terminal ${props.sessionId}] 移除终端背景图片。`); } } @@ -634,41 +621,46 @@ const applyTerminalBackground = () => { diff --git a/packages/frontend/src/locales/en-US.json b/packages/frontend/src/locales/en-US.json index 4fb68cd..bfa6d16 100644 --- a/packages/frontend/src/locales/en-US.json +++ b/packages/frontend/src/locales/en-US.json @@ -91,7 +91,12 @@ "defaultMode": "Default Mode", "darkMode": "Dark Mode", "darkModeApplied": "Dark mode applied", - "darkModeApplyFailed": "Failed to apply dark mode: {message}" + "darkModeApplyFailed": "Failed to apply dark mode: {message}", + "terminalBgOverlayOpacity": "Terminal Background Overlay Opacity:", + "terminalBgOverlayOpacityDesc": "Controls the opacity of the black overlay on top of the background image. 0 is fully transparent, 1 is fully opaque.", + "errorInvalidOpacityValue": "Invalid opacity value. Must be between 0 and 1.", + "terminalBgOverlayOpacitySaved": "Terminal background overlay opacity saved.", + "terminalBgOverlayOpacitySaveFailed": "Failed to save terminal background overlay opacity: {message}" }, "login": { "title": "User Login", diff --git a/packages/frontend/src/locales/ja-JP.json b/packages/frontend/src/locales/ja-JP.json index c9976d2..f1408a8 100644 --- a/packages/frontend/src/locales/ja-JP.json +++ b/packages/frontend/src/locales/ja-JP.json @@ -1260,9 +1260,14 @@ "uiThemeSaveFailed": "UI テーマの保存に失敗しました: {message}", "uploadFailed": "アップロードに失敗しました: {message}", "uploadPageBg": "ページの背景をアップロード", - "uploadTerminalBg": "ターミナルの背景をアップロード" - }, - "tags": { + "uploadTerminalBg": "ターミナルの背景をアップロード", + "terminalBgOverlayOpacity": "ターミナル背景オーバーレイの不透明度:", + "terminalBgOverlayOpacityDesc": "背景画像上の黒いオーバーレイの不透明度を制御します。0は完全に透明、1は完全に不透明です。", + "errorInvalidOpacityValue": "無効な不透明度の値です。0から1の間でなければなりません。", + "terminalBgOverlayOpacitySaved": "ターミナル背景オーバーレイの不透明度が保存されました。", + "terminalBgOverlayOpacitySaveFailed": "ターミナル背景オーバーレイの不透明度の保存に失敗しました: {message}" + }, + "tags": { "addTag": "新しいタグを追加", "deleteTagGlobally": "このタグをグローバルに削除", "error": "タグリストのロードに失敗しました: {error}", diff --git a/packages/frontend/src/locales/zh-CN.json b/packages/frontend/src/locales/zh-CN.json index 0dfbc42..e931145 100644 --- a/packages/frontend/src/locales/zh-CN.json +++ b/packages/frontend/src/locales/zh-CN.json @@ -90,7 +90,12 @@ "defaultMode": "默认模式", "darkMode": "黑暗模式", "darkModeApplied": "黑暗模式已应用", - "darkModeApplyFailed": "应用黑暗模式失败: {message}" + "darkModeApplyFailed": "应用黑暗模式失败: {message}", + "terminalBgOverlayOpacity": "终端背景蒙版透明度:", + "terminalBgOverlayOpacityDesc": "控制背景图片上方黑色蒙版的透明度。0为完全透明,1为完全不透明。", + "errorInvalidOpacityValue": "无效的透明度值,必须在0到1之间", + "terminalBgOverlayOpacitySaved": "终端背景蒙版透明度已保存", + "terminalBgOverlayOpacitySaveFailed": "终端背景蒙版透明度保存失败: {message}" }, "login": { "title": "用户登录", diff --git a/packages/frontend/src/stores/appearance.store.ts b/packages/frontend/src/stores/appearance.store.ts index 5e2ead3..9470d26 100644 --- a/packages/frontend/src/stores/appearance.store.ts +++ b/packages/frontend/src/stores/appearance.store.ts @@ -85,6 +85,12 @@ export const useAppearanceStore = defineStore('appearance', () => { return typeof enabled === 'boolean' ? enabled : true; // 默认启用 }); + // 终端背景蒙版透明度 + const currentTerminalBackgroundOverlayOpacity = computed(() => { + const opacity = appearanceSettings.value.terminalBackgroundOverlayOpacity; + return typeof opacity === 'number' && opacity >= 0 && opacity <= 1 ? opacity : 0.5; // 默认 0.5 + }); + // --- Actions --- /** @@ -234,6 +240,14 @@ export const useAppearanceStore = defineStore('appearance', () => { console.log(`[AppearanceStore LOG] setTerminalBackgroundEnabled 更新后端调用完成。`); // 添加日志 } + /** + * 设置终端背景蒙版透明度 + * @param opacity 透明度 (0-1) + */ + async function setTerminalBackgroundOverlayOpacity(opacity: number) { + await updateAppearanceSettings({ terminalBackgroundOverlayOpacity: opacity }); + } + // --- 终端主题列表管理 Actions --- /** @@ -567,6 +581,7 @@ export const useAppearanceStore = defineStore('appearance', () => { // pageBackgroundOpacity, // Removed terminalBackgroundImage, // terminalBackgroundOpacity, // Removed + currentTerminalBackgroundOverlayOpacity, // <-- 新增导出 // Actions loadInitialAppearanceData, updateAppearanceSettings, @@ -586,6 +601,7 @@ export const useAppearanceStore = defineStore('appearance', () => { uploadTerminalBackground, // setPageBackgroundOpacity, // Removed // setTerminalBackgroundOpacity, // Removed + setTerminalBackgroundOverlayOpacity, // <-- 新增导出 removePageBackground, removeTerminalBackground, loadTerminalThemeData, // <-- 新增导出 diff --git a/packages/frontend/src/types/appearance.types.ts b/packages/frontend/src/types/appearance.types.ts index 2bb184f..0b16e3a 100644 --- a/packages/frontend/src/types/appearance.types.ts +++ b/packages/frontend/src/types/appearance.types.ts @@ -12,6 +12,7 @@ export interface AppearanceSettings { pageBackgroundImage?: string; editorFontSize?: number; terminalBackgroundEnabled?: boolean; // 终端背景是否启用 + terminalBackgroundOverlayOpacity?: number; // 终端背景蒙版透明度 (0-1) } // 前端用于更新外观设置的数据结构 (对应 API 请求体)