feat(ui): 完善系统管理页面权限控制

- 修复用户管理页面操作按钮权限检查
- 完善角色管理页面权限控制逻辑
- 使用权限常量替代硬编码权限标识
- 确保权限控制逻辑的一致性和准确性
This commit is contained in:
Leo 2025-07-07 01:14:21 +08:00
parent fed1ee9089
commit fb1b2583bf
2 changed files with 71 additions and 32 deletions

View File

@ -94,7 +94,7 @@
<!-- 表格头部操作栏 --> <!-- 表格头部操作栏 -->
<div class="flex items-center justify-between px-4 py-2 border-b border-gray-100"> <div class="flex items-center justify-between px-4 py-2 border-b border-gray-100">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<NButton type="primary" class="px-6 flex items-center" @click="handleAdd"> <NButton v-button="PERMISSIONS.ROLE.ADD" type="primary" class="px-6 flex items-center" @click="handleAdd">
<template #icon> <template #icon>
<NIcon class="mr-1" style="transform: translateY(-1px)"> <NIcon class="mr-1" style="transform: translateY(-1px)">
<icon-park-outline:plus /> <icon-park-outline:plus />
@ -104,6 +104,7 @@
</NButton> </NButton>
<NButton <NButton
v-button="PERMISSIONS.ROLE.DELETE"
type="error" type="error"
:disabled="selectedRows.length === 0" :disabled="selectedRows.length === 0"
class="px-6 flex items-center" class="px-6 flex items-center"
@ -356,6 +357,11 @@ import {
} from '@/service/api/system/menu' } from '@/service/api/system/menu'
import type { MenuPermissionData, MenuVo } from '@/service/api/system/menu' import type { MenuPermissionData, MenuVo } from '@/service/api/system/menu'
import { coiMsgBox, coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi' import { coiMsgBox, coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi'
import { PERMISSIONS } from '@/constants/permissions'
import { usePermission } from '@/hooks/usePermission'
//
const { hasButton } = usePermission()
// //
const loading = ref(false) const loading = ref(false)
@ -515,16 +521,23 @@ const columns: DataTableColumns<RoleVo> = [
align: 'center', align: 'center',
fixed: 'right', fixed: 'right',
render: (row) => { render: (row) => {
return h('div', { class: 'flex items-center justify-center gap-2' }, [ const buttons = []
h(NButton, {
//
if (hasButton(PERMISSIONS.ROLE.UPDATE)) {
buttons.push(h(NButton, {
type: 'primary', type: 'primary',
size: 'small', size: 'small',
onClick: () => handleEdit(row), onClick: () => handleEdit(row),
}, { }, {
icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:edit') }), icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:edit') }),
default: () => '编辑', default: () => '编辑',
}), }))
h(NPopconfirm, { }
//
if (hasButton(PERMISSIONS.ROLE.DELETE)) {
buttons.push(h(NPopconfirm, {
onPositiveClick: () => handleDelete(row.roleId), onPositiveClick: () => handleDelete(row.roleId),
negativeText: '取消', negativeText: '取消',
positiveText: '确定', positiveText: '确定',
@ -538,21 +551,22 @@ const columns: DataTableColumns<RoleVo> = [
icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:delete') }), icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:delete') }),
default: () => '删除', default: () => '删除',
}), }),
}), }))
// }
...(row.roleId === 1
? [] // -
: [ if (hasButton(PERMISSIONS.ROLE.MENU) && row.roleId !== 1) {
h(NButton, { buttons.push(h(NButton, {
type: 'warning', type: 'warning',
size: 'small', size: 'small',
onClick: () => handleAssignMenu(row), onClick: () => handleAssignMenu(row),
}, { }, {
icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:setting') }), icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:setting') }),
default: () => '分配权限', default: () => '分配权限',
}), }))
]), }
])
return h('div', { class: 'flex items-center justify-center gap-2' }, buttons)
}, },
}, },
] ]

View File

