Pārlūkot izejas kodu

feature: 全量与kafka同步服务

luoyb 1 gadu atpakaļ
vecāks
revīzija
0be3afa0fa
91 mainītis faili ar 4930 papildinājumiem un 78 dzēšanām
  1. 1 0
      pom.xml
  2. 38 0
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java
  3. 21 0
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemotePostService.java
  4. 21 0
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteUserService.java
  5. 124 0
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteDeptBo.java
  6. 57 1
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteUserBo.java
  7. 47 0
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteUserDeptBo.java
  8. 5 0
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/vo/RemoteDeptVo.java
  9. 64 0
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/vo/RemotePostVo.java
  10. 29 3
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/vo/RemoteUserVo.java
  11. 23 2
      ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/mq/KafkaNormalConsumer.java
  12. 6 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java
  13. 4 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java
  14. 15 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java
  15. 19 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysDeptBoConvert.java
  16. 19 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysDeptVoConvert.java
  17. 96 3
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java
  18. 44 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemotePostServiceImpl.java
  19. 71 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java
  20. 8 8
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java
  21. 0 7
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
  22. 30 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java
  23. 7 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
  24. 51 3
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
  25. 1 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
  26. 72 42
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
  27. 20 7
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/UserDeptServiceImpl.java
  28. 27 0
      ruoyi-server/pom.xml
  29. 39 0
      ruoyi-server/ruoyi-server-base/pom.xml
  30. 78 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/SyncRemoteDeptService.java
  31. 24 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/strategy/ISyncDeptStrategy.java
  32. 38 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/strategy/SyncDeptStrategyContent.java
  33. 150 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/strategy/impl/GraduateClassStrategyImpl.java
  34. 121 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/strategy/impl/HrDeptStrategyImpl.java
  35. 170 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/strategy/impl/TrainClassStrategyImpl.java
  36. 319 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/SyncRemoteUserService.java
  37. 25 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/strategy/ISyncUserStrategy.java
  38. 38 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/strategy/SyncUserStrategyContent.java
  39. 49 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/strategy/impl/SyncGraduateStrategyImpl.java
  40. 49 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/strategy/impl/SyncTeacherStrategyImpl.java
  41. 49 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/strategy/impl/SyncTraineeStrategyImpl.java
  42. 88 0
      ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/util/EncryptorUtil.java
  43. 10 0
      ruoyi-server/ruoyi-server-base/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  44. 26 0
      ruoyi-server/ruoyi-server-common/pom.xml
  45. 88 0
      ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/constant/DefaultConstants.java
  46. 39 0
      ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/constant/SyncResourceConstants.java
  47. 33 0
      ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/KafkaHeader.java
  48. 19 0
      ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/KafkaMessage.java
  49. 98 0
      ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/ResourceDept.java
  50. 97 0
      ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/ResourcePerson.java
  51. 47 0
      ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/ResourcePersonDept.java
  52. 42 0
      ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/SyncFullDataBo.java
  53. 25 0
      ruoyi-server/ruoyi-server-mqdata/Dockerfile
  54. 146 0
      ruoyi-server/ruoyi-server-mqdata/pom.xml
  55. 22 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/RuoYiServerMqDataApplication.java
  56. 44 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/constant/kafka/GraduateEventConstraints.java
  57. 44 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/constant/kafka/TeacherEventConstraints.java
  58. 44 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/constant/kafka/TrainEventConstraints.java
  59. 40 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/consumer/KafkaConsumer.java
  60. 32 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/EventStrategyContext.java
  61. 21 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/IEventStrategy.java
  62. 35 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/DeptAddEventStrategyImpl.java
  63. 32 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/DeptDelEventStrategyImpl.java
  64. 36 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/DeptUpdateEventStrategyImpl.java
  65. 36 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/TeacherAddEventStrategyImpl.java
  66. 28 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/TeacherDelEventStrategyImpl.java
  67. 35 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/TeacherUpdateEventStrategyImpl.java
  68. 62 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/TeacherUtils.java
  69. 36 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/ClassAddEventStrategyImpl.java
  70. 29 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/ClassDelEventStrategyImpl.java
  71. 36 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/ClassUpdateEventStrategyImpl.java
  72. 29 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/TrainUpdateEventStrategyImpl.java
  73. 49 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/TrainUtils.java
  74. 29 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/TraineeAddEventStrategyImpl.java
  75. 29 0
      ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/TraineeDelEventStrategyImpl.java
  76. 34 0
      ruoyi-server/ruoyi-server-mqdata/src/main/resources/application.yml
  77. 10 0
      ruoyi-server/ruoyi-server-mqdata/src/main/resources/banner.txt
  78. 28 0
      ruoyi-server/ruoyi-server-mqdata/src/main/resources/logback-plus.xml
  79. 3 0
      ruoyi-server/ruoyi-server-mqdata/src/main/resources/mapper/package-info.md
  80. 25 0
      ruoyi-server/ruoyi-server-sync/Dockerfile
  81. 136 0
      ruoyi-server/ruoyi-server-sync/pom.xml
  82. 37 0
      ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/InitRunnerTest.java
  83. 22 0
      ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/RuoYiServerSyncApplication.java
  84. 28 0
      ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/service/CreateHttpRequest.java
  85. 193 0
      ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/service/SyncGraduateService.java
  86. 239 0
      ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/service/SyncHrService.java
  87. 525 0
      ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/service/SyncTrainService.java
  88. 34 0
      ruoyi-server/ruoyi-server-sync/src/main/resources/application.yml
  89. 10 0
      ruoyi-server/ruoyi-server-sync/src/main/resources/banner.txt
  90. 28 0
      ruoyi-server/ruoyi-server-sync/src/main/resources/logback-plus.xml
  91. 3 0
      ruoyi-server/ruoyi-server-sync/src/main/resources/mapper/package-info.md

+ 1 - 0
pom.xml

@@ -423,6 +423,7 @@
         <module>ruoyi-api</module>
         <module>ruoyi-common</module>
         <module>ruoyi-example</module>
+        <module>ruoyi-server</module>
     </modules>
     <packaging>pom</packaging>
 

+ 38 - 0
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java

@@ -1,6 +1,9 @@
 package org.dromara.system.api;
 
 import cn.hutool.core.lang.tree.Tree;
+import org.dromara.common.core.domain.R;
+import org.dromara.system.api.domain.bo.RemoteDeptBo;
+import org.dromara.system.api.domain.vo.RemoteDeptVo;
 
 import java.util.List;
 
@@ -23,4 +26,39 @@ public interface RemoteDeptService {
 
     //根据部门id查询子部门列表
     List<Long> selectDeptAndChildrenDeptById(Long parentId);
+
+    /**
+     * 根据第三方对接的唯一标识符查询对应的部门信息
+     *
+     * @param otherId  第三方对接的唯一标识符
+     * @param tenantId
+     * @return 部门信息
+     */
+    RemoteDeptVo selectDeptByOtherId(String otherId, String tenantId);
+
+    /**
+     * 增加新部门
+     *
+     * @param remoteDeptBo 部门业务模型
+     * @return 增加结果
+     */
+    R<Object> insertDept(RemoteDeptBo remoteDeptBo);
+
+    /**
+     * 修改部门
+     *
+     * @param remoteDeptBo 部门业务模型
+     * @return 增加结果
+     */
+    R<Object> updateDept(RemoteDeptBo remoteDeptBo);
+
+    /**
+     * 根据第三方对接的唯一标识符删除部门
+     *
+     * @param otherId 第三方对接后的唯一标识符
+     * @return 删除结果
+     */
+    R<Object> deleteDeptByOtherId(String otherId);
+
+    RemoteDeptVo selectDeptByParentIdAndName(Long parentId, String deptName);
 }

+ 21 - 0
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemotePostService.java

@@ -0,0 +1,21 @@
+package org.dromara.system.api;
+
+import org.dromara.system.api.domain.vo.RemotePostVo;
+
+import java.util.List;
+
+/**
+ * 配置岗位服务
+ *
+ * @author Michelle.Chung
+ */
+public interface RemotePostService {
+
+    /**
+     * 获取岗位列表
+     * @param tenantId 租户id
+     * @return 岗位列表
+     */
+    List<RemotePostVo> selectPostVo(String tenantId);
+
+}

+ 21 - 0
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteUserService.java

@@ -1,5 +1,6 @@
 package org.dromara.system.api;
 
+import org.dromara.common.core.domain.R;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.exception.user.UserException;
 import org.dromara.system.api.domain.bo.RemoteUserBo;
@@ -132,4 +133,24 @@ public interface RemoteUserService {
      */
     List<Long> selectUserIdsByRoleIds(List<Long> roleIds);
 
+    /**
+     * 根据第三方标识查询用户信息
+     * @param otherId 第三方标识
+     * @return 用户信息
+     */
+    RemoteUserVo selectUserVoByOtherId(String otherId);
+
+    /**
+     * 增加新人员
+     * @param remoteUserBo 人员业务类型
+     * @return 增加结果
+     */
+    R<RemoteUserVo> insertUser(RemoteUserBo remoteUserBo);
+
+    /**
+     * 修改人员信息
+     * @param remoteUserBo 人员业务类型
+     * @return 修改结果
+     */
+    R<RemoteUserVo> updateUser(RemoteUserBo remoteUserBo);
 }

+ 124 - 0
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteDeptBo.java

@@ -0,0 +1,124 @@
+package org.dromara.system.api.domain.bo;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * name: RemoteDeptBo
+ * package: org.dromara.system.api.domain.bo
+ * description: 部门服务业务模型
+ * date: 2024-10-17 22:08:20 22:08
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+public class RemoteDeptBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 8436140477797284244L;
+
+
+    /**
+     * 部门id
+     */
+    private Long deptId;
+
+    /**
+     * 父部门ID
+     */
+    private Long parentId;
+
+    /**
+     * 部门名称
+     */
+    private String deptName;
+
+    /**
+     * 部门类别编码
+     */
+    private String deptType;
+
+    /**
+     * 显示顺序
+     */
+    private Integer orderNum;
+
+    /**
+     * 联系电话
+     */
+    private String phone;
+
+    /**
+     * 邮箱
+     */
+    private String email;
+
+    /**
+     * 部门状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 唯一标识
+     */
+    private String otherId;
+
+    /**
+     * 租户编号
+     */
+    private String tenantId;
+
+    /**
+     * 开班日期
+     */
+    private Date beginDate;
+
+    /**
+     * 结业日期
+     */
+    private Date endDate;
+
+    /**
+     * 报到日期
+     */
+    private Date checkDate;
+
+    /**
+     * 是否自主选房
+     */
+    private String chooseRoom;
+
+    /**
+     * 是否就餐
+     */
+    private String canEat;
+
+    /**
+     * 是否先缴费再报到
+     */
+    private String payCheck;
+
+    /**
+     * 缴费开始日期
+     */
+    private Date payBegin;
+
+    /**
+     * 缴费开始日期
+     */
+    private Date payEnd;
+
+    /**
+     * 部门状态
+     */
+    private String delFlag;
+}

+ 57 - 1
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteUserBo.java

@@ -13,6 +13,7 @@ import jakarta.validation.constraints.Size;
 import java.io.Serial;
 import java.io.Serializable;
 import java.util.Date;
+import java.util.List;
 
 /**
  * 用户信息业务对象 t_sys_user
@@ -41,6 +42,10 @@ public class RemoteUserBo implements Serializable {
      */
     private Long deptId;
 
+    /**
+     * 岗位Id
+     */
+    private Long postId;
     /**
      * 用户账号
      */
