hookehuyr

feat(parser): 完善文档解析与测试

- 更新 parse-docs.js 解析逻辑
- 添加完整的测试用例
- 更新 CHANGELOG.md
- 完善配置生成器

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
...@@ -24,8 +24,3 @@ CLAUDE.md ...@@ -24,8 +24,3 @@ CLAUDE.md
24 *.pptx 24 *.pptx
25 25
26 .swc/ 26 .swc/
27 -
28 -# 文档解析工具临时文件
29 -docs/parsed-backup/
30 -docs/to-parse/*.md
31 -!docs/to-parse/README.md
......
...@@ -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 ### 新增
......
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"}
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 +}
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 |
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 +**用途**: 测试文档解析功能
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 *
......