212 lines
7.4 KiB
Markdown
212 lines
7.4 KiB
Markdown
# 需求02:H5 流程顺序配置化
|
||
|
||
---
|
||
|
||
## 背景
|
||
|
||
H5 用户进入后:绑定手机号 → 充值 → 实名(当前顺序写死)
|
||
|
||
需求:允许**按资产个体**配置充值和实名的顺序,支持后台单条或批量改。
|
||
|
||
---
|
||
|
||
## 流程图
|
||
|
||
### 图一:H5 登录后资产视角判断与策略读取
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[用户扫码 / 输入虚拟号] --> B[解析 identifier]
|
||
B --> C{资产类型}
|
||
|
||
C -->|card| D{该卡是否绑定设备?}
|
||
D -->|否 独立卡| E[卡视角\n读 IotCard.realname_policy]
|
||
D -->|是| F[设备视角\n读 Device.realname_policy\n卡自身策略忽略]
|
||
|
||
C -->|device| F
|
||
|
||
E --> G{realname_policy}
|
||
F --> G
|
||
|
||
G -->|none| H[无需实名\n直接进充值页]
|
||
G -->|before_order| I[先进实名页\n实名完成后才能充值]
|
||
G -->|after_order| J[先进充值页\n充值完成后提示实名]
|
||
```
|
||
|
||
### 图二:H5 充值/购买前的策略拦截逻辑
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[用户发起充值/购买] --> B[读取 resolved.Asset.RealnamePolicy]
|
||
B --> C{策略是 before_order?}
|
||
C -->|否| D[放行,正常创建订单]
|
||
C -->|是| E{当前资产 RealNameStatus == 1?}
|
||
E -->|已实名| D
|
||
E -->|未实名| F[返回 CodeNeedRealname\nH5 跳转实名页]
|
||
```
|
||
|
||
### 图三:GetEffectiveRealnamePolicy 取值逻辑
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[GetEffectiveRealnamePolicy\ncard, device] --> B{device != nil?}
|
||
B -->|是| C[返回 device.RealnamePolicy]
|
||
B -->|否| D{card != nil?}
|
||
D -->|是| E[返回 card.RealnamePolicy]
|
||
D -->|否| F[返回 none]
|
||
```
|
||
|
||
---
|
||
|
||
## 资产类型与策略归属
|
||
|
||
系统有两类资产:**独立卡** 和 **设备**。
|
||
|
||
| 资产类型 | realname_policy 归属 | H5 视角 |
|
||
|---------|---------------------|---------|
|
||
| 独立卡(无设备绑定) | 卡自身的 `realname_policy` | 卡视角 |
|
||
| 设备 | 设备自身的 `realname_policy` | 设备视角 |
|
||
| 设备下的卡 | **设备**的 `realname_policy`(卡自身策略无效) | 设备视角 |
|
||
|
||
**关键规则**:设备下的卡无法以卡视角独立登录 H5,登录后自动进入设备视角,因此实名流程策略由设备决定,卡自身的 `realname_policy` 字段对 H5 流程无影响(但字段保留,仅作记录)。
|
||
|
||
该逻辑已在 `internal/service/asset/service.go:GetEffectiveRealnamePolicy()` 实现:设备不为 nil 时取设备策略,否则取卡策略。
|
||
|
||
---
|
||
|
||
## 当前字段状态
|
||
|
||
两个模型都已有 `realname_policy` 字段,无需迁移:
|
||
|
||
```go
|
||
// internal/model/iot_card.go
|
||
RealnamePolicy string `gorm:"column:realname_policy;type:varchar(20);default:'after_order';not null;
|
||
comment:实名认证策略(none=无需实名,before_order=先实名后充值/购买,after_order=先充值/购买后实名)"`
|
||
|
||
// internal/model/device.go
|
||
RealnamePolicy string `gorm:"column:realname_policy;type:varchar(20);default:'after_order';not null;
|
||
comment:实名认证策略(none=无需实名,before_order=先实名后充值/购买,after_order=先充值/购买后实名)"`
|
||
```
|
||
|
||
值含义:
|
||
- `none` — 无需实名
|
||
- `before_order` — 先实名后充值
|
||
- `after_order` — 先充值后实名(**当前默认**)
|
||
|
||
---
|
||
|
||
## 后端实现
|
||
|
||
### 1. 单条修改接口(已有,无需新建)
|
||
|
||
```
|
||
PATCH /api/admin/assets/:identifier/realname-mode
|
||
```
|
||
|
||
该接口已在 `internal/handler/admin/asset.go:UpdateRealnamePolicy()` 实现,通过 identifier 自动解析资产类型,卡和设备都走这里,**不需要再建卡专属或设备专属路由**。
|
||
|
||
请求体(已有 DTO):
|
||
```go
|
||
type UpdateAssetRealnamePolicyRequest struct {
|
||
RealnamePolicy string `json:"realname_policy" validate:"required,oneof=none before_order after_order"
|
||
description:"实名策略 (none:无需实名, before_order:先实名后充值, after_order:先充值后实名)"`
|
||
}
|
||
```
|
||
|
||
### 2. 新增批量修改接口(需新建)
|
||
|
||
卡和设备分开批量接口,因为两者在后台是不同的列表页。
|
||
|
||
#### 2a. 批量修改卡实名策略
|
||
|
||
```
|
||
POST /admin/iot-cards/batch-update-realname-policy
|
||
```
|
||
|
||
请求体:
|
||
```go
|
||
type BatchUpdateIotCardRealnamePolicy struct {
|
||
IotCardIDs []uint `json:"iot_card_ids" validate:"required,min=1" description:"卡ID列表"`
|
||
RealnamePolicy string `json:"realname_policy" validate:"required,oneof=none before_order after_order"
|
||
description:"实名策略 (none:无需实名, before_order:先实名后充值, after_order:先充值后实名)"`
|
||
}
|
||
```
|
||
|
||
Service:`UPDATE tb_iot_cards SET realname_policy = ? WHERE id IN (...)`,逐条写审计日志。
|
||
|
||
#### 2b. 批量修改设备实名策略
|
||
|
||
```
|
||
POST /admin/devices/batch-update-realname-policy
|
||
```
|
||
|
||
请求体:
|
||
```go
|
||
type BatchUpdateDeviceRealnamePolicy struct {
|
||
DeviceIDs []uint `json:"device_ids" validate:"required,min=1" description:"设备ID列表"`
|
||
RealnamePolicy string `json:"realname_policy" validate:"required,oneof=none before_order after_order"
|
||
description:"实名策略 (none:无需实名, before_order:先实名后充值, after_order:先充值后实名)"`
|
||
}
|
||
```
|
||
|
||
Service:`UPDATE tb_devices SET realname_policy = ? WHERE id IN (...)`,逐条写审计日志。
|
||
|
||
### 3. 全局默认值(兜底)
|
||
|
||
新建卡/设备时默认 `after_order`,通过 GORM default 标签保证,不需要读 `tb_system_config`。
|
||
|
||
---
|
||
|
||
## 前端对接
|
||
|
||
### 卡列表页
|
||
|
||
"操作"列或批量操作下拉增加"设置实名策略":
|
||
|
||
- **单条**:弹框选策略 → `PATCH /api/admin/assets/{iccid}/realname-mode`
|
||
- **批量**:勾选多条 → 批量操作 → "设置实名策略" → `POST /admin/iot-cards/batch-update-realname-policy`
|
||
|
||
> 注意:设备下的卡即使在卡列表中修改了策略,对 H5 流程也无效(H5 取设备策略)。建议在卡列表展示"所属设备"列,提示运营该卡已属于某设备,实名策略需到设备处修改。
|
||
|
||
### 设备列表页
|
||
|
||
"操作"列或批量操作下拉增加"设置实名策略":
|
||
|
||
- **单条**:弹框选策略 → `PATCH /api/admin/assets/{sn}/realname-mode`
|
||
- **批量**:勾选多条 → 批量操作 → "设置实名策略" → `POST /admin/devices/batch-update-realname-policy`
|
||
|
||
### 字段展示
|
||
|
||
卡列表/详情、设备列表/详情均展示"实名策略"字段:
|
||
|
||
| realname_policy | 展示文案 |
|
||
|----------------|---------|
|
||
| `none` | 无需实名 |
|
||
| `before_order` | 先实名后充值 |
|
||
| `after_order` | 先充值后实名 |
|
||
|
||
### H5 侧(C端)
|
||
|
||
H5 读取资产初始化接口返回的 `realname_policy` 字段,决定先跳充值页还是先跳实名页。
|
||
|
||
- 独立卡登录 → 读卡的 `realname_policy`
|
||
- 设备/设备下的卡登录 → 读设备的 `realname_policy`
|
||
|
||
该逻辑由 `GetEffectiveRealnamePolicy()` 统一处理,H5 无需区分资产类型,直接用接口返回值即可。
|
||
|
||
---
|
||
|
||
## 实施范围汇总
|
||
|
||
| 项目 | 状态 | 说明 |
|
||
|------|------|------|
|
||
| `IotCard.realname_policy` 字段 | ✅ 已有 | 无需迁移 |
|
||
| `Device.realname_policy` 字段 | ✅ 已有 | 无需迁移 |
|
||
| 单条修改接口 | ✅ 已有 | `PATCH /api/admin/assets/:identifier/realname-mode` |
|
||
| `GetEffectiveRealnamePolicy()` | ✅ 已有 | 设备视角取设备策略 |
|
||
| H5 充值前校验 | ✅ 已有 | `client_wallet.go` 已正确读取 |
|
||
| 批量修改卡接口 | ❌ 待建 | `POST /admin/iot-cards/batch-update-realname-policy` |
|
||
| 批量修改设备接口 | ❌ 待建 | `POST /admin/devices/batch-update-realname-policy` |
|
||
| 后台卡列表操作入口 | ❌ 待建(前端) | 单条+批量 |
|
||
| 后台设备列表操作入口 | ❌ 待建(前端) | 单条+批量 |
|