组织同步逻辑修改

This commit is contained in:
2026-09-21 17:01:10 +08:00
parent d1821bbfcf
commit 12ef1210bc
3 changed files with 90 additions and 3 deletions
@@ -199,4 +199,11 @@ public interface IDeptService extends IService<Dept> {
*/ */
void rebuildOaHierarchy(); void rebuildOaHierarchy();
/**
* 删除 OA 同步后无法挂到上级的组织(上级 OA 主键在本地不存在),并级联删除其子级
*
* @return 删除数量
*/
int removeOaOrphansWithoutParent();
} }
@@ -632,6 +632,79 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements ID
this.refreshAncestors(true, null); this.refreshAncestors(true, null);
} }
@Transactional(rollbackFor = Exception.class)
@Override
public int removeOaOrphansWithoutParent() {
List<Dept> oaDeptList = this.list(Wrappers.<Dept>lambdaQuery()
.isNotNull(Dept::getOaId)
.ne(Dept::getOaId, ""));
if (CollectionUtil.isEmpty(oaDeptList)) {
return 0;
}
Map<String, Dept> companyByOaId = this.indexByOaId(oaDeptList, DeptCategory.COMPANY.getCode());
Map<String, Dept> departmentByOaId = this.indexByOaId(oaDeptList, DeptCategory.DEPT.getCode());
Set<Long> 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<Dept> 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 主键索引 * 按机构类型建立 OA 主键索引
*/ */
@@ -74,10 +74,14 @@ public class OASyncServiceImpl implements IOASyncService {
Date startTime = this.syncAndRecord(DataSyncRecordUtils::createOAOrgFetch, queryStartTime -> { Date startTime = this.syncAndRecord(DataSyncRecordUtils::createOAOrgFetch, queryStartTime -> {
// 1. 同步公司 // 1. 同步公司
this.syncCompany(queryStartTime); this.syncCompany(queryStartTime);
// 公司分批入库后,重建层级并清理无法挂载的公司
deptService.rebuildOaHierarchy();
deptService.removeOaOrphansWithoutParent();
// 2. 同步部门 // 2. 同步部门
this.syncDept(queryStartTime); this.syncDept(queryStartTime);
// 3. 分批写入完成后,按 OA 主键重建组织、部门层级 // 3. 分批写入完成后,按 OA 主键重建组织、部门层级
deptService.rebuildOaHierarchy(); deptService.rebuildOaHierarchy();
deptService.removeOaOrphansWithoutParent();
// 4. 更新部门祖级列表 // 4. 更新部门祖级列表
deptService.updateAncestors(queryStartTime); deptService.updateAncestors(queryStartTime);
CacheUtil.clear(SYS_CACHE); CacheUtil.clear(SYS_CACHE);
@@ -344,7 +348,9 @@ public class OASyncServiceImpl implements IOASyncService {
} }
OaOrgSyncPageVO pageVO = buildOrgSyncPageVO("company", pageNo, pageSize, totalSize, oaCompanies.size(), syncCount); OaOrgSyncPageVO pageVO = buildOrgSyncPageVO("company", pageNo, pageSize, totalSize, oaCompanies.size(), syncCount);
if (Boolean.TRUE.equals(pageVO.getFinished())) { if (Boolean.TRUE.equals(pageVO.getFinished())) {
// 公司全部分批入库后:重建层级,并删除上级不存在的数据
deptService.rebuildOaHierarchy(); deptService.rebuildOaHierarchy();
deptService.removeOaOrphansWithoutParent();
} }
CacheUtil.clear(SYS_CACHE); CacheUtil.clear(SYS_CACHE);
CacheUtil.clear(SYS_CACHE, Boolean.FALSE); 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); OaOrgSyncPageVO pageVO = buildOrgSyncPageVO("department", pageNo, pageSize, totalSize, oaDepartments.size(), syncCount);
if (Boolean.TRUE.equals(pageVO.getFinished())) { if (Boolean.TRUE.equals(pageVO.getFinished())) {
// 部门分批同步完成后,按 OA 主键重建层级并刷新祖级列表 // 部门分批同步完成后,重建层级、清理无法挂载数据并刷新祖级列表
deptService.rebuildOaHierarchy(); deptService.rebuildOaHierarchy();
deptService.removeOaOrphansWithoutParent();
deptService.updateAncestors(null); deptService.updateAncestors(null);
} }
CacheUtil.clear(SYS_CACHE); CacheUtil.clear(SYS_CACHE);
@@ -587,7 +594,7 @@ public class OASyncServiceImpl implements IOASyncService {
} }
}); });
// 重新把没有父id的数据设置一下父id;上级尚未入库时,新增记录先挂到根节点,分批结束后再重建 // 重新把没有父id的数据设置一下父id;上级尚未入库时,新增记录先挂到根节点,全部分批完成后重建层级并清理无法挂载的数据
int unresolvedParentCount = 0; int unresolvedParentCount = 0;
for (Dept dept : allParam) { for (Dept dept : allParam) {
if (dept.getParentId() != null) { if (dept.getParentId() != null) {
@@ -604,7 +611,7 @@ public class OASyncServiceImpl implements IOASyncService {
} }
} }
if (unresolvedParentCount > 0) { if (unresolvedParentCount > 0) {
ComposeLogUtil.getLastLog().warn("同步{}时有{}条上级尚未入库,已先保存,分批结束后按OA主键重建层级", ComposeLogUtil.getLastLog().warn("同步{}时有{}条上级尚未入库,已先保存,分批结束后重建层级并清理无法挂载数据",
deptCategory.getName(), unresolvedParentCount); deptCategory.getName(), unresolvedParentCount);
} }