# 接口变化说明:资产标识符规范化 + 历史订单 + 导入必填 > **涉及提案**: > - `asset-identifier-standardization`(BREAKING) > - `asset-historical-orders`(新增接口) > - `import-mandatory-virtual-no`(行为变更) > > **影响范围**:B 端资产操作、设备管理、订单创建、IoT 卡 / 设备导入 --- ## 1. 资产操作接口路由变更 **变更前**:路径参数为数据库主键 ID,需同时传 `asset_type` **变更后**:路径参数统一为资产标识符(ICCID 或 VirtualNo),系统内部自动识别资产类型 | 旧路由 | 新路由 | |---|---| | `GET /api/admin/assets/:asset_type/:id/realtime-status` | `GET /api/admin/assets/:identifier/realtime-status` | | `POST /api/admin/assets/:asset_type/:id/refresh` | `POST /api/admin/assets/:identifier/refresh` | | `GET /api/admin/assets/:asset_type/:id/packages` | `GET /api/admin/assets/:identifier/packages` | | `GET /api/admin/assets/:asset_type/:id/current-package` | `GET /api/admin/assets/:identifier/current-package` | | `GET /api/admin/assets/:asset_type/:id/wallet` | `GET /api/admin/assets/:identifier/wallet` | | `GET /api/admin/assets/:asset_type/:id/wallet/transactions` | `GET /api/admin/assets/:identifier/wallet/transactions` | | `PATCH /api/admin/assets/:asset_type/:id/polling-status` | `PATCH /api/admin/assets/:identifier/polling-status` | | `POST /api/admin/assets/device/:device_id/stop` | `POST /api/admin/assets/:identifier/stop` | | `POST /api/admin/assets/card/:iccid/stop` | `POST /api/admin/assets/:identifier/stop`(已合并) | | `POST /api/admin/assets/device/:device_id/start` | `POST /api/admin/assets/:identifier/start` | | `POST /api/admin/assets/card/:iccid/start` | `POST /api/admin/assets/:identifier/start`(已合并) | | `PATCH /api/admin/devices/:id/deactivate` | `PATCH /api/admin/assets/:identifier/deactivate` | | `PATCH /api/admin/iot-cards/:id/deactivate` | `PATCH /api/admin/assets/:identifier/deactivate`(已合并) | **注意事项:** - `:identifier` 只接受 ICCID 或 VirtualNo(全局唯一标识符) - `stop` / `start` / `deactivate` 已合并为统一接口,系统内部按资产类型自动分支处理,前端无需区分卡和设备 - IMEI / SN / MSISDN 仍可用于 `GET /api/admin/assets/resolve/:identifier` 搜索,但不适用于操作接口 --- ## 2. 设备管理接口路由变更 **变更前**:路径参数为数据库主键 ID **变更后**:路径参数改为 VirtualNo(虚拟号) | 旧路由 | 新路由 | |---|---| | `DELETE /api/admin/devices/:id` | `DELETE /api/admin/devices/:virtual_no` | | `GET /api/admin/devices/:id/cards` | `GET /api/admin/devices/:virtual_no/cards` | | `POST /api/admin/devices/:id/cards` | `POST /api/admin/devices/:virtual_no/cards` | | `DELETE /api/admin/devices/:id/cards/:cardId` | `DELETE /api/admin/devices/:virtual_no/cards/:iccid` | **注意事项:** - 解绑卡接口第二段路径参数从 `cardId`(数据库 ID)改为 `iccid`(ICCID 字符串) --- ## 3. 创建订单接口请求体变更 ### B 端:`POST /api/admin/orders` **请求体字段变化:** | 字段 | 旧 | 新 | 说明 | |---|---|---|---| | `order_type` | 必填 | **废弃** | 系统根据 `identifier` 解析结果自动填入 | | `iot_card_id` | 单卡购买必填 | **废弃** | 改用 `identifier` | | `device_id` | 设备购买必填 | **废弃** | 改用 `identifier` | | `identifier` | — | **必填** | ICCID 或 VirtualNo,最长 100 字符 | | `package_ids` | 必填 | 不变 | — | | `payment_method` | 必填 | 不变 | — | **变更后请求体示例:** ```json { "identifier": "8986XXXXXXXXXXXXXXXX",[前端接口变更通知.md](%E5%89%8D%E7%AB%AF%E6%8E%A5%E5%8F%A3%E5%8F%98%E6%9B%B4%E9%80%9A%E7%9F%A5.md) "package_ids": [5], "payment_method": "wallet" } ``` ### C 端:`POST /api/c/v1/orders/create` 同 B 端,废弃 `order_type` / `iot_card_id` / `device_id`,统一使用 `identifier`。C 端原本已有此字段,行为不变。 --- ## 4. 订单列表接口新增过滤参数 ### `GET /api/admin/orders` 新增可选查询参数: | 参数 | 类型 | 说明 | |---|---|---| | `identifier` | string | 按资产标识符精确过滤,匹配订单的 `asset_identifier` 快照字段 | **示例:** ``` GET /api/admin/orders?identifier=8986XXXXXXXXXXXXXXXX GET /api/admin/orders?identifier=DEV-001 ``` --- ## 5. 响应结构新增字段 ### `OrderResponse`(所有订单相关接口响应) | 新增字段 | 类型 | 说明 | |---|---|---| | `asset_identifier` | string | 下单时资产的标识符快照,资产删除后仍可读 | | `asset_type` | string | 资产类型:`single_card` 或 `device` | ### `AssetResolveResponse`(`GET /api/admin/assets/resolve/:identifier`) | 新增字段 | 类型 | 说明 | |---|---|---| | `identifier` | string | 原样回传本次查询所用的标识符 | --- ## 6. 新增业务规则 ### 已绑设备的卡不可单独购买套餐 - **触发条件**:IoT 卡的 `is_standalone = false`(已绑定设备) - **影响接口**:所有套餐购买入口(B 端后台、C 端 H5) - **返回错误**: ```json { "code": 40001, "msg": "该卡已绑定设备,请前往设备页面购买套餐" } ``` --- --- ## 7. 新增接口:资产历史订单 > **来源提案**:`asset-historical-orders` ### `GET /api/admin/assets/:identifier/orders` 查询某资产本代历史订单,可选通过换货链追溯前代(最多10代)。 **路径参数:** | 参数 | 说明 | |---|---| | `identifier` | 资产标识符(ICCID 或 VirtualNo) | **查询参数:** | 参数 | 类型 | 必填 | 说明 | |---|---|---|---| | `page` | int | 否 | 页码,默认 1 | | `page_size` | int | 否 | 每页条数,默认 20,最大 100 | | `include_previous` | bool | 否 | 是否追溯换货前代,默认 false | **响应示例:** ```json { "code": 0, "data": { "current_generation": { "generation": 2, "identifier": "VNO-001", "asset_type": "card", "total": 3, "page": 1, "page_size": 20, "items": [ { "order_no": "ORD-20250101-001", "order_type": "single_card", "payment_status": 2, "payment_status_text": "已支付", "total_amount": 9900, "payment_method": "wallet", "paid_at": "2025-01-01T10:00:00Z", "generation": 2, "items": [ { "package_name": "30天1GB套餐", "quantity": 1, "unit_price": 9900, "amount": 9900 } ], "created_at": "2025-01-01T09:58:00Z" } ] }, "previous_generations": [ { "generation": 1, "identifier": "VNO-000", "asset_type": "card", "exchange_no": "EX-20241201-001", "exchanged_at": "2024-12-01T10:00:00Z", "total": 1, "items": [...] } ], "truncated": false } } ``` **注意事项:** - `previous_generations` 仅在 `include_previous=true` 时返回,否则字段不存在 - `truncated: true` 表示换货链超过 10 代,已截断,前代数据不完整 - 前代订单每代最多返回 20 条(不分页) - 依赖提案一(`asset-identifier-standardization`)中的 `Order.asset_identifier` 快照字段 --- ## 8. 行为变更:导入接口 virtual_no 必填 > **来源提案**:`import-mandatory-virtual-no`(无 Schema 结构变化,仅行为变更) ### `POST /api/admin/iot-cards/import` — BREAKING | 场景 | 旧行为 | 新行为 | |---|---|---| | Excel 缺少 `virtual_no` 列 | 正常导入,卡的 `virtual_no` 存空字符串 | **整批失败**,任务状态=失败,错误:"Excel 文件缺少 virtual_no 列,请使用最新模板" | | 某行 `virtual_no` 为空 | 该行导入成功 | 该行计入 `fail_count`,`failed_items` 含原因:"虚拟号(virtual_no)不能为空" | | `virtual_no` 重复 | 无变化 | 无变化 | > IoT 卡导入 Excel 模板**必须新增 `virtual_no` 列**,否则全批失败。 ### `POST /api/admin/devices/import` — 统计语义变更 | 场景 | 旧行为 | 新行为 | |---|---|---| | 某行 `virtual_no` 为空 | 计入 `skip_count`,无失败详情 | 计入 `fail_count`,`failed_items` 含原因:"设备虚拟号(virtual_no)不能为空" | > 前端若有"跳过了 N 行设备"的提示文案,需同步调整为失败处理逻辑。 --- ## 前端迁移清单 ### asset-identifier-standardization(必须改) - [ ] 将 `/assets/:asset_type/:id/` 系列 URL 改为 `/assets/:identifier/`,传 ICCID 或 VirtualNo - [ ] 停复机不再区分卡/设备,统一调 `/assets/:identifier/stop` 和 `/assets/:identifier/start` - [ ] 停用不再区分 `/iot-cards/:id/deactivate` 和 `/devices/:id/deactivate`,统一调 `/assets/:identifier/deactivate` - [ ] 设备管理接口将 `/:id` 改为 `/:virtual_no`,解绑卡将 `/:cardId` 改为 `/:iccid` - [ ] 创建订单请求体移除 `order_type`、`iot_card_id`、`device_id`,改传 `identifier` - [ ] 订单列表可通过 `?identifier=xxx` 过滤指定资产的历史订单 - [ ] 展示订单详情时可直接读取 `asset_identifier` 字段,无需额外查询资产 ### asset-historical-orders(新功能) - [ ] 资产详情页接入 `GET /api/admin/assets/:identifier/orders` 展示历史订单 - [ ] 换货资产可通过 `?include_previous=true` 追溯前代购买记录 ### import-mandatory-virtual-no(需同步) - [ ] 更新 IoT 卡导入 Excel 模板,必须包含 `virtual_no` 列 - [ ] 导入结果展示逻辑:设备导入"跳过行"统计移至"失败行",并展示原因