feat: 在用户列表展示角色信息

- 分页批量补全用户关联角色名称,避免逐行查询

- 支持多角色标签、溢出数量和完整信息提示
This commit is contained in:
2026-08-07 12:47:04 +08:00
parent 4b52d85512
commit 6ad004da9b
3 changed files with 190 additions and 1 deletions

View File

@@ -20,6 +20,8 @@ import {
ElMessageBox,
ElTable,
ElTableColumn,
ElTag,
ElTooltip,
} from 'element-plus';
import { api } from '#/api/request';
@@ -47,6 +49,7 @@ const selectedRows = ref<any[]>([]);
const batchActionLoading = ref(false);
const dictStore = useDictStore();
const selectedCount = computed(() => selectedRows.value.length);
const maxVisibleRoleCount = 2;
const headerButtons = [
{
key: 'create',
@@ -68,6 +71,30 @@ const headerButtons = [
function initDict() {
dictStore.fetchDictionary('dataStatus');
}
function getRoleNames(row: any): string[] {
if (!Array.isArray(row?.roleNames)) {
return [];
}
const roleNames: unknown[] = row.roleNames;
return [
...new Set(
roleNames
.filter(
(roleName: unknown) =>
roleName !== null &&
roleName !== undefined &&
String(roleName).trim().length > 0,
)
.map(String),
),
];
}
function getVisibleRoleNames(row: any) {
return getRoleNames(row).slice(0, maxVisibleRoleCount);
}
function getHiddenRoleCount(row: any) {
return Math.max(getRoleNames(row).length - maxVisibleRoleCount, 0);
}
const handleSearch = (params: string) => {
pageDataRef.value.setQuery({ keyword: params.trim() });
};
@@ -353,6 +380,58 @@ function isAdmin(data: any) {
{{ row.nickname }}
</template>
</ElTableColumn>
<ElTableColumn
prop="roleIds"
align="center"
min-width="260"
:label="$t('sysAccount.roleIds')"
>
<template #default="{ row }">
<ElTooltip
v-if="getRoleNames(row).length > 0"
placement="top"
popper-class="sys-account-role-tooltip"
:show-after="300"
>
<template #content>
<div class="sys-account-role-tooltip__content">
<ElTag
v-for="roleName in getRoleNames(row)"
:key="roleName"
effect="plain"
type="info"
>
{{ roleName }}
</ElTag>
</div>
</template>
<div
class="sys-account-role-summary"
tabindex="0"
:aria-label="getRoleNames(row).join('、')"
>
<ElTag
v-for="roleName in getVisibleRoleNames(row)"
:key="roleName"
class="sys-account-role-tag"
effect="plain"
type="info"
>
{{ roleName }}
</ElTag>
<ElTag
v-if="getHiddenRoleCount(row) > 0"
class="sys-account-role-more"
effect="plain"
type="info"
>
+{{ getHiddenRoleCount(row) }}
</ElTag>
</div>
</ElTooltip>
<span v-else class="sys-account-role-empty">-</span>
</template>
</ElTableColumn>
<ElTableColumn
prop="mobile"
align="center"
@@ -464,6 +543,48 @@ function isAdmin(data: any) {
align-items: center;
}
.sys-account-role-summary {
display: flex;
gap: var(--space-1);
align-items: center;
justify-content: center;
min-width: 0;
outline: none;
}
.sys-account-role-summary:focus-visible {
border-radius: var(--radius-control);
box-shadow: 0 0 0 2px hsl(var(--primary) / 24%);
}
.sys-account-role-tag {
max-width: 88px;
}
.sys-account-role-tag :deep(.el-tag__content) {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.sys-account-role-more {
flex: none;
}
.sys-account-role-empty {
color: hsl(var(--text-muted));
}
:global(.sys-account-role-tooltip) {
max-width: 320px;
}
:global(.sys-account-role-tooltip .sys-account-role-tooltip__content) {
display: flex;
flex-wrap: wrap;
gap: var(--space-1);
}
.sys-account-batch-inline__actions :deep(.el-button) {
height: 32px;
min-height: 32px;