@@ -49,6 +54,14 @@ public class RemoteUserBo implements Serializable {
     @Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符")
     private String userName;
 
+    /**
+     * 学/工号
+     */
+    @Xss(message = "学/工号不能包含脚本字符")
+    @NotBlank(message = "学/工号不能为空")
+    @Size(min = 0, max = 30, message = "学/工号长度不能超过{max}个字符")
+    private String userNumb;
+
     /**
      * 用户昵称
      */
@@ -56,11 +69,21 @@ public class RemoteUserBo implements Serializable {
     @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符")
     private String nickName;
 
+    /**
+     * 用户姓名
+     */
+    @NotBlank(message = "用户姓名不能为空")
+    private String realName;
+
     /**
      * 用户类型(t_sys_user系统用户)
      */
     private String userType;
 
+    /**
+     * 用户身份(0=内部用户 1=老师 2=学生 3=研究生  4=其他人员)
+     */
+    private String category;
     /**
      * 用户邮箱
      */
@@ -71,7 +94,7 @@ public class RemoteUserBo implements Serializable {
     /**
      * 手机号码
      */
-    private String phonenumber;
+    private String phone;
 
     /**
      * 用户性别(0男 1女 2未知)
@@ -108,11 +131,44 @@ public class RemoteUserBo implements Serializable {
      */
     private String remark;
 
+    /**
+     * 角色组
+     */
+    @Size(min = 1, message = "用户角色不能为空")
+    private Long[] roleIds;
     /**
      * 数据权限 当前角色ID
      */
     private Long roleId;
 
+    /**
+     * 账户卡片类型
+     */
+    private Long cardType;
+
+    /**
+     * 账户有效期
+     */
+    private Date lifespan;
+
+    /**
+     * 身份证号
+     */
+    private String idNumber;
+
+    /**
+     * 第三方统一标识Id
+     */
+    private String otherId;
+    /**
+     * 第三方人员状态
+     */
+    private String userState;
+    /*
+     * 人员部门列表,一人多部门情况
+     */
+    private List<RemoteUserDeptBo> userDeptList;
+
     public RemoteUserBo(Long userId) {
         this.userId = userId;
     }

+ 47 - 0
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteUserDeptBo.java

@@ -0,0 +1,47 @@
+package org.dromara.system.api.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * name: RemoteUserDeptBo
+ * package: org.dromara.system.api.domain.bo
+ * description: 用户部门关系业务对象
+ * date: 2024-10-25 15:09:55 15:09
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+public class RemoteUserDeptBo implements Serializable {
+    @Serial
+    private static final long serialVersionUID = 9089072746070501413L;
+
+    /**
+     * 用户Id
+     */
+    private Long userId;
+
+    /**
+     * 部门Id
+     */
+    private Long deptId;
+
+    /**
+     * 岗位Id
+     */
+    private Long postId;
+
+    /**
+     * 是否主部门
+     */
+    private String mainDept;
+
+    /**
+     * 删除标志(0-未删除 2-已删除)
+     */
+    private String delFlag;
+}

+ 5 - 0
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/vo/RemoteDeptVo.java

@@ -85,4 +85,9 @@ public class RemoteDeptVo implements Serializable {
      * 唯一标识
      */
     private String otherId;
+
+    /**
+     * 结业日期
+     */
+    private Date endDate;
 }

+ 64 - 0
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/vo/RemotePostVo.java

@@ -0,0 +1,64 @@
+package org.dromara.system.api.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 岗位信息视图对象 t_sys_post
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class RemotePostVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 岗位ID
+     */
+    private Long postId;
+
+    /**
+     * 岗位编码
+     */
+    private String postCode;
+
+    /**
+     * 岗位名称
+     */
+    private String postName;
+
+    /**
+     * 显示顺序
+     */
+    private Integer postSort;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 是否系统数据(Y是 N否)
+     */
+    private String sysData;
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 租户ID
+     */
+    private String tenantId;
+}

+ 29 - 3
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/vo/RemoteUserVo.java

@@ -1,7 +1,10 @@
 package org.dromara.system.api.domain.vo;
 
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import org.dromara.common.core.xss.Xss;
 
 import java.io.Serial;
 import java.io.Serializable;
@@ -25,26 +28,49 @@ public class RemoteUserVo implements Serializable {
      */
     private Long userId;
 
+    /**
+     * 租户ID
+     */
+    private String tenantId;
+
     /**
      * 部门ID
      */
     private Long deptId;
 
+    /**
+     * 岗位Id
+     */
+    private Long postId;
     /**
      * 用户账号
      */
     private String userName;
 
     /**
-     * 用户昵称
+     * 学/工号
+     */
+    private String userNumb;
+    /**
+     * 用户呢称
      */
+
     private String nickName;
+    /**
+     * 用户姓名
+     */
+    private String realName;
 
     /**
-     * 用户类型(sys_user系统用户)
+     * 用户类型(t_sys_user系统用户)
      */
     private String userType;
 
+    /**
+     * 用户身份(0=内部用户 1=老师 2=学生 3=研究生  4=其他人员)
+     */
+    private String category;
+
     /**
      * 用户邮箱
      */
@@ -53,7 +79,7 @@ public class RemoteUserVo implements Serializable {
     /**
      * 手机号码
      */
-    private String phonenumber;
+    private String phone;
 
     /**
      * 用户性别(0男 1女 2未知)

+ 23 - 2
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/mq/KafkaNormalConsumer.java

@@ -33,7 +33,7 @@ import java.util.HashMap;
  */
 @RequiredArgsConstructor
 @Slf4j
-@Component
+//@Component
 public class KafkaNormalConsumer {
     private final ConsumeStrategyContent consumeStrategyContent;
 
@@ -48,8 +48,10 @@ public class KafkaNormalConsumer {
                 //uploadByHttp(data);
 
                 uploadByService(data);
+
+                //uploadtest();
             } catch (Exception e) {
-                log.info("消费失败");
+                log.info(e.getMessage());
             }
         }
         log.info("【消费者】received the message key {},value:{}", key, value);
@@ -75,7 +77,26 @@ public class KafkaNormalConsumer {
         recordBo.setConsumeId(vo.getOriginalId());
         consumeStrategyContent.postOrder(recordBo);
     }
+    private void uploadtest() {
+        ConsumptionBo recordBo = new ConsumptionBo();
+        recordBo.setConsumeMoney(BigDecimal.ZERO);
+        recordBo.setConsumeDate(DateUtil.parse("2024-10-16 18:25:58"));
+        recordBo.setCardNo(35193L);
+        recordBo.setFactoryId(3656457030L);
+        recordBo.setTermNo(7L);
+        recordBo.setTermRecordId(46940L);
+        recordBo.setRealName("苏兵");
+        recordBo.setUserNumb("15674973790");
+        recordBo.setRecordStatus(364L);
+        recordBo.setCreditType(CreditTypeEnum.TERM_CONSUME);
+        recordBo.setTenantId("20200813044411");
+        R<Object> result = consumeStrategyContent.createOrder(recordBo);
+        XfConsumeDetailOriginalVo vo = (XfConsumeDetailOriginalVo)result.getData();
 
+        recordBo.setRecordId(vo.getRecordId());
+        recordBo.setConsumeId(vo.getOriginalId());
+        consumeStrategyContent.postOrder(recordBo);
+    }
     private void uploadByHttp(JSONObject data) {
         ConsumeRecordBo recordBo = new ConsumeRecordBo();
         String time = data.get("consumeDate").toString();

+ 6 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java

@@ -42,7 +42,7 @@ public class SysDeptBo extends BaseEntity {
      * 部门类别编码
      */
     @Size(min = 0, max = 100, message = "部门类别编码长度不能超过{max}个字符")
-    private String deptCategory;
+    private String deptType;
 
     /**
      * 显示顺序
@@ -73,4 +73,9 @@ public class SysDeptBo extends BaseEntity {
      */
     private String otherId;
 
+    /**
+     * 租户编号
+     */
+    private String tenantId;
+
 }

+ 4 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java

@@ -59,6 +59,9 @@ public class SysPostBo extends BaseEntity {
      * 备注
      */
     private String remark;
-
+    /**
+     * 租户ID
+     */
+    private String tenantId;
 
 }

+ 15 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java

@@ -17,7 +17,9 @@ import org.dromara.common.sensitive.annotation.Sensitive;
 import org.dromara.common.sensitive.core.SensitiveStrategy;
 import org.dromara.system.domain.SysUser;
 
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
 
 /**
  * 用户信息业务对象 sys_user
@@ -140,6 +142,19 @@ public class SysUserBo extends BaseEntity {
      * 身份证号
      */
     private String idNumber;
+
+    /**
+     * 第三方统一标识Id
+     */
+    private String otherId;
+    /**
+     * 第三方人员状态
+     */
+    private String userState;
+    /*
+    人员所属部门
+     */
+    List<UserDeptBo> userDeptBoList;
     /**
      * 排除不查询的用户(工作流用)
      */

+ 19 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysDeptBoConvert.java

@@ -0,0 +1,19 @@
+package org.dromara.system.domain.convert;
+
+import io.github.linpeilie.BaseMapper;
+import org.dromara.system.api.domain.bo.RemoteDeptBo;
+import org.dromara.system.api.domain.vo.RemoteDeptVo;
+import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.vo.SysDeptVo;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingConstants;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * 租户转换器
+ * @author zhujie
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysDeptBoConvert extends BaseMapper<SysDeptBo, RemoteDeptBo> {
+
+}

+ 19 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysDeptVoConvert.java

@@ -0,0 +1,19 @@
+package org.dromara.system.domain.convert;
+
+import io.github.linpeilie.BaseMapper;
+import org.dromara.system.api.domain.vo.RemoteDeptVo;
+import org.dromara.system.api.domain.vo.RemoteUserVo;
+import org.dromara.system.domain.vo.SysDeptVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingConstants;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * 租户转换器
+ * @author zhujie
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysDeptVoConvert extends BaseMapper<SysDeptVo, RemoteDeptVo> {
+
+}

+ 96 - 3
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java

@@ -1,13 +1,24 @@
 package org.dromara.system.dubbo;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.system.api.RemoteDeptService;
+import org.dromara.system.api.domain.bo.RemoteDeptBo;
+import org.dromara.system.api.domain.vo.RemoteDeptVo;
 import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.vo.SysDeptVo;
 import org.dromara.system.service.ISysDeptService;
-import lombok.RequiredArgsConstructor;
-import org.apache.dubbo.config.annotation.DubboService;
 import org.springframework.stereotype.Service;
 
+import java.text.MessageFormat;
+import java.time.Duration;
 import java.util.List;
 
 /**
@@ -43,7 +54,7 @@ public class RemoteDeptServiceImpl implements RemoteDeptService {
      * @return
      */
     @Override
-    public List<Tree<Long>>deptTree(){
+    public List<Tree<Long>> deptTree() {
         SysDeptBo dept = new SysDeptBo();
         return sysDeptService.selectDeptTreeList(dept);
     }
@@ -52,4 +63,86 @@ public class RemoteDeptServiceImpl implements RemoteDeptService {
     public List<Long> selectDeptAndChildrenDeptById(Long parentId) {
         return sysDeptService.selectDeptAndChildrenDeptById(parentId);
     }
+
+    /**
+     * 根据第三方对接的唯一标识符查询对应的部门信息
+     *
+     * @param otherId  第三方对接的唯一标识符
+     * @param tenantId 租户Id
+     * @return 部门信息
+     */
+    @Override
+    public RemoteDeptVo selectDeptByOtherId(String otherId, String tenantId) {
+        String cacheKey = tenantId + "_dept_:" + otherId;
+        RemoteDeptVo remoteDeptVo = RedisUtils.getCacheObject(cacheKey);
+        if (ObjectUtil.isNotEmpty(remoteDeptVo)) {
+            return remoteDeptVo;
+        } else {
+            SysDeptVo deptVo = sysDeptService.selectVoByOtherId(otherId);
+            remoteDeptVo = MapstructUtils.convert(deptVo, RemoteDeptVo.class);
+            RedisUtils.setCacheObject(cacheKey, remoteDeptVo, Duration.ofHours(2));
+            return remoteDeptVo;
+        }
+    }
+
+    /**
+     * 增加新部门
+     *
+     * @param remoteDeptBo 部门业务模型
+     * @return 增加结果
+     */
+    @Override
+    public R<Object> insertDept(RemoteDeptBo remoteDeptBo) {
+        String message = MessageFormat.format("[增加部门失败]-[{0}]", JSONUtil.toJsonStr(remoteDeptBo));
+        SysDeptBo deptBo = BeanUtil.copyProperties(remoteDeptBo, SysDeptBo.class);
+        SysDeptVo vo = sysDeptService.insertDeptBo(deptBo);
+        if(vo!=null){
+            RemoteDeptVo remoteDeptVo = BeanUtil.copyProperties(vo, RemoteDeptVo.class);
+            return R.ok(remoteDeptVo);
+        } else {
+           return R.fail(message);
+        }
+    }
+
+    /**
+     * 修改部门
+     *
+     * @param remoteDeptBo 部门业务模型
+     * @return 增加结果
+     */
+    @Override
+    public R<Object> updateDept(RemoteDeptBo remoteDeptBo) {
+        String message = MessageFormat.format("[修改部门失败]-[{0}]", JSONUtil.toJsonStr(remoteDeptBo));
+        //SysDeptBo deptBo = MapstructUtils.convert(remoteDeptBo, SysDeptBo.class);
+        SysDeptBo deptBo = BeanUtil.copyProperties(remoteDeptBo, SysDeptBo.class);
+        return sysDeptService.updateDept(deptBo) > 0 ? R.ok() : R.fail(message);
+    }
+
+    /**
+     * 根据第三方对接的唯一标识符删除部门
+     *
+     * @param otherId 第三方对接后的唯一标识符
+     * @return 删除结果
+     */
+    @Override
+    public R<Object> deleteDeptByOtherId(String otherId) {
+        String message = MessageFormat.format("[删除部门失败]-[部门标识Id:{0}]", otherId);
+
+        return null;
+    }
+
+    /**
+     * 根据父节点Id和名称查询部门
+     * @param parentId 父节点
+     * @param deptName 名称
+     * @return 部门信息
+     */
+    @Override
+    public RemoteDeptVo selectDeptByParentIdAndName(Long parentId, String deptName) {
+        SysDeptVo deptVo = sysDeptService.selectDeptByParentIdAndName(parentId, deptName);
+        if(deptVo != null){
+            return MapstructUtils.convert(deptVo, RemoteDeptVo.class);
+        }
+        return null;
+    }
 }

+ 44 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemotePostServiceImpl.java

@@ -0,0 +1,44 @@
+package org.dromara.system.dubbo;
+
+import cn.hutool.core.bean.BeanUtil;
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.system.api.RemoteConfigService;
+import org.dromara.system.api.RemotePostService;
+import org.dromara.system.api.domain.vo.RemotePostVo;
+import org.dromara.system.domain.SysPost;
+import org.dromara.system.domain.bo.SysPostBo;
+import org.dromara.system.domain.vo.SysPostVo;
+import org.dromara.system.service.ISysConfigService;
+import org.dromara.system.service.ISysPostService;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 岗位服务实现
+ *
+ * @author Michelle.Chung
+ */
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemotePostServiceImpl implements RemotePostService {
+
+    private final ISysPostService postService;
+
+
+    @Override
+    public List<RemotePostVo> selectPostVo(String tenantId) {
+        SysPostBo bo = new SysPostBo();
+        bo.setTenantId(tenantId);
+        List<SysPostVo> postList = postService.selectPostList(bo);
+        List<RemotePostVo> voList = new ArrayList<>();
+        postList.forEach(post -> {
+            RemotePostVo vo = BeanUtil.copyProperties(post, RemotePostVo.class);
+            voList.add(vo);
+        });
+        return voList;
+    }
+}

+ 71 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java

@@ -4,7 +4,9 @@ import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.domain.R;
 import org.dromara.common.core.enums.UserStatus;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.exception.user.UserException;
@@ -20,6 +22,7 @@ import org.dromara.system.api.model.RoleDTO;
 import org.dromara.system.api.model.XcxLoginUser;
 import org.dromara.system.domain.SysUser;
 import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.bo.UserDeptBo;
 import org.dromara.system.domain.vo.SysDeptVo;
 import org.dromara.system.domain.vo.SysRoleVo;
 import org.dromara.system.domain.vo.SysUserVo;
@@ -27,6 +30,7 @@ import org.dromara.system.mapper.SysUserMapper;
 import org.dromara.system.service.*;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -34,6 +38,7 @@ import java.util.List;
  *
  * @author Lion Li
  */
+@Slf4j
 @RequiredArgsConstructor
 @Service
 @DubboService
@@ -309,4 +314,70 @@ public class RemoteUserServiceImpl implements RemoteUserService {
         return userService.selectUserIdsByRoleIds(roleIds);
     }
 
+    /**
+     * 根据第三方标识查询用户信息
+     *
+     * @param otherId 第三方标识
+     * @return 用户信息
+     */
+    @Override
+    public RemoteUserVo selectUserVoByOtherId(String otherId) {
+        SysUserVo vo = userService.selectUserVoByOtherId(otherId);
+        return BeanUtil.copyProperties(vo, RemoteUserVo.class);
+    }
+
+    /**
+     * 增加新人员
+     *
+     * @param remoteUserBo 人员业务类型
+     * @return 增加结果
+     */
+    @Override
+    public R<RemoteUserVo> insertUser(RemoteUserBo remoteUserBo) {
+        String message = "增加人员入库失败";
+        try {
+            SysUserBo bo = BeanUtil.copyProperties(remoteUserBo, SysUserBo.class);
+            List<UserDeptBo> userDeptBoList = new ArrayList<>();
+            if(ObjectUtil.isNotEmpty(remoteUserBo.getUserDeptList())){
+                remoteUserBo.getUserDeptList().forEach(remoteUserDeptBo -> {
+                    UserDeptBo userDeptBo = BeanUtil.copyProperties(remoteUserDeptBo, UserDeptBo.class);
+                    userDeptBoList.add(userDeptBo);
+                });
+            }
+            bo.setUserDeptBoList(userDeptBoList);
+            return userService.insertUser(bo) > 0 ? R.ok() : R.fail(message);
+        } catch (Exception e) {
+            return R.fail(message+','+ e.getMessage());
+        }
+    }
+
+    /**
+     * 修改人员信息
+     *
+     * @param remoteUserBo 人员业务类型
+     * @return 修改结果
+     */
+    @Override
+    public R<RemoteUserVo> updateUser(RemoteUserBo remoteUserBo) {
+        String message = "[修改人员入库失败]";
+        //try {
+        SysUserBo bo = BeanUtil.copyProperties(remoteUserBo, SysUserBo.class);
+        setUserDept(bo, remoteUserBo);
+        return userService.updateUser(bo) > 0 ? R.ok() : R.fail(message);
+        //} catch (Exception e) {
+        //    return R.fail(MessageFormat.format("[{0}]",e.getMessage()));
+        //}
+    }
+
+    private void setUserDept(SysUserBo bo,RemoteUserBo remoteBo){
+        List<UserDeptBo> userDeptBoList = new ArrayList<>();
+        if(ObjectUtil.isNotEmpty(remoteBo.getUserDeptList())){
+            remoteBo.getUserDeptList().forEach(remoteUserDeptBo -> {
+                UserDeptBo userDeptBo = BeanUtil.copyProperties(remoteUserDeptBo, UserDeptBo.class);
+                userDeptBoList.add(userDeptBo);
+            });
+        }
+        bo.setUserDeptBoList(userDeptBoList);
+    }
+
 }

+ 8 - 8
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java

@@ -31,16 +31,16 @@ public interface SysRoleMapper extends BaseMapperPlus<SysRole, SysRoleVo> {
      * @param queryWrapper 查询条件
      * @return 角色数据集合信息
      */
-    @DataPermission({
-        @DataColumn(key = "deptName", value = "d.dept_id"),
-        @DataColumn(key = "userName", value = "r.create_by")
-    })
+    //@DataPermission({
+    //    @DataColumn(key = "deptName", value = "d.dept_id"),
+    //    @DataColumn(key = "userName", value = "r.create_by")
+    //})
     List<SysRoleVo> selectRoleList(@Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
 
-    @DataPermission({
-        @DataColumn(key = "deptName", value = "d.dept_id"),
-        @DataColumn(key = "userName", value = "r.create_by")
-    })
+    //@DataPermission({
+    //    @DataColumn(key = "deptName", value = "d.dept_id"),
+    //    @DataColumn(key = "userName", value = "r.create_by")
+    //})
     SysRoleVo selectRoleById(Long roleId);
 
     /**

+ 0 - 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java

@@ -81,11 +81,4 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
     })
     int update(@Param(Constants.ENTITY) SysUser user, @Param(Constants.WRAPPER) Wrapper<SysUser> updateWrapper);
 
-    @Override
-    @DataPermission({
-        @DataColumn(key = "deptName", value = "dept_id"),
-        @DataColumn(key = "userName", value = "user_id")
-    })
-    int updateById(@Param(Constants.ENTITY) SysUser user);
-
 }

+ 30 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java

@@ -1,6 +1,7 @@
 package org.dromara.system.service;
 
 import cn.hutool.core.lang.tree.Tree;
+import org.dromara.system.api.domain.vo.RemoteDeptVo;
 import org.dromara.system.domain.bo.SysDeptBo;
 import org.dromara.system.domain.vo.SysDeptVo;
 
@@ -116,6 +117,13 @@ public interface ISysDeptService {
      */
     int insertDept(SysDeptBo bo);
 
+    /**
+     * 新增部门信息
+     * @param bo 部门业务对象
+     * @return 部门视图对象
+     */
+    SysDeptVo insertDeptBo(SysDeptBo bo);
+
     /**
      * 修改保存部门信息
      *
@@ -134,4 +142,26 @@ public interface ISysDeptService {
 
     //根据部门ID查询子部门列表
     List<Long> selectDeptAndChildrenDeptById(Long deptId);
+
+    /**
+     * 根据统一标识Id查询部门信息
+     * @param otherId 统一身份标识
+     * @return 部门信息
+     */
+    SysDeptVo selectVoByOtherId(String otherId);
+
+    /**
+     * 获取同层级的最大部门排序号
+     * @param deptId 部门Id
+     * @return 排序号
+     */
+    Integer getMaxLevelOrderNumb(Long deptId);
+
+    /**
+     * 根据父节点Id和部门名称获取部门信息
+     * @param parentId 父节点Id
+     * @param deptName 部门名称
+     * @return 部门信息
+     */
+    SysDeptVo selectDeptByParentIdAndName(Long parentId, String deptName);
 }

+ 7 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java

@@ -275,4 +275,11 @@ public interface ISysUserService {
      */
     List<Long> selectUserIdsByRoleIds(List<Long> roleIds);
 
+    /**
+     * 根据第三方标识查询用户信息
+     * @param otherId 第三方标识
+     * @return 用户信息
+     */
+    SysUserVo selectUserVoByOtherId(String otherId);
+
 }

+ 51 - 3
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.core.convert.Convert;
 import cn.hutool.core.lang.tree.Tree;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
@@ -81,7 +82,7 @@ public class SysDeptServiceImpl implements ISysDeptService {
         lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId());
         lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), SysDept::getParentId, bo.getParentId());
         lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName());
-        lqw.like(StringUtils.isNotBlank(bo.getDeptCategory()), SysDept::getDeptType, bo.getDeptCategory());
+        lqw.like(StringUtils.isNotBlank(bo.getDeptType()), SysDept::getDeptType, bo.getDeptType());
         lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus());
         lqw.orderByAsc(SysDept::getAncestors);
         lqw.orderByAsc(SysDept::getParentId);
@@ -254,9 +255,31 @@ public class SysDeptServiceImpl implements ISysDeptService {
         if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) {
             throw new ServiceException("部门停用,不允许新增");
         }
+        if (bo.getOrderNum() == null || bo.getOrderNum() == 0) {
+            int orderNum = this.getMaxLevelOrderNumb(info.getDeptId());
+            bo.setOrderNum(orderNum + 1);
+        }
         SysDept dept = MapstructUtils.convert(bo, SysDept.class);
         dept.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + dept.getParentId());
-        return baseMapper.insert(dept);
+        int count = baseMapper.insert(dept);
+        if (count > 0) {
+            bo.setDeptId(dept.getDeptId());
+        }
+        return count;
+    }
+
+    /**
+     * 新增部门信息
+     * @param bo 部门业务对象
+     * @return 部门视图
+     */
+    @Override
+    public SysDeptVo insertDeptBo(SysDeptBo bo) {
+        int count = this.insertDept(bo);
+        if (count > 0) {
+            return baseMapper.selectVoById(bo.getDeptId());
+        }
+        return null;
     }
 
     /**
@@ -272,7 +295,7 @@ public class SysDeptServiceImpl implements ISysDeptService {
         SysDept oldDept = baseMapper.selectById(dept.getDeptId());
         if (!oldDept.getParentId().equals(dept.getParentId())) {
             // 如果是新父部门 则校验是否具有新父部门权限 避免越权
-            this.checkDeptDataScope(dept.getParentId());
+            //this.checkDeptDataScope(dept.getParentId());
             SysDept newParentDept = baseMapper.selectById(dept.getParentId());
             if (ObjectUtil.isNotNull(newParentDept) && ObjectUtil.isNotNull(oldDept)) {
                 String newAncestors = newParentDept.getAncestors() + StringUtils.SEPARATOR + newParentDept.getDeptId();
@@ -346,4 +369,29 @@ public class SysDeptServiceImpl implements ISysDeptService {
             .eq(SysDept::getParentId, deptId).or().eq(SysDept::getDeptId, deptId)
         ).stream().map(SysDept::getDeptId).toList();
     }
+
+    @Override
+    public SysDeptVo selectVoByOtherId(String otherId) {
+        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysDept>().eq(SysDept::getOtherId, otherId));
+    }
+
+    @Override
+    public SysDeptVo selectDeptByParentIdAndName(Long parentId, String deptName) {
+        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysDept>()
+            .eq(SysDept::getParentId, parentId)
+            .eq(SysDept::getDeptName, deptName));
+    }
+
+    @Override
+    public Integer getMaxLevelOrderNumb(Long deptId) {
+        QueryWrapper<SysDept> qw = new QueryWrapper<>();
+        qw.select("max(order_num) as order_num");
+        qw.eq("parent_id", deptId);
+
+        SysDept dept = baseMapper.selectOne(qw);
+        if (dept == null) {
+            return 1;
+        }
+        return dept.getOrderNum();
+    }
 }

+ 1 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java

@@ -75,6 +75,7 @@ public class SysPostServiceImpl implements ISysPostService {
         wrapper.like(StringUtils.isNotBlank(bo.getPostCode()), SysPost::getPostCode, bo.getPostCode())
             .like(StringUtils.isNotBlank(bo.getPostName()), SysPost::getPostName, bo.getPostName())
             .eq(StringUtils.isNotBlank(bo.getStatus()), SysPost::getStatus, bo.getStatus())
+            .eq(StringUtils.isNotBlank(bo.getTenantId()), SysPost::getTenantId, bo.getTenantId())
             .eq(SysPost::getDelFlag,UserConstants.POST_NORMAL)
             .orderByAsc(SysPost::getPostSort);
         return wrapper;

+ 72 - 42
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java

@@ -331,34 +331,39 @@ public class SysUserServiceImpl implements ISysUserService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int insertUser(SysUserBo user) {
-        SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
-        // 新增用户信息
-        int rows = baseMapper.insert(sysUser);
-        if (sysUser != null) {
-            user.setUserId(sysUser.getUserId());
-        }
-        // 新增用户岗位关联
-         insertUserDept(user);
-        // 新增用户与角色管理
-        insertUserRole(user, false);
-        //一卡通账户处理
-        String autoUserAccount = remotePtParameterService.getPtParameterByKey("AUTO_CREATE_BAG");
-        RemoteUserAccountBo remoteUserAccountBo = BeanUtil.copyProperties(user, RemoteUserAccountBo.class);
-        if(Constants.AUTO_USER_ACCOUNT.equals(autoUserAccount)){
-            //自动开通一卡通账户
-            remoteUserAccountBo.setAccountStatus("1");
-            R<String> result = remoteUserAccountService.openAccount(remoteUserAccountBo);
-            if(result.getCode()== HttpStatus.SUCCESS){
-                return rows;
+        try {
+            SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
+            // 新增用户信息
+            int rows = baseMapper.insert(sysUser);
+            if (sysUser != null) {
+                user.setUserId(sysUser.getUserId());
+            }
+            // 新增用户岗位关联
+            insertUserDept(user, user.getUserDeptBoList());
+            // 新增用户与角色管理
+            insertUserRole(user, false);
+            //一卡通账户处理
+            String autoUserAccount = remotePtParameterService.getPtParameterByKey("AUTO_CREATE_BAG");
+            RemoteUserAccountBo remoteUserAccountBo = BeanUtil.copyProperties(user, RemoteUserAccountBo.class);
+            if (Constants.AUTO_USER_ACCOUNT.equals(autoUserAccount)) {
+                //自动开通一卡通账户
+                remoteUserAccountBo.setAccountStatus("1");
+                R<String> result = remoteUserAccountService.openAccount(remoteUserAccountBo);
+                if (result.getCode() == HttpStatus.SUCCESS) {
+                    return rows;
+                } else {
+                    throw new UserException(result.getMsg());
+                }
             } else {
-                throw new UserException(result.getMsg());
+                //不自动开通
+                remoteUserAccountBo.setAccountStatus("0");
+                remoteUserAccountService.insertByBo(remoteUserAccountBo);
             }
-        } else {
-            //不自动开通
-          remoteUserAccountBo.setAccountStatus("0");
-          remoteUserAccountService.insertByBo(remoteUserAccountBo);
+            return rows;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new RuntimeException(e);
         }
-        return rows;
     }
 
     /**
@@ -386,18 +391,21 @@ public class SysUserServiceImpl implements ISysUserService {
     @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId")
     @Transactional(rollbackFor = Exception.class)
     public int updateUser(SysUserBo user) {
-        // 新增用户与角色管理
-        insertUserRole(user, true);
-        // 新增用户部门岗位管理
-        insertUserDept(user);
-        SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
-        // 防止错误更新后导致的数据误删除
-        int flag = baseMapper.updateById(sysUser);
-        remoteUserAccountService.updateByBo(BeanUtil.copyProperties(user, RemoteUserAccountBo.class));
-        if (flag < 1) {
-            throw new ServiceException("修改用户" + user.getUserName() + "信息失败");
+        try {
+            // 新增用户与角色管理
+            insertUserRole(user, true);
+            // 新增用户部门岗位管理
+            insertUserDept(user, user.getUserDeptBoList());
+            SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
+            // 防止错误更新后导致的数据误删除
+            int flag = baseMapper.updateById(sysUser);
+            //更新对应的一卡通账户信息
+            remoteUserAccountService.updateByBo(BeanUtil.copyProperties(user, RemoteUserAccountBo.class));
+            return flag;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new RuntimeException(e);
         }
-        return flag;
     }
 
     /**
@@ -660,12 +668,34 @@ public class SysUserServiceImpl implements ISysUserService {
         return ObjectUtil.isNull(sysUser) ? null : sysUser.getEmail();
     }
 
-    private void insertUserDept(SysUserBo bo){
-        UserDeptBo userDeptBo = new UserDeptBo();
-        userDeptBo.setDeptId(bo.getDeptId());
-        userDeptBo.setPostId(bo.getPostId());
-        userDeptBo.setUserId(bo.getUserId());
+    /**
+     * 根据第三方标识查询用户信息
+     *
+     * @param otherId 第三方标识
+     * @return 用户信息
+     */
+    @Override
+    public SysUserVo selectUserVoByOtherId(String otherId) {
+        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysUser>()
+            .eq(SysUser::getOtherId, otherId));
+    }
 
