baodan/docs/PPT与海报编辑体验及解析问题专项优化修复计划书_20260731.md
wsb1224 cb09ed4803 已按计划书完成本轮核心 P0/P1 修复,覆盖用户反馈的三个主要问题。
主要结果:
PPT:
已完成步骤可自由返回,刷新后保留当前步骤。
结果页改为固定三栏视口,缩略图和质量面板独立滚动。
修复画布宽度计算和宽高自适应缩放。
返回配置页时恢复上次模板。
Worker 禁止静默替换模板,不兼容时明确失败。
结果页显示实际应用的模板。

海报解析与合规:
修复 insured/policy 嵌套字段映射。
增加 partial/failed 解析质量判断和缺失字段提示。
传入险种、产品、保司和别名上下文。
修复性别、币种归一化和错误字段计数。
新增服务端字符级合规接口与生成前复检。
不合规文字可高亮、点击定位并选中对应文字。

海报编辑:
AI 图片现在作为背景资产,不再替换整个海报。
单图、长图生成后仍可编辑标题、正文、CTA、数据和卖点。
背景生成失败不会清空当前编辑内容。
下载时合成背景、文字、数据、图表和免责声明。
增加可编辑文档快照、最终 PNG 保存和历史继续编辑。
新增数据库迁移:[migrate_028.py](/D:/work/code/python/coding/baodanagent/api/insurance/db/migrate_028.py)

验证结果:
专项及相关后端测试:26 passed, 1 skipped
Python 全模块编译检查:通过
前端生产构建:通过
git diff --check:通过
全量测试收集受本机缺少 python-pptx 依赖影响,报错为 ModuleNotFoundError: pptx,不是本次修改产生的测试失败。
2026-07-31 15:20:37 +08:00

