feat: 预计最终到期时间展示新增具体
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 6m49s

This commit is contained in:
luo
2026-07-24 09:31:11 +08:00
parent 127fdb560b
commit 15122e225a
13 changed files with 133 additions and 38 deletions

View File

@@ -2,7 +2,7 @@
### Requirement: Asset Estimated Final Expiry Contract
The admin asset information integration SHALL preserve `estimated_final_expires_at`, `days_until_final_expiry`, `expiry_estimate_status`, and `is_expiring` returned by `GET /api/admin/assets/resolve/{identifier}`.
The admin asset information integration SHALL preserve the five backend fields `estimated_final_expires_at`, `days_until_final_expiry`, `expiry_estimate_status`, `expiry_estimate_status_name`, and `is_expiring` returned by `GET /api/admin/assets/resolve/{identifier}`. `estimated_final_expires_at` SHALL be an RFC3339 string or `null`, `days_until_final_expiry` SHALL be an integer or `null`, and `expiry_estimate_status` SHALL be one of `exact`, `waiting_activation`, `none`, or `invalid_data`. This requirement applies only to the admin frontend and excludes C-end asset information.
#### Scenario: Preserve an exact final expiry estimate
@@ -11,6 +11,15 @@ The admin asset information integration SHALL preserve `estimated_final_expires_
- **THEN** 前端状态 MUST preserve `estimated_final_expires_at` as `string | null`
- **AND** 前端状态 MUST preserve `days_until_final_expiry` as `number | null`
- **AND** 前端状态 MUST preserve `is_expiring` as a boolean
- **AND** 前端状态 MUST preserve `expiry_estimate_status_name` as the backend-provided status name
#### Scenario: Preserve null fields for non-exact estimates
- **GIVEN** 用户查询后台资产详情
- **WHEN** `expiry_estimate_status` is `waiting_activation`, `none`, or `invalid_data`
- **THEN** `estimated_final_expires_at` MUST be preserved as `null`
- **AND** `days_until_final_expiry` MUST be preserved as `null`
- **AND** 前端 MUST NOT calculate either field
#### Scenario: Preserve an unavailable final expiry estimate
@@ -18,6 +27,7 @@ The admin asset information integration SHALL preserve `estimated_final_expires_
- **WHEN** 接口返回待激活或其他不可预计的 `expiry_estimate_status`
- **THEN** 前端状态 MUST preserve `expiry_estimate_status`
- **AND** 前端 MUST NOT derive `estimated_final_expires_at` from current-package or package-detail fields
- **AND** 前端 MUST NOT use `expiry_estimate_status_name` as a substitute for the status enum when choosing the display rule
### Requirement: Asset Estimated Final Expiry Display
@@ -33,11 +43,18 @@ The admin asset information view SHALL display one asset-level field labeled `
#### Scenario: Display activation-pending final expiry
- **GIVEN** 资产详情返回等待激活等不可预计的 `expiry_estimate_status`
- **GIVEN** 资产详情返回 `expiry_estimate_status=waiting_activation`
- **WHEN** 页面渲染卡资产或设备资产基础信息
- **THEN** `预计套餐到期时间` MUST display `待激活后起算`
- **AND** 页面 MUST NOT display a fabricated date
#### Scenario: Handle an unknown estimate status safely
- **GIVEN** 资产详情返回未约定的 `expiry_estimate_status`
- **WHEN** 页面渲染资产基础信息
- **THEN** 页面 MUST treat the estimate as unavailable
- **AND** 页面 MUST NOT display `estimated_final_expires_at` as a date
#### Scenario: Display no-package placeholder
- **GIVEN** 资产没有当前或排队主套餐
@@ -59,3 +76,11 @@ The admin asset information view SHALL display one asset-level field labeled `
- **WHEN** 页面渲染单个套餐的到期时间
- **THEN** 页面 MUST continue to display that package's own expiry field in the package detail context
- **AND** 页面 MUST NOT replace it with `estimated_final_expires_at`
#### Scenario: Display no-package and invalid-data statuses
- **GIVEN** 资产详情返回 `expiry_estimate_status=none``expiry_estimate_status=invalid_data`
- **WHEN** 页面渲染资产基础信息
- **THEN** `none` MUST display a stable empty placeholder
- **AND** `invalid_data` MUST display `数据异常`
- **AND** 页面 MUST NOT display a fabricated date

View File

