From 4c14c6fbb93a1387f86e4d4d25f6a0ebc9d1e9a4 Mon Sep 17 00:00:00 2001 From: KiriAky 107 Date: Mon, 7 Sep 2026 21:21:56 +0800 Subject: [PATCH] =?UTF-8?q?fix(desktop):=20=E6=89=A9=E5=85=85=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E5=B9=B6=E5=BA=94=E7=94=A8=E5=8A=9F=E8=83=BD=E9=A1=B5?= =?UTF-8?q?=E4=B8=BB=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/contracts/Host-v1契约.md | 2 +- .../Tauri-Rust桌面客户端需求说明-第三阶段.md | 2 +- .../components/common/TitleBarMenu.spec.ts | 4 +- .../src/components/common/TitleBarMenu.vue | 43 +++++++++++++++++-- .../src/features/community/CommunityView.vue | 21 ++++++--- 5 files changed, 58 insertions(+), 14 deletions(-) diff --git a/docs/contracts/Host-v1契约.md b/docs/contracts/Host-v1契约.md index 8f457d1..0b53990 100644 --- a/docs/contracts/Host-v1契约.md +++ b/docs/contracts/Host-v1契约.md @@ -35,6 +35,6 @@ OS 文件锁配合 Rust Mutex 维持单实例 Vault 写入。Web `serialized_vau ## 前端与发布 -Web 模式沿用现有服务。Tauri Workspace Service 调用原生命令;当前预览版通过 Host 连接已在 `127.0.0.1:8000` 启动的 AI Core,连接失败时返回 CORE_UNAVAILABLE。随机端口、临时令牌和自动管理进程仍属于后续 Sidecar 交付。桌面窗口关闭系统装饰,统一由应用标题栏提供拖动、最小化、最大化/还原及关闭;窗口命令只授予本地 `main` WebView。关闭请求先尝试保存,冲突或保存失败时保持窗口。原生菜单事件和标题栏可见的“段落”菜单复用 `editor.import-note-properties`;仅在源码模式、已打开笔记且无冲突时启用,转换作为单次编辑器历史事务执行。 +Web 模式沿用现有服务。Tauri Workspace Service 调用原生命令;当前预览版通过 Host 连接已在 `127.0.0.1:8000` 启动的 AI Core,连接失败时返回 CORE_UNAVAILABLE。随机端口、临时令牌和自动管理进程仍属于后续 Sidecar 交付。桌面窗口关闭系统装饰,统一由应用标题栏提供拖动、最小化、最大化/还原及关闭;窗口命令只授予本地 `main` WebView。关闭请求先尝试保存,冲突或保存失败时保持窗口。标题栏下的完整应用菜单复用 `editorCommandService`,主题菜单直接调用统一主题 Store;功能页使用 `feature-page`、`feature-header`、`panel` 等主题扩展点,确保自定义主题同时作用于编辑器与应用页面。原生菜单事件和可见“段落”菜单复用 `editor.import-note-properties`;仅在源码模式、已打开笔记且无冲突时启用,转换作为单次编辑器历史事务执行。 `bundle.active=false`,无自动更新、无签名安装包。开发命令为前端 `pnpm dev` 与 `cargo run --features desktop`;生产 EXE 必须在 `frontend` 目录执行 `pnpm desktop:build`,由 Tauri CLI 先构建并嵌入前端资源。不要用普通 `cargo build --release` 代替该命令,否则 Rust Host 会更新但 WebView 仍可能携带旧资源。需要对应平台 C++ 工具链和 WebView;本次 Windows 已使用系统 `x86_64-pc-windows-gnu` 工具链构建,仍不替代 MSVC 或其他平台验证。 diff --git a/docs/contracts/Tauri-Rust桌面客户端需求说明-第三阶段.md b/docs/contracts/Tauri-Rust桌面客户端需求说明-第三阶段.md index 5e4b4e7..8f674e7 100644 --- a/docs/contracts/Tauri-Rust桌面客户端需求说明-第三阶段.md +++ b/docs/contracts/Tauri-Rust桌面客户端需求说明-第三阶段.md @@ -23,7 +23,7 @@ 稳定的前端命令标识为 `editor.import-note-properties`。属性转换处理器、Tauri 原生菜单事件和无边框窗口内的可见“段落”菜单均分发同一命令,没有维护第二套转换逻辑。默认快捷键为 Windows/Linux 的 `Ctrl+Alt+P`、macOS 的 `⌘⌥P`;Rust Host 使用 `CmdOrCtrl+Alt+P` 注册 accelerator,仍由活动编辑器能力检查决定是否可用。 -无边框桌面窗口在标题栏下方固定显示“文件 / 编辑 / 段落 / 视图”菜单行。保存使用 `Ctrl+S`;撤销和重做沿用编辑器已有的 `Ctrl+Z` 与 `Ctrl+Shift+Z`,菜单只调用相同编辑器命令,不额外注册按键监听,以免一次按键执行两次。 +无边框桌面窗口在标题栏下方固定显示“文件 / 编辑 / 段落 / 格式 / 视图 / 主题 / 帮助”菜单行。段落菜单提供正文、六级标题、列表、引用、代码块和属性导入;格式菜单复用编辑器已有的加粗、斜体、行内代码、代码块、公式及警告框命令;主题菜单列出当前已安装主题并可进入主题管理。保存使用 `Ctrl+S`;撤销和重做沿用编辑器已有的 `Ctrl+Z` 与 `Ctrl+Shift+Z`,菜单只调用相同编辑器命令,不额外注册按键监听,以免一次按键执行两次。 Markdown 格式(含警告框)与元数据共用 `editorCommandService` 的能力查询和命令分发接口,详见 [警告框与桌面编辑命令开发说明](../development/警告框与桌面编辑命令开发说明.md)。Host 根据 supported / enabled 显隐或禁用菜单,不能把已预留的命令 ID 当作已可执行能力;原生快捷键不绕过活动文档、只读和冲突检查。 diff --git a/frontend/src/components/common/TitleBarMenu.spec.ts b/frontend/src/components/common/TitleBarMenu.spec.ts index 1a98bba..1123703 100644 --- a/frontend/src/components/common/TitleBarMenu.spec.ts +++ b/frontend/src/components/common/TitleBarMenu.spec.ts @@ -26,7 +26,7 @@ describe('桌面顶部段落菜单', () => { editor.currentFilePath = '/示例.md' editor.saveStatus = 'saved' const wrapper = mount(TitleBarMenu) - expect(wrapper.text()).toContain('文件编辑段落视图') + expect(wrapper.text()).toContain('文件编辑段落格式视图主题帮助') await wrapper.get('[data-menu="paragraph"] .menu-trigger').trigger('click') const item = wrapper.get('.import-properties') expect((item.element as HTMLButtonElement).disabled).toBe(false) @@ -51,7 +51,7 @@ describe('桌面顶部段落菜单', () => { it('标题命令传入对应级别并显示快捷键', async () => { const wrapper = mount(TitleBarMenu) await wrapper.get('[data-menu="paragraph"] .menu-trigger').trigger('click') - const headings = wrapper.findAll('[data-menu="paragraph"] [role="menuitem"]').filter(item => item.text().startsWith('标题')) + const headings = wrapper.findAll('[data-menu="paragraph"] [role="menuitem"]').filter(item => item.text().includes('级标题')) await headings[1].trigger('click') expect(execute).toHaveBeenCalledWith('editor.heading', 2) await wrapper.get('[data-menu="paragraph"] .menu-trigger').trigger('click') diff --git a/frontend/src/components/common/TitleBarMenu.vue b/frontend/src/components/common/TitleBarMenu.vue index 55289f5..7ec630f 100644 --- a/frontend/src/components/common/TitleBarMenu.vue +++ b/frontend/src/components/common/TitleBarMenu.vue @@ -4,10 +4,12 @@ import { useEditorStore } from '@/stores/editor' import { useThemeStore } from '@/stores/theme' import { executeEditorCommand, getEditorCommandCapabilities, type EditorCommandId } from '@/services/editorCommandService' import { t } from '@/i18n' +import { useRouter } from 'vue-router' -type MenuName = 'file' | 'edit' | 'paragraph' | 'view' +type MenuName = 'file' | 'edit' | 'paragraph' | 'format' | 'view' | 'theme' | 'help' const editor = useEditorStore() const theme = useThemeStore() +const router = useRouter() const open = ref(null) const bar = ref(null) const error = ref('') @@ -32,6 +34,8 @@ async function command(id: EditorCommandId, params?: unknown) { async function save() { await editor.save(); close() } function setMode(mode: 'source' | 'wysiwyg') { editor.setMode(mode); close() } function toggleTheme() { theme.toggleTheme(); close() } +function applyTheme(id: string) { theme.applyTheme(id); close() } +function navigate(path: string) { void router.push(path); close() } onMounted(() => window.addEventListener('pointerdown', dismiss)) onBeforeUnmount(() => window.removeEventListener('pointerdown', dismiss)) @@ -42,6 +46,8 @@ onBeforeUnmount(() => window.removeEventListener('pointerdown', dismiss))