# 需求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` | | 后台卡列表操作入口 | ❌ 待建(前端) | 单条+批量 | | 后台设备列表操作入口 | ❌ 待建(前端) | 单条+批量 |