package com.qqflow.engine.domain.ewechat.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.qqflow.engine.domain.ewechat.api.EnterpriseWechatApi; import com.qqflow.engine.domain.ewechat.mapper.EnterpriseWechatDepartmentMapper; import com.qqflow.engine.domain.ewechat.mapper.EnterpriseWechatMemberMapper; import com.qqflow.engine.domain.ewechat.model.enterprise.rsp.EnterpriseWechatUserListRsp; import com.qqflow.engine.domain.ewechat.po.EnterpriseWechatDepartment; import com.qqflow.engine.domain.ewechat.po.EnterpriseWechatMember; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.*; /** * 企微通讯录同步服务(懒加载 + 全量同步) */ @Slf4j @Service @RequiredArgsConstructor public class WecomContactSyncService { private final EnterpriseWechatDepartmentMapper departmentMapper; private final EnterpriseWechatMemberMapper memberMapper; private final EnterpriseWechatApi enterpriseWechatApi; private final EnterpriseWechatMsgService wechatMsgService; /** 获取子部门列表(从本地DB查询) */ public List listSubDepartments(Long parentId) { return departmentMapper.selectList( new LambdaQueryWrapper().eq(EnterpriseWechatDepartment::getParentId, parentId)); } /** 获取部门成员(懒加载) */ public List listDepartmentMembers(Long departmentId) { List cached = memberMapper.selectList( new LambdaQueryWrapper().eq(EnterpriseWechatMember::getDepartmentId, departmentId)); if (!cached.isEmpty()) return cached; String accessToken = wechatMsgService.getCorpAccessToken(); if (accessToken == null) return List.of(); EnterpriseWechatUserListRsp rsp = enterpriseWechatApi.listDepartmentUsers(accessToken, departmentId); if (rsp == null || rsp.getUserlist() == null) return List.of(); List members = new ArrayList<>(); for (var u : rsp.getUserlist()) { EnterpriseWechatMember wm = new EnterpriseWechatMember(); wm.setUserid(u.getUserid()); wm.setName(u.getName() != null ? u.getName() : u.getUserid()); wm.setDepartmentId(departmentId); wm.setOpenUserid(u.getOpenUserid()); memberMapper.insert(wm); members.add(wm); } return members; } // ==================== 全量同步 ==================== /** * 全量同步:部门 + 成员 * @return 同步结果摘要 */ public Map syncAll() { String accessToken = wechatMsgService.getCorpAccessToken(); if (accessToken == null) { throw new RuntimeException("无法获取企微 access_token,请检查授权配置"); } Map result = new LinkedHashMap<>(); Map deptResult = this.syncAllDepartments(accessToken); result.put("departments", deptResult); Map memberResult = this.syncAllMembers(accessToken); result.put("members", memberResult); return result; } /** * 全量同步部门:从企微拉取完整部门树,upsert 到本地表 */ private Map 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 syncAllMembers(String accessToken) { List allDepts = departmentMapper.selectList( new LambdaQueryWrapper()); 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() .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); } }