package com.ruoyi.framework.util; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.support.SFunction; import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.http.HttpUtils; import com.ruoyi.framework.config.AliDingConfig; import lombok.extern.slf4j.Slf4j; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; /** *
* 根据宜搭表单 ID 获取数据 *
* * @author deslrey * @version 1.0 * @since 2026/03/14 11:11 */ @Slf4j public class AliDingUtils { /** * 根据表单 ID 获取宜搭数据 * * @param aliDingConfig 钉钉宜搭接口配置 * @param formUuid 获取数据的表单ID * @param searchFieldJson 需要携带的查询条件 * @param service 获取最近表单更新的日期Service * @param timeField 表单修改日期 * @param 实体类 * @return 对应表单的数据 */ public static JSONArray getFormDataList(AliDingConfig aliDingConfig, String formUuid, String searchFieldJson, IService service, SFunction timeField) { // 获取 accessToken String accessToken = getAccessToken(aliDingConfig); // 获取最后同步时间 LocalDateTime lastSyncTime = getLastSyncTime(service, timeField); log.info("开始同步数据,本地最后修改时间: {}", lastSyncTime); JSONArray allData = new JSONArray(); int pageNumber = 1; int pageSize = 50; boolean hasMore = true; while (hasMore) { JSONObject searchParam = new JSONObject(); searchParam.put("appType", aliDingConfig.getAppType()); searchParam.put("systemToken", aliDingConfig.getSystemToken()); searchParam.put("userId", aliDingConfig.getUserId()); searchParam.put("formUuid", formUuid); searchParam.put("currentPage", pageNumber); searchParam.put("pageSize", pageSize); if (StringUtils.isNotEmpty(searchFieldJson)) { searchParam.put("searchFieldJson", searchFieldJson); } searchParam.put("orderConfigJson", "{\"gmt_modified\":\"+\"}"); if (lastSyncTime != null) { String startTime = lastSyncTime.plusSeconds(1) .atZone(ZoneId.systemDefault()) .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); searchParam.put("modifiedFromTimeGMT", startTime); } String endTime = LocalDateTime.now() .atZone(ZoneId.systemDefault()) .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); searchParam.put("modifiedToTimeGMT", endTime); String dataRes = HttpUtils.sendPostJson( aliDingConfig.getSearchFormDataUrl(), searchParam.toJSONString(), StandardCharsets.UTF_8.name(), null, accessToken ); if (StringUtils.isEmpty(dataRes)) { log.warn("第 {} 页拉取数据为空", pageNumber); break; } JSONObject resultObj = JSON.parseObject(dataRes); JSONArray dataArr = resultObj.getJSONArray("data"); Integer totalCount = resultObj.getInteger("totalCount"); if (dataArr == null || dataArr.isEmpty()) { log.info("没有更多新数据需要同步"); break; } allData.addAll(dataArr); hasMore = (pageNumber * pageSize) < totalCount; pageNumber++; log.info("正在提取宜搭分页数据,第 {} 页已处理,当前提取数: {}/{}", pageNumber - 1, allData.size(), totalCount); } return allData; } /** * 获取钉钉 AccessToken */ private static String getAccessToken(AliDingConfig aliDingConfig) { String params = "appkey=" + aliDingConfig.getAppKey() + "&appsecret=" + aliDingConfig.getAppSecret(); String tokenRes = HttpUtils.sendGet(aliDingConfig.getAccessTokenUrl(), params); JSONObject tokenObj = JSON.parseObject(tokenRes); String accessToken = tokenObj.getString("access_token"); if (StringUtils.isEmpty(accessToken)) { log.error("获取钉钉AccessToken失败: {}", tokenRes); } return accessToken; } /** * 日期格式化 * * @param utcString 日期 * @return LocalDateTime */ public static LocalDateTime parseUtcTime(String utcString) { if (StringUtils.isEmpty(utcString)) { return null; } try { OffsetDateTime odt = OffsetDateTime.parse(utcString); return odt.toLocalDateTime(); } catch (DateTimeParseException ex) { log.warn("解析时间 {} 失败: {}", utcString, ex.getMessage()); return null; } } private static LocalDateTime getLastSyncTime(IService service, SFunction timeField) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.orderByDesc(timeField).last("LIMIT 1"); T lastRecord = service.getOne(queryWrapper); if (lastRecord == null) { return null; } try { Method writeReplace = timeField.getClass().getDeclaredMethod("writeReplace"); writeReplace.setAccessible(true); SerializedLambda lambda = (SerializedLambda) writeReplace.invoke(timeField); // 获取方法名 String methodName = lambda.getImplMethodName(); // 转字段名 String fieldName = methodName.substring(3, 4).toLowerCase() + methodName.substring(4); Field field = lastRecord.getClass().getDeclaredField(fieldName); field.setAccessible(true); return (LocalDateTime) field.get(lastRecord); } catch (Exception e) { throw new RuntimeException("获取最后同步时间失败", e); } } }