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' => '', ]; } protected static function resolveRoleLabel($roleType, $roleRefId, array $roles = []) { foreach ($roles as $role) { if ($role['role_type'] === $roleType && intval($role['role_ref_id']) === intval($roleRefId)) { return $role['role_label']; } } if ($roleType === 'promoter') { return '分销商'; } if ($roleType === 'regional_agent') { $agent = Db::name('shopro_regional_agent')->where('id', $roleRefId)->find(); $label = '区域公司'; if ($agent && !empty($agent['area_name'])) { $label .= '(' . $agent['area_name'] . ')'; } return $label; } return $roleType; } /** * 小程序端回显已提交的进件资料(完整字段,仅当前登录用户接口使用) */ public static function clientFormFromRow($row) { if (!$row) { return null; } $data = is_array($row) ? $row : $row->toArray(); $payload = self::parsePayload($data['payload'] ?? ''); if (!$payload) { return null; } $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]); } } return $form; } 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]); } } $userId = intval($data['user_id'] ?? 0); $user = self::fetchUser($userId); $userOption = self::formatUserOption($user); $roles = self::listRolesForUser($userId); $roleType = (string) ($data['role_type'] ?? ''); $roleRefId = intval($data['role_ref_id'] ?? 0); $roleLabel = self::resolveRoleLabel($roleType, $roleRefId, $roles); return [ 'onboard_id' => intval($data['id'] ?? 0), 'user_id' => $userId, 'user_label' => $userOption['option_label'] ?? trim(($user['nickname'] ?? '') . ' (' . ($user['mobile'] ?? $userId) . ')'), 'role_type' => $roleType, 'role_ref_id' => $roleRefId, 'role_label' => $roleLabel, 'onboard_status' => $data['onboard_status'] ?? '', 'form' => $form, ]; } }