diff --git a/docs/contracts/Host-v1契约.md b/docs/contracts/Host-v1契约.md index 3d785e5..0fe80f6 100644 --- a/docs/contracts/Host-v1契约.md +++ b/docs/contracts/Host-v1契约.md @@ -1,6 +1,6 @@ # Rust Host v1 预览契约 -状态:Rust 核心测试、clippy、Tauri 工程编译及 Windows GNU 开发可执行文件构建通过。**尚无可发布安装包,未完成原生界面实测**。不将开发构建等同 D01–D08 全部通过。 +状态:Rust 核心测试、clippy、Tauri 工程编译及 Windows GNU 开发可执行文件构建通过。**尚无可发布安装包,新标题栏仍待原生界面实测**。不将开发构建等同 D01–D08 全部通过。 ## 命令 @@ -33,6 +33,6 @@ OS 文件锁配合 Rust Mutex 维持单实例 Vault 写入。Web `serialized_vau ## 前端与发布 -Web 模式沿用现有服务。Tauri Workspace Service 调用原生命令;AI Core 未接通时明确返回 CORE_UNAVAILABLE。关闭请求先尝试保存;冲突或保存失败时保持窗口。原生“导入为笔记属性”菜单已创建但禁用,转换事务尚未完成。 +Web 模式沿用现有服务。Tauri Workspace Service 调用原生命令;AI Core 未接通时明确返回 CORE_UNAVAILABLE。桌面窗口关闭系统装饰,统一由应用标题栏提供拖动、最小化、最大化/还原及关闭;窗口命令只授予本地 `main` WebView。关闭请求先尝试保存,冲突或保存失败时保持窗口。原生“导入为笔记属性”菜单仅在源码模式和已打开笔记时启用,转换作为单次编辑器历史事务执行。 -`bundle.active=false`,无自动更新、无签名安装包。开发命令为前端 `pnpm dev` 与 `cargo run --features desktop`;前端生产构建后可 `cargo build --features desktop --release`,仍只构建预览程序。需要对应平台 C++ 工具链和 WebView;本次 Windows 使用工作树内隔离 GNU/LLVM 工具链,不替代官方 MSVC 或其他平台构建。 +`bundle.active=false`,无自动更新、无签名安装包。开发命令为前端 `pnpm dev` 与 `cargo run --features desktop`;前端生产构建后可 `cargo build --features desktop --release`,仍只构建预览程序。需要对应平台 C++ 工具链和 WebView;本次 Windows 已使用系统 `x86_64-pc-windows-gnu` 工具链构建,仍不替代 MSVC 或其他平台验证。 diff --git a/docs/development/第三阶段实施与验收记录.md b/docs/development/第三阶段实施与验收记录.md index 23f90b0..956564a 100644 --- a/docs/development/第三阶段实施与验收记录.md +++ b/docs/development/第三阶段实施与验收记录.md @@ -17,7 +17,7 @@ ## 已执行验证 - 后端:887 项 pytest 通过;新增 Web/桌面单写入者门禁测试。 -- 前端:87 个文件、471 项 Vitest 通过;TypeScript 检查与 Vite 生产构建通过,保留既有大 chunk 提示。 +- 前端:88 个文件、473 项 Vitest 通过;TypeScript 检查与 Vite 生产构建通过,保留既有大 chunk 提示。桌面标题栏窗口操作使用 Tauri capability,Web 模式不显示伪窗口按钮。 - Sync v1:18 项隔离测试通过,Windows / Python 3.13.9 / SQLite / 磁盘对象 Fixture。包括双线程并发 CAS;不是 PostgreSQL 多 Worker 压测。 - Community v1:13 项隔离测试通过;前端使用 Python 生成的真实 Ed25519 向量互验。 - Rust:系统 `rustc/cargo 1.98.1`(`x86_64-pc-windows-gnu`)下,5 项文件恢复测试、rustfmt、clippy `-D warnings` 和 Tauri desktop 开发构建通过。没有安装包或实机 UI 证据。 diff --git a/frontend/src-tauri/capabilities/main.json b/frontend/src-tauri/capabilities/main.json index ab5c673..280df55 100644 --- a/frontend/src-tauri/capabilities/main.json +++ b/frontend/src-tauri/capabilities/main.json @@ -18,6 +18,10 @@ "allow-workspace-recent", "allow-workspace-revoke", "core:window:allow-destroy", + "core:window:allow-close", + "core:window:allow-minimize", + "core:window:allow-toggle-maximize", + "core:window:allow-start-dragging", "allow-editor-capabilities" ] } diff --git a/frontend/src-tauri/tauri.conf.json b/frontend/src-tauri/tauri.conf.json index 9c82cae..d5d2d23 100644 --- a/frontend/src-tauri/tauri.conf.json +++ b/frontend/src-tauri/tauri.conf.json @@ -10,7 +10,7 @@ "frontendDist": "../dist" }, "app": { - "windows": [{"label": "main", "title": "NotesAgent Preview", "width": 1200, "height": 800, "minWidth": 640, "minHeight": 480}], + "windows": [{"label": "main", "title": "NotesAgent Preview", "width": 1200, "height": 800, "minWidth": 640, "minHeight": 480, "decorations": false}], "security": { "csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src ipc: http://ipc.localhost; frame-src 'self' blob:; object-src 'none'; base-uri 'self'", "capabilities": ["main"] diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 547ed72..06f082e 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -2,17 +2,29 @@ import { computed } from 'vue' import { useRoute } from 'vue-router' import AppShell from '@/components/common/AppShell.vue' +import TitleBar from '@/components/common/TitleBar.vue' +import { isDesktop } from '@/services/platform/desktop' const route = useRoute() const isVaultEntry = computed(() => route.path === '/') +const desktop = isDesktop() diff --git a/frontend/src/components/common/TitleBar.vue b/frontend/src/components/common/TitleBar.vue index 3d7a9f3..da5819a 100644 --- a/frontend/src/components/common/TitleBar.vue +++ b/frontend/src/components/common/TitleBar.vue @@ -7,11 +7,14 @@ import { useThemeStore } from '@/stores/theme' import { Moon, Sunny } from '@element-plus/icons-vue' import AppIcon from './AppIcon.vue' import { t } from '@/i18n' +import { isDesktop } from '@/services/platform/desktop' +import { minimizeWindow, requestWindowClose, toggleMaximizeWindow } from '@/services/platform/windowControls' const route = useRoute() const workspaceStore = useWorkspaceStore() const editorStore = useEditorStore() const themeStore = useThemeStore() +const desktop = isDesktop() const pageTitle = computed(() => { const name = route.name as string @@ -25,6 +28,11 @@ const pageTitle = computed(() => { plugins: t('Plugin 与 MCP', 'Plugins and MCP'), themes: t('主题管理', 'Theme Management'), settings: t('设置', 'Settings'), + 'vault-entry': t('选择知识库', 'Select Knowledge Base'), + community: t('社区目录', 'Community Catalog'), + benchmarks: 'Benchmark', + logs: t('运行日志', 'Operation Logs'), + media: t('音视频转写', 'Media Transcription'), } return titles[name] || 'NotesAgent' }) @@ -38,32 +46,36 @@ const currentFileName = computed(() => { }) const isDirty = computed(() => editorStore.saveStatus === 'dirty' || editorStore.saveStatus === 'conflict') + +function toggleFromTitlebar(event: MouseEvent) { + if (desktop && !(event.target as HTMLElement).closest('button')) void toggleMaximizeWindow() +}