|
@@ -11,11 +11,11 @@ import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
-import java.util.ArrayList;
|
|
|
|
|
-import java.util.List;
|
|
|
|
|
|
|
+import java.time.LocalDateTime;
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 企微通讯录同步服务(懒加载:先查本地DB,没有再调企微接口同步后返回)
|
|
|
|
|
|
|
+ * 企微通讯录同步服务(懒加载 + 全量同步)
|
|
|
*/
|
|
*/
|
|
|
@Slf4j
|
|
@Slf4j
|
|
|
@Service
|
|
@Service
|
|
@@ -58,4 +58,102 @@ public class WecomContactSyncService {
|
|
|
return members;
|
|
return members;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // ==================== 全量同步 ====================
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 全量同步:部门 + 成员
|
|
|
|
|
+ * @return 同步结果摘要
|
|
|
|
|
+ */
|
|
|
|
|
+ public Map<String, Object> syncAll() {
|
|
|
|
|
+ String accessToken = wechatMsgService.getCorpAccessToken();
|
|
|
|
|
+ if (accessToken == null) {
|
|
|
|
|
+ throw new RuntimeException("无法获取企微 access_token,请检查授权配置");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> result = new LinkedHashMap<>();
|
|
|
|
|
+ Map<String, Integer> deptResult = this.syncAllDepartments(accessToken);
|
|
|
|
|
+ result.put("departments", deptResult);
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Integer> memberResult = this.syncAllMembers(accessToken);
|
|
|
|
|
+ result.put("members", memberResult);
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 全量同步部门:从企微拉取完整部门树,upsert 到本地表
|
|
|
|
|
+ */
|
|
|
|
|
+ private Map<String, Integer> syncAllDepartments(String accessToken) {
|
|
|
|
|
+ var rsp = enterpriseWechatApi.listDepartment(accessToken, null);
|
|
|
|
|
+ if (rsp == null || rsp.getDepartment() == null || rsp.getDepartment().isEmpty()) {
|
|
|
|
|
+ log.warn("[通讯录同步] 企微返回的部门列表为空");
|
|
|
|
|
+ return Map.of("total", 0, "inserted", 0, "updated", 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int inserted = 0, updated = 0;
|
|
|
|
|
+ for (var d : rsp.getDepartment()) {
|
|
|
|
|
+ EnterpriseWechatDepartment dept = departmentMapper.selectById(d.getId());
|
|
|
|
|
+ if (dept == null) {
|
|
|
|
|
+ dept = new EnterpriseWechatDepartment();
|
|
|
|
|
+ dept.setId(d.getId());
|
|
|
|
|
+ dept.setCreatedTime(LocalDateTime.now());
|
|
|
|
|
+ inserted++;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ updated++;
|
|
|
|
|
+ }
|
|
|
|
|
+ dept.setName(d.getName());
|
|
|
|
|
+ dept.setParentId(d.getParentid() != null ? d.getParentid() : 0L);
|
|
|
|
|
+ this.departmentMapper.insertOrUpdate(dept);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("[通讯录同步] 部门同步完成 | 总数:{} 新增:{} 更新:{}", rsp.getDepartment().size(), inserted, updated);
|
|
|
|
|
+ return Map.of("total", rsp.getDepartment().size(), "inserted", inserted, "updated", updated);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 全量同步成员:遍历本地已同步的所有部门,从企微拉取各部门成员并 upsert
|
|
|
|
|
+ */
|
|
|
|
|
+ private Map<String, Integer> syncAllMembers(String accessToken) {
|
|
|
|
|
+ List<EnterpriseWechatDepartment> allDepts = departmentMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<EnterpriseWechatDepartment>());
|
|
|
|
|
+ if (allDepts.isEmpty()) {
|
|
|
|
|
+ log.warn("[通讯录同步] 本地无部门数据,请先同步部门");
|
|
|
|
|
+ return Map.of("departments", 0, "total", 0, "inserted", 0, "updated", 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int totalInserted = 0, totalUpdated = 0, totalMembers = 0;
|
|
|
|
|
+ for (var dept : allDepts) {
|
|
|
|
|
+ var rsp = enterpriseWechatApi.listDepartmentUsers(accessToken, dept.getId());
|
|
|
|
|
+ if (rsp == null || rsp.getUserlist() == null) continue;
|
|
|
|
|
+
|
|
|
|
|
+ for (var u : rsp.getUserlist()) {
|
|
|
|
|
+ totalMembers++;
|
|
|
|
|
+ // 按 userid + departmentId 查重(一个用户可能在多个部门)
|
|
|
|
|
+ var existing = memberMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<EnterpriseWechatMember>()
|
|
|
|
|
+ .eq(EnterpriseWechatMember::getUserid, u.getUserid())
|
|
|
|
|
+ .eq(EnterpriseWechatMember::getDepartmentId, dept.getId()));
|
|
|
|
|
+ EnterpriseWechatMember wm;
|
|
|
|
|
+ if (existing != null && !existing.isEmpty()) {
|
|
|
|
|
+ wm = existing.get(0);
|
|
|
|
|
+ totalUpdated++;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ wm = new EnterpriseWechatMember();
|
|
|
|
|
+ totalInserted++;
|
|
|
|
|
+ }
|
|
|
|
|
+ wm.setUserid(u.getUserid());
|
|
|
|
|
+ wm.setName(u.getName() != null ? u.getName() : u.getUserid());
|
|
|
|
|
+ wm.setDepartmentId(dept.getId());
|
|
|
|
|
+ wm.setOpenUserid(u.getOpenUserid());
|
|
|
|
|
+ wm.setUpdatedTime(LocalDateTime.now());
|
|
|
|
|
+ this.memberMapper.insertOrUpdate(wm);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("[通讯录同步] 成员同步完成 | 部门数:{} 成员总数:{} 新增:{} 更新:{}",
|
|
|
|
|
+ allDepts.size(), totalMembers, totalInserted, totalUpdated);
|
|
|
|
|
+ return Map.of("departments", allDepts.size(), "total", totalMembers,
|
|
|
|
|
+ "inserted", totalInserted, "updated", totalUpdated);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
}
|
|
}
|