fix: 优化界面以及更新接口
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 1m27s

This commit is contained in:
sexygoat
2026-04-15 11:54:43 +08:00
parent 0d0b5ec14a
commit 91d7d4c21f
30 changed files with 1863 additions and 1742 deletions

View File

@@ -0,0 +1,265 @@
# 接口变化说明:资产标识符规范化 + 历史订单 + 导入必填
> **涉及提案**
> - `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`
- [ ] 导入结果展示逻辑:设备导入"跳过行"统计移至"失败行",并展示原因

View File

@@ -0,0 +1,129 @@
前端接口变更通知
背景 & 原因
平台需要展示代理的\*\*预充值钱包(主钱包)\*\*余额与流水,原来这部分数据完全不可见。同时,代理的佣金相关接口散落在 /my/ 路径下,与平台统一的 /shops/:id/ 资源路径存在职责重叠,本次统一收拢到 /shops/ 下。
---
一、BREAKING CHANGE — 必须迁移
1. 概况列表接口改造
┌──────────────┬──────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────────────┐ │ │ 旧 │ 新 │ ├──────────────┼──────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────┤ │ 路径 │ GET /api/admin/shops/commission-summary │ GET /api/admin/shops/fund-summary │ ├──────────────┼──────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────┤ │ 入参 │ 完全相同page, page_size, shop_name, username │ 无变化 │ ├──────────────┼──────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────┤ │ 响应新增字段 │ — │ main_balance预充值余额main_frozen_balance预充值冻结余额 │ ├──────────────┼──────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────┤ │ 响应删除字段 │ — │ 无 │ └──────────────┴──────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────────────┘
旧响应 items 字段(已废弃 DTO ShopCommissionSummaryItem→ 新 DTO ShopFundSummaryItem
{ "shop_id": 1, "shop_name": "代理A", "shop_code": "A001", "username": "agent_a", "phone": "138xxxx",
* "main_balance": 200000, // 新增:预充值钱包余额(分)
* "main_frozen_balance": 0, // 新增预充值冻结余额当前均为0 "total_commission": 50000, "withdrawn_commission": 10000, "unwithdraw_commission": 30000, "frozen_commission": 5000, "withdrawing_commission": 5000, "available_commission": 30000, "created_at": "2025-01-01T00:00:00Z" }
▎ 操作:把所有调用 /commission-summary 的地方改为 /fund-summary同时在 UI 上新增"预充值余额"列。
---
2. 废弃的 /my/ 接口 — 全部删除,必须切换
┌────────────────────────────────┬─────────────────────────────────────────────┬─────────────────────────────────────────────┐ │ 废弃路由 │ 替代路由 │ 变化 │ ├────────────────────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────┤ │ GET /my/commission-summary │ GET /shops/fund-summary │ 见上方,返回结构有变化 │ ├────────────────────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────┤ │ GET /my/withdrawal-requests │ GET /shops/{shop_id}/withdrawal-requests │ 入参、响应完全一致,只需把 shop_id 放进路径 │ ├────────────────────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────┤ │ GET /my/commission-records │ GET /shops/{shop_id}/commission-records │ 入参、响应完全一致,只需把 shop_id 放进路径 │ ├────────────────────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────┤ │ GET /my/commission-stats │ GET /shops/{shop_id}/commission-stats │ 见下方详情 │ ├────────────────────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────┤ │ GET /my/commission-daily-stats │ GET /shops/{shop_id}/commission-daily-stats │ 见下方详情 │ ├────────────────────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────┤ │ POST /my/withdrawal-requests │ POST /shops/{shop_id}/withdrawal-requests │ 见下方详情 │ └────────────────────────────────┴─────────────────────────────────────────────┴─────────────────────────────────────────────┘
▎ 旧 /my/ 接口已从服务端完全删除,调用会 404。
---
二、新增接口详情
GET /api/admin/shops/{shop_id}/commission-stats
替代 GET /my/commission-stats
入参Query
┌────────────┬────────┬──────────────────┐ │ 参数 │ 类型 │ 说明 │ ├────────────┼────────┼──────────────────┤ │ start_time │ string │ 开始时间(可选) │ ├────────────┼────────┼──────────────────┤ │ end_time │ string │ 结束时间(可选) │ └────────────┴────────┴──────────────────┘
▎ 旧接口的 shop_id query 参数已去掉,改为路径参数 {shop_id}
响应(无变化): { "total_amount": 50000, "cost_diff_amount": 30000, "one_time_amount": 20000, "cost_diff_percent": 600, "one_time_percent": 400, "total_count": 15, "cost_diff_count": 10, "one_time_count": 5 }
---
GET /api/admin/shops/{shop_id}/commission-daily-stats
替代 GET /my/commission-daily-stats
入参Query
┌────────────┬────────┬───────────────────────────────────┐ │ 参数 │ 类型 │ 说明 │ ├────────────┼────────┼───────────────────────────────────┤ │ start_date │ string │ 开始日期 YYYY-MM-DD可选 │ ├────────────┼────────┼───────────────────────────────────┤ │ end_date │ string │ 结束日期 YYYY-MM-DD可选 │ ├────────────┼────────┼───────────────────────────────────┤ │ days │ int │ 查询天数默认30最大365可选 │ └────────────┴────────┴───────────────────────────────────┘
响应(无变化): \[ { "date": "2025-04-08", "total_amount": 10000, "total_count": 3 }, { "date": "2025-04-07", "total_amount": 5000, "total_count": 2 } \]
---
POST /api/admin/shops/{shop_id}/withdrawal-requests
替代 POST /my/withdrawal-requests
Body无变化 { "amount": 10000, "withdrawal_method": "alipay", "account_name": "张三", "account_number": "138xxxx" }
权限变化(重要):
* 仅代理账号可调用,平台账号调用返回 403 仅代理商用户可发起提现
* 只能为自己的 shop_id 提现topLevel 代理不能替下级提现,否则返回 403 仅可为本人店铺发起提现
---
GET /api/admin/shops/{shop_id}/main-wallet/transactions ✨ 全新
预充值钱包流水列表(此前无此功能)
入参Query
┌──────────────────┬────────┬────────────────────────────────────────────────────────────────────────┐ │ 参数 │ 类型 │ 说明 │ ├──────────────────┼────────┼────────────────────────────────────────────────────────────────────────┤ │ page │ int │ 页码默认1 │ ├──────────────────┼────────┼────────────────────────────────────────────────────────────────────────┤ │ page_size │ int │ 每页数量默认20最大100 │ ├──────────────────┼────────┼────────────────────────────────────────────────────────────────────────┤ │ transaction_type │ string │ 交易类型过滤recharge充值入账/ deduct套餐扣款/ refund退款 │ ├──────────────────┼────────┼────────────────────────────────────────────────────────────────────────┤ │ start_date │ string │ 开始日期 YYYY-MM-DD │ ├──────────────────┼────────┼────────────────────────────────────────────────────────────────────────┤ │ end_date │ string │ 结束日期 YYYY-MM-DD │ └──────────────────┴────────┴────────────────────────────────────────────────────────────────────────┘
响应: { "items": \[ { "id": 1, "transaction_type": "recharge", "transaction_subtype": "", "amount": 50000, "balance_before": 150000, "balance_after": 200000, "remark": "线下充值", "created_at": "2025-04-08T10:00:00Z" } \], "total": 3, "page": 1, "size": 20 }
▎ amount 正数为入账,负数为扣款,单位:分
---
三、数据权限说明(前端需了解)
两种角色访问同一套接口,后端自动过滤数据:
┌──────────┬─────────────────────────┬──────────────────────────────────────────┐ │ 角色 │ /shops/fund-summary │ /shops/{shop_id}/... │ ├──────────┼─────────────────────────┼──────────────────────────────────────────┤ │ 平台账号 │ 返回所有代理店铺 │ 可查任意 shop_id │ ├──────────┼─────────────────────────┼──────────────────────────────────────────┤ │ 代理账号 │ 返回自己 + 所有下级店铺 │ 只能查自己和下级的 shop_id其他返回 403 │ └──────────┴─────────────────────────┴──────────────────────────────────────────┘
提现操作额外限制:代理账号只能为自己的 shop_id 发起提现,即使是上级代理也不能替下级操作。
---
四、变更全景图
变更前 变更后 ────────────────────────────────────────────────────────────────────── GET /shops/commission-summary → GET /shops/fund-summary ★ 改路径 + 新增字段 GET /shops/:id/withdrawal-requests GET /shops/:id/withdrawal-requests (不变) GET /shops/:id/commission-records GET /shops/:id/commission-records (不变) → GET /shops/:id/commission-stats ★ 新增 → GET /shops/:id/commission-daily-stats ★ 新增 → POST /shops/:id/withdrawal-requests ★ 新增 → GET /shops/:id/main-wallet/transactions ★ 新增(全新功能)
GET /my/commission-summary × 已删除 GET /my/withdrawal-requests × 已删除 GET /my/commission-records × 已删除 GET /my/commission-stats × 已删除 GET /my/commission-daily-stats × 已删除 POST /my/withdrawal-requests × 已删除
---
五、前端改造核实清单
* 将 GET /shops/commission-summary → 改为 GET /shops/fund-summaryUI 新增"预充值余额"列
* 代理侧"我的余额概览"调用改为 GET /shops/fund-summary不再有独立的 /my/commission-summary
* 代理侧"提现记录"改为 GET /shops/{自己shopID}/withdrawal-requests
* 代理侧"佣金明细"改为 GET /shops/{自己shopID}/commission-records
* 代理侧"佣金统计"改为 GET /shops/{自己shopID}/commission-stats去掉 query 里的 shop_id
* 代理侧"每日统计"改为 GET /shops/{自己shopID}/commission-daily-stats去掉 query 里的 shop_id
* 代理侧"发起提现"改为 POST /shops/{自己shopID}/withdrawal-requestsshop_id 进路径body 不变)
* 新建"预充值钱包流水"页面,调用 GET /shops/{shopID}/main-wallet/transactions
\