11
tjx
10 小时以前 3aac44ea5ee6afbba7358124c8c2f38e5a6eb9ad
src/main/java/com/gs/dingtalk/service/WorkWXService.java
@@ -710,6 +710,7 @@
    }
    @Data
    @com.fasterxml.jackson.annotation.JsonIgnoreProperties(ignoreUnknown = true)
    public static class CheckinTime {
        @JsonProperty("work_sec")
        private Integer workSec;
@@ -824,4 +825,138 @@
        private Integer timelineId;
        private String deviceid;
    }
    // ==================== 设备打卡数据结构 ====================
    @Data
    @com.fasterxml.jackson.annotation.JsonIgnoreProperties(ignoreUnknown = true)
    private static class WorkWXHardwareCheckinResponse {
        private Integer errcode;
        private String errmsg;
        private List<HardwareCheckinData> checkindata;
    }
    @Data
    @com.fasterxml.jackson.annotation.JsonIgnoreProperties(ignoreUnknown = true)
    public static class HardwareCheckinData {
        private String userid;
        @JsonProperty("checkin_time")
        private Long checkinTime;
        @JsonProperty("device_sn")
        private String deviceSn;
        @JsonProperty("device_name")
        private String deviceName;
    }
    /**
     * 获取设备打卡数据
     * 接口文档: https://developer.work.weixin.qq.com/document/path/94126
     * 1. 获取记录时间跨度不超过一个月
     * 2. 用户列表不超过100个,若用户超过100个,请分批获取
     *
     * @param startTime  开始时间戳(秒)
     * @param endTime    结束时间戳(秒)
     * @param useridList 用户ID列表
     * @return 设备打卡数据列表
     */
    public List<HardwareCheckinData> getHardwareCheckinData(long startTime, long endTime, List<String> useridList) throws IOException {
        String accessToken = getAccessToken();
        String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/hardware/get_hardware_checkin_data?access_token=%s", accessToken);
        List<HardwareCheckinData> 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("filter_type", 1);  // 1表示按userid过滤
            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();
                WorkWXHardwareCheckinResponse checkinResponse = objectMapper.readValue(responseBody, WorkWXHardwareCheckinResponse.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());
                }
            }
            // 批次间等待500ms,避免请求过于频繁
            if (i < batchCount - 1) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.warn("批次间等待被中断");
                }
            }
        }
        log.info("设备打卡数据获取完成,总记录数: {}", allCheckinData.size());
        return allCheckinData;
    }
    /**
     * 根据QW_STAFF表获取设备打卡数据
     *
     * @param startTime 开始时间戳(秒)
     * @param endTime   结束时间戳(秒)
     * @return 设备打卡数据列表
     */
    public List<HardwareCheckinData> getHardwareCheckinDataByQwStaff(long startTime, long endTime) throws IOException {
        List<QwStaff> qwStaffList = qwStaffMapper.selectList(new LambdaQueryWrapper<QwStaff>());
        if (qwStaffList == null || qwStaffList.isEmpty()) {
            log.warn("QW_STAFF表中没有数据");
            return new ArrayList<>();
        }
        List<String> useridList = qwStaffList.stream()
                .map(QwStaff::getAccount)
                .filter(account -> account != null && !account.isEmpty())
                .collect(Collectors.toList());
        if (useridList.isEmpty()) {
            log.warn("QW_STAFF表中没有有效的account数据");
            return new ArrayList<>();
        }
        log.info("从QW_STAFF表获取到 {} 个用户account", useridList.size());
        return getHardwareCheckinData(startTime, endTime, useridList);
    }
}