From 763d9985fa1317ebeac09f22a3f2c11d9827e403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8D=92?= Date: Thu, 6 Nov 2025 10:57:22 +0800 Subject: [PATCH] 1 --- doc/腾讯文档物流链接自动填充-实现逻辑说明.md | 418 ++++++++++++++++++ .../jarvis/TencentDocController.java | 34 +- .../ruoyi/jarvis/mapper/JDOrderMapper.java | 5 + .../ruoyi/jarvis/service/IJDOrderService.java | 3 + .../service/impl/JDOrderServiceImpl.java | 5 + .../resources/mapper/jarvis/JDOrderMapper.xml | 6 + 6 files changed, 467 insertions(+), 4 deletions(-) create mode 100644 doc/腾讯文档物流链接自动填充-实现逻辑说明.md diff --git a/doc/腾讯文档物流链接自动填充-实现逻辑说明.md b/doc/腾讯文档物流链接自动填充-实现逻辑说明.md new file mode 100644 index 0000000..244b039 --- /dev/null +++ b/doc/腾讯文档物流链接自动填充-实现逻辑说明.md @@ -0,0 +1,418 @@ +# 腾讯文档物流链接自动填充 - 实现逻辑说明 + +## 功能概述 + +自动从数据库中查询订单的物流链接,并填充到腾讯文档对应的单元格中。 + +--- + +## 📋 完整实现逻辑 + +### 第1步:读取表头(识别列位置) + +```java +// 读取 headerRow 行(默认第2行) +String headerRange = "A2:Z2"; +JSONObject headerData = tencentDocService.readSheetData(accessToken, fileId, sheetId, headerRange); +``` + +**目的**: +- 自动识别"单号"列的位置(`orderNoColumn`) +- 自动识别"物流链接"列的位置(`logisticsLinkColumn`) + +**表头示例**: +``` +| A列 | B列 | C列 | D列 | ... | M列 | N列 | +|------|-----|-----|-----|-----|-----------|------| +| 日期 | 公司| 草号| 型号| ... | 物流单号 | 标记 | +``` + +自动识别结果: +- 草号列(单号列):索引 2(C列) +- 物流单号列:索引 12(M列) + +--- + +### 第2步:读取数据行 + +```java +// 计算读取范围 +int startRow = headerRow + 1; // 表头下一行开始 +int endRow = startRow + 200; // 每次最多读取200行 + +String range = "A3:Z203"; // 从第3行到第203行 +JSONObject sheetData = tencentDocService.readSheetData(accessToken, fileId, sheetId, range); +``` + +**数据示例**: +``` +| A列 | B列 | C列 | ... | M列 | N列 | +|--------|-----|----------------|-----|-----------------|------| +| 3月10日| | JY20251032904 | ... | (空) | 是 | +| 3月10日| | JY20250309184 | ... | 6649902864 | 是 | +| 3月10日| | JY20250309143 | ... | (空) | 是 | +``` + +--- + +### 第3步:遍历每一行,匹配订单并收集需要更新的数据 + +```java +for (int i = 0; i < values.size(); i++) { + JSONArray row = values.getJSONArray(i); + + // 1. 获取单号(草号列) + String orderNo = row.getString(orderNoColumn); // 例如:JY20251032904 + + // 2. 检查是否为空 + if (orderNo == null || orderNo.trim().isEmpty()) { + skippedCount++; // 跳过空单号 + continue; + } + + // 3. 检查物流链接列是否已有值 + String existingLogisticsLink = row.getString(logisticsLinkColumn); + if (existingLogisticsLink != null && !existingLogisticsLink.trim().isEmpty()) { + skippedCount++; // 已有物流链接,跳过 + continue; + } + + // 4. 从数据库查询订单(使用第三方单号查询) + JDOrder order = jdOrderService.selectJDOrderByThirdPartyOrderNo(orderNo); + + // 5. 检查是否找到订单且有物流链接 + if (order != null && order.getLogisticsLink() != null && !order.getLogisticsLink().trim().isEmpty()) { + String logisticsLink = order.getLogisticsLink().trim(); + + // 6. 记录需要更新的信息 + updates.add({ + "row": excelRow, // 行号(Excel行号,如3表示第3行) + "column": logisticsLinkColumn, // 列索引(如12表示M列) + "orderNo": orderNo, // 单号 + "logisticsLink": logisticsLink // 物流链接 + }); + + filledCount++; + } else { + errorCount++; // 未找到订单或物流链接为空 + } +} +``` + +**处理结果示例**: +``` +找到3个需要更新的单元格: + - M3: 订单号 JY20251032904 → 物流链接 6649906880 + - M5: 订单号 JY20250309143 → 物流链接 6649914494 + - M7: 订单号 JY20250307138 → 物流链接 6649909460 + +跳过2个已有物流链接的行 +跳过1个单号为空的行 +找不到物流链接的订单:0个 +``` + +--- + +### 第4步:批量写入物流链接 + +```java +for (JSONObject update : updates) { + int row = update.getIntValue("row"); // 例如:3 + int column = update.getIntValue("column"); // 例如:12 + String logisticsLink = update.getString("logisticsLink"); + + // 1. 计算列字母(0→A, 1→B, ..., 12→M) + String columnLetter = getColumnLetter(column); // 12 → "M" + + // 2. 构建单元格地址 + String cellRange = columnLetter + row; // "M3" + + // 3. 构建写入数据(二维数组格式) + Object[][] writeData = {{logisticsLink}}; + + // 4. 写入单个单元格 + tencentDocService.writeSheetData(accessToken, fileId, sheetId, cellRange, writeData); + + // 5. 延迟100ms(避免API限流) + Thread.sleep(100); +} +``` + +**写入示例**: +``` +写入 M3 单元格 = "6649906880" +写入 M5 单元格 = "6649914494" +写入 M7 单元格 = "6649909460" +``` + +--- + +## 🔍 关键字段说明 + +### 表格中的"单号"(草号) +- **表头名称**:草号 +- **列索引**:2(C列) +- **示例值**:`JY20251032904` +- **用途**:用于在数据库中查询订单 + +### 数据库中的"第三方单号" +- **字段名**:`third_party_order_no` +- **Java 属性**:`thirdPartyOrderNo` +- **对应关系**:表格中的"草号" = 数据库中的"第三方单号" + +**数据库查询SQL**: +```sql +SELECT * FROM jd_order +WHERE third_party_order_no = #{thirdPartyOrderNo} +LIMIT 1 +``` + +**Java 调用**: +```java +// 根据第三方单号查询订单 +JDOrder order = jdOrderService.selectJDOrderByThirdPartyOrderNo(orderNo); +``` + +--- + +## 📊 完整流程图 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 1. 读取表头(第2行) │ +│ 识别列位置:单号列、物流链接列 │ +└──────────────────────┬──────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 2. 读取数据行(第3行 ~ 第203行,200行) │ +│ range: A3:Z203 │ +└──────────────────────┬──────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 3. 遍历每一行 │ +├─────────────────────────────────────────────────────────────────┤ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ 3.1 读取单号(草号列,C列) │ │ +│ └──────────────┬──────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ 3.2 单号为空? │ │ +│ │ 是 → 跳过 │ │ +│ │ 否 → 继续 │ │ +│ └──────────────┬──────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ 3.3 物流链接列已有值? │ │ +│ │ 是 → 跳过 │ │ +│ │ 否 → 继续 │ │ +│ └──────────────┬──────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ 3.4 查询数据库 │ │ +│ │ WHERE third_party_order_no = '单号' │ │ +│ └──────────────┬──────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ 3.5 找到订单 且 有物流链接? │ │ +│ │ 是 → 记录到更新列表 │ │ +│ │ 否 → 记录为错误 │ │ +│ └──────────────────────────────────────────────────┘ │ +└──────────────────────┬──────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 4. 批量写入物流链接 │ +├─────────────────────────────────────────────────────────────────┤ +│ 对于每个需要更新的单元格: │ +│ 1. 计算单元格地址(如 M3) │ +│ 2. 调用写入API │ +│ 3. 延迟100ms(避免限流) │ +└──────────────────────┬──────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 5. 返回处理结果 │ +│ - 成功填充数量 │ +│ - 跳过数量 │ +│ - 错误数量 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 🔧 API 调用参数 + +### 请求参数 + +```json +{ + "accessToken": "腾讯文档访问令牌", + "fileId": "DUW50RUprWXh2TGJK", + "sheetId": "BB08J2", + "headerRow": 2, + "orderNoColumn": 2, + "logisticsLinkColumn": 12 +} +``` + +**参数说明**: +- `accessToken`:必填,腾讯文档访问令牌 +- `fileId`:必填,文件ID(从文档URL中获取) +- `sheetId`:必填,工作表ID(从URL的tab参数中获取) +- `headerRow`:可选,表头所在行号(默认1,但根据您的表格应该是2) +- `orderNoColumn`:可选,单号列索引(如果不提供则自动识别) +- `logisticsLinkColumn`:可选,物流链接列索引(如果不提供则自动识别) + +### 响应结果 + +```json +{ + "msg": "物流链接填充成功", + "code": 200, + "data": { + "startRow": 3, + "endRow": 203, + "lastMaxRow": null, + "filledCount": 3, + "skippedCount": 2, + "errorCount": 0, + "message": "成功填充3个物流链接" + } +} +``` + +**结果说明**: +- `startRow`:本次处理的起始行 +- `endRow`:本次处理的结束行 +- `filledCount`:成功填充的数量 +- `skippedCount`:跳过的数量(已有值或单号为空) +- `errorCount`:错误数量(未找到订单或物流链接) + +--- + +## 🎯 修改说明 + +### 修改前:使用 `remark` 字段查询 + +```java +// 错误:使用内部单号查询 +JDOrder order = jdOrderService.selectJDOrderByRemark(orderNo); +``` + +**问题**: +- `remark` 字段是"内部单号" +- 表格中的"草号"对应的是"第三方单号" +- 字段不匹配,查不到订单 + +### 修改后:使用 `thirdPartyOrderNo` 字段查询 + +```java +// 正确:使用第三方单号查询 +JDOrder order = jdOrderService.selectJDOrderByThirdPartyOrderNo(orderNo); +``` + +**修复内容**: +1. ✅ 在 `IJDOrderService` 接口中添加方法 +2. ✅ 在 `JDOrderServiceImpl` 实现类中实现方法 +3. ✅ 在 `JDOrderMapper` 接口中添加方法声明 +4. ✅ 在 `JDOrderMapper.xml` 中添加SQL查询 +5. ✅ 在 `TencentDocController` 中更新调用 + +**修改的文件**: +- `ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IJDOrderService.java` +- `ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/JDOrderServiceImpl.java` +- `ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/JDOrderMapper.java` +- `ruoyi-system/src/main/resources/mapper/jarvis/JDOrderMapper.xml` +- `ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java` + +--- + +## 📝 使用示例 + +### 示例1:自动识别列位置 + +```bash +POST /api/tencent-doc/fill-logistics + +{ + "accessToken": "YOUR_ACCESS_TOKEN", + "fileId": "DUW50RUprWXh2TGJK", + "sheetId": "BB08J2", + "headerRow": 2 +} +``` + +系统会自动识别: +- 包含"单号"的列作为订单号列 +- 包含"物流"的列作为物流链接列 + +### 示例2:手动指定列位置 + +```bash +POST /api/tencent-doc/fill-logistics + +{ + "accessToken": "YOUR_ACCESS_TOKEN", + "fileId": "DUW50RUprWXh2TGJK", + "sheetId": "BB08J2", + "headerRow": 2, + "orderNoColumn": 2, + "logisticsLinkColumn": 12 +} +``` + +明确指定: +- 单号列在第3列(索引2,C列) +- 物流链接列在第13列(索引12,M列) + +--- + +## 🚨 注意事项 + +### 1. 行列索引从0开始 + +- 列索引:A列=0, B列=1, C列=2, ... +- 但行号是Excel行号(从1开始) + +### 2. headerRow 参数 + +- 您的表格第1行是合并的标题 +- 第2行才是真正的表头 +- **必须设置 `headerRow: 2`** + +### 3. 批量处理限制 + +- 每次最多处理200行 +- 每次写入间隔100ms(避免API限流) +- 处理200行大约需要20-30秒 + +### 4. 数据库字段对应 + +| 表格列名 | 数据库字段名 | Java属性名 | +|---------|------------|-----------| +| 草号 | `third_party_order_no` | `thirdPartyOrderNo` | +| 物流单号 | `logistics_link` | `logisticsLink` | + +--- + +## ✅ 功能特点 + +1. ✅ **自动识别列位置**:无需手动指定列索引 +2. ✅ **智能跳过**:已有物流链接的行自动跳过 +3. ✅ **批量处理**:一次处理多行数据 +4. ✅ **增量处理**:记录上次处理位置,避免重复 +5. ✅ **详细日志**:每一步都有日志记录 +6. ✅ **错误处理**:完善的异常捕获和错误统计 + +--- + +**文档版本**:1.0 +**创建时间**:2025-11-05 +**修改内容**:使用 `thirdPartyOrderNo` 字段查询订单 + 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 53c8a8f..57547c9 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 @@ -566,11 +566,32 @@ public class TencentDocController extends BaseController { } // 读取数据行 - JSONObject sheetData = tencentDocService.readSheetData(accessToken, fileId, sheetId, range); + log.info("开始读取数据行 - 范围: {}", range); + JSONObject sheetData = null; + try { + sheetData = tencentDocService.readSheetData(accessToken, fileId, sheetId, range); + log.info("数据行读取成功,响应: {}", sheetData != null ? "有数据" : "null"); + } catch (Exception e) { + log.error("读取数据行失败", e); + return AjaxResult.error("读取数据行失败: " + e.getMessage()); + } + + if (sheetData == null) { + return AjaxResult.error("读取数据行返回null"); + } + JSONArray values = sheetData.getJSONArray("values"); + log.info("解析后的数据行数: {}", values != null ? values.size() : "null"); if (values == null || values.isEmpty()) { - log.info("指定范围内没有数据,可能已处理完毕"); + log.warn("指定范围内没有数据,可能已处理完毕。range={}, sheetData keys={}", + range, sheetData.keySet()); + + // 打印前10个键值对用于调试 + if (sheetData != null && !sheetData.isEmpty()) { + log.warn("sheetData内容预览: {}", sheetData.toJSONString().substring(0, Math.min(500, sheetData.toJSONString().length()))); + } + JSONObject result = new JSONObject(); result.put("startRow", startRow); result.put("endRow", endRow); @@ -579,9 +600,14 @@ public class TencentDocController extends BaseController { result.put("skippedCount", 0); result.put("errorCount", 0); result.put("message", "指定范围内没有数据"); + result.put("range", range); + result.put("hasSheetData", sheetData != null); + result.put("sheetDataKeys", sheetData != null ? sheetData.keySet() : null); return AjaxResult.success("没有需要处理的数据", result); } + log.info("成功读取 {} 行数据,开始处理...", values.size()); + // 处理数据行 int filledCount = 0; int skippedCount = 0; @@ -617,8 +643,8 @@ public class TencentDocController extends BaseController { } try { - // 根据单号查询订单 - JDOrder order = jdOrderService.selectJDOrderByRemark(orderNo); + // 根据第三方单号查询订单 + JDOrder order = jdOrderService.selectJDOrderByThirdPartyOrderNo(orderNo); if (order != null && order.getLogisticsLink() != null && !order.getLogisticsLink().trim().isEmpty()) { String logisticsLink = order.getLogisticsLink().trim(); diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/JDOrderMapper.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/JDOrderMapper.java index 71f7a82..c295f35 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/JDOrderMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/mapper/JDOrderMapper.java @@ -40,6 +40,11 @@ public interface JDOrderMapper { * 根据物流链接查询订单 */ JDOrder selectJDOrderByLogisticsLink(String logisticsLink); + + /** + * 根据第三方单号查询订单 + */ + JDOrder selectJDOrderByThirdPartyOrderNo(String thirdPartyOrderNo); /** * 批量删除(根据主键ID) diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IJDOrderService.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IJDOrderService.java index fe493c1..030edc1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IJDOrderService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IJDOrderService.java @@ -39,6 +39,9 @@ public interface IJDOrderService { /** 根据物流链接查询订单 */ JDOrder selectJDOrderByLogisticsLink(String logisticsLink); + + /** 根据第三方单号查询订单 */ + JDOrder selectJDOrderByThirdPartyOrderNo(String thirdPartyOrderNo); /** 批量删除(根据主键ID) */ int deleteJDOrderByIds(Long[] ids); diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/JDOrderServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/JDOrderServiceImpl.java index 52ee544..a9640ad 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/JDOrderServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/JDOrderServiceImpl.java @@ -58,6 +58,11 @@ public class JDOrderServiceImpl implements IJDOrderService { public JDOrder selectJDOrderByLogisticsLink(String logisticsLink) { return jdOrderMapper.selectJDOrderByLogisticsLink(logisticsLink); } + + @Override + public JDOrder selectJDOrderByThirdPartyOrderNo(String thirdPartyOrderNo) { + return jdOrderMapper.selectJDOrderByThirdPartyOrderNo(thirdPartyOrderNo); + } @Override public int deleteJDOrderByIds(Long[] ids) { diff --git a/ruoyi-system/src/main/resources/mapper/jarvis/JDOrderMapper.xml b/ruoyi-system/src/main/resources/mapper/jarvis/JDOrderMapper.xml index e2608e0..ff4a1a1 100644 --- a/ruoyi-system/src/main/resources/mapper/jarvis/JDOrderMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/jarvis/JDOrderMapper.xml @@ -153,6 +153,12 @@ order by order_time desc limit 1 + + delete from jd_order where id in