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" >