# 腾讯文档 API Range 格式说明 ## 问题发现 在调用腾讯文档 V3 API 时,使用 Excel 格式的 range(如 `A3:Z203`)会返回错误: ```json { "code": 400001, "message": "invalid param error: 'range' invalid" } ``` ## ✅ 正确的 Range 格式 腾讯文档 V3 API 使用**索引格式**,不是 Excel 的字母+数字格式。 ### 格式规范 ``` startRow,startColumn,endRow,endColumn ``` **说明**: - 所有索引**从 0 开始** - 用逗号分隔四个值 - `startRow`:起始行索引 - `startColumn`:起始列索引 - `endRow`:结束行索引 - `endColumn`:结束列索引 --- ## 📋 格式转换示例 ### 示例 1:读取表头(第2行,A到Z列) **Excel 格式**(错误): ``` A2:Z2 ``` **索引格式**(正确): ``` 1,0,1,25 ``` **解释**: - 第2行 → 索引 1(行从0开始) - A列 → 索引 0 - 第2行 → 索引 1 - Z列 → 索引 25(A=0, B=1, ..., Z=25) --- ### 示例 2:读取数据行(第3行到第203行,A到Z列) **Excel 格式**(错误): ``` A3:Z203 ``` **索引格式**(正确): ``` 2,0,202,25 ``` **解释**: - 第3行 → 索引 2 - A列 → 索引 0 - 第203行 → 索引 202 - Z列 → 索引 25 --- ### 示例 3:读取单个单元格(M3) **Excel 格式**(错误): ``` M3 ``` **索引格式**(正确): ``` 2,12,2,12 ``` **解释**: - 第3行 → 索引 2 - M列 → 索引 12(A=0, ..., M=12) - 结束行也是第3行 → 索引 2 - 结束列也是M列 → 索引 12 --- ## 🔢 行列索引对照表 ### 行索引(Excel行号 → 索引) | Excel 行号 | 索引 | |-----------|------| | 1 | 0 | | 2 | 1 | | 3 | 2 | | ... | ... | | 100 | 99 | | 203 | 202 | **转换公式**:`索引 = Excel行号 - 1` ### 列索引(列字母 → 索引) | 列字母 | 索引 | |-------|------| | A | 0 | | B | 1 | | C | 2 | | D | 3 | | ... | ... | | M | 12 | | ... | ... | | Z | 25 | | AA | 26 | | AB | 27 | **转换公式**: - 单字母:`索引 = 字母 - 'A'`(A=0, B=1, ...) - 多字母:`索引 = (第一字母 - 'A' + 1) * 26 + (第二字母 - 'A')` --- ## 💻 代码实现 ### Java 转换方法 ```java /** * 将Excel行号转换为API索引 * @param excelRow Excel行号(从1开始) * @return API索引(从0开始) */ public static int excelRowToIndex(int excelRow) { return excelRow - 1; } /** * 将列字母转换为索引 * @param column 列字母(A, B, C, ..., Z, AA, AB, ...) * @return 列索引(从0开始) */ public static int columnLetterToIndex(String column) { column = column.toUpperCase(); int index = 0; for (int i = 0; i < column.length(); i++) { index = index * 26 + (column.charAt(i) - 'A' + 1); } return index - 1; } /** * 将Excel范围转换为API range格式 * @param excelRange Excel范围(如 "A3:Z203") * @return API range格式(如 "2,0,202,25") */ public static String excelRangeToApiRange(String excelRange) { // 解析 A3:Z203 String[] parts = excelRange.split(":"); String start = parts[0]; // A3 String end = parts[1]; // Z203 // 提取起始列和行 int startCol = columnLetterToIndex(start.replaceAll("\\d", "")); // A -> 0 int startRow = Integer.parseInt(start.replaceAll("[A-Z]", "")) - 1; // 3 -> 2 // 提取结束列和行 int endCol = columnLetterToIndex(end.replaceAll("\\d", "")); // Z -> 25 int endRow = Integer.parseInt(end.replaceAll("[A-Z]", "")) - 1; // 203 -> 202 return String.format("%d,%d,%d,%d", startRow, startCol, endRow, endCol); } ``` ### 使用示例 ```java // 读取表头(第2行) int headerRowIndex = headerRow - 1; // 2 -> 1 String headerRange = String.format("%d,0,%d,25", headerRowIndex, headerRowIndex); // 结果:"1,0,1,25" // 读取数据行(第3行到第203行) int startRowIndex = startRow - 1; // 3 -> 2 int endRowIndex = endRow - 1; // 203 -> 202 String dataRange = String.format("%d,0,%d,25", startRowIndex, endRowIndex); // 结果:"2,0,202,25" // 读取单个单元格(M3) int rowIndex = 2; // 第3行 -> 索引2 int colIndex = 12; // M列 -> 索引12 String cellRange = String.format("%d,%d,%d,%d", rowIndex, colIndex, rowIndex, colIndex); // 结果:"2,12,2,12" ``` --- ## 🔍 API 调用示例 ### 完整的 API URL ``` https://docs.qq.com/openapi/spreadsheet/v3/files/{fileId}/{sheetId}/{range} ``` **示例**: ``` # 读取表头(第2行) https://docs.qq.com/openapi/spreadsheet/v3/files/DUW50RUprWXh2TGJK/BB08J2/1,0,1,25 # 读取数据行(第3行到第203行) https://docs.qq.com/openapi/spreadsheet/v3/files/DUW50RUprWXh2TGJK/BB08J2/2,0,202,25 # 读取单个单元格(M3) https://docs.qq.com/openapi/spreadsheet/v3/files/DUW50RUprWXh2TGJK/BB08J2/2,12,2,12 ``` --- ## ⚠️ 常见错误 ### 错误 1:使用 Excel 格式 ``` ❌ https://.../ files/xxx/yyy/A3:Z203 ✅ https://.../files/xxx/yyy/2,0,202,25 ``` ### 错误 2:索引从 1 开始 ``` ❌ 第1行 → 索引 1 ✅ 第1行 → 索引 0 ❌ A列 → 索引 1 ✅ A列 → 索引 0 ``` ### 错误 3:行列顺序错误 ``` ❌ startColumn,startRow,endColumn,endRow ✅ startRow,startColumn,endRow,endColumn ``` 正确顺序:**行在前,列在后** --- ## 📊 快速参考表 | Excel 表示 | 索引格式 | 说明 | |-----------|---------|------| | A1:Z1 | 0,0,0,25 | 第1行,A到Z列 | | A2:Z2 | 1,0,1,25 | 第2行,A到Z列(表头) | | A3:Z203 | 2,0,202,25 | 第3行到第203行,A到Z列 | | A1:A100 | 0,0,99,0 | A列,前100行 | | M3 | 2,12,2,12 | M列第3行(单个单元格) | | A1 | 0,0,0,0 | A1单元格 | | AA1:AZ100 | 0,26,99,51 | AA到AZ列,前100行 | --- ## 🔧 修改记录 ### 修改文件 1. ✅ `TencentDocApiUtil.java` - 更新 `readSheetData` 方法的注释 - 说明 range 格式为索引格式 2. ✅ `TencentDocController.java` - 将 range 构建从 Excel 格式改为索引格式 - 添加详细的转换日志 3. ✅ `TencentDocServiceImpl.java` - 添加 API 错误响应检查 - 当 code != 0 时抛出异常 --- ## 🎯 测试验证 ### 测试参数 ```json { "accessToken": "YOUR_ACCESS_TOKEN", "fileId": "DUW50RUprWXh2TGJK", "sheetId": "BB08J2", "headerRow": 2, "orderNoColumn": 2, "logisticsLinkColumn": 12 } ``` ### 预期日志输出 ``` 读取表头 - Excel行号: 2, 索引行号: 1, range: 1,0,1,25 读取数据行 - Excel行号: 3 ~ 203, 索引: 2 ~ 202, range: 2,0,202,25 ``` ### 成功响应 ```json { "gridData": { "startRow": 1, "startColumn": 0, "rows": [ { "values": [ {"cellValue": {"text": "日期"}}, {"cellValue": {"text": "公司"}}, {"cellValue": {"text": "草号"}}, ... ] } ] } } ``` --- ## 📚 参考文档 根据实际API测试结果和错误提示总结的格式规范。 **关键要点**: 1. ✅ Range 使用索引格式:`startRow,startColumn,endRow,endColumn` 2. ✅ 所有索引从 0 开始 3. ✅ 顺序:行在前,列在后 4. ✅ Excel行号需要减1转换为索引 --- **文档版本**:1.0 **创建时间**:2025-11-05 **修改原因**:修复 "invalid param error: 'range' invalid" 错误