541 行
19 KiB
PHP
541 行
19 KiB
PHP
<?php
|
||
|
||
namespace addons\shopro_huifu\library\onboard;
|
||
|
||
use think\Db;
|
||
|
||
class HuifuOnboardAdminView
|
||
{
|
||
public static function enrichListRow($row)
|
||
{
|
||
if (!$row) {
|
||
return $row;
|
||
}
|
||
$data = is_array($row) ? $row : $row->toArray();
|
||
$payload = self::parsePayload($data['payload'] ?? '');
|
||
$user = self::fetchUser($data['user_id']);
|
||
$biz = self::businessStatus($data);
|
||
|
||
$data['user_nickname'] = $user['nickname'] ?? '';
|
||
$data['user_mobile'] = $user['mobile'] ?? '';
|
||
$data['payload_name'] = $payload['name'] ?? '';
|
||
$data['payload_mobile'] = $payload['mobile_no'] ?? '';
|
||
$data['payload_cert_no'] = self::maskCertNo($payload['cert_no'] ?? '');
|
||
$data['payload_card_tail'] = self::maskCardTail($payload['card_no'] ?? '');
|
||
$data['business_status'] = $biz['status'];
|
||
$data['business_status_text'] = $biz['status_text'];
|
||
$data['audit_url'] = $biz['audit_url'];
|
||
return $data;
|
||
}
|
||
|
||
public static function buildDetail($row)
|
||
{
|
||
if (!$row) {
|
||
return null;
|
||
}
|
||
$data = is_array($row) ? $row : $row->toArray();
|
||
$payload = self::parsePayload($data['payload'] ?? '');
|
||
$user = self::fetchUser($data['user_id']);
|
||
$biz = self::businessStatus($data);
|
||
$fileMap = self::parsePayload($data['file_map'] ?? '');
|
||
|
||
$validityMap = ['0' => '非长期有效', '1' => '长期有效'];
|
||
$form = [
|
||
'account_type' => $payload['account_type'] ?? 'indv',
|
||
'account_type_text' => ($payload['account_type'] ?? 'indv') === 'ent' ? '个体户/企业' : '个人',
|
||
'reg_name' => $payload['reg_name'] ?? '',
|
||
'license_code' => $payload['license_code'] ?? '',
|
||
'legal_name' => $payload['legal_name'] ?? '',
|
||
'branch_name' => $payload['branch_name'] ?? '',
|
||
'name' => $payload['name'] ?? '',
|
||
'cert_no' => $payload['cert_no'] ?? '',
|
||
'cert_no_masked' => self::maskCertNo($payload['cert_no'] ?? ''),
|
||
'cert_validity_type' => $payload['cert_validity_type'] ?? '',
|
||
'cert_validity_text' => $validityMap[$payload['cert_validity_type'] ?? ''] ?? '-',
|
||
'cert_begin_date' => self::formatYmd($payload['cert_begin_date'] ?? ''),
|
||
'cert_end_date' => self::formatYmd($payload['cert_end_date'] ?? ''),
|
||
'mobile_no' => $payload['mobile_no'] ?? '',
|
||
'card_no' => $payload['card_no'] ?? '',
|
||
'card_no_masked' => self::maskCardNo($payload['card_no'] ?? ''),
|
||
'card_name' => $payload['card_name'] ?? '',
|
||
'branch_code' => $payload['branch_code'] ?? '',
|
||
'prov_id' => $payload['prov_id'] ?? '',
|
||
'area_id' => $payload['area_id'] ?? '',
|
||
'id_card_front_url' => self::fullUrl($payload['id_card_front_url'] ?? ''),
|
||
'id_card_back_url' => self::fullUrl($payload['id_card_back_url'] ?? ''),
|
||
'bank_card_url' => self::fullUrl($payload['bank_card_url'] ?? ''),
|
||
];
|
||
|
||
return [
|
||
'record' => [
|
||
'id' => $data['id'],
|
||
'user_id' => $data['user_id'],
|
||
'role_type' => $data['role_type'],
|
||
'role_ref_id' => $data['role_ref_id'],
|
||
'onboard_status' => $data['onboard_status'],
|
||
'huifu_id' => $data['huifu_id'] ?? '',
|
||
'apply_no' => $data['apply_no'] ?? '',
|
||
'reject_reason' => $data['reject_reason'] ?? '',
|
||
'createtime' => $data['createtime'] ?? 0,
|
||
'updatetime' => $data['updatetime'] ?? 0,
|
||
],
|
||
'user' => [
|
||
'id' => $user['id'] ?? $data['user_id'],
|
||
'nickname' => $user['nickname'] ?? '',
|
||
'mobile' => $user['mobile'] ?? '',
|
||
'avatar' => self::fullUrl($user['avatar'] ?? ''),
|
||
],
|
||
'business' => $biz,
|
||
'form' => $form,
|
||
'file_map' => $fileMap,
|
||
'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),
|
||
];
|
||
}
|
||
|
||
public static function fetchUserPublic($userId)
|
||
{
|
||
return self::fetchUser($userId);
|
||
}
|
||
|
||
protected static function fetchUser($userId)
|
||
{
|
||
$userId = intval($userId);
|
||
if ($userId <= 0) {
|
||
return [];
|
||
}
|
||
try {
|
||
return Db::name('user')->where('id', $userId)->field('id,nickname,username,mobile,avatar')->find() ?: [];
|
||
} catch (\Throwable $e) {
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 后台进件:搜索可选用户(下拉展示昵称/实名/手机/ID)
|
||
*/
|
||
public static function searchUsers($keyword, $limit = 20)
|
||
{
|
||
$keyword = trim((string) $keyword);
|
||
if ($keyword === '') {
|
||
return [];
|
||
}
|
||
$limit = max(1, min(50, intval($limit)));
|
||
$idKeyword = is_numeric($keyword) ? intval($keyword) : 0;
|
||
$query = Db::name('user')->where(function ($q) use ($keyword, $idKeyword) {
|
||
if ($idKeyword > 0) {
|
||
$q->whereOr('id', '=', $idKeyword);
|
||
}
|
||
$q->whereOr('nickname', 'like', "%{$keyword}%")
|
||
->whereOr('mobile', 'like', "%{$keyword}%")
|
||
->whereOr('username', 'like', "%{$keyword}%");
|
||
});
|
||
$list = $query->field('id,nickname,username,mobile,avatar')->order('id desc')->limit($limit)->select();
|
||
$userIds = [];
|
||
foreach ($list as $user) {
|
||
$userIds[] = intval($user['id']);
|
||
}
|
||
$roleMap = self::listRoleSummariesForUsers($userIds);
|
||
$rows = [];
|
||
foreach ($list as $user) {
|
||
$uid = intval($user['id']);
|
||
$rows[] = self::formatUserOption($user, $roleMap[$uid] ?? []);
|
||
}
|
||
return $rows;
|
||
}
|
||
|
||
public static function formatUserOption($user, array $roles = null)
|
||
{
|
||
$user = is_array($user) ? $user : (method_exists($user, 'toArray') ? $user->toArray() : []);
|
||
$id = intval($user['id'] ?? 0);
|
||
if ($id <= 0) {
|
||
return [];
|
||
}
|
||
$nickname = trim((string) ($user['nickname'] ?? ''));
|
||
$username = trim((string) ($user['username'] ?? ''));
|
||
$mobile = trim((string) ($user['mobile'] ?? ''));
|
||
$avatar = self::fullUrl($user['avatar'] ?? '');
|
||
$realName = self::fetchUserRealNameHint($id);
|
||
$displayName = self::resolveUserDisplayName($id, $nickname, $username, $realName);
|
||
if ($roles === null) {
|
||
$roles = self::listRoleSummariesForUsers([$id])[$id] ?? [];
|
||
}
|
||
$rolesText = self::buildRolesText($roles);
|
||
|
||
return [
|
||
'id' => $id,
|
||
'nickname' => $nickname,
|
||
'username' => $username,
|
||
'mobile' => $mobile,
|
||
'avatar' => $avatar,
|
||
'display_name' => $displayName,
|
||
'real_name' => $realName,
|
||
'roles' => $roles,
|
||
'roles_text' => $rolesText,
|
||
'option_label' => self::buildUserOptionLabel($displayName, $realName, $mobile, $id, $rolesText),
|
||
];
|
||
}
|
||
|
||
protected static function resolveUserDisplayName($id, $nickname, $username, $realName = '')
|
||
{
|
||
if ($nickname !== '' && $nickname !== (string) $id) {
|
||
return $nickname;
|
||
}
|
||
if ($username !== '' && $username !== (string) $id) {
|
||
return $username;
|
||
}
|
||
if ($realName !== '') {
|
||
return $realName;
|
||
}
|
||
if ($nickname !== '') {
|
||
return $nickname;
|
||
}
|
||
return '用户' . $id;
|
||
}
|
||
|
||
protected static function fetchUserRealNameHint($userId)
|
||
{
|
||
$userId = intval($userId);
|
||
if ($userId <= 0) {
|
||
return '';
|
||
}
|
||
try {
|
||
$row = Db::name('shopro_huifu_onboard')->where('user_id', $userId)->order('id desc')->find();
|
||
if (!$row) {
|
||
return '';
|
||
}
|
||
$payload = self::parsePayload($row['payload'] ?? '');
|
||
return trim((string) ($payload['name'] ?? $payload['legal_name'] ?? $payload['reg_name'] ?? ''));
|
||
} catch (\Throwable $e) {
|
||
return '';
|
||
}
|
||
}
|
||
|
||
protected static function buildUserOptionLabel($displayName, $realName, $mobile, $id, $rolesText = '')
|
||
{
|
||
$parts = [$displayName];
|
||
if ($rolesText !== '') {
|
||
$parts[] = $rolesText;
|
||
}
|
||
if ($realName !== '' && $realName !== $displayName) {
|
||
$parts[] = '实名:' . $realName;
|
||
}
|
||
if ($mobile !== '') {
|
||
$parts[] = $mobile;
|
||
}
|
||
$parts[] = 'ID:' . $id;
|
||
return implode(' · ', $parts);
|
||
}
|
||
|
||
/**
|
||
* 批量获取用户可进件角色摘要(分销商/区域公司等)
|
||
*/
|
||
public static function listRoleSummariesForUsers(array $userIds)
|
||
{
|
||
$userIds = array_values(array_unique(array_filter(array_map('intval', $userIds))));
|
||
$map = [];
|
||
foreach ($userIds as $uid) {
|
||
$map[$uid] = [];
|
||
}
|
||
if (!$userIds) {
|
||
return $map;
|
||
}
|
||
|
||
$statusMap = [
|
||
'pending' => '待审核',
|
||
'normal' => '已通过',
|
||
'needinfo' => '待完善',
|
||
'reject' => '已驳回',
|
||
'forbidden' => '已禁用',
|
||
'freeze' => '已冻结',
|
||
];
|
||
|
||
$commissionAgents = Db::name('shopro_commission_agent')->where('user_id', 'in', $userIds)->select();
|
||
foreach ($commissionAgents as $agent) {
|
||
$uid = intval($agent['user_id']);
|
||
$status = $agent['status'] ?? '';
|
||
$map[$uid][] = [
|
||
'role_type' => 'promoter',
|
||
'role_label' => '分销商',
|
||
'status' => $status,
|
||
'status_text' => $statusMap[$status] ?? ($status ?: ''),
|
||
];
|
||
}
|
||
|
||
$regionalAgents = Db::name('shopro_regional_agent')->where('user_id', 'in', $userIds)->order('id desc')->select();
|
||
foreach ($regionalAgents as $agent) {
|
||
$uid = intval($agent['user_id']);
|
||
$label = '区域公司';
|
||
if (!empty($agent['area_name'])) {
|
||
$label .= '(' . $agent['area_name'] . ')';
|
||
}
|
||
$status = $agent['status'] ?? '';
|
||
$map[$uid][] = [
|
||
'role_type' => 'regional_agent',
|
||
'role_label' => $label,
|
||
'status' => $status,
|
||
'status_text' => $statusMap[$status] ?? ($status ?: ''),
|
||
];
|
||
}
|
||
|
||
return $map;
|
||
}
|
||
|
||
protected static function buildRolesText(array $roles)
|
||
{
|
||
if (!$roles) {
|
||
return '无进件角色';
|
||
}
|
||
$parts = [];
|
||
foreach ($roles as $role) {
|
||
$text = trim((string) ($role['role_label'] ?? ''));
|
||
$statusText = trim((string) ($role['status_text'] ?? ''));
|
||
if ($text === '') {
|
||
continue;
|
||
}
|
||
if ($statusText !== '') {
|
||
$text .= '[' . $statusText . ']';
|
||
}
|
||
$parts[] = $text;
|
||
}
|
||
return $parts ? implode('、', $parts) : '无进件角色';
|
||
}
|
||
|
||
protected static function businessStatus(array $data)
|
||
{
|
||
$roleType = $data['role_type'] ?? '';
|
||
$userId = intval($data['user_id'] ?? 0);
|
||
$roleRefId = intval($data['role_ref_id'] ?? 0);
|
||
$statusMap = [
|
||
'pending' => '待审核',
|
||
'normal' => '已通过',
|
||
'needinfo' => '待完善资料',
|
||
'reject' => '已驳回',
|
||
'forbidden' => '已禁用',
|
||
'freeze' => '已冻结',
|
||
];
|
||
|
||
if ($roleType === 'regional_agent') {
|
||
$agent = Db::name('shopro_regional_agent')->where('id', $roleRefId)->find();
|
||
$status = $agent['status'] ?? '';
|
||
return [
|
||
'type' => 'regional_agent',
|
||
'type_text' => '区域公司',
|
||
'status' => $status,
|
||
'status_text' => $statusMap[$status] ?? ($status ?: '未知'),
|
||
'area_name' => $agent['area_name'] ?? '',
|
||
'audit_url' => $roleRefId ? ('shopro/regional_agent/agent/index') : '',
|
||
];
|
||
}
|
||
|
||
$agent = Db::name('shopro_commission_agent')->where('user_id', $userId)->find();
|
||
$status = $agent['status'] ?? '';
|
||
return [
|
||
'type' => 'promoter',
|
||
'type_text' => '推广员/分销商',
|
||
'status' => $status,
|
||
'status_text' => $statusMap[$status] ?? ($status ?: '未成为分销商'),
|
||
'area_name' => '',
|
||
'audit_url' => 'shopro/commission/agent/index',
|
||
];
|
||
}
|
||
|
||
protected static function parsePayload($raw)
|
||
{
|
||
if (!$raw) {
|
||
return [];
|
||
}
|
||
if (is_array($raw)) {
|
||
return $raw;
|
||
}
|
||
$data = json_decode($raw, true);
|
||
return is_array($data) ? $data : [];
|
||
}
|
||
|
||
protected static function fullUrl($url)
|
||
{
|
||
$url = trim((string) $url);
|
||
if ($url === '') {
|
||
return '';
|
||
}
|
||
if (preg_match('/^https?:\/\//i', $url)) {
|
||
return $url;
|
||
}
|
||
return cdnurl($url, true);
|
||
}
|
||
|
||
protected static function maskCertNo($certNo)
|
||
{
|
||
$certNo = trim((string) $certNo);
|
||
if (strlen($certNo) < 8) {
|
||
return $certNo;
|
||
}
|
||
return substr($certNo, 0, 6) . '********' . substr($certNo, -4);
|
||
}
|
||
|
||
protected static function maskCardNo($cardNo)
|
||
{
|
||
$cardNo = preg_replace('/\s+/', '', (string) $cardNo);
|
||
$len = strlen($cardNo);
|
||
if ($len <= 4) {
|
||
return $cardNo;
|
||
}
|
||
return str_repeat('*', max(0, $len - 4)) . substr($cardNo, -4);
|
||
}
|
||
|
||
protected static function maskCardTail($cardNo)
|
||
{
|
||
$cardNo = preg_replace('/\s+/', '', (string) $cardNo);
|
||
if ($cardNo === '') {
|
||
return '';
|
||
}
|
||
return '****' . substr($cardNo, -4);
|
||
}
|
||
|
||
protected static function formatYmd($value)
|
||
{
|
||
$value = preg_replace('/\D/', '', (string) $value);
|
||
if (strlen($value) !== 8) {
|
||
return $value;
|
||
}
|
||
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,
|
||
];
|
||
}
|
||
}
|