SFT/docs/superpowers/specs/2026-07-23-personal-open-co...

5.9 KiB
Raw Permalink Blame History

个人开户"确认"二次确认弹窗 + 邀请扫码办理 设计文档

背景

src/views/wallet/personal-open/PersonalOpenForm.vue(新增个人开户申请页)当前点击顶部"确认"按钮后,直接执行前置校验并调用 create-draft 接口提交,没有任何二次确认环节。产品要求新增二次确认弹窗,并在弹窗中提供"邀请扫码办理"选项,允许柜员生成二维码交由客户扫码办理(扫码后走向的移动端 H5 页面本身不在本项目前端实现范围内,仅需生成二维码内容并展示)。

本次改动只影响 PersonalOpenForm.vue新增create模式"确认"按钮流程编辑edit模式的"保存"按钮不受影响。

交互流程

  1. 用户在新增个人开户表单页填写完信息,点击顶部"确认"按钮。
  2. 前端执行现有的全部前置校验(原 handleSubmit 中 441-470 行逻辑):
    • 是否已勾选协议
    • 是否已选择渠道归属
    • 是否已选择客户
    • 证件照片是否仍在上传中
    • 创建模式下是否已上传身份证正反面 + 正面免冠照
    • 身份证 OCR 信息是否与所选客户一致
    • 表单 formRef.value.validate() 是否通过
    • 任意一项不通过:按现有方式提示错误(showErrorModal不弹出二次确认弹窗
  3. 全部通过后,弹出"提示"二次确认弹窗(对应产品提供的截图),弹窗内容:"是否确认开户?",三个按钮:保存(主按钮)/ 取消 / 邀请扫码办理
  4. 弹窗内点击保存
    • 调用 create-draft 接口(逻辑与现有提交一致:构造 payload + fileList)。
    • 成功(code === 200):记录 submittedApplicationNomessage.success('申请已提交'),关闭弹窗。表单页因 submittedApplicationNo 有值而自动切换到现有的"开户申请已提交"结果面板(既有 template 条件不变)。
    • 失败:由全局响应拦截器统一弹出错误提示(showErrorModal,见 src/api/request.js 响应拦截器),弹窗保持打开,允许用户重试或取消。
  5. 弹窗内点击取消:仅关闭弹窗,不发任何请求,不做页面跳转,表单数据保留,用户可以继续修改后重新点击"确认"。
  6. 弹窗内点击邀请扫码办理
    • 调用与"保存"完全相同的提交逻辑(同一个 create-draft 接口),拿到 applicationNo 并同样记录到 submittedApplicationNo(因此背后的表单页状态与点"保存"效果一致,会进入"已提交"结果面板)。
    • 成功后不关闭弹窗,而是把弹窗内容切换为"二维码展示"态:显示二维码图片 + "申请编号:{applicationNo}" 文字 + "关闭"按钮;不额外弹出"申请已提交"的 message 提示(避免和二维码展示态叠加打扰)。
    • 二维码内容为一个完整 URL${VITE_H5_QRCODE_BASE_URL}${VITE_H5_QRCODE_PATH}?applicationNo=${applicationNo}。域名/路径通过环境变量配置(见下),当前域名尚未确定,未配置时使用占位域名照常生成二维码(不阻断流程)。
    • 用户点击"关闭"或弹窗右上角 X仅关闭弹窗此时表单页已处于"已提交"结果面板状态(与点保存效果一致)。
    • 失败:同上由全局拦截器提示,弹窗保持在"确认"态,允许重试。

UI 结构

复用 ant-design-vuea-modal

  • title="提示"
  • :footer="null"(按钮放在正文里自定义,与截图一致)
  • :mask-closable="false"(避免误触遮罩关闭)
  • 内部用一个 confirmModalStep ref'confirm' | 'qrcode')控制展示"确认文案+三按钮"还是"二维码+关闭按钮"两种视图。

二维码组件使用新增依赖 qrcode.vueVue3 兼容,peerDependencies: vue ^3.0.0),以 <qrcode-vue :value="qrCodeUrl" :size="200" /> 方式渲染。

代码结构调整(PersonalOpenForm.vue

将原 handleSubmit 拆分为职责更清晰的几个函数,避免重复代码:

  • validateBeforeSubmit():抽取原 441-470 行的全部前置校验(含 formRef.value.validate()),返回 boolean(或 reject。供"确认"按钮预检和 isEdit 保存流程共用。
  • buildSubmitPayload():抽取原 473-495 行 fileList/payload 构造逻辑,供 create 提交与 edit 保存共用。
  • submitCreateDraft():仅负责调用 createPersonalOpenDraftApi,成功后设置 submittedApplicationNo 并返回 applicationNo;失败返回 null(错误提示交给全局拦截器)。供弹窗内"保存"与"邀请扫码办理"共用,各自维护自己的 loading refmodalSaving / modalInviting),防止重复点击。
  • handleConfirmButtonClick():新增个人开户"确认"按钮的点击处理——调用 validateBeforeSubmit(),通过后打开确认弹窗(confirmModalVisible = trueconfirmModalStep = 'confirm')。
  • handleEditSubmit():原 handleSubmitisEdit 分支逻辑原样保留(校验 + 调用 updatePersonalOpenApplicationApi),仅改名,行为不变,绑定到编辑模式"保存"按钮。

环境变量

新增于 .env.development.env.production

VITE_H5_QRCODE_BASE_URL=
VITE_H5_QRCODE_PATH=/mobile/personal-open

VITE_H5_QRCODE_BASE_URL 留空时使用代码内占位域名(如 https://example.com)兜底拼接,保证二维码始终可以生成;域名确定后运维/开发只需在 .env.production 中填入真实域名即可,无需改代码。

依赖变更

新增 qrcode.vuedependencies

范围边界

  • 不实现移动端 H5 扫码后的确认页面(personal-opening/mobile/*),本次改动只负责柜员端生成二维码内容并展示。
  • 不改动 isEdit(编辑)模式的提交流程与按钮。
  • 不改动 isDetail(查看)模式。
  • 不引入全局的 busy/a-spin 统一遮罩规范补齐(该页面现状缺口不在本次需求范围内,维持现状,仅用按钮级 loading 防重复点击)。