This commit is contained in:
2025-11-06 17:53:16 +08:00
parent 6768fa5061
commit 99d64022dd
3 changed files with 192 additions and 8 deletions

View File

@@ -69,6 +69,7 @@ public class TencentDocConfigController extends BaseController {
// 2. 从Redis获取文档配置
String fileId = redisCache.getCacheObject(REDIS_KEY_PREFIX + "fileId");
String sheetId = redisCache.getCacheObject(REDIS_KEY_PREFIX + "sheetId");
Integer headerRow = redisCache.getCacheObject(REDIS_KEY_PREFIX + "headerRow");
Integer startRow = redisCache.getCacheObject(REDIS_KEY_PREFIX + "startRow");
// 如果Redis中没有则使用配置文件中的默认值
@@ -78,6 +79,9 @@ public class TencentDocConfigController extends BaseController {
if (sheetId == null || sheetId.isEmpty()) {
sheetId = tencentDocConfig.getSheetId();
}
if (headerRow == null) {
headerRow = tencentDocConfig.getHeaderRow();
}
if (startRow == null) {
startRow = tencentDocConfig.getStartRow();
}
@@ -86,6 +90,7 @@ public class TencentDocConfigController extends BaseController {
config.put("accessTokenStatus", accessTokenStatus);
config.put("fileId", fileId);
config.put("sheetId", sheetId);
config.put("headerRow", headerRow);
config.put("startRow", startRow);
config.put("appId", tencentDocConfig.getAppId());
config.put("apiBaseUrl", tencentDocConfig.getApiBaseUrl());
@@ -162,6 +167,7 @@ public class TencentDocConfigController extends BaseController {
try {
String fileId = params.getString("fileId");
String sheetId = params.getString("sheetId");
Integer headerRow = params.getInteger("headerRow");
Integer startRow = params.getInteger("startRow");
// 验证必填字段
@@ -172,6 +178,11 @@ public class TencentDocConfigController extends BaseController {
return AjaxResult.error("工作表ID不能为空");
}
// headerRow默认值为2
if (headerRow == null || headerRow < 1) {
headerRow = 2;
}
// startRow默认值为3
if (startRow == null || startRow < 1) {
startRow = 3;
@@ -193,6 +204,7 @@ public class TencentDocConfigController extends BaseController {
// 保存到Redis180天有效期
redisCache.setCacheObject(REDIS_KEY_PREFIX + "fileId", fileId.trim(), 180, TimeUnit.DAYS);
redisCache.setCacheObject(REDIS_KEY_PREFIX + "sheetId", sheetId.trim(), 180, TimeUnit.DAYS);
redisCache.setCacheObject(REDIS_KEY_PREFIX + "headerRow", headerRow, 180, TimeUnit.DAYS);
redisCache.setCacheObject(REDIS_KEY_PREFIX + "startRow", startRow, 180, TimeUnit.DAYS);
// 清除该文档的同步进度配置更新时重置进度从新的startRow重新开始
@@ -205,15 +217,17 @@ public class TencentDocConfigController extends BaseController {
// 同时更新TencentDocConfig对象内存中
tencentDocConfig.setFileId(fileId.trim());
tencentDocConfig.setSheetId(sheetId.trim());
tencentDocConfig.setHeaderRow(headerRow);
tencentDocConfig.setStartRow(startRow);
log.info("H-TF订单自动写入配置已更新 - fileId: {}, sheetId: {}, startRow: {}",
fileId.trim(), sheetId.trim(), startRow);
log.info("H-TF订单自动写入配置已更新 - fileId: {}, sheetId: {}, headerRow: {}, startRow: {}",
fileId.trim(), sheetId.trim(), headerRow, startRow);
JSONObject result = new JSONObject();
result.put("message", "配置更新成功已保存到Redis180天有效期");
result.put("fileId", fileId.trim());
result.put("sheetId", sheetId.trim());
result.put("headerRow", headerRow);
result.put("startRow", startRow);
result.put("hint", "现在录入分销标识为 H-TF 的订单时,将自动追加到此腾讯文档(从第" + startRow + "行开始匹配)");

View File

@@ -445,7 +445,164 @@ public class TencentDocController extends BaseController {
}
/**
* 根据单号填充物流链接 - 读取表格数据,根据单号查询订单系统中的物流链接,并填充到表格
* 直接填充单个订单的物流链接
*
* @param params 包含 thirdPartyOrderNo第三方单号和 logisticsLink物流链接
* @return 填充结果
*/
@PostMapping("/fillSingleLogistics")
public AjaxResult fillSingleLogistics(@RequestBody Map<String, Object> params) {
try {
// 1. 获取参数
String thirdPartyOrderNo = (String) params.get("thirdPartyOrderNo");
String logisticsLink = (String) params.get("logisticsLink");
if (thirdPartyOrderNo == null || thirdPartyOrderNo.isEmpty()) {
return AjaxResult.error("第三方单号不能为空");
}
if (logisticsLink == null || logisticsLink.isEmpty()) {
return AjaxResult.error("物流链接不能为空");
}
// 2. 获取访问令牌
String accessToken;
try {
accessToken = tencentDocTokenService.getValidAccessToken();
} catch (Exception e) {
return AjaxResult.error("访问令牌无效,请先完成授权");
}
// 3. 从配置中读取文档信息
final String CONFIG_KEY_PREFIX = "tencent:doc:auto:config:";
String fileId = redisCache.getCacheObject(CONFIG_KEY_PREFIX + "fileId");
String sheetId = redisCache.getCacheObject(CONFIG_KEY_PREFIX + "sheetId");
Integer headerRow = redisCache.getCacheObject(CONFIG_KEY_PREFIX + "headerRow");
Integer configStartRow = redisCache.getCacheObject(CONFIG_KEY_PREFIX + "startRow");
if (fileId == null || fileId.isEmpty()) {
fileId = tencentDocConfig.getFileId();
}
if (sheetId == null || sheetId.isEmpty()) {
sheetId = tencentDocConfig.getSheetId();
}
if (headerRow == null) {
headerRow = tencentDocConfig.getHeaderRow();
}
if (configStartRow == null) {
configStartRow = tencentDocConfig.getStartRow();
}
if (fileId == null || fileId.isEmpty() || sheetId == null || sheetId.isEmpty()) {
return AjaxResult.error("文档配置不完整,请先完成配置");
}
// 4. 读取表头(从配置的 headerRow 读取,与 startRow 独立)
String headerRange = String.format("A%d:Z%d", headerRow, headerRow);
JSONObject headerData = tencentDocService.readSheetData(accessToken, fileId, sheetId, headerRange);
if (headerData == null || !headerData.containsKey("gridData")) {
return AjaxResult.error("无法读取表头数据");
}
// 5. 解析表头,找到"单号"和"物流单号"列
JSONObject gridData = headerData.getJSONObject("gridData");
JSONArray rows = gridData.getJSONArray("rows");
if (rows == null || rows.isEmpty()) {
return AjaxResult.error("表头数据为空");
}
JSONObject headerRowData = rows.getJSONObject(0);
JSONArray headerCells = headerRowData.getJSONArray("values");
int orderNoColumn = -1;
int logisticsColumn = -1;
for (int i = 0; i < headerCells.size(); i++) {
JSONObject cell = headerCells.getJSONObject(i);
if (cell.containsKey("cellValue")) {
String cellText = cell.getJSONObject("cellValue").getString("text");
if (cellText != null) {
if (cellText.contains("单号")) {
orderNoColumn = i;
} else if (cellText.contains("物流")) {
logisticsColumn = i;
}
}
}
}
if (orderNoColumn == -1 || logisticsColumn == -1) {
return AjaxResult.error("未找到'单号'或'物流'列,请检查表头配置");
}
log.info("表头解析完成 - 单号列: {}, 物流列: {}", orderNoColumn, logisticsColumn);
// 6. 读取数据区域,查找指定单号
String dataRange = String.format("A%d:Z%d", configStartRow, configStartRow + 999);
JSONObject data = tencentDocService.readSheetData(accessToken, fileId, sheetId, dataRange);
if (data == null || !data.containsKey("gridData")) {
return AjaxResult.error("无法读取数据区域");
}
JSONObject dataGridData = data.getJSONObject("gridData");
JSONArray dataRows = dataGridData.getJSONArray("rows");
if (dataRows == null || dataRows.isEmpty()) {
return AjaxResult.error("数据区域为空");
}
// 7. 查找匹配的单号
int targetRow = -1;
for (int i = 0; i < dataRows.size(); i++) {
JSONObject row = dataRows.getJSONObject(i);
JSONArray cells = row.getJSONArray("values");
if (cells != null && cells.size() > orderNoColumn) {
JSONObject orderNoCell = cells.getJSONObject(orderNoColumn);
if (orderNoCell.containsKey("cellValue")) {
String cellText = orderNoCell.getJSONObject("cellValue").getString("text");
if (thirdPartyOrderNo.equals(cellText)) {
targetRow = configStartRow + i;
break;
}
}
}
}
if (targetRow == -1) {
return AjaxResult.error("未找到单号: " + thirdPartyOrderNo);
}
log.info("找到单号 {} 在第 {} 行", thirdPartyOrderNo, targetRow);
// 8. 写入物流链接
com.ruoyi.jarvis.util.TencentDocApiUtil.writeSheetData(
accessToken,
fileId,
sheetId,
String.format("%s%d", getColumnLetter(logisticsColumn), targetRow),
logisticsLink,
tencentDocConfig.getAppId(),
tencentDocConfig.getApiBaseUrl()
);
JSONObject result = new JSONObject();
result.put("thirdPartyOrderNo", thirdPartyOrderNo);
result.put("logisticsLink", logisticsLink);
result.put("row", targetRow);
result.put("column", logisticsColumn);
return AjaxResult.success("物流链接填充成功", result);
} catch (Exception e) {
log.error("填充物流链接失败", e);
return AjaxResult.error("填充物流链接失败: " + e.getMessage());
}
}
/**
* 批量同步物流链接 - 读取表格数据,根据单号查询订单系统中的物流链接,并填充到表格
* 优化:记录上次处理的最大行数,每次从最大行数-100开始读取避免重复处理历史数据
* 自动获取和管理访问令牌点击同步时自动刷新token
*/
@@ -486,15 +643,17 @@ public class TencentDocController extends BaseController {
}
}
// 从配置中读取startRow数据起始行号)
// 从配置中读取表头行和数据起始行
Integer headerRow = redisCache.getCacheObject(CONFIG_KEY_PREFIX + "headerRow");
Integer configStartRow = redisCache.getCacheObject(CONFIG_KEY_PREFIX + "startRow");
if (headerRow == null) {
headerRow = tencentDocConfig.getHeaderRow();
}
if (configStartRow == null) {
configStartRow = tencentDocConfig.getStartRow();
}
// 表头行号 = 数据起始行 - 1例如数据从第3行开始表头在第2行
Integer headerRow = configStartRow != null ? configStartRow - 1 : 2;
// 可选参数是否强制从指定行开始如果为true则忽略Redis记录的最大行数
Boolean forceStart = params.get("forceStart") != null ?
Boolean.valueOf(params.get("forceStart").toString()) : false;

View File

@@ -50,7 +50,10 @@ public class TencentDocConfig {
/** 工作表IDH-TF订单的目标工作表ID */
private String sheetId;
/** 起始行号(从第几行开始搜索匹配单号默认为3即第3行开始为数据行 */
/** 表头行号(表头所在的行默认为2 */
private Integer headerRow = 2;
/** 起始行号数据开始的行从第几行开始搜索匹配单号默认为3 */
private Integer startRow = 3;
/**
@@ -154,6 +157,14 @@ public class TencentDocConfig {
this.sheetId = sheetId;
}
public Integer getHeaderRow() {
return headerRow;
}
public void setHeaderRow(Integer headerRow) {
this.headerRow = headerRow;
}
public Integer getStartRow() {
return startRow;
}