## ADDED Requirements ### Requirement: Asset Estimated Final Expiry Contract 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 - **GIVEN** 用户查询后台资产详情 - **WHEN** `GET /api/admin/assets/resolve/{identifier}` returns `expiry_estimate_status=exact` - **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 - **GIVEN** 用户查询后台资产详情 - **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 The admin asset information view SHALL display one asset-level field labeled `预计套餐到期时间` for the current primary package and all queued primary packages, without replacing individual package expiry dates in package details. #### Scenario: Display an exact final expiry date - **GIVEN** 资产详情返回 `expiry_estimate_status=exact` - **AND** `estimated_final_expires_at` has a value - **WHEN** 页面渲染卡资产或设备资产基础信息 - **THEN** 页面 MUST display `预计套餐到期时间` - **AND** 页面 MUST format and display `estimated_final_expires_at` #### Scenario: Display activation-pending final expiry - **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** 资产没有当前或排队主套餐 - **AND** `estimated_final_expires_at` is null or absent - **WHEN** 页面渲染资产基础信息 - **THEN** `预计套餐到期时间` MUST display a stable placeholder - **AND** 页面 MUST NOT substitute the current package detail expiry date #### Scenario: Highlight backend-designated expiring asset - **GIVEN** 资产详情返回 `is_expiring=true` - **WHEN** 页面渲染 `预计套餐到期时间` - **THEN** 页面 MUST apply the expiring visual treatment using `days_until_final_expiry` - **AND** 页面 MUST NOT derive whether the asset is expiring from a locally calculated date difference #### Scenario: Preserve package detail expiry semantics - **GIVEN** 用户查看资产详情中的套餐明细 - **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