计划书录入功能模块 - 架构设计方案
创建时间: 2026-02-06 设计师: Claude Code 状态: ✅ 已批准 批准时间: 2026-02-06 版本: v2.1 最后更新: 2026-02-06
更新记录:
- v2.1 (2026-02-06): 更新储蓄型产品提取计划逻辑,明确三层结构和字段分布
- v2.0 (2026-02-06): 整合储蓄型产品(GS/GC/FA/LV2),新增提取计划功能
- v1.0 (2026-02-06): 初始版本,支持人寿保险和重疾保险产品
📋 需求总结
核心需求
- 产品驱动:一个产品对应一个计划书模版,用户不需要选择模版类型
- 保额配置:支持不同币种(人民币、美元等),币种符号可配置
- 年龄选择:使用 NutUI Popup + Picker 多列选择器,3位数字,初始值018,传给后端的值是数字18
- 缴费年期:key 和 value 相同(如"整付(0-75 岁)")
- 日期选择:使用 DatePicker 日期选择器
- 扩展性:产品和模版的映射方式需要考虑未来扩展
用户流程
用户在首页/产品详情页点击"计划书"按钮
↓
系统根据产品名称/ID自动选择对应的模版
↓
显示计划书录入弹窗(包含动态表单)
↓
用户填写表单(性别、年龄、出生年月日、是否吸烟、保额、缴费年期等)
↓
提交 → 跳转到计划书提交结果页
🔍 现有实现分析
当前架构
首页 (index.vue)
└─ 点击"计划书"按钮
└─ 打开 PlanPopup
├─ SchemeA (硬编码)
└─ SchemeB (硬编码)
问题
- ❌ 硬编码模版:通过
currentScheme变量手动选择 SchemeA 或 SchemeB - ❌ 缺少产品-模版映射:没有根据产品自动选择模版的机制
- ❌ 表单组件有限:缺少保额(币种配置)、年龄选择器、日期选择器等组件
- ❌ 扩展性差:新增产品或模版需要修改代码
现有表单字段
| 模版 | 字段 | 类型 |
|---|---|---|
| SchemeA | 客户姓名、性别、年龄、行业、年收入、家庭结构、保险需求、期望收益率 | Input、Radio、Picker、多选标签 |
| SchemeB | 币种、计划、附加计划、性别、年龄、保险期间、交费期间、年交保费 | 固定值、Radio、Input |
产品 API 数据结构
{
id: 1,
product_name: "WIOP3E 盈传创富保障计划 3 - 优选版",
form_sn: "xxx", // 关联表单sn(可能用来关联模版)
categories: [...],
tags: [...],
documents: [...],
cover_image: "..."
}
计划书文档定义
第一版模版(docs/plan/计划书模版.md):
人寿产品(WIOP3E、WIOP3):
- 核心信息:性别、年龄、出生年月日、是否吸烟
- 保额
- 缴费年期:整付(0-75 岁)、5 年(0-70 岁)、10 年(0-70 岁)
重疾产品(MPC、MBC PRO、MBC2):
- 核心信息:性别、年龄、出生年月日、是否吸烟
- 保额
- 缴费年期:10 年(15 日 - 65 岁)、20 年(15 日 - 65 岁)、25 年(15 日 - 60 岁)
第二版模版(docs/plan/计划书模版2.docx):
储蓄型产品(统一逻辑):
- 产品列表:
- GS(宏摯傳承保障計劃)
- GC(宏摯家傳承保險計劃)
- FA(宏浚傳承保障計劃)
- LV2(赤霞珠終身壽險計劃2)
- 核心信息:性别、年龄、出生年月日、是否吸烟
- 保额(年缴保费)
- 缴费年期:各产品不同(详见配置文件)
- 提取计划功能(所有储蓄产品通用):
字段结构说明:
字段1:是否希望生成一份容许减少名义金额的提取说明?(是/否)
- 独立字段,不影响下面的提取方案配置
- 仅用于标识是否需要生成说明文档
字段2:提取选项(二选一):
- 指定提取金额
- 最高固定提取金额
字段3-N:根据字段2的选择显示不同字段:
A. 指定提取金额模式: - 提取方式: 1. 按年岁
- **按年岁**字段(3个):
- 由几岁开始(withdrawal_start_age)
- 提取期(年)(withdrawal_period)
- 每年递增提取之百分比(%)(increase_rate)
B. 最高固定提取金额模式(2个字段): - 按年岁:由几岁开始(withdrawal_start_age) - 提取期(年)(withdrawal_period)
⚠️ 小程序端特别说明:
- 币种固定(使用配置中的默认币种,如 HKD)
- 无需手动选择币种字段
- 无需"每年提取金额"字段(由后端计算)
字段清理逻辑:
- 切换提取方式时,自动清除不相关字段
- "是否希望生成说明"字段不影响任何其他字段
🏗️ 架构设计方案
方案 A:产品 API 驱动(推荐)⭐
核心思路
后端在产品 API 返回数据中已有 form_sn 字段,用于指定该产品使用的计划书模版。
数据结构设计
1. 产品 API 返回数据(已有字段)
// src/api/get_product.js
{
id: 1,
product_name: "WIOP3E 盈传创富保障计划 3 - 优选版",
form_sn: "life-insurance-wiop3e", // ✅ 已有字段:计划书模版标识(就是模版名称)
// 注意:如果需要模版配置(如币种、缴费年期选项),可以新增 plan_config 字段
// 或者前端根据 form_sn 从配置文件中读取对应的配置
// ... 其他字段
}
2. 模版配置文件
// src/config/plan-templates.js
export const PLAN_TEMPLATES = {
// form_sn: life-insurance-wiop3e
'life-insurance-wiop3e': {
name: 'WIOP3E 盈传创富保障计划 3 - 优选版',
component: 'LifeInsuranceTemplate',
// 模版配置(可选:如果后端不提供 plan_config,则使用这里的配置)
config: {
currency: "USD", // 币种:USD/CNY
payment_periods: [ // 缴费年期选项
"整付(0-75 岁)",
"5 年(0-70 岁)",
"10 年(0-70 岁)"
],
age_range: { min: 0, max: 75 }, // 年龄范围
insurance_period: "终身" // 保险期间
}
},
// form_sn: critical-illness-mpc
'critical-illness-mpc': {
name: 'MPC 守护无间重疾',
component: 'CriticalIllnessTemplate',
config: {
currency: "CNY",
payment_periods: [
"10 年(15 日 - 65 岁)",
"20 年(15 日 - 65 岁)",
"25 年(15 日 - 60 岁)"
],
age_range: { min: 0, max: 65 },
insurance_period: "终身"
}
}
}
3. 功能开关配置(未来扩展用)
// src/config/plan-templates.js
/**
* 全局功能开关
* @description 用于控制实验性功能或未来扩展功能的开关
* @example 开启多币种功能:设置 MULTI_CURRENCY_ENABLED = true
*/
export const FEATURE_FLAGS = {
// 多币种切换功能(当前:关闭,未来:开启)
// false: 方案 1 - 固定币种(当前实现)
// true: 方案 2 - 支持多币种切换(未来扩展)
MULTI_CURRENCY_ENABLED: false,
}
4. 出生日期驱动年龄(推荐方案)
核心逻辑
用户选择"出生年月日"
↓
系统自动计算年龄 = 当前年份 - 出生年份
↓
年龄字段自动填充
↓
用户可以手动修改年龄(特殊情况)
优势
- ✅ 更准确:出生日期是准确的个人信息
- ✅ 自动计算:避免用户手动输入错误
- ✅ 灵活性:用户可以修改年龄
- ✅ 逻辑简单:不需要复杂的日期限制
实现示例
// 用户选择出生日期
const onBirthdayChange = (birthday) => {
form.birthday = birthday
// 自动计算年龄
const birthYear = new Date(birthday).getFullYear()
const currentYear = new Date().getFullYear()
form.age = currentYear - birthYear
}
组件架构
PlanFormContainer (计划书表单容器)
└─ 根据产品 form_sn 动态加载模版组件
├─ LifeInsuranceTemplate (人寿保险模版)
├─ CriticalIllnessTemplate (重疾保险模版)
├─ SavingsTemplate (储蓄型产品模版)
└─ 其他模版...
动态表单字段组件:
├─ AgePicker (年龄选择器)
├─ AmountInput (保额输入 + 币种)
├─ DatePicker (日期选择器)
├─ RadioGroup (单选)
├─ SelectPicker (下拉选择)
└─ WithdrawalPlanSelector (提取计划选择器 - 储蓄产品专用)
提取计划相关组件:
├─ WithdrawalPlanSelector.vue (主选择器:方式1/方式2)
├─ SpecifiedAmountForm.vue (年龄指定金额表单)
├─ FixedAmountForm.vue (最高固定金额表单)
└─ CurrencySelector.vue (币种选择器)
🎯 推荐方案
选择:方案 A(产品 API 驱动)
理由
- ✅ 扩展性强:新增产品只需后端配置
plan_template字段 - ✅ 维护成本低:产品信息和模版信息都在同一处
- ✅ 类型安全:前端可以使用 TypeScript 验证模版配置
- ✅ 支持动态配置:可以通过 CMS 后台管理产品和模版的映射关系
后端配合要求
-
产品已有字段:
form_sn- 模版标识(如life-insurance-wiop3e)- ✅ 这个字段已经存在,可以直接使用
-
可选增强:如果需要动态配置模版参数(如币种、缴费年期选项),可以新增
plan_config字段:-
currency: 币种(USD/CNY) -
payment_periods: 缴费年期选项数组 -
age_range: 年龄范围({ min, max }) -
insurance_period: 保险期间
-
注意:如果后端不提供 plan_config,前端会从 src/config/plan-templates.js 配置文件中读取默认配置。
📂 文件结构
src/
├── api/
│ └── plan.js # 计划书 API(新增)
│
├── config/
│ └── plan-templates.js # 计划书模版配置(新增)
│
├── components/
│ ├── PlanFormContainer.vue # 计划书表单容器(新增)
│ ├── PlanPopup/
│ │ └── index.vue # 弹窗容器(已有)
│ │
│ ├── PlanTemplates/ # 具体模版组件(新增)
│ │ ├── LifeInsuranceTemplate.vue
│ │ ├── CriticalIllnessTemplate.vue
│ │ ├── SavingsTemplate.vue # 储蓄型产品模版(GS/GC/FA/LV2)
│ │ └── README.md # 模版开发文档
│ │
│ └── PlanFields/ # 通用表单字段组件(新增)
│ ├── AgePicker.vue # 年龄选择器
│ ├── AmountInput.vue # 保额输入
│ ├── DatePicker.vue # 日期选择器
│ ├── RadioGroup.vue # 单选组
│ ├── SelectPicker.vue # 下拉选择
│ └── WithdrawalPlan/ # 提取计划组件(储蓄产品专用)
│ ├── WithdrawalPlanSelector.vue # 主选择器
│ ├── SpecifiedAmountForm.vue # 年龄指定金额表单
│ ├── FixedAmountForm.vue # 最高固定金额表单
│ └── CurrencySelector.vue # 币种选择器
│
└── pages/
├── index.vue # 首页(修改)
└── product-detail/
└── index.vue # 产品详情页(修改)
🔧 表单字段组件设计
1. AgePicker(年龄选择器)
需求:
- 使用 NutUI Popup + Picker 多列样式
- 年龄范围:0-120 岁
- 显示格式:3位数字(018)
- 提交格式:数字(18)
2. AmountInput(保额输入)
需求:
- 支持不同币种(CNY、USD、HKD、EUR)
- 小数点后2位控制
- 币种符号可配置
3. DatePicker(出生日期选择器)→ 自动计算年龄
优化方案:
- 用户选择出生年月日
- 系统自动计算年龄 = 当前年份 - 出生年份
- 年龄字段自动填充
- 用户可以手动修改年龄(特殊情况)
4. RadioGroup(单选组)
需求:
- 性别、是否吸烟等单选项
5. SelectPicker(下拉选择)
需求:
- 缴费年期选择
- key 和 value 相同(如"整付(0-75 岁)")
6. WithdrawalPlanSelector(提取计划选择器)⭐ 储蓄产品专用
业务场景:储蓄型产品(GS/GC/FA/LV2)支持提取计划功能
字段结构:
字段1:是否生成说明(独立字段)
问题:是否希望生成一份容许减少名义金额的提取说明?
选项:是 / 否(默认:否)
说明:此字段为独立配置,不影响下面的提取方案
字段2:提取选项
问题:提取选项
选项:
- 指定提取金额
- 最高固定提取金额
字段3-N:具体配置字段(根据字段2选择显示不同字段)
A. 指定提取金额模式
子选项:提取方式
选项:
- 按年岁
按年岁字段(3个):
{
withdrawal_enabled: '是',
withdrawal_mode: '指定提取金额',
withdrawal_method: '按年岁',
withdrawal_start_age: 60, // 由几岁开始
withdrawal_period: '10年', // 提取期(年)
increase_rate: '5' // 每年递增提取之百分比(%)
}
B. 最高固定提取金额模式(2个字段)
{
withdrawal_enabled: '是',
withdrawal_mode: '最高固定提取金额',
withdrawal_start_age: 60, // 按年岁:由几岁开始
withdrawal_period: '10年' // 提取期(年)
}
⚠️ 小程序端特别说明:
- 币种固定(从配置文件读取,如 HKD),无需用户选择
- 无需"每年提取金额"字段(小程序端不需要)
- 字段清理逻辑:切换模式时自动清除不相关字段
组件设计(独立字段结构):
<template>
<div>
<!-- 字段1:是否生成说明(独立字段) -->
<PlanFieldRadio
v-model="form.withdrawal_enabled"
label="是否希望生成一份容许减少名义金额的提取说明?"
:options="['是', '否']"
/>
<!-- 字段2:款项提取配置(始终显示) -->
<h3>款项提取(容许减少名义金额)</h3>
<!-- 提取选项 -->
<PlanFieldRadio
v-model="form.withdrawal_mode"
label="提取选项"
:options="['指定提取金额', '最高固定提取金额']"
@change="onWithdrawalModeChange"
/>
<!-- 指定提取金额模式 -->
<template v-if="form.withdrawal_mode === '指定提取金额'">
<!-- 子选项:提取方式 -->
<PlanFieldRadio
v-model="form.withdrawal_method"
label="提取方式"
:options="['按年岁']"
/>
<!-- 按年岁字段 -->
<template v-if="form.withdrawal_method === '按年岁'">
<PlanFieldAgePicker
v-model="form.withdrawal_start_age"
label="由几岁开始"
placeholder="请输入开始提取年龄"
/>
<PlanFieldSelect
v-model="form.withdrawal_period"
label="提取期(年)"
placeholder="请选择提取期"
:options="withdrawalPeriods"
/>
<!-- 每年递增提取之百分比 -->
<div>
<div class="text-sm text-gray-700 mb-2">
每年递增提取之百分比(%)
</div>
<nut-input
v-model="form.increase_rate"
type="digit"
placeholder="请输入递增百分比"
/>
</div>
</template>
</template>
<!-- 最高固定提取金额模式 -->
<template v-if="form.withdrawal_mode === '最高固定提取金额'">
<PlanFieldAgePicker
v-model="form.withdrawal_start_age"
label="按年岁:由几岁开始"
placeholder="请输入开始提取年龄"
/>
<PlanFieldSelect
v-model="form.withdrawal_period"
label="提取期(年)"
placeholder="请选择提取期"
:options="withdrawalPeriods"
/>
</template>
</div>
</template>
<script setup>
// 提取模式切换时的字段清理逻辑
const onWithdrawalModeChange = (mode) => {
if (mode === '最高固定提取金额') {
// 最高固定金额模式不需要指定金额的相关字段
delete form.withdrawal_method
delete form.increase_rate
}
}
// 监听提取方式变化
watch(() => form.withdrawal_method, (newType) => {
// 两种方式都不需要 annual_amount 和 increase_rate(小程序端不需要)
delete form.annual_amount
delete form.increase_rate
})
</script>
📊 数据流
用户点击"计划书"按钮
↓
openPlanPopup(productId)
↓
查找产品对象
↓
获取 product.form_sn(已有字段)
↓
根据 form_sn 从 PLAN_TEMPLATES 配置中查找对应模版
↓
加载对应的模版组件(如 LifeInsuranceTemplate)
↓
显示动态表单(使用 product.plan_config 或配置文件中的默认配置)
↓
用户填写表单
↓
提交 → handlePlanSubmit(formData)
↓
跳转到结果页
🚀 实施步骤
阶段 1:基础架构(2-3天)
-
创建模版配置文件
-
创建
src/config/plan-templates.js - 定义模版映射关系(人寿、重疾产品)
- 添加储蓄型产品配置(GS/GC/FA/LV2)
- 编写模版配置文档
-
创建
-
创建通用表单字段组件
-
AgePicker.vue- 年龄选择器 -
AmountInput.vue- 保额输入 -
DatePicker.vue- 日期选择器 -
RadioGroup.vue- 单选组 -
SelectPicker.vue- 下拉选择
-
-
创建计划书 API
-
创建
src/api/plan.js - 定义提交计划书 API 接口
-
创建
阶段 2:模版组件(2-3天)
-
创建具体模版组件
-
LifeInsuranceTemplate.vue- 人寿保险模版 -
CriticalIllnessTemplate.vue- 重疾保险模版 -
SavingsTemplate.vue- 储蓄型产品模版(GS/GC/FA/LV2)
-
-
创建表单容器
-
PlanFormContainer.vue- 动态模版容器
-
-
创建提取计划组件(储蓄产品专用)
-
WithdrawalPlanSelector.vue- 主选择器 -
SpecifiedAmountForm.vue- 年龄指定金额表单 -
FixedAmountForm.vue- 最高固定金额表单 -
CurrencySelector.vue- 币种选择器
-
阶段 3:集成测试(1-2天)
-
修改首页
-
集成
PlanFormContainer - 传递产品对象
-
集成
-
修改产品详情页
- 添加"计划书"按钮
-
集成
PlanFormContainer
-
测试
- 测试不同产品的模版加载
- 测试表单验证
- 测试提交流程
📝 API 接口设计
1. 获取产品详情(已存在,包含 form_sn)
请求:
GET /srv/?a=get_product&t=detail&i=1
返回:
{
"code": 1,
"msg": "success",
"data": {
"id": 1,
"product_name": "WIOP3E 盈传创富保障计划 3 - 优选版",
"form_sn": "life-insurance-wiop3e", // ✅ 已有字段,用于指定模版
// 可选:如果需要动态配置模版参数
"plan_config": {
"currency": "USD",
"payment_periods": [
"整付(0-75 岁)",
"5 年(0-70 岁)",
"10 年(0-70 岁)"
],
"age_range": { "min": 0, "max": 75 },
"insurance_period": "终身"
},
// ... 其他现有字段
}
}
2. 提交计划书(新增)
请求:
POST /srv/?a=submit_plan
{
"product_id": 1,
"template": "life-insurance-wiop3e",
"form_data": {
"gender": "男",
"age": 18,
"birthday": "1990-01-01",
"smoker": "否",
"coverage": 100000, // 单位:分
"payment_period": "10 年(0-70 岁)"
}
}
返回:
{
"code": 1,
"msg": "提交成功",
"data": {
"plan_id": 123,
"status": "processing", // processing | generated
"estimated_time": 300 // 预计生成时间(秒)
}
}
✅ 验收标准
- 用户点击产品"计划书"按钮,自动显示对应的模版
- 年龄选择器显示3位数字,提交时转换为数字
- 保额输入支持不同币种,保留2位小数
- 日期选择器限制年龄范围
- 缴费年期选项完整,key 和 value 相同
- 表单验证正常,必填项有提示
- 提交成功后跳转到结果页
- 支持扩展新产品模版(无需修改代码)
📚 参考文档
💡 未来扩展
-
CMS 后台管理:
- 通过后台管理产品和模版的映射关系
- 动态配置表单字段
- 无需修改代码即可新增模版
-
表单字段扩展:
- 支持更多字段类型(多选、文件上传等)
- 支持字段联动(如年龄变化影响保额范围)
- 支持条件显示(如某些产品显示特定字段)
-
预览功能:
- 实时预览计划书
- 保存草稿功能
- 历史记录查看
-
批量生成:
- 支持批量导入客户信息
- 批量生成计划书
- 导出为 Excel/PDF
文档版本: v1.0 创建时间: 2026-02-06 最后更新: 2026-02-06