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>
|
<script setup>
|
||||||
import { ref } from "vue";
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
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([
|
// 搜索表单
|
||||||
{
|
const searchForm = ref({
|
||||||
id: 1,
|
keyword: '',
|
||||||
name: "用户管理",
|
type: '',
|
||||||
code: "system:user",
|
category: '',
|
||||||
description: "用户的增删改查权限",
|
status: ''
|
||||||
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 dialogVisible = ref(false);
|
const typeOptions = [
|
||||||
const isEdit = ref(false);
|
{ label: '菜单权限', value: 'menu' },
|
||||||
const currentPermission = ref(null);
|
{ 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({
|
const formData = ref({
|
||||||
name: "",
|
name: '',
|
||||||
code: "",
|
code: '',
|
||||||
description: "",
|
description: '',
|
||||||
type: "",
|
category: '',
|
||||||
status: true,
|
type: 'menu',
|
||||||
});
|
parent_id: null,
|
||||||
|
path: '',
|
||||||
|
component: '',
|
||||||
|
icon: '',
|
||||||
|
sort_order: 0,
|
||||||
|
status: 1
|
||||||
|
})
|
||||||
|
|
||||||
// 表单验证规则
|
// 表单校验规则
|
||||||
const rules = {
|
const rules = {
|
||||||
name: [{ required: true, message: "请输入权限名称", trigger: "blur" }],
|
name: [
|
||||||
code: [{ required: true, message: "请输入权限标识", trigger: "blur" }],
|
{ required: true, message: '请输入权限名称', trigger: 'blur' },
|
||||||
type: [{ required: true, message: "请选择权限类型", trigger: "change" }],
|
{ 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 = (parentId = null) => {
|
||||||
// 打开新增弹窗
|
dialogTitle.value = '新增权限'
|
||||||
const handleAdd = () => {
|
|
||||||
isEdit.value = false;
|
|
||||||
currentPermission.value = null;
|
|
||||||
resetForm();
|
|
||||||
dialogVisible.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 打开编辑弹窗
|
|
||||||
const handleEdit = (row) => {
|
|
||||||
isEdit.value = true;
|
|
||||||
currentPermission.value = row;
|
|
||||||
formData.value = {
|
formData.value = {
|
||||||
name: row.name,
|
name: '',
|
||||||
code: row.code,
|
code: '',
|
||||||
description: row.description,
|
description: '',
|
||||||
type: row.type,
|
category: '',
|
||||||
status: row.status,
|
type: 'menu',
|
||||||
};
|
parent_id: parentId,
|
||||||
dialogVisible.value = true;
|
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 () => {
|
const handleSubmit = async () => {
|
||||||
if (!formRef.value) return;
|
if (!formRef.value) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await formRef.value.validate();
|
await formRef.value.validate()
|
||||||
if (isEdit.value && currentPermission.value) {
|
const submitFunc = formData.value.id ? updatePermission : createPermission
|
||||||
// 编辑模式:更新表格中的数据
|
const res = await submitFunc(
|
||||||
const index = tableData.value.findIndex(
|
formData.value.id,
|
||||||
(item) => item.id === currentPermission.value.id
|
formData.value
|
||||||
);
|
)
|
||||||
if (index !== -1) {
|
|
||||||
tableData.value[index] = {
|
if (res.success) {
|
||||||
...currentPermission.value,
|
ElMessage.success(formData.value.id ? '更新成功' : '创建成功')
|
||||||
...formData.value,
|
dialogVisible.value = false
|
||||||
};
|
getList()
|
||||||
ElMessage.success("更新成功");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// 新增模式:添加到表格
|
ElMessage.error(res.message || (formData.value.id ? '更新失败' : '创建失败'))
|
||||||
const newPermission = {
|
|
||||||
id: tableData.value.length + 1,
|
|
||||||
...formData.value,
|
|
||||||
createTime: new Date().toLocaleString(),
|
|
||||||
};
|
|
||||||
tableData.value.push(newPermission);
|
|
||||||
ElMessage.success("添加成功");
|
|
||||||
}
|
}
|
||||||
dialogVisible.value = false;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("表单验证失败:", error);
|
console.error('提交表单错误:', error)
|
||||||
|
ElMessage.error('提交失败,请检查表单数据')
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// 重置表单
|
// 处理展开/折叠
|
||||||
const resetForm = () => {
|
const handleExpandAll = () => {
|
||||||
formData.value = {
|
expandAll.value = !expandAll.value
|
||||||
name: "",
|
const table = document.querySelector('.permission-table')
|
||||||
code: "",
|
const expandBtns = table.querySelectorAll('.el-table__expand-icon')
|
||||||
description: "",
|
expandBtns.forEach(btn => {
|
||||||
type: "",
|
const isExpanded = btn.classList.contains('el-table__expand-icon--expanded')
|
||||||
status: true,
|
if (expandAll.value && !isExpanded) {
|
||||||
};
|
btn.click()
|
||||||
if (formRef.value) {
|
} else if (!expandAll.value && isExpanded) {
|
||||||
formRef.value.resetFields();
|
btn.click()
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 弹窗关闭前的处理
|
|
||||||
const handleDialogClose = () => {
|
|
||||||
resetForm();
|
|
||||||
isEdit.value = false;
|
|
||||||
currentPermission.value = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 删除权限
|
|
||||||
const handleDelete = (row) => {
|
|
||||||
ElMessageBox.confirm("确认删除该权限?", "提示", {
|
|
||||||
confirmButtonText: "确定",
|
|
||||||
cancelButtonText: "取消",
|
|
||||||
type: "warning",
|
|
||||||
})
|
|
||||||
.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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="permission-container">
|
<div class="permission-management">
|
||||||
<el-card>
|
<el-card>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span>权限管理</span>
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table :data="tableData" style="width: 100%">
|
<!-- 搜索表单 -->
|
||||||
<el-table-column prop="id" label="ID" width="80" />
|
<el-form :model="searchForm" inline class="search-form">
|
||||||
<el-table-column prop="name" label="权限名称" width="150" />
|
<el-form-item label="关键词">
|
||||||
<el-table-column prop="code" label="权限标识" width="150" />
|
<el-input
|
||||||
<el-table-column prop="description" label="描述" min-width="200" />
|
v-model="searchForm.keyword"
|
||||||
<el-table-column prop="type" label="类型" width="120" />
|
placeholder="请输入权限名称/代码"
|
||||||
<el-table-column prop="status" label="状态" width="100">
|
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 }">
|
<template #default="{ row }">
|
||||||
<el-tag :type="row.status ? 'success' : 'danger'">
|
<span>{{ row.name }}</span>
|
||||||
{{ row.status ? "启用" : "禁用" }}
|
<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>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="createTime" label="创建时间" width="180" />
|
<el-table-column prop="description" label="描述" min-width="150" show-overflow-tooltip/>
|
||||||
<el-table-column label="操作" width="180" fixed="right">
|
<el-table-column prop="created_at" label="创建时间" width="180" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="primary" size="small" @click="handleEdit(row)">
|
{{ formatDateTime(row.created_at) }}
|
||||||
编辑
|
</template>
|
||||||
</el-button>
|
</el-table-column>
|
||||||
<el-button type="danger" size="small" @click="handleDelete(row)">
|
<el-table-column label="操作" width="250" fixed="right" align="center">
|
||||||
删除
|
<template #default="{ row }">
|
||||||
</el-button>
|
<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>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 新增/编辑权限弹窗 -->
|
<!-- 表单对话框 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="dialogVisible"
|
v-model="dialogVisible"
|
||||||
:title="isEdit ? '编辑权限' : '新增权限'"
|
:title="dialogTitle"
|
||||||
width="500px"
|
width="600px"
|
||||||
@close="handleDialogClose"
|
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-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>
|
||||||
<el-form-item label="权限标识" prop="code">
|
<el-form-item label="权限代码" prop="code">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.code"
|
v-model="formData.code"
|
||||||
placeholder="请输入权限标识"
|
placeholder="请输入权限代码"
|
||||||
:disabled="isEdit"
|
maxlength="100"
|
||||||
|
show-word-limit
|
||||||
|
:disabled="!!formData.id"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="权限类型" prop="type">
|
<el-form-item label="权限类型" prop="type">
|
||||||
<el-select v-model="formData.type" placeholder="请选择权限类型">
|
<el-select v-model="formData.type" placeholder="请选择权限类型">
|
||||||
<el-option label="菜单权限" value="菜单权限" />
|
<el-option
|
||||||
<el-option label="操作权限" value="操作权限" />
|
v-for="item in typeOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</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-form-item label="权限描述">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.description"
|
v-model="formData.description"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
rows="4"
|
:rows="4"
|
||||||
placeholder="请输入权限描述"
|
placeholder="请输入权限描述"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态">
|
|
||||||
<el-switch v-model="formData.status" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
@ -236,56 +489,28 @@ const handleDelete = (row) => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@use "../../../styles/variables.scss" as *;
|
.permission-management {
|
||||||
|
.card-header {
|
||||||
.permission-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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
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 {
|
.search-form {
|
||||||
padding: 6px 16px;
|
margin-bottom: 24px;
|
||||||
}
|
padding: 24px;
|
||||||
}
|
background-color: #f8f9fa;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
:deep(.el-form) {
|
:deep(.el-form-item) {
|
||||||
.el-form-item__label {
|
margin-bottom: 0;
|
||||||
font-weight: normal;
|
margin-right: 16px;
|
||||||
color: $text-regular;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-footer {
|
.el-input,
|
||||||
.el-button {
|
.el-select {
|
||||||
margin-left: 12px;
|
width: 200px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,112 +1,454 @@
|
|||||||
<script setup>
|
<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([
|
// 搜索表单
|
||||||
{
|
const searchForm = ref({
|
||||||
id: 1,
|
keyword: ''
|
||||||
name: "超级管理员",
|
})
|
||||||
description: "系统最高权限",
|
|
||||||
permissions: ["all"],
|
|
||||||
createTime: "2024-03-20",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: "管理人员",
|
|
||||||
description: "日常运维管理",
|
|
||||||
permissions: ["monitor", "patrol"],
|
|
||||||
createTime: "2024-03-20",
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
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) => {
|
const handleDelete = (row) => {
|
||||||
console.log("删除角色:", row);
|
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(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理表单提交
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!formRef.value) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
await formRef.value.validate()
|
||||||
|
const submitData = {
|
||||||
|
name: formData.value.name,
|
||||||
|
description: formData.value.description,
|
||||||
|
permissions: formData.value.permissions || []
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitFunc = formData.value.id ? updateRole : createRole
|
||||||
|
const res = await submitFunc(
|
||||||
|
formData.value.id,
|
||||||
|
submitData
|
||||||
|
)
|
||||||
|
|
||||||
|
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 ? '更新失败' : '创建失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 权限分配对话框
|
||||||
|
const permissionDialogVisible = ref(false)
|
||||||
|
const currentRole = ref(null)
|
||||||
|
const permissionList = ref([])
|
||||||
|
const selectedPermissions = ref([])
|
||||||
|
|
||||||
|
// 处理树节点选中状态变化
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开权限分配对话框
|
||||||
|
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('获取权限列表失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交权限分配
|
||||||
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="role-container">
|
<div class="role-management">
|
||||||
<el-card>
|
<el-card>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span>角色管理</span>
|
<span>角色管理</span>
|
||||||
<el-button type="primary">新增角色</el-button>
|
<el-button type="primary" :icon="Plus" @click="handleAdd">新增角色</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table :data="tableData" style="width: 100%">
|
<!-- 搜索表单 -->
|
||||||
<el-table-column prop="id" label="ID" width="80" />
|
<el-form :model="searchForm" inline class="search-form">
|
||||||
<el-table-column prop="name" label="角色名称" width="120" />
|
<el-form-item label="关键词">
|
||||||
<el-table-column prop="description" label="描述" />
|
<el-input
|
||||||
<el-table-column label="权限" width="200">
|
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 }">
|
<template #default="{ row }">
|
||||||
<el-tag v-for="perm in row.permissions" :key="perm" class="permission-tag">
|
{{ formatDateTime(row.created_at) }}
|
||||||
{{ perm }}
|
|
||||||
</el-tag>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="createTime" label="创建时间" width="180" />
|
<el-table-column prop="updated_at" label="更新时间" width="180" align="center">
|
||||||
<el-table-column label="操作" width="180">
|
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button type="primary" size="small" @click="handleEdit(row)">
|
{{ formatDateTime(row.updated_at) }}
|
||||||
编辑
|
</template>
|
||||||
</el-button>
|
</el-table-column>
|
||||||
<el-button type="danger" size="small" @click="handleDelete(row)">
|
<el-table-column label="操作" width="250" fixed="right" align="center">
|
||||||
删除
|
<template #default="{ row }">
|
||||||
</el-button>
|
<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>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</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-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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@use "../../../styles/variables.scss" as *;
|
.role-management {
|
||||||
|
.card-header {
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
span {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: $text-primary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.permission-tag {
|
|
||||||
margin-right: 8px;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-table) {
|
|
||||||
th.el-table__cell {
|
|
||||||
background-color: #fafafa;
|
|
||||||
color: $text-primary;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-button--small {
|
.search-form {
|
||||||
padding: 6px 16px;
|
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>
|
</style>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user