文件
xionggeshop/application/admin/view/shopro_huifu/onboard/index.html
可乐加冰 ace8b830af feat(huifu): 重构并增强更换结算银行卡功能
将原本简单的卡号输入弹窗重构为完整的表单弹窗。
新增开户支行关键字搜索功能,支持自动带出联行号。
支持修改账户类型,对公账户需上传开户许可证。
增加银行卡照片上传,当卡号变更时强制重新上传。
完善提交前的卡号、手机号及必填项等前端校验逻辑。
2026-11-15 16:12:57 +08:00

222 行
16 KiB
HTML

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<link rel="stylesheet" href="__CDN__/assets/addons/shopro/libs/element/element.css">
<style>
[v-cloak] { display: none; }
.status-draft { color: #909399; }
.status-submitting, .status-basic_ok, .status-busi_pending { color: #e6a23c; }
.status-approved { color: #67c23a; }
.status-rejected, .status-failed { color: #f56c6c; }
.onboard-detail .section-title { font-size: 14px; font-weight: 600; margin: 16px 0 10px; padding-left: 8px; border-left: 3px solid #409EFF; }
.onboard-detail .info-grid { display: flex; flex-wrap: wrap; }
.onboard-detail .info-item { width: 50%; margin-bottom: 10px; font-size: 13px; line-height: 1.6; }
.onboard-detail .info-label { color: #909399; margin-right: 6px; }
.onboard-detail .photo-grid { display: flex; flex-wrap: wrap; gap: 16px; }
.onboard-detail .photo-box { width: 220px; }
.onboard-detail .photo-label { font-size: 12px; color: #606266; margin-bottom: 6px; }
.onboard-detail .photo-img { width: 220px; height: 140px; border: 1px solid #ebeef5; border-radius: 4px; background: #f5f7fa; }
.onboard-detail .biz-tip { margin-top: 12px; padding: 10px 12px; background: #fdf6ec; border: 1px solid #faecd8; border-radius: 4px; color: #e6a23c; font-size: 13px; line-height: 1.6; }
.modify-card-dialog .branch-panel { max-height: 180px; overflow-y: auto; border: 1px solid #ebeef5; border-radius: 4px; margin-top: 6px; }
.modify-card-dialog .branch-item { padding: 8px 10px; border-bottom: 1px solid #f0f0f0; cursor: pointer; }
.modify-card-dialog .branch-item:hover { background: #f5f7fa; }
.modify-card-dialog .upload-box { width: 160px; height: 100px; border: 1px dashed #dcdfe6; border-radius: 4px; display: flex; align-items: center; justify-content: center; overflow: hidden; background: #fafafa; }
.modify-card-dialog .upload-box img { max-width: 100%; max-height: 100%; object-fit: contain; }
</style>
<script src="__CDN__/assets/addons/shopro/libs/vue.js"></script>
<script src="__CDN__/assets/addons/shopro/libs/element/element.js"></script>
<div id="huifuOnboardIndex" v-cloak>
<div class="panel panel-default panel-intro">
<div class="panel-heading">
汇付个人进件
<span class="text-muted" style="font-size:12px;margin-left:12px;">用户提交资料后直连汇付;失败可手动「重提」,可选定时任务兜底重试</span>
</div>
<div class="panel-body">
<div style="margin-bottom:12px;">
<el-select v-model="filterStatus" placeholder="全部状态" clearable size="small" style="width:180px" @change="getList">
<el-option label="待后台审核(draft)" value="draft"></el-option>
<el-option label="提交中" value="submitting"></el-option>
<el-option label="汇付审核中" value="busi_pending"></el-option>
<el-option label="已通过" value="approved"></el-option>
<el-option label="已驳回" value="rejected"></el-option>
<el-option label="失败" value="failed"></el-option>
</el-select>
<el-button size="small" type="success" @click="openCreate" style="margin-left:8px;">新建进件</el-button>
<el-button size="small" type="primary" @click="getList" style="margin-left:8px;">刷新列表</el-button>
</div>
<el-table :data="listData" v-loading="loading" border empty-text="暂无进件记录">
<el-table-column prop="id" label="ID" width="70"></el-table-column>
<el-table-column prop="user_id" label="用户ID" width="90"></el-table-column>
<el-table-column prop="user_nickname" label="用户昵称" min-width="120" show-overflow-tooltip></el-table-column>
<el-table-column prop="payload_name" label="姓名" width="100"></el-table-column>
<el-table-column prop="payload_mobile" label="手机号" width="120"></el-table-column>
<el-table-column prop="role_type" label="角色" width="100">
<template slot-scope="scope">{{ roleText(scope.row.role_type) }}</template>
</el-table-column>
<el-table-column prop="business_status_text" label="业务状态" width="110"></el-table-column>
<el-table-column prop="onboard_status" label="进件状态" width="120">
<template slot-scope="scope">
<span :class="'status-' + scope.row.onboard_status">{{ statusText(scope.row.onboard_status) }}</span>
</template>
</el-table-column>
<el-table-column prop="payload_cert_no" label="身份证号" min-width="160"></el-table-column>
<el-table-column prop="payload_card_tail" label="银行卡" width="100"></el-table-column>
<el-table-column prop="updatetime" label="更新时间" width="160">
<template slot-scope="scope">{{ formatTime(scope.row.updatetime) }}</template>
</el-table-column>
<el-table-column label="操作" width="300" fixed="right">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="openDetail(scope.row.id)">查看资料</el-button>
<el-button size="mini" type="text" @click="openEdit(scope.row.id)" v-if="canEditRow(scope.row)">编辑</el-button>
<el-button size="mini" type="primary" @click="submitRow(scope.row.id)" v-if="scope.row.onboard_status === 'draft'">提交汇付</el-button>
<el-button size="mini" @click="pollRow(scope.row.id)" v-if="scope.row.onboard_status !== 'draft' && scope.row.onboard_status !== 'approved'">刷新</el-button>
<el-button size="mini" type="warning" @click="retryRow(scope.row.id)" v-if="scope.row.onboard_status === 'rejected' || scope.row.onboard_status === 'failed'">重提</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-dialog title="进件资料审核" :visible.sync="detailVisible" width="860px" top="5vh" @closed="detailData = null">
<div v-loading="detailLoading" class="onboard-detail" v-if="detailData">
<el-descriptions :column="3" border size="small">
<el-descriptions-item label="记录ID">{{ detailData.record.id }}</el-descriptions-item>
<el-descriptions-item label="用户">{{ detailData.user.nickname || '-' }} (ID: {{ detailData.user.id }})</el-descriptions-item>
<el-descriptions-item label="角色">{{ roleText(detailData.record.role_type) }}</el-descriptions-item>
<el-descriptions-item label="进件状态">
<span :class="'status-' + detailData.record.onboard_status">{{ statusText(detailData.record.onboard_status) }}</span>
</el-descriptions-item>
<el-descriptions-item label="业务状态">{{ detailData.business.status_text }}</el-descriptions-item>
<el-descriptions-item label="汇付ID">{{ detailData.record.huifu_id || '-' }}</el-descriptions-item>
<el-descriptions-item label="申请单号" :span="2">{{ detailData.record.apply_no || '-' }}</el-descriptions-item>
<el-descriptions-item label="提交时间">{{ formatTime(detailData.record.updatetime) }}</el-descriptions-item>
</el-descriptions>
<div class="biz-tip" v-if="detailData.business.status === 'pending'">
该用户业务身份仍为「待审核」,请先在{{ detailData.business.type_text }}管理中审核;若进件仍为草稿可手动「提交汇付」。
<el-button type="text" size="mini" @click="goAudit(detailData.business.audit_url)">前往业务审核</el-button>
</div>
<div class="biz-tip" v-else-if="detailData.record.onboard_status === 'draft' && detailData.business.status === 'normal'">
业务已审核通过,请核对下方资料无误后点击「提交汇付」。
</div>
<div class="section-title">身份信息</div>
<div class="info-grid">
<div class="info-item"><span class="info-label">真实姓名</span>{{ detailData.form.name || '-' }}</div>
<div class="info-item"><span class="info-label">身份证号</span>{{ detailData.form.cert_no || detailData.form.cert_no_masked || '-' }}</div>
<div class="info-item"><span class="info-label">证件有效期</span>{{ detailData.form.cert_validity_text }}</div>
<div class="info-item"><span class="info-label">证件开始</span>{{ detailData.form.cert_begin_date || '-' }}</div>
<div class="info-item"><span class="info-label">证件截止</span>{{ detailData.form.cert_end_date || (detailData.form.cert_validity_type === '1' ? '长期' : '-') }}</div>
<div class="info-item"><span class="info-label">手机号</span>{{ detailData.form.mobile_no || '-' }}</div>
</div>
<div class="section-title">银行卡信息</div>
<div class="info-grid">
<div class="info-item"><span class="info-label">开户名</span>{{ detailData.form.card_name || '-' }}</div>
<div class="info-item"><span class="info-label">银行卡号</span>{{ detailData.form.card_no || detailData.form.card_no_masked || '-' }}</div>
<div class="info-item"><span class="info-label">联行号</span>{{ detailData.form.branch_code || '-' }}</div>
<div class="info-item"><span class="info-label">省份编码</span>{{ detailData.form.prov_id || '-' }}</div>
<div class="info-item"><span class="info-label">城市编码</span>{{ detailData.form.area_id || '-' }}</div>
</div>
<div class="section-title">证件照片</div>
<div class="photo-grid">
<div class="photo-box" v-if="detailData.form.id_card_front_url">
<div class="photo-label">身份证人像面</div>
<el-image class="photo-img" :src="detailData.form.id_card_front_url" :preview-src-list="previewList" fit="contain"></el-image>
</div>
<div class="photo-box" v-if="detailData.form.id_card_back_url">
<div class="photo-label">身份证国徽面</div>
<el-image class="photo-img" :src="detailData.form.id_card_back_url" :preview-src-list="previewList" fit="contain"></el-image>
</div>
<div class="photo-box" v-if="detailData.form.bank_card_url">
<div class="photo-label">银行卡照片</div>
<el-image class="photo-img" :src="detailData.form.bank_card_url" :preview-src-list="previewList" fit="contain"></el-image>
</div>
<div v-if="!detailData.form.id_card_front_url && !detailData.form.id_card_back_url" style="color:#909399;font-size:13px;">暂无图片资料</div>
</div>
<div v-if="detailData.record.reject_reason">
<div class="section-title">驳回/失败原因</div>
<div style="color:#f56c6c;font-size:13px;line-height:1.6;">{{ detailData.record.reject_reason }}</div>
</div>
</div>
<span slot="footer">
<el-button @click="detailVisible = false">关闭</el-button>
<el-button v-if="detailData && canEditRow(detailData.record)" @click="editFromDetail">编辑资料</el-button>
<el-button type="primary" v-if="detailData && detailData.can_submit_huifu" @click="submitFromDetail">提交汇付</el-button>
<el-button v-if="detailData && detailData.can_poll" @click="pollFromDetail">刷新状态</el-button>
<el-button type="warning" v-if="detailData && detailData.can_retry_huifu" @click="retryFromDetail">重新提交</el-button>
<el-button type="primary" plain v-if="detailData && detailData.can_modify_card" @click="modifyCardFromDetail">更换结算卡</el-button>
<el-tag size="mini" type="warning" v-if="detailData && detailData.card_modify_pending" style="margin-left:8px;">换卡审核中</el-tag>
</span>
</el-dialog>
<el-dialog
title="更换结算银行卡"
custom-class="modify-card-dialog"
:visible.sync="modifyCardVisible"
width="640px"
append-to-body
:close-on-click-modal="false"
>
<el-alert
type="info"
:closable="false"
show-icon
title="仅修改结算卡相关信息;身份/执照资料保持不变。"
style="margin-bottom:14px;"
></el-alert>
<el-form label-width="110px" size="small" v-if="modifyCardForm">
<el-form-item label="开户名">
<el-input :value="modifyCardForm.card_name || detailData && detailData.form && (detailData.form.card_name || detailData.form.name) || '-'" disabled></el-input>
</el-form-item>
<el-form-item label="账户类型" v-if="detailData && detailData.form && detailData.form.account_type === 'ent'">
<el-radio-group v-model="modifyCardForm.bank_account_type">
<el-radio label="0">对私</el-radio>
<el-radio label="1">对公</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="银行卡号" required>
<el-input v-model="modifyCardForm.card_no" maxlength="32" placeholder="请输入新结算银行卡号" @input="onModifyCardNoInput"></el-input>
</el-form-item>
<el-form-item label="开户支行" required>
<el-input v-model="modifyCardBranchKeyword" placeholder="搜索支行名称,例如:建设银行贵阳XX支行" @input="onModifyBranchInput"></el-input>
<div class="branch-panel" v-if="modifyCardBranchResults.length">
<div class="branch-item" v-for="(item, idx) in modifyCardBranchResults" :key="idx" @click="selectModifyBranch(item)">
<div>{{ item.branch_name }}</div>
<div style="color:#909399;font-size:12px;">{{ item.branch_code }}</div>
</div>
</div>
<div style="color:#7536D0;font-size:12px;margin-top:4px;" v-if="modifyCardForm.branch_code">
已选:{{ modifyCardForm.branch_name }}(联行号 {{ modifyCardForm.branch_code }})
</div>
</el-form-item>
<el-form-item label="联行号" required>
<el-input v-model="modifyCardForm.branch_code" maxlength="20" placeholder="可搜索支行自动带出,也可手动填写"></el-input>
</el-form-item>
<el-form-item label="预留手机号" required>
<el-input v-model="modifyCardForm.mobile_no" maxlength="11" placeholder="银行预留手机号"></el-input>
</el-form-item>
<el-form-item label="银行卡照片" :required="modifyCardNeedNewPhoto">
<el-upload :action="modifyCardUploadUrl" :show-file-list="false" accept="image/*" :on-success="onModifyCardUploadSuccess">
<div class="upload-box">
<img v-if="modifyCardForm.bank_card_url" :src="modifyCardForm.bank_card_url">
<span v-else style="color:#909399;font-size:12px;">点击上传</span>
</div>
</el-upload>
<div style="color:#E6A23C;font-size:12px;margin-top:4px;" v-if="modifyCardNeedNewPhoto">更换卡号后请重新上传银行卡照片</div>
</el-form-item>
<el-form-item label="开户许可证" v-if="modifyCardForm.bank_account_type === '1'" required>
<el-upload :action="modifyCardUploadUrl" :show-file-list="false" accept="image/*" :on-success="onModifyPermitUploadSuccess">
<div class="upload-box">
<img v-if="modifyCardForm.account_permit_url" :src="modifyCardForm.account_permit_url">
<span v-else style="color:#909399;font-size:12px;">点击上传</span>
</div>
</el-upload>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="modifyCardVisible = false">取消</el-button>
<el-button type="primary" :loading="modifyCardSaving" @click="submitModifyCard">提交更换</el-button>
</span>
</el-dialog>
</div>