```
feat(shopro_huifu): 添加汇付进件管理功能 - 新增汇付进件管理模块,支持新建、编辑进件流程 - 实现用户角色绑定验证功能,确保进件角色的有效性 - 集成Vue.js前端界面,提供完整的表单操作体验 - 支持个人和企业两种账户类型的进件资料录入 - 添加银行支行搜索功能,方便结算账户信息填写 - 完善进件状态管理和审核流程控制 - 增加图片上传组件,支持身份证、营业执照等证件上传 ```
这个提交包含在:
@@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
namespace app\admin\controller\shopro_huifu;
|
namespace app\admin\controller\shopro_huifu;
|
||||||
|
|
||||||
|
use addons\shopro_huifu\library\onboard\HuifuOnboardAdminService;
|
||||||
use addons\shopro_huifu\library\onboard\HuifuOnboardAdminView;
|
use addons\shopro_huifu\library\onboard\HuifuOnboardAdminView;
|
||||||
|
use addons\shopro_huifu\library\onboard\HuifuOnboardBankBranch;
|
||||||
|
use addons\shopro_huifu\library\onboard\HuifuOnboardError;
|
||||||
use addons\shopro_huifu\library\onboard\HuifuOnboardQuery;
|
use addons\shopro_huifu\library\onboard\HuifuOnboardQuery;
|
||||||
use addons\shopro_huifu\library\onboard\HuifuOnboardService;
|
use addons\shopro_huifu\library\onboard\HuifuOnboardService;
|
||||||
use addons\shopro_huifu\model\Onboard as OnboardModel;
|
use addons\shopro_huifu\model\Onboard as OnboardModel;
|
||||||
@@ -10,6 +13,8 @@ use app\admin\controller\shopro\Base;
|
|||||||
|
|
||||||
class Onboard extends Base
|
class Onboard extends Base
|
||||||
{
|
{
|
||||||
|
protected $noNeedRight = ['userRoles', 'searchBranch'];
|
||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
if ($this->request->isAjax()) {
|
if ($this->request->isAjax()) {
|
||||||
@@ -74,6 +79,78 @@ class Onboard extends Base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function add()
|
||||||
|
{
|
||||||
|
if ($this->request->isPost()) {
|
||||||
|
return $this->persistDraft();
|
||||||
|
}
|
||||||
|
return $this->view->fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit($ids = null)
|
||||||
|
{
|
||||||
|
$row = OnboardModel::get($ids);
|
||||||
|
if (!$row) {
|
||||||
|
$this->error('记录不存在');
|
||||||
|
}
|
||||||
|
if ($this->request->isPost()) {
|
||||||
|
return $this->persistDraft($row);
|
||||||
|
}
|
||||||
|
$this->assignconfig('onboardForm', HuifuOnboardAdminView::formDataFromRow($row));
|
||||||
|
return $this->view->fetch('shopro_huifu/onboard/add');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userRoles()
|
||||||
|
{
|
||||||
|
$userId = intval($this->request->get('user_id', 0));
|
||||||
|
if ($userId <= 0) {
|
||||||
|
$this->error('请选择用户');
|
||||||
|
}
|
||||||
|
$user = HuifuOnboardAdminView::enrichListRow(['user_id' => $userId, 'payload' => '']);
|
||||||
|
$this->success('ok', null, [
|
||||||
|
'user' => [
|
||||||
|
'id' => $userId,
|
||||||
|
'nickname' => $user['user_nickname'] ?? '',
|
||||||
|
'mobile' => $user['user_mobile'] ?? '',
|
||||||
|
],
|
||||||
|
'roles' => HuifuOnboardAdminView::listRolesForUser($userId),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchBranch()
|
||||||
|
{
|
||||||
|
$keyword = trim((string) $this->request->get('keyword', ''));
|
||||||
|
$areaId = trim((string) $this->request->get('area_id', ''));
|
||||||
|
$this->success('ok', null, HuifuOnboardBankBranch::search($keyword, $areaId, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function persistDraft($row = null)
|
||||||
|
{
|
||||||
|
$userId = intval($this->request->post('user_id', 0));
|
||||||
|
$roleType = trim((string) $this->request->post('role_type', ''));
|
||||||
|
$roleRefId = intval($this->request->post('role_ref_id', 0));
|
||||||
|
$form = $this->request->post('form/a', []);
|
||||||
|
if ($row) {
|
||||||
|
$userId = intval($row['user_id']);
|
||||||
|
$roleType = $row['role_type'];
|
||||||
|
$roleRefId = intval($row['role_ref_id']);
|
||||||
|
}
|
||||||
|
if (!$form || !is_array($form)) {
|
||||||
|
$this->error('请填写进件资料');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$service = new HuifuOnboardAdminService();
|
||||||
|
$saved = $service->saveDraft($userId, $roleType, $roleRefId, $form);
|
||||||
|
$this->success('进件资料已保存,状态为待后台审核', null, [
|
||||||
|
'id' => $saved ? $saved['id'] : 0,
|
||||||
|
]);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->error(HuifuOnboardError::translate($e->getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function retry($ids = null)
|
public function retry($ids = null)
|
||||||
{
|
{
|
||||||
$row = OnboardModel::get($ids);
|
$row = OnboardModel::get($ids);
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
<link rel="stylesheet" href="__CDN__/assets/addons/shopro/libs/element/element.css">
|
||||||
|
<style>
|
||||||
|
[v-cloak] { display: none; }
|
||||||
|
#huifuOnboardAdd { padding: 16px 20px 24px; color: #444; max-height: 78vh; overflow-y: auto; }
|
||||||
|
#huifuOnboardAdd .form-input { width: 100%; }
|
||||||
|
#huifuOnboardAdd .section-title { font-size: 14px; font-weight: 600; margin: 18px 0 12px; padding-left: 8px; border-left: 3px solid #409EFF; }
|
||||||
|
#huifuOnboardAdd .field-tip { color: #909399; font-size: 12px; line-height: 1.5; margin-top: 4px; }
|
||||||
|
#huifuOnboardAdd .upload-box { width: 140px; height: 90px; border: 1px dashed #dcdfe6; border-radius: 4px; display: flex; align-items: center; justify-content: center; overflow: hidden; background: #fafafa; }
|
||||||
|
#huifuOnboardAdd .upload-box img { width: 100%; height: 100%; object-fit: cover; }
|
||||||
|
#huifuOnboardAdd .branch-item { padding: 8px 0; border-bottom: 1px solid #f0f0f0; cursor: pointer; }
|
||||||
|
#huifuOnboardAdd .branch-item:hover { background: #f5f7fa; }
|
||||||
|
#huifuOnboardAdd .branch-panel { max-height: 180px; overflow-y: auto; border: 1px solid #ebeef5; border-radius: 4px; padding: 0 10px; margin-top: 6px; }
|
||||||
|
</style>
|
||||||
|
<script src="__CDN__/assets/addons/shopro/libs/vue.js"></script>
|
||||||
|
<script src="__CDN__/assets/addons/shopro/libs/element/element.js"></script>
|
||||||
|
<div id="huifuOnboardAdd" v-cloak>
|
||||||
|
<el-form label-width="120px" size="small">
|
||||||
|
<div class="section-title">用户与角色</div>
|
||||||
|
<el-form-item label="选择用户" v-if="!isEdit">
|
||||||
|
<el-select v-model="userId" filterable remote reserve-keyword placeholder="输入昵称/手机号/ID搜索" :remote-method="searchUser" :loading="userLoading" class="form-input" @change="onUserChange">
|
||||||
|
<el-option v-for="item in userOptions" :key="item.id" :label="item.nickname + ' (' + (item.mobile || item.id) + ')'" :value="item.id"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户" v-else>
|
||||||
|
<span>{{ userLabel }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="进件角色" v-if="!isEdit">
|
||||||
|
<el-select v-model="roleKey" placeholder="请先选择用户" class="form-input" :disabled="!roleOptions.length" @change="onRoleChange">
|
||||||
|
<el-option v-for="item in roleOptions" :key="item.role_type + '-' + item.role_ref_id" :label="item.role_label + (item.onboard_status ? ' [' + item.onboard_status + ']' : '')" :value="item.role_type + ':' + item.role_ref_id" :disabled="!item.can_save">
|
||||||
|
<span>{{ item.role_label }}</span>
|
||||||
|
<span style="color:#909399;font-size:12px;margin-left:8px;">{{ item.disabled_reason || (item.onboard_status ? '已有记录:' + item.onboard_status : '新建') }}</span>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="进件角色" v-else>
|
||||||
|
<span>{{ roleLabel }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="section-title">账户类型</div>
|
||||||
|
<el-form-item label="结算账户类型">
|
||||||
|
<el-radio-group v-model="form.account_type">
|
||||||
|
<el-radio label="indv">个人</el-radio>
|
||||||
|
<el-radio label="ent">个体户/企业</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="银行卡类型" v-if="form.account_type === 'ent'">
|
||||||
|
<el-radio-group v-model="form.bank_account_type">
|
||||||
|
<el-radio label="0">对私</el-radio>
|
||||||
|
<el-radio label="1">对公</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<template v-if="form.account_type === 'indv'">
|
||||||
|
<div class="section-title">身份实名信息</div>
|
||||||
|
<el-form-item label="真实姓名" required>
|
||||||
|
<el-input v-model="form.name" class="form-input" placeholder="与身份证一致"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="身份证号" required>
|
||||||
|
<el-input v-model="form.cert_no" maxlength="18" class="form-input"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="证件有效期">
|
||||||
|
<el-radio-group v-model="form.cert_validity_type">
|
||||||
|
<el-radio label="1">长期有效</el-radio>
|
||||||
|
<el-radio label="0">有截止日期</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="证件开始日期" required>
|
||||||
|
<el-date-picker v-model="form.cert_begin_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" placeholder="选择日期" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="证件截止日期" v-if="form.cert_validity_type === '0'" required>
|
||||||
|
<el-date-picker v-model="form.cert_end_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" placeholder="长期可填20991231" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号" required>
|
||||||
|
<el-input v-model="form.mobile_no" maxlength="11" class="form-input"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所在区域" required>
|
||||||
|
<el-cascader v-model="regionPath" :options="areaOptions" :props="areaProps" filterable clearable class="form-input" @change="onRegionChange"></el-cascader>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="详细地址" required>
|
||||||
|
<el-input v-model="form.reg_detail" class="form-input" placeholder="详细居住地址"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="身份证人像面" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('id_card_front_url', res)">
|
||||||
|
<div class="upload-box">
|
||||||
|
<img v-if="form.id_card_front_url" :src="form.id_card_front_url">
|
||||||
|
<span v-else style="color:#909399;font-size:12px;">点击上传</span>
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="身份证国徽面" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('id_card_back_url', res)">
|
||||||
|
<div class="upload-box">
|
||||||
|
<img v-if="form.id_card_back_url" :src="form.id_card_back_url">
|
||||||
|
<span v-else style="color:#909399;font-size:12px;">点击上传</span>
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<div class="section-title">商户信息</div>
|
||||||
|
<el-form-item label="商户名称" required><el-input v-model="form.reg_name" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="统一社会信用代码" required><el-input v-model="form.license_code" maxlength="18" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="执照有效期">
|
||||||
|
<el-radio-group v-model="form.license_validity_type"><el-radio label="1">长期</el-radio><el-radio label="0">有截止</el-radio></el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="执照开始日期" required>
|
||||||
|
<el-date-picker v-model="form.license_begin_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="执照截止日期" v-if="form.license_validity_type === '0'" required>
|
||||||
|
<el-date-picker v-model="form.license_end_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所在区域" required>
|
||||||
|
<el-cascader v-model="regionPath" :options="areaOptions" :props="areaProps" filterable clearable class="form-input" @change="onRegionChange"></el-cascader>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="详细地址" required><el-input v-model="form.reg_detail" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="法人姓名" required><el-input v-model="form.legal_name" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="法人手机号" required><el-input v-model="form.legal_mobile" maxlength="11" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="法人身份证号" required><el-input v-model="form.legal_cert_no" maxlength="18" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="法人证件有效期">
|
||||||
|
<el-radio-group v-model="form.legal_cert_validity_type"><el-radio label="1">长期</el-radio><el-radio label="0">有截止</el-radio></el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="法人证件开始" required>
|
||||||
|
<el-date-picker v-model="form.legal_cert_begin_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="法人证件截止" v-if="form.legal_cert_validity_type === '0'" required>
|
||||||
|
<el-date-picker v-model="form.legal_cert_end_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="营业执照" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('license_url', res)">
|
||||||
|
<div class="upload-box"><img v-if="form.license_url" :src="form.license_url"><span v-else style="color:#909399;font-size:12px;">点击上传</span></div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="法人身份证人像面" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('legal_id_front_url', res)">
|
||||||
|
<div class="upload-box"><img v-if="form.legal_id_front_url" :src="form.legal_id_front_url"><span v-else style="color:#909399;font-size:12px;">点击上传</span></div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="法人身份证国徽面" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('legal_id_back_url', res)">
|
||||||
|
<div class="upload-box"><img v-if="form.legal_id_back_url" :src="form.legal_id_back_url"><span v-else style="color:#909399;font-size:12px;">点击上传</span></div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="section-title">结算账户信息</div>
|
||||||
|
<el-form-item label="银行卡号" required>
|
||||||
|
<el-input v-model="form.card_no" class="form-input" placeholder="一类借记卡"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
<div style="color:#909399;font-size:12px;">{{ item.branch_code }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="银行预留手机号" required>
|
||||||
|
<el-input v-model="bankMobile" maxlength="11" class="form-input"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="银行卡正面照">
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('bank_card_url', res)">
|
||||||
|
<div class="upload-box"><img v-if="form.bank_card_url" :src="form.bank_card_url"><span v-else style="color:#909399;font-size:12px;">点击上传</span></div>
|
||||||
|
</el-upload>
|
||||||
|
<div class="field-tip">建议上传,可加快审核</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="开户许可证" v-if="form.account_type === 'ent' && form.bank_account_type === '1'" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('account_permit_url', res)">
|
||||||
|
<div class="upload-box"><img v-if="form.account_permit_url" :src="form.account_permit_url"><span v-else style="color:#909399;font-size:12px;">点击上传</span></div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" :loading="saving" @click="submitForm">{{ isEdit ? '保存修改' : '保存进件资料' }}</el-button>
|
||||||
|
<el-button @click="closeForm">取消</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
<el-option label="已驳回" value="rejected"></el-option>
|
<el-option label="已驳回" value="rejected"></el-option>
|
||||||
<el-option label="失败" value="failed"></el-option>
|
<el-option label="失败" value="failed"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
<el-button size="small" type="success" @click="openCreate" style="margin-left:8px;">新建进件</el-button>
|
||||||
<el-button size="small" type="primary" @click="getList" style="margin-left:8px;">刷新列表</el-button>
|
<el-button size="small" type="primary" @click="getList" style="margin-left:8px;">刷新列表</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="listData" v-loading="loading" border empty-text="暂无进件记录">
|
<el-table :data="listData" v-loading="loading" border empty-text="暂无进件记录">
|
||||||
@@ -55,9 +56,10 @@
|
|||||||
<el-table-column prop="updatetime" label="更新时间" width="160">
|
<el-table-column prop="updatetime" label="更新时间" width="160">
|
||||||
<template slot-scope="scope">{{ formatTime(scope.row.updatetime) }}</template>
|
<template slot-scope="scope">{{ formatTime(scope.row.updatetime) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="240" fixed="right">
|
<el-table-column label="操作" width="300" fixed="right">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button size="mini" type="text" @click="openDetail(scope.row.id)">查看资料</el-button>
|
<el-button size="mini" type="text" @click="openDetail(scope.row.id)">查看资料</el-button>
|
||||||
|
<el-button size="mini" type="text" @click="openEdit(scope.row.id)" v-if="canEditRow(scope.row)">编辑</el-button>
|
||||||
<el-button size="mini" type="primary" @click="submitRow(scope.row.id)" v-if="scope.row.onboard_status === 'draft'">提交汇付</el-button>
|
<el-button size="mini" type="primary" @click="submitRow(scope.row.id)" v-if="scope.row.onboard_status === 'draft'">提交汇付</el-button>
|
||||||
<el-button size="mini" @click="pollRow(scope.row.id)" v-if="scope.row.onboard_status !== 'draft' && scope.row.onboard_status !== 'approved'">刷新</el-button>
|
<el-button size="mini" @click="pollRow(scope.row.id)" v-if="scope.row.onboard_status !== 'draft' && scope.row.onboard_status !== 'approved'">刷新</el-button>
|
||||||
<el-button size="mini" type="warning" @click="retryRow(scope.row.id)" v-if="scope.row.onboard_status === 'rejected' || scope.row.onboard_status === 'failed'">重提</el-button>
|
<el-button size="mini" type="warning" @click="retryRow(scope.row.id)" v-if="scope.row.onboard_status === 'rejected' || scope.row.onboard_status === 'failed'">重提</el-button>
|
||||||
@@ -133,6 +135,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<span slot="footer">
|
<span slot="footer">
|
||||||
<el-button @click="detailVisible = false">关闭</el-button>
|
<el-button @click="detailVisible = false">关闭</el-button>
|
||||||
|
<el-button v-if="detailData && canEditRow(detailData.record)" @click="editFromDetail">编辑资料</el-button>
|
||||||
<el-button type="primary" v-if="detailData && detailData.can_submit_huifu" @click="submitFromDetail">提交汇付</el-button>
|
<el-button type="primary" v-if="detailData && detailData.can_submit_huifu" @click="submitFromDetail">提交汇付</el-button>
|
||||||
<el-button v-if="detailData && detailData.can_poll" @click="pollFromDetail">刷新状态</el-button>
|
<el-button v-if="detailData && detailData.can_poll" @click="pollFromDetail">刷新状态</el-button>
|
||||||
<el-button type="warning" v-if="detailData && detailData.can_retry_huifu" @click="retryFromDetail">重新提交</el-button>
|
<el-button type="warning" v-if="detailData && detailData.can_retry_huifu" @click="retryFromDetail">重新提交</el-button>
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ return [
|
|||||||
'weigh' => 4,
|
'weigh' => 4,
|
||||||
'sublist' => [
|
'sublist' => [
|
||||||
['type' => 'file', 'name' => 'shopro_huifu/onboard/index', 'title' => '查看', 'ismenu' => 0],
|
['type' => 'file', 'name' => 'shopro_huifu/onboard/index', 'title' => '查看', 'ismenu' => 0],
|
||||||
|
['type' => 'file', 'name' => 'shopro_huifu/onboard/add', 'title' => '新建进件', 'ismenu' => 0],
|
||||||
|
['type' => 'file', 'name' => 'shopro_huifu/onboard/edit', 'title' => '编辑进件', 'ismenu' => 0],
|
||||||
|
['type' => 'file', 'name' => 'shopro_huifu/onboard/userRoles', 'title' => '用户角色', 'ismenu' => 0],
|
||||||
|
['type' => 'file', 'name' => 'shopro_huifu/onboard/searchBranch', 'title' => '搜索支行', 'ismenu' => 0],
|
||||||
['type' => 'file', 'name' => 'shopro_huifu/onboard/detail', 'title' => '查看资料', 'ismenu' => 0],
|
['type' => 'file', 'name' => 'shopro_huifu/onboard/detail', 'title' => '查看资料', 'ismenu' => 0],
|
||||||
['type' => 'file', 'name' => 'shopro_huifu/onboard/poll', 'title' => '刷新状态', 'ismenu' => 0],
|
['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/submit', 'title' => '提交汇付', 'ismenu' => 0],
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace addons\shopro_huifu\library\onboard;
|
||||||
|
|
||||||
|
use addons\shopro_huifu\model\Onboard;
|
||||||
|
use think\Db;
|
||||||
|
|
||||||
|
class HuifuOnboardAdminService
|
||||||
|
{
|
||||||
|
public function saveDraft($userId, $roleType, $roleRefId, array $formData)
|
||||||
|
{
|
||||||
|
$userId = intval($userId);
|
||||||
|
$roleRefId = intval($roleRefId);
|
||||||
|
if ($userId <= 0) {
|
||||||
|
throw new \InvalidArgumentException('请选择用户');
|
||||||
|
}
|
||||||
|
if (!in_array($roleType, ['promoter', 'regional_agent'], true)) {
|
||||||
|
throw new \InvalidArgumentException('请选择进件角色');
|
||||||
|
}
|
||||||
|
$this->assertRoleBinding($userId, $roleType, $roleRefId);
|
||||||
|
|
||||||
|
$service = new HuifuOnboardService();
|
||||||
|
return $service->saveDraft($userId, $roleType, $roleRefId, $formData);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function assertRoleBinding($userId, $roleType, $roleRefId)
|
||||||
|
{
|
||||||
|
if ($roleType === 'promoter') {
|
||||||
|
if ($roleRefId !== $userId) {
|
||||||
|
throw new \InvalidArgumentException('分销商角色参数无效');
|
||||||
|
}
|
||||||
|
$agent = Db::name('shopro_commission_agent')->where('user_id', $userId)->find();
|
||||||
|
if (!$agent) {
|
||||||
|
throw new \InvalidArgumentException('该用户不是分销商,无法创建分销商进件');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$agent = Db::name('shopro_regional_agent')
|
||||||
|
->where('id', $roleRefId)
|
||||||
|
->where('user_id', $userId)
|
||||||
|
->find();
|
||||||
|
if (!$agent) {
|
||||||
|
throw new \InvalidArgumentException('区域公司与用户不匹配');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -206,4 +206,140 @@ class HuifuOnboardAdminView
|
|||||||
}
|
}
|
||||||
return substr($value, 0, 4) . '-' . substr($value, 4, 2) . '-' . substr($value, 6, 2);
|
return substr($value, 0, 4) . '-' . substr($value, 4, 2) . '-' . substr($value, 6, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台新建/编辑进件:列出用户可绑定的角色
|
||||||
|
*/
|
||||||
|
public static function listRolesForUser($userId)
|
||||||
|
{
|
||||||
|
$userId = intval($userId);
|
||||||
|
if ($userId <= 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$roles = [];
|
||||||
|
$commissionAgent = Db::name('shopro_commission_agent')->where('user_id', $userId)->find();
|
||||||
|
if ($commissionAgent) {
|
||||||
|
$row = \addons\shopro_huifu\model\Onboard::findByRole($userId, 'promoter', $userId);
|
||||||
|
$roles[] = self::buildRoleOption(
|
||||||
|
'promoter',
|
||||||
|
$userId,
|
||||||
|
'分销商',
|
||||||
|
$commissionAgent['status'] ?? '',
|
||||||
|
$row
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$regionalAgents = Db::name('shopro_regional_agent')->where('user_id', $userId)->order('id desc')->select();
|
||||||
|
foreach ($regionalAgents as $agent) {
|
||||||
|
$row = \addons\shopro_huifu\model\Onboard::findByRole($userId, 'regional_agent', $agent['id']);
|
||||||
|
$label = '区域公司';
|
||||||
|
if (!empty($agent['area_name'])) {
|
||||||
|
$label .= '(' . $agent['area_name'] . ')';
|
||||||
|
}
|
||||||
|
$roles[] = self::buildRoleOption(
|
||||||
|
'regional_agent',
|
||||||
|
$agent['id'],
|
||||||
|
$label,
|
||||||
|
$agent['status'] ?? '',
|
||||||
|
$row
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function buildRoleOption($roleType, $roleRefId, $label, $agentStatus, $onboardRow)
|
||||||
|
{
|
||||||
|
$onboardStatus = $onboardRow ? ($onboardRow['onboard_status'] ?? '') : '';
|
||||||
|
$blocked = $onboardRow && in_array($onboardStatus, [
|
||||||
|
\addons\shopro_huifu\model\Onboard::STATUS_SUBMITTING,
|
||||||
|
\addons\shopro_huifu\model\Onboard::STATUS_BASIC_OK,
|
||||||
|
\addons\shopro_huifu\model\Onboard::STATUS_BUSI_PENDING,
|
||||||
|
\addons\shopro_huifu\model\Onboard::STATUS_APPROVED,
|
||||||
|
], true);
|
||||||
|
return [
|
||||||
|
'role_type' => $roleType,
|
||||||
|
'role_ref_id' => $roleRefId,
|
||||||
|
'role_label' => $label,
|
||||||
|
'agent_status' => $agentStatus,
|
||||||
|
'onboard_id' => $onboardRow ? intval($onboardRow['id']) : 0,
|
||||||
|
'onboard_status' => $onboardStatus ?: null,
|
||||||
|
'can_save' => !$blocked,
|
||||||
|
'disabled_reason' => $blocked ? '该角色进件处理中或已通过,不可新建/覆盖' : '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function defaultFormData()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'account_type' => 'indv',
|
||||||
|
'bank_account_type' => '0',
|
||||||
|
'name' => '',
|
||||||
|
'cert_no' => '',
|
||||||
|
'cert_validity_type' => '1',
|
||||||
|
'cert_begin_date' => '',
|
||||||
|
'cert_end_date' => '',
|
||||||
|
'mobile_no' => '',
|
||||||
|
'reg_detail' => '',
|
||||||
|
'shopro_province_id' => '',
|
||||||
|
'shopro_city_id' => '',
|
||||||
|
'shopro_district_id' => '',
|
||||||
|
'prov_id' => '',
|
||||||
|
'area_id' => '',
|
||||||
|
'district_id' => '',
|
||||||
|
'card_no' => '',
|
||||||
|
'card_name' => '',
|
||||||
|
'branch_code' => '',
|
||||||
|
'branch_name' => '',
|
||||||
|
'mp' => '',
|
||||||
|
'id_card_front_url' => '',
|
||||||
|
'id_card_back_url' => '',
|
||||||
|
'bank_card_url' => '',
|
||||||
|
'reg_name' => '',
|
||||||
|
'license_code' => '',
|
||||||
|
'license_validity_type' => '1',
|
||||||
|
'license_begin_date' => '',
|
||||||
|
'license_end_date' => '',
|
||||||
|
'legal_name' => '',
|
||||||
|
'legal_mobile' => '',
|
||||||
|
'legal_cert_no' => '',
|
||||||
|
'legal_cert_validity_type' => '1',
|
||||||
|
'legal_cert_begin_date' => '',
|
||||||
|
'legal_cert_end_date' => '',
|
||||||
|
'license_url' => '',
|
||||||
|
'legal_id_front_url' => '',
|
||||||
|
'legal_id_back_url' => '',
|
||||||
|
'account_permit_url' => '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function formDataFromRow($row)
|
||||||
|
{
|
||||||
|
$data = is_array($row) ? $row : $row->toArray();
|
||||||
|
$payload = self::parsePayload($data['payload'] ?? '');
|
||||||
|
$form = array_merge(self::defaultFormData(), $payload);
|
||||||
|
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'] as $field) {
|
||||||
|
if (!empty($form[$field])) {
|
||||||
|
$form[$field] = self::fullUrl($form[$field]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$user = self::fetchUser($data['user_id'] ?? 0);
|
||||||
|
$roles = self::listRolesForUser($data['user_id'] ?? 0);
|
||||||
|
$roleLabel = '';
|
||||||
|
foreach ($roles as $role) {
|
||||||
|
if ($role['role_type'] === ($data['role_type'] ?? '') && intval($role['role_ref_id']) === intval($data['role_ref_id'] ?? 0)) {
|
||||||
|
$roleLabel = $role['role_label'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'onboard_id' => intval($data['id'] ?? 0),
|
||||||
|
'user_id' => intval($data['user_id'] ?? 0),
|
||||||
|
'user_label' => trim(($user['nickname'] ?? '') . ' (' . ($user['mobile'] ?? $data['user_id']) . ')'),
|
||||||
|
'role_type' => $data['role_type'] ?? '',
|
||||||
|
'role_ref_id' => intval($data['role_ref_id'] ?? 0),
|
||||||
|
'role_label' => $roleLabel,
|
||||||
|
'onboard_status' => $data['onboard_status'] ?? '',
|
||||||
|
'form' => $form,
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
||||||
|
|
||||||
|
var areaCache = null;
|
||||||
|
var branchTimer = null;
|
||||||
|
|
||||||
function withVue(callback) {
|
function withVue(callback) {
|
||||||
if (typeof Vue !== 'undefined') {
|
if (typeof Vue !== 'undefined') {
|
||||||
callback(Vue);
|
callback(Vue);
|
||||||
@@ -22,6 +25,262 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function defaultForm() {
|
||||||
|
return {
|
||||||
|
account_type: 'indv',
|
||||||
|
bank_account_type: '0',
|
||||||
|
name: '',
|
||||||
|
cert_no: '',
|
||||||
|
cert_validity_type: '1',
|
||||||
|
cert_begin_date: '',
|
||||||
|
cert_end_date: '',
|
||||||
|
mobile_no: '',
|
||||||
|
reg_detail: '',
|
||||||
|
shopro_province_id: '',
|
||||||
|
shopro_city_id: '',
|
||||||
|
shopro_district_id: '',
|
||||||
|
prov_id: '',
|
||||||
|
area_id: '',
|
||||||
|
district_id: '',
|
||||||
|
card_no: '',
|
||||||
|
card_name: '',
|
||||||
|
branch_code: '',
|
||||||
|
branch_name: '',
|
||||||
|
mp: '',
|
||||||
|
id_card_front_url: '',
|
||||||
|
id_card_back_url: '',
|
||||||
|
bank_card_url: '',
|
||||||
|
reg_name: '',
|
||||||
|
license_code: '',
|
||||||
|
license_validity_type: '1',
|
||||||
|
license_begin_date: '',
|
||||||
|
license_end_date: '',
|
||||||
|
legal_name: '',
|
||||||
|
legal_mobile: '',
|
||||||
|
legal_cert_no: '',
|
||||||
|
legal_cert_validity_type: '1',
|
||||||
|
legal_cert_begin_date: '',
|
||||||
|
legal_cert_end_date: '',
|
||||||
|
license_url: '',
|
||||||
|
legal_id_front_url: '',
|
||||||
|
legal_id_back_url: '',
|
||||||
|
account_permit_url: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFormMixin() {
|
||||||
|
return {
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
isEdit: false,
|
||||||
|
editId: 0,
|
||||||
|
userId: '',
|
||||||
|
userLabel: '',
|
||||||
|
roleKey: '',
|
||||||
|
roleType: '',
|
||||||
|
roleRefId: 0,
|
||||||
|
roleLabel: '',
|
||||||
|
userOptions: [],
|
||||||
|
userLoading: false,
|
||||||
|
roleOptions: [],
|
||||||
|
form: defaultForm(),
|
||||||
|
regionPath: [],
|
||||||
|
areaOptions: [],
|
||||||
|
areaProps: { value: 'id', label: 'name', children: 'children' },
|
||||||
|
branchKeyword: '',
|
||||||
|
branchResults: [],
|
||||||
|
uploadUrl: Fast.api.fixurl('ajax/upload'),
|
||||||
|
saving: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
bankMobile: {
|
||||||
|
get: function () {
|
||||||
|
return this.form.account_type === 'ent' ? this.form.legal_mobile : this.form.mobile_no;
|
||||||
|
},
|
||||||
|
set: function (val) {
|
||||||
|
if (this.form.account_type === 'ent') {
|
||||||
|
this.form.legal_mobile = val;
|
||||||
|
} else {
|
||||||
|
this.form.mobile_no = val;
|
||||||
|
}
|
||||||
|
this.form.mp = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted: function () {
|
||||||
|
this.loadAreaTree();
|
||||||
|
this.initFromConfig();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initFromConfig: function () {
|
||||||
|
var init = (typeof Config !== 'undefined' && Config.onboardForm) ? Config.onboardForm : null;
|
||||||
|
if (!init) return;
|
||||||
|
this.isEdit = true;
|
||||||
|
this.editId = init.onboard_id || 0;
|
||||||
|
this.userId = init.user_id;
|
||||||
|
this.userLabel = init.user_label || '';
|
||||||
|
this.roleType = init.role_type;
|
||||||
|
this.roleRefId = init.role_ref_id;
|
||||||
|
this.roleKey = init.role_type + ':' + init.role_ref_id;
|
||||||
|
this.roleLabel = init.role_label || '';
|
||||||
|
this.form = Object.assign(defaultForm(), init.form || {});
|
||||||
|
this.branchKeyword = this.form.branch_name || '';
|
||||||
|
this.restoreRegionPath();
|
||||||
|
},
|
||||||
|
loadAreaTree: function () {
|
||||||
|
var vm = this;
|
||||||
|
var done = function (data) {
|
||||||
|
areaCache = data || [];
|
||||||
|
vm.areaOptions = areaCache;
|
||||||
|
vm.restoreRegionPath();
|
||||||
|
};
|
||||||
|
if (areaCache) {
|
||||||
|
done(areaCache);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Fast.api.ajax({ url: 'shopro/area/getCascader', type: 'GET' }, function (ret, res) {
|
||||||
|
done(res.data || []);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
restoreRegionPath: function () {
|
||||||
|
var ids = [];
|
||||||
|
if (this.form.shopro_province_id) ids.push(parseInt(this.form.shopro_province_id, 10));
|
||||||
|
if (this.form.shopro_city_id) ids.push(parseInt(this.form.shopro_city_id, 10));
|
||||||
|
if (this.form.shopro_district_id) ids.push(parseInt(this.form.shopro_district_id, 10));
|
||||||
|
this.regionPath = ids.filter(function (n) { return !!n; });
|
||||||
|
},
|
||||||
|
onRegionChange: function (val) {
|
||||||
|
val = val || [];
|
||||||
|
this.form.shopro_province_id = val[0] ? String(val[0]) : '';
|
||||||
|
this.form.shopro_city_id = val[1] ? String(val[1]) : '';
|
||||||
|
this.form.shopro_district_id = val[2] ? String(val[2]) : '';
|
||||||
|
this.form.prov_id = this.form.shopro_province_id;
|
||||||
|
this.form.area_id = this.form.shopro_city_id;
|
||||||
|
this.form.district_id = this.form.shopro_district_id;
|
||||||
|
},
|
||||||
|
searchUser: function (keyword) {
|
||||||
|
if (!keyword) return;
|
||||||
|
var vm = this;
|
||||||
|
vm.userLoading = true;
|
||||||
|
Fast.api.ajax({
|
||||||
|
url: 'shopro/user/user/index',
|
||||||
|
type: 'GET',
|
||||||
|
data: { offset: 0, limit: 20, searchWhere: keyword }
|
||||||
|
}, function (ret, res) {
|
||||||
|
vm.userOptions = (res.data && res.data.rows) || [];
|
||||||
|
vm.userLoading = false;
|
||||||
|
return false;
|
||||||
|
}, function () {
|
||||||
|
vm.userLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onUserChange: function () {
|
||||||
|
var vm = this;
|
||||||
|
vm.roleKey = '';
|
||||||
|
vm.roleType = '';
|
||||||
|
vm.roleRefId = 0;
|
||||||
|
vm.roleOptions = [];
|
||||||
|
if (!vm.userId) return;
|
||||||
|
Fast.api.ajax({
|
||||||
|
url: 'shopro_huifu/onboard/userRoles',
|
||||||
|
type: 'GET',
|
||||||
|
data: { user_id: vm.userId }
|
||||||
|
}, function (ret, res) {
|
||||||
|
var data = res.data || {};
|
||||||
|
vm.roleOptions = data.roles || [];
|
||||||
|
if (data.user) {
|
||||||
|
vm.userLabel = (data.user.nickname || '') + ' (' + (data.user.mobile || data.user.id) + ')';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onRoleChange: function () {
|
||||||
|
var parts = String(this.roleKey || '').split(':');
|
||||||
|
this.roleType = parts[0] || '';
|
||||||
|
this.roleRefId = parseInt(parts[1] || '0', 10);
|
||||||
|
var role = this.roleOptions.find(function (item) {
|
||||||
|
return item.role_type === this.roleType && item.role_ref_id === this.roleRefId;
|
||||||
|
}.bind(this));
|
||||||
|
this.roleLabel = role ? role.role_label : '';
|
||||||
|
},
|
||||||
|
onBranchInput: function () {
|
||||||
|
var vm = this;
|
||||||
|
clearTimeout(branchTimer);
|
||||||
|
branchTimer = setTimeout(function () {
|
||||||
|
if (!vm.branchKeyword) {
|
||||||
|
vm.branchResults = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Fast.api.ajax({
|
||||||
|
url: 'shopro_huifu/onboard/searchBranch',
|
||||||
|
type: 'GET',
|
||||||
|
data: {
|
||||||
|
keyword: vm.branchKeyword,
|
||||||
|
area_id: vm.form.area_id || vm.form.shopro_city_id
|
||||||
|
}
|
||||||
|
}, function (ret, res) {
|
||||||
|
vm.branchResults = res.data || [];
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
selectBranch: function (item) {
|
||||||
|
this.form.branch_code = item.branch_code;
|
||||||
|
this.form.branch_name = item.branch_name;
|
||||||
|
this.branchKeyword = item.branch_name;
|
||||||
|
this.branchResults = [];
|
||||||
|
if (item.prov_id) this.form.prov_id = item.prov_id;
|
||||||
|
if (item.area_id) this.form.area_id = item.area_id;
|
||||||
|
},
|
||||||
|
onUploadSuccess: function (field, res) {
|
||||||
|
if (res && res.code === 1 && res.data && res.data.url) {
|
||||||
|
this.form[field] = res.data.fullurl || res.data.url;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$message.error((res && res.msg) || '上传失败');
|
||||||
|
},
|
||||||
|
closeForm: function () {
|
||||||
|
Fast.api.close();
|
||||||
|
},
|
||||||
|
submitForm: function () {
|
||||||
|
var vm = this;
|
||||||
|
if (!vm.isEdit) {
|
||||||
|
if (!vm.userId) {
|
||||||
|
Toastr.error('请选择用户');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!vm.roleType || !vm.roleRefId) {
|
||||||
|
Toastr.error('请选择进件角色');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm.saving = true;
|
||||||
|
var url = vm.isEdit
|
||||||
|
? ('shopro_huifu/onboard/edit/ids/' + vm.editId)
|
||||||
|
: 'shopro_huifu/onboard/add';
|
||||||
|
Fast.api.ajax({
|
||||||
|
url: url,
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
user_id: vm.userId,
|
||||||
|
role_type: vm.roleType,
|
||||||
|
role_ref_id: vm.roleRefId,
|
||||||
|
form: vm.form
|
||||||
|
}
|
||||||
|
}, function () {
|
||||||
|
vm.saving = false;
|
||||||
|
Fast.api.close();
|
||||||
|
return false;
|
||||||
|
}, function () {
|
||||||
|
vm.saving = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var Controller = {
|
var Controller = {
|
||||||
index: function () {
|
index: function () {
|
||||||
withVue(function (Vue) {
|
withVue(function (Vue) {
|
||||||
@@ -49,6 +308,30 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
|||||||
this.getList();
|
this.getList();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
openCreate: function () {
|
||||||
|
var vm = this;
|
||||||
|
Backend.api.open('shopro_huifu/onboard/add', '新建汇付进件', {
|
||||||
|
area: ['900px', '90%'],
|
||||||
|
callback: function () {
|
||||||
|
vm.getList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
openEdit: function (id) {
|
||||||
|
var vm = this;
|
||||||
|
Backend.api.open('shopro_huifu/onboard/edit/ids/' + id, '编辑汇付进件', {
|
||||||
|
area: ['900px', '90%'],
|
||||||
|
callback: function () {
|
||||||
|
vm.getList();
|
||||||
|
if (vm.detailVisible && vm.detailId === id) {
|
||||||
|
vm.openDetail(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
canEditRow: function (row) {
|
||||||
|
return ['draft', 'failed', 'rejected'].indexOf(row.onboard_status) >= 0;
|
||||||
|
},
|
||||||
getList: function () {
|
getList: function () {
|
||||||
var vm = this;
|
var vm = this;
|
||||||
vm.loading = true;
|
vm.loading = true;
|
||||||
@@ -131,6 +414,11 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
|||||||
this.retryRow(this.detailId);
|
this.retryRow(this.detailId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
editFromDetail: function () {
|
||||||
|
if (this.detailId) {
|
||||||
|
this.openEdit(this.detailId);
|
||||||
|
}
|
||||||
|
},
|
||||||
statusText: function (status) {
|
statusText: function (status) {
|
||||||
var map = {
|
var map = {
|
||||||
draft: '待后台审核',
|
draft: '待后台审核',
|
||||||
@@ -155,6 +443,17 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
add: function () {
|
||||||
|
withVue(function (Vue) {
|
||||||
|
new Vue({
|
||||||
|
el: '#huifuOnboardAdd',
|
||||||
|
mixins: [createFormMixin()]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
edit: function () {
|
||||||
|
Controller.add();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return Controller;
|
return Controller;
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
namespace app\admin\controller\shopro_huifu;
|
namespace app\admin\controller\shopro_huifu;
|
||||||
|
|
||||||
|
use addons\shopro_huifu\library\onboard\HuifuOnboardAdminService;
|
||||||
use addons\shopro_huifu\library\onboard\HuifuOnboardAdminView;
|
use addons\shopro_huifu\library\onboard\HuifuOnboardAdminView;
|
||||||
|
use addons\shopro_huifu\library\onboard\HuifuOnboardBankBranch;
|
||||||
|
use addons\shopro_huifu\library\onboard\HuifuOnboardError;
|
||||||
use addons\shopro_huifu\library\onboard\HuifuOnboardQuery;
|
use addons\shopro_huifu\library\onboard\HuifuOnboardQuery;
|
||||||
use addons\shopro_huifu\library\onboard\HuifuOnboardService;
|
use addons\shopro_huifu\library\onboard\HuifuOnboardService;
|
||||||
use addons\shopro_huifu\model\Onboard as OnboardModel;
|
use addons\shopro_huifu\model\Onboard as OnboardModel;
|
||||||
@@ -10,6 +13,7 @@ use app\admin\controller\shopro\Base;
|
|||||||
|
|
||||||
class Onboard extends Base
|
class Onboard extends Base
|
||||||
{
|
{
|
||||||
|
protected $noNeedRight = ['userRoles', 'searchBranch'];
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
if ($this->request->isAjax()) {
|
if ($this->request->isAjax()) {
|
||||||
@@ -77,6 +81,78 @@ class Onboard extends Base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function add()
|
||||||
|
{
|
||||||
|
if ($this->request->isPost()) {
|
||||||
|
return $this->persistDraft();
|
||||||
|
}
|
||||||
|
return $this->view->fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit($ids = null)
|
||||||
|
{
|
||||||
|
$row = OnboardModel::get($ids);
|
||||||
|
if (!$row) {
|
||||||
|
$this->error('记录不存在');
|
||||||
|
}
|
||||||
|
if ($this->request->isPost()) {
|
||||||
|
return $this->persistDraft($row);
|
||||||
|
}
|
||||||
|
$this->assignconfig('onboardForm', HuifuOnboardAdminView::formDataFromRow($row));
|
||||||
|
return $this->view->fetch('shopro_huifu/onboard/add');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userRoles()
|
||||||
|
{
|
||||||
|
$userId = intval($this->request->get('user_id', 0));
|
||||||
|
if ($userId <= 0) {
|
||||||
|
$this->error('请选择用户');
|
||||||
|
}
|
||||||
|
$user = HuifuOnboardAdminView::enrichListRow(['user_id' => $userId, 'payload' => '']);
|
||||||
|
$this->success('ok', null, [
|
||||||
|
'user' => [
|
||||||
|
'id' => $userId,
|
||||||
|
'nickname' => $user['user_nickname'] ?? '',
|
||||||
|
'mobile' => $user['user_mobile'] ?? '',
|
||||||
|
],
|
||||||
|
'roles' => HuifuOnboardAdminView::listRolesForUser($userId),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchBranch()
|
||||||
|
{
|
||||||
|
$keyword = trim((string) $this->request->get('keyword', ''));
|
||||||
|
$areaId = trim((string) $this->request->get('area_id', ''));
|
||||||
|
$this->success('ok', null, HuifuOnboardBankBranch::search($keyword, $areaId, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function persistDraft($row = null)
|
||||||
|
{
|
||||||
|
$userId = intval($this->request->post('user_id', 0));
|
||||||
|
$roleType = trim((string) $this->request->post('role_type', ''));
|
||||||
|
$roleRefId = intval($this->request->post('role_ref_id', 0));
|
||||||
|
$form = $this->request->post('form/a', []);
|
||||||
|
if ($row) {
|
||||||
|
$userId = intval($row['user_id']);
|
||||||
|
$roleType = $row['role_type'];
|
||||||
|
$roleRefId = intval($row['role_ref_id']);
|
||||||
|
}
|
||||||
|
if (!$form || !is_array($form)) {
|
||||||
|
$this->error('请填写进件资料');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$service = new HuifuOnboardAdminService();
|
||||||
|
$saved = $service->saveDraft($userId, $roleType, $roleRefId, $form);
|
||||||
|
$this->success('进件资料已保存,状态为待后台审核', null, [
|
||||||
|
'id' => $saved ? $saved['id'] : 0,
|
||||||
|
]);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->error(HuifuOnboardError::translate($e->getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function retry($ids = null)
|
public function retry($ids = null)
|
||||||
{
|
{
|
||||||
$row = OnboardModel::get($ids);
|
$row = OnboardModel::get($ids);
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
<link rel="stylesheet" href="__CDN__/assets/addons/shopro/libs/element/element.css">
|
||||||
|
<style>
|
||||||
|
[v-cloak] { display: none; }
|
||||||
|
#huifuOnboardAdd { padding: 16px 20px 24px; color: #444; max-height: 78vh; overflow-y: auto; }
|
||||||
|
#huifuOnboardAdd .form-input { width: 100%; }
|
||||||
|
#huifuOnboardAdd .section-title { font-size: 14px; font-weight: 600; margin: 18px 0 12px; padding-left: 8px; border-left: 3px solid #409EFF; }
|
||||||
|
#huifuOnboardAdd .field-tip { color: #909399; font-size: 12px; line-height: 1.5; margin-top: 4px; }
|
||||||
|
#huifuOnboardAdd .upload-box { width: 140px; height: 90px; border: 1px dashed #dcdfe6; border-radius: 4px; display: flex; align-items: center; justify-content: center; overflow: hidden; background: #fafafa; }
|
||||||
|
#huifuOnboardAdd .upload-box img { width: 100%; height: 100%; object-fit: cover; }
|
||||||
|
#huifuOnboardAdd .branch-item { padding: 8px 0; border-bottom: 1px solid #f0f0f0; cursor: pointer; }
|
||||||
|
#huifuOnboardAdd .branch-item:hover { background: #f5f7fa; }
|
||||||
|
#huifuOnboardAdd .branch-panel { max-height: 180px; overflow-y: auto; border: 1px solid #ebeef5; border-radius: 4px; padding: 0 10px; margin-top: 6px; }
|
||||||
|
</style>
|
||||||
|
<script src="__CDN__/assets/addons/shopro/libs/vue.js"></script>
|
||||||
|
<script src="__CDN__/assets/addons/shopro/libs/element/element.js"></script>
|
||||||
|
<div id="huifuOnboardAdd" v-cloak>
|
||||||
|
<el-form label-width="120px" size="small">
|
||||||
|
<div class="section-title">用户与角色</div>
|
||||||
|
<el-form-item label="选择用户" v-if="!isEdit">
|
||||||
|
<el-select v-model="userId" filterable remote reserve-keyword placeholder="输入昵称/手机号/ID搜索" :remote-method="searchUser" :loading="userLoading" class="form-input" @change="onUserChange">
|
||||||
|
<el-option v-for="item in userOptions" :key="item.id" :label="item.nickname + ' (' + (item.mobile || item.id) + ')'" :value="item.id"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户" v-else>
|
||||||
|
<span>{{ userLabel }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="进件角色" v-if="!isEdit">
|
||||||
|
<el-select v-model="roleKey" placeholder="请先选择用户" class="form-input" :disabled="!roleOptions.length" @change="onRoleChange">
|
||||||
|
<el-option v-for="item in roleOptions" :key="item.role_type + '-' + item.role_ref_id" :label="item.role_label + (item.onboard_status ? ' [' + item.onboard_status + ']' : '')" :value="item.role_type + ':' + item.role_ref_id" :disabled="!item.can_save">
|
||||||
|
<span>{{ item.role_label }}</span>
|
||||||
|
<span style="color:#909399;font-size:12px;margin-left:8px;">{{ item.disabled_reason || (item.onboard_status ? '已有记录:' + item.onboard_status : '新建') }}</span>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="进件角色" v-else>
|
||||||
|
<span>{{ roleLabel }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="section-title">账户类型</div>
|
||||||
|
<el-form-item label="结算账户类型">
|
||||||
|
<el-radio-group v-model="form.account_type">
|
||||||
|
<el-radio label="indv">个人</el-radio>
|
||||||
|
<el-radio label="ent">个体户/企业</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="银行卡类型" v-if="form.account_type === 'ent'">
|
||||||
|
<el-radio-group v-model="form.bank_account_type">
|
||||||
|
<el-radio label="0">对私</el-radio>
|
||||||
|
<el-radio label="1">对公</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<template v-if="form.account_type === 'indv'">
|
||||||
|
<div class="section-title">身份实名信息</div>
|
||||||
|
<el-form-item label="真实姓名" required>
|
||||||
|
<el-input v-model="form.name" class="form-input" placeholder="与身份证一致"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="身份证号" required>
|
||||||
|
<el-input v-model="form.cert_no" maxlength="18" class="form-input"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="证件有效期">
|
||||||
|
<el-radio-group v-model="form.cert_validity_type">
|
||||||
|
<el-radio label="1">长期有效</el-radio>
|
||||||
|
<el-radio label="0">有截止日期</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="证件开始日期" required>
|
||||||
|
<el-date-picker v-model="form.cert_begin_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" placeholder="选择日期" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="证件截止日期" v-if="form.cert_validity_type === '0'" required>
|
||||||
|
<el-date-picker v-model="form.cert_end_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" placeholder="长期可填20991231" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号" required>
|
||||||
|
<el-input v-model="form.mobile_no" maxlength="11" class="form-input"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所在区域" required>
|
||||||
|
<el-cascader v-model="regionPath" :options="areaOptions" :props="areaProps" filterable clearable class="form-input" @change="onRegionChange"></el-cascader>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="详细地址" required>
|
||||||
|
<el-input v-model="form.reg_detail" class="form-input" placeholder="详细居住地址"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="身份证人像面" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('id_card_front_url', res)">
|
||||||
|
<div class="upload-box">
|
||||||
|
<img v-if="form.id_card_front_url" :src="form.id_card_front_url">
|
||||||
|
<span v-else style="color:#909399;font-size:12px;">点击上传</span>
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="身份证国徽面" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('id_card_back_url', res)">
|
||||||
|
<div class="upload-box">
|
||||||
|
<img v-if="form.id_card_back_url" :src="form.id_card_back_url">
|
||||||
|
<span v-else style="color:#909399;font-size:12px;">点击上传</span>
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<div class="section-title">商户信息</div>
|
||||||
|
<el-form-item label="商户名称" required><el-input v-model="form.reg_name" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="统一社会信用代码" required><el-input v-model="form.license_code" maxlength="18" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="执照有效期">
|
||||||
|
<el-radio-group v-model="form.license_validity_type"><el-radio label="1">长期</el-radio><el-radio label="0">有截止</el-radio></el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="执照开始日期" required>
|
||||||
|
<el-date-picker v-model="form.license_begin_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="执照截止日期" v-if="form.license_validity_type === '0'" required>
|
||||||
|
<el-date-picker v-model="form.license_end_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所在区域" required>
|
||||||
|
<el-cascader v-model="regionPath" :options="areaOptions" :props="areaProps" filterable clearable class="form-input" @change="onRegionChange"></el-cascader>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="详细地址" required><el-input v-model="form.reg_detail" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="法人姓名" required><el-input v-model="form.legal_name" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="法人手机号" required><el-input v-model="form.legal_mobile" maxlength="11" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="法人身份证号" required><el-input v-model="form.legal_cert_no" maxlength="18" class="form-input"></el-input></el-form-item>
|
||||||
|
<el-form-item label="法人证件有效期">
|
||||||
|
<el-radio-group v-model="form.legal_cert_validity_type"><el-radio label="1">长期</el-radio><el-radio label="0">有截止</el-radio></el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="法人证件开始" required>
|
||||||
|
<el-date-picker v-model="form.legal_cert_begin_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="法人证件截止" v-if="form.legal_cert_validity_type === '0'" required>
|
||||||
|
<el-date-picker v-model="form.legal_cert_end_date" type="date" value-format="yyyyMMdd" format="yyyy-MM-dd" class="form-input"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="营业执照" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('license_url', res)">
|
||||||
|
<div class="upload-box"><img v-if="form.license_url" :src="form.license_url"><span v-else style="color:#909399;font-size:12px;">点击上传</span></div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="法人身份证人像面" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('legal_id_front_url', res)">
|
||||||
|
<div class="upload-box"><img v-if="form.legal_id_front_url" :src="form.legal_id_front_url"><span v-else style="color:#909399;font-size:12px;">点击上传</span></div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="法人身份证国徽面" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('legal_id_back_url', res)">
|
||||||
|
<div class="upload-box"><img v-if="form.legal_id_back_url" :src="form.legal_id_back_url"><span v-else style="color:#909399;font-size:12px;">点击上传</span></div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="section-title">结算账户信息</div>
|
||||||
|
<el-form-item label="银行卡号" required>
|
||||||
|
<el-input v-model="form.card_no" class="form-input" placeholder="一类借记卡"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
<div style="color:#909399;font-size:12px;">{{ item.branch_code }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="银行预留手机号" required>
|
||||||
|
<el-input v-model="bankMobile" maxlength="11" class="form-input"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="银行卡正面照">
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('bank_card_url', res)">
|
||||||
|
<div class="upload-box"><img v-if="form.bank_card_url" :src="form.bank_card_url"><span v-else style="color:#909399;font-size:12px;">点击上传</span></div>
|
||||||
|
</el-upload>
|
||||||
|
<div class="field-tip">建议上传,可加快审核</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="开户许可证" v-if="form.account_type === 'ent' && form.bank_account_type === '1'" required>
|
||||||
|
<el-upload :action="uploadUrl" :show-file-list="false" accept="image/*" :on-success="(res) => onUploadSuccess('account_permit_url', res)">
|
||||||
|
<div class="upload-box"><img v-if="form.account_permit_url" :src="form.account_permit_url"><span v-else style="color:#909399;font-size:12px;">点击上传</span></div>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" :loading="saving" @click="submitForm">{{ isEdit ? '保存修改' : '保存进件资料' }}</el-button>
|
||||||
|
<el-button @click="closeForm">取消</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
<el-option label="已驳回" value="rejected"></el-option>
|
<el-option label="已驳回" value="rejected"></el-option>
|
||||||
<el-option label="失败" value="failed"></el-option>
|
<el-option label="失败" value="failed"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
<el-button size="small" type="success" @click="openCreate" style="margin-left:8px;">新建进件</el-button>
|
||||||
<el-button size="small" type="primary" @click="getList" style="margin-left:8px;">刷新列表</el-button>
|
<el-button size="small" type="primary" @click="getList" style="margin-left:8px;">刷新列表</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="listData" v-loading="loading" border empty-text="暂无进件记录">
|
<el-table :data="listData" v-loading="loading" border empty-text="暂无进件记录">
|
||||||
@@ -55,9 +56,10 @@
|
|||||||
<el-table-column prop="updatetime" label="更新时间" width="160">
|
<el-table-column prop="updatetime" label="更新时间" width="160">
|
||||||
<template slot-scope="scope">{{ formatTime(scope.row.updatetime) }}</template>
|
<template slot-scope="scope">{{ formatTime(scope.row.updatetime) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="240" fixed="right">
|
<el-table-column label="操作" width="300" fixed="right">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button size="mini" type="text" @click="openDetail(scope.row.id)">查看资料</el-button>
|
<el-button size="mini" type="text" @click="openDetail(scope.row.id)">查看资料</el-button>
|
||||||
|
<el-button size="mini" type="text" @click="openEdit(scope.row.id)" v-if="canEditRow(scope.row)">编辑</el-button>
|
||||||
<el-button size="mini" type="primary" @click="submitRow(scope.row.id)" v-if="scope.row.onboard_status === 'draft'">提交汇付</el-button>
|
<el-button size="mini" type="primary" @click="submitRow(scope.row.id)" v-if="scope.row.onboard_status === 'draft'">提交汇付</el-button>
|
||||||
<el-button size="mini" @click="pollRow(scope.row.id)" v-if="scope.row.onboard_status !== 'draft' && scope.row.onboard_status !== 'approved'">刷新</el-button>
|
<el-button size="mini" @click="pollRow(scope.row.id)" v-if="scope.row.onboard_status !== 'draft' && scope.row.onboard_status !== 'approved'">刷新</el-button>
|
||||||
<el-button size="mini" type="warning" @click="retryRow(scope.row.id)" v-if="scope.row.onboard_status === 'rejected' || scope.row.onboard_status === 'failed'">重提</el-button>
|
<el-button size="mini" type="warning" @click="retryRow(scope.row.id)" v-if="scope.row.onboard_status === 'rejected' || scope.row.onboard_status === 'failed'">重提</el-button>
|
||||||
@@ -133,6 +135,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<span slot="footer">
|
<span slot="footer">
|
||||||
<el-button @click="detailVisible = false">关闭</el-button>
|
<el-button @click="detailVisible = false">关闭</el-button>
|
||||||
|
<el-button v-if="detailData && canEditRow(detailData.record)" @click="editFromDetail">编辑资料</el-button>
|
||||||
<el-button type="primary" v-if="detailData && detailData.can_submit_huifu" @click="submitFromDetail">提交汇付</el-button>
|
<el-button type="primary" v-if="detailData && detailData.can_submit_huifu" @click="submitFromDetail">提交汇付</el-button>
|
||||||
<el-button v-if="detailData && detailData.can_poll" @click="pollFromDetail">刷新状态</el-button>
|
<el-button v-if="detailData && detailData.can_poll" @click="pollFromDetail">刷新状态</el-button>
|
||||||
<el-button type="warning" v-if="detailData && detailData.can_retry_huifu" @click="retryFromDetail">重新提交</el-button>
|
<el-button type="warning" v-if="detailData && detailData.can_retry_huifu" @click="retryFromDetail">重新提交</el-button>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
||||||
|
|
||||||
|
var areaCache = null;
|
||||||
|
var branchTimer = null;
|
||||||
|
|
||||||
function withVue(callback) {
|
function withVue(callback) {
|
||||||
if (typeof Vue !== 'undefined') {
|
if (typeof Vue !== 'undefined') {
|
||||||
callback(Vue);
|
callback(Vue);
|
||||||
@@ -22,6 +25,262 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function defaultForm() {
|
||||||
|
return {
|
||||||
|
account_type: 'indv',
|
||||||
|
bank_account_type: '0',
|
||||||
|
name: '',
|
||||||
|
cert_no: '',
|
||||||
|
cert_validity_type: '1',
|
||||||
|
cert_begin_date: '',
|
||||||
|
cert_end_date: '',
|
||||||
|
mobile_no: '',
|
||||||
|
reg_detail: '',
|
||||||
|
shopro_province_id: '',
|
||||||
|
shopro_city_id: '',
|
||||||
|
shopro_district_id: '',
|
||||||
|
prov_id: '',
|
||||||
|
area_id: '',
|
||||||
|
district_id: '',
|
||||||
|
card_no: '',
|
||||||
|
card_name: '',
|
||||||
|
branch_code: '',
|
||||||
|
branch_name: '',
|
||||||
|
mp: '',
|
||||||
|
id_card_front_url: '',
|
||||||
|
id_card_back_url: '',
|
||||||
|
bank_card_url: '',
|
||||||
|
reg_name: '',
|
||||||
|
license_code: '',
|
||||||
|
license_validity_type: '1',
|
||||||
|
license_begin_date: '',
|
||||||
|
license_end_date: '',
|
||||||
|
legal_name: '',
|
||||||
|
legal_mobile: '',
|
||||||
|
legal_cert_no: '',
|
||||||
|
legal_cert_validity_type: '1',
|
||||||
|
legal_cert_begin_date: '',
|
||||||
|
legal_cert_end_date: '',
|
||||||
|
license_url: '',
|
||||||
|
legal_id_front_url: '',
|
||||||
|
legal_id_back_url: '',
|
||||||
|
account_permit_url: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFormMixin() {
|
||||||
|
return {
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
isEdit: false,
|
||||||
|
editId: 0,
|
||||||
|
userId: '',
|
||||||
|
userLabel: '',
|
||||||
|
roleKey: '',
|
||||||
|
roleType: '',
|
||||||
|
roleRefId: 0,
|
||||||
|
roleLabel: '',
|
||||||
|
userOptions: [],
|
||||||
|
userLoading: false,
|
||||||
|
roleOptions: [],
|
||||||
|
form: defaultForm(),
|
||||||
|
regionPath: [],
|
||||||
|
areaOptions: [],
|
||||||
|
areaProps: { value: 'id', label: 'name', children: 'children' },
|
||||||
|
branchKeyword: '',
|
||||||
|
branchResults: [],
|
||||||
|
uploadUrl: Fast.api.fixurl('ajax/upload'),
|
||||||
|
saving: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
bankMobile: {
|
||||||
|
get: function () {
|
||||||
|
return this.form.account_type === 'ent' ? this.form.legal_mobile : this.form.mobile_no;
|
||||||
|
},
|
||||||
|
set: function (val) {
|
||||||
|
if (this.form.account_type === 'ent') {
|
||||||
|
this.form.legal_mobile = val;
|
||||||
|
} else {
|
||||||
|
this.form.mobile_no = val;
|
||||||
|
}
|
||||||
|
this.form.mp = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted: function () {
|
||||||
|
this.loadAreaTree();
|
||||||
|
this.initFromConfig();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initFromConfig: function () {
|
||||||
|
var init = (typeof Config !== 'undefined' && Config.onboardForm) ? Config.onboardForm : null;
|
||||||
|
if (!init) return;
|
||||||
|
this.isEdit = true;
|
||||||
|
this.editId = init.onboard_id || 0;
|
||||||
|
this.userId = init.user_id;
|
||||||
|
this.userLabel = init.user_label || '';
|
||||||
|
this.roleType = init.role_type;
|
||||||
|
this.roleRefId = init.role_ref_id;
|
||||||
|
this.roleKey = init.role_type + ':' + init.role_ref_id;
|
||||||
|
this.roleLabel = init.role_label || '';
|
||||||
|
this.form = Object.assign(defaultForm(), init.form || {});
|
||||||
|
this.branchKeyword = this.form.branch_name || '';
|
||||||
|
this.restoreRegionPath();
|
||||||
|
},
|
||||||
|
loadAreaTree: function () {
|
||||||
|
var vm = this;
|
||||||
|
var done = function (data) {
|
||||||
|
areaCache = data || [];
|
||||||
|
vm.areaOptions = areaCache;
|
||||||
|
vm.restoreRegionPath();
|
||||||
|
};
|
||||||
|
if (areaCache) {
|
||||||
|
done(areaCache);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Fast.api.ajax({ url: 'shopro/area/getCascader', type: 'GET' }, function (ret, res) {
|
||||||
|
done(res.data || []);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
restoreRegionPath: function () {
|
||||||
|
var ids = [];
|
||||||
|
if (this.form.shopro_province_id) ids.push(parseInt(this.form.shopro_province_id, 10));
|
||||||
|
if (this.form.shopro_city_id) ids.push(parseInt(this.form.shopro_city_id, 10));
|
||||||
|
if (this.form.shopro_district_id) ids.push(parseInt(this.form.shopro_district_id, 10));
|
||||||
|
this.regionPath = ids.filter(function (n) { return !!n; });
|
||||||
|
},
|
||||||
|
onRegionChange: function (val) {
|
||||||
|
val = val || [];
|
||||||
|
this.form.shopro_province_id = val[0] ? String(val[0]) : '';
|
||||||
|
this.form.shopro_city_id = val[1] ? String(val[1]) : '';
|
||||||
|
this.form.shopro_district_id = val[2] ? String(val[2]) : '';
|
||||||
|
this.form.prov_id = this.form.shopro_province_id;
|
||||||
|
this.form.area_id = this.form.shopro_city_id;
|
||||||
|
this.form.district_id = this.form.shopro_district_id;
|
||||||
|
},
|
||||||
|
searchUser: function (keyword) {
|
||||||
|
if (!keyword) return;
|
||||||
|
var vm = this;
|
||||||
|
vm.userLoading = true;
|
||||||
|
Fast.api.ajax({
|
||||||
|
url: 'shopro/user/user/index',
|
||||||
|
type: 'GET',
|
||||||
|
data: { offset: 0, limit: 20, searchWhere: keyword }
|
||||||
|
}, function (ret, res) {
|
||||||
|
vm.userOptions = (res.data && res.data.rows) || [];
|
||||||
|
vm.userLoading = false;
|
||||||
|
return false;
|
||||||
|
}, function () {
|
||||||
|
vm.userLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onUserChange: function () {
|
||||||
|
var vm = this;
|
||||||
|
vm.roleKey = '';
|
||||||
|
vm.roleType = '';
|
||||||
|
vm.roleRefId = 0;
|
||||||
|
vm.roleOptions = [];
|
||||||
|
if (!vm.userId) return;
|
||||||
|
Fast.api.ajax({
|
||||||
|
url: 'shopro_huifu/onboard/userRoles',
|
||||||
|
type: 'GET',
|
||||||
|
data: { user_id: vm.userId }
|
||||||
|
}, function (ret, res) {
|
||||||
|
var data = res.data || {};
|
||||||
|
vm.roleOptions = data.roles || [];
|
||||||
|
if (data.user) {
|
||||||
|
vm.userLabel = (data.user.nickname || '') + ' (' + (data.user.mobile || data.user.id) + ')';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onRoleChange: function () {
|
||||||
|
var parts = String(this.roleKey || '').split(':');
|
||||||
|
this.roleType = parts[0] || '';
|
||||||
|
this.roleRefId = parseInt(parts[1] || '0', 10);
|
||||||
|
var role = this.roleOptions.find(function (item) {
|
||||||
|
return item.role_type === this.roleType && item.role_ref_id === this.roleRefId;
|
||||||
|
}.bind(this));
|
||||||
|
this.roleLabel = role ? role.role_label : '';
|
||||||
|
},
|
||||||
|
onBranchInput: function () {
|
||||||
|
var vm = this;
|
||||||
|
clearTimeout(branchTimer);
|
||||||
|
branchTimer = setTimeout(function () {
|
||||||
|
if (!vm.branchKeyword) {
|
||||||
|
vm.branchResults = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Fast.api.ajax({
|
||||||
|
url: 'shopro_huifu/onboard/searchBranch',
|
||||||
|
type: 'GET',
|
||||||
|
data: {
|
||||||
|
keyword: vm.branchKeyword,
|
||||||
|
area_id: vm.form.area_id || vm.form.shopro_city_id
|
||||||
|
}
|
||||||
|
}, function (ret, res) {
|
||||||
|
vm.branchResults = res.data || [];
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
selectBranch: function (item) {
|
||||||
|
this.form.branch_code = item.branch_code;
|
||||||
|
this.form.branch_name = item.branch_name;
|
||||||
|
this.branchKeyword = item.branch_name;
|
||||||
|
this.branchResults = [];
|
||||||
|
if (item.prov_id) this.form.prov_id = item.prov_id;
|
||||||
|
if (item.area_id) this.form.area_id = item.area_id;
|
||||||
|
},
|
||||||
|
onUploadSuccess: function (field, res) {
|
||||||
|
if (res && res.code === 1 && res.data && res.data.url) {
|
||||||
|
this.form[field] = res.data.fullurl || res.data.url;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$message.error((res && res.msg) || '上传失败');
|
||||||
|
},
|
||||||
|
closeForm: function () {
|
||||||
|
Fast.api.close();
|
||||||
|
},
|
||||||
|
submitForm: function () {
|
||||||
|
var vm = this;
|
||||||
|
if (!vm.isEdit) {
|
||||||
|
if (!vm.userId) {
|
||||||
|
Toastr.error('请选择用户');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!vm.roleType || !vm.roleRefId) {
|
||||||
|
Toastr.error('请选择进件角色');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm.saving = true;
|
||||||
|
var url = vm.isEdit
|
||||||
|
? ('shopro_huifu/onboard/edit/ids/' + vm.editId)
|
||||||
|
: 'shopro_huifu/onboard/add';
|
||||||
|
Fast.api.ajax({
|
||||||
|
url: url,
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
user_id: vm.userId,
|
||||||
|
role_type: vm.roleType,
|
||||||
|
role_ref_id: vm.roleRefId,
|
||||||
|
form: vm.form
|
||||||
|
}
|
||||||
|
}, function () {
|
||||||
|
vm.saving = false;
|
||||||
|
Fast.api.close();
|
||||||
|
return false;
|
||||||
|
}, function () {
|
||||||
|
vm.saving = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var Controller = {
|
var Controller = {
|
||||||
index: function () {
|
index: function () {
|
||||||
withVue(function (Vue) {
|
withVue(function (Vue) {
|
||||||
@@ -49,6 +308,30 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
|||||||
this.getList();
|
this.getList();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
openCreate: function () {
|
||||||
|
var vm = this;
|
||||||
|
Backend.api.open('shopro_huifu/onboard/add', '新建汇付进件', {
|
||||||
|
area: ['900px', '90%'],
|
||||||
|
callback: function () {
|
||||||
|
vm.getList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
openEdit: function (id) {
|
||||||
|
var vm = this;
|
||||||
|
Backend.api.open('shopro_huifu/onboard/edit/ids/' + id, '编辑汇付进件', {
|
||||||
|
area: ['900px', '90%'],
|
||||||
|
callback: function () {
|
||||||
|
vm.getList();
|
||||||
|
if (vm.detailVisible && vm.detailId === id) {
|
||||||
|
vm.openDetail(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
canEditRow: function (row) {
|
||||||
|
return ['draft', 'failed', 'rejected'].indexOf(row.onboard_status) >= 0;
|
||||||
|
},
|
||||||
getList: function () {
|
getList: function () {
|
||||||
var vm = this;
|
var vm = this;
|
||||||
vm.loading = true;
|
vm.loading = true;
|
||||||
@@ -131,6 +414,11 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
|||||||
this.retryRow(this.detailId);
|
this.retryRow(this.detailId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
editFromDetail: function () {
|
||||||
|
if (this.detailId) {
|
||||||
|
this.openEdit(this.detailId);
|
||||||
|
}
|
||||||
|
},
|
||||||
statusText: function (status) {
|
statusText: function (status) {
|
||||||
var map = {
|
var map = {
|
||||||
draft: '待后台审核',
|
draft: '待后台审核',
|
||||||
@@ -144,7 +432,7 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
|||||||
return map[status] || status || '-';
|
return map[status] || status || '-';
|
||||||
},
|
},
|
||||||
roleText: function (role) {
|
roleText: function (role) {
|
||||||
return role === 'regional_agent' ? '区域代理' : (role === 'promoter' ? '推广员' : role);
|
return role === 'regional_agent' ? '区域公司' : (role === 'promoter' ? '推广员' : role);
|
||||||
},
|
},
|
||||||
formatTime: function (ts) {
|
formatTime: function (ts) {
|
||||||
if (!ts) return '-';
|
if (!ts) return '-';
|
||||||
@@ -155,6 +443,17 @@ define(['jquery', 'bootstrap', 'backend'], function ($, undefined, Backend) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
add: function () {
|
||||||
|
withVue(function (Vue) {
|
||||||
|
new Vue({
|
||||||
|
el: '#huifuOnboardAdd',
|
||||||
|
mixins: [createFormMixin()]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
edit: function () {
|
||||||
|
Controller.add();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return Controller;
|
return Controller;
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户