feat(plan): 优化提取金额字段并新增每年提取字段
- 统一所有储蓄型产品的提取币种为 USD - 新增每年提取金额字段 (annual_withdrawal_amount) - 新增每年递增提取百分比字段 (annual_increase_percentage) - 添加 inputLabel prop 支持动态提示文字 - 修复百分比输入的类型转换和实时验证 - 修复 AmountKeyboard 组件属性类型不匹配问题 - 修复 ESLint 警告:使用 Number.isNaN() 替代 isNaN() 影响文件: - src/config/plan-templates.js: 币种统一为 USD - src/components/plan/PlanFields/AmountKeyboard.vue: 添加 inputLabel prop - src/components/plan/PlanTemplates/SavingsTemplate.vue: 新增字段和验证逻辑 - src/components/plan/PlanFormContainer.vue: 添加字段映射和数据转换 - src/components/plan/PlanTemplates/*Template.vue: 添加 inputLabel 使用 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Showing
9 changed files
with
160 additions
and
86 deletions
| ... | @@ -85,6 +85,12 @@ paths: | ... | @@ -85,6 +85,12 @@ paths: |
| 85 | product_id: | 85 | product_id: |
| 86 | type: integer | 86 | type: integer |
| 87 | title: 产品id | 87 | title: 产品id |
| 88 | + annual_withdrawal_amount: | ||
| 89 | + type: integer | ||
| 90 | + title: 每年提取金额 | ||
| 91 | + annual_increase_percentage: | ||
| 92 | + type: integer | ||
| 93 | + title: 每年递增提取百分比 | ||
| 88 | required: | 94 | required: |
| 89 | - customer_name | 95 | - customer_name |
| 90 | - customer_gender | 96 | - customer_gender |
| ... | @@ -100,6 +106,8 @@ paths: | ... | @@ -100,6 +106,8 @@ paths: |
| 100 | - smoking_status | 106 | - smoking_status |
| 101 | - total_premium | 107 | - total_premium |
| 102 | - product_id | 108 | - product_id |
| 109 | + - annual_increase_percentage | ||
| 110 | + - annual_withdrawal_amount | ||
| 103 | x-apifox-orders: | 111 | x-apifox-orders: |
| 104 | - customer_name | 112 | - customer_name |
| 105 | - customer_gender | 113 | - customer_gender |
| ... | @@ -115,6 +123,8 @@ paths: | ... | @@ -115,6 +123,8 @@ paths: |
| 115 | - withdrawal_period | 123 | - withdrawal_period |
| 116 | - smoking_status | 124 | - smoking_status |
| 117 | - total_premium | 125 | - total_premium |
| 126 | + - annual_withdrawal_amount | ||
| 127 | + - annual_increase_percentage | ||
| 118 | example: "{\r\n customer_name: '张三',\r\n customer_gender: 'male',\r\n customer_age: 30,\r\n annual_premium: 5000,\r\n payment_years: '10年',\r\n currency_type: 'CNY',\r\n product_id: 1\r\n }" | 128 | example: "{\r\n customer_name: '张三',\r\n customer_gender: 'male',\r\n customer_age: 30,\r\n annual_premium: 5000,\r\n payment_years: '10年',\r\n currency_type: 'CNY',\r\n product_id: 1\r\n }" |
| 119 | responses: | 129 | responses: |
| 120 | '200': | 130 | '200': |
| ... | @@ -166,4 +176,4 @@ servers: | ... | @@ -166,4 +176,4 @@ servers: |
| 166 | description: 正式环境 | 176 | description: 正式环境 |
| 167 | security: [] | 177 | security: [] |
| 168 | 178 | ||
| 169 | -``` | 179 | +```\ | ... | ... |
| ... | @@ -40,7 +40,6 @@ const Api = { | ... | @@ -40,7 +40,6 @@ const Api = { |
| 40 | file_name: string; // 附件名 | 40 | file_name: string; // 附件名 |
| 41 | file_size: string; // 附件大小 | 41 | file_size: string; // 附件大小 |
| 42 | file_size_formatted: string; // 附件大小(转换过显示) | 42 | file_size_formatted: string; // 附件大小(转换过显示) |
| 43 | - extension?: string; // 文件扩展名(优先使用) | ||
| 44 | }>; | 43 | }>; |
| 45 | cover_image: string; // 产品封面图 | 44 | cover_image: string; // 产品封面图 |
| 46 | * }; | 45 | * }; | ... | ... |
| ... | @@ -3,32 +3,35 @@ import { fn, fetch } from '@/api/fn'; | ... | @@ -3,32 +3,35 @@ import { fn, fetch } from '@/api/fn'; |
| 3 | const Api = { | 3 | const Api = { |
| 4 | Add: '/srv/?a=proposal&t=add', | 4 | Add: '/srv/?a=proposal&t=add', |
| 5 | Delete: '/srv/?a=proposal&t=delete', | 5 | Delete: '/srv/?a=proposal&t=delete', |
| 6 | - View: '/srv/?a=proposal&t=view', | ||
| 7 | List: '/srv/?a=proposal&t=list', | 6 | List: '/srv/?a=proposal&t=list', |
| 8 | -}; | 7 | + View: '/srv/?a=proposal&t=view', |
| 8 | +} | ||
| 9 | 9 | ||
| 10 | /** | 10 | /** |
| 11 | * @description 新增计划书 | 11 | * @description 新增计划书 |
| 12 | + * @remark | ||
| 12 | * @param {Object} params 请求参数 | 13 | * @param {Object} params 请求参数 |
| 13 | * @param {string} params.customer_name 申请人 | 14 | * @param {string} params.customer_name 申请人 |
| 14 | * @param {string} params.customer_gender 性别 | 15 | * @param {string} params.customer_gender 性别 |
| 15 | - * @param {number} params.customer_age 年龄 | 16 | + * @param {integer} params.customer_age 年龄 |
| 16 | * @param {string} params.customer_birthday 出生年月日 | 17 | * @param {string} params.customer_birthday 出生年月日 |
| 17 | - * @param {number} params.annual_premium 保额 | 18 | + * @param {integer} params.annual_premium 保额 |
| 18 | - * @param {string} params.payment_years 缴费年期 | 19 | + * @param {string} params.payment_years 繳費年期 |
| 19 | * @param {string} params.currency_type 币种 | 20 | * @param {string} params.currency_type 币种 |
| 20 | * @param {string} params.allow_reduce_amount 是否容许减少名义金额 | 21 | * @param {string} params.allow_reduce_amount 是否容许减少名义金额 |
| 21 | * @param {string} params.withdrawal_option 提取选项 | 22 | * @param {string} params.withdrawal_option 提取选项 |
| 22 | - * @param {number} params.withdrawal_start_age 提取开始年龄 | 23 | + * @param {integer} params.withdrawal_start_age 提取开始年龄 |
| 23 | - * @param {number} params.withdrawal_period 提取期(年) | 24 | + * @param {integer} params.withdrawal_period 提取期(年) |
| 24 | * @param {string} params.smoking_status 是否吸烟 | 25 | * @param {string} params.smoking_status 是否吸烟 |
| 25 | - * @param {number} params.total_premium 总保费金额 | 26 | + * @param {integer} params.total_premium 总保费金额 |
| 26 | - * @param {number} params.product_id 产品id | 27 | + * @param {integer} params.product_id 产品id |
| 28 | + * @param {integer} params.annual_withdrawal_amount 每年提取金额 | ||
| 29 | + * @param {integer} params.annual_increase_percentage 每年递增提取百分比 | ||
| 27 | * @returns {Promise<{ | 30 | * @returns {Promise<{ |
| 28 | * code: number; // 状态码 | 31 | * code: number; // 状态码 |
| 29 | * msg: string; // 消息 | 32 | * msg: string; // 消息 |
| 30 | * data: { | 33 | * data: { |
| 31 | - * order_id: string; // 订单ID | 34 | + order_id: string; // |
| 32 | * }; | 35 | * }; |
| 33 | * }>} | 36 | * }>} |
| 34 | */ | 37 | */ |
| ... | @@ -36,55 +39,58 @@ export const addAPI = (params) => fn(fetch.post(Api.Add, params)); | ... | @@ -36,55 +39,58 @@ export const addAPI = (params) => fn(fetch.post(Api.Add, params)); |
| 36 | 39 | ||
| 37 | /** | 40 | /** |
| 38 | * @description 删除计划书 | 41 | * @description 删除计划书 |
| 42 | + * @remark | ||
| 39 | * @param {Object} params 请求参数 | 43 | * @param {Object} params 请求参数 |
| 40 | - * @param {string} params.i 计划书id | ||
| 41 | * @returns {Promise<{ | 44 | * @returns {Promise<{ |
| 42 | * code: number; // 状态码 | 45 | * code: number; // 状态码 |
| 43 | * msg: string; // 消息 | 46 | * msg: string; // 消息 |
| 47 | + * data: any; | ||
| 44 | * }>} | 48 | * }>} |
| 45 | */ | 49 | */ |
| 46 | export const deleteAPI = (params) => fn(fetch.post(Api.Delete, params)); | 50 | export const deleteAPI = (params) => fn(fetch.post(Api.Delete, params)); |
| 47 | 51 | ||
| 48 | /** | 52 | /** |
| 49 | - * @description 查看计划书 | 53 | + * @description 计划书列表 |
| 54 | + * @remark | ||
| 50 | * @param {Object} params 请求参数 | 55 | * @param {Object} params 请求参数 |
| 51 | - * @param {string} params.i 计划书id | 56 | + * @param {string} params.status (可选) 3:待处理,5:处理中,7:已生成,9:已查看 |
| 57 | + * @param {string} params.keyword (可选) | ||
| 58 | + * @param {string} params.limit (可选) | ||
| 59 | + * @param {string} params.page (可选) | ||
| 52 | * @returns {Promise<{ | 60 | * @returns {Promise<{ |
| 53 | * code: number; // 状态码 | 61 | * code: number; // 状态码 |
| 54 | * msg: string; // 消息 | 62 | * msg: string; // 消息 |
| 63 | + * data: { | ||
| 64 | + list: Array<{ | ||
| 65 | + id: integer; // | ||
| 66 | + customer_name: string; // 申请人 | ||
| 67 | + product_name: string; // 产品名 | ||
| 68 | + categories: Array<{ | ||
| 69 | + id: string; // 分类id | ||
| 70 | + name: string; // 分类名 | ||
| 71 | + }>; | ||
| 72 | + created_time: string; // 创建时间 | ||
| 73 | + order_status: string; // 状态 | ||
| 74 | + proposal_files: Array<{ | ||
| 75 | + file_name: string; // 名称 | ||
| 76 | + file_url: string; // 地址 | ||
| 77 | + id: integer; // | ||
| 78 | + }>; | ||
| 79 | + }>; | ||
| 80 | + total: string; // | ||
| 81 | + * }; | ||
| 55 | * }>} | 82 | * }>} |
| 56 | */ | 83 | */ |
| 57 | -export const viewAPI = (params) => fn(fetch.post(Api.View, params)); | 84 | +export const listAPI = (params) => fn(fetch.get(Api.List, params)); |
| 58 | 85 | ||
| 59 | /** | 86 | /** |
| 60 | - * @description 计划书列表 | 87 | + * @description 查看计划书 |
| 88 | + * @remark | ||
| 61 | * @param {Object} params 请求参数 | 89 | * @param {Object} params 请求参数 |
| 62 | - * @param {string} [params.status] 状态筛选(3:待处理,5:处理中,7:已生成,9:已查看) | ||
| 63 | - * @param {string} [params.keyword] 搜索关键词 | ||
| 64 | - * @param {string} [params.limit] 每页数量(默认10) | ||
| 65 | - * @param {string} [params.page] 页码(默认0) | ||
| 66 | * @returns {Promise<{ | 90 | * @returns {Promise<{ |
| 67 | * code: number; // 状态码 | 91 | * code: number; // 状态码 |
| 68 | * msg: string; // 消息 | 92 | * msg: string; // 消息 |
| 69 | - * data: { | 93 | + * data: any; |
| 70 | - * list: Array<{ | ||
| 71 | - * id: number; // 计划书id | ||
| 72 | - * customer_name: string; // 申请人 | ||
| 73 | - * product_name: string; // 产品名 | ||
| 74 | - * categories: Array<{ | ||
| 75 | - * id: string; // 分类id | ||
| 76 | - * name: string; // 分类名 | ||
| 77 | - * }>; // 分类 | ||
| 78 | - * created_time: string; // 创建时间 | ||
| 79 | - * order_status: string; // 状态 | ||
| 80 | - * proposal_files: Array<{ | ||
| 81 | - * file_name: string; // 文件名称 | ||
| 82 | - * file_url: string; // 文件地址 | ||
| 83 | - * id: number; // 文件id | ||
| 84 | - * }>; // 生成的计划书 | ||
| 85 | - * }>; // 计划书列表 | ||
| 86 | - * total: string; // 总数 | ||
| 87 | - * }; | ||
| 88 | * }>} | 94 | * }>} |
| 89 | */ | 95 | */ |
| 90 | -export const listAPI = (params) => fn(fetch.get(Api.List, params)); | 96 | +export const viewAPI = (params) => fn(fetch.post(Api.View, params)); | ... | ... |
| ... | @@ -53,7 +53,7 @@ | ... | @@ -53,7 +53,7 @@ |
| 53 | <!-- 内容容器 --> | 53 | <!-- 内容容器 --> |
| 54 | <view class="relative z-10 w-full px-8 flex flex-col items-center"> | 54 | <view class="relative z-10 w-full px-8 flex flex-col items-center"> |
| 55 | <!-- 顶部提示文字 --> | 55 | <!-- 顶部提示文字 --> |
| 56 | - <view class="text-sm text-gray-400 font-normal tracking-wide mb-6">请输入保额金额</view> | 56 | + <view class="text-sm text-gray-400 font-normal tracking-wide mb-6">{{ inputLabel }}</view> |
| 57 | 57 | ||
| 58 | <!-- 垂直布局核心区域 --> | 58 | <!-- 垂直布局核心区域 --> |
| 59 | <view class="flex flex-col items-center justify-center w-full mb-8"> | 59 | <view class="flex flex-col items-center justify-center w-full mb-8"> |
| ... | @@ -155,6 +155,16 @@ const props = defineProps({ | ... | @@ -155,6 +155,16 @@ const props = defineProps({ |
| 155 | }, | 155 | }, |
| 156 | 156 | ||
| 157 | /** | 157 | /** |
| 158 | + * 键盘弹窗顶部提示文字 | ||
| 159 | + * @type {string} | ||
| 160 | + * @default '请输入保额金额' | ||
| 161 | + */ | ||
| 162 | + inputLabel: { | ||
| 163 | + type: String, | ||
| 164 | + default: '请输入保额金额' | ||
| 165 | + }, | ||
| 166 | + | ||
| 167 | + /** | ||
| 158 | * 绑定的值(单位:分) | 168 | * 绑定的值(单位:分) |
| 159 | * @type {number} | 169 | * @type {number} |
| 160 | * @example 100000 表示 1000.00 元 | 170 | * @example 100000 表示 1000.00 元 | ... | ... |
| ... | @@ -267,7 +267,10 @@ const submit = async () => { | ... | @@ -267,7 +267,10 @@ const submit = async () => { |
| 267 | withdrawal_mode: 'withdrawal_option', // 提取选项 | 267 | withdrawal_mode: 'withdrawal_option', // 提取选项 |
| 268 | withdrawal_start_age: 'withdrawal_start_age', // 提取开始年龄 | 268 | withdrawal_start_age: 'withdrawal_start_age', // 提取开始年龄 |
| 269 | withdrawal_period: 'withdrawal_period', // 提取期 | 269 | withdrawal_period: 'withdrawal_period', // 提取期 |
| 270 | - currency_type: 'currency_type' // 币种类型 | 270 | + currency_type: 'currency_type', // 币种类型 |
| 271 | + // 新增字段映射 | ||
| 272 | + annual_withdrawal_amount: 'annual_withdrawal_amount', // 每年提取金额 | ||
| 273 | + annual_increase_percentage: 'annual_increase_percentage' // 每年递增提取百分比 | ||
| 271 | } | 274 | } |
| 272 | 275 | ||
| 273 | // 构建请求数据 | 276 | // 构建请求数据 |
| ... | @@ -286,7 +289,18 @@ const submit = async () => { | ... | @@ -286,7 +289,18 @@ const submit = async () => { |
| 286 | const coverageInYuan = (formData.value[key] / 100).toFixed(2) | 289 | const coverageInYuan = (formData.value[key] / 100).toFixed(2) |
| 287 | console.log(`[PlanFormContainer] coverage 转换: ${key} (${formData.value[key]} 分) → ${apiField} (${coverageInYuan} 元)`) | 290 | console.log(`[PlanFormContainer] coverage 转换: ${key} (${formData.value[key]} 分) → ${apiField} (${coverageInYuan} 元)`) |
| 288 | requestData[apiField] = coverageInYuan | 291 | requestData[apiField] = coverageInYuan |
| 289 | - } else { | 292 | + } |
| 293 | + // 特殊处理:annual_withdrawal_amount(分)需要转换为元 | ||
| 294 | + else if (key === 'annual_withdrawal_amount') { | ||
| 295 | + const amountInYuan = (formData.value[key] / 100).toFixed(2) | ||
| 296 | + console.log(`[PlanFormContainer] annual_withdrawal_amount 转换: ${key} (${formData.value[key]} 分) → ${apiField} (${amountInYuan} 元)`) | ||
| 297 | + requestData[apiField] = amountInYuan | ||
| 298 | + } | ||
| 299 | + // 特殊处理:annual_increase_percentage(直接传递,已是字符串) | ||
| 300 | + else if (key === 'annual_increase_percentage') { | ||
| 301 | + requestData[apiField] = formData.value[key] | ||
| 302 | + } | ||
| 303 | + else { | ||
| 290 | requestData[apiField] = formData.value[key] | 304 | requestData[apiField] = formData.value[key] |
| 291 | } | 305 | } |
| 292 | } else if (key === 'total_amount') { | 306 | } else if (key === 'total_amount') { | ... | ... |
| ... | @@ -41,6 +41,7 @@ | ... | @@ -41,6 +41,7 @@ |
| 41 | v-model="form.coverage" | 41 | v-model="form.coverage" |
| 42 | label="保额" | 42 | label="保额" |
| 43 | placeholder="请输入保额" | 43 | placeholder="请输入保额" |
| 44 | + :input-label="'请输入保额金额'" | ||
| 44 | :currency="config.currency" | 45 | :currency="config.currency" |
| 45 | :required="true" | 46 | :required="true" |
| 46 | class="mb-5" | 47 | class="mb-5" | ... | ... |
| ... | @@ -41,6 +41,7 @@ | ... | @@ -41,6 +41,7 @@ |
| 41 | v-model="form.coverage" | 41 | v-model="form.coverage" |
| 42 | label="保额" | 42 | label="保额" |
| 43 | placeholder="请输入保额" | 43 | placeholder="请输入保额" |
| 44 | + :input-label="'请输入保额金额'" | ||
| 44 | :currency="config.currency" | 45 | :currency="config.currency" |
| 45 | :required="true" | 46 | :required="true" |
| 46 | class="mb-5" | 47 | class="mb-5" | ... | ... |
| ... | @@ -41,6 +41,7 @@ | ... | @@ -41,6 +41,7 @@ |
| 41 | v-model="form.coverage" | 41 | v-model="form.coverage" |
| 42 | label="年缴保费" | 42 | label="年缴保费" |
| 43 | placeholder="请输入年缴保费" | 43 | placeholder="请输入年缴保费" |
| 44 | + :input-label="'请输入年缴保费金额'" | ||
| 44 | :currency="config.currency" | 45 | :currency="config.currency" |
| 45 | :required="true" | 46 | :required="true" |
| 46 | class="mb-5" | 47 | class="mb-5" |
| ... | @@ -96,16 +97,16 @@ | ... | @@ -96,16 +97,16 @@ |
| 96 | 97 | ||
| 97 | <!-- 按年岁 --> | 98 | <!-- 按年岁 --> |
| 98 | <template v-if="form.specified_amount_type === '按年岁'"> | 99 | <template v-if="form.specified_amount_type === '按年岁'"> |
| 99 | - <!-- 提取金额币种(只读) --> | 100 | + <!-- 每年提取金额 --> |
| 100 | - <div class="mb-5"> | 101 | + <PlanFieldAmount |
| 101 | - <div class="text-sm text-gray-600 mb-2 flex items-center"> | 102 | + v-model="form.annual_withdrawal_amount" |
| 102 | - <span class="text-red-500 mr-1">*</span> | 103 | + label="每年提取金额" |
| 103 | - <span>提取金额币种</span> | 104 | + placeholder="请输入每年提取金额" |
| 104 | - </div> | 105 | + :input-label="'请输入每年提取金额'" |
| 105 | - <div class="px-4 py-3 bg-gray-50 rounded-lg border border-gray-200"> | 106 | + :currency="config.withdrawal_plan.default_currency" |
| 106 | - <span class="text-gray-900">{{ currencyLabel }}</span> | 107 | + :required="true" |
| 107 | - </div> | 108 | + class="mb-5" |
| 108 | - </div> | 109 | + /> |
| 109 | 110 | ||
| 110 | <!-- 由几岁开始 --> | 111 | <!-- 由几岁开始 --> |
| 111 | <PlanFieldAgePicker | 112 | <PlanFieldAgePicker |
| ... | @@ -133,9 +134,10 @@ | ... | @@ -133,9 +134,10 @@ |
| 133 | <span>每年递增提取之百分比(%)</span> | 134 | <span>每年递增提取之百分比(%)</span> |
| 134 | </div> | 135 | </div> |
| 135 | <nut-input | 136 | <nut-input |
| 136 | - v-model="form.increase_rate" | 137 | + v-model="form.annual_increase_percentage" |
| 137 | type="digit" | 138 | type="digit" |
| 138 | placeholder="请输入递增百分比" | 139 | placeholder="请输入递增百分比" |
| 140 | + @input="onPercentageInput" | ||
| 139 | class="w-full" | 141 | class="w-full" |
| 140 | /> | 142 | /> |
| 141 | </div> | 143 | </div> |
| ... | @@ -272,7 +274,9 @@ const initializeForm = (value) => { | ... | @@ -272,7 +274,9 @@ const initializeForm = (value) => { |
| 272 | withdrawal_enabled: value.withdrawal_enabled || '否', | 274 | withdrawal_enabled: value.withdrawal_enabled || '否', |
| 273 | withdrawal_mode: value.withdrawal_mode || '指定提取金额', | 275 | withdrawal_mode: value.withdrawal_mode || '指定提取金额', |
| 274 | specified_amount_type: value.specified_amount_type || '按年岁', | 276 | specified_amount_type: value.specified_amount_type || '按年岁', |
| 275 | - withdrawal_currency: value.withdrawal_currency || props.config?.withdrawal_plan?.default_currency || 'HKD' | 277 | + // 新字段默认值(使用 null 以匹配 AmountKeyboard 的 Number 类型) |
| 278 | + annual_withdrawal_amount: value.annual_withdrawal_amount ?? null, | ||
| 279 | + annual_increase_percentage: value.annual_increase_percentage ?? null | ||
| 276 | }) | 280 | }) |
| 277 | } | 281 | } |
| 278 | 282 | ||
| ... | @@ -304,7 +308,9 @@ watch( | ... | @@ -304,7 +308,9 @@ watch( |
| 304 | withdrawal_enabled: newVal.withdrawal_enabled || '否', | 308 | withdrawal_enabled: newVal.withdrawal_enabled || '否', |
| 305 | withdrawal_mode: newVal.withdrawal_mode || '指定提取金额', | 309 | withdrawal_mode: newVal.withdrawal_mode || '指定提取金额', |
| 306 | specified_amount_type: newVal.specified_amount_type || '按年岁', | 310 | specified_amount_type: newVal.specified_amount_type || '按年岁', |
| 307 | - withdrawal_currency: newVal.withdrawal_currency || props.config?.withdrawal_plan?.default_currency || 'HKD' | 311 | + // 新字段默认值(使用 null 以匹配 AmountKeyboard 的 Number 类型) |
| 312 | + annual_withdrawal_amount: newVal.annual_withdrawal_amount ?? null, | ||
| 313 | + annual_increase_percentage: newVal.annual_increase_percentage ?? null | ||
| 308 | }) | 314 | }) |
| 309 | previousModelValue = newVal | 315 | previousModelValue = newVal |
| 310 | } | 316 | } |
| ... | @@ -322,22 +328,6 @@ watch( | ... | @@ -322,22 +328,6 @@ watch( |
| 322 | ) | 328 | ) |
| 323 | 329 | ||
| 324 | /** | 330 | /** |
| 325 | - * 提取金额币种标签(用于显示) | ||
| 326 | - * @type {ComputedRef<string>} | ||
| 327 | - * @description 显示币种的完整名称,如"港币 HKD" | ||
| 328 | - */ | ||
| 329 | -const currencyLabel = computed(() => { | ||
| 330 | - const currencyCode = props.config?.withdrawal_plan?.default_currency || 'HKD' | ||
| 331 | - const currencyNames = { | ||
| 332 | - 'HKD': '港币', | ||
| 333 | - 'USD': '美元', | ||
| 334 | - 'CNY': '人民币', | ||
| 335 | - 'EUR': '欧元' | ||
| 336 | - } | ||
| 337 | - return `${currencyNames[currencyCode] || currencyCode} ${currencyCode}` | ||
| 338 | -}) | ||
| 339 | - | ||
| 340 | -/** | ||
| 341 | * 提取年期选项(从配置读取) | 331 | * 提取年期选项(从配置读取) |
| 342 | * @type {ComputedRef<Array<string>>} | 332 | * @type {ComputedRef<Array<string>>} |
| 343 | */ | 333 | */ |
| ... | @@ -366,9 +356,8 @@ const onWithdrawalModeChange = (mode) => { | ... | @@ -366,9 +356,8 @@ const onWithdrawalModeChange = (mode) => { |
| 366 | if (mode === '最高固定提取金额') { | 356 | if (mode === '最高固定提取金额') { |
| 367 | // 最高固定金额模式不需要指定金额的相关字段 | 357 | // 最高固定金额模式不需要指定金额的相关字段 |
| 368 | delete form.specified_amount_type | 358 | delete form.specified_amount_type |
| 369 | - delete form.withdrawal_currency | 359 | + delete form.annual_withdrawal_amount |
| 370 | - delete form.annual_amount | 360 | + delete form.annual_increase_percentage |
| 371 | - delete form.increase_rate | ||
| 372 | } else if (mode === '指定提取金额') { | 361 | } else if (mode === '指定提取金额') { |
| 373 | // 指定提取金额模式(按年岁),保留现有字段 | 362 | // 指定提取金额模式(按年岁),保留现有字段 |
| 374 | } | 363 | } |
| ... | @@ -385,16 +374,53 @@ watch( | ... | @@ -385,16 +374,53 @@ watch( |
| 385 | // 清除所有提取计划相关字段 | 374 | // 清除所有提取计划相关字段 |
| 386 | delete form.withdrawal_mode | 375 | delete form.withdrawal_mode |
| 387 | delete form.specified_amount_type | 376 | delete form.specified_amount_type |
| 388 | - delete form.withdrawal_currency | ||
| 389 | delete form.withdrawal_start_age | 377 | delete form.withdrawal_start_age |
| 390 | delete form.withdrawal_period | 378 | delete form.withdrawal_period |
| 391 | - delete form.annual_amount | 379 | + delete form.annual_withdrawal_amount |
| 392 | - delete form.increase_rate | 380 | + delete form.annual_increase_percentage |
| 393 | } | 381 | } |
| 394 | } | 382 | } |
| 395 | ) | 383 | ) |
| 396 | 384 | ||
| 397 | /** | 385 | /** |
| 386 | + * 百分比输入限制(实时) | ||
| 387 | + * @description 限制百分比输入为有效数值,最多2位小数 | ||
| 388 | + * 只允许输入数字和一个小数点 | ||
| 389 | + * @param {string} value - 输入值 | ||
| 390 | + */ | ||
| 391 | +const onPercentageInput = (value) => { | ||
| 392 | + // 转换为字符串(处理 value 为 null 或其他类型的情况) | ||
| 393 | + let strValue = String(value ?? '') | ||
| 394 | + | ||
| 395 | + // 移除所有非数字字符(保留小数点) | ||
| 396 | + let cleaned = strValue.replace(/[^0-9.]/g, '') | ||
| 397 | + | ||
| 398 | + // 只允许一个小数点 | ||
| 399 | + const parts = cleaned.split('.') | ||
| 400 | + if (parts.length > 2) { | ||
| 401 | + cleaned = parts[0] + '.' + parts.slice(1).join('') | ||
| 402 | + } | ||
| 403 | + | ||
| 404 | + // 限制小数位数为2位 | ||
| 405 | + if (parts.length === 2 && parts[1].length > 2) { | ||
| 406 | + cleaned = parts[0] + '.' + parts[1].slice(0, 2) | ||
| 407 | + } | ||
| 408 | + | ||
| 409 | + // 限制范围:0-100 | ||
| 410 | + const numValue = parseFloat(cleaned) | ||
| 411 | + if (!Number.isNaN(numValue)) { | ||
| 412 | + if (numValue > 100) { | ||
| 413 | + cleaned = '100' | ||
| 414 | + } else if (numValue < 0) { | ||
| 415 | + cleaned = '0' | ||
| 416 | + } | ||
| 417 | + } | ||
| 418 | + | ||
| 419 | + // 更新表单值 | ||
| 420 | + form.annual_increase_percentage = cleaned | ||
| 421 | +} | ||
| 422 | + | ||
| 423 | +/** | ||
| 398 | * 表单校验 | 424 | * 表单校验 |
| 399 | * @returns {boolean} 是否通过校验 | 425 | * @returns {boolean} 是否通过校验 |
| 400 | */ | 426 | */ |
| ... | @@ -455,14 +481,21 @@ const validate = () => { | ... | @@ -455,14 +481,21 @@ const validate = () => { |
| 455 | } | 481 | } |
| 456 | 482 | ||
| 457 | if (form.specified_amount_type === '按年岁') { | 483 | if (form.specified_amount_type === '按年岁') { |
| 458 | - if (!form.withdrawal_currency) { | 484 | + if (!form.annual_withdrawal_amount || form.annual_withdrawal_amount === '') { |
| 459 | - Taro.showToast({ title: '请选择提取金额币种', icon: 'none' }) | 485 | + Taro.showToast({ title: '请输入每年提取金额', icon: 'none' }) |
| 460 | return false | 486 | return false |
| 461 | } | 487 | } |
| 462 | - if (form.increase_rate === undefined || form.increase_rate === '') { | 488 | + if (form.annual_increase_percentage === undefined || form.annual_increase_percentage === '') { |
| 463 | Taro.showToast({ title: '请输入每年递增提取之百分比', icon: 'none' }) | 489 | Taro.showToast({ title: '请输入每年递增提取之百分比', icon: 'none' }) |
| 464 | return false | 490 | return false |
| 465 | } | 491 | } |
| 492 | + | ||
| 493 | + // 验证百分比范围 | ||
| 494 | + const percentage = parseFloat(form.annual_increase_percentage) | ||
| 495 | + if (Number.isNaN(percentage) || percentage < 0 || percentage > 100) { | ||
| 496 | + Taro.showToast({ title: '请输入0-100之间的百分比', icon: 'none' }) | ||
| 497 | + return false | ||
| 498 | + } | ||
| 466 | } | 499 | } |
| 467 | } else if (form.withdrawal_mode === '最高固定提取金额') { | 500 | } else if (form.withdrawal_mode === '最高固定提取金额') { |
| 468 | if (form.withdrawal_start_age === undefined || form.withdrawal_start_age === '') { | 501 | if (form.withdrawal_start_age === undefined || form.withdrawal_start_age === '') { | ... | ... |
| ... | @@ -123,7 +123,7 @@ export const PLAN_TEMPLATES = { | ... | @@ -123,7 +123,7 @@ export const PLAN_TEMPLATES = { |
| 123 | withdrawal_plan: { | 123 | withdrawal_plan: { |
| 124 | enabled: true, | 124 | enabled: true, |
| 125 | currencies: ['HKD', 'USD', 'CNY'], // 支持的币种 | 125 | currencies: ['HKD', 'USD', 'CNY'], // 支持的币种 |
| 126 | - default_currency: 'HKD', | 126 | + default_currency: 'USD', // 统一为美元 |
| 127 | withdrawal_modes: [ | 127 | withdrawal_modes: [ |
| 128 | '年龄指定金额', // 方式1 | 128 | '年龄指定金额', // 方式1 |
| 129 | '最高固定金额' // 方式2 | 129 | '最高固定金额' // 方式2 |
| ... | @@ -159,7 +159,7 @@ export const PLAN_TEMPLATES = { | ... | @@ -159,7 +159,7 @@ export const PLAN_TEMPLATES = { |
| 159 | withdrawal_plan: { | 159 | withdrawal_plan: { |
| 160 | enabled: true, | 160 | enabled: true, |
| 161 | currencies: ['HKD', 'USD', 'CNY'], | 161 | currencies: ['HKD', 'USD', 'CNY'], |
| 162 | - default_currency: 'HKD', | 162 | + default_currency: 'USD', // 统一为美元 |
| 163 | withdrawal_modes: ['年龄指定金额', '最高固定金额'], | 163 | withdrawal_modes: ['年龄指定金额', '最高固定金额'], |
| 164 | withdrawal_periods: [ | 164 | withdrawal_periods: [ |
| 165 | '1年', | 165 | '1年', |
| ... | @@ -192,7 +192,7 @@ export const PLAN_TEMPLATES = { | ... | @@ -192,7 +192,7 @@ export const PLAN_TEMPLATES = { |
| 192 | withdrawal_plan: { | 192 | withdrawal_plan: { |
| 193 | enabled: true, | 193 | enabled: true, |
| 194 | currencies: ['HKD', 'USD', 'CNY'], | 194 | currencies: ['HKD', 'USD', 'CNY'], |
| 195 | - default_currency: 'HKD', | 195 | + default_currency: 'USD', // 统一为美元 |
| 196 | withdrawal_modes: ['年龄指定金额', '最高固定金额'], | 196 | withdrawal_modes: ['年龄指定金额', '最高固定金额'], |
| 197 | withdrawal_periods: [ | 197 | withdrawal_periods: [ |
| 198 | '1年', | 198 | '1年', |
| ... | @@ -226,7 +226,7 @@ export const PLAN_TEMPLATES = { | ... | @@ -226,7 +226,7 @@ export const PLAN_TEMPLATES = { |
| 226 | withdrawal_plan: { | 226 | withdrawal_plan: { |
| 227 | enabled: true, | 227 | enabled: true, |
| 228 | currencies: ['HKD', 'USD', 'CNY'], | 228 | currencies: ['HKD', 'USD', 'CNY'], |
| 229 | - default_currency: 'HKD', | 229 | + default_currency: 'USD', // 统一为美元 |
| 230 | withdrawal_modes: ['年龄指定金额', '最高固定金额'], | 230 | withdrawal_modes: ['年龄指定金额', '最高固定金额'], |
| 231 | withdrawal_periods: [ | 231 | withdrawal_periods: [ |
| 232 | '1年', | 232 | '1年', | ... | ... |
-
Please register or login to post a comment