@ -104,7 +104,7 @@
<!-- 表格头部操作栏 --> <!-- 表格头部操作栏 -->
<div class="flex items-center justify-between px-4 py-2 border-b border-gray-100"> <div class="flex items-center justify-between px-4 py-2 border-b border-gray-100">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<NButton type="primary" class="px-6 flex items-center" @click="handleAdd"> <NButton v-button="PERMISSIONS.USER.ADD" type="primary" class="px-6 flex items-center" @click="handleAdd">
<template #icon> <template #icon>
<NIcon class="mr-1" style="transform: translateY(-1px)"> <NIcon class="mr-1" style="transform: translateY(-1px)">
<icon-park-outline:plus /> <icon-park-outline:plus />
@ -114,6 +114,7 @@
</NButton> </NButton>
<NButton <NButton
v-button="PERMISSIONS.USER.DELETE"
type="error" type="error"
:disabled="selectedRows.length === 0" :disabled="selectedRows.length === 0"
class="px-6 flex items-center" class="px-6 flex items-center"
@ -128,6 +129,7 @@
</NButton> </NButton>
<NButton <NButton
v-button="PERMISSIONS.USER.ROLE"
type="info" type="info"
:disabled="selectedRows.length !== 1" :disabled="selectedRows.length !== 1"
class="px-6 flex items-center" class="px-6 flex items-center"
@ -142,6 +144,7 @@
</NButton> </NButton>
<NDropdown <NDropdown
v-button="PERMISSIONS.USER.EXPORT"
trigger="click" trigger="click"
:show="showExportDropdown" :show="showExportDropdown"
:options="[ :options="[
@ -180,7 +183,7 @@
</NButton> </NButton>
</NDropdown> </NDropdown>
<NButton class="px-6 flex items-center" @click="handleImport"> <NButton v-button="PERMISSIONS.USER.IMPORT" class="px-6 flex items-center" @click="handleImport">
<template #icon> <template #icon>
<NIcon class="mr-1" style="transform: translateY(-1px)"> <NIcon class="mr-1" style="transform: translateY(-1px)">
<icon-park-outline:upload /> <icon-park-outline:upload />
@ -693,6 +696,11 @@ import {
} from '@/service/api/system/role' } from '@/service/api/system/role'
import type { RoleVo } from '@/service/api/system/role' import type { RoleVo } from '@/service/api/system/role'
import { coiMsgBox, coiMsgError, coiMsgInfo, coiMsgSuccess, coiMsgWarning } from '@/utils/coi' import { coiMsgBox, coiMsgError, coiMsgInfo, coiMsgSuccess, coiMsgWarning } from '@/utils/coi'
import { PERMISSIONS } from '@/constants/permissions'
import { usePermission } from '@/hooks/usePermission'
//
const { hasButton } = usePermission()
// //
const loading = ref(false) const loading = ref(false)
@ -974,16 +982,23 @@ const columns: DataTableColumns<UserVo> = [
align: 'center', align: 'center',
fixed: 'right', fixed: 'right',
render: (row) => { render: (row) => {
return h('div', { class: 'flex items-center justify-center gap-2' }, [ const buttons = []
h(NButton, {
//
if (hasButton(PERMISSIONS.USER.UPDATE)) {
buttons.push(h(NButton, {
type: 'primary', type: 'primary',
size: 'small', size: 'small',
onClick: () => handleEdit(row), onClick: () => handleEdit(row),
}, { }, {
icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:edit') }), icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:edit') }),
default: () => '编辑', default: () => '编辑',
}), }))
h(NPopconfirm, { }
//
if (hasButton(PERMISSIONS.USER.DELETE)) {
buttons.push(h(NPopconfirm, {
onPositiveClick: () => handleDelete(row.userId), onPositiveClick: () => handleDelete(row.userId),
negativeText: '取消', negativeText: '取消',
positiveText: '确定', positiveText: '确定',
@ -996,24 +1011,34 @@ const columns: DataTableColumns<UserVo> = [
icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:delete') }), icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:delete') }),
default: () => '删除', default: () => '删除',
}), }),
}), }))
h(NButton, { }
//
if (hasButton(PERMISSIONS.USER.RESET_PWD)) {
buttons.push(h(NButton, {
type: 'warning', type: 'warning',
size: 'small', size: 'small',
onClick: () => handleResetPassword(row), onClick: () => handleResetPassword(row),
}, { }, {
icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:refresh') }), icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:refresh') }),
default: () => '重置密码', default: () => '重置密码',
}), }))
h(NButton, { }
//
if (hasButton(PERMISSIONS.USER.ROLE)) {
buttons.push(h(NButton, {
type: 'info', type: 'info',
size: 'small', size: 'small',
onClick: () => handleAssignRole(row), onClick: () => handleAssignRole(row),
}, { }, {
icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:setting') }), icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h('icon-park-outline:setting') }),
default: () => '分配角色', default: () => '分配角色',
}), }))
]) }
return h('div', { class: 'flex items-center justify-center gap-2' }, buttons)
}, },
}, },
] ]