From 3aac44ea5ee6afbba7358124c8c2f38e5a6eb9ad Mon Sep 17 00:00:00 2001
From: tjx <t2856754968@163.com>
Date: 星期三, 24 十二月 2025 19:41:04 +0800
Subject: [PATCH] 11
---
src/main/java/com/gs/dingtalk/service/WorkWXService.java | 559 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 559 insertions(+), 0 deletions(-)
diff --git a/src/main/java/com/gs/dingtalk/service/WorkWXService.java b/src/main/java/com/gs/dingtalk/service/WorkWXService.java
index 493ed70..265e68c 100644
--- a/src/main/java/com/gs/dingtalk/service/WorkWXService.java
+++ b/src/main/java/com/gs/dingtalk/service/WorkWXService.java
@@ -314,6 +314,293 @@
return allCheckinData;
}
+ /**
+ * 鑾峰彇鎵撳崱鏃ユ姤鏁版嵁
+ * 鎺ュ彛璋冪敤棰戠巼闄愬埗涓�100娆�/鍒嗛挓
+ * @param startTime 寮�濮嬫椂闂存埑锛堢锛�
+ * @param endTime 缁撴潫鏃堕棿鎴筹紙绉掞級
+ * @param useridList 鐢ㄦ埛ID鍒楄〃
+ * @return 鎵撳崱鏃ユ姤鏁版嵁鍒楄〃
+ */
+ public List<CheckinDayData> getCheckinDayData(long startTime, long endTime, List<String> useridList) throws IOException {
+ String accessToken = getAccessToken();
+ String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckin_daydata?access_token=%s", accessToken);
+
+ List<CheckinDayData> allDayData = 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("姝e湪鑾峰彇绗� {}/{} 鎵规墦鍗℃棩鎶ユ暟鎹紝鐢ㄦ埛鏁�: {}", i + 1, batchCount, batchUserList.size());
+
+ Map<String, Object> requestBody = new HashMap<>();
+ 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("鑾峰彇鎵撳崱鏃ユ姤鏁版嵁澶辫触锛孒TTP鐘舵�佺爜: {}", response.code());
+ throw new IOException("鑾峰彇鎵撳崱鏃ユ姤鏁版嵁澶辫触: " + response.message());
+ }
+
+ String responseBody = response.body().string();
+
+ WorkWXCheckinDayDataResponse dayDataResponse = objectMapper.readValue(responseBody, WorkWXCheckinDayDataResponse.class);
+
+ if (dayDataResponse.getErrcode() != 0) {
+ log.error("鑾峰彇鎵撳崱鏃ユ姤鏁版嵁澶辫触锛岄敊璇爜: {}, 閿欒淇℃伅: {}",
+ dayDataResponse.getErrcode(), dayDataResponse.getErrmsg());
+ throw new IOException("鑾峰彇鎵撳崱鏃ユ姤鏁版嵁澶辫触: " + dayDataResponse.getErrmsg());
+ }
+
+ if (dayDataResponse.getDatas() != null) {
+ allDayData.addAll(dayDataResponse.getDatas());
+ log.info("绗� {}/{} 鎵硅幏鍙栧埌鎵撳崱鏃ユ姤璁板綍鏁�: {}", i + 1, batchCount, dayDataResponse.getDatas().size());
+ }
+ }
+
+ // 鎺ュ彛闄愬埗100娆�/鍒嗛挓锛屾壒娆¢棿绛夊緟600ms纭繚涓嶈秴闄�
+ if (i < batchCount - 1) {
+ try {
+ Thread.sleep(600);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ log.warn("鎵规闂寸瓑寰呰涓柇");
+ }
+ }
+ }
+
+ log.info("鎵撳崱鏃ユ姤鏁版嵁鑾峰彇瀹屾垚锛屾�昏褰曟暟: {}", allDayData.size());
+ return allDayData;
+ }
+
+ /**
+ * 鏍规嵁QW_STAFF琛ㄨ幏鍙栨墦鍗℃棩鎶ユ暟鎹�
+ */
+ public List<CheckinDayData> getCheckinDayDataByQwStaff(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琛ㄤ腑娌℃湁鏈夋晥鐨刟ccount鏁版嵁");
+ return new ArrayList<>();
+ }
+
+ log.info("浠嶲W_STAFF琛ㄨ幏鍙栧埌 {} 涓敤鎴穉ccount", useridList.size());
+ return getCheckinDayData(startTime, endTime, useridList);
+ }
+
+ //鑾峰彇鎵撳崱鏃ユ姤鏁版嵁
+ //璇锋眰鏂瑰紡: POST(HTTPS)
+ //璇锋眰鍦板潃: https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckin_daydata?access_token=ACCESS_TOKEN
+ //鍙傛暟绀轰緥
+ // {
+ // "starttime": 1599062400,
+ // "endtime": 1599062400,
+ // "useridlist": [
+ // "ZhangSan"
+ // ]
+ //}
+ //鎺ュ彛璋冪敤棰戠巼闄愬埗涓�100娆�/鍒嗛挓銆�
+ //杩斿洖缁撴灉
+ //{
+ // "errcode":0,
+ // "errmsg":"ok",
+ // "datas":[
+ // {
+ // "base_info":{
+ // "date":1599062400,
+ // "record_type":1,
+ // "name":"寮犱笁",
+ // "name_ex":"Three Zhang",
+ // "departs_name":"鏈夊浼佷笟/realempty;鏈夊浼佷笟;鏈夊浼佷笟/閮ㄩ棬A4",
+ // "acctid":"ZhangSan",
+ // "rule_info":{
+ // "groupid":10,
+ // "groupname":"瑙勫垯娴嬭瘯",
+ // "scheduleid":0,
+ // "schedulename":"",
+ // "checkintime":[
+ // {
+ // "work_sec":38760,
+ // "off_work_sec":38880
+ // }
+ // ]
+ // },
+ // "day_type":0
+ // },
+ // "summary_info":{
+ // "checkin_count":2,
+ // "regular_work_sec":31,
+ // "standard_work_sec":120,
+ // "earliest_time":38827,
+ // "lastest_time":38858
+ // },
+ // "holiday_infos":[
+ // {
+ // "sp_description":{
+ // "data":[
+ // {
+ // "lang":"zh_CN",
+ // "text":"09/03 10:00~09/03 10:01"
+ // }
+ // ]
+ // },
+ // "sp_number":"202009030002",
+ // "sp_title":{
+ // "data":[
+ // {
+ // "lang":"zh_CN",
+ // "text":"璇峰亣0.1灏忔椂"
+ // }
+ // ]
+ // }
+ // },
+ // {
+ // "sp_description":{
+ // "data":[
+ // {
+ // "lang":"zh_CN",
+ // "text":"08/25 14:37~09/10 14:37"
+ // }
+ // ]
+ // },
+ // "sp_number":"202008270004",
+ // "sp_title":{
+ // "data":[
+ // {
+ // "lang":"zh_CN",
+ // "text":"鍔犵彮17.0灏忔椂"
+ // }
+ // ]
+ // }
+ // }
+ // ],
+ // "exception_infos":[
+ // {
+ // "count":1,
+ // "duration":60,
+ // "exception":1
+ // },
+ // {
+ // "count":1,
+ // "duration":60,
+ // "exception":2
+ // }
+ // ],
+ // "ot_info":{
+ // "ot_status":1,
+ // "ot_duration":3600,
+ // "exception_duration":[],
+ // "workday_over_as_money": 54000
+ // },
+ // "sp_items":[
+ // {
+ // "count":1,
+ // "duration":360,
+ // "time_type":0,
+ // "type":1,
+ // "vacation_id":2,
+ // "name":"骞村亣"
+ // },
+ // {
+ // "count":0,
+ // "duration":0,
+ // "time_type":0,
+ // "type":100,
+ // "vacation_id":0,
+ // "name":"澶栧嫟娆℃暟"
+ // }
+ // ]
+ // }
+ // ]
+ //}
+ //鍙傛暟璇存槑:
+ //errcode int32 杩斿洖鐮�
+ //errmsg string 閿欒鐮佹弿杩�
+ //datas obj[] 鏃ユ姤鏁版嵁鍒楄〃
+ //datas.base_info obj 鍩虹淇℃伅
+ //datas.base_info.date uint32 鏃ユ姤鏃ユ湡
+ //datas.base_info.record_type uint32 璁板綍绫诲瀷锛�1-鍥哄畾涓婁笅鐝紱2-澶栧嚭锛堟鎶ヨ〃涓笉浼氬嚭鐜板鍑烘墦鍗℃暟鎹級锛�3-鎸夌彮娆′笂涓嬬彮锛�4-鑷敱绛惧埌锛�5-鍔犵彮锛�7-鏃犺鍒�
+ //datas.base_info.name string 鎵撳崱浜哄憳濮撳悕
+ //datas.base_info.name_ex string 鎵撳崱浜哄憳鍒悕
+ //datas.base_info.departs_name string 鎵撳崱浜哄憳鎵�鍦ㄩ儴闂紝浼氭樉绀烘墍鏈夋墍鍦ㄩ儴闂�
+ //datas.base_info.acctid string 鎵撳崱浜哄憳璐﹀彿锛屽嵆userid
+ //datas.base_info.rule_info obj 鎵撳崱浜哄憳鎵�灞炶鍒欎俊鎭�
+ //datas.base_info.rule_info.groupid int32 鎵�灞炶鍒欑殑id
+ //datas.base_info.rule_info.groupname string 鎵撳崱瑙勫垯鍚�
+ //datas.base_info.rule_info.scheduleid int32 褰撴棩鎵�灞炵彮娆d锛屼粎鎸夌彮娆′笂涓嬬彮鎵嶆湁鍊硷紝鏄剧ず鍦ㄦ墦鍗℃棩鎶�-鐝鍒�
+ //datas.base_info.rule_info.schedulename string 褰撴棩鎵�灞炵彮娆″悕绉帮紝浠呮寜鐝涓婁笅鐝墠鏈夊�硷紝鏄剧ず鍦ㄦ墦鍗℃棩鎶�-鐝鍒�
+ //datas.base_info.rule_info.checkintime obj[] 褰撴棩鎵撳崱鏃堕棿锛屼粎鍥哄畾涓婁笅鐝鍒欐湁鍊硷紝鏄剧ず鍦ㄦ墦鍗℃棩鎶�-鐝鍒�
+ //datas.base_info.rule_info.checkintime.work_sec uint32 涓婄彮鏃堕棿锛屼负璺濈0鐐圭殑鏃堕棿宸�
+ //datas.base_info.rule_info.checkintime.off_work_sec uint32 涓嬬彮鏃堕棿锛屼负璺濈0鐐圭殑鏃堕棿宸�
+ //datas.base_info.day_type uint32 鏃ユ姤绫诲瀷锛�0-宸ヤ綔鏃ユ棩鎶ワ紱1-浼戞伅鏃ユ棩鎶�
+ //datas.summary_info obj 姹囨�讳俊鎭�
+ //datas.summary_info.checkin_count int32 褰撴棩鎵撳崱娆℃暟
+ //datas.summary_info.regular_work_sec int32 褰撴棩瀹為檯宸ヤ綔鏃堕暱锛屽崟浣嶏細绉�
+ //datas.summary_info.standard_work_sec int32 褰撴棩鏍囧噯宸ヤ綔鏃堕暱锛屽崟浣嶏細绉�
+ //datas.summary_info.earliest_time int32 褰撴棩鏈�鏃╂墦鍗℃椂闂�
+ //datas.summary_info.lastest_time int32 褰撴棩鏈�鏅氭墦鍗℃椂闂�
+ //datas.holiday_infos obj[] 鍋囧嫟鐩稿叧淇℃伅
+ //datas.holiday_infos.sp_number string 鍋囧嫟鐢宠id锛屽嵆褰撴棩鍏宠仈鐨勫亣鍕ゅ鎵瑰崟id
+ //datas.holiday_infos.sp_title obj 鍋囧嫟淇℃伅鎽樿-鏍囬淇℃伅
+ //datas.holiday_infos.sp_title.data obj[] 澶氱璇█鎻忚堪锛岀洰鍓嶅彧鏈変腑鏂囦竴绉�
+ //datas.holiday_infos.sp_title.data.text string 鍋囧嫟淇℃伅鎽樿-鏍囬鏂囨湰
+ //datas.holiday_infos.sp_title.data.lang string 璇█绫诲瀷锛�"zh_CN"
+ //datas.holiday_infos.sp_description obj 鍋囧嫟淇℃伅鎽樿-鎻忚堪淇℃伅
+ //datas.holiday_infos.sp_description.data obj[] 澶氱璇█鎻忚堪锛岀洰鍓嶅彧鏈変腑鏂囦竴绉�
+ //datas.holiday_infos.sp_description.data.text string 鍋囧嫟淇℃伅鎽樿-鎻忚堪鏂囨湰
+ //datas.holiday_infos.sp_description.data.lang string 璇█绫诲瀷锛�"zh_CN"
+ //datas.exception_infos obj[] 鏍″噯鐘舵�佷俊鎭�
+ //datas.exception_infos.exception uint32 鏍″噯鐘舵�佺被鍨嬶細1-杩熷埌锛�2-鏃╅��锛�3-缂哄崱锛�4-鏃峰伐锛�5-鍦扮偣寮傚父锛�6-璁惧寮傚父
+ //datas.exception_infos.count int32 褰撴棩姝ゅ紓甯哥殑娆℃暟
+ //datas.exception_infos.duration int32 褰撴棩姝ゅ紓甯哥殑鏃堕暱锛堣繜鍒�/鏃╅��/鏃峰伐鎵嶆湁鍊硷級
+ //datas.ot_info obj 鍔犵彮淇℃伅
+ //datas.ot_info.ot_status uint32 鐘舵�侊細0-鏃犲姞鐝紱1-姝e父锛�2-缂烘椂闀�
+ //datas.ot_info.ot_duration uint32 鍔犵彮鏃堕暱
+ //datas.ot_info.exception_duration uint32[] ot_status涓�2涓嬶紝鍔犵彮涓嶈冻鐨勬椂闀�
+ //datas.ot_info.workday_over_as_vacation int32 宸ヤ綔鏃ュ姞鐝涓鸿皟浼戯紝鍗曚綅绉�
+ //datas.ot_info.workday_over_as_money int32 宸ヤ綔鏃ュ姞鐝涓哄姞鐝垂锛屽崟浣嶇
+ //datas.ot_info.restday_over_as_vacation int32 浼戞伅鏃ュ姞鐝涓鸿皟浼戯紝鍗曚綅绉�
+ //datas.ot_info.restday_over_as_money int32 浼戞伅鏃ュ姞鐝涓哄姞鐝垂锛屽崟浣嶇
+ //datas.ot_info.holiday_over_as_vacation int32 鑺傚亣鏃ュ姞鐝涓鸿皟浼戯紝鍗曚綅绉�
+ //datas.ot_info.holiday_over_as_money int32 鑺傚亣鏃ュ姞鐝涓哄姞鐝垂锛屽崟浣嶇
+ //datas.sp_items obj[] 鍋囧嫟缁熻淇℃伅
+ //datas.sp_items.type uint32 绫诲瀷锛�1-璇峰亣锛�2-琛ュ崱锛�3-鍑哄樊锛�4-澶栧嚭锛�15-瀹℃壒鎵撳崱锛�100-澶栧嫟
+ //datas.sp_items.vacation_id uint32 鍏蜂綋璇峰亣绫诲瀷锛屽綋type涓�1璇峰亣鏃讹紝鍏蜂綋鐨勮鍋囩被鍨媔d锛屽彲閫氳繃瀹℃壒鐩稿叧鎺ュ彛鑾峰彇鍋囨湡璇︽儏
+ //datas.sp_items.count uint32 褰撴棩鍋囧嫟娆℃暟
+ //datas.sp_items.duration uint32 褰撴棩鍋囧嫟鏃堕暱绉掓暟锛屾椂闀垮崟浣嶄负澶╃洿鎺ラ櫎浠�86400鍗充负澶╂暟锛屽崟浣嶄负灏忔椂鐩存帴闄や互3600鍗充负灏忔椂鏁�
+ //datas.sp_items.time_type uint32 鏃堕暱鍗曚綅锛�0-鎸夊ぉ 1-鎸夊皬鏃�
+ //datas.sp_items.name string 缁熻椤瑰悕绉�
+
@Data
private static class WorkWXTokenResponse {
private Integer errcode;
@@ -371,6 +658,144 @@
private List<CheckinData> checkindata;
}
+ // ==================== 鎵撳崱鏃ユ姤鏁版嵁鍝嶅簲缁撴瀯 ====================
+
+ @Data
+ private static class WorkWXCheckinDayDataResponse {
+ private Integer errcode;
+ private String errmsg;
+ private List<CheckinDayData> datas;
+ }
+
+ @Data
+ public static class CheckinDayData {
+ @JsonProperty("base_info")
+ private BaseInfo baseInfo;
+ @JsonProperty("summary_info")
+ private SummaryInfo summaryInfo;
+ @JsonProperty("holiday_infos")
+ private List<HolidayInfo> holidayInfos;
+ @JsonProperty("exception_infos")
+ private List<ExceptionInfo> exceptionInfos;
+ @JsonProperty("ot_info")
+ private OtInfo otInfo;
+ @JsonProperty("sp_items")
+ private List<SpItem> spItems;
+ }
+
+ @Data
+ public static class BaseInfo {
+ private Long date;
+ @JsonProperty("record_type")
+ private Integer recordType;
+ private String name;
+ @JsonProperty("name_ex")
+ private String nameEx;
+ @JsonProperty("departs_name")
+ private String departsName;
+ private String acctid;
+ @JsonProperty("rule_info")
+ private RuleInfo ruleInfo;
+ @JsonProperty("day_type")
+ private Integer dayType;
+ }
+
+ @Data
+ public static class RuleInfo {
+ private Integer groupid;
+ private String groupname;
+ private Integer scheduleid;
+ private String schedulename;
+ private List<CheckinTime> checkintime;
+ }
+
+ @Data
+ @com.fasterxml.jackson.annotation.JsonIgnoreProperties(ignoreUnknown = true)
+ public static class CheckinTime {
+ @JsonProperty("work_sec")
+ private Integer workSec;
+ @JsonProperty("off_work_sec")
+ private Integer offWorkSec;
+ }
+
+ @Data
+ public static class SummaryInfo {
+ @JsonProperty("checkin_count")
+ private Integer checkinCount;
+ @JsonProperty("regular_work_sec")
+ private Integer regularWorkSec;
+ @JsonProperty("standard_work_sec")
+ private Integer standardWorkSec;
+ @JsonProperty("earliest_time")
+ private Integer earliestTime;
+ @JsonProperty("lastest_time")
+ private Integer lastestTime;
+ }
+
+ @Data
+ public static class HolidayInfo {
+ @JsonProperty("sp_number")
+ private String spNumber;
+ @JsonProperty("sp_title")
+ private LangData spTitle;
+ @JsonProperty("sp_description")
+ private LangData spDescription;
+ }
+
+ @Data
+ public static class LangData {
+ private List<LangText> data;
+ }
+
+ @Data
+ public static class LangText {
+ private String lang;
+ private String text;
+ }
+
+ @Data
+ public static class ExceptionInfo {
+ private Integer exception; // 1-杩熷埌锛�2-鏃╅��锛�3-缂哄崱锛�4-鏃峰伐锛�5-鍦扮偣寮傚父锛�6-璁惧寮傚父
+ private Integer count;
+ private Integer duration;
+ }
+
+ @Data
+ public static class OtInfo {
+ @JsonProperty("ot_status")
+ private Integer otStatus; // 0-鏃犲姞鐝紱1-姝e父锛�2-缂烘椂闀�
+ @JsonProperty("ot_duration")
+ private Integer otDuration;
+ @JsonProperty("exception_duration")
+ private List<Integer> exceptionDuration;
+ @JsonProperty("workday_over_as_vacation")
+ private Integer workdayOverAsVacation;
+ @JsonProperty("workday_over_as_money")
+ private Integer workdayOverAsMoney;
+ @JsonProperty("restday_over_as_vacation")
+ private Integer restdayOverAsVacation;
+ @JsonProperty("restday_over_as_money")
+ private Integer restdayOverAsMoney;
+ @JsonProperty("holiday_over_as_vacation")
+ private Integer holidayOverAsVacation;
+ @JsonProperty("holiday_over_as_money")
+ private Integer holidayOverAsMoney;
+ }
+
+ @Data
+ public static class SpItem {
+ private Integer type; // 1-璇峰亣锛�2-琛ュ崱锛�3-鍑哄樊锛�4-澶栧嚭锛�15-瀹℃壒鎵撳崱锛�100-澶栧嫟
+ @JsonProperty("vacation_id")
+ private Integer vacationId;
+ private Integer count;
+ private Integer duration;
+ @JsonProperty("time_type")
+ private Integer timeType; // 0-鎸夊ぉ 1-鎸夊皬鏃�
+ private String name;
+ }
+
+ // ==================== 鎵撳崱鍘熷鏁版嵁缁撴瀯 ====================
+
@Data
public static class CheckinData {
private String userid;
@@ -400,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("姝e湪鑾峰彇绗� {}/{} 鎵硅澶囨墦鍗℃暟鎹紝鐢ㄦ埛鏁�: {}", i + 1, batchCount, batchUserList.size());
+
+ Map<String, Object> requestBody = new HashMap<>();
+ requestBody.put("filter_type", 1); // 1琛ㄧず鎸塽serid杩囨护
+ 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("鑾峰彇璁惧鎵撳崱鏁版嵁澶辫触锛孒TTP鐘舵�佺爜: {}", 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琛ㄤ腑娌℃湁鏈夋晥鐨刟ccount鏁版嵁");
+ return new ArrayList<>();
+ }
+
+ log.info("浠嶲W_STAFF琛ㄨ幏鍙栧埌 {} 涓敤鎴穉ccount", useridList.size());
+ return getHardwareCheckinData(startTime, endTime, useridList);
+ }
}
--
Gitblit v1.9.3