Refactor permissions and roles management with comprehensive updates
- Implement advanced permission management with tree-based structure - Add detailed search, filtering, and tree expansion features - Enhance role management with permission assignment dialog - Integrate API calls for CRUD operations on permissions and roles - Improve form validation and error handling - Update UI with more informative table columns and icons
This commit is contained in:
parent
c041ef9671
commit
2545bf43ac
83
src/api/system/permissions.js
Normal file
83
src/api/system/permissions.js
Normal file
@ -0,0 +1,83 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取权限树形列表
|
||||
* @returns {Promise} 返回权限树形数据
|
||||
*/
|
||||
export function getPermissionTree() {
|
||||
return request.get('/api/permissions/tree')
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建权限
|
||||
* @param {Object} data - 权限数据
|
||||
* @param {string} data.name - 权限名称
|
||||
* @param {string} data.code - 权限代码
|
||||
* @param {string} [data.description] - 权限描述
|
||||
* @param {string} [data.category] - 权限分类
|
||||
* @param {string} data.type - 权限类型:menu-菜单 button-按钮 api-接口
|
||||
* @param {number} [data.parent_id] - 父权限ID
|
||||
* @param {string} [data.path] - 权限路径(菜单权限必填)
|
||||
* @param {string} [data.component] - 前端组件(菜单权限必填)
|
||||
* @param {string} [data.icon] - 图标(菜单权限可选)
|
||||
* @param {number} [data.sort_order=0] - 排序号
|
||||
* @param {number} [data.status=1] - 状态:0-禁用 1-启用
|
||||
* @returns {Promise} 返回创建结果
|
||||
*/
|
||||
export function createPermission(data) {
|
||||
return request.post('/api/permissions', {
|
||||
code: data.code,
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
category: data.category,
|
||||
type: data.type,
|
||||
parent_id: data.parent_id,
|
||||
path: data.path,
|
||||
component: data.component,
|
||||
icon: data.icon,
|
||||
sort_order: data.sort_order || 0,
|
||||
status: data.status || 1
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新权限
|
||||
* @param {number} id - 权限ID
|
||||
* @param {Object} data - 更新数据
|
||||
* @param {string} data.name - 权限名称
|
||||
* @param {string} data.code - 权限代码
|
||||
* @param {string} [data.description] - 权限描述
|
||||
* @param {string} [data.category] - 权限分类
|
||||
* @param {string} data.type - 权限类型
|
||||
* @param {number} [data.parent_id] - 父权限ID
|
||||
* @param {string} [data.path] - 权限路径(菜单权限必填)
|
||||
* @param {string} [data.component] - 前端组件(菜单权限必填)
|
||||
* @param {string} [data.icon] - 图标(菜单权限可选)
|
||||
* @param {number} [data.sort_order] - 排序号
|
||||
* @param {number} [data.status] - 状态
|
||||
* @returns {Promise} 返回更新结果
|
||||
*/
|
||||
export function updatePermission(id, data) {
|
||||
return request.put(`/api/permissions/${id}`, {
|
||||
name: data.name,
|
||||
code: data.code,
|
||||
description: data.description,
|
||||
category: data.category,
|
||||
type: data.type,
|
||||
parent_id: data.parent_id,
|
||||
path: data.path,
|
||||
component: data.component,
|
||||
icon: data.icon,
|
||||
sort_order: data.sort_order,
|
||||
status: data.status
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除权限
|
||||
* @param {number} id - 权限ID
|
||||
* @returns {Promise} 返回删除结果
|
||||
*/
|
||||
export function deletePermission(id) {
|
||||
return request.delete(`/api/permissions/${id}`)
|
||||
}
|
||||
99
src/api/system/roles.js
Normal file
99
src/api/system/roles.js
Normal file
@ -0,0 +1,99 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取角色列表
|
||||
* @param {Object} params - 查询参数
|
||||
* @param {number} [params.page=1] - 页码
|
||||
* @param {number} [params.page_size=10] - 每页条数
|
||||
* @param {string} [params.keyword] - 搜索关键词
|
||||
* @returns {Promise} 返回角色列表数据
|
||||
*/
|
||||
export function getRoleList(params = {}) {
|
||||
return request.get('/api/roles', {
|
||||
params: {
|
||||
page: params.page || 1,
|
||||
page_size: params.page_size || 10,
|
||||
keyword: params.keyword
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色详情
|
||||
* @param {number|string} id - 角色ID
|
||||
* @returns {Promise} 返回角色详情数据
|
||||
*/
|
||||
export function getRoleDetail(id) {
|
||||
return request.get(`/api/roles/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建角色
|
||||
* @param {Object} data - 角色数据
|
||||
* @param {string} data.name - 角色名称
|
||||
* @param {string} [data.description] - 角色描述
|
||||
* @returns {Promise} 返回创建结果
|
||||
*/
|
||||
export function createRole(data) {
|
||||
return request.post('/api/roles', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新角色
|
||||
* @param {number|string} id - 角色ID
|
||||
* @param {Object} data - 更新数据
|
||||
* @param {string} data.name - 角色名称
|
||||
* @param {string} [data.description] - 角色描述
|
||||
* @param {Array<number>} [data.permissions] - 权限ID数组
|
||||
* @returns {Promise} 返回更新结果
|
||||
*/
|
||||
export function updateRole(id, data) {
|
||||
return request.put(`/api/roles/${id}`, {
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
permissions: data.permissions || []
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
* @param {number|string} id - 角色ID
|
||||
* @returns {Promise} 返回删除结果
|
||||
*/
|
||||
export function deleteRole(id) {
|
||||
return request.delete(`/api/roles/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有权限列表(树形结构)
|
||||
* @returns {Promise} 返回权限树形数据
|
||||
*/
|
||||
export function getPermissionTree() {
|
||||
return request.get('/api/permissions/tree')
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色权限
|
||||
* @param {number|string} id - 角色ID
|
||||
* @returns {Promise} 返回角色权限数据
|
||||
*/
|
||||
export function getRolePermissions(id) {
|
||||
return request.get(`/api/roles/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配角色权限
|
||||
* @param {number|string} id - 角色ID
|
||||
* @param {Object} data - 权限数据
|
||||
* @param {string} data.name - 角色名称
|
||||
* @param {string} data.description - 角色描述
|
||||
* @param {Array<number>} data.permissions - 权限ID数组
|
||||
* @returns {Promise} 返回分配结果
|
||||
*/
|
||||
export function assignRolePermissions(id, data) {
|
||||
return request.put(`/api/roles/${id}`, {
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
permissions: Array.isArray(data.permissions) ? data.permissions.filter(id => id != null) : []
|
||||
})
|
||||
}
|
||||
@ -1,229 +1,482 @@
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Search, Plus, Edit, Delete, Folder, FolderOpened } from '@element-plus/icons-vue'
|
||||
import { formatDateTime } from '@/utils/format'
|
||||
import {
|
||||
getPermissionTree,
|
||||
createPermission,
|
||||
updatePermission,
|
||||
deletePermission
|
||||
} from '@/api/system/permissions'
|
||||
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: "用户管理",
|
||||
code: "system:user",
|
||||
description: "用户的增删改查权限",
|
||||
type: "菜单权限",
|
||||
status: true,
|
||||
createTime: "2024-03-20",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "角色管理",
|
||||
code: "system:role",
|
||||
description: "角色的增删改查权限",
|
||||
type: "菜单权限",
|
||||
status: true,
|
||||
createTime: "2024-03-20",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "新增用户",
|
||||
code: "system:user:add",
|
||||
description: "新增用户的权限",
|
||||
type: "操作权限",
|
||||
status: true,
|
||||
createTime: "2024-03-20",
|
||||
},
|
||||
]);
|
||||
// 搜索表单
|
||||
const searchForm = ref({
|
||||
keyword: '',
|
||||
type: '',
|
||||
category: '',
|
||||
status: ''
|
||||
})
|
||||
|
||||
// 新增/编辑权限
|
||||
const dialogVisible = ref(false);
|
||||
const isEdit = ref(false);
|
||||
const currentPermission = ref(null);
|
||||
// 权限类型选项
|
||||
const typeOptions = [
|
||||
{ label: '菜单权限', value: 'menu' },
|
||||
{ label: '按钮权限', value: 'button' },
|
||||
{ label: '接口权限', value: 'api' }
|
||||
]
|
||||
|
||||
// 权限分类选项
|
||||
const categoryOptions = [
|
||||
{ label: '系统管理', value: 'system' },
|
||||
{ label: '内容管理', value: 'content' },
|
||||
{ label: '用户管理', value: 'user' }
|
||||
]
|
||||
|
||||
// 状态选项
|
||||
const statusOptions = [
|
||||
{ label: '启用', value: 1 },
|
||||
{ label: '禁用', value: 0 }
|
||||
]
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([])
|
||||
const loading = ref(false)
|
||||
const permissionTree = ref([])
|
||||
|
||||
// 添加展开控制变量
|
||||
const expandAll = ref(false)
|
||||
|
||||
// 获取权限列表
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getPermissionTree()
|
||||
if (res.success) {
|
||||
permissionTree.value = res.data
|
||||
tableData.value = res.data // 直接使用树形数据,不需要扁平化
|
||||
} else {
|
||||
ElMessage.error(res.message || '获取权限列表失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取权限列表错误:', error)
|
||||
ElMessage.error('获取权限列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = () => {
|
||||
const filterNode = (data) => {
|
||||
const matchKeyword = !searchForm.value.keyword ||
|
||||
data.name.toLowerCase().includes(searchForm.value.keyword.toLowerCase()) ||
|
||||
data.code.toLowerCase().includes(searchForm.value.keyword.toLowerCase())
|
||||
|
||||
const matchType = !searchForm.value.type || data.type === searchForm.value.type
|
||||
const matchCategory = !searchForm.value.category || data.category === searchForm.value.category
|
||||
const matchStatus = searchForm.value.status === '' || data.status === searchForm.value.status
|
||||
|
||||
// 如果当前节点匹配,直接返回true
|
||||
if (matchKeyword && matchType && matchCategory && matchStatus) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 如果有子节点,递归检查子节点
|
||||
if (data.children && data.children.length) {
|
||||
data.children = data.children.filter(filterNode)
|
||||
return data.children.length > 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 深拷贝原始数据进行过滤
|
||||
const filteredData = JSON.parse(JSON.stringify(permissionTree.value))
|
||||
tableData.value = filteredData.filter(filterNode)
|
||||
}
|
||||
|
||||
// 重置搜索
|
||||
const resetSearch = () => {
|
||||
searchForm.value = {
|
||||
keyword: '',
|
||||
type: '',
|
||||
category: '',
|
||||
status: ''
|
||||
}
|
||||
tableData.value = permissionTree.value // 恢复原始树形数据
|
||||
}
|
||||
|
||||
// 表单对话框
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('新增权限')
|
||||
const formRef = ref(null)
|
||||
const formData = ref({
|
||||
name: "",
|
||||
code: "",
|
||||
description: "",
|
||||
type: "",
|
||||
status: true,
|
||||
});
|
||||
name: '',
|
||||
code: '',
|
||||
description: '',
|
||||
category: '',
|
||||
type: 'menu',
|
||||
parent_id: null,
|
||||
path: '',
|
||||
component: '',
|
||||
icon: '',
|
||||
sort_order: 0,
|
||||
status: 1
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
// 表单校验规则
|
||||
const rules = {
|
||||
name: [{ required: true, message: "请输入权限名称", trigger: "blur" }],
|
||||
code: [{ required: true, message: "请输入权限标识", trigger: "blur" }],
|
||||
type: [{ required: true, message: "请选择权限类型", trigger: "change" }],
|
||||
};
|
||||
name: [
|
||||
{ required: true, message: '请输入权限名称', trigger: 'blur' },
|
||||
{ min: 2, max: 100, message: '长度在 2 到 100 个字符', trigger: 'blur' }
|
||||
],
|
||||
code: [
|
||||
{ required: true, message: '请输入权限代码', trigger: 'blur' },
|
||||
{ min: 2, max: 100, message: '长度在 2 到 100 个字符', trigger: 'blur' }
|
||||
],
|
||||
type: [
|
||||
{ required: true, message: '请选择权限类型', trigger: 'change' }
|
||||
],
|
||||
category: [
|
||||
{ required: true, message: '请选择权限分类', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
|
||||
const formRef = ref();
|
||||
|
||||
// 打开新增弹窗
|
||||
const handleAdd = () => {
|
||||
isEdit.value = false;
|
||||
currentPermission.value = null;
|
||||
resetForm();
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 打开编辑弹窗
|
||||
const handleEdit = (row) => {
|
||||
isEdit.value = true;
|
||||
currentPermission.value = row;
|
||||
// 处理新增
|
||||
const handleAdd = (parentId = null) => {
|
||||
dialogTitle.value = '新增权限'
|
||||
formData.value = {
|
||||
name: row.name,
|
||||
code: row.code,
|
||||
description: row.description,
|
||||
type: row.type,
|
||||
status: row.status,
|
||||
};
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
name: '',
|
||||
code: '',
|
||||
description: '',
|
||||
category: '',
|
||||
type: 'menu',
|
||||
parent_id: parentId,
|
||||
path: '',
|
||||
component: '',
|
||||
icon: '',
|
||||
sort_order: 0,
|
||||
status: 1
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
// 处理编辑
|
||||
const handleEdit = (row) => {
|
||||
dialogTitle.value = '编辑权限'
|
||||
formData.value = { ...row } // 直接使用表格行数据
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 处理删除
|
||||
const handleDelete = (row) => {
|
||||
if (!row.id) {
|
||||
ElMessage.error('权限ID不存在')
|
||||
return
|
||||
}
|
||||
|
||||
ElMessageBox.confirm('确认删除该权限吗?删除后将无法恢复!', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const res = await deletePermission(row.id)
|
||||
if (res.success) {
|
||||
ElMessage.success('删除成功')
|
||||
getList()
|
||||
} else {
|
||||
ElMessage.error(res.message || '删除失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除权限错误:', error)
|
||||
const errorMsg = error.response?.data?.message || error.message || '删除失败'
|
||||
ElMessage.error(errorMsg)
|
||||
}
|
||||
}).catch(() => {
|
||||
// 用户取消删除操作,不需要做任何处理
|
||||
})
|
||||
}
|
||||
|
||||
// 处理表单提交
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return;
|
||||
if (!formRef.value) return
|
||||
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
if (isEdit.value && currentPermission.value) {
|
||||
// 编辑模式:更新表格中的数据
|
||||
const index = tableData.value.findIndex(
|
||||
(item) => item.id === currentPermission.value.id
|
||||
);
|
||||
if (index !== -1) {
|
||||
tableData.value[index] = {
|
||||
...currentPermission.value,
|
||||
...formData.value,
|
||||
};
|
||||
ElMessage.success("更新成功");
|
||||
}
|
||||
await formRef.value.validate()
|
||||
const submitFunc = formData.value.id ? updatePermission : createPermission
|
||||
const res = await submitFunc(
|
||||
formData.value.id,
|
||||
formData.value
|
||||
)
|
||||
|
||||
if (res.success) {
|
||||
ElMessage.success(formData.value.id ? '更新成功' : '创建成功')
|
||||
dialogVisible.value = false
|
||||
getList()
|
||||
} else {
|
||||
// 新增模式:添加到表格
|
||||
const newPermission = {
|
||||
id: tableData.value.length + 1,
|
||||
...formData.value,
|
||||
createTime: new Date().toLocaleString(),
|
||||
};
|
||||
tableData.value.push(newPermission);
|
||||
ElMessage.success("添加成功");
|
||||
ElMessage.error(res.message || (formData.value.id ? '更新失败' : '创建失败'))
|
||||
}
|
||||
dialogVisible.value = false;
|
||||
} catch (error) {
|
||||
console.error("表单验证失败:", error);
|
||||
console.error('提交表单错误:', error)
|
||||
ElMessage.error('提交失败,请检查表单数据')
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
name: "",
|
||||
code: "",
|
||||
description: "",
|
||||
type: "",
|
||||
status: true,
|
||||
};
|
||||
if (formRef.value) {
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
};
|
||||
|
||||
// 弹窗关闭前的处理
|
||||
const handleDialogClose = () => {
|
||||
resetForm();
|
||||
isEdit.value = false;
|
||||
currentPermission.value = null;
|
||||
};
|
||||
|
||||
// 删除权限
|
||||
const handleDelete = (row) => {
|
||||
ElMessageBox.confirm("确认删除该权限?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
// 处理展开/折叠
|
||||
const handleExpandAll = () => {
|
||||
expandAll.value = !expandAll.value
|
||||
const table = document.querySelector('.permission-table')
|
||||
const expandBtns = table.querySelectorAll('.el-table__expand-icon')
|
||||
expandBtns.forEach(btn => {
|
||||
const isExpanded = btn.classList.contains('el-table__expand-icon--expanded')
|
||||
if (expandAll.value && !isExpanded) {
|
||||
btn.click()
|
||||
} else if (!expandAll.value && isExpanded) {
|
||||
btn.click()
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
// 从表格中删除数据
|
||||
const index = tableData.value.findIndex((item) => item.id === row.id);
|
||||
if (index !== -1) {
|
||||
tableData.value.splice(index, 1);
|
||||
ElMessage.success("删除成功");
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 取消删除
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="permission-container">
|
||||
<div class="permission-management">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>权限管理</span>
|
||||
<el-button type="primary" @click="handleAdd">新增权限</el-button>
|
||||
<div class="header-btns">
|
||||
<el-button
|
||||
:icon="expandAll ? 'FolderOpened' : 'Folder'"
|
||||
@click="handleExpandAll"
|
||||
>{{ expandAll ? '折叠' : '展开' }}所有</el-button>
|
||||
<el-button type="primary" :icon="Plus" @click="handleAdd">新增权限</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table :data="tableData" style="width: 100%">
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column prop="name" label="权限名称" width="150" />
|
||||
<el-table-column prop="code" label="权限标识" width="150" />
|
||||
<el-table-column prop="description" label="描述" min-width="200" />
|
||||
<el-table-column prop="type" label="类型" width="120" />
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<!-- 搜索表单 -->
|
||||
<el-form :model="searchForm" inline class="search-form">
|
||||
<el-form-item label="关键词">
|
||||
<el-input
|
||||
v-model="searchForm.keyword"
|
||||
placeholder="请输入权限名称/代码"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限类型">
|
||||
<el-select
|
||||
v-model="searchForm.type"
|
||||
placeholder="请选择类型"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限分类">
|
||||
<el-input
|
||||
v-model="searchForm.category"
|
||||
placeholder="请输入权限分类"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select
|
||||
v-model="searchForm.status"
|
||||
placeholder="请选择状态"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in statusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
|
||||
<el-button @click="resetSearch">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 权限列表 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
row-key="id"
|
||||
border
|
||||
class="permission-table"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
>
|
||||
<el-table-column prop="name" label="权限名称" min-width="200">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status ? 'success' : 'danger'">
|
||||
{{ row.status ? "启用" : "禁用" }}
|
||||
<span>{{ row.name }}</span>
|
||||
<el-tag
|
||||
v-if="row.type === 'menu'"
|
||||
size="small"
|
||||
type="success"
|
||||
class="ml-2"
|
||||
>菜单</el-tag>
|
||||
<el-tag
|
||||
v-else-if="row.type === 'button'"
|
||||
size="small"
|
||||
type="warning"
|
||||
class="ml-2"
|
||||
>按钮</el-tag>
|
||||
<el-tag
|
||||
v-else
|
||||
size="small"
|
||||
type="info"
|
||||
class="ml-2"
|
||||
>接口</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="code" label="权限代码" min-width="150"/>
|
||||
<el-table-column prop="category" label="权限分类" width="120" align="center"/>
|
||||
<el-table-column prop="path" label="权限路径" min-width="150" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ row.path || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sort_order" label="排序" width="80" align="center"/>
|
||||
<el-table-column prop="status" label="状态" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
|
||||
{{ row.status === 1 ? '启用' : '禁用' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" />
|
||||
<el-table-column label="操作" width="180" fixed="right">
|
||||
<el-table-column prop="description" label="描述" min-width="150" show-overflow-tooltip/>
|
||||
<el-table-column prop="created_at" label="创建时间" width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" size="small" @click="handleEdit(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button type="danger" size="small" @click="handleDelete(row)">
|
||||
删除
|
||||
</el-button>
|
||||
{{ formatDateTime(row.created_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="250" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-if="row.type === 'menu'"
|
||||
type="primary"
|
||||
:icon="Plus"
|
||||
link
|
||||
@click="handleAdd(row.id)"
|
||||
>新增子权限</el-button>
|
||||
<el-button type="primary" :icon="Edit" link @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
link
|
||||
@click="handleDelete(row)"
|
||||
:disabled="row.children && row.children.length > 0"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<!-- 新增/编辑权限弹窗 -->
|
||||
<!-- 表单对话框 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="isEdit ? '编辑权限' : '新增权限'"
|
||||
width="500px"
|
||||
@close="handleDialogClose"
|
||||
:title="dialogTitle"
|
||||
width="600px"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="100px">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="权限名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入权限名称" />
|
||||
<el-input
|
||||
v-model="formData.name"
|
||||
placeholder="请输入权限名称"
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限标识" prop="code">
|
||||
<el-form-item label="权限代码" prop="code">
|
||||
<el-input
|
||||
v-model="formData.code"
|
||||
placeholder="请输入权限标识"
|
||||
:disabled="isEdit"
|
||||
placeholder="请输入权限代码"
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
:disabled="!!formData.id"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限类型" prop="type">
|
||||
<el-select v-model="formData.type" placeholder="请选择权限类型">
|
||||
<el-option label="菜单权限" value="菜单权限" />
|
||||
<el-option label="操作权限" value="操作权限" />
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限分类" prop="category">
|
||||
<el-select v-model="formData.category" placeholder="请选择权限分类">
|
||||
<el-option
|
||||
v-for="item in categoryOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限路径" prop="path">
|
||||
<el-input
|
||||
v-model="formData.path"
|
||||
placeholder="请输入权限路径"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="前端组件" prop="component">
|
||||
<el-input
|
||||
v-model="formData.component"
|
||||
placeholder="请输入前端组件路径"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="图标" prop="icon">
|
||||
<el-input
|
||||
v-model="formData.icon"
|
||||
placeholder="请输入图标名称"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序号" prop="sort_order">
|
||||
<el-input-number
|
||||
v-model="formData.sort_order"
|
||||
:min="0"
|
||||
:max="999"
|
||||
controls-position="right"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-switch
|
||||
v-model="formData.status"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限描述">
|
||||
<el-input
|
||||
v-model="formData.description"
|
||||
type="textarea"
|
||||
rows="4"
|
||||
:rows="4"
|
||||
placeholder="请输入权限描述"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-switch v-model="formData.status" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
@ -236,56 +489,28 @@ const handleDelete = (row) => {
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "../../../styles/variables.scss" as *;
|
||||
.permission-management {
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.permission-container {
|
||||
.el-card {
|
||||
background: #ffffff;
|
||||
border: none;
|
||||
.search-form {
|
||||
margin-bottom: 24px;
|
||||
padding: 24px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
box-shadow: $box-shadow;
|
||||
|
||||
.el-card__header {
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid $border-color;
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.el-input,
|
||||
.el-select {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: $text-primary;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-table) {
|
||||
th.el-table__cell {
|
||||
background-color: #fafafa;
|
||||
color: $text-primary;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-button--small {
|
||||
padding: 6px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-form) {
|
||||
.el-form-item__label {
|
||||
font-weight: normal;
|
||||
color: $text-regular;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
.el-button {
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,112 +1,454 @@
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Search, Plus, Edit, Delete, Setting } from '@element-plus/icons-vue'
|
||||
import { formatDateTime } from '@/utils/format'
|
||||
import {
|
||||
getRoleList,
|
||||
getRoleDetail,
|
||||
createRole,
|
||||
updateRole,
|
||||
deleteRole,
|
||||
getRolePermissions,
|
||||
assignRolePermissions,
|
||||
getPermissionTree
|
||||
} from '@/api/system/roles'
|
||||
|
||||
const tableData = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: "超级管理员",
|
||||
description: "系统最高权限",
|
||||
permissions: ["all"],
|
||||
createTime: "2024-03-20",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "管理人员",
|
||||
description: "日常运维管理",
|
||||
permissions: ["monitor", "patrol"],
|
||||
createTime: "2024-03-20",
|
||||
},
|
||||
]);
|
||||
// 搜索表单
|
||||
const searchForm = ref({
|
||||
keyword: ''
|
||||
})
|
||||
|
||||
const handleEdit = (row) => {
|
||||
console.log("编辑角色:", row);
|
||||
};
|
||||
// 表格数据
|
||||
const tableData = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
// 分页配置
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 获取角色列表
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getRoleList({
|
||||
page: pagination.value.page,
|
||||
page_size: pagination.value.page_size,
|
||||
keyword: searchForm.value.keyword
|
||||
})
|
||||
if (res.success) {
|
||||
tableData.value = res.data
|
||||
pagination.value.total = res.data.length
|
||||
} else {
|
||||
ElMessage.error(res.message || '获取角色列表失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取角色列表错误:', error)
|
||||
ElMessage.error('获取角色列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = () => {
|
||||
pagination.value.page = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
// 重置搜索
|
||||
const resetSearch = () => {
|
||||
searchForm.value.keyword = ''
|
||||
pagination.value.page = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
// 处理分页变化
|
||||
const handleSizeChange = (val) => {
|
||||
pagination.value.page_size = val
|
||||
getList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
pagination.value.page = val
|
||||
getList()
|
||||
}
|
||||
|
||||
// 表单对话框
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('新增角色')
|
||||
const formRef = ref(null)
|
||||
const formData = ref({
|
||||
name: '',
|
||||
description: ''
|
||||
})
|
||||
|
||||
// 表单校验规则
|
||||
const rules = {
|
||||
name: [
|
||||
{ required: true, message: '请输入角色名称', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
// 处理新增
|
||||
const handleAdd = () => {
|
||||
dialogTitle.value = '新增角色'
|
||||
formData.value = {
|
||||
name: '',
|
||||
description: ''
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 处理编辑
|
||||
const handleEdit = async (row) => {
|
||||
dialogTitle.value = '编辑角色'
|
||||
try {
|
||||
const res = await getRoleDetail(row.id)
|
||||
if (res.success) {
|
||||
formData.value = res.data
|
||||
dialogVisible.value = true
|
||||
} else {
|
||||
ElMessage.error(res.message || '获取角色详情失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取角色详情错误:', error)
|
||||
ElMessage.error('获取角色详情失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 处理删除
|
||||
const handleDelete = (row) => {
|
||||
console.log("删除角色:", row);
|
||||
};
|
||||
</script>
|
||||
ElMessageBox.confirm('确认删除该角色吗?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const res = await deleteRole(row.id)
|
||||
if (res.success) {
|
||||
ElMessage.success('删除成功')
|
||||
getList()
|
||||
} else {
|
||||
ElMessage.error(res.message || '删除失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除角色错误:', error)
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
<template>
|
||||
<div class="role-container">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>角色管理</span>
|
||||
<el-button type="primary">新增角色</el-button>
|
||||
</div>
|
||||
</template>
|
||||
// 处理表单提交
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return
|
||||
|
||||
<el-table :data="tableData" style="width: 100%">
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column prop="name" label="角色名称" width="120" />
|
||||
<el-table-column prop="description" label="描述" />
|
||||
<el-table-column label="权限" width="200">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-for="perm in row.permissions" :key="perm" class="permission-tag">
|
||||
{{ perm }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" />
|
||||
<el-table-column label="操作" width="180">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" size="small" @click="handleEdit(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button type="danger" size="small" @click="handleDelete(row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
try {
|
||||
await formRef.value.validate()
|
||||
const submitData = {
|
||||
name: formData.value.name,
|
||||
description: formData.value.description,
|
||||
permissions: formData.value.permissions || []
|
||||
}
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use "../../../styles/variables.scss" as *;
|
||||
const submitFunc = formData.value.id ? updateRole : createRole
|
||||
const res = await submitFunc(
|
||||
formData.value.id,
|
||||
submitData
|
||||
)
|
||||
|
||||
.role-container {
|
||||
.el-card {
|
||||
background: #ffffff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
box-shadow: $box-shadow;
|
||||
|
||||
.el-card__header {
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid $border-color;
|
||||
if (res.success) {
|
||||
ElMessage.success(formData.value.id ? '更新成功' : '创建成功')
|
||||
dialogVisible.value = false
|
||||
getList()
|
||||
} else {
|
||||
ElMessage.error(res.message || (formData.value.id ? '更新失败' : '创建失败'))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交表单错误:', error)
|
||||
if (error.response?.data?.message) {
|
||||
ElMessage.error(error.response.data.message)
|
||||
} else {
|
||||
ElMessage.error(formData.value.id ? '更新失败' : '创建失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
// 权限分配对话框
|
||||
const permissionDialogVisible = ref(false)
|
||||
const currentRole = ref(null)
|
||||
const permissionList = ref([])
|
||||
const selectedPermissions = ref([])
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: $text-primary;
|
||||
// 处理树节点选中状态变化
|
||||
const handleCheckChange = (data, checked) => {
|
||||
// 如果是叶子节点,更新选中的权限ID列表
|
||||
if (!data.children || data.children.length === 0) {
|
||||
if (checked) {
|
||||
if (!selectedPermissions.value.includes(data.id)) {
|
||||
selectedPermissions.value.push(data.id)
|
||||
}
|
||||
} else {
|
||||
const index = selectedPermissions.value.indexOf(data.id)
|
||||
if (index > -1) {
|
||||
selectedPermissions.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.permission-tag {
|
||||
margin-right: 8px;
|
||||
margin-bottom: 4px;
|
||||
// 打开权限分配对话框
|
||||
const handlePermission = async (row) => {
|
||||
currentRole.value = row
|
||||
try {
|
||||
// 获取所有权限树
|
||||
const permissionRes = await getPermissionTree()
|
||||
// 获取角色当前权限
|
||||
const roleRes = await getRolePermissions(row.id)
|
||||
|
||||
if (permissionRes.success && roleRes.success) {
|
||||
permissionList.value = permissionRes.data
|
||||
selectedPermissions.value = roleRes.data.permissions?.map(p => p.id) || []
|
||||
permissionDialogVisible.value = true
|
||||
} else {
|
||||
ElMessage.error('获取权限数据失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取权限列表错误:', error)
|
||||
ElMessage.error('获取权限列表失败')
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-table) {
|
||||
th.el-table__cell {
|
||||
background-color: #fafafa;
|
||||
color: $text-primary;
|
||||
font-weight: 500;
|
||||
// 提交权限分配
|
||||
const handleSubmitPermissions = async () => {
|
||||
try {
|
||||
if (!currentRole.value || !selectedPermissions.value) {
|
||||
ElMessage.error('数据不完整,请重试')
|
||||
return
|
||||
}
|
||||
|
||||
const submitData = {
|
||||
name: currentRole.value.name,
|
||||
description: currentRole.value.description,
|
||||
permission_ids: selectedPermissions.value
|
||||
}
|
||||
console.log('提交权限数据:', submitData)
|
||||
|
||||
const res = await assignRolePermissions(currentRole.value.id, submitData)
|
||||
|
||||
if (res.success) {
|
||||
ElMessage.success('权限分配成功')
|
||||
permissionDialogVisible.value = false
|
||||
// 重新获取角色列表和当前角色信息
|
||||
await getList()
|
||||
} else {
|
||||
ElMessage.error(res.message || '权限分配失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('分配权限错误:', error)
|
||||
if (error.response?.data) {
|
||||
console.error('错误详情:', error.response.data)
|
||||
ElMessage.error(error.response.data.message || '权限分配失败')
|
||||
} else {
|
||||
ElMessage.error('权限分配失败,请检查数据后重试')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="role-management">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>角色管理</span>
|
||||
<el-button type="primary" :icon="Plus" @click="handleAdd">新增角色</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 搜索表单 -->
|
||||
<el-form :model="searchForm" inline class="search-form">
|
||||
<el-form-item label="关键词">
|
||||
<el-input
|
||||
v-model="searchForm.keyword"
|
||||
placeholder="请输入角色名称"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
|
||||
<el-button @click="resetSearch">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 角色列表 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="60" align="center"/>
|
||||
<el-table-column prop="name" label="角色名称" min-width="150"/>
|
||||
<el-table-column prop="description" label="角色描述" min-width="200" show-overflow-tooltip/>
|
||||
<el-table-column prop="created_at" label="创建时间" width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ formatDateTime(row.created_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="updated_at" label="更新时间" width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ formatDateTime(row.updated_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="250" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" :icon="Setting" link @click="handlePermission(row)">权限设置</el-button>
|
||||
<el-button type="primary" :icon="Edit" link @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button type="danger" :icon="Delete" link @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页器 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.page_size"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
background
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 表单对话框 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
width="500px"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="角色名称" prop="name">
|
||||
<el-input
|
||||
v-model="formData.name"
|
||||
placeholder="请输入角色名称"
|
||||
maxlength="50"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="角色描述" prop="description">
|
||||
<el-input
|
||||
v-model="formData.description"
|
||||
type="textarea"
|
||||
placeholder="请输入角色描述"
|
||||
:rows="4"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 权限分配对话框 -->
|
||||
<el-dialog
|
||||
v-model="permissionDialogVisible"
|
||||
title="权限分配"
|
||||
width="600px"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-form label-width="100px">
|
||||
<el-form-item label="角色名称">
|
||||
<span>{{ currentRole?.name }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="权限列表">
|
||||
<el-tree
|
||||
:data="permissionList"
|
||||
show-checkbox
|
||||
node-key="id"
|
||||
:default-checked-keys="selectedPermissions"
|
||||
:props="{
|
||||
children: 'children',
|
||||
label: 'name'
|
||||
}"
|
||||
@check="handleCheckChange"
|
||||
>
|
||||
<template #default="{ data }">
|
||||
<span class="custom-tree-node">
|
||||
<span>{{ data.name }}</span>
|
||||
<el-tag size="small" type="info" class="permission-tag">
|
||||
{{ data.type === 'menu' ? '菜单' : '按钮' }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="permissionDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmitPermissions">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.role-management {
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.el-button--small {
|
||||
padding: 6px 16px;
|
||||
.search-form {
|
||||
margin-bottom: 24px;
|
||||
padding: 24px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.custom-tree-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
|
||||
.permission-tag {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-tree-node__content) {
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user