1090 lines
37 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PPT 与海报编辑体验及解析问题专项优化修复计划书
> 版本v1.0
> 日期2026-07-31
> 分析范围PPT 任务恢复与结果编辑、PPT 模板应用、海报计划书解析、海报文案合规标注、单图/长图海报编辑与导出
> 变更边界:仅修改 `api/insurance/`、`frontend/`、`tests/`、自定义迁移和项目文档,不修改 BaoDan 基座业务代码
> 实施原则:先修阻断性根因,再优化交互;复用现有工作区、任务、版本、存储与 HTML 海报能力,不引入不必要的大型编辑器框架
## 1. 执行摘要
本次反馈不是单一页面样式问题,而是三类问题叠加:
1. **PPT 工作区虽然已经具备步骤导航、缩略图和文字编辑的局部能力,但完成态的布局、任务恢复、版本切换和模板反馈没有形成完整闭环。**
2. **海报计划书“解析成功但字段为空”存在明确的数据结构映射错误。**
3. **海报生成链路把可编辑 HTML 海报替换成了生图模型返回的无字 PNG 背景,因此生成后天然不可编辑。**
建议按以下优先级实施:
| 优先级 | 问题 | 处理目标 |
|---|---|---|
| P0 | 海报解析成功但字段为空 | 修正嵌套字段映射和质量门,不再把空结果标记为成功 |
| P0 | 海报生成后只剩底图、无法编辑 | 改为“背景资产 + 可编辑内容层”的合成架构 |
| P1 | PPT 完成后返回步骤、编辑和浏览不便 | 固定工作区视口、消除整页长滚动、可靠恢复全部已完成步骤 |
| P1 | PPT 选择模板后视觉变化不明显 | 消除静默回退,明确模板真实能力,保证预览和实际渲染一致 |
| P1 | 不合规文案无法定位 | 统一合规引擎,返回字段和字符区间并在编辑器中高亮 |
| P2 | PPT/海报高级编辑体验 | 增加撤销重做、版本对比、长图区块排序等增强能力 |
推荐总工作量约 **1420 人日**。若由一名前端和一名后端并行,包含联调与 UAT建议安排 **23 个自然周**。如果要求首期直接实现接近 PowerPoint/Canva 的自由拖拽、任意图层、字体和图片编辑,工作量需单独评估,不应混入本次可用性修复。
## 2. 审计方法与当前验证结果
### 2.1 已检查内容
- 对照四张截图检查 PPT 和海报页面的实际组件结构。
- 追踪任务中心到 PPT/海报工作区的路由恢复流程。
- 追踪 PPT 模板选择从前端、生成 API、任务快照、Worker 到渲染器的完整链路。
- 追踪海报计划书上传、解析、字段映射、确认、文案生成、合规检查、生图和下载链路。
- 检查现有 PPT 画布、HTML 海报画布、版本历史和自动保存实现。
- 执行现有相关后端测试:
- `18 passed`
- 执行前端生产构建:
- 构建成功。
- 存在既有大包体告警,但不是本次功能故障的直接根因。
- 执行目标页面静态 UI 检测:
- `PptPage.vue``PosterPage.vue` 未发现规则型静态问题。
- 本次主要问题属于状态流、数据契约和交互架构问题,静态检测无法发现。
### 2.2 结论可信度
| 结论 | 可信度 | 依据 |
|---|---:|---|
| 海报空字段由嵌套数据映射错误导致 | 已确认 | 提取器输出 `insured/policy`,映射函数却主要读取顶层字段 |
| 海报完成后只剩底图是现有设计结果 | 已确认 | 生图 Prompt 明确要求无文字;完成态只渲染返回 PNG |
| 合规问题不能定位是因为只返回布尔/汇总结果 | 已确认 | 当前仅用关键词 `some()` 判断,没有字符位置和字段信息 |
| PPT 结果页长滚动由高度和滚动容器设计造成 | 已确认 | 结果工作台未占满父容器,内部三栏没有稳定高度,外层内容区承担滚动 |
| PPT 模板只产生有限视觉差异 | 已确认 | 固定 Builder 重新绘制页面,模板主要影响配色、母版和少量配置 |
| 某一线上任务是否发生模板静默回退 | 需运行数据复核 | Worker 存在静默回退路径,但需查看该任务快照和日志确认是否命中 |
## 3. 问题一PPT 完成态、步骤返回、编辑和模板应用
### 3.1 当前代码事实
#### 3.1.1 已经具备但没有形成闭环的能力
- `PptPage.vue` 有五步流程和左侧步骤导航。
- 结果页顶部已有“重新生成”“修改核验数据”等入口。
- `PptSlideCanvas.vue` 支持点击文本框后修改文字。
- `PptResult.vue` 有幻灯片缩略图、上一页/下一页、隐藏页面和版本列表。
- 工作区根据 `sessionId``taskId` 恢复任务状态。
因此不建议推倒重做。首期应修复状态恢复、布局和反馈,再逐步增强编辑能力。
#### 3.1.2 结果页“所有页面一直溜”的直接原因
`PptResult.vue` 的结果工作台只有 `display:flex`,没有稳定的 `height:100%`/`min-height:0` 约束;内部 `.workspace-body` 虽然声明 `overflow:hidden`,但父容器没有可约束的高度。与此同时,`PptPage.vue` 的 `.ppt-ws__content` 使用 `overflow-y:auto`
实际结果是:
- 左侧缩略图栏无法形成独立、稳定的滚动区域;
- 整个结果工作台随页面内容向下增长;
- 用户需要在多个嵌套滚动区域间移动;
- 底部“返回上一步”和页码可能离当前操作位置很远;
- 大屏截图中会出现缩略图已经滚到后半段,但主画布和外层页面位置不一致的感知。
#### 3.1.3 返回步骤在任务恢复场景下不够可靠
当前恢复逻辑以任务状态决定 `currentStep`,随后用:
```text
maxAccessibleStep = currentStep
```
对“已完成的生成任务”通常会得到 4因此理论上可访问前面步骤。但还存在以下问题
- 可访问步骤只保存在前端内存,没有明确服务端工作流完成度字段。
- URL 不保存当前查看步骤;刷新后又会被任务终态强制带回结果页。
- 任务中心始终带 `taskId` 打开,任务状态会持续压过用户的步骤选择。
- 步骤导航在右侧上下文面板打开时会收窄为图标,截图中不容易理解每个图标代表什么。
- 版本列表只是展示,不能点击查看或恢复旧版本。
这会让用户感觉“能偶尔返回,但无法稳定回到原步骤继续修改”。
#### 3.1.4 当前 PPT 编辑能力过弱
当前结果画布仅支持:
- 点击文本框;
- 用浮层 `textarea` 修改文本;
- 隐藏/显示页面;
- 基于编辑内容生成新版本。
当前不支持或反馈不足:
- 当前可编辑对象没有明显边框和悬停提示;
- 图片只显示占位图,无法替换;
- 表格不可直接编辑;
- 没有撤销/重做;
- 没有字体、字号、颜色、对齐等属性面板;
- 没有页面网格总览;
- 版本列表不能切换;
- 画布缩放只按宽度计算,窗口变化后没有稳定的 `ResizeObserver`
- `baseWidth` 的表达式存在运算优先级问题,实际会固定为 960传入宽度不能可靠生效。
#### 3.1.5 模板“选择后像没应用”的根因
模板链路表面上是连通的:
```text
前端 templateId
→ POST /ppt/generate/{sessionId}
→ 任务快照 templateId/theme
→ Worker 加载 PptTemplate
→ renderer.render_enhanced()
```
但渲染行为有三项关键限制:
1. **Worker 会静默改用别的模板。**
Worker 查询所选模板时额外要求 `plan_type` 匹配;不匹配时会自动选择场景模板或同风格模板,前端没有收到“实际使用了哪个模板”。
2. **模板不是完整视觉版式。**
渲染器打开源 PPTX 后删除所有原幻灯片,再用固定的 Python Builder 重新绘制页面。源模板主要提供母版/布局资源,绝大部分页面位置和组件结构仍由固定代码决定。
3. **场景页配置优先于模板页配置。**
`scenarioSlides` 优先级高于 `templateConfig.slidesConfig`,所以选择不同模板时,页面结构通常不变,最明显变化可能只有配色。
用户把“模板”理解成完整设计版式,但当前实现更接近“主题配色 + 母版资源 + 页面类型配置”,这就是预期与实现不一致的核心原因。
### 3.2 PPT 修复方案
#### 3.2.1 P1-A工作区与步骤恢复
目标:从任务中心打开完成任务后,用户可以稳定访问任意已完成步骤,刷新后保持当前位置。
改造:
1. URL 增加可选参数:
```text
/ppt/{sessionId}?taskId={taskId}&step=result
```
2. 恢复优先级改为:
```text
显式且合法的 step
> 用户当前工作区草稿 step
> 任务状态映射 step
> session.workflow_step
```
3. 服务端工作区返回:
```json
{
"workflowStep": "result",
"maxCompletedStep": 4,
"lastViewedStep": 2
}
```
4. 用户点击步骤时:
- 更新 `currentStep`
- 更新 URL 的 `step`
- 轻量保存 `lastViewedStep`
- 不删除 `taskId`,但不再让终态任务每次覆盖用户选择。
5. 从结果返回“核对数据”或“配置生成”时:
- 保留原 session
- 保留已选择模板和公司;
- 修改后标记草稿版本高于已生成版本;
- 主按钮显示“应用修改并生成新版本”,不覆盖旧版本。
验收:
- 完成任务从任务中心打开后,五个步骤中已完成的步骤均可点击。
- 切到第 3 步刷新页面,仍停留在第 3 步。
- 修改数据后返回结果页时明确提示需要重新生成。
#### 3.2.2 P1-B结果页固定视口
目标:主页面不再随 12 页、30 页 PPT 无限向下增长。
桌面端结构:
```text
结果工具栏(固定)
├── 左:缩略图栏(独立滚动)
├── 中:单页画布(独立缩放/平移)
└── 右:属性/质量面板(独立滚动,可折叠)
底部步骤栏(固定)
```
具体修改:
- `PptPage` 在结果步骤给内容区增加专用类,使用 `overflow:hidden`
- `PptResult`、`workspace-layout`、`workspace-body` 全链路补齐:
- `height:100%`
- `min-height:0`
- `min-width:0`
- 缩略图栏使用自身 `overflow-y:auto`
- 质量面板使用自身 `overflow-y:auto`
- 主画布居中并按宽高共同计算缩放比例。
- 使用 `ResizeObserver` 在窗口、侧栏宽度变化时重新计算画布。
- 页数超过 30 时对缩略图使用虚拟列表。
- 增加“缩略图 / 网格总览”切换;网格总览适合跨页查找,缩略图适合逐页编辑。
验收:
- 12、30、100 页 PPT 均只有缩略图栏滚动,不推动整页高度。
- 页码、返回上一步和下载入口始终可见。
- 在 1366×768、1920×1080、2560×1440 下无横向页面溢出。
#### 3.2.3 P1-C最小可用编辑增强
本阶段不实现完整 PowerPoint 编辑器,只完成最常用修改:
- 单击选中对象,双击编辑文字;
- 可编辑对象显示边框和“可编辑”悬停提示;
- 右侧属性面板提供:
- 字体;
- 字号;
- 加粗;
- 文字颜色;
- 对齐;
- 表格支持双击单元格编辑文字;
- 图片对象提供“替换图片”;
- `Ctrl/Cmd+Z``Ctrl/Cmd+Shift+Z` 撤销/重做;
- 自动保存显示“保存中/已保存/保存失败”;
- 失败时保留本地编辑,不直接丢失;
- 修正画布宽度表达式和响应式缩放。
后续可选 P2
- 拖动/缩放对象;
- 新增/删除文本框和图片;
- 页面复制、排序;
- 多选和对齐;
- 母版级编辑。
#### 3.2.4 P1-D模板真实生效
短期先做到“选择什么,就明确使用什么”:
1. API 和 Worker 不再静默替换用户所选模板。
2. 不兼容时在生成前返回明确错误和可选模板列表。
3. 任务输出增加:
```json
{
"requestedTemplateId": "savings-minimal",
"appliedTemplateId": "savings-minimal",
"appliedStylePreset": "minimal",
"templateFallback": false
}
```
4. 结果页显示“已应用:简洁风”,若发生兼容性降级必须显式提示。
5. 模板卡片预览改为真实渲染缩略图,不再只用 CSS 渐变模拟。
6. 模板选择后按钮文案改为“应用此模板并生成新版本”,避免用户以为只点卡片就会实时替换成品。
中期实现模板差异:
- 把固定 Builder 中的布局参数提取为模板设计令牌:
- 字体族;
- 标题字号;
- 页边距;
- 卡片圆角;
- 表格样式;
- 背景;
- 装饰元素;
- 图表配色;
- 页脚。
- `slidesConfig``scenarioSlides` 合并时采用明确规则,而不是场景配置完全覆盖模板配置。
- 为每个模板建立金标截图,至少保证封面、数据页、图表页、表格页、结尾页有显著且一致的风格差异。
不建议首期承诺“任意上传 PPTX 都能自动变成可复用模板”。任意 PPTX 的占位符、母版和图层语义不一致,需要模板规范或专用适配器。
#### 3.2.5 P2版本历史可用化
当前版本列表只展示,不可操作。建议增加:
- 点击版本加载该版本预览;
- 当前版本和历史版本明确标识;
- “恢复为新版本”,不直接覆盖历史;
- 显示版本来源:
- 原始生成;
- 修改数据后生成;
- 更换模板;
- 页面编辑;
- 可选双栏对比当前页。
## 4. 问题二:海报计划书解析为空
### 4.1 已确认根因
完整计划书提取输出结构类似:
```json
{
"insured": {
"age": 35,
"gender": "female"
},
"policy": {
"currency": "USD",
"sum_insured": 500000,
"annual_premium": 100000,
"premium_payment_period": 5,
"coverage_period": "终身"
},
"benefit_illustration": []
}
```
但海报映射函数当前读取:
```text
data.age
data.gender
data.currency
data.sum_insured
data.annual_premium
```
因此绝大多数关键字段都会变成 `None/null`
更严重的是,映射结果仍包含:
```text
plan_type
extraction_status
key_benefits: []
benefit_table: []
```
这个字典并非空字典,所以任务被标记为 `parsed`,前端显示“已解析”,但七个表单字段全部空白。
### 4.2 其他放大问题
1. `extract_plan()` 调用没有传入已选产品的险种、名称和别名提示,默认按储蓄险解析。
2. 轻量降级解析只截取 PDF 前 6000 字符,关键字段如果位于后续页面会继续丢失。
3. `gender` 后端可能返回 `male/female`,前端选项值却是 `男/女`,即使解析成功也可能无法显示。
4. 前端“已确认字段数”在没有任何解析字段时会回退显示 7属于错误的成功反馈。
5. 页面只提供七个固定字段,没有显示:
- 解析方法;
- 字段来源页;
- 置信度;
- 缺失字段;
- OCR 质量;
- 利益表和关键卖点。
6. 解析任务失败记录没有保存可供用户查看的细分错误原因。
### 4.3 修复方案
#### 4.3.1 建立唯一的海报计划事实模型
新增专用转换函数,不在多个组件中继续堆叠别名:
```text
map_plan_to_poster_facts(raw, plan_type)
```
标准输出:
```json
{
"insured": {
"age": 35,
"gender": "female"
},
"policy": {
"currency": "USD",
"sumAssured": 500000,
"annualPremium": 100000,
"premiumTerm": 5,
"coveragePeriod": "终身"
},
"keyBenefits": [],
"benefitRows": [],
"meta": {
"planType": "savings",
"status": "partial",
"method": "regex+llm",
"missingFields": [],
"lowQualityPages": []
}
}
```
前端若暂时继续使用扁平字段,可由 API 序列化层一次性提供兼容字段,但内部模型只保留一套。
字段映射至少覆盖:
| 前端字段 | 正确来源 |
|---|---|
| `age` | `insured.age` |
| `gender` | `insured.gender` |
| `currency` | `policy.currency` |
| `sum_assured` | `policy.sum_insured` / `policy.basic_sum_insured` |
| `premium_term` | `policy.premium_payment_period` |
| `annual_premium` | `policy.annual_premium` |
| `coverage_period` | `policy.coverage_period` |
| `benefit_table` | `benefit_illustration` |
#### 4.3.2 增加解析质量门
不再只有 `parsed/failed`
```text
queued
parsing
parsed 核心字段完整
partial 有数据但核心字段缺失
failed 无法获得可用数据
```
按险种定义核心字段:
- 储蓄险:年龄、币种、年缴保费、缴费期。
- 重疾险:年龄、币种、保额。
- IUL年龄、币种、保额、目标/计划保费之一。
规则:
- 核心字段全部为空时,不得返回 `parsed`
- `partial` 时页面显示缺失字段清单并允许人工补录。
- `parsedData` 必须至少有一个有效业务字段。
- `confirmedFieldCount` 只统计非空值,不得使用固定默认数。
#### 4.3.3 使用产品上下文辅助解析
上传计划书时已有产品来源快照,解析任务应传入:
- `plan_type`
- `product_id`
- `product_name_hint`
- `product_aliases`
- `company_id`
这样可以:
- 选择正确险种 Prompt
- 降低产品名识别错误;
- 对多语言计划书使用已知产品名纠错;
- 在计划书与所选产品不匹配时给出明确提示。
#### 4.3.4 改进 PDF 页面选择与 OCR
- 轻量解析不再固定取前 6000 字符。
- 使用已有关键页选择逻辑,优先:
- 投保人/被保人资料页;
- 保单摘要页;
- 保费页;
- 保障摘要页;
- 利益演示表页。
- 对低质量页执行逐页 OCR。
- 保存 `lowQualityPages` 和解析方法。
- 扫描 PDF 无法 OCR 时返回“第 XY 页无法识别”,而不是空表单。
#### 4.3.5 前端数据核对改造
核对区分为:
1. 核心信息;
2. 保费与保障;
3. 利益演示摘要;
4. 解析诊断。
每个字段显示:
- 当前值;
- 来源页;
- 置信度或“人工填写”;
- 是否缺失;
- 修改状态。
当所有字段为空时显示明确空状态:
```text
没有识别到可用字段
可能原因扫描件质量低、PDF 加密、计划书版式暂不支持
[重新解析] [人工填写] [更换文件]
```
## 5. AI 文案不合规内容高亮
### 5.1 当前问题
当前合规检查在两个前端文件中分别维护同一组关键词:
```text
保证、稳赚、无风险、零风险、最高收益、保底、回报率
```
存在以下问题:
- 只知道“有风险”,不知道在哪个字段、哪个位置。
- “发布”面板把风险标成 `warn`,生成函数却直接阻断,语义不一致。
- 标题和正文修改后,已勾选的 `complianceConfirmed` 不会自动失效。
- 仅依赖客户端关键词,直接调用生成 API 可以绕过。
- 没有规则编号、替换建议和上下文。
- `el-input/textarea` 本身不能对局部文字加背景高亮。
### 5.2 统一合规接口
新增:
```text
POST /insurance/poster/compliance-check
```
请求:
```json
{
"headline": "保证收益",
"body": "……",
"callToAction": "……",
"productSource": {},
"caseUploadId": 123
}
```
响应:
```json
{
"code": 0,
"message": "success",
"data": {
"status": "block",
"revision": "sha256-of-copy",
"issues": [
{
"ruleId": "RETURN_GUARANTEE",
"severity": "block",
"field": "headline",
"start": 0,
"end": 2,
"text": "保证",
"message": "不得使用确定性收益承诺",
"suggestion": "改为“利益以正式计划书为准”"
}
]
}
}
```
要求:
- 第一阶段使用可审计规则库。
- 后续可增加 AI 语义复核,但 AI 结果不能替代确定性规则。
- 生成 API 服务端重新校验,不能信任前端确认。
- 校验结果绑定文案哈希;文案变化后旧确认自动失效。
### 5.3 前端高亮方案
保留输入框用于编辑,增加“标注预览”:
- 标题、正文和行动号召按字符区间切分;
- 风险片段使用红色/橙色背景;
- 鼠标悬停显示规则说明和修改建议;
- 点击问题项:
- 自动切换到文案标签;
- 聚焦对应输入框;
- 选中对应字符范围;
- 每个问题提供“采用建议”按钮;
- 修正后实时重新校验并移除高亮。
这比直接把 textarea 改成富文本编辑器更简单、风险更小,也能满足“明确看到哪里不合规”的核心需求。
### 5.4 合规状态规则
```text
block禁止生成
warn允许生成但必须人工确认
pass允许生成
```
当以下内容变化时自动清除人工确认:
- 标题;
- 正文;
- 行动号召;
- 产品;
- 客户计划书;
- 模板文案;
- AI 候选版本。
## 6. 问题三:海报生成后只剩底图、无法编辑
### 6.1 已确认根因
当前海报在生成前使用 `PosterHtmlCanvas`
- 标题可编辑;
- 正文可编辑;
- 行动号召可编辑;
- 摘要卡片、图表、卖点和免责声明由 HTML 组件组成。
生图 Prompt 则明确要求:
```text
只生成背景视觉图不包含任何文字、数字、Logo 或图表
```
生成完成后,`PosterStage.vue` 不再显示 `PosterHtmlCanvas`,而是显示:
```html
<img :src="draft.posterUrl">
```
因此:
- 用户看到的必然只是无字底图;
- 原来的 HTML 文字层被完全隐藏;
- PNG 是扁平图片,没有可编辑图层;
- 单图和长图都无法继续修改;
- 长图模式也只是改变生成参数和生成前 HTML 高度,并没有生成可编辑长图文档。
### 6.2 推荐架构:背景资产与内容文档分离
不再把生图结果叫“最终海报”,而是叫“背景图”。
```text
AI 背景图 backgroundAsset
+
模板布局 template
+
结构化文案 copy
+
计划书事实 facts
+
样式和区块配置 document
可编辑 HTML 海报
导出 PNG/JPG
```
新增/扩展海报文档快照:
```json
{
"revision": 3,
"backgroundUrl": "/...",
"templateId": 10,
"outputMode": "long",
"copy": {},
"facts": {},
"style": {
"primary": "#17324d",
"accent": "#c9a027"
},
"sections": [
{"id": "hero", "visible": true},
{"id": "summary", "visible": true},
{"id": "benefits", "visible": true},
{"id": "features", "visible": true},
{"id": "cta", "visible": true},
{"id": "disclaimer", "visible": true}
]
}
```
### 6.3 P0 可用性修复
1. 生成完成后不再切换到单独的 `<img>`
2. 始终显示 `PosterHtmlCanvas`
3. 将生成结果保存为 `backgroundUrl`,传给 `PosterHtmlCanvas.heroBackground`
4. 文案、数据卡片、图表、CTA 和免责声明继续作为可编辑 HTML 图层显示。
5. “重新生成”改为:
- 仅重新生成背景;
- 保留现有文案和数据;
- 新背景先作为候选,用户确认后替换。
6. 生成背景失败时继续保留当前可编辑海报,不清空内容。
### 6.4 单图编辑范围
首期支持:
- 编辑标题、正文、行动号召;
- 修改确认后的客户字段;
- 替换/重新生成背景;
- 选择模板和配色;
- 显示/隐藏摘要、卖点、CTA、免责声明
- 编辑卖点标题和摘要;
- 调整常用字号档位;
- 恢复到上一版本。
首期不支持自由拖动任意元素。对于业务海报,结构化编辑比自由画布更稳定,也更容易保证合规和导出一致。
### 6.5 长图编辑范围
长图使用同一文档模型,但允许:
- 区块排序;
- 区块显示/隐藏;
- 每个区块独立编辑;
- 图表数据来源锁定为已确认字段;
- 自动高度;
- 分段背景或统一背景;
- 导出前显示实际像素高度和预计文件大小。
长图背景不能只依赖一张固定比例 AI 图强行拉伸。建议:
- Hero 区使用 AI 背景;
- 内容区使用模板颜色、渐变或可重复纹理;
- 底部 CTA 使用独立纯色/渐变区;
- 避免把人物、建筑等场景图纵向拉伸到整张长图。
### 6.6 导出和历史
现有项目已经依赖 `html-to-image`,首期可复用:
1. 浏览器把最终 HTML 海报导出为 PNG。
2. 导出成功后把最终 PNG 上传并绑定到海报记录。
3. 同时保存 `documentJson``revision`
4. 历史打开时恢复文档,而不是只恢复 PNG。
5. 下载使用服务器保存的最终合成 PNG保证历史结果稳定。
注意:
- 背景图片必须转为同源或 Blob URL避免 Canvas 跨域污染。
- 导出前等待字体、图片和图表渲染完成。
- 长图应限制最大高度/像素总量,超限时分片渲染后拼接或提示调整。
中期如果要求服务器端批量导出,可使用 Playwright/Chromium 根据同一文档模型渲染,不能另写一套与前端不同的布局逻辑。
## 7. 数据与接口改造
### 7.1 海报记录建议新增字段
优先复用现有 `PosterRecord`,通过自定义迁移增加:
```text
document_json TEXT
document_revision INT NOT NULL DEFAULT 1
background_file_url VARCHAR(500)
final_file_url VARCHAR(500)
compliance_json TEXT
compliance_revision VARCHAR(64)
```
如果现有 `output_file_url` 已承载最终文件,可继续复用,不重复增加 `final_file_url`
### 7.2 海报任务输出
背景生成任务输出:
```json
{
"backgroundUrl": "/insurance/poster/background/123",
"generationMode": "ai",
"provider": {},
"documentRevision": 4
}
```
不要继续把背景 URL 当成完整海报 URL。
### 7.3 海报接口
建议新增或调整:
```text
POST /poster/compliance-check
PUT /poster/records/{id}/document
POST /poster/records/{id}/background/regenerate
POST /poster/records/{id}/rendered
GET /poster/records/{id}/document
GET /poster/records/{id}/background
```
### 7.4 PPT 任务输出
生成任务输出补充:
```json
{
"requestedTemplateId": "",
"appliedTemplateId": "",
"appliedStylePreset": "",
"templateFallback": false,
"revision": 4
}
```
## 8. 文件级改造清单
### 8.1 前端
| 文件 | 主要改动 |
|---|---|
| `frontend/src/pages/PptPage.vue` | 步骤 URL、结果专用布局、已完成步骤恢复 |
| `frontend/src/composables/useWorkspace.ts` | `step/maxCompletedStep/lastViewedStep` 恢复优先级 |
| `frontend/src/pages/components/ppt/PptResult.vue` | 固定三栏视口、网格总览、可切换版本、编辑状态 |
| `frontend/src/pages/components/ppt/PptSlideCanvas.vue` | 修正尺寸、ResizeObserver、选中态、属性编辑、表格/图片入口 |
| `frontend/src/pages/components/ppt/PptGenerate.vue` | 真实预览、实际应用模板反馈、生成新版本文案 |
| `frontend/src/pages/TasksPage.vue` | 打开工作区时携带推荐步骤,但允许用户后续覆盖 |
| `frontend/src/components/poster/workspace/PosterSourcePanel.vue` | partial/failed 空状态、来源与缺失字段、正确字段计数 |
| `frontend/src/components/poster/workspace/PosterCopyPanel.vue` | 合规标注预览、定位与替换建议 |
| `frontend/src/components/poster/workspace/PosterDeliveryPanel.vue` | 使用统一合规结果,移除重复关键词逻辑 |
| `frontend/src/components/poster/workspace/PosterStage.vue` | 完成后保留 HTML 画布,把生成图作为背景 |
| `frontend/src/components/poster/long/PosterHtmlCanvas.vue` | 接收背景、文档模型、区块显隐与顺序 |
| `frontend/src/pages/PosterPage.vue` | 文案变化清除合规确认、背景生成与最终导出分离 |
| `frontend/src/composables/usePosterWorkspace.ts` | 保存 document/background/compliance revision |
| `frontend/src/utils/ppt-api.ts` | 模板应用、版本读取和步骤状态类型 |
| `frontend/src/utils/poster-api.ts` | 合规、文档保存、背景和最终文件接口 |
### 8.2 后端
| 文件 | 主要改动 |
|---|---|
| `api/insurance/poster/tasks.py` | 正确映射嵌套数据、传入产品上下文、解析质量门 |
| `api/insurance/ppt/extraction.py` | 海报关键页选择、轻量解析上下文、结构化诊断 |
| `api/insurance/poster/service.py` | 文档保存、背景与最终文件分离、服务端合规门禁 |
| `api/insurance/poster/routes.py` | 新增文档、背景、合规和最终导出接口 |
| `api/insurance/poster/image_generator.py` | 明确只生成背景,返回背景资产元数据 |
| `api/insurance/poster/content_builder.py` | 统一生成可编辑文档 ViewModel |
| `api/insurance/models/poster_record.py` | 文档、背景、合规版本字段 |
| `api/insurance/models/poster_case_upload.py` | 解析诊断、partial 状态和错误详情 |
| `api/insurance/ppt/routes.py` | 模板兼容性前置校验、任务输出请求模板信息 |
| `api/insurance/generation/celery_tasks.py` | 禁止模板静默回退、记录实际模板、背景任务输出 |
| `api/insurance/ppt/renderer.py` | 模板令牌进入 DeckContract |
| `api/insurance/ppt/scripts/fast_pptx_renderer.py` | 应用模板布局令牌、明确场景与模板合并规则 |
| `api/insurance/db/migrate_*.py` | 海报文档/背景/合规字段迁移 |
## 9. 分阶段实施计划
### 阶段 0复现基线与契约冻结0.51 人日)
- 保存本次四个问题的复现步骤和截图。
- 导出一个发生问题的 PPT 任务快照。
- 保存一份解析为空的脱敏 PDF 样本及原始提取 JSON。
- 保存一份海报生成记录及生图任务输出。
- 冻结 PPT 模板、海报事实模型、合规结果和海报文档的 JSON 契约。
验收:每个问题均有可重复用例,不再只靠人工描述。
### 阶段 1P0 海报解析修复1.52.5 人日)
- 修正嵌套字段映射。
- 传入险种和产品提示。
- 增加 `partial` 和缺失字段。
- 修正性别/币种归一化。
- 修正空字段计数。
- 增加单元和 API 回归测试。
验收:目标 PDF 至少识别核心字段;全空时不得显示“已解析成功”。
### 阶段 2P0 海报可编辑合成34 人日)
- 生成图改为背景资产。
- 完成态继续显示 HTML 画布。
- 单图/长图保留文字和数据层。
- 最终 PNG 由 HTML 合成并保存。
- 历史恢复文档。
验收生成背景后可继续改标题、正文、CTA 和字段;下载图与屏幕预览一致。
### 阶段 3P1 合规高亮1.52.5 人日)
- 后端统一规则和接口。
- 返回字符区间。
- 前端标注预览、定位和建议替换。
- 文案变化自动清除人工确认。
- 生成接口服务端复检。
验收:每个阻断项都能定位到具体文字;修正后高亮和阻断即时消失。
### 阶段 4P1 PPT 工作区和编辑2.53.5 人日)
- 步骤位置写入 URL/草稿。
- 固定结果三栏视口。
- 缩略图/网格总览。
- 修正画布尺寸和响应式缩放。
- 增加选中态、文字属性、表格文字、图片替换、撤销重做。
验收从任务中心打开后可回到任意完成步骤30 页 PPT 不再整页长滚动。
### 阶段 5P1 PPT 模板真实生效2.54 人日)
- 禁止静默回退。
- 返回请求模板和实际模板。
- 真实缩略图。
- 模板令牌进入渲染器。
- 建立模板金标截图。
验收:选择不同模板后,封面、数据页、图表页和结尾页存在可观察且符合预览的差异。
### 阶段 6回归、UAT 与灰度23 人日)
- 全量后端测试和前端构建。
- 真实 PDF 样本测试。
- PPT/海报视觉金标。
- Windows/Chrome/Edge 和常见分辨率验证。
- 灰度观察解析失败率、合规阻断率、背景生成失败率和导出耗时。
## 10. 测试计划
### 10.1 海报解析单元测试
- 完整提取结果含 `insured/policy` 时正确映射。
- 储蓄险、重疾险、IUL 各一套字段映射。
- 顶层旧结构继续兼容一个版本。
- 全部核心字段为空时状态为 `failed/partial`,不能为 `parsed`
- `male/female/男/女` 归一化。
- `RMB/CNY/HKD/USD` 归一化。
- 利益表行保留。
- OCR 低质量页进入诊断。
### 10.2 合规测试
- 单个和多个风险词返回正确字符区间。
- 同一词重复出现时返回全部位置。
- 标题、正文、CTA 分字段定位。
- Unicode 中文字符索引前后端一致。
- 文案修改后旧确认哈希失效。
- 客户端绕过检查直接生成时服务端仍阻断。
- warning 可人工确认block 不可绕过。
### 10.3 海报编辑与导出测试
- 背景生成后文案仍存在且可编辑。
- 更换背景不覆盖文案和字段。
- 单图导出尺寸正确。
- 长图高度随内容增长。
- 隐藏区块后导出同步变化。
- 中文字体、长产品名、大金额不溢出。
- 背景失败后保留当前文档。
- 历史记录重新打开后可继续编辑。
- 最终下载图和文档 revision 一致。
### 10.4 PPT 工作区测试
- 完成任务打开时 `maxCompletedStep=4`
- 显式 `step=review` 不被终态任务覆盖。
- 刷新保持步骤。
- 修改数据后生成新版本。
- 12、30、100 页缩略图滚动不推动整页。
- 1366×768 下工具栏、页码和返回按钮可见。
- 画布随侧栏开关重新缩放。
- 文本修改保存失败时不丢失。
- 撤销/重做。
- 版本切换和恢复为新版本。
### 10.5 PPT 模板测试
- 所选模板不兼容时 API 在创建任务前返回明确错误。
- Worker 不得静默换模板。
- `requestedTemplateId == appliedTemplateId`
- 每种模板生成封面、数据、图表、表格和结尾页金标。
- 模板预览缩略图与生成结果一致。
- 更换模板生成新版本,旧版本仍可查看。
## 11. 验收标准
### 11.1 PPT
- [ ] 从任务中心打开已完成 PPT 后,可以返回所有已完成步骤。
- [ ] 刷新不会强制跳回结果页。
- [ ] 结果页只显示当前页大画布,其他页在独立缩略图栏或网格中浏览。
- [ ] 30 页 PPT 不产生整页无限滚动。
- [ ] 用户能清楚识别哪些元素可编辑。
- [ ] 文字、表格文字和图片替换可以保存并生成新版本。
- [ ] 模板选择与实际应用模板一致,不存在静默回退。
- [ ] 不同模板的真实预览和最终输出一致。
### 11.2 海报解析与合规
- [ ] 目标计划书不再出现“状态成功、字段全空”。
- [ ] 解析不完整时明确显示缺失字段和原因。
- [ ] 人工补录后可确认并用于文案与海报。
- [ ] 不合规文字按字符区间高亮。
- [ ] 点击问题可以定位到对应输入框和文字。
- [ ] 文案修改后必须重新合规确认。
- [ ] 服务端不能被绕过。
### 11.3 海报编辑
- [ ] 生图结果作为背景,不再替换整个可编辑海报。
- [ ] 单图和长图生成后均可继续编辑。
- [ ] 标题、正文、CTA、摘要字段和卖点可修改。
- [ ] 重新生成背景不会覆盖文字。
- [ ] 最终下载图包含背景、文字、数据、图表和免责声明。
- [ ] 历史记录既能下载最终图,也能恢复可编辑文档。
## 12. 监控与上线观察
新增或补充指标:
```text
poster_case_parse_total{status,plan_type,method}
poster_case_parse_missing_fields_total{field}
poster_compliance_issues_total{rule_id,severity}
poster_background_generation_total{status,provider}
poster_document_export_duration_seconds
ppt_template_requested_total{template_id}
ppt_template_applied_total{template_id}
ppt_template_fallback_total{reason}
ppt_workspace_restore_total{source_step}
```
日志必须包含:
```text
task_id
workspace_id
record_id
template_id
applied_template_id
plan_type
parse_method
missing_fields
document_revision
compliance_revision
error_code
```
不得记录完整客户计划书文本、完整客户身份信息或未脱敏营销文案。
建议告警:
- 海报解析 `parsed` 但有效字段数为 0
- 同一模板请求和实际模板不一致;
- 海报完成任务没有 `backgroundUrl`
- 最终导出 revision 落后于文档 revision
- PPT/海报任务运行超过 10 分钟。
## 13. 风险和边界
1. **真实计划书差异**
字段修正有明确根因但仍需储蓄险、重疾险、IUL 的脱敏真实样本验证关键词、OCR 和字段口径。
2. **模板定义需要业务统一**
如果后台继续把“配色主题”称为“模板”,用户仍会期待完整布局变化。产品文案和后台字段必须区分“主题”和“版式模板”。
3. **自由编辑范围**
本计划首期提供结构化业务编辑器,不是通用平面设计工具。若要求任意拖拽、旋转、自由图层、字体上传和素材库,应另立项目。
4. **浏览器导出稳定性**
`html-to-image` 适合首期复用,但需要处理字体加载、跨域背景和超长画布。批量和高一致性导出后续应转服务器渲染。
5. **旧记录兼容**
旧海报只有扁平 PNG、没有文档快照时只能查看和下载不能恢复完整图层。页面需明确标记“旧版本仅支持查看”。
## 14. Definition of Done
- [ ] 每个已确认根因都有自动化回归测试。
- [ ] 相关后端测试、前端类型检查和生产构建全部通过。
- [ ] 至少 9 份脱敏真实 PDF 完成解析 UAT。
- [ ] 至少 3 个 PPT 模板完成五类页面视觉金标。
- [ ] 单图和长图各完成 6 个边界案例。
- [ ] 合规规则有编号、严重级别、字符区间和修改建议。
- [ ] 完成态工作区可返回、可编辑、可保存、可恢复。
- [ ] 历史版本不可被无提示覆盖。
- [ ] API 文档、测试用例和部署说明同步更新。
- [ ] 灰度期无“解析成功但字段全空”、无模板静默回退、无最终海报只含底图。
## 15. 建议立即执行的前三项
1. **先修 `_map_extract_plan_fields()` 的嵌套字段映射,并建立“全空不得成功”的质量门。**
2. **把海报生图结果从“最终海报”改名并改造为“背景资产”,生成完成后继续渲染可编辑 HTML 海报。**
3. **调整 PPT 结果工作台的高度和滚动容器,同时在任务输出记录请求模板与实际模板,先消除交互和模板反馈的不确定性。**