tjx
2025-11-26 3ba118feb585368de68b0a1cf583e192c313a8a6
src/main/java/com/gs/xky/service/WorkWXService.java
@@ -11,6 +11,7 @@
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -60,12 +61,42 @@
        }
    }
    public List<DeptUser> getUserList() throws IOException {
        String accessToken = getAccessToken();
        String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/user/list_id?access_token=%s", accessToken);
    public String getContactAccessToken() throws IOException {
        String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s",
                DataAcquisitionConfiguration.CORPID,
                DataAcquisitionConfiguration.TXL_CORPSECRET);
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                log.error("获取企业微信通讯录access_token失败,HTTP状态码: {}", response.code());
                throw new IOException("获取通讯录access_token失败: " + response.message());
            }
            String responseBody = response.body().string();
            WorkWXTokenResponse tokenResponse = objectMapper.readValue(responseBody, WorkWXTokenResponse.class);
            if (tokenResponse.getErrcode() != 0) {
                log.error("获取企业微信通讯录access_token失败,错误码: {}, 错误信息: {}",
                        tokenResponse.getErrcode(), tokenResponse.getErrmsg());
                throw new IOException("获取通讯录access_token失败: " + tokenResponse.getErrmsg());
            }
            log.info("成功获取企业微信通讯录access_token,有效期: {}秒", tokenResponse.getExpiresIn());
            return tokenResponse.getAccessToken();
        }
    }
    public String getUserIdByMobile(String mobile) throws IOException {
        String accessToken = getContactAccessToken();
        String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=%s", accessToken);
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("limit", 10000);
        requestBody.put("mobile", mobile);
        MediaType mediaType = MediaType.parse("application/json; charset=UTF-8");
        String jsonBody = objectMapper.writeValueAsString(requestBody);
@@ -79,11 +110,46 @@
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                log.error("通过手机号获取userid失败,HTTP状态码: {}", response.code());
                throw new IOException("获取userid失败: " + response.message());
            }
            String responseBody = response.body().string();
            log.info("通过手机号获取userid响应: {}", responseBody);
            WorkWXUserIdResponse userIdResponse = objectMapper.readValue(responseBody, WorkWXUserIdResponse.class);
            if (userIdResponse.getErrcode() != 0) {
                log.error("通过手机号获取userid失败,错误码: {}, 错误信息: {}",
                        userIdResponse.getErrcode(), userIdResponse.getErrmsg());
                throw new IOException("获取userid失败: " + userIdResponse.getErrmsg());
            }
            log.info("成功通过手机号 {} 获取userid: {}", mobile, userIdResponse.getUserid());
            return userIdResponse.getUserid();
        }
    }
    public List<WorkWXUser> getUserList() throws IOException {
        String accessToken = getContactAccessToken();
        String url = String.format(
                "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?access_token=%s&department_id=1&fetch_child=1",
                accessToken);
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                log.error("获取企业微信用户列表失败,HTTP状态码: {}", response.code());
                throw new IOException("获取用户列表失败: " + response.message());
            }
            String responseBody = response.body().string();
            log.info("获取用户列表响应: {}", responseBody);
            WorkWXUserListResponse userListResponse = objectMapper.readValue(responseBody, WorkWXUserListResponse.class);
            if (userListResponse.getErrcode() != 0) {
@@ -93,9 +159,80 @@
            }
            log.info("成功获取企业微信用户列表,用户数量: {}",
                    userListResponse.getDeptUser() != null ? userListResponse.getDeptUser().size() : 0);
            return userListResponse.getDeptUser();
                    userListResponse.getUserlist() != null ? userListResponse.getUserlist().size() : 0);
            return userListResponse.getUserlist();
        }
    }
    public List<CheckinData> getCheckinData(long startTime, long endTime, List<String> useridList) throws IOException {
        String accessToken = getAccessToken();
        String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata?access_token=%s", accessToken);
        List<CheckinData> allCheckinData = new ArrayList<>();
        int batchSize = 100;
        int totalUsers = useridList.size();
        int batchCount = (totalUsers + batchSize - 1) / batchSize;
        log.info("开始获取打卡数据,总用户数: {}, 分批数: {}, 时间范围: {} - {}", totalUsers, batchCount, startTime, endTime);
        for (int i = 0; i < batchCount; i++) {
            int fromIndex = i * batchSize;
            int toIndex = Math.min((i + 1) * batchSize, totalUsers);
            List<String> batchUserList = useridList.subList(fromIndex, toIndex);
            log.info("正在获取第 {}/{} 批打卡数据,用户数: {}", i + 1, batchCount, batchUserList.size());
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("opencheckindatatype", 3);
            requestBody.put("starttime", startTime);
            requestBody.put("endtime", endTime);
            requestBody.put("useridlist", batchUserList);
            MediaType mediaType = MediaType.parse("application/json; charset=UTF-8");
            String jsonBody = objectMapper.writeValueAsString(requestBody);
            RequestBody body = RequestBody.create(mediaType, jsonBody);
            Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .addHeader("Content-Type", "application/json; charset=UTF-8")
                    .build();
            try (Response response = client.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    log.error("获取打卡数据失败,HTTP状态码: {}", response.code());
                    throw new IOException("获取打卡数据失败: " + response.message());
                }
                String responseBody = response.body().string();
                WorkWXCheckinResponse checkinResponse = objectMapper.readValue(responseBody, WorkWXCheckinResponse.class);
                if (checkinResponse.getErrcode() != 0) {
                    log.error("获取打卡数据失败,错误码: {}, 错误信息: {}",
                            checkinResponse.getErrcode(), checkinResponse.getErrmsg());
                    throw new IOException("获取打卡数据失败: " + checkinResponse.getErrmsg());
                }
                if (checkinResponse.getCheckindata() != null) {
                    allCheckinData.addAll(checkinResponse.getCheckindata());
                    log.info("第 {}/{} 批获取到打卡记录数: {}", i + 1, batchCount, checkinResponse.getCheckindata().size());
                }
            }
            if (i < batchCount - 1) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.warn("批次间等待被中断");
                }
            }
        }
        log.info("打卡数据获取完成,总记录数: {}", allCheckinData.size());
        return allCheckinData;
    }
    @Data
@@ -109,18 +246,54 @@
    }
    @Data
    private static class WorkWXUserListResponse {
    private static class WorkWXUserIdResponse {
        private Integer errcode;
        private String errmsg;
        @JsonProperty("next_cursor")
        private String nextCursor;
        @JsonProperty("dept_user")
        private List<DeptUser> deptUser;
        private String userid;
    }
    @Data
    public static class DeptUser {
    private static class WorkWXUserListResponse {
        private Integer errcode;
        private String errmsg;
        private List<WorkWXUser> userlist;
    }
    @Data
    public static class WorkWXUser {
        private String userid;
        private Integer department;
        private String name;
        private List<Integer> department;
        @JsonProperty("open_userid")
        private String openUserid;
    }
    @Data
    private static class WorkWXCheckinResponse {
        private Integer errcode;
        private String errmsg;
        private List<CheckinData> checkindata;
    }
    @Data
    public static class CheckinData {
        private String userid;
        private String groupname;
        @JsonProperty("checkin_type")
        private String checkinType;
        @JsonProperty("exception_type")
        private String exceptionType;
        @JsonProperty("checkin_time")
        private Long checkinTime;
        @JsonProperty("location_title")
        private String locationTitle;
        @JsonProperty("location_detail")
        private String locationDetail;
        private String wifiname;
        private String notes;
        private String wifimac;
        private String mediaids;
        private Double lat;
        private Double lng;
    }
}