-        userDeptService.setUserDeptPost(userDeptBo);
+    private void insertUserDept(SysUserBo bo, List<UserDeptBo> userDeptBoList) {
+        //将已有的人员部门关系设置成非主部门
+        userDeptService.updateMainDeptByUserId(bo.getUserId());
+        if(ObjectUtil.isEmpty(userDeptBoList)){
+            UserDeptBo userDeptBo = new UserDeptBo();
+            userDeptBo.setDeptId(bo.getDeptId());
+            userDeptBo.setPostId(bo.getPostId());
+            userDeptBo.setUserId(bo.getUserId());
+            userDeptBo.setMainDept("Y");
+
+            userDeptService.setUserDeptPost(userDeptBo);
+        } else {
+            userDeptBoList.forEach(userDeptBo -> {
+                userDeptBo.setUserId(bo.getUserId());
+                userDeptService.setUserDeptPost(userDeptBo);
+            });
+        }
     }
 }

+ 20 - 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/UserDeptServiceImpl.java

@@ -1,5 +1,6 @@
 package org.dromara.system.service.impl;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -162,21 +163,33 @@ public class UserDeptServiceImpl implements IUserDeptService {
 
     @Override
     public Boolean setUserDeptPost(UserDeptBo bo) {
-        this.updateMainDeptByUserId(bo.getUserId());
+        //this.updateMainDeptByUserId(bo.getUserId());
         UserDept entity = MapstructUtils.convert(bo, UserDept.class);
-        LambdaQueryWrapper<UserDept> lqw = buildQueryWrapper(bo);
+        LambdaQueryWrapper<UserDept> lqw = new LambdaQueryWrapper<UserDept>()
+            .eq(UserDept::getUserId,bo.getUserId())
+            .eq(UserDept::getPostId, bo.getPostId())
+            .eq(UserDept::getDeptId, bo.getDeptId());
+
         UserDeptVo vo = baseMapper.selectVoOne(lqw);
-        if (entity != null) {
-            entity.setMainDept("Y");
-        }
-        if(vo==null){
+        if(ObjectUtil.isEmpty(vo)){
             return baseMapper.insert(entity) > 0;
-        } else {
+        } else{
             if (entity != null) {
                 entity.setUserDeptId(vo.getUserDeptId());
             }
             return baseMapper.updateById(entity) > 0;
         }
+        //if (entity != null) {
+        //    entity.setMainDept("Y");
+        //}
+        //if(vo==null){
+        //    return baseMapper.insert(entity) > 0;
+        //} else {
+        //    if (entity != null) {
+        //        entity.setUserDeptId(vo.getUserDeptId());
+        //    }
+        //    return baseMapper.updateById(entity) > 0;
+        //}
     }
 
     @Override

+ 27 - 0
ruoyi-server/pom.xml

@@ -0,0 +1,27 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-cloud-plus</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modules>
+        <module>ruoyi-server-common</module>
+        <module>ruoyi-server-base</module>
+        <module>ruoyi-server-sync</module>
+        <module>ruoyi-server-mqdata</module>
+    </modules>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-server</artifactId>
+    <packaging>pom</packaging>
+
+    <name>ruoyi-server</name>
+    <description>
+        ruoyi-service 业务服务
+    </description>
+
+    <dependencies>
+
+    </dependencies>
+</project>

+ 39 - 0
ruoyi-server/ruoyi-server-base/pom.xml

@@ -0,0 +1,39 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-server</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <artifactId>ruoyi-server-base</artifactId>
+    <packaging>jar</packaging>
+
+    <name>ruoyi-server-base</name>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-api-system</artifactId>
+        </dependency>
+         <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-dubbo</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-server-common</artifactId>
+            <version>2.2.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 78 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/SyncRemoteDeptService.java

@@ -0,0 +1,78 @@
+package org.dromara.server.base.service.dept;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.common.core.domain.R;
+import org.dromara.system.api.RemoteDeptService;
+import org.dromara.system.api.domain.bo.RemoteDeptBo;
+import org.dromara.system.api.domain.vo.RemoteDeptVo;
+import org.springframework.stereotype.Service;
+
+/**
+ * name: SyncRemoteDeptService
+ * package: org.dromara.service.sync.dept.service
+ * description: 部门同步处理服务,将同步过来的部门信息转换成可入库的业务模型以及调用远程服务更新部门数据
+ * date: 2024-10-17 23:09:01 23:09
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class SyncRemoteDeptService {
+
+    @DubboReference
+    private final RemoteDeptService remoteDeptService;
+
+    /**
+     * 根据第三方对接的唯一标识符查询对应的部门信息
+     *
+     * @param otherId  第三方对接的唯一标识符
+     * @param tenantId 租户Id
+     * @return 部门信息
+     */
+    public RemoteDeptVo selectDeptByOtherId(String otherId, String tenantId){
+        return remoteDeptService.selectDeptByOtherId(otherId, tenantId);
+    }
+    /**
+     * 根据父节点Id和名称查询部门
+     * @param parentId 父节点
+     * @param deptName 名称
+     * @return 部门信息
+     */
+    public RemoteDeptVo selectDeptByParentIdAndName(Long parentId, String deptName) {
+        return remoteDeptService.selectDeptByParentIdAndName(parentId, deptName);
+    }
+    /**
+     * 增加新部门
+     *
+     * @param remoteDeptBo 部门业务模型
+     * @return 增加结果
+     */
+    public R<Object> insertDept(RemoteDeptBo remoteDeptBo){
+        return remoteDeptService.insertDept(remoteDeptBo);
+    }
+
+    /**
+     * 修改部门
+     *
+     * @param remoteDeptBo 部门业务模型
+     * @return 增加结果
+     */
+    public R<Object> updateDept(RemoteDeptBo remoteDeptBo){
+        return remoteDeptService.updateDept(remoteDeptBo);
+    }
+
+    /**
+     * 根据第三方对接的唯一标识符删除部门
+     *
+     * @param otherId 第三方对接后的唯一标识符
+     * @return 删除结果
+     */
+    public R<Object> deleteDeptByOtherId(String otherId){
+        return remoteDeptService.deleteDeptByOtherId(otherId);
+    }
+}

+ 24 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/strategy/ISyncDeptStrategy.java

@@ -0,0 +1,24 @@
+package org.dromara.server.base.service.dept.strategy;
+
+import org.dromara.server.common.domain.bo.ResourceDept;
+
+import java.util.List;
+
+/**
+ * name: IDoDeptStrategy
+ * package: org.dromara.server.base.dept.service.strategy
+ * description: 部门同步写入策略
+ * date: 2024-10-18 14:17:38 14:17
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface ISyncDeptStrategy {
+    /**
+     * 处理部门的部门数据
+     *
+     * @param deptList 部门数据
+     */
+    void syncDept(List<ResourceDept> deptList);
+}

+ 38 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/strategy/SyncDeptStrategyContent.java

@@ -0,0 +1,38 @@
+package org.dromara.server.base.service.dept.strategy;
+
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * name: SyncDeptStrategyContent
+ * package: org.dromara.server.base.dept.service.strategy.impl
+ * description: 部门同步处理策略上下文
+ * date: 2024-10-18 14:51:26 14:51
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Service
+public class SyncDeptStrategyContent {
+    private final Map<String, ISyncDeptStrategy> strategyMap = new ConcurrentHashMap<>();
+
+    @Autowired
+    public SyncDeptStrategyContent(Map<String, ISyncDeptStrategy> strategyMap) {
+        this.strategyMap.putAll(strategyMap);
+    }
+
+    /**
+     * 同步处理入口
+     * @param deptList 部门数据
+     * @param syncResource 数据来源
+     */
+    public void syncDept(List<ResourceDept> deptList ,String syncResource){
+        strategyMap.get(syncResource).syncDept(deptList);
+    }
+}

+ 150 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/strategy/impl/GraduateClassStrategyImpl.java

