| src/main/java/com/ruoyi/framework/util/AliDingUtils.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/production/service/impl/ProductMaterialServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/productionPlan/service/impl/ProductionPlanServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/main/java/com/ruoyi/framework/util/AliDingUtils.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,173 @@ 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; /** * <br> * æ ¹æ®å®æè¡¨å ID è·åæ°æ® * </br> * * @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 <T> å®ä½ç±» * @return 对åºè¡¨åçæ°æ® */ public static <T> JSONArray getFormDataList(AliDingConfig aliDingConfig, String formUuid, String searchFieldJson, IService<T> service, SFunction<T, ?> 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 <T> LocalDateTime getLastSyncTime(IService<T> service, SFunction<T, ?> timeField) { LambdaQueryWrapper<T> 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); } } } src/main/java/com/ruoyi/production/service/impl/ProductMaterialServiceImpl.java
@@ -1,6 +1,5 @@ package com.ruoyi.production.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -8,8 +7,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.http.HttpUtils; import com.ruoyi.framework.config.AliDingConfig; import com.ruoyi.framework.util.AliDingUtils; import com.ruoyi.production.dto.ProductMaterialDto; import com.ruoyi.production.dto.ProductMaterialGroupDto; import com.ruoyi.production.enums.MaterialConfigTypeEnum; @@ -25,13 +24,11 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; 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; import java.util.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; @@ -85,92 +82,7 @@ } try { // è·å AccessToken String accessToken = getAccessToken(); if (StringUtils.isEmpty(accessToken)) { return; } // è·åæ¬å°æå忥æ¶é´ LocalDateTime lastSyncTime = getLastSyncTime(); log.info("å¼å§ç©æç¼ç å¢éåæ¥ï¼æ¬å°æåä¿®æ¹æ¶é´: {}", lastSyncTime); int pageNumber = 1; int pageSize = 50; boolean hasMore = true; int totalSynced = 0; while (hasMore) { // æ¥è¯¢åæ° JSONObject searchParam = buildSearchParam(lastSyncTime, pageNumber, pageSize); // è°ç¨å®ææ¥å£æåæ°æ® 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; } // è§£æå¹¶ä¿åæ°æ® List<ProductMaterialSku> list = parseProductMaterials(dataArr, totalCount); if (!list.isEmpty()) { // å¤çæ´æ°ææ°å¢ int affected = processSaveOrUpdate(list); totalSynced += affected; } // 夿æ¯å¦è¿æä¸ä¸é¡µ hasMore = (pageNumber * pageSize) < totalCount; pageNumber++; log.info("æ£å¨åæ¥ç¬¬ {} 页ï¼å½å已忥 {}/{}", pageNumber - 1, totalSynced, totalCount); } log.info("ç©ææ°æ®åæ¥å®æï¼å ±åæ¥ {} æ¡æ°æ®", totalSynced); } catch (Exception e) { log.error("åæ¥ç©æç¼ç å¼å¸¸", e); } finally { // éæ¾é syncLock.unlock(); } } private String getAccessToken() { 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; } private LocalDateTime getLastSyncTime() { LambdaQueryWrapper<ProductMaterialSku> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.orderByDesc(ProductMaterialSku::getFormModifiedTime).last("LIMIT 1"); ProductMaterialSku lastRecord = productMaterialSkuService.getOne(queryWrapper); return lastRecord != null ? lastRecord.getFormModifiedTime() : null; } private JSONObject buildSearchParam(LocalDateTime lastSyncTime, int pageNumber, int pageSize) { JSONObject searchParam = new JSONObject(); searchParam.put("appType", aliDingConfig.getAppType()); searchParam.put("systemToken", aliDingConfig.getSystemToken()); searchParam.put("userId", aliDingConfig.getUserId()); searchParam.put("formUuid", aliDingConfig.getMaterialCodeFormUuid()); searchParam.put("currentPage", pageNumber); searchParam.put("pageSize", pageSize); JSONArray searchConditions = new JSONArray(); JSONObject statusCondition = new JSONObject(); @@ -193,18 +105,29 @@ resultCondition.put("componentName", "SelectField"); searchConditions.add(resultCondition); searchParam.put("searchFieldJson", searchConditions.toJSONString()); searchParam.put("orderConfigJson", "{\"gmt_modified\":\"+\"}"); String searchFieldJson = searchConditions.toJSONString(); if (lastSyncTime != null) { String startTime = lastSyncTime.plusSeconds(1).atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); searchParam.put("modifiedFromTimeGMT", startTime); JSONArray dataArr = AliDingUtils.getFormDataList(aliDingConfig, aliDingConfig.getMaterialCodeFormUuid(), searchFieldJson, productMaterialSkuService, ProductMaterialSku::getFormModifiedTime); if (dataArr.isEmpty()) { log.info("æ²¡ææ´å¤æ°æ°æ®éè¦åæ¥"); return; } String endTime = LocalDateTime.now().atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); searchParam.put("modifiedToTimeGMT", endTime); // è§£æå¹¶ä¿åæ°æ® List<ProductMaterialSku> list = parseProductMaterials(dataArr, dataArr.size()); if (!list.isEmpty()) { // å¤çæ´æ°ææ°å¢ int affected = processSaveOrUpdate(list); log.info("ç©ææ°æ®åæ¥å®æï¼å ±åæ¥ {} æ¡æ°æ®", affected); } return searchParam; } catch (Exception e) { log.error("åæ¥ç©æç¼ç å¼å¸¸", e); } finally { // éæ¾é syncLock.unlock(); } } private List<ProductMaterialSku> parseProductMaterials(JSONArray dataArr, Integer totalCount) { @@ -241,7 +164,7 @@ sku.setSupplyType(formData.getString("selectField_la14k51j")); sku.setOriginatorName(originatorName); sku.setOriginatorOrg("å®å¤ä¸å绿è½å®ä¸é墿éå ¬å¸"); sku.setFormModifiedTime(parseUtcTime(item.getString("modifiedTimeGMT"))); sku.setFormModifiedTime(AliDingUtils.parseUtcTime(item.getString("modifiedTimeGMT"))); sku.setCreateTime(now); sku.setUpdateTime(now); @@ -332,19 +255,6 @@ } } return affected; } private 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; } } @Override src/main/java/com/ruoyi/productionPlan/service/impl/ProductionPlanServiceImpl.java
@@ -1,6 +1,5 @@ package com.ruoyi.productionPlan.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -12,10 +11,9 @@ import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.common.utils.http.HttpUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.config.AliDingConfig; import com.ruoyi.production.pojo.ProductMaterial; import com.ruoyi.framework.util.AliDingUtils; import com.ruoyi.production.pojo.ProductMaterialSku; import com.ruoyi.production.pojo.ProductOrder; import com.ruoyi.production.service.ProductMaterialService; @@ -38,10 +36,9 @@ import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.*; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; @@ -248,101 +245,6 @@ } try { // è·å AccessToken String accessToken = getAccessToken(); if (StringUtils.isEmpty(accessToken)) { return; } // è·åæ¬å°æå忥æ¶é´ LocalDateTime lastSyncTime = getLastSyncTime(); log.info("å¼å§å¢éåæ¥ï¼æ¬å°æåä¿®æ¹æ¶é´: {}", lastSyncTime); int pageNumber = 1; int pageSize = 50; boolean hasMore = true; int totalSynced = 0; while (hasMore) { // æ¥è¯¢åæ° JSONObject searchParam = buildSearchParam(lastSyncTime, pageNumber, pageSize); // è°ç¨å®ææ¥å£æåæ°æ® 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; } // è§£æå¹¶ä¿åæ°æ® List<ProductionPlan> list = parseProductionPlans(dataArr, dataSyncType, totalCount); if (!list.isEmpty()) { // å¤çæ´æ°ææ°å¢ int affected = processSaveOrUpdate(list); totalSynced += affected; } // 夿æ¯å¦è¿æä¸ä¸é¡µ hasMore = (pageNumber * pageSize) < totalCount; pageNumber++; log.info("æ£å¨åæ¥ç¬¬ {} 页ï¼å½å已忥 {}/{}", pageNumber - 1, totalSynced, totalCount); } log.info("æ°æ®åæ¥å®æï¼å ±åæ¥ {} æ¡æ°æ®", totalSynced); } catch (Exception e) { log.error("忥ç产计åå¼å¸¸", e); } finally { // éæ¾é syncLock.unlock(); } } private String getAccessToken() { 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; } private LocalDateTime getLastSyncTime() { // æ¥è¯¢æ¬å°æ°æ®åºä¸ formModifiedTime æå¤§çè®°å½ LambdaQueryWrapper<ProductionPlan> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.orderByDesc(ProductionPlan::getFormModifiedTime).last("LIMIT 1"); ProductionPlan lastRecord = this.getOne(queryWrapper); return lastRecord != null ? lastRecord.getFormModifiedTime() : null; } private JSONObject buildSearchParam(LocalDateTime lastSyncTime, int pageNumber, int pageSize) { JSONObject searchParam = new JSONObject(); searchParam.put("appType", aliDingConfig.getAppType()); searchParam.put("systemToken", aliDingConfig.getSystemToken()); searchParam.put("userId", aliDingConfig.getUserId()); searchParam.put("formUuid", aliDingConfig.getProducePlanFormUuid()); searchParam.put("currentPage", pageNumber); searchParam.put("pageSize", pageSize); JSONArray searchConditions = new JSONArray(); JSONObject condition = new JSONObject(); condition.put("key", "processApprovedResult"); @@ -355,26 +257,29 @@ condition.put("componentName", "SelectField"); searchConditions.add(condition); searchParam.put("searchFieldJson", searchConditions.toJSONString()); String searchFieldJson = searchConditions.toJSONString(); // é»è®¤æä¿®æ¹æ¶é´ååºæåºï¼ç¡®ä¿å页æåæ°æ®çè¿ç»æ§ // "+" 表示ååºï¼"gmt_modified" æ¯å®æ¹å ç½®åæ®µ searchParam.put("orderConfigJson", "{\"gmt_modified\":\"+\"}"); JSONArray dataArr = AliDingUtils.getFormDataList(aliDingConfig, aliDingConfig.getProducePlanFormUuid(), searchFieldJson, this, ProductionPlan::getFormModifiedTime); // è®¾ç½®ä¿®æ¹æ¶é´çéåºé´ (æ ¼å¼å¿ 须为yyyy-MM-dd HH:mm:ss) if (lastSyncTime != null) { // èµ·å§æ¶é´ï¼ä¸æ¬¡åæ¥å°çæå䏿¡æ°æ®çä¿®æ¹æ¶é´ String startTime = lastSyncTime.plusSeconds(1).atZone(ZoneId.systemDefault()) .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); searchParam.put("modifiedFromTimeGMT", startTime); if (dataArr.isEmpty()) { log.info("æ²¡ææ´å¤æ°æ°æ®éè¦åæ¥"); return; } // æªæ¢æ¶é´ï¼å½åæ¶é´ï¼ç¡®ä¿è·åææ°ç已修æ¹/å·²æ°å¢æ°æ® String endTime = LocalDateTime.now().atZone(ZoneId.systemDefault()) .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); searchParam.put("modifiedToTimeGMT", endTime); // è§£æå¹¶ä¿åæ°æ® List<ProductionPlan> list = parseProductionPlans(dataArr, dataSyncType, dataArr.size()); if (!list.isEmpty()) { // å¤çæ´æ°ææ°å¢ int affected = processSaveOrUpdate(list); log.info("æ°æ®åæ¥å®æï¼å ±åæ¥ {} æ¡æ°æ®", affected); } return searchParam; } catch (Exception e) { log.error("忥ç产计åå¼å¸¸", e); } finally { // éæ¾é syncLock.unlock(); } } private List<ProductionPlan> parseProductionPlans(JSONArray dataArr, Integer dataSyncType, Integer totalCount) { @@ -458,8 +363,8 @@ plan.setModifierName(modifyUser.getJSONObject("userName").getString("nameInChinese")); } plan.setFormCreatedTime(parseUtcTime(item.getString("createdTimeGMT"))); plan.setFormModifiedTime(parseUtcTime(item.getString("modifiedTimeGMT"))); plan.setFormCreatedTime(AliDingUtils.parseUtcTime(item.getString("createdTimeGMT"))); plan.setFormModifiedTime(AliDingUtils.parseUtcTime(item.getString("modifiedTimeGMT"))); plan.setDataSourceType(DataSourceTypeEnum.DING_TALK.getCode()); plan.setCreateTime(now); plan.setUpdateTime(now); @@ -513,19 +418,6 @@ } } return affected; } private 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; } } @Override