用户选择组件增加角色标签显示

这个提交包含在:
可乐加冰
2026-09-29 15:51:26 +08:00
父节点 375bc7af20
当前提交 767e1a00c5
共有 3 个文件被更改,包括 155 次插入 和 8 次删除

查看文件

@@ -116,6 +116,19 @@
.user-option-nick { margin-right: 4px; }
.user-option-real { font-weight: 400; color: #7536D0; font-size: 12px; }
.user-option-meta { font-size: 12px; color: #909399; margin-top: 2px; }
.user-role-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.user-role-tag {
display: inline-block;
padding: 0 8px;
height: 20px;
line-height: 20px;
border-radius: 10px;
font-size: 11px;
font-weight: 500;
}
.user-role-tag--promoter { background: #f0e8ff; color: #7536D0; }
.user-role-tag--regional_agent { background: #e8f7ef; color: #2e9f6a; }
.user-role-tag--empty { background: #f4f4f5; color: #909399; }
</style>
<script src="__CDN__/assets/addons/shopro/libs/vue.js"></script>
<script src="__CDN__/assets/addons/shopro/libs/element/element.js"></script>
@@ -155,6 +168,14 @@
<template v-if="item.mobile"> · 手机 {{ item.mobile }}</template>
<template v-if="item.nickname && item.nickname !== item.display_name"> · 昵称 {{ item.nickname }}</template>
</div>
<div class="user-role-tags">
<template v-if="item.roles && item.roles.length">
<span v-for="(role, rIdx) in item.roles" :key="rIdx" class="user-role-tag" :class="'user-role-tag--' + role.role_type">
{{ role.role_label }}<template v-if="role.status_text">[{{ role.status_text }}]</template>
</span>
</template>
<span v-else class="user-role-tag user-role-tag--empty">无进件角色</span>
</div>
</div>
</div>
</el-option>
@@ -163,8 +184,16 @@
<img v-if="selectedUser.avatar" :src="selectedUser.avatar" class="user-selected-avatar" style="border-radius:50%;">
<div v-else class="user-selected-avatar">{{ userAvatarText(selectedUser) }}</div>
<div>
<div class="user-selected-name">{{ selectedUser.option_label }}</div>
<div class="user-selected-meta" v-if="selectedUser.real_name">实名:{{ selectedUser.real_name }}</div>
<div class="user-selected-name">{{ selectedUser.display_name }} · ID {{ selectedUser.id }}<template v-if="selectedUser.mobile"> · {{ selectedUser.mobile }}</template></div>
<div class="user-selected-meta" v-if="selectedUser.real_name && selectedUser.real_name !== selectedUser.display_name">实名:{{ selectedUser.real_name }}</div>
<div class="user-role-tags">
<template v-if="selectedUser.roles && selectedUser.roles.length">
<span v-for="(role, rIdx) in selectedUser.roles" :key="rIdx" class="user-role-tag" :class="'user-role-tag--' + role.role_type">
{{ role.role_label }}<template v-if="role.status_text">[{{ role.status_text }}]</template>
</span>
</template>
<span v-else class="user-role-tag user-role-tag--empty">无进件角色</span>
</div>
</div>
</div>
</el-form-item>

查看文件

@@ -132,14 +132,20 @@ class HuifuOnboardAdminView
->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) {
$rows[] = self::formatUserOption($user);
$uid = intval($user['id']);
$rows[] = self::formatUserOption($user, $roleMap[$uid] ?? []);
}
return $rows;
}
public static function formatUserOption($user)
public static function formatUserOption($user, array $roles = null)
{
$user = is_array($user) ? $user : (method_exists($user, 'toArray') ? $user->toArray() : []);
$id = intval($user['id'] ?? 0);
@@ -152,6 +158,10 @@ class HuifuOnboardAdminView
$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,
@@ -161,7 +171,9 @@ class HuifuOnboardAdminView
'avatar' => $avatar,
'display_name' => $displayName,
'real_name' => $realName,
'option_label' => self::buildUserOptionLabel($displayName, $realName, $mobile, $id),
'roles' => $roles,
'roles_text' => $rolesText,
'option_label' => self::buildUserOptionLabel($displayName, $realName, $mobile, $id, $rolesText),
];
}
@@ -200,9 +212,12 @@ class HuifuOnboardAdminView
}
}
protected static function buildUserOptionLabel($displayName, $realName, $mobile, $id)
protected static function buildUserOptionLabel($displayName, $realName, $mobile, $id, $rolesText = '')
{
$parts = [$displayName];
if ($rolesText !== '') {
$parts[] = $rolesText;
}
if ($realName !== '' && $realName !== $displayName) {
$parts[] = '实名:' . $realName;
}
@@ -213,6 +228,80 @@ class HuifuOnboardAdminView
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'] ?? '';

查看文件

@@ -116,6 +116,19 @@
.user-option-nick { margin-right: 4px; }
.user-option-real { font-weight: 400; color: #7536D0; font-size: 12px; }
.user-option-meta { font-size: 12px; color: #909399; margin-top: 2px; }
.user-role-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.user-role-tag {
display: inline-block;
padding: 0 8px;
height: 20px;
line-height: 20px;
border-radius: 10px;
font-size: 11px;
font-weight: 500;
}
.user-role-tag--promoter { background: #f0e8ff; color: #7536D0; }
.user-role-tag--regional_agent { background: #e8f7ef; color: #2e9f6a; }
.user-role-tag--empty { background: #f4f4f5; color: #909399; }
</style>
<script src="__CDN__/assets/addons/shopro/libs/vue.js"></script>
<script src="__CDN__/assets/addons/shopro/libs/element/element.js"></script>
@@ -155,6 +168,14 @@
<template v-if="item.mobile"> · 手机 {{ item.mobile }}</template>
<template v-if="item.nickname && item.nickname !== item.display_name"> · 昵称 {{ item.nickname }}</template>
</div>
<div class="user-role-tags">
<template v-if="item.roles && item.roles.length">
<span v-for="(role, rIdx) in item.roles" :key="rIdx" class="user-role-tag" :class="'user-role-tag--' + role.role_type">
{{ role.role_label }}<template v-if="role.status_text">[{{ role.status_text }}]</template>
</span>
</template>
<span v-else class="user-role-tag user-role-tag--empty">无进件角色</span>
</div>
</div>
</div>
</el-option>
@@ -163,8 +184,16 @@
<img v-if="selectedUser.avatar" :src="selectedUser.avatar" class="user-selected-avatar" style="border-radius:50%;">
<div v-else class="user-selected-avatar">{{ userAvatarText(selectedUser) }}</div>
<div>
<div class="user-selected-name">{{ selectedUser.option_label }}</div>
<div class="user-selected-meta" v-if="selectedUser.real_name">实名:{{ selectedUser.real_name }}</div>
<div class="user-selected-name">{{ selectedUser.display_name }} · ID {{ selectedUser.id }}<template v-if="selectedUser.mobile"> · {{ selectedUser.mobile }}</template></div>
<div class="user-selected-meta" v-if="selectedUser.real_name && selectedUser.real_name !== selectedUser.display_name">实名:{{ selectedUser.real_name }}</div>
<div class="user-role-tags">
<template v-if="selectedUser.roles && selectedUser.roles.length">
<span v-for="(role, rIdx) in selectedUser.roles" :key="rIdx" class="user-role-tag" :class="'user-role-tag--' + role.role_type">
{{ role.role_label }}<template v-if="role.status_text">[{{ role.status_text }}]</template>
</span>
</template>
<span v-else class="user-role-tag user-role-tag--empty">无进件角色</span>
</div>
</div>
</div>
</el-form-item>