fix: 管理员详情深色UI与按俱乐部分组展示角色

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-06 18:06:38 +08:00
parent 58be204448
commit f3a6fa47bc

View File

@@ -110,26 +110,26 @@
</div> </div>
</div> </div>
<!-- 用户详情弹窗须在 v-if/v-else --> <!-- 用户详情弹窗 -->
<el-dialog <el-dialog
v-model="detailDialogVisible" v-model="detailDialogVisible"
:title="detailDialogTitle" :title="detailDialogTitle"
width="720px" width="760px"
class="user-dialog" class="admin-user-dialog"
append-to-body append-to-body
align-center align-center
:close-on-click-modal="false" :close-on-click-modal="false"
> >
<div class="dialog-content"> <div class="dialog-content detail-dialog-body">
<!-- 基本信息 --> <!-- 基本信息 -->
<div class="info-section"> <div class="info-section">
<div class="section-title">基本信息</div> <div class="section-title">基本信息</div>
<el-form :model="editForm" label-width="100px"> <el-form :model="editForm" label-width="100px">
<el-form-item label="用户ID"> <el-form-item label="用户ID">
<span>{{ currentUser?.yonghuid }}</span> <span class="info-value">{{ currentUser?.yonghuid }}</span>
</el-form-item> </el-form-item>
<el-form-item label="账号"> <el-form-item label="账号">
<span>{{ currentUser?.phone }}</span> <span class="info-value">{{ currentUser?.phone }}</span>
</el-form-item> </el-form-item>
<el-form-item label="昵称"> <el-form-item label="昵称">
<el-input v-model="editForm.nicheng" placeholder="请输入昵称" /> <el-input v-model="editForm.nicheng" placeholder="请输入昵称" />
@@ -164,11 +164,20 @@
<!-- 俱乐部任职 --> <!-- 俱乐部任职 -->
<div class="club-section"> <div class="club-section">
<div class="section-title"> <div class="section-title">
<span>俱乐部任职切换范围</span> <span>俱乐部任职顶栏切换范围</span>
<el-button type="primary" size="small" @click="openAddClubDialog"> <el-button v-if="canManageClubAssignments" type="primary" size="small" @click="openAddClubDialog">
<el-icon><Plus /></el-icon> 添加俱乐部 <el-icon><Plus /></el-icon> 添加俱乐部
</el-button> </el-button>
</div> </div>
<el-alert
v-if="!canManageClubAssignments"
type="warning"
:closable="false"
show-icon
title="分配/移除俱乐部仅集团高层可操作"
description="俱乐部负责人000001只能在本俱乐部内绑定功能角色不能跨俱乐部分配任职。"
class="scope-hint"
/>
<div class="club-assign-list"> <div class="club-assign-list">
<div <div
v-for="a in currentUserAssignments" v-for="a in currentUserAssignments"
@@ -178,37 +187,59 @@
<el-tag :type="a.is_primary ? 'success' : 'info'" size="small"> <el-tag :type="a.is_primary ? 'success' : 'info'" size="small">
{{ a.club_label }}{{ a.is_primary ? '(主任职)' : '' }} {{ a.club_label }}{{ a.is_primary ? '(主任职)' : '' }}
</el-tag> </el-tag>
<span class="assign-role-label">{{ a.role_name }}</span> <span class="assign-role-label">任职{{ a.role_name }}</span>
<el-button type="danger" link size="small" @click="removeClubAssignment(a)">移除</el-button> <el-button
v-if="canManageClubAssignments"
type="danger"
link
size="small"
@click="removeClubAssignment(a)"
>移除</el-button>
</div> </div>
<div v-if="currentUserAssignments.length === 0" class="empty-role"> <div v-if="currentUserAssignments.length === 0" class="empty-role">
暂未分配俱乐部添加后该用户顶栏可切换无角色则看不到菜单 暂未分配俱乐部需集团高层添加后用户顶栏可切换
</div> </div>
</div> </div>
</div> </div>
<!-- 角色管理 --> <!-- 各俱乐部功能角色 -->
<div class="role-section"> <div class="role-section">
<div class="section-title"> <div class="section-title">
<span>功能角色按俱乐部</span> <span>各俱乐部功能角色</span>
<el-button type="primary" size="small" @click="openAddRoleForUser">
<el-icon><Plus /></el-icon> 添加角色
</el-button>
</div> </div>
<div class="role-list"> <div
<div v-for="block in clubRoleBlocks"
v-for="role in currentUserRoles" :key="block.club_id || '__global__'"
:key="`${role.club_id}-${role.role_code}`" class="club-role-block"
class="role-tag" >
> <div class="club-block-header">
{{ roleClubLabel(role) }} <div>
<el-icon class="remove-icon" @click="removeUserRole(role)"> <strong class="club-block-title">{{ block.club_label }}</strong>
<Close /> <span class="club-block-meta">已绑 {{ block.roles.length }} · 可选 {{ block.catalogRoles.length }} </span>
</el-icon> </div>
<el-button type="primary" size="small" link @click="openAddRoleForClub(block.club_id)">
+ 添加角色
</el-button>
</div> </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>
<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> </div>
</div> </div>
@@ -222,9 +253,9 @@
<!-- 为用户添加角色的弹窗 --> <!-- 为用户添加角色的弹窗 -->
<el-dialog <el-dialog
v-model="addRoleForUserVisible" v-model="addRoleForUserVisible"
title="添加角色" title="添加功能角色"
width="520px" width="520px"
class="role-select-dialog" class="admin-user-dialog"
append-to-body append-to-body
align-center align-center
> >
@@ -232,7 +263,7 @@
<el-form-item label="所属俱乐部" required> <el-form-item label="所属俱乐部" required>
<el-select v-model="roleBindClubId" placeholder="先选俱乐部" style="width: 100%" @change="selectedRoleCodes = []"> <el-select v-model="roleBindClubId" placeholder="先选俱乐部" style="width: 100%" @change="selectedRoleCodes = []">
<el-option <el-option
v-for="c in clubOptions" v-for="c in roleBindClubOptions"
:key="c.club_id" :key="c.club_id"
:label="c.name" :label="c.name"
:value="c.club_id" :value="c.club_id"
@@ -249,6 +280,7 @@
> >
<el-checkbox :label="role.role_code"> <el-checkbox :label="role.role_code">
<span>{{ role.role_name }}</span> <span>{{ role.role_name }}</span>
<span class="role-code-tag">{{ role.role_code }}</span>
</el-checkbox> </el-checkbox>
</div> </div>
</el-checkbox-group> </el-checkbox-group>
@@ -262,7 +294,7 @@
</el-dialog> </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 label-width="100px">
<el-form-item label="俱乐部" required> <el-form-item label="俱乐部" required>
<el-select v-model="clubAssignForm.club_id" placeholder="选择俱乐部" style="width: 100%"> <el-select v-model="clubAssignForm.club_id" placeholder="选择俱乐部" style="width: 100%">
@@ -299,7 +331,7 @@
v-model="addUserDialogVisible" v-model="addUserDialogVisible"
title="添加后台用户" title="添加后台用户"
width="600px" width="600px"
class="user-dialog" class="admin-user-dialog"
append-to-body append-to-body
align-center align-center
> >
@@ -377,6 +409,7 @@ const roleClubLabel = (role) => {
// 权限状态 // 权限状态
const hasPermission = ref(true) const hasPermission = ref(true)
const canManageClubAssignments = ref(false)
// 角色列表(用于筛选和添加) // 角色列表(用于筛选和添加)
const roleList = ref([]) 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 addUserDialogVisible = ref(false)
const newUserForm = ref({ const newUserForm = ref({
@@ -510,6 +590,7 @@ const fetchUserList = async () => {
if (res.code === 0) { if (res.code === 0) {
userList.value = res.data.list || [] userList.value = res.data.list || []
total.value = res.data.total || 0 total.value = res.data.total || 0
canManageClubAssignments.value = !!res.data.can_manage_club_assignments
} else { } else {
ElMessage.error(res.msg || '获取用户列表失败') ElMessage.error(res.msg || '获取用户列表失败')
} }
@@ -581,12 +662,16 @@ const saveUserInfo = async () => {
} }
// 为用户添加角色(打开弹窗) // 为用户添加角色(打开弹窗)
const openAddRoleForUser = () => { const openAddRoleForClub = (clubId) => {
selectedRoleCodes.value = [] 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 addRoleForUserVisible.value = true
} }
const openAddRoleForUser = () => {
openAddRoleForClub(roleBindClubOptions.value[0]?.club_id || clubOptions.value[0]?.club_id || '')
}
const openAddClubDialog = () => { const openAddClubDialog = () => {
clubAssignForm.value = { clubAssignForm.value = {
club_id: availableClubsForAssign.value[0]?.club_id || '', 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) const updated = userList.value.find((u) => u.yonghuid === currentUser.value.yonghuid)
if (updated) { if (updated) {
currentUserRoles.value = [...(updated.roles || [])] currentUserRoles.value = [...(updated.roles || [])]
currentUserAssignments.value = [...(updated.assignments || [])]
} }
} else { } else {
ElMessage.error(res.msg || '添加失败') ElMessage.error(res.msg || '添加失败')
@@ -855,28 +941,6 @@ onMounted(async () => {
display: flex; display: flex;
justify-content: flex-end; 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 { .section-title {
font-size: 18px; font-size: 18px;
font-weight: bold; font-weight: bold;
@@ -913,6 +977,10 @@ onMounted(async () => {
padding: 20px 0; padding: 20px 0;
text-align: center; text-align: center;
} }
.empty-role.inline-empty {
padding: 8px 0;
text-align: left;
}
.muted-text { .muted-text {
color: rgba(255,255,255,0.45); color: rgba(255,255,255,0.45);
font-size: 13px; font-size: 13px;
@@ -935,6 +1003,37 @@ onMounted(async () => {
color: rgba(255,255,255,0.65); color: rgba(255,255,255,0.65);
font-size: 13px; 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 { .role-select-list {
max-height: 400px; max-height: 400px;
overflow-y: auto; overflow-y: auto;
@@ -945,9 +1044,95 @@ onMounted(async () => {
background: rgba(255,255,255,0.05); background: rgba(255,255,255,0.05);
border-radius: 8px; border-radius: 8px;
} }
.role-code-tag {
margin-left: 8px;
font-size: 12px;
color: rgba(255, 255, 255, 0.45);
}
.form-hint { .form-hint {
font-size: 12px; font-size: 12px;
color: rgba(255,255,255,0.5); color: rgba(255,255,255,0.5);
margin-top: 4px; 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> </style>