物联网问题解决,只差最后测试完善

This commit is contained in:
xuqiuyun
2025-10-23 17:28:06 +08:00
parent 0249dfc5bb
commit ecccd025d1
72 changed files with 7372 additions and 653 deletions

View File

@@ -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;