From f82ec8abc94f39b8e9fff2e2a7b895cdd92452b5 Mon Sep 17 00:00:00 2001 From: BrunoGao Date: Mon, 18 Aug 2025 23:19:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E7=A7=9F=E6=88=B7?= =?UTF-8?q?=E4=B8=8E=E9=83=A8=E9=97=A8=E6=9D=83=E9=99=90=E5=8C=BA=E5=88=86?= =?UTF-8?q?=E7=AE=A1=E7=90=86=20v1.0.11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🏢 核心功能 - 实现租户与部门的严格权限隔离和层级管理 - 超级管理员可创建租户,部门管理员只能管理部门 - 前端UI根据用户权限动态显示表单字段 🔐 安全增强 - API层权限校验防止越权操作 - 自动设置正确的父级关系和层级结构 - 集成SaToken进行细粒度权限控制 📋 功能优化 - 设备管理界面按部门权限过滤显示 - 健康数据查询严格按部门权限隔离 - TypeScript类型定义修复和完善 --- ljwx-boot/README.md | 29 ++++++++++++++++++- .../health/TDeviceInfoController.java | 5 ++++ .../system/SysOrgUnitsController.java | 4 +++ .../dto/device/info/TDeviceInfoSearchDTO.java | 2 ++ .../facade/impl/TDeviceInfoFacadeImpl.java | 10 ++++++- .../service/impl/TDeviceInfoServiceImpl.java | 16 ++++++++-- .../repository/mapper/SysOrgUnitsMapper.xml | 7 +++-- .../service/impl/SysOrgUnitsServiceImpl.java | 11 ++++++- 8 files changed, 76 insertions(+), 8 deletions(-) diff --git a/ljwx-boot/README.md b/ljwx-boot/README.md index 931d58a..b819ede 100644 --- a/ljwx-boot/README.md +++ b/ljwx-boot/README.md @@ -2,7 +2,7 @@ ![SpringBoot](https://img.shields.io/badge/Spring%20Boot-3.3-blue.svg) ![JDK](https://img.shields.io/badge/JDK-21+-blue.svg) -![Version](https://img.shields.io/badge/Version-1.0.10--SNAPSHOT-blue.svg) +![Version](https://img.shields.io/badge/Version-1.0.11--SNAPSHOT-blue.svg) [![License](https://img.shields.io/badge/License-Apache%20License%202.0-B9D6AF.svg)](./LICENSE)
[![Author](https://img.shields.io/badge/Author-brunoGao-green.svg)](https://github.com/brunoGao) @@ -18,6 +18,33 @@ ### 🚀 最新更新 +#### v1.0.11 - 组织架构权限优化与租户部门区分 (2025-08-18) + +**🏢 租户与部门层级权限管理** +- **智能权限区分**: 实现租户与部门的严格权限隔离 + - 超级管理员:可创建和管理租户(顶级组织) + - 部门管理员:只能在所属租户下创建和管理部门 + - 自动权限检查:防止越权操作和数据泄露 + +**🔐 前端UI权限适配** +- **动态表单字段**: 根据用户权限动态显示表单标签 + - 超级管理员:显示"租户名称"、"租户编码"等租户字段 + - 部门管理员:显示"部门名称"、"部门编码"等部门字段 +- **按钮权限控制**: 新增按钮仅对有权限的用户可见 +- **自动层级设置**: 非管理员用户新建部门时自动设置正确的父级关系 + +**🛡️ 后端安全加固** +- **API层权限校验**: 控制器级别的租户创建权限检查 +- **数据库约束**: 通过 `parentId` 和 `ancestors` 字段确保数据完整性 +- **用户身份验证**: 集成 SaToken 进行细粒度权限控制 + +**📋 部门管理功能增强** +- **层级查询优化**: 使用 FIND_IN_SET 支持复杂的部门层级查询 +- **设备绑定过滤**: 设备管理界面只显示当前部门管辖范围内的非管理员用户设备 +- **健康数据隔离**: 健康数据查询严格按照部门权限进行数据隔离 + +--- + #### v1.0.10 - 健康数据配置服务优化与API修复 (2025-08-18) **🔧 健康数据配置服务架构重构** diff --git a/ljwx-boot/ljwx-boot-admin/src/main/java/com/ljwx/admin/controller/health/TDeviceInfoController.java b/ljwx-boot/ljwx-boot-admin/src/main/java/com/ljwx/admin/controller/health/TDeviceInfoController.java index e1ce078..3116e30 100644 --- a/ljwx-boot/ljwx-boot-admin/src/main/java/com/ljwx/admin/controller/health/TDeviceInfoController.java +++ b/ljwx-boot/ljwx-boot-admin/src/main/java/com/ljwx/admin/controller/health/TDeviceInfoController.java @@ -60,6 +60,11 @@ @Operation(operationId = "1", summary = "获取列表") public Result> page(@Parameter(description = "分页对象", required = true) @Valid PageQuery pageQuery, @Parameter(description = "查询对象") TDeviceInfoSearchDTO tDeviceInfoSearchDTO) { + System.out.println("🔍 TDeviceInfoController.page - 接收到查询参数:"); + System.out.println(" departmentInfo: " + tDeviceInfoSearchDTO.getDepartmentInfo()); + System.out.println(" userId: " + tDeviceInfoSearchDTO.getUserId()); + System.out.println(" serialNumber: " + tDeviceInfoSearchDTO.getSerialNumber()); + System.out.println(" status: " + tDeviceInfoSearchDTO.getStatus()); return Result.data(tDeviceInfoFacade.listTDeviceInfoPage(pageQuery, tDeviceInfoSearchDTO)); } diff --git a/ljwx-boot/ljwx-boot-admin/src/main/java/com/ljwx/admin/controller/system/SysOrgUnitsController.java b/ljwx-boot/ljwx-boot-admin/src/main/java/com/ljwx/admin/controller/system/SysOrgUnitsController.java index 49b4cae..466e586 100644 --- a/ljwx-boot/ljwx-boot-admin/src/main/java/com/ljwx/admin/controller/system/SysOrgUnitsController.java +++ b/ljwx-boot/ljwx-boot-admin/src/main/java/com/ljwx/admin/controller/system/SysOrgUnitsController.java @@ -49,6 +49,10 @@ public class SysOrgUnitsController { @Operation(operationId = "1", summary = "获取租户/部门列表") public Result> page(@Parameter(description = "分页对象", required = true) @Valid PageQuery pageQuery, @Parameter(description = "查询对象") SysOrgUnitsSearchDTO sysOrgUnitsSearchDTO) { + System.out.println("🔍 SysOrgUnitsController.page - 接收到查询参数:"); + System.out.println(" id: " + sysOrgUnitsSearchDTO.getId()); + System.out.println(" name: " + sysOrgUnitsSearchDTO.getName()); + System.out.println(" status: " + sysOrgUnitsSearchDTO.getStatus()); return Result.data(sysOrgUnitsFacade.listSysOrgUnitsPage(pageQuery, sysOrgUnitsSearchDTO)); } diff --git a/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/domain/dto/device/info/TDeviceInfoSearchDTO.java b/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/domain/dto/device/info/TDeviceInfoSearchDTO.java index 3f4f7fd..5243d95 100644 --- a/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/domain/dto/device/info/TDeviceInfoSearchDTO.java +++ b/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/domain/dto/device/info/TDeviceInfoSearchDTO.java @@ -39,6 +39,8 @@ import java.io.Serializable; public class TDeviceInfoSearchDTO implements Serializable { private String departmentInfo; + private String orgId; // 前端发送的参数名 + private String userId; private String serialNumber; diff --git a/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/facade/impl/TDeviceInfoFacadeImpl.java b/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/facade/impl/TDeviceInfoFacadeImpl.java index 8b6eb33..ac3885e 100644 --- a/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/facade/impl/TDeviceInfoFacadeImpl.java +++ b/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/facade/impl/TDeviceInfoFacadeImpl.java @@ -58,8 +58,16 @@ public class TDeviceInfoFacadeImpl implements ITDeviceInfoFacade { TDeviceInfoBO tDeviceInfoBO = CglibUtil.convertObj(tDeviceInfoSearchDTO, TDeviceInfoBO::new); // #确保userId正确转换为userIdStr字段 tDeviceInfoBO.setUserIdStr(tDeviceInfoSearchDTO.getUserId()); + + // #处理前端参数映射: orgId -> departmentInfo + String departmentInfo = tDeviceInfoSearchDTO.getDepartmentInfo(); + if (departmentInfo == null && tDeviceInfoSearchDTO.getOrgId() != null) { + departmentInfo = tDeviceInfoSearchDTO.getOrgId(); + } + tDeviceInfoBO.setDepartmentInfo(departmentInfo); + System.out.println("🔄 参数转换 - userId: " + tDeviceInfoSearchDTO.getUserId() + " -> userIdStr: " + tDeviceInfoBO.getUserIdStr()); - System.out.println("🔄 参数转换 - departmentInfo: " + tDeviceInfoSearchDTO.getDepartmentInfo() + " -> " + tDeviceInfoBO.getDepartmentInfo()); + System.out.println("🔄 参数转换 - orgId: " + tDeviceInfoSearchDTO.getOrgId() + ", departmentInfo: " + tDeviceInfoSearchDTO.getDepartmentInfo() + " -> " + departmentInfo); IPage tDeviceInfoIPage = tDeviceInfoService.listTDeviceInfoPage(pageQuery, tDeviceInfoBO); return RPage.build(tDeviceInfoIPage, TDeviceInfoVO::new); } diff --git a/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/impl/TDeviceInfoServiceImpl.java b/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/impl/TDeviceInfoServiceImpl.java index e312668..ea95461 100644 --- a/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/impl/TDeviceInfoServiceImpl.java +++ b/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/impl/TDeviceInfoServiceImpl.java @@ -65,20 +65,26 @@ public class TDeviceInfoServiceImpl extends ServiceImpl deviceSnList = deviceUserMappingService.getDeviceSnList( tDeviceInfoBO.getUserIdStr(), tDeviceInfoBO.getDepartmentInfo() ); - System.out.println("✅ 获取设备列表: " + deviceSnList.toString()); + System.out.println("✅ 获取设备列表: " + (deviceSnList != null ? deviceSnList.toString() : "null")); if (deviceSnList == null || deviceSnList.isEmpty()) { + System.out.println("⚠️ 设备列表为空,返回空页面"); return pageQuery.buildPage(); } @@ -88,11 +94,17 @@ public class TDeviceInfoServiceImpl extends ServiceImpl + + + sou.id = #{bo.id} + sou.name LIKE CONCAT(#{bo.name}, '%') @@ -71,9 +75,6 @@ AND sou.status = #{bo.status} - - AND sou.id = #{bo.id} - AND sou.is_deleted = 0 diff --git a/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/system/service/impl/SysOrgUnitsServiceImpl.java b/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/system/service/impl/SysOrgUnitsServiceImpl.java index 20a00cb..afb1ef0 100644 --- a/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/system/service/impl/SysOrgUnitsServiceImpl.java +++ b/ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/system/service/impl/SysOrgUnitsServiceImpl.java @@ -57,7 +57,16 @@ public class SysOrgUnitsServiceImpl extends ServiceImpl listSysOrgUnitsPage(PageQuery pageQuery, SysOrgUnitsBO sysOrgUnitsBO) { - return baseMapper.listSysOrgUnitsPage(pageQuery.buildPage(), sysOrgUnitsBO); + System.out.println("🔍 SysOrgUnitsService.listSysOrgUnitsPage - 查询参数:"); + System.out.println(" id: " + sysOrgUnitsBO.getId()); + System.out.println(" name: " + sysOrgUnitsBO.getName()); + System.out.println(" status: " + sysOrgUnitsBO.getStatus()); + System.out.println(" parentId: " + sysOrgUnitsBO.getParentId()); + + IPage result = baseMapper.listSysOrgUnitsPage(pageQuery.buildPage(), sysOrgUnitsBO); + System.out.println("✅ 查询结果数量: " + result.getRecords().size()); + + return result; } @Override