16 KiB
贷款申请移动端H5信息核对页 设计文档
背景
《缺失的后端接口.md》第145/147条曾记载:贷款申请扫码后的移动端H5确认页(短信验证+人脸识别,对应 POST /api/credit-apply/loan-application/confirm)此前"不在本项目前端实现范围",原因是该接口鉴权情况不明、且贷款场景无专用发码接口。本次任务是把这块补上:
- 新增"个人贷款申请信息核对"H5页面(
fryl_h5子工程,匿名访问)。 - 新增"企业贷款申请信息核对"H5页面(同上)。
- 给管理后台
src/views/credit/loan-application/EnterpriseLoanForm.vue补齐与PersonalLoanForm.vue一致的"二次确认弹窗+二维码"入口(该表单本次改造前明确"不引入二维码模式",见2026-08-10-enterprise-loan-application-form-redesign.md第5条,本次改变这一决定)。
页面严格按 ./授信信息核对页面截图/1.jpg~5.jpg(1、2为个人;3、4、5为企业)的字段与步骤结构实现,5张截图已逐张读取分析,详见下文。
关键决策(已与用户确认,不再更改)
- 短信验证码走真实发送+真实校验,
verifyCode与其他信息一起提交给confirm接口。 - 发码接口复用现有
POST /api/wallet-management/personal-opening/mobile/send-verify-code/general(tradeNo固定"221506"、tradeType固定"0"),不新增专用发码接口。 - 页面结构为多步骤手风琴(与开户H5一致的"折叠步骤行"交互),非单页。
- 个人贷款和企业贷款的二维码路径是两条独立路径(不是共用一个路径按类型区分),架构完全对齐现有开户H5模式(
PersonalOpenMobile.vue/EnterpriseOpenMobile.vue两个独立组件+两条独立路由)。 - 信息核对步骤严格按截图1.jpg(个人)/3.jpg(企业)字段展示;业务类型文案照抄截图原文案"授信申请"(不改为"贷款申请")。
- 企业侧"人脸比对"步骤简化为拍照上传模式(复用现有
FaceCompareStep.vue的交互模式,UI文案对齐截图改为"开始采集"),比对接口复用个人开户的face-recognize接口,legalPersonCertId当idNo、legalPersonName当name。 - 信息核对步骤拆分为
PersonalLoanInfoConfirmStep.vue/EnterpriseLoanInfoConfirmStep.vue两个独立组件(与现有开户H5InfoConfirmStep.vue/EnterpriseInfoConfirmStep.vue分开的先例保持一致)。 - 完成页参照现有
ResultStep.vue的成功/失败展示模式改造为LoanResultStep.vue(5张截图均未展示"完成"步骤实际内容,无截图可依)。 - 发码接口所需的"标准四要素+渠道编号",个人贷款场景要求后端在
LoanApplicationDetailVo新增channelNo/certificateNumber/bankCardNumber三个字段;企业贷款场景channelNo同样要求新增,idNo复用已有legalPersonCertId,cardNo(银行卡号)因企业本身无此概念,前端传空字符串并登记风险。
截图分析结果
1.jpg / 2.jpg(个人,"稠州个人授信申请")
- 顶部蓝色横幅:"业务确认" + 副标题"稠州个人授信申请" + 浙江稠州商业银行logo。
- 步骤条3步:1.信息核对 → 2.手机验证 → 3.完成。
- 信息核对字段(label-value两列):业务类型="稠州个人授信申请"(固定文案);办理渠道="巺平(线上)";客户=customerName;手机号="130****2222"(3+4+4脱敏);金额="¥20.00万元";利率="年化9.00%"。底部按钮"确认无误,下一步"。
- 手机验证步骤:红字提示"请确认手机号:130****2222" + 验证码输入框 + "发送"按钮 + "提交"按钮。
3.jpg / 4.jpg / 5.jpg(企业,"稠州企业授信申请")
- 步骤条4步:1.信息核对 → 2.人脸比对 → 3.手机验证 → 4.完成(比个人多"人脸比对")。
- 信息核对字段结构与个人一致:业务类型="稠州企业授信申请";办理渠道="巺平(线上)";客户=enterpriseName;手机号="157****1164";金额="¥1000.00万元";利率="年化10.00%"。
- 人脸比对步骤:人物占位图 + 提示文案"请保证光线充足,摘除帽子,正视屏幕,点击"开始采集"按钮" + "开始采集"按钮。
- 手机验证步骤:与个人版UI一致(红字手机号确认+验证码输入框+发送(倒计时)按钮+提交按钮)。
后端接口契约(来自 swagger_project_scfs_2026-08-05_15-15-22.json,均无鉴权标注)
POST /api/credit-apply/loan-application/detail
请求:{ loanApplicationId }(必填)。
响应 LoanApplicationDetailVo(个人/企业合并Vo,约60字段),本次用到的字段:
| 字段 | 说明 |
|---|---|
applicationType |
PERSONAL/BUSINESS |
applicationStatus |
DRAFT/CONFIRMED/SUBMITTED/APPLY_FAILED |
channel |
渠道展示字符串(如"巺平"),非渠道编码 |
customerName |
客户名称(个人贷款场景=客户本人姓名) |
enterpriseName |
经营实体名称(企业贷款场景展示用) |
phoneNo |
手机号(个人/企业贷款场景通用的联系手机号,柜员在表单里手工录入的独立字段,非法人手机号) |
loanAmount |
申请金额(字符串) |
applicationInterestRate |
申请利率(字符串) |
legalPersonName/legalPersonCertId |
法人姓名/证件号码(企业贷款人脸比对用) |
frchainOnlineSerialNo |
凡荣e链任务流水号(SUBMITTED时返回) |
failReason |
失败原因(APPLY_FAILED时返回) |
以下字段当前不存在,需登记后端新增(见"待登记后端缺口"):channelNo、certificateNumber(个人证件号码)、bankCardNumber(个人银行卡号)。
POST /api/credit-apply/loan-application/confirm
请求:{ loanApplicationId(必填), verifyCode(选填,描述为"个人申请必填"), fileNoList(选填,逗号分隔影像文件编号) }。
响应 ConfirmLoanApplicationResultVo:{ loanApplicationId, applicationStatus, frchainOnlineSerialNo(SUBMITTED时返回), failReason(APPLY_FAILED时返回) }。
业务逻辑(后端描述):校验状态为 DRAFT 后更新为 CONFIRMED,并调用凡荣e链贷款申请接口。
整体架构
路由与二维码路径
个人贷款与企业贷款使用两条完全独立的路径(对齐开户H5模式):
| 场景 | 环境变量 | 默认路径 | 说明 |
|---|---|---|---|
| 个人贷款 | VITE_H5_QRCODE_PATH_LOAN |
/mobile/loan-application |
已存在,本次沿用不变 |
| 企业贷款 | VITE_H5_QRCODE_PATH_LOAN_ENTERPRISE |
/mobile/enterprise-loan-application |
新增,命名对齐现有 VITE_H5_QRCODE_PATH_ENTERPRISE(开户场景)的风格 |
二维码内容均为 ${base}${path}?loanApplicationId=${id},域名复用同一个 VITE_H5_QRCODE_BASE_URL。
新增文件(fryl_h5/src/)
views/PersonalLoanApplicationMobile.vue # 个人贷款H5页面,3步向导
views/EnterpriseLoanApplicationMobile.vue # 企业贷款H5页面,4步向导
views/steps/loan/PersonalLoanInfoConfirmStep.vue
views/steps/loan/EnterpriseLoanInfoConfirmStep.vue
views/steps/loan/LoanFaceCompareStep.vue # 企业专属
views/steps/loan/LoanSmsVerifyStep.vue # 个人/企业共用,通过 applicationType prop 区分发码参数
views/steps/loan/LoanResultStep.vue # 个人/企业共用
api/loanApplication.js # fetchLoanApplicationDetailApi / sendVerifyCodeApi / confirmLoanApplicationApi
utils/format.js # formatLoanAmountToWan(amount),公式对齐 LoanApplicationList.vue 现有 formatToWan
修改文件
fryl_h5/src/router/index.js:新增两条静态路由(无鉴权,与现状一致)。fryl_h5/src/utils/mask.js:补充maskMobile(保留前3位后4位,中间****,从主项目src/utils/mask.js原样搬入)。src/utils/qrCode.js:新增buildEnterpriseLoanApplicationQrCodeUrl。.env.development/.env.production:新增VITE_H5_QRCODE_PATH_LOAN_ENTERPRISE。src/views/credit/loan-application/EnterpriseLoanForm.vue:补齐二次确认弹窗+二维码(见下)。
个人贷款H5页面设计(PersonalLoanApplicationMobile.vue)
整体骨架复用 PersonalOpenMobile.vue 的手风琴模式(顶部蓝色横幅+银行logo,step-list+step-row+STEP_ORDER/isDone/rowClass,不支持回退)。
加载流程:route.query.loanApplicationId 缺失 → 错误态"链接无效,缺少申请编号,请重新扫描二维码";调用 detail 接口后按 applicationStatus 分支:
DRAFT:正常进入向导,从INFO步骤开始。SUBMITTED/APPLY_FAILED:说明客户已完成过确认流程(重复扫码/刷新页面等场景),直接跳到RESULT步骤展示最终结果,不再重新走INFO/SMS,体验优于生硬报错。CONFIRMED:理论上是极短暂的中间态(confirm接口内部会同步转成SUBMITTED/APPLY_FAILED),如果查询到该状态,展示错误态"该贷款申请正在处理中,请稍候重新扫描二维码"。
STEP_ORDER = ['INFO', 'SMS', 'RESULT'],横幅副标题固定文案"稠州个人授信申请"。
步骤1:信息核对(PersonalLoanInfoConfirmStep.vue)
纯展示,不调接口。label-value两列:
| 字段 | 取值 |
|---|---|
| 业务类型 | 固定文案"稠州个人授信申请" |
| 办理渠道 | ${detail.channel}(线上) |
| 客户 | detail.customerName |
| 手机号 | maskMobile(detail.phoneNo) |
| 金额 | ¥${formatLoanAmountToWan(detail.loanAmount)}万元(loanAmount 原始单位为元,需 /10000 换算,公式对齐 LoanApplicationList.vue 现有的 formatToWan,带千分位两位小数,仅后缀文案由"万"改为"万元"以对齐截图) |
| 利率 | 年化${Number(detail.applicationInterestRate).toFixed(2)}%(applicationInterestRate 本身即百分数数值,无需换算) |
底部按钮"确认无误,下一步" → currentStep = 'SMS'。
步骤2:手机验证(LoanSmsVerifyStep.vue)
UI参照现有 SmsVerifyStep.vue(手机号展示+验证码输入框+60s倒计时发送按钮+提交按钮)。
发送验证码参数:
sendVerifyCodeApi({
tradeNo: '221506',
tradeType: '0',
mobile: detail.phoneNo,
cardNo: detail.bankCardNumber, // 新增字段,需后端补充
cardName: detail.customerName,
idNo: detail.certificateNumber, // 新增字段,需后端补充
channelNo: detail.channelNo // 新增字段,需后端补充
})
提交:confirmLoanApplicationApi({ loanApplicationId, verifyCode })。
步骤3:完成(LoanResultStep.vue)
applicationStatus === 'SUBMITTED':成功态,展示"提交成功"+frchainOnlineSerialNo。applicationStatus === 'APPLY_FAILED':失败态,展示failReason。- 其他:兜底展示"处理中,请稍候"(理论上不会出现,仅防止页面空白)。
组件 props 接受一个通用 { applicationStatus, frchainOnlineSerialNo, failReason } 对象,两个来源结构一致,无需转换:① confirm 接口正常提交后的返回值(ConfirmLoanApplicationResultVo);② 重复扫码场景下直接从 detail 接口返回值中取同名字段(LoanApplicationDetailVo 本身就带这三个字段)。
企业贷款H5页面设计(EnterpriseLoanApplicationMobile.vue)
STEP_ORDER = ['INFO', 'FACE', 'SMS', 'RESULT'],横幅副标题固定文案"稠州企业授信申请"。加载流程与个人版一致。
步骤1:信息核对(EnterpriseLoanInfoConfirmStep.vue)
| 字段 | 取值 |
|---|---|
| 业务类型 | 固定文案"稠州企业授信申请" |
| 办理渠道 | ${detail.channel}(线上) |
| 客户 | detail.enterpriseName |
| 手机号 | maskMobile(detail.phoneNo) |
| 金额 | ¥${formatLoanAmountToWan(detail.loanAmount)}万元(同上,/10000 换算) |
| 利率 | 年化${Number(detail.applicationInterestRate).toFixed(2)}% |
步骤2:人脸比对(LoanFaceCompareStep.vue,企业专属)
- UI参照现有
FaceCompareStep.vue(van-uploader拍照上传一张照片→自动调用识别接口),文案改为对齐截图:"请保证光线充足,摘除帽子,正视屏幕,点击"开始采集"按钮",按钮文案"开始采集"。 - 识别通过后自动进入下一步(
currentStep = 'SMS'),不支持回退,与个人开户"手机验证"自动前进模式一致。 - 接口:复用
faceRecognizeApi(/api/customer-info/personal/face-recognize),参数idNo: detail.legalPersonCertId、name: detail.legalPersonName。风险登记:接口路径含personal,企业法人场景是否被后端业务逻辑接受未知。
步骤3:手机验证(LoanSmsVerifyStep.vue,与个人共用)
发送验证码参数:
sendVerifyCodeApi({
tradeNo: '221506',
tradeType: '0',
mobile: detail.phoneNo,
cardNo: '', // 企业无银行卡号概念,风险登记
cardName: detail.legalPersonName,
idNo: detail.legalPersonCertId,
channelNo: detail.channelNo // 新增字段,需后端补充
})
提交同个人版。
步骤4:完成(LoanResultStep.vue,与个人共用)
EnterpriseLoanForm.vue 改造点
照抄 PersonalLoanForm.vue 的二次确认弹窗模式:
- "提交"按钮改为触发
handleConfirmButtonClick→ 弹出a-modal(confirmModalStep为'confirm'/'qrcode'),文案"是否确认{提交/修改}贷款申请?",三个按钮:保存/取消/扫码确认。 - 原
handleSubmit拆成submitApplication()(真正提交)+handleModalSave(保存后返回列表)+handleModalInvite(提交成功后切到二维码态)。 - 二维码态:
qrCodeUrl = buildEnterpriseLoanApplicationQrCodeUrl(loanApplicationId)。 - 引入
QrcodeVue组件(项目已有依赖qrcode.vue)。 - 原有提交前校验(影像资料上传中/协议勾选等)保留在
handleConfirmButtonClick里,校验通过才弹窗。
待登记后端缺口清单
以下问题将追加到《缺失的后端接口.md》:
LoanApplicationDetailVo缺少channelNo(渠道编号),现有channel是展示字符串,无法用作发码接口参数。需新增(个人/企业贷款共用)。LoanApplicationDetailVo缺少个人贷款客户证件号码,需新增certificateNumber字段(企业贷款已有legalPersonCertId可复用,无需新增)。LoanApplicationDetailVo缺少个人贷款客户银行卡号,需新增bankCardNumber字段。- 企业贷款场景发码接口
cardNo参数无字段来源(企业无银行卡号概念),前端暂传空字符串,风险登记待后端确认该通用发码接口在企业场景下能否容忍cardNo为空。 - 人脸识别接口
/api/customer-info/personal/face-recognize路径含personal,企业法人场景复用风险,需后端确认业务逻辑是否适用。 confirm接口verifyCode描述为"个人申请必填",企业贷款场景该字段强制校验语义不明确,前端仍会传值,风险登记以防后端做特殊处理导致提交失败。
测试/验证方式
无自动化测试脚本(项目未配置单测),按以下方式手工验证:
- 管理后台创建一条企业贷款草稿 → 点击"提交" → 验证二次确认弹窗+扫码确认+二维码展示(对照
PersonalLoanForm.vue的现有行为)。 npm run dev(fryl_h5)启动后手动访问/mobile/loan-application?loanApplicationId=xxx与/mobile/enterprise-loan-application?loanApplicationId=xxx,核对各步骤UI与截图一致、手机验证码可发送(若后端字段缺口未补齐,预期报错并提示明确的缺失原因,而非静默失败)。- 核对
applicationStatus !== 'DRAFT'时的错误态提示、confirm接口返回SUBMITTED/APPLY_FAILED两种终态的完成页展示。