feat: 卡/设备是否有生效套餐
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m19s

This commit is contained in:
sexygoat
2026-05-19 15:14:39 +08:00
parent 14832f5c6f
commit 59167d2630
14 changed files with 3792 additions and 3963 deletions

View File

@@ -0,0 +1,43 @@
# Change: 为 IoT 卡管理和设备管理新增生效套餐筛选
## Why
当前后台的 IoT 卡管理页和设备管理页都缺少“是否有生效中的套餐”搜索条件,运营人员无法直接按资产当前是否存在生效中的套餐快速筛选目标记录。
本次需求要求两个列表统一新增该筛选能力,并通过查询参数 `has_active_package` 向后端传递筛选条件,避免用户依赖列表详情或手工比对来判断。
## What Changes
- 在 IoT 卡管理页搜索栏新增 `是否有生效中的套餐` 筛选项:
- 使用“是 / 否”布尔选项
-`GET /api/admin/iot-cards/standalone` 提交可选查询参数 `has_active_package`
- 未选择时不提交该参数
- 在设备管理页搜索栏新增 `是否有生效中的套餐` 筛选项:
- 使用“是 / 否”布尔选项
-`GET /api/admin/devices` 提交可选查询参数 `has_active_package`
- 未选择时不提交该参数
- 补齐前端类型契约与搜索状态管理:
- `StandaloneCardQueryParams` 支持 `has_active_package`
- `DeviceQueryParams` 支持 `has_active_package`
- 搜索、重置、翻页、刷新流程中正确保留或清空该条件
- 明确 `false` 是有效筛选值:
- 选择“否”时必须提交 `has_active_package=false`
- 前端不得因为通用空值清理或 `|| undefined` 之类的写法丢掉该参数
## Impact
- Affected specs:
- `iot-card-management`
- `device-management`
- Affected code:
- `src/types/api/card.ts`
- `src/types/api/device.ts`
- `src/api/modules/card.ts`
- `src/api/modules/device.ts`
- `src/views/asset-management/iot-card-management/index.vue`
- `src/views/asset-management/device-list/index.vue`
- Dependencies:
- `GET /api/admin/iot-cards/standalone`
- `GET /api/admin/devices`
- Breaking changes:
-

View File

@@ -0,0 +1,44 @@
## ADDED Requirements
### Requirement: Device Active Package Query Contract
The device management list integration SHALL support filtering records by whether the device currently has an active package via the query parameter `has_active_package`.
#### Scenario: Query devices with active package
- **GIVEN** 用户正在后台设备管理页查询列表
- **WHEN** 用户在 `是否有生效中的套餐` 中选择“是”并执行搜索
- **THEN** 系统 MUST 调用 `GET /api/admin/devices`
- **AND** 请求 MUST 提交 `has_active_package=true`
#### Scenario: Query devices without active package
- **GIVEN** 用户正在后台设备管理页查询列表
- **WHEN** 用户在 `是否有生效中的套餐` 中选择“否”并执行搜索
- **THEN** 系统 MUST 调用 `GET /api/admin/devices`
- **AND** 请求 MUST 提交 `has_active_package=false`
- **AND** 前端 MUST NOT 因为该值为 `false` 而省略此参数
#### Scenario: Omit active package filter when not selected
- **GIVEN** 用户未选择 `是否有生效中的套餐`
- **WHEN** 用户执行设备列表搜索、刷新或翻页
- **THEN** 列表请求 MUST NOT 携带 `has_active_package`
### Requirement: Device Active Package Search Filter
The device management page SHALL provide a search filter labeled `是否有生效中的套餐` and keep its selected state consistent across list interactions.
#### Scenario: Show yes and no options for active package filter
- **GIVEN** 用户打开后台设备管理页
- **WHEN** 页面渲染搜索栏
- **THEN** 页面 MUST 显示 `是否有生效中的套餐` 筛选项
- **AND** 该筛选项 MUST 提供“是”和“否”两个可选值
#### Scenario: Reset clears active package filter
- **GIVEN** 用户已经在 `是否有生效中的套餐` 中选择了“是”或“否”
- **WHEN** 用户重置搜索条件
- **THEN** 页面 MUST 清空该筛选项
- **AND** 后续列表请求 MUST NOT 再携带 `has_active_package`

View File

