89 lines
4.9 KiB
Markdown
89 lines
4.9 KiB
Markdown
## ADDED Requirements
|
|
|
|
### Requirement: IoT Card Enterprise Authorization Filters
|
|
|
|
The IoT card management page SHALL support filtering standalone cards by effective enterprise authorization.
|
|
|
|
#### Scenario: Filter cards by authorized enterprise ID
|
|
|
|
- **GIVEN** 用户在 IoT 卡管理搜索栏选择或输入企业 ID
|
|
- **WHEN** 用户执行搜索
|
|
- **THEN** 系统 MUST send `authorized_enterprise_id` to the IoT card list API
|
|
- **AND** the list MUST only show cards currently authorized to that enterprise according to the backend response
|
|
|
|
#### Scenario: Filter cards by enterprise authorization status
|
|
|
|
- **GIVEN** 用户在 IoT 卡管理搜索栏选择企业授权状态
|
|
- **WHEN** 用户选择“已授权”并搜索
|
|
- **THEN** 系统 MUST send `is_authorized_to_enterprise=true`
|
|
- **WHEN** 用户选择“未授权”并搜索
|
|
- **THEN** 系统 MUST send `is_authorized_to_enterprise=false`
|
|
- **AND** clearing the filter MUST omit `is_authorized_to_enterprise` from the request
|
|
|
|
### Requirement: IoT Card Enterprise Authorization Actions
|
|
|
|
The IoT card management page SHALL provide enterprise card authorization actions directly in the table header before the export button.
|
|
|
|
#### Scenario: Show permission-controlled card authorization buttons
|
|
|
|
- **GIVEN** 用户访问 IoT 卡管理页面
|
|
- **WHEN** the table header renders
|
|
- **THEN** the “授权卡给企业” button MUST appear to the left of the “导出” button only when the user has permission `iot_card:authorize_enterprise`
|
|
- **AND** the “回收卡授权” button MUST appear to the left of the “导出” button only when the user has permission `iot_card:recall_enterprise_authorization`
|
|
|
|
#### Scenario: Authorize selected cards to an enterprise
|
|
|
|
- **GIVEN** 用户在 IoT 卡管理列表选中了卡
|
|
- **WHEN** 用户点击“授权卡给企业”并选择目标企业
|
|
- **AND** 用户选择 `list` 选取方式
|
|
- **THEN** 系统 MUST call `POST /api/admin/enterprises/{id}/allocate-cards`
|
|
- **AND** the request body MUST include `selection_type: 'list'`
|
|
- **AND** the request body MUST include selected row ICCIDs as `iccids`
|
|
- **AND** the UI MUST display success count, fail count, and failed item reasons from the response
|
|
- **AND** the card list MUST refresh after any successful authorization
|
|
|
|
#### Scenario: Authorize cards by range
|
|
|
|
- **GIVEN** 用户打开“授权卡给企业” dialog
|
|
- **WHEN** 用户选择 `range` 选取方式并填写起始和结束 ICCID
|
|
- **THEN** 系统 MUST call `POST /api/admin/enterprises/{id}/allocate-cards`
|
|
- **AND** the request body MUST include `selection_type: 'range'`, `iccid_start`, `iccid_end`, and optional `remark`
|
|
|
|
#### Scenario: Authorize cards by filters
|
|
|
|
- **GIVEN** 用户打开“授权卡给企业” dialog
|
|
- **WHEN** 用户选择 `filter` 选取方式并确认
|
|
- **THEN** 系统 MUST call `POST /api/admin/enterprises/{id}/allocate-cards`
|
|
- **AND** the request body MUST include `selection_type: 'filter'`
|
|
- **AND** filter fields MUST be populated from the dialog filter form or current list filters when applicable, including available values such as `carrier_id`, `shop_id`, `shop_ids`, `batch_no`, and `iccid`
|
|
- **AND** empty filter fields MUST be omitted
|
|
|
|
#### Scenario: Authorize cards filter selects shop from cascade tree
|
|
|
|
- **GIVEN** 用户在“授权卡给企业” dialog 中选择 `filter` 选取方式
|
|
- **WHEN** the shop filter field renders
|
|
- **THEN** the field MUST use the same lazy cascade tree pattern as the “上级店铺” field in the add-shop dialog
|
|
- **AND** it MUST load children through `ShopService.getShopsCascade({ parent_id })`
|
|
- **AND** it MUST allow selecting any level with `checkStrictly: true`
|
|
- **AND** when submitted, the request MUST use the last selected cascade node ID as `shop_id`
|
|
- **AND** clearing the cascade field MUST omit `shop_id`
|
|
|
|
#### Scenario: Recall selected card authorization
|
|
|
|
- **GIVEN** 用户在 IoT 卡管理列表选中了 currently enterprise-authorized cards
|
|
- **WHEN** 用户点击“回收卡授权”
|
|
- **THEN** the UI MUST require a source enterprise ID unless it can safely infer one from `authorized_enterprise_id` or selected row data returned by the list API
|
|
- **WHEN** 用户 confirms `list` recall
|
|
- **THEN** 系统 MUST call `POST /api/admin/enterprises/{id}/recall-cards`
|
|
- **AND** the request body MUST include `selection_type: 'list'` and selected row ICCIDs as `iccids`
|
|
- **AND** the UI MUST display success count, fail count, failed item reasons, and any `recalled_devices`
|
|
- **AND** the card list MUST refresh after any successful recall
|
|
|
|
#### Scenario: Recall card authorization by range or filters
|
|
|
|
- **GIVEN** 用户打开“回收卡授权” dialog
|
|
- **WHEN** 用户选择 `range` or `filter` selection mode and confirms
|
|
- **THEN** 系统 MUST call `POST /api/admin/enterprises/{id}/recall-cards`
|
|
- **AND** the request body MUST match the selected mode using the contract in `docs/授权、回收.md`
|
|
- **AND** empty filter fields MUST be omitted
|