From abc40ef2a9f7dd4c58c6d649f8f1bd9e5a6bf976 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8F=AF=E4=B9=90=E5=8A=A0=E5=86=B0?=
<11869599+addie66@user.noreply.gitee.com>
Date: Sun, 15 Nov 2026 00:52:59 +0800
Subject: [PATCH] =?UTF-8?q?feat(huifu):=20=E6=94=AF=E6=8C=81=E6=B1=87?=
=?UTF-8?q?=E4=BB=98=E8=BF=9B=E4=BB=B6=E9=80=9A=E8=BF=87=E5=90=8E=E6=9B=B4?=
=?UTF-8?q?=E6=8D=A2=E7=BB=93=E7=AE=97=E9=93=B6=E8=A1=8C=E5=8D=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 用户端及后台管理端新增更换结算卡接口与页面交互
- 服务层实现换卡核心逻辑、参数校验及汇付接口调用
- 增加换卡异步通知处理与定时轮询补偿以同步审核状态
- 完善进件状态网关,补充换卡审核状态及驳回原因等字段
---
addons/shopro/controller/UserWalletApply.php | 116 ++++++
.../admin/controller/shopro_huifu/Onboard.php | 36 ++
.../view/shopro_huifu/onboard/index.html | 2 +
addons/shopro_huifu/command/OnboardPoll.php | 2 +
addons/shopro_huifu/config/menu.php | 1 +
addons/shopro_huifu/controller/Onboard.php | 37 +-
.../library/onboard/HuifuOnboardAdminView.php | 7 +
.../onboard/HuifuOnboardBusiModify.php | 114 ++++++
.../library/onboard/HuifuOnboardGate.php | 20 +
.../library/onboard/HuifuOnboardService.php | 371 +++++++++++++++++-
.../library/onboard/HuifuOnboardValidator.php | 48 +++
.../assets/js/backend/shopro_huifu/onboard.js | 41 ++
.../admin/controller/shopro_huifu/Onboard.php | 36 ++
.../view/shopro_huifu/onboard/index.html | 2 +
.../assets/js/backend/shopro_huifu/onboard.js | 41 ++
.../huifu-onboard-form/huifu-onboard-form.vue | 168 ++++++--
.../pages/user/wallet/onboard-bind.vue | 54 ++-
.../pages/user/wallet/withdraw.vue | 15 +-
xgsc.gynhc.com_wx/shopro/request/apis.js | 6 +
19 files changed, 1058 insertions(+), 59 deletions(-)
create mode 100644 addons/shopro_huifu/library/onboard/HuifuOnboardBusiModify.php
diff --git a/addons/shopro/controller/UserWalletApply.php b/addons/shopro/controller/UserWalletApply.php
index f79ca10..5285a5c 100644
--- a/addons/shopro/controller/UserWalletApply.php
+++ b/addons/shopro/controller/UserWalletApply.php
@@ -142,6 +142,97 @@ class UserWalletApply extends Base
$this->success($msg, $this->resolveWalletOnboard($userId));
}
+ /**
+ * 进件已通过后更换结算银行卡
+ */
+ public function onboardModifyCard()
+ {
+ if (!class_exists('\\addons\\shopro_huifu\\library\\onboard\\HuifuOnboardGate')
+ || !\addons\shopro_huifu\library\onboard\HuifuOnboardGate::isOnboardRequired()) {
+ $this->error('当前无需绑定进件资料');
+ }
+
+ $form = $this->request->post('huifu_onboard/a', []);
+ if (empty($form) || !is_array($form)) {
+ $this->error('请填写结算银行卡信息');
+ }
+
+ $userId = $this->auth->id;
+ $bindings = $this->collectOnboardBindings($userId);
+ if (!$bindings) {
+ $this->error('您暂无可更换结算卡的角色');
+ }
+
+ $roleType = trim((string) $this->request->post('role_type', ''));
+ $roleRefId = intval($this->request->post('role_ref_id', 0));
+
+ $modifiable = [];
+ $pending = false;
+ foreach ($bindings as $binding) {
+ $huifu = $binding['huifu_onboard'];
+ if (!empty($huifu['card_modify_pending'])) {
+ $pending = true;
+ continue;
+ }
+ if (($huifu['status'] ?? '') === 'approved' && !empty($huifu['can_modify_card'])) {
+ $modifiable[] = $binding;
+ }
+ }
+
+ if (!$modifiable) {
+ $this->error($pending ? '结算卡更换审核中,请耐心等待' : '当前状态不可更换结算卡');
+ }
+
+ $target = null;
+ if ($roleType !== '') {
+ foreach ($modifiable as $binding) {
+ if ($binding['role_type'] !== $roleType) {
+ continue;
+ }
+ if ($roleType === 'promoter' || $roleRefId <= 0 || intval($binding['role_ref_id']) === $roleRefId) {
+ $target = $binding;
+ break;
+ }
+ }
+ if (!$target) {
+ $this->error('未找到可更换结算卡的指定角色');
+ }
+ } elseif (count($modifiable) === 1) {
+ $target = $modifiable[0];
+ } else {
+ $this->error('存在多个已进件角色,请指定要更换结算卡的角色');
+ }
+
+ try {
+ $service = new \addons\shopro_huifu\library\onboard\HuifuOnboardService();
+ $service->modifySettleCard(
+ $userId,
+ $target['role_type'],
+ $target['role_ref_id'],
+ $form
+ );
+ } catch (\InvalidArgumentException $e) {
+ $this->error($e->getMessage());
+ } catch (\RuntimeException $e) {
+ $msg = class_exists('\\addons\\shopro_huifu\\library\\onboard\\HuifuOnboardError')
+ ? \addons\shopro_huifu\library\onboard\HuifuOnboardError::translate($e->getMessage())
+ : $e->getMessage();
+ $this->error($msg);
+ } catch (\Throwable $e) {
+ $msg = class_exists('\\addons\\shopro_huifu\\library\\onboard\\HuifuOnboardError')
+ ? \addons\shopro_huifu\library\onboard\HuifuOnboardError::translate($e->getMessage())
+ : $e->getMessage();
+ $this->error($msg ?: '更换结算卡失败');
+ }
+
+ $result = $this->resolveWalletOnboard($userId);
+ $pending = !empty($result['huifu_onboard']['card_modify_pending']);
+ $this->success(
+ $pending ? '结算卡更换已提交,请耐心等待审核' : '结算卡更换成功',
+ $result
+ );
+ }
+
protected function resolveWalletOnboard($userId)
{
if (!class_exists('\\addons\\shopro_huifu\\library\\onboard\\HuifuOnboardGate')) {
@@ -169,6 +260,15 @@ class UserWalletApply extends Base
$primary = $binding;
}
}
+ if (!$primary) {
+ foreach ($bindings as $binding) {
+ if (!empty($binding['huifu_onboard']['can_modify_card'])
+ || !empty($binding['huifu_onboard']['card_modify_pending'])) {
+ $primary = $binding;
+ break;
+ }
+ }
+ }
if (!$primary) {
$primary = $bindings[0];
}
@@ -176,11 +276,15 @@ class UserWalletApply extends Base
$huifu = $primary['huifu_onboard'];
$show = count($bindings) > 0;
$canSubmitBind = false;
+ $canModifyCardBind = false;
foreach ($bindings as $binding) {
$item = $binding['huifu_onboard'];
if (!empty($item['can_submit']) || !empty($item['can_save_draft'])) {
$canSubmitBind = true;
}
+ if (!empty($item['can_modify_card'])) {
+ $canModifyCardBind = true;
+ }
}
$config = [
@@ -199,9 +303,21 @@ class UserWalletApply extends Base
'required' => true,
'role_labels' => array_column($bindings, 'role_label'),
'role_type' => $primary['role_type'],
+ 'role_ref_id' => intval($primary['role_ref_id']),
'huifu_onboard' => $huifu,
'can_submit_bind' => $canSubmitBind,
+ 'can_modify_card_bind' => $canModifyCardBind,
'onboard_config' => $config,
+ 'bindings' => array_map(function ($b) {
+ return [
+ 'role_type' => $b['role_type'],
+ 'role_ref_id' => intval($b['role_ref_id']),
+ 'role_label' => $b['role_label'],
+ 'status' => $b['huifu_onboard']['status'] ?? null,
+ 'can_modify_card' => !empty($b['huifu_onboard']['can_modify_card']),
+ 'card_modify_pending' => !empty($b['huifu_onboard']['card_modify_pending']),
+ ];
+ }, $bindings),
];
}
diff --git a/addons/shopro_huifu/application/admin/controller/shopro_huifu/Onboard.php b/addons/shopro_huifu/application/admin/controller/shopro_huifu/Onboard.php
index f7497d1..0886846 100644
--- a/addons/shopro_huifu/application/admin/controller/shopro_huifu/Onboard.php
+++ b/addons/shopro_huifu/application/admin/controller/shopro_huifu/Onboard.php
@@ -187,4 +187,40 @@ class Onboard extends Base
}
$this->success('已重新提交进件');
}
+
+ /**
+ * 已通过进件更换结算卡(后台代操作)
+ */
+ public function modifyCard($ids = null)
+ {
+ $row = OnboardModel::get($ids);
+ if (!$row) {
+ $this->error('记录不存在');
+ }
+ if ($row['onboard_status'] !== OnboardModel::STATUS_APPROVED) {
+ $this->error('仅进件已通过时可更换结算卡');
+ }
+ $form = $this->request->post('row/a', []);
+ if (!$form) {
+ $form = $this->request->post('huifu_onboard/a', []);
+ }
+ if (!$form || !is_array($form)) {
+ $this->error('请填写结算银行卡信息');
+ }
+ try {
+ $service = new HuifuOnboardService();
+ $service->modifySettleCard(
+ $row['user_id'],
+ $row['role_type'],
+ $row['role_ref_id'],
+ $form,
+ intval($row['id'])
+ );
+ } catch (\think\exception\HttpResponseException $e) {
+ throw $e;
+ } catch (\Throwable $e) {
+ $this->error(HuifuOnboardError::translate($e->getMessage()) ?: '更换结算卡失败');
+ }
+ $this->success('结算卡更换已提交');
+ }
}
diff --git a/addons/shopro_huifu/application/admin/view/shopro_huifu/onboard/index.html b/addons/shopro_huifu/application/admin/view/shopro_huifu/onboard/index.html
index 81d52d7..8d9e92e 100644
--- a/addons/shopro_huifu/application/admin/view/shopro_huifu/onboard/index.html
+++ b/addons/shopro_huifu/application/admin/view/shopro_huifu/onboard/index.html
@@ -139,6 +139,8 @@
提交汇付
刷新状态
重新提交
+ 更换结算卡
+ 换卡审核中
diff --git a/addons/shopro_huifu/command/OnboardPoll.php b/addons/shopro_huifu/command/OnboardPoll.php
index 008844f..9531c1c 100644
--- a/addons/shopro_huifu/command/OnboardPoll.php
+++ b/addons/shopro_huifu/command/OnboardPoll.php
@@ -19,6 +19,8 @@ class OnboardPoll extends Command
{
$service = new HuifuOnboardService();
$count = $service->pollPending(100);
+ $cardCount = $service->pollCardModifyPending(100);
$output->writeln('Polled onboard records: ' . $count);
+ $output->writeln('Polled card-modify records: ' . $cardCount);
}
}
diff --git a/addons/shopro_huifu/config/menu.php b/addons/shopro_huifu/config/menu.php
index 518e54b..70afc17 100644
--- a/addons/shopro_huifu/config/menu.php
+++ b/addons/shopro_huifu/config/menu.php
@@ -33,6 +33,7 @@ return [
['type' => 'file', 'name' => 'shopro_huifu/onboard/poll', 'title' => '刷新状态', 'ismenu' => 0],
['type' => 'file', 'name' => 'shopro_huifu/onboard/submit', 'title' => '提交汇付', 'ismenu' => 0],
['type' => 'file', 'name' => 'shopro_huifu/onboard/retry', 'title' => '重新提交', 'ismenu' => 0],
+ ['type' => 'file', 'name' => 'shopro_huifu/onboard/modifyCard', 'title' => '更换结算卡', 'ismenu' => 0],
],
],
];
diff --git a/addons/shopro_huifu/controller/Onboard.php b/addons/shopro_huifu/controller/Onboard.php
index 57bbedc..87a86e8 100644
--- a/addons/shopro_huifu/controller/Onboard.php
+++ b/addons/shopro_huifu/controller/Onboard.php
@@ -119,7 +119,42 @@ class Onboard extends Controller
try {
$service = new HuifuOnboardService();
$row = $service->resubmit($userId, $roleType, $roleRefId, $form);
- $this->success('进件已重新提交', HuifuOnboardGate::publicStatus($row));
+ $this->success('进件已重新提交', HuifuOnboardGate::publicStatus($row, $userId, $roleType, $roleRefId));
+ } catch (\Throwable $e) {
+ $this->error($e->getMessage());
+ }
+ }
+
+ /**
+ * 进件已通过后更换结算银行卡
+ */
+ public function modifyCard()
+ {
+ $this->ensureEnabled();
+ if (!HuifuOnboardGate::isOnboardRequired()) {
+ $this->error('当前未开启汇付进件');
+ }
+ $userId = $this->auth->id;
+ $roleType = $this->request->post('role_type', 'promoter');
+ $roleRefId = intval($this->request->post('role_ref_id', $userId));
+ if ($roleType === 'promoter') {
+ $roleRefId = $userId;
+ }
+ $form = $this->request->post('huifu_onboard/a', []);
+ if (!$form) {
+ $form = $this->request->post('form/a', []);
+ }
+ if (!$form || !is_array($form)) {
+ $this->error('请填写结算银行卡信息');
+ }
+ try {
+ $service = new HuifuOnboardService();
+ $row = $service->modifySettleCard($userId, $roleType, $roleRefId, $form);
+ $status = HuifuOnboardGate::publicStatus($row, $userId, $roleType, $roleRefId);
+ $msg = !empty($status['card_modify_pending'])
+ ? '结算卡更换已提交,请等待审核'
+ : '结算卡更换成功';
+ $this->success($msg, $status);
} catch (\Throwable $e) {
$this->error($e->getMessage());
}
diff --git a/addons/shopro_huifu/library/onboard/HuifuOnboardAdminView.php b/addons/shopro_huifu/library/onboard/HuifuOnboardAdminView.php
index 7120d13..6cf4cb7 100644
--- a/addons/shopro_huifu/library/onboard/HuifuOnboardAdminView.php
+++ b/addons/shopro_huifu/library/onboard/HuifuOnboardAdminView.php
@@ -91,6 +91,12 @@ class HuifuOnboardAdminView
'can_submit_huifu' => ($data['onboard_status'] ?? '') === 'draft',
'can_retry_huifu' => in_array($data['onboard_status'] ?? '', ['rejected', 'failed'], true),
'can_poll' => !in_array($data['onboard_status'] ?? '', ['draft', 'approved'], true),
+ 'can_modify_card' => ($data['onboard_status'] ?? '') === 'approved' && !empty($data['huifu_id'])
+ && (($payload['_card_modify']['status'] ?? '') !== 'pending'),
+ 'card_modify_pending' => ($payload['_card_modify']['status'] ?? '') === 'pending',
+ 'card_modify_reject_reason' => (string) (($payload['_card_modify']['status'] ?? '') === 'rejected'
+ ? ($payload['_card_modify']['reject_reason'] ?? '')
+ : ''),
];
}
@@ -550,6 +556,7 @@ class HuifuOnboardAdminView
return null;
}
$form = array_merge(self::defaultFormData(), $payload);
+ unset($form['_card_modify']);
foreach ([
'id_card_front_url', 'id_card_back_url', 'bank_card_url', 'license_url',
'legal_id_front_url', 'legal_id_back_url', 'account_permit_url',
diff --git a/addons/shopro_huifu/library/onboard/HuifuOnboardBusiModify.php b/addons/shopro_huifu/library/onboard/HuifuOnboardBusiModify.php
new file mode 100644
index 0000000..3908735
--- /dev/null
+++ b/addons/shopro_huifu/library/onboard/HuifuOnboardBusiModify.php
@@ -0,0 +1,114 @@
+sdk = $sdk ?: new HuifuOnboardSdk();
+ }
+
+ public function modifyCard($huifuId, array $form, array $fileMap)
+ {
+ SdkLoader::requireRequest('V2UserBusiModifyRequest.php');
+
+ $meta = $this->sdk->newReqMeta();
+ $request = new \BsPaySdk\request\V2UserBusiModifyRequest();
+ $request->setHuifuId($huifuId);
+ $request->setReqSeqId($meta['req_seq_id']);
+ $request->setReqDate($meta['req_date']);
+
+ $cardInfo = self::buildCardInfo($form);
+ $fileList = self::buildFileList($form, $fileMap);
+
+ $extend = [
+ 'card_info' => json_encode($cardInfo, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
+ 'async_return_url' => $this->sdk->getOnboardNotifyUrl(),
+ ];
+ if ($fileList) {
+ $extend['file_list'] = json_encode($fileList, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+ }
+ $request->setExtendInfo($extend);
+
+ $result = $this->sdk->getClient()->postRequest($request);
+ $data = $this->sdk->getClient()->parseResponse($result);
+ $applyNo = (string) ($data['apply_no'] ?? ($data['apply_id'] ?? ''));
+
+ return [
+ 'req_date' => $meta['req_date'],
+ 'req_seq_id' => $meta['req_seq_id'],
+ 'apply_no' => $applyNo,
+ 'resp' => $data,
+ ];
+ }
+
+ public static function buildCardInfo(array $form)
+ {
+ // 系统 bank_account_type:0=对私,1=对公
+ // 汇付 card_type:0=对公,1=对私法人,2=对私非法人
+ $bankAccountType = (string) ($form['bank_account_type'] ?? '0');
+ $cardType = $bankAccountType === '1' ? '0' : '1';
+ $accountType = $form['account_type'] ?? 'indv';
+ $cardName = $form['card_name'] ?? '';
+ if ($accountType === 'indv') {
+ $cardName = $form['name'] ?? $cardName;
+ } elseif ($bankAccountType === '0') {
+ $cardName = $form['legal_name'] ?? $cardName;
+ }
+
+ $cardInfo = [
+ 'card_type' => $cardType,
+ 'card_name' => $cardName,
+ 'card_no' => $form['card_no'],
+ 'prov_id' => $form['prov_id'],
+ 'area_id' => HuifuOnboardAreaHelper::toHuifuCityCode($form['area_id'] ?? ''),
+ 'mp' => $form['mp'] ?? '',
+ ];
+ if (!empty($form['branch_code'])) {
+ $cardInfo['branch_code'] = $form['branch_code'];
+ }
+ if (!empty($form['branch_name'])) {
+ $cardInfo['branch_name'] = $form['branch_name'];
+ }
+ if ($cardType === '1') {
+ $cardInfo['cert_type'] = '00';
+ $cardInfo['cert_no'] = $form['cert_no'];
+ $cardInfo['cert_validity_type'] = $form['cert_validity_type'];
+ $cardInfo['cert_begin_date'] = $form['cert_begin_date'];
+ if (($form['cert_validity_type'] ?? '') === '0' && !empty($form['cert_end_date'])) {
+ $cardInfo['cert_end_date'] = $form['cert_end_date'];
+ }
+ }
+ return $cardInfo;
+ }
+
+ public static function buildFileList(array $form, array $fileMap)
+ {
+ $bankAccountType = (string) ($form['bank_account_type'] ?? '0');
+ $cardType = $bankAccountType === '1' ? '0' : '1';
+ $fileList = [];
+ if (!empty($fileMap['F13'])) {
+ $fileList[] = [
+ 'file_type' => 'F13',
+ 'file_id' => $fileMap['F13'],
+ 'file_name' => 'bank_card.jpg',
+ ];
+ }
+ if ($cardType === '0' && !empty($fileMap['F08'])) {
+ $fileList[] = [
+ 'file_type' => 'F08',
+ 'file_id' => $fileMap['F08'],
+ 'file_name' => 'account_permit.jpg',
+ ];
+ }
+ return $fileList;
+ }
+}
diff --git a/addons/shopro_huifu/library/onboard/HuifuOnboardGate.php b/addons/shopro_huifu/library/onboard/HuifuOnboardGate.php
index 281ddb8..052bda5 100644
--- a/addons/shopro_huifu/library/onboard/HuifuOnboardGate.php
+++ b/addons/shopro_huifu/library/onboard/HuifuOnboardGate.php
@@ -118,11 +118,26 @@ class HuifuOnboardGate
// 仅历史 draft 残留时提示等待(正常已改为用户提交直连汇付)
$awaitAdmin = $required && $row && $row['onboard_status'] === Onboard::STATUS_DRAFT
&& in_array($agentStatus, ['pending', 'needinfo', 'reject'], true);
+ $cardModifyPending = false;
+ $cardModifyReject = '';
+ $canModifyCard = false;
+ if ($row && $row['onboard_status'] === Onboard::STATUS_APPROVED && $required) {
+ $payload = json_decode($row['payload'] ?? '', true);
+ $meta = is_array($payload) ? HuifuOnboardService::getCardModifyMeta($payload) : [];
+ $cardModifyPending = ($meta['status'] ?? '') === 'pending';
+ if (($meta['status'] ?? '') === 'rejected') {
+ $cardModifyReject = (string) ($meta['reject_reason'] ?? '');
+ }
+ $canModifyCard = !$cardModifyPending && !empty($row['huifu_id']);
+ }
if (!$row) {
return [
'required' => $required,
'can_submit' => $canSubmit,
'can_save_draft' => $canSaveDraft,
+ 'can_modify_card' => false,
+ 'card_modify_pending' => false,
+ 'card_modify_reject_reason' => '',
'await_admin' => false,
'audit_first' => false,
'status' => null,
@@ -135,12 +150,17 @@ class HuifuOnboardGate
'required' => $required,
'can_submit' => $canSubmit,
'can_save_draft' => $canSaveDraft,
+ 'can_modify_card' => $canModifyCard,
+ 'card_modify_pending' => $cardModifyPending,
+ 'card_modify_reject_reason' => $cardModifyReject,
'await_admin' => $awaitAdmin,
'audit_first' => false,
'status' => $row['onboard_status'],
'huifu_id' => $row['huifu_id'] ? substr($row['huifu_id'], 0, 4) . '****' . substr($row['huifu_id'], -4) : '',
'reject_reason' => $row['reject_reason'] ?? '',
'apply_no' => $row['apply_no'] ?? '',
+ 'role_type' => $row['role_type'] ?? $roleType,
+ 'role_ref_id' => intval($row['role_ref_id'] ?? $roleRefId),
'draft' => HuifuOnboardAdminView::clientFormFromRow($row),
];
}
diff --git a/addons/shopro_huifu/library/onboard/HuifuOnboardService.php b/addons/shopro_huifu/library/onboard/HuifuOnboardService.php
index 42300bb..f6f390e 100644
--- a/addons/shopro_huifu/library/onboard/HuifuOnboardService.php
+++ b/addons/shopro_huifu/library/onboard/HuifuOnboardService.php
@@ -13,6 +13,7 @@ class HuifuOnboardService
protected $basic;
protected $basicEnt;
protected $busi;
+ protected $busiModify;
protected $query;
protected function sdk()
@@ -23,6 +24,7 @@ class HuifuOnboardService
$this->basic = new HuifuOnboardBasicIndv($this->sdk);
$this->basicEnt = new HuifuOnboardBasicEnt($this->sdk);
$this->busi = new HuifuOnboardBusiOpen($this->sdk);
+ $this->busiModify = new HuifuOnboardBusiModify($this->sdk);
$this->query = new HuifuOnboardQuery($this->sdk);
}
return $this->sdk;
@@ -230,23 +232,382 @@ class HuifuOnboardService
return $fileMap;
}
+ /**
+ * 已通过进件后更换结算银行卡(V2UserBusiModify,仅 card_info)
+ */
+ public function modifySettleCard($userId, $roleType, $roleRefId, array $formData, $onboardId = 0)
+ {
+ if (!HuifuOnboardGate::isOnboardRequired()) {
+ throw new \RuntimeException('当前未开启汇付进件');
+ }
+ if (!in_array($roleType, ['promoter', 'regional_agent'], true)) {
+ throw new \InvalidArgumentException('无效角色类型');
+ }
+
+ $onboardId = intval($onboardId);
+ if ($onboardId > 0) {
+ $row = Onboard::get($onboardId);
+ if (!$row || intval($row['user_id']) !== intval($userId)) {
+ throw new \InvalidArgumentException('进件记录不存在');
+ }
+ } else {
+ $row = Onboard::findByRole($userId, $roleType, $roleRefId);
+ }
+ if (!$row || $row['onboard_status'] !== Onboard::STATUS_APPROVED) {
+ throw new \RuntimeException('仅进件已通过时可更换结算卡');
+ }
+ if (empty($row['huifu_id'])) {
+ throw new \RuntimeException('缺少汇付商户号,无法更换结算卡');
+ }
+
+ $payload = json_decode($row['payload'] ?? '', true);
+ if (!is_array($payload)) {
+ $payload = [];
+ }
+ $cardModify = self::getCardModifyMeta($payload);
+ if (($cardModify['status'] ?? '') === 'pending') {
+ throw new \RuntimeException('结算卡更换审核中,请稍后再试');
+ }
+
+ $form = HuifuOnboardValidator::validateCardModify($formData, $payload);
+ $oldCard = preg_replace('/\s+/', '', (string) ($payload['card_no'] ?? ''));
+ $newCard = preg_replace('/\s+/', '', (string) ($form['card_no'] ?? ''));
+
+ try {
+ $this->sdk();
+ $fileMap = $this->uploadCardModifyPictures($form, $payload, $oldCard !== $newCard);
+ $result = $this->busiModify->modifyCard($row['huifu_id'], $form, $fileMap);
+ $resp = is_array($result['resp'] ?? null) ? $result['resp'] : [];
+ $applyNo = (string) ($result['apply_no'] ?? '');
+ $pending = $this->isCardModifyPending($resp, $applyNo);
+
+ if ($pending) {
+ $payload['_card_modify'] = [
+ 'status' => 'pending',
+ 'apply_no' => $applyNo,
+ 'req_seq_id' => (string) ($result['req_seq_id'] ?? ''),
+ 'req_date' => (string) ($result['req_date'] ?? ''),
+ 'pending_form' => $this->cardFieldsOnly($form),
+ 'reject_reason' => '',
+ 'updated_at' => time(),
+ ];
+ $row->payload = json_encode($payload, JSON_UNESCAPED_UNICODE);
+ $row->resp_snapshot = json_encode($resp, JSON_UNESCAPED_UNICODE);
+ $row->save();
+ return $row;
+ }
+
+ if (!$this->isCardModifySyncSuccess($resp)) {
+ $msg = (string) ($resp['resp_desc'] ?? '更换结算卡失败');
+ throw new \RuntimeException(HuifuOnboardError::translate($msg));
+ }
+
+ return $this->commitCardModifySuccess($row, $payload, $form, $resp);
+ } catch (\RuntimeException $e) {
+ throw $e;
+ } catch (\Throwable $e) {
+ $friendly = HuifuOnboardError::translate($e->getMessage());
+ Log::error('[shopro_huifu] card modify fail uid=' . $userId . ' id=' . $row['id'] . ' ' . $e->getMessage());
+ throw new \RuntimeException($friendly, 0, $e);
+ }
+ }
+
public function handleNotify(array $data)
{
$huifuId = trim((string) ($data['huifu_id'] ?? ''));
- $applyNo = trim((string) ($data['apply_no'] ?? ''));
if ($huifuId === '') {
return false;
}
- $query = Onboard::where('huifu_id', $huifuId);
- if ($applyNo !== '') {
- $query->where('apply_no', $applyNo);
+
+ $auditInfo = $data['audit_info'] ?? null;
+ if (is_string($auditInfo)) {
+ $auditInfo = json_decode($auditInfo, true) ?: [];
}
- $row = $query->order('id desc')->find();
+ if (!is_array($auditInfo)) {
+ $auditInfo = [];
+ }
+
+ $applyNo = trim((string) ($data['apply_no'] ?? ($auditInfo['apply_no'] ?? '')));
+ $reqSeqId = trim((string) ($data['req_seq_id'] ?? ''));
+
+ $row = Onboard::where('huifu_id', $huifuId)->order('id desc')->find();
if (!$row) {
return false;
}
+
+ if ($this->tryApplyCardModifyNotify($row, $data, $auditInfo, $applyNo, $reqSeqId)) {
+ return true;
+ }
+
+ // 原进件审核:优先按 apply_no 精确匹配,避免误更新其他记录
+ if ($applyNo !== '') {
+ $byApply = Onboard::where('huifu_id', $huifuId)->where('apply_no', $applyNo)->order('id desc')->find();
+ if ($byApply) {
+ $row = $byApply;
+ }
+ }
+
$this->sdk();
$this->query->pollAndUpdate($row);
return true;
}
+
+ /**
+ * 补偿:扫描换卡 pending,查单后更新(不改 onboard_status)
+ */
+ public function pollCardModifyPending($limit = 50)
+ {
+ $list = Onboard::where('onboard_status', Onboard::STATUS_APPROVED)
+ ->where('payload', 'like', '%"_card_modify"%')
+ ->limit($limit)
+ ->select();
+ if (!$list || count($list) === 0) {
+ return 0;
+ }
+ $this->sdk();
+ $count = 0;
+ foreach ($list as $row) {
+ try {
+ $payload = json_decode($row['payload'] ?? '', true);
+ if (!is_array($payload)) {
+ continue;
+ }
+ $meta = self::getCardModifyMeta($payload);
+ if (($meta['status'] ?? '') !== 'pending') {
+ continue;
+ }
+ $applyNo = trim((string) ($meta['apply_no'] ?? ''));
+ if ($applyNo === '' || empty($row['huifu_id'])) {
+ continue;
+ }
+ $status = $this->query->queryApply($row['huifu_id'], $applyNo);
+ $this->applyCardModifyRemoteStatus($row, $payload, $meta, $status);
+ $count++;
+ } catch (\Throwable $e) {
+ Log::error('[shopro_huifu] card modify poll fail id=' . $row['id'] . ' ' . $e->getMessage());
+ }
+ }
+ return $count;
+ }
+
+ protected function uploadCardModifyPictures(array $form, array $stored, $cardChanged)
+ {
+ $fileMap = [];
+ $needBankPic = $cardChanged || empty($stored['bank_card_url']) || (!empty($form['bank_card_url']) && ($form['bank_card_url'] !== ($stored['bank_card_url'] ?? '')));
+ if ($needBankPic && !empty($form['bank_card_url'])) {
+ $fileMap['F13'] = $this->picture->uploadByUrl('F13', $form['bank_card_url']);
+ }
+ if ((string) ($form['bank_account_type'] ?? '0') === '1' && !empty($form['account_permit_url'])) {
+ $oldPermit = (string) ($stored['account_permit_url'] ?? '');
+ if ($form['account_permit_url'] !== $oldPermit || empty($oldPermit)) {
+ $fileMap['F08'] = $this->picture->uploadByUrl('F08', $form['account_permit_url']);
+ }
+ }
+ return $fileMap;
+ }
+
+ protected function isCardModifyPending(array $resp, $applyNo)
+ {
+ $applyNo = trim((string) $applyNo);
+ if ($applyNo === '') {
+ return false;
+ }
+ // 有申请单号且绑卡结果未明确成功 → 审核中
+ if ($this->cardBusinessSucceeded($resp)) {
+ return false;
+ }
+ return true;
+ }
+
+ protected function isCardModifySyncSuccess(array $resp)
+ {
+ $code = (string) ($resp['resp_code'] ?? '');
+ if (!in_array($code, ['00000000', '00', '0000'], true) && $code !== '') {
+ // parseResponse 成功时通常已是业务成功码;若无码但有 token_no 也视为成功
+ if (empty($resp['token_no']) && !$this->cardBusinessSucceeded($resp)) {
+ return false;
+ }
+ }
+ if ($this->cardBusinessFailed($resp)) {
+ return false;
+ }
+ return true;
+ }
+
+ protected function cardBusinessSucceeded(array $resp)
+ {
+ $list = $resp['resp_business'] ?? [];
+ if (is_string($list)) {
+ $list = json_decode($list, true) ?: [];
+ }
+ if (!is_array($list) || !$list) {
+ return false;
+ }
+ foreach ($list as $item) {
+ if (!is_array($item)) {
+ continue;
+ }
+ if ((string) ($item['type'] ?? '') === '1' && strtoupper((string) ($item['code'] ?? '')) === 'S') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected function cardBusinessFailed(array $resp)
+ {
+ $list = $resp['resp_business'] ?? [];
+ if (is_string($list)) {
+ $list = json_decode($list, true) ?: [];
+ }
+ if (!is_array($list)) {
+ return false;
+ }
+ foreach ($list as $item) {
+ if (!is_array($item)) {
+ continue;
+ }
+ if ((string) ($item['type'] ?? '') === '1' && strtoupper((string) ($item['code'] ?? '')) === 'F') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected function commitCardModifySuccess(Onboard $row, array $payload, array $form, array $resp = [])
+ {
+ foreach ($this->cardFieldsOnly($form) as $key => $val) {
+ $payload[$key] = $val;
+ }
+ unset($payload['_card_modify']);
+ $row->payload = json_encode($payload, JSON_UNESCAPED_UNICODE);
+ if ($resp) {
+ $row->resp_snapshot = json_encode($resp, JSON_UNESCAPED_UNICODE);
+ }
+ // 保持 approved,不改 apply_no
+ $row->save();
+ return $row;
+ }
+
+ protected function cardFieldsOnly(array $form)
+ {
+ $keys = [
+ 'bank_account_type', 'card_no', 'card_name', 'branch_code', 'branch_name',
+ 'prov_id', 'area_id', 'district_id', 'shopro_province_id', 'shopro_city_id', 'shopro_district_id',
+ 'mp', 'mobile_no', 'legal_mobile', 'bank_card_url', 'account_permit_url',
+ // normalize 可能同步的证件字段(对私)
+ 'cert_no', 'cert_validity_type', 'cert_begin_date', 'cert_end_date', 'name',
+ ];
+ $out = [];
+ foreach ($keys as $key) {
+ if (array_key_exists($key, $form)) {
+ $out[$key] = $form[$key];
+ }
+ }
+ return $out;
+ }
+
+ protected function tryApplyCardModifyNotify(Onboard $row, array $data, array $auditInfo, $applyNo, $reqSeqId)
+ {
+ $payload = json_decode($row['payload'] ?? '', true);
+ if (!is_array($payload)) {
+ return false;
+ }
+ $meta = self::getCardModifyMeta($payload);
+ if (($meta['status'] ?? '') !== 'pending') {
+ return false;
+ }
+
+ $metaApply = trim((string) ($meta['apply_no'] ?? ''));
+ $metaReq = trim((string) ($meta['req_seq_id'] ?? ''));
+ $matched = false;
+ if ($applyNo !== '' && $metaApply !== '' && $applyNo === $metaApply) {
+ $matched = true;
+ } elseif ($reqSeqId !== '' && $metaReq !== '' && $reqSeqId === $metaReq) {
+ $matched = true;
+ }
+ if (!$matched) {
+ return false;
+ }
+
+ $auditStatus = strtoupper(trim((string) (
+ $auditInfo['audit_status']
+ ?? $data['audit_status']
+ ?? $data['apply_status']
+ ?? ''
+ )));
+ $auditDesc = (string) (
+ $auditInfo['audit_desc']
+ ?? $data['audit_desc']
+ ?? $data['sub_resp_desc']
+ ?? $data['resp_desc']
+ ?? ''
+ );
+
+ if (in_array($auditStatus, ['Y', 'S', 'SUCCESS', 'APPROVED', '1', '02', '2'], true)) {
+ $pendingForm = is_array($meta['pending_form'] ?? null) ? $meta['pending_form'] : [];
+ $this->commitCardModifySuccess($row, $payload, $pendingForm, $data);
+ return true;
+ }
+ if (in_array($auditStatus, ['N', 'F', 'FAIL', 'FAILED', 'REJECTED', '3', '03', '-1'], true)) {
+ $payload['_card_modify'] = [
+ 'status' => 'rejected',
+ 'apply_no' => $metaApply,
+ 'req_seq_id' => $metaReq,
+ 'pending_form' => $meta['pending_form'] ?? [],
+ 'reject_reason' => $auditDesc ?: '结算卡更换被驳回',
+ 'updated_at' => time(),
+ ];
+ $row->payload = json_encode($payload, JSON_UNESCAPED_UNICODE);
+ $row->resp_snapshot = json_encode($data, JSON_UNESCAPED_UNICODE);
+ $row->save();
+ return true;
+ }
+
+ // 审核中:保持 pending
+ $payload['_card_modify']['updated_at'] = time();
+ $row->payload = json_encode($payload, JSON_UNESCAPED_UNICODE);
+ $row->resp_snapshot = json_encode($data, JSON_UNESCAPED_UNICODE);
+ $row->save();
+ return true;
+ }
+
+ protected function applyCardModifyRemoteStatus(Onboard $row, array $payload, array $meta, array $status)
+ {
+ if (!$status) {
+ return;
+ }
+ $stat = strtoupper(trim((string) (
+ $status['audit_status']
+ ?? $status['apply_status']
+ ?? $status['status']
+ ?? ''
+ )));
+ $desc = (string) ($status['audit_desc'] ?? $status['apply_desc'] ?? $status['resp_desc'] ?? '');
+
+ if (in_array($stat, ['Y', 'S', 'SUCCESS', 'APPROVED', '1', '02', '2'], true)) {
+ $pendingForm = is_array($meta['pending_form'] ?? null) ? $meta['pending_form'] : [];
+ $this->commitCardModifySuccess($row, $payload, $pendingForm, $status);
+ return;
+ }
+ if (in_array($stat, ['N', 'F', 'FAIL', 'FAILED', 'REJECTED', '3', '03', '-1'], true)) {
+ $payload['_card_modify'] = [
+ 'status' => 'rejected',
+ 'apply_no' => (string) ($meta['apply_no'] ?? ''),
+ 'req_seq_id' => (string) ($meta['req_seq_id'] ?? ''),
+ 'pending_form' => $meta['pending_form'] ?? [],
+ 'reject_reason' => $desc ?: '结算卡更换被驳回',
+ 'updated_at' => time(),
+ ];
+ $row->payload = json_encode($payload, JSON_UNESCAPED_UNICODE);
+ $row->resp_snapshot = json_encode($status, JSON_UNESCAPED_UNICODE);
+ $row->save();
+ }
+ }
+
+ public static function getCardModifyMeta(array $payload)
+ {
+ $meta = $payload['_card_modify'] ?? null;
+ return is_array($meta) ? $meta : [];
+ }
}
diff --git a/addons/shopro_huifu/library/onboard/HuifuOnboardValidator.php b/addons/shopro_huifu/library/onboard/HuifuOnboardValidator.php
index 30fea04..3502f78 100644
--- a/addons/shopro_huifu/library/onboard/HuifuOnboardValidator.php
+++ b/addons/shopro_huifu/library/onboard/HuifuOnboardValidator.php
@@ -43,6 +43,54 @@ class HuifuOnboardValidator
return self::normalize($data);
}
+ /**
+ * 已通过进件后仅更换结算卡:银行卡字段来自 patch,身份/执照沿用库内 stored
+ */
+ public static function validateCardModify(array $patch, array $stored)
+ {
+ if (!$stored || !is_array($stored)) {
+ throw new \InvalidArgumentException('缺少原进件资料,无法更换结算卡');
+ }
+
+ $merged = $stored;
+ $bankKeys = [
+ 'bank_account_type', 'card_no', 'card_name', 'branch_code', 'branch_name',
+ 'prov_id', 'area_id', 'district_id', 'shopro_province_id', 'shopro_city_id', 'shopro_district_id',
+ 'mp', 'mobile_no', 'legal_mobile', 'bank_card_url', 'account_permit_url',
+ ];
+ foreach ($bankKeys as $key) {
+ if (!array_key_exists($key, $patch)) {
+ continue;
+ }
+ $val = $patch[$key];
+ if ($val === null || $val === '') {
+ continue;
+ }
+ $merged[$key] = $val;
+ }
+
+ $oldCard = preg_replace('/\s+/', '', (string) ($stored['card_no'] ?? ''));
+ $newCardRaw = preg_replace('/\s+/', '', (string) ($merged['card_no'] ?? ''));
+ // 前端若回显脱敏卡号且用户未改,沿用库内原卡号
+ if ($newCardRaw !== '' && strpos($newCardRaw, '*') !== false) {
+ $merged['card_no'] = $oldCard;
+ $newCardRaw = $oldCard;
+ }
+
+ HuifuOnboardAreaHelper::applyRegionCodes($merged);
+ self::resolveBranch($merged);
+ self::validateBank($merged);
+
+ if ($newCardRaw !== $oldCard && empty($merged['bank_card_url'])) {
+ throw new \InvalidArgumentException('更换银行卡号时请重新上传银行卡照片');
+ }
+ if ((string) ($merged['bank_account_type'] ?? '0') === '1' && empty($merged['account_permit_url'])) {
+ throw new \InvalidArgumentException('对公账户请上传开户许可证');
+ }
+
+ return self::normalize($merged);
+ }
+
protected static function validateIndividual(array $data)
{
foreach (['name', 'cert_no', 'mobile_no', 'reg_detail', 'id_card_front_url', 'id_card_back_url'] as $field) {
diff --git a/addons/shopro_huifu/public/assets/js/backend/shopro_huifu/onboard.js b/addons/shopro_huifu/public/assets/js/backend/shopro_huifu/onboard.js
index 17e3525..10186e0 100644
--- a/addons/shopro_huifu/public/assets/js/backend/shopro_huifu/onboard.js
+++ b/addons/shopro_huifu/public/assets/js/backend/shopro_huifu/onboard.js
@@ -508,6 +508,47 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
this.retryRow(this.detailId);
}
},
+ modifyCardFromDetail: function () {
+ var vm = this;
+ if (!vm.detailId || !vm.detailData || !vm.detailData.form) {
+ return;
+ }
+ var form = vm.detailData.form;
+ Layer.prompt({
+ title: '输入新结算银行卡号(支行等信息沿用当前资料,更换卡号请同步在资料中更新支行/卡图)',
+ value: form.card_no || '',
+ formType: 0,
+ maxlength: 32
+ }, function (cardNo, index) {
+ Layer.close(index);
+ cardNo = (cardNo || '').replace(/\s+/g, '');
+ if (!/^\d{12,19}$/.test(cardNo)) {
+ Toastr.error('银行卡号格式不正确');
+ return;
+ }
+ Fast.api.ajax({
+ url: 'shopro_huifu/onboard/modifyCard/ids/' + vm.detailId,
+ type: 'POST',
+ data: {
+ row: {
+ card_no: cardNo,
+ bank_account_type: form.bank_account_type || '0',
+ branch_code: form.branch_code || '',
+ branch_name: form.branch_name || '',
+ prov_id: form.prov_id || '',
+ area_id: form.area_id || '',
+ mp: form.mobile_no || '',
+ mobile_no: form.mobile_no || '',
+ bank_card_url: form.bank_card_url || '',
+ account_permit_url: form.account_permit_url || ''
+ }
+ }
+ }, function () {
+ vm.openDetail(vm.detailId);
+ vm.getList();
+ });
+ });
+ },
editFromDetail: function () {
if (this.detailId) {
this.openEdit(this.detailId);
diff --git a/application/admin/controller/shopro_huifu/Onboard.php b/application/admin/controller/shopro_huifu/Onboard.php
index 65c7fc8..03c7a75 100644
--- a/application/admin/controller/shopro_huifu/Onboard.php
+++ b/application/admin/controller/shopro_huifu/Onboard.php
@@ -189,4 +189,40 @@ class Onboard extends Base
}
$this->success('已重新提交进件');
}
+
+ /**
+ * 已通过进件更换结算卡(后台代操作)
+ */
+ public function modifyCard($ids = null)
+ {
+ $row = OnboardModel::get($ids);
+ if (!$row) {
+ $this->error('记录不存在');
+ }
+ if ($row['onboard_status'] !== OnboardModel::STATUS_APPROVED) {
+ $this->error('仅进件已通过时可更换结算卡');
+ }
+ $form = $this->request->post('row/a', []);
+ if (!$form) {
+ $form = $this->request->post('huifu_onboard/a', []);
+ }
+ if (!$form || !is_array($form)) {
+ $this->error('请填写结算银行卡信息');
+ }
+ try {
+ $service = new HuifuOnboardService();
+ $service->modifySettleCard(
+ $row['user_id'],
+ $row['role_type'],
+ $row['role_ref_id'],
+ $form,
+ intval($row['id'])
+ );
+ } catch (\think\exception\HttpResponseException $e) {
+ throw $e;
+ } catch (\Throwable $e) {
+ $this->error(HuifuOnboardError::translate($e->getMessage()) ?: '更换结算卡失败');
+ }
+ $this->success('结算卡更换已提交');
+ }
}
diff --git a/application/admin/view/shopro_huifu/onboard/index.html b/application/admin/view/shopro_huifu/onboard/index.html
index 81d52d7..8d9e92e 100644
--- a/application/admin/view/shopro_huifu/onboard/index.html
+++ b/application/admin/view/shopro_huifu/onboard/index.html
@@ -139,6 +139,8 @@
提交汇付
刷新状态
重新提交
+ 更换结算卡
+ 换卡审核中
diff --git a/public/assets/js/backend/shopro_huifu/onboard.js b/public/assets/js/backend/shopro_huifu/onboard.js
index 17e3525..10186e0 100644
--- a/public/assets/js/backend/shopro_huifu/onboard.js
+++ b/public/assets/js/backend/shopro_huifu/onboard.js
@@ -508,6 +508,47 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
this.retryRow(this.detailId);
}
},
+ modifyCardFromDetail: function () {
+ var vm = this;
+ if (!vm.detailId || !vm.detailData || !vm.detailData.form) {
+ return;
+ }
+ var form = vm.detailData.form;
+ Layer.prompt({
+ title: '输入新结算银行卡号(支行等信息沿用当前资料,更换卡号请同步在资料中更新支行/卡图)',
+ value: form.card_no || '',
+ formType: 0,
+ maxlength: 32
+ }, function (cardNo, index) {
+ Layer.close(index);
+ cardNo = (cardNo || '').replace(/\s+/g, '');
+ if (!/^\d{12,19}$/.test(cardNo)) {
+ Toastr.error('银行卡号格式不正确');
+ return;
+ }
+ Fast.api.ajax({
+ url: 'shopro_huifu/onboard/modifyCard/ids/' + vm.detailId,
+ type: 'POST',
+ data: {
+ row: {
+ card_no: cardNo,
+ bank_account_type: form.bank_account_type || '0',
+ branch_code: form.branch_code || '',
+ branch_name: form.branch_name || '',
+ prov_id: form.prov_id || '',
+ area_id: form.area_id || '',
+ mp: form.mobile_no || '',
+ mobile_no: form.mobile_no || '',
+ bank_card_url: form.bank_card_url || '',
+ account_permit_url: form.account_permit_url || ''
+ }
+ }
+ }, function () {
+ vm.openDetail(vm.detailId);
+ vm.getList();
+ });
+ });
+ },
editFromDetail: function () {
if (this.detailId) {
this.openEdit(this.detailId);
diff --git a/xgsc.gynhc.com_wx/components/huifu-onboard-form/huifu-onboard-form.vue b/xgsc.gynhc.com_wx/components/huifu-onboard-form/huifu-onboard-form.vue
index 6f61674..9252c61 100644
--- a/xgsc.gynhc.com_wx/components/huifu-onboard-form/huifu-onboard-form.vue
+++ b/xgsc.gynhc.com_wx/components/huifu-onboard-form/huifu-onboard-form.vue
@@ -6,7 +6,7 @@
汇付
绑定银行卡
- 填写开户资料,先由平台审核,通过后再提交汇付
+ {{ formTipText }}
@@ -21,7 +21,7 @@
class="type-item"
v-for="item in accountTypeOptions"
:key="item.value"
- :class="{ active: form.account_type === item.value, disabled: readonly }"
+ :class="{ active: form.account_type === item.value, disabled: identityReadonly }"
@tap="setAccountType(item.value)"
>
{{ form.account_type === item.value ? '✓' : '' }}
@@ -36,19 +36,19 @@
真实姓名
银行卡绑定的用户姓名
-
+
{{ fieldErrors.name }}
身份证号
18 位二代身份证号码
-
+
{{ fieldErrors.cert_no }}
身份证有效期至
长期有效请选择 2099-12-31
-
+
{{ certEndDisplay || '请选择日期' }}
›
@@ -66,18 +66,18 @@
详细地址
-
+
{{ fieldErrors.reg_detail }}
身份证人像面
-
+
{{ fieldErrors.id_card_front_url }}
身份证国徽面
-
+
{{ fieldErrors.id_card_back_url }}
@@ -89,18 +89,18 @@
商户名称
请输入营业执照上的名称
-
+
{{ fieldErrors.reg_name }}
统一社会信用代码
-
+
{{ fieldErrors.license_code }}
统一社会信用代码有效期
长期有效请选择 2099-12-31
-
+
{{ licenseEndDisplay || '请选择日期' }}
›
@@ -118,27 +118,27 @@
企业地址
-
+
{{ fieldErrors.reg_detail }}
法人姓名
-
+
{{ fieldErrors.legal_name }}
法人手机号
-
+
{{ fieldErrors.legal_mobile }}
法人身份证号
-
+
{{ fieldErrors.legal_cert_no }}
法人身份证有效期
-
+
{{ legalCertEndDisplay || '请选择日期' }}
›
@@ -149,17 +149,17 @@
营业执照照片
-
+
{{ fieldErrors.license_url }}
法人身份证人像面
-
+
{{ fieldErrors.legal_id_front_url }}
法人身份证国徽面
-
+
{{ fieldErrors.legal_id_back_url }}
@@ -173,7 +173,7 @@
class="type-item small"
v-for="item in bankAccountTypeOptions"
:key="item.value"
- :class="{ active: form.bank_account_type === item.value, disabled: readonly }"
+ :class="{ active: form.bank_account_type === item.value, disabled: bankReadonly }"
@tap="setBankAccountType(item.value)"
>
{{ form.bank_account_type === item.value ? '✓' : '' }}
@@ -183,14 +183,14 @@
结算账户银行卡号
分成资金到账银行卡号,须为一类借记卡
-
+
{{ fieldErrors.card_no }}
开户银行名称
搜索支行名称,系统将自动匹配联行号
-
-
+
+
{{ item.branch_name }}
{{ item.branch_code }}
@@ -207,23 +207,24 @@
{{ form.account_type === 'ent' ? '手机号' : '手机号' }}
银行卡开户预留的手机号
-
+
{{ fieldErrors.mobile_no }}
- 银行卡正面照
- 建议上传,可加快审核
-
+ 银行卡正面照
+ {{ editMode === 'bank_only' ? '更换卡号时请重新上传银行卡照片' : '建议上传,可加快审核' }}
+
+ {{ fieldErrors.bank_card_url }}
开户许可证/基本户证明
-
+
-
- 驳回原因
- {{ statusInfo.reject_reason }}
+
+ {{ statusInfo.card_modify_reject_reason ? '换卡驳回原因' : '驳回原因' }}
+ {{ statusInfo.card_modify_reject_reason || statusInfo.reject_reason }}
@@ -236,7 +237,9 @@ export default {
props: {
required: { type: Boolean, default: false },
statusInfo: { type: Object, default: () => ({}) },
- readonly: { type: Boolean, default: false }
+ readonly: { type: Boolean, default: false },
+ /** full=完整进件;bank_only=仅更换结算卡 */
+ editMode: { type: String, default: 'full' }
},
data() {
return {
@@ -248,6 +251,7 @@ export default {
{ label: '对公', value: '1' },
{ label: '对私', value: '0' }
],
+ originalCardNo: '',
form: {
account_type: 'indv',
bank_account_type: '0',
@@ -308,6 +312,18 @@ export default {
uploadHeader() {
return { token: uni.getStorageSync('token') || '' };
},
+ identityReadonly() {
+ return this.readonly || this.editMode === 'bank_only';
+ },
+ bankReadonly() {
+ return this.readonly;
+ },
+ formTipText() {
+ if (this.editMode === 'bank_only') {
+ return '进件已通过,可修改结算银行卡信息后提交更换';
+ }
+ return '填写开户资料,先由平台审核,通过后再提交汇付';
+ },
bankMobile: {
get() {
return this.form.account_type === 'ent' ? this.form.legal_mobile : this.form.mobile_no;
@@ -340,10 +356,49 @@ export default {
return this.displayDate(this.form.legal_cert_end_date);
}
},
+ watch: {
+ statusInfo: {
+ immediate: true,
+ deep: true,
+ handler(val) {
+ if (val && val.draft) {
+ this.applyDraft(val.draft);
+ }
+ }
+ }
+ },
mounted() {
this.loadArea();
},
methods: {
+ applyDraft(draft) {
+ if (!draft || typeof draft !== 'object') return;
+ Object.keys(this.form).forEach(key => {
+ if (draft[key] !== undefined && draft[key] !== null && draft[key] !== '') {
+ this.form[key] = draft[key];
+ }
+ });
+ this.originalCardNo = String(this.form.card_no || '').replace(/\s+/g, '');
+ if (draft.branch_name) {
+ this.branchKeyword = draft.branch_name;
+ }
+ const setList = (url, listKey) => {
+ if (url) this[listKey] = [{ url }];
+ };
+ setList(this.form.id_card_front_url, 'frontList');
+ setList(this.form.id_card_back_url, 'backList');
+ setList(this.form.license_url, 'licenseList');
+ setList(this.form.legal_id_front_url, 'legalFrontList');
+ setList(this.form.legal_id_back_url, 'legalBackList');
+ setList(this.form.bank_card_url, 'bankList');
+ setList(this.form.account_permit_url, 'permitList');
+ if (draft.shopro_province_id || draft.prov_id) {
+ // 区域文案在无完整省市区树时先用编码占位,用户可重选支行补齐
+ if (!this.regionText) {
+ this.regionText = [draft.prov_id, draft.area_id, draft.district_id].filter(Boolean).join(' / ');
+ }
+ }
+ },
loadArea() {
this.$http('address.area').then(res => {
if (res.code !== 1) return;
@@ -360,18 +415,18 @@ export default {
});
},
setAccountType(value) {
- if (this.readonly) return;
+ if (this.identityReadonly) return;
this.form.account_type = value;
if (value === 'indv') {
this.form.bank_account_type = '0';
}
},
setBankAccountType(value) {
- if (this.readonly) return;
+ if (this.bankReadonly) return;
this.form.bank_account_type = value;
},
openRegionPicker() {
- if (this.readonly) return;
+ if (this.identityReadonly) return;
if (!this.addressAreaList.length) {
this.$u.toast('区域数据加载中,请稍候');
return;
@@ -414,8 +469,20 @@ export default {
this.applyValidityByEnd('legal_cert', e.detail.value);
this.clearError('legal_cert_end_date');
},
+ onCardNoInput() {
+ this.clearError('card_no');
+ if (this.editMode !== 'bank_only') return;
+ const newCard = String(this.form.card_no || '').replace(/\s+/g, '');
+ const oldCard = String(this.originalCardNo || '').replace(/\s+/g, '');
+ if (newCard && oldCard && newCard !== oldCard) {
+ // 卡号变更后必须重新上传银行卡图,避免沿用旧图
+ this.form.bank_card_url = '';
+ this.bankList = [];
+ this.clearError('bank_card_url');
+ }
+ },
onBranchInput() {
- if (this.readonly) return;
+ if (this.bankReadonly) return;
clearTimeout(this.branchTimer);
const keyword = (this.branchKeyword || '').trim();
if (keyword.length < 2) {
@@ -545,13 +612,16 @@ export default {
if (!this.required) return true;
this.fieldErrors = {};
const f = this.form;
- if (!f.prov_id || !f.area_id) return this.failField('prov_id', '请选择所在区域');
if (!f.branch_code && !(this.branchKeyword || f.branch_name)) {
return this.failField('branch_name', '请搜索并选择开户银行支行');
}
if (!f.branch_name && this.branchKeyword) {
f.branch_name = this.branchKeyword.trim();
}
+ if (this.editMode === 'bank_only') {
+ return this.validateBankOnly();
+ }
+ if (!f.prov_id || !f.area_id) return this.failField('prov_id', '请选择所在区域');
if (f.account_type === 'indv') {
if (!f.name) return this.failField('name', '请填写真实姓名');
if (!f.cert_no) return this.failField('cert_no', '请填写身份证号');
@@ -597,6 +667,30 @@ export default {
}
return true;
},
+ validateBankOnly() {
+ const f = this.form;
+ if (!f.card_no || !/^\d{12,19}$/.test(String(f.card_no).replace(/\s+/g, ''))) {
+ return this.failField('card_no', '请填写正确银行卡号');
+ }
+ if (!f.branch_code) {
+ return this.failField('branch_name', '请搜索并选择开户银行支行');
+ }
+ const newCard = String(f.card_no).replace(/\s+/g, '');
+ const oldCard = String(this.originalCardNo || '').replace(/\s+/g, '');
+ if (newCard !== oldCard && !f.bank_card_url) {
+ return this.failField('bank_card_url', '更换银行卡号时请重新上传银行卡照片');
+ }
+ if (f.account_type === 'indv' || (f.account_type === 'ent' && f.bank_account_type === '0')) {
+ const mobile = f.account_type === 'ent' ? f.legal_mobile : f.mobile_no;
+ if (!mobile || !/^1\d{10}$/.test(mobile)) {
+ return this.failField('mobile_no', '请填写银行预留手机号');
+ }
+ }
+ if (f.account_type === 'ent' && f.bank_account_type === '1' && !f.account_permit_url) {
+ return this.failField('account_permit_url', '对公账户请上传开户许可证');
+ }
+ return true;
+ },
statusText(status) {
const map = {
draft: '待后台审核',
diff --git a/xgsc.gynhc.com_wx/pages/user/wallet/onboard-bind.vue b/xgsc.gynhc.com_wx/pages/user/wallet/onboard-bind.vue
index 7da65a7..42830f8 100644
--- a/xgsc.gynhc.com_wx/pages/user/wallet/onboard-bind.vue
+++ b/xgsc.gynhc.com_wx/pages/user/wallet/onboard-bind.vue
@@ -13,6 +13,7 @@
:required="huifuRequired"
:statusInfo="huifuStatus"
:readonly="huifuFormReadonly"
+ :editMode="formEditMode"
>