diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java index af73967..2143596 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java @@ -1789,117 +1789,168 @@ public class TencentDocController extends BaseController { return AjaxResult.error("无法识别表头列,请确保表头包含'单号'和'物流单号'列"); } - // 读取数据行 - String dataRange = String.format("A%d:Z%d", startRow, endRow); - log.info("读取数据范围: {}", dataRange); - - JSONObject dataResponse = tencentDocService.readSheetData(accessToken, fileId, sheetId, dataRange); - if (dataResponse == null || !dataResponse.containsKey("values")) { - return AjaxResult.error("读取数据失败"); - } - - JSONArray rows = dataResponse.getJSONArray("values"); - if (rows == null || rows.isEmpty()) { - return AjaxResult.error("数据为空"); - } - // 统计结果 int successCount = 0; int skippedCount = 0; int errorCount = 0; - // 处理每一行 - for (int rowIndex = 0; rowIndex < rows.size(); rowIndex++) { - JSONArray row = rows.getJSONArray(rowIndex); - if (row == null || row.size() <= Math.max(orderNoColumn, logisticsLinkColumn)) { - skippedCount++; - continue; - } + // 分批读取数据,每批200行(避免单次读取过多数据导致API限制) + final int BATCH_SIZE = 200; + int currentStartRow = startRow; + int totalBatches = (int) Math.ceil((double)(endRow - startRow + 1) / BATCH_SIZE); + int currentBatch = 0; + + log.info("开始分批处理,共 {} 批,每批 {} 行", totalBatches, BATCH_SIZE); + + while (currentStartRow <= endRow) { + currentBatch++; + int currentEndRow = Math.min(currentStartRow + BATCH_SIZE - 1, endRow); - int actualRow = startRow + rowIndex; - String logisticsLink = row.getString(logisticsLinkColumn); - String orderNoFromDoc = row.getString(orderNoColumn); + log.info("正在处理第 {}/{} 批:第 {} 行到第 {} 行", currentBatch, totalBatches, currentStartRow, currentEndRow); - // 跳过物流链接为空的行 - if (logisticsLink == null || logisticsLink.trim().isEmpty()) { - log.debug("跳过第 {} 行:物流链接为空", actualRow); - skippedCount++; - logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", null, actualRow, null, - "SKIPPED", "物流链接为空"); - continue; - } - - // 跳过单号为空的行 - if (orderNoFromDoc == null || orderNoFromDoc.trim().isEmpty()) { - log.debug("跳过第 {} 行:单号为空", actualRow); - skippedCount++; - logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", null, actualRow, logisticsLink, - "SKIPPED", "单号为空"); - continue; - } - - // 清理物流链接(去除空格、换行符、中文等) - logisticsLink = cleanLogisticsLink(logisticsLink); + // 读取当前批次的数据行 + String dataRange = String.format("A%d:Z%d", currentStartRow, currentEndRow); + log.info("读取数据范围: {}", dataRange); + JSONObject dataResponse = null; try { - // 通过物流链接查找订单 - JDOrder order = jdOrderService.selectJDOrderByLogisticsLink(logisticsLink); - - if (order == null) { - log.warn("未找到匹配的订单 - 行: {}, 物流链接: {}", actualRow, logisticsLink); - errorCount++; - logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", null, actualRow, logisticsLink, - "FAILED", "未找到匹配的订单"); + dataResponse = tencentDocService.readSheetData(accessToken, fileId, sheetId, dataRange); + } catch (Exception e) { + log.error("读取第 {} 批数据失败({} - {} 行)", currentBatch, currentStartRow, currentEndRow, e); + errorCount += (currentEndRow - currentStartRow + 1); + // 继续处理下一批 + currentStartRow = currentEndRow + 1; + continue; + } + + if (dataResponse == null || !dataResponse.containsKey("values")) { + log.warn("第 {} 批数据读取返回空({} - {} 行),跳过", currentBatch, currentStartRow, currentEndRow); + currentStartRow = currentEndRow + 1; + continue; + } + + JSONArray rows = dataResponse.getJSONArray("values"); + if (rows == null || rows.isEmpty()) { + log.info("第 {} 批数据为空({} - {} 行),跳过", currentBatch, currentStartRow, currentEndRow); + currentStartRow = currentEndRow + 1; + continue; + } + + log.info("第 {} 批读取到 {} 行数据", currentBatch, rows.size()); + + // 处理当前批次的每一行 + for (int rowIndex = 0; rowIndex < rows.size(); rowIndex++) { + JSONArray row = rows.getJSONArray(rowIndex); + if (row == null || row.size() <= Math.max(orderNoColumn, logisticsLinkColumn)) { + skippedCount++; continue; } - // 检查订单是否已有第三方单号(如果已有且与文档中的不同,跳过) - if (order.getThirdPartyOrderNo() != null && !order.getThirdPartyOrderNo().trim().isEmpty()) { - if (!order.getThirdPartyOrderNo().trim().equals(orderNoFromDoc.trim())) { - log.info("跳过第 {} 行:订单已有第三方单号且不同 - 现有: {}, 文档: {}", - actualRow, order.getThirdPartyOrderNo(), orderNoFromDoc); - skippedCount++; - logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", order.getRemark(), actualRow, logisticsLink, - "SKIPPED", "订单已有第三方单号且不同"); + int actualRow = currentStartRow + rowIndex; + // 确保不超过结束行 + if (actualRow > endRow) { + break; + } + + String logisticsLink = row.getString(logisticsLinkColumn); + String orderNoFromDoc = row.getString(orderNoColumn); + + // 跳过物流链接为空的行 + if (logisticsLink == null || logisticsLink.trim().isEmpty()) { + log.debug("跳过第 {} 行:物流链接为空", actualRow); + skippedCount++; + logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", null, actualRow, null, + "SKIPPED", "物流链接为空"); + continue; + } + + // 跳过单号为空的行 + if (orderNoFromDoc == null || orderNoFromDoc.trim().isEmpty()) { + log.debug("跳过第 {} 行:单号为空", actualRow); + skippedCount++; + logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", null, actualRow, logisticsLink, + "SKIPPED", "单号为空"); + continue; + } + + // 清理物流链接(去除空格、换行符、中文等) + logisticsLink = cleanLogisticsLink(logisticsLink); + + try { + // 通过物流链接查找订单 + JDOrder order = jdOrderService.selectJDOrderByLogisticsLink(logisticsLink); + + if (order == null) { + log.warn("未找到匹配的订单 - 行: {}, 物流链接: {}", actualRow, logisticsLink); + errorCount++; + logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", null, actualRow, logisticsLink, + "FAILED", "未找到匹配的订单"); continue; } - // 如果相同,继续执行(清除物流链接) - } - - // 更新订单的第三方单号 - order.setThirdPartyOrderNo(orderNoFromDoc.trim()); - int updateResult = jdOrderService.updateJDOrder(order); - - if (updateResult <= 0) { - log.error("更新订单失败 - 行: {}, 订单ID: {}, 单号: {}", - actualRow, order.getId(), order.getRemark()); - errorCount++; + + // 检查订单是否已有第三方单号(如果已有且与文档中的不同,跳过) + if (order.getThirdPartyOrderNo() != null && !order.getThirdPartyOrderNo().trim().isEmpty()) { + if (!order.getThirdPartyOrderNo().trim().equals(orderNoFromDoc.trim())) { + log.info("跳过第 {} 行:订单已有第三方单号且不同 - 现有: {}, 文档: {}", + actualRow, order.getThirdPartyOrderNo(), orderNoFromDoc); + skippedCount++; + logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", order.getRemark(), actualRow, logisticsLink, + "SKIPPED", "订单已有第三方单号且不同"); + continue; + } + // 如果相同,继续执行(清除物流链接) + } + + // 更新订单的第三方单号 + order.setThirdPartyOrderNo(orderNoFromDoc.trim()); + int updateResult = jdOrderService.updateJDOrder(order); + + if (updateResult <= 0) { + log.error("更新订单失败 - 行: {}, 订单ID: {}, 单号: {}", + actualRow, order.getId(), order.getRemark()); + errorCount++; + logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", order.getRemark(), actualRow, logisticsLink, + "FAILED", "更新订单失败"); + continue; + } + + log.info("✓ 更新订单成功 - 行: {}, 订单: {}, 第三方单号: {}", + actualRow, order.getRemark(), orderNoFromDoc); + + successCount++; + + // 记录成功日志 logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", order.getRemark(), actualRow, logisticsLink, - "FAILED", "更新订单失败"); - continue; + "SUCCESS", String.format("已将单号 %s 写入订单的第三方单号字段", orderNoFromDoc)); + + } catch (Exception e) { + log.error("处理第 {} 行失败", actualRow, e); + errorCount++; + logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", null, actualRow, logisticsLink, + "FAILED", "处理异常: " + e.getMessage()); } - log.info("✓ 更新订单成功 - 行: {}, 订单: {}, 第三方单号: {}", - actualRow, order.getRemark(), orderNoFromDoc); - - successCount++; - - // 记录成功日志 - logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", order.getRemark(), actualRow, logisticsLink, - "SUCCESS", String.format("已将单号 %s 写入订单的第三方单号字段", orderNoFromDoc)); - - } catch (Exception e) { - log.error("处理第 {} 行失败", actualRow, e); - errorCount++; - logOperation(batchId, fileId, sheetId, "REVERSE_SYNC", null, actualRow, logisticsLink, - "FAILED", "处理异常: " + e.getMessage()); + // 添加延迟,避免API调用频率过高 + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } } - // 添加延迟,避免API调用频率过高 - try { - Thread.sleep(100); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); + log.info("第 {}/{} 批处理完成,当前统计 - 成功: {}, 跳过: {}, 错误: {}", + currentBatch, totalBatches, successCount, skippedCount, errorCount); + + // 移动到下一批 + currentStartRow = currentEndRow + 1; + + // 批次之间的延迟,避免API调用频率过高 + if (currentStartRow <= endRow) { + try { + Thread.sleep(200); // 批次之间延迟200ms + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } } }