diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocConfigController.java index 832b093..28d84f0 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocConfigController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocConfigController.java @@ -90,6 +90,22 @@ public class TencentDocConfigController extends BaseController { config.put("appId", tencentDocConfig.getAppId()); config.put("apiBaseUrl", tencentDocConfig.getApiBaseUrl()); + // 获取当前同步进度(如果有配置) + if (fileId != null && !fileId.isEmpty() && sheetId != null && !sheetId.isEmpty()) { + String syncProgressKey = "tencent:doc:sync:last_row:" + fileId + ":" + sheetId; + Integer currentProgress = redisCache.getCacheObject(syncProgressKey); + if (currentProgress != null) { + config.put("currentProgress", currentProgress); + config.put("nextStartRow", currentProgress + 1); + config.put("progressHint", String.format("已同步到第 %d 行,下次将从第 %d 行继续", + currentProgress, currentProgress + 1)); + } else { + config.put("currentProgress", null); + config.put("nextStartRow", startRow); + config.put("progressHint", String.format("尚未开始同步,将从第 %d 行开始", startRow)); + } + } + // 检查配置是否完整 boolean isConfigured = hasAccessToken && fileId != null && !fileId.isEmpty() && @@ -157,6 +173,13 @@ public class TencentDocConfigController extends BaseController { redisCache.setCacheObject(REDIS_KEY_PREFIX + "sheetId", sheetId.trim(), 180, TimeUnit.DAYS); redisCache.setCacheObject(REDIS_KEY_PREFIX + "startRow", startRow, 180, TimeUnit.DAYS); + // 清除该文档的同步进度(配置更新时重置进度,从新的startRow重新开始) + String syncProgressKey = "tencent:doc:sync:last_row:" + fileId.trim() + ":" + sheetId.trim(); + String configVersionKey = "tencent:doc:sync:config_version:" + fileId.trim() + ":" + sheetId.trim(); + redisCache.deleteObject(syncProgressKey); + redisCache.deleteObject(configVersionKey); + log.info("配置已更新,已清除同步进度,将从第 {} 行重新开始同步", startRow); + // 同时更新TencentDocConfig对象(内存中) tencentDocConfig.setFileId(fileId.trim()); tencentDocConfig.setSheetId(sheetId.trim()); 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 0e7c01b..d2078c4 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 @@ -314,6 +314,7 @@ public class TencentDocController extends BaseController { return AjaxResult.error("上传物流信息失败: " + e.getMessage()); } } + /** * 将单个订单的物流信息追加到表格 @@ -501,29 +502,48 @@ public class TencentDocController extends BaseController { return AjaxResult.error("文档配置不完整,请先配置 fileId 和 sheetId"); } - log.info("同步物流配置 - fileId: {}, sheetId: {}, 数据起始行: {}, 表头行: {}", + log.info("同步物流配置 - fileId: {}, sheetId: {}, 配置起始行: {}, 表头行: {}", fileId, sheetId, configStartRow, headerRow); - // 生成Redis key,用于存储该文件的工作表的上次处理最大行数 + // 生成Redis key,用于存储该文件的工作表的动态处理进度 String redisKey = LAST_PROCESSED_ROW_KEY_PREFIX + fileId + ":" + sheetId; + // 生成配置版本key,用于检测配置是否被重新设置 + String configVersionKey = "tencent:doc:sync:config_version:" + fileId + ":" + sheetId; + String currentConfigVersion = configStartRow + "_" + headerRow; // 配置版本:起始行_表头行 - // 获取上次处理的最大行数 + // 检查配置是否被更新(如果配置版本变化,则重置动态进度) + String savedConfigVersion = redisCache.getCacheObject(configVersionKey); + if (savedConfigVersion == null || !savedConfigVersion.equals(currentConfigVersion)) { + // 配置已更新,清除旧的处理进度 + redisCache.deleteObject(redisKey); + redisCache.setCacheObject(configVersionKey, currentConfigVersion, 180, TimeUnit.DAYS); + log.info("检测到配置更新,重置同步进度 - 新配置版本: {}", currentConfigVersion); + } + + // 获取动态处理进度(上次处理到的最大行数) Integer lastMaxRow = null; if (!forceStart && redisCache.hasKey(redisKey)) { Object cacheObj = redisCache.getCacheObject(redisKey); if (cacheObj != null) { lastMaxRow = Integer.valueOf(cacheObj.toString()); + log.info("读取到上次处理进度 - 最大行: {}", lastMaxRow); } } - // 计算起始行:从上次最大行数-100开始,或者从强制指定的行开始,或者从表头下一行开始 + // 计算本次同步的起始行 int startRow; if (forceStartRow != null) { + // 强制指定行(手动指定) startRow = forceStartRow; - } else if (lastMaxRow != null && lastMaxRow > headerRow) { - startRow = Math.max(headerRow + 1, lastMaxRow - 100); // 从最大行数-100开始,但至少是表头下一行 + log.info("使用强制指定的起始行: {}", startRow); + } else if (lastMaxRow != null && lastMaxRow >= configStartRow) { + // 有上次进度,且大于等于配置的起始行,则从上次进度+1继续(增量同步) + startRow = lastMaxRow + 1; + log.info("继续上次进度,从第 {} 行开始(上次到 {} 行)", startRow, lastMaxRow); } else { - startRow = headerRow + 1; // 默认从表头下一行开始 + // 首次同步或配置被重置,使用配置的起始行 + startRow = configStartRow != null ? configStartRow : (headerRow + 1); + log.info("首次同步或配置已重置,从配置的起始行开始: {}", startRow); } // 计算读取范围:从起始行开始,读取足够多的行 @@ -799,18 +819,33 @@ public class TencentDocController extends BaseController { log.info("更新上次处理的最大行数 - 文件ID: {}, 工作表ID: {}, 最大行: {}", fileId, sheetId, currentMaxRow); } + // 计算下次同步的起始行 + int nextStartRow = currentMaxRow + 1; + JSONObject result = new JSONObject(); result.put("startRow", startRow); result.put("endRow", endRow); result.put("currentMaxRow", currentMaxRow); result.put("lastMaxRow", lastMaxRow); + result.put("nextStartRow", nextStartRow); result.put("filledCount", filledCount); result.put("skippedCount", skippedCount); result.put("errorCount", errorCount); result.put("orderNoColumn", orderNoColumn); result.put("logisticsLinkColumn", logisticsLinkColumn); - result.put("message", String.format("处理完成:成功填充 %d 条,跳过 %d 条,错误 %d 条,最大行号: %d", - filledCount, skippedCount, errorCount, currentMaxRow)); + + // 构建详细的提示信息 + String message = String.format( + "✓ 同步完成:成功填充 %d 条,跳过 %d 条,错误 %d 条\n" + + " 本次范围:第 %d-%d 行\n" + + " 当前进度:第 %d 行\n" + + " 下次将从第 %d 行继续(增量同步)", + filledCount, skippedCount, errorCount, + startRow, currentMaxRow, + currentMaxRow, + nextStartRow + ); + result.put("message", message); return AjaxResult.success("填充物流链接完成", result); } catch (Exception e) {