@@ -0,0 +1,44 @@
## ADDED Requirements
### Requirement: IoT Card Active Package Query Contract
The IoT card management list integration SHALL support filtering records by whether the card currently has an active package via the query parameter `has_active_package`.
#### Scenario: Query IoT cards with active package
- **GIVEN** 用户正在后台 IoT 卡管理页查询列表
- **WHEN** 用户在 `是否有生效中的套餐` 中选择“是”并执行搜索
- **THEN** 系统 MUST 调用 `GET /api/admin/iot-cards/standalone`
- **AND** 请求 MUST 提交 `has_active_package=true`
#### Scenario: Query IoT cards without active package
- **GIVEN** 用户正在后台 IoT 卡管理页查询列表
- **WHEN** 用户在 `是否有生效中的套餐` 中选择“否”并执行搜索
- **THEN** 系统 MUST 调用 `GET /api/admin/iot-cards/standalone`
- **AND** 请求 MUST 提交 `has_active_package=false`
- **AND** 前端 MUST NOT 因为该值为 `false` 而省略此参数
#### Scenario: Omit active package filter when not selected
- **GIVEN** 用户未选择 `是否有生效中的套餐`
- **WHEN** 用户执行 IoT 卡列表搜索、刷新或翻页
- **THEN** 列表请求 MUST NOT 携带 `has_active_package`
### Requirement: IoT Card Active Package Search Filter
The IoT card management page SHALL provide a search filter labeled `是否有生效中的套餐` and keep its selected state consistent across list interactions.
#### Scenario: Show yes and no options for active package filter
- **GIVEN** 用户打开后台 IoT 卡管理页
- **WHEN** 页面渲染搜索栏
- **THEN** 页面 MUST 显示 `是否有生效中的套餐` 筛选项
- **AND** 该筛选项 MUST 提供“是”和“否”两个可选值
#### Scenario: Reset clears active package filter
- **GIVEN** 用户已经在 `是否有生效中的套餐` 中选择了“是”或“否”
- **WHEN** 用户重置搜索条件
- **THEN** 页面 MUST 清空该筛选项
- **AND** 后续列表请求 MUST NOT 再携带 `has_active_package`

View File

@@ -0,0 +1,18 @@
## 1. Contract Alignment
- [ ] 1.1 为 `StandaloneCardQueryParams` 新增可选布尔参数 `has_active_package`
- [ ] 1.2 为 `DeviceQueryParams` 新增可选布尔参数 `has_active_package`
- [ ] 1.3 检查卡列表与设备列表请求参数组装逻辑,确保选择“否”时的 `has_active_package=false` 不会被误删
## 2. Search UI
- [ ] 2.1 在 IoT 卡管理页搜索栏新增 `是否有生效中的套餐` 筛选,并将选择结果提交为 `has_active_package`
- [ ] 2.2 在设备管理页搜索栏新增 `是否有生效中的套餐` 筛选,并将选择结果提交为 `has_active_package`
- [ ] 2.3 确保两个页面在搜索、重置、翻页和刷新时正确保留或清空该筛选条件
## 3. Verification
- [ ] 3.1 验证 IoT 卡管理页选择“是”时请求提交 `has_active_package=true`
- [ ] 3.2 验证 IoT 卡管理页选择“否”时请求提交 `has_active_package=false`,且不会被省略
- [ ] 3.3 验证设备管理页选择“是 / 否”时请求都能正确提交 `has_active_package`
- [ ] 3.4 验证两个页面重置搜索后,后续请求不再携带 `has_active_package`

View File

@@ -0,0 +1,31 @@
# Change: 更新批量号段分配数量提示与格式化展示
## Why
IoT 卡管理中的“批量分配”和“批量回收”已经支持按号段范围提交,但当前在输入起止 ICCID 后不会提示本次将覆盖多少张卡,运营人员仍需手动换算,容易误判批量范围。
同时,现有“批量设置套餐系列绑定”和“批量设置设备套餐系列绑定”虽然已经展示派生数量提示,但大范围操作时直接显示原始整数,可读性不足。需要将这些数量统一为带千分号的展示格式。
## What Changes
- 为 IoT 卡管理中的“批量分配”对话框新增号段范围派生数量提示,文案与现有系列绑定场景保持一致。
- 为 IoT 卡管理中的“批量回收”对话框新增号段范围派生数量提示,文案与现有系列绑定场景保持一致。
- 将以下批量 range 提示中的数量统一为千分号格式展示,例如 `1,000`
- IoT 卡“批量分配”
- IoT 卡“批量回收”
- IoT 卡“批量设置套餐系列绑定”
- 设备“批量设置设备套餐系列绑定”
- 不调整后端接口、请求参数或返回结构,仅补充前端展示与交互约束。
## Impact
- Affected specs:
- `iot-card-management`
- `iot-card-series-binding`
- `device-series-binding`
- Affected code:
- `src/views/asset-management/iot-card-management/index.vue`
- `src/views/asset-management/device-list/index.vue`
- Related changes:
- `update-asset-carrier-status-and-range-allocation-hints`
- `update-batch-series-binding-contract`

View File

@@ -0,0 +1,16 @@
## ADDED Requirements
### Requirement: Device Batch Series Binding Range Allocation Hint Formatting
The device batch series binding dialog SHALL render its derived device-range allocation-count hint using decimal thousands separators.
The displayed count MUST continue to map to the same accepted numeric range as `virtual_no_end - virtual_no_start + 1`.
#### Scenario: Format device batch series binding range count with thousands separators
- **GIVEN** 用户打开“批量设置设备套餐系列绑定”对话框
- **AND** 用户选择 `selection_type="range"`
- **WHEN** 用户输入一个有效设备号范围,且派生数量为 `1000`
- **THEN** 对话框 MUST 显示 `共分配1,000台设备`
- **AND** 对话框 MUST NOT 显示未分组的 `共分配1000台设备`
- **AND** 当任一端点变化时,格式化后的数量 MUST 立即更新

