723 lines
28 KiB
Markdown
723 lines
28 KiB
Markdown
|
|
# PPT 多文件上传比对功能详细修复计划书
|
|||
|
|
|
|||
|
|
> 文档状态:待确认
|
|||
|
|
> 适用范围:PPT 生成工作台的“上传材料 → 智能解析 → 核对数据 → 配置生成 → 预览交付”流程
|
|||
|
|
> 目标版本:在不改变现有工作台结构、不新增数据库表的前提下,完整支持 1~4 份计划书上传、同险种比较和跨险种组合分析
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 结论摘要
|
|||
|
|
|
|||
|
|
当前系统并不是从零实现多文件能力:
|
|||
|
|
|
|||
|
|
- 后端 `/insurance/ppt/upload` 已按数组接收多个 `files/types/companies/products/passwords`。
|
|||
|
|
- 会话模型已使用 `files_json` 和 `extractions_json` 保存文件列表及多个解析结果。
|
|||
|
|
- 解析任务会逐个处理会话中的全部文件。
|
|||
|
|
- 比较契约已支持最多 4 份计划书,并能识别单份、多储蓄险、同险种比较和跨险种组合场景。
|
|||
|
|
- 已存在 `multi_savings_comparison.pptx` 多储蓄险比较模板。
|
|||
|
|
|
|||
|
|
当前主要问题集中在四处:
|
|||
|
|
|
|||
|
|
1. 前端上传页把储蓄险、重疾险、IUL 分别建模成单个 `File`,每个上传框 `limit=1`,同一险种无法添加第二份。
|
|||
|
|
2. 上传接口没有提前限制最多 4 份,也没有严格校验五组并行数组是否一一对应。
|
|||
|
|
3. 同币种、同险种等跨文件兼容性校验发生得太晚,用户可能完成解析后,到生成任务阶段才看到失败。
|
|||
|
|
4. 储蓄险比较渲染较完整;通用重疾险/IUL 比较页主要读取前两个产品,不能完整表达 3~4 份计划书。
|
|||
|
|
|
|||
|
|
本次修复应采用“前端条目化 + 后端原子校验 + 核对阶段前置兼容性检查 + 渲染器全量消费比较契约”的方案。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 修复范围与边界
|
|||
|
|
|
|||
|
|
### 2.1 本次必须完成
|
|||
|
|
|
|||
|
|
- 支持一次添加、删除并上传 1~4 份 PDF。
|
|||
|
|
- 允许多份文件选择相同险种。
|
|||
|
|
- 每份文件独立配置险种、保险公司、产品和 PDF 密码。
|
|||
|
|
- 自动识别以下业务场景:
|
|||
|
|
- 1 份:单计划书分析。
|
|||
|
|
- 2~4 份同险种:横向比较。
|
|||
|
|
- 多份不同险种:组合方案,不直接做产品高低排名。
|
|||
|
|
- 同险种横向比较时,在数据核对阶段检查币种、受保人条件等兼容性。
|
|||
|
|
- 储蓄险、重疾险、IUL 的 2~4 份同类型计划书都必须在成品中完整出现。
|
|||
|
|
- 保留现有 5 步工作流、工作台导航、主题色、组件库和 API 路径。
|
|||
|
|
- 补充后端自动化测试、前端构建检查和真实 PPTX 渲染验证。
|
|||
|
|
|
|||
|
|
### 2.2 明确不做
|
|||
|
|
|
|||
|
|
- 不修改数据库表结构,不新增迁移脚本。
|
|||
|
|
- 不修改 BaoDan 基座文件。
|
|||
|
|
- 不新增“手动选择比较/组合模式”的开关,场景继续由实际文件自动判断。
|
|||
|
|
- 不加入拖拽排序;V1 按添加顺序标记为方案 A~D。
|
|||
|
|
- 不支持 PDF 以外的计划书格式。
|
|||
|
|
- 不在本次引入新的前端测试框架或状态管理库。
|
|||
|
|
- 不重做智能解析、归一化和模板管理模块。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 现状分析
|
|||
|
|
|
|||
|
|
### 3.1 当前前端数据结构
|
|||
|
|
|
|||
|
|
`PptUpload.vue` 使用以下固定状态:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
savingsFile / savingsCompany / savingsProduct / savingsPassword
|
|||
|
|
ciFile / ciCompany / ciProduct / ciPassword
|
|||
|
|
iulFile / iulCompany / iulProduct / iulPassword
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这意味着每个险种最多只有一个文件。即使把 `el-upload` 的 `limit` 从 1 改大,保司、产品和密码仍然无法与多份文件分别绑定,所以不能只改 `multiple` 或 `limit`。
|
|||
|
|
|
|||
|
|
### 3.2 当前页面布局条件
|
|||
|
|
|
|||
|
|
- PPT 页面是“左侧步骤导航 + 中间工作区 + 右侧上下文”的三栏布局。
|
|||
|
|
- 上传步骤创建会话前没有右侧上下文面板,因此中间区域可使用较完整宽度。
|
|||
|
|
- 中间内容区桌面端内边距为 20px,移动端为 12px。
|
|||
|
|
- 当前上传区域使用自适应三列卡片;小于 768px 时切换为单列。
|
|||
|
|
- 页面已经使用 Element Plus、绿色主色、10~12px 圆角和轻边框,不需要建立新的视觉语言。
|
|||
|
|
|
|||
|
|
### 3.3 当前后端链路
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart LR
|
|||
|
|
A["PptUpload.vue 固定三个单文件槽位"] --> B["POST /ppt/upload 数组参数"]
|
|||
|
|
B --> C["PptSession.files_json"]
|
|||
|
|
C --> D["解析任务逐文件处理"]
|
|||
|
|
D --> E["PptSession.extractions_json"]
|
|||
|
|
E --> F["逐文件校验"]
|
|||
|
|
F --> G["生成阶段判断场景"]
|
|||
|
|
G --> H["比较契约,最多 4 份"]
|
|||
|
|
H --> I["PPT 渲染"]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
后端主链路已经能保存和解析多个文件。修复重点不是重写接口,而是补齐入口约束、跨文件校验和渲染一致性。
|
|||
|
|
|
|||
|
|
### 3.4 当前业务限制
|
|||
|
|
|
|||
|
|
- 横向比较至少需要 2 份有效计划书。
|
|||
|
|
- 一次最多比较 4 份。
|
|||
|
|
- 横向比较要求险种一致。
|
|||
|
|
- 横向比较要求币种一致。
|
|||
|
|
- 受保人年龄或性别不一致时可以继续,但必须警告用户谨慎使用结论。
|
|||
|
|
- 不同险种应进入组合模式,不能直接横向排名。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 目标交互设计
|
|||
|
|
|
|||
|
|
### 4.1 设计原则
|
|||
|
|
|
|||
|
|
1. 文件和业务配置必须一一绑定,避免并行状态错位。
|
|||
|
|
2. 同险种第二份文件必须容易添加,不能隐藏在高级操作中。
|
|||
|
|
3. 用户在上传前就能看懂本次会生成“单份分析、同险种比较还是组合方案”。
|
|||
|
|
4. 错误尽量在当前步骤暴露,不能到生成任务阶段才失败。
|
|||
|
|
5. 保持现有工作台的操作型界面,不引入大面积装饰或新的页面层级。
|
|||
|
|
|
|||
|
|
### 4.2 上传区目标结构
|
|||
|
|
|
|||
|
|
上传页面改为“场景摘要 + 计划书条目列表 + 添加入口 + 安全说明 + 主操作按钮”。
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
┌──────────────────────────────────────────────────────────────┐
|
|||
|
|
│ 本次方案 [同险种对比] 已添加 2 / 4 │
|
|||
|
|
│ 将按相同保单年度比较;币种将在解析后校验 │
|
|||
|
|
├──────────────────────────────────────────────────────────────┤
|
|||
|
|
│ 方案 A [储蓄险 ▼] [删除] │
|
|||
|
|
│ ┌──────────────── PDF 文件区域 ────────────────────────────┐ │
|
|||
|
|
│ │ 计划书_A.pdf · 3.2 MB [重新选择] │ │
|
|||
|
|
│ └─────────────────────────────────────────────────────────┘ │
|
|||
|
|
│ [保险公司 ▼] [产品(可选) ▼] [PDF 密码(如有)] │
|
|||
|
|
├──────────────────────────────────────────────────────────────┤
|
|||
|
|
│ 方案 B [储蓄险 ▼] [删除] │
|
|||
|
|
│ ┌──────────────── PDF 文件区域 ────────────────────────────┐ │
|
|||
|
|
│ │ 拖拽 PDF 到此处,或点击选择 │ │
|
|||
|
|
│ └─────────────────────────────────────────────────────────┘ │
|
|||
|
|
│ [保险公司 ▼] [产品(可选) ▼] [PDF 密码(如有)] │
|
|||
|
|
├──────────────────────────────────────────────────────────────┤
|
|||
|
|
│ [+ 添加计划书] 最多 4 份 │
|
|||
|
|
├──────────────────────────────────────────────────────────────┤
|
|||
|
|
│ 🔒 文件仅用于本次生成;密码仅用于本次解密 │
|
|||
|
|
│ [上传 2 份并开始解析] │
|
|||
|
|
└──────────────────────────────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 条目行为
|
|||
|
|
|
|||
|
|
每个条目包含:
|
|||
|
|
|
|||
|
|
- 方案编号:按数组顺序显示方案 A、B、C、D。
|
|||
|
|
- 险种:储蓄险、重疾险、IUL。
|
|||
|
|
- PDF 文件:每个条目仅绑定一个 PDF。
|
|||
|
|
- 保险公司:可选。
|
|||
|
|
- 产品:可选,按险种及保司过滤。
|
|||
|
|
- PDF 密码:可选,仅保留在浏览器当前状态和本次请求中。
|
|||
|
|
- 删除操作:至少保留一个空条目;只有一个条目时删除等价于清空。
|
|||
|
|
|
|||
|
|
新增条目规则:
|
|||
|
|
|
|||
|
|
- 初始显示一个空条目。
|
|||
|
|
- 点击“添加计划书”时,新条目默认沿用上一条的险种,方便连续添加同险种比较文件。
|
|||
|
|
- 新条目不继承文件、产品、保司或密码。
|
|||
|
|
- 达到 4 份时禁用新增按钮,并显示“最多支持 4 份计划书”。
|
|||
|
|
|
|||
|
|
字段联动规则:
|
|||
|
|
|
|||
|
|
- 修改险种后,清空当前不兼容的产品。
|
|||
|
|
- 选择产品后,自动回填对应保司,保持现有行为。
|
|||
|
|
- 修改保司后,如果当前产品不属于该保司,则清空产品。
|
|||
|
|
- 文件替换只替换当前条目的文件,不清除险种和产品配置。
|
|||
|
|
- 删除条目后立即重新编号,但不改变其他条目的内容和顺序。
|
|||
|
|
|
|||
|
|
### 4.4 场景摘要
|
|||
|
|
|
|||
|
|
前端根据当前条目即时计算,仅用于解释,不作为后端最终判断依据:
|
|||
|
|
|
|||
|
|
| 条件 | 标签 | 提示 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 无有效文件 | 待添加 | 添加 1~4 份 PDF 计划书 |
|
|||
|
|
| 1 份 | 单份分析 | 生成一份计划书的客户讲解 PPT |
|
|||
|
|
| 2~4 份且险种相同 | 同险种对比 | 将按相同保单年度和统一口径比较 |
|
|||
|
|
| 多份且险种不同 | 组合方案 | 展示产品分工与现金流关系,不直接排名 |
|
|||
|
|
|
|||
|
|
同险种比较提示必须明确:“币种、受保人条件和关键年度将在解析后核对。”
|
|||
|
|
|
|||
|
|
### 4.5 主按钮状态
|
|||
|
|
|
|||
|
|
按钮文案随文件数量变化:
|
|||
|
|
|
|||
|
|
- 0 份:`开始上传并解析`,禁用。
|
|||
|
|
- 1 份:`上传 1 份并开始解析`。
|
|||
|
|
- 2~4 份:`上传 N 份并开始解析`。
|
|||
|
|
- 上传中:`正在上传 N 份计划书…`,所有条目和新增/删除操作锁定。
|
|||
|
|
|
|||
|
|
`canSubmit` 条件:
|
|||
|
|
|
|||
|
|
- 有 1~4 个条目绑定了 PDF。
|
|||
|
|
- 所有准备提交的条目险种合法。
|
|||
|
|
- 没有本地文件格式错误。
|
|||
|
|
- 不要求必须选择保司或产品。
|
|||
|
|
- 不要求空条目必须填写;提交时应忽略完全空白条目。
|
|||
|
|
- 如果条目填写了业务配置但没有文件,应在该条目显示“请先选择 PDF”,不能静默忽略。
|
|||
|
|
|
|||
|
|
### 4.6 状态与错误展示
|
|||
|
|
|
|||
|
|
必须覆盖以下状态:
|
|||
|
|
|
|||
|
|
- 配置加载中:保留当前骨架屏。
|
|||
|
|
- 配置加载失败:显示页内错误和“重新加载”,不能只弹一次消息。
|
|||
|
|
- 空状态:一个可直接操作的空条目。
|
|||
|
|
- 文件格式错误:条目内显示“仅支持 PDF”。
|
|||
|
|
- 文件安全校验失败:错误绑定到具体方案和文件名。
|
|||
|
|
- 密码错误:显示在对应条目的密码字段下。
|
|||
|
|
- 数量超过限制:新增操作禁用,后端再次拦截。
|
|||
|
|
- 部分文件不合法:整个上传请求失败,不创建残缺会话。
|
|||
|
|
- 上传失败:保留用户已选文件和配置,允许修改后重试。
|
|||
|
|
- 上传成功:清空密码,再进入智能解析步骤。
|
|||
|
|
|
|||
|
|
### 4.7 响应式布局
|
|||
|
|
|
|||
|
|
#### 宽屏工作区
|
|||
|
|
|
|||
|
|
- 条目列表使用两列卡片,最多两行。
|
|||
|
|
- 每张卡片内部保司和产品并排,密码单独一行或与其组成三列,按可用宽度决定。
|
|||
|
|
- 场景摘要和底部操作占整行。
|
|||
|
|
|
|||
|
|
#### 中等宽度
|
|||
|
|
|
|||
|
|
- 条目列表改为单列。
|
|||
|
|
- 文件区域和业务字段仍保持紧凑的两列结构。
|
|||
|
|
- 不依赖右侧上下文面板展示关键信息。
|
|||
|
|
|
|||
|
|
#### 小于 768px
|
|||
|
|
|
|||
|
|
- 条目、字段和按钮全部单列。
|
|||
|
|
- 删除、重新选择和添加按钮触控高度不低于 44px。
|
|||
|
|
- 底部主按钮占满宽度。
|
|||
|
|
- 文件名允许两行省略,不能把删除按钮挤出屏幕。
|
|||
|
|
|
|||
|
|
应优先使用现有容器查询逻辑,不额外建立一套互相冲突的断点。
|
|||
|
|
|
|||
|
|
### 4.8 可访问性要求
|
|||
|
|
|
|||
|
|
- 险种、保司、产品、密码必须有可识别标签,不能只依赖 placeholder。
|
|||
|
|
- 删除按钮包含方案名称,例如 `aria-label="删除方案 B"`。
|
|||
|
|
- 场景变化和上传错误使用可被辅助技术感知的状态区域。
|
|||
|
|
- 错误信息与对应输入控件关联。
|
|||
|
|
- 键盘可完成新增、选择文件、修改字段、删除和提交。
|
|||
|
|
- 不能只用颜色区分储蓄险、重疾险和 IUL,必须同时显示文字标签。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 前端实施方案
|
|||
|
|
|
|||
|
|
### 5.1 目标数据结构
|
|||
|
|
|
|||
|
|
将固定的 12 个状态字段替换为一个条目数组:
|
|||
|
|
|
|||
|
|
```ts
|
|||
|
|
type PlanType = 'savings' | 'ci' | 'iul'
|
|||
|
|
|
|||
|
|
interface UploadPlanItem {
|
|||
|
|
id: string
|
|||
|
|
file: File | null
|
|||
|
|
planType: PlanType
|
|||
|
|
companyId: string
|
|||
|
|
productId: string
|
|||
|
|
password: string
|
|||
|
|
errors: {
|
|||
|
|
file?: string
|
|||
|
|
password?: string
|
|||
|
|
general?: string
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- `id` 只用于前端稳定渲染,不发送给后端。
|
|||
|
|
- 不把 `File` 放入全局状态或持久化草稿。
|
|||
|
|
- 方案字母通过数组索引计算,不单独保存。
|
|||
|
|
- 保留后端现有五组 FormData 字段,避免扩大 API 改动。
|
|||
|
|
|
|||
|
|
### 5.2 `PptUpload.vue` 改动
|
|||
|
|
|
|||
|
|
删除:
|
|||
|
|
|
|||
|
|
- `savingsFile/ciFile/iulFile`。
|
|||
|
|
- 三组 company/product/password 状态。
|
|||
|
|
- 针对三个险种分别判断的 `watch` 和 `if/else`。
|
|||
|
|
- 固定 `ports` 计算属性。
|
|||
|
|
|
|||
|
|
新增:
|
|||
|
|
|
|||
|
|
- `uploadItems`。
|
|||
|
|
- `addItem/removeItem/updatePlanType/handleProductChange`。
|
|||
|
|
- `activeItems/fileCount/scenarioSummary/canAdd/canSubmit` 计算属性。
|
|||
|
|
- `buildUploadFormData`,按条目顺序同步追加五组字段。
|
|||
|
|
- 条目级错误映射。
|
|||
|
|
|
|||
|
|
保留:
|
|||
|
|
|
|||
|
|
- `pptApi.getRenderOptions()`。
|
|||
|
|
- `productsFor()` 的过滤规则。
|
|||
|
|
- 当前上传接口和成功后的 `uploaded` 事件。
|
|||
|
|
- 安全说明、主按钮和现有主题样式。
|
|||
|
|
|
|||
|
|
### 5.3 `PptGenerate.vue` 改动
|
|||
|
|
|
|||
|
|
当前前端场景识别只显式覆盖:
|
|||
|
|
|
|||
|
|
- `single_savings`
|
|||
|
|
- `multi_savings_comparison`
|
|||
|
|
- `savings_iul_comprehensive`
|
|||
|
|
|
|||
|
|
需要补齐:
|
|||
|
|
|
|||
|
|
- 单份重疾险/IUL:`generic_single`
|
|||
|
|
- 多份相同重疾险/IUL:`generic_compare`
|
|||
|
|
- 其他混合组合:`generic_portfolio`
|
|||
|
|
|
|||
|
|
模板筛选仍以服务端最终判断为准。前端只负责正确显示场景名称,避免同类型重疾险/IUL 被笼统显示为“通用方案”。
|
|||
|
|
|
|||
|
|
建议场景文案:
|
|||
|
|
|
|||
|
|
- `generic_single`:单份计划分析。
|
|||
|
|
- `generic_compare`:同险种计划对比。
|
|||
|
|
- `generic_portfolio`:跨险种组合方案。
|
|||
|
|
|
|||
|
|
### 5.4 不新增全局抽象
|
|||
|
|
|
|||
|
|
上传条目只在 `PptUpload.vue` 使用,不为单一页面建立新的 store、composable 或通用表单引擎。只有当组件实现后明显超过可维护范围时,才将纯数据转换函数提取到 `frontend/src/utils/ppt-upload.ts`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 后端实施方案
|
|||
|
|
|
|||
|
|
### 6.1 上传入口校验
|
|||
|
|
|
|||
|
|
在 `upload_pdfs()` 最前面增加:
|
|||
|
|
|
|||
|
|
1. 文件数量必须为 1~4。
|
|||
|
|
2. `types/companies/products/passwords` 的元素数量必须与 `files` 相同。
|
|||
|
|
3. `type` 必须属于 `savings/ci/iul`。
|
|||
|
|
4. 每个文件必须通过现有 `prepare_pdf_upload()`。
|
|||
|
|
5. 保司、产品、险种关系继续使用现有校验。
|
|||
|
|
|
|||
|
|
不改变字段名称和响应外壳。
|
|||
|
|
|
|||
|
|
### 6.2 原子上传
|
|||
|
|
|
|||
|
|
当前循环可能先保存有效文件,再发现后续文件无效。多文件比较不能默默丢失其中一份,因此应调整为:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
读取并校验全部文件
|
|||
|
|
→ 任一失败则返回完整错误列表,不创建会话
|
|||
|
|
→ 全部通过后统一写入存储
|
|||
|
|
→ 创建 PptSession
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
如果实现中仍需边校验边写入,则异常时必须清理本次请求已写入的文件。优先选择“先校验、后写入”,逻辑更容易验证。
|
|||
|
|
|
|||
|
|
错误响应应包含可展示的结构化明细:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 4002,
|
|||
|
|
"message": "部分计划书校验失败",
|
|||
|
|
"data": {
|
|||
|
|
"fileErrors": [
|
|||
|
|
{
|
|||
|
|
"index": 1,
|
|||
|
|
"fileName": "方案B.pdf",
|
|||
|
|
"field": "password",
|
|||
|
|
"message": "PDF 密码错误"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
如果现有统一错误工具暂不支持 `data`,V1 可以保留拼接后的 `message`,但前端只能显示全局错误;结构化错误应作为本次修复的推荐实现。
|
|||
|
|
|
|||
|
|
### 6.3 跨文件兼容性校验前置
|
|||
|
|
|
|||
|
|
扩展 `/ppt/validate/<session_id>`:
|
|||
|
|
|
|||
|
|
1. 按现有逻辑归一化所有成功或部分成功的提取结果。
|
|||
|
|
2. 计算实际场景和生成模式。
|
|||
|
|
3. 对多文件场景调用现有 `build_comparison_contract()`。
|
|||
|
|
4. 捕获 `ValueError` 并追加:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"field": "comparison",
|
|||
|
|
"severity": "error",
|
|||
|
|
"message": "不同币种不能直接比较,请上传相同币种的计划书"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这样现有 `PptDataReview.vue` 会自动阻止用户进入配置生成步骤,无需新增接口。
|
|||
|
|
|
|||
|
|
警告规则:
|
|||
|
|
|
|||
|
|
- 受保人年龄或性别不一致:警告,可继续。
|
|||
|
|
- 缺少共同关键年份:警告,可继续,但比较页显示待确认。
|
|||
|
|
- 产品条件不完全一致:警告,不进行高低排名。
|
|||
|
|
|
|||
|
|
错误规则:
|
|||
|
|
|
|||
|
|
- 同险种比较币种不同。
|
|||
|
|
- 有效计划书不足 2 份却进入比较模式。
|
|||
|
|
- 有效计划书超过 4 份。
|
|||
|
|
- 数据归一化失败导致某份计划书无法参与比较。
|
|||
|
|
|
|||
|
|
### 6.4 生成阶段最终保护
|
|||
|
|
|
|||
|
|
生成任务仍保留 `build_comparison_contract()` 校验,作为并发修改或绕过前端时的最终保护。
|
|||
|
|
|
|||
|
|
需要改善错误信息:
|
|||
|
|
|
|||
|
|
- `ValueError` 应转换为明确的 `validation_error` 或 `comparison_validation_error`。
|
|||
|
|
- 任务错误消息保留业务提示,不统一变成“生成失败”。
|
|||
|
|
- 不重复实现一套与核对接口不同的比较规则。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 比较与渲染修复
|
|||
|
|
|
|||
|
|
### 7.1 场景识别
|
|||
|
|
|
|||
|
|
保留当前自动识别规则:
|
|||
|
|
|
|||
|
|
| 文件组合 | 场景 | 模式 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 单份储蓄险 | `single_savings` | `single` |
|
|||
|
|
| 2~4 份储蓄险 | `multi_savings_comparison` | `compare` |
|
|||
|
|
| 储蓄险 + IUL | `savings_iul_comprehensive` | `portfolio` |
|
|||
|
|
| 单份其他险种 | `generic_single` | `single` |
|
|||
|
|
| 2~4 份相同其他险种 | `generic_compare` | `compare` |
|
|||
|
|
| 其他混合险种 | `generic_portfolio` | `portfolio` |
|
|||
|
|
|
|||
|
|
前端和后端文案可以不同,但场景判断结果必须一致。
|
|||
|
|
|
|||
|
|
### 7.2 储蓄险
|
|||
|
|
|
|||
|
|
现有能力基本可复用:
|
|||
|
|
|
|||
|
|
- 多产品价值走势图遍历全部产品。
|
|||
|
|
- 关键年份对比表遍历全部产品。
|
|||
|
|
- 每份产品生成独立保单摘要。
|
|||
|
|
- 支持 2~4 份。
|
|||
|
|
|
|||
|
|
本次主要补自动化测试,避免前端开放多文件后暴露潜在回归。
|
|||
|
|
|
|||
|
|
### 7.3 重疾险
|
|||
|
|
|
|||
|
|
同类型重疾险比较不能只沿用储蓄价值指标。比较页至少应包含:
|
|||
|
|
|
|||
|
|
- 年缴保费。
|
|||
|
|
- 缴费年期。
|
|||
|
|
- 基本保额。
|
|||
|
|
- 保障期。
|
|||
|
|
- 重疾/早期重疾或主要保障项目数量。
|
|||
|
|
- 关键保单年度的身故保障或重疾保障数据(仅在正式计划书提供时展示)。
|
|||
|
|
|
|||
|
|
要求:
|
|||
|
|
|
|||
|
|
- 2~4 份产品全部出现在总览表。
|
|||
|
|
- 不用“回本年”“IRR”作为重疾险核心结论。
|
|||
|
|
- 保障定义、赔付次数或疾病范围不一致时提示“条款口径不同,不直接排名”。
|
|||
|
|
|
|||
|
|
### 7.4 IUL
|
|||
|
|
|
|||
|
|
同类型 IUL 比较页至少应包含:
|
|||
|
|
|
|||
|
|
- 年缴保费、缴费年期、基本保额。
|
|||
|
|
- 保证现金价值。
|
|||
|
|
- 非保证现金价值。
|
|||
|
|
- 保证/非保证身故保障。
|
|||
|
|
- 关键年度价值。
|
|||
|
|
- 正式计划书中披露的演示假设或指数账户信息。
|
|||
|
|
|
|||
|
|
要求:
|
|||
|
|
|
|||
|
|
- 明确区分保证与非保证数据。
|
|||
|
|
- 不把不同演示利率条件下的非保证价值直接排名。
|
|||
|
|
- 2~4 份产品全部进入表格或图表。
|
|||
|
|
|
|||
|
|
### 7.5 通用比较页面修复
|
|||
|
|
|
|||
|
|
当前通用 `compare` 和 `synergy` 页面主要读取 `products[0]` 与 `products[1]`。需要改为:
|
|||
|
|
|
|||
|
|
- 比较模式使用 2×2 指标卡或全量表格,遍历最多 4 份产品。
|
|||
|
|
- 同险种比较不使用“协同关系”页面;“协同”只属于跨险种组合模式。
|
|||
|
|
- 渲染器优先消费 `deck.comparison.products` 中已计算的比较指标,避免在页面构建器里重复计算。
|
|||
|
|
- 缺失数据统一显示“待正式计划书确认”,不得补零或推算。
|
|||
|
|
|
|||
|
|
### 7.6 模板策略
|
|||
|
|
|
|||
|
|
- 多储蓄险继续优先使用 `multi_savings_comparison.pptx`。
|
|||
|
|
- 同类型重疾险/IUL 暂时复用对应险种的现有 business 模板,不强制新增 PPTX 模板文件。
|
|||
|
|
- 场景页面清单由 `scenarioSlides` 保证,模板只提供母版和视觉。
|
|||
|
|
- 如果复用模板后出现布局不足,再单独新增 `generic_compare` 场景模板;不作为本次修复的前置条件。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 文件级改动清单
|
|||
|
|
|
|||
|
|
| 文件 | 改动 |
|
|||
|
|
|---|---|
|
|||
|
|
| `frontend/src/pages/components/ppt/PptUpload.vue` | 固定三槽位改为 1~4 个动态条目;新增场景摘要、条目级错误和响应式布局 |
|
|||
|
|
| `frontend/src/pages/components/ppt/PptGenerate.vue` | 补齐通用单份、同险种比较和跨险种组合的场景识别与文案 |
|
|||
|
|
| `api/insurance/ppt/routes.py` | 上传数量/数组/type 校验;原子上传;核对接口增加跨文件兼容性校验 |
|
|||
|
|
| `api/insurance/ppt/comparison.py` | 必要时补充按险种输出的比较指标;保持单一校验规则来源 |
|
|||
|
|
| `api/insurance/generation/celery_tasks.py` | 将比较校验异常转换为明确任务错误;继续保留最终保护 |
|
|||
|
|
| `api/insurance/ppt/scripts/fast_pptx_renderer.py` | 通用比较遍历全部产品;区分 compare 与 portfolio;按险种展示指标 |
|
|||
|
|
| `tests/ppt_multi_upload_route_test.py` | 新增多文件上传、数量、数组对齐和原子失败测试 |
|
|||
|
|
| `tests/ppt_comparison_test.py` | 新增场景、币种、险种、人数条件和 4 份上限测试 |
|
|||
|
|
| `tests/ppt_multi_render_test.py` | 新增 2/4 份储蓄险、重疾险、IUL 的 PPTX 渲染回归测试 |
|
|||
|
|
|
|||
|
|
不需要修改:
|
|||
|
|
|
|||
|
|
- `api/insurance/models/ppt_session.py`
|
|||
|
|
- 数据库迁移
|
|||
|
|
- `frontend/src/utils/ppt-api.ts` 的上传接口路径
|
|||
|
|
- BaoDan `main.py`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. 实施阶段
|
|||
|
|
|
|||
|
|
### Phase 1:后端保护与测试基线
|
|||
|
|
|
|||
|
|
- [ ] 为当前比较场景识别和上限补单元测试。
|
|||
|
|
- [ ] 上传接口增加 1~4 份限制。
|
|||
|
|
- [ ] 校验五组数组长度。
|
|||
|
|
- [ ] 校验险种白名单。
|
|||
|
|
- [ ] 实现多文件原子成功/失败。
|
|||
|
|
- [ ] 保证单文件上传兼容现有调用方式。
|
|||
|
|
|
|||
|
|
验收:
|
|||
|
|
|
|||
|
|
- 单文件原有用例通过。
|
|||
|
|
- 两份同类型文件可创建一个会话。
|
|||
|
|
- 第 5 份在读取和解析前被拒绝。
|
|||
|
|
- 任一文件校验失败时不创建会话,不遗留本次上传文件。
|
|||
|
|
|
|||
|
|
### Phase 2:前端动态条目
|
|||
|
|
|
|||
|
|
- [ ] 使用 `uploadItems` 替换固定三组状态。
|
|||
|
|
- [ ] 实现新增、删除、文件替换和字段联动。
|
|||
|
|
- [ ] 实现场景摘要和动态按钮文案。
|
|||
|
|
- [ ] 实现条目级错误。
|
|||
|
|
- [ ] 完成宽屏、中屏、移动端布局。
|
|||
|
|
- [ ] 保留失败后的用户输入,成功后清除密码。
|
|||
|
|
|
|||
|
|
验收:
|
|||
|
|
|
|||
|
|
- 可连续添加 4 份储蓄险。
|
|||
|
|
- 可添加储蓄险 + IUL 组合。
|
|||
|
|
- 删除中间条目后剩余内容不串位。
|
|||
|
|
- 修改险种后不保留不兼容产品。
|
|||
|
|
- 手机宽度下无横向溢出。
|
|||
|
|
|
|||
|
|
### Phase 3:核对阶段兼容性校验
|
|||
|
|
|
|||
|
|
- [ ] `/validate` 归一化全部有效提取结果。
|
|||
|
|
- [ ] 同险种比较调用现有比较契约校验。
|
|||
|
|
- [ ] 将跨文件错误/警告加入现有 issues。
|
|||
|
|
- [ ] 确认 `PptDataReview` 能阻止错误状态继续。
|
|||
|
|
|
|||
|
|
验收:
|
|||
|
|
|
|||
|
|
- 两份同险种不同币种时,在数据核对步骤阻止继续。
|
|||
|
|
- 年龄或性别不同只显示警告。
|
|||
|
|
- 修改提取数据并保存后会重新执行跨文件校验。
|
|||
|
|
|
|||
|
|
### Phase 4:全险种多产品渲染
|
|||
|
|
|
|||
|
|
- [ ] 验证 2~4 份储蓄险现有页面。
|
|||
|
|
- [ ] 重疾险比较使用保障类指标。
|
|||
|
|
- [ ] IUL 比较区分保证/非保证指标。
|
|||
|
|
- [ ] 通用比较页面遍历全部产品。
|
|||
|
|
- [ ] 同险种比较移除不合适的协同页。
|
|||
|
|
- [ ] 比较页优先读取 `deck.comparison`。
|
|||
|
|
|
|||
|
|
验收:
|
|||
|
|
|
|||
|
|
- 4 份产品名称均能在成品中检索到。
|
|||
|
|
- 重疾险页面不出现储蓄险专属 IRR/回本结论。
|
|||
|
|
- IUL 保证与非保证数据有明确标识。
|
|||
|
|
- 组合场景仍保留协同与现金流页面。
|
|||
|
|
|
|||
|
|
### Phase 5:回归与交付
|
|||
|
|
|
|||
|
|
- [ ] 后端 PPT 相关测试全部通过。
|
|||
|
|
- [ ] 前端 `lint`、TypeScript 检查和生产构建通过。
|
|||
|
|
- [ ] 使用真实或脱敏样本完成端到端验证。
|
|||
|
|
- [ ] 打开生成的 PPTX 检查页数、产品覆盖、表格溢出和中文字体。
|
|||
|
|
- [ ] 验证单文件流程未受影响。
|
|||
|
|
- [ ] 验证密码 PDF、多文件部分失败和任务重试。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. 测试矩阵
|
|||
|
|
|
|||
|
|
### 10.1 上传与接口
|
|||
|
|
|
|||
|
|
| 用例 | 预期 |
|
|||
|
|
|---|---|
|
|||
|
|
| 1 份储蓄险 | 上传成功,进入单份分析 |
|
|||
|
|
| 2 份储蓄险 | 上传成功,进入多储蓄险比较 |
|
|||
|
|
| 4 份同类型文件 | 上传成功 |
|
|||
|
|
| 5 份文件 | 上传前被后端拒绝 |
|
|||
|
|
| 2 份文件但只有 1 个 type | 参数错误,不创建会话 |
|
|||
|
|
| type 为未知值 | 参数错误 |
|
|||
|
|
| 第 2 份 PDF 密码错误 | 整体失败,不创建残缺会话 |
|
|||
|
|
| 第 2 份不是 PDF | 整体失败 |
|
|||
|
|
| 产品与险种不匹配 | 整体失败,指出具体文件 |
|
|||
|
|
|
|||
|
|
### 10.2 场景与兼容性
|
|||
|
|
|
|||
|
|
| 文件组合 | 预期 |
|
|||
|
|
|---|---|
|
|||
|
|
| 储蓄险 × 2 | `multi_savings_comparison / compare` |
|
|||
|
|
| 重疾险 × 2 | `generic_compare / compare` |
|
|||
|
|
| IUL × 4 | `generic_compare / compare` |
|
|||
|
|
| 储蓄险 + IUL | `savings_iul_comprehensive / portfolio` |
|
|||
|
|
| 重疾险 + IUL | `generic_portfolio / portfolio` |
|
|||
|
|
| 同险种不同币种 | 核对步骤错误 |
|
|||
|
|
| 同险种不同年龄 | 核对步骤警告 |
|
|||
|
|
| 同险种共同年份不足 | 警告并显示缺失值,不伪造数据 |
|
|||
|
|
|
|||
|
|
### 10.3 前端交互
|
|||
|
|
|
|||
|
|
| 用例 | 预期 |
|
|||
|
|
|---|---|
|
|||
|
|
| 初始进入 | 显示 1 个空条目 |
|
|||
|
|
| 连续点击添加 | 最多出现 4 个条目 |
|
|||
|
|
| 删除方案 B | C、D 重新编号,数据不串位 |
|
|||
|
|
| 选择产品 | 自动回填保司 |
|
|||
|
|
| 修改保司 | 不兼容产品被清空 |
|
|||
|
|
| 修改险种 | 不兼容产品被清空 |
|
|||
|
|
| 上传失败后重试 | 文件及配置仍保留 |
|
|||
|
|
| 上传进行中 | 所有会改变请求内容的操作被禁用 |
|
|||
|
|
| 手机端 | 单列,无横向滚动,主按钮全宽 |
|
|||
|
|
|
|||
|
|
### 10.4 成品验证
|
|||
|
|
|
|||
|
|
- 每份有效产品至少有一个产品名称或摘要落点。
|
|||
|
|
- 对比表行数/列数与产品数量一致。
|
|||
|
|
- 关键年份缺失时显示待确认,不显示虚假 0。
|
|||
|
|
- 4 产品页面无文本越界、重叠或被裁切。
|
|||
|
|
- 生成结果仍能进入预览、编辑、重新生成和下载流程。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. 验收标准
|
|||
|
|
|
|||
|
|
功能验收:
|
|||
|
|
|
|||
|
|
1. 用户可以在现有上传步骤添加 1~4 份 PDF,且同一险种可重复添加。
|
|||
|
|
2. 每份文件的险种、保司、产品、密码不会与其他文件串位。
|
|||
|
|
3. 同险种 2~4 份计划书在核对阶段完成比较条件校验。
|
|||
|
|
4. 生成的 PPT 包含全部参与比较的产品,不只展示前两个。
|
|||
|
|
5. 储蓄险、重疾险、IUL 使用与险种相符的比较口径。
|
|||
|
|
6. 不同险种进入组合模式,不做直接排名。
|
|||
|
|
7. 任何一份上传校验失败时不创建残缺会话。
|
|||
|
|
8. 原单文件上传、解析、核对、生成和下载流程保持可用。
|
|||
|
|
|
|||
|
|
质量验收:
|
|||
|
|
|
|||
|
|
- 后端新增测试全部通过,现有 PPT 生命周期测试无回归。
|
|||
|
|
- 前端生产构建和 lint 通过。
|
|||
|
|
- 桌面、平板和手机布局均可完成全部操作。
|
|||
|
|
- 错误能定位到具体文件或比较条件。
|
|||
|
|
- 不新增数据库迁移、全局状态库或重复 API。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 12. 风险与控制措施
|
|||
|
|
|
|||
|
|
| 风险 | 影响 | 控制措施 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 多文件解析时间线性增加 | 用户等待变长 | 保留现有逐文件进度;后续再按既有并发方案优化,不与本次 UI 修复绑定 |
|
|||
|
|
| 一份失败导致比较不完整 | 生成错误结论 | 上传阶段原子失败;解析失败在核对阶段作为错误阻止继续 |
|
|||
|
|
| 前后端场景判断漂移 | 模板筛选与实际生成不一致 | 后端作为最终真相;前端只做说明,并补齐与后端同名场景 |
|
|||
|
|
| 4 产品表格拥挤 | PPT 文本溢出 | 采用全量表格或 2×2 卡片;加入真实 PPTX 渲染测试 |
|
|||
|
|
| 不同险种误做排名 | 业务和合规风险 | `compare` 强制同险种;混合险种只进入 `portfolio` |
|
|||
|
|
| 不同币种金额误比 | 错误销售结论 | 核对步骤直接阻断同险种横比 |
|
|||
|
|
| 密码残留 | 敏感信息风险 | 不持久化密码;成功后立即清空;日志不得记录密码 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 13. 工作量建议
|
|||
|
|
|
|||
|
|
| 阶段 | 预计工作量 |
|
|||
|
|
|---|---:|
|
|||
|
|
| 后端入口保护与路由测试 | 0.5~1 人日 |
|
|||
|
|
| 前端动态上传条目与响应式布局 | 1~1.5 人日 |
|
|||
|
|
| 跨文件核对校验 | 0.5 人日 |
|
|||
|
|
| 重疾险/IUL/4 产品渲染完善 | 1.5~2 人日 |
|
|||
|
|
| 回归、真实样本和 PPTX 视觉检查 | 1 人日 |
|
|||
|
|
| 合计 | 4.5~6 人日 |
|
|||
|
|
|
|||
|
|
建议先完成 Phase 1~3,确保“能正确上传且不能错误生成”;再完成 Phase 4 的全险种成品表达。不要只上线前端多选控件。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 14. 完成定义
|
|||
|
|
|
|||
|
|
只有同时满足以下条件,才能将该功能标记为完成:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
页面能添加同类型多份文件
|
|||
|
|
AND 后端能原子接收 1~4 份
|
|||
|
|
AND 解析结果全部进入核对
|
|||
|
|
AND 比较条件在生成前验证
|
|||
|
|
AND 成品展示全部参与产品
|
|||
|
|
AND 单文件和组合场景没有回归
|
|||
|
|
```
|
|||
|
|
|