# 物流链接自动填充 - 多字段更新功能 ## ✅ 新功能说明 在成功匹配订单并写入物流链接的同时,自动更新以下三个字段: | 字段 | 写入内容 | 说明 | |------|----------|------| | **物流单号** | 物流链接 URL | 从数据库中查询到的物流链接 | | **是否安排** | `2` | 固定值,表示已安排 | | **标记** | 当天日期 | 格式:`yyMMdd`(如:`251105`) | --- ## 🎯 实现效果 ### 修改前(只更新一个字段) ``` 写入物流链接 - 单元格: M3, 单号: JY2025110329041 ``` **表格更新**: | 行 | 单号 | ... | 物流单号 | 是否安排 | 标记 | |----|------|-----|----------|----------|------| | 3 | JY2025110329041 | ... | ✅ https://... | (空) | (空) | --- ### 修改后(同时更新三个字段) ``` 成功写入数据 - 行: 3, 单号: JY2025110329041, 物流链接: https://3.cn/2ume-Ak1, 是否安排: 2, 标记: 251105 ``` **表格更新**: | 行 | 单号 | ... | 物流单号 | 是否安排 | 标记 | |----|------|-----|----------|----------|------| | 3 | JY2025110329041 | ... | ✅ https://... | ✅ 2 | ✅ 251105 | --- ## 🔧 技术实现 ### 1. 自动识别列位置 在读取表头时,自动识别所有相关列: ```java // 查找所有相关列 for (int i = 0; i < headerRowData.size(); i++) { String cellValue = headerRowData.getString(i); if (cellValue != null) { String cellValueTrim = cellValue.trim(); // 识别"单号"列 if (orderNoColumn == null && cellValueTrim.contains("单号")) { orderNoColumn = i; } // 识别"物流单号"列 if (logisticsLinkColumn == null && (cellValueTrim.contains("物流单号") || cellValueTrim.contains("物流链接"))) { logisticsLinkColumn = i; } // 识别"是否安排"列 if (arrangedColumn == null && cellValueTrim.contains("是否安排")) { arrangedColumn = i; } // 识别"标记"列 if (markColumn == null && cellValueTrim.contains("标记")) { markColumn = i; } } } ``` **识别结果示例**: ``` 识别到 '单号' 列:第 3 列(索引2) 识别到 '物流单号' 列:第 13 列(索引12) 识别到 '是否安排' 列:第 12 列(索引11) 识别到 '标记' 列:第 15 列(索引14) ``` --- ### 2. 获取当前日期 使用 `SimpleDateFormat` 格式化当前日期: ```java // 获取今天的日期,格式:yyMMdd(如:251105) String today = new java.text.SimpleDateFormat("yyMMdd").format(new java.util.Date()); ``` **日期格式示例**: | 日期 | 格式化结果 | |------|-----------| | 2025年11月5日 | `251105` | | 2025年11月1日 | `251101` | | 2025年12月31日 | `251231` | --- ### 3. 使用 batchUpdate 一次性更新多个字段 使用腾讯文档的 `batchUpdate` API,在一个请求中更新同一行的多个单元格: ```java // 使用 batchUpdate 一次性更新多个字段 JSONArray requests = new JSONArray(); // 1. 更新物流单号 requests.add(buildUpdateCellRequest(sheetId, row - 1, logisticsLinkColumn, logisticsLink)); // 2. 更新"是否安排"列(如果存在) if (arrangedColumn != null) { requests.add(buildUpdateCellRequest(sheetId, row - 1, arrangedColumn, "2")); } // 3. 更新"标记"列(如果存在) if (markColumn != null) { requests.add(buildUpdateCellRequest(sheetId, row - 1, markColumn, today)); } // 构建完整的 batchUpdate 请求体 JSONObject batchUpdateBody = new JSONObject(); batchUpdateBody.put("requests", requests); // 调用 batchUpdate API tencentDocService.batchUpdate(accessToken, fileId, batchUpdateBody); ``` --- ### 4. buildUpdateCellRequest 辅助方法 构建单个单元格的更新请求: ```java private JSONObject buildUpdateCellRequest(String sheetId, int rowIndex, int columnIndex, String value) { // 构建 updateRangeRequest JSONObject updateRangeRequest = new JSONObject(); updateRangeRequest.put("sheetId", sheetId); // 构建 gridData JSONObject gridData = new JSONObject(); gridData.put("startRow", rowIndex); gridData.put("startColumn", columnIndex); // 构建 rows 数组 JSONArray rows = new JSONArray(); JSONObject rowData = new JSONObject(); JSONArray cellValues = new JSONArray(); // 构建单元格数据 JSONObject cellData = new JSONObject(); JSONObject cellValue = new JSONObject(); cellValue.put("text", value); cellData.put("cellValue", cellValue); cellValues.add(cellData); rowData.put("values", cellValues); rows.add(rowData); gridData.put("rows", rows); updateRangeRequest.put("gridData", gridData); // 包装为 request 对象 JSONObject request = new JSONObject(); request.put("updateRangeRequest", updateRangeRequest); return request; } ``` --- ## 📊 完整的 batchUpdate 请求示例 ### 请求体结构 ```json { "requests": [ { "updateRangeRequest": { "sheetId": "BB08J2", "gridData": { "startRow": 2, "startColumn": 12, "rows": [ { "values": [ { "cellValue": { "text": "https://3.cn/2ume-Ak1" } } ] } ] } } }, { "updateRangeRequest": { "sheetId": "BB08J2", "gridData": { "startRow": 2, "startColumn": 11, "rows": [ { "values": [ { "cellValue": { "text": "2" } } ] } ] } } }, { "updateRangeRequest": { "sheetId": "BB08J2", "gridData": { "startRow": 2, "startColumn": 14, "rows": [ { "values": [ { "cellValue": { "text": "251105" } } ] } ] } } } ] } ``` **说明**: - 第1个请求:更新第3行(索引2)、第13列(索引12)- 物流单号 - 第2个请求:更新第3行(索引2)、第12列(索引11)- 是否安排 - 第3个请求:更新第3行(索引2)、第15列(索引14)- 标记 --- ## 🔄 处理流程 ``` 1. 读取表头 ├─ 识别"单号"列(必需) ├─ 识别"物流单号"列(必需) ├─ 识别"是否安排"列(可选) └─ 识别"标记"列(可选) 2. 读取数据行 3. 逐行处理 ├─ 提取单号 ├─ 查询数据库 └─ 如果找到订单和物流链接 ├─ 构建 updateRangeRequest(物流单号) ├─ 构建 updateRangeRequest(是否安排 = "2")- 如果列存在 ├─ 构建 updateRangeRequest(标记 = 当天日期)- 如果列存在 └─ 调用 batchUpdate API 一次性更新 4. 返回统计结果 ``` --- ## 📝 新增方法清单 ### Controller 层(TencentDocController.java) | 方法名 | 说明 | |--------|------| | `buildUpdateCellRequest` | 构建单个单元格的更新请求 | **修改内容**: - ✅ 识别"是否安排"列和"标记"列 - ✅ 获取当前日期(`yyMMdd` 格式) - ✅ 使用 `batchUpdate` 一次性更新多个字段 --- ### Service 层(ITencentDocService.java / TencentDocServiceImpl.java) | 方法名 | 说明 | |--------|------| | `batchUpdate` | 批量更新表格的接口方法 | **接口定义**: ```java /** * 批量更新表格(batchUpdate API) * * @param accessToken 访问令牌 * @param fileId 文件ID * @param requestBody batchUpdate 请求体,包含 requests 数组 * @return 更新结果 */ JSONObject batchUpdate(String accessToken, String fileId, JSONObject requestBody); ``` --- ### Util 层(TencentDocApiUtil.java) | 方法名 | 说明 | |--------|------| | `batchUpdate` | 调用腾讯文档 batchUpdate API 的静态方法 | **方法签名**: ```java public static JSONObject batchUpdate( String accessToken, String appId, String openId, String fileId, JSONObject requestBody, String apiBaseUrl ) ``` --- ## 🧪 测试验证 ### 测试请求 ```bash curl -X POST 'http://localhost:30313/jarvis/tencentDoc/fillLogisticsByOrderNo' \ -H 'Content-Type: application/json' \ -d '{ "accessToken": "YOUR_ACCESS_TOKEN", "fileId": "DUW50RUprWXh2TGJK", "sheetId": "BB08J2", "headerRow": 2 }' ``` ### 预期日志 ``` 识别到 '单号' 列:第 3 列(索引2) 识别到 '物流单号' 列:第 13 列(索引12) 识别到 '是否安排' 列:第 12 列(索引11) 识别到 '标记' 列:第 15 列(索引14) 找到订单物流链接 - 单号: JY2025110329041, 物流链接: https://3.cn/2ume-Ak1, 行号: 3 批量更新表格(batchUpdate)- fileId: DUW50RUprWXh2TGJK, requests数量: 3 成功写入数据 - 行: 3, 单号: JY2025110329041, 物流链接: https://3.cn/2ume-Ak1, 是否安排: 2, 标记: 251105 ``` ### 预期结果 **返回 JSON**: ```json { "msg": "填充物流链接完成", "code": 200, "data": { "filledCount": 45, "skippedCount": 3, "errorCount": 0, "message": "处理完成:成功填充 45 条,跳过 3 条,错误 0 条" } } ``` **表格变化**: | 单号 | 物流单号 | 是否安排 | 标记 | |------|----------|----------|------| | JY2025110329041 | ✅ https://3.cn/2ume-Ak1 | ✅ 2 | ✅ 251105 | --- ## ⚠️ 注意事项 ### 1. 列必须存在 - **必需列**:单号、物流单号 - **可选列**:是否安排、标记 如果表头中没有"是否安排"或"标记"列,系统会跳过这些字段的更新,不会报错。 ### 2. 日期格式 日期格式固定为 `yyMMdd`: - 年份:2位数(如 `25` = 2025年) - 月份:2位数(如 `11` = 11月) - 日期:2位数(如 `05` = 5日) ### 3. API 调用次数 使用 `batchUpdate` 可以在一个请求中更新多个单元格,减少 API 调用次数: **修改前**:每行调用1次 API(只更新物流单号) **修改后**:每行仍然调用1次 API(但一次更新3个字段) ✅ **API 调用次数不变,但更新的字段更多!** --- ## 📚 相关官方文档 - [批量更新接口(batchUpdate)](https://docs.qq.com/open/document/app/openapi/v3/sheet/batchupdate/update.html) - [UpdateRangeRequest 说明](https://docs.qq.com/open/document/app/openapi/v3/sheet/batchupdate/request.html#updaterangerequest) --- ## ✅ 总结 ### 功能增强 1. ✅ **自动识别更多列**:单号、物流单号、是否安排、标记 2. ✅ **一次性更新多个字段**:物流单号 + 是否安排 + 标记 3. ✅ **自动填充日期**:标记列自动填入当天日期(`yyMMdd` 格式) 4. ✅ **状态标记**:"是否安排"列自动填入 `2` ### 技术优势 - ✅ 使用 `batchUpdate` API 一次性更新多个字段 - ✅ API 调用次数不变,效率更高 - ✅ 代码结构清晰,易于维护 - ✅ 兼容性好:如果列不存在,自动跳过,不影响主流程 --- **文档版本**:1.0 **创建时间**:2025-11-05 **功能状态**:✅ 已实现