From 12ef1210bc7f23cad17a523ee37ff8874024ab5c Mon Sep 17 00:00:00 2001 From: b2894lxlx <517289602@qq.com> Date: Mon, 21 Sep 2026 17:01:10 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=84=E7=BB=87=E5=90=8C=E6=AD=A5=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/service/IDeptService.java | 7 ++ .../system/service/impl/DeptServiceImpl.java | 73 +++++++++++++++++++ .../service/impl/OASyncServiceImpl.java | 13 +++- 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/IDeptService.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/IDeptService.java index 744ec5d..cde043f 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/service/IDeptService.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/IDeptService.java @@ -199,4 +199,11 @@ public interface IDeptService extends IService { */ void rebuildOaHierarchy(); + /** + * 删除 OA 同步后无法挂到上级的组织(上级 OA 主键在本地不存在),并级联删除其子级 + * + * @return 删除数量 + */ + int removeOaOrphansWithoutParent(); + } diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/DeptServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/DeptServiceImpl.java index a4b6455..1eeabb4 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/DeptServiceImpl.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/DeptServiceImpl.java @@ -632,6 +632,79 @@ public class DeptServiceImpl extends ServiceImpl implements ID this.refreshAncestors(true, null); } + @Transactional(rollbackFor = Exception.class) + @Override + public int removeOaOrphansWithoutParent() { + List oaDeptList = this.list(Wrappers.lambdaQuery() + .isNotNull(Dept::getOaId) + .ne(Dept::getOaId, "")); + if (CollectionUtil.isEmpty(oaDeptList)) { + return 0; + } + Map companyByOaId = this.indexByOaId(oaDeptList, DeptCategory.COMPANY.getCode()); + Map departmentByOaId = this.indexByOaId(oaDeptList, DeptCategory.DEPT.getCode()); + Set deleteIds = new HashSet<>(); + for (Dept dept : oaDeptList) { + String parentOaId = dept.getOaSupSubComId(); + // 上级为空或为 0:视为本地锚点/根级,不作为孤儿删除 + if (StringUtil.isBlank(parentOaId) || OAConstant.ROOT_COMPANY_ID.equals(parentOaId)) { + continue; + } + boolean parentExists; + if (DeptCategory.COMPANY.getCode().equals(dept.getDeptCategory())) { + parentExists = companyByOaId.containsKey(parentOaId); + } else { + parentExists = departmentByOaId.containsKey(parentOaId) || companyByOaId.containsKey(parentOaId); + } + if (!parentExists) { + deleteIds.add(dept.getId()); + } + } + if (CollectionUtil.isEmpty(deleteIds)) { + log.info("没有需要清理的OA孤儿组织"); + return 0; + } + // 按 OA 上级关系级联:上级被删则子级一并删除 + boolean oaCascadeChanged = true; + while (oaCascadeChanged) { + oaCascadeChanged = false; + for (Dept dept : oaDeptList) { + if (deleteIds.contains(dept.getId())) { + continue; + } + String parentOaId = dept.getOaSupSubComId(); + if (StringUtil.isBlank(parentOaId) || OAConstant.ROOT_COMPANY_ID.equals(parentOaId)) { + continue; + } + Dept parent = DeptCategory.COMPANY.getCode().equals(dept.getDeptCategory()) + ? companyByOaId.get(parentOaId) + : Optional.ofNullable(departmentByOaId.get(parentOaId)).orElse(companyByOaId.get(parentOaId)); + if (parent != null && deleteIds.contains(parent.getId())) { + deleteIds.add(dept.getId()); + oaCascadeChanged = true; + } + } + } + // 按本地 parent_id 再级联一轮,清掉挂在已删节点下的子树 + List allDeptList = this.list(); + boolean parentIdCascadeChanged = true; + while (parentIdCascadeChanged) { + parentIdCascadeChanged = false; + for (Dept dept : allDeptList) { + if (deleteIds.contains(dept.getId())) { + continue; + } + if (dept.getParentId() != null && deleteIds.contains(dept.getParentId())) { + deleteIds.add(dept.getId()); + parentIdCascadeChanged = true; + } + } + } + this.removeByIds(deleteIds); + log.info("删除OA层级无法挂载的组织{}条", deleteIds.size()); + return deleteIds.size(); + } + /** * 按机构类型建立 OA 主键索引 */ diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java index fb452a3..7bd93f9 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OASyncServiceImpl.java @@ -74,10 +74,14 @@ public class OASyncServiceImpl implements IOASyncService { Date startTime = this.syncAndRecord(DataSyncRecordUtils::createOAOrgFetch, queryStartTime -> { // 1. 同步公司 this.syncCompany(queryStartTime); + // 公司分批入库后,重建层级并清理无法挂载的公司 + deptService.rebuildOaHierarchy(); + deptService.removeOaOrphansWithoutParent(); // 2. 同步部门 this.syncDept(queryStartTime); // 3. 分批写入完成后,按 OA 主键重建组织、部门层级 deptService.rebuildOaHierarchy(); + deptService.removeOaOrphansWithoutParent(); // 4. 更新部门祖级列表 deptService.updateAncestors(queryStartTime); CacheUtil.clear(SYS_CACHE); @@ -344,7 +348,9 @@ public class OASyncServiceImpl implements IOASyncService { } OaOrgSyncPageVO pageVO = buildOrgSyncPageVO("company", pageNo, pageSize, totalSize, oaCompanies.size(), syncCount); if (Boolean.TRUE.equals(pageVO.getFinished())) { + // 公司全部分批入库后:重建层级,并删除上级不存在的数据 deptService.rebuildOaHierarchy(); + deptService.removeOaOrphansWithoutParent(); } CacheUtil.clear(SYS_CACHE); CacheUtil.clear(SYS_CACHE, Boolean.FALSE); @@ -388,8 +394,9 @@ public class OASyncServiceImpl implements IOASyncService { } OaOrgSyncPageVO pageVO = buildOrgSyncPageVO("department", pageNo, pageSize, totalSize, oaDepartments.size(), syncCount); if (Boolean.TRUE.equals(pageVO.getFinished())) { - // 部门分批同步完成后,按 OA 主键重建层级并刷新祖级列表 + // 部门分批同步完成后,重建层级、清理无法挂载数据并刷新祖级列表 deptService.rebuildOaHierarchy(); + deptService.removeOaOrphansWithoutParent(); deptService.updateAncestors(null); } CacheUtil.clear(SYS_CACHE); @@ -587,7 +594,7 @@ public class OASyncServiceImpl implements IOASyncService { } }); - // 重新把没有父id的数据设置一下父id;上级尚未入库时,新增记录先挂到根节点,分批结束后再重建 + // 重新把没有父id的数据设置一下父id;上级尚未入库时,新增记录先挂到根节点,全部分批完成后重建层级并清理无法挂载的数据 int unresolvedParentCount = 0; for (Dept dept : allParam) { if (dept.getParentId() != null) { @@ -604,7 +611,7 @@ public class OASyncServiceImpl implements IOASyncService { } } if (unresolvedParentCount > 0) { - ComposeLogUtil.getLastLog().warn("同步{}时有{}条上级尚未入库,已先保存,分批结束后按OA主键重建层级", + ComposeLogUtil.getLastLog().warn("同步{}时有{}条上级尚未入库,已先保存,分批结束后重建层级并清理无法挂载数据", deptCategory.getName(), unresolvedParentCount); }