feat: 资产标识符标准化、资产历史订单查询及导入虚拟号强制验证
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
主要变更: - 新增 AssetIdentifier 模型及 Store,统一管理资产标识符(ICCID/IMEI/SN 等) - 新增迁移:asset_identifier 表、order 表新增 asset_identifier 字段、iot_card.virtual_no NOT NULL 约束 - 资产 Handler/Service/Route 全面重构,支持标识符路由查询与解析 - 新增资产历史订单查询接口,支持跨设备/卡/钱包维度的订单聚合 - 设备与物联卡导入任务强制校验虚拟号,缺失时直接拒绝 - Excel 工具函数优化,前端导入指引文档同步更新 - 归档三个 OpenSpec 提案:asset-identifier-standardization、asset-historical-orders、import-mandatory-virtual-no - 更新 OpenAPI 文档及相关 DTO Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -12,10 +12,12 @@
|
||||
|
||||
**API 端点**: `GET /api/admin/assets/resolve/:identifier`
|
||||
|
||||
**查找顺序**:
|
||||
1. 先在 `tb_device` 表查找(匹配 `virtual_no = ? OR imei = ? OR sn = ?`)
|
||||
2. 未命中则在 `tb_iot_card` 表查找(匹配 `virtual_no = ? OR iccid = ? OR msisdn = ?`)
|
||||
3. 两表均未命中 → 返回 HTTP 404
|
||||
**查找顺序(更新后)**:
|
||||
1. **主路径**:查 `tb_asset_identifier` WHERE identifier = ? → 命中则得到 asset_type + asset_id,直接查对应表取完整记录
|
||||
2. **Fallback 路径**(注册表未命中时):
|
||||
- 先查 `tb_device`(匹配 `virtual_no = ? OR imei = ? OR sn = ?`)
|
||||
- 未命中则查 `tb_iot_card`(匹配 `virtual_no = ? OR iccid = ? OR msisdn = ?`)
|
||||
3. 两条路径均未命中 → 返回 HTTP 404
|
||||
4. 找到后应用数据权限过滤,无权限 → 返回 HTTP 403
|
||||
|
||||
**数据权限规则**:
|
||||
@@ -28,8 +30,11 @@
|
||||
*通用字段(device 和 card 均有)*:
|
||||
- `asset_type`: 资产类型(`"device"` 或 `"card"`)
|
||||
- `asset_id`: 资产主键 ID
|
||||
- `identifier`: 本次查询所用的标识符(原样回传)
|
||||
- `virtual_no`: 虚拟号(设备/卡均使用此字段)
|
||||
- `status`: 资产状态(整型)
|
||||
- `asset_status`: 业务状态(1-在库 2-已销售 3-已换货 4-已停用)
|
||||
- `generation`: 资产世代编号
|
||||
- `batch_no`: 批次号
|
||||
- `shop_id`: 所属店铺 ID(平台库存时为空)
|
||||
- `shop_name`: 所属店铺名称
|
||||
@@ -136,3 +141,20 @@
|
||||
|
||||
- **WHEN** 管理员查询一台没有购买任何套餐的设备
|
||||
- **THEN** `current_package = ""`,`package_total_mb = 0`,`package_used_mb = 0`,`package_remain_mb = 0`
|
||||
|
||||
#### Scenario: 通过注册表主路径精确解析
|
||||
|
||||
- **WHEN** 管理员输入 identifier 为已存在于 `tb_asset_identifier` 的 VirtualNo 或 ICCID
|
||||
- **THEN** 系统单次查询注册表命中,直接查对应表返回完整资产信息,响应时间 < 50ms
|
||||
|
||||
#### Scenario: Fallback 路径解析 IMEI
|
||||
|
||||
- **WHEN** 管理员输入 identifier 为设备 IMEI(不在注册表中)
|
||||
- **THEN** 注册表未命中,系统 fallback 查 tb_device 的 imei 字段,找到后返回资产信息
|
||||
- **THEN** 响应中 `identifier` 字段原样回传该 IMEI 值
|
||||
|
||||
#### Scenario: Fallback 路径解析 MSISDN
|
||||
|
||||
- **WHEN** 管理员输入 identifier 为 IoT 卡的手机号(MSISDN)
|
||||
- **THEN** 注册表未命中,fallback 查 tb_iot_card 的 msisdn 字段
|
||||
- **THEN** 若存在多张卡的 MSISDN 相同,返回第一条匹配记录(MSISDN 非唯一,存在歧义,记录 warn 日志)
|
||||
|
||||
Reference in New Issue
Block a user