diff --git a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/pom.xml b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/pom.xml
index a6db4949..9f0c712f 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/pom.xml
@@ -47,6 +47,10 @@
yudao-spring-boot-starter-test
test
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-biz-tenant
+
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java
index 7ec7a4a5..a2e82f46 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/rule/dept/DeptDataPermissionRule.java
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.biz.system.permission.PermissionCommonApi;
+import cn.iocoder.yudao.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
@@ -12,11 +13,14 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
-import cn.iocoder.yudao.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO;
+import cn.iocoder.yudao.framework.tenant.core.context.DeptContextHolder;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import net.sf.jsqlparser.expression.*;
+import net.sf.jsqlparser.expression.Alias;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.LongValue;
+import net.sf.jsqlparser.expression.NullValue;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
@@ -112,6 +116,15 @@ public class DeptDataPermissionRule implements DataPermissionRule {
// 添加到上下文中,避免重复计算
loginUser.setContext(CONTEXT_KEY, deptDataPermission);
}
+ // 如果开启了部门上下文,且缓存的部门编号不等于 DeptContextHolder 的部门编号,则更新缓存
+ if(!DeptContextHolder.isIgnore()) {
+ Set deptIds = DeptContextHolder.getDeptIdList();
+ if (CollUtil.isNotEmpty(deptIds) && !CollUtil.isEqualList(deptDataPermission.getDeptIds(), deptIds)) {
+ deptDataPermission.setDeptIds(deptIds);
+ // 更新到上下文中
+ loginUser.setContext(CONTEXT_KEY, deptDataPermission);
+ }
+ }
// 情况一,如果是 ALL 可查看全部,则无需拼接条件
if (deptDataPermission.getAll()) {
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
index 8fe59c3a..49055ded 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.framework.tenant.config;
import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.biz.system.tenant.TenantCommonApi;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties;
@@ -16,11 +17,11 @@ import cn.iocoder.yudao.framework.tenant.core.redis.TenantRedisCacheManager;
import cn.iocoder.yudao.framework.tenant.core.security.TenantSecurityWebFilter;
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkServiceImpl;
+import cn.iocoder.yudao.framework.tenant.core.web.DeptVisitContextInterceptor;
import cn.iocoder.yudao.framework.tenant.core.web.TenantContextWebFilter;
import cn.iocoder.yudao.framework.tenant.core.web.TenantVisitContextInterceptor;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
-import cn.iocoder.yudao.framework.common.biz.system.tenant.TenantCommonApi;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import jakarta.annotation.Resource;
@@ -133,6 +134,10 @@ public class YudaoTenantAutoConfiguration {
SecurityFrameworkService securityFrameworkService) {
return new TenantVisitContextInterceptor(tenantProperties, securityFrameworkService);
}
+ @Bean
+ public DeptVisitContextInterceptor deptVisitContextInterceptor(SecurityFrameworkService securityFrameworkService) {
+ return new DeptVisitContextInterceptor(securityFrameworkService);
+ }
@Bean
public WebMvcConfigurer tenantWebMvcConfigurer(TenantProperties tenantProperties,
@@ -147,6 +152,17 @@ public class YudaoTenantAutoConfiguration {
};
}
+ @Bean
+ public WebMvcConfigurer deptWebMvcConfigurer(TenantProperties tenantProperties, DeptVisitContextInterceptor deptVisitContextInterceptor) {
+ return new WebMvcConfigurer() {
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(deptVisitContextInterceptor)
+ .excludePathPatterns(tenantProperties.getIgnoreVisitUrls().toArray(new String[0]));
+ }
+ };
+ }
+
// ========== Security ==========
@Bean
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/DeptVisitIgnore.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/DeptVisitIgnore.java
new file mode 100644
index 00000000..b30160f5
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/DeptVisitIgnore.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.framework.tenant.core.aop;
+
+import java.lang.annotation.*;
+
+/**
+ * 忽略单位切换,标记指定方法不进行租户切换的覆盖
+ * @author chenbowen
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface DeptVisitIgnore {
+
+ /**
+ * 是否开启忽略租户,默认为 true 开启
+ *
+ * 支持 Spring EL 表达式,如果返回 true 则满足条件,进行租户的忽略
+ */
+ String enable() default "true";
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/DeptVisitIgnoreAspect.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/DeptVisitIgnoreAspect.java
new file mode 100644
index 00000000..cc3b0aa2
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/aop/DeptVisitIgnoreAspect.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.framework.tenant.core.aop;
+
+import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
+import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+
+/**
+ * 忽略单位切换,标记指定方法不进行租户切换的覆盖,基于 {@link DeptVisitIgnore} 注解实现,用于一些全局的逻辑。
+ * 例如说,一个定时任务,读取所有数据,进行处理。
+ * 又例如说,读取所有数据,进行缓存。
+ * @author 芋道源码
+ */
+@Aspect
+@Slf4j
+public class DeptVisitIgnoreAspect {
+
+ @Around("@annotation(deptVisitIgnore)")
+ public Object around(ProceedingJoinPoint joinPoint, DeptVisitIgnore deptVisitIgnore) throws Throwable {
+ Boolean oldIgnore = TenantContextHolder.isIgnore();
+ try {
+ // 计算条件,满足的情况下,才进行忽略
+ Object enable = SpringExpressionUtils.parseExpression(deptVisitIgnore.enable());
+ if (Boolean.TRUE.equals(enable)) {
+ TenantContextHolder.setIgnore(true);
+ }
+
+ // 执行逻辑
+ return joinPoint.proceed();
+ } finally {
+ TenantContextHolder.setIgnore(oldIgnore);
+ }
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/DeptContextHolder.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/DeptContextHolder.java
new file mode 100644
index 00000000..e4c5d7ce
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/DeptContextHolder.java
@@ -0,0 +1,70 @@
+package cn.iocoder.yudao.framework.tenant.core.context;
+
+import cn.iocoder.yudao.framework.common.enums.DocumentEnum;
+import com.alibaba.ttl.TransmittableThreadLocal;
+
+import java.util.Set;
+
+/**
+ * 多部门上下文 Holder
+ *
+ * @author 芋道源码
+ */
+public class DeptContextHolder {
+
+ /**
+ * 当前部门编号列表
+ */
+ private static final ThreadLocal> DEPT_ID_LIST = new TransmittableThreadLocal<>();
+
+ /**
+ * 是否忽略部门
+ */
+ private static final ThreadLocal IGNORE = new TransmittableThreadLocal<>();
+
+ /**
+ * 获得部门编号列表
+ *
+ * @return 部门编号列表
+ */
+ public static Set getDeptIdList() {
+ return DEPT_ID_LIST.get();
+ }
+
+ /**
+ * 获得部门编号列表。如果不存在,则抛出 NullPointerException 异常
+ *
+ * @return 部门编号列表
+ */
+ public static Set getRequiredDeptIdList() {
+ Set deptIdList = getDeptIdList();
+ if (deptIdList == null) {
+ throw new NullPointerException("DeptContextHolder 不存在部门编号列表!可参考文档:"
+ + DocumentEnum.TENANT.getUrl());
+ }
+ return deptIdList;
+ }
+
+ public static void setDeptIdList(Set deptIdList) {
+ DEPT_ID_LIST.set(deptIdList);
+ }
+
+ public static void setIgnore(Boolean ignore) {
+ IGNORE.set(ignore);
+ }
+
+ /**
+ * 当前是否忽略部门
+ *
+ * @return 是否忽略
+ */
+ public static boolean isIgnore() {
+ return Boolean.TRUE.equals(IGNORE.get());
+ }
+
+ public static void clear() {
+ DEPT_ID_LIST.remove();
+ IGNORE.remove();
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/DeptVisitContextInterceptor.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/DeptVisitContextInterceptor.java
new file mode 100644
index 00000000..7c1370da
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/DeptVisitContextInterceptor.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.framework.tenant.core.web;
+
+import cn.iocoder.yudao.framework.security.core.LoginUser;
+import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.framework.tenant.core.context.DeptContextHolder;
+import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import java.util.Set;
+
+/**
+ * @author chenbowen
+ */
+@RequiredArgsConstructor
+@Slf4j
+public class DeptVisitContextInterceptor implements HandlerInterceptor {
+
+ private static final String PERMISSION = "system:dept:visit";
+
+ private final SecurityFrameworkService securityFrameworkService;
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
+ // 解析 header 并设置 visitDeptIds
+ Set deptIds = WebFrameworkUtils.getVisitDeptIds(request);
+ if (deptIds == null) {
+ return true;
+ }
+ LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
+ if (loginUser == null) {
+ return true;
+ }
+// if (!securityFrameworkService.hasAnyPermissions(PERMISSION)) {
+// throw exception0(GlobalErrorCodeConstants.FORBIDDEN.getCode(), "您无权切换部门");
+// }
+ loginUser.setVisitDeptIds(deptIds);
+ DeptContextHolder.setDeptIdList(deptIds);
+ return true;
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
+ // 清理 visitDeptIds
+ LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
+ if (loginUser != null) {
+ loginUser.setVisitDeptIds(null);
+ }
+ }
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantVisitContextInterceptor.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantVisitContextInterceptor.java
index 12d78774..4ab9eb6a 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantVisitContextInterceptor.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantVisitContextInterceptor.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.framework.tenant.core.web;
import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
@@ -13,6 +14,11 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
+
+/**
+ * @author chenbowen
+ */
@RequiredArgsConstructor
@Slf4j
public class TenantVisitContextInterceptor implements HandlerInterceptor {
@@ -39,10 +45,10 @@ public class TenantVisitContextInterceptor implements HandlerInterceptor {
return true;
}
-// // 校验用户是否可切换租户
-// if (!securityFrameworkService.hasAnyPermissions(PERMISSION)) {
-// throw exception0(GlobalErrorCodeConstants.FORBIDDEN.getCode(), "您无权切换租户");
-// }
+ // 校验用户是否可切换租户
+ if (!securityFrameworkService.hasAnyPermissions(PERMISSION)) {
+ throw exception0(GlobalErrorCodeConstants.FORBIDDEN.getCode(), "您无权切换租户");
+ }
// 【重点】切换租户编号
loginUser.setVisitTenantId(visitTenantId);
diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
index ec53d203..91dd320e 100644
--- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
+++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
@@ -9,6 +9,7 @@ import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* 登录用户信息
@@ -62,6 +63,8 @@ public class LoginUser {
*/
private Long visitTenantId;
+ private Set visitDeptIds;
+
public void setContext(String key, Object value) {
if (context == null) {
context = new HashMap<>();
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
index 86b5c3e4..013a2523 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
@@ -1,19 +1,20 @@
package cn.iocoder.yudao.framework.web.core.util;
import cn.hutool.core.util.NumberUtil;
-import cn.hutool.extra.servlet.ServletUtil;
+import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.RpcConstants;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.web.config.WebProperties;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
-import jakarta.servlet.ServletRequest;
-import jakarta.servlet.http.HttpServletRequest;
+import java.util.HashSet;
+import java.util.Set;
/**
* 专属于 web 包的工具类
@@ -29,6 +30,7 @@ public class WebFrameworkUtils {
public static final String HEADER_TENANT_ID = "tenant-id";
public static final String HEADER_VISIT_TENANT_ID = "visit-tenant-id";
+ public static final String HEADER_VISIT_DEPT_IDS = "visit-dept-ids";
/**
* 终端的 Header
@@ -179,4 +181,27 @@ public class WebFrameworkUtils {
return className.endsWith("Api");
}
+ /**
+ * 获得访问的部门编号列表,从 header 中
+ * @param request 请求
+ * @return 部门编号列表,解析失败或无效时返回 null
+ */
+ public static Set getVisitDeptIds(HttpServletRequest request) {
+ String deptIdsHeader = request.getHeader(HEADER_VISIT_DEPT_IDS);
+ if (StrUtil.isBlank(deptIdsHeader)) {
+ return new HashSet<>();
+ }
+ try {
+ Set deptIds = java.util.Arrays.stream(deptIdsHeader.split(","))
+ .map(String::trim)
+ .filter(cn.hutool.core.util.StrUtil::isNotBlank)
+ .map(Long::valueOf)
+ .collect(java.util.stream.Collectors.toSet());
+ return deptIds.isEmpty() ? new HashSet<>() : deptIds;
+ } catch (Exception e) {
+ // 解析失败
+ return new HashSet<>();
+ }
+ }
+
}
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/DeptController.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/DeptController.java
index 2f43da82..144b55a6 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/DeptController.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/DeptController.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.controller.admin.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.tenant.core.aop.DeptVisitIgnore;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptRespVO;
@@ -71,12 +72,22 @@ public class DeptController {
@GetMapping(value = {"/list-all-simple", "/simple-list"})
@Operation(summary = "获取部门精简信息列表", description = "只包含被开启的部门,主要用于前端的下拉选项")
+ @DeptVisitIgnore
public CommonResult> getSimpleDeptList() {
List list = deptService.getDeptList(
new DeptListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
}
+ @GetMapping(value = {"/list-simple", "/simple-dept-list"})
+ @Operation(summary = "获取部门精简信息列表(不包含当前用户归属部门的上级部门)", description = "只包含被开启的部门,主要用于前端的下拉选项")
+ @DeptVisitIgnore
+ public CommonResult> getNoParentSimpleDeptList() {
+ List list = deptService.getNoParentDeptList(
+ new DeptListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
+ return success(BeanUtils.toBean(list, DeptSimpleRespVO.class));
+ }
+
@GetMapping("/get")
@Operation(summary = "获得部门信息")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java
index a0b765e5..285063f7 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptService.java
@@ -59,6 +59,7 @@ public interface DeptService {
* @return 部门列表
*/
List getDeptList(DeptListReqVO reqVO);
+ List getNoParentDeptList(DeptListReqVO reqVO);
/**
* 获得指定编号的部门 Map
diff --git a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
index 89d1f64e..cc63ff95 100644
--- a/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
+++ b/yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
@@ -19,9 +19,11 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.*;
+import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserDeptId;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/**
@@ -169,6 +171,28 @@ public class DeptServiceImpl implements DeptService {
return list;
}
+ @Override
+ public List getNoParentDeptList(DeptListReqVO reqVO){
+ List list = deptMapper.selectList(reqVO);
+ // 循环过滤掉当前用户归属部门的所有上级部门
+ Long loginUserDeptId = getLoginUserDeptId();
+ Set parentIds = new HashSet<>();
+ Map deptMap = list.stream().collect(Collectors.toMap(DeptDO::getId, d -> d));
+ Long currentId = loginUserDeptId;
+ while (currentId != null && !DeptDO.PARENT_ID_ROOT.equals(currentId)) {
+ DeptDO dept = deptMap.get(currentId);
+ if (dept == null) break;
+ Long parentId = dept.getParentId();
+ if (parentId == null || DeptDO.PARENT_ID_ROOT.equals(parentId)) break;
+ parentIds.add(parentId);
+ currentId = parentId;
+ }
+ // 过滤掉所有上级部门
+ return list.stream()
+ .filter(dept -> !parentIds.contains(dept.getId()))
+ .collect(Collectors.toList());
+ }
+
@Override
public List getChildDeptList(Collection ids) {
List children = new LinkedList<>();