diff --git a/zt-framework/zt-common/src/main/java/com/zt/plat/framework/common/exception/enums/GlobalErrorCodeConstants.java b/zt-framework/zt-common/src/main/java/com/zt/plat/framework/common/exception/enums/GlobalErrorCodeConstants.java index ae712088..a01ff26e 100644 --- a/zt-framework/zt-common/src/main/java/com/zt/plat/framework/common/exception/enums/GlobalErrorCodeConstants.java +++ b/zt-framework/zt-common/src/main/java/com/zt/plat/framework/common/exception/enums/GlobalErrorCodeConstants.java @@ -25,6 +25,7 @@ public interface GlobalErrorCodeConstants { ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确"); ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许 ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试"); + ErrorCode NOT_NULL_REQUEST_ERROR = new ErrorCode(430, "请求参数不能为空"); // ========== 服务端错误段 ========== diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/esp/EspApiImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/esp/EspApiImpl.java index 5cf33fa5..97c8a031 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/esp/EspApiImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/api/esp/EspApiImpl.java @@ -1,6 +1,8 @@ package com.zt.plat.module.system.api.esp; +import com.zt.plat.framework.common.exception.enums.GlobalErrorCodeConstants; import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.common.util.object.ObjectUtils; import com.zt.plat.module.system.api.dept.dto.DeptSaveReqDTO; import com.zt.plat.module.system.api.esp.dto.EspDto; import com.zt.plat.module.system.service.dept.IEspService; @@ -8,6 +10,7 @@ import jakarta.annotation.Resource; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; import java.util.List; +import java.util.Objects; @RestController @Validated @@ -19,6 +22,11 @@ public class EspApiImpl implements EspApi { @Override public CommonResult> pushMsg(DeptSaveReqDTO syncReqDTO) { + if(Objects.isNull(syncReqDTO) || null == syncReqDTO.getId()) + { + return CommonResult.error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), + "ID不能为空"); + } return CommonResult.success(deptService.pushMsg(syncReqDTO)); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/EspController.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/EspController.java index 8ae5afa5..3a7d88da 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/EspController.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/dept/EspController.java @@ -14,6 +14,7 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import org.apache.commons.collections.CollectionUtils; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -94,13 +95,13 @@ public class EspController private void fillDeptInfo(List list) { - if (list == null || list.isEmpty()) { + if (CollectionUtils.isEmpty(list)) { return; } Set deptIds = list.stream() .map(EspSaveRespVo::getDeptId) .collect(Collectors.toCollection(HashSet::new)); - if (deptIds == null || deptIds.isEmpty()) { + if (CollectionUtils.isEmpty(deptIds)) { return; } Map deptMap = deptService.getDeptList(deptIds).stream() diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java index b5a63c35..88adb502 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/IWorkIntegrationController.java @@ -6,6 +6,7 @@ import com.zt.plat.module.system.controller.admin.integration.iwork.vo.*; import com.zt.plat.module.system.service.integration.iwork.IWorkIntegrationService; import com.zt.plat.module.system.service.integration.iwork.IWorkOrgRestService; import com.zt.plat.module.system.service.integration.iwork.IWorkSyncService; +import lombok.extern.slf4j.Slf4j; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.security.PermitAll; @@ -18,9 +19,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; - import static com.zt.plat.framework.common.pojo.CommonResult.success; - /** * 提供统一 iWork 流程能力的管理端接口。 */ @@ -29,6 +28,7 @@ import static com.zt.plat.framework.common.pojo.CommonResult.success; @RequestMapping("/system/integration/iwork") @RequiredArgsConstructor @Validated +@Slf4j public class IWorkIntegrationController { private final IWorkIntegrationService integrationService; @@ -139,6 +139,17 @@ public class IWorkIntegrationController { return success(syncService.fullSyncUsers(reqVO)); } + // ----------------- 根据ID同步到本地 ----------------- + + @PostMapping("/syncById") + @Operation(summary = "根据ID触发 iWork 同步公司") + public CommonResult syncById(@Valid @RequestBody IWorkSyncByIdReqVO reqVO) { + + log.error("IWork集成后端手动录入syncById{}",reqVO); + return success(syncService.manuallySyncData(reqVO)); + } + + private ResponseEntity buildOaResponse(IWorkOaRawResponse resp) { if (resp == null) { return ResponseEntity.internalServerError().body("OA 响应为空"); diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkFullSyncReqVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkFullSyncReqVO.java index 09fe2d3e..e3793181 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkFullSyncReqVO.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkFullSyncReqVO.java @@ -56,4 +56,8 @@ public class IWorkFullSyncReqVO { } return resolved; } + + + + } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncByIdReqVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncByIdReqVO.java new file mode 100644 index 00000000..c91a3f66 --- /dev/null +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncByIdReqVO.java @@ -0,0 +1,99 @@ +package com.zt.plat.module.system.controller.admin.integration.iwork.vo; + +import com.zt.plat.module.system.enums.integration.IWorkSyncEntityTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * iWork 手动同步请求 + */ +@Data +public class IWorkSyncByIdReqVO { + + + @Schema(description = "起始页码,从 1 开始", example = "1") + @Min(1) + private Integer startPage = 1; + + @Schema(description = "最大处理页数,null 表示处理至 iWork 返回的末页", example = "10") + @Min(1) + private Integer maxPages; + + @Schema(description = "每次分页从 iWork 拉取的记录数", example = "100") + @Min(1) + @Max(500) + private Integer pageSize = 100; + + @Schema(description = "同步范围列表,默认同步全部。可选:subcompany、department、jobTitle、user") + private List scopes; + + @Schema(description = "是否包含已失效(canceled=1)的记录", example = "false") + private Boolean includeCanceled = Boolean.FALSE; + + @Schema(description = "是否允许更新已存在的本地实体", example = "false") + private Boolean allowUpdate = Boolean.FALSE; + + + @Schema(description = "指定同步记录的 iWork ID。传入后仅同步对应记录", example = "12345") + @NotBlank(message = "ID不能为空") + private String id; + + @Schema(description = "部门编码", example = "ZT001") + private String code; + + @Schema(description = "部门名称", example = "ZT") + private String name; + + @Schema(description = "部门简称", example = "技术") + private String shortName; + + @Schema(description = "父部门 ID", example = "1024") + private String parentId; + + @Schema(description = "负责人的用户编号", example = "2048") + private String leaderUserId; + + @Schema(description = "联系电话", example = "15601691000") + private String phone; + + @Schema(description = "邮箱", example = "zt@iocoder.cn") + private String email; + + @Schema(description = "状态,见 CommonStatusEnum 枚举0 开启 1 关闭", example = "0") + private Integer status; + + private Long tenantId; + + @Schema(description = "是否公司", example = "false") + private boolean isCompany; + + @Schema(description = "是否集团", example = "false") + private boolean isGroup; + + private boolean hasChildren; + + + public Set resolveScopes() { + EnumSet defaults = EnumSet.allOf(IWorkSyncEntityTypeEnum.class); + if (scopes == null || scopes.isEmpty()) { + return defaults; + } + Set resolved = scopes.stream() + .map(IWorkSyncEntityTypeEnum::fromCode) + .filter(java.util.Objects::nonNull) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(IWorkSyncEntityTypeEnum.class))); + if (resolved.isEmpty()) { + return defaults; + } + return resolved; + } + +} diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/EspMapper.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/EspMapper.java index 804f9362..80466f46 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/EspMapper.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/dal/mysql/dept/EspMapper.java @@ -56,10 +56,10 @@ public interface EspMapper extends BaseMapperX { return selectList(DeptPushMsgDO::getSystemCode, systemCode); } - @Select("SELECT ID,DEPT_ID, SYSTEM_CODE,EXTERNAL_DEPT_CODE,EXTERNAL_DEPT_NAME,STATUS,REMARK,TENANT_ID,CREATOR,CREATE_TIME,UPDATER,UPDATE_TIME\n" + - "FROM \n" + - "\t\tSYSTEM_DEPT_PUSH_MSG\n" + - "WHERE\n" + - " IS_SEND_MSG = '0' AND DELETED = '0' ") + @Select("SELECT ID,DEPT_ID, SYSTEM_CODE,EXTERNAL_DEPT_CODE,EXTERNAL_DEPT_NAME,STATUS,REMARK,TENANT_ID,CREATOR,CREATE_TIME,UPDATER,UPDATE_TIME" + + "FROM" + + "SYSTEM_DEPT_PUSH_MSG" + + "WHERE" + + " ID = #{id} AND IS_SEND_MSG = '0' AND DELETED = '0' ") List selectpushMsg(@Param("syncReqDTO") DeptSaveReqDTO syncReqDTO); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncProcessor.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncProcessor.java index 17ec9b6a..5fa3a802 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncProcessor.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncProcessor.java @@ -19,19 +19,19 @@ public interface IWorkSyncProcessor { BatchResult syncSubcompanies(List data, SyncOptions options); - + // 同步子公司 BatchResult syncSubcompanies(List data, SyncOptions options, DeptSyncContext context); BatchResult syncDepartments(List data, SyncOptions options); - + // 同步部门 BatchResult syncDepartments(List data, SyncOptions options, DeptSyncContext context); - + // 同步岗位 BatchResult syncJobTitles(List data, SyncOptions options); - + // 同步用户 BatchResult syncUsers(List data, SyncOptions options); /** diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java index 47c70b70..c39dbaf6 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java @@ -2,6 +2,9 @@ package com.zt.plat.module.system.service.integration.iwork; import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkFullSyncReqVO; import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkFullSyncRespVO; +import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkSyncByIdReqVO; +import jakarta.validation.Valid; +import java.util.List; /** * iWork 组织/人员同步服务 @@ -28,4 +31,8 @@ public interface IWorkSyncService { */ IWorkFullSyncRespVO fullSyncUsers(IWorkFullSyncReqVO reqVO); + /** + * 手动同步 + */ + IWorkFullSyncRespVO manuallySyncData(@Valid IWorkSyncByIdReqVO list); } diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java index abf94ac4..0d44b790 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncProcessorImpl.java @@ -52,7 +52,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { public BatchResult syncSubcompanies(List data, SyncOptions options) { return syncSubcompanies(data, options, null); } - + //1、同步子公司 @Override public BatchResult syncSubcompanies(List data, SyncOptions options, @@ -154,7 +154,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { } return result; } - + //2、同步部门 @Override public BatchResult syncDepartments(List data, SyncOptions options) { return syncDepartments(data, options, null); @@ -272,7 +272,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { result.merge(syncDepartmentsInternal(Collections.emptyList(), options, context, true)); return result; } - + //TODO 3、同步岗位 @Override public BatchResult syncJobTitles(List data, SyncOptions options) { List records = CollUtil.emptyIfNull(data); @@ -310,7 +310,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { } return result; } - + //TODO 4、同步用户 @Override public BatchResult syncUsers(List data, SyncOptions options) { List records = CollUtil.emptyIfNull(data); @@ -377,7 +377,7 @@ public class IWorkSyncProcessorImpl implements IWorkSyncProcessor { } return result; } - + //TODO private DeptSyncOutcome upsertDept(Long deptId, DeptSaveReqVO desired, boolean disabled, diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java index b06959d6..95ac0cdc 100644 --- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java +++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkSyncServiceImpl.java @@ -12,6 +12,7 @@ import com.zt.plat.module.system.service.integration.iwork.IWorkSyncService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.EnumSet; @@ -34,32 +35,59 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { private final IWorkSyncProcessor syncProcessor; private final DeptService deptService; + /** + * 同步部门 + */ @Override public IWorkFullSyncRespVO fullSyncDepartments(IWorkFullSyncReqVO reqVO) { return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.DEPARTMENT)); } + /** + * 仅同步分部 + */ @Override public IWorkFullSyncRespVO fullSyncSubcompanies(IWorkFullSyncReqVO reqVO) { return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.SUBCOMPANY)); } + /** + * 仅同步岗位 + */ @Override public IWorkFullSyncRespVO fullSyncJobTitles(IWorkFullSyncReqVO reqVO) { return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.JOB_TITLE)); } + /** + * 仅同步人员(会自动包含依赖的分部、部门) + */ @Override public IWorkFullSyncRespVO fullSyncUsers(IWorkFullSyncReqVO reqVO) { return runFullSync(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.USER)); } + /** + * 手动同步 + */ + @Transactional + @Override + public IWorkFullSyncRespVO manuallySyncData(IWorkSyncByIdReqVO reqVO) { + return manuallySyncData(reqVO, EnumSet.of(IWorkSyncEntityTypeEnum.USER)); + } + + /** + * 全量同步方法 + * @param reqVO 请求参数 + * @param scopes 同步范围 + * @return 响应对象 + */ private IWorkFullSyncRespVO runFullSync(IWorkFullSyncReqVO reqVO, Set scopes) { - IWorkFullSyncRespVO respVO = new IWorkFullSyncRespVO(); + IWorkFullSyncRespVO respVO = new IWorkFullSyncRespVO();//1 初始化响应对象:创建响应VO并设置分页大小和批次统计列表 respVO.setPageSize(reqVO.getPageSize()); List batchStats = new ArrayList<>(); respVO.setBatches(batchStats); - + //2 解析同步范围:根据传入的scopes确定需要同步的实体类型(用户、部门、分部、岗位) boolean syncUsers = scopes.contains(IWorkSyncEntityTypeEnum.USER); boolean syncDepartments = scopes.contains(IWorkSyncEntityTypeEnum.DEPARTMENT); boolean syncSubcompanies = scopes.contains(IWorkSyncEntityTypeEnum.SUBCOMPANY); @@ -69,18 +97,20 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { IWorkSyncProcessor.DeptSyncContext deptSyncContext = (syncDepartments || syncSubcompanies) ? new IWorkSyncProcessor.DeptSyncContext() : null; - if (syncSubcompanies) { + //3 按类型执行同步:依次执行分部、部门、岗位、用户的分页同步操作 + if (syncSubcompanies) { //公司 processedPages += executeSubcompanyFullSync(reqVO, options, respVO.getSubcompanyStat(), batchStats, deptSyncContext); } - if (syncDepartments) { + if (syncDepartments) { //部门 processedPages += executeDepartmentFullSync(reqVO, options, respVO.getDepartmentStat(), batchStats, deptSyncContext); } - if (syncJobTitle) { + if (syncJobTitle) { // 岗位 processedPages += executeJobTitleFullSync(reqVO, options, respVO.getJobTitleStat(), batchStats); } - if (syncUsers) { + if (syncUsers) { //人员 processedPages += executeUserFullSync(reqVO, options, respVO.getUserStat(), batchStats); } + //4、处理部门上下文:对部门和分部同步进行特殊处理,包括刷新待处理数据和补全部门编码 if (deptSyncContext != null) { IWorkSyncProcessor.BatchResult flushResult = syncProcessor.flushDeptPending(deptSyncContext, options); updateStat(respVO.getDepartmentStat(), flushResult, 0); @@ -92,6 +122,9 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { return respVO; } + /** + * 全量执行子公司全量同步 + */ private int executeSubcompanyFullSync(IWorkFullSyncReqVO reqVO, IWorkSyncProcessor.SyncOptions options, IWorkSyncEntityStatVO stat, @@ -103,7 +136,7 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { query.setPagesize(pageSize); applyQueryConditions(query, reqVO); IWorkHrSubcompanyPageRespVO pageResp = orgRestService.listSubcompanies(query); - ensureIWorkSuccess("拉取分部", pageResp.isSuccess(), pageResp.getMessage()); + ensureIWorkSuccess("拉取分部", pageResp.isSuccess(), pageResp.getMessage());// IWork执行成功 List dataList = CollUtil.emptyIfNull(pageResp.getDataList()); IWorkSyncProcessor.BatchResult result = syncProcessor.syncSubcompanies(dataList, options, context); updateStat(stat, result, dataList.size()); @@ -111,6 +144,9 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { }); } + /** + * 执行部门全量同步 + */ private int executeDepartmentFullSync(IWorkFullSyncReqVO reqVO, IWorkSyncProcessor.SyncOptions options, IWorkSyncEntityStatVO stat, @@ -130,6 +166,9 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { }); } + /** + * 执行岗位全量同步 + */ private int executeJobTitleFullSync(IWorkFullSyncReqVO reqVO, IWorkSyncProcessor.SyncOptions options, IWorkSyncEntityStatVO stat, @@ -148,6 +187,9 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { }); } + /** + * 执行用户全量同步 + */ private int executeUserFullSync(IWorkFullSyncReqVO reqVO, IWorkSyncProcessor.SyncOptions options, IWorkSyncEntityStatVO stat, @@ -193,6 +235,12 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { return processedPages; } + /** + * 更新统计 + * @param stat 统计 + * @param result 结果 + * @param pulled 拉取数量 + */ private void updateStat(IWorkSyncEntityStatVO stat, IWorkSyncProcessor.BatchResult result, int pulled) { stat.incrementPulled(pulled); stat.incrementCreated(result.getCreated()); @@ -201,6 +249,11 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { stat.incrementFailed(result.getFailed()); } + /** + * 查询条件 + * @param query 查询条件 + * @param reqVO 请求 + */ private void applyQueryConditions(IWorkOrgBaseQueryReqVO query, IWorkFullSyncReqVO reqVO) { if (query == null || reqVO == null) { return; @@ -216,6 +269,9 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { params.put("id", reqVO.getId()); } + /** + * 全量同步 + */ private IWorkSyncProcessor.SyncOptions buildFullSyncOptions(IWorkFullSyncReqVO reqVO) { boolean includeCanceled = Boolean.TRUE.equals(reqVO.getIncludeCanceled()); boolean allowUpdate = Boolean.TRUE.equals(reqVO.getAllowUpdate()); @@ -237,4 +293,197 @@ public class IWorkSyncServiceImpl implements IWorkSyncService { private record BatchExecution(IWorkSyncProcessor.BatchResult result, int totalPulled) { } + + + /** + * 根据ID同步 + */ + private IWorkFullSyncRespVO manuallySyncData(IWorkSyncByIdReqVO reqVO, Set scopes) { + + //1 初始化响应对象:创建响应VO并设置分页大小和批次统计列表 + IWorkFullSyncRespVO respVO = new IWorkFullSyncRespVO(); + List batchStats = new ArrayList<>(); + respVO.setBatches(batchStats); + //2 解析同步范围:根据传入的scopes确定需要同步的实体类型(用户、部门、分部、岗位) + boolean syncUsers = scopes.contains(IWorkSyncEntityTypeEnum.USER); + boolean syncDepartments = scopes.contains(IWorkSyncEntityTypeEnum.DEPARTMENT); + boolean syncSubcompanies = scopes.contains(IWorkSyncEntityTypeEnum.SUBCOMPANY); + boolean syncJobTitle = scopes.contains(IWorkSyncEntityTypeEnum.JOB_TITLE); + int processedPages = 0; + IWorkSyncProcessor.SyncOptions options = manualSync(reqVO); + IWorkSyncProcessor.DeptSyncContext deptSyncContext = (syncDepartments || syncSubcompanies) + ? new IWorkSyncProcessor.DeptSyncContext() + : null; + //3 按类型执行同步:依次执行分部、部门、岗位、用户的分页同步操作 + if (syncSubcompanies) { + processedPages += runManualFullSyncForSubsidiaries(reqVO, options, respVO.getSubcompanyStat(), batchStats, deptSyncContext);//分部统计信息 + } + if (syncDepartments) { + processedPages += departments(reqVO, options, respVO.getDepartmentStat(), batchStats, deptSyncContext);//部门统计信息 + } + if (syncJobTitle) { + processedPages += syncPositionsManually(reqVO, options, respVO.getJobTitleStat(), batchStats);//岗位统计信息 + } + if (syncUsers) { + processedPages += syncUsers(reqVO, options, respVO.getUserStat(), batchStats);//用户统计信息 + } + //4、处理部门上下文:对部门和分部同步进行特殊处理,包括刷新待处理数据和补全部门编码 + if (deptSyncContext != null) { + IWorkSyncProcessor.BatchResult flushResult = syncProcessor.flushDeptPending(deptSyncContext, options); + updateStat(respVO.getDepartmentStat(), flushResult, 0);//部门统计信息 + if (CollUtil.isNotEmpty(deptSyncContext.getPlaceholderDeptIds())) { + deptService.backfillMissingCodesWithoutEvent(deptSyncContext.getPlaceholderDeptIds()); + } + } + respVO.setProcessedPages(processedPages); + return respVO; + } + + + /** + * 手动同步 + */ + private IWorkSyncProcessor.SyncOptions manualSync(IWorkSyncByIdReqVO reqVO) { + boolean includeCanceled = Boolean.TRUE.equals(reqVO.getIncludeCanceled()); + boolean allowUpdate = Boolean.TRUE.equals(reqVO.getAllowUpdate()); + return IWorkSyncProcessor.SyncOptions.custom(includeCanceled, allowUpdate, true); + } + + + /** + * 手动执行子公司全量同步f + */ + private int runManualFullSyncForSubsidiaries(IWorkSyncByIdReqVO reqVO, + IWorkSyncProcessor.SyncOptions options, + IWorkSyncEntityStatVO stat, + List batches, + IWorkSyncProcessor.DeptSyncContext context) { + return paged(reqVO, IWorkSyncEntityTypeEnum.SUBCOMPANY, batches, (page, pageSize) -> { + IWorkSubcompanyQueryReqVO query = new IWorkSubcompanyQueryReqVO(); + query.setCurpage(page); + query.setPagesize(pageSize); + applyQuery(query, reqVO);//查询条件 + IWorkHrSubcompanyPageRespVO pageResp = orgRestService.listSubcompanies(query); + ensureIWorkSuccess("拉取分部", pageResp.isSuccess(), pageResp.getMessage());// IWork执行成功 + List dataList = CollUtil.emptyIfNull(pageResp.getDataList()); + IWorkSyncProcessor.BatchResult result = syncProcessor.syncSubcompanies(dataList, options, context); + updateStat(stat, result, dataList.size()); + return new BatchExecution(result, dataList.size()); + }); + } + + + /** + * 查询条件 + * @param query 查询条件 + * @param reqVO 请求 + */ + private void applyQuery(IWorkOrgBaseQueryReqVO query, IWorkSyncByIdReqVO reqVO) { + if (query == null || reqVO == null) { + return; + } + if (StrUtil.isBlank(reqVO.getId())) { + return; + } + Map params = query.getParams(); + if (params == null) { + params = new HashMap<>(); + query.setParams(params); + } + params.put("id", reqVO.getId()); + } + + + private int paged(IWorkSyncByIdReqVO reqVO, + IWorkSyncEntityTypeEnum type, + List batches, + PageExecutor executor) { + int startPage = reqVO.getStartPage() == null ? 1 : reqVO.getStartPage(); + int pageSize = reqVO.getPageSize() == null ? 100 : reqVO.getPageSize(); + int pagesLimit = reqVO.getMaxPages() == null ? Integer.MAX_VALUE : reqVO.getMaxPages(); + int processedPages = 0; + for (int page = startPage; processedPages < pagesLimit; page++) { + BatchExecution execution = executor.execute(page, pageSize); + if (execution == null || execution.totalPulled == 0) { + break; + } + processedPages++; + IWorkSyncBatchStatVO batchStat = new IWorkSyncBatchStatVO(); + batchStat.setEntityType(type); + batchStat.setPageNumber(page); + batchStat.setPulled(execution.totalPulled); + batchStat.setCreated(execution.result.getCreated()); + batchStat.setSkippedExisting(execution.result.getSkipped()); + batchStat.setDisabled(execution.result.getDisabled()); + batchStat.setFailed(execution.result.getFailed()); + batches.add(batchStat); + } + return processedPages; + } + + /** + * 手动执行部门同步 + */ + private int departments(IWorkSyncByIdReqVO reqVO, + IWorkSyncProcessor.SyncOptions options, + IWorkSyncEntityStatVO stat, + List batches, + IWorkSyncProcessor.DeptSyncContext context) { + return paged(reqVO, IWorkSyncEntityTypeEnum.DEPARTMENT, batches, (page, pageSize) -> { + IWorkDepartmentQueryReqVO query = new IWorkDepartmentQueryReqVO(); + query.setCurpage(page); + query.setPagesize(pageSize); + applyQuery(query, reqVO); + IWorkHrDepartmentPageRespVO pageResp = orgRestService.listDepartments(query); + ensureIWorkSuccess("拉取部门", pageResp.isSuccess(), pageResp.getMessage()); + List dataList = CollUtil.emptyIfNull(pageResp.getDataList()); + IWorkSyncProcessor.BatchResult result = syncProcessor.syncDepartments(dataList, options, context); + updateStat(stat, result, dataList.size()); + return new BatchExecution(result, dataList.size()); + }); + } + + + /** + * 手动执行岗位同步 + */ + private int syncPositionsManually(IWorkSyncByIdReqVO reqVO, + IWorkSyncProcessor.SyncOptions options, + IWorkSyncEntityStatVO stat, + List batches) { + return paged(reqVO, IWorkSyncEntityTypeEnum.JOB_TITLE, batches, (page, pageSize) -> { + IWorkJobTitleQueryReqVO query = new IWorkJobTitleQueryReqVO(); + query.setCurpage(page); + query.setPagesize(pageSize); + applyQuery(query, reqVO); + IWorkHrJobTitlePageRespVO pageResp = orgRestService.listJobTitles(query); + ensureIWorkSuccess("拉取岗位", pageResp.isSuccess(), pageResp.getMessage()); + List dataList = CollUtil.emptyIfNull(pageResp.getDataList()); + IWorkSyncProcessor.BatchResult result = syncProcessor.syncJobTitles(dataList, options); + updateStat(stat, result, dataList.size()); + return new BatchExecution(result, dataList.size()); + }); + } + + /** + * 手动执行用户同步 + */ + private int syncUsers(IWorkSyncByIdReqVO reqVO, + IWorkSyncProcessor.SyncOptions options, + IWorkSyncEntityStatVO stat, + List batches) { + return paged(reqVO, IWorkSyncEntityTypeEnum.USER, batches, (page, pageSize) -> { + IWorkUserQueryReqVO query = new IWorkUserQueryReqVO(); + query.setCurpage(page); + query.setPagesize(pageSize); + applyQuery(query, reqVO); + IWorkHrUserPageRespVO pageResp = orgRestService.listUsers(query); + ensureIWorkSuccess("拉取人员", pageResp.isSuccess(), pageResp.getMessage()); + List dataList = CollUtil.emptyIfNull(pageResp.getDataList()); + IWorkSyncProcessor.BatchResult result = syncProcessor.syncUsers(dataList, options); + updateStat(stat, result, dataList.size()); + return new BatchExecution(result, dataList.size()); + }); + } + }