@@ -0,0 +1,150 @@
+package org.dromara.server.base.service.dept.strategy.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.server.base.service.dept.SyncRemoteDeptService;
+import org.dromara.server.base.service.dept.strategy.ISyncDeptStrategy;
+import org.dromara.server.common.constant.DefaultConstants;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.dromara.system.api.domain.bo.RemoteDeptBo;
+import org.dromara.system.api.domain.vo.RemoteDeptVo;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: GraduateClassStrategyImpl
+ * package: org.dromara.server.base.dept.service.strategy.impl
+ * description: 研究生班级同步策略
+ * date: 2024-10-18 14:47:28 14:47
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(SyncResourceConstants.GRADUATE_CLASS)
+public class GraduateClassStrategyImpl implements ISyncDeptStrategy {
+    private final SyncRemoteDeptService syncRemoteDeptService;
+
+    @Override
+    public void syncDept(List<ResourceDept> deptList) {
+        List<String> syncMessage = new ArrayList<>();
+        deptList.forEach(resourceDept -> {
+            R<Object> result = syncDept(resourceDept);
+            if (result.getCode() == R.SUCCESS) {
+                syncMessage.add(MessageFormat.format("[同步研究生班级成功]-[{0}]", JsonUtils.toJsonString(resourceDept)));
+            } else {
+                syncMessage.add(MessageFormat.format("[同步研究生班级失败]-[{0}]-[{1}]", JsonUtils.toJsonString(resourceDept), result.getMsg()));
+            }
+        });
+        syncMessage.forEach(System.out::println);
+    }
+
+    /**
+     * 单个研究生班级处理
+     *
+     * @param resourceDept 研究生班
+     * @return 处理结果
+     */
+    private R<Object> syncDept(ResourceDept resourceDept) {
+        String tenantId = resourceDept.getTenantId();
+        if (StrUtil.isEmpty(tenantId)) {
+            tenantId = DefaultConstants.TENANT_ID;
+            resourceDept.setTenantId(tenantId);
+        }
+
+        try {
+            String otherId = resourceDept.getDept_id();
+            RemoteDeptVo remoteDeptVo = syncRemoteDeptService.selectDeptByOtherId(otherId, tenantId);
+            //将班级组装成入库的对模型
+            R<RemoteDeptBo> result = setRemoteDeptBo(resourceDept, remoteDeptVo);
+            if (result.getCode() == R.SUCCESS) {
+                if (remoteDeptVo != null) {
+                    // 已存在此班级,更新
+                    return syncRemoteDeptService.updateDept(result.getData());
+                } else {
+                    return syncRemoteDeptService.insertDept(result.getData());
+                }
+            } else {
+                return R.fail(result.getMsg());
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            return R.fail(e.getMessage());
+        }
+    }
+
+    /**
+     * 组装写库的研究生班级
+     * 研究生的班级结构为 在校研究生(系统初始化后的固定值)->年级(对应年份)->班级(对应班名)
+     *
+     * @param resourceDept 源班级数据
+     * @param remoteDeptVo 源班级对应一卡通系统数据
+     * @return 写库班级业务数据
+     */
+    private R<RemoteDeptBo> setRemoteDeptBo(ResourceDept resourceDept, RemoteDeptVo remoteDeptVo) {
+        RemoteDeptVo yearDeptVo = doYearDept(resourceDept);
+        if (yearDeptVo == null) {
+            //处理年份对应的班级失败,直接返回失败
+            return R.fail("创建年份对应部门失败");
+        }
+        RemoteDeptBo remoteDeptBo;
+        if (ObjUtil.isEmpty(remoteDeptVo)) {
+            remoteDeptBo = new RemoteDeptBo();
+        } else {
+            remoteDeptBo = BeanUtil.copyProperties(remoteDeptVo, RemoteDeptBo.class);
+        }
+        //研究生班级对应部门类型类型为06,以和培训班的转换部门区分
+        remoteDeptBo.setDeptType(DefaultConstants.GRADUATE_DEPT_TYPE);
+        remoteDeptBo.setDeptName(resourceDept.getDept_name());
+        remoteDeptBo.setOtherId(resourceDept.getDept_id());
+        remoteDeptBo.setBeginDate(resourceDept.getBeginDate());
+        remoteDeptBo.setEndDate(resourceDept.getEndDate());
+        if (StringUtils.isNotEmpty(resourceDept.getTenantId())) {
+            remoteDeptBo.setTenantId(resourceDept.getTenantId());
+        }
+        if (StringUtils.isNotEmpty(resourceDept.getDelFlag())) {
+            remoteDeptBo.setDelFlag(resourceDept.getDelFlag());
+        }
+        return R.ok(remoteDeptBo);
+    }
+
+    /**
+     * 创建研究生的年份对应的部门
+     * @param resourceDept 源班级数据
+     * @return 部门信息
+     */
+    private RemoteDeptVo doYearDept(ResourceDept resourceDept) {
+        //检查年份对应的部门,年份的父节点固定为在校研究生->162
+        Long rootId = DefaultConstants.GRADUATE_PARENT_DEPT_ID;
+        RemoteDeptVo yearDeptVo = syncRemoteDeptService.selectDeptByParentIdAndName(rootId, resourceDept.getYear().toString());
+        if (yearDeptVo != null) {
+            return yearDeptVo;
+        }
+        //不存在对应的部门,需要增加
+        RemoteDeptBo remoteDeptBo = new RemoteDeptBo();
+        remoteDeptBo.setDeptName(resourceDept.getYear().toString());
+        remoteDeptBo.setDeptType(DefaultConstants.YEAR_DEPT_TYPE);
+        remoteDeptBo.setParentId(rootId);
+        if (StringUtils.isNotEmpty(resourceDept.getTenantId())) {
+            remoteDeptBo.setTenantId(remoteDeptBo.getTenantId());
+        }
+
+        R<Object> result = syncRemoteDeptService.insertDept(remoteDeptBo);
+        if (result.getCode() == R.SUCCESS) {
+            return (RemoteDeptVo) result.getData();
+        }
+        return null;
+    }
+}

+ 121 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/strategy/impl/HrDeptStrategyImpl.java

@@ -0,0 +1,121 @@
+package org.dromara.server.base.service.dept.strategy.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.server.base.service.dept.SyncRemoteDeptService;
+import org.dromara.server.base.service.dept.strategy.ISyncDeptStrategy;
+import org.dromara.server.common.constant.DefaultConstants;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.dromara.system.api.domain.bo.RemoteDeptBo;
+import org.dromara.system.api.domain.vo.RemoteDeptVo;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: HrDeptStrategyImpl
+ * package: org.dromara.server.base.dept.service.strategy.impl
+ * description: 人事部门同步处理策略
+ * date: 2024-10-18 14:40:23 14:40
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(SyncResourceConstants.HR_DEPT)
+public class HrDeptStrategyImpl implements ISyncDeptStrategy {
+    private final SyncRemoteDeptService syncRemoteDeptService;
+
+    @Override
+    public void syncDept(List<ResourceDept> deptList) {
+        List<String> syncMessage = new ArrayList<>();
+        deptList.forEach(resourceDept -> {
+            R<Object> result = syncDept(resourceDept);
+            if (result.getCode() == R.SUCCESS) {
+                syncMessage.add(MessageFormat.format("[同步部门成功]-[{0}]", JsonUtils.toJsonString(resourceDept)));
+            } else {
+                syncMessage.add(MessageFormat.format("[同步部门失败]-[{0}]-[{1}]", JsonUtils.toJsonString(resourceDept), result.getMsg()));
+            }
+        });
+        syncMessage.forEach(System.out::println);
+    }
+
+    /**
+     * 单个部门处理
+     *
+     * @param resourceDept 源部门
+     * @return 入库部门模型
+     */
+    public R<Object> syncDept(ResourceDept resourceDept) {
+        try {
+            String tenantId = resourceDept.getTenantId();
+            if (StrUtil.isEmpty(tenantId)) {
+                tenantId = DefaultConstants.TENANT_ID;
+                resourceDept.setTenantId(tenantId);
+            }
+            String otherId = resourceDept.getDept_id();
+            String parentId = resourceDept.getParent_id();
+            //获取同步的部门在一卡通系统中对应的部门
+            RemoteDeptVo remoteDeptVo = syncRemoteDeptService.selectDeptByOtherId(otherId, tenantId);
+            //获取同步的部门在一卡通系统中对应的父部门
+            RemoteDeptVo remoteParentDeptVo = syncRemoteDeptService.selectDeptByOtherId(parentId, tenantId);
+            //组装写库的部门业务对象
+            RemoteDeptBo remoteDeptBo = setRemoteDeptBo(resourceDept, remoteDeptVo, remoteParentDeptVo);
+            if (remoteDeptVo != null) {
+                // 已存在此部门,更新
+                return syncRemoteDeptService.updateDept(remoteDeptBo);
+            } else {
+                return syncRemoteDeptService.insertDept(remoteDeptBo);
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            return R.fail(e.getMessage());
+        }
+    }
+
+    /**
+     * 同步部门预处理
+     * @param resourceDept 源部门
+     * @param remoteDeptVo 一卡通系统对应部门
+     * @param remoteParentDeptVo 一卡通系统对应父部门
+     * @return 部门业务对象
+     */
+    private RemoteDeptBo setRemoteDeptBo(ResourceDept resourceDept, RemoteDeptVo remoteDeptVo, RemoteDeptVo remoteParentDeptVo) {
+        String deptNum = resourceDept.getDept_num();
+        String tenantId = resourceDept.getTenantId();
+        RemoteDeptBo remoteDeptBo;
+        if (ObjUtil.isEmpty(remoteDeptVo)) {
+            remoteDeptBo = new RemoteDeptBo();
+            //业中同步的部门默认类型为03-部门
+            remoteDeptBo.setDeptType(DefaultConstants.DEPT_DEPT_TYPE);
+        } else {
+            remoteDeptBo = BeanUtil.copyProperties(remoteDeptVo, RemoteDeptBo.class);
+        }
+        remoteDeptBo.setDeptName(resourceDept.getDept_name());
+        remoteDeptBo.setOtherId(resourceDept.getDept_id());
+        if (StringUtils.isNotEmpty(tenantId)) {
+            remoteDeptBo.setTenantId(tenantId);
+        }
+        if (remoteParentDeptVo != null) {
+            remoteDeptBo.setParentId(remoteParentDeptVo.getDeptId());
+        } else {
+            //如果同步的部门的父部门在系统中不存在,则父部门为学校
+            remoteDeptBo.setParentId(DefaultConstants.PARENT_DEPT_ID);
+        }
+        if (StringUtils.isNotEmpty(deptNum)) {
+            remoteDeptBo.setOrderNum(Integer.valueOf(deptNum));
+        }
+        return remoteDeptBo;
+    }
+}

+ 170 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/dept/strategy/impl/TrainClassStrategyImpl.java

@@ -0,0 +1,170 @@
+package org.dromara.server.base.service.dept.strategy.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.server.base.service.dept.SyncRemoteDeptService;
+import org.dromara.server.base.service.dept.strategy.ISyncDeptStrategy;
+import org.dromara.server.common.constant.DefaultConstants;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.dromara.system.api.domain.bo.RemoteDeptBo;
+import org.dromara.system.api.domain.vo.RemoteDeptVo;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: TrainClassStrategyImpl
+ * package: org.dromara.server.base.dept.service.strategy.impl
+ * description: 培训班级部门同步策略
+ * date: 2024-10-18 14:42:17 14:42
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(SyncResourceConstants.TRAIN_CLASS)
+public class TrainClassStrategyImpl implements ISyncDeptStrategy {
+
+    private final SyncRemoteDeptService syncRemoteDeptService;
+
+    @Override
+    public void syncDept(List<ResourceDept> deptList) {
+        List<String> syncMessage = new ArrayList<>();
+        deptList.forEach(resourceDept -> {
+            R<Object> result = syncDept(resourceDept);
+            if (result.getCode() == R.SUCCESS) {
+                syncMessage.add(MessageFormat.format("[同步培训班级成功]-[{0}]", JsonUtils.toJsonString(resourceDept)));
+            } else {
+                syncMessage.add(MessageFormat.format("[同步培训班级失败]-[{0}]-[{1}]", JsonUtils.toJsonString(resourceDept), result.getMsg()));
+            }
+        });
+        syncMessage.forEach(System.out::println);
+    }
+
+    /**
+     * 单个培训班级的处理
+     * 党校->培训班->校本部->年份->学期->班级
+     *
+     * @param resourceDept 班级数据
+     * @return 处理结果
+     */
+    private R<Object> syncDept(ResourceDept resourceDept) {
+        String tenantId = resourceDept.getTenantId();
+        if (StrUtil.isEmpty(tenantId)) {
+            tenantId = DefaultConstants.TENANT_ID;
+            resourceDept.setTenantId(tenantId);
+        }
+        String otherId = resourceDept.getDept_id();
+        RemoteDeptVo remoteDeptVo = syncRemoteDeptService.selectDeptByOtherId(otherId, tenantId);
+        //将班级组装成入库的对模型
+        R<RemoteDeptBo> result = setRemoteDeptBo(resourceDept, remoteDeptVo);
+        if (result.getCode() == R.SUCCESS) {
+            if (remoteDeptVo != null) {
+                // 已存在此班级,更新
+                return syncRemoteDeptService.updateDept(result.getData());
+            } else {
+                return syncRemoteDeptService.insertDept(result.getData());
+            }
+        } else {
+            return R.fail(result.getMsg());
+        }
+    }
+
+    /**
+     * 组装写库的培训班级数据
+     * 培训班的班级结构为 校本部(系统初始化后的固定值)->年份(培训的年份)->学期(培训班的学期)->班级(对应班名)
+     *
+     * @param resourceDept 源班级数据
+     * @param remoteDeptVo 源班级对应一卡通系统数据
+     * @return 写库班级业务数据
+     */
+    private R<RemoteDeptBo> setRemoteDeptBo(ResourceDept resourceDept, RemoteDeptVo remoteDeptVo) {
+        //检查年份对应的部门,年份的父节点固定为127->校本部
+        Long rootId = DefaultConstants.TRAIN_PARENT_DEPT_ID;
+        RemoteDeptVo yearDeptVo = doYearOrSemesterDept(resourceDept, rootId, 0);
+        if (yearDeptVo == null) {
+            //处理年份对应的班级失败,直接返回失败
+            return R.fail("创建年份对应部门失败");
+        }
+        //检查学期对应的部门
+        RemoteDeptVo semesterDeptVo = doYearOrSemesterDept(resourceDept, yearDeptVo.getDeptId(), 1);
+        if (semesterDeptVo == null) {
+            //处理学期对应的班级失败,直接返回失败
+            return R.fail("创建学期对应部门失败");
+        }
+
+        //处理班级对应的部门
+        String deptNum = resourceDept.getDept_num();
+        String tenantId = resourceDept.getTenantId();
+        RemoteDeptBo remoteDeptBo;
+        if (ObjUtil.isEmpty(remoteDeptVo)) {
+            remoteDeptBo = new RemoteDeptBo();
+            //班级对应的部门默认类型为 05-班级
+            remoteDeptBo.setDeptType(DefaultConstants.CLASS_DEPT_TYPE);
+        } else {
+            remoteDeptBo = BeanUtil.copyProperties(remoteDeptVo, RemoteDeptBo.class);
+        }
+        remoteDeptBo.setDeptName(resourceDept.getDept_name());
+        remoteDeptBo.setOtherId(resourceDept.getDept_id());
+        remoteDeptBo.setParentId(semesterDeptVo.getDeptId());
+        remoteDeptBo.setPayCheck(resourceDept.getPayCheck());
+        remoteDeptBo.setPayBegin(resourceDept.getPayBegin());
+        remoteDeptBo.setPayEnd(resourceDept.getPayEnd());
+        remoteDeptBo.setCheckDate(resourceDept.getCheckDate());
+        remoteDeptBo.setBeginDate(resourceDept.getBeginDate());
+        remoteDeptBo.setEndDate(resourceDept.getEndDate());
+        remoteDeptBo.setCanEat(resourceDept.getCanEat());
+        remoteDeptBo.setChooseRoom(resourceDept.getChooseRoom());
+        if (StringUtils.isNotEmpty(deptNum)) {
+            remoteDeptBo.setOrderNum(Integer.valueOf(deptNum));
+        }
+
+        if (StringUtils.isNotEmpty(tenantId)) {
+            remoteDeptBo.setTenantId(tenantId);
+        }
+
+        return R.ok(remoteDeptBo);
+    }
+
+    /**
+     * 处理培训班年份或学期对应的班级
+     *
+     * @param resourceDept 源班级
+     * @param rootId       父节点
+     * @param flag         标识 0-年份 1-学期
+     * @return 部门
+     */
+    private RemoteDeptVo doYearOrSemesterDept(ResourceDept resourceDept, Long rootId, int flag) {
+        String deptName = flag == 0 ? resourceDept.getYear().toString()+"年" : resourceDept.getSemester();
+
+        RemoteDeptVo yearDeptVo = syncRemoteDeptService.selectDeptByParentIdAndName(rootId, deptName);
+        if (yearDeptVo != null) {
+            return yearDeptVo;
+        }
+        //不存在对应的部门,需要增加
+        RemoteDeptBo remoteDeptBo = new RemoteDeptBo();
+        remoteDeptBo.setDeptName(deptName);
+        remoteDeptBo.setParentId(rootId);
+        remoteDeptBo.setDeptType(DefaultConstants.YEAR_DEPT_TYPE);
+        remoteDeptBo.setParentId(rootId);
+        if (StringUtils.isNotEmpty(resourceDept.getTenantId())) {
+            remoteDeptBo.setTenantId(remoteDeptBo.getTenantId());
+        }
+        R<Object> result = syncRemoteDeptService.insertDept(remoteDeptBo);
+        if (result.getCode() == R.SUCCESS) {
+            return (RemoteDeptVo) result.getData();
+        }
+        return null;
+    }
+}

+ 319 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/SyncRemoteUserService.java

@@ -0,0 +1,319 @@
+package org.dromara.server.base.service.user;
+
+import cn.dev33.satoken.secure.BCrypt;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.server.base.util.EncryptorUtil;
+import org.dromara.server.common.constant.DefaultConstants;
+import org.dromara.server.common.domain.bo.ResourcePerson;
+import org.dromara.server.common.domain.bo.ResourcePersonDept;
+import org.dromara.system.api.RemoteDeptService;
+import org.dromara.system.api.RemotePostService;
+import org.dromara.system.api.RemoteUserService;
+import org.dromara.system.api.domain.bo.RemoteUserBo;
+import org.dromara.system.api.domain.bo.RemoteUserDeptBo;
+import org.dromara.system.api.domain.vo.RemoteDeptVo;
+import org.dromara.system.api.domain.vo.RemotePostVo;
+import org.dromara.system.api.domain.vo.RemoteUserVo;
+import org.springframework.stereotype.Service;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * name: ConvertUserService
+ * package: org.dromara.server.base.user.service
+ * description: 人员同步处理服务,调用远程服务将同步的人员信息入库
+ * date: 2024-10-23 10:52:40 10:52
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class SyncRemoteUserService {
+    @DubboReference
+    private final RemoteUserService remoteUserService;
+    @DubboReference
+    private final RemoteDeptService remoteDeptService;
+    @DubboReference
+    private final RemotePostService remotePostService;
+
+    /**
+     * 单个人员同步处理
+     *
+     * @param person 人员
+     * @return 结果
+     */
+    public R<RemoteUserVo> syncPeron(ResourcePerson person) {
+        try {
+            String otherId = person.getUserId();
+            //获取人员在一卡通系统中的数据
+            RemoteUserVo remoteUserVo = remoteUserService.selectUserVoByOtherId(otherId);
+            //组装入库的人员业务对象
+            R<RemoteUserBo> result = setUserInfo(person, remoteUserVo);
+            if (result.getCode() == R.SUCCESS) {
+                if (ObjectUtil.isEmpty(remoteUserVo)) {
+                    //不存在此人员,增加
+                    return remoteUserService.insertUser(result.getData());
+                } else {
+                    //存在此人员,修改
+                    return remoteUserService.updateUser(result.getData());
+                }
+            }
+            return R.fail(result.getMsg());
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            return R.fail(e.getMessage());
+        }
+    }
+
+    /**
+     * 获取租户配置的岗位清单
+     *
+     * @param tenantId 租户
+     * @return 岗位清单
+     */
+    public List<RemotePostVo> selectPostVoByTenantId(String tenantId) {
+        String cacheKey = tenantId + "_post:";
+        List<RemotePostVo> postVos = RedisUtils.getCacheObject(cacheKey);
+        if (ObjectUtil.isEmpty(postVos)) {
+            postVos = remotePostService.selectPostVo(tenantId);
+            RedisUtils.setCacheObject(cacheKey, postVos, Duration.ofHours(4));
+        }
+        return postVos;
+    }
+
+    /**
+     * 组装入库的人员业务对象
+     *
+     * @param person       源人员信息
+     * @param remoteUserVo 一卡通对应信息
+     * @return 组装结果
+     */
+    private R<RemoteUserBo> setUserInfo(ResourcePerson person, RemoteUserVo remoteUserVo) {
+        String tenantId = person.getTenantId();
+        if (StrUtil.isEmpty(tenantId)) {
+            tenantId = DefaultConstants.TENANT_ID;
+            person.setTenantId(tenantId);
+        }
+        //获取人员对应的部门信息
+        RemoteDeptVo remoteDeptVo = remoteDeptService.selectDeptByOtherId(person.getDeptId(), tenantId);
+        if (remoteDeptVo == null) {
+            return R.fail("没有找到对应的部门信息");
+        }
+        RemoteUserBo remoteUserBo;
+        if (ObjectUtil.isEmpty(remoteUserVo)) {
+            String userName = getUserName(person);
+            remoteUserBo = new RemoteUserBo();
+            remoteUserBo.setUserType("sys_user");
+            remoteUserBo.setPassword(BCrypt.hashpw(DefaultConstants.LOGIN_PASSWORD));
+            remoteUserBo.setUserName(userName);
+            remoteUserBo.setUserNumb(userName);
+            remoteUserBo.setRoleIds(getUserRole(person));
+        } else {
+            remoteUserBo = BeanUtil.copyProperties(remoteUserVo, RemoteUserBo.class);
+        }
+
+        remoteUserBo.setRealName(person.getRealName());
+        remoteUserBo.setNickName(person.getRealName());
+        remoteUserBo.setCategory(person.getCategory());
+        remoteUserBo.setOtherId(person.getUserId());
+        remoteUserBo.setSex(person.getSex());
+        remoteUserBo.setRemark(person.getRemark());
+        remoteUserBo.setUserState(person.getUserState());
+        remoteUserBo.setPhone(person.getPhone());
+        remoteUserBo.setDeptId(remoteDeptVo.getDeptId());
+        remoteUserBo.setPostId(getUserPostId(person.getPostCode(), tenantId));
+        remoteUserBo.setCardType(getUserCardType(person));
+        remoteUserBo.setLifespan(getUserLifespan(person, remoteDeptVo));
+        remoteUserBo.setTenantId(tenantId);
+        //身份证
+        String idNumber = person.getIdNumber();
+        if (StrUtil.isNotEmpty(idNumber)) {
+            remoteUserBo.setIdNumber(getUserIdNumber(idNumber));
+        }
+        remoteUserBo.setUserDeptList(getUserDept(person));
+        return R.ok(remoteUserBo);
+    }
+
+    /**
+     * 获取人员的卡类,如果同步数据有卡类则为同步数据的卡类,否则要根据规则获取
+     * 人员类型
+     * 教职工  category=1
+     * userState=在职(on) 返回 cardType=1
+     * userState=离校(quit) 返回 cardType=5
+     * userState=退休(retire) 返回 cardType=1
+     * userState=去世(die) 返回 cardType=6
+     * 学员   category=2 返回 cardType=2
+     * 研究生 category=3 返回 cardType=3
+     *
+     * @param person 源人员信息
+     * @return 卡类
+     */
+    private Long getUserCardType(ResourcePerson person) {
+        if (StrUtil.isNotEmpty(person.getCardType())) {
+            return Long.valueOf(person.getCardType());
+        }
+        //默认卡类
+        String cardType = "1";
+        String category = person.getCategory();
+        String userState = person.getUserState();
+        cardType = switch (category) {
+            case "1" -> switch (userState) {
+                case "on", "retire" -> "1";
+                case "quit" -> "5";
+                case "die" -> "6";
+                default -> cardType;
+            };
+            case "2" -> "2";
+            case "3" -> "3";
+            default -> cardType;
+        };
+        return Long.valueOf(cardType);
+    }
+
+    /**
+     * 获取人员的有效期
+     * 如果同步的有有效基体则返回此有效期,否则再检查人员所在的部门是否有结束日期,如有则返回结束日期,否则返回
+     * 默认2050-12-31 23:59:59
+     *
+     * @param person       源人员信息
+     * @param remoteDeptVo 所在部门信息
+     * @return 有效期
+     */
+    private Date getUserLifespan(ResourcePerson person, RemoteDeptVo remoteDeptVo) {
+        if (ObjectUtil.isNotEmpty(person.getLifespan())) {
+            return person.getLifespan();
+        }
+        Date endDate = remoteDeptVo.getEndDate();
+        if (ObjectUtil.isEmpty(endDate)) {
+            return DateUtil.parse("2050-12-31 23:59:59");
+        } else {
+            return endDate;
+        }
+    }
+
+    /**
+     * 解密人员身份证
+     *
+     * @param sourceIdNumb 待解密身份号
+     * @return 解密后身份证号
+     */
+    private String getUserIdNumber(String sourceIdNumb) {
+        return ObjectUtil.isEmpty(sourceIdNumb) ? null : EncryptorUtil.decode(sourceIdNumb);
+    }
+
+    /**
+     * 获取人员对应的岗位Id
+     *
+     * @param postCode 岗位编码
+     * @param tenantId 租户Id
+     * @return 岗位Id
+     */
+    private Long getUserPostId(String postCode, String tenantId) {
+        List<RemotePostVo> postVos = selectPostVoByTenantId(tenantId);
+        List<Long> postIds = postVos.stream().filter(post -> postCode.equals(post.getPostCode()))
+            .map(RemotePostVo::getPostId).toList();
+        if (postIds.isEmpty()) {
+            return DefaultConstants.POST_ID;
+        }
+        return postIds.get(0);
+    }
+
+    /**
+     * 获取同步人员的登录账号
+     *
+     * @param person 源人员
+     * @return 登录账号
+     */
+    private String getUserName(ResourcePerson person) {
+        String userName = person.getUserName();
+        //如果同步的有登录账号,返回同步的登录账号
+        if (StrUtil.isNotEmpty(userName)) {
+            return userName;
+        }
+        String phone = person.getPhone();
+        //如果同步没有登录账号,但同步有手机号,则将手机号作为登录账号
+        if (StrUtil.isNotEmpty(phone)) {
+            return phone;
+        }
+        //如果都没有,则要自动生成一个
+        String temp = DateUtil.format(new Date(), "yyyyMMdd");
+        String cacheKey = person.getTenantId() + "_day_number:";
+        Integer count = RedisUtils.getCacheObject(cacheKey);
+        if (ObjectUtil.isEmpty(count)) {
+            count = 1;
+        } else {
+            count++;
+        }
+        RedisUtils.setCacheObject(cacheKey, count, Duration.ofDays(1));
+        return temp + StrUtil.padPre(count.toString(), 4, '0');
+    }
+
+    /**
+     * 获取同步人员的默认角色
+     *
+     * @param person 源人员
+     * @return 角色
+     */
+    private Long[] getUserRole(ResourcePerson person) {
+        String category = person.getCategory();
+        Long[] roleIds = new Long[1];
+        switch (category) {
+            //教职工
+            case "1":
+                roleIds[0] = DefaultConstants.TEACHER_ROLE_ID;
+                break;
+            //学员
+            case "2":
+                roleIds[0] = DefaultConstants.TRAIN_ROLE_ID;
+                break;
+            //研究生
+            case "3":
+                roleIds[0] = DefaultConstants.GRADUATE_ROLE_ID;
+                break;
+        }
+
+        return roleIds;
+    }
+
+    /**
+     * 获取同步人员的部门
+     *
+     * @param person 源人员
+     * @return 人员部门
+     */
+    private List<RemoteUserDeptBo> getUserDept(ResourcePerson person) {
+        List<ResourcePersonDept> resourcePersonDeptList = person.getUserDeptList();
+        if (ObjectUtil.isEmpty(resourcePersonDeptList)) {
+            return null;
+        }
+        List<RemoteUserDeptBo> remoteUserDeptBos = new ArrayList<>();
+        resourcePersonDeptList.forEach(resourcePersonDept -> {
+            RemoteUserDeptBo remoteUserDeptBo = new RemoteUserDeptBo();
+            RemoteDeptVo remoteDeptVo = remoteDeptService.selectDeptByOtherId(resourcePersonDept.getDeptId(), person.getTenantId());
+            if (ObjectUtil.isNotEmpty(remoteDeptVo)) {
+                remoteUserDeptBo.setDeptId(remoteDeptVo.getDeptId());
+                remoteUserDeptBo.setPostId(getUserPostId(resourcePersonDept.getPostCode(), person.getTenantId()));
+                remoteUserDeptBo.setMainDept(resourcePersonDept.getMainDept());
+                remoteUserDeptBo.setDelFlag(resourcePersonDept.getDelFlag());
+
+                remoteUserDeptBos.add(remoteUserDeptBo);
+            }
+        });
+
+        return remoteUserDeptBos;
+    }
+}

+ 25 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/strategy/ISyncUserStrategy.java

@@ -0,0 +1,25 @@
+package org.dromara.server.base.service.user.strategy;
+
+import org.dromara.server.common.domain.bo.ResourcePerson;
+
+import java.util.List;
+
+/**
+ * name: ISyncUserStrategy
+ * package: org.dromara.server.base.user.service.strategy
+ * description: 人员同步写入策略
+ * date: 2024-10-23 11:13:28 11:13
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface ISyncUserStrategy {
+
+    /**
+     * 人员同步处理
+     * @param persons 源人员列表
+     * @return 同步结果
+     */
+    boolean syncUser(List<ResourcePerson> persons);
+}

+ 38 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/strategy/SyncUserStrategyContent.java

@@ -0,0 +1,38 @@
+package org.dromara.server.base.service.user.strategy;
+
+import org.dromara.server.common.domain.bo.ResourcePerson;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * name: SyncDeptStrategyContent
+ * package: org.dromara.server.base.dept.service.strategy.impl
+ * description: 人员同步处理策略上下文
+ * date: 2024-10-18 14:51:26 14:51
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Service
+public class SyncUserStrategyContent {
+    private final Map<String, ISyncUserStrategy> strategyMap = new ConcurrentHashMap<>();
+
+    @Autowired
+    public SyncUserStrategyContent(Map<String, ISyncUserStrategy> strategyMap) {
+        this.strategyMap.putAll(strategyMap);
+    }
+
+    /**
+     * 同步处理入口
+     * @param personList 人员数据
+     * @param syncResource 数据来源
+     */
+    public boolean syncUser(List<ResourcePerson> personList , String syncResource){
+        return strategyMap.get(syncResource).syncUser(personList);
+    }
+}

+ 49 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/strategy/impl/SyncGraduateStrategyImpl.java

@@ -0,0 +1,49 @@
+package org.dromara.server.base.service.user.strategy.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.server.base.service.user.SyncRemoteUserService;
+import org.dromara.server.base.service.user.strategy.ISyncUserStrategy;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourcePerson;
+import org.dromara.system.api.domain.vo.RemoteUserVo;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: SyncGraduateStrategyImpl
+ * package: org.dromara.server.base.dept.service.strategy.impl
+ * description: 研究生人员同步处理策略
+ * date: 2024-10-18 14:40:23 14:40
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(SyncResourceConstants.GRADUATE)
+public class SyncGraduateStrategyImpl implements ISyncUserStrategy {
+    private final SyncRemoteUserService syncUserService;
+
+    @Override
+    public boolean syncUser(List<ResourcePerson> persons) {
+        List<String> syncMessage = new ArrayList<>();
+
+        persons.forEach(person -> {
+            R<RemoteUserVo> result = syncUserService.syncPeron(person);
+            if (result.getCode() == R.SUCCESS) {
+                syncMessage.add(MessageFormat.format("[同步研究生成功]-[{0}]", JsonUtils.toJsonString(person)));
+            } else {
+                syncMessage.add(MessageFormat.format("[同步研究生失败]-[{0}]-[{1}]", JsonUtils.toJsonString(person), result.getMsg()));
+            }
+        });
+        syncMessage.forEach(log::info);
+        return true;
+    }
+}

+ 49 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/strategy/impl/SyncTeacherStrategyImpl.java

@@ -0,0 +1,49 @@
+package org.dromara.server.base.service.user.strategy.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.server.base.service.user.SyncRemoteUserService;
+import org.dromara.server.base.service.user.strategy.ISyncUserStrategy;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourcePerson;
+import org.dromara.system.api.domain.vo.RemoteUserVo;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: SyncTeacherStrategyImpl
+ * package: org.dromara.server.base.dept.service.strategy.impl
+ * description: 教职工同步处理策略
+ * date: 2024-10-18 14:40:23 14:40
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(SyncResourceConstants.TEACHER)
+public class SyncTeacherStrategyImpl implements ISyncUserStrategy {
+    private final SyncRemoteUserService syncUserService;
+
+    @Override
+    public boolean syncUser(List<ResourcePerson> persons) {
+        List<String> syncMessage = new ArrayList<>();
+
+        persons.forEach(person -> {
+            R<RemoteUserVo> result = syncUserService.syncPeron(person);
+            if (result.getCode() == R.SUCCESS) {
+                syncMessage.add(MessageFormat.format("[同步教职工成功]-[{0}]", JsonUtils.toJsonString(person)));
+            } else {
+                syncMessage.add(MessageFormat.format("[同步教职工失败]-[{0}]-[{1}]", JsonUtils.toJsonString(person), result.getMsg()));
+            }
+        });
+        syncMessage.forEach(log::info);
+        return true;
+    }
+}

+ 49 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/service/user/strategy/impl/SyncTraineeStrategyImpl.java

@@ -0,0 +1,49 @@
+package org.dromara.server.base.service.user.strategy.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.server.base.service.user.SyncRemoteUserService;
+import org.dromara.server.base.service.user.strategy.ISyncUserStrategy;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourcePerson;
+import org.dromara.system.api.domain.vo.RemoteUserVo;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: HrDeptStrategyImpl
+ * package: org.dromara.server.base.dept.service.strategy.impl
+ * description: 培训学员同步处理策略
+ * date: 2024-10-18 14:40:23 14:40
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(SyncResourceConstants.TRAINEE)
+public class SyncTraineeStrategyImpl implements ISyncUserStrategy {
+    private final SyncRemoteUserService syncUserService;
+
+    @Override
+    public boolean syncUser(List<ResourcePerson> persons) {
+        List<String> syncMessage = new ArrayList<>();
+
+        persons.forEach(person -> {
+            R<RemoteUserVo> result = syncUserService.syncPeron(person);
+            if (result.getCode() == R.SUCCESS) {
+                syncMessage.add(MessageFormat.format("[同步培训学员成功]-[{0}]", JsonUtils.toJsonString(person)));
+            } else {
+                syncMessage.add(MessageFormat.format("[同步培训学员失败]-[{0}]-[{1}]", JsonUtils.toJsonString(person), result.getMsg()));
+            }
+        });
+        syncMessage.forEach(log::info);
+        return true;
+    }
+}

+ 88 - 0
ruoyi-server/ruoyi-server-base/src/main/java/org/dromara/server/base/util/EncryptorUtil.java

@@ -0,0 +1,88 @@
+package org.dromara.server.base.util;
+
+import cn.hutool.core.codec.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import java.security.Key;
+import java.security.SecureRandom;
+
+/**
+ * name: EncryptorUtil
+ * package: org.dromara.server.base.util
+ * description: 同步时身份证的加解密工具
+ * date: 2024-10-23 17:08:53 17:08
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public class EncryptorUtil {
+    private static final Key key;
+    private static final String KEY_STR = "Hnswdx2020";
+    private static final String CHARSET_NAME = "UTF-8";
+    private static final String ALGORITHM = "DES";
+
+    static {
+        try {
+            // 生成DES算法对象
+            KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM);
+            // 运用SHA1安全策略
+            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
+            // 设置上密钥种子
+            secureRandom.setSeed(KEY_STR.getBytes());
+            // 初始化基于SHA1的算法对象
+            generator.init(secureRandom);
+            // 生成密钥对象
+            key = generator.generateKey();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /***
+     * 获取加密的信息
+     *
+     * @param str 待加密字符串
+     * @return 加密结果
+     */
+    public static String encrypt(String str) {
+        // 基于BASE64编码,接收byte[]并转换成String
+        try {
+            // 按utf8编码
+            byte[] bytes = str.getBytes(CHARSET_NAME);
+            // 获取加密对象
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            // 初始化密码信息
+            cipher.init(Cipher.ENCRYPT_MODE, key);
+            // 加密
+            byte[] doFinal = cipher.doFinal(bytes);
+            // byte[]to encode好的String 并返回
+            return Base64.encode(doFinal);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /***
+     * 获取解密之后的信息
+     *
+     * @param str 待解密字符串
+     * @return 解密后的结果
+     */
+    public static String decode(String str) {
+        try {
+            // 将字符串decode成byte[]
+            byte[] bytes = Base64.decode(str);
+            // 获取解密对象
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            // 初始化解密信息
+            cipher.init(Cipher.DECRYPT_MODE, key);
+            // 解密
+            byte[] doFial = cipher.doFinal(bytes);
+            return new String(doFial, CHARSET_NAME);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

+ 10 - 0
ruoyi-server/ruoyi-server-base/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -0,0 +1,10 @@
+org.dromara.server.base.service.dept.SyncRemoteDeptService
+org.dromara.server.base.service.dept.strategy.SyncDeptStrategyContent
+org.dromara.server.base.service.dept.strategy.impl.HrDeptStrategyImpl
+org.dromara.server.base.service.dept.strategy.impl.GraduateClassStrategyImpl
+org.dromara.server.base.service.dept.strategy.impl.TrainClassStrategyImpl
+org.dromara.server.base.service.user.SyncRemoteUserService
+org.dromara.server.base.service.user.strategy.SyncUserStrategyContent
+org.dromara.server.base.service.user.strategy.impl.SyncTeacherStrategyImpl
+org.dromara.server.base.service.user.strategy.impl.SyncGraduateStrategyImpl
+org.dromara.server.base.service.user.strategy.impl.SyncTraineeStrategyImpl

+ 26 - 0
ruoyi-server/ruoyi-server-common/pom.xml

@@ -0,0 +1,26 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-server</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <artifactId>ruoyi-server-common</artifactId>
+    <packaging>jar</packaging>
+
+    <name>ruoyi-server-base</name>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 88 - 0
ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/constant/DefaultConstants.java

@@ -0,0 +1,88 @@
+package org.dromara.server.common.constant;
+
+/**
+ * name: DefaultConstants
+ * package: org.dromara.server.common.constant
+ * description: 缺省数据常量
+ * date: 2024-10-23 19:56:12 19:56
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface DefaultConstants {
+    /**
+     * 教职工岗位编码
+     */
+    String TEACHER_CODE="12";
+    /**
+     * 学员岗位编码
+     */
+    String TRAINEE_CODE="14";
+    /**
+     * 研究生岗位编码
+     */
+    String GRADUATE_CODE="16";
+
+    /**
+     * 租户Id
+     */
+    String TENANT_ID = "20200813044411";
+    /**
+     * 岗位Id
+     */
+    Long POST_ID = 111L;
+
+    /**
+     * 登录密码
+     */
+    String LOGIN_PASSWORD = "dtSchool@2024";
+
+    /**
+     * 时间格式
+     */
+    String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
+    /**
+     * 父部门Id(学校)
+     */
+    Long PARENT_DEPT_ID = 100L;
+
+    /**
+     * 研究生年份父部门Id(研究生部)
+     */
+    Long GRADUATE_PARENT_DEPT_ID = 162L;
+    /**
+     * 培训班年份父部门Id(培训班)
+     */
+    Long TRAIN_PARENT_DEPT_ID = 127L;
+    /**
+     * 部门类型代码
+     */
+    String DEPT_DEPT_TYPE = "03";
+
+    /**
+     * 年份对应部门类型代码
+     */
+    String YEAR_DEPT_TYPE = "04";
+    /**
+     * 培训班级对应部门类型代码
+     */
+    String CLASS_DEPT_TYPE = "05";
+    /**
+     * 研究生班级对应的部门类型代码
+     */
+    String GRADUATE_DEPT_TYPE = "06";
+    /**
+     * 教职工默认角色
+     */
+    Long TEACHER_ROLE_ID = 1833306814969163778L;
+    /**
+     * 学员默认角色
+     */
+    Long TRAIN_ROLE_ID = 1833306897299156993L;
+    /**
+     * 研究生默认角色
+     */
+    Long GRADUATE_ROLE_ID = 1844275170961874946L;
+}

+ 39 - 0
ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/constant/SyncResourceConstants.java

@@ -0,0 +1,39 @@
+package org.dromara.server.common.constant;
+
+/**
+ * name: SyncResourceConstants
+ * package: org.dromara.server.common.constant
+ * description: 数据同步来源常量定义
+ * date: 2024-10-23 11:21:58 11:21
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface SyncResourceConstants {
+    /**
+     * 业中(人事)
+     */
+    String HR_DEPT = "HR_DEPT";
+    /**
+     * 研究生班级
+     */
+    String GRADUATE_CLASS = "GRADUATE_CLASS";
+    /**
+     * 培训班
+     */
+    String TRAIN_CLASS = "TRAIN_CLASS";
+
+    /**
+     * 教职工
+     */
+    String TEACHER = "TEACHER";
+    /**
+     * 研究生
+     */
+    String GRADUATE = "GRADUATE";
+    /**
+     * 培训学员
+     */
+    String TRAINEE = "TRAINEE";
+}

+ 33 - 0
ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/KafkaHeader.java

@@ -0,0 +1,33 @@
+package org.dromara.server.common.domain.bo;
+
+import lombok.Data;
+
+/**
+ * name: KafkaHeader
+ * package: org.dromara.stream.domain.bo
+ * description: kafka消息头
+ * date: 2024-10-15 11:22:26 11:22
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+public class KafkaHeader {
+    /**
+     * 发送方
+     */
+    private String sender;
+    /**
+     * 时间戳
+     */
+    private Long timestamp;
+    /**
+     * 事件类型
+     */
+    private String eventType;
+    /**
+     * 事件Id
+     */
+    private String eventId;
+}

+ 19 - 0
ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/KafkaMessage.java

@@ -0,0 +1,19 @@
+package org.dromara.server.common.domain.bo;
+
+import lombok.Data;
+/**
+ * name: KafkaMessage
+ * package: org.dromara.stream.domain.bo
+ * description: Kafka消息内容
+ * date: 2024-10-15 11:28:02 11:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+public class KafkaMessage<T> {
+    private KafkaHeader header=new KafkaHeader();
+
+    private T body;
+}

+ 98 - 0
ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/ResourceDept.java

@@ -0,0 +1,98 @@
+package org.dromara.server.common.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * name: ResourceDept
+ * package: org.dromara.service.sync.dept.domain.bo
+ * description: 数据同步时的获取到的部门业务模型
+ * date: 2024-10-17 17:23:33 17:23
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+public class ResourceDept implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = -6275731371600822161L;
+    /**
+     * 部门id
+     */
+    private String dept_id;
+    /**
+     * 部门名称
+     */
+    private String dept_name;
+    /**
+     * 上级部门Id
+     */
+    private String parent_id;
+    /**
+     * 部门排序号
+     */
+    private String dept_num;
+
+    /**
+     * 租户编号
+     */
+    private String tenantId;
+
+    /**
+     * 开班日期
+     */
+    private Date beginDate;
+
+    /**
+     * 结业日期
+     */
+    private Date endDate;
+
+    /**
+     * 报到日期
+     */
+    private Date checkDate;
+
+    /**
+     * 是否自主选房
+     */
+    private String chooseRoom;
+
+    /**
+     * 是否就餐
+     */
+    private String canEat;
+
+    /**
+     * 是否先缴费再报到
+     */
+    private String payCheck;
+
+    /**
+     * 缴费开始日期
+     */
+    private Date payBegin;
+
+    /**
+     * 缴费开始日期
+     */
+    private Date payEnd;
+    /**
+     * 删除标志 默认为0,研究生系统数据会有此字段的值
+     */
+    private String delFlag;
+    /**
+     * 年份
+     */
+    private Integer year;
+    /**
+     * 学期
+     */
+    private String semester;
+
+}

+ 97 - 0
ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/ResourcePerson.java

@@ -0,0 +1,97 @@
+package org.dromara.server.common.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * name: ResourcePerson
+ * package: org.dromara.server.common.domain.bo
+ * description: 数据同步获取到的人员信息
+ * date: 2024-10-23 09:01:29 09:01
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+public class ResourcePerson implements Serializable {
+    @Serial
+    private static final long serialVersionUID = 1L;
+    /**
+     * 租户ID
+     */
+    private String tenantId;
+    /**
+     * 用户ID
+     */
+    private String userId;
+
+    /**
+     * 登录账户名
+     */
+    private String userName;
+    /**
+     * 部门ID
+     */
+    private String deptId;
+
+    /**
+     * 岗位编码 教师=12  学员=14 研究生=16
+     */
+    private String postCode;
+
+    /**
+     * 用户姓名
+     */
+    private String realName;
+
+    /**
+     * 用户性别(0男 1女 2未知)
+     */
+    private String sex;
+
+    /**
+     * 手机号码
+     */
+    private String phone;
+    /**
+     * 账户卡片类型
+     */
+    private String cardType;
+
+    /**
+     * 账户有效期
+     */
+    private Date lifespan;
+
+    /**
+     * 身份证号
+     */
+    private String idNumber;
+    /**
+     * 删除标志 默认为0,研究生系统数据会有此字段的值
+     */
+    private String delFlag;
+    /**
+     * 用户身份(1=教师 2=学员 3=研究生)
+     */
+    private String category;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 第三方人员状态
+     */
+    private String userState;
+
+    /**
+     * 人员所在部门(多部门情况)
+     */
+    private List<ResourcePersonDept> userDeptList;
+
+}

+ 47 - 0
ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/ResourcePersonDept.java

@@ -0,0 +1,47 @@
+package org.dromara.server.common.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * name: ResourcePerson
+ * package: org.dromara.server.common.domain.bo
+ * description: 数据同步获取到的人员所属部门信息,一人可在多部门
+ * date: 2024-10-23 09:01:29 09:01
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+public class ResourcePersonDept implements Serializable {
+    @Serial
+    private static final long serialVersionUID = 1L;
+    /**
+     * 用户Id
+     */
+    private String userId;
+
+    /**
+     * 部门Id
+     */
+    private String deptId;
+
+    /**
+     * 岗位编码
+     */
+    private String postCode;
+
+    /**
+     * 是否主部门
+     */
+    private String mainDept;
+
+    /**
+     * 删除标志(0-未删除 2-已删除)
+     */
+    private String delFlag;
+}

+ 42 - 0
ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/domain/bo/SyncFullDataBo.java

@@ -0,0 +1,42 @@
+package org.dromara.server.common.domain.bo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * name: SyncFullDataBo
+ * package: org.dromara.server.common.domain.bo
+ * description: 全量同步数据业务模型
+ * date: 2024-10-21 21:36:31 21:36
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Data
+public class SyncFullDataBo {
+    private String MessageStatus;
+    private String MessageSequence;
+    private String Remark;
+    private ResponseParam ResponseParam;
+
+    @Data
+    public static class ResponseParam {
+
+        private List<ResourceInfos> ResourceInfos;
+
+        @Data
+        public static class ResourceInfos {
+            private String ResourceName;
+            private List<DataItems> DataItems;
+            private List<List<String>> DataInfo;
+
+            @Data
+            public static class DataItems {
+                private String Name;
+                private String Fmt;
+            }
+        }
+    }
+}

+ 25 - 0
ruoyi-server/ruoyi-server-mqdata/Dockerfile

@@ -0,0 +1,25 @@
+# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
+FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
+#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds
+#FROM findepi/graalvm:java17-native
+
+LABEL maintainer="Lion Li"
+
+RUN mkdir -p /ruoyi/system/logs \
+    /ruoyi/system/temp \
+    /ruoyi/skywalking/agent
+
+WORKDIR /ruoyi/system
+
+ENV SERVER_PORT=9201 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
+
+EXPOSE ${SERVER_PORT}
+
+ADD ./target/ruoyi-system.jar ./app.jar
+
+ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
+           #-Dskywalking.agent.service_name=ruoyi-system \
+           #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
+           -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
+           -jar app.jar
+

+ 146 - 0
ruoyi-server/ruoyi-server-mqdata/pom.xml

@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-server</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-server-mqdata</artifactId>
+
+    <description>
+        ruoyi-service-mqdata 消息队列服务
+    </description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-nacos</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sentinel</artifactId>
+        </dependency>
+
+        <!-- RuoYi Common Log -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-log</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-dict</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-doc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mybatis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-dubbo</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-seata</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-idempotent</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-tenant</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-security</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-translation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sensitive</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-encrypt</artifactId>
+        </dependency>
+
+        <!-- RuoYi Api System -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-api-system</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-api-resource</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.kingbase</groupId>
+            <artifactId>kingbase8</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-server-common</artifactId>
+            <version>2.2.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-server-base</artifactId>
+            <version>2.2.0</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 22 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/RuoYiServerMqDataApplication.java

@@ -0,0 +1,22 @@
+package org.dromara.server.mq;
+
+import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
+
+/**
+ * 系统模块
+ *
+ * @author ruoyi
+ */
+@EnableDubbo
+@SpringBootApplication
+public class RuoYiServerMqDataApplication {
+    public static void main(String[] args) {
+        SpringApplication application = new SpringApplication(RuoYiServerMqDataApplication.class);
+        application.setApplicationStartup(new BufferingApplicationStartup(2048));
+        application.run(args);
+        System.out.println("(♥◠‿◠)ノ゙  消息队列服务启动成功   ლ(´ڡ`ლ)゙  ");
+    }
+}

+ 44 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/constant/kafka/GraduateEventConstraints.java

@@ -0,0 +1,44 @@
+package org.dromara.server.mq.constant.kafka;
+
+/**
+ * name: GraduateEventConstraints
+ * package: org.dromara.server.mq.constant.kafka
+ * description: 研究生kafka事件常量
+ * date: 2024-10-26 11:35:54 11:35
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public class GraduateEventConstraints {
+    /**
+     * 研究生发送者标识
+     */
+    private static final String SENDER = "002";
+
+    /**
+     * 研究生班级增加
+     */
+    public static final String GRADUATE_CLASS_ADD = SENDER + "00001";
+    /**
+     * 研究生班级修改
+     */
+    public static final String GRADUATE_CLASS_UPDATE = SENDER + "00002";
+    /**
+     * 研究生班级增加
+     */
+    public static final String GRADUATE_CLASS_DEL = SENDER + "00003";
+
+    /**
+     * 研究生学员增加
+     */
+    public static final String GRADUATE_ADD = SENDER + "00004";
+    /**
+     * 研究生学员更新
+     */
+    public static final String GRADUATE_UPDATE = SENDER + "00005";
+    /**
+     * 研究生学员删除
+     */
+    public static final String GRADUATE_DEL = SENDER + "00006";
+}

