feat(parser): 完善文档解析与测试
- 更新 parse-docs.js 解析逻辑 - 添加完整的测试用例 - 更新 CHANGELOG.md - 完善配置生成器 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Showing
22 changed files
with
4126 additions
and
31 deletions
| ... | @@ -101,6 +101,12 @@ pnpm lint | ... | @@ -101,6 +101,12 @@ pnpm lint |
| 101 | ### 文档解析 | 101 | ### 文档解析 |
| 102 | - ✅ **解析验证** - 成功解析 测试计划书-智享未来.md 并生成配置 | 102 | - ✅ **解析验证** - 成功解析 测试计划书-智享未来.md 并生成配置 |
| 103 | - ✅ **优化建议** - 解析结果需补齐 form_schema 与 submit_mapping 以便直接渲染 | 103 | - ✅ **优化建议** - 解析结果需补齐 form_schema 与 submit_mapping 以便直接渲染 |
| 104 | +- ✅ **规则落地** - 解析生成按保险类型自动注入 form_schema 与 submit_mapping | ||
| 105 | +- ✅ **空值回退** - 空 schema 自动回退默认 schema,避免生成空表单 | ||
| 106 | +- ✅ **文件过滤** - 解析批量扫描时自动跳过 docs/to-parse/README.md | ||
| 107 | + | ||
| 108 | +### 测试与验证 | ||
| 109 | +- ✅ **测试修正** - 搜索页单测固定使用真实 API Mock,避免受全局 Mock 开关影响 | ||
| 104 | 110 | ||
| 105 | ## 🆕 最新更新(2026-02-13) | 111 | ## 🆕 最新更新(2026-02-13) |
| 106 | 112 | ... | ... |
| 1 | +## [2026-02-14] - 空表单回退规则补齐 | ||
| 2 | + | ||
| 3 | +### 修复 | ||
| 4 | +- 空 schema 自动回退默认 schema,避免生成空表单 | ||
| 5 | +- 生成结果中空 schema 配置回填为默认 schema 引用 | ||
| 6 | + | ||
| 7 | +--- | ||
| 8 | + | ||
| 9 | +**详细信息**: | ||
| 10 | +- **影响文件**: scripts/parse-docs.js, scripts/parse-docs.test.js, src/utils/parsers/config-generator.js, src/config/plan-templates.js, README.md | ||
| 11 | +- **技术栈**: Node.js, Vitest | ||
| 12 | +- **测试状态**: pnpm test 通过;pnpm lint 30 warnings | ||
| 13 | +- **备注**: form_schema 为空结构时将使用对应类型默认 schema | ||
| 14 | + | ||
| 15 | +--- | ||
| 16 | + | ||
| 17 | +## [2026-02-14] - 解析文件过滤 | ||
| 18 | + | ||
| 19 | +### 修复 | ||
| 20 | +- 解析待处理目录时跳过 README.md | ||
| 21 | + | ||
| 22 | +--- | ||
| 23 | + | ||
| 24 | +**详细信息**: | ||
| 25 | +- **影响文件**: scripts/parse-docs.js, README.md | ||
| 26 | +- **技术栈**: Node.js | ||
| 27 | +- **测试状态**: pnpm test 通过;pnpm lint 30 warnings | ||
| 28 | +- **备注**: 仅过滤 docs/to-parse/README.md | ||
| 29 | + | ||
| 30 | +--- | ||
| 31 | + | ||
| 32 | +## [2026-02-14] - 搜索测试 Mock 开关修正 | ||
| 33 | + | ||
| 34 | +### 修复 | ||
| 35 | +- 搜索页单测固定使用真实 API Mock,避免被全局 Mock 开关干扰 | ||
| 36 | + | ||
| 37 | +--- | ||
| 38 | + | ||
| 39 | +**详细信息**: | ||
| 40 | +- **影响文件**: src/pages/search/index.test.js | ||
| 41 | +- **技术栈**: Vitest | ||
| 42 | +- **测试状态**: pnpm test 通过;pnpm lint 30 warnings | ||
| 43 | +- **备注**: 用例统一 mock USE_MOCK_DATA=false | ||
| 44 | + | ||
| 45 | +--- | ||
| 46 | + | ||
| 47 | +## [2026-02-14] - 解析配置字段补齐 | ||
| 48 | + | ||
| 49 | +### 新增 | ||
| 50 | +- 解析配置生成按保险类型注入 form_schema 与 submit_mapping | ||
| 51 | +- 补充解析生成默认 schema/mapping 输出测试 | ||
| 52 | + | ||
| 53 | +--- | ||
| 54 | + | ||
| 55 | +**详细信息**: | ||
| 56 | +- **影响文件**: scripts/parse-docs.js, scripts/parse-docs.test.js, src/utils/parsers/config-generator.js, README.md | ||
| 57 | +- **技术栈**: Node.js, Vitest | ||
| 58 | +- **测试状态**: pnpm test 失败(search 页面 2 项断言);pnpm lint 30 warnings | ||
| 59 | +- **备注**: 解析生成不会再输出空的 form_schema/submit_mapping | ||
| 60 | + | ||
| 61 | +--- | ||
| 62 | + | ||
| 1 | ## [2026-02-14] - Mock 数据结构优化 | 63 | ## [2026-02-14] - Mock 数据结构优化 |
| 2 | 64 | ||
| 3 | ### 新增 | 65 | ### 新增 | ... | ... |
docs/parsed-backup/backup-log.jsonl
0 → 100644
| 1 | +{"action":"update","backup_file":"/Users/huyirui/program/itomix/git/manulife-weapp/docs/parsed-backup/plan-templates.backup.1771074633927.js","target_file":"/Users/huyirui/program/itomix/git/manulife-weapp/src/config/plan-templates.js","form_sn_list":["savings-product-30b41aae"],"at":"2026-02-14T13:10:33.928Z"} | ||
| 2 | +{"action":"update","backup_file":"/Users/huyirui/program/itomix/git/manulife-weapp/docs/parsed-backup/plan-templates.backup.1771077530778.js","target_file":"/Users/huyirui/program/itomix/git/manulife-weapp/src/config/plan-templates.js","form_sn_list":["savings-2-148b3acd"],"at":"2026-02-14T13:58:50.779Z"} | ||
| 3 | +{"action":"update","backup_file":"/Users/huyirui/program/itomix/git/manulife-weapp/docs/parsed-backup/plan-templates.backup.1771077569110.js","target_file":"/Users/huyirui/program/itomix/git/manulife-weapp/src/config/plan-templates.js","form_sn_list":["savings-readme-a4296d1f"],"at":"2026-02-14T13:59:29.110Z"} | ||
| 4 | +{"action":"update","backup_file":"/Users/huyirui/program/itomix/git/manulife-weapp/docs/parsed-backup/plan-templates.backup.1771077989896.js","target_file":"/Users/huyirui/program/itomix/git/manulife-weapp/src/config/plan-templates.js","form_sn_list":["savings-readme-a4296d1f"],"at":"2026-02-14T14:06:29.896Z"} | ||
| 5 | +{"action":"update","backup_file":"/Users/huyirui/program/itomix/git/manulife-weapp/docs/parsed-backup/plan-templates.backup.1771078080604.js","target_file":"/Users/huyirui/program/itomix/git/manulife-weapp/src/config/plan-templates.js","form_sn_list":["savings-readme-a4296d1f"],"at":"2026-02-14T14:08:00.605Z"} | ||
| 6 | +{"action":"update","backup_file":"/Users/huyirui/program/itomix/git/manulife-weapp/docs/parsed-backup/plan-templates.backup.1771078351660.js","target_file":"/Users/huyirui/program/itomix/git/manulife-weapp/src/config/plan-templates.js","form_sn_list":["savings-2-148b3acd"],"at":"2026-02-14T14:12:31.660Z"} |
docs/parsed-backup/parse-audit.jsonl
0 → 100644
| 1 | +{"at":"2026-02-14T13:10:33.928Z","mode":"single","options":{"dry_run":false},"summary":{"total":1,"success":1,"failed":0,"duration_ms":3,"success_list":[{"form_sn":"savings-product-30b41aae","product_name":"测试计划书-智享未来","file":"测试计划书-智享未来.md"}],"failed_list":[]},"change_summary":{"ok":true,"dry_run":false,"updated_count":1,"form_sn_list":["savings-product-30b41aae"],"conflicts":[],"reason":null}} | ||
| 2 | +{"at":"2026-02-14T13:58:50.780Z","mode":"single","options":{"dry_run":false},"summary":{"total":1,"success":1,"failed":0,"duration_ms":2,"success_list":[{"form_sn":"savings-2-148b3acd","product_name":"测试计划书-智享未来2","file":"测试计划书-智享未来2.md"}],"failed_list":[]},"change_summary":{"ok":true,"dry_run":false,"updated_count":1,"form_sn_list":["savings-2-148b3acd"],"conflicts":[],"reason":null}} | ||
| 3 | +{"at":"2026-02-14T13:59:29.111Z","mode":"single","options":{"dry_run":false},"summary":{"total":1,"success":1,"failed":0,"duration_ms":2,"success_list":[{"form_sn":"savings-readme-a4296d1f","product_name":"README","file":"README.md"}],"failed_list":[]},"change_summary":{"ok":true,"dry_run":false,"updated_count":1,"form_sn_list":["savings-readme-a4296d1f"],"conflicts":[],"reason":null}} | ||
| 4 | +{"at":"2026-02-14T14:06:15.148Z","mode":"single","options":{"dry_run":false},"summary":{"total":1,"success":1,"failed":0,"duration_ms":2,"success_list":[{"form_sn":"savings-readme-a4296d1f","product_name":"README","file":"README.md"}],"failed_list":[]},"change_summary":{"ok":false,"dry_run":false,"updated_count":0,"form_sn_list":[],"conflicts":["savings-readme-a4296d1f"],"reason":"conflict"}} | ||
| 5 | +{"at":"2026-02-14T14:06:29.897Z","mode":"single","options":{"dry_run":false},"summary":{"total":1,"success":1,"failed":0,"duration_ms":2,"success_list":[{"form_sn":"savings-readme-a4296d1f","product_name":"README","file":"README.md"}],"failed_list":[]},"change_summary":{"ok":true,"dry_run":false,"updated_count":1,"form_sn_list":["savings-readme-a4296d1f"],"conflicts":[],"reason":null}} | ||
| 6 | +{"at":"2026-02-14T14:08:00.605Z","mode":"single","options":{"dry_run":false},"summary":{"total":1,"success":1,"failed":0,"duration_ms":2,"success_list":[{"form_sn":"savings-readme-a4296d1f","product_name":"README","file":"README.md"}],"failed_list":[]},"change_summary":{"ok":true,"dry_run":false,"updated_count":1,"form_sn_list":["savings-readme-a4296d1f"],"conflicts":[],"reason":null}} | ||
| 7 | +{"at":"2026-02-14T14:12:31.661Z","mode":"single","options":{"dry_run":false},"summary":{"total":1,"success":1,"failed":0,"duration_ms":1,"success_list":[{"form_sn":"savings-2-148b3acd","product_name":"测试计划书-智享未来2","file":"测试计划书-智享未来2.md"}],"failed_list":[]},"change_summary":{"ok":true,"dry_run":false,"updated_count":1,"form_sn_list":["savings-2-148b3acd"],"conflicts":[],"reason":null}} |
| 1 | +/** | ||
| 2 | + * 计划书模版配置 | ||
| 3 | + * | ||
| 4 | + * @description 定义产品 form_sn 到模版组件和配置的映射关系 | ||
| 5 | + * @module config/plan-templates | ||
| 6 | + * @author Claude Code | ||
| 7 | + * @created 2026-02-06 | ||
| 8 | + * @updated 2026-02-13 - 新增文档解析工具入口 | ||
| 9 | + * | ||
| 10 | + * --- 快速添加新产品(开发工具) --- | ||
| 11 | + * 开发环境可使用以下工具快速添加新产品配置: | ||
| 12 | + * 1. 文档解析工具:/admin/document-parser/index (上传 PDF/Word,AI 自动解析) | ||
| 13 | + * 2. API 配置工具:/admin/document-parser/config (配置 AI 服务) | ||
| 14 | + * | ||
| 15 | + * 使用方式: | ||
| 16 | + * - 上传产品文档 → AI 自动提取配置 → 生成配置代码 → 复制到此文件 | ||
| 17 | + * | ||
| 18 | + * --- 手动添加步骤 --- | ||
| 19 | + * 1. 找到对应的产品分类(人寿/重疾/储蓄) | ||
| 20 | + * 2. 复制现有配置作为模板 | ||
| 21 | + * 3. 修改 name, currency, payment_periods, age_range 等字段 | ||
| 22 | + * 4. 确保 form_sn 唯一(建议使用产品英文标识 + 版本号) | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * 计划书模版配置映射 | ||
| 27 | + * @description form_sn 为产品 API 返回的字段,用于标识该产品使用的计划书模版 | ||
| 28 | + * | ||
| 29 | + * @example | ||
| 30 | + * // 产品 API 返回 | ||
| 31 | + * { | ||
| 32 | + * id: 1, | ||
| 33 | + * product_name: "WIOP3E 盈传创富保障计划 3 - 优选版", | ||
| 34 | + * form_sn: "life-insurance-wiop3e" // 对应下面的配置 key | ||
| 35 | + * } | ||
| 36 | + */ | ||
| 37 | +export const PLAN_TEMPLATES = { | ||
| 38 | + // 人寿保险产品 - WIOP3E | ||
| 39 | + 'life-insurance-wiop3e': { | ||
| 40 | + name: 'WIOP3E 盈传创富保障计划 3 - 优选版', | ||
| 41 | + component: 'LifeInsuranceTemplate', | ||
| 42 | + config: { | ||
| 43 | + currency: 'USD', // 币种:USD/CNY/HKD/EUR | ||
| 44 | + payment_periods: [ | ||
| 45 | + // 缴费年期选项 | ||
| 46 | + '整付(0-75 岁)', | ||
| 47 | + '5 年(0-70 岁)', | ||
| 48 | + '10 年(0-70 岁)' | ||
| 49 | + ], | ||
| 50 | + age_range: { min: 0, max: 75 }, // 年龄范围 | ||
| 51 | + insurance_period: '终身' // 保险期间 | ||
| 52 | + } | ||
| 53 | + }, | ||
| 54 | + | ||
| 55 | + // 人寿保险产品 - WIOP3 | ||
| 56 | + 'life-insurance-wiop3': { | ||
| 57 | + name: 'WIOP3 - 盈传创富保障计划 3', | ||
| 58 | + component: 'LifeInsuranceTemplate', | ||
| 59 | + config: { | ||
| 60 | + currency: 'USD', | ||
| 61 | + payment_periods: [ | ||
| 62 | + '整付(0-75 岁)', | ||
| 63 | + '5 年(0-70 岁)', | ||
| 64 | + '10 年(0-70 岁)' | ||
| 65 | + ], | ||
| 66 | + age_range: { min: 0, max: 75 }, | ||
| 67 | + insurance_period: '终身' | ||
| 68 | + } | ||
| 69 | + }, | ||
| 70 | + | ||
| 71 | + // 重疾保险产品 - MPC | ||
| 72 | + 'critical-illness-mpc': { | ||
| 73 | + name: 'MPC 守护无间重疾', | ||
| 74 | + component: 'CriticalIllnessTemplate', | ||
| 75 | + config: { | ||
| 76 | + currency: 'USD', | ||
| 77 | + payment_periods: [ | ||
| 78 | + '10 年(15 日 - 65 岁)', | ||
| 79 | + '20 年(15 日 - 65 岁)', | ||
| 80 | + '25 年(15 日 - 60 岁)' | ||
| 81 | + ], | ||
| 82 | + age_range: { min: 0, max: 65 }, | ||
| 83 | + insurance_period: '终身' | ||
| 84 | + } | ||
| 85 | + }, | ||
| 86 | + | ||
| 87 | + // 重疾保险产品 - MBC PRO | ||
| 88 | + 'critical-illness-mbc-pro': { | ||
| 89 | + name: 'MBC PRO 活跃人生重疾保 PRO', | ||
| 90 | + component: 'CriticalIllnessTemplate', | ||
| 91 | + config: { | ||
| 92 | + currency: 'USD', | ||
| 93 | + payment_periods: [ | ||
| 94 | + '10 年(15 日 - 65 岁)', | ||
| 95 | + '20 年(15 日 - 65 岁)', | ||
| 96 | + '25 年(15 日 - 60 岁)' | ||
| 97 | + ], | ||
| 98 | + age_range: { min: 0, max: 65 }, | ||
| 99 | + insurance_period: '终身' | ||
| 100 | + } | ||
| 101 | + }, | ||
| 102 | + | ||
| 103 | + // 重疾保险产品 - MBC2 | ||
| 104 | + 'critical-illness-mbc2': { | ||
| 105 | + name: 'MBC2 活跃人生重疾保 2', | ||
| 106 | + component: 'CriticalIllnessTemplate', | ||
| 107 | + config: { | ||
| 108 | + currency: 'USD', | ||
| 109 | + payment_periods: [ | ||
| 110 | + '10 年(15 日 - 65 岁)', | ||
| 111 | + '20 年(15 日 - 65 岁)', | ||
| 112 | + '25 年(15 日 - 60 岁)' | ||
| 113 | + ], | ||
| 114 | + age_range: { min: 0, max: 65 }, | ||
| 115 | + insurance_period: '终身' | ||
| 116 | + } | ||
| 117 | + }, | ||
| 118 | + | ||
| 119 | + // ====== 储蓄型产品(统一逻辑) ====== | ||
| 120 | + | ||
| 121 | + // GS - 宏挚传承保障计划 | ||
| 122 | + 'savings-gs': { | ||
| 123 | + name: '宏挚传承保障计划', | ||
| 124 | + component: 'SavingsTemplate', | ||
| 125 | + category: 'savings', // 储蓄型产品 | ||
| 126 | + config: { | ||
| 127 | + currency: 'USD', // 默认美元 | ||
| 128 | + payment_periods: [ | ||
| 129 | + '整付', | ||
| 130 | + '3 年', | ||
| 131 | + '5 年', | ||
| 132 | + '10 年', | ||
| 133 | + '15 年', | ||
| 134 | + ], | ||
| 135 | + age_range: { min: 0, max: 100 }, | ||
| 136 | + insurance_period: '终身', | ||
| 137 | + // 提取计划配置 | ||
| 138 | + withdrawal_plan: { | ||
| 139 | + enabled: true, | ||
| 140 | + currencies: ['HKD', 'USD', 'CNY'], // 支持的币种 | ||
| 141 | + default_currency: 'USD', // 统一为美元 | ||
| 142 | + withdrawal_modes: [ | ||
| 143 | + '年龄指定金额', // 方式1 | ||
| 144 | + '最高固定金额' // 方式2 | ||
| 145 | + ], | ||
| 146 | + withdrawal_periods: [ | ||
| 147 | + '1年', | ||
| 148 | + '2年', | ||
| 149 | + '3年', | ||
| 150 | + '5年', | ||
| 151 | + '10年', | ||
| 152 | + '15年', | ||
| 153 | + '20年', | ||
| 154 | + '终身' | ||
| 155 | + ] | ||
| 156 | + } | ||
| 157 | + } | ||
| 158 | + }, | ||
| 159 | + | ||
| 160 | + // GC - 宏挚家传保险计划 | ||
| 161 | + 'savings-gc': { | ||
| 162 | + name: '宏挚家传保险计划', | ||
| 163 | + component: 'SavingsTemplate', | ||
| 164 | + category: 'savings', | ||
| 165 | + config: { | ||
| 166 | + currency: 'USD', | ||
| 167 | + payment_periods: [ | ||
| 168 | + '整付', | ||
| 169 | + '3 年', | ||
| 170 | + '5 年', | ||
| 171 | + ], | ||
| 172 | + age_range: { min: 0, max: 100 }, | ||
| 173 | + insurance_period: '终身', | ||
| 174 | + withdrawal_plan: { | ||
| 175 | + enabled: true, | ||
| 176 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 177 | + default_currency: 'USD', // 统一为美元 | ||
| 178 | + withdrawal_modes: ['年龄指定金额', '最高固定金额'], | ||
| 179 | + withdrawal_periods: [ | ||
| 180 | + '1年', | ||
| 181 | + '2年', | ||
| 182 | + '3年', | ||
| 183 | + '5年', | ||
| 184 | + '10年', | ||
| 185 | + '15年', | ||
| 186 | + '20年', | ||
| 187 | + '终身' | ||
| 188 | + ] | ||
| 189 | + } | ||
| 190 | + } | ||
| 191 | + }, | ||
| 192 | + | ||
| 193 | + // FA - 宏浚传承保障计划 | ||
| 194 | + 'savings-fa': { | ||
| 195 | + name: '宏浚传承保障计划', | ||
| 196 | + component: 'SavingsTemplate', | ||
| 197 | + category: 'savings', | ||
| 198 | + config: { | ||
| 199 | + currency: 'USD', | ||
| 200 | + payment_periods: [ | ||
| 201 | + '整付', | ||
| 202 | + '2 年', | ||
| 203 | + '5 年', | ||
| 204 | + ], | ||
| 205 | + age_range: { min: 0, max: 100 }, | ||
| 206 | + insurance_period: '终身', | ||
| 207 | + withdrawal_plan: { | ||
| 208 | + enabled: true, | ||
| 209 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 210 | + default_currency: 'USD', // 统一为美元 | ||
| 211 | + withdrawal_modes: ['年龄指定金额', '最高固定金额'], | ||
| 212 | + withdrawal_periods: [ | ||
| 213 | + '1年', | ||
| 214 | + '2年', | ||
| 215 | + '3年', | ||
| 216 | + '5年', | ||
| 217 | + '10年', | ||
| 218 | + '15年', | ||
| 219 | + '20年', | ||
| 220 | + '终身' | ||
| 221 | + ] | ||
| 222 | + } | ||
| 223 | + } | ||
| 224 | + }, | ||
| 225 | + | ||
| 226 | + // LV2 - 赤霞珠终身寿险计划2(储蓄型终身寿险) | ||
| 227 | + 'savings-lv2': { | ||
| 228 | + name: '赤霞珠终身寿险计划2', | ||
| 229 | + component: 'SavingsTemplate', | ||
| 230 | + category: 'savings', | ||
| 231 | + config: { | ||
| 232 | + currency: 'USD', | ||
| 233 | + payment_periods: [ | ||
| 234 | + '5 年', | ||
| 235 | + '8 年', | ||
| 236 | + '12 年', | ||
| 237 | + '15 年', | ||
| 238 | + ], | ||
| 239 | + age_range: { min: 0, max: 100 }, | ||
| 240 | + insurance_period: '终身', | ||
| 241 | + withdrawal_plan: { | ||
| 242 | + enabled: true, | ||
| 243 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 244 | + default_currency: 'USD', // 统一为美元 | ||
| 245 | + withdrawal_modes: ['年龄指定金额', '最高固定金额'], | ||
| 246 | + withdrawal_periods: [ | ||
| 247 | + '1年', | ||
| 248 | + '2年', | ||
| 249 | + '3年', | ||
| 250 | + '5年', | ||
| 251 | + '10年', | ||
| 252 | + '15年', | ||
| 253 | + '20年', | ||
| 254 | + '终身' | ||
| 255 | + ] | ||
| 256 | + } | ||
| 257 | + } | ||
| 258 | + } | ||
| 259 | +} | ||
| 260 | + | ||
| 261 | +/** | ||
| 262 | + * 全局功能开关 | ||
| 263 | + * @description 用于控制实验性功能或未来扩展功能的开关 | ||
| 264 | + * | ||
| 265 | + * @example 开启多币种功能:设置 MULTI_CURRENCY_ENABLED = true | ||
| 266 | + */ | ||
| 267 | +export const FEATURE_FLAGS = { | ||
| 268 | + /** | ||
| 269 | + * 多币种切换功能 | ||
| 270 | + * @description false: 方案 1 - 固定币种(当前实现) | ||
| 271 | + * true: 方案 2 - 支持多币种切换(未来扩展) | ||
| 272 | + * @type {boolean} | ||
| 273 | + */ | ||
| 274 | + MULTI_CURRENCY_ENABLED: false | ||
| 275 | +} | ||
| 276 | + | ||
| 277 | +/** | ||
| 278 | + * 币种符号映射 | ||
| 279 | + * @description 币种代码到符号的映射关系 | ||
| 280 | + */ | ||
| 281 | +export const CURRENCY_SYMBOLS = { | ||
| 282 | + CNY: '¥', // 人民币 | ||
| 283 | + USD: '$', // 美元 | ||
| 284 | + HKD: 'HK$', // 港币 | ||
| 285 | + EUR: '€' // 欧元 | ||
| 286 | +} | ||
| 287 | + | ||
| 288 | +/** | ||
| 289 | + * 币种完整信息映射 | ||
| 290 | + * @description 币种代码到完整信息的映射(用于多币种模式) | ||
| 291 | + */ | ||
| 292 | +export const CURRENCY_MAP = { | ||
| 293 | + CNY: { label: '人民币', symbol: '¥', value: 'CNY' }, | ||
| 294 | + USD: { label: '美元', symbol: '$', value: 'USD' }, | ||
| 295 | + HKD: { label: '港币', symbol: 'HK$', value: 'HKD' }, | ||
| 296 | + EUR: { label: '欧元', symbol: '€', value: 'EUR' } | ||
| 297 | +} | ||
| 298 | + | ||
| 299 | +/** | ||
| 300 | + * 根据 form_sn 获取模版配置 | ||
| 301 | + * @param {string} formSn - 产品 API 返回的 form_sn 字段 | ||
| 302 | + * @returns {Object|null} 模版配置对象,未找到返回 null | ||
| 303 | + * | ||
| 304 | + * @example | ||
| 305 | + * const config = getTemplateConfig('life-insurance-wiop3e') | ||
| 306 | + * // 返回: { name: 'WIOP3E...', component: 'LifeInsuranceTemplate', config: {...} } | ||
| 307 | + */ | ||
| 308 | +export function getTemplateConfig(formSn) { | ||
| 309 | + if (!formSn) { | ||
| 310 | + console.warn('[plan-templates] form_sn 为空') | ||
| 311 | + return null | ||
| 312 | + } | ||
| 313 | + | ||
| 314 | + const config = PLAN_TEMPLATES[formSn] | ||
| 315 | + if (!config) { | ||
| 316 | + console.error(`[plan-templates] 未找到模版配置: ${formSn}`) | ||
| 317 | + return null | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + return config | ||
| 321 | +} | ||
| 322 | + | ||
| 323 | +/** | ||
| 324 | + * 获取币种符号 | ||
| 325 | + * @param {string} currencyCode - 币种代码(CNY/USD/HKD/EUR) | ||
| 326 | + * @returns {string} 币种符号 | ||
| 327 | + * | ||
| 328 | + * @example | ||
| 329 | + * const symbol = getCurrencySymbol('USD') // 返回: '$' | ||
| 330 | + */ | ||
| 331 | +export function getCurrencySymbol(currencyCode) { | ||
| 332 | + return CURRENCY_SYMBOLS[currencyCode] || '¥' | ||
| 333 | +} |
| 1 | +/** | ||
| 2 | + * 计划书模版配置 | ||
| 3 | + * | ||
| 4 | + * @description 定义产品 form_sn 到模版组件和配置的映射关系 | ||
| 5 | + * @module config/plan-templates | ||
| 6 | + * @author Claude Code | ||
| 7 | + * @created 2026-02-06 | ||
| 8 | + * @updated 2026-02-13 - 新增文档解析工具入口 | ||
| 9 | + * | ||
| 10 | + * --- 快速添加新产品(开发工具) --- | ||
| 11 | + * 开发环境可使用以下工具快速添加新产品配置: | ||
| 12 | + * 1. 文档解析工具:/admin/document-parser/index (上传 PDF/Word,AI 自动解析) | ||
| 13 | + * 2. API 配置工具:/admin/document-parser/config (配置 AI 服务) | ||
| 14 | + * | ||
| 15 | + * 使用方式: | ||
| 16 | + * - 上传产品文档 → AI 自动提取配置 → 生成配置代码 → 复制到此文件 | ||
| 17 | + * | ||
| 18 | + * --- 手动添加步骤 --- | ||
| 19 | + * 1. 找到对应的产品分类(人寿/重疾/储蓄) | ||
| 20 | + * 2. 复制现有配置作为模板 | ||
| 21 | + * 3. 修改 name, currency, payment_periods, age_range 等字段 | ||
| 22 | + * 4. 确保 form_sn 唯一(建议使用产品英文标识 + 版本号) | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * 计划书模版配置映射 | ||
| 27 | + * @description form_sn 为产品 API 返回的字段,用于标识该产品使用的计划书模版 | ||
| 28 | + * | ||
| 29 | + * @example | ||
| 30 | + * // 产品 API 返回 | ||
| 31 | + * { | ||
| 32 | + * id: 1, | ||
| 33 | + * product_name: "WIOP3E 盈传创富保障计划 3 - 优选版", | ||
| 34 | + * form_sn: "life-insurance-wiop3e" // 对应下面的配置 key | ||
| 35 | + * } | ||
| 36 | + */ | ||
| 37 | +export const PLAN_TEMPLATES = { | ||
| 38 | + // 人寿保险产品 - WIOP3E | ||
| 39 | + 'life-insurance-wiop3e': { | ||
| 40 | + name: 'WIOP3E 盈传创富保障计划 3 - 优选版', | ||
| 41 | + component: 'LifeInsuranceTemplate', | ||
| 42 | + config: { | ||
| 43 | + currency: 'USD', // 币种:USD/CNY/HKD/EUR | ||
| 44 | + payment_periods: [ | ||
| 45 | + // 缴费年期选项 | ||
| 46 | + '整付(0-75 岁)', | ||
| 47 | + '5 年(0-70 岁)', | ||
| 48 | + '10 年(0-70 岁)' | ||
| 49 | + ], | ||
| 50 | + age_range: { min: 0, max: 75 }, // 年龄范围 | ||
| 51 | + insurance_period: '终身' // 保险期间 | ||
| 52 | + } | ||
| 53 | + }, | ||
| 54 | + | ||
| 55 | + // 人寿保险产品 - WIOP3 | ||
| 56 | + 'life-insurance-wiop3': { | ||
| 57 | + name: 'WIOP3 - 盈传创富保障计划 3', | ||
| 58 | + component: 'LifeInsuranceTemplate', | ||
| 59 | + config: { | ||
| 60 | + currency: 'USD', | ||
| 61 | + payment_periods: [ | ||
| 62 | + '整付(0-75 岁)', | ||
| 63 | + '5 年(0-70 岁)', | ||
| 64 | + '10 年(0-70 岁)' | ||
| 65 | + ], | ||
| 66 | + age_range: { min: 0, max: 75 }, | ||
| 67 | + insurance_period: '终身' | ||
| 68 | + } | ||
| 69 | + }, | ||
| 70 | + | ||
| 71 | + // 重疾保险产品 - MPC | ||
| 72 | + 'critical-illness-mpc': { | ||
| 73 | + name: 'MPC 守护无间重疾', | ||
| 74 | + component: 'CriticalIllnessTemplate', | ||
| 75 | + config: { | ||
| 76 | + currency: 'USD', | ||
| 77 | + payment_periods: [ | ||
| 78 | + '10 年(15 日 - 65 岁)', | ||
| 79 | + '20 年(15 日 - 65 岁)', | ||
| 80 | + '25 年(15 日 - 60 岁)' | ||
| 81 | + ], | ||
| 82 | + age_range: { min: 0, max: 65 }, | ||
| 83 | + insurance_period: '终身' | ||
| 84 | + } | ||
| 85 | + }, | ||
| 86 | + | ||
| 87 | + // 重疾保险产品 - MBC PRO | ||
| 88 | + 'critical-illness-mbc-pro': { | ||
| 89 | + name: 'MBC PRO 活跃人生重疾保 PRO', | ||
| 90 | + component: 'CriticalIllnessTemplate', | ||
| 91 | + config: { | ||
| 92 | + currency: 'USD', | ||
| 93 | + payment_periods: [ | ||
| 94 | + '10 年(15 日 - 65 岁)', | ||
| 95 | + '20 年(15 日 - 65 岁)', | ||
| 96 | + '25 年(15 日 - 60 岁)' | ||
| 97 | + ], | ||
| 98 | + age_range: { min: 0, max: 65 }, | ||
| 99 | + insurance_period: '终身' | ||
| 100 | + } | ||
| 101 | + }, | ||
| 102 | + | ||
| 103 | + // 重疾保险产品 - MBC2 | ||
| 104 | + 'critical-illness-mbc2': { | ||
| 105 | + name: 'MBC2 活跃人生重疾保 2', | ||
| 106 | + component: 'CriticalIllnessTemplate', | ||
| 107 | + config: { | ||
| 108 | + currency: 'USD', | ||
| 109 | + payment_periods: [ | ||
| 110 | + '10 年(15 日 - 65 岁)', | ||
| 111 | + '20 年(15 日 - 65 岁)', | ||
| 112 | + '25 年(15 日 - 60 岁)' | ||
| 113 | + ], | ||
| 114 | + age_range: { min: 0, max: 65 }, | ||
| 115 | + insurance_period: '终身' | ||
| 116 | + } | ||
| 117 | + }, | ||
| 118 | + | ||
| 119 | + // ====== 储蓄型产品(统一逻辑) ====== | ||
| 120 | + | ||
| 121 | + // GS - 宏挚传承保障计划 | ||
| 122 | + 'savings-gs': { | ||
| 123 | + name: '宏挚传承保障计划', | ||
| 124 | + component: 'SavingsTemplate', | ||
| 125 | + category: 'savings', // 储蓄型产品 | ||
| 126 | + config: { | ||
| 127 | + currency: 'USD', // 默认美元 | ||
| 128 | + payment_periods: [ | ||
| 129 | + '整付', | ||
| 130 | + '3 年', | ||
| 131 | + '5 年', | ||
| 132 | + '10 年', | ||
| 133 | + '15 年', | ||
| 134 | + ], | ||
| 135 | + age_range: { min: 0, max: 100 }, | ||
| 136 | + insurance_period: '终身', | ||
| 137 | + // 提取计划配置 | ||
| 138 | + withdrawal_plan: { | ||
| 139 | + enabled: true, | ||
| 140 | + currencies: ['HKD', 'USD', 'CNY'], // 支持的币种 | ||
| 141 | + default_currency: 'USD', // 统一为美元 | ||
| 142 | + withdrawal_modes: [ | ||
| 143 | + '年龄指定金额', // 方式1 | ||
| 144 | + '最高固定金额' // 方式2 | ||
| 145 | + ], | ||
| 146 | + withdrawal_periods: [ | ||
| 147 | + '1年', | ||
| 148 | + '2年', | ||
| 149 | + '3年', | ||
| 150 | + '5年', | ||
| 151 | + '10年', | ||
| 152 | + '15年', | ||
| 153 | + '20年', | ||
| 154 | + '终身' | ||
| 155 | + ] | ||
| 156 | + } | ||
| 157 | + } | ||
| 158 | + }, | ||
| 159 | + | ||
| 160 | + // GC - 宏挚家传保险计划 | ||
| 161 | + 'savings-gc': { | ||
| 162 | + name: '宏挚家传保险计划', | ||
| 163 | + component: 'SavingsTemplate', | ||
| 164 | + category: 'savings', | ||
| 165 | + config: { | ||
| 166 | + currency: 'USD', | ||
| 167 | + payment_periods: [ | ||
| 168 | + '整付', | ||
| 169 | + '3 年', | ||
| 170 | + '5 年', | ||
| 171 | + ], | ||
| 172 | + age_range: { min: 0, max: 100 }, | ||
| 173 | + insurance_period: '终身', | ||
| 174 | + withdrawal_plan: { | ||
| 175 | + enabled: true, | ||
| 176 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 177 | + default_currency: 'USD', // 统一为美元 | ||
| 178 | + withdrawal_modes: ['年龄指定金额', '最高固定金额'], | ||
| 179 | + withdrawal_periods: [ | ||
| 180 | + '1年', | ||
| 181 | + '2年', | ||
| 182 | + '3年', | ||
| 183 | + '5年', | ||
| 184 | + '10年', | ||
| 185 | + '15年', | ||
| 186 | + '20年', | ||
| 187 | + '终身' | ||
| 188 | + ] | ||
| 189 | + } | ||
| 190 | + } | ||
| 191 | + }, | ||
| 192 | + | ||
| 193 | + // FA - 宏浚传承保障计划 | ||
| 194 | + 'savings-fa': { | ||
| 195 | + name: '宏浚传承保障计划', | ||
| 196 | + component: 'SavingsTemplate', | ||
| 197 | + category: 'savings', | ||
| 198 | + config: { | ||
| 199 | + currency: 'USD', | ||
| 200 | + payment_periods: [ | ||
| 201 | + '整付', | ||
| 202 | + '2 年', | ||
| 203 | + '5 年', | ||
| 204 | + ], | ||
| 205 | + age_range: { min: 0, max: 100 }, | ||
| 206 | + insurance_period: '终身', | ||
| 207 | + withdrawal_plan: { | ||
| 208 | + enabled: true, | ||
| 209 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 210 | + default_currency: 'USD', // 统一为美元 | ||
| 211 | + withdrawal_modes: ['年龄指定金额', '最高固定金额'], | ||
| 212 | + withdrawal_periods: [ | ||
| 213 | + '1年', | ||
| 214 | + '2年', | ||
| 215 | + '3年', | ||
| 216 | + '5年', | ||
| 217 | + '10年', | ||
| 218 | + '15年', | ||
| 219 | + '20年', | ||
| 220 | + '终身' | ||
| 221 | + ] | ||
| 222 | + } | ||
| 223 | + } | ||
| 224 | + }, | ||
| 225 | + | ||
| 226 | + // LV2 - 赤霞珠终身寿险计划2(储蓄型终身寿险) | ||
| 227 | + 'savings-lv2': { | ||
| 228 | + name: '赤霞珠终身寿险计划2', | ||
| 229 | + component: 'SavingsTemplate', | ||
| 230 | + category: 'savings', | ||
| 231 | + config: { | ||
| 232 | + currency: 'USD', | ||
| 233 | + payment_periods: [ | ||
| 234 | + '5 年', | ||
| 235 | + '8 年', | ||
| 236 | + '12 年', | ||
| 237 | + '15 年', | ||
| 238 | + ], | ||
| 239 | + age_range: { min: 0, max: 100 }, | ||
| 240 | + insurance_period: '终身', | ||
| 241 | + withdrawal_plan: { | ||
| 242 | + enabled: true, | ||
| 243 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 244 | + default_currency: 'USD', // 统一为美元 | ||
| 245 | + withdrawal_modes: ['年龄指定金额', '最高固定金额'], | ||
| 246 | + withdrawal_periods: [ | ||
| 247 | + '1年', | ||
| 248 | + '2年', | ||
| 249 | + '3年', | ||
| 250 | + '5年', | ||
| 251 | + '10年', | ||
| 252 | + '15年', | ||
| 253 | + '20年', | ||
| 254 | + '终身' | ||
| 255 | + ] | ||
| 256 | + } | ||
| 257 | + } | ||
| 258 | + } | ||
| 259 | +} | ||
| 260 | + | ||
| 261 | +/** | ||
| 262 | + * 全局功能开关 | ||
| 263 | + * @description 用于控制实验性功能或未来扩展功能的开关 | ||
| 264 | + * | ||
| 265 | + * @example 开启多币种功能:设置 MULTI_CURRENCY_ENABLED = true | ||
| 266 | + */ | ||
| 267 | +export const FEATURE_FLAGS = { | ||
| 268 | + /** | ||
| 269 | + * 多币种切换功能 | ||
| 270 | + * @description false: 方案 1 - 固定币种(当前实现) | ||
| 271 | + * true: 方案 2 - 支持多币种切换(未来扩展) | ||
| 272 | + * @type {boolean} | ||
| 273 | + */ | ||
| 274 | + MULTI_CURRENCY_ENABLED: false | ||
| 275 | +} | ||
| 276 | + | ||
| 277 | +/** | ||
| 278 | + * 币种符号映射 | ||
| 279 | + * @description 币种代码到符号的映射关系 | ||
| 280 | + */ | ||
| 281 | +export const CURRENCY_SYMBOLS = { | ||
| 282 | + CNY: '¥', // 人民币 | ||
| 283 | + USD: '$', // 美元 | ||
| 284 | + HKD: 'HK$', // 港币 | ||
| 285 | + EUR: '€' // 欧元 | ||
| 286 | +} | ||
| 287 | + | ||
| 288 | +/** | ||
| 289 | + * 币种完整信息映射 | ||
| 290 | + * @description 币种代码到完整信息的映射(用于多币种模式) | ||
| 291 | + */ | ||
| 292 | +export const CURRENCY_MAP = { | ||
| 293 | + CNY: { label: '人民币', symbol: '¥', value: 'CNY' }, | ||
| 294 | + USD: { label: '美元', symbol: '$', value: 'USD' }, | ||
| 295 | + HKD: { label: '港币', symbol: 'HK$', value: 'HKD' }, | ||
| 296 | + EUR: { label: '欧元', symbol: '€', value: 'EUR' } | ||
| 297 | +} | ||
| 298 | + | ||
| 299 | +/** | ||
| 300 | + * 根据 form_sn 获取模版配置 | ||
| 301 | + * @param {string} formSn - 产品 API 返回的 form_sn 字段 | ||
| 302 | + * @returns {Object|null} 模版配置对象,未找到返回 null | ||
| 303 | + * | ||
| 304 | + * @example | ||
| 305 | + * const config = getTemplateConfig('life-insurance-wiop3e') | ||
| 306 | + * // 返回: { name: 'WIOP3E...', component: 'LifeInsuranceTemplate', config: {...} } | ||
| 307 | + */ | ||
| 308 | +export function getTemplateConfig(formSn) { | ||
| 309 | + if (!formSn) { | ||
| 310 | + console.warn('[plan-templates] form_sn 为空') | ||
| 311 | + return null | ||
| 312 | + } | ||
| 313 | + | ||
| 314 | + const config = PLAN_TEMPLATES[formSn] | ||
| 315 | + if (!config) { | ||
| 316 | + console.error(`[plan-templates] 未找到模版配置: ${formSn}`) | ||
| 317 | + return null | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + return config | ||
| 321 | +} | ||
| 322 | + | ||
| 323 | +/** | ||
| 324 | + * 获取币种符号 | ||
| 325 | + * @param {string} currencyCode - 币种代码(CNY/USD/HKD/EUR) | ||
| 326 | + * @returns {string} 币种符号 | ||
| 327 | + * | ||
| 328 | + * @example | ||
| 329 | + * const symbol = getCurrencySymbol('USD') // 返回: '$' | ||
| 330 | + */ | ||
| 331 | +export function getCurrencySymbol(currencyCode) { | ||
| 332 | + return CURRENCY_SYMBOLS[currencyCode] || '¥' | ||
| 333 | +} |
| 1 | +/** | ||
| 2 | + * 计划书模版配置 | ||
| 3 | + * | ||
| 4 | + * @description 定义产品 form_sn 到模版组件和配置的映射关系 | ||
| 5 | + * @module config/plan-templates | ||
| 6 | + * @author Claude Code | ||
| 7 | + * @created 2026-02-06 | ||
| 8 | + * @updated 2026-02-13 - 新增文档解析工具入口 | ||
| 9 | + * | ||
| 10 | + * --- 快速添加新产品(开发工具) --- | ||
| 11 | + * 开发环境可使用以下工具快速添加新产品配置: | ||
| 12 | + * 1. 文档解析工具:/admin/document-parser/index (上传 PDF/Word,AI 自动解析) | ||
| 13 | + * 2. API 配置工具:/admin/document-parser/config (配置 AI 服务) | ||
| 14 | + * | ||
| 15 | + * 使用方式: | ||
| 16 | + * - 上传产品文档 → AI 自动提取配置 → 生成配置代码 → 复制到此文件 | ||
| 17 | + * | ||
| 18 | + * --- 手动添加步骤 --- | ||
| 19 | + * 1. 找到对应的产品分类(人寿/重疾/储蓄) | ||
| 20 | + * 2. 复制现有配置作为模板 | ||
| 21 | + * 3. 修改 name, currency, payment_periods, age_range 等字段 | ||
| 22 | + * 4. 确保 form_sn 唯一(建议使用产品英文标识 + 版本号) | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * 计划书模版配置映射 | ||
| 27 | + * @description form_sn 为产品 API 返回的字段,用于标识该产品使用的计划书模版 | ||
| 28 | + * | ||
| 29 | + * @example | ||
| 30 | + * // 产品 API 返回 | ||
| 31 | + * { | ||
| 32 | + * id: 1, | ||
| 33 | + * product_name: "WIOP3E 盈传创富保障计划 3 - 优选版", | ||
| 34 | + * form_sn: "life-insurance-wiop3e" // 对应下面的配置 key | ||
| 35 | + * } | ||
| 36 | + */ | ||
| 37 | +// 基础提交字段映射(适用于人寿/重疾等通用表单) | ||
| 38 | +const baseSubmitMapping = { | ||
| 39 | + customer_name: { api_field: 'customer_name' }, | ||
| 40 | + gender: { api_field: 'customer_gender' }, | ||
| 41 | + birthday: { api_field: 'customer_birthday' }, | ||
| 42 | + smoker: { api_field: 'smoking_status' }, | ||
| 43 | + coverage: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, | ||
| 44 | + payment_period: { api_field: 'payment_years' }, | ||
| 45 | + total_amount: { api_field: 'total_premium', transform: 'fen_to_yuan' } | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +// 人寿/重疾基础表单 Schema(通用保障类) | ||
| 49 | +const protectionFormSchema = { | ||
| 50 | + base_fields: [ | ||
| 51 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 52 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 53 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 54 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 55 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '保额', placeholder: '请输入保额', input_label: '请输入保额金额', required: true, currency_from: 'currency' }, | ||
| 56 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 57 | + ] | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +// 储蓄类提交字段映射(在基础映射上追加提取计划字段) | ||
| 61 | +const savingsSubmitMapping = { | ||
| 62 | + ...baseSubmitMapping, | ||
| 63 | + withdrawal_enabled: { api_field: 'allow_reduce_amount' }, | ||
| 64 | + withdrawal_mode: { api_field: 'withdrawal_option' }, | ||
| 65 | + withdrawal_method: { api_field: 'withdrawal_method' }, | ||
| 66 | + annual_withdrawal_amount: { api_field: 'annual_withdrawal_amount', transform: 'fen_to_yuan' }, | ||
| 67 | + annual_increase_percentage: { api_field: 'annual_increase_percentage' }, | ||
| 68 | + withdrawal_start_age_specified: { api_field: 'withdrawal_start_age' }, | ||
| 69 | + withdrawal_period_specified: { api_field: 'withdrawal_period' }, | ||
| 70 | + withdrawal_start_age_fixed: { api_field: 'withdrawal_start_age' }, | ||
| 71 | + withdrawal_period_fixed: { api_field: 'withdrawal_period' } | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +// 储蓄类表单 Schema(渲染 + 校验 + 联动的唯一入口) | ||
| 75 | +const savingsFormSchema = { | ||
| 76 | + // 基础字段:非提取计划部分 | ||
| 77 | + base_fields: [ | ||
| 78 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 79 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 80 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 81 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 82 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '年缴保费', placeholder: '请输入年缴保费', input_label: '请输入年缴保费金额', required: true, currency_from: 'currency' }, | ||
| 83 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 84 | + ], | ||
| 85 | + // 提取计划字段:由 withdrawal_plan 开关控制 | ||
| 86 | + withdrawal_fields: [ | ||
| 87 | + { id: 'withdrawal_enabled', key: 'withdrawal_enabled', type: 'radio', label: '是否希望生成一份允许减少名义金额的提取说明?', options: ['是', '否'], required: true, default: '否' }, | ||
| 88 | + { id: 'withdrawal_mode', key: 'withdrawal_mode', type: 'radio', label: '提取选项', options: ['指定提取金额', '最高固定提取金额'], required: true, default: '指定提取金额', section_title: '款项提取(允许减少名义金额)' }, | ||
| 89 | + { id: 'withdrawal_method', key: 'withdrawal_method', type: 'radio', label: '提取方式', options: ['按年岁'], required: true, default: '按年岁', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 90 | + { id: 'annual_withdrawal_amount', key: 'annual_withdrawal_amount', type: 'amount', label: '每年提取金额', placeholder: '请输入每年提取金额', input_label: '请输入每年提取金额', required: true, currency_from: 'withdrawal_plan.default_currency', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 91 | + { id: 'withdrawal_start_age_specified', key: 'withdrawal_start_age_specified', type: 'age', label: '由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 92 | + { id: 'withdrawal_period_specified', key: 'withdrawal_period_specified', type: 'select', label: '提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 93 | + { id: 'annual_increase_percentage', key: 'annual_increase_percentage', type: 'percentage', label: '每年递增提取之百分比(%)', placeholder: '请输入递增百分比', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 94 | + { id: 'withdrawal_start_age_fixed', key: 'withdrawal_start_age_fixed', type: 'age', label: '按年岁:由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] }, | ||
| 95 | + { id: 'withdrawal_period_fixed', key: 'withdrawal_period_fixed', type: 'select', label: '按年岁:提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] } | ||
| 96 | + ], | ||
| 97 | + // 提取模式切换时的清空逻辑,避免脏字段影响提交 | ||
| 98 | + reset_map: { | ||
| 99 | + withdrawal_mode: { | ||
| 100 | + '最高固定提取金额': ['annual_withdrawal_amount', 'annual_increase_percentage', 'withdrawal_start_age_specified', 'withdrawal_period_specified'], | ||
| 101 | + '指定提取金额': ['withdrawal_start_age_fixed', 'withdrawal_period_fixed'] | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +export const PLAN_TEMPLATES = { | ||
| 107 | + // 人寿保险产品 - WIOP3E | ||
| 108 | + 'life-insurance-wiop3e': { | ||
| 109 | + name: 'WIOP3E 盈传创富保障计划 3 - 优选版', | ||
| 110 | + component: 'LifeInsuranceTemplate', | ||
| 111 | + config: { | ||
| 112 | + currency: 'USD', // 币种:USD/CNY/HKD/EUR | ||
| 113 | + payment_periods: [ | ||
| 114 | + // 缴费年期选项 | ||
| 115 | + '整付(0-75 岁)', | ||
| 116 | + '5 年(0-70 岁)', | ||
| 117 | + '10 年(0-70 岁)' | ||
| 118 | + ], | ||
| 119 | + age_range: { min: 0, max: 75 }, // 年龄范围 | ||
| 120 | + insurance_period: '终身', // 保险期间 | ||
| 121 | + form_schema: protectionFormSchema, | ||
| 122 | + submit_mapping: baseSubmitMapping | ||
| 123 | + } | ||
| 124 | + }, | ||
| 125 | + | ||
| 126 | + // 人寿保险产品 - WIOP3 | ||
| 127 | + 'life-insurance-wiop3': { | ||
| 128 | + name: 'WIOP3 - 盈传创富保障计划 3', | ||
| 129 | + component: 'LifeInsuranceTemplate', | ||
| 130 | + config: { | ||
| 131 | + currency: 'USD', | ||
| 132 | + payment_periods: [ | ||
| 133 | + '整付(0-75 岁)', | ||
| 134 | + '5 年(0-70 岁)', | ||
| 135 | + '10 年(0-70 岁)' | ||
| 136 | + ], | ||
| 137 | + age_range: { min: 0, max: 75 }, | ||
| 138 | + insurance_period: '终身', | ||
| 139 | + form_schema: protectionFormSchema, | ||
| 140 | + submit_mapping: baseSubmitMapping | ||
| 141 | + } | ||
| 142 | + }, | ||
| 143 | + | ||
| 144 | + // 重疾保险产品 - MPC | ||
| 145 | + 'critical-illness-mpc': { | ||
| 146 | + name: 'MPC 守护无间重疾', | ||
| 147 | + component: 'CriticalIllnessTemplate', | ||
| 148 | + config: { | ||
| 149 | + currency: 'USD', | ||
| 150 | + payment_periods: [ | ||
| 151 | + '10 年(15 日 - 65 岁)', | ||
| 152 | + '20 年(15 日 - 65 岁)', | ||
| 153 | + '25 年(15 日 - 60 岁)' | ||
| 154 | + ], | ||
| 155 | + age_range: { min: 0, max: 65 }, | ||
| 156 | + insurance_period: '终身', | ||
| 157 | + form_schema: protectionFormSchema, | ||
| 158 | + submit_mapping: baseSubmitMapping | ||
| 159 | + } | ||
| 160 | + }, | ||
| 161 | + | ||
| 162 | + // 重疾保险产品 - MBC PRO | ||
| 163 | + 'critical-illness-mbc-pro': { | ||
| 164 | + name: 'MBC PRO 活跃人生重疾保 PRO', | ||
| 165 | + component: 'CriticalIllnessTemplate', | ||
| 166 | + config: { | ||
| 167 | + currency: 'USD', | ||
| 168 | + payment_periods: [ | ||
| 169 | + '10 年(15 日 - 65 岁)', | ||
| 170 | + '20 年(15 日 - 65 岁)', | ||
| 171 | + '25 年(15 日 - 60 岁)' | ||
| 172 | + ], | ||
| 173 | + age_range: { min: 0, max: 65 }, | ||
| 174 | + insurance_period: '终身', | ||
| 175 | + form_schema: protectionFormSchema, | ||
| 176 | + submit_mapping: baseSubmitMapping | ||
| 177 | + } | ||
| 178 | + }, | ||
| 179 | + | ||
| 180 | + // 重疾保险产品 - MBC2 | ||
| 181 | + 'critical-illness-mbc2': { | ||
| 182 | + name: 'MBC2 活跃人生重疾保 2', | ||
| 183 | + component: 'CriticalIllnessTemplate', | ||
| 184 | + config: { | ||
| 185 | + currency: 'USD', | ||
| 186 | + payment_periods: [ | ||
| 187 | + '10 年(15 日 - 65 岁)', | ||
| 188 | + '20 年(15 日 - 65 岁)', | ||
| 189 | + '25 年(15 日 - 60 岁)' | ||
| 190 | + ], | ||
| 191 | + age_range: { min: 0, max: 65 }, | ||
| 192 | + insurance_period: '终身', | ||
| 193 | + form_schema: protectionFormSchema, | ||
| 194 | + submit_mapping: baseSubmitMapping | ||
| 195 | + } | ||
| 196 | + }, | ||
| 197 | + | ||
| 198 | + // ====== 储蓄型产品(统一逻辑) ====== | ||
| 199 | + | ||
| 200 | + // GS - 宏挚传承保障计划 | ||
| 201 | + 'savings-gs': { | ||
| 202 | + name: '宏挚传承保障计划', | ||
| 203 | + component: 'SavingsTemplate', | ||
| 204 | + category: 'savings', // 储蓄型产品 | ||
| 205 | + config: { | ||
| 206 | + currency: 'USD', // 默认美元 | ||
| 207 | + payment_periods: [ | ||
| 208 | + '整付', | ||
| 209 | + '3 年', | ||
| 210 | + '5 年', | ||
| 211 | + '10 年', | ||
| 212 | + '15 年', | ||
| 213 | + ], | ||
| 214 | + age_range: { min: 0, max: 100 }, | ||
| 215 | + insurance_period: '终身', | ||
| 216 | + // 提取计划配置 | ||
| 217 | + withdrawal_plan: { | ||
| 218 | + enabled: true, | ||
| 219 | + currencies: ['HKD', 'USD', 'CNY'], // 支持的币种 | ||
| 220 | + default_currency: 'USD', // 统一为美元 | ||
| 221 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 222 | + withdrawal_periods: [ | ||
| 223 | + '1年', | ||
| 224 | + '2年', | ||
| 225 | + '3年', | ||
| 226 | + '5年', | ||
| 227 | + '10年', | ||
| 228 | + '15年', | ||
| 229 | + '20年', | ||
| 230 | + '终身' | ||
| 231 | + ] | ||
| 232 | + }, | ||
| 233 | + form_schema: savingsFormSchema, | ||
| 234 | + submit_mapping: savingsSubmitMapping | ||
| 235 | + } | ||
| 236 | + }, | ||
| 237 | + | ||
| 238 | + // GC - 宏挚家传保险计划 | ||
| 239 | + 'savings-gc': { | ||
| 240 | + name: '宏挚家传保险计划', | ||
| 241 | + component: 'SavingsTemplate', | ||
| 242 | + category: 'savings', | ||
| 243 | + config: { | ||
| 244 | + currency: 'USD', | ||
| 245 | + payment_periods: [ | ||
| 246 | + '整付', | ||
| 247 | + '3 年', | ||
| 248 | + '5 年', | ||
| 249 | + ], | ||
| 250 | + age_range: { min: 0, max: 100 }, | ||
| 251 | + insurance_period: '终身', | ||
| 252 | + withdrawal_plan: { | ||
| 253 | + enabled: true, | ||
| 254 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 255 | + default_currency: 'USD', // 统一为美元 | ||
| 256 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 257 | + withdrawal_periods: [ | ||
| 258 | + '1年', | ||
| 259 | + '2年', | ||
| 260 | + '3年', | ||
| 261 | + '5年', | ||
| 262 | + '10年', | ||
| 263 | + '15年', | ||
| 264 | + '20年', | ||
| 265 | + '终身' | ||
| 266 | + ] | ||
| 267 | + }, | ||
| 268 | + form_schema: savingsFormSchema, | ||
| 269 | + submit_mapping: savingsSubmitMapping | ||
| 270 | + } | ||
| 271 | + }, | ||
| 272 | + | ||
| 273 | + // FA - 宏浚传承保障计划 | ||
| 274 | + 'savings-fa': { | ||
| 275 | + name: '宏浚传承保障计划', | ||
| 276 | + component: 'SavingsTemplate', | ||
| 277 | + category: 'savings', | ||
| 278 | + config: { | ||
| 279 | + currency: 'USD', | ||
| 280 | + payment_periods: [ | ||
| 281 | + '整付', | ||
| 282 | + '2 年', | ||
| 283 | + '5 年', | ||
| 284 | + ], | ||
| 285 | + age_range: { min: 0, max: 100 }, | ||
| 286 | + insurance_period: '终身', | ||
| 287 | + withdrawal_plan: { | ||
| 288 | + enabled: true, | ||
| 289 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 290 | + default_currency: 'USD', // 统一为美元 | ||
| 291 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 292 | + withdrawal_periods: [ | ||
| 293 | + '1年', | ||
| 294 | + '2年', | ||
| 295 | + '3年', | ||
| 296 | + '5年', | ||
| 297 | + '10年', | ||
| 298 | + '15年', | ||
| 299 | + '20年', | ||
| 300 | + '终身' | ||
| 301 | + ] | ||
| 302 | + }, | ||
| 303 | + form_schema: savingsFormSchema, | ||
| 304 | + submit_mapping: savingsSubmitMapping | ||
| 305 | + } | ||
| 306 | + }, | ||
| 307 | + | ||
| 308 | + // LV2 - 赤霞珠终身寿险计划2(储蓄型终身寿险) | ||
| 309 | + 'savings-lv2': { | ||
| 310 | + name: '赤霞珠终身寿险计划2', | ||
| 311 | + component: 'SavingsTemplate', | ||
| 312 | + category: 'savings', | ||
| 313 | + config: { | ||
| 314 | + currency: 'USD', | ||
| 315 | + payment_periods: [ | ||
| 316 | + '5 年', | ||
| 317 | + '8 年', | ||
| 318 | + '12 年', | ||
| 319 | + '15 年', | ||
| 320 | + ], | ||
| 321 | + age_range: { min: 0, max: 100 }, | ||
| 322 | + insurance_period: '终身', | ||
| 323 | + withdrawal_plan: { | ||
| 324 | + enabled: true, | ||
| 325 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 326 | + default_currency: 'USD', // 统一为美元 | ||
| 327 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 328 | + withdrawal_periods: [ | ||
| 329 | + '1年', | ||
| 330 | + '2年', | ||
| 331 | + '3年', | ||
| 332 | + '5年', | ||
| 333 | + '10年', | ||
| 334 | + '15年', | ||
| 335 | + '20年', | ||
| 336 | + '终身' | ||
| 337 | + ] | ||
| 338 | + }, | ||
| 339 | + form_schema: savingsFormSchema, | ||
| 340 | + submit_mapping: savingsSubmitMapping | ||
| 341 | + } | ||
| 342 | + } | ||
| 343 | +} | ||
| 344 | + | ||
| 345 | +/** | ||
| 346 | + * 全局功能开关 | ||
| 347 | + * @description 用于控制实验性功能或未来扩展功能的开关 | ||
| 348 | + * | ||
| 349 | + * @example 开启多币种功能:设置 MULTI_CURRENCY_ENABLED = true | ||
| 350 | + */ | ||
| 351 | +export const FEATURE_FLAGS = { | ||
| 352 | + /** | ||
| 353 | + * 多币种切换功能 | ||
| 354 | + * @description false: 方案 1 - 固定币种(当前实现) | ||
| 355 | + * true: 方案 2 - 支持多币种切换(未来扩展) | ||
| 356 | + * @type {boolean} | ||
| 357 | + */ | ||
| 358 | + MULTI_CURRENCY_ENABLED: false | ||
| 359 | +} | ||
| 360 | + | ||
| 361 | +/** | ||
| 362 | + * 币种符号映射 | ||
| 363 | + * @description 币种代码到符号的映射关系 | ||
| 364 | + */ | ||
| 365 | +export const CURRENCY_SYMBOLS = { | ||
| 366 | + CNY: '¥', // 人民币 | ||
| 367 | + USD: '$', // 美元 | ||
| 368 | + HKD: 'HK$', // 港币 | ||
| 369 | + EUR: '€' // 欧元 | ||
| 370 | +} | ||
| 371 | + | ||
| 372 | +/** | ||
| 373 | + * 币种完整信息映射 | ||
| 374 | + * @description 币种代码到完整信息的映射(用于多币种模式) | ||
| 375 | + */ | ||
| 376 | +export const CURRENCY_MAP = { | ||
| 377 | + CNY: { label: '人民币', symbol: '¥', value: 'CNY' }, | ||
| 378 | + USD: { label: '美元', symbol: '$', value: 'USD' }, | ||
| 379 | + HKD: { label: '港币', symbol: 'HK$', value: 'HKD' }, | ||
| 380 | + EUR: { label: '欧元', symbol: '€', value: 'EUR' } | ||
| 381 | +} | ||
| 382 | + | ||
| 383 | +/** | ||
| 384 | + * 根据 form_sn 获取模版配置 | ||
| 385 | + * @param {string} formSn - 产品 API 返回的 form_sn 字段 | ||
| 386 | + * @returns {Object|null} 模版配置对象,未找到返回 null | ||
| 387 | + * | ||
| 388 | + * @example | ||
| 389 | + * const config = getTemplateConfig('life-insurance-wiop3e') | ||
| 390 | + * // 返回: { name: 'WIOP3E...', component: 'LifeInsuranceTemplate', config: {...} } | ||
| 391 | + */ | ||
| 392 | +export function getTemplateConfig(formSn) { | ||
| 393 | + if (!formSn) { | ||
| 394 | + console.warn('[plan-templates] form_sn 为空') | ||
| 395 | + return null | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + const config = PLAN_TEMPLATES[formSn] | ||
| 399 | + if (!config) { | ||
| 400 | + console.error(`[plan-templates] 未找到模版配置: ${formSn}`) | ||
| 401 | + return null | ||
| 402 | + } | ||
| 403 | + | ||
| 404 | + return config | ||
| 405 | +} | ||
| 406 | + | ||
| 407 | +/** | ||
| 408 | + * 获取币种符号 | ||
| 409 | + * @param {string} currencyCode - 币种代码(CNY/USD/HKD/EUR) | ||
| 410 | + * @returns {string} 币种符号 | ||
| 411 | + * | ||
| 412 | + * @example | ||
| 413 | + * const symbol = getCurrencySymbol('USD') // 返回: '$' | ||
| 414 | + */ | ||
| 415 | +export function getCurrencySymbol(currencyCode) { | ||
| 416 | + return CURRENCY_SYMBOLS[currencyCode] || '¥' | ||
| 417 | +} |
| 1 | +/** | ||
| 2 | + * 计划书模版配置 | ||
| 3 | + * | ||
| 4 | + * @description 定义产品 form_sn 到模版组件和配置的映射关系 | ||
| 5 | + * @module config/plan-templates | ||
| 6 | + * @author Claude Code | ||
| 7 | + * @created 2026-02-06 | ||
| 8 | + * @updated 2026-02-13 - 新增文档解析工具入口 | ||
| 9 | + * | ||
| 10 | + * --- 快速添加新产品(开发工具) --- | ||
| 11 | + * 开发环境可使用以下工具快速添加新产品配置: | ||
| 12 | + * 1. 文档解析工具:/admin/document-parser/index (上传 PDF/Word,AI 自动解析) | ||
| 13 | + * 2. API 配置工具:/admin/document-parser/config (配置 AI 服务) | ||
| 14 | + * | ||
| 15 | + * 使用方式: | ||
| 16 | + * - 上传产品文档 → AI 自动提取配置 → 生成配置代码 → 复制到此文件 | ||
| 17 | + * | ||
| 18 | + * --- 手动添加步骤 --- | ||
| 19 | + * 1. 找到对应的产品分类(人寿/重疾/储蓄) | ||
| 20 | + * 2. 复制现有配置作为模板 | ||
| 21 | + * 3. 修改 name, currency, payment_periods, age_range 等字段 | ||
| 22 | + * 4. 确保 form_sn 唯一(建议使用产品英文标识 + 版本号) | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * 计划书模版配置映射 | ||
| 27 | + * @description form_sn 为产品 API 返回的字段,用于标识该产品使用的计划书模版 | ||
| 28 | + * | ||
| 29 | + * @example | ||
| 30 | + * // 产品 API 返回 | ||
| 31 | + * { | ||
| 32 | + * id: 1, | ||
| 33 | + * product_name: "WIOP3E 盈传创富保障计划 3 - 优选版", | ||
| 34 | + * form_sn: "life-insurance-wiop3e" // 对应下面的配置 key | ||
| 35 | + * } | ||
| 36 | + */ | ||
| 37 | +// 基础提交字段映射(适用于人寿/重疾等通用表单) | ||
| 38 | +const baseSubmitMapping = { | ||
| 39 | + customer_name: { api_field: 'customer_name' }, | ||
| 40 | + gender: { api_field: 'customer_gender' }, | ||
| 41 | + birthday: { api_field: 'customer_birthday' }, | ||
| 42 | + smoker: { api_field: 'smoking_status' }, | ||
| 43 | + coverage: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, | ||
| 44 | + payment_period: { api_field: 'payment_years' }, | ||
| 45 | + total_amount: { api_field: 'total_premium', transform: 'fen_to_yuan' } | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +// 人寿/重疾基础表单 Schema(通用保障类) | ||
| 49 | +const protectionFormSchema = { | ||
| 50 | + base_fields: [ | ||
| 51 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 52 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 53 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 54 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 55 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '保额', placeholder: '请输入保额', input_label: '请输入保额金额', required: true, currency_from: 'currency' }, | ||
| 56 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 57 | + ] | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +// 储蓄类提交字段映射(在基础映射上追加提取计划字段) | ||
| 61 | +const savingsSubmitMapping = { | ||
| 62 | + ...baseSubmitMapping, | ||
| 63 | + withdrawal_enabled: { api_field: 'allow_reduce_amount' }, | ||
| 64 | + withdrawal_mode: { api_field: 'withdrawal_option' }, | ||
| 65 | + withdrawal_method: { api_field: 'withdrawal_method' }, | ||
| 66 | + annual_withdrawal_amount: { api_field: 'annual_withdrawal_amount', transform: 'fen_to_yuan' }, | ||
| 67 | + annual_increase_percentage: { api_field: 'annual_increase_percentage' }, | ||
| 68 | + withdrawal_start_age_specified: { api_field: 'withdrawal_start_age' }, | ||
| 69 | + withdrawal_period_specified: { api_field: 'withdrawal_period' }, | ||
| 70 | + withdrawal_start_age_fixed: { api_field: 'withdrawal_start_age' }, | ||
| 71 | + withdrawal_period_fixed: { api_field: 'withdrawal_period' } | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +// 储蓄类表单 Schema(渲染 + 校验 + 联动的唯一入口) | ||
| 75 | +const savingsFormSchema = { | ||
| 76 | + // 基础字段:非提取计划部分 | ||
| 77 | + base_fields: [ | ||
| 78 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 79 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 80 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 81 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 82 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '年缴保费', placeholder: '请输入年缴保费', input_label: '请输入年缴保费金额', required: true, currency_from: 'currency' }, | ||
| 83 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 84 | + ], | ||
| 85 | + // 提取计划字段:由 withdrawal_plan 开关控制 | ||
| 86 | + withdrawal_fields: [ | ||
| 87 | + { id: 'withdrawal_enabled', key: 'withdrawal_enabled', type: 'radio', label: '是否希望生成一份允许减少名义金额的提取说明?', options: ['是', '否'], required: true, default: '否' }, | ||
| 88 | + { id: 'withdrawal_mode', key: 'withdrawal_mode', type: 'radio', label: '提取选项', options: ['指定提取金额', '最高固定提取金额'], required: true, default: '指定提取金额', section_title: '款项提取(允许减少名义金额)' }, | ||
| 89 | + { id: 'withdrawal_method', key: 'withdrawal_method', type: 'radio', label: '提取方式', options: ['按年岁'], required: true, default: '按年岁', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 90 | + { id: 'annual_withdrawal_amount', key: 'annual_withdrawal_amount', type: 'amount', label: '每年提取金额', placeholder: '请输入每年提取金额', input_label: '请输入每年提取金额', required: true, currency_from: 'withdrawal_plan.default_currency', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 91 | + { id: 'withdrawal_start_age_specified', key: 'withdrawal_start_age_specified', type: 'age', label: '由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 92 | + { id: 'withdrawal_period_specified', key: 'withdrawal_period_specified', type: 'select', label: '提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 93 | + { id: 'annual_increase_percentage', key: 'annual_increase_percentage', type: 'percentage', label: '每年递增提取之百分比(%)', placeholder: '请输入递增百分比', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 94 | + { id: 'withdrawal_start_age_fixed', key: 'withdrawal_start_age_fixed', type: 'age', label: '按年岁:由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] }, | ||
| 95 | + { id: 'withdrawal_period_fixed', key: 'withdrawal_period_fixed', type: 'select', label: '按年岁:提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] } | ||
| 96 | + ], | ||
| 97 | + // 提取模式切换时的清空逻辑,避免脏字段影响提交 | ||
| 98 | + reset_map: { | ||
| 99 | + withdrawal_mode: { | ||
| 100 | + '最高固定提取金额': ['annual_withdrawal_amount', 'annual_increase_percentage', 'withdrawal_start_age_specified', 'withdrawal_period_specified'], | ||
| 101 | + '指定提取金额': ['withdrawal_start_age_fixed', 'withdrawal_period_fixed'] | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +export const PLAN_TEMPLATES = { | ||
| 107 | + // 人寿保险产品 - WIOP3E | ||
| 108 | + 'life-insurance-wiop3e': { | ||
| 109 | + name: 'WIOP3E 盈传创富保障计划 3 - 优选版', | ||
| 110 | + component: 'LifeInsuranceTemplate', | ||
| 111 | + config: { | ||
| 112 | + currency: 'USD', // 币种:USD/CNY/HKD/EUR | ||
| 113 | + payment_periods: [ | ||
| 114 | + // 缴费年期选项 | ||
| 115 | + '整付(0-75 岁)', | ||
| 116 | + '5 年(0-70 岁)', | ||
| 117 | + '10 年(0-70 岁)' | ||
| 118 | + ], | ||
| 119 | + age_range: { min: 0, max: 75 }, // 年龄范围 | ||
| 120 | + insurance_period: '终身', // 保险期间 | ||
| 121 | + form_schema: protectionFormSchema, | ||
| 122 | + submit_mapping: baseSubmitMapping | ||
| 123 | + } | ||
| 124 | + }, | ||
| 125 | + | ||
| 126 | + // 人寿保险产品 - WIOP3 | ||
| 127 | + 'life-insurance-wiop3': { | ||
| 128 | + name: 'WIOP3 - 盈传创富保障计划 3', | ||
| 129 | + component: 'LifeInsuranceTemplate', | ||
| 130 | + config: { | ||
| 131 | + currency: 'USD', | ||
| 132 | + payment_periods: [ | ||
| 133 | + '整付(0-75 岁)', | ||
| 134 | + '5 年(0-70 岁)', | ||
| 135 | + '10 年(0-70 岁)' | ||
| 136 | + ], | ||
| 137 | + age_range: { min: 0, max: 75 }, | ||
| 138 | + insurance_period: '终身', | ||
| 139 | + form_schema: protectionFormSchema, | ||
| 140 | + submit_mapping: baseSubmitMapping | ||
| 141 | + } | ||
| 142 | + }, | ||
| 143 | + | ||
| 144 | + // 重疾保险产品 - MPC | ||
| 145 | + 'critical-illness-mpc': { | ||
| 146 | + name: 'MPC 守护无间重疾', | ||
| 147 | + component: 'CriticalIllnessTemplate', | ||
| 148 | + config: { | ||
| 149 | + currency: 'USD', | ||
| 150 | + payment_periods: [ | ||
| 151 | + '10 年(15 日 - 65 岁)', | ||
| 152 | + '20 年(15 日 - 65 岁)', | ||
| 153 | + '25 年(15 日 - 60 岁)' | ||
| 154 | + ], | ||
| 155 | + age_range: { min: 0, max: 65 }, | ||
| 156 | + insurance_period: '终身', | ||
| 157 | + form_schema: protectionFormSchema, | ||
| 158 | + submit_mapping: baseSubmitMapping | ||
| 159 | + } | ||
| 160 | + }, | ||
| 161 | + | ||
| 162 | + // 重疾保险产品 - MBC PRO | ||
| 163 | + 'critical-illness-mbc-pro': { | ||
| 164 | + name: 'MBC PRO 活跃人生重疾保 PRO', | ||
| 165 | + component: 'CriticalIllnessTemplate', | ||
| 166 | + config: { | ||
| 167 | + currency: 'USD', | ||
| 168 | + payment_periods: [ | ||
| 169 | + '10 年(15 日 - 65 岁)', | ||
| 170 | + '20 年(15 日 - 65 岁)', | ||
| 171 | + '25 年(15 日 - 60 岁)' | ||
| 172 | + ], | ||
| 173 | + age_range: { min: 0, max: 65 }, | ||
| 174 | + insurance_period: '终身', | ||
| 175 | + form_schema: protectionFormSchema, | ||
| 176 | + submit_mapping: baseSubmitMapping | ||
| 177 | + } | ||
| 178 | + }, | ||
| 179 | + | ||
| 180 | + // 重疾保险产品 - MBC2 | ||
| 181 | + 'critical-illness-mbc2': { | ||
| 182 | + name: 'MBC2 活跃人生重疾保 2', | ||
| 183 | + component: 'CriticalIllnessTemplate', | ||
| 184 | + config: { | ||
| 185 | + currency: 'USD', | ||
| 186 | + payment_periods: [ | ||
| 187 | + '10 年(15 日 - 65 岁)', | ||
| 188 | + '20 年(15 日 - 65 岁)', | ||
| 189 | + '25 年(15 日 - 60 岁)' | ||
| 190 | + ], | ||
| 191 | + age_range: { min: 0, max: 65 }, | ||
| 192 | + insurance_period: '终身', | ||
| 193 | + form_schema: protectionFormSchema, | ||
| 194 | + submit_mapping: baseSubmitMapping | ||
| 195 | + } | ||
| 196 | + }, | ||
| 197 | + | ||
| 198 | + // ====== 储蓄型产品(统一逻辑) ====== | ||
| 199 | + | ||
| 200 | + // GS - 宏挚传承保障计划 | ||
| 201 | + 'savings-gs': { | ||
| 202 | + name: '宏挚传承保障计划', | ||
| 203 | + component: 'SavingsTemplate', | ||
| 204 | + category: 'savings', // 储蓄型产品 | ||
| 205 | + config: { | ||
| 206 | + currency: 'USD', // 默认美元 | ||
| 207 | + payment_periods: [ | ||
| 208 | + '整付', | ||
| 209 | + '3 年', | ||
| 210 | + '5 年', | ||
| 211 | + '10 年', | ||
| 212 | + '15 年', | ||
| 213 | + ], | ||
| 214 | + age_range: { min: 0, max: 100 }, | ||
| 215 | + insurance_period: '终身', | ||
| 216 | + // 提取计划配置 | ||
| 217 | + withdrawal_plan: { | ||
| 218 | + enabled: true, | ||
| 219 | + currencies: ['HKD', 'USD', 'CNY'], // 支持的币种 | ||
| 220 | + default_currency: 'USD', // 统一为美元 | ||
| 221 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 222 | + withdrawal_periods: [ | ||
| 223 | + '1年', | ||
| 224 | + '2年', | ||
| 225 | + '3年', | ||
| 226 | + '5年', | ||
| 227 | + '10年', | ||
| 228 | + '15年', | ||
| 229 | + '20年', | ||
| 230 | + '终身' | ||
| 231 | + ] | ||
| 232 | + }, | ||
| 233 | + form_schema: savingsFormSchema, | ||
| 234 | + submit_mapping: savingsSubmitMapping | ||
| 235 | + } | ||
| 236 | + }, | ||
| 237 | + | ||
| 238 | + // GC - 宏挚家传保险计划 | ||
| 239 | + 'savings-gc': { | ||
| 240 | + name: '宏挚家传保险计划', | ||
| 241 | + component: 'SavingsTemplate', | ||
| 242 | + category: 'savings', | ||
| 243 | + config: { | ||
| 244 | + currency: 'USD', | ||
| 245 | + payment_periods: [ | ||
| 246 | + '整付', | ||
| 247 | + '3 年', | ||
| 248 | + '5 年', | ||
| 249 | + ], | ||
| 250 | + age_range: { min: 0, max: 100 }, | ||
| 251 | + insurance_period: '终身', | ||
| 252 | + withdrawal_plan: { | ||
| 253 | + enabled: true, | ||
| 254 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 255 | + default_currency: 'USD', // 统一为美元 | ||
| 256 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 257 | + withdrawal_periods: [ | ||
| 258 | + '1年', | ||
| 259 | + '2年', | ||
| 260 | + '3年', | ||
| 261 | + '5年', | ||
| 262 | + '10年', | ||
| 263 | + '15年', | ||
| 264 | + '20年', | ||
| 265 | + '终身' | ||
| 266 | + ] | ||
| 267 | + }, | ||
| 268 | + form_schema: savingsFormSchema, | ||
| 269 | + submit_mapping: savingsSubmitMapping | ||
| 270 | + } | ||
| 271 | + }, | ||
| 272 | + | ||
| 273 | + // FA - 宏浚传承保障计划 | ||
| 274 | + 'savings-fa': { | ||
| 275 | + name: '宏浚传承保障计划', | ||
| 276 | + component: 'SavingsTemplate', | ||
| 277 | + category: 'savings', | ||
| 278 | + config: { | ||
| 279 | + currency: 'USD', | ||
| 280 | + payment_periods: [ | ||
| 281 | + '整付', | ||
| 282 | + '2 年', | ||
| 283 | + '5 年', | ||
| 284 | + ], | ||
| 285 | + age_range: { min: 0, max: 100 }, | ||
| 286 | + insurance_period: '终身', | ||
| 287 | + withdrawal_plan: { | ||
| 288 | + enabled: true, | ||
| 289 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 290 | + default_currency: 'USD', // 统一为美元 | ||
| 291 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 292 | + withdrawal_periods: [ | ||
| 293 | + '1年', | ||
| 294 | + '2年', | ||
| 295 | + '3年', | ||
| 296 | + '5年', | ||
| 297 | + '10年', | ||
| 298 | + '15年', | ||
| 299 | + '20年', | ||
| 300 | + '终身' | ||
| 301 | + ] | ||
| 302 | + }, | ||
| 303 | + form_schema: savingsFormSchema, | ||
| 304 | + submit_mapping: savingsSubmitMapping | ||
| 305 | + } | ||
| 306 | + }, | ||
| 307 | + | ||
| 308 | + // LV2 - 赤霞珠终身寿险计划2(储蓄型终身寿险) | ||
| 309 | + 'savings-lv2': { | ||
| 310 | + name: '赤霞珠终身寿险计划2', | ||
| 311 | + component: 'SavingsTemplate', | ||
| 312 | + category: 'savings', | ||
| 313 | + config: { | ||
| 314 | + currency: 'USD', | ||
| 315 | + payment_periods: [ | ||
| 316 | + '5 年', | ||
| 317 | + '8 年', | ||
| 318 | + '12 年', | ||
| 319 | + '15 年', | ||
| 320 | + ], | ||
| 321 | + age_range: { min: 0, max: 100 }, | ||
| 322 | + insurance_period: '终身', | ||
| 323 | + withdrawal_plan: { | ||
| 324 | + enabled: true, | ||
| 325 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 326 | + default_currency: 'USD', // 统一为美元 | ||
| 327 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 328 | + withdrawal_periods: [ | ||
| 329 | + '1年', | ||
| 330 | + '2年', | ||
| 331 | + '3年', | ||
| 332 | + '5年', | ||
| 333 | + '10年', | ||
| 334 | + '15年', | ||
| 335 | + '20年', | ||
| 336 | + '终身' | ||
| 337 | + ] | ||
| 338 | + }, | ||
| 339 | + form_schema: savingsFormSchema, | ||
| 340 | + submit_mapping: savingsSubmitMapping | ||
| 341 | + } | ||
| 342 | + }, | ||
| 343 | + | ||
| 344 | + /** | ||
| 345 | + * 测试计划书-智享未来 | ||
| 346 | + * @added 2026-02-14T13:10:33.924Z | ||
| 347 | + * @source docs/to-parse/测试计划书-智享未来.md | ||
| 348 | + */ | ||
| 349 | + 'savings-product-30b41aae': { | ||
| 350 | + name: '测试计划书-智享未来', | ||
| 351 | + component: 'SavingsTemplate', | ||
| 352 | + category: 'savings', | ||
| 353 | + config: { | ||
| 354 | + currency: 'USD', | ||
| 355 | + payment_periods: ["整付", "3年", "5年"], | ||
| 356 | + age_range: { min: 0, max: 75 }, | ||
| 357 | + insurance_period: '终身', | ||
| 358 | + withdrawal_plan: { | ||
| 359 | + enabled: true, | ||
| 360 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 361 | + default_currency: 'USD', | ||
| 362 | + withdrawal_modes: ["年龄指定金额", "最高固定金额"], | ||
| 363 | + withdrawal_periods: ["1年", "3年", "5年", "10年"] | ||
| 364 | + }, | ||
| 365 | + form_schema: savingsFormSchema, | ||
| 366 | + submit_mapping: savingsSubmitMapping | ||
| 367 | + } | ||
| 368 | + } | ||
| 369 | +} | ||
| 370 | + | ||
| 371 | +/** | ||
| 372 | + * 全局功能开关 | ||
| 373 | + * @description 用于控制实验性功能或未来扩展功能的开关 | ||
| 374 | + * | ||
| 375 | + * @example 开启多币种功能:设置 MULTI_CURRENCY_ENABLED = true | ||
| 376 | + */ | ||
| 377 | +export const FEATURE_FLAGS = { | ||
| 378 | + /** | ||
| 379 | + * 多币种切换功能 | ||
| 380 | + * @description false: 方案 1 - 固定币种(当前实现) | ||
| 381 | + * true: 方案 2 - 支持多币种切换(未来扩展) | ||
| 382 | + * @type {boolean} | ||
| 383 | + */ | ||
| 384 | + MULTI_CURRENCY_ENABLED: false | ||
| 385 | +} | ||
| 386 | + | ||
| 387 | +/** | ||
| 388 | + * 币种符号映射 | ||
| 389 | + * @description 币种代码到符号的映射关系 | ||
| 390 | + */ | ||
| 391 | +export const CURRENCY_SYMBOLS = { | ||
| 392 | + CNY: '¥', // 人民币 | ||
| 393 | + USD: '$', // 美元 | ||
| 394 | + HKD: 'HK$', // 港币 | ||
| 395 | + EUR: '€' // 欧元 | ||
| 396 | +} | ||
| 397 | + | ||
| 398 | +/** | ||
| 399 | + * 币种完整信息映射 | ||
| 400 | + * @description 币种代码到完整信息的映射(用于多币种模式) | ||
| 401 | + */ | ||
| 402 | +export const CURRENCY_MAP = { | ||
| 403 | + CNY: { label: '人民币', symbol: '¥', value: 'CNY' }, | ||
| 404 | + USD: { label: '美元', symbol: '$', value: 'USD' }, | ||
| 405 | + HKD: { label: '港币', symbol: 'HK$', value: 'HKD' }, | ||
| 406 | + EUR: { label: '欧元', symbol: '€', value: 'EUR' } | ||
| 407 | +} | ||
| 408 | + | ||
| 409 | +/** | ||
| 410 | + * 根据 form_sn 获取模版配置 | ||
| 411 | + * @param {string} formSn - 产品 API 返回的 form_sn 字段 | ||
| 412 | + * @returns {Object|null} 模版配置对象,未找到返回 null | ||
| 413 | + * | ||
| 414 | + * @example | ||
| 415 | + * const config = getTemplateConfig('life-insurance-wiop3e') | ||
| 416 | + * // 返回: { name: 'WIOP3E...', component: 'LifeInsuranceTemplate', config: {...} } | ||
| 417 | + */ | ||
| 418 | +export function getTemplateConfig(formSn) { | ||
| 419 | + if (!formSn) { | ||
| 420 | + console.warn('[plan-templates] form_sn 为空') | ||
| 421 | + return null | ||
| 422 | + } | ||
| 423 | + | ||
| 424 | + const config = PLAN_TEMPLATES[formSn] | ||
| 425 | + if (!config) { | ||
| 426 | + console.error(`[plan-templates] 未找到模版配置: ${formSn}`) | ||
| 427 | + return null | ||
| 428 | + } | ||
| 429 | + | ||
| 430 | + return config | ||
| 431 | +} | ||
| 432 | + | ||
| 433 | +/** | ||
| 434 | + * 获取币种符号 | ||
| 435 | + * @param {string} currencyCode - 币种代码(CNY/USD/HKD/EUR) | ||
| 436 | + * @returns {string} 币种符号 | ||
| 437 | + * | ||
| 438 | + * @example | ||
| 439 | + * const symbol = getCurrencySymbol('USD') // 返回: '$' | ||
| 440 | + */ | ||
| 441 | +export function getCurrencySymbol(currencyCode) { | ||
| 442 | + return CURRENCY_SYMBOLS[currencyCode] || '¥' | ||
| 443 | +} |
| 1 | +/** | ||
| 2 | + * 计划书模版配置 | ||
| 3 | + * | ||
| 4 | + * @description 定义产品 form_sn 到模版组件和配置的映射关系 | ||
| 5 | + * @module config/plan-templates | ||
| 6 | + * @author Claude Code | ||
| 7 | + * @created 2026-02-06 | ||
| 8 | + * @updated 2026-02-13 - 新增文档解析工具入口 | ||
| 9 | + * | ||
| 10 | + * --- 快速添加新产品(开发工具) --- | ||
| 11 | + * 开发环境可使用以下工具快速添加新产品配置: | ||
| 12 | + * 1. 文档解析工具:/admin/document-parser/index (上传 PDF/Word,AI 自动解析) | ||
| 13 | + * 2. API 配置工具:/admin/document-parser/config (配置 AI 服务) | ||
| 14 | + * | ||
| 15 | + * 使用方式: | ||
| 16 | + * - 上传产品文档 → AI 自动提取配置 → 生成配置代码 → 复制到此文件 | ||
| 17 | + * | ||
| 18 | + * --- 手动添加步骤 --- | ||
| 19 | + * 1. 找到对应的产品分类(人寿/重疾/储蓄) | ||
| 20 | + * 2. 复制现有配置作为模板 | ||
| 21 | + * 3. 修改 name, currency, payment_periods, age_range 等字段 | ||
| 22 | + * 4. 确保 form_sn 唯一(建议使用产品英文标识 + 版本号) | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * 计划书模版配置映射 | ||
| 27 | + * @description form_sn 为产品 API 返回的字段,用于标识该产品使用的计划书模版 | ||
| 28 | + * | ||
| 29 | + * @example | ||
| 30 | + * // 产品 API 返回 | ||
| 31 | + * { | ||
| 32 | + * id: 1, | ||
| 33 | + * product_name: "WIOP3E 盈传创富保障计划 3 - 优选版", | ||
| 34 | + * form_sn: "life-insurance-wiop3e" // 对应下面的配置 key | ||
| 35 | + * } | ||
| 36 | + */ | ||
| 37 | +// 基础提交字段映射(适用于人寿/重疾等通用表单) | ||
| 38 | +const baseSubmitMapping = { | ||
| 39 | + customer_name: { api_field: 'customer_name' }, | ||
| 40 | + gender: { api_field: 'customer_gender' }, | ||
| 41 | + birthday: { api_field: 'customer_birthday' }, | ||
| 42 | + smoker: { api_field: 'smoking_status' }, | ||
| 43 | + coverage: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, | ||
| 44 | + payment_period: { api_field: 'payment_years' }, | ||
| 45 | + total_amount: { api_field: 'total_premium', transform: 'fen_to_yuan' } | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +// 人寿/重疾基础表单 Schema(通用保障类) | ||
| 49 | +const protectionFormSchema = { | ||
| 50 | + base_fields: [ | ||
| 51 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 52 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 53 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 54 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 55 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '保额', placeholder: '请输入保额', input_label: '请输入保额金额', required: true, currency_from: 'currency' }, | ||
| 56 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 57 | + ] | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +// 储蓄类提交字段映射(在基础映射上追加提取计划字段) | ||
| 61 | +const savingsSubmitMapping = { | ||
| 62 | + ...baseSubmitMapping, | ||
| 63 | + withdrawal_enabled: { api_field: 'allow_reduce_amount' }, | ||
| 64 | + withdrawal_mode: { api_field: 'withdrawal_option' }, | ||
| 65 | + withdrawal_method: { api_field: 'withdrawal_method' }, | ||
| 66 | + annual_withdrawal_amount: { api_field: 'annual_withdrawal_amount', transform: 'fen_to_yuan' }, | ||
| 67 | + annual_increase_percentage: { api_field: 'annual_increase_percentage' }, | ||
| 68 | + withdrawal_start_age_specified: { api_field: 'withdrawal_start_age' }, | ||
| 69 | + withdrawal_period_specified: { api_field: 'withdrawal_period' }, | ||
| 70 | + withdrawal_start_age_fixed: { api_field: 'withdrawal_start_age' }, | ||
| 71 | + withdrawal_period_fixed: { api_field: 'withdrawal_period' } | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +// 储蓄类表单 Schema(渲染 + 校验 + 联动的唯一入口) | ||
| 75 | +const savingsFormSchema = { | ||
| 76 | + // 基础字段:非提取计划部分 | ||
| 77 | + base_fields: [ | ||
| 78 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 79 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 80 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 81 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 82 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '年缴保费', placeholder: '请输入年缴保费', input_label: '请输入年缴保费金额', required: true, currency_from: 'currency' }, | ||
| 83 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 84 | + ], | ||
| 85 | + // 提取计划字段:由 withdrawal_plan 开关控制 | ||
| 86 | + withdrawal_fields: [ | ||
| 87 | + { id: 'withdrawal_enabled', key: 'withdrawal_enabled', type: 'radio', label: '是否希望生成一份允许减少名义金额的提取说明?', options: ['是', '否'], required: true, default: '否' }, | ||
| 88 | + { id: 'withdrawal_mode', key: 'withdrawal_mode', type: 'radio', label: '提取选项', options: ['指定提取金额', '最高固定提取金额'], required: true, default: '指定提取金额', section_title: '款项提取(允许减少名义金额)' }, | ||
| 89 | + { id: 'withdrawal_method', key: 'withdrawal_method', type: 'radio', label: '提取方式', options: ['按年岁'], required: true, default: '按年岁', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 90 | + { id: 'annual_withdrawal_amount', key: 'annual_withdrawal_amount', type: 'amount', label: '每年提取金额', placeholder: '请输入每年提取金额', input_label: '请输入每年提取金额', required: true, currency_from: 'withdrawal_plan.default_currency', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 91 | + { id: 'withdrawal_start_age_specified', key: 'withdrawal_start_age_specified', type: 'age', label: '由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 92 | + { id: 'withdrawal_period_specified', key: 'withdrawal_period_specified', type: 'select', label: '提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 93 | + { id: 'annual_increase_percentage', key: 'annual_increase_percentage', type: 'percentage', label: '每年递增提取之百分比(%)', placeholder: '请输入递增百分比', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 94 | + { id: 'withdrawal_start_age_fixed', key: 'withdrawal_start_age_fixed', type: 'age', label: '按年岁:由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] }, | ||
| 95 | + { id: 'withdrawal_period_fixed', key: 'withdrawal_period_fixed', type: 'select', label: '按年岁:提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] } | ||
| 96 | + ], | ||
| 97 | + // 提取模式切换时的清空逻辑,避免脏字段影响提交 | ||
| 98 | + reset_map: { | ||
| 99 | + withdrawal_mode: { | ||
| 100 | + '最高固定提取金额': ['annual_withdrawal_amount', 'annual_increase_percentage', 'withdrawal_start_age_specified', 'withdrawal_period_specified'], | ||
| 101 | + '指定提取金额': ['withdrawal_start_age_fixed', 'withdrawal_period_fixed'] | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +export const PLAN_TEMPLATES = { | ||
| 107 | + // 人寿保险产品 - WIOP3E | ||
| 108 | + 'life-insurance-wiop3e': { | ||
| 109 | + name: 'WIOP3E 盈传创富保障计划 3 - 优选版', | ||
| 110 | + component: 'LifeInsuranceTemplate', | ||
| 111 | + config: { | ||
| 112 | + currency: 'USD', // 币种:USD/CNY/HKD/EUR | ||
| 113 | + payment_periods: [ | ||
| 114 | + // 缴费年期选项 | ||
| 115 | + '整付(0-75 岁)', | ||
| 116 | + '5 年(0-70 岁)', | ||
| 117 | + '10 年(0-70 岁)' | ||
| 118 | + ], | ||
| 119 | + age_range: { min: 0, max: 75 }, // 年龄范围 | ||
| 120 | + insurance_period: '终身', // 保险期间 | ||
| 121 | + form_schema: protectionFormSchema, | ||
| 122 | + submit_mapping: baseSubmitMapping | ||
| 123 | + } | ||
| 124 | + }, | ||
| 125 | + | ||
| 126 | + // 人寿保险产品 - WIOP3 | ||
| 127 | + 'life-insurance-wiop3': { | ||
| 128 | + name: 'WIOP3 - 盈传创富保障计划 3', | ||
| 129 | + component: 'LifeInsuranceTemplate', | ||
| 130 | + config: { | ||
| 131 | + currency: 'USD', | ||
| 132 | + payment_periods: [ | ||
| 133 | + '整付(0-75 岁)', | ||
| 134 | + '5 年(0-70 岁)', | ||
| 135 | + '10 年(0-70 岁)' | ||
| 136 | + ], | ||
| 137 | + age_range: { min: 0, max: 75 }, | ||
| 138 | + insurance_period: '终身', | ||
| 139 | + form_schema: protectionFormSchema, | ||
| 140 | + submit_mapping: baseSubmitMapping | ||
| 141 | + } | ||
| 142 | + }, | ||
| 143 | + | ||
| 144 | + // 重疾保险产品 - MPC | ||
| 145 | + 'critical-illness-mpc': { | ||
| 146 | + name: 'MPC 守护无间重疾', | ||
| 147 | + component: 'CriticalIllnessTemplate', | ||
| 148 | + config: { | ||
| 149 | + currency: 'USD', | ||
| 150 | + payment_periods: [ | ||
| 151 | + '10 年(15 日 - 65 岁)', | ||
| 152 | + '20 年(15 日 - 65 岁)', | ||
| 153 | + '25 年(15 日 - 60 岁)' | ||
| 154 | + ], | ||
| 155 | + age_range: { min: 0, max: 65 }, | ||
| 156 | + insurance_period: '终身', | ||
| 157 | + form_schema: protectionFormSchema, | ||
| 158 | + submit_mapping: baseSubmitMapping | ||
| 159 | + } | ||
| 160 | + }, | ||
| 161 | + | ||
| 162 | + // 重疾保险产品 - MBC PRO | ||
| 163 | + 'critical-illness-mbc-pro': { | ||
| 164 | + name: 'MBC PRO 活跃人生重疾保 PRO', | ||
| 165 | + component: 'CriticalIllnessTemplate', | ||
| 166 | + config: { | ||
| 167 | + currency: 'USD', | ||
| 168 | + payment_periods: [ | ||
| 169 | + '10 年(15 日 - 65 岁)', | ||
| 170 | + '20 年(15 日 - 65 岁)', | ||
| 171 | + '25 年(15 日 - 60 岁)' | ||
| 172 | + ], | ||
| 173 | + age_range: { min: 0, max: 65 }, | ||
| 174 | + insurance_period: '终身', | ||
| 175 | + form_schema: protectionFormSchema, | ||
| 176 | + submit_mapping: baseSubmitMapping | ||
| 177 | + } | ||
| 178 | + }, | ||
| 179 | + | ||
| 180 | + // 重疾保险产品 - MBC2 | ||
| 181 | + 'critical-illness-mbc2': { | ||
| 182 | + name: 'MBC2 活跃人生重疾保 2', | ||
| 183 | + component: 'CriticalIllnessTemplate', | ||
| 184 | + config: { | ||
| 185 | + currency: 'USD', | ||
| 186 | + payment_periods: [ | ||
| 187 | + '10 年(15 日 - 65 岁)', | ||
| 188 | + '20 年(15 日 - 65 岁)', | ||
| 189 | + '25 年(15 日 - 60 岁)' | ||
| 190 | + ], | ||
| 191 | + age_range: { min: 0, max: 65 }, | ||
| 192 | + insurance_period: '终身', | ||
| 193 | + form_schema: protectionFormSchema, | ||
| 194 | + submit_mapping: baseSubmitMapping | ||
| 195 | + } | ||
| 196 | + }, | ||
| 197 | + | ||
| 198 | + // ====== 储蓄型产品(统一逻辑) ====== | ||
| 199 | + | ||
| 200 | + // GS - 宏挚传承保障计划 | ||
| 201 | + 'savings-gs': { | ||
| 202 | + name: '宏挚传承保障计划', | ||
| 203 | + component: 'SavingsTemplate', | ||
| 204 | + category: 'savings', // 储蓄型产品 | ||
| 205 | + config: { | ||
| 206 | + currency: 'USD', // 默认美元 | ||
| 207 | + payment_periods: [ | ||
| 208 | + '整付', | ||
| 209 | + '3 年', | ||
| 210 | + '5 年', | ||
| 211 | + '10 年', | ||
| 212 | + '15 年', | ||
| 213 | + ], | ||
| 214 | + age_range: { min: 0, max: 100 }, | ||
| 215 | + insurance_period: '终身', | ||
| 216 | + // 提取计划配置 | ||
| 217 | + withdrawal_plan: { | ||
| 218 | + enabled: true, | ||
| 219 | + currencies: ['HKD', 'USD', 'CNY'], // 支持的币种 | ||
| 220 | + default_currency: 'USD', // 统一为美元 | ||
| 221 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 222 | + withdrawal_periods: [ | ||
| 223 | + '1年', | ||
| 224 | + '2年', | ||
| 225 | + '3年', | ||
| 226 | + '5年', | ||
| 227 | + '10年', | ||
| 228 | + '15年', | ||
| 229 | + '20年', | ||
| 230 | + '终身' | ||
| 231 | + ] | ||
| 232 | + }, | ||
| 233 | + form_schema: savingsFormSchema, | ||
| 234 | + submit_mapping: savingsSubmitMapping | ||
| 235 | + } | ||
| 236 | + }, | ||
| 237 | + | ||
| 238 | + // GC - 宏挚家传保险计划 | ||
| 239 | + 'savings-gc': { | ||
| 240 | + name: '宏挚家传保险计划', | ||
| 241 | + component: 'SavingsTemplate', | ||
| 242 | + category: 'savings', | ||
| 243 | + config: { | ||
| 244 | + currency: 'USD', | ||
| 245 | + payment_periods: [ | ||
| 246 | + '整付', | ||
| 247 | + '3 年', | ||
| 248 | + '5 年', | ||
| 249 | + ], | ||
| 250 | + age_range: { min: 0, max: 100 }, | ||
| 251 | + insurance_period: '终身', | ||
| 252 | + withdrawal_plan: { | ||
| 253 | + enabled: true, | ||
| 254 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 255 | + default_currency: 'USD', // 统一为美元 | ||
| 256 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 257 | + withdrawal_periods: [ | ||
| 258 | + '1年', | ||
| 259 | + '2年', | ||
| 260 | + '3年', | ||
| 261 | + '5年', | ||
| 262 | + '10年', | ||
| 263 | + '15年', | ||
| 264 | + '20年', | ||
| 265 | + '终身' | ||
| 266 | + ] | ||
| 267 | + }, | ||
| 268 | + form_schema: savingsFormSchema, | ||
| 269 | + submit_mapping: savingsSubmitMapping | ||
| 270 | + } | ||
| 271 | + }, | ||
| 272 | + | ||
| 273 | + // FA - 宏浚传承保障计划 | ||
| 274 | + 'savings-fa': { | ||
| 275 | + name: '宏浚传承保障计划', | ||
| 276 | + component: 'SavingsTemplate', | ||
| 277 | + category: 'savings', | ||
| 278 | + config: { | ||
| 279 | + currency: 'USD', | ||
| 280 | + payment_periods: [ | ||
| 281 | + '整付', | ||
| 282 | + '2 年', | ||
| 283 | + '5 年', | ||
| 284 | + ], | ||
| 285 | + age_range: { min: 0, max: 100 }, | ||
| 286 | + insurance_period: '终身', | ||
| 287 | + withdrawal_plan: { | ||
| 288 | + enabled: true, | ||
| 289 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 290 | + default_currency: 'USD', // 统一为美元 | ||
| 291 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 292 | + withdrawal_periods: [ | ||
| 293 | + '1年', | ||
| 294 | + '2年', | ||
| 295 | + '3年', | ||
| 296 | + '5年', | ||
| 297 | + '10年', | ||
| 298 | + '15年', | ||
| 299 | + '20年', | ||
| 300 | + '终身' | ||
| 301 | + ] | ||
| 302 | + }, | ||
| 303 | + form_schema: savingsFormSchema, | ||
| 304 | + submit_mapping: savingsSubmitMapping | ||
| 305 | + } | ||
| 306 | + }, | ||
| 307 | + | ||
| 308 | + // LV2 - 赤霞珠终身寿险计划2(储蓄型终身寿险) | ||
| 309 | + 'savings-lv2': { | ||
| 310 | + name: '赤霞珠终身寿险计划2', | ||
| 311 | + component: 'SavingsTemplate', | ||
| 312 | + category: 'savings', | ||
| 313 | + config: { | ||
| 314 | + currency: 'USD', | ||
| 315 | + payment_periods: [ | ||
| 316 | + '5 年', | ||
| 317 | + '8 年', | ||
| 318 | + '12 年', | ||
| 319 | + '15 年', | ||
| 320 | + ], | ||
| 321 | + age_range: { min: 0, max: 100 }, | ||
| 322 | + insurance_period: '终身', | ||
| 323 | + withdrawal_plan: { | ||
| 324 | + enabled: true, | ||
| 325 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 326 | + default_currency: 'USD', // 统一为美元 | ||
| 327 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 328 | + withdrawal_periods: [ | ||
| 329 | + '1年', | ||
| 330 | + '2年', | ||
| 331 | + '3年', | ||
| 332 | + '5年', | ||
| 333 | + '10年', | ||
| 334 | + '15年', | ||
| 335 | + '20年', | ||
| 336 | + '终身' | ||
| 337 | + ] | ||
| 338 | + }, | ||
| 339 | + form_schema: savingsFormSchema, | ||
| 340 | + submit_mapping: savingsSubmitMapping | ||
| 341 | + } | ||
| 342 | + }, | ||
| 343 | + | ||
| 344 | + /** | ||
| 345 | + * 测试计划书-智享未来 | ||
| 346 | + * @added 2026-02-14T13:10:33.924Z | ||
| 347 | + * @source docs/to-parse/测试计划书-智享未来.md | ||
| 348 | + */ | ||
| 349 | + 'savings-product-30b41aae': { | ||
| 350 | + name: '测试计划书-智享未来', | ||
| 351 | + component: 'SavingsTemplate', | ||
| 352 | + category: 'savings', | ||
| 353 | + config: { | ||
| 354 | + currency: 'USD', | ||
| 355 | + payment_periods: ["整付", "3年", "5年"], | ||
| 356 | + age_range: { min: 0, max: 75 }, | ||
| 357 | + insurance_period: '终身', | ||
| 358 | + withdrawal_plan: { | ||
| 359 | + enabled: true, | ||
| 360 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 361 | + default_currency: 'USD', | ||
| 362 | + withdrawal_modes: ["年龄指定金额", "最高固定金额"], | ||
| 363 | + withdrawal_periods: ["1年", "3年", "5年", "10年"] | ||
| 364 | + }, | ||
| 365 | + form_schema: savingsFormSchema, | ||
| 366 | + submit_mapping: savingsSubmitMapping | ||
| 367 | + } | ||
| 368 | + }, | ||
| 369 | + | ||
| 370 | + /** | ||
| 371 | + * 测试计划书-智享未来2 | ||
| 372 | + * @added 2026-02-14T13:58:50.776Z | ||
| 373 | + * @source docs/to-parse/测试计划书-智享未来2.md | ||
| 374 | + */ | ||
| 375 | + 'savings-2-148b3acd': { | ||
| 376 | + name: '测试计划书-智享未来2', | ||
| 377 | + component: 'SavingsTemplate', | ||
| 378 | + category: 'savings', | ||
| 379 | + config: { | ||
| 380 | + currency: 'USD', | ||
| 381 | + payment_periods: ["整付","3年","5年"], | ||
| 382 | + age_range: { min: 0, max: 75 }, | ||
| 383 | + insurance_period: '终身', | ||
| 384 | + withdrawal_plan: { | ||
| 385 | + enabled: true, | ||
| 386 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 387 | + default_currency: 'USD', | ||
| 388 | + withdrawal_modes: ["年龄指定金额","最高固定金额"], | ||
| 389 | + withdrawal_periods: ["1年","3年","5年","10年"] | ||
| 390 | + }, | ||
| 391 | + form_schema: { | ||
| 392 | + "base_fields": [], | ||
| 393 | + "withdrawal_fields": [], | ||
| 394 | + "reset_map": {} | ||
| 395 | + }, | ||
| 396 | + submit_mapping: savingsSubmitMapping | ||
| 397 | + } | ||
| 398 | + }} | ||
| 399 | + | ||
| 400 | +/** | ||
| 401 | + * 全局功能开关 | ||
| 402 | + * @description 用于控制实验性功能或未来扩展功能的开关 | ||
| 403 | + * | ||
| 404 | + * @example 开启多币种功能:设置 MULTI_CURRENCY_ENABLED = true | ||
| 405 | + */ | ||
| 406 | +export const FEATURE_FLAGS = { | ||
| 407 | + /** | ||
| 408 | + * 多币种切换功能 | ||
| 409 | + * @description false: 方案 1 - 固定币种(当前实现) | ||
| 410 | + * true: 方案 2 - 支持多币种切换(未来扩展) | ||
| 411 | + * @type {boolean} | ||
| 412 | + */ | ||
| 413 | + MULTI_CURRENCY_ENABLED: false | ||
| 414 | +} | ||
| 415 | + | ||
| 416 | +/** | ||
| 417 | + * 币种符号映射 | ||
| 418 | + * @description 币种代码到符号的映射关系 | ||
| 419 | + */ | ||
| 420 | +export const CURRENCY_SYMBOLS = { | ||
| 421 | + CNY: '¥', // 人民币 | ||
| 422 | + USD: '$', // 美元 | ||
| 423 | + HKD: 'HK$', // 港币 | ||
| 424 | + EUR: '€' // 欧元 | ||
| 425 | +} | ||
| 426 | + | ||
| 427 | +/** | ||
| 428 | + * 币种完整信息映射 | ||
| 429 | + * @description 币种代码到完整信息的映射(用于多币种模式) | ||
| 430 | + */ | ||
| 431 | +export const CURRENCY_MAP = { | ||
| 432 | + CNY: { label: '人民币', symbol: '¥', value: 'CNY' }, | ||
| 433 | + USD: { label: '美元', symbol: '$', value: 'USD' }, | ||
| 434 | + HKD: { label: '港币', symbol: 'HK$', value: 'HKD' }, | ||
| 435 | + EUR: { label: '欧元', symbol: '€', value: 'EUR' } | ||
| 436 | +} | ||
| 437 | + | ||
| 438 | +/** | ||
| 439 | + * 根据 form_sn 获取模版配置 | ||
| 440 | + * @param {string} formSn - 产品 API 返回的 form_sn 字段 | ||
| 441 | + * @returns {Object|null} 模版配置对象,未找到返回 null | ||
| 442 | + * | ||
| 443 | + * @example | ||
| 444 | + * const config = getTemplateConfig('life-insurance-wiop3e') | ||
| 445 | + * // 返回: { name: 'WIOP3E...', component: 'LifeInsuranceTemplate', config: {...} } | ||
| 446 | + */ | ||
| 447 | +export function getTemplateConfig(formSn) { | ||
| 448 | + if (!formSn) { | ||
| 449 | + console.warn('[plan-templates] form_sn 为空') | ||
| 450 | + return null | ||
| 451 | + } | ||
| 452 | + | ||
| 453 | + const config = PLAN_TEMPLATES[formSn] | ||
| 454 | + if (!config) { | ||
| 455 | + console.error(`[plan-templates] 未找到模版配置: ${formSn}`) | ||
| 456 | + return null | ||
| 457 | + } | ||
| 458 | + | ||
| 459 | + return config | ||
| 460 | +} | ||
| 461 | + | ||
| 462 | +/** | ||
| 463 | + * 获取币种符号 | ||
| 464 | + * @param {string} currencyCode - 币种代码(CNY/USD/HKD/EUR) | ||
| 465 | + * @returns {string} 币种符号 | ||
| 466 | + * | ||
| 467 | + * @example | ||
| 468 | + * const symbol = getCurrencySymbol('USD') // 返回: '$' | ||
| 469 | + */ | ||
| 470 | +export function getCurrencySymbol(currencyCode) { | ||
| 471 | + return CURRENCY_SYMBOLS[currencyCode] || '¥' | ||
| 472 | +} |
| 1 | +/** | ||
| 2 | + * 计划书模版配置 | ||
| 3 | + * | ||
| 4 | + * @description 定义产品 form_sn 到模版组件和配置的映射关系 | ||
| 5 | + * @module config/plan-templates | ||
| 6 | + * @author Claude Code | ||
| 7 | + * @created 2026-02-06 | ||
| 8 | + * @updated 2026-02-13 - 新增文档解析工具入口 | ||
| 9 | + * | ||
| 10 | + * --- 快速添加新产品(开发工具) --- | ||
| 11 | + * 开发环境可使用以下工具快速添加新产品配置: | ||
| 12 | + * 1. 文档解析工具:/admin/document-parser/index (上传 PDF/Word,AI 自动解析) | ||
| 13 | + * 2. API 配置工具:/admin/document-parser/config (配置 AI 服务) | ||
| 14 | + * | ||
| 15 | + * 使用方式: | ||
| 16 | + * - 上传产品文档 → AI 自动提取配置 → 生成配置代码 → 复制到此文件 | ||
| 17 | + * | ||
| 18 | + * --- 手动添加步骤 --- | ||
| 19 | + * 1. 找到对应的产品分类(人寿/重疾/储蓄) | ||
| 20 | + * 2. 复制现有配置作为模板 | ||
| 21 | + * 3. 修改 name, currency, payment_periods, age_range 等字段 | ||
| 22 | + * 4. 确保 form_sn 唯一(建议使用产品英文标识 + 版本号) | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * 计划书模版配置映射 | ||
| 27 | + * @description form_sn 为产品 API 返回的字段,用于标识该产品使用的计划书模版 | ||
| 28 | + * | ||
| 29 | + * @example | ||
| 30 | + * // 产品 API 返回 | ||
| 31 | + * { | ||
| 32 | + * id: 1, | ||
| 33 | + * product_name: "WIOP3E 盈传创富保障计划 3 - 优选版", | ||
| 34 | + * form_sn: "life-insurance-wiop3e" // 对应下面的配置 key | ||
| 35 | + * } | ||
| 36 | + */ | ||
| 37 | +// 基础提交字段映射(适用于人寿/重疾等通用表单) | ||
| 38 | +const baseSubmitMapping = { | ||
| 39 | + customer_name: { api_field: 'customer_name' }, | ||
| 40 | + gender: { api_field: 'customer_gender' }, | ||
| 41 | + birthday: { api_field: 'customer_birthday' }, | ||
| 42 | + smoker: { api_field: 'smoking_status' }, | ||
| 43 | + coverage: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, | ||
| 44 | + payment_period: { api_field: 'payment_years' }, | ||
| 45 | + total_amount: { api_field: 'total_premium', transform: 'fen_to_yuan' } | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +// 人寿/重疾基础表单 Schema(通用保障类) | ||
| 49 | +const protectionFormSchema = { | ||
| 50 | + base_fields: [ | ||
| 51 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 52 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 53 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 54 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 55 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '保额', placeholder: '请输入保额', input_label: '请输入保额金额', required: true, currency_from: 'currency' }, | ||
| 56 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 57 | + ] | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +// 储蓄类提交字段映射(在基础映射上追加提取计划字段) | ||
| 61 | +const savingsSubmitMapping = { | ||
| 62 | + ...baseSubmitMapping, | ||
| 63 | + withdrawal_enabled: { api_field: 'allow_reduce_amount' }, | ||
| 64 | + withdrawal_mode: { api_field: 'withdrawal_option' }, | ||
| 65 | + withdrawal_method: { api_field: 'withdrawal_method' }, | ||
| 66 | + annual_withdrawal_amount: { api_field: 'annual_withdrawal_amount', transform: 'fen_to_yuan' }, | ||
| 67 | + annual_increase_percentage: { api_field: 'annual_increase_percentage' }, | ||
| 68 | + withdrawal_start_age_specified: { api_field: 'withdrawal_start_age' }, | ||
| 69 | + withdrawal_period_specified: { api_field: 'withdrawal_period' }, | ||
| 70 | + withdrawal_start_age_fixed: { api_field: 'withdrawal_start_age' }, | ||
| 71 | + withdrawal_period_fixed: { api_field: 'withdrawal_period' } | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +// 储蓄类表单 Schema(渲染 + 校验 + 联动的唯一入口) | ||
| 75 | +const savingsFormSchema = { | ||
| 76 | + // 基础字段:非提取计划部分 | ||
| 77 | + base_fields: [ | ||
| 78 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 79 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 80 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 81 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 82 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '年缴保费', placeholder: '请输入年缴保费', input_label: '请输入年缴保费金额', required: true, currency_from: 'currency' }, | ||
| 83 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 84 | + ], | ||
| 85 | + // 提取计划字段:由 withdrawal_plan 开关控制 | ||
| 86 | + withdrawal_fields: [ | ||
| 87 | + { id: 'withdrawal_enabled', key: 'withdrawal_enabled', type: 'radio', label: '是否希望生成一份允许减少名义金额的提取说明?', options: ['是', '否'], required: true, default: '否' }, | ||
| 88 | + { id: 'withdrawal_mode', key: 'withdrawal_mode', type: 'radio', label: '提取选项', options: ['指定提取金额', '最高固定提取金额'], required: true, default: '指定提取金额', section_title: '款项提取(允许减少名义金额)' }, | ||
| 89 | + { id: 'withdrawal_method', key: 'withdrawal_method', type: 'radio', label: '提取方式', options: ['按年岁'], required: true, default: '按年岁', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 90 | + { id: 'annual_withdrawal_amount', key: 'annual_withdrawal_amount', type: 'amount', label: '每年提取金额', placeholder: '请输入每年提取金额', input_label: '请输入每年提取金额', required: true, currency_from: 'withdrawal_plan.default_currency', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 91 | + { id: 'withdrawal_start_age_specified', key: 'withdrawal_start_age_specified', type: 'age', label: '由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 92 | + { id: 'withdrawal_period_specified', key: 'withdrawal_period_specified', type: 'select', label: '提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 93 | + { id: 'annual_increase_percentage', key: 'annual_increase_percentage', type: 'percentage', label: '每年递增提取之百分比(%)', placeholder: '请输入递增百分比', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 94 | + { id: 'withdrawal_start_age_fixed', key: 'withdrawal_start_age_fixed', type: 'age', label: '按年岁:由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] }, | ||
| 95 | + { id: 'withdrawal_period_fixed', key: 'withdrawal_period_fixed', type: 'select', label: '按年岁:提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] } | ||
| 96 | + ], | ||
| 97 | + // 提取模式切换时的清空逻辑,避免脏字段影响提交 | ||
| 98 | + reset_map: { | ||
| 99 | + withdrawal_mode: { | ||
| 100 | + '最高固定提取金额': ['annual_withdrawal_amount', 'annual_increase_percentage', 'withdrawal_start_age_specified', 'withdrawal_period_specified'], | ||
| 101 | + '指定提取金额': ['withdrawal_start_age_fixed', 'withdrawal_period_fixed'] | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +export const PLAN_TEMPLATES = { | ||
| 107 | + // 人寿保险产品 - WIOP3E | ||
| 108 | + 'life-insurance-wiop3e': { | ||
| 109 | + name: 'WIOP3E 盈传创富保障计划 3 - 优选版', | ||
| 110 | + component: 'LifeInsuranceTemplate', | ||
| 111 | + config: { | ||
| 112 | + currency: 'USD', // 币种:USD/CNY/HKD/EUR | ||
| 113 | + payment_periods: [ | ||
| 114 | + // 缴费年期选项 | ||
| 115 | + '整付(0-75 岁)', | ||
| 116 | + '5 年(0-70 岁)', | ||
| 117 | + '10 年(0-70 岁)' | ||
| 118 | + ], | ||
| 119 | + age_range: { min: 0, max: 75 }, // 年龄范围 | ||
| 120 | + insurance_period: '终身', // 保险期间 | ||
| 121 | + form_schema: protectionFormSchema, | ||
| 122 | + submit_mapping: baseSubmitMapping | ||
| 123 | + } | ||
| 124 | + }, | ||
| 125 | + | ||
| 126 | + // 人寿保险产品 - WIOP3 | ||
| 127 | + 'life-insurance-wiop3': { | ||
| 128 | + name: 'WIOP3 - 盈传创富保障计划 3', | ||
| 129 | + component: 'LifeInsuranceTemplate', | ||
| 130 | + config: { | ||
| 131 | + currency: 'USD', | ||
| 132 | + payment_periods: [ | ||
| 133 | + '整付(0-75 岁)', | ||
| 134 | + '5 年(0-70 岁)', | ||
| 135 | + '10 年(0-70 岁)' | ||
| 136 | + ], | ||
| 137 | + age_range: { min: 0, max: 75 }, | ||
| 138 | + insurance_period: '终身', | ||
| 139 | + form_schema: protectionFormSchema, | ||
| 140 | + submit_mapping: baseSubmitMapping | ||
| 141 | + } | ||
| 142 | + }, | ||
| 143 | + | ||
| 144 | + // 重疾保险产品 - MPC | ||
| 145 | + 'critical-illness-mpc': { | ||
| 146 | + name: 'MPC 守护无间重疾', | ||
| 147 | + component: 'CriticalIllnessTemplate', | ||
| 148 | + config: { | ||
| 149 | + currency: 'USD', | ||
| 150 | + payment_periods: [ | ||
| 151 | + '10 年(15 日 - 65 岁)', | ||
| 152 | + '20 年(15 日 - 65 岁)', | ||
| 153 | + '25 年(15 日 - 60 岁)' | ||
| 154 | + ], | ||
| 155 | + age_range: { min: 0, max: 65 }, | ||
| 156 | + insurance_period: '终身', | ||
| 157 | + form_schema: protectionFormSchema, | ||
| 158 | + submit_mapping: baseSubmitMapping | ||
| 159 | + } | ||
| 160 | + }, | ||
| 161 | + | ||
| 162 | + // 重疾保险产品 - MBC PRO | ||
| 163 | + 'critical-illness-mbc-pro': { | ||
| 164 | + name: 'MBC PRO 活跃人生重疾保 PRO', | ||
| 165 | + component: 'CriticalIllnessTemplate', | ||
| 166 | + config: { | ||
| 167 | + currency: 'USD', | ||
| 168 | + payment_periods: [ | ||
| 169 | + '10 年(15 日 - 65 岁)', | ||
| 170 | + '20 年(15 日 - 65 岁)', | ||
| 171 | + '25 年(15 日 - 60 岁)' | ||
| 172 | + ], | ||
| 173 | + age_range: { min: 0, max: 65 }, | ||
| 174 | + insurance_period: '终身', | ||
| 175 | + form_schema: protectionFormSchema, | ||
| 176 | + submit_mapping: baseSubmitMapping | ||
| 177 | + } | ||
| 178 | + }, | ||
| 179 | + | ||
| 180 | + // 重疾保险产品 - MBC2 | ||
| 181 | + 'critical-illness-mbc2': { | ||
| 182 | + name: 'MBC2 活跃人生重疾保 2', | ||
| 183 | + component: 'CriticalIllnessTemplate', | ||
| 184 | + config: { | ||
| 185 | + currency: 'USD', | ||
| 186 | + payment_periods: [ | ||
| 187 | + '10 年(15 日 - 65 岁)', | ||
| 188 | + '20 年(15 日 - 65 岁)', | ||
| 189 | + '25 年(15 日 - 60 岁)' | ||
| 190 | + ], | ||
| 191 | + age_range: { min: 0, max: 65 }, | ||
| 192 | + insurance_period: '终身', | ||
| 193 | + form_schema: protectionFormSchema, | ||
| 194 | + submit_mapping: baseSubmitMapping | ||
| 195 | + } | ||
| 196 | + }, | ||
| 197 | + | ||
| 198 | + // ====== 储蓄型产品(统一逻辑) ====== | ||
| 199 | + | ||
| 200 | + // GS - 宏挚传承保障计划 | ||
| 201 | + 'savings-gs': { | ||
| 202 | + name: '宏挚传承保障计划', | ||
| 203 | + component: 'SavingsTemplate', | ||
| 204 | + category: 'savings', // 储蓄型产品 | ||
| 205 | + config: { | ||
| 206 | + currency: 'USD', // 默认美元 | ||
| 207 | + payment_periods: [ | ||
| 208 | + '整付', | ||
| 209 | + '3 年', | ||
| 210 | + '5 年', | ||
| 211 | + '10 年', | ||
| 212 | + '15 年', | ||
| 213 | + ], | ||
| 214 | + age_range: { min: 0, max: 100 }, | ||
| 215 | + insurance_period: '终身', | ||
| 216 | + // 提取计划配置 | ||
| 217 | + withdrawal_plan: { | ||
| 218 | + enabled: true, | ||
| 219 | + currencies: ['HKD', 'USD', 'CNY'], // 支持的币种 | ||
| 220 | + default_currency: 'USD', // 统一为美元 | ||
| 221 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 222 | + withdrawal_periods: [ | ||
| 223 | + '1年', | ||
| 224 | + '2年', | ||
| 225 | + '3年', | ||
| 226 | + '5年', | ||
| 227 | + '10年', | ||
| 228 | + '15年', | ||
| 229 | + '20年', | ||
| 230 | + '终身' | ||
| 231 | + ] | ||
| 232 | + }, | ||
| 233 | + form_schema: savingsFormSchema, | ||
| 234 | + submit_mapping: savingsSubmitMapping | ||
| 235 | + } | ||
| 236 | + }, | ||
| 237 | + | ||
| 238 | + // GC - 宏挚家传保险计划 | ||
| 239 | + 'savings-gc': { | ||
| 240 | + name: '宏挚家传保险计划', | ||
| 241 | + component: 'SavingsTemplate', | ||
| 242 | + category: 'savings', | ||
| 243 | + config: { | ||
| 244 | + currency: 'USD', | ||
| 245 | + payment_periods: [ | ||
| 246 | + '整付', | ||
| 247 | + '3 年', | ||
| 248 | + '5 年', | ||
| 249 | + ], | ||
| 250 | + age_range: { min: 0, max: 100 }, | ||
| 251 | + insurance_period: '终身', | ||
| 252 | + withdrawal_plan: { | ||
| 253 | + enabled: true, | ||
| 254 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 255 | + default_currency: 'USD', // 统一为美元 | ||
| 256 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 257 | + withdrawal_periods: [ | ||
| 258 | + '1年', | ||
| 259 | + '2年', | ||
| 260 | + '3年', | ||
| 261 | + '5年', | ||
| 262 | + '10年', | ||
| 263 | + '15年', | ||
| 264 | + '20年', | ||
| 265 | + '终身' | ||
| 266 | + ] | ||
| 267 | + }, | ||
| 268 | + form_schema: savingsFormSchema, | ||
| 269 | + submit_mapping: savingsSubmitMapping | ||
| 270 | + } | ||
| 271 | + }, | ||
| 272 | + | ||
| 273 | + // FA - 宏浚传承保障计划 | ||
| 274 | + 'savings-fa': { | ||
| 275 | + name: '宏浚传承保障计划', | ||
| 276 | + component: 'SavingsTemplate', | ||
| 277 | + category: 'savings', | ||
| 278 | + config: { | ||
| 279 | + currency: 'USD', | ||
| 280 | + payment_periods: [ | ||
| 281 | + '整付', | ||
| 282 | + '2 年', | ||
| 283 | + '5 年', | ||
| 284 | + ], | ||
| 285 | + age_range: { min: 0, max: 100 }, | ||
| 286 | + insurance_period: '终身', | ||
| 287 | + withdrawal_plan: { | ||
| 288 | + enabled: true, | ||
| 289 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 290 | + default_currency: 'USD', // 统一为美元 | ||
| 291 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 292 | + withdrawal_periods: [ | ||
| 293 | + '1年', | ||
| 294 | + '2年', | ||
| 295 | + '3年', | ||
| 296 | + '5年', | ||
| 297 | + '10年', | ||
| 298 | + '15年', | ||
| 299 | + '20年', | ||
| 300 | + '终身' | ||
| 301 | + ] | ||
| 302 | + }, | ||
| 303 | + form_schema: savingsFormSchema, | ||
| 304 | + submit_mapping: savingsSubmitMapping | ||
| 305 | + } | ||
| 306 | + }, | ||
| 307 | + | ||
| 308 | + // LV2 - 赤霞珠终身寿险计划2(储蓄型终身寿险) | ||
| 309 | + 'savings-lv2': { | ||
| 310 | + name: '赤霞珠终身寿险计划2', | ||
| 311 | + component: 'SavingsTemplate', | ||
| 312 | + category: 'savings', | ||
| 313 | + config: { | ||
| 314 | + currency: 'USD', | ||
| 315 | + payment_periods: [ | ||
| 316 | + '5 年', | ||
| 317 | + '8 年', | ||
| 318 | + '12 年', | ||
| 319 | + '15 年', | ||
| 320 | + ], | ||
| 321 | + age_range: { min: 0, max: 100 }, | ||
| 322 | + insurance_period: '终身', | ||
| 323 | + withdrawal_plan: { | ||
| 324 | + enabled: true, | ||
| 325 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 326 | + default_currency: 'USD', // 统一为美元 | ||
| 327 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 328 | + withdrawal_periods: [ | ||
| 329 | + '1年', | ||
| 330 | + '2年', | ||
| 331 | + '3年', | ||
| 332 | + '5年', | ||
| 333 | + '10年', | ||
| 334 | + '15年', | ||
| 335 | + '20年', | ||
| 336 | + '终身' | ||
| 337 | + ] | ||
| 338 | + }, | ||
| 339 | + form_schema: savingsFormSchema, | ||
| 340 | + submit_mapping: savingsSubmitMapping | ||
| 341 | + } | ||
| 342 | + }, | ||
| 343 | + | ||
| 344 | + /** | ||
| 345 | + * 测试计划书-智享未来 | ||
| 346 | + * @added 2026-02-14T13:10:33.924Z | ||
| 347 | + * @source docs/to-parse/测试计划书-智享未来.md | ||
| 348 | + */ | ||
| 349 | + 'savings-product-30b41aae': { | ||
| 350 | + name: '测试计划书-智享未来', | ||
| 351 | + component: 'SavingsTemplate', | ||
| 352 | + category: 'savings', | ||
| 353 | + config: { | ||
| 354 | + currency: 'USD', | ||
| 355 | + payment_periods: ["整付", "3年", "5年"], | ||
| 356 | + age_range: { min: 0, max: 75 }, | ||
| 357 | + insurance_period: '终身', | ||
| 358 | + withdrawal_plan: { | ||
| 359 | + enabled: true, | ||
| 360 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 361 | + default_currency: 'USD', | ||
| 362 | + withdrawal_modes: ["年龄指定金额", "最高固定金额"], | ||
| 363 | + withdrawal_periods: ["1年", "3年", "5年", "10年"] | ||
| 364 | + }, | ||
| 365 | + form_schema: savingsFormSchema, | ||
| 366 | + submit_mapping: savingsSubmitMapping | ||
| 367 | + } | ||
| 368 | + }, | ||
| 369 | + | ||
| 370 | +} | ||
| 371 | + | ||
| 372 | +/** | ||
| 373 | + * 全局功能开关 | ||
| 374 | + * @description 用于控制实验性功能或未来扩展功能的开关 | ||
| 375 | + * | ||
| 376 | + * @example 开启多币种功能:设置 MULTI_CURRENCY_ENABLED = true | ||
| 377 | + */ | ||
| 378 | +export const FEATURE_FLAGS = { | ||
| 379 | + /** | ||
| 380 | + * 多币种切换功能 | ||
| 381 | + * @description false: 方案 1 - 固定币种(当前实现) | ||
| 382 | + * true: 方案 2 - 支持多币种切换(未来扩展) | ||
| 383 | + * @type {boolean} | ||
| 384 | + */ | ||
| 385 | + MULTI_CURRENCY_ENABLED: false | ||
| 386 | +} | ||
| 387 | + | ||
| 388 | +/** | ||
| 389 | + * 币种符号映射 | ||
| 390 | + * @description 币种代码到符号的映射关系 | ||
| 391 | + */ | ||
| 392 | +export const CURRENCY_SYMBOLS = { | ||
| 393 | + CNY: '¥', // 人民币 | ||
| 394 | + USD: '$', // 美元 | ||
| 395 | + HKD: 'HK$', // 港币 | ||
| 396 | + EUR: '€' // 欧元 | ||
| 397 | +} | ||
| 398 | + | ||
| 399 | +/** | ||
| 400 | + * 币种完整信息映射 | ||
| 401 | + * @description 币种代码到完整信息的映射(用于多币种模式) | ||
| 402 | + */ | ||
| 403 | +export const CURRENCY_MAP = { | ||
| 404 | + CNY: { label: '人民币', symbol: '¥', value: 'CNY' }, | ||
| 405 | + USD: { label: '美元', symbol: '$', value: 'USD' }, | ||
| 406 | + HKD: { label: '港币', symbol: 'HK$', value: 'HKD' }, | ||
| 407 | + EUR: { label: '欧元', symbol: '€', value: 'EUR' } | ||
| 408 | +} | ||
| 409 | + | ||
| 410 | +/** | ||
| 411 | + * 根据 form_sn 获取模版配置 | ||
| 412 | + * @param {string} formSn - 产品 API 返回的 form_sn 字段 | ||
| 413 | + * @returns {Object|null} 模版配置对象,未找到返回 null | ||
| 414 | + * | ||
| 415 | + * @example | ||
| 416 | + * const config = getTemplateConfig('life-insurance-wiop3e') | ||
| 417 | + * // 返回: { name: 'WIOP3E...', component: 'LifeInsuranceTemplate', config: {...} } | ||
| 418 | + */ | ||
| 419 | +export function getTemplateConfig(formSn) { | ||
| 420 | + if (!formSn) { | ||
| 421 | + console.warn('[plan-templates] form_sn 为空') | ||
| 422 | + return null | ||
| 423 | + } | ||
| 424 | + | ||
| 425 | + const config = PLAN_TEMPLATES[formSn] | ||
| 426 | + if (!config) { | ||
| 427 | + console.error(`[plan-templates] 未找到模版配置: ${formSn}`) | ||
| 428 | + return null | ||
| 429 | + } | ||
| 430 | + | ||
| 431 | + return config | ||
| 432 | +} | ||
| 433 | + | ||
| 434 | +/** | ||
| 435 | + * 获取币种符号 | ||
| 436 | + * @param {string} currencyCode - 币种代码(CNY/USD/HKD/EUR) | ||
| 437 | + * @returns {string} 币种符号 | ||
| 438 | + * | ||
| 439 | + * @example | ||
| 440 | + * const symbol = getCurrencySymbol('USD') // 返回: '$' | ||
| 441 | + */ | ||
| 442 | +export function getCurrencySymbol(currencyCode) { | ||
| 443 | + return CURRENCY_SYMBOLS[currencyCode] || '¥' | ||
| 444 | +} |
| 1 | +/** | ||
| 2 | + * 计划书模版配置 | ||
| 3 | + * | ||
| 4 | + * @description 定义产品 form_sn 到模版组件和配置的映射关系 | ||
| 5 | + * @module config/plan-templates | ||
| 6 | + * @author Claude Code | ||
| 7 | + * @created 2026-02-06 | ||
| 8 | + * @updated 2026-02-13 - 新增文档解析工具入口 | ||
| 9 | + * | ||
| 10 | + * --- 快速添加新产品(开发工具) --- | ||
| 11 | + * 开发环境可使用以下工具快速添加新产品配置: | ||
| 12 | + * 1. 文档解析工具:/admin/document-parser/index (上传 PDF/Word,AI 自动解析) | ||
| 13 | + * 2. API 配置工具:/admin/document-parser/config (配置 AI 服务) | ||
| 14 | + * | ||
| 15 | + * 使用方式: | ||
| 16 | + * - 上传产品文档 → AI 自动提取配置 → 生成配置代码 → 复制到此文件 | ||
| 17 | + * | ||
| 18 | + * --- 手动添加步骤 --- | ||
| 19 | + * 1. 找到对应的产品分类(人寿/重疾/储蓄) | ||
| 20 | + * 2. 复制现有配置作为模板 | ||
| 21 | + * 3. 修改 name, currency, payment_periods, age_range 等字段 | ||
| 22 | + * 4. 确保 form_sn 唯一(建议使用产品英文标识 + 版本号) | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * 计划书模版配置映射 | ||
| 27 | + * @description form_sn 为产品 API 返回的字段,用于标识该产品使用的计划书模版 | ||
| 28 | + * | ||
| 29 | + * @example | ||
| 30 | + * // 产品 API 返回 | ||
| 31 | + * { | ||
| 32 | + * id: 1, | ||
| 33 | + * product_name: "WIOP3E 盈传创富保障计划 3 - 优选版", | ||
| 34 | + * form_sn: "life-insurance-wiop3e" // 对应下面的配置 key | ||
| 35 | + * } | ||
| 36 | + */ | ||
| 37 | +// 基础提交字段映射(适用于人寿/重疾等通用表单) | ||
| 38 | +const baseSubmitMapping = { | ||
| 39 | + customer_name: { api_field: 'customer_name' }, | ||
| 40 | + gender: { api_field: 'customer_gender' }, | ||
| 41 | + birthday: { api_field: 'customer_birthday' }, | ||
| 42 | + smoker: { api_field: 'smoking_status' }, | ||
| 43 | + coverage: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, | ||
| 44 | + payment_period: { api_field: 'payment_years' }, | ||
| 45 | + total_amount: { api_field: 'total_premium', transform: 'fen_to_yuan' } | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +// 人寿/重疾基础表单 Schema(通用保障类) | ||
| 49 | +const protectionFormSchema = { | ||
| 50 | + base_fields: [ | ||
| 51 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 52 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 53 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 54 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 55 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '保额', placeholder: '请输入保额', input_label: '请输入保额金额', required: true, currency_from: 'currency' }, | ||
| 56 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 57 | + ] | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +// 储蓄类提交字段映射(在基础映射上追加提取计划字段) | ||
| 61 | +const savingsSubmitMapping = { | ||
| 62 | + ...baseSubmitMapping, | ||
| 63 | + withdrawal_enabled: { api_field: 'allow_reduce_amount' }, | ||
| 64 | + withdrawal_mode: { api_field: 'withdrawal_option' }, | ||
| 65 | + withdrawal_method: { api_field: 'withdrawal_method' }, | ||
| 66 | + annual_withdrawal_amount: { api_field: 'annual_withdrawal_amount', transform: 'fen_to_yuan' }, | ||
| 67 | + annual_increase_percentage: { api_field: 'annual_increase_percentage' }, | ||
| 68 | + withdrawal_start_age_specified: { api_field: 'withdrawal_start_age' }, | ||
| 69 | + withdrawal_period_specified: { api_field: 'withdrawal_period' }, | ||
| 70 | + withdrawal_start_age_fixed: { api_field: 'withdrawal_start_age' }, | ||
| 71 | + withdrawal_period_fixed: { api_field: 'withdrawal_period' } | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +// 储蓄类表单 Schema(渲染 + 校验 + 联动的唯一入口) | ||
| 75 | +const savingsFormSchema = { | ||
| 76 | + // 基础字段:非提取计划部分 | ||
| 77 | + base_fields: [ | ||
| 78 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 79 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 80 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 81 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 82 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '年缴保费', placeholder: '请输入年缴保费', input_label: '请输入年缴保费金额', required: true, currency_from: 'currency' }, | ||
| 83 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 84 | + ], | ||
| 85 | + // 提取计划字段:由 withdrawal_plan 开关控制 | ||
| 86 | + withdrawal_fields: [ | ||
| 87 | + { id: 'withdrawal_enabled', key: 'withdrawal_enabled', type: 'radio', label: '是否希望生成一份允许减少名义金额的提取说明?', options: ['是', '否'], required: true, default: '否' }, | ||
| 88 | + { id: 'withdrawal_mode', key: 'withdrawal_mode', type: 'radio', label: '提取选项', options: ['指定提取金额', '最高固定提取金额'], required: true, default: '指定提取金额', section_title: '款项提取(允许减少名义金额)' }, | ||
| 89 | + { id: 'withdrawal_method', key: 'withdrawal_method', type: 'radio', label: '提取方式', options: ['按年岁'], required: true, default: '按年岁', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 90 | + { id: 'annual_withdrawal_amount', key: 'annual_withdrawal_amount', type: 'amount', label: '每年提取金额', placeholder: '请输入每年提取金额', input_label: '请输入每年提取金额', required: true, currency_from: 'withdrawal_plan.default_currency', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 91 | + { id: 'withdrawal_start_age_specified', key: 'withdrawal_start_age_specified', type: 'age', label: '由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 92 | + { id: 'withdrawal_period_specified', key: 'withdrawal_period_specified', type: 'select', label: '提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 93 | + { id: 'annual_increase_percentage', key: 'annual_increase_percentage', type: 'percentage', label: '每年递增提取之百分比(%)', placeholder: '请输入递增百分比', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 94 | + { id: 'withdrawal_start_age_fixed', key: 'withdrawal_start_age_fixed', type: 'age', label: '按年岁:由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] }, | ||
| 95 | + { id: 'withdrawal_period_fixed', key: 'withdrawal_period_fixed', type: 'select', label: '按年岁:提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] } | ||
| 96 | + ], | ||
| 97 | + // 提取模式切换时的清空逻辑,避免脏字段影响提交 | ||
| 98 | + reset_map: { | ||
| 99 | + withdrawal_mode: { | ||
| 100 | + '最高固定提取金额': ['annual_withdrawal_amount', 'annual_increase_percentage', 'withdrawal_start_age_specified', 'withdrawal_period_specified'], | ||
| 101 | + '指定提取金额': ['withdrawal_start_age_fixed', 'withdrawal_period_fixed'] | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +export const PLAN_TEMPLATES = { | ||
| 107 | + // 人寿保险产品 - WIOP3E | ||
| 108 | + 'life-insurance-wiop3e': { | ||
| 109 | + name: 'WIOP3E 盈传创富保障计划 3 - 优选版', | ||
| 110 | + component: 'LifeInsuranceTemplate', | ||
| 111 | + config: { | ||
| 112 | + currency: 'USD', // 币种:USD/CNY/HKD/EUR | ||
| 113 | + payment_periods: [ | ||
| 114 | + // 缴费年期选项 | ||
| 115 | + '整付(0-75 岁)', | ||
| 116 | + '5 年(0-70 岁)', | ||
| 117 | + '10 年(0-70 岁)' | ||
| 118 | + ], | ||
| 119 | + age_range: { min: 0, max: 75 }, // 年龄范围 | ||
| 120 | + insurance_period: '终身', // 保险期间 | ||
| 121 | + form_schema: protectionFormSchema, | ||
| 122 | + submit_mapping: baseSubmitMapping | ||
| 123 | + } | ||
| 124 | + }, | ||
| 125 | + | ||
| 126 | + // 人寿保险产品 - WIOP3 | ||
| 127 | + 'life-insurance-wiop3': { | ||
| 128 | + name: 'WIOP3 - 盈传创富保障计划 3', | ||
| 129 | + component: 'LifeInsuranceTemplate', | ||
| 130 | + config: { | ||
| 131 | + currency: 'USD', | ||
| 132 | + payment_periods: [ | ||
| 133 | + '整付(0-75 岁)', | ||
| 134 | + '5 年(0-70 岁)', | ||
| 135 | + '10 年(0-70 岁)' | ||
| 136 | + ], | ||
| 137 | + age_range: { min: 0, max: 75 }, | ||
| 138 | + insurance_period: '终身', | ||
| 139 | + form_schema: protectionFormSchema, | ||
| 140 | + submit_mapping: baseSubmitMapping | ||
| 141 | + } | ||
| 142 | + }, | ||
| 143 | + | ||
| 144 | + // 重疾保险产品 - MPC | ||
| 145 | + 'critical-illness-mpc': { | ||
| 146 | + name: 'MPC 守护无间重疾', | ||
| 147 | + component: 'CriticalIllnessTemplate', | ||
| 148 | + config: { | ||
| 149 | + currency: 'USD', | ||
| 150 | + payment_periods: [ | ||
| 151 | + '10 年(15 日 - 65 岁)', | ||
| 152 | + '20 年(15 日 - 65 岁)', | ||
| 153 | + '25 年(15 日 - 60 岁)' | ||
| 154 | + ], | ||
| 155 | + age_range: { min: 0, max: 65 }, | ||
| 156 | + insurance_period: '终身', | ||
| 157 | + form_schema: protectionFormSchema, | ||
| 158 | + submit_mapping: baseSubmitMapping | ||
| 159 | + } | ||
| 160 | + }, | ||
| 161 | + | ||
| 162 | + // 重疾保险产品 - MBC PRO | ||
| 163 | + 'critical-illness-mbc-pro': { | ||
| 164 | + name: 'MBC PRO 活跃人生重疾保 PRO', | ||
| 165 | + component: 'CriticalIllnessTemplate', | ||
| 166 | + config: { | ||
| 167 | + currency: 'USD', | ||
| 168 | + payment_periods: [ | ||
| 169 | + '10 年(15 日 - 65 岁)', | ||
| 170 | + '20 年(15 日 - 65 岁)', | ||
| 171 | + '25 年(15 日 - 60 岁)' | ||
| 172 | + ], | ||
| 173 | + age_range: { min: 0, max: 65 }, | ||
| 174 | + insurance_period: '终身', | ||
| 175 | + form_schema: protectionFormSchema, | ||
| 176 | + submit_mapping: baseSubmitMapping | ||
| 177 | + } | ||
| 178 | + }, | ||
| 179 | + | ||
| 180 | + // 重疾保险产品 - MBC2 | ||
| 181 | + 'critical-illness-mbc2': { | ||
| 182 | + name: 'MBC2 活跃人生重疾保 2', | ||
| 183 | + component: 'CriticalIllnessTemplate', | ||
| 184 | + config: { | ||
| 185 | + currency: 'USD', | ||
| 186 | + payment_periods: [ | ||
| 187 | + '10 年(15 日 - 65 岁)', | ||
| 188 | + '20 年(15 日 - 65 岁)', | ||
| 189 | + '25 年(15 日 - 60 岁)' | ||
| 190 | + ], | ||
| 191 | + age_range: { min: 0, max: 65 }, | ||
| 192 | + insurance_period: '终身', | ||
| 193 | + form_schema: protectionFormSchema, | ||
| 194 | + submit_mapping: baseSubmitMapping | ||
| 195 | + } | ||
| 196 | + }, | ||
| 197 | + | ||
| 198 | + // ====== 储蓄型产品(统一逻辑) ====== | ||
| 199 | + | ||
| 200 | + // GS - 宏挚传承保障计划 | ||
| 201 | + 'savings-gs': { | ||
| 202 | + name: '宏挚传承保障计划', | ||
| 203 | + component: 'SavingsTemplate', | ||
| 204 | + category: 'savings', // 储蓄型产品 | ||
| 205 | + config: { | ||
| 206 | + currency: 'USD', // 默认美元 | ||
| 207 | + payment_periods: [ | ||
| 208 | + '整付', | ||
| 209 | + '3 年', | ||
| 210 | + '5 年', | ||
| 211 | + '10 年', | ||
| 212 | + '15 年', | ||
| 213 | + ], | ||
| 214 | + age_range: { min: 0, max: 100 }, | ||
| 215 | + insurance_period: '终身', | ||
| 216 | + // 提取计划配置 | ||
| 217 | + withdrawal_plan: { | ||
| 218 | + enabled: true, | ||
| 219 | + currencies: ['HKD', 'USD', 'CNY'], // 支持的币种 | ||
| 220 | + default_currency: 'USD', // 统一为美元 | ||
| 221 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 222 | + withdrawal_periods: [ | ||
| 223 | + '1年', | ||
| 224 | + '2年', | ||
| 225 | + '3年', | ||
| 226 | + '5年', | ||
| 227 | + '10年', | ||
| 228 | + '15年', | ||
| 229 | + '20年', | ||
| 230 | + '终身' | ||
| 231 | + ] | ||
| 232 | + }, | ||
| 233 | + form_schema: savingsFormSchema, | ||
| 234 | + submit_mapping: savingsSubmitMapping | ||
| 235 | + } | ||
| 236 | + }, | ||
| 237 | + | ||
| 238 | + // GC - 宏挚家传保险计划 | ||
| 239 | + 'savings-gc': { | ||
| 240 | + name: '宏挚家传保险计划', | ||
| 241 | + component: 'SavingsTemplate', | ||
| 242 | + category: 'savings', | ||
| 243 | + config: { | ||
| 244 | + currency: 'USD', | ||
| 245 | + payment_periods: [ | ||
| 246 | + '整付', | ||
| 247 | + '3 年', | ||
| 248 | + '5 年', | ||
| 249 | + ], | ||
| 250 | + age_range: { min: 0, max: 100 }, | ||
| 251 | + insurance_period: '终身', | ||
| 252 | + withdrawal_plan: { | ||
| 253 | + enabled: true, | ||
| 254 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 255 | + default_currency: 'USD', // 统一为美元 | ||
| 256 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 257 | + withdrawal_periods: [ | ||
| 258 | + '1年', | ||
| 259 | + '2年', | ||
| 260 | + '3年', | ||
| 261 | + '5年', | ||
| 262 | + '10年', | ||
| 263 | + '15年', | ||
| 264 | + '20年', | ||
| 265 | + '终身' | ||
| 266 | + ] | ||
| 267 | + }, | ||
| 268 | + form_schema: savingsFormSchema, | ||
| 269 | + submit_mapping: savingsSubmitMapping | ||
| 270 | + } | ||
| 271 | + }, | ||
| 272 | + | ||
| 273 | + // FA - 宏浚传承保障计划 | ||
| 274 | + 'savings-fa': { | ||
| 275 | + name: '宏浚传承保障计划', | ||
| 276 | + component: 'SavingsTemplate', | ||
| 277 | + category: 'savings', | ||
| 278 | + config: { | ||
| 279 | + currency: 'USD', | ||
| 280 | + payment_periods: [ | ||
| 281 | + '整付', | ||
| 282 | + '2 年', | ||
| 283 | + '5 年', | ||
| 284 | + ], | ||
| 285 | + age_range: { min: 0, max: 100 }, | ||
| 286 | + insurance_period: '终身', | ||
| 287 | + withdrawal_plan: { | ||
| 288 | + enabled: true, | ||
| 289 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 290 | + default_currency: 'USD', // 统一为美元 | ||
| 291 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 292 | + withdrawal_periods: [ | ||
| 293 | + '1年', | ||
| 294 | + '2年', | ||
| 295 | + '3年', | ||
| 296 | + '5年', | ||
| 297 | + '10年', | ||
| 298 | + '15年', | ||
| 299 | + '20年', | ||
| 300 | + '终身' | ||
| 301 | + ] | ||
| 302 | + }, | ||
| 303 | + form_schema: savingsFormSchema, | ||
| 304 | + submit_mapping: savingsSubmitMapping | ||
| 305 | + } | ||
| 306 | + }, | ||
| 307 | + | ||
| 308 | + // LV2 - 赤霞珠终身寿险计划2(储蓄型终身寿险) | ||
| 309 | + 'savings-lv2': { | ||
| 310 | + name: '赤霞珠终身寿险计划2', | ||
| 311 | + component: 'SavingsTemplate', | ||
| 312 | + category: 'savings', | ||
| 313 | + config: { | ||
| 314 | + currency: 'USD', | ||
| 315 | + payment_periods: [ | ||
| 316 | + '5 年', | ||
| 317 | + '8 年', | ||
| 318 | + '12 年', | ||
| 319 | + '15 年', | ||
| 320 | + ], | ||
| 321 | + age_range: { min: 0, max: 100 }, | ||
| 322 | + insurance_period: '终身', | ||
| 323 | + withdrawal_plan: { | ||
| 324 | + enabled: true, | ||
| 325 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 326 | + default_currency: 'USD', // 统一为美元 | ||
| 327 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 328 | + withdrawal_periods: [ | ||
| 329 | + '1年', | ||
| 330 | + '2年', | ||
| 331 | + '3年', | ||
| 332 | + '5年', | ||
| 333 | + '10年', | ||
| 334 | + '15年', | ||
| 335 | + '20年', | ||
| 336 | + '终身' | ||
| 337 | + ] | ||
| 338 | + }, | ||
| 339 | + form_schema: savingsFormSchema, | ||
| 340 | + submit_mapping: savingsSubmitMapping | ||
| 341 | + } | ||
| 342 | + }, | ||
| 343 | + | ||
| 344 | +} | ||
| 345 | + | ||
| 346 | +/** | ||
| 347 | + * 全局功能开关 | ||
| 348 | + * @description 用于控制实验性功能或未来扩展功能的开关 | ||
| 349 | + * | ||
| 350 | + * @example 开启多币种功能:设置 MULTI_CURRENCY_ENABLED = true | ||
| 351 | + */ | ||
| 352 | +export const FEATURE_FLAGS = { | ||
| 353 | + /** | ||
| 354 | + * 多币种切换功能 | ||
| 355 | + * @description false: 方案 1 - 固定币种(当前实现) | ||
| 356 | + * true: 方案 2 - 支持多币种切换(未来扩展) | ||
| 357 | + * @type {boolean} | ||
| 358 | + */ | ||
| 359 | + MULTI_CURRENCY_ENABLED: false | ||
| 360 | +} | ||
| 361 | + | ||
| 362 | +/** | ||
| 363 | + * 币种符号映射 | ||
| 364 | + * @description 币种代码到符号的映射关系 | ||
| 365 | + */ | ||
| 366 | +export const CURRENCY_SYMBOLS = { | ||
| 367 | + CNY: '¥', // 人民币 | ||
| 368 | + USD: '$', // 美元 | ||
| 369 | + HKD: 'HK$', // 港币 | ||
| 370 | + EUR: '€' // 欧元 | ||
| 371 | +} | ||
| 372 | + | ||
| 373 | +/** | ||
| 374 | + * 币种完整信息映射 | ||
| 375 | + * @description 币种代码到完整信息的映射(用于多币种模式) | ||
| 376 | + */ | ||
| 377 | +export const CURRENCY_MAP = { | ||
| 378 | + CNY: { label: '人民币', symbol: '¥', value: 'CNY' }, | ||
| 379 | + USD: { label: '美元', symbol: '$', value: 'USD' }, | ||
| 380 | + HKD: { label: '港币', symbol: 'HK$', value: 'HKD' }, | ||
| 381 | + EUR: { label: '欧元', symbol: '€', value: 'EUR' } | ||
| 382 | +} | ||
| 383 | + | ||
| 384 | +/** | ||
| 385 | + * 根据 form_sn 获取模版配置 | ||
| 386 | + * @param {string} formSn - 产品 API 返回的 form_sn 字段 | ||
| 387 | + * @returns {Object|null} 模版配置对象,未找到返回 null | ||
| 388 | + * | ||
| 389 | + * @example | ||
| 390 | + * const config = getTemplateConfig('life-insurance-wiop3e') | ||
| 391 | + * // 返回: { name: 'WIOP3E...', component: 'LifeInsuranceTemplate', config: {...} } | ||
| 392 | + */ | ||
| 393 | +export function getTemplateConfig(formSn) { | ||
| 394 | + if (!formSn) { | ||
| 395 | + console.warn('[plan-templates] form_sn 为空') | ||
| 396 | + return null | ||
| 397 | + } | ||
| 398 | + | ||
| 399 | + const config = PLAN_TEMPLATES[formSn] | ||
| 400 | + if (!config) { | ||
| 401 | + console.error(`[plan-templates] 未找到模版配置: ${formSn}`) | ||
| 402 | + return null | ||
| 403 | + } | ||
| 404 | + | ||
| 405 | + return config | ||
| 406 | +} | ||
| 407 | + | ||
| 408 | +/** | ||
| 409 | + * 获取币种符号 | ||
| 410 | + * @param {string} currencyCode - 币种代码(CNY/USD/HKD/EUR) | ||
| 411 | + * @returns {string} 币种符号 | ||
| 412 | + * | ||
| 413 | + * @example | ||
| 414 | + * const symbol = getCurrencySymbol('USD') // 返回: '$' | ||
| 415 | + */ | ||
| 416 | +export function getCurrencySymbol(currencyCode) { | ||
| 417 | + return CURRENCY_SYMBOLS[currencyCode] || '¥' | ||
| 418 | +} |
| 1 | +/** | ||
| 2 | + * 计划书模版配置 | ||
| 3 | + * | ||
| 4 | + * @description 定义产品 form_sn 到模版组件和配置的映射关系 | ||
| 5 | + * @module config/plan-templates | ||
| 6 | + * @author Claude Code | ||
| 7 | + * @created 2026-02-06 | ||
| 8 | + * @updated 2026-02-13 - 新增文档解析工具入口 | ||
| 9 | + * | ||
| 10 | + * --- 快速添加新产品(开发工具) --- | ||
| 11 | + * 开发环境可使用以下工具快速添加新产品配置: | ||
| 12 | + * 1. 文档解析工具:/admin/document-parser/index (上传 PDF/Word,AI 自动解析) | ||
| 13 | + * 2. API 配置工具:/admin/document-parser/config (配置 AI 服务) | ||
| 14 | + * | ||
| 15 | + * 使用方式: | ||
| 16 | + * - 上传产品文档 → AI 自动提取配置 → 生成配置代码 → 复制到此文件 | ||
| 17 | + * | ||
| 18 | + * --- 手动添加步骤 --- | ||
| 19 | + * 1. 找到对应的产品分类(人寿/重疾/储蓄) | ||
| 20 | + * 2. 复制现有配置作为模板 | ||
| 21 | + * 3. 修改 name, currency, payment_periods, age_range 等字段 | ||
| 22 | + * 4. 确保 form_sn 唯一(建议使用产品英文标识 + 版本号) | ||
| 23 | + */ | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * 计划书模版配置映射 | ||
| 27 | + * @description form_sn 为产品 API 返回的字段,用于标识该产品使用的计划书模版 | ||
| 28 | + * | ||
| 29 | + * @example | ||
| 30 | + * // 产品 API 返回 | ||
| 31 | + * { | ||
| 32 | + * id: 1, | ||
| 33 | + * product_name: "WIOP3E 盈传创富保障计划 3 - 优选版", | ||
| 34 | + * form_sn: "life-insurance-wiop3e" // 对应下面的配置 key | ||
| 35 | + * } | ||
| 36 | + */ | ||
| 37 | +// 基础提交字段映射(适用于人寿/重疾等通用表单) | ||
| 38 | +const baseSubmitMapping = { | ||
| 39 | + customer_name: { api_field: 'customer_name' }, | ||
| 40 | + gender: { api_field: 'customer_gender' }, | ||
| 41 | + birthday: { api_field: 'customer_birthday' }, | ||
| 42 | + smoker: { api_field: 'smoking_status' }, | ||
| 43 | + coverage: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, | ||
| 44 | + payment_period: { api_field: 'payment_years' }, | ||
| 45 | + total_amount: { api_field: 'total_premium', transform: 'fen_to_yuan' } | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +// 人寿/重疾基础表单 Schema(通用保障类) | ||
| 49 | +const protectionFormSchema = { | ||
| 50 | + base_fields: [ | ||
| 51 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 52 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 53 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 54 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 55 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '保额', placeholder: '请输入保额', input_label: '请输入保额金额', required: true, currency_from: 'currency' }, | ||
| 56 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 57 | + ] | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +// 储蓄类提交字段映射(在基础映射上追加提取计划字段) | ||
| 61 | +const savingsSubmitMapping = { | ||
| 62 | + ...baseSubmitMapping, | ||
| 63 | + withdrawal_enabled: { api_field: 'allow_reduce_amount' }, | ||
| 64 | + withdrawal_mode: { api_field: 'withdrawal_option' }, | ||
| 65 | + withdrawal_method: { api_field: 'withdrawal_method' }, | ||
| 66 | + annual_withdrawal_amount: { api_field: 'annual_withdrawal_amount', transform: 'fen_to_yuan' }, | ||
| 67 | + annual_increase_percentage: { api_field: 'annual_increase_percentage' }, | ||
| 68 | + withdrawal_start_age_specified: { api_field: 'withdrawal_start_age' }, | ||
| 69 | + withdrawal_period_specified: { api_field: 'withdrawal_period' }, | ||
| 70 | + withdrawal_start_age_fixed: { api_field: 'withdrawal_start_age' }, | ||
| 71 | + withdrawal_period_fixed: { api_field: 'withdrawal_period' } | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +// 储蓄类表单 Schema(渲染 + 校验 + 联动的唯一入口) | ||
| 75 | +const savingsFormSchema = { | ||
| 76 | + // 基础字段:非提取计划部分 | ||
| 77 | + base_fields: [ | ||
| 78 | + { id: 'customer_name', key: 'customer_name', type: 'name', label: '申请人', placeholder: '请输入申请人', required: true }, | ||
| 79 | + { id: 'gender', key: 'gender', type: 'radio', label: '性别', options: ['男', '女'], required: true }, | ||
| 80 | + { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: true }, | ||
| 81 | + { id: 'smoker', key: 'smoker', type: 'radio', label: '是否吸烟', options: ['是', '否'], required: true }, | ||
| 82 | + { id: 'coverage', key: 'coverage', type: 'amount', label: '年缴保费', placeholder: '请输入年缴保费', input_label: '请输入年缴保费金额', required: true, currency_from: 'currency' }, | ||
| 83 | + { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | ||
| 84 | + ], | ||
| 85 | + // 提取计划字段:由 withdrawal_plan 开关控制 | ||
| 86 | + withdrawal_fields: [ | ||
| 87 | + { id: 'withdrawal_enabled', key: 'withdrawal_enabled', type: 'radio', label: '是否希望生成一份允许减少名义金额的提取说明?', options: ['是', '否'], required: true, default: '否' }, | ||
| 88 | + { id: 'withdrawal_mode', key: 'withdrawal_mode', type: 'radio', label: '提取选项', options: ['指定提取金额', '最高固定提取金额'], required: true, default: '指定提取金额', section_title: '款项提取(允许减少名义金额)' }, | ||
| 89 | + { id: 'withdrawal_method', key: 'withdrawal_method', type: 'radio', label: '提取方式', options: ['按年岁'], required: true, default: '按年岁', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 90 | + { id: 'annual_withdrawal_amount', key: 'annual_withdrawal_amount', type: 'amount', label: '每年提取金额', placeholder: '请输入每年提取金额', input_label: '请输入每年提取金额', required: true, currency_from: 'withdrawal_plan.default_currency', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 91 | + { id: 'withdrawal_start_age_specified', key: 'withdrawal_start_age_specified', type: 'age', label: '由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 92 | + { id: 'withdrawal_period_specified', key: 'withdrawal_period_specified', type: 'select', label: '提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 93 | + { id: 'annual_increase_percentage', key: 'annual_increase_percentage', type: 'percentage', label: '每年递增提取之百分比(%)', placeholder: '请输入递增百分比', required: true, show_when: [{ field: 'withdrawal_mode', equals: '指定提取金额' }] }, | ||
| 94 | + { id: 'withdrawal_start_age_fixed', key: 'withdrawal_start_age_fixed', type: 'age', label: '按年岁:由几岁开始', placeholder: '请输入开始提取年龄', required: true, show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] }, | ||
| 95 | + { id: 'withdrawal_period_fixed', key: 'withdrawal_period_fixed', type: 'select', label: '按年岁:提取期(年)', placeholder: '请选择提取期', required: true, options_from: 'withdrawal_plan.withdrawal_periods', show_when: [{ field: 'withdrawal_mode', equals: '最高固定提取金额' }] } | ||
| 96 | + ], | ||
| 97 | + // 提取模式切换时的清空逻辑,避免脏字段影响提交 | ||
| 98 | + reset_map: { | ||
| 99 | + withdrawal_mode: { | ||
| 100 | + '最高固定提取金额': ['annual_withdrawal_amount', 'annual_increase_percentage', 'withdrawal_start_age_specified', 'withdrawal_period_specified'], | ||
| 101 | + '指定提取金额': ['withdrawal_start_age_fixed', 'withdrawal_period_fixed'] | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +export const PLAN_TEMPLATES = { | ||
| 107 | + // 人寿保险产品 - WIOP3E | ||
| 108 | + 'life-insurance-wiop3e': { | ||
| 109 | + name: 'WIOP3E 盈传创富保障计划 3 - 优选版', | ||
| 110 | + component: 'LifeInsuranceTemplate', | ||
| 111 | + config: { | ||
| 112 | + currency: 'USD', // 币种:USD/CNY/HKD/EUR | ||
| 113 | + payment_periods: [ | ||
| 114 | + // 缴费年期选项 | ||
| 115 | + '整付(0-75 岁)', | ||
| 116 | + '5 年(0-70 岁)', | ||
| 117 | + '10 年(0-70 岁)' | ||
| 118 | + ], | ||
| 119 | + age_range: { min: 0, max: 75 }, // 年龄范围 | ||
| 120 | + insurance_period: '终身', // 保险期间 | ||
| 121 | + form_schema: protectionFormSchema, | ||
| 122 | + submit_mapping: baseSubmitMapping | ||
| 123 | + } | ||
| 124 | + }, | ||
| 125 | + | ||
| 126 | + // 人寿保险产品 - WIOP3 | ||
| 127 | + 'life-insurance-wiop3': { | ||
| 128 | + name: 'WIOP3 - 盈传创富保障计划 3', | ||
| 129 | + component: 'LifeInsuranceTemplate', | ||
| 130 | + config: { | ||
| 131 | + currency: 'USD', | ||
| 132 | + payment_periods: [ | ||
| 133 | + '整付(0-75 岁)', | ||
| 134 | + '5 年(0-70 岁)', | ||
| 135 | + '10 年(0-70 岁)' | ||
| 136 | + ], | ||
| 137 | + age_range: { min: 0, max: 75 }, | ||
| 138 | + insurance_period: '终身', | ||
| 139 | + form_schema: protectionFormSchema, | ||
| 140 | + submit_mapping: baseSubmitMapping | ||
| 141 | + } | ||
| 142 | + }, | ||
| 143 | + | ||
| 144 | + // 重疾保险产品 - MPC | ||
| 145 | + 'critical-illness-mpc': { | ||
| 146 | + name: 'MPC 守护无间重疾', | ||
| 147 | + component: 'CriticalIllnessTemplate', | ||
| 148 | + config: { | ||
| 149 | + currency: 'USD', | ||
| 150 | + payment_periods: [ | ||
| 151 | + '10 年(15 日 - 65 岁)', | ||
| 152 | + '20 年(15 日 - 65 岁)', | ||
| 153 | + '25 年(15 日 - 60 岁)' | ||
| 154 | + ], | ||
| 155 | + age_range: { min: 0, max: 65 }, | ||
| 156 | + insurance_period: '终身', | ||
| 157 | + form_schema: protectionFormSchema, | ||
| 158 | + submit_mapping: baseSubmitMapping | ||
| 159 | + } | ||
| 160 | + }, | ||
| 161 | + | ||
| 162 | + // 重疾保险产品 - MBC PRO | ||
| 163 | + 'critical-illness-mbc-pro': { | ||
| 164 | + name: 'MBC PRO 活跃人生重疾保 PRO', | ||
| 165 | + component: 'CriticalIllnessTemplate', | ||
| 166 | + config: { | ||
| 167 | + currency: 'USD', | ||
| 168 | + payment_periods: [ | ||
| 169 | + '10 年(15 日 - 65 岁)', | ||
| 170 | + '20 年(15 日 - 65 岁)', | ||
| 171 | + '25 年(15 日 - 60 岁)' | ||
| 172 | + ], | ||
| 173 | + age_range: { min: 0, max: 65 }, | ||
| 174 | + insurance_period: '终身', | ||
| 175 | + form_schema: protectionFormSchema, | ||
| 176 | + submit_mapping: baseSubmitMapping | ||
| 177 | + } | ||
| 178 | + }, | ||
| 179 | + | ||
| 180 | + // 重疾保险产品 - MBC2 | ||
| 181 | + 'critical-illness-mbc2': { | ||
| 182 | + name: 'MBC2 活跃人生重疾保 2', | ||
| 183 | + component: 'CriticalIllnessTemplate', | ||
| 184 | + config: { | ||
| 185 | + currency: 'USD', | ||
| 186 | + payment_periods: [ | ||
| 187 | + '10 年(15 日 - 65 岁)', | ||
| 188 | + '20 年(15 日 - 65 岁)', | ||
| 189 | + '25 年(15 日 - 60 岁)' | ||
| 190 | + ], | ||
| 191 | + age_range: { min: 0, max: 65 }, | ||
| 192 | + insurance_period: '终身', | ||
| 193 | + form_schema: protectionFormSchema, | ||
| 194 | + submit_mapping: baseSubmitMapping | ||
| 195 | + } | ||
| 196 | + }, | ||
| 197 | + | ||
| 198 | + // ====== 储蓄型产品(统一逻辑) ====== | ||
| 199 | + | ||
| 200 | + // GS - 宏挚传承保障计划 | ||
| 201 | + 'savings-gs': { | ||
| 202 | + name: '宏挚传承保障计划', | ||
| 203 | + component: 'SavingsTemplate', | ||
| 204 | + category: 'savings', // 储蓄型产品 | ||
| 205 | + config: { | ||
| 206 | + currency: 'USD', // 默认美元 | ||
| 207 | + payment_periods: [ | ||
| 208 | + '整付', | ||
| 209 | + '3 年', | ||
| 210 | + '5 年', | ||
| 211 | + '10 年', | ||
| 212 | + '15 年', | ||
| 213 | + ], | ||
| 214 | + age_range: { min: 0, max: 100 }, | ||
| 215 | + insurance_period: '终身', | ||
| 216 | + // 提取计划配置 | ||
| 217 | + withdrawal_plan: { | ||
| 218 | + enabled: true, | ||
| 219 | + currencies: ['HKD', 'USD', 'CNY'], // 支持的币种 | ||
| 220 | + default_currency: 'USD', // 统一为美元 | ||
| 221 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 222 | + withdrawal_periods: [ | ||
| 223 | + '1年', | ||
| 224 | + '2年', | ||
| 225 | + '3年', | ||
| 226 | + '5年', | ||
| 227 | + '10年', | ||
| 228 | + '15年', | ||
| 229 | + '20年', | ||
| 230 | + '终身' | ||
| 231 | + ] | ||
| 232 | + }, | ||
| 233 | + form_schema: savingsFormSchema, | ||
| 234 | + submit_mapping: savingsSubmitMapping | ||
| 235 | + } | ||
| 236 | + }, | ||
| 237 | + | ||
| 238 | + // GC - 宏挚家传保险计划 | ||
| 239 | + 'savings-gc': { | ||
| 240 | + name: '宏挚家传保险计划', | ||
| 241 | + component: 'SavingsTemplate', | ||
| 242 | + category: 'savings', | ||
| 243 | + config: { | ||
| 244 | + currency: 'USD', | ||
| 245 | + payment_periods: [ | ||
| 246 | + '整付', | ||
| 247 | + '3 年', | ||
| 248 | + '5 年', | ||
| 249 | + ], | ||
| 250 | + age_range: { min: 0, max: 100 }, | ||
| 251 | + insurance_period: '终身', | ||
| 252 | + withdrawal_plan: { | ||
| 253 | + enabled: true, | ||
| 254 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 255 | + default_currency: 'USD', // 统一为美元 | ||
| 256 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 257 | + withdrawal_periods: [ | ||
| 258 | + '1年', | ||
| 259 | + '2年', | ||
| 260 | + '3年', | ||
| 261 | + '5年', | ||
| 262 | + '10年', | ||
| 263 | + '15年', | ||
| 264 | + '20年', | ||
| 265 | + '终身' | ||
| 266 | + ] | ||
| 267 | + }, | ||
| 268 | + form_schema: savingsFormSchema, | ||
| 269 | + submit_mapping: savingsSubmitMapping | ||
| 270 | + } | ||
| 271 | + }, | ||
| 272 | + | ||
| 273 | + // FA - 宏浚传承保障计划 | ||
| 274 | + 'savings-fa': { | ||
| 275 | + name: '宏浚传承保障计划', | ||
| 276 | + component: 'SavingsTemplate', | ||
| 277 | + category: 'savings', | ||
| 278 | + config: { | ||
| 279 | + currency: 'USD', | ||
| 280 | + payment_periods: [ | ||
| 281 | + '整付', | ||
| 282 | + '2 年', | ||
| 283 | + '5 年', | ||
| 284 | + ], | ||
| 285 | + age_range: { min: 0, max: 100 }, | ||
| 286 | + insurance_period: '终身', | ||
| 287 | + withdrawal_plan: { | ||
| 288 | + enabled: true, | ||
| 289 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 290 | + default_currency: 'USD', // 统一为美元 | ||
| 291 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 292 | + withdrawal_periods: [ | ||
| 293 | + '1年', | ||
| 294 | + '2年', | ||
| 295 | + '3年', | ||
| 296 | + '5年', | ||
| 297 | + '10年', | ||
| 298 | + '15年', | ||
| 299 | + '20年', | ||
| 300 | + '终身' | ||
| 301 | + ] | ||
| 302 | + }, | ||
| 303 | + form_schema: savingsFormSchema, | ||
| 304 | + submit_mapping: savingsSubmitMapping | ||
| 305 | + } | ||
| 306 | + }, | ||
| 307 | + | ||
| 308 | + // LV2 - 赤霞珠终身寿险计划2(储蓄型终身寿险) | ||
| 309 | + 'savings-lv2': { | ||
| 310 | + name: '赤霞珠终身寿险计划2', | ||
| 311 | + component: 'SavingsTemplate', | ||
| 312 | + category: 'savings', | ||
| 313 | + config: { | ||
| 314 | + currency: 'USD', | ||
| 315 | + payment_periods: [ | ||
| 316 | + '5 年', | ||
| 317 | + '8 年', | ||
| 318 | + '12 年', | ||
| 319 | + '15 年', | ||
| 320 | + ], | ||
| 321 | + age_range: { min: 0, max: 100 }, | ||
| 322 | + insurance_period: '终身', | ||
| 323 | + withdrawal_plan: { | ||
| 324 | + enabled: true, | ||
| 325 | + currencies: ['HKD', 'USD', 'CNY'], | ||
| 326 | + default_currency: 'USD', // 统一为美元 | ||
| 327 | + withdrawal_modes: ['指定提取金额', '最高固定提取金额'], | ||
| 328 | + withdrawal_periods: [ | ||
| 329 | + '1年', | ||
| 330 | + '2年', | ||
| 331 | + '3年', | ||
| 332 | + '5年', | ||
| 333 | + '10年', | ||
| 334 | + '15年', | ||
| 335 | + '20年', | ||
| 336 | + '终身' | ||
| 337 | + ] | ||
| 338 | + }, | ||
| 339 | + form_schema: savingsFormSchema, | ||
| 340 | + submit_mapping: savingsSubmitMapping | ||
| 341 | + } | ||
| 342 | + }, | ||
| 343 | + | ||
| 344 | + | ||
| 345 | +} | ||
| 346 | + | ||
| 347 | +/** | ||
| 348 | + * 全局功能开关 | ||
| 349 | + * @description 用于控制实验性功能或未来扩展功能的开关 | ||
| 350 | + * | ||
| 351 | + * @example 开启多币种功能:设置 MULTI_CURRENCY_ENABLED = true | ||
| 352 | + */ | ||
| 353 | +export const FEATURE_FLAGS = { | ||
| 354 | + /** | ||
| 355 | + * 多币种切换功能 | ||
| 356 | + * @description false: 方案 1 - 固定币种(当前实现) | ||
| 357 | + * true: 方案 2 - 支持多币种切换(未来扩展) | ||
| 358 | + * @type {boolean} | ||
| 359 | + */ | ||
| 360 | + MULTI_CURRENCY_ENABLED: false | ||
| 361 | +} | ||
| 362 | + | ||
| 363 | +/** | ||
| 364 | + * 币种符号映射 | ||
| 365 | + * @description 币种代码到符号的映射关系 | ||
| 366 | + */ | ||
| 367 | +export const CURRENCY_SYMBOLS = { | ||
| 368 | + CNY: '¥', // 人民币 | ||
| 369 | + USD: '$', // 美元 | ||
| 370 | + HKD: 'HK$', // 港币 | ||
| 371 | + EUR: '€' // 欧元 | ||
| 372 | +} | ||
| 373 | + | ||
| 374 | +/** | ||
| 375 | + * 币种完整信息映射 | ||
| 376 | + * @description 币种代码到完整信息的映射(用于多币种模式) | ||
| 377 | + */ | ||
| 378 | +export const CURRENCY_MAP = { | ||
| 379 | + CNY: { label: '人民币', symbol: '¥', value: 'CNY' }, | ||
| 380 | + USD: { label: '美元', symbol: '$', value: 'USD' }, | ||
| 381 | + HKD: { label: '港币', symbol: 'HK$', value: 'HKD' }, | ||
| 382 | + EUR: { label: '欧元', symbol: '€', value: 'EUR' } | ||
| 383 | +} | ||
| 384 | + | ||
| 385 | +/** | ||
| 386 | + * 根据 form_sn 获取模版配置 | ||
| 387 | + * @param {string} formSn - 产品 API 返回的 form_sn 字段 | ||
| 388 | + * @returns {Object|null} 模版配置对象,未找到返回 null | ||
| 389 | + * | ||
| 390 | + * @example | ||
| 391 | + * const config = getTemplateConfig('life-insurance-wiop3e') | ||
| 392 | + * // 返回: { name: 'WIOP3E...', component: 'LifeInsuranceTemplate', config: {...} } | ||
| 393 | + */ | ||
| 394 | +export function getTemplateConfig(formSn) { | ||
| 395 | + if (!formSn) { | ||
| 396 | + console.warn('[plan-templates] form_sn 为空') | ||
| 397 | + return null | ||
| 398 | + } | ||
| 399 | + | ||
| 400 | + const config = PLAN_TEMPLATES[formSn] | ||
| 401 | + if (!config) { | ||
| 402 | + console.error(`[plan-templates] 未找到模版配置: ${formSn}`) | ||
| 403 | + return null | ||
| 404 | + } | ||
| 405 | + | ||
| 406 | + return config | ||
| 407 | +} | ||
| 408 | + | ||
| 409 | +/** | ||
| 410 | + * 获取币种符号 | ||
| 411 | + * @param {string} currencyCode - 币种代码(CNY/USD/HKD/EUR) | ||
| 412 | + * @returns {string} 币种符号 | ||
| 413 | + * | ||
| 414 | + * @example | ||
| 415 | + * const symbol = getCurrencySymbol('USD') // 返回: '$' | ||
| 416 | + */ | ||
| 417 | +export function getCurrencySymbol(currencyCode) { | ||
| 418 | + return CURRENCY_SYMBOLS[currencyCode] || '¥' | ||
| 419 | +} |
docs/tmp/保险知识库.md
0 → 100644
| 1 | +# 保险知识库 | ||
| 2 | + | ||
| 3 | +> 本文档提供保险产品解析所需的行业知识,AI 解析器可以引用此内容来正确识别和提取产品信息。 | ||
| 4 | + | ||
| 5 | +## 📚 保险产品分类 | ||
| 6 | + | ||
| 7 | +### 1. 储蓄型保险(Savings Insurance) | ||
| 8 | + | ||
| 9 | +**特点**: | ||
| 10 | +- 具有储蓄功能,保单有现金价值 | ||
| 11 | +- 通常支持灵活提取现金 | ||
| 12 | +- 保险期间较长(终身或至指定年龄如 100 岁) | ||
| 13 | + | ||
| 14 | +**常见产品名关键词**: | ||
| 15 | +- 储蓄计划 | ||
| 16 | +- 传承计划 | ||
| 17 | +- 累积计划 | ||
| 18 | +- 增值计划 | ||
| 19 | +- 万能险 | ||
| 20 | +- 投连险 | ||
| 21 | + | ||
| 22 | +**关键提取字段**: | ||
| 23 | +| 字段 | 说明 | 示例 | | ||
| 24 | +|------|------|------| | ||
| 25 | +| 产品名称 | 保险产品全称 | 宏挚传承保障计划 | | ||
| 26 | +| 币种 | 支持的货币 | HKD, USD, CNY | | ||
| 27 | +| 缴费年期 | 可选择的缴费年限 | 整交、5年、10年 | | ||
| 28 | +| 保险期间 | 保障期限 | 终身、至 100 岁 | | ||
| 29 | +| 最低/最高投保年龄 | 年龄限制 | 15 日 - 75 岁 | | ||
| 30 | +| 提取方式 | 现金提取方式 | 灵活提取、固定提取 | | ||
| 31 | +| 提取周期 | 提取频率 | 每年、每半年、每季、每月 | | ||
| 32 | + | ||
| 33 | +--- | ||
| 34 | + | ||
| 35 | +### 2. 人寿保险(Life Insurance) | ||
| 36 | + | ||
| 37 | +**特点**: | ||
| 38 | +- 提供身故保障 | ||
| 39 | +- 保费相对较低 | ||
| 40 | +- 保障期间固定 | ||
| 41 | + | ||
| 42 | +**常见产品名关键词**: | ||
| 43 | +- 人寿保险 | ||
| 44 | +- 定期寿险 | ||
| 45 | +- 终身寿险 | ||
| 46 | +- 保障计划 | ||
| 47 | + | ||
| 48 | +**关键提取字段**: | ||
| 49 | +| 字段 | 说明 | 示例 | | ||
| 50 | +|------|------|------| | ||
| 51 | +| 身故保险金 | 被人身故赔付金额 | 基本保额 × 倍数 | | ||
| 52 | +| 保费形式 | 缴费方式 | 年缴、季缴、月缴 | | ||
| 53 | + | ||
| 54 | +--- | ||
| 55 | + | ||
| 56 | +### 3. 重疾保险(Critical Illness Insurance) | ||
| 57 | + | ||
| 58 | +**特点**: | ||
| 59 | +- 保障重大疾病 | ||
| 60 | +- 确诊即赔付 | ||
| 61 | +- 可选保费豁免 | ||
| 62 | + | ||
| 63 | +**常见产品名关键词**: | ||
| 64 | +- 重疾险 | ||
| 65 | +- 危疾保障 | ||
| 66 | +- 重大疾病保险 | ||
| 67 | +- 健康保障 | ||
| 68 | + | ||
| 69 | +**关键提取字段**: | ||
| 70 | +| 字段 | 说明 | 示例 | | ||
| 71 | +|------|------|------| | ||
| 72 | +| 保障疾病数量 | 覆盖病种数量 | 100+ 种 | | ||
| 73 | +| 赔付次数 | 可赔付次数 | 单次、多次 | | ||
| 74 | +| 等待期 | 观察期 | 90 天、180 天 | | ||
| 75 | + | ||
| 76 | +--- | ||
| 77 | + | ||
| 78 | +## 📋 保险专业术语对照表 | ||
| 79 | + | ||
| 80 | +| 中文术语 | 英文术语 | 说明 | | ||
| 81 | +|---------|---------|------| | ||
| 82 | +| 投保人 | Applicant | 购买保险的人 | | ||
| 83 | +| 被保险人 | Insured | 受保障的人 | | ||
| 84 | +| 受益人 | Beneficiary | 接受保险金的人 | | ||
| 85 | +| 保额 | Sum Assured | 保险公司承担的最高赔偿额 | | ||
| 86 | +| 保费 | Premium | 投保人支付的费用 | | ||
| 87 | +| 缴费年期 | Payment Period | 保费缴纳的年限 | | ||
| 88 | +| 保险期间 | Policy Term | 保险合同的有效期 | | ||
| 89 | +| 现金价值 | Cash Value | 退保时可获得的价值 | | ||
| 90 | +| 保单年度 | Policy Year | 保单生效的年数 | | ||
| 91 | +| 宽限期 | Grace Period | 逾期未缴保费但保障仍有效的期间 | | ||
| 92 | +| 观察期/等待期 | Waiting Period | 保险生效后需等待的一段时间 | | ||
| 93 | +| 免责期 | Exclusion Period | 保险公司不承担责任的时间 | | ||
| 94 | + | ||
| 95 | +--- | ||
| 96 | + | ||
| 97 | +## 🏦 币种识别 | ||
| 98 | + | ||
| 99 | +| 币种代码 | 币种名称 | 符号 | | ||
| 100 | +|---------|---------|------| | ||
| 101 | +| HKD | 港元 | $, HK$ | | ||
| 102 | +| USD | 美元 | US$, $ | | ||
| 103 | +| CNY | 人民币 | ¥, RMB | | ||
| 104 | +| MOP | 澳门元 | MOP$ | | ||
| 105 | + | ||
| 106 | +--- | ||
| 107 | + | ||
| 108 | +## 📊 缴费年期识别规则 | ||
| 109 | + | ||
| 110 | +| 文案表述 | 标准化值 | | ||
| 111 | +|---------|---------| | ||
| 112 | +| 整交、趸交 | lump_sum | | ||
| 113 | +| 5年、5年缴 | 5 | | ||
| 114 | +| 10年、10年缴 | 10 | | ||
| 115 | +| 15年、15年缴 | 15 | | ||
| 116 | +| 20年、20年缴 | 20 | | ||
| 117 | +| 25年、25年缴 | 25 | | ||
| 118 | +| 30年、30年缴 | 30 | | ||
| 119 | +| 终身缴费、至终身 | to_age_100 | | ||
| 120 | + | ||
| 121 | +--- | ||
| 122 | + | ||
| 123 | +## 📅 保险期间识别规则 | ||
| 124 | + | ||
| 125 | +| 文案表述 | 标准化值 | | ||
| 126 | +|---------|---------| | ||
| 127 | +| 终身、100岁 |终身 | | ||
| 128 | +| 至 85 岁 | to_85 | | ||
| 129 | +| 至 88 岁 | to_88 | | ||
| 130 | +| 至 100 岁 | to_100 | | ||
| 131 | +| 1 年、1 年期 | 1_year | | ||
| 132 | +| 20 年、20 年期 | 20_years | | ||
| 133 | + | ||
| 134 | +--- | ||
| 135 | + | ||
| 136 | +## 🎯 年龄范围识别 | ||
| 137 | + | ||
| 138 | +| 文案表述 | 最低年龄 | 最高年龄 | | ||
| 139 | +|---------|---------|---------| | ||
| 140 | +| 出生 15 天起 | 0 | - | | ||
| 141 | +| 15 日 - 75 岁 | 0 | 75 | | ||
| 142 | +| 18 岁 - 65 岁 | 18 | 65 | | ||
| 143 | +| 30 日 - 70 岁 | 0 | 70 | | ||
| 144 | + | ||
| 145 | +**注意**:年龄通常按周岁计算。 | ||
| 146 | + | ||
| 147 | +--- | ||
| 148 | + | ||
| 149 | +## 💰 提取功能识别 | ||
| 150 | + | ||
| 151 | +### 提取方式(Withdrawal Modes) | ||
| 152 | + | ||
| 153 | +| 文案表述 | 标准化值 | | ||
| 154 | +|---------|---------| | ||
| 155 | +| 灵活提取 | flexible | | ||
| 156 | +| 固定提取 | fixed | | ||
| 157 | +| 定期提取 | regular | | ||
| 158 | +| 终身年金 | lifetime_annuity | | ||
| 159 | + | ||
| 160 | +### 提取周期(Withdrawal Periods) | ||
| 161 | + | ||
| 162 | +| 文案表述 | 标准化值 | | ||
| 163 | +|---------|---------| | ||
| 164 | +| 每年 | yearly | | ||
| 165 | +| 每半年 | half_yearly | | ||
| 166 | +| 每季 | quarterly | | ||
| 167 | +| 每月 | monthly | | ||
| 168 | +| 终身 | lifetime | | ||
| 169 | + | ||
| 170 | +--- | ||
| 171 | + | ||
| 172 | +## 🔍 产品名称关键词识别 | ||
| 173 | + | ||
| 174 | +### 储蓄型关键词 | ||
| 175 | +- 传承、累积、增值、储蓄、分红 | ||
| 176 | +- 宏挚、迈达、创富、丰誉 | ||
| 177 | +- 5G、6G、世代 | ||
| 178 | + | ||
| 179 | +### 人寿保险关键词 | ||
| 180 | +- 人寿、寿险、身故保障 | ||
| 181 | +- 定期、终身、保额 | ||
| 182 | + | ||
| 183 | +### 重疾保险关键词 | ||
| 184 | +- 重疾、危疾、重大疾病 | ||
| 185 | +- 疾病保障、健康保障 | ||
| 186 | +- 守护、守护 | ||
| 187 | + | ||
| 188 | +--- | ||
| 189 | + | ||
| 190 | +## 📐 配置生成规则 | ||
| 191 | + | ||
| 192 | +### form_sn 生成规则 | ||
| 193 | + | ||
| 194 | +``` | ||
| 195 | +{产品类型}-{产品代号}-{币种} | ||
| 196 | +``` | ||
| 197 | + | ||
| 198 | +**示例**: | ||
| 199 | +- `savings-hc77-hkd` - 宏挚 77(储蓄型,港币) | ||
| 200 | +- `life-term-20-usd` - 定期寿险 20 年期(人寿,美元) | ||
| 201 | +- `ci-essential-cny` - 基础重疾险(重疾,人民币) | ||
| 202 | + | ||
| 203 | +### 组件选择规则 | ||
| 204 | + | ||
| 205 | +| 产品类型 | 对应组件 | | ||
| 206 | +|---------|----------| | ||
| 207 | +| 储蓄型 | SavingsTemplate | | ||
| 208 | +| 人寿保险 | LifeInsuranceTemplate | | ||
| 209 | +| 重疾保险 | CriticalIllnessTemplate | | ||
| 210 | + | ||
| 211 | +--- | ||
| 212 | + | ||
| 213 | +## ⚠️ 常见解析错误及修正 | ||
| 214 | + | ||
| 215 | +### 错误 1:币种识别错误 | ||
| 216 | +- **问题**:将 "USD$" 识别为港币 | ||
| 217 | +- **修正**:检查符号,$ 后面跟 USD 才是美元 | ||
| 218 | + | ||
| 219 | +### 错误 2:年龄范围解析错误 | ||
| 220 | +- **问题**:将 "15 日 - 75 岁" 的最低年龄识别为 15 | ||
| 221 | +- **修正**:15 日应转换为 0 岁 | ||
| 222 | + | ||
| 223 | +### 错误 3:缴费年期单位错误 | ||
| 224 | +- **问题**:将 "20 年期" 识别为 20 年缴费 | ||
| 225 | +- **修正**:"年期"通常指保险期间,"缴费"才是缴费年期 | ||
| 226 | + | ||
| 227 | +### 错误 4:提取方式缺失 | ||
| 228 | +- **问题**:储蓄型产品未识别到提取功能 | ||
| 229 | +- **修正**:查找"现金价值"、"提取"、"红利"等关键词 | ||
| 230 | + | ||
| 231 | +--- | ||
| 232 | + | ||
| 233 | +## 📖 参考规范 | ||
| 234 | + | ||
| 235 | +### 产品说明书标准结构 | ||
| 236 | + | ||
| 237 | +1. **产品概述** - 产品定位和特点 | ||
| 238 | +2. **投保条件** - 年龄、职业限制 | ||
| 239 | +3. **保障内容** - 具体保障项目 | ||
| 240 | +4. **缴费方式** - 缴费年期和币种 | ||
| 241 | +5. **红利分配**(如有)- 红利政策和领取方式 | ||
| 242 | +6. **提取功能**(如有)- 现金价值提取规则 | ||
| 243 | +7. **费用说明** - 各项费用标准 | ||
| 244 | +8. **案例演示** - 实际投保示例 | ||
| 245 | + | ||
| 246 | +### 文档解析优先级 | ||
| 247 | + | ||
| 248 | +1. **表格数据** > 文本描述 | ||
| 249 | +2. **明确的数字** > 模糊的表达(如"左右"、"约") | ||
| 250 | +3. **章节标题** > 正文内容 | ||
| 251 | +4. **示例数据** > 说明文字 | ||
| 252 | + | ||
| 253 | +--- | ||
| 254 | + | ||
| 255 | +## 🔄 更新记录 | ||
| 256 | + | ||
| 257 | +| 日期 | 更新内容 | 更新人 | | ||
| 258 | +|------|---------|--------| | ||
| 259 | +| 2026-02-13 | 创建初始版本,添加保险产品分类和术语表 | Claude Code | |
docs/tmp/测试计划书-智享未来.md
0 → 100644
| 1 | +# 智享未来储蓄计划书 | ||
| 2 | + | ||
| 3 | +## 产品概述 | ||
| 4 | + | ||
| 5 | +**产品名称**: 智享未来储蓄计划 | ||
| 6 | +**产品类型**: 储蓄型保险 | ||
| 7 | +**保险公司**: 宏利人寿保险 | ||
| 8 | +**币种**: 美元 (USD) | ||
| 9 | + | ||
| 10 | +--- | ||
| 11 | + | ||
| 12 | +## 产品特点 | ||
| 13 | + | ||
| 14 | +### 核心优势 | ||
| 15 | +- 保证现金价值,稳健增值 | ||
| 16 | +- 灵活提取方式,满足不同人生阶段需求 | ||
| 17 | +- 多种缴费年期选择,适应不同财务规划 | ||
| 18 | +- 美元/港币/人民币多币种选择 | ||
| 19 | + | ||
| 20 | +### 适合人群 | ||
| 21 | +- 希望长期稳健增值的客户 | ||
| 22 | +- 有子女教育金规划需求的父母 | ||
| 23 | +- 有养老规划需求的人士 | ||
| 24 | +- 希望灵活运用资金的高净值人士 | ||
| 25 | + | ||
| 26 | +--- | ||
| 27 | + | ||
| 28 | +## 投保条件 | ||
| 29 | + | ||
| 30 | +### 投保年龄 | ||
| 31 | +- 最低投保年龄:出生 15 天 | ||
| 32 | +- 最高投保年龄:75 岁 | ||
| 33 | + | ||
| 34 | +### 缴费年期 | ||
| 35 | +- 整付(0-75 岁) | ||
| 36 | +- 3 年期缴 | ||
| 37 | +- 5 年期缴 | ||
| 38 | +- 10 年期缴 | ||
| 39 | + | ||
| 40 | +### 保险期间 | ||
| 41 | +- 终身(至 100 岁) | ||
| 42 | + | ||
| 43 | +--- | ||
| 44 | + | ||
| 45 | +## 保障利益 | ||
| 46 | + | ||
| 47 | +### 身故保险金 | ||
| 48 | +若被保险人身故,我们将支付身故保险金予受益人。 | ||
| 49 | + | ||
| 50 | +### 现金价值 | ||
| 51 | +保单生效后具有现金价值,现金价值随保单年度增长而增加。 | ||
| 52 | + | ||
| 53 | +### 红利分配 | ||
| 54 | +本公司将根据分红保险业务的投资经营状况决定红利分配金额。 | ||
| 55 | + | ||
| 56 | +--- | ||
| 57 | + | ||
| 58 | +## 提取计划 | ||
| 59 | + | ||
| 60 | +### 提取方式 | ||
| 61 | +客户可选择以下提取方式: | ||
| 62 | + | ||
| 63 | +**方式一:年龄指定金额提取** | ||
| 64 | +- 客户可指定从特定年龄开始,每年提取固定金额 | ||
| 65 | +- 提取年龄可选:18/20/22/25/30/35/40/45/50/55/60 岁 | ||
| 66 | +- 每年提取金额:最低 1,000 美元 | ||
| 67 | + | ||
| 68 | +**方式二:最高固定金额提取** | ||
| 69 | +- 客户可选择提取最高固定金额 | ||
| 70 | +- 适用于需要大额资金支出的场景 | ||
| 71 | + | ||
| 72 | +### 提取周期 | ||
| 73 | +- 每年提取 | ||
| 74 | +- 每 2 年提取 | ||
| 75 | +- 每 3 年提取 | ||
| 76 | +- 每 5 年提取 | ||
| 77 | +- 每 10 年提取 | ||
| 78 | +- 终身提取 | ||
| 79 | + | ||
| 80 | +### 支持币种 | ||
| 81 | +- 美元 (USD) | ||
| 82 | +- 港币 (HKD) | ||
| 83 | +- 人民币 (CNY) | ||
| 84 | + | ||
| 85 | +--- | ||
| 86 | + | ||
| 87 | +## 缴费示例 | ||
| 88 | + | ||
| 89 | +### 案例:35 岁男性,整付,年缴保费 50,000 美元 | ||
| 90 | + | ||
| 91 | +| 保单年度 | 年缴保费 | 累计保费 | 保证现金价值 | | ||
| 92 | +|---------|---------|---------|-------------| | ||
| 93 | +| 第 1 年 | $50,000 | $50,000 | $45,000 | | ||
| 94 | +| 第 5 年 | $50,000 | $250,000 | $235,000 | | ||
| 95 | +| 第 10 年 | $50,000 | $500,000 | $490,000 | | ||
| 96 | +| 第 20 年 | - | $500,000 | $1,050,000 | | ||
| 97 | +| 第 30 年 | - | $500,000 | $1,650,000 | | ||
| 98 | + | ||
| 99 | +*注:以上数字仅为示例,实际现金价值以保险公司公布为准。 | ||
| 100 | + | ||
| 101 | +--- | ||
| 102 | + | ||
| 103 | +## 退保规定 | ||
| 104 | + | ||
| 105 | +### 犹豫期 | ||
| 106 | +保单签收后 15 天内为犹豫期,投保人可无条件解除合同,本公司无息退还已收保费。 | ||
| 107 | + | ||
| 108 | +### 退保价值 | ||
| 109 | +保单生效后,投保人可申请解除合同,本公司将支付退保金(即当时的现金价值)予投保人。 | ||
| 110 | + | ||
| 111 | +--- | ||
| 112 | + | ||
| 113 | +## 保费表 | ||
| 114 | + | ||
| 115 | +### 整付保费表(美元) | ||
| 116 | + | ||
| 117 | +| 年龄 | 男性 | 女性 | | ||
| 118 | +|-----|------|------| | ||
| 119 | +| 0 岁 | $45,200 | $44,800 | | ||
| 120 | +| 10 岁 | $46,500 | $46,100 | | ||
| 121 | +| 20 岁 | $48,000 | $47,600 | | ||
| 122 | +| 30 岁 | $50,000 | $49,500 | | ||
| 123 | +| 40 岁 | $53,500 | $52,800 | | ||
| 124 | +| 50 岁 | $59,200 | $58,000 | | ||
| 125 | +| 60 岁 | $68,500 | $66,800 | | ||
| 126 | +| 70 岁 | $89,200 | $86,500 | | ||
| 127 | + | ||
| 128 | +### 5 年期缴保费表(美元) | ||
| 129 | + | ||
| 130 | +| 年龄 | 年缴保费 | 总保费 | | ||
| 131 | +|-----|---------|-------| | ||
| 132 | +| 0 岁 | $10,500 | $52,500 | | ||
| 133 | +| 10 岁 | $10,800 | $54,000 | | ||
| 134 | +| 20 岁 | $11,200 | $56,000 | | ||
| 135 | +| 30 岁 | $11,800 | $59,000 | | ||
| 136 | +| 40 岁 | $12,800 | $64,000 | | ||
| 137 | +| 50 岁 | $14,500 | $72,500 | | ||
| 138 | +| 60 岁 | $17,200 | $86,000 | | ||
| 139 | +| 70 岁 | $23,500 | $117,500 | | ||
| 140 | + | ||
| 141 | +--- | ||
| 142 | + | ||
| 143 | +## 责任免除 | ||
| 144 | + | ||
| 145 | +因下列情形之一导致被保险人身故的,本公司不承担保险责任: | ||
| 146 | + | ||
| 147 | +1. 投保人故意造成被保险人死亡、故意伤害被保险人 | ||
| 148 | +2. 被保险人故意自伤、故意犯罪或抗拒依法采取的刑事强制措施 | ||
| 149 | +3. 被保险人主动吸食或注射毒品 | ||
| 150 | +4. 被保险人在本合同成立或复效之日起 2 年内自杀 | ||
| 151 | +5. 战争、军事冲突、暴乱或武装叛乱 | ||
| 152 | +6. 核爆炸、核辐射、辐射污染 | ||
| 153 | + | ||
| 154 | +--- | ||
| 155 | + | ||
| 156 | +## 特别约定 | ||
| 157 | + | ||
| 158 | +1. 本合同项下的保险责任自本公司同意承保并收取首期保险费后开始 | ||
| 159 | +2. 投保人应如实告知被保险人的健康状况,如故意不履行如实告知义务,本公司有权解除合同 | ||
| 160 | +3. 本合同项下的保险金请求权,自被保险人或受益人知道保险事故发生之日起 5 年内不行使而消灭 | ||
| 161 | + | ||
| 162 | +--- | ||
| 163 | + | ||
| 164 | +## 联系方式 | ||
| 165 | + | ||
| 166 | +**客服热线**: 400-888-8888 | ||
| 167 | +**公司网址**: www.manulife.com | ||
| 168 | +**营业时间**: 周一至周五 9:00-17:30 | ||
| 169 | + | ||
| 170 | +--- | ||
| 171 | + | ||
| 172 | +*本计划书仅供参考,具体保险责任及责任免除以保险合同为准* | ||
| 173 | + | ||
| 174 | +--- | ||
| 175 | + | ||
| 176 | +**文档版本**: V1.0 | ||
| 177 | +**生成日期**: 2026年2月13日 | ||
| 178 | +**用途**: 测试文档解析功能 |
docs/to-parse/测试计划书-智享未来2.md
0 → 100644
| 1 | +# 智享未来储蓄计划书 | ||
| 2 | + | ||
| 3 | +## 产品概述 | ||
| 4 | + | ||
| 5 | +**产品名称**: 智享未来储蓄计划 | ||
| 6 | +**产品类型**: 储蓄型保险 | ||
| 7 | +**保险公司**: 宏利人寿保险 | ||
| 8 | +**币种**: 美元 (USD) | ||
| 9 | + | ||
| 10 | +--- | ||
| 11 | + | ||
| 12 | +## 产品特点 | ||
| 13 | + | ||
| 14 | +### 核心优势 | ||
| 15 | +- 保证现金价值,稳健增值 | ||
| 16 | +- 灵活提取方式,满足不同人生阶段需求 | ||
| 17 | +- 多种缴费年期选择,适应不同财务规划 | ||
| 18 | +- 美元/港币/人民币多币种选择 | ||
| 19 | + | ||
| 20 | +### 适合人群 | ||
| 21 | +- 希望长期稳健增值的客户 | ||
| 22 | +- 有子女教育金规划需求的父母 | ||
| 23 | +- 有养老规划需求的人士 | ||
| 24 | +- 希望灵活运用资金的高净值人士 | ||
| 25 | + | ||
| 26 | +--- | ||
| 27 | + | ||
| 28 | +## 投保条件 | ||
| 29 | + | ||
| 30 | +### 投保年龄 | ||
| 31 | +- 最低投保年龄:出生 15 天 | ||
| 32 | +- 最高投保年龄:75 岁 | ||
| 33 | + | ||
| 34 | +### 缴费年期 | ||
| 35 | +- 整付(0-75 岁) | ||
| 36 | +- 3 年期缴 | ||
| 37 | +- 5 年期缴 | ||
| 38 | +- 10 年期缴 | ||
| 39 | + | ||
| 40 | +### 保险期间 | ||
| 41 | +- 终身(至 100 岁) | ||
| 42 | + | ||
| 43 | +--- | ||
| 44 | + | ||
| 45 | +## 保障利益 | ||
| 46 | + | ||
| 47 | +### 身故保险金 | ||
| 48 | +若被保险人身故,我们将支付身故保险金予受益人。 | ||
| 49 | + | ||
| 50 | +### 现金价值 | ||
| 51 | +保单生效后具有现金价值,现金价值随保单年度增长而增加。 | ||
| 52 | + | ||
| 53 | +### 红利分配 | ||
| 54 | +本公司将根据分红保险业务的投资经营状况决定红利分配金额。 | ||
| 55 | + | ||
| 56 | +--- | ||
| 57 | + | ||
| 58 | +## 提取计划 | ||
| 59 | + | ||
| 60 | +### 提取方式 | ||
| 61 | +客户可选择以下提取方式: | ||
| 62 | + | ||
| 63 | +**方式一:年龄指定金额提取** | ||
| 64 | +- 客户可指定从特定年龄开始,每年提取固定金额 | ||
| 65 | +- 提取年龄可选:18/20/22/25/30/35/40/45/50/55/60 岁 | ||
| 66 | +- 每年提取金额:最低 1,000 美元 | ||
| 67 | + | ||
| 68 | +**方式二:最高固定金额提取** | ||
| 69 | +- 客户可选择提取最高固定金额 | ||
| 70 | +- 适用于需要大额资金支出的场景 | ||
| 71 | + | ||
| 72 | +### 提取周期 | ||
| 73 | +- 每年提取 | ||
| 74 | +- 每 2 年提取 | ||
| 75 | +- 每 3 年提取 | ||
| 76 | +- 每 5 年提取 | ||
| 77 | +- 每 10 年提取 | ||
| 78 | +- 终身提取 | ||
| 79 | + | ||
| 80 | +### 支持币种 | ||
| 81 | +- 美元 (USD) | ||
| 82 | +- 港币 (HKD) | ||
| 83 | +- 人民币 (CNY) | ||
| 84 | + | ||
| 85 | +--- | ||
| 86 | + | ||
| 87 | +## 缴费示例 | ||
| 88 | + | ||
| 89 | +### 案例:35 岁男性,整付,年缴保费 50,000 美元 | ||
| 90 | + | ||
| 91 | +| 保单年度 | 年缴保费 | 累计保费 | 保证现金价值 | | ||
| 92 | +|---------|---------|---------|-------------| | ||
| 93 | +| 第 1 年 | $50,000 | $50,000 | $45,000 | | ||
| 94 | +| 第 5 年 | $50,000 | $250,000 | $235,000 | | ||
| 95 | +| 第 10 年 | $50,000 | $500,000 | $490,000 | | ||
| 96 | +| 第 20 年 | - | $500,000 | $1,050,000 | | ||
| 97 | +| 第 30 年 | - | $500,000 | $1,650,000 | | ||
| 98 | + | ||
| 99 | +*注:以上数字仅为示例,实际现金价值以保险公司公布为准。 | ||
| 100 | + | ||
| 101 | +--- | ||
| 102 | + | ||
| 103 | +## 退保规定 | ||
| 104 | + | ||
| 105 | +### 犹豫期 | ||
| 106 | +保单签收后 15 天内为犹豫期,投保人可无条件解除合同,本公司无息退还已收保费。 | ||
| 107 | + | ||
| 108 | +### 退保价值 | ||
| 109 | +保单生效后,投保人可申请解除合同,本公司将支付退保金(即当时的现金价值)予投保人。 | ||
| 110 | + | ||
| 111 | +--- | ||
| 112 | + | ||
| 113 | +## 保费表 | ||
| 114 | + | ||
| 115 | +### 整付保费表(美元) | ||
| 116 | + | ||
| 117 | +| 年龄 | 男性 | 女性 | | ||
| 118 | +|-----|------|------| | ||
| 119 | +| 0 岁 | $45,200 | $44,800 | | ||
| 120 | +| 10 岁 | $46,500 | $46,100 | | ||
| 121 | +| 20 岁 | $48,000 | $47,600 | | ||
| 122 | +| 30 岁 | $50,000 | $49,500 | | ||
| 123 | +| 40 岁 | $53,500 | $52,800 | | ||
| 124 | +| 50 岁 | $59,200 | $58,000 | | ||
| 125 | +| 60 岁 | $68,500 | $66,800 | | ||
| 126 | +| 70 岁 | $89,200 | $86,500 | | ||
| 127 | + | ||
| 128 | +### 5 年期缴保费表(美元) | ||
| 129 | + | ||
| 130 | +| 年龄 | 年缴保费 | 总保费 | | ||
| 131 | +|-----|---------|-------| | ||
| 132 | +| 0 岁 | $10,500 | $52,500 | | ||
| 133 | +| 10 岁 | $10,800 | $54,000 | | ||
| 134 | +| 20 岁 | $11,200 | $56,000 | | ||
| 135 | +| 30 岁 | $11,800 | $59,000 | | ||
| 136 | +| 40 岁 | $12,800 | $64,000 | | ||
| 137 | +| 50 岁 | $14,500 | $72,500 | | ||
| 138 | +| 60 岁 | $17,200 | $86,000 | | ||
| 139 | +| 70 岁 | $23,500 | $117,500 | | ||
| 140 | + | ||
| 141 | +--- | ||
| 142 | + | ||
| 143 | +## 责任免除 | ||
| 144 | + | ||
| 145 | +因下列情形之一导致被保险人身故的,本公司不承担保险责任: | ||
| 146 | + | ||
| 147 | +1. 投保人故意造成被保险人死亡、故意伤害被保险人 | ||
| 148 | +2. 被保险人故意自伤、故意犯罪或抗拒依法采取的刑事强制措施 | ||
| 149 | +3. 被保险人主动吸食或注射毒品 | ||
| 150 | +4. 被保险人在本合同成立或复效之日起 2 年内自杀 | ||
| 151 | +5. 战争、军事冲突、暴乱或武装叛乱 | ||
| 152 | +6. 核爆炸、核辐射、辐射污染 | ||
| 153 | + | ||
| 154 | +--- | ||
| 155 | + | ||
| 156 | +## 特别约定 | ||
| 157 | + | ||
| 158 | +1. 本合同项下的保险责任自本公司同意承保并收取首期保险费后开始 | ||
| 159 | +2. 投保人应如实告知被保险人的健康状况,如故意不履行如实告知义务,本公司有权解除合同 | ||
| 160 | +3. 本合同项下的保险金请求权,自被保险人或受益人知道保险事故发生之日起 5 年内不行使而消灭 | ||
| 161 | + | ||
| 162 | +--- | ||
| 163 | + | ||
| 164 | +## 联系方式 | ||
| 165 | + | ||
| 166 | +**客服热线**: 400-888-8888 | ||
| 167 | +**公司网址**: www.manulife.com | ||
| 168 | +**营业时间**: 周一至周五 9:00-17:30 | ||
| 169 | + | ||
| 170 | +--- | ||
| 171 | + | ||
| 172 | +*本计划书仅供参考,具体保险责任及责任免除以保险合同为准* | ||
| 173 | + | ||
| 174 | +--- | ||
| 175 | + | ||
| 176 | +**文档版本**: V1.0 | ||
| 177 | +**生成日期**: 2026年2月13日 | ||
| 178 | +**用途**: 测试文档解析功能 |
| ... | @@ -36,7 +36,7 @@ | ... | @@ -36,7 +36,7 @@ |
| 36 | "prepare": "husky", | 36 | "prepare": "husky", |
| 37 | "parse:docs": "node scripts/parse-docs.js", | 37 | "parse:docs": "node scripts/parse-docs.js", |
| 38 | "parse:docs:list": "node scripts/parse-docs.js --list", | 38 | "parse:docs:list": "node scripts/parse-docs.js --list", |
| 39 | - "parse:docs:file": "node scripts/parse-docs.js --file=\"产品说明书.pdf\"", | 39 | + "parse:docs:file": "node scripts/parse-docs.js --file=", |
| 40 | "release": "standard-version" | 40 | "release": "standard-version" |
| 41 | }, | 41 | }, |
| 42 | "browserslist": [ | 42 | "browserslist": [ | ... | ... |
| ... | @@ -187,6 +187,7 @@ function getDocsToParse() { | ... | @@ -187,6 +187,7 @@ function getDocsToParse() { |
| 187 | const files = fs.readdirSync(DOCS_DIR) | 187 | const files = fs.readdirSync(DOCS_DIR) |
| 188 | return files | 188 | return files |
| 189 | .filter(file => SUPPORTED_EXTENSIONS.includes(path.extname(file).toLowerCase())) | 189 | .filter(file => SUPPORTED_EXTENSIONS.includes(path.extname(file).toLowerCase())) |
| 190 | + .filter(file => file !== 'README.md') | ||
| 190 | .map(file => ({ | 191 | .map(file => ({ |
| 191 | name: file, | 192 | name: file, |
| 192 | fullPath: path.join(DOCS_DIR, file), | 193 | fullPath: path.join(DOCS_DIR, file), |
| ... | @@ -225,6 +226,9 @@ export function generateConfigCode(config) { | ... | @@ -225,6 +226,9 @@ export function generateConfigCode(config) { |
| 225 | const componentName = isSavings | 226 | const componentName = isSavings |
| 226 | ? 'SavingsTemplate' | 227 | ? 'SavingsTemplate' |
| 227 | : (productType === 'critical-illness' ? 'CriticalIllnessTemplate' : 'LifeInsuranceTemplate') | 228 | : (productType === 'critical-illness' ? 'CriticalIllnessTemplate' : 'LifeInsuranceTemplate') |
| 229 | + const { form_schema_ref, submit_mapping_ref } = resolveSchemaRefs(config) | ||
| 230 | + const form_schema_code = buildSchemaCode(config.form_schema, form_schema_ref) | ||
| 231 | + const submit_mapping_code = buildSchemaCode(config.submit_mapping, submit_mapping_ref) | ||
| 228 | 232 | ||
| 229 | let code = " /**\n" | 233 | let code = " /**\n" |
| 230 | code += " * " + config.product_name + "\n" | 234 | code += " * " + config.product_name + "\n" |
| ... | @@ -251,28 +255,16 @@ export function generateConfigCode(config) { | ... | @@ -251,28 +255,16 @@ export function generateConfigCode(config) { |
| 251 | code += " withdrawal_modes: " + JSON.stringify(config.withdrawal_modes || []) + ",\n" | 255 | code += " withdrawal_modes: " + JSON.stringify(config.withdrawal_modes || []) + ",\n" |
| 252 | code += " withdrawal_periods: " + JSON.stringify(config.withdrawal_periods || []) + "\n" | 256 | code += " withdrawal_periods: " + JSON.stringify(config.withdrawal_periods || []) + "\n" |
| 253 | code += " },\n" | 257 | code += " },\n" |
| 254 | - if (config.form_schema) { | ||
| 255 | - const form_schema_code = JSON.stringify(config.form_schema, null, 2).replace(/\n/g, '\n ') | ||
| 256 | code += " form_schema: " + form_schema_code + ",\n" | 258 | code += " form_schema: " + form_schema_code + ",\n" |
| 257 | - } | ||
| 258 | - if (config.submit_mapping) { | ||
| 259 | - const submit_mapping_code = JSON.stringify(config.submit_mapping, null, 2).replace(/\n/g, '\n ') | ||
| 260 | code += " submit_mapping: " + submit_mapping_code + "\n" | 259 | code += " submit_mapping: " + submit_mapping_code + "\n" |
| 261 | - } | ||
| 262 | } else { | 260 | } else { |
| 263 | code += " currency: '" + config.currency + "',\n" | 261 | code += " currency: '" + config.currency + "',\n" |
| 264 | code += " payment_periods: " + JSON.stringify(config.payment_periods || []) + ",\n" | 262 | code += " payment_periods: " + JSON.stringify(config.payment_periods || []) + ",\n" |
| 265 | code += " age_range: { min: " + (config.age_range?.min || 0) + ", max: " + (config.age_range?.max || 75) + " },\n" | 263 | code += " age_range: { min: " + (config.age_range?.min || 0) + ", max: " + (config.age_range?.max || 75) + " },\n" |
| 266 | code += " insurance_period: '" + (config.insurance_period || '终身') + "',\n" | 264 | code += " insurance_period: '" + (config.insurance_period || '终身') + "',\n" |
| 267 | - if (config.form_schema) { | ||
| 268 | - const form_schema_code = JSON.stringify(config.form_schema, null, 2).replace(/\n/g, '\n ') | ||
| 269 | code += " form_schema: " + form_schema_code + ",\n" | 265 | code += " form_schema: " + form_schema_code + ",\n" |
| 270 | - } | ||
| 271 | - if (config.submit_mapping) { | ||
| 272 | - const submit_mapping_code = JSON.stringify(config.submit_mapping, null, 2).replace(/\n/g, '\n ') | ||
| 273 | code += " submit_mapping: " + submit_mapping_code + "\n" | 266 | code += " submit_mapping: " + submit_mapping_code + "\n" |
| 274 | } | 267 | } |
| 275 | - } | ||
| 276 | 268 | ||
| 277 | code += " }\n" | 269 | code += " }\n" |
| 278 | code += " }\n\n" | 270 | code += " }\n\n" |
| ... | @@ -280,6 +272,48 @@ export function generateConfigCode(config) { | ... | @@ -280,6 +272,48 @@ export function generateConfigCode(config) { |
| 280 | return { formSn, code } | 272 | return { formSn, code } |
| 281 | } | 273 | } |
| 282 | 274 | ||
| 275 | +function resolveSchemaRefs(config) { | ||
| 276 | + const isSavings = config?.is_savings || config?.product_type === 'savings' | ||
| 277 | + if (isSavings) { | ||
| 278 | + return { | ||
| 279 | + form_schema_ref: 'savingsFormSchema', | ||
| 280 | + submit_mapping_ref: 'savingsSubmitMapping' | ||
| 281 | + } | ||
| 282 | + } | ||
| 283 | + return { | ||
| 284 | + form_schema_ref: 'protectionFormSchema', | ||
| 285 | + submit_mapping_ref: 'baseSubmitMapping' | ||
| 286 | + } | ||
| 287 | +} | ||
| 288 | + | ||
| 289 | +function buildSchemaCode(value, fallbackRef) { | ||
| 290 | + if (!value || isEmptyObject(value)) { | ||
| 291 | + return fallbackRef | ||
| 292 | + } | ||
| 293 | + if (value && typeof value === 'object' && !Array.isArray(value)) { | ||
| 294 | + const baseFields = value.base_fields | ||
| 295 | + const withdrawalFields = value.withdrawal_fields | ||
| 296 | + const resetMap = value.reset_map | ||
| 297 | + const baseFieldsEmpty = Array.isArray(baseFields) && baseFields.length === 0 | ||
| 298 | + const withdrawalFieldsEmpty = !Array.isArray(withdrawalFields) || withdrawalFields.length === 0 | ||
| 299 | + const resetMapEmpty = !resetMap || (typeof resetMap === 'object' && !Array.isArray(resetMap) && Object.keys(resetMap).length === 0) | ||
| 300 | + if (baseFieldsEmpty && withdrawalFieldsEmpty && resetMapEmpty) { | ||
| 301 | + return fallbackRef | ||
| 302 | + } | ||
| 303 | + } | ||
| 304 | + if (typeof value === 'string') { | ||
| 305 | + return value | ||
| 306 | + } | ||
| 307 | + return JSON.stringify(value, null, 2).replace(/\n/g, '\n ') | ||
| 308 | +} | ||
| 309 | + | ||
| 310 | +function isEmptyObject(value) { | ||
| 311 | + if (!value || typeof value !== 'object' || Array.isArray(value)) { | ||
| 312 | + return false | ||
| 313 | + } | ||
| 314 | + return Object.keys(value).length === 0 | ||
| 315 | +} | ||
| 316 | + | ||
| 283 | function formatSize(size) { | 317 | function formatSize(size) { |
| 284 | if (size < 1024) return `${size} B` | 318 | if (size < 1024) return `${size} B` |
| 285 | if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB` | 319 | if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB` | ... | ... |
| ... | @@ -38,6 +38,37 @@ describe('parse-docs 生成逻辑', () => { | ... | @@ -38,6 +38,37 @@ describe('parse-docs 生成逻辑', () => { |
| 38 | expect(result.code.includes("config: {\n category")).toBe(false) | 38 | expect(result.code.includes("config: {\n category")).toBe(false) |
| 39 | }) | 39 | }) |
| 40 | 40 | ||
| 41 | + it('generateConfigCode 按类型输出默认 schema 与 mapping', () => { | ||
| 42 | + const savings_result = generateConfigCode({ | ||
| 43 | + product_name: '宏挚传承保障计划', | ||
| 44 | + product_type: 'savings', | ||
| 45 | + currency: 'USD', | ||
| 46 | + payment_periods: ['整付'], | ||
| 47 | + age_range: { min: 0, max: 75 }, | ||
| 48 | + insurance_period: '终身', | ||
| 49 | + is_savings: true, | ||
| 50 | + withdrawal_modes: ['年龄指定金额'], | ||
| 51 | + withdrawal_periods: ['1年'], | ||
| 52 | + form_schema: { base_fields: [], withdrawal_fields: [], reset_map: {} }, | ||
| 53 | + submit_mapping: {} | ||
| 54 | + }) | ||
| 55 | + const life_result = generateConfigCode({ | ||
| 56 | + product_name: 'WIOP3E 盈传创富保障计划 3 - 优选版', | ||
| 57 | + product_type: 'life-insurance', | ||
| 58 | + currency: 'USD', | ||
| 59 | + payment_periods: ['整付'], | ||
| 60 | + age_range: { min: 0, max: 75 }, | ||
| 61 | + insurance_period: '终身', | ||
| 62 | + form_schema: { base_fields: [] }, | ||
| 63 | + submit_mapping: {} | ||
| 64 | + }) | ||
| 65 | + | ||
| 66 | + expect(savings_result.code.includes('form_schema: savingsFormSchema')).toBe(true) | ||
| 67 | + expect(savings_result.code.includes('submit_mapping: savingsSubmitMapping')).toBe(true) | ||
| 68 | + expect(life_result.code.includes('form_schema: protectionFormSchema')).toBe(true) | ||
| 69 | + expect(life_result.code.includes('submit_mapping: baseSubmitMapping')).toBe(true) | ||
| 70 | + }) | ||
| 71 | + | ||
| 41 | it('updateConfigContent 插入到 PLAN_TEMPLATES 末尾', () => { | 72 | it('updateConfigContent 插入到 PLAN_TEMPLATES 末尾', () => { |
| 42 | const base_content = `export const PLAN_TEMPLATES = { | 73 | const base_content = `export const PLAN_TEMPLATES = { |
| 43 | 'a': { | 74 | 'a': { | ... | ... |
| ... | @@ -342,31 +342,30 @@ export const PLAN_TEMPLATES = { | ... | @@ -342,31 +342,30 @@ export const PLAN_TEMPLATES = { |
| 342 | }, | 342 | }, |
| 343 | 343 | ||
| 344 | /** | 344 | /** |
| 345 | - * 测试计划书-智享未来 | 345 | + * 测试计划书-智享未来2 |
| 346 | - * @added 2026-02-14T13:10:33.924Z | 346 | + * @added 2026-02-14T14:12:31.658Z |
| 347 | - * @source docs/to-parse/测试计划书-智享未来.md | 347 | + * @source docs/to-parse/测试计划书-智享未来2.md |
| 348 | */ | 348 | */ |
| 349 | - 'savings-product-30b41aae': { | 349 | + 'savings-2-148b3acd': { |
| 350 | - name: '测试计划书-智享未来', | 350 | + name: '测试计划书-智享未来2', |
| 351 | component: 'SavingsTemplate', | 351 | component: 'SavingsTemplate', |
| 352 | category: 'savings', | 352 | category: 'savings', |
| 353 | config: { | 353 | config: { |
| 354 | currency: 'USD', | 354 | currency: 'USD', |
| 355 | - payment_periods: ["整付", "3年", "5年"], | 355 | + payment_periods: ["整付","3年","5年"], |
| 356 | age_range: { min: 0, max: 75 }, | 356 | age_range: { min: 0, max: 75 }, |
| 357 | insurance_period: '终身', | 357 | insurance_period: '终身', |
| 358 | withdrawal_plan: { | 358 | withdrawal_plan: { |
| 359 | enabled: true, | 359 | enabled: true, |
| 360 | currencies: ['HKD', 'USD', 'CNY'], | 360 | currencies: ['HKD', 'USD', 'CNY'], |
| 361 | default_currency: 'USD', | 361 | default_currency: 'USD', |
| 362 | - withdrawal_modes: ["年龄指定金额", "最高固定金额"], | 362 | + withdrawal_modes: ["年龄指定金额","最高固定金额"], |
| 363 | - withdrawal_periods: ["1年", "3年", "5年", "10年"] | 363 | + withdrawal_periods: ["1年","3年","5年","10年"] |
| 364 | }, | 364 | }, |
| 365 | form_schema: savingsFormSchema, | 365 | form_schema: savingsFormSchema, |
| 366 | submit_mapping: savingsSubmitMapping | 366 | submit_mapping: savingsSubmitMapping |
| 367 | } | 367 | } |
| 368 | - } | 368 | + }} |
| 369 | -} | ||
| 370 | 369 | ||
| 371 | /** | 370 | /** |
| 372 | * 全局功能开关 | 371 | * 全局功能开关 | ... | ... |
| ... | @@ -30,6 +30,10 @@ vi.mock('@/api/search', () => ({ | ... | @@ -30,6 +30,10 @@ vi.mock('@/api/search', () => ({ |
| 30 | searchAPI: vi.fn() | 30 | searchAPI: vi.fn() |
| 31 | })) | 31 | })) |
| 32 | 32 | ||
| 33 | +vi.mock('@/config/app', () => ({ | ||
| 34 | + USE_MOCK_DATA: false | ||
| 35 | +})) | ||
| 36 | + | ||
| 33 | const create_wrapper = () => { | 37 | const create_wrapper = () => { |
| 34 | const pinia = createPinia() | 38 | const pinia = createPinia() |
| 35 | setActivePinia(pinia) | 39 | setActivePinia(pinia) | ... | ... |
| ... | @@ -81,6 +81,9 @@ function generateSavingsConfig(config, formSn, includeComment) { | ... | @@ -81,6 +81,9 @@ function generateSavingsConfig(config, formSn, includeComment) { |
| 81 | const paymentPeriodsArray = JSON.stringify(config.payment_periods, null, 2) | 81 | const paymentPeriodsArray = JSON.stringify(config.payment_periods, null, 2) |
| 82 | const withdrawalModesArray = JSON.stringify(config.withdrawal_modes, null, 2) | 82 | const withdrawalModesArray = JSON.stringify(config.withdrawal_modes, null, 2) |
| 83 | const withdrawalPeriodsArray = JSON.stringify(config.withdrawal_periods, null, 2) | 83 | const withdrawalPeriodsArray = JSON.stringify(config.withdrawal_periods, null, 2) |
| 84 | + const { form_schema_ref, submit_mapping_ref } = resolveSchemaRefs(config) | ||
| 85 | + const form_schema_code = buildSchemaCode(config.form_schema, form_schema_ref) | ||
| 86 | + const submit_mapping_code = buildSchemaCode(config.submit_mapping, submit_mapping_ref) | ||
| 84 | 87 | ||
| 85 | return ` '${formSn}': {${comment} | 88 | return ` '${formSn}': {${comment} |
| 86 | name: '${config.product_name}', | 89 | name: '${config.product_name}', |
| ... | @@ -97,7 +100,9 @@ function generateSavingsConfig(config, formSn, includeComment) { | ... | @@ -97,7 +100,9 @@ function generateSavingsConfig(config, formSn, includeComment) { |
| 97 | default_currency: '${config.currency}', | 100 | default_currency: '${config.currency}', |
| 98 | withdrawal_modes: ${withdrawalModesArray}, | 101 | withdrawal_modes: ${withdrawalModesArray}, |
| 99 | withdrawal_periods: ${withdrawalPeriodsArray} | 102 | withdrawal_periods: ${withdrawalPeriodsArray} |
| 100 | - } | 103 | + }, |
| 104 | + form_schema: ${form_schema_code}, | ||
| 105 | + submit_mapping: ${submit_mapping_code} | ||
| 101 | } | 106 | } |
| 102 | }` | 107 | }` |
| 103 | } | 108 | } |
| ... | @@ -113,6 +118,9 @@ function generateLifeInsuranceConfig(config, formSn, includeComment) { | ... | @@ -113,6 +118,9 @@ function generateLifeInsuranceConfig(config, formSn, includeComment) { |
| 113 | // form_sn: ${formSn}` : '' | 118 | // form_sn: ${formSn}` : '' |
| 114 | 119 | ||
| 115 | const paymentPeriodsArray = JSON.stringify(config.payment_periods, null, 2) | 120 | const paymentPeriodsArray = JSON.stringify(config.payment_periods, null, 2) |
| 121 | + const { form_schema_ref, submit_mapping_ref } = resolveSchemaRefs(config) | ||
| 122 | + const form_schema_code = buildSchemaCode(config.form_schema, form_schema_ref) | ||
| 123 | + const submit_mapping_code = buildSchemaCode(config.submit_mapping, submit_mapping_ref) | ||
| 116 | 124 | ||
| 117 | return ` '${formSn}': {${comment} | 125 | return ` '${formSn}': {${comment} |
| 118 | name: '${config.product_name}', | 126 | name: '${config.product_name}', |
| ... | @@ -121,7 +129,9 @@ function generateLifeInsuranceConfig(config, formSn, includeComment) { | ... | @@ -121,7 +129,9 @@ function generateLifeInsuranceConfig(config, formSn, includeComment) { |
| 121 | currency: '${config.currency}', | 129 | currency: '${config.currency}', |
| 122 | payment_periods: ${paymentPeriodsArray}, | 130 | payment_periods: ${paymentPeriodsArray}, |
| 123 | age_range: { min: ${config.age_range.min}, max: ${config.age_range.max} }, | 131 | age_range: { min: ${config.age_range.min}, max: ${config.age_range.max} }, |
| 124 | - insurance_period: '${config.insurance_period}' | 132 | + insurance_period: '${config.insurance_period}', |
| 133 | + form_schema: ${form_schema_code}, | ||
| 134 | + submit_mapping: ${submit_mapping_code} | ||
| 125 | } | 135 | } |
| 126 | }` | 136 | }` |
| 127 | } | 137 | } |
| ... | @@ -137,6 +147,9 @@ function generateCriticalIllnessConfig(config, formSn, includeComment) { | ... | @@ -137,6 +147,9 @@ function generateCriticalIllnessConfig(config, formSn, includeComment) { |
| 137 | // form_sn: ${formSn}` : '' | 147 | // form_sn: ${formSn}` : '' |
| 138 | 148 | ||
| 139 | const paymentPeriodsArray = JSON.stringify(config.payment_periods, null, 2) | 149 | const paymentPeriodsArray = JSON.stringify(config.payment_periods, null, 2) |
| 150 | + const { form_schema_ref, submit_mapping_ref } = resolveSchemaRefs(config) | ||
| 151 | + const form_schema_code = buildSchemaCode(config.form_schema, form_schema_ref) | ||
| 152 | + const submit_mapping_code = buildSchemaCode(config.submit_mapping, submit_mapping_ref) | ||
| 140 | 153 | ||
| 141 | return ` '${formSn}': {${comment} | 154 | return ` '${formSn}': {${comment} |
| 142 | name: '${config.product_name}', | 155 | name: '${config.product_name}', |
| ... | @@ -145,7 +158,9 @@ function generateCriticalIllnessConfig(config, formSn, includeComment) { | ... | @@ -145,7 +158,9 @@ function generateCriticalIllnessConfig(config, formSn, includeComment) { |
| 145 | currency: '${config.currency}', | 158 | currency: '${config.currency}', |
| 146 | payment_periods: ${paymentPeriodsArray}, | 159 | payment_periods: ${paymentPeriodsArray}, |
| 147 | age_range: { min: ${config.age_range.min}, max: ${config.age_range.max} }, | 160 | age_range: { min: ${config.age_range.min}, max: ${config.age_range.max} }, |
| 148 | - insurance_period: '${config.insurance_period}' | 161 | + insurance_period: '${config.insurance_period}', |
| 162 | + form_schema: ${form_schema_code}, | ||
| 163 | + submit_mapping: ${submit_mapping_code} | ||
| 149 | } | 164 | } |
| 150 | }` | 165 | }` |
| 151 | } | 166 | } |
| ... | @@ -205,6 +220,48 @@ function toCamelCase(str) { | ... | @@ -205,6 +220,48 @@ function toCamelCase(str) { |
| 205 | .replace(/^(.)/, (c) => c.toLowerCase()) | 220 | .replace(/^(.)/, (c) => c.toLowerCase()) |
| 206 | } | 221 | } |
| 207 | 222 | ||
| 223 | +function resolveSchemaRefs(config) { | ||
| 224 | + const isSavings = config?.is_savings || config?.product_type === 'savings' | ||
| 225 | + if (isSavings) { | ||
| 226 | + return { | ||
| 227 | + form_schema_ref: 'savingsFormSchema', | ||
| 228 | + submit_mapping_ref: 'savingsSubmitMapping' | ||
| 229 | + } | ||
| 230 | + } | ||
| 231 | + return { | ||
| 232 | + form_schema_ref: 'protectionFormSchema', | ||
| 233 | + submit_mapping_ref: 'baseSubmitMapping' | ||
| 234 | + } | ||
| 235 | +} | ||
| 236 | + | ||
| 237 | +function buildSchemaCode(value, fallbackRef) { | ||
| 238 | + if (!value || isEmptyObject(value)) { | ||
| 239 | + return fallbackRef | ||
| 240 | + } | ||
| 241 | + if (value && typeof value === 'object' && !Array.isArray(value)) { | ||
| 242 | + const baseFields = value.base_fields | ||
| 243 | + const withdrawalFields = value.withdrawal_fields | ||
| 244 | + const resetMap = value.reset_map | ||
| 245 | + const baseFieldsEmpty = Array.isArray(baseFields) && baseFields.length === 0 | ||
| 246 | + const withdrawalFieldsEmpty = !Array.isArray(withdrawalFields) || withdrawalFields.length === 0 | ||
| 247 | + const resetMapEmpty = !resetMap || (typeof resetMap === 'object' && !Array.isArray(resetMap) && Object.keys(resetMap).length === 0) | ||
| 248 | + if (baseFieldsEmpty && withdrawalFieldsEmpty && resetMapEmpty) { | ||
| 249 | + return fallbackRef | ||
| 250 | + } | ||
| 251 | + } | ||
| 252 | + if (typeof value === 'string') { | ||
| 253 | + return value | ||
| 254 | + } | ||
| 255 | + return JSON.stringify(value, null, 2).replace(/\n/g, '\n ') | ||
| 256 | +} | ||
| 257 | + | ||
| 258 | +function isEmptyObject(value) { | ||
| 259 | + if (!value || typeof value !== 'object' || Array.isArray(value)) { | ||
| 260 | + return false | ||
| 261 | + } | ||
| 262 | + return Object.keys(value).length === 0 | ||
| 263 | +} | ||
| 264 | + | ||
| 208 | /** | 265 | /** |
| 209 | * 批量生成配置代码 | 266 | * 批量生成配置代码 |
| 210 | * | 267 | * | ... | ... |
-
Please register or login to post a comment