From 59167d2630caef5ecbdd8861b83de3312c1f7954 Mon Sep 17 00:00:00 2001 From: sexygoat <1538832180@qq.com> Date: Tue, 19 May 2026 15:14:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8D=A1/=E8=AE=BE=E5=A4=87=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E6=9C=89=E7=94=9F=E6=95=88=E5=A5=97=E9=A4=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../proposal.md | 43 + .../specs/device-management/spec.md | 44 + .../specs/iot-card-management/spec.md | 44 + .../tasks.md | 18 + .../proposal.md | 31 + .../specs/device-series-binding/spec.md | 16 + .../specs/iot-card-management/spec.md | 53 + .../specs/iot-card-series-binding/spec.md | 16 + .../tasks.md | 10 + src/api/modules/card.ts | 8 +- src/types/api/card.ts | 3 + src/types/api/device.ts | 1 + .../asset-management/device-list/index.vue | 3982 ++++++++--------- .../iot-card-management/index.vue | 3486 +++++++-------- 14 files changed, 3792 insertions(+), 3963 deletions(-) create mode 100644 openspec/changes/update-asset-search-has-active-package-filter/proposal.md create mode 100644 openspec/changes/update-asset-search-has-active-package-filter/specs/device-management/spec.md create mode 100644 openspec/changes/update-asset-search-has-active-package-filter/specs/iot-card-management/spec.md create mode 100644 openspec/changes/update-asset-search-has-active-package-filter/tasks.md create mode 100644 openspec/changes/update-batch-range-count-hints-formatting/proposal.md create mode 100644 openspec/changes/update-batch-range-count-hints-formatting/specs/device-series-binding/spec.md create mode 100644 openspec/changes/update-batch-range-count-hints-formatting/specs/iot-card-management/spec.md create mode 100644 openspec/changes/update-batch-range-count-hints-formatting/specs/iot-card-series-binding/spec.md create mode 100644 openspec/changes/update-batch-range-count-hints-formatting/tasks.md diff --git a/openspec/changes/update-asset-search-has-active-package-filter/proposal.md b/openspec/changes/update-asset-search-has-active-package-filter/proposal.md new file mode 100644 index 0000000..5c16acc --- /dev/null +++ b/openspec/changes/update-asset-search-has-active-package-filter/proposal.md @@ -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: + - 无 diff --git a/openspec/changes/update-asset-search-has-active-package-filter/specs/device-management/spec.md b/openspec/changes/update-asset-search-has-active-package-filter/specs/device-management/spec.md new file mode 100644 index 0000000..78736e0 --- /dev/null +++ b/openspec/changes/update-asset-search-has-active-package-filter/specs/device-management/spec.md @@ -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` diff --git a/openspec/changes/update-asset-search-has-active-package-filter/specs/iot-card-management/spec.md b/openspec/changes/update-asset-search-has-active-package-filter/specs/iot-card-management/spec.md new file mode 100644 index 0000000..dde03bd --- /dev/null +++ b/openspec/changes/update-asset-search-has-active-package-filter/specs/iot-card-management/spec.md @@ -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` diff --git a/openspec/changes/update-asset-search-has-active-package-filter/tasks.md b/openspec/changes/update-asset-search-has-active-package-filter/tasks.md new file mode 100644 index 0000000..d75eb44 --- /dev/null +++ b/openspec/changes/update-asset-search-has-active-package-filter/tasks.md @@ -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` diff --git a/openspec/changes/update-batch-range-count-hints-formatting/proposal.md b/openspec/changes/update-batch-range-count-hints-formatting/proposal.md new file mode 100644 index 0000000..de03584 --- /dev/null +++ b/openspec/changes/update-batch-range-count-hints-formatting/proposal.md @@ -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` diff --git a/openspec/changes/update-batch-range-count-hints-formatting/specs/device-series-binding/spec.md b/openspec/changes/update-batch-range-count-hints-formatting/specs/device-series-binding/spec.md new file mode 100644 index 0000000..89a69a1 --- /dev/null +++ b/openspec/changes/update-batch-range-count-hints-formatting/specs/device-series-binding/spec.md @@ -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 立即更新 diff --git a/openspec/changes/update-batch-range-count-hints-formatting/specs/iot-card-management/spec.md b/openspec/changes/update-batch-range-count-hints-formatting/specs/iot-card-management/spec.md new file mode 100644 index 0000000..cf65239 --- /dev/null +++ b/openspec/changes/update-batch-range-count-hints-formatting/specs/iot-card-management/spec.md @@ -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 显示误导性的数量提示 diff --git a/openspec/changes/update-batch-range-count-hints-formatting/specs/iot-card-series-binding/spec.md b/openspec/changes/update-batch-range-count-hints-formatting/specs/iot-card-series-binding/spec.md new file mode 100644 index 0000000..40fddf4 --- /dev/null +++ b/openspec/changes/update-batch-range-count-hints-formatting/specs/iot-card-series-binding/spec.md @@ -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 立即更新 diff --git a/openspec/changes/update-batch-range-count-hints-formatting/tasks.md b/openspec/changes/update-batch-range-count-hints-formatting/tasks.md new file mode 100644 index 0000000..ea3afb8 --- /dev/null +++ b/openspec/changes/update-batch-range-count-hints-formatting/tasks.md @@ -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` diff --git a/src/api/modules/card.ts b/src/api/modules/card.ts index 54d96e9..6c0d622 100644 --- a/src/api/modules/card.ts +++ b/src/api/modules/card.ts @@ -24,6 +24,8 @@ import type { ImportIotCardResponse, IotCardImportTask, IotCardImportTaskDetail, + StandaloneCardQueryParams, + StandaloneIotCard, BatchSetCardSeriesBindingRequest, BatchSetCardSeriesBindingResponse } from '@/types/api' @@ -318,8 +320,10 @@ export class CardService extends BaseService { * 获取单卡列表(未绑定设备) * @param params 查询参数 */ - static getStandaloneIotCards(params?: any): Promise> { - return this.getPage('/api/admin/iot-cards/standalone', params) + static getStandaloneIotCards( + params?: StandaloneCardQueryParams + ): Promise> { + return this.getPage('/api/admin/iot-cards/standalone', params) } /** diff --git a/src/types/api/card.ts b/src/types/api/card.ts index 418f3a3..82bb6e2 100644 --- a/src/types/api/card.ts +++ b/src/types/api/card.ts @@ -332,6 +332,9 @@ export enum StandaloneCardStatus { // 单卡查询参数 export interface StandaloneCardQueryParams extends PaginationParams { + has_active_package?: boolean // has active package filter + carrier_name?: string // carrier name filter + is_standalone?: boolean // standalone filter status?: StandaloneCardStatus // 状态 carrier_id?: number // 运营商ID shop_id?: number // 分销商ID diff --git a/src/types/api/device.ts b/src/types/api/device.ts index 8ff177a..60189f4 100644 --- a/src/types/api/device.ts +++ b/src/types/api/device.ts @@ -58,6 +58,7 @@ export interface Device { // 设备查询参数 export interface DeviceQueryParams extends PaginationParams { + has_active_package?: boolean // has active package filter virtual_no?: string // 虚拟号(模糊查询,原 device_no) device_name?: string // 设备名称(模糊查询) status?: DeviceStatus // 状态 diff --git a/src/views/asset-management/device-list/index.vue b/src/views/asset-management/device-list/index.vue index a46a213..6a0e680 100644 --- a/src/views/asset-management/device-list/index.vue +++ b/src/views/asset-management/device-list/index.vue @@ -2,63 +2,32 @@
- + - + - +