feat(import): 用 Excel 格式替换 CSV 导入
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m33s

- 删除 CSV 解析代码,新增 Excel 解析器 (excelize)

- 更新 IoT 卡和设备导入任务处理器

- 更新 API 路由文档和前端接入指南

- 归档变更到 openspec/changes/archive/

- 同步 delta specs 到 main specs
This commit is contained in:
2026-01-31 14:13:02 +08:00
parent 62708892ec
commit d309951493
24 changed files with 2279 additions and 589 deletions

View File

@@ -7514,24 +7514,26 @@ paths:
/api/admin/devices/import:
post:
description: |-
仅平台用户可操作。
仅平台用户可操作。文件格式已从 CSV 升级为 Excel (.xlsx)。
### 完整导入流程
1. **获取上传 URL**: 调用 `POST /api/admin/storage/upload-url`
2. **上传 CSV 文件**: 使用预签名 URL 上传文件到对象存储
2. **上传 Excel 文件**: 使用预签名 URL 上传文件到对象存储
3. **调用本接口**: 使用返回的 `file_key` 提交导入任务
### CSV 文件格式
### Excel 文件格式
必须包含列(首行为表头):
- `device_no`: 设备号(必填,唯一)
- `device_name`: 设备名称
- `device_model`: 设备型号
- `device_type`: 设备
- `max_sim_slots`: 最大插槽数默认4
- `manufacturer`: 制造商
- `iccid_1` ~ `iccid_4`: 绑定的卡 ICCID卡必须已存在且未绑定
- 文件格式:仅支持 .xlsx (Excel 2007+)
- 必须包含列(首行为表头):
- `device_no`: 设备号(必填,唯一)
- `device_name`: 设备名称
- `device_model`: 设备型
- `device_type`: 设备类型
- `max_sim_slots`: 最大插槽数默认4
- `manufacturer`: 制造商
- `iccid_1` ~ `iccid_4`: 绑定的卡 ICCID卡必须已存在且未绑定
- 列格式:设置为文本格式(避免长数字被转为科学记数法)
requestBody:
content:
application/json:
@@ -8881,11 +8883,12 @@ paths:
## ⚠️ 接口变更说明BREAKING CHANGE
本接口已从 `multipart/form-data` 改为 `application/json`。
文件格式从 CSV 升级为 Excel (.xlsx),解决长数字被转为科学记数法的问题。
### 完整导入流程
1. **获取上传 URL**: 调用 `POST /api/admin/storage/upload-url`
2. **上传 CSV 文件**: 使用预签名 URL 上传文件到对象存储
2. **上传 Excel 文件**: 使用预签名 URL 上传文件到对象存储
3. **调用本接口**: 使用返回的 `file_key` 提交导入任务
### 请求示例
@@ -8894,15 +8897,16 @@ paths:
{
"carrier_id": 1,
"batch_no": "BATCH-2025-01",
"file_key": "imports/2025/01/24/abc123.csv"
"file_key": "imports/2025/01/24/abc123.xlsx"
}
```
### CSV 文件格式
### Excel 文件格式
- 必须包含两列:`iccid`, `msisdn`
- 首行为表头
- 编码UTF-8
- 文件格式:仅支持 .xlsx (Excel 2007+)
- 必须包含两列:`ICCID`, `MSISDN`
- 首行为表头(可选,但建议包含)
- 列格式:设置为文本格式(避免长数字被转为科学记数法)
requestBody:
content:
application/json:
@@ -14806,15 +14810,15 @@ paths:
```javascript
// 1. 获取预签名 URL
const { data } = await api.post('/storage/upload-url', {
file_name: 'cards.csv',
content_type: 'text/csv',
file_name: 'cards.xlsx',
content_type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
purpose: 'iot_import'
});
// 2. 上传文件到对象存储
await fetch(data.upload_url, {
method: 'PUT',
headers: { 'Content-Type': 'text/csv' },
headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' },
body: file
});
@@ -14830,7 +14834,7 @@ paths:
| 值 | 说明 | 生成路径格式 |
|---|------|-------------|
| iot_import | ICCID 导入 | imports/YYYY/MM/DD/uuid.csv |
| iot_import | ICCID/设备导入 (Excel) | imports/YYYY/MM/DD/uuid.xlsx |
| export | 数据导出 | exports/YYYY/MM/DD/uuid.xlsx |
| attachment | 附件上传 | attachments/YYYY/MM/DD/uuid.ext |