352 lines
7.1 KiB
Markdown
352 lines
7.1 KiB
Markdown
# 腾讯文档 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" 错误
|
||
|