fix: 管理员详情深色UI与按俱乐部分组展示角色
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -110,26 +110,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 用户详情弹窗(须在 v-if/v-else 外,避免被条件渲染挡住) -->
|
||||
<!-- 用户详情弹窗 -->
|
||||
<el-dialog
|
||||
v-model="detailDialogVisible"
|
||||
:title="detailDialogTitle"
|
||||
width="720px"
|
||||
class="user-dialog"
|
||||
width="760px"
|
||||
class="admin-user-dialog"
|
||||
append-to-body
|
||||
align-center
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<div class="dialog-content">
|
||||
<div class="dialog-content detail-dialog-body">
|
||||
<!-- 基本信息 -->
|
||||
<div class="info-section">
|
||||
<div class="section-title">基本信息</div>
|
||||
<el-form :model="editForm" label-width="100px">
|
||||
<el-form-item label="用户ID">
|
||||
<span>{{ currentUser?.yonghuid }}</span>
|
||||
<span class="info-value">{{ currentUser?.yonghuid }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="账号">
|
||||
<span>{{ currentUser?.phone }}</span>
|
||||
<span class="info-value">{{ currentUser?.phone }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="昵称">
|
||||
<el-input v-model="editForm.nicheng" placeholder="请输入昵称" />
|
||||
@@ -164,11 +164,20 @@
|
||||
<!-- 俱乐部任职 -->
|
||||
<div class="club-section">
|
||||
<div class="section-title">
|
||||
<span>俱乐部任职(切换范围)</span>
|
||||
<el-button type="primary" size="small" @click="openAddClubDialog">
|
||||
<span>俱乐部任职(顶栏切换范围)</span>
|
||||
<el-button v-if="canManageClubAssignments" type="primary" size="small" @click="openAddClubDialog">
|
||||
<el-icon><Plus /></el-icon> 添加俱乐部
|
||||
</el-button>
|
||||
</div>
|
||||
<el-alert
|
||||
v-if="!canManageClubAssignments"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="分配/移除俱乐部仅集团高层可操作"
|
||||
description="俱乐部负责人(000001)只能在本俱乐部内绑定功能角色,不能跨俱乐部分配任职。"
|
||||
class="scope-hint"
|
||||
/>
|
||||
<div class="club-assign-list">
|
||||
<div
|
||||
v-for="a in currentUserAssignments"
|
||||
@@ -178,37 +187,59 @@
|
||||
<el-tag :type="a.is_primary ? 'success' : 'info'" size="small">
|
||||
{{ a.club_label }}{{ a.is_primary ? '(主任职)' : '' }}
|
||||
</el-tag>
|
||||
<span class="assign-role-label">{{ a.role_name }}</span>
|
||||
<el-button type="danger" link size="small" @click="removeClubAssignment(a)">移除</el-button>
|
||||
<span class="assign-role-label">任职:{{ a.role_name }}</span>
|
||||
<el-button
|
||||
v-if="canManageClubAssignments"
|
||||
type="danger"
|
||||
link
|
||||
size="small"
|
||||
@click="removeClubAssignment(a)"
|
||||
>移除</el-button>
|
||||
</div>
|
||||
<div v-if="currentUserAssignments.length === 0" class="empty-role">
|
||||
暂未分配俱乐部,添加后该用户顶栏可切换;无角色则看不到菜单
|
||||
暂未分配俱乐部;需集团高层添加后,用户顶栏才可切换
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 角色管理 -->
|
||||
<!-- 各俱乐部功能角色 -->
|
||||
<div class="role-section">
|
||||
<div class="section-title">
|
||||
<span>功能角色(按俱乐部)</span>
|
||||
<el-button type="primary" size="small" @click="openAddRoleForUser">
|
||||
<el-icon><Plus /></el-icon> 添加角色
|
||||
</el-button>
|
||||
<span>各俱乐部功能角色</span>
|
||||
</div>
|
||||
<div class="role-list">
|
||||
<div
|
||||
v-for="role in currentUserRoles"
|
||||
:key="`${role.club_id}-${role.role_code}`"
|
||||
class="role-tag"
|
||||
>
|
||||
{{ roleClubLabel(role) }}
|
||||
<el-icon class="remove-icon" @click="removeUserRole(role)">
|
||||
<Close />
|
||||
</el-icon>
|
||||
<div
|
||||
v-for="block in clubRoleBlocks"
|
||||
:key="block.club_id || '__global__'"
|
||||
class="club-role-block"
|
||||
>
|
||||
<div class="club-block-header">
|
||||
<div>
|
||||
<strong class="club-block-title">{{ block.club_label }}</strong>
|
||||
<span class="club-block-meta">已绑 {{ block.roles.length }} 个 · 可选 {{ block.catalogRoles.length }} 个</span>
|
||||
</div>
|
||||
<el-button type="primary" size="small" link @click="openAddRoleForClub(block.club_id)">
|
||||
+ 添加角色
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-if="currentUserRoles.length === 0" class="empty-role">
|
||||
暂无角色,点击上方按钮添加
|
||||
<div v-if="block.roles.length" class="role-list">
|
||||
<div
|
||||
v-for="role in block.roles"
|
||||
:key="`${block.club_id}-${role.role_code}`"
|
||||
class="role-tag"
|
||||
>
|
||||
{{ role.role_name || role.role_code }}
|
||||
<el-icon class="remove-icon" @click="removeUserRole(role)">
|
||||
<Close />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="empty-role inline-empty">该俱乐部暂无功能角色</div>
|
||||
<div v-if="block.catalogRoles.length" class="catalog-hint">
|
||||
可选角色:{{ block.catalogRoles.map(r => r.role_name).join('、') }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!clubRoleBlocks.length" class="empty-role">
|
||||
请由集团高层先分配俱乐部任职;再点击各俱乐部「添加角色」绑定菜单权限
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -222,9 +253,9 @@
|
||||
<!-- 为用户添加角色的弹窗 -->
|
||||
<el-dialog
|
||||
v-model="addRoleForUserVisible"
|
||||
title="添加角色"
|
||||
title="添加功能角色"
|
||||
width="520px"
|
||||
class="role-select-dialog"
|
||||
class="admin-user-dialog"
|
||||
append-to-body
|
||||
align-center
|
||||
>
|
||||
@@ -232,7 +263,7 @@
|
||||
<el-form-item label="所属俱乐部" required>
|
||||
<el-select v-model="roleBindClubId" placeholder="先选俱乐部" style="width: 100%" @change="selectedRoleCodes = []">
|
||||
<el-option
|
||||
v-for="c in clubOptions"
|
||||
v-for="c in roleBindClubOptions"
|
||||
:key="c.club_id"
|
||||
:label="c.name"
|
||||
:value="c.club_id"
|
||||
@@ -249,6 +280,7 @@
|
||||
>
|
||||
<el-checkbox :label="role.role_code">
|
||||
<span>{{ role.role_name }}</span>
|
||||
<span class="role-code-tag">{{ role.role_code }}</span>
|
||||
</el-checkbox>
|
||||
</div>
|
||||
</el-checkbox-group>
|
||||
@@ -262,7 +294,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 添加俱乐部任职 -->
|
||||
<el-dialog v-model="addClubVisible" title="添加俱乐部任职" width="480px" append-to-body align-center>
|
||||
<el-dialog v-model="addClubVisible" title="添加俱乐部任职" width="480px" class="admin-user-dialog" append-to-body align-center>
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="俱乐部" required>
|
||||
<el-select v-model="clubAssignForm.club_id" placeholder="选择俱乐部" style="width: 100%">
|
||||
@@ -299,7 +331,7 @@
|
||||
v-model="addUserDialogVisible"
|
||||
title="添加后台用户"
|
||||
width="600px"
|
||||
class="user-dialog"
|
||||
class="admin-user-dialog"
|
||||
append-to-body
|
||||
align-center
|
||||
>
|
||||
@@ -377,6 +409,7 @@ const roleClubLabel = (role) => {
|
||||
|
||||
// 权限状态
|
||||
const hasPermission = ref(true)
|
||||
const canManageClubAssignments = ref(false)
|
||||
|
||||
// 角色列表(用于筛选和添加)
|
||||
const roleList = ref([])
|
||||
@@ -440,6 +473,53 @@ const availableRolesForUser = computed(() => {
|
||||
)
|
||||
})
|
||||
|
||||
const roleBindClubOptions = computed(() => {
|
||||
const fromAssign = (currentUserAssignments.value || [])
|
||||
.filter((a) => a.club_id)
|
||||
.map((a) => ({
|
||||
club_id: a.club_id,
|
||||
name: a.club_label || clubNameMap.value[a.club_id] || a.club_id,
|
||||
}))
|
||||
if (fromAssign.length) return fromAssign
|
||||
return clubOptions.value
|
||||
})
|
||||
|
||||
const clubRoleBlocks = computed(() => {
|
||||
const blocks = []
|
||||
const assignments = currentUserAssignments.value || []
|
||||
const roles = currentUserRoles.value || []
|
||||
|
||||
const pushBlock = (clubId, clubLabel) => {
|
||||
const cid = clubId || ''
|
||||
if (blocks.some((b) => (b.club_id || '') === cid)) return
|
||||
blocks.push({
|
||||
club_id: cid,
|
||||
club_label: clubLabel || (cid ? (clubNameMap.value[cid] || cid) : '全局角色'),
|
||||
roles: roles.filter((r) => (r.club_id || '') === cid),
|
||||
catalogRoles: roleList.value.filter((r) => (r.club_id || '') === cid),
|
||||
})
|
||||
}
|
||||
|
||||
for (const a of assignments) {
|
||||
if (a.club_id) {
|
||||
pushBlock(a.club_id, a.club_label)
|
||||
}
|
||||
}
|
||||
|
||||
const globalRoles = roles.filter((r) => !r.club_id)
|
||||
if (globalRoles.length) {
|
||||
pushBlock('', '全局角色')
|
||||
}
|
||||
|
||||
if (!assignments.length) {
|
||||
for (const r of roles) {
|
||||
pushBlock(r.club_id || '', clubNameMap.value[r.club_id] || r.club_id)
|
||||
}
|
||||
}
|
||||
|
||||
return blocks
|
||||
})
|
||||
|
||||
// 添加用户弹窗
|
||||
const addUserDialogVisible = ref(false)
|
||||
const newUserForm = ref({
|
||||
@@ -510,6 +590,7 @@ const fetchUserList = async () => {
|
||||
if (res.code === 0) {
|
||||
userList.value = res.data.list || []
|
||||
total.value = res.data.total || 0
|
||||
canManageClubAssignments.value = !!res.data.can_manage_club_assignments
|
||||
} else {
|
||||
ElMessage.error(res.msg || '获取用户列表失败')
|
||||
}
|
||||
@@ -581,12 +662,16 @@ const saveUserInfo = async () => {
|
||||
}
|
||||
|
||||
// 为用户添加角色(打开弹窗)
|
||||
const openAddRoleForUser = () => {
|
||||
const openAddRoleForClub = (clubId) => {
|
||||
selectedRoleCodes.value = []
|
||||
roleBindClubId.value = currentUserAssignments.value[0]?.club_id || clubOptions.value[0]?.club_id || ''
|
||||
roleBindClubId.value = clubId || roleBindClubOptions.value[0]?.club_id || ''
|
||||
addRoleForUserVisible.value = true
|
||||
}
|
||||
|
||||
const openAddRoleForUser = () => {
|
||||
openAddRoleForClub(roleBindClubOptions.value[0]?.club_id || clubOptions.value[0]?.club_id || '')
|
||||
}
|
||||
|
||||
const openAddClubDialog = () => {
|
||||
clubAssignForm.value = {
|
||||
club_id: availableClubsForAssign.value[0]?.club_id || '',
|
||||
@@ -678,6 +763,7 @@ const confirmAddUserRoles = async () => {
|
||||
const updated = userList.value.find((u) => u.yonghuid === currentUser.value.yonghuid)
|
||||
if (updated) {
|
||||
currentUserRoles.value = [...(updated.roles || [])]
|
||||
currentUserAssignments.value = [...(updated.assignments || [])]
|
||||
}
|
||||
} else {
|
||||
ElMessage.error(res.msg || '添加失败')
|
||||
@@ -855,28 +941,6 @@ onMounted(async () => {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
:deep(.el-dialog) {
|
||||
background: rgba(6,12,20,0.95);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(0,242,255,0.3);
|
||||
border-radius: 20px;
|
||||
}
|
||||
:deep(.el-dialog__title) {
|
||||
color: #00f2ff;
|
||||
}
|
||||
:deep(.el-form-item__label) {
|
||||
color: rgba(255,255,255,0.8);
|
||||
}
|
||||
:deep(.el-input__wrapper) {
|
||||
background: rgba(0,0,0,0.5);
|
||||
border-color: rgba(0,242,255,0.3);
|
||||
}
|
||||
:deep(.el-input__inner) {
|
||||
color: #fff;
|
||||
}
|
||||
:deep(.el-input__inner::placeholder) {
|
||||
color: rgba(255,255,255,0.4);
|
||||
}
|
||||
.section-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
@@ -913,6 +977,10 @@ onMounted(async () => {
|
||||
padding: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.empty-role.inline-empty {
|
||||
padding: 8px 0;
|
||||
text-align: left;
|
||||
}
|
||||
.muted-text {
|
||||
color: rgba(255,255,255,0.45);
|
||||
font-size: 13px;
|
||||
@@ -935,6 +1003,37 @@ onMounted(async () => {
|
||||
color: rgba(255,255,255,0.65);
|
||||
font-size: 13px;
|
||||
}
|
||||
.club-role-block {
|
||||
margin-bottom: 16px;
|
||||
padding: 14px;
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
border: 1px solid rgba(0, 242, 255, 0.18);
|
||||
border-radius: 10px;
|
||||
}
|
||||
.club-block-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.club-block-title {
|
||||
color: #00f2ff;
|
||||
font-size: 15px;
|
||||
}
|
||||
.club-block-meta {
|
||||
margin-left: 10px;
|
||||
color: rgba(255, 255, 255, 0.45);
|
||||
font-size: 12px;
|
||||
}
|
||||
.catalog-hint {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.scope-hint {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.role-select-list {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
@@ -945,9 +1044,95 @@ onMounted(async () => {
|
||||
background: rgba(255,255,255,0.05);
|
||||
border-radius: 8px;
|
||||
}
|
||||
.role-code-tag {
|
||||
margin-left: 8px;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.45);
|
||||
}
|
||||
.form-hint {
|
||||
font-size: 12px;
|
||||
color: rgba(255,255,255,0.5);
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- 弹窗 teleport 到 body,必须用非 scoped 样式 -->
|
||||
<style>
|
||||
.admin-user-dialog.el-dialog {
|
||||
background: linear-gradient(165deg, #0a1018 0%, #121c2e 100%) !important;
|
||||
border: 1px solid rgba(0, 242, 255, 0.35) !important;
|
||||
border-radius: 14px !important;
|
||||
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.65) !important;
|
||||
}
|
||||
.admin-user-dialog .el-dialog__header {
|
||||
border-bottom: 1px solid rgba(0, 242, 255, 0.2);
|
||||
margin-right: 0;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
.admin-user-dialog .el-dialog__title {
|
||||
color: #00f2ff !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
.admin-user-dialog .el-dialog__body {
|
||||
color: #e8eeff !important;
|
||||
background: transparent !important;
|
||||
padding-top: 16px;
|
||||
}
|
||||
.admin-user-dialog .el-dialog__footer {
|
||||
border-top: 1px solid rgba(0, 242, 255, 0.15);
|
||||
}
|
||||
.admin-user-dialog .el-form-item__label {
|
||||
color: rgba(232, 238, 255, 0.88) !important;
|
||||
}
|
||||
.admin-user-dialog .info-value {
|
||||
color: #ffffff !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
.admin-user-dialog .el-input__wrapper {
|
||||
background: rgba(0, 0, 0, 0.45) !important;
|
||||
box-shadow: 0 0 0 1px rgba(0, 242, 255, 0.28) inset !important;
|
||||
}
|
||||
.admin-user-dialog .el-input__inner {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
.admin-user-dialog .el-input__inner::placeholder {
|
||||
color: rgba(255, 255, 255, 0.35) !important;
|
||||
}
|
||||
.admin-user-dialog .el-radio__label {
|
||||
color: #e8eeff !important;
|
||||
}
|
||||
.admin-user-dialog .el-select .el-input__inner {
|
||||
color: #fff !important;
|
||||
}
|
||||
.admin-user-dialog .section-title {
|
||||
color: #00f2ff !important;
|
||||
}
|
||||
.admin-user-dialog .role-tag {
|
||||
color: #fff !important;
|
||||
background: rgba(0, 242, 255, 0.12) !important;
|
||||
border-color: rgba(0, 242, 255, 0.35) !important;
|
||||
}
|
||||
.admin-user-dialog .club-role-block {
|
||||
background: rgba(0, 0, 0, 0.35) !important;
|
||||
}
|
||||
.admin-user-dialog .empty-role {
|
||||
color: rgba(255, 255, 255, 0.55) !important;
|
||||
}
|
||||
.admin-user-dialog .assign-role-label,
|
||||
.admin-user-dialog .catalog-hint,
|
||||
.admin-user-dialog .form-hint {
|
||||
color: rgba(255, 255, 255, 0.6) !important;
|
||||
}
|
||||
.admin-user-dialog .role-select-item {
|
||||
background: rgba(255, 255, 255, 0.06) !important;
|
||||
}
|
||||
.admin-user-dialog .el-checkbox__label {
|
||||
color: #e8eeff !important;
|
||||
}
|
||||
.admin-user-dialog .el-alert__title {
|
||||
color: #e6a23c !important;
|
||||
}
|
||||
.admin-user-dialog .el-alert__description {
|
||||
color: rgba(255, 255, 255, 0.65) !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user