View File

@@ -0,0 +1,53 @@
## ADDED Requirements
### Requirement: IoT Card Batch Allocation Range Allocation Hint
The IoT card batch allocation dialog SHALL provide a derived allocation-count hint for ICCID range selection.
The hint MUST appear immediately below the `iccid_start` and `iccid_end` inputs when `selection_type="range"`.
The count MUST be computed with exact integer arithmetic as `iccid_end - iccid_start + 1` so that long ICCID values do not lose precision.
When displayed, the count MUST use decimal thousands separators, for example `1,000`.
#### Scenario: Show allocation count for a valid ICCID range in batch allocation
- **GIVEN** 用户打开“批量分配”对话框
- **AND** 用户选择 `selection_type="range"`
- **WHEN** 用户输入有效的 `iccid_start``iccid_end`,且计算结果为正整数
- **THEN** 对话框 MUST 显示 `共分配xxx张卡`
- **AND** `xxx` MUST 等于 `iccid_end - iccid_start + 1`
- **AND** 当数量大于等于 `1000` 时,`xxx` MUST 使用千分号格式展示
- **AND** 当任一端点变化时,提示 MUST 立即更新
#### Scenario: Hide allocation count for incomplete or invalid ICCID ranges in batch allocation
- **GIVEN** 用户选择 `selection_type="range"`
- **WHEN** 任一起止 ICCID 为空、无法按整数计算,或计算结果小于 `1`
- **THEN** 对话框 MUST NOT 显示误导性的数量提示
### Requirement: IoT Card Batch Recall Range Allocation Hint
The IoT card batch recall dialog SHALL provide a derived allocation-count hint for ICCID range selection.
The hint MUST appear immediately below the `iccid_start` and `iccid_end` inputs when `selection_type="range"`.
The count MUST be computed with exact integer arithmetic as `iccid_end - iccid_start + 1` so that long ICCID values do not lose precision.
When displayed, the count MUST use decimal thousands separators, for example `1,000`.
#### Scenario: Show allocation count for a valid ICCID range in batch recall
- **GIVEN** 用户打开“批量回收”对话框
- **AND** 用户选择 `selection_type="range"`
- **WHEN** 用户输入有效的 `iccid_start``iccid_end`,且计算结果为正整数
- **THEN** 对话框 MUST 显示 `共分配xxx张卡`
- **AND** `xxx` MUST 等于 `iccid_end - iccid_start + 1`
- **AND** 当数量大于等于 `1000` 时,`xxx` MUST 使用千分号格式展示
- **AND** 当任一端点变化时,提示 MUST 立即更新
#### Scenario: Hide allocation count for incomplete or invalid ICCID ranges in batch recall
- **GIVEN** 用户选择 `selection_type="range"`
- **WHEN** 任一起止 ICCID 为空、无法按整数计算,或计算结果小于 `1`
- **THEN** 对话框 MUST NOT 显示误导性的数量提示

View File

@@ -0,0 +1,16 @@
## ADDED Requirements
### Requirement: IoT Card Batch Series Binding Range Allocation Hint Formatting
The IoT card batch series binding dialog SHALL render its derived ICCID range allocation-count hint using decimal thousands separators.
The displayed count MUST continue to be derived from exact integer arithmetic as `iccid_end - iccid_start + 1`.
#### Scenario: Format batch series binding range count with thousands separators
- **GIVEN** 用户打开“批量设置套餐系列绑定”对话框
- **AND** 用户选择 `selection_type="range"`
- **WHEN** 用户输入一个有效 ICCID 范围,且派生数量为 `1000`
- **THEN** 对话框 MUST 显示 `共分配1,000张卡`
- **AND** 对话框 MUST NOT 显示未分组的 `共分配1000张卡`
- **AND** 当任一端点变化时,格式化后的数量 MUST 立即更新

View File

@@ -0,0 +1,10 @@
## 1. Specification
- [x] 1.1 为 IoT 卡管理“批量分配”补充号段范围派生数量提示 requirement并明确无效范围时不展示提示
- [x] 1.2 为 IoT 卡管理“批量回收”补充号段范围派生数量提示 requirement并明确无效范围时不展示提示
- [x] 1.3 为 IoT 卡“批量设置套餐系列绑定”和设备“批量设置设备套餐系列绑定”补充千分号格式化 requirement
- [x] 1.4 明确所有新增或既有的 `共分配` range 提示都使用统一的十进制千分位分组格式
## 2. Validation
- [x] 2.1 运行 `openspec validate update-batch-range-count-hints-formatting --strict`