From 0b2348f8fc88118028d6eb4da1be736f9dfeb55c Mon Sep 17 00:00:00 2001 From: b2894lxlx <517289602@qq.com> Date: Mon, 2 Nov 2026 16:44:06 +0800 Subject: [PATCH] =?UTF-8?q?:zap:=20OA=E4=BA=BA=E5=91=98=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E6=8C=89=E5=B7=A5=E5=8F=B7=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- .../system/convert/UserConvert.java | 39 +++- .../service/impl/OASyncServiceImpl.java | 6 +- .../service/impl/OaUserListSyncHelper.java | 220 ++++-------------- 3 files changed, 82 insertions(+), 183 deletions(-) diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/convert/UserConvert.java b/blade-service/blade-system/src/main/java/org/springblade/system/convert/UserConvert.java index 2dabbf04..e1167b0e 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/convert/UserConvert.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/convert/UserConvert.java @@ -70,14 +70,14 @@ public interface UserConvert { @Mapping(source = "lastname", target = "realName") @Mapping(source = "mobile", target = "phone") @Mapping(source = "email", target = "email") - @Mapping(source = "loginid", target = "oaLoginId") + @Mapping(target = "oaLoginId", ignore = true) @Mapping(source = "modified", target = "oaModified") User baseConvert(OAPersonResponse person); @Mapping(source = "subcompanyname", target = "companyName") @Mapping(source = "departmentname", target = "deptName") @Mapping(source = "id", target = "oaId") - @Mapping(source = "loginid", target = "oaLoginId") + @Mapping(target = "oaLoginId", ignore = true) UserDept userDeptConvert(OAPersonResponse person); /** @@ -88,6 +88,7 @@ public interface UserConvert { */ default User person2user(OAPersonResponse person, String defaultPassword) { User user = baseConvert(person); + user.setOaLoginId(resolveOaLoginId(person)); user.setAccount(resolveAccount(person)); // OA 可能返回多号(如 133.../137...),只保留首个号码再入库加密 user.setPhone(normalizeMobile(user.getPhone())); @@ -106,6 +107,22 @@ public interface UserConvert { return user; } + /** + * 解析 OA 登录名:优先工号 workcode,其次 loginid + */ + default String resolveOaLoginId(OAPersonResponse person) { + if (person == null) { + return null; + } + if (StringUtils.isNotBlank(person.getWorkcode())) { + return person.getWorkcode().trim(); + } + if (StringUtils.isNotBlank(person.getLoginid())) { + return person.getLoginid().trim(); + } + return null; + } + /** * 规范化手机号:去空白,多号时取第一个 */ @@ -124,7 +141,7 @@ public interface UserConvert { } /** - * 解析本系统登录账号:优先 OA loginid,其次工号,最后手机号 + * 解析本系统登录账号:优先工号 workcode,其次 OA loginid,最后手机号 * * @param person OA人员 * @return 账号,无法识别时返回 null @@ -133,12 +150,12 @@ public interface UserConvert { if (person == null) { return null; } - if (StringUtils.isNotBlank(person.getLoginid())) { - return person.getLoginid().trim(); - } if (StringUtils.isNotBlank(person.getWorkcode())) { return person.getWorkcode().trim(); } + if (StringUtils.isNotBlank(person.getLoginid())) { + return person.getLoginid().trim(); + } if (StringUtils.isNotBlank(person.getMobile())) { return person.getMobile().trim(); } @@ -148,7 +165,7 @@ public interface UserConvert { /** * oa人员转本系统用户部门 * @param person - * @param userMap OA登录名与用户id + * @param userMap 同步键(W:工号)与用户id * @return */ default UserDept person2userDept(OAPersonResponse person, Map userMap) { @@ -162,9 +179,11 @@ public interface UserConvert { userDept.setStatus(status); // 排序 userDept.setSort(OAUtils.parseInt(person.getDsporder())); - // 用户id,按 OA 登录名关联本批已新增或更新的用户 - String oaLoginId = person == null ? null : StringUtils.trimToNull(person.getLoginid()); - userDept.setUserId(oaLoginId == null ? null : userMap.get(oaLoginId)); + // 用户id,按工号同步键关联本批已新增或更新的用户 + String oaLoginId = resolveOaLoginId(person); + userDept.setOaLoginId(oaLoginId); + String workcode = person == null ? null : StringUtils.trimToNull(person.getWorkcode()); + userDept.setUserId(workcode == null ? null : userMap.get("W:" + workcode)); userDept.setSyncTime(new Date()); return userDept; } 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 21d62c4a..3d40bc8e 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 @@ -278,9 +278,7 @@ public class OASyncServiceImpl implements IOASyncService { OaUserListSyncHelper.OaOrgIndex orgIndex = oaUserListSyncHelper.syncOrgsFromPersons(oaPersons); OaUserListSyncHelper.PersonSyncCount personSyncCount = oaUserListSyncHelper.handlePerson(oaPersons, orgIndex); if (startTime == null) { - oaUserListSyncHelper.removeOaUsersAbsentFrom( - oaUserListSyncHelper.extractOaLoginIds(oaPersons), - oaUserListSyncHelper.extractWorkcodes(oaPersons)); + oaUserListSyncHelper.removeOaUsersAbsentFrom(oaUserListSyncHelper.extractWorkcodes(oaPersons)); } CacheUtil.clear(USER_CACHE); CacheUtil.clear(SYS_CACHE); @@ -300,7 +298,7 @@ public class OASyncServiceImpl implements IOASyncService { private OaPersonSyncPageVO syncPersonFromOaPage(int current, int size, boolean incremental, String modifiedSince) { int pageNo = current < 1 ? 1 : current; int pageSize = size < 1 ? 20 : Math.min(size, 200); - // 全量同步首页开启原始数据收集,并开始累积登录名,最后一页再删除本地多余人员 + // 全量同步首页开启原始数据收集,并开始累积工号,最后一页再删除本地多余人员 if (!incremental && pageNo == 1) { oaSyncRawDumpHelper.beginFullDump(); oaUserListSyncHelper.beginFullSyncReconcile(); diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OaUserListSyncHelper.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OaUserListSyncHelper.java index d4c89dc2..a99147a6 100644 --- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OaUserListSyncHelper.java +++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/OaUserListSyncHelper.java @@ -87,10 +87,8 @@ public class OaUserListSyncHelper { private static final String OA_PERSON_STATUS_RESIGNED = "5"; /** - * 全量同步跨页累积的 OA 登录名。分页接口每页独立事务,删除必须等最后一页再执行。 + * 全量同步跨页累积的 OA 工号。分页接口每页独立事务,删除必须等最后一页再执行。 */ - private final Set fullSyncLoginIds = ConcurrentHashMap.newKeySet(); - private final Set fullSyncWorkcodes = ConcurrentHashMap.newKeySet(); private volatile boolean fullSyncCollecting; @@ -409,16 +407,15 @@ public class OaUserListSyncHelper { } /** - * 全量同步从第一页开始收集 OA 登录名,最后一页再删除本地多余的 is_oa=2 人员。 + * 全量同步从第一页开始收集 OA 工号,最后一页再删除本地多余的 is_oa=2 人员。 */ public synchronized void beginFullSyncReconcile() { - this.fullSyncLoginIds.clear(); this.fullSyncWorkcodes.clear(); this.fullSyncCollecting = true; } /** - * 累积本页 OA 人员登录名,供全量同步结束后比对删除。 + * 累积本页 OA 人员工号,供全量同步结束后比对删除。 * * @param oaPersons 本页 OA 人员 */ @@ -426,49 +423,26 @@ public class OaUserListSyncHelper { if (!this.fullSyncCollecting || CollectionUtil.isEmpty(oaPersons)) { return; } - this.fullSyncLoginIds.addAll(this.extractOaLoginIds(oaPersons)); this.fullSyncWorkcodes.addAll(this.extractWorkcodes(oaPersons)); } /** - * 全量同步结束后,删除登录名不在本次 OA 数据中的 is_oa=2 人员。 + * 全量同步结束后,删除工号不在本次 OA 数据中的 is_oa=2 人员。 * - * @return 删除人数;未开始收集或登录名集合为空时返回 0,避免误删全部 OA 人员 + * @return 删除人数;未开始收集或工号集合为空时返回 0,避免误删全部 OA 人员 */ public synchronized int finishFullSyncReconcile() { if (!this.fullSyncCollecting) { return 0; } this.fullSyncCollecting = false; - Set oaLoginIds = new LinkedHashSet<>(this.fullSyncLoginIds); Set workcodes = new LinkedHashSet<>(this.fullSyncWorkcodes); - this.fullSyncLoginIds.clear(); this.fullSyncWorkcodes.clear(); - return this.removeOaUsersAbsentFrom(oaLoginIds, workcodes); + return this.removeOaUsersAbsentFrom(workcodes); } /** - * 提取仍在职的 OA 人员登录名。离职人员不计入,全量同步结束时会删掉对应本地账号。 - * - * @param oaPersons OA人员 - * @return 去重后的登录名 - */ - public Set extractOaLoginIds(List oaPersons) { - Set oaLoginIds = new LinkedHashSet<>(); - if (CollectionUtil.isEmpty(oaPersons)) { - return oaLoginIds; - } - for (OAPersonResponse oaPerson : oaPersons) { - String oaLoginId = this.resolveOaLoginId(oaPerson); - if (oaLoginId != null && !this.isOaResigned(oaPerson)) { - oaLoginIds.add(oaLoginId); - } - } - return oaLoginIds; - } - - /** - * 提取仍在职人员的工号。没有登录名时靠工号保留本地账号。 + * 提取仍在职人员的工号。离职人员不计入,全量同步结束时会删掉对应本地账号。 * * @param oaPersons OA人员 * @return 去重后的工号 @@ -488,25 +462,21 @@ public class OaUserListSyncHelper { } /** - * 删除当前租户中 is_oa=2、且既不在本次登录名里、也不是无登录名工号人员的账号。 - * 登录名和工号都没收集到时不删除。当前登录账号即使不在同步数据中也保留。 + * 删除当前租户中 is_oa=2、且工号不在本次同步工号集合中的账号。 + * 未收集到工号时不删除。当前登录账号即使不在同步数据中也保留。 * - * @param oaLoginIds 本次全量同步出现过的 OA 登录名 * @param workcodes 本次全量同步出现过的工号 * @return 删除人数 */ - public int removeOaUsersAbsentFrom(Set oaLoginIds, Set workcodes) { - boolean noLoginIds = CollectionUtil.isEmpty(oaLoginIds); - boolean noWorkcodes = CollectionUtil.isEmpty(workcodes); - if (noLoginIds && noWorkcodes) { - ComposeLogUtil.getLastLog().warn("全量同步未收集到OA登录名和工号,跳过删除本地 is_oa=2 人员"); + public int removeOaUsersAbsentFrom(Set workcodes) { + if (CollectionUtil.isEmpty(workcodes)) { + ComposeLogUtil.getLastLog().warn("全量同步未收集到OA工号,跳过删除本地 is_oa=2 人员"); return 0; } - Set loginIdSet = noLoginIds ? Set.of() : oaLoginIds; - Set workcodeSet = noWorkcodes ? Set.of() : workcodes; + Set workcodeSet = workcodes; String tenantId = this.resolveTenantId(); List oaUsers = this.userService.list(Wrappers.lambdaQuery() - .select(User::getId, User::getOaLoginId, User::getCode) + .select(User::getId, User::getCode) .eq(User::getTenantId, tenantId) .eq(User::getIsOa, CommonConstant.YES)); Long currentUserId = AuthUtil.getUserId(); @@ -519,11 +489,8 @@ public class OaUserListSyncHelper { ComposeLogUtil.getLastLog().warn("全量同步跳过删除当前登录账号 userId={}", oaUser.getId()); continue; } - String oaLoginId = StringUtils.trimToNull(oaUser.getOaLoginId()); String workcode = StringUtils.trimToNull(oaUser.getCode()); - boolean keptByLoginId = oaLoginId != null && loginIdSet.contains(oaLoginId); - boolean keptByWorkcode = oaLoginId == null && workcode != null && workcodeSet.contains(workcode); - if (!keptByLoginId && !keptByWorkcode) { + if (workcode == null || !workcodeSet.contains(workcode)) { removeIds.add(oaUser.getId()); } } @@ -535,54 +502,13 @@ public class OaUserListSyncHelper { } /** - * 按 OA 登录名删除已有 is_oa=2 人员。用于离职人员,全量和增量同步都会执行。 - * - * @param tenantId 租户 - * @param oaLoginIds 离职人员登录名 - * @return 删除人数 - */ - private int removeOaUsersByLoginIds(String tenantId, Collection oaLoginIds) { - if (CollectionUtil.isEmpty(oaLoginIds)) { - return 0; - } - List oaLoginIdList = oaLoginIds.stream() - .filter(StringUtils::isNotBlank) - .distinct() - .toList(); - if (oaLoginIdList.isEmpty()) { - return 0; - } - Long currentUserId = AuthUtil.getUserId(); - List removeIds = new ArrayList<>(); - for (int fromIndex = 0; fromIndex < oaLoginIdList.size(); fromIndex += OA_LOGIN_ID_BATCH_SIZE) { - List oaLoginIdBatch = oaLoginIdList.subList(fromIndex, Math.min(fromIndex + OA_LOGIN_ID_BATCH_SIZE, oaLoginIdList.size())); - this.userService.list(Wrappers.lambdaQuery() - .select(User::getId, User::getOaLoginId) - .eq(User::getTenantId, tenantId) - .eq(User::getIsOa, CommonConstant.YES) - .in(User::getOaLoginId, oaLoginIdBatch)) - .forEach(oaUser -> { - if (oaUser.getId() == null) { - return; - } - if (currentUserId != null && currentUserId > 0 && currentUserId.equals(oaUser.getId())) { - ComposeLogUtil.getLastLog().warn("同步跳过删除当前登录账号 userId={}", oaUser.getId()); - return; - } - removeIds.add(oaUser.getId()); - }); - } - return this.deleteOaUsers(removeIds, "同步删除OA离职人员"); - } - - /** - * 删除没有登录名、且工号属于离职人员的 is_oa=2 账号。 + * 按工号删除已有 is_oa=2 人员。用于离职人员,全量和增量同步都会执行。 * * @param tenantId 租户 * @param workcodes 离职人员工号 * @return 删除人数 */ - private int removeOaUsersByBlankLoginWorkcodes(String tenantId, Collection workcodes) { + private int removeOaUsersByWorkcodes(String tenantId, Collection workcodes) { if (CollectionUtil.isEmpty(workcodes)) { return 0; } @@ -598,11 +524,10 @@ public class OaUserListSyncHelper { for (int fromIndex = 0; fromIndex < workcodeList.size(); fromIndex += OA_LOGIN_ID_BATCH_SIZE) { List workcodeBatch = workcodeList.subList(fromIndex, Math.min(fromIndex + OA_LOGIN_ID_BATCH_SIZE, workcodeList.size())); this.userService.list(Wrappers.lambdaQuery() - .select(User::getId, User::getOaLoginId, User::getCode) + .select(User::getId, User::getCode) .eq(User::getTenantId, tenantId) .eq(User::getIsOa, CommonConstant.YES) - .in(User::getCode, workcodeBatch) - .and(wrapper -> wrapper.isNull(User::getOaLoginId).or().eq(User::getOaLoginId, ""))) + .in(User::getCode, workcodeBatch)) .forEach(oaUser -> { if (oaUser.getId() == null) { return; @@ -614,7 +539,7 @@ public class OaUserListSyncHelper { removeIds.add(oaUser.getId()); }); } - return this.deleteOaUsers(removeIds, "同步删除无登录名的OA离职人员"); + return this.deleteOaUsers(removeIds, "同步删除OA离职人员"); } /** @@ -645,7 +570,8 @@ public class OaUserListSyncHelper { } /** - * 同步人员并绑定到三级部门。有登录名按登录名更新,没有登录名但有工号则按工号更新且不回填登录名。离职人员直接删除。 + * 同步人员并绑定到三级部门。按工号 workcode(对应本地 code)匹配已有用户; + * OA登录名仍优先填 workcode,其次 loginid。无工号则跳过。离职人员按工号删除。 * * @param oaPersons OA人员 * @param orgIndex 组织索引 @@ -656,7 +582,6 @@ public class OaUserListSyncHelper { return new PersonSyncCount(0, 0, 0); } Map uniquePersonMap = new LinkedHashMap<>(); - Set resignedLoginIds = new LinkedHashSet<>(); Set resignedWorkcodes = new LinkedHashSet<>(); int skippedCount = 0; for (OAPersonResponse oaPerson : oaPersons) { @@ -665,49 +590,36 @@ public class OaUserListSyncHelper { skippedCount++; continue; } - String oaLoginId = this.resolveOaLoginId(oaPerson); String workcode = this.resolveWorkcode(oaPerson); if (this.isOaResigned(oaPerson)) { uniquePersonMap.remove(syncKey); - if (oaLoginId != null) { - resignedLoginIds.add(oaLoginId); - } else if (workcode != null) { + if (workcode != null) { resignedWorkcodes.add(workcode); } continue; } - if (oaLoginId != null) { - resignedLoginIds.remove(oaLoginId); - } else if (workcode != null) { + if (workcode != null) { resignedWorkcodes.remove(workcode); } uniquePersonMap.put(syncKey, oaPerson); } String tenantId = resolveTenantId(); - int removedCount = this.removeOaUsersByLoginIds(tenantId, resignedLoginIds) - + this.removeOaUsersByBlankLoginWorkcodes(tenantId, resignedWorkcodes); + int removedCount = this.removeOaUsersByWorkcodes(tenantId, resignedWorkcodes); if (uniquePersonMap.isEmpty()) { - if (resignedLoginIds.isEmpty() && resignedWorkcodes.isEmpty()) { - ComposeLogUtil.getLastLog().warn("OA人员均缺少登录名和工号,跳过人员同步"); + if (resignedWorkcodes.isEmpty()) { + ComposeLogUtil.getLastLog().warn("OA人员均缺少工号,跳过人员同步"); } return new PersonSyncCount(0, skippedCount, removedCount); } String defaultPassword = DigestUtil.encrypt(ParamCache.getValue(DEFAULT_PARAM_PASSWORD)); - Set oaLoginIds = new LinkedHashSet<>(); Set workcodes = new LinkedHashSet<>(); for (OAPersonResponse oaPerson : uniquePersonMap.values()) { - String oaLoginId = this.resolveOaLoginId(oaPerson); - if (oaLoginId != null) { - oaLoginIds.add(oaLoginId); - continue; - } String workcode = this.resolveWorkcode(oaPerson); if (workcode != null) { workcodes.add(workcode); } } - Map existingByOaLoginId = this.loadUsersByOaLoginId(tenantId, oaLoginIds); - Map existingByWorkcode = this.loadUsersByBlankLoginWorkcode(tenantId, workcodes); + Map existingByWorkcode = this.loadUsersByWorkcode(tenantId, workcodes); List users = new ArrayList<>(); Map userMap = new HashMap<>(); Set existsUserIds = new HashSet<>(); @@ -717,7 +629,7 @@ public class OaUserListSyncHelper { String workcode = this.resolveWorkcode(oaPerson); User user = this.userConvert.person2user(oaPerson, defaultPassword); user.setTenantId(tenantId); - User existingUser = oaLoginId != null ? existingByOaLoginId.get(oaLoginId) : existingByWorkcode.get(workcode); + User existingUser = workcode == null ? null : existingByWorkcode.get(workcode); if (oaLoginId != null) { user.setOaLoginId(oaLoginId); user.setAccount(oaLoginId); @@ -757,7 +669,7 @@ public class OaUserListSyncHelper { ComposeLogUtil.getLastLog().info("批量修改用户:{}", updateUsers.size()); userService.updateBatchById(updateUsers); } - ComposeLogUtil.getLastLog().info("缺少登录名和工号已跳过的人员:{}", skippedCount); + ComposeLogUtil.getLastLog().info("缺少工号已跳过的人员:{}", skippedCount); int syncedCount = addUsers.size() + updateUsers.size(); if (userMap.isEmpty()) { return new PersonSyncCount(0, skippedCount, removedCount); @@ -882,50 +794,9 @@ public class OaUserListSyncHelper { } /** - * 按 OA 登录名加载已有 is_oa=2 用户。同一登录名有多条时保留较早的一条,后续同步都更新这一条。 + * 按工号(User.code)加载已有 is_oa=2 用户。同一工号有多条时保留较早的一条,后续同步都更新这一条。 */ - private Map loadUsersByOaLoginId(String tenantId, Collection oaLoginIds) { - Map existingByOaLoginId = new HashMap<>(); - if (CollectionUtil.isEmpty(oaLoginIds)) { - return existingByOaLoginId; - } - List oaLoginIdList = oaLoginIds.stream() - .filter(StringUtils::isNotBlank) - .distinct() - .toList(); - for (int fromIndex = 0; fromIndex < oaLoginIdList.size(); fromIndex += OA_LOGIN_ID_BATCH_SIZE) { - List oaLoginIdBatch = oaLoginIdList.subList(fromIndex, Math.min(fromIndex + OA_LOGIN_ID_BATCH_SIZE, oaLoginIdList.size())); - userService.list(Wrappers.lambdaQuery() - .eq(User::getTenantId, tenantId) - .eq(User::getIsOa, CommonConstant.YES) - .in(User::getOaLoginId, oaLoginIdBatch)) - .forEach(user -> { - String oaLoginId = StringUtils.trimToNull(user.getOaLoginId()); - if (oaLoginId == null) { - return; - } - User previous = existingByOaLoginId.get(oaLoginId); - if (previous == null) { - existingByOaLoginId.put(oaLoginId, user); - return; - } - if (user.getId() != null && previous.getId() != null && user.getId() < previous.getId()) { - ComposeLogUtil.getLastLog().warn("OA登录名重复,保留较早用户 oaLoginId={} keepUserId={} dropUserId={}", - oaLoginId, user.getId(), previous.getId()); - existingByOaLoginId.put(oaLoginId, user); - return; - } - ComposeLogUtil.getLastLog().warn("OA登录名重复,保留较早用户 oaLoginId={} keepUserId={} dropUserId={}", - oaLoginId, previous.getId(), user.getId()); - }); - } - return existingByOaLoginId; - } - - /** - * 按工号加载没有登录名的 is_oa=2 用户。同一工号有多条时保留较早的一条。 - */ - private Map loadUsersByBlankLoginWorkcode(String tenantId, Collection workcodes) { + private Map loadUsersByWorkcode(String tenantId, Collection workcodes) { Map existingByWorkcode = new HashMap<>(); if (CollectionUtil.isEmpty(workcodes)) { return existingByWorkcode; @@ -939,26 +810,41 @@ public class OaUserListSyncHelper { this.userService.list(Wrappers.lambdaQuery() .eq(User::getTenantId, tenantId) .eq(User::getIsOa, CommonConstant.YES) - .in(User::getCode, workcodeBatch) - .and(wrapper -> wrapper.isNull(User::getOaLoginId).or().eq(User::getOaLoginId, ""))) + .in(User::getCode, workcodeBatch)) .forEach(user -> { String workcode = StringUtils.trimToNull(user.getCode()); if (workcode == null) { return; } User previous = existingByWorkcode.get(workcode); - if (previous == null || (user.getId() != null && previous.getId() != null && user.getId() < previous.getId())) { + if (previous == null) { existingByWorkcode.put(workcode, user); + return; } + if (user.getId() != null && previous.getId() != null && user.getId() < previous.getId()) { + ComposeLogUtil.getLastLog().warn("OA工号重复,保留较早用户 workcode={} keepUserId={} dropUserId={}", + workcode, user.getId(), previous.getId()); + existingByWorkcode.put(workcode, user); + return; + } + ComposeLogUtil.getLastLog().warn("OA工号重复,保留较早用户 workcode={} keepUserId={} dropUserId={}", + workcode, previous.getId(), user.getId()); }); } return existingByWorkcode; } + /** + * OA登录名:优先 workcode,其次 loginid。仅用于填充 oaLoginId/account,不参与匹配。 + */ private String resolveOaLoginId(OAPersonResponse oaPerson) { if (oaPerson == null) { return null; } + String workcode = StringUtils.trimToNull(oaPerson.getWorkcode()); + if (workcode != null) { + return workcode; + } return StringUtils.trimToNull(oaPerson.getLoginid()); } @@ -970,13 +856,9 @@ public class OaUserListSyncHelper { } /** - * 有登录名用登录名,没有登录名但有工号用工号。两者都没有则不同步。 + * 同步去重与匹配键:仅使用工号。无工号则不同步。 */ private String resolveSyncKey(OAPersonResponse oaPerson) { - String oaLoginId = this.resolveOaLoginId(oaPerson); - if (oaLoginId != null) { - return "L:" + oaLoginId; - } String workcode = this.resolveWorkcode(oaPerson); if (workcode != null) { return "W:" + workcode;