+ 44 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/constant/kafka/TeacherEventConstraints.java

@@ -0,0 +1,44 @@
+package org.dromara.server.mq.constant.kafka;
+
+/**
+ * name: TeacherEventConstraints
+ * package: org.dromara.server.mq.constant.kafka
+ * description: 教职工kafka事件常量
+ * date: 2024-10-26 11:35:54 11:35
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public class TeacherEventConstraints {
+    /**
+     * 教职工发送者标识
+     */
+    private static final String SENDER = "003";
+
+    /**
+     * 教职工部门增加
+     */
+    public static final String DEPT_ADD = SENDER + "00001";
+    /**
+     * 教职工部门修改
+     */
+    public static final String DEPT_UPDATE = SENDER + "00002";
+    /**
+     * 教职工部门增加
+     */
+    public static final String DEPT_DEL = SENDER + "00003";
+
+    /**
+     * 教职工增加
+     */
+    public static final String TEACHER_ADD = SENDER + "00004";
+    /**
+     * 教职工更新
+     */
+    public static final String TEACHER_UPDATE = SENDER + "00005";
+    /**
+     * 教职工删除
+     */
+    public static final String TEACHER_DEL = SENDER + "00006";
+}

+ 44 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/constant/kafka/TrainEventConstraints.java

@@ -0,0 +1,44 @@
+package org.dromara.server.mq.constant.kafka;
+
+/**
+ * name: TrainEventConstraints
+ * package: org.dromara.server.mq.constant.kafka
+ * description: 培训班kafka事件常量
+ * date: 2024-10-26 11:35:54 11:35
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public class TrainEventConstraints {
+    /**
+     * 培训班发送者标识
+     */
+    private static final String SENDER = "002";
+
+    /**
+     * 培训班班级增加
+     */
+    public static final String TRAIN_CLASS_ADD = SENDER + "00001";
+    /**
+     * 培训班班级修改
+     */
+    public static final String TRAIN_CLASS_UPDATE = SENDER + "00002";
+    /**
+     * 培训班班级增加
+     */
+    public static final String TRAIN_CLASS_DEL = SENDER + "00003";
+
+    /**
+     * 培训班学员增加
+     */
+    public static final String TRAINEE_ADD = SENDER + "00004";
+    /**
+     * 培训班学员更新
+     */
+    public static final String TRAINEE_UPDATE = SENDER + "00005";
+    /**
+     * 培训班学员删除
+     */
+    public static final String TRAINEE_DEL = SENDER + "00006";
+}

