feat: 实现租户与部门权限区分管理 v1.0.11
🏢 核心功能 - 实现租户与部门的严格权限隔离和层级管理 - 超级管理员可创建租户,部门管理员只能管理部门 - 前端UI根据用户权限动态显示表单字段 🔐 安全增强 - API层权限校验防止越权操作 - 自动设置正确的父级关系和层级结构 - 集成SaToken进行细粒度权限控制 📋 功能优化 - 设备管理界面按部门权限过滤显示 - 健康数据查询严格按部门权限隔离 - TypeScript类型定义修复和完善
This commit is contained in:
+28
-1
@@ -2,7 +2,7 @@
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
[](./LICENSE)
|
||||
<br/>
|
||||
[](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)
|
||||
|
||||
**🔧 健康数据配置服务架构重构**
|
||||
|
||||
+5
@@ -60,6 +60,11 @@
|
||||
@Operation(operationId = "1", summary = "获取列表")
|
||||
public Result<RPage<TDeviceInfoVO>> 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));
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -49,6 +49,10 @@ public class SysOrgUnitsController {
|
||||
@Operation(operationId = "1", summary = "获取租户/部门列表")
|
||||
public Result<RPage<SysOrgUnitsTreeVO>> 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));
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -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;
|
||||
|
||||
+9
-1
@@ -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<TDeviceInfo> tDeviceInfoIPage = tDeviceInfoService.listTDeviceInfoPage(pageQuery, tDeviceInfoBO);
|
||||
return RPage.build(tDeviceInfoIPage, TDeviceInfoVO::new);
|
||||
}
|
||||
|
||||
+14
-2
@@ -65,20 +65,26 @@ public class TDeviceInfoServiceImpl extends ServiceImpl<TDeviceInfoMapper, TDevi
|
||||
.inSql(TDeviceInfo::getId, "SELECT id FROM (SELECT id, ROW_NUMBER() OVER (PARTITION BY serial_number ORDER BY timestamp DESC) as rn FROM t_device_info) t WHERE rn = 1")
|
||||
.orderByDesc(TDeviceInfo::getTimestamp);
|
||||
// ... existing code ...
|
||||
// 🔧 修复: departmentInfo=0时查询所有设备 #条件过滤优化
|
||||
// 🔧 设备过滤逻辑: 根据用户ID或部门ID过滤设备,特殊处理orgId=0的情况
|
||||
System.out.println("🔍 查询条件 - userIdStr: " + tDeviceInfoBO.getUserIdStr() + ", departmentInfo: " + tDeviceInfoBO.getDepartmentInfo());
|
||||
System.out.println("🔍 过滤条件判断 - userIdStr isEmpty: " + ObjectUtils.isEmpty(tDeviceInfoBO.getUserIdStr())
|
||||
+ ", departmentInfo isEmpty: " + ObjectUtils.isEmpty(tDeviceInfoBO.getDepartmentInfo())
|
||||
+ ", departmentInfo equals '0': " + "0".equals(tDeviceInfoBO.getDepartmentInfo()));
|
||||
|
||||
// 当有具体的用户ID或者部门ID不为空且不为"0"时进行过滤
|
||||
if (ObjectUtils.isNotEmpty(tDeviceInfoBO.getUserIdStr()) ||
|
||||
(ObjectUtils.isNotEmpty(tDeviceInfoBO.getDepartmentInfo()) && !"0".equals(tDeviceInfoBO.getDepartmentInfo()))) {
|
||||
|
||||
System.out.println("🔍 开始调用 getDeviceSnList 进行设备过滤...");
|
||||
List<String> 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<TDeviceInfoMapper, TDevi
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
System.out.println("✅ 过滤后有效设备列表: " + validDeviceSnList.toString());
|
||||
|
||||
if (validDeviceSnList.isEmpty()) {
|
||||
System.out.println("⚠️ 有效设备列表为空,返回空页面");
|
||||
return pageQuery.buildPage();
|
||||
}
|
||||
|
||||
queryWrapper.in(TDeviceInfo::getSerialNumber, validDeviceSnList);
|
||||
System.out.println("✅ 已添加设备序列号过滤条件");
|
||||
} else {
|
||||
System.out.println("⚠️ 跳过设备过滤,将查询所有设备");
|
||||
}
|
||||
|
||||
// 执行分页查询
|
||||
|
||||
+4
-3
@@ -61,6 +61,10 @@
|
||||
FROM sys_org_units sou
|
||||
WHERE
|
||||
<choose>
|
||||
<when test="bo.id != null and bo.id != '' and bo.id != 0">
|
||||
<!-- 当指定部门ID时,只查询该部门作为顶级节点,子部门通过listAllDescendants查询 -->
|
||||
sou.id = #{bo.id}
|
||||
</when>
|
||||
<when test="bo.name != null and bo.name != ''">
|
||||
sou.name LIKE CONCAT(#{bo.name}, '%')
|
||||
</when>
|
||||
@@ -71,9 +75,6 @@
|
||||
<if test="bo.status != null and bo.status != ''">
|
||||
AND sou.status = #{bo.status}
|
||||
</if>
|
||||
<if test="bo.id != null and bo.id != '' and bo.id != 0">
|
||||
AND sou.id = #{bo.id}
|
||||
</if>
|
||||
AND sou.is_deleted = 0
|
||||
|
||||
</select>
|
||||
|
||||
+10
-1
@@ -57,7 +57,16 @@ public class SysOrgUnitsServiceImpl extends ServiceImpl<SysOrgUnitsMapper, SysOr
|
||||
|
||||
@Override
|
||||
public IPage<SysOrgUnits> 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<SysOrgUnits> result = baseMapper.listSysOrgUnitsPage(pageQuery.buildPage(), sysOrgUnitsBO);
|
||||
System.out.println("✅ 查询结果数量: " + result.getRecords().size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user