物联网问题解决,只差最后测试完善
This commit is contained in:
@@ -3,23 +3,27 @@
|
||||
<el-row :gutter="20">
|
||||
<!-- 左侧:用户列表 -->
|
||||
<el-col :span="8">
|
||||
<el-card class="role-card">
|
||||
<el-card class="user-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">用户列表</span>
|
||||
<el-tag type="success" size="small" style="margin-left: 10px;">
|
||||
用户专属权限
|
||||
</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table
|
||||
:data="paginatedRoleList"
|
||||
:data="paginatedUserList"
|
||||
highlight-current-row
|
||||
@current-change="handleRoleChange"
|
||||
v-loading="roleLoading"
|
||||
@current-change="handleUserChange"
|
||||
v-loading="userLoading"
|
||||
style="width: 100%"
|
||||
max-height="500"
|
||||
>
|
||||
<el-table-column prop="name" label="用户名称" width="120" />
|
||||
<el-table-column prop="mobile" label="手机号" />
|
||||
<el-table-column prop="roleId" label="角色ID" width="80" />
|
||||
</el-table>
|
||||
|
||||
<!-- 分页器 -->
|
||||
@@ -28,7 +32,7 @@
|
||||
v-model:current-page="pagination.currentPage"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="roleList.length"
|
||||
:total="userList.length"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@@ -43,13 +47,16 @@
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
{{ currentRole ? `${currentRole.name} - 菜单访问权限` : '请选择角色' }}
|
||||
{{ currentUser ? `${currentUser.name} - 菜单访问权限` : '请选择用户' }}
|
||||
</span>
|
||||
<el-tag v-if="currentUser" type="success" size="small" style="margin-right: 10px">
|
||||
用户ID: {{ currentUser.id }}
|
||||
</el-tag>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleSaveMenuPermissions"
|
||||
:disabled="!currentRole"
|
||||
:disabled="!currentUser"
|
||||
:loading="saveLoading"
|
||||
>
|
||||
保存菜单权限
|
||||
@@ -58,23 +65,42 @@
|
||||
type="success"
|
||||
size="small"
|
||||
@click="handleQuickAssignAll"
|
||||
:disabled="!currentRole"
|
||||
:disabled="!currentUser"
|
||||
:loading="quickAssignLoading"
|
||||
style="margin-left: 10px"
|
||||
>
|
||||
一键分配全部权限
|
||||
一键分配全部菜单权限
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleClearUserPermissions"
|
||||
:disabled="!currentUser"
|
||||
:loading="clearLoading"
|
||||
style="margin-left: 10px"
|
||||
>
|
||||
清空用户权限
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-if="currentRole" v-loading="permissionLoading">
|
||||
<div v-if="currentUser" v-loading="permissionLoading">
|
||||
<el-alert
|
||||
title="提示"
|
||||
title="用户专属菜单权限管理"
|
||||
type="info"
|
||||
:closable="false"
|
||||
style="margin-bottom: 20px"
|
||||
>
|
||||
勾选菜单和按钮后,该用户登录系统时可以访问这些菜单页面和执行相应的操作
|
||||
<template #default>
|
||||
<div>
|
||||
<p><strong>当前系统使用基于用户的菜单权限管理</strong></p>
|
||||
<p>• 修改菜单权限只影响当前选择的用户</p>
|
||||
<p>• 当前用户: <strong>{{ currentUser.name }}</strong> (ID: {{ currentUser.id }})</p>
|
||||
<p>• 角色ID: <strong>{{ currentUser.roleId }}</strong></p>
|
||||
<p>• 勾选菜单后,该用户可以访问相应的菜单页面</p>
|
||||
<p>• 按钮权限请在"操作权限管理"页面中设置</p>
|
||||
</div>
|
||||
</template>
|
||||
</el-alert>
|
||||
|
||||
<el-tree
|
||||
@@ -137,15 +163,17 @@ import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import {
|
||||
getUserList,
|
||||
getMenuTree,
|
||||
getRoleMenuIds,
|
||||
assignRoleMenus,
|
||||
getUserMenuIds,
|
||||
assignUserMenus,
|
||||
clearUserMenus,
|
||||
getMenuList,
|
||||
} from '@/api/permission.js';
|
||||
import usePermissionStore from '@/store/permission.js';
|
||||
|
||||
// 角色相关数据
|
||||
const roleLoading = ref(false);
|
||||
const roleList = ref([]);
|
||||
const currentRole = ref(null);
|
||||
// 用户相关数据
|
||||
const userLoading = ref(false);
|
||||
const userList = ref([]);
|
||||
const currentUser = ref(null);
|
||||
|
||||
// 分页数据
|
||||
const pagination = reactive({
|
||||
@@ -154,16 +182,17 @@ const pagination = reactive({
|
||||
});
|
||||
|
||||
// 计算分页后的用户列表
|
||||
const paginatedRoleList = computed(() => {
|
||||
const paginatedUserList = computed(() => {
|
||||
const start = (pagination.currentPage - 1) * pagination.pageSize;
|
||||
const end = start + pagination.pageSize;
|
||||
return roleList.value.slice(start, end);
|
||||
return userList.value.slice(start, end);
|
||||
});
|
||||
|
||||
// 权限相关数据
|
||||
const permissionLoading = ref(false);
|
||||
const saveLoading = ref(false);
|
||||
const quickAssignLoading = ref(false);
|
||||
const clearLoading = ref(false);
|
||||
const menuTree = ref([]);
|
||||
const menuTreeRef = ref(null);
|
||||
const checkedMenuIds = ref([]);
|
||||
@@ -174,42 +203,48 @@ const treeProps = {
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
loadRoleList();
|
||||
loadUserList();
|
||||
});
|
||||
|
||||
// 加载用户列表
|
||||
const loadRoleList = async () => {
|
||||
roleLoading.value = true;
|
||||
const loadUserList = async () => {
|
||||
userLoading.value = true;
|
||||
try {
|
||||
const res = await getUserList();
|
||||
if (res.code === 200) {
|
||||
roleList.value = res.data || [];
|
||||
userList.value = res.data || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载用户列表失败:', error);
|
||||
ElMessage.error('加载用户列表失败');
|
||||
} finally {
|
||||
roleLoading.value = false;
|
||||
userLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 角色选择改变
|
||||
const handleRoleChange = async (row) => {
|
||||
// 用户选择改变
|
||||
const handleUserChange = async (row) => {
|
||||
if (!row) return;
|
||||
|
||||
currentRole.value = row;
|
||||
console.log('=== 菜单权限管理 - 用户选择改变 ===');
|
||||
console.log('选择的用户:', row);
|
||||
console.log('用户ID:', row.id);
|
||||
|
||||
currentUser.value = row;
|
||||
await loadMenuTree();
|
||||
await loadRoleMenus(row.roleId);
|
||||
await loadUserMenus(row.id);
|
||||
};
|
||||
|
||||
// 加载菜单树(显示所有菜单,包括菜单和按钮)
|
||||
// 加载菜单树(只显示菜单,不显示按钮)
|
||||
const loadMenuTree = async () => {
|
||||
permissionLoading.value = true;
|
||||
try {
|
||||
const res = await getMenuTree();
|
||||
if (res.code === 200) {
|
||||
// 显示所有菜单和按钮,不进行过滤
|
||||
menuTree.value = res.data || [];
|
||||
// 过滤掉按钮权限(type=2),只保留菜单(type=0,1)
|
||||
const filteredTree = filterMenuTree(res.data || []);
|
||||
menuTree.value = filteredTree;
|
||||
console.log('=== 菜单权限管理 - 过滤后的菜单树 ===', filteredTree);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载菜单树失败:', error);
|
||||
@@ -219,12 +254,42 @@ const loadMenuTree = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 加载角色已分配的菜单
|
||||
const loadRoleMenus = async (roleId) => {
|
||||
// 过滤菜单树,只保留菜单项(type=0,1),移除按钮(type=2)
|
||||
const filterMenuTree = (tree) => {
|
||||
return tree.map(node => {
|
||||
const filteredNode = { ...node };
|
||||
|
||||
// 如果当前节点是按钮(type=2),返回null(会被过滤掉)
|
||||
if (node.type === 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 如果有子节点,递归过滤
|
||||
if (node.children && node.children.length > 0) {
|
||||
const filteredChildren = filterMenuTree(node.children).filter(child => child !== null);
|
||||
filteredNode.children = filteredChildren;
|
||||
}
|
||||
|
||||
return filteredNode;
|
||||
}).filter(node => node !== null);
|
||||
};
|
||||
|
||||
// 加载用户已分配的菜单(只加载菜单权限,不加载按钮权限)
|
||||
const loadUserMenus = async (userId) => {
|
||||
try {
|
||||
const res = await getRoleMenuIds(roleId);
|
||||
const res = await getUserMenuIds(userId);
|
||||
if (res.code === 200) {
|
||||
checkedMenuIds.value = res.data || [];
|
||||
const allMenuIds = res.data || [];
|
||||
|
||||
// 过滤掉按钮权限,只保留菜单权限
|
||||
const menuOnlyIds = await filterMenuOnlyIds(allMenuIds);
|
||||
checkedMenuIds.value = menuOnlyIds;
|
||||
|
||||
console.log('=== 菜单权限管理 - 过滤后的菜单权限 ===', {
|
||||
userId: userId,
|
||||
allMenuIds: allMenuIds,
|
||||
menuOnlyIds: menuOnlyIds
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
if (menuTreeRef.value) {
|
||||
@@ -232,8 +297,33 @@ const loadRoleMenus = async (roleId) => {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载角色菜单失败:', error);
|
||||
ElMessage.error('加载角色菜单失败');
|
||||
console.error('加载用户菜单失败:', error);
|
||||
ElMessage.error('加载用户菜单失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 过滤菜单ID列表,只保留菜单项(type=0,1),移除按钮(type=2)
|
||||
const filterMenuOnlyIds = async (menuIds) => {
|
||||
try {
|
||||
// 获取所有菜单信息
|
||||
const menuListRes = await getMenuList();
|
||||
if (menuListRes.code !== 200) {
|
||||
return menuIds; // 如果获取失败,返回原始列表
|
||||
}
|
||||
|
||||
const allMenus = menuListRes.data || [];
|
||||
const menuMap = new Map(allMenus.map(menu => [menu.id, menu]));
|
||||
|
||||
// 过滤掉按钮权限
|
||||
const menuOnlyIds = menuIds.filter(id => {
|
||||
const menu = menuMap.get(id);
|
||||
return menu && menu.type !== 2; // 只保留菜单项(type=0,1)
|
||||
});
|
||||
|
||||
return menuOnlyIds;
|
||||
} catch (error) {
|
||||
console.error('过滤菜单权限失败:', error);
|
||||
return menuIds; // 如果过滤失败,返回原始列表
|
||||
}
|
||||
};
|
||||
|
||||
@@ -247,27 +337,64 @@ const handleCurrentChange = (page) => {
|
||||
pagination.currentPage = page;
|
||||
};
|
||||
|
||||
// 保存菜单权限
|
||||
// 保存菜单权限(只保存菜单权限,不保存按钮权限)
|
||||
const handleSaveMenuPermissions = async () => {
|
||||
if (!currentRole.value) {
|
||||
if (!currentUser.value) {
|
||||
ElMessage.warning('请先选择用户');
|
||||
return;
|
||||
}
|
||||
|
||||
// 确认对话框,让用户明确知道影响范围
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`您即将为用户 ${currentUser.value.name} (ID: ${currentUser.value.id}) 设置菜单权限。\n\n这将只影响当前选择的用户。\n\n确定要继续吗?`,
|
||||
'确认菜单权限修改',
|
||||
{
|
||||
confirmButtonText: '确定修改',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
dangerouslyUseHTMLString: false
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
// 用户取消操作
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取选中的节点(包括半选中的父节点)
|
||||
const checkedKeys = menuTreeRef.value.getCheckedKeys();
|
||||
const halfCheckedKeys = menuTreeRef.value.getHalfCheckedKeys();
|
||||
const allKeys = [...checkedKeys, ...halfCheckedKeys];
|
||||
|
||||
// 过滤掉按钮权限,只保留菜单权限
|
||||
const menuOnlyIds = await filterMenuOnlyIds(allKeys);
|
||||
|
||||
console.log('=== 保存菜单权限 ===', {
|
||||
user: currentUser.value,
|
||||
allKeys: allKeys,
|
||||
menuOnlyIds: menuOnlyIds
|
||||
});
|
||||
|
||||
saveLoading.value = true;
|
||||
try {
|
||||
const res = await assignRoleMenus({
|
||||
roleId: currentRole.value.roleId,
|
||||
menuIds: allKeys,
|
||||
const res = await assignUserMenus({
|
||||
userId: currentUser.value.id,
|
||||
menuIds: menuOnlyIds, // 只保存菜单权限
|
||||
});
|
||||
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('菜单权限保存成功');
|
||||
ElMessage.success(`用户 ${currentUser.value.name} 的菜单权限保存成功,共保存 ${menuOnlyIds.length} 个菜单权限。`);
|
||||
|
||||
// 权限保存成功后,刷新权限数据
|
||||
try {
|
||||
const permissionStore = usePermissionStore();
|
||||
await permissionStore.refreshPermissions();
|
||||
ElMessage.success('权限已保存并刷新成功!');
|
||||
console.log('权限数据已刷新');
|
||||
} catch (error) {
|
||||
console.error('刷新权限失败:', error);
|
||||
ElMessage.warning('权限已保存,但刷新失败,请手动刷新页面');
|
||||
}
|
||||
} else {
|
||||
ElMessage.error(res.msg || '保存失败');
|
||||
}
|
||||
@@ -279,9 +406,9 @@ const handleSaveMenuPermissions = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 一键分配全部权限
|
||||
// 一键分配全部菜单权限(只分配菜单权限,不分配按钮权限)
|
||||
const handleQuickAssignAll = async () => {
|
||||
if (!currentRole.value) {
|
||||
if (!currentUser.value) {
|
||||
ElMessage.warning('请先选择用户');
|
||||
return;
|
||||
}
|
||||
@@ -289,10 +416,10 @@ const handleQuickAssignAll = async () => {
|
||||
try {
|
||||
// 确认操作
|
||||
const confirmed = await ElMessageBox.confirm(
|
||||
`确定要为用户 ${currentRole.value.name} (${currentRole.value.mobile}) 分配所有菜单权限吗?`,
|
||||
'确认分配权限',
|
||||
`您即将为用户 ${currentUser.value.name} (ID: ${currentUser.value.id}) 分配所有菜单权限。\n\n这将只影响当前选择的用户。\n\n注意:此操作只分配菜单权限,按钮权限请在"操作权限管理"页面中设置。`,
|
||||
'确认分配菜单权限',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
confirmButtonText: '确定分配',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
@@ -311,38 +438,111 @@ const handleQuickAssignAll = async () => {
|
||||
}
|
||||
|
||||
const allMenus = menuListRes.data || [];
|
||||
const allMenuIds = allMenus.map(menu => menu.id);
|
||||
|
||||
// 过滤掉按钮权限,只保留菜单权限
|
||||
const menuOnlyMenus = allMenus.filter(menu => menu.type !== 2);
|
||||
const menuOnlyIds = menuOnlyMenus.map(menu => menu.id);
|
||||
|
||||
console.log('=== 一键分配全部权限 ===', {
|
||||
user: currentRole.value,
|
||||
console.log('=== 一键分配全部菜单权限 ===', {
|
||||
user: currentUser.value,
|
||||
totalMenus: allMenus.length,
|
||||
menuIds: allMenuIds
|
||||
menuOnlyMenus: menuOnlyMenus.length,
|
||||
menuOnlyIds: menuOnlyIds
|
||||
});
|
||||
|
||||
// 分配所有菜单权限
|
||||
const res = await assignRoleMenus({
|
||||
roleId: currentRole.value.roleId,
|
||||
menuIds: allMenuIds,
|
||||
const res = await assignUserMenus({
|
||||
userId: currentUser.value.id,
|
||||
menuIds: menuOnlyIds,
|
||||
});
|
||||
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(`成功为用户 ${currentRole.value.name} 分配了 ${allMenuIds.length} 个菜单权限`);
|
||||
ElMessage.success(`成功为用户 ${currentUser.value.name} 分配了 ${menuOnlyIds.length} 个菜单权限。`);
|
||||
|
||||
// 重新加载权限显示
|
||||
await loadRoleMenus(currentRole.value.roleId);
|
||||
await loadUserMenus(currentUser.value.id);
|
||||
|
||||
// 权限保存成功后,刷新权限数据
|
||||
try {
|
||||
const permissionStore = usePermissionStore();
|
||||
await permissionStore.refreshPermissions();
|
||||
ElMessage.success('权限已保存并刷新成功!');
|
||||
console.log('权限数据已刷新');
|
||||
} catch (error) {
|
||||
console.error('刷新权限失败:', error);
|
||||
ElMessage.warning('权限已保存,但刷新失败,请手动刷新页面');
|
||||
}
|
||||
} else {
|
||||
ElMessage.error(res.msg || '分配失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('一键分配权限失败:', error);
|
||||
console.error('一键分配菜单权限失败:', error);
|
||||
ElMessage.error(`分配失败: ${error.message || error}`);
|
||||
}
|
||||
} finally {
|
||||
quickAssignLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 清空用户权限
|
||||
const handleClearUserPermissions = async () => {
|
||||
if (!currentUser.value) {
|
||||
ElMessage.warning('请先选择用户');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 确认操作
|
||||
const confirmed = await ElMessageBox.confirm(
|
||||
`您即将清空用户 ${currentUser.value.name} (ID: ${currentUser.value.id}) 的所有权限。\n\n清空后,该用户将无法访问任何菜单。\n\n确定要继续吗?`,
|
||||
'确认清空用户权限',
|
||||
{
|
||||
confirmButtonText: '确定清空',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
);
|
||||
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearLoading.value = true;
|
||||
|
||||
// 清空用户权限
|
||||
const res = await clearUserMenus(currentUser.value.id);
|
||||
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(`用户 ${currentUser.value.name} 的权限已清空!`);
|
||||
|
||||
// 重新加载权限显示
|
||||
await loadUserMenus(currentUser.value.id);
|
||||
|
||||
// 权限清空后,刷新权限数据
|
||||
try {
|
||||
const permissionStore = usePermissionStore();
|
||||
await permissionStore.refreshPermissions();
|
||||
ElMessage.success('权限已清空并刷新成功!');
|
||||
console.log('权限数据已刷新');
|
||||
} catch (error) {
|
||||
console.error('刷新权限失败:', error);
|
||||
ElMessage.warning('权限已清空,但刷新失败,请手动刷新页面');
|
||||
}
|
||||
} else {
|
||||
ElMessage.error(res.msg || '清空失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('清空用户权限失败:', error);
|
||||
ElMessage.error(`清空失败: ${error.message || error}`);
|
||||
}
|
||||
} finally {
|
||||
clearLoading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -350,7 +550,7 @@ const handleQuickAssignAll = async () => {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.role-card,
|
||||
.user-card,
|
||||
.permission-card {
|
||||
border-radius: 8px;
|
||||
min-height: 600px;
|
||||
|
||||
@@ -3,23 +3,27 @@
|
||||
<el-row :gutter="20">
|
||||
<!-- 左侧:用户列表 -->
|
||||
<el-col :span="8">
|
||||
<el-card class="role-card">
|
||||
<el-card class="user-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">用户列表</span>
|
||||
<el-tag type="success" size="small" style="margin-left: 10px;">
|
||||
用户专属权限
|
||||
</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table
|
||||
:data="paginatedRoleList"
|
||||
:data="paginatedUserList"
|
||||
highlight-current-row
|
||||
@current-change="handleRoleChange"
|
||||
v-loading="roleLoading"
|
||||
@current-change="handleUserChange"
|
||||
v-loading="userLoading"
|
||||
style="width: 100%"
|
||||
max-height="500"
|
||||
>
|
||||
<el-table-column prop="name" label="用户名称" width="120" />
|
||||
<el-table-column prop="mobile" label="手机号" />
|
||||
<el-table-column prop="roleId" label="角色ID" width="80" />
|
||||
</el-table>
|
||||
|
||||
<!-- 分页器 -->
|
||||
@@ -28,7 +32,7 @@
|
||||
v-model:current-page="pagination.currentPage"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="roleList.length"
|
||||
:total="userList.length"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@@ -37,39 +41,62 @@
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- 右侧:操作权限分配 -->
|
||||
<!-- 右侧:用户权限分配 -->
|
||||
<el-col :span="16">
|
||||
<el-card class="permission-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
{{ currentRole ? `${currentRole.name} - 操作权限分配` : '请选择角色' }}
|
||||
{{ currentUser ? `${currentUser.name} - 操作权限分配` : '请选择用户' }}
|
||||
</span>
|
||||
<el-tag type="success" size="small" style="margin-left: 10px;">
|
||||
用户ID: {{ currentUser ? currentUser.id : '-' }}
|
||||
</el-tag>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
v-hasPermi="['permission:operation:assign']"
|
||||
@click="handleSavePermissions"
|
||||
:disabled="!currentRole"
|
||||
@click="handleSaveUserPermissions"
|
||||
:disabled="!currentUser"
|
||||
:loading="saveLoading"
|
||||
style="margin-left: 10px;"
|
||||
>
|
||||
保存操作权限
|
||||
保存用户权限
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
v-hasPermi="['permission:operation:assign']"
|
||||
@click="handleClearUserPermissions"
|
||||
:disabled="!currentUser"
|
||||
:loading="clearLoading"
|
||||
style="margin-left: 10px;"
|
||||
>
|
||||
清空用户权限
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-if="currentRole" v-loading="permissionLoading">
|
||||
<div v-if="currentUser" v-loading="permissionLoading">
|
||||
<el-alert
|
||||
title="提示"
|
||||
title="用户专属操作权限管理"
|
||||
type="info"
|
||||
:closable="false"
|
||||
style="margin-bottom: 20px"
|
||||
>
|
||||
勾选操作权限后,该角色可以执行相应的按钮操作(新增、编辑、删除等)
|
||||
<template #default>
|
||||
<div>
|
||||
<p><strong>当前系统使用基于用户的操作权限管理</strong></p>
|
||||
<p>• 修改权限只影响当前选择的用户</p>
|
||||
<p>• 当前用户: <strong>{{ currentUser.name }}</strong> (ID: {{ currentUser.id }})</p>
|
||||
<p>• 角色ID: <strong>{{ currentUser.roleId }}</strong></p>
|
||||
<p>• 勾选操作权限后,该用户可以执行相应的按钮操作(新增、编辑、删除等)</p>
|
||||
</div>
|
||||
</template>
|
||||
</el-alert>
|
||||
|
||||
<el-tree
|
||||
ref="permissionTreeRef"
|
||||
ref="userPermissionTreeRef"
|
||||
:data="permissionTree"
|
||||
show-checkbox
|
||||
node-key="id"
|
||||
@@ -82,39 +109,11 @@
|
||||
<el-icon v-if="data.icon" style="margin-right: 5px">
|
||||
<component :is="data.icon" />
|
||||
</el-icon>
|
||||
<span>{{ node.label }}</span>
|
||||
<el-tag
|
||||
v-if="data.type === 1"
|
||||
type="info"
|
||||
size="small"
|
||||
style="margin-left: 10px"
|
||||
>
|
||||
菜单
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="data.type === 2"
|
||||
type="warning"
|
||||
size="small"
|
||||
style="margin-left: 10px"
|
||||
>
|
||||
按钮
|
||||
</el-tag>
|
||||
<span
|
||||
v-if="data.authority"
|
||||
style="margin-left: 10px; color: #999; font-size: 12px"
|
||||
>
|
||||
{{ data.authority }}
|
||||
</span>
|
||||
<span>{{ data.label }}</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
|
||||
<el-empty
|
||||
v-else
|
||||
description="请从左侧选择一个角色,为其分配操作权限"
|
||||
:image-size="100"
|
||||
/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -123,18 +122,20 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, nextTick, computed } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import {
|
||||
getUserList,
|
||||
getMenuTree,
|
||||
getRoleMenuIds,
|
||||
assignRoleMenus,
|
||||
getUserMenuIds,
|
||||
assignUserMenus,
|
||||
clearUserMenus,
|
||||
} from '@/api/permission.js';
|
||||
import usePermissionStore from '@/store/permission.js';
|
||||
|
||||
// 用户相关数据
|
||||
const roleLoading = ref(false);
|
||||
const roleList = ref([]);
|
||||
const currentRole = ref(null);
|
||||
const userLoading = ref(false);
|
||||
const userList = ref([]);
|
||||
const currentUser = ref(null);
|
||||
|
||||
// 分页数据
|
||||
const pagination = reactive({
|
||||
@@ -143,18 +144,18 @@ const pagination = reactive({
|
||||
});
|
||||
|
||||
// 计算分页后的用户列表
|
||||
const paginatedRoleList = computed(() => {
|
||||
const paginatedUserList = computed(() => {
|
||||
const start = (pagination.currentPage - 1) * pagination.pageSize;
|
||||
const end = start + pagination.pageSize;
|
||||
return roleList.value.slice(start, end);
|
||||
return userList.value.slice(start, end);
|
||||
});
|
||||
|
||||
// 权限相关数据
|
||||
const permissionLoading = ref(false);
|
||||
const saveLoading = ref(false);
|
||||
const clearLoading = ref(false);
|
||||
const permissionTree = ref([]);
|
||||
const permissionTreeRef = ref(null);
|
||||
const checkedPermissionIds = ref([]);
|
||||
const userPermissionTreeRef = ref(null);
|
||||
const treeProps = {
|
||||
children: 'children',
|
||||
label: 'label',
|
||||
@@ -162,46 +163,194 @@ const treeProps = {
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
loadRoleList();
|
||||
loadUserList();
|
||||
});
|
||||
|
||||
// 加载用户列表
|
||||
const loadRoleList = async () => {
|
||||
roleLoading.value = true;
|
||||
const loadUserList = async () => {
|
||||
userLoading.value = true;
|
||||
try {
|
||||
const res = await getUserList();
|
||||
if (res.code === 200) {
|
||||
roleList.value = res.data || [];
|
||||
userList.value = res.data || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载用户列表失败:', error);
|
||||
ElMessage.error('加载用户列表失败');
|
||||
} finally {
|
||||
roleLoading.value = false;
|
||||
userLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 角色选择改变
|
||||
const handleRoleChange = async (row) => {
|
||||
// 用户选择改变
|
||||
const handleUserChange = async (row) => {
|
||||
if (!row) return;
|
||||
|
||||
console.log('=== 用户选择改变 ===');
|
||||
console.log('=== 操作权限管理 - 用户选择改变 ===');
|
||||
console.log('选择的用户:', row);
|
||||
console.log('用户roleId:', row.roleId);
|
||||
console.log('用户ID:', row.id);
|
||||
|
||||
currentRole.value = row;
|
||||
currentUser.value = row;
|
||||
await loadPermissionTree();
|
||||
await loadRolePermissions(row.roleId);
|
||||
await loadUserPermissions(row.id);
|
||||
};
|
||||
|
||||
// 分页处理
|
||||
const handleSizeChange = (size) => {
|
||||
pagination.pageSize = size;
|
||||
pagination.currentPage = 1;
|
||||
// 加载用户已分配的权限
|
||||
const loadUserPermissions = async (userId) => {
|
||||
console.log('=== 加载用户权限 ===');
|
||||
console.log('userId:', userId);
|
||||
|
||||
try {
|
||||
const res = await getUserMenuIds(userId);
|
||||
console.log('用户权限API响应:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
const menuIds = res.data || [];
|
||||
console.log('已分配的用户权限IDs:', menuIds);
|
||||
|
||||
// 设置权限树选中状态
|
||||
await nextTick();
|
||||
if (userPermissionTreeRef.value) {
|
||||
userPermissionTreeRef.value.setCheckedKeys(menuIds);
|
||||
console.log('用户权限树已设置选中状态');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载用户权限失败:', error);
|
||||
ElMessage.error('加载用户权限失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCurrentChange = (page) => {
|
||||
pagination.currentPage = page;
|
||||
// 保存用户权限
|
||||
const handleSaveUserPermissions = async () => {
|
||||
if (!currentUser.value) {
|
||||
ElMessage.warning('请先选择用户');
|
||||
return;
|
||||
}
|
||||
|
||||
// 确认对话框
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`您即将为用户 ${currentUser.value.name} (ID: ${currentUser.value.id}) 设置操作权限。\n\n这将只影响当前选择的用户。\n\n确定要继续吗?`,
|
||||
'确认用户权限修改',
|
||||
{
|
||||
confirmButtonText: '确定修改',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
dangerouslyUseHTMLString: false
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('=== 保存用户权限 ===');
|
||||
console.log('当前用户:', currentUser.value);
|
||||
|
||||
// 获取选中的节点
|
||||
const checkedKeys = userPermissionTreeRef.value.getCheckedKeys();
|
||||
const halfCheckedKeys = userPermissionTreeRef.value.getHalfCheckedKeys();
|
||||
const allKeys = [...checkedKeys, ...halfCheckedKeys];
|
||||
|
||||
console.log('选中的权限IDs:', checkedKeys);
|
||||
console.log('半选中的权限IDs:', halfCheckedKeys);
|
||||
console.log('所有权限IDs:', allKeys);
|
||||
|
||||
const saveData = {
|
||||
userId: currentUser.value.id,
|
||||
menuIds: allKeys,
|
||||
};
|
||||
console.log('保存数据:', saveData);
|
||||
|
||||
saveLoading.value = true;
|
||||
try {
|
||||
const res = await assignUserMenus(saveData);
|
||||
console.log('保存API响应:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(`用户 ${currentUser.value.name} 的操作权限保存成功!`);
|
||||
console.log('用户权限保存成功');
|
||||
|
||||
// 权限保存成功后,刷新权限数据
|
||||
try {
|
||||
const permissionStore = usePermissionStore();
|
||||
await permissionStore.refreshPermissions();
|
||||
ElMessage.success('权限已保存并刷新成功!');
|
||||
console.log('权限数据已刷新');
|
||||
} catch (error) {
|
||||
console.error('刷新权限失败:', error);
|
||||
ElMessage.warning('权限已保存,但刷新失败,请手动刷新页面');
|
||||
}
|
||||
} else {
|
||||
ElMessage.error(res.msg || '保存失败');
|
||||
console.error('用户权限保存失败:', res);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存用户权限失败:', error);
|
||||
ElMessage.error('保存失败');
|
||||
} finally {
|
||||
saveLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 清空用户权限
|
||||
const handleClearUserPermissions = async () => {
|
||||
if (!currentUser.value) {
|
||||
ElMessage.warning('请先选择用户');
|
||||
return;
|
||||
}
|
||||
|
||||
// 确认对话框
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`您即将清空用户 ${currentUser.value.name} (ID: ${currentUser.value.id}) 的所有权限。\n\n清空后,该用户将无法执行任何操作。\n\n确定要继续吗?`,
|
||||
'确认清空用户权限',
|
||||
{
|
||||
confirmButtonText: '确定清空',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
dangerouslyUseHTMLString: false
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('=== 清空用户权限 ===');
|
||||
console.log('当前用户:', currentUser.value);
|
||||
|
||||
clearLoading.value = true;
|
||||
try {
|
||||
const res = await clearUserMenus(currentUser.value.id);
|
||||
console.log('清空API响应:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(`用户 ${currentUser.value.name} 的权限已清空!`);
|
||||
console.log('用户权限清空成功');
|
||||
|
||||
// 重新加载用户权限(显示空权限)
|
||||
await loadUserPermissions(currentUser.value.id);
|
||||
|
||||
// 权限清空后,刷新权限数据
|
||||
try {
|
||||
const permissionStore = usePermissionStore();
|
||||
await permissionStore.refreshPermissions();
|
||||
ElMessage.success('权限已清空并刷新成功!');
|
||||
console.log('权限数据已刷新');
|
||||
} catch (error) {
|
||||
console.error('刷新权限失败:', error);
|
||||
ElMessage.warning('权限已清空,但刷新失败,请手动刷新页面');
|
||||
}
|
||||
} else {
|
||||
ElMessage.error(res.msg || '清空失败');
|
||||
console.error('用户权限清空失败:', res);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('清空用户权限失败:', error);
|
||||
ElMessage.error('清空失败');
|
||||
} finally {
|
||||
clearLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 加载权限树(包含所有菜单和按钮)
|
||||
@@ -220,88 +369,14 @@ const loadPermissionTree = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 加载角色已分配的权限
|
||||
const loadRolePermissions = async (roleId) => {
|
||||
console.log('=== 加载角色权限 ===');
|
||||
console.log('roleId:', roleId);
|
||||
|
||||
try {
|
||||
const res = await getRoleMenuIds(roleId);
|
||||
console.log('权限API响应:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
checkedPermissionIds.value = res.data || [];
|
||||
console.log('已分配的权限IDs:', checkedPermissionIds.value);
|
||||
|
||||
await nextTick();
|
||||
if (permissionTreeRef.value) {
|
||||
permissionTreeRef.value.setCheckedKeys(checkedPermissionIds.value);
|
||||
console.log('权限树已设置选中状态');
|
||||
|
||||
// 验证权限树的实际选中状态
|
||||
setTimeout(() => {
|
||||
const actualCheckedKeys = permissionTreeRef.value.getCheckedKeys();
|
||||
const actualHalfCheckedKeys = permissionTreeRef.value.getHalfCheckedKeys();
|
||||
console.log('=== 权限树实际选中状态验证 ===');
|
||||
console.log('实际选中的权限IDs:', actualCheckedKeys);
|
||||
console.log('实际半选中的权限IDs:', actualHalfCheckedKeys);
|
||||
console.log('期望的权限IDs:', checkedPermissionIds.value);
|
||||
console.log('选中状态是否一致:', JSON.stringify(actualCheckedKeys.sort()) === JSON.stringify(checkedPermissionIds.value.sort()));
|
||||
}, 100);
|
||||
}
|
||||
} else {
|
||||
console.error('权限API返回错误:', res);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载角色权限失败:', error);
|
||||
ElMessage.error('加载角色权限失败');
|
||||
}
|
||||
// 分页处理
|
||||
const handleSizeChange = (size) => {
|
||||
pagination.pageSize = size;
|
||||
pagination.currentPage = 1;
|
||||
};
|
||||
|
||||
// 保存操作权限
|
||||
const handleSavePermissions = async () => {
|
||||
if (!currentRole.value) {
|
||||
ElMessage.warning('请先选择用户');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('=== 保存操作权限 ===');
|
||||
console.log('当前用户:', currentRole.value);
|
||||
console.log('用户roleId:', currentRole.value.roleId);
|
||||
|
||||
// 获取选中的节点(包括半选中的父节点)
|
||||
const checkedKeys = permissionTreeRef.value.getCheckedKeys();
|
||||
const halfCheckedKeys = permissionTreeRef.value.getHalfCheckedKeys();
|
||||
const allKeys = [...checkedKeys, ...halfCheckedKeys];
|
||||
|
||||
console.log('选中的权限IDs:', checkedKeys);
|
||||
console.log('半选中的权限IDs:', halfCheckedKeys);
|
||||
console.log('所有权限IDs:', allKeys);
|
||||
|
||||
const saveData = {
|
||||
roleId: currentRole.value.roleId,
|
||||
menuIds: allKeys,
|
||||
};
|
||||
console.log('保存数据:', saveData);
|
||||
|
||||
saveLoading.value = true;
|
||||
try {
|
||||
const res = await assignRoleMenus(saveData);
|
||||
console.log('保存API响应:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('操作权限保存成功');
|
||||
console.log('权限保存成功');
|
||||
} else {
|
||||
ElMessage.error(res.msg || '保存失败');
|
||||
console.error('权限保存失败:', res);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存操作权限失败:', error);
|
||||
ElMessage.error('保存失败');
|
||||
} finally {
|
||||
saveLoading.value = false;
|
||||
}
|
||||
const handleCurrentChange = (page) => {
|
||||
pagination.currentPage = page;
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -310,30 +385,24 @@ const handleSavePermissions = async () => {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.role-card,
|
||||
.permission-card {
|
||||
border-radius: 8px;
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.tree-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
:deep(.el-tree-node__content) {
|
||||
height: 36px;
|
||||
.user-card,
|
||||
.permission-card {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
Reference in New Issue
Block a user