feat(shopro_huifu): 完善汇付进件功能的表单验证和错误处理

- 增加支行搜索功能的城市筛选支持,优化搜索逻辑
- 添加前端表单验证机制,包括身份证、银行卡、区域等必填字段校验
- 改进支行选择验证,确保必须从搜索结果中选择带联行号的支行
- 优化后端保存逻辑,添加强制保存参数控制
- 统一异常处理机制,增加HttpResponseException的正确抛出
- 完善用户界面提示信息,明确操作指引和错误反馈
- 修复表单提交前的数据准备逻辑,确保数据完整性
```
这个提交包含在:
可乐加冰
2026-09-29 16:08:44 +08:00
父节点 98bd0be5e4
当前提交 38c66b8f5e
共有 10 个文件被更改,包括 142 次插入 和 18 次删除

查看文件

@@ -147,14 +147,19 @@ class Onboard extends Base
$service = new HuifuOnboardAdminService();
$onboardId = $row ? intval($row['id']) : 0;
$saved = $service->saveDraft($userId, $roleType, $roleRefId, $form, $onboardId);
$this->success('进件资料已保存,状态为待后台审核', null, [
'id' => $saved ? $saved['id'] : 0,
]);
} catch (\InvalidArgumentException $e) {
$this->error($e->getMessage());
} catch (\think\exception\HttpResponseException $e) {
throw $e;
} catch (\Throwable $e) {
$this->error(HuifuOnboardError::translate($e->getMessage()));
}
if (!$saved) {
$this->error('进件资料保存失败,请检查汇付分账配置是否已启用');
}
$this->success('进件资料已保存,状态为待后台审核', null, [
'id' => intval($saved['id']),
]);
}
public function retry($ids = null)

查看文件

@@ -389,8 +389,9 @@
</el-col>
<el-col :span="24">
<el-form-item label="开户银行支行" required>
<el-input v-model="branchKeyword" class="form-input" placeholder="搜索支行名称" @input="onBranchInput"></el-input>
<div class="field-tip" v-if="form.branch_name">已选:{{ form.branch_name }}({{ form.branch_code }})</div>
<el-input v-model="branchKeyword" class="form-input" placeholder="输入支行名称搜索,并从下方结果中点击选择" @input="onBranchInput"></el-input>
<div class="field-tip">须从搜索结果中点击选择支行,仅输入文字无法保存</div>
<div class="field-tip" v-if="form.branch_code" style="color:#7536D0;">已选:{{ form.branch_name }}(联行号 {{ form.branch_code }})</div>
<div class="branch-panel" v-if="branchResults.length">
<div class="branch-item" v-for="(item, idx) in branchResults" :key="idx" @click="selectBranch(item)">
<div>{{ item.branch_name }}</div>

查看文件

@@ -31,7 +31,7 @@ class HuifuOnboardAdminService
}
$service = new HuifuOnboardService();
return $service->saveDraft($userId, $roleType, $roleRefId, $formData, $onboardId);
return $service->saveDraft($userId, $roleType, $roleRefId, $formData, $onboardId, true);
}
protected function assertRoleBinding($userId, $roleType, $roleRefId)

查看文件

@@ -72,15 +72,20 @@ class HuifuOnboardBankBranch
}
}
protected static function searchJson($keyword, $limit)
protected static function searchJson($keyword, $cityCode = '', $limit = 20)
{
$limit = max(0, (int) $limit);
if ($limit <= 0) {
return [];
}
$cityCode = HuifuOnboardAreaHelper::toCode($cityCode);
$all = self::loadJson();
$keywordLower = mb_strtolower($keyword, 'UTF-8');
$rows = [];
foreach ($all as $item) {
if ($cityCode !== '' && HuifuOnboardAreaHelper::toCode($item['area_id'] ?? '') !== $cityCode) {
continue;
}
$hay = mb_strtolower(
($item['branch_name'] ?? '') . ' ' . ($item['bank_name'] ?? '') . ' ' . ($item['branch_code'] ?? ''),
'UTF-8'

查看文件

@@ -31,9 +31,9 @@ class HuifuOnboardService
/**
* 用户申请时仅保存进件资料,待后台业务审核通过后再提交汇付
*/
public function saveDraft($userId, $roleType, $roleRefId, array $formData, $onboardId = 0)
public function saveDraft($userId, $roleType, $roleRefId, array $formData, $onboardId = 0, $force = false)
{
if (!HuifuOnboardGate::isOnboardRequired()) {
if (!$force && !HuifuOnboardGate::isOnboardRequired()) {
return null;
}
if (!in_array($roleType, ['promoter', 'regional_agent'], true)) {

查看文件

@@ -93,6 +93,9 @@ class HuifuOnboardValidator
if (empty($data['branch_code']) && empty($data['branch_name'])) {
throw new \InvalidArgumentException('请选择开户银行支行');
}
if (empty($data['branch_code']) && !empty($data['branch_name'])) {
throw new \InvalidArgumentException('请从搜索结果中点击选择开户银行支行(需联行号)');
}
if (empty($data['prov_id']) || empty($data['area_id'])) {
throw new \InvalidArgumentException('请选择所在区域');
}

查看文件

@@ -233,17 +233,24 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
},
onBranchInput: function () {
var vm = this;
var keyword = (vm.branchKeyword || '').trim();
if (keyword !== vm.form.branch_name) {
vm.form.branch_code = '';
vm.form.branch_name = keyword;
}
clearTimeout(branchTimer);
branchTimer = setTimeout(function () {
if (!vm.branchKeyword) {
if (!keyword) {
vm.branchResults = [];
vm.form.branch_code = '';
vm.form.branch_name = '';
return;
}
Fast.api.ajax({
url: 'shopro_huifu/onboard/searchBranch',
type: 'GET',
data: {
keyword: vm.branchKeyword,
keyword: keyword,
area_id: vm.form.area_id || vm.form.shopro_city_id
}
}, function (ret, res) {
@@ -252,6 +259,47 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
});
}, 300);
},
prepareFormBeforeSubmit: function () {
var keyword = (this.branchKeyword || '').trim();
if (keyword) {
this.form.branch_name = keyword;
}
this.form.mp = this.bankMobile;
},
validateFormBeforeSubmit: function () {
var form = this.form;
if (form.account_type === 'indv') {
if (!form.name || !form.cert_no || !form.mobile_no || !form.reg_detail) {
Toastr.error('请完整填写身份实名信息');
return false;
}
if (!form.id_card_front_url || !form.id_card_back_url) {
Toastr.error('请上传身份证人像面和国徽面');
return false;
}
}
if (!form.card_no) {
Toastr.error('请填写银行卡号');
return false;
}
if (!this.bankMobile) {
Toastr.error('请填写银行预留手机号');
return false;
}
if (!form.branch_code) {
if ((this.branchKeyword || '').trim() || form.branch_name) {
Toastr.error('请从支行搜索结果中点击选择开户银行(需联行号)');
} else {
Toastr.error('请搜索并选择开户银行支行');
}
return false;
}
if (!form.shopro_province_id && !form.prov_id) {
Toastr.error('请选择所在区域');
return false;
}
return true;
},
selectBranch: function (item) {
this.form.branch_code = item.branch_code;
this.form.branch_name = item.branch_name;
@@ -282,6 +330,10 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
return;
}
}
vm.prepareFormBeforeSubmit();
if (!vm.validateFormBeforeSubmit()) {
return;
}
vm.saving = true;
var url = vm.isEdit
? ('shopro_huifu/onboard/edit/ids/' + vm.editId)

查看文件

@@ -149,14 +149,19 @@ class Onboard extends Base
$service = new HuifuOnboardAdminService();
$onboardId = $row ? intval($row['id']) : 0;
$saved = $service->saveDraft($userId, $roleType, $roleRefId, $form, $onboardId);
$this->success('进件资料已保存,状态为待后台审核', null, [
'id' => $saved ? $saved['id'] : 0,
]);
} catch (\InvalidArgumentException $e) {
$this->error($e->getMessage());
} catch (\think\exception\HttpResponseException $e) {
throw $e;
} catch (\Throwable $e) {
$this->error(HuifuOnboardError::translate($e->getMessage()));
}
if (!$saved) {
$this->error('进件资料保存失败,请检查汇付分账配置是否已启用');
}
$this->success('进件资料已保存,状态为待后台审核', null, [
'id' => intval($saved['id']),
]);
}
public function retry($ids = null)

查看文件

@@ -389,8 +389,9 @@
</el-col>
<el-col :span="24">
<el-form-item label="开户银行支行" required>
<el-input v-model="branchKeyword" class="form-input" placeholder="搜索支行名称" @input="onBranchInput"></el-input>
<div class="field-tip" v-if="form.branch_name">已选:{{ form.branch_name }}({{ form.branch_code }})</div>
<el-input v-model="branchKeyword" class="form-input" placeholder="输入支行名称搜索,并从下方结果中点击选择" @input="onBranchInput"></el-input>
<div class="field-tip">须从搜索结果中点击选择支行,仅输入文字无法保存</div>
<div class="field-tip" v-if="form.branch_code" style="color:#7536D0;">已选:{{ form.branch_name }}(联行号 {{ form.branch_code }})</div>
<div class="branch-panel" v-if="branchResults.length">
<div class="branch-item" v-for="(item, idx) in branchResults" :key="idx" @click="selectBranch(item)">
<div>{{ item.branch_name }}</div>

查看文件

@@ -233,17 +233,24 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
},
onBranchInput: function () {
var vm = this;
var keyword = (vm.branchKeyword || '').trim();
if (keyword !== vm.form.branch_name) {
vm.form.branch_code = '';
vm.form.branch_name = keyword;
}
clearTimeout(branchTimer);
branchTimer = setTimeout(function () {
if (!vm.branchKeyword) {
if (!keyword) {
vm.branchResults = [];
vm.form.branch_code = '';
vm.form.branch_name = '';
return;
}
Fast.api.ajax({
url: 'shopro_huifu/onboard/searchBranch',
type: 'GET',
data: {
keyword: vm.branchKeyword,
keyword: keyword,
area_id: vm.form.area_id || vm.form.shopro_city_id
}
}, function (ret, res) {
@@ -252,6 +259,47 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
});
}, 300);
},
prepareFormBeforeSubmit: function () {
var keyword = (this.branchKeyword || '').trim();
if (keyword) {
this.form.branch_name = keyword;
}
this.form.mp = this.bankMobile;
},
validateFormBeforeSubmit: function () {
var form = this.form;
if (form.account_type === 'indv') {
if (!form.name || !form.cert_no || !form.mobile_no || !form.reg_detail) {
Toastr.error('请完整填写身份实名信息');
return false;
}
if (!form.id_card_front_url || !form.id_card_back_url) {
Toastr.error('请上传身份证人像面和国徽面');
return false;
}
}
if (!form.card_no) {
Toastr.error('请填写银行卡号');
return false;
}
if (!this.bankMobile) {
Toastr.error('请填写银行预留手机号');
return false;
}
if (!form.branch_code) {
if ((this.branchKeyword || '').trim() || form.branch_name) {
Toastr.error('请从支行搜索结果中点击选择开户银行(需联行号)');
} else {
Toastr.error('请搜索并选择开户银行支行');
}
return false;
}
if (!form.shopro_province_id && !form.prov_id) {
Toastr.error('请选择所在区域');
return false;
}
return true;
},
selectBranch: function (item) {
this.form.branch_code = item.branch_code;
this.form.branch_name = item.branch_name;
@@ -282,6 +330,10 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
return;
}
}
vm.prepareFormBeforeSubmit();
if (!vm.validateFormBeforeSubmit()) {
return;
}
vm.saving = true;
var url = vm.isEdit
? ('shopro_huifu/onboard/edit/ids/' + vm.editId)