+ 40 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/consumer/KafkaConsumer.java

@@ -0,0 +1,40 @@
+package org.dromara.server.mq.consumer;
+
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.dromara.server.common.domain.bo.KafkaMessage;
+import org.dromara.server.mq.event.kafka.EventStrategyContext;
+import org.springframework.kafka.annotation.KafkaListener;
+
+/**
+ * name: KafkaNormalConsumer
+ * package: org.dromara.server.mq.consumer
+ * description: kafka消息消费
+ * date: 2024-10-26 11:12:56 11:12
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@RequiredArgsConstructor
+@Slf4j
+//@Component
+public class KafkaConsumer {
+    private final EventStrategyContext eventStrategyContext;
+    @KafkaListener(topics = "eventBus", groupId = "test-group-id")
+    public void kafkaReceiveHandler(ConsumerRecord<String, String> record) {
+        KafkaMessage<?> receiveMsg = JSONUtil.toBean(record.value(), KafkaMessage.class);
+        log.info("[接收到Kafka消息]-[{}]", receiveMsg);
+        String eventType = receiveMsg.getHeader().getEventType();
+        JSONObject eventMsg = JSONUtil.parseObj(receiveMsg.getBody());
+
+        try {
+            eventStrategyContext.doMsgHandle(eventType, eventMsg);
+        } catch (Exception e) {
+            log.error("[kafka消息处理失败]-[消息:{}-[错误:{}]", receiveMsg, e.getMessage());
+        }
+    }
+}

+ 32 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/EventStrategyContext.java

@@ -0,0 +1,32 @@
+package org.dromara.server.mq.event.kafka;
+
+import cn.hutool.json.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * name: EventStrategyContext
+ * package: org.dromara.server.mq.event.kafka
+ * description: 事件处理策略上下文
+ * date: 2024-10-26 11:48:28 11:48
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Service
+public class EventStrategyContext {
+    private final Map<String, IEventStrategy> strategyMap = new ConcurrentHashMap<>();
+
+    @Autowired
+    public EventStrategyContext(Map<String, IEventStrategy> strategyMap) {
+        this.strategyMap.putAll(strategyMap);
+    }
+
+    public void doMsgHandle(String eventType, JSONObject msg) {
+        strategyMap.get(eventType).doMsgHandle(msg);
+    }
+}

+ 21 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/IEventStrategy.java

@@ -0,0 +1,21 @@
+package org.dromara.server.mq.event.kafka;
+
+import cn.hutool.json.JSONObject;
+
+/**
+ * name: IEventStrategy
+ * package: org.dromara.server.mq.event.kafka
+ * description: kafka事件处理策略
+ * date: 2024-10-26 11:46:08 11:46
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public interface IEventStrategy {
+    /**
+     * kafka消息处理
+     * @param msg 消息内容
+     */
+    void doMsgHandle(JSONObject msg);
+}

+ 35 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/DeptAddEventStrategyImpl.java

@@ -0,0 +1,35 @@
+package org.dromara.server.mq.event.kafka.impl.teacher;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.base.service.dept.strategy.SyncDeptStrategyContent;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.dromara.server.mq.constant.kafka.TeacherEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * name: DeptAddEventStrategyImpl
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 部门增加事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TeacherEventConstraints.DEPT_ADD)
+public class DeptAddEventStrategyImpl implements IEventStrategy {
+    private final SyncDeptStrategyContent syncDeptStrategyContent;
+    @Override
+    public void doMsgHandle(JSONObject data) {
+        List<ResourceDept> resourceDeptlist = TeacherUtils.getSyncDept(data);
+        syncDeptStrategyContent.syncDept(resourceDeptlist, SyncResourceConstants.HR_DEPT);
+    }
+}

+ 32 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/DeptDelEventStrategyImpl.java

@@ -0,0 +1,32 @@
+package org.dromara.server.mq.event.kafka.impl.teacher;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.base.service.dept.SyncRemoteDeptService;
+import org.dromara.server.mq.constant.kafka.TeacherEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+/**
+ * name: DeptDelEventStrategyImpl
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 部门删除事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TeacherEventConstraints.DEPT_DEL)
+public class DeptDelEventStrategyImpl implements IEventStrategy {
+    private final SyncRemoteDeptService syncRemoteDeptService;
+    @Override
+    public void doMsgHandle(JSONObject data) {
+        String otherId = data.get("dept_id").toString();
+
+        syncRemoteDeptService.deleteDeptByOtherId(otherId);
+    }
+}

+ 36 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/DeptUpdateEventStrategyImpl.java

@@ -0,0 +1,36 @@
+package org.dromara.server.mq.event.kafka.impl.teacher;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.base.service.dept.strategy.SyncDeptStrategyContent;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.dromara.server.mq.constant.kafka.TeacherEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * name: TeacherEventConstraints
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 部门修改事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TeacherEventConstraints.DEPT_UPDATE)
+public class DeptUpdateEventStrategyImpl implements IEventStrategy {
+    private final SyncDeptStrategyContent syncDeptStrategyContent;
+
+    @Override
+    public void doMsgHandle(JSONObject data) {
+        List<ResourceDept> resourceDeptlist = TeacherUtils.getSyncDept(data);
+        syncDeptStrategyContent.syncDept(resourceDeptlist, SyncResourceConstants.HR_DEPT);
+    }
+}

+ 36 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/TeacherAddEventStrategyImpl.java

@@ -0,0 +1,36 @@
+package org.dromara.server.mq.event.kafka.impl.teacher;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.base.service.user.strategy.SyncUserStrategyContent;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourcePerson;
+import org.dromara.server.mq.constant.kafka.TeacherEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * name: TeacherAddEventStrategyImpl
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 教职工增加事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TeacherEventConstraints.TEACHER_ADD)
+public class TeacherAddEventStrategyImpl implements IEventStrategy {
+    private final SyncUserStrategyContent syncUserStrategyContent;
+
+    @Override
+    public void doMsgHandle(JSONObject data) {
+        List<ResourcePerson> resourcePersonList = TeacherUtils.getSyncTeacher(data);
+        syncUserStrategyContent.syncUser(resourcePersonList, SyncResourceConstants.TEACHER);
+    }
+}

+ 28 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/TeacherDelEventStrategyImpl.java

@@ -0,0 +1,28 @@
+package org.dromara.server.mq.event.kafka.impl.teacher;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.mq.constant.kafka.TeacherEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+/**
+ * name: TeacherEventConstraints
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 教职工删除事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TeacherEventConstraints.TEACHER_DEL)
+public class TeacherDelEventStrategyImpl implements IEventStrategy {
+    @Override
+    public void doMsgHandle(JSONObject msg) {
+
+    }
+}

+ 35 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/TeacherUpdateEventStrategyImpl.java

@@ -0,0 +1,35 @@
+package org.dromara.server.mq.event.kafka.impl.teacher;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.base.service.user.strategy.SyncUserStrategyContent;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourcePerson;
+import org.dromara.server.mq.constant.kafka.TeacherEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * name: TeacherEventConstraints
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 教职工修改事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TeacherEventConstraints.TEACHER_UPDATE)
+public class TeacherUpdateEventStrategyImpl implements IEventStrategy {
+    private final SyncUserStrategyContent syncUserStrategyContent;
+    @Override
+    public void doMsgHandle(JSONObject data) {
+        List<ResourcePerson> resourcePersonList = TeacherUtils.getSyncTeacher(data);
+        syncUserStrategyContent.syncUser(resourcePersonList, SyncResourceConstants.TEACHER);
+    }
+}

+ 62 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/teacher/TeacherUtils.java

@@ -0,0 +1,62 @@
+package org.dromara.server.mq.event.kafka.impl.teacher;
+
+import cn.hutool.json.JSONObject;
+import org.dromara.server.common.constant.DefaultConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.dromara.server.common.domain.bo.ResourcePerson;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: TeachserUtil
+ * package: org.dromara.server.mq.event.kafka.impl.teacher
+ * description: 教职工辅助工具类
+ * date: 2024-10-26 13:22:53 13:22
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public class TeacherUtils {
+
+    /**
+     * 处理教职工信息
+     * @param data 教职工
+     * @return 结果
+     */
+    public static List<ResourcePerson> getSyncTeacher(JSONObject data){
+        List<ResourcePerson> resourcePersonList = new ArrayList<>();
+        ResourcePerson person = new ResourcePerson();
+        person.setUserId(data.get("employee_id").toString());
+        person.setDeptId(data.get("dept_id").toString());
+        person.setPostCode(DefaultConstants.TEACHER_CODE);
+        person.setRealName(data.get("name").toString());
+        person.setSex(data.get("sex").toString());
+        person.setPhone(data.get("mobile_phone").toString());
+        person.setCategory("1");
+        person.setUserState(data.get("status").toString());
+
+        resourcePersonList.add(person);
+
+        return resourcePersonList;
+    }
+
+    /**
+     * 处理部门数据
+     * @param data 部门
+     * @return 处理结果
+     */
+    public static List<ResourceDept> getSyncDept(JSONObject data){
+        List<ResourceDept> resourceDeptlist = new ArrayList<>();
+        ResourceDept dept = new ResourceDept();
+        dept.setParent_id(data.get("parent_id").toString());
+        dept.setDept_id(data.get("dept_id").toString());
+        dept.setDept_name(data.get("dept_name").toString());
+        dept.setDept_num(data.get("dept_num").toString());
+
+        resourceDeptlist.add(dept);
+
+        return resourceDeptlist;
+    }
+}

+ 36 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/ClassAddEventStrategyImpl.java

@@ -0,0 +1,36 @@
+package org.dromara.server.mq.event.kafka.impl.train;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.base.service.dept.strategy.SyncDeptStrategyContent;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.dromara.server.mq.constant.kafka.TrainEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * name: TeacherAddEventStrategyImpl
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 教职工增加事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TrainEventConstraints.TRAIN_CLASS_ADD)
+public class ClassAddEventStrategyImpl implements IEventStrategy {
+    private final SyncDeptStrategyContent syncDeptStrategyContent;
+
+    @Override
+    public void doMsgHandle(JSONObject msg) {
+        List<ResourceDept> resourceDeptList = TrainUtils.getSycClass(msg);
+        syncDeptStrategyContent.syncDept(resourceDeptList, SyncResourceConstants.TRAIN_CLASS);
+    }
+}

+ 29 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/ClassDelEventStrategyImpl.java

