Browse Source

数据权限过滤

dev-V1.0.1
庄锐波 6 months ago
parent
commit
ad08a8ed68
  1. 27
      doc/执法码数据权限过滤使用说明.md
  2. 139
      script/sql/zfjd-refactoring-v1/013-计划任务表设计.sql
  3. 97
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/common/util/DataFilterUtil.java

27
doc/执法码数据权限过滤使用说明.md

@ -244,13 +244,13 @@ public TableDataInfo<TestEnfDemoVo> directFilterPageList(TestEnfDemoBo bo, PageQ
|----------|--------|------| |----------|--------|------|
| `getUserDeptId(userId)` | `String` | 获取用户的 dept_id(来源 sys_user 表) | | `getUserDeptId(userId)` | `String` | 获取用户的 dept_id(来源 sys_user 表) |
| `getUserOrganId(userId)` | `String` | 查询用户所属执法单位的 organizationId(来源 srz_dept 表,向上递归) | | `getUserOrganId(userId)` | `String` | 查询用户所属执法单位的 organizationId(来源 srz_dept 表,向上递归) |
| `getUserBureauDeptId(userId)` | `String` | 查询用户所在执法单位的 vir_id(来源 efcode_virtual_unit 表) | | `getUserBureauDeptId(userId)` | `String` | 查询用户所在执法单位的 sys_dept_id(沿 sys_dept 父链向上递归查找 efcode_virtual_unit) |
#### 5.4.1 getUserDeptId #### 5.4.1 getUserDeptId 获取用户所在的部门ID
通过 `UserService.selectListByIds()` 查询用户的 `dept_id` 并返回字符串。 通过 `UserService.selectListByIds()` 查询用户的 `dept_id` 并返回字符串。
#### 5.4.2 getUserOrganId #### 5.4.2 getUserOrganId 获取用户所在的单位ID,有可能和部门ID相同
``` ```
userId → getUserDeptId → deptId userId → getUserDeptId → deptId
@ -261,17 +261,22 @@ deptId → srz_dept.organizationId 匹配
(最大递归深度:4层) (最大递归深度:4层)
``` ```
#### 5.4.3 getUserBureauDeptId #### 5.4.3 getUserBureauDeptId 获取用户所在的执法单位ID有可能和部门ID相同,单位ID相同
``` ```
userId → getUserDeptId → deptId userId → getUserDeptId → deptId
deptId → efcode_virtual_unit.sys_dept_id 匹配 循环(自身 + 最多4层父节点,共5层):
├─ 筛选 vir_show_at_business='是' 的记录 currentDeptId → efcode_virtual_unit.sys_dept_id 匹配
│ ├─ 恰好1条 → 返回 vir_id ├─ 存在匹配记录
│ └─ 多条 → 抛出异常 │ ├─ 筛选 vir_show_at_business='是' 的记录
└─ 无 vir_show_at_business='是' 的记录 │ │ ├─ 恰好1条 → 返回该记录的 sys_dept_id
├─ 总匹配只有1条 → 返回 vir_id │ │ └─ 多条 → 抛出异常
└─ 多条 → 抛出异常 │ └─ 无 vir_show_at_business='是' 的记录
│ ├─ 总匹配只有1条 → 返回该记录的 sys_dept_id
│ └─ 多条 → 抛出异常
└─ 无匹配记录
└─ 通过 sys_dept 查找 parentId → currentDeptId = parentId → 继续下一层
到达根节点或超过4层仍未找到 → 返回 null
``` ```
### 5.5 常量定义 ### 5.5 常量定义

139
script/sql/zfjd-refactoring-v1/013-计划任务表设计.sql

@ -1,61 +1,84 @@
DROP TABLE IF EXISTS `enforcement_law_check_plan`; CREATE TABLE `efcode_cp_plan`
CREATE TABLE `enforcement_law_check_plan` ( (
`id` varchar(50) NOT NULL COMMENT '主键ID', `id` varchar(50) NOT NULL COMMENT '主键ID',
-- `plan_code` varchar(32) NOT NULL COMMENT '计划编号(唯一)', `plan_type` tinyint NOT NULL COMMENT '计划类别 1=日常计划 2=专项计划',
`plan_type` tinyint NOT NULL COMMENT '计划类别 1=日常计划 2=专项计划', `plan_date` varchar(16) NOT NULL COMMENT '计划执行日期(如 2025-05-08)',
`plan_date` varchar(16) NOT NULL COMMENT '计划执行日期(如 2025-05-08)', `plan_time` tinyint NOT NULL COMMENT '执行时段 1=上午 2=下午 3=其他',
`plan_time` tinyint NOT NULL COMMENT '执行时段 1=上午 2=下午 3=其他', `enforce_content` varchar(1000) NOT NULL COMMENT '执法事项(最多1000字)',
`enforce_content` varchar(1000) NOT NULL COMMENT '执法事项(最多1000字)', `dept_id` varchar(50) NOT NULL COMMENT '执法单位ID',
`dept_id` varchar(50) NOT NULL COMMENT '执法单位ID', `dept_name` varchar(100) NOT NULL COMMENT '执法单位名称',
`dept_name` varchar(100) NOT NULL COMMENT '执法单位名称', `company_name` varchar(200) NOT NULL COMMENT '被检查企业/机构名称',
`company_name` varchar(200) NOT NULL COMMENT '被检查企业/机构名称', `enforce_user_name` varchar(512) NOT NULL COMMENT '执法人员姓名(多个逗号分隔)',
`enforce_user_name` varchar(512) NOT NULL COMMENT '执法人员姓名(多个逗号分隔)', `enforce_user_code` varchar(512) NOT NULL COMMENT '执法人员证件编号(多个逗号分隔)',
`enforce_user_code` varchar(512) NOT NULL COMMENT '执法人员证件编号(多个逗号分隔)', `is_public` tinyint NOT NULL DEFAULT 1 COMMENT '是否公开 1=是 0=否',
`is_public` tinyint NOT NULL DEFAULT 1 COMMENT '是否公开 1=是 0=否', `is_union` tinyint NOT NULL DEFAULT 1 COMMENT '是否联合执法 1=是 0=否',
`is_union` tinyint NOT NULL DEFAULT 1 COMMENT '是否联合执法 1=是 0=否', `union_dept` varchar(500) DEFAULT NULL COMMENT '联合执法单位(多个逗号分隔)',
`union_dept` varchar(500) DEFAULT NULL COMMENT '联合执法单位(多个逗号分隔)', `reserve_status` tinyint NOT NULL DEFAULT 0 COMMENT '预约状态 0=待预约 1=预约中 2=预约完成 3=停止预约',
-- `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态 1=草稿 2=已提交 3=已执行 4=已作废', `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`reserve_status` tinyint NOT NULL DEFAULT 0 COMMENT '预约状态 0=待预约 1=预约中 2=预约完成 3=停止预约', `create_dept` varchar(64) DEFAULT NULL COMMENT '创建人部门',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者', `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`create_dept` varchar(64) DEFAULT NULL COMMENT '创建人部门', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `is_delete` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除 0=否 1=是',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `remark` varchar(255) DEFAULT NULL COMMENT '备注',
`is_delete` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除 0=否 1=是', PRIMARY KEY (`id`),
`remark` varchar(255) DEFAULT NULL COMMENT '备注', KEY `idx_dept_id` (`dept_id`),
PRIMARY KEY (`id`), KEY `idx_reserve_status` (`reserve_status`)
KEY `idx_dept_id` (`dept_id`), ) comment '行政执法检查计划-计划表' row_format = DYNAMIC;
KEY `idx_reserve_status` (`reserve_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='行政执法检查计划表'; CREATE TABLE `efcode_cp_task`(
) comment '行政执法检查计划-计划参与人员表' row_format = DYNAMIC;
CREATE TABLE `efcode_cp_task`(
) comment '行政执法检查计划-任务表' row_format = DYNAMIC;
CREATE TABLE `efcode_cp_task`(
) comment '行政执法检查计划-预约表' row_format = DYNAMIC;
CREATE TABLE `efcode_cp_task`(
) comment '行政执法检查计划-预告表' row_format = DYNAMIC;
CREATE TABLE `efcode_cp_task`(
) comment '行政执法检查计划-预告交流表' row_format = DYNAMIC;
CREATE TABLE `efcode_cp_setting`(
) comment '行政执法检查计划-设置表' row_format = DYNAMIC;
DROP TABLE IF EXISTS `enforcement_law_notice`; DROP TABLE IF EXISTS `enforcement_law_notice`;
CREATE TABLE `enforcement_law_notice` ( CREATE TABLE `enforcement_law_notice`
`id` varchar(50) NOT NULL COMMENT '主键ID', (
`plan_id` bigint DEFAULT NULL COMMENT '导入的计划ID(关联执法计划表)', `id` varchar(50) NOT NULL COMMENT '主键ID',
`enforce_date` varchar(16) NOT NULL COMMENT '执法日期', `plan_id` bigint DEFAULT NULL COMMENT '导入的计划ID(关联执法计划表)',
`enforce_period` tinyint NOT NULL COMMENT '执法时段 1=上午 2=下午 3=其他', `enforce_date` varchar(16) NOT NULL COMMENT '执法日期',
`dept_id` varchar(50) NOT NULL COMMENT '执法单位ID', `enforce_period` tinyint NOT NULL COMMENT '执法时段 1=上午 2=下午 3=其他',
`dept_name` varchar(100) NOT NULL COMMENT '执法单位名称', `dept_id` varchar(50) NOT NULL COMMENT '执法单位ID',
`enforce_user_names` varchar(512) NOT NULL COMMENT '执法人员姓名(多人员逗号分隔)', `dept_name` varchar(100) NOT NULL COMMENT '执法单位名称',
`enforce_user_codes` varchar(512) NOT NULL COMMENT '执法人员证件编号(多人员逗号分隔)', `enforce_user_names` varchar(512) NOT NULL COMMENT '执法人员姓名(多人员逗号分隔)',
`company_id` varchar(50) NOT NULL COMMENT '被检查企业ID', `enforce_user_codes` varchar(512) NOT NULL COMMENT '执法人员证件编号(多人员逗号分隔)',
`company_name` varchar(200) NOT NULL COMMENT '被检查企业名称', `company_id` varchar(50) NOT NULL COMMENT '被检查企业ID',
`credit_code` varchar(32) DEFAULT NULL COMMENT '企业统一社会信用代码', `company_name` varchar(200) NOT NULL COMMENT '被检查企业名称',
`contact_person` varchar(50) NOT NULL COMMENT '企业联系人', `credit_code` varchar(32) DEFAULT NULL COMMENT '企业统一社会信用代码',
`contact_phone` varchar(20) NOT NULL COMMENT '企业联系电话', `contact_person` varchar(50) NOT NULL COMMENT '企业联系人',
`enforce_content` varchar(1000) NOT NULL COMMENT '执法事项', `contact_phone` varchar(20) NOT NULL COMMENT '企业联系电话',
`enforce_requirement` varchar(1000) NOT NULL COMMENT '执法要求', `enforce_content` varchar(1000) NOT NULL COMMENT '执法事项',
`publish_time` datetime DEFAULT NULL COMMENT '预告发布时间', `enforce_requirement` varchar(1000) NOT NULL COMMENT '执法要求',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '预告状态 1=草稿 2=已发布 3=已取消 4=已执行', `publish_time` datetime DEFAULT NULL COMMENT '预告发布时间',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者', `status` tinyint NOT NULL DEFAULT 1 COMMENT '预告状态 1=草稿 2=已发布 3=已取消 4=已执行',
`create_dept` varchar(64) DEFAULT NULL COMMENT '创建人部门', `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者', `create_dept` varchar(64) DEFAULT NULL COMMENT '创建人部门',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`is_delete` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除 0=否 1=是', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`remark` varchar(255) DEFAULT NULL COMMENT '备注', `is_delete` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除 0=否 1=是',
PRIMARY KEY (`id`), `remark` varchar(255) DEFAULT NULL COMMENT '备注',
KEY `idx_dept_id` (`dept_id`), PRIMARY KEY (`id`),
KEY `idx_company_id` (`company_id`), KEY `idx_dept_id` (`dept_id`),
KEY `idx_credit_code` (`credit_code`) KEY `idx_company_id` (`company_id`),
KEY `idx_credit_code` (`credit_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='行政执法预告表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='行政执法预告表';

97
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/common/util/DataFilterUtil.java

@ -20,6 +20,8 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.system.domain.vo.SysDeptVo;
import org.dromara.system.service.ISysDeptService;
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DataFilterUtil { public class DataFilterUtil {
@ -409,70 +411,81 @@ public class DataFilterUtil {
// ======================== 用户执法单位查询方法 ======================== // ======================== 用户执法单位查询方法 ========================
/** /**
* 查询指定用户所在的执法单位的 vir_id。 * 查询指定用户所在的执法单位的 sys_dept_id。
* <p> * <p>
* 逻辑: * 逻辑:
* <ol> * <ol>
* <li>通过 userId 查询用户的 dept_id</li> * <li>通过 userId 查询用户的 dept_id</li>
* <li>用 dept_id 匹配 efcode_virtual_unit.sys_dept_id</li> * <li>用 dept_id 查找 efcode_virtual_unit(按 sys_dept_id 匹配)</li>
* <li>优先返回 vir_show_at_business='是' 的记录的 vir_id</li> * <li>若存在匹配记录,优先返回 vir_show_at_business='是' 的记录的 sys_dept_id;
* <li>如果 vir_show_at_business='是' 的有多条,抛出异常</li> * 若无 business 记录且只有一条匹配也直接返回</li>
* <li>如果没有 vir_show_at_business='是' 的记录,且只有一条匹配 sys_dept_id 的记录,也直接返回</li> * <li>若不存在匹配记录,通过 sys_dept 查找父节点,再用父节点 dept_id 重复上述查找</li>
* <li>递归向上最多查 4 层父节点</li>
* </ol> * </ol>
* *
* @param userId 用户ID * @param userId 用户ID
* @return 用户所在执法单位的 vir_id;如果用户不存在或未分配部门则返回 null * @return 用户所在执法单位的 sys_dept_id;如果用户不存在、未分配部门或向上 4 层仍未找到则返回 null
* @throws IllegalStateException 当匹配到多条 vir_show_at_business='是' 的记录时抛出 * @throws IllegalStateException 当某层匹配到多条 vir_show_at_business='是' 的记录,或多条匹配但无法确定唯一执法单位时抛出
*/ */
public static String getUserBureauDeptId(Long userId) { public static String getUserBureauDeptId(Long userId) {
if (userId == null) { if (userId == null) {
return null; return null;
} }
// 1. 通过 userId 获取用户的 deptId // 1. 通过 userId 获取用户的 deptId
UserService userService = SpringUtils.getBean(UserService.class); String deptId = getUserDeptId(userId);
List<UserDTO> users = userService.selectListByIds(Collections.singletonList(userId)); if (StrUtil.isBlank(deptId)) {
if (CollUtil.isEmpty(users)) {
return null;
}
UserDTO user = users.get(0);
if (user.getDeptId() == null) {
return null; return null;
} }
String deptId = String.valueOf(user.getDeptId());
// 2. 通过 deptId 查询 efcode_virtual_unit 中所有匹配 sys_dept_id 的记录 // 2. 从当前 deptId 开始,向上查找 sys_dept 父链,最多查 5 层(自身 + 4 层父节点)
IEfcodeVirtualUnitService virtualUnitService = SpringUtils.getBean(IEfcodeVirtualUnitService.class); IEfcodeVirtualUnitService virtualUnitService = SpringUtils.getBean(IEfcodeVirtualUnitService.class);
EfcodeVirtualUnitBo bo = new EfcodeVirtualUnitBo(); ISysDeptService sysDeptService = SpringUtils.getBean(ISysDeptService.class);
bo.setSysDeptId(deptId);
List<EfcodeVirtualUnitVo> allMatched = virtualUnitService.queryList(bo);
if (CollUtil.isEmpty(allMatched)) {
return null;
}
// 3. 筛选 vir_show_at_business='是' 的记录 String currentDeptId = deptId;
List<EfcodeVirtualUnitVo> businessUnits = allMatched.stream() for (int i = 0; i < 5; i++) {
.filter(v -> "是".equals(v.getVirShowAtBusiness())) if (StrUtil.isBlank(currentDeptId)) {
.collect(Collectors.toList()); break;
}
if (businessUnits.size() == 1) { // 查询 efcode_virtual_unit 中所有匹配 sys_dept_id 的记录
// 恰好一条业务记录,直接返回 EfcodeVirtualUnitBo bo = new EfcodeVirtualUnitBo();
return businessUnits.get(0).getVirId(); bo.setSysDeptId(currentDeptId);
} List<EfcodeVirtualUnitVo> allMatched = virtualUnitService.queryList(bo);
if (businessUnits.size() > 1) {
// 多条业务记录,抛出异常 if (CollUtil.isNotEmpty(allMatched)) {
throw new IllegalStateException( // 筛选 vir_show_at_business='是' 的记录
"用户(userId=" + userId + ")的部门(deptId=" + deptId List<EfcodeVirtualUnitVo> businessUnits = allMatched.stream()
+ ")在虚拟单位表中匹配到多条 vir_show_at_business='是' 的记录,无法确定唯一执法单位"); .filter(v -> "是".equals(v.getVirShowAtBusiness()))
} .collect(Collectors.toList());
if (businessUnits.size() == 1) {
return businessUnits.get(0).getSysDeptId();
}
if (businessUnits.size() > 1) {
throw new IllegalStateException(
"用户(userId=" + userId + ")的部门(deptId=" + currentDeptId
+ ")在虚拟单位表中匹配到多条 vir_show_at_business='是' 的记录,无法确定唯一执法单位");
}
// 没有 business 记录,如果只有一条匹配则返回
if (allMatched.size() == 1) {
return allMatched.get(0).getSysDeptId();
}
// 多条匹配但无 business 标记,无法确定唯一执法单位
throw new IllegalStateException(
"用户(userId=" + userId + ")的部门(deptId=" + currentDeptId
+ ")在虚拟单位表中匹配到多条记录且无 vir_show_at_business='是',无法确定唯一执法单位");
}
// 4. 没有 vir_show_at_business='是' 的记录,如果只有一条匹配记录则返回 // 不存在匹配记录,通过 sys_dept 查找父节点
if (allMatched.size() == 1) { SysDeptVo dept = sysDeptService.selectDeptById(currentDeptId);
return allMatched.get(0).getVirId(); if (dept == null || StrUtil.isBlank(dept.getParentId()) || "0".equals(dept.getParentId())) {
break;
}
currentDeptId = dept.getParentId();
} }
// 多条匹配但无法确定唯一执法单位 // 向上查找 4 层仍未找到对应的虚拟单位
throw new IllegalStateException( return null;
"无法找到当前用户所在的执法单位!");
} }
// ======================== 私有辅助方法 ======================== // ======================== 私有辅助方法 ========================

Loading…
Cancel
Save