diff --git a/pom.xml b/pom.xml
index 07531eeb..9c0cd2b3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -237,8 +237,8 @@
172.16.46.63:30848
dev
DEFAULT_GROUP
-
-
+ nacos
+ P@ssword25
1.0.0
@@ -250,8 +250,8 @@
172.16.46.63:30848
prod
DEFAULT_GROUP
-
-
+ nacos
+ P@ssword25
1.0.0
@@ -263,8 +263,8 @@
172.16.46.63:30848
local
DEFAULT_GROUP
-
-
+ nacos
+ P@ssword25
1.0.0
diff --git a/zt-dependencies/pom.xml b/zt-dependencies/pom.xml
index 21599245..db55ba9d 100644
--- a/zt-dependencies/pom.xml
+++ b/zt-dependencies/pom.xml
@@ -87,6 +87,7 @@
4.1.116.Final
1.2.5
0.9.0
+ 4.12.0
2.15.1
4.5.13
diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/dept/DeptSourceEnum.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/dept/DeptSourceEnum.java
index 9933f0b3..805d56d9 100644
--- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/dept/DeptSourceEnum.java
+++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/dept/DeptSourceEnum.java
@@ -13,7 +13,8 @@ import lombok.Getter;
public enum DeptSourceEnum {
EXTERNAL(1, "外部部门"), // 系统创建的部门
- SYNC(2, "同步部门"); // 通过 OrgSyncService 同步的部门
+ SYNC(2, "同步部门"), // 通过 OrgSyncService 同步的部门
+ IWORK(3, "iWork 同步"); // 通过 iWork 同步的部门
/**
* 类型
diff --git a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/user/UserSourceEnum.java b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/user/UserSourceEnum.java
index 20c8b9f0..2299cd0d 100644
--- a/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/user/UserSourceEnum.java
+++ b/zt-module-system/zt-module-system-api/src/main/java/com/zt/plat/module/system/enums/user/UserSourceEnum.java
@@ -13,7 +13,8 @@ import lombok.Getter;
public enum UserSourceEnum {
EXTERNAL(1, "外部用户"), // 系统创建、注册等方式产生的用户
- SYNC(2, "同步用户"); // 通过 UserSyncService 同步的用户
+ SYNC(2, "同步用户"), // 通过 UserSyncService 同步的用户
+ IWORK(3, "iWork 用户"); // 通过 iWork 全量/单条同步产生的用户
/**
* 类型
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 f66a0f2a..97637868 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
@@ -1,23 +1,10 @@
package com.zt.plat.module.system.controller.admin.integration.iwork;
import com.zt.plat.framework.common.pojo.CommonResult;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkAuthRegisterReqVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkAuthRegisterRespVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkAuthTokenReqVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkAuthTokenRespVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkDepartmentQueryReqVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkJobTitleQueryReqVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkOperationRespVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkOrgRespVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkOrgSyncReqVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkSubcompanyQueryReqVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkUserInfoReqVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkUserInfoRespVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkUserQueryReqVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkWorkflowCreateReqVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkWorkflowVoidReqVO;
+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 io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
@@ -42,6 +29,7 @@ public class IWorkIntegrationController {
private final IWorkIntegrationService integrationService;
private final IWorkOrgRestService orgRestService;
+ private final IWorkSyncService syncService;
@PostMapping("/auth/register")
@Operation(summary = "注册 iWork 凭证,获取服务端公钥与 secret")
@@ -77,49 +65,63 @@ public class IWorkIntegrationController {
@PostMapping("/hr/subcompany/page")
@Operation(summary = "获取 iWork 分部列表")
- public CommonResult listSubcompanies(@Valid @RequestBody IWorkSubcompanyQueryReqVO reqVO) {
+ public CommonResult listSubcompanies(@Valid @RequestBody IWorkSubcompanyQueryReqVO reqVO) {
return success(orgRestService.listSubcompanies(reqVO));
}
@PostMapping("/hr/department/page")
@Operation(summary = "获取 iWork 部门列表")
- public CommonResult listDepartments(@Valid @RequestBody IWorkDepartmentQueryReqVO reqVO) {
+ public CommonResult listDepartments(@Valid @RequestBody IWorkDepartmentQueryReqVO reqVO) {
return success(orgRestService.listDepartments(reqVO));
}
@PostMapping("/hr/job-title/page")
@Operation(summary = "获取 iWork 岗位列表")
- public CommonResult listJobTitles(@Valid @RequestBody IWorkJobTitleQueryReqVO reqVO) {
+ public CommonResult listJobTitles(@Valid @RequestBody IWorkJobTitleQueryReqVO reqVO) {
return success(orgRestService.listJobTitles(reqVO));
}
@PostMapping("/hr/user/page")
@Operation(summary = "获取 iWork 人员列表")
- public CommonResult listUsers(@Valid @RequestBody IWorkUserQueryReqVO reqVO) {
+ public CommonResult listUsers(@Valid @RequestBody IWorkUserQueryReqVO reqVO) {
return success(orgRestService.listUsers(reqVO));
}
- @PostMapping("/hr/subcompany/sync")
- @Operation(summary = "同步分部信息至 iWork")
- public CommonResult syncSubcompanies(@Valid @RequestBody IWorkOrgSyncReqVO reqVO) {
- return success(orgRestService.syncSubcompanies(reqVO));
+// @PostMapping("/hr/subcompany/sync")
+// @Operation(summary = "同步分部信息至 iWork")
+// public CommonResult syncSubcompanies(@Valid @RequestBody IWorkOrgSyncReqVO reqVO) {
+// return success(orgRestService.syncSubcompanies(reqVO));
+// }
+//
+// @PostMapping("/hr/department/sync")
+// @Operation(summary = "同步部门信息至 iWork")
+// public CommonResult syncDepartments(@Valid @RequestBody IWorkOrgSyncReqVO reqVO) {
+// return success(orgRestService.syncDepartments(reqVO));
+// }
+//
+// @PostMapping("/hr/job-title/sync")
+// @Operation(summary = "同步岗位信息至 iWork")
+// public CommonResult syncJobTitles(@Valid @RequestBody IWorkOrgSyncReqVO reqVO) {
+// return success(orgRestService.syncJobTitles(reqVO));
+// }
+//
+// @PostMapping("/hr/user/sync")
+// @Operation(summary = "同步人员信息至 iWork")
+// public CommonResult syncUsers(@Valid @RequestBody IWorkOrgSyncReqVO reqVO) {
+// return success(orgRestService.syncUsers(reqVO));
+// }
+
+ // ----------------- 同步到本地 -----------------
+
+ @PostMapping("/hr/full-sync")
+ @Operation(summary = "手动触发 iWork 组织/人员全量同步")
+ public CommonResult fullSync(@Valid @RequestBody IWorkFullSyncReqVO reqVO) {
+ return success(syncService.fullSync(reqVO));
}
- @PostMapping("/hr/department/sync")
- @Operation(summary = "同步部门信息至 iWork")
- public CommonResult syncDepartments(@Valid @RequestBody IWorkOrgSyncReqVO reqVO) {
- return success(orgRestService.syncDepartments(reqVO));
- }
-
- @PostMapping("/hr/job-title/sync")
- @Operation(summary = "同步岗位信息至 iWork")
- public CommonResult syncJobTitles(@Valid @RequestBody IWorkOrgSyncReqVO reqVO) {
- return success(orgRestService.syncJobTitles(reqVO));
- }
-
- @PostMapping("/hr/user/sync")
- @Operation(summary = "同步人员信息至 iWork")
- public CommonResult syncUsers(@Valid @RequestBody IWorkOrgSyncReqVO reqVO) {
- return success(orgRestService.syncUsers(reqVO));
+ @PostMapping("/hr/single-sync")
+ @Operation(summary = "按 iWork ID 同步单条组织/人员")
+ public CommonResult singleSync(@Valid @RequestBody IWorkSingleSyncReqVO reqVO) {
+ return success(syncService.syncSingle(reqVO));
}
}
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
new file mode 100644
index 00000000..5fa63d05
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkFullSyncReqVO.java
@@ -0,0 +1,53 @@
+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 lombok.Data;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * iWork 全量同步请求
+ */
+@Data
+public class IWorkFullSyncReqVO {
+
+ @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;
+
+ 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/controller/admin/integration/iwork/vo/IWorkFullSyncRespVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkFullSyncRespVO.java
new file mode 100644
index 00000000..e88e45c1
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkFullSyncRespVO.java
@@ -0,0 +1,34 @@
+package com.zt.plat.module.system.controller.admin.integration.iwork.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * iWork 全量同步响应
+ */
+@Data
+public class IWorkFullSyncRespVO {
+
+ @Schema(description = "本次处理的总页数")
+ private Integer processedPages;
+
+ @Schema(description = "每次分页请求的条数")
+ private Integer pageSize;
+
+ @Schema(description = "分部统计信息")
+ private IWorkSyncEntityStatVO subcompanyStat = new IWorkSyncEntityStatVO();
+
+ @Schema(description = "部门统计信息")
+ private IWorkSyncEntityStatVO departmentStat = new IWorkSyncEntityStatVO();
+
+ @Schema(description = "岗位统计信息")
+ private IWorkSyncEntityStatVO jobTitleStat = new IWorkSyncEntityStatVO();
+
+ @Schema(description = "人员统计信息")
+ private IWorkSyncEntityStatVO userStat = new IWorkSyncEntityStatVO();
+
+ @Schema(description = "每个批次的详细统计")
+ private List batches;
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrDepartmentPageRespVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrDepartmentPageRespVO.java
new file mode 100644
index 00000000..ecdf6045
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrDepartmentPageRespVO.java
@@ -0,0 +1,138 @@
+package com.zt.plat.module.system.controller.admin.integration.iwork.vo;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import com.zt.plat.module.system.service.integration.iwork.jackson.LenientIntegerDeserializer;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * iWork 部门分页响应。
+ */
+@Data
+@Schema(description = "iWork 部门分页响应")
+public class IWorkHrDepartmentPageRespVO {
+
+ @Schema(description = "响应码")
+ private String code;
+
+ @Schema(description = "提示信息")
+ private String message;
+
+ @Schema(description = "是否成功")
+ private boolean success;
+
+ @Schema(description = "总条数")
+ private Integer totalSize;
+
+ @Schema(description = "总页数")
+ private Integer totalPage;
+
+ @Schema(description = "每页条数")
+ private Integer pageSize;
+
+ @Schema(description = "当前页码")
+ private Integer pageNumber;
+
+ @Schema(description = "部门数据列表")
+ private List dataList;
+
+ @Data
+ @Schema(description = "部门信息")
+ public static class Department {
+
+ @Schema(description = "部门 ID")
+ @JsonProperty("departmentid")
+ private Integer departmentid;
+
+ @Schema(description = "部门编码")
+ @JsonProperty("departmentcode")
+ private String departmentcode;
+
+ @Schema(description = "部门名称")
+ @JsonProperty("departmentname")
+ private String departmentname;
+
+ @Schema(description = "部门标识")
+ @JsonProperty("departmentmark")
+ private String departmentmark;
+
+ @Schema(description = "所属分部 ID")
+ @JsonProperty("subcompanyid1")
+ private Integer subcompanyid1;
+
+ @Schema(description = "所属分部名称")
+ @JsonProperty("subcompanyname")
+ private String subcompanyname;
+
+ @Schema(description = "上级分部 ID")
+ @JsonProperty("supsubcomid")
+ private Integer supsubcomid;
+
+ @Schema(description = "上级分部名称")
+ @JsonProperty("supsubcomname")
+ private String supsubcomname;
+
+ @Schema(description = "父部门 ID")
+ @JsonProperty("parentdeptid")
+ private Integer parentdeptid;
+
+ @Schema(description = "父部门名称")
+ @JsonProperty("parentdeptname")
+ private String parentdeptname;
+
+ @Schema(description = "层级路径")
+ @JsonProperty("alllevel")
+ private String alllevel;
+
+ @Schema(description = "显示顺序")
+ @JsonProperty("showorder")
+ @JsonDeserialize(using = LenientIntegerDeserializer.class)
+ private Integer showorder;
+
+ @Schema(description = "是否有子部门 (0/1)")
+ @JsonProperty("haschild")
+ private String haschild;
+
+ @Schema(description = "是否已失效 (0/1)")
+ @JsonProperty("canceled")
+ private String canceled;
+
+ @Schema(description = "部门类型")
+ @JsonProperty("departmenttype")
+ private String departmenttype;
+
+ @Schema(description = "负责人 ID")
+ @JsonProperty("managerid")
+ private Integer managerid;
+
+ @Schema(description = "负责人名称")
+ @JsonProperty("manager")
+ private String manager;
+
+ @JsonIgnore
+ private Map attributes;
+
+ @JsonAnySetter
+ public void putAttribute(String key, Object value) {
+ if (attributes == null) {
+ attributes = new LinkedHashMap<>();
+ }
+ attributes.put(key, value);
+ }
+
+ @JsonAnyGetter
+ public Map any() {
+ return attributes == null ? Collections.emptyMap() : attributes;
+ }
+ }
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrJobTitlePageRespVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrJobTitlePageRespVO.java
new file mode 100644
index 00000000..2bb7089a
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrJobTitlePageRespVO.java
@@ -0,0 +1,122 @@
+package com.zt.plat.module.system.controller.admin.integration.iwork.vo;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import com.zt.plat.module.system.service.integration.iwork.jackson.LenientIntegerDeserializer;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * iWork 岗位分页响应。
+ */
+@Data
+@Schema(description = "iWork 岗位分页响应")
+public class IWorkHrJobTitlePageRespVO {
+
+ @Schema(description = "响应码")
+ private String code;
+
+ @Schema(description = "提示信息")
+ private String message;
+
+ @Schema(description = "是否成功")
+ private boolean success;
+
+ @Schema(description = "总条数")
+ private Integer totalSize;
+
+ @Schema(description = "总页数")
+ private Integer totalPage;
+
+ @Schema(description = "每页条数")
+ private Integer pageSize;
+
+ @Schema(description = "当前页码")
+ private Integer pageNumber;
+
+ @Schema(description = "岗位数据列表")
+ private List dataList;
+
+ @Data
+ @Schema(description = "岗位信息")
+ public static class JobTitle {
+
+ @Schema(description = "岗位 ID")
+ @JsonProperty("jobtitleid")
+ private Integer jobtitleid;
+
+ @Schema(description = "岗位编码")
+ @JsonProperty("jobtitlecode")
+ private String jobtitlecode;
+
+ @Schema(description = "岗位名称")
+ @JsonProperty("jobtitlename")
+ private String jobtitlename;
+
+ @Schema(description = "岗位类型")
+ @JsonProperty("jobtitletype")
+ private String jobtitletype;
+
+ @Schema(description = "所属岗位组 ID")
+ @JsonProperty("jobgroupid")
+ private Integer jobgroupid;
+
+ @Schema(description = "所属岗位组名称")
+ @JsonProperty("jobgroupname")
+ private String jobgroupname;
+
+ @Schema(description = "岗位层级")
+ @JsonProperty("joblevel")
+ private String joblevel;
+
+ @Schema(description = "岗位职责")
+ @JsonProperty("jobfunction")
+ private String jobfunction;
+
+ @Schema(description = "岗位描述")
+ @JsonProperty("description")
+ private String description;
+
+ @Schema(description = "上级岗位 ID")
+ @JsonProperty("supjobtitleid")
+ private Integer supjobtitleid;
+
+ @Schema(description = "上级岗位名称")
+ @JsonProperty("supjobtitlename")
+ private String supjobtitlename;
+
+ @Schema(description = "显示顺序")
+ @JsonProperty("showorder")
+ @JsonDeserialize(using = LenientIntegerDeserializer.class)
+ private Integer showorder;
+
+ @Schema(description = "是否已失效 (0/1)")
+ @JsonProperty("canceled")
+ private String canceled;
+
+ @JsonIgnore
+ private Map attributes;
+
+ @JsonAnySetter
+ public void putAttribute(String key, Object value) {
+ if (attributes == null) {
+ attributes = new LinkedHashMap<>();
+ }
+ attributes.put(key, value);
+ }
+
+ @JsonAnyGetter
+ public Map any() {
+ return attributes == null ? Collections.emptyMap() : attributes;
+ }
+ }
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrSubcompanyPageRespVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrSubcompanyPageRespVO.java
new file mode 100644
index 00000000..fdbda82a
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrSubcompanyPageRespVO.java
@@ -0,0 +1,114 @@
+package com.zt.plat.module.system.controller.admin.integration.iwork.vo;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import com.zt.plat.module.system.service.integration.iwork.jackson.LenientIntegerDeserializer;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * iWork 分部分页响应。
+ */
+@Data
+@Schema(description = "iWork 分部分页响应")
+public class IWorkHrSubcompanyPageRespVO {
+
+ @Schema(description = "响应码")
+ private String code;
+
+ @Schema(description = "提示信息")
+ private String message;
+
+ @Schema(description = "是否成功")
+ private boolean success;
+
+ @Schema(description = "总条数")
+ private Integer totalSize;
+
+ @Schema(description = "总页数")
+ private Integer totalPage;
+
+ @Schema(description = "每页条数")
+ private Integer pageSize;
+
+ @Schema(description = "当前页码")
+ private Integer pageNumber;
+
+ @Schema(description = "分部数据列表")
+ private List dataList;
+
+ @Data
+ @Schema(description = "分部信息")
+ public static class Subcompany {
+
+ @Schema(description = "分部唯一 ID")
+ @JsonProperty("subcompanyid1")
+ private Integer subcompanyid1;
+
+ @Schema(description = "分部编码")
+ @JsonProperty("subcompanycode")
+ private String subcompanycode;
+
+ @Schema(description = "分部名称")
+ @JsonProperty("subcompanyname")
+ private String subcompanyname;
+
+ @Schema(description = "所属总部 ID")
+ @JsonProperty("companyid")
+ private Integer companyid;
+
+ @Schema(description = "所属总部名称")
+ @JsonProperty("companyname")
+ private String companyname;
+
+ @Schema(description = "上级分部 ID")
+ @JsonProperty("supsubcomid")
+ private Integer supsubcomid;
+
+ @Schema(description = "上级分部名称")
+ @JsonProperty("supsubcomname")
+ private String supsubcomname;
+
+ @Schema(description = "显示顺序")
+ @JsonProperty("showorder")
+ @JsonDeserialize(using = LenientIntegerDeserializer.class)
+ private Integer showorder;
+
+ @Schema(description = "分部描述")
+ @JsonProperty("description")
+ private String description;
+
+ @Schema(description = "是否已失效(0/1)")
+ @JsonProperty("canceled")
+ private String canceled;
+
+ @Schema(description = "层级路径")
+ @JsonProperty("alllevel")
+ private String alllevel;
+
+ @JsonIgnore
+ private Map attributes;
+
+ @JsonAnySetter
+ public void putAttribute(String key, Object value) {
+ if (attributes == null) {
+ attributes = new LinkedHashMap<>();
+ }
+ attributes.put(key, value);
+ }
+
+ @JsonAnyGetter
+ public Map any() {
+ return attributes == null ? Collections.emptyMap() : attributes;
+ }
+ }
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrSyncRespVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrSyncRespVO.java
new file mode 100644
index 00000000..c0e17393
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrSyncRespVO.java
@@ -0,0 +1,74 @@
+package com.zt.plat.module.system.controller.admin.integration.iwork.vo;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * iWork 人力同步响应。
+ */
+@Data
+@Schema(description = "iWork 人力同步响应")
+public class IWorkHrSyncRespVO {
+
+ @Schema(description = "响应码")
+ private String code;
+
+ @Schema(description = "提示信息")
+ private String message;
+
+ @Schema(description = "是否成功")
+ private boolean success;
+
+ @Schema(description = "同步结果明细")
+ private List result;
+
+ @Data
+ @Schema(description = "同步结果项")
+ public static class SyncResult {
+
+ @Schema(description = "操作动作 add/update/delete")
+ @JsonProperty("@action")
+ private String action;
+
+ @Schema(description = "外部编码")
+ @JsonProperty("code")
+ private String code;
+
+ @Schema(description = "执行结果 success/fail")
+ @JsonProperty("result")
+ private String result;
+
+ @Schema(description = "是否成功")
+ @JsonProperty("success")
+ private Boolean success;
+
+ @Schema(description = "失败描述")
+ @JsonProperty("message")
+ private String message;
+
+ @JsonIgnore
+ private Map attributes;
+
+ @JsonAnySetter
+ public void putAttribute(String key, Object value) {
+ if (attributes == null) {
+ attributes = new LinkedHashMap<>();
+ }
+ attributes.put(key, value);
+ }
+
+ @JsonAnyGetter
+ public Map any() {
+ return attributes == null ? Collections.emptyMap() : attributes;
+ }
+ }
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrUserPageRespVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrUserPageRespVO.java
new file mode 100644
index 00000000..03cafc17
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkHrUserPageRespVO.java
@@ -0,0 +1,190 @@
+package com.zt.plat.module.system.controller.admin.integration.iwork.vo;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import com.zt.plat.module.system.service.integration.iwork.jackson.LenientIntegerDeserializer;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * iWork 人员分页响应。
+ */
+@Data
+@Schema(description = "iWork 人员分页响应")
+public class IWorkHrUserPageRespVO {
+
+ @Schema(description = "响应码")
+ private String code;
+
+ @Schema(description = "提示信息")
+ private String message;
+
+ @Schema(description = "是否成功")
+ private boolean success;
+
+ @Schema(description = "总条数")
+ private Integer totalSize;
+
+ @Schema(description = "总页数")
+ private Integer totalPage;
+
+ @Schema(description = "每页条数")
+ private Integer pageSize;
+
+ @Schema(description = "当前页码")
+ private Integer pageNumber;
+
+ @Schema(description = "人员数据列表")
+ private List dataList;
+
+ @Data
+ @Schema(description = "人员信息")
+ public static class User {
+
+ @Schema(description = "人员 ID")
+ @JsonProperty("id")
+ private Integer id;
+
+ @Schema(description = "人员姓名")
+ @JsonProperty("lastname")
+ private String lastname;
+
+ @Schema(description = "登录账号")
+ @JsonProperty("loginid")
+ private String loginid;
+
+ @Schema(description = "工号")
+ @JsonProperty("workcode")
+ private String workcode;
+
+ @Schema(description = "性别")
+ @JsonProperty("sex")
+ private String sex;
+
+ @Schema(description = "所属分部 ID")
+ @JsonProperty("subcompanyid1")
+ private Integer subcompanyid1;
+
+ @Schema(description = "所属分部名称")
+ @JsonProperty("subcompanyname")
+ private String subcompanyname;
+
+ @Schema(description = "所属部门 ID")
+ @JsonProperty("departmentid")
+ private Integer departmentid;
+
+ @Schema(description = "所属部门名称")
+ @JsonProperty("departmentname")
+ private String departmentname;
+
+ @Schema(description = "所属岗位 ID")
+ @JsonProperty("jobtitleid")
+ private Integer jobtitleid;
+
+ @Schema(description = "所属岗位名称")
+ @JsonProperty("jobtitlename")
+ private String jobtitlename;
+
+ @Schema(description = "手机号码")
+ @JsonProperty("mobile")
+ private String mobile;
+
+ @Schema(description = "办公电话")
+ @JsonProperty("telephone")
+ private String telephone;
+
+ @Schema(description = "邮箱")
+ @JsonProperty("email")
+ private String email;
+
+ @Schema(description = "直属上级 ID")
+ @JsonProperty("managerid")
+ private Integer managerid;
+
+ @Schema(description = "助理 ID")
+ @JsonProperty("assistantid")
+ private Integer assistantid;
+
+ @Schema(description = "安全级别")
+ @JsonProperty("seclevel")
+ private Integer seclevel;
+
+ @Schema(description = "当前状态")
+ @JsonProperty("status")
+ private String status;
+
+ @Schema(description = "入职日期")
+ @JsonProperty("hiredate")
+ private String hiredate;
+
+ @Schema(description = "离职日期")
+ @JsonProperty("leavedate")
+ private String leavedate;
+
+ @Schema(description = "出生日期")
+ @JsonProperty("birthday")
+ private String birthday;
+
+ @Schema(description = "民族")
+ @JsonProperty("folk")
+ private String folk;
+
+ @Schema(description = "婚姻状况")
+ @JsonProperty("maritalstatus")
+ private String maritalstatus;
+
+ @Schema(description = "文化程度")
+ @JsonProperty("educationlevel")
+ private String educationlevel;
+
+ @Schema(description = "籍贯")
+ @JsonProperty("nativeplace")
+ private String nativeplace;
+
+ @Schema(description = "户口所在地")
+ @JsonProperty("nationality")
+ private String nationality;
+
+ @Schema(description = "证件号码")
+ @JsonProperty("certificatenum")
+ private String certificatenum;
+
+ @Schema(description = "显示顺序")
+ @JsonProperty("dsporder")
+ @JsonDeserialize(using = LenientIntegerDeserializer.class)
+ private Integer dsporder;
+
+ @Schema(description = "系统语言")
+ @JsonProperty("systemlanguage")
+ private String systemlanguage;
+
+ @Schema(description = "账号类型")
+ @JsonProperty("accounttype")
+ private String accounttype;
+
+ @JsonIgnore
+ private Map attributes;
+
+ @JsonAnySetter
+ public void putAttribute(String key, Object value) {
+ if (attributes == null) {
+ attributes = new LinkedHashMap<>();
+ }
+ attributes.put(key, value);
+ }
+
+ @JsonAnyGetter
+ public Map any() {
+ return attributes == null ? Collections.emptyMap() : attributes;
+ }
+ }
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkOrgRespVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkOrgRespVO.java
index 63bf2845..40d6da15 100644
--- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkOrgRespVO.java
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkOrgRespVO.java
@@ -1,28 +1,15 @@
package com.zt.plat.module.system.controller.admin.integration.iwork.vo;
import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.util.Map;
/**
- * 对 iWork 人力组织 REST 请求的响应封装。
+ * @deprecated 请改用强类型的 IWorkHr*RespVO,避免再引用该占位类。
*/
-@Data
-public class IWorkOrgRespVO {
+@Deprecated(forRemoval = true)
+@Schema(description = "已废弃,占位用")
+public final class IWorkOrgRespVO {
- @Schema(description = "响应中的业务数据(data 字段或整体映射)")
- private Map payload;
-
- @Schema(description = "原始响应字符串")
- private String rawBody;
-
- @Schema(description = "是否判断为成功")
- private boolean success;
-
- @Schema(description = "提示信息")
- private String message;
-
- @Schema(description = "响应码")
- private String code;
+ private IWorkOrgRespVO() {
+ throw new UnsupportedOperationException("Use IWorkHr*RespVO instead");
+ }
}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSingleSyncReqVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSingleSyncReqVO.java
new file mode 100644
index 00000000..85d290e4
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSingleSyncReqVO.java
@@ -0,0 +1,26 @@
+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.Min;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * iWork 单条同步请求
+ */
+@Data
+public class IWorkSingleSyncReqVO {
+
+ @Schema(description = "同步的实体类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "user")
+ @NotNull(message = "实体类型不能为空")
+ private IWorkSyncEntityTypeEnum entityType;
+
+ @Schema(description = "iWork 提供的实体主键 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "10001")
+ @NotNull(message = "实体 ID 不能为空")
+ @Min(1)
+ private Long entityId;
+
+ @Schema(description = "缺失时是否自动创建", example = "true")
+ private Boolean createIfMissing = Boolean.TRUE;
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSingleSyncRespVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSingleSyncRespVO.java
new file mode 100644
index 00000000..0e799b3e
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSingleSyncRespVO.java
@@ -0,0 +1,27 @@
+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 lombok.Data;
+
+/**
+ * iWork 单条同步响应
+ */
+@Data
+public class IWorkSingleSyncRespVO {
+
+ @Schema(description = "同步的实体类型")
+ private IWorkSyncEntityTypeEnum entityType;
+
+ @Schema(description = "实体 ID")
+ private Long entityId;
+
+ @Schema(description = "是否创建了新的记录")
+ private boolean created;
+
+ @Schema(description = "是否对已有记录进行了更新")
+ private boolean updated;
+
+ @Schema(description = "提示信息")
+ private String message;
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncBatchStatVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncBatchStatVO.java
new file mode 100644
index 00000000..87d284a4
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncBatchStatVO.java
@@ -0,0 +1,34 @@
+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 lombok.Data;
+
+/**
+ * 记录一次分页批次执行的统计信息。
+ */
+@Data
+public class IWorkSyncBatchStatVO {
+
+ @Schema(description = "同步的实体类型")
+ private IWorkSyncEntityTypeEnum entityType;
+
+ @Schema(description = "当前批次处理的页码,从 1 开始")
+ private Integer pageNumber;
+
+ @Schema(description = "本批次从 iWork 拉取的记录数量")
+ private Integer pulled;
+
+ @Schema(description = "本批次创建的记录数量")
+ private Integer created;
+
+ @Schema(description = "本批次因已存在而跳过的记录数量")
+ private Integer skippedExisting;
+
+ @Schema(description = "本批次禁用的记录数量")
+ private Integer disabled;
+
+ @Schema(description = "本批次失败的记录数量")
+ private Integer failed;
+
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncEntityStatVO.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncEntityStatVO.java
new file mode 100644
index 00000000..98741ddb
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/controller/admin/integration/iwork/vo/IWorkSyncEntityStatVO.java
@@ -0,0 +1,46 @@
+package com.zt.plat.module.system.controller.admin.integration.iwork.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * iWork 同步实体统计信息
+ */
+@Data
+public class IWorkSyncEntityStatVO {
+
+ @Schema(description = "从 iWork 拉取的记录数量")
+ private int pulled;
+
+ @Schema(description = "在本系统中新创建的记录数量")
+ private int created;
+
+ @Schema(description = "因已存在而跳过的记录数量")
+ private int skippedExisting;
+
+ @Schema(description = "在本系统中被禁用的记录数量")
+ private int disabled;
+
+ @Schema(description = "同步失败的记录数量")
+ private int failed;
+
+ public void incrementPulled(int delta) {
+ this.pulled += delta;
+ }
+
+ public void incrementCreated(int delta) {
+ this.created += delta;
+ }
+
+ public void incrementSkipped(int delta) {
+ this.skippedExisting += delta;
+ }
+
+ public void incrementDisabled(int delta) {
+ this.disabled += delta;
+ }
+
+ public void incrementFailed(int delta) {
+ this.failed += delta;
+ }
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/enums/integration/IWorkSyncEntityTypeEnum.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/enums/integration/IWorkSyncEntityTypeEnum.java
new file mode 100644
index 00000000..c9e9e00a
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/enums/integration/IWorkSyncEntityTypeEnum.java
@@ -0,0 +1,32 @@
+package com.zt.plat.module.system.enums.integration;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * iWork 同步支持的实体类型。
+ */
+@AllArgsConstructor
+@Getter
+public enum IWorkSyncEntityTypeEnum {
+
+ SUBCOMPANY("subcompany", "分部 / 公司"),
+ DEPARTMENT("department", "部门"),
+ JOB_TITLE("jobTitle", "岗位"),
+ USER("user", "人员");
+
+ private final String code;
+ private final String label;
+
+ public static IWorkSyncEntityTypeEnum fromCode(String code) {
+ if (code == null) {
+ return null;
+ }
+ for (IWorkSyncEntityTypeEnum value : values()) {
+ if (value.code.equalsIgnoreCase(code)) {
+ return value;
+ }
+ }
+ return null;
+ }
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java
index 6b6246fb..6983360b 100644
--- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/auth/AdminAuthServiceImpl.java
@@ -444,7 +444,9 @@ public class AdminAuthServiceImpl implements AdminAuthService {
Integer userSource = user.getUserSource();
// 同步用户(SYNC = 2)为内部用户,需要使用E办登录
- if (userSource != null && userSource.equals(UserSourceEnum.SYNC.getSource())) {
+ if (userSource != null &&
+ (userSource.equals(UserSourceEnum.SYNC.getSource()) ||
+ userSource.equals(UserSourceEnum.IWORK.getSource()))) {
return true;
}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkOrgRestService.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkOrgRestService.java
index 18fbe3e4..2e291fe3 100644
--- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkOrgRestService.java
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkOrgRestService.java
@@ -1,8 +1,12 @@
package com.zt.plat.module.system.service.integration.iwork;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkDepartmentQueryReqVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrDepartmentPageRespVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrJobTitlePageRespVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrSubcompanyPageRespVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrSyncRespVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrUserPageRespVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkJobTitleQueryReqVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkOrgRespVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkOrgSyncReqVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkSubcompanyQueryReqVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkUserQueryReqVO;
@@ -12,19 +16,19 @@ import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkUser
*/
public interface IWorkOrgRestService {
- IWorkOrgRespVO listSubcompanies(IWorkSubcompanyQueryReqVO reqVO);
+ IWorkHrSubcompanyPageRespVO listSubcompanies(IWorkSubcompanyQueryReqVO reqVO);
- IWorkOrgRespVO listDepartments(IWorkDepartmentQueryReqVO reqVO);
+ IWorkHrDepartmentPageRespVO listDepartments(IWorkDepartmentQueryReqVO reqVO);
- IWorkOrgRespVO listJobTitles(IWorkJobTitleQueryReqVO reqVO);
+ IWorkHrJobTitlePageRespVO listJobTitles(IWorkJobTitleQueryReqVO reqVO);
- IWorkOrgRespVO listUsers(IWorkUserQueryReqVO reqVO);
+ IWorkHrUserPageRespVO listUsers(IWorkUserQueryReqVO reqVO);
- IWorkOrgRespVO syncSubcompanies(IWorkOrgSyncReqVO reqVO);
+ IWorkHrSyncRespVO syncSubcompanies(IWorkOrgSyncReqVO reqVO);
- IWorkOrgRespVO syncDepartments(IWorkOrgSyncReqVO reqVO);
+ IWorkHrSyncRespVO syncDepartments(IWorkOrgSyncReqVO reqVO);
- IWorkOrgRespVO syncJobTitles(IWorkOrgSyncReqVO reqVO);
+ IWorkHrSyncRespVO syncJobTitles(IWorkOrgSyncReqVO reqVO);
- IWorkOrgRespVO syncUsers(IWorkOrgSyncReqVO reqVO);
+ IWorkHrSyncRespVO syncUsers(IWorkOrgSyncReqVO reqVO);
}
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
new file mode 100644
index 00000000..c93c6208
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncProcessor.java
@@ -0,0 +1,195 @@
+package com.zt.plat.module.system.service.integration.iwork;
+
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrDepartmentPageRespVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrJobTitlePageRespVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrSubcompanyPageRespVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrUserPageRespVO;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Abstraction for applying iWork entities into local persistence.
+ */
+public interface IWorkSyncProcessor {
+
+ BatchResult syncSubcompanies(List data, SyncOptions options);
+
+ BatchResult syncDepartments(List data, SyncOptions options);
+
+ BatchResult syncJobTitles(List data, SyncOptions options);
+
+ BatchResult syncUsers(List data, SyncOptions options);
+
+ /**
+ * Execution options shared by batch and single sync flows.
+ */
+ final class SyncOptions {
+ private final boolean includeCanceled;
+ private final boolean allowUpdate;
+ private final boolean createIfMissing;
+
+ private SyncOptions(boolean includeCanceled, boolean allowUpdate, boolean createIfMissing) {
+ this.includeCanceled = includeCanceled;
+ this.allowUpdate = allowUpdate;
+ this.createIfMissing = createIfMissing;
+ }
+
+ public static SyncOptions full(boolean includeCanceled) {
+ return new SyncOptions(includeCanceled, false, true);
+ }
+
+ public static SyncOptions single(boolean createIfMissing) {
+ return new SyncOptions(true, true, Boolean.TRUE.equals(createIfMissing));
+ }
+
+ public static SyncOptions custom(boolean includeCanceled, boolean allowUpdate, boolean createIfMissing) {
+ return new SyncOptions(includeCanceled, allowUpdate, createIfMissing);
+ }
+
+ public boolean isIncludeCanceled() {
+ return includeCanceled;
+ }
+
+ public boolean isAllowUpdate() {
+ return allowUpdate;
+ }
+
+ public boolean isCreateIfMissing() {
+ return createIfMissing;
+ }
+ }
+
+ /**
+ * Aggregated result for a sync batch.
+ */
+ final class BatchResult {
+ private int pulled;
+ private int created;
+ private int skipped;
+ private int disabled;
+ private int failed;
+ private int updated;
+ private String message;
+
+ public static BatchResult empty() {
+ return new BatchResult();
+ }
+
+ public BatchResult withMessage(String message) {
+ this.message = message;
+ return this;
+ }
+
+ public BatchResult merge(BatchResult other) {
+ if (other == null) {
+ return this;
+ }
+ this.pulled += other.pulled;
+ this.created += other.created;
+ this.skipped += other.skipped;
+ this.disabled += other.disabled;
+ this.failed += other.failed;
+ this.updated += other.updated;
+ if (Objects.nonNull(other.message)) {
+ this.message = other.message;
+ }
+ return this;
+ }
+
+ public static BatchResult fromSingle(BatchResult single) {
+ return empty().merge(single);
+ }
+
+ public static BatchResult singleCreated(String message) {
+ BatchResult result = empty();
+ result.created = 1;
+ result.message = message;
+ return result;
+ }
+
+ public static BatchResult singleSkipped(String message) {
+ BatchResult result = empty();
+ result.skipped = 1;
+ result.message = message;
+ return result;
+ }
+
+ public static BatchResult singleFailed(String message) {
+ BatchResult result = empty();
+ result.failed = 1;
+ result.message = message;
+ return result;
+ }
+
+ public BatchResult increasePulled(int delta) {
+ this.pulled += delta;
+ return this;
+ }
+
+ public void increaseCreated() {
+ this.created++;
+ }
+
+ public void increaseSkipped() {
+ this.skipped++;
+ }
+
+ public void increaseDisabled() {
+ this.disabled++;
+ }
+
+ public void increaseFailed() {
+ this.failed++;
+ }
+
+ public void increaseUpdated() {
+ this.updated++;
+ }
+
+ public int getPulled() {
+ return pulled;
+ }
+
+ public int getCreated() {
+ return created;
+ }
+
+ public int getSkipped() {
+ return skipped;
+ }
+
+ public int getDisabled() {
+ return disabled;
+ }
+
+ public int getFailed() {
+ return failed;
+ }
+
+ public int getUpdated() {
+ return updated;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+ }
+
+ default BatchResult syncSubcompany(IWorkHrSubcompanyPageRespVO.Subcompany data, SyncOptions options) {
+ return syncSubcompanies(Collections.singletonList(data), options);
+ }
+
+ default BatchResult syncDepartment(IWorkHrDepartmentPageRespVO.Department data, SyncOptions options) {
+ return syncDepartments(Collections.singletonList(data), options);
+ }
+
+ default BatchResult syncJobTitle(IWorkHrJobTitlePageRespVO.JobTitle data, SyncOptions options) {
+ return syncJobTitles(Collections.singletonList(data), options);
+ }
+
+ default BatchResult syncUser(IWorkHrUserPageRespVO.User data, SyncOptions options) {
+ return syncUsers(Collections.singletonList(data), 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
new file mode 100644
index 00000000..2c84ffa0
--- /dev/null
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/IWorkSyncService.java
@@ -0,0 +1,22 @@
+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.IWorkSingleSyncReqVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkSingleSyncRespVO;
+
+/**
+ * iWork 组织/人员同步服务
+ */
+public interface IWorkSyncService {
+
+ /**
+ * 发起全量分批同步
+ */
+ IWorkFullSyncRespVO fullSync(IWorkFullSyncReqVO reqVO);
+
+ /**
+ * 根据 iWork ID 进行单条同步
+ */
+ IWorkSingleSyncRespVO syncSingle(IWorkSingleSyncReqVO reqVO);
+}
diff --git a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkOrgRestServiceImpl.java b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkOrgRestServiceImpl.java
index dfd962e2..89133941 100644
--- a/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkOrgRestServiceImpl.java
+++ b/zt-module-system/zt-module-system-server/src/main/java/com/zt/plat/module/system/service/integration/iwork/impl/IWorkOrgRestServiceImpl.java
@@ -6,9 +6,13 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkDepartmentQueryReqVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrDepartmentPageRespVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrJobTitlePageRespVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrSubcompanyPageRespVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrSyncRespVO;
+import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkHrUserPageRespVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkJobTitleQueryReqVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkOrgBaseQueryReqVO;
-import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkOrgRespVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkOrgSyncReqVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkSubcompanyQueryReqVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkUserQueryReqVO;
@@ -30,8 +34,10 @@ import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import static com.zt.plat.module.system.service.integration.iwork.IWorkIntegrationErrorCodeConstants.IWORK_BASE_URL_MISSING;
import static com.zt.plat.module.system.service.integration.iwork.IWorkIntegrationErrorCodeConstants.IWORK_ORG_IDENTIFIER_MISSING;
@@ -44,8 +50,21 @@ import static com.zt.plat.module.system.service.integration.iwork.IWorkIntegrati
@Service
public class IWorkOrgRestServiceImpl implements IWorkOrgRestService {
- private static final TypeReference