liu
2026-09-30 91491239c5d4611b5b1404a7abeb2bb23d0edad5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package cn.iocoder.yudao.module.wxcp.service.member;
 
import cn.iocoder.yudao.module.wxcp.controller.admin.member.vo.WxCpDepartmentRespVO;
import cn.iocoder.yudao.module.wxcp.controller.admin.member.vo.WxCpMemberRespVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpDepart;
import me.chanjar.weixin.cp.bean.WxCpUser;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.wxcp.enums.ErrorCodeConstants.WXCP_API_ERROR;
 
/**
 * 企业微信通讯录 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
@Slf4j
public class WxCpMemberServiceImpl implements WxCpMemberService {
 
    /**
     * 企业微信根部门ID固定为 1
     */
    private static final Long ROOT_DEPARTMENT_ID = 1L;
 
    @Resource
    private WxCpService wxCpService;
 
    @Override
    public List<WxCpDepartmentRespVO> getDepartmentList() {
        List<WxCpDepart> departs = listDeparts();
        return departs.stream().map(this::toDeptVO).toList();
    }
 
    @Override
    public List<WxCpDepartmentRespVO> getDepartmentTree() {
        List<WxCpDepart> departs = listDeparts();
        Map<Long, WxCpDepartmentRespVO> voMap = new LinkedHashMap<>();
        for (WxCpDepart d : departs) {
            voMap.put(d.getId(), toDeptVO(d));
        }
        List<WxCpDepartmentRespVO> roots = new ArrayList<>();
        for (WxCpDepartmentRespVO vo : voMap.values()) {
            Long parentId = vo.getParentId();
            WxCpDepartmentRespVO parent = parentId == null ? null : voMap.get(parentId);
            // 找不到父节点的(含顶级部门)都作为根返回,避免因数据缺失导致部门"消失"
            if (parent == null || parent == vo) {
                roots.add(vo);
            } else {
                parent.getChildren().add(vo);
            }
        }
        return roots;
    }
 
    @Override
    public List<WxCpMemberRespVO> getMemberList(Long departmentId, Boolean fetchChild) {
        Long deptId = departmentId != null ? departmentId : ROOT_DEPARTMENT_ID;
        boolean child = fetchChild == null || fetchChild;
        List<WxCpUser> users;
        try {
            users = wxCpService.getUserService().listSimpleByDepartment(deptId, child, null);
        } catch (Exception e) {
            log.error("[getMemberList][获取企业微信成员失败 deptId={} fetchChild={}]", deptId, child, e);
            throw exception(WXCP_API_ERROR);
        }
 
        // 部门名映射,用于把成员的部门ID翻译成可读名称
        Map<Long, String> deptNameMap = new LinkedHashMap<>();
        for (WxCpDepart d : listDeparts()) {
            deptNameMap.put(d.getId(), d.getName());
        }
 
        return users.stream().map(u -> toMemberVO(u, deptNameMap)).toList();
    }
 
    /**
     * 获取全部部门(平铺)。企业微信 department/list 不传 id 时返回全量。
     */
    private List<WxCpDepart> listDeparts() {
        try {
            List<WxCpDepart> departs = wxCpService.getDepartmentService().list(null);
            return departs != null ? departs : List.of();
        } catch (Exception e) {
            log.error("[listDeparts][获取企业微信部门失败]", e);
            throw exception(WXCP_API_ERROR);
        }
    }
 
    private WxCpDepartmentRespVO toDeptVO(WxCpDepart depart) {
        WxCpDepartmentRespVO vo = new WxCpDepartmentRespVO();
        vo.setId(depart.getId());
        vo.setName(depart.getName());
        vo.setParentId(depart.getParentId());
        vo.setOrder(depart.getOrder());
        return vo;
    }
 
    private WxCpMemberRespVO toMemberVO(WxCpUser user, Map<Long, String> deptNameMap) {
        WxCpMemberRespVO vo = new WxCpMemberRespVO();
        vo.setUserId(user.getUserId());
        vo.setName(user.getName());
        vo.setMobile(user.getMobile());
        vo.setEmail(user.getEmail());
        vo.setAvatar(user.getAvatar());
        // 优先取 position,老接口可能只返回 positions 数组
        String position = user.getPosition();
        if (position == null && user.getPositions() != null && user.getPositions().length > 0) {
            position = String.join("、", user.getPositions());
        }
        vo.setPosition(position);
        vo.setStatus(user.getStatus());
        // Gender.getCode() 返回基本类型 int,不能与 null 组成三元表达式,这里单独判断
        if (user.getGender() != null) {
            vo.setGender(user.getGender().getCode());
        }
 
        Long[] deptIds = user.getDepartIds();
        if (deptIds != null && deptIds.length > 0) {
            List<Long> ids = Arrays.asList(deptIds);
            vo.setDepartmentIds(ids);
            vo.setDepartmentNames(String.join("、", ids.stream()
                    .map(id -> deptNameMap.getOrDefault(id, "部门" + id))
                    .toList()));
        }
        return vo;
    }
 
}