feat: 角色等级体系与权限管控实施
- 数据库:auth_roles 表新增 level 字段(1=超管, 10=管理员, 100=普通用户) - 后端:新增 GetAllRoles/GetUserMaxLevel/SetUserRoles/FindByCodeList DAO 方法 - 后端:SetRolesRequest 替换 AssignRoleRequest,AdminUserInfo.Roles 改为 []RoleInfo - 后端:所有管理操作(禁用/启用/角色分配/创建用户)强制层级权限校验 - 后端:PUT /users/:id/roles(批量设置角色)+ GET /roles(角色列表) - 前端:角色管理改为 Checkbox Group 多选,高等级角色禁用 - 前端:禁用/启用按钮受角色层级约束,列表页操作按钮权限管控 - 前端:创建用户对话框角色选项根据操作者等级动态过滤 - 文档:API 文档、设计方案、集成规范、进度文档同步更新 Made-with: Cursor
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
/**
|
||||
* 用户管理 API 模块
|
||||
*
|
||||
* 对应后端路由:/api/v1/admin/users
|
||||
* 对应后端路由:/api/v1/admin/users, /api/v1/admin/roles
|
||||
* 所有接口需要 JWT + admin 角色权限
|
||||
*
|
||||
* 接口列表:
|
||||
* - GET /api/v1/admin/users 用户列表(分页 + 搜索 + 筛选)
|
||||
* - GET /api/v1/admin/users/:id 用户详情
|
||||
* - GET /api/v1/admin/users 用户列表(分页 + 搜索 + 筛选)
|
||||
* - GET /api/v1/admin/users/:id 用户详情
|
||||
* - PUT /api/v1/admin/users/:id/status 更新用户状态
|
||||
* - PUT /api/v1/admin/users/:id/role 分配角色
|
||||
* - POST /api/v1/admin/users 管理员创建用户
|
||||
* - PUT /api/v1/admin/users/:id/roles 批量设置角色
|
||||
* - POST /api/v1/admin/users 管理员创建用户
|
||||
* - GET /api/v1/admin/roles 获取所有角色列表
|
||||
*/
|
||||
import request from '@/utils/request'
|
||||
|
||||
@@ -57,16 +58,27 @@ export function updateUserStatus(id, status) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配角色
|
||||
* 批量设置用户角色(先清后设)
|
||||
* @param {number} id - 用户 ID
|
||||
* @param {string} roleCode - 角色代码:user/admin/super_admin
|
||||
* @param {string[]} roleCodes - 角色代码列表
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function assignUserRole(id, roleCode) {
|
||||
export function setUserRoles(id, roleCodes) {
|
||||
return request({
|
||||
url: `/api/v1/admin/users/${id}/role`,
|
||||
url: `/api/v1/admin/users/${id}/roles`,
|
||||
method: 'put',
|
||||
data: { role_code: roleCode }
|
||||
data: { role_codes: roleCodes }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有角色列表(含 level 等级信息)
|
||||
* @returns {Promise<{data: Array<{code: string, name: string, level: number}>}>}
|
||||
*/
|
||||
export function getAllRoles() {
|
||||
return request({
|
||||
url: '/api/v1/admin/roles',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,15 @@
|
||||
|
||||
功能:
|
||||
- 基本信息展示(ID、用户名、邮箱、昵称、性别、手机、状态、注册/更新时间)
|
||||
- 角色管理(查看当前角色 + 分配新角色)
|
||||
- 状态切换(启用/禁用)
|
||||
- 角色管理(Checkbox Group 多选,权限等级管控)
|
||||
- 状态切换(启用/禁用,受角色层级约束)
|
||||
- 会议记录 Tab(占位,后续完善)
|
||||
|
||||
对应后端 API:
|
||||
- GET /api/v1/admin/users/:id
|
||||
- PUT /api/v1/admin/users/:id/status
|
||||
- PUT /api/v1/admin/users/:id/role
|
||||
- PUT /api/v1/admin/users/:id/roles
|
||||
- GET /api/v1/admin/roles
|
||||
-->
|
||||
<template>
|
||||
<div class="user-detail-page" v-loading="loading">
|
||||
@@ -43,7 +44,7 @@
|
||||
{{ userInfo.status_text }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="user-actions">
|
||||
<div class="user-actions" v-if="canManageTarget">
|
||||
<el-button
|
||||
v-if="userInfo.status === 1"
|
||||
type="danger"
|
||||
@@ -59,6 +60,9 @@
|
||||
启用账号
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="user-actions" v-else>
|
||||
<el-tag type="info" size="small">权限不足,无法操作该用户</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 详细信息表格 -->
|
||||
@@ -80,45 +84,39 @@
|
||||
<el-tab-pane label="角色管理" name="roles">
|
||||
<el-card shadow="never" class="role-card">
|
||||
<div class="role-section">
|
||||
<h4 class="section-title">当前角色</h4>
|
||||
<div class="current-roles">
|
||||
<el-tag
|
||||
v-for="role in userInfo.roles"
|
||||
:key="role"
|
||||
:type="getRoleTagType(role)"
|
||||
size="large"
|
||||
class="role-tag"
|
||||
<h4 class="section-title">角色分配</h4>
|
||||
<p class="role-hint" v-if="!canManageTarget" style="margin-bottom: 12px">
|
||||
该用户权限等级高于或等于您,无法修改其角色。
|
||||
</p>
|
||||
<el-checkbox-group v-model="selectedRoleCodes" class="role-checkbox-group">
|
||||
<el-checkbox
|
||||
v-for="role in allRoles"
|
||||
:key="role.code"
|
||||
:value="role.code"
|
||||
:disabled="isRoleDisabled(role)"
|
||||
class="role-checkbox-item"
|
||||
>
|
||||
{{ getRoleName(role) }}
|
||||
</el-tag>
|
||||
<span v-if="!userInfo.roles || userInfo.roles.length === 0" class="no-role">
|
||||
暂未分配角色
|
||||
</span>
|
||||
</div>
|
||||
<div class="role-checkbox-label">
|
||||
<el-tag :type="getRoleTagType(role.code)" size="small">{{ role.name }}</el-tag>
|
||||
<span class="role-level-badge">Lv.{{ role.level }}</span>
|
||||
</div>
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<p class="role-hint" style="margin-top: 12px">
|
||||
灰色不可选的角色等级高于或等于您的权限,无法分配。勾选后点击"保存"生效。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<div class="role-section">
|
||||
<h4 class="section-title">分配角色</h4>
|
||||
<div class="assign-role-form">
|
||||
<el-select v-model="selectedRole" placeholder="选择角色" style="width: 200px">
|
||||
<el-option label="普通用户" value="user" />
|
||||
<el-option label="管理员" value="admin" />
|
||||
<el-option label="超级管理员" value="super_admin" />
|
||||
</el-select>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="roleLoading"
|
||||
:disabled="!selectedRole"
|
||||
@click="handleAssignRole"
|
||||
>
|
||||
分配角色
|
||||
</el-button>
|
||||
</div>
|
||||
<p class="role-hint">
|
||||
分配角色将为该用户添加所选角色权限。已有角色不会受影响。
|
||||
</p>
|
||||
<div class="role-actions" v-if="canManageTarget">
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="roleLoading"
|
||||
:disabled="!hasRoleChanges"
|
||||
@click="handleSaveRoles"
|
||||
>
|
||||
保存角色
|
||||
</el-button>
|
||||
<el-button @click="resetRoleSelection">重置</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
@@ -143,103 +141,129 @@
|
||||
*
|
||||
* 数据流:
|
||||
* 1. 从路由参数获取 userId
|
||||
* 2. 调用 API 获取用户详情
|
||||
* 3. 支持状态切换和角色分配操作
|
||||
* 2. 并行调用 getUserDetail + getAllRoles 获取用户详情和角色列表
|
||||
* 3. 通过比较操作者 level 和目标用户 level 控制权限
|
||||
* 4. 角色分配使用 Checkbox Group 多选,高等级角色禁用
|
||||
*/
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { getUserDetail, updateUserStatus, assignUserRole } from '@/api/user'
|
||||
import { getUserDetail, updateUserStatus, setUserRoles, getAllRoles } from '@/api/user'
|
||||
import { useUserStore } from '@/store/user'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
/** 加载状态 */
|
||||
const loading = ref(false)
|
||||
|
||||
/** 用户详情数据 */
|
||||
const userInfo = ref(null)
|
||||
|
||||
/** 当前 Tab */
|
||||
const activeTab = ref('info')
|
||||
|
||||
/** 角色分配选中值 */
|
||||
const selectedRole = ref('')
|
||||
|
||||
/** 角色分配加载状态 */
|
||||
const roleLoading = ref(false)
|
||||
|
||||
/** 路由参数中的用户 ID */
|
||||
/** 系统所有角色列表(从 API 获取,含 level) */
|
||||
const allRoles = ref([])
|
||||
|
||||
/** Checkbox Group 绑定值:选中的角色 code 列表 */
|
||||
const selectedRoleCodes = ref([])
|
||||
|
||||
/** 记录用户原始角色 codes,用于比较是否有变更 */
|
||||
const originalRoleCodes = ref([])
|
||||
|
||||
const userId = computed(() => Number(route.params.id))
|
||||
|
||||
/** 头像占位字母 */
|
||||
const avatarLetter = computed(() => {
|
||||
if (!userInfo.value) return '?'
|
||||
const name = userInfo.value.nickname || userInfo.value.username || '?'
|
||||
return name.charAt(0).toUpperCase()
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取状态 Tag 类型
|
||||
* @param {number} status
|
||||
*/
|
||||
/** 当前操作者的最高权限等级(最小 level 值) */
|
||||
const adminMaxLevel = computed(() => {
|
||||
const adminRoleCodes = userStore.roles || []
|
||||
if (!allRoles.value.length || !adminRoleCodes.length) return 999
|
||||
let minLevel = 999
|
||||
for (const r of allRoles.value) {
|
||||
if (adminRoleCodes.includes(r.code) && r.level < minLevel) {
|
||||
minLevel = r.level
|
||||
}
|
||||
}
|
||||
return minLevel
|
||||
})
|
||||
|
||||
/** 目标用户的最高权限等级(后端无角色时返回 MaxInt32,前端以 999 作为等效兜底) */
|
||||
const targetMaxLevel = computed(() => {
|
||||
if (!userInfo.value || userInfo.value.max_level == null) return 999
|
||||
return userInfo.value.max_level
|
||||
})
|
||||
|
||||
/** 操作者是否有权管理目标用户(level 严格小于) */
|
||||
const canManageTarget = computed(() => {
|
||||
return adminMaxLevel.value < targetMaxLevel.value
|
||||
})
|
||||
|
||||
/** Checkbox 是否有变更 */
|
||||
const hasRoleChanges = computed(() => {
|
||||
if (selectedRoleCodes.value.length !== originalRoleCodes.value.length) return true
|
||||
const sorted1 = [...selectedRoleCodes.value].sort()
|
||||
const sorted2 = [...originalRoleCodes.value].sort()
|
||||
return sorted1.some((v, i) => v !== sorted2[i])
|
||||
})
|
||||
|
||||
const getStatusType = (status) => {
|
||||
const map = { 1: 'success', 2: 'danger', 3: 'info' }
|
||||
return map[status] || 'info'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取性别文本
|
||||
* @param {number} gender
|
||||
*/
|
||||
const getGenderText = (gender) => {
|
||||
const map = { 0: '未知', 1: '男', 2: '女' }
|
||||
return map[gender] || '未知'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色 Tag 类型
|
||||
* @param {string} role
|
||||
*/
|
||||
const getRoleTagType = (role) => {
|
||||
const map = { super_admin: 'danger', admin: 'warning', user: '' }
|
||||
return map[role] || 'info'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色中文名称
|
||||
* @param {string} role
|
||||
* 判断角色 checkbox 是否禁用
|
||||
* 规则:角色 level <= 操作者 level 时禁用(不能分配高于或等于自身等级的角色)
|
||||
* 如果无法管理目标用户,全部禁用
|
||||
*/
|
||||
const getRoleName = (role) => {
|
||||
const map = { super_admin: '超级管理员', admin: '管理员', user: '普通用户' }
|
||||
return map[role] || role
|
||||
const isRoleDisabled = (role) => {
|
||||
if (!canManageTarget.value) return true
|
||||
return role.level <= adminMaxLevel.value
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户详情
|
||||
*/
|
||||
const fetchUserDetail = async () => {
|
||||
/** 重置角色选择到原始状态 */
|
||||
const resetRoleSelection = () => {
|
||||
selectedRoleCodes.value = [...originalRoleCodes.value]
|
||||
}
|
||||
|
||||
const fetchData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getUserDetail(userId.value)
|
||||
userInfo.value = res.data
|
||||
const [userRes, rolesRes] = await Promise.all([
|
||||
getUserDetail(userId.value),
|
||||
getAllRoles()
|
||||
])
|
||||
userInfo.value = userRes.data
|
||||
allRoles.value = rolesRes.data || []
|
||||
|
||||
const codes = (userRes.data.roles || []).map(r => r.code)
|
||||
selectedRoleCodes.value = [...codes]
|
||||
originalRoleCodes.value = [...codes]
|
||||
} catch (err) {
|
||||
console.error('获取用户详情失败:', err)
|
||||
console.error('获取数据失败:', err)
|
||||
userInfo.value = null
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 返回列表 */
|
||||
const goBack = () => {
|
||||
router.push('/user/list')
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换用户状态
|
||||
* @param {number} newStatus
|
||||
*/
|
||||
const handleToggleStatus = async (newStatus) => {
|
||||
const action = newStatus === 2 ? '禁用' : '启用'
|
||||
try {
|
||||
@@ -248,38 +272,33 @@ const handleToggleStatus = async (newStatus) => {
|
||||
`${action}确认`,
|
||||
{ type: 'warning' }
|
||||
)
|
||||
|
||||
await updateUserStatus(userId.value, newStatus)
|
||||
ElMessage.success(`${action}成功`)
|
||||
fetchUserDetail()
|
||||
fetchData()
|
||||
} catch (err) {
|
||||
if (err !== 'cancel') {
|
||||
if (err !== 'cancel' && err !== 'close') {
|
||||
console.error(`${action}失败:`, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配角色
|
||||
*/
|
||||
const handleAssignRole = async () => {
|
||||
if (!selectedRole.value) return
|
||||
const handleSaveRoles = async () => {
|
||||
if (!hasRoleChanges.value) return
|
||||
|
||||
roleLoading.value = true
|
||||
try {
|
||||
await assignUserRole(userId.value, selectedRole.value)
|
||||
ElMessage.success('角色分配成功')
|
||||
selectedRole.value = ''
|
||||
fetchUserDetail()
|
||||
await setUserRoles(userId.value, selectedRoleCodes.value)
|
||||
ElMessage.success('角色设置成功')
|
||||
fetchData()
|
||||
} catch (err) {
|
||||
console.error('角色分配失败:', err)
|
||||
console.error('角色设置失败:', err)
|
||||
} finally {
|
||||
roleLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchUserDetail()
|
||||
fetchData()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -369,7 +388,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.role-section {
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
@@ -379,27 +398,37 @@ onMounted(() => {
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.current-roles {
|
||||
.role-checkbox-group {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.role-tag {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.no-role {
|
||||
color: #94A3B8;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.assign-role-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.role-checkbox-item {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.role-checkbox-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.role-level-badge {
|
||||
font-size: 11px;
|
||||
color: #94A3B8;
|
||||
background: #F1F5F9;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.role-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #E2E8F0;
|
||||
}
|
||||
|
||||
.role-hint {
|
||||
font-size: 12px;
|
||||
color: #94A3B8;
|
||||
|
||||
@@ -89,12 +89,12 @@
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
v-for="role in row.roles"
|
||||
:key="role"
|
||||
:type="getRoleTagType(role)"
|
||||
:key="role.code"
|
||||
:type="getRoleTagType(role.code)"
|
||||
size="small"
|
||||
class="role-tag"
|
||||
>
|
||||
{{ getRoleName(role) }}
|
||||
{{ role.name }}
|
||||
</el-tag>
|
||||
<span v-if="!row.roles || row.roles.length === 0" class="no-role">未分配</span>
|
||||
</template>
|
||||
@@ -121,24 +121,26 @@
|
||||
<el-button type="primary" link size="small" @click.stop="goDetail(row.id)">
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 1"
|
||||
type="danger"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="handleToggleStatus(row, 2)"
|
||||
>
|
||||
禁用
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else-if="row.status === 2"
|
||||
type="success"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="handleToggleStatus(row, 1)"
|
||||
>
|
||||
启用
|
||||
</el-button>
|
||||
<template v-if="canManageRow(row)">
|
||||
<el-button
|
||||
v-if="row.status === 1"
|
||||
type="danger"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="handleToggleStatus(row, 2)"
|
||||
>
|
||||
禁用
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else-if="row.status === 2"
|
||||
type="success"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="handleToggleStatus(row, 1)"
|
||||
>
|
||||
启用
|
||||
</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -185,8 +187,12 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="角色" prop="role_code">
|
||||
<el-select v-model="createForm.role_code" placeholder="选择角色" style="width: 100%">
|
||||
<el-option label="普通用户" value="user" />
|
||||
<el-option label="管理员" value="admin" />
|
||||
<el-option
|
||||
v-for="role in assignableRoles"
|
||||
:key="role.code"
|
||||
:label="role.name"
|
||||
:value="role.code"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -207,12 +213,14 @@
|
||||
* 2. 搜索/筛选/分页变化时重新加载
|
||||
* 3. 操作(禁用/启用/创建)成功后刷新列表
|
||||
*/
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { getUserList, updateUserStatus, createUser } from '@/api/user'
|
||||
import { getUserList, updateUserStatus, createUser, getAllRoles } from '@/api/user'
|
||||
import { useUserStore } from '@/store/user'
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
|
||||
/** 加载状态 */
|
||||
const loading = ref(false)
|
||||
@@ -233,6 +241,36 @@ const pagination = reactive({
|
||||
total: 0
|
||||
})
|
||||
|
||||
/** 系统所有角色列表(从 API 获取,含 level) */
|
||||
const allRoles = ref([])
|
||||
|
||||
/** 当前操作者的最高权限等级(最小 level 值) */
|
||||
const adminMaxLevel = computed(() => {
|
||||
const adminRoleCodes = userStore.roles || []
|
||||
if (!allRoles.value.length || !adminRoleCodes.length) return 999
|
||||
let minLevel = 999
|
||||
for (const r of allRoles.value) {
|
||||
if (adminRoleCodes.includes(r.code) && r.level < minLevel) {
|
||||
minLevel = r.level
|
||||
}
|
||||
}
|
||||
return minLevel
|
||||
})
|
||||
|
||||
/** 创建用户对话框中可选的角色列表(过滤掉高于操作者等级的角色) */
|
||||
const assignableRoles = computed(() => {
|
||||
return allRoles.value.filter(r => r.level > adminMaxLevel.value)
|
||||
})
|
||||
|
||||
/**
|
||||
* 判断操作者是否有权管理目标用户(level 严格小于)
|
||||
* @param {Object} row - 用户行数据(含 max_level)
|
||||
*/
|
||||
const canManageRow = (row) => {
|
||||
const targetLevel = (row.max_level == null) ? 999 : row.max_level
|
||||
return adminMaxLevel.value < targetLevel
|
||||
}
|
||||
|
||||
/** 创建用户对话框显示状态 */
|
||||
const showCreateDialog = ref(false)
|
||||
|
||||
@@ -276,15 +314,6 @@ const getRoleTagType = (role) => {
|
||||
return map[role] || 'info'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色中文名称
|
||||
* @param {string} role - 角色代码
|
||||
*/
|
||||
const getRoleName = (role) => {
|
||||
const map = { super_admin: '超级管理员', admin: '管理员', user: '普通用户' }
|
||||
return map[role] || role
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态 Tag 类型
|
||||
* @param {number} status - 状态码
|
||||
@@ -364,7 +393,7 @@ const handleToggleStatus = async (row, newStatus) => {
|
||||
ElMessage.success(`${action}成功`)
|
||||
fetchUserList()
|
||||
} catch (err) {
|
||||
if (err !== 'cancel') {
|
||||
if (err !== 'cancel' && err !== 'close') {
|
||||
console.error(`${action}用户失败:`, err)
|
||||
}
|
||||
}
|
||||
@@ -405,8 +434,19 @@ const resetCreateForm = () => {
|
||||
createForm.role_code = 'user'
|
||||
}
|
||||
|
||||
/** 获取角色列表(用于权限判断和创建用户的角色选项) */
|
||||
const fetchRoles = async () => {
|
||||
try {
|
||||
const res = await getAllRoles()
|
||||
allRoles.value = res.data || []
|
||||
} catch (err) {
|
||||
console.error('获取角色列表失败:', err)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchUserList()
|
||||
fetchRoles()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user