@@ -0,0 +1,29 @@
+package org.dromara.server.mq.event.kafka.impl.train;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.mq.constant.kafka.TeacherEventConstraints;
+import org.dromara.server.mq.constant.kafka.TrainEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+/**
+ * name: TeacherAddEventStrategyImpl
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 教职工增加事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TrainEventConstraints.TRAIN_CLASS_DEL)
+public class ClassDelEventStrategyImpl implements IEventStrategy {
+    @Override
+    public void doMsgHandle(JSONObject msg) {
+
+    }
+}

+ 36 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/ClassUpdateEventStrategyImpl.java

@@ -0,0 +1,36 @@
+package org.dromara.server.mq.event.kafka.impl.train;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.base.service.dept.strategy.SyncDeptStrategyContent;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.dromara.server.mq.constant.kafka.TrainEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * name: TeacherAddEventStrategyImpl
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 教职工增加事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TrainEventConstraints.TRAIN_CLASS_UPDATE)
+public class ClassUpdateEventStrategyImpl implements IEventStrategy {
+    private final SyncDeptStrategyContent syncDeptStrategyContent;
+
+    @Override
+    public void doMsgHandle(JSONObject msg) {
+        List<ResourceDept> resourceDeptList = TrainUtils.getSycClass(msg);
+        syncDeptStrategyContent.syncDept(resourceDeptList, SyncResourceConstants.TRAIN_CLASS);
+    }
+}

+ 29 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/TrainUpdateEventStrategyImpl.java

@@ -0,0 +1,29 @@
+package org.dromara.server.mq.event.kafka.impl.train;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.mq.constant.kafka.TeacherEventConstraints;
+import org.dromara.server.mq.constant.kafka.TrainEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+/**
+ * name: TrainUpdateEventStrategyImpl
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 培训班学员修改事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TrainEventConstraints.TRAINEE_UPDATE)
+public class TrainUpdateEventStrategyImpl implements IEventStrategy {
+    @Override
+    public void doMsgHandle(JSONObject msg) {
+
+    }
+}

+ 49 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/TrainUtils.java

@@ -0,0 +1,49 @@
+package org.dromara.server.mq.event.kafka.impl.train;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.json.JSONObject;
+import org.dromara.server.common.constant.DefaultConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: TrainUtils
+ * package: org.dromara.server.mq.event.kafka.impl.train
+ * description: 培训班辅助工具类
+ * date: 2024-10-26 13:33:32 13:33
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public class TrainUtils {
+
+    /**
+     * 培训班级处理
+     * @param data 班级数据
+     * @return 处理结果
+     */
+    public static List<ResourceDept> getSycClass(JSONObject data) {
+        List<ResourceDept> resourceDeptlist = new ArrayList<>();
+        ResourceDept dept = new ResourceDept();
+        dept.setDept_id(data.get("id").toString());
+        dept.setDept_name(data.get("name").toString());
+        dept.setYear(Integer.valueOf(data.get("year").toString()));
+        dept.setSemester("0".equals(data.get("xq").toString()) ? "上学期" : "下学期");
+        dept.setPayBegin(DateUtil.parse(data.get("bmStarttime").toString(),DefaultConstants.DATE_FORMAT));
+        dept.setCheckDate(DateUtil.parse(data.get("bdTime").toString(),DefaultConstants.DATE_FORMAT));
+        dept.setBeginDate(DateUtil.parse(data.get("kbTime").toString(),DefaultConstants.DATE_FORMAT));
+        dept.setEndDate(DateUtil.parse(data.get("byTime").toString(), DefaultConstants.DATE_FORMAT));
+        dept.setPayEnd(DateUtil.parse(data.get("byTime").toString(), DefaultConstants.DATE_FORMAT));
+        dept.setChooseRoom("0");
+        dept.setCanEat("1");
+        dept.setPayCheck(data.get("noPayAllow").toString());
+        dept.setDept_num(data.get("sortNum").toString());
+
+        resourceDeptlist.add(dept);
+
+        return resourceDeptlist;
+    }
+}

+ 29 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/TraineeAddEventStrategyImpl.java

@@ -0,0 +1,29 @@
+package org.dromara.server.mq.event.kafka.impl.train;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.mq.constant.kafka.TeacherEventConstraints;
+import org.dromara.server.mq.constant.kafka.TrainEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+/**
+ * name: TraineeAddEventStrategyImpl
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 培训班学员加事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TrainEventConstraints.TRAINEE_ADD)
+public class TraineeAddEventStrategyImpl implements IEventStrategy {
+    @Override
+    public void doMsgHandle(JSONObject msg) {
+
+    }
+}

+ 29 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/java/org/dromara/server/mq/event/kafka/impl/train/TraineeDelEventStrategyImpl.java

@@ -0,0 +1,29 @@
+package org.dromara.server.mq.event.kafka.impl.train;
+
+import cn.hutool.json.JSONObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.mq.constant.kafka.TeacherEventConstraints;
+import org.dromara.server.mq.constant.kafka.TrainEventConstraints;
+import org.dromara.server.mq.event.kafka.IEventStrategy;
+import org.springframework.stereotype.Service;
+
+/**
+ * name: TraineeDelEventStrategyImpl
+ * package: org.dromara.server.mq.event.kafka.teacher.impl
+ * description: 培训班学员删除事件处理策略实现
+ * date: 2024-10-26 12:28:18 12:28
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service(TrainEventConstraints.TRAINEE_DEL)
+public class TraineeDelEventStrategyImpl implements IEventStrategy {
+    @Override
+    public void doMsgHandle(JSONObject msg) {
+
+    }
+}

+ 34 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/resources/application.yml

@@ -0,0 +1,34 @@
+# Tomcat
+server:
+  port: 9100
+
+# Spring
+spring:
+  application:
+    # 应用名称
+    name: ruoyi-server-mqdata
+  profiles:
+    # 环境配置
+    active: @profiles.active@
+
+--- # nacos 配置
+spring:
+  cloud:
+    nacos:
+      # nacos 服务地址
+      server-addr: @nacos.server@
+      username: @nacos.username@
+      password: @nacos.password@
+      discovery:
+        # 注册组
+        group: @nacos.discovery.group@
+        namespace: ${spring.profiles.active}
+      config:
+        # 配置组
+        group: @nacos.config.group@
+        namespace: ${spring.profiles.active}
+  config:
+    import:
+      - optional:nacos:application-common.yml
+      - optional:nacos:datasource.yml
+      - optional:nacos:${spring.application.name}.yml

+ 10 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/resources/banner.txt

@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+                            _                           _                    
+                           (_)                         | |                   
+ _ __  _   _   ___   _   _  _  ______  ___  _   _  ___ | |_   ___  _ __ ___  
+| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \ 
+| |   | |_| || (_) || |_| || |        \__ \| |_| |\__ \| |_ |  __/| | | | | |
+|_|    \__,_| \___/  \__, ||_|        |___/ \__, ||___/ \__| \___||_| |_| |_|
+                      __/ |                  __/ |                           
+                     |___/                  |___/                            

+ 28 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/resources/logback-plus.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+    <!-- 日志存放路径 -->
+	<property name="log.path" value="logs/${project.artifactId}" />
+   <!-- 日志输出格式 -->
+    <property name="console.log.pattern"
+              value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+
+    <!-- 控制台输出 -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${console.log.pattern}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+    </appender>
+
+    <include resource="logback-common.xml" />
+
+    <include resource="logback-logstash.xml" />
+
+    <!-- 开启 skywalking 日志收集 -->
+    <include resource="logback-skylog.xml" />
+
+	<!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="console" />
+    </root>
+</configuration>

+ 3 - 0
ruoyi-server/ruoyi-server-mqdata/src/main/resources/mapper/package-info.md

@@ -0,0 +1,3 @@
+java包使用 `.` 分割 resource 目录使用 `/` 分割
+<br>
+此文件目的 防止文件夹粘连找不到 `xml` 文件

+ 25 - 0
ruoyi-server/ruoyi-server-sync/Dockerfile

@@ -0,0 +1,25 @@
+# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
+FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
+#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds
+#FROM findepi/graalvm:java17-native
+
+LABEL maintainer="Lion Li"
+
+RUN mkdir -p /ruoyi/system/logs \
+    /ruoyi/system/temp \
+    /ruoyi/skywalking/agent
+
+WORKDIR /ruoyi/system
+
+ENV SERVER_PORT=9201 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
+
+EXPOSE ${SERVER_PORT}
+
+ADD ./target/ruoyi-system.jar ./app.jar
+
+ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
+           #-Dskywalking.agent.service_name=ruoyi-system \
+           #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
+           -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
+           -jar app.jar
+

+ 136 - 0
ruoyi-server/ruoyi-server-sync/pom.xml

@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-server</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-server-sync</artifactId>
+
+    <description>
+        ruoyi-service-sync 全量同步服务
+    </description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-nacos</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sentinel</artifactId>
+        </dependency>
+
+        <!-- RuoYi Common Log -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-log</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-dict</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-doc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mybatis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-dubbo</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-seata</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-idempotent</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-tenant</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-security</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-translation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sensitive</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-encrypt</artifactId>
+        </dependency>
+
+        <!-- RuoYi Api System -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-api-system</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-api-resource</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.kingbase</groupId>
+            <artifactId>kingbase8</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-server-base</artifactId>
+            <version>2.2.0</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 37 - 0
ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/InitRunnerTest.java

@@ -0,0 +1,37 @@
+package org.dromara.server.sync;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.server.sync.service.SyncGraduateService;
+import org.dromara.server.sync.service.SyncHrService;
+import org.dromara.server.sync.service.SyncTrainService;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+/**
+ * name: InitRunnerTest
+ * package: org.dromara.server.sync
+ * description: 同步测试入口
+ * date: 2024-10-21 10:48:30 10:48
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@RequiredArgsConstructor
+@Component
+public class InitRunnerTest implements CommandLineRunner {
+    private final SyncGraduateService syncGraduateClass;
+    private final SyncHrService syncHrService;
+    private final SyncTrainService syncTrainService;
+    @Override
+    public void run(String... args) throws Exception {
+        //syncHrService.syncDept();
+        //syncHrService.syncTeacher();
+
+        //syncGraduateClass.syncGraduateClass();
+        //syncGraduateClass.syncGraduate();
+
+        //syncTrainService.syncTrainClass();
+        //syncTrainService.syncTrainee();
+    }
+}

+ 22 - 0
ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/RuoYiServerSyncApplication.java

@@ -0,0 +1,22 @@
+package org.dromara.server.sync;
+
+import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
+
+/**
+ * 系统模块
+ *
+ * @author ruoyi
+ */
+@EnableDubbo
+@SpringBootApplication
+public class RuoYiServerSyncApplication {
+    public static void main(String[] args) {
+        SpringApplication application = new SpringApplication(RuoYiServerSyncApplication.class);
+        application.setApplicationStartup(new BufferingApplicationStartup(2048));
+        application.run(args);
+        System.out.println("(♥◠‿◠)ノ゙  全量同步服务启动成功   ლ(´ڡ`ლ)゙  ");
+    }
+}

+ 28 - 0
ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/service/CreateHttpRequest.java

@@ -0,0 +1,28 @@
+package org.dromara.server.sync.service;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+
+/**
+ * name: CreateHttpRequest
+ * package: org.dromara.server.sync.service
+ * description: 创建全量查询接口
+ * date: 2024-10-21 21:26:55 21:26
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+public class CreateHttpRequest {
+
+    public static HttpRequest createRequest(){
+        String url = "https://show.hnswdx.gov.cn/card/commonData/queryCard";
+        HttpRequest req = HttpUtil.createPost(url);
+
+        req.header("SenderID", "A-130100-0001");
+        req.header("serviceResourceId", "130100-0100-00001");
+        req.header("userId", "ezmap");
+
+        return req;
+    }
+}

+ 193 - 0
ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/service/SyncGraduateService.java

@@ -0,0 +1,193 @@
+package org.dromara.server.sync.service;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.base.service.dept.strategy.SyncDeptStrategyContent;
+import org.dromara.server.base.service.user.strategy.SyncUserStrategyContent;
+import org.dromara.server.common.constant.DefaultConstants;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.dromara.server.common.domain.bo.ResourcePerson;
+import org.dromara.server.common.domain.bo.SyncFullDataBo;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: SyncGraduateService
+ * package: org.dromara.server.sync.service
+ * description: 研究生信息同步
+ * date: 2024-10-21 21:17:02 21:17
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class SyncGraduateService {
+    private final SyncDeptStrategyContent syncDeptStrategyContent;
+    private final SyncUserStrategyContent syncUserStrategyContent;
+
+    public void syncGraduateClass() {
+        HttpRequest req = CreateHttpRequest.createRequest();
+        req.body(getQueryBodyForClass());
+
+        SyncFullDataBo dataBo = JSONUtil.toBean(req.execute().body(), SyncFullDataBo.class);
+
+        List<ResourceDept> resourceDeptlist = new ArrayList<>();
+        for (List<String> list : dataBo.getResponseParam().getResourceInfos().get(0).getDataInfo()) {
+            ResourceDept dept = new ResourceDept();
+            dept.setDept_id(list.get(0));
+            dept.setYear(Integer.valueOf(list.get(1)));
+            dept.setDept_name(list.get(2));
+            dept.setBeginDate(DateUtil.parse(list.get(3), "yyyy-MM-dd HH:mm:ss"));
+            dept.setEndDate(DateUtil.parse(list.get(4), "yyyy-MM-dd HH:mm:ss"));
+            dept.setDelFlag("ZC".equals(list.get(5)) ? "0 " : "1");
+            resourceDeptlist.add(dept);
+        }
+        log.info("[全量获取到的研究生班级数据]-共[{}]条-[{}]",resourceDeptlist.size(), JSONUtil.toJsonStr(dataBo));
+        syncDeptStrategyContent.syncDept(resourceDeptlist, SyncResourceConstants.GRADUATE_CLASS);
+    }
+
+    public void syncGraduate() {
+        HttpRequest req = CreateHttpRequest.createRequest();
+        req.body(getQueryBodyForGraduate());
+
+        SyncFullDataBo dataBo = JSONUtil.toBean(req.execute().body(), SyncFullDataBo.class);
+        List<ResourcePerson> resourcePersonList = getResourcePeople(dataBo);
+        log.info("[全量获取到的研究生数据]-共[{}]条-[{}]",resourcePersonList.size(), JSONUtil.toJsonStr(dataBo));
+
+        syncUserStrategyContent.syncUser(resourcePersonList, SyncResourceConstants.GRADUATE);
+    }
+
+    /**
+     * 研究生数据预处理
+     * @param dataBo 研究生数据
+     * @return 处理结果
+     */
+    @NotNull
+    private List<ResourcePerson> getResourcePeople(SyncFullDataBo dataBo) {
+        List<ResourcePerson> resourcePersonList = new ArrayList<>();
+        for (List<String> list : dataBo.getResponseParam().getResourceInfos().get(0).getDataInfo()) {
+            ResourcePerson person = new ResourcePerson();
+            person.setUserId(list.get(0));
+            person.setRealName(list.get(1));
+            person.setSex(list.get(2));
+            person.setPhone(list.get(3));
+            person.setDeptId(list.get(5));
+            person.setPostCode(DefaultConstants.GRADUATE_CODE);
+            person.setCategory("3");
+            resourcePersonList.add(person);
+        }
+        return resourcePersonList;
+    }
+
+    /**
+     * 研究生班级查询body
+     *
+     * @return body
+     */
+    private String getQueryBodyForClass() {
+        return """
+            {\r
+                "From": "A-130100-0001",\r
+                "To": "110000000001",\r
+                "MessageSequence": "2019010714141200001",\r
+                "RequestParam": {\r
+                    "Condition": "1='1'",\r
+                    "ResourceInfos": [{\r
+                        "ResourceName": "R-13010005-00000053", \r
+                        "DataItems": [{\r
+                            "Name": "Id",\r
+                            "Fmt": ""\r
+                        },{\r
+                            "Name": "years",\r
+                            "Fmt": ""\r
+                        },{\r
+                            "Name": "class_name",\r
+                            "Fmt": ""\r
+                        },{\r
+                            "Name": "opening_time",\r
+                            "Fmt": ""\r
+                        },{\r
+                            "Name": "close_time",\r
+                            "Fmt": ""\r
+                        },{\r
+                            "Name": "status",\r
+                            "Fmt": ""\r
+                        }]\r
+                    }],\r
+                    "OtherCondition": {\r
+                        "MaxReturnNum": "50000",\r
+                        "AsyncIdentity": "0",\r
+                        "AsyncOnceReturnNum": "2",\r
+                        "AsynQuery": "",\r
+                        "CallbackID": "",\r
+                        "CodeMode": "0",\r
+                        "SortResults": ""\r
+                    }\r
+                }\r
+            }""";
+    }
+
+    /**
+     * 研究生人员查询body
+     *
+     * @return body
+     */
+    private String getQueryBodyForGraduate() {
+        return """
+            {
+                "From": "A-130100-0001",
+                "To": "110000000001",
+                "MessageSequence": "2019010714141200001",
+                "RequestParam": {
+                    "Condition": "1='1'",
+                    "ResourceInfos": [{
+                        "ResourceName": "R-13010005-00000052",\s
+                        "DataItems": [{
+                            "Name": "commonId",
+                            "Fmt": ""
+                        },{
+                            "Name": "stu_name",
+                            "Fmt": ""
+                        },{
+                            "Name": "sex",
+                            "Fmt": ""
+                        },{
+                            "Name": "phone",
+                            "Fmt": ""
+                        },{
+                            "Name": "id_card",
+                            "Fmt": ""
+                        },{
+                            "Name": "class_id",
+                            "Fmt": ""
+                        },{
+                            "Name": "status",
+                            "Fmt": ""
+                        },{
+                            "Name": "expected_completion_date",
+                            "Fmt": ""
+                        }]
+                    }],
+                    "OtherCondition": {
+                        "MaxReturnNum": "50000",
+                        "AsyncIdentity": "0",
+                        "AsyncOnceReturnNum": "2",
+                        "AsynQuery": "",
+                        "CallbackID": "",
+                        "CodeMode": "0",
+                        "SortResults": ""
+                    }
+                }
+            }""";
+    }
+}

+ 239 - 0
ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/service/SyncHrService.java

