From 894f220239ba9dad197aab78354f43ff45d13797 Mon Sep 17 00:00:00 2001 From: KiriAky 107 Date: Mon, 7 Sep 2026 14:40:56 +0800 Subject: [PATCH] fix(export): render themed note metadata in PDF snapshots --- .../PDF实际主题样式修复验收-2026-09-07.md | 7 +++++++ .../src/services/pdfSnapshotService.spec.ts | 20 +++++++++++++++++++ frontend/src/services/pdfSnapshotService.ts | 14 +++++++++---- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/docs/development/PDF实际主题样式修复验收-2026-09-07.md b/docs/development/PDF实际主题样式修复验收-2026-09-07.md index 28a5a45..307cc39 100644 --- a/docs/development/PDF实际主题样式修复验收-2026-09-07.md +++ b/docs/development/PDF实际主题样式修复验收-2026-09-07.md @@ -9,3 +9,10 @@ - 后端全量 882 项、前端全量 451 项通过;最终排版调整后相关前端19项、资源/浏览器后端15项通过;生产构建成功。1 条既有 Starlette 警告和既有大分包提示保留。 - 浏览器烟测验证 CSS 伪元素文本进入 PDF,文档脚本未执行;Vault 越界图片被拒绝,17 条函数表达式可准备。 - 用户已有的三份笔记修改未纳入提交。 + + +## 元数据栏补充验收 + +PDF 快照使用与可视编辑器相同的 `splitNoteMetadata` 解析当前内容,在正文前输出笔记属性、标题和标签,保留 `.note-metadata` 结构及 Vue scoped 样式属性。标签输入框和移除按钮不进入导出。识别出的 YAML 不再作为 Markdown 正文渲染;不支持的元数据仍按编辑器规则保留原文。不额外读取磁盘,因此导出包含当前未保存的元数据。 + +验证:PDF 快照与导出服务 15 项测试通过,前端类型检查及生产构建通过(保留已有大分块提示)。六种主题均实际生成 PDF,并检查包含元数据栏的第一页:paper-moments、dark、light、sepia、ocean-blue、midnight-purple。纸张主题的胶带、缝线及标签配色正常,其他主题的元数据背景、边框和文字配色正常。 diff --git a/frontend/src/services/pdfSnapshotService.spec.ts b/frontend/src/services/pdfSnapshotService.spec.ts index 9c65ed6..a454943 100644 --- a/frontend/src/services/pdfSnapshotService.spec.ts +++ b/frontend/src/services/pdfSnapshotService.spec.ts @@ -38,3 +38,23 @@ it('an aborted snapshot never requests backend resources',async()=>{ await expect(preparePdfSnapshot('text','note',{theme_id:'light',include_title:false,page_size:'A4'},controller.signal)).rejects.toMatchObject({name:'AbortError'}) expect(apiClient.post).not.toHaveBeenCalled() }) + +it('renders snapshot metadata with editor theme scopes and excludes YAML from the body',async()=>{ + const markdown='---\ntitle: ""\ntags: ["", "未保存标签"]\n---\n# Body' + const html=await preparePdfSnapshot(markdown,'filename',{theme_id:'light',include_title:false,page_size:'A4'}) + const doc=new DOMParser().parseFromString(html,'text/html') + const metadata=doc.querySelector('.milkdown-host > .note-metadata')! + expect(metadata.querySelector('h1')?.textContent).toBe('') + expect([...metadata.querySelectorAll('.metadata-tag')].map(el=>el.textContent)).toEqual(['','未保存标签']) + expect([...metadata.querySelectorAll('*')].every(el=>el.hasAttribute('data-v-editor'))).toBe(true) + expect(metadata.querySelector('button,input,form')).toBeNull() + expect(renderMarkdown).toHaveBeenCalledWith('# Body',expect.anything()) + expect(apiClient.post).toHaveBeenCalledWith('/api/exports/preview-resources',expect.objectContaining({source:expect.objectContaining({markdown:'# Body'})})) +}) +it('does not invent a metadata bar for plain notes or unsupported frontmatter',async()=>{ + for(const source of ['plain text','---\ntitle: [invalid]\n---\nbody']) { + const html=await preparePdfSnapshot(source,'filename',{theme_id:'light',include_title:true,page_size:'A4'}) + expect(html).not.toContain('