@@ -2,7 +2,7 @@
### Requirement: Device Estimated Final Expiry Display
The device management list integration SHALL preserve and display the backend device-level estimated final package expiry fields without traversing bound cards or calculating package continuation dates in the frontend.
The device management list integration SHALL preserve and display the five backend device-level estimated final package expiry fields `estimated_final_expires_at`, `days_until_final_expiry`, `expiry_estimate_status`, `expiry_estimate_status_name`, and `is_expiring` returned in `data.items[]` by `GET /api/admin/devices`. The status SHALL be one of `exact`, `waiting_activation`, `none`, or `invalid_data`; non-`exact` records SHALL have `estimated_final_expires_at=null` and `days_until_final_expiry=null`. The frontend SHALL NOT traverse bound cards or calculate package continuation dates. This requirement applies only to the admin device list.
#### Scenario: Display exact device final expiry estimate
@@ -13,11 +13,26 @@ The device management list integration SHALL preserve and display the backend de
#### Scenario: Display activation-pending device final expiry
- **GIVEN** 设备列表接口返回待激活等不可预计的 `expiry_estimate_status`
- **GIVEN** 设备列表接口返回 `expiry_estimate_status=waiting_activation`
- **WHEN** 页面渲染设备列表行
- **THEN** `预计套餐到期时间` MUST display `待激活后起算`
- **AND** 页面 MUST NOT traverse bound cards or display a fabricated date
#### Scenario: Display device estimate status names for non-exact states
- **GIVEN** 设备列表接口返回 `expiry_estimate_status=none``expiry_estimate_status=invalid_data`
- **WHEN** 页面渲染设备列表行
- **THEN** `none` MUST display a stable empty placeholder
- **AND** `invalid_data` MUST display `数据异常`
- **AND** 页面 MUST use the status enum to choose the display rule
#### Scenario: Preserve null fields for non-exact device estimates
- **GIVEN** 设备列表接口返回 `expiry_estimate_status=none``expiry_estimate_status=invalid_data`
- **THEN** `estimated_final_expires_at` MUST be `null`
- **AND** `days_until_final_expiry` MUST be `null`
- **AND** 页面 MUST NOT derive either field from绑定卡或套餐数据
#### Scenario: Highlight expiring device without reordering
- **GIVEN** 设备列表接口返回 `is_expiring=true` and `days_until_final_expiry`
@@ -31,3 +46,9 @@ The device management list integration SHALL preserve and display the backend de
- **WHEN** 页面渲染预计套餐到期时间列
- **THEN** 页面 MUST display a stable placeholder
- **AND** 页面 MUST NOT use an individual package expiry as a substitute
#### Scenario: Preserve device status name without using it for business calculation
- **WHEN** 设备列表接口返回 `expiry_estimate_status_name`
- **THEN** 前端类型 MUST preserve the field
- **AND** 页面 MUST NOT calculate or replace the backend status name

View File

@@ -2,7 +2,7 @@
### Requirement: IoT Card Estimated Final Expiry Display
The IoT card management list integration SHALL preserve and display the backend asset-level estimated final package expiry fields without calculating package continuation dates in the frontend.
The IoT card management list integration SHALL preserve and display the five backend asset-level estimated final package expiry fields `estimated_final_expires_at`, `days_until_final_expiry`, `expiry_estimate_status`, `expiry_estimate_status_name`, and `is_expiring` returned in `data.items[]` by `GET /api/admin/iot-cards/standalone`. The status SHALL be one of `exact`, `waiting_activation`, `none`, or `invalid_data`; non-`exact` records SHALL have `estimated_final_expires_at=null` and `days_until_final_expiry=null`. The frontend SHALL NOT calculate package continuation dates. This requirement applies only to the admin IoT card list.
#### Scenario: Display exact card final expiry estimate
@@ -13,11 +13,26 @@ The IoT card management list integration SHALL preserve and display the backend
#### Scenario: Display activation-pending card final expiry
- **GIVEN** 卡列表接口返回待激活等不可预计的 `expiry_estimate_status`
- **GIVEN** 卡列表接口返回 `expiry_estimate_status=waiting_activation`
- **WHEN** 页面渲染卡列表行
- **THEN** `预计套餐到期时间` MUST display `待激活后起算`
- **AND** 页面 MUST NOT calculate or display a fabricated date
#### Scenario: Display card estimate status names for non-exact states
- **GIVEN** 卡列表接口返回 `expiry_estimate_status=none``expiry_estimate_status=invalid_data`
- **WHEN** 页面渲染卡列表行
- **THEN** `none` MUST display a stable empty placeholder
- **AND** `invalid_data` MUST display `数据异常`
- **AND** 页面 MUST use the status enum to choose the display rule
#### Scenario: Preserve null fields for non-exact card estimates
- **GIVEN** 卡列表接口返回 `expiry_estimate_status=none``expiry_estimate_status=invalid_data`
- **THEN** `estimated_final_expires_at` MUST be `null`
- **AND** `days_until_final_expiry` MUST be `null`
- **AND** 页面 MUST NOT derive either field from套餐数据
#### Scenario: Highlight expiring card without reordering
- **GIVEN** 卡列表接口返回 `is_expiring=true` and `days_until_final_expiry`
@@ -31,3 +46,9 @@ The IoT card management list integration SHALL preserve and display the backend
- **WHEN** 页面渲染预计套餐到期时间列
- **THEN** 页面 MUST display a stable placeholder
- **AND** 页面 MUST NOT use an individual package expiry as a substitute
#### Scenario: Preserve card status name without using it for business calculation
- **WHEN** 卡列表接口返回 `expiry_estimate_status_name`
- **THEN** 前端类型 MUST preserve the field
- **AND** 页面 MUST NOT calculate or replace the backend status name