@@ -0,0 +1,239 @@
+package org.dromara.server.sync.service;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.base.service.dept.strategy.SyncDeptStrategyContent;
+import org.dromara.server.base.service.user.strategy.SyncUserStrategyContent;
+import org.dromara.server.common.constant.DefaultConstants;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.dromara.server.common.domain.bo.ResourcePerson;
+import org.dromara.server.common.domain.bo.SyncFullDataBo;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: SyncHrService
+ * package: org.dromara.server.sync.service
+ * description: 业中人员部门同步
+ * date: 2024-10-21 21:14:49 21:14
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class SyncHrService {
+    private final SyncDeptStrategyContent syncDeptStrategyContent;
+    private final SyncUserStrategyContent syncUserStrategyContent;
+
+    /**
+     * 同步教职工部门数据,该方法将提供给定时任务调用
+     */
+    public void syncDept() {
+        HttpRequest req = CreateHttpRequest.createRequest();
+        req.body(getQueryBodyForDept());
+
+        SyncFullDataBo dataBo = JSONUtil.toBean(req.execute().body(), SyncFullDataBo.class);
+        List<ResourceDept> resourceDeptlist = new ArrayList<>();
+        for (List<String> list : dataBo.getResponseParam().getResourceInfos().get(0).getDataInfo()) {
+            ResourceDept dept = new ResourceDept();
+            dept.setParent_id(list.get(0));
+            dept.setDept_id(list.get(1));
+            dept.setDept_name(list.get(2));
+            resourceDeptlist.add(dept);
+        }
+        log.info("[全量获取到的部门数据]-共[{}]条-[{}]", resourceDeptlist.size(), JSONUtil.toJsonStr(dataBo));
+        syncDeptStrategyContent.syncDept(resourceDeptlist, SyncResourceConstants.HR_DEPT);
+    }
+
+    /**
+     * 同步教职工数据
+     */
+    public void syncTeacher() {
+        //HttpRequest req = CreateHttpRequest.createRequest();
+        //req.body(getQueryBodyForTeacher());
+        //
+        //SyncFullDataBo dataBo = JSONUtil.toBean(req.execute().body(), SyncFullDataBo.class);
+        //List<ResourcePerson> resourcePersonList = new ArrayList<>();
+        //for (List<String> list : dataBo.getResponseParam().getResourceInfos().get(0).getDataInfo()) {
+        //    ResourcePerson person = new ResourcePerson();
+        //    person.setUserId(list.get(12));
+        //    person.setDeptId(list.get(14));
+        //    person.setPostCode(DefaultConstants.TEACHER_CODE);
+        //    person.setRealName(list.get(0));
+        //    person.setSex(list.get(1));
+        //    person.setPhone(list.get(3));
+        //    person.setIdNumber(list.get(5));
+        //    person.setCategory("1");
+        //    person.setRemark("");
+        //    person.setUserState(list.get(16));
+        //    resourcePersonList.add(person);
+        //}
+        //log.info("[全量获取到的教职工数据]-[共{}条]-[{}]", resourcePersonList.size(), JSONUtil.toJsonStr(dataBo));
+
+        //region 模拟测试数据
+        List<ResourcePerson> resourcePersonList = new ArrayList<>();
+        ResourcePerson person = new ResourcePerson();
+        person.setUserId("00314200");
+        person.setDeptId("001001001000");
+        person.setPostCode(DefaultConstants.TEACHER_CODE);
+        person.setRealName("康重文");
+        person.setSex("1");
+        person.setPhone("13875850616");
+        person.setCategory("1");
+        person.setRemark("");
+        person.setUserState("on");
+        resourcePersonList.add(person);
+        //endregion
+
+
+        syncUserStrategyContent.syncUser(resourcePersonList, SyncResourceConstants.TEACHER);
+
+    }
+
+    /**
+     * 生成部门查询body参数
+     * @return body数据
+     */
+    private String getQueryBodyForDept() {
+        return """
+            {\r
+            	"From": "A-130100-0001",\r
+            	"To": "110000000001",\r
+            	"MessageSequence": "2019010714141200001",\r
+            	"RequestParam": {\r
+            		"Condition": "1='1'",\r
+            		"ResourceInfos": [{\r
+            			"ResourceName": "R-13010005-00000014",\r
+            			"DataItems": [{\r
+            					"Name": "PARENT_ID",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "DEPT_ID",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "DEPT_NAME",\r
+            					"Fmt": ""\r
+            				}]\r
+            		}],\r
+            		"OtherCondition": {\r
+            			"MaxReturnNum": "50000",\r
+            			"AsyncIdentity": "0",\r
+            			"AsyncOnceReturnNum": "2",\r
+            			"AsynQuery": "",\r
+            			"CallbackID": "",\r
+            			"CodeMode": "0",\r
+            			"SortResults": "DEPT_ID+"\r
+            		}\r
+            	}\r
+            }\r
+            """;
+    }
+
+    /**
+     * 生成教职工查询的body参数
+     * @return body 数据
+     */
+    private String getQueryBodyForTeacher() {
+        return """
+            {\r
+            	"From": "A-130100-0001",\r
+            	"To": "110000000001",\r
+            	"MessageSequence": "2019010714141200001",\r
+            	"RequestParam": {\r
+            		"Condition": "1='1'",\r
+            		"ResourceInfos": [{\r
+            			"ResourceName": "R-13010005-00000013",\r
+            			"DataItems": [{\r
+            					"Name": "NAME",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "SEX",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "NATION",\r
+            					"Fmt": ""\r
+            				},\r
+                            {\r
+            					"Name": "mobile_phone",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "BIRTHDAY",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "ID_CODE",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "NATIVE_PLACE",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "STAFF_RANK",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "EDUCATION",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "POLITY",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "PERSON_CATEGORY",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "POST",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "EMPLOYEE_ID",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "THIRD_UNIT",\r
+            					"Fmt": ""\r
+            				},\r
+            				{\r
+            					"Name": "DEPT_ID",\r
+            					"Fmt": ""\r
+            				},\r
+                            {\r
+                                    "Name": "STAFF_TYPE_",\r
+                                    "Fmt": ""\r
+                            },\r
+                            {\r
+                                    "Name": "STATUS",\r
+                                    "Fmt": ""\r
+                            }\r
+            			]\r
+            		}],\r
+            		"OtherCondition": {\r
+            			"MaxReturnNum": "50000",\r
+            			"AsyncIdentity": "0",\r
+            			"AsyncOnceReturnNum": "2",\r
+            			"AsynQuery": "",\r
+            			"CallbackID": "",\r
+            			"CodeMode": "0",\r
+            			"SortResults": ""\r
+            		}\r
+            	}\r
+            }\r
+            """;
+    }
+}

+ 525 - 0
ruoyi-server/ruoyi-server-sync/src/main/java/org/dromara/server/sync/service/SyncTrainService.java

@@ -0,0 +1,525 @@
+package org.dromara.server.sync.service;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.server.base.service.dept.strategy.SyncDeptStrategyContent;
+import org.dromara.server.base.service.user.strategy.SyncUserStrategyContent;
+import org.dromara.server.common.constant.DefaultConstants;
+import org.dromara.server.common.constant.SyncResourceConstants;
+import org.dromara.server.common.domain.bo.ResourceDept;
+import org.dromara.server.common.domain.bo.ResourcePerson;
+import org.dromara.server.common.domain.bo.ResourcePersonDept;
+import org.dromara.server.common.domain.bo.SyncFullDataBo;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * name: SyncTrainService
+ * package: org.dromara.server.sync.service
+ * description: 培训班学员与开班信息同步
+ * date: 2024-10-21 21:15:36 21:15
+ *
+ * @author luoyibo
+ * @version 0.1
+ * @since JDK 1.8
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class SyncTrainService {
+    private final SyncDeptStrategyContent syncDeptStrategyContent;
+    private final SyncUserStrategyContent syncUserStrategyContent;
+
+    public void syncTrainClass() {
+        HttpRequest req = CreateHttpRequest.createRequest();
+        req.body(getQueryBodyForClass());
+
+        SyncFullDataBo dataBo = JSONUtil.toBean(req.execute().body(), SyncFullDataBo.class);
+
+        List<ResourceDept> resourceDeptlist = new ArrayList<>();
+        for (List<String> list : dataBo.getResponseParam().getResourceInfos().get(0).getDataInfo()) {
+            ResourceDept dept = convertClassToDept(list);
+            resourceDeptlist.add(dept);
+        }
+        log.info("[全量获取到的培训班级数据]-[{}]条-[{}]", resourceDeptlist.size(), JSONUtil.toJsonStr(dataBo));
+        syncDeptStrategyContent.syncDept(resourceDeptlist, SyncResourceConstants.TRAIN_CLASS);
+    }
+
+    public void syncTrainee() {
+        //HttpRequest req = CreateHttpRequest.createRequest();
+        //req.body(getQueryBodyForTrainee());
+        //获取到培训学员数据
+        //SyncFullDataBo traineeDataBo = JSONUtil.toBean(req.execute().body(), SyncFullDataBo.class);
+        //List<ResourcePerson> resourcePersonList = new ArrayList<>();
+        //for (List<String> list : traineeDataBo.getResponseParam().getResourceInfos().get(0).getDataInfo()) {
+        //    ResourcePerson person = new ResourcePerson();
+        //    resourcePersonList.add(person);
+        //}
+        //获取到的学员与培训班对应关系
+        //req.body(getQueryBodyForClassTrainee());
+        //SyncFullDataBo classTraineeDataBo = JSONUtil.toBean(req.execute().body(), SyncFullDataBo.class);
+        //List<ResourcePersonDept> resourcePersonDeptList = getResourcePersonDeptList(classTraineeDataBo);
+
+        //region 模拟测试
+        List<ResourcePerson> resourcePersonList = new ArrayList<>();
+        ResourcePerson person = new ResourcePerson();
+        person.setTenantId(DefaultConstants.TENANT_ID);
+        person.setUserId("1799827959791554562");
+        person.setDeptId("1799803773266235394");
+        person.setPostCode(DefaultConstants.TRAINEE_CODE);
+        person.setRealName("赵开羽");
+        person.setSex("1");
+        person.setPhone("18974390367");
+        person.setIdNumber("XP4aO5yhQyNPUctSqDOU9Syh9KUo/DN8");
+        person.setCategory("2");
+        resourcePersonList.add(person);
+
+        List<ResourcePersonDept> resourcePersonDeptList = new ArrayList<>();
+        ResourcePersonDept personDept = new ResourcePersonDept();
+        personDept.setUserId("1799827959791554562");
+        personDept.setDeptId("1799803773266235394");
+        personDept.setPostCode(DefaultConstants.TRAINEE_CODE);
+        personDept.setDelFlag("0");
+        resourcePersonDeptList.add(personDept);
+
+        personDept = new ResourcePersonDept();
+        personDept.setUserId("1799827959791554562");
+        personDept.setDeptId("ffe051b8cf2e45ddb899d596108699d7");
+        personDept.setPostCode(DefaultConstants.TRAINEE_CODE);
+        personDept.setDelFlag("0");
+        resourcePersonDeptList.add(personDept);
+        //endregion
+        getResourcePeople(resourcePersonDeptList, resourcePersonList);
+
+        syncUserStrategyContent.syncUser(resourcePersonList, SyncResourceConstants.TRAINEE);
+    }
+
+    /**
+     * 设置班级查询参数
+     *
+     * @return 查询参数
+     */
+    private String getQueryBodyForClass() {
+        return """
+            {\r
+                "From": "A-130100-0001",\r
+                "To": "110000000001",\r
+                "MessageSequence": "2019010714141200001",\r
+                "RequestParam": {\r
+                    "Condition": "1='1'",\r
+                    "ResourceInfos": [\r
+                        {\r
+                            "ResourceName": "R-13010005-00000034",\r
+                            "DataItems": [\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "id"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "name"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "short_name"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "class_code"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "year"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "xq"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "xz"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "bcsx"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "bblx"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "pxdx"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "student_num"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "man_num"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "woman_num"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "classroom"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                     "Name": "bm_starttime"\r
+                                },\r
+                                {\r
+                  \
+                                  "Fmt": "",\r
+                                    "Name": "bm_endtime"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "bd_time"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "kb_time"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "by_time"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "master"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "tutor"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "remarks"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "create_user"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "create_date"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "update_user"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "update_date"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "status"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "no_pay_allow"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "file_name"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "file_path"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "master_id"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "tutor_id"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "one_card_sign"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "round"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "sort_num"\r
+                                },\r
+                                {\r
+                                    "Fmt": "",\r
+                                    "Name": "room_id"\r
+                                }\r
+                            ]\r
+                        }\r
+                    ],\r
+                    "OtherCondition": {\r
+                        "MaxReturnNum": "50000",\r
+                        "AsyncIdentity": "0",\r
+                        "AsyncOnceReturnNum": "2",\r
+                        "AsynQuery": "",\r
+                        "CallbackID": "",\r
+                        "CodeMode": "0",\r
+                        "SortResults": ""\r
+                    }\r
+                }\r
+            }""";
+    }
+
+    /**
+     * 设置培训学员查询参数
+     *
+     * @return 查询参数
+     */
+    private String getQueryBodyForTrainee() {
+        return """
+            {\r
+                "From": "A-130100-0001",\r
+                "To": "110000000001",\r
+                "MessageSequence": "2019010714141200001",\r
+                "RequestParam": {\r
+                    "Condition": "1='1'",\r
+                    "ResourceInfos": [{\r
+                        "ResourceName": "R-13010005-00000048",\r
+                        "DataItems": [{\r
+                            "Fmt": "",\r
+                            "Name": "id"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "name"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "sex"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "nation"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "jiguan"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "birthday"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "id_card"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "phone"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "post"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "remarks"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "work_time"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "party_time"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "culture"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "school"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "personnel_dep_name"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "flag"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "open_id"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "current_jigou_id"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "current_jigou_name"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "plate_number"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "current_class_id"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "_rank"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "zzmm"\r
+                        }, {\r
+                            "Fmt": "",\r
+                            "Name": "photo_path"\r
+                        }]\r
+                    }],\r
+                    "OtherCondition": {\r
+                        "MaxReturnNum": "50000",\r
+                        "AsyncIdentity": "0",\r
+                        "AsyncOnceReturnNum": "2",\r
+                        "AsynQuery": "",\r
+                        "CallbackID": "",\r
+                        "CodeMode": "0",\r
+                        "SortResults": ""\r
+                    }\r
+                }\r
+            }""";
+    }
+
+    /**
+     * 设置班级学员查询参数
+     *
+     * @return 班级学员
+     */
+    private String getQueryBodyForClassTrainee() {
+        return """
+            {\r
+            	"From": "A-130100-0001",\r
+            	"To": "110000000001",\r
+            	"MessageSequence": "2019010714141200001",\r
+            	"RequestParam": {\r
+            		"Condition": "1='1'",\r
+            		"ResourceInfos": [{\r
+            			"ResourceName": "R-13010005-00000035",\r
+            			"DataItems": [{\r
+            				"Fmt": "",\r
+            				"Name": "class_id"\r
+            			}, {\r
+            				"Fmt": "",\r
+            				"Name": "student_id"\r
+            			}, {\r
+            				"Fmt": "",\r
+            				"Name": "status"\r
+            			}, {\r
+            				"Fmt": "",\r
+            				"Name": "up_time"\r
+            			}, {\r
+            				"Fmt": "",\r
+            				"Name": "up_status"\r
+            			}, {\r
+            				"Fmt": "",\r
+            				"Name": "bd_time"\r
+            			}, {\r
+            				"Fmt": "",\r
+            				"Name": "xh"\r
+            			}, {\r
+            				"Fmt": "",\r
+            				"Name": "fjh"\r
+            			}, {\r
+            				"Fmt": "",\r
+            				"Name": "group_id"\r
+            			}, {\r
+            				"Fmt": "",\r
+            				"Name": "class_post"\r
+            			}, {\r
+            				"Fmt": "",\r
+            				"Name": "class_sort"\r
+            			}, {\r
+            				"Fmt": "",\r
+            				"Name": "group_sort"\r
+            			}]\r
+            		}],\r
+            		"OtherCondition": {\r
+            			"MaxReturnNum": "50000",\r
+            			"AsyncIdentity": "0",\r
+            			"AsyncOnceReturnNum": "2",\r
+            			"AsynQuery": "",\r
+            			"CallbackID": "",\r
+            			"CodeMode": "0",\r
+            			"SortResults": ""\r
+            		}\r
+            	}\r
+            }""";
+    }
+
+    /**
+     * 班级数据预处理
+     *
+     * @param list 源数据
+     * @return 班级信息
+     */
+    private ResourceDept convertClassToDept(List<String> list) {
+         ResourceDept dept = new ResourceDept();
+        dept.setDept_id(list.get(0));
+        dept.setDept_name(list.get(1));
+        dept.setYear(Integer.valueOf(list.get(4)));
+        dept.setSemester("0".equals(list.get(5)) ? "上学期" : "下学期");
+
+        dept.setPayBegin(DateUtil.parseDate(list.get(16)));
+        dept.setCheckDate(DateUtil.parseDate(list.get(16)));
+        dept.setBeginDate(DateUtil.parseDate(list.get(17)));
+        dept.setEndDate(DateUtil.parse(list.get(18), "yyyy-MM-dd HH:mm:ss"));
+        dept.setPayEnd(DateUtil.parse(list.get(18), "yyyy-MM-dd HH:mm:ss"));
+        dept.setChooseRoom("0");
+        dept.setCanEat("1");
+        dept.setPayCheck(list.get(27));
+
+        dept.setDept_num(list.get(34));
+
+        return dept;
+    }
+
+    /**
+     * 班级与学员对应关系预处理
+     *
+     * @param classTraineeDataBo 班级与学员对应关系
+     * @return 班级与学员对应关系
+     */
+    @NotNull
+    private List<ResourcePersonDept> getResourcePersonDeptList(SyncFullDataBo classTraineeDataBo) {
+        String isCheck = "1";
+        List<ResourcePersonDept> resourcePersonDeptList = new ArrayList<>();
+        for (List<String> personDeptSr : classTraineeDataBo.getResponseParam().getResourceInfos().get(0).getDataInfo()) {
+            ResourcePersonDept personDept = new ResourcePersonDept();
+            //学员Id
+            personDept.setUserId(personDeptSr.get(1));
+            //班级Id
+            personDept.setDeptId(personDeptSr.get(0));
+            //岗位编码,默认为学员
+            personDept.setPostCode(DefaultConstants.TRAINEE_CODE);
+            //和班级的绑定状态 0-正常 1-已报到一卡通不处理 2-退学 一卡通删除
+            personDept.setDelFlag(personDeptSr.get(2).equals(isCheck) ? "0" : personDeptSr.get(2));
+            resourcePersonDeptList.add(personDept);
+        }
+        return resourcePersonDeptList;
+    }
+
+    /**
+     * 学员数据预处理
+     *
+     * @param resourcePersonDeptList 学员与班级对应关系
+     * @param resourcePersonList     学员
+     */
+    private void getResourcePeople(List<ResourcePersonDept> resourcePersonDeptList, List<ResourcePerson> resourcePersonList) {
+        resourcePersonList.forEach(resourcePerson -> {
+            //找出该学员绑定的所有班级
+            List<ResourcePersonDept> personDeptList = resourcePersonDeptList.stream()
+                .filter(p -> p.getUserId().equals(resourcePerson.getUserId()))
+                .toList();
+            //将绑定班级中的学员当前班级设置成主部门
+            personDeptList.forEach(personDept -> {
+                if (personDept.getDeptId().equals(resourcePerson.getDeptId())) {
+                    personDept.setMainDept("Y");
+                }else{
+                    personDept.setMainDept("N");
+                }
+            });
+
+            resourcePerson.setUserDeptList(personDeptList);
+        });
+    }
+}

+ 34 - 0
ruoyi-server/ruoyi-server-sync/src/main/resources/application.yml

@@ -0,0 +1,34 @@
+# Tomcat
+server:
+  port: 9104
+
+# Spring
+spring:
+  application:
+    # 应用名称
+    name: ruoyi-server-sync
+  profiles:
+    # 环境配置
+    active: @profiles.active@
+
+--- # nacos 配置
+spring:
+  cloud:
+    nacos:
+      # nacos 服务地址
+      server-addr: @nacos.server@
+      username: @nacos.username@
+      password: @nacos.password@
+      discovery:
+        # 注册组
+        group: @nacos.discovery.group@
+        namespace: ${spring.profiles.active}
+      config:
+        # 配置组
+        group: @nacos.config.group@
+        namespace: ${spring.profiles.active}
+  config:
+    import:
+      - optional:nacos:application-common.yml
+      - optional:nacos:datasource.yml
+      - optional:nacos:${spring.application.name}.yml

+ 10 - 0
ruoyi-server/ruoyi-server-sync/src/main/resources/banner.txt

@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+                            _                           _                    
+                           (_)                         | |                   
+ _ __  _   _   ___   _   _  _  ______  ___  _   _  ___ | |_   ___  _ __ ___  
+| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \ 
+| |   | |_| || (_) || |_| || |        \__ \| |_| |\__ \| |_ |  __/| | | | | |
+|_|    \__,_| \___/  \__, ||_|        |___/ \__, ||___/ \__| \___||_| |_| |_|
+                      __/ |                  __/ |                           
+                     |___/                  |___/                            

+ 28 - 0
ruoyi-server/ruoyi-server-sync/src/main/resources/logback-plus.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+    <!-- 日志存放路径 -->
+	<property name="log.path" value="logs/${project.artifactId}" />
+   <!-- 日志输出格式 -->
+    <property name="console.log.pattern"
+              value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+
+    <!-- 控制台输出 -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${console.log.pattern}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+    </appender>
+
+    <include resource="logback-common.xml" />
+
+    <include resource="logback-logstash.xml" />
+
+    <!-- 开启 skywalking 日志收集 -->
+    <include resource="logback-skylog.xml" />
+
+	<!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="console" />
+    </root>
+</configuration>

+ 3 - 0
ruoyi-server/ruoyi-server-sync/src/main/resources/mapper/package-info.md

@@ -0,0 +1,3 @@
+java包使用 `.` 分割 resource 目录使用 `/` 分割
+<br>
+此文件目的 防止文件夹粘连找不到 `xml` 文件