# 腾讯文档物流链接自动填充 - 实现逻辑说明 ## 功能概述 自动从数据库中查询订单的物流链接,并填充到腾讯文档对应的单元格中。 --- ## 📋 完整实现逻辑 ### 第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` 字段查询订单