From 15122e225a968fa49ff35b59d2a8fbae6164c453 Mon Sep 17 00:00:00 2001 From: luo Date: Fri, 24 Jul 2026 09:31:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=A2=84=E8=AE=A1=E6=9C=80=E7=BB=88?= =?UTF-8?q?=E5=88=B0=E6=9C=9F=E6=97=B6=E9=97=B4=E5=B1=95=E7=A4=BA=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=85=B7=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../design.md | 5 ++-- .../proposal.md | 9 ++++-- .../specs/asset-information/spec.md | 29 +++++++++++++++++-- .../specs/device-management/spec.md | 25 ++++++++++++++-- .../specs/iot-card-management/spec.md | 25 ++++++++++++++-- .../tasks.md | 29 ++++++++++--------- src/types/api/asset.ts | 3 +- src/types/api/card.ts | 4 ++- src/types/api/device.ts | 4 ++- src/utils/business/expiryEstimate.ts | 22 +++++++++----- .../components/BasicInfoCard.vue | 10 +++++-- .../composables/useAssetInfo.ts | 1 + .../asset-information/types.ts | 5 ++-- 13 files changed, 133 insertions(+), 38 deletions(-) diff --git a/openspec/changes/add-asset-estimated-final-expiry-display/design.md b/openspec/changes/add-asset-estimated-final-expiry-display/design.md index 976be2b..56b344b 100644 --- a/openspec/changes/add-asset-estimated-final-expiry-display/design.md +++ b/openspec/changes/add-asset-estimated-final-expiry-display/design.md @@ -15,7 +15,8 @@ ## Decisions -- Decision: 统一使用资产详情和资产列表响应中的 `estimated_final_expires_at`、`days_until_final_expiry`、`expiry_estimate_status`、`is_expiring`,不调用额外计算接口。 +- Decision: 统一使用以下五个后台响应字段:`estimated_final_expires_at`、`days_until_final_expiry`、`expiry_estimate_status`、`expiry_estimate_status_name`、`is_expiring`,不调用额外计算接口。 +- Decision: `expiry_estimate_status` 仅使用 `exact`、`waiting_activation`、`none`、`invalid_data`。除 `exact` 外,`estimated_final_expires_at` 和 `days_until_final_expiry` 必须为 `null`;已过期的 `exact` 资产允许返回负数剩余天数。 - Decision: 仅当 `expiry_estimate_status=exact` 且存在 `estimated_final_expires_at` 时格式化展示日期;不可预计状态展示“待激活后起算”。 - Decision: `is_expiring=true` 是临期样式的唯一触发条件,`days_until_final_expiry` 只作为剩余天数展示或样式辅助信息,前端不自行判定临期阈值。 - Decision: 普通卡和设备列表保持既有服务端返回顺序与前端排序行为,不因临期字段重排。 @@ -37,4 +38,4 @@ ## Open Questions -- `expiry_estimate_status` 除 `exact` 和待激活状态外的完整枚举及对应文案由后端接口文档确认;本提案要求未知状态不得伪造日期。 +- 后端若返回未约定的状态值,前端不得按 `estimated_final_expires_at` 是否为空展示日期,应按不可预计状态处理。 diff --git a/openspec/changes/add-asset-estimated-final-expiry-display/proposal.md b/openspec/changes/add-asset-estimated-final-expiry-display/proposal.md index 3c089d2..bc9c9f4 100644 --- a/openspec/changes/add-asset-estimated-final-expiry-display/proposal.md +++ b/openspec/changes/add-asset-estimated-final-expiry-display/proposal.md @@ -7,11 +7,13 @@ ## What Changes - 在资产详情、IoT 卡列表和设备列表增加统一的 `预计套餐到期时间` 展示。 -- 资产详情接口和资产列表响应支持 `estimated_final_expires_at`、`days_until_final_expiry`、`expiry_estimate_status` 和 `is_expiring` 字段。 +- 资产详情接口和资产列表响应支持统一的 5 个字段:`estimated_final_expires_at`、`days_until_final_expiry`、`expiry_estimate_status`、`expiry_estimate_status_name` 和 `is_expiring`。 +- `expiry_estimate_status` 使用 `exact`、`waiting_activation`、`none`、`invalid_data` 四种状态;非 `exact` 状态下日期和剩余天数字段必须为 `null`。 - 当 `expiry_estimate_status=exact` 时,展示后端返回的 `estimated_final_expires_at`。 - 当套餐尚待激活等无法预计最终日期时,展示“待激活后起算”,不得伪造日期。 - 当 `is_expiring=true` 时,按后端返回的剩余天数使用临期颜色提示;普通资产列表不得因临期状态改变既有排序。 - 当前套餐自身的到期时间继续仅在套餐明细中展示;前端不得叠加套餐时长计算预计最终到期时间。 +- 本次仅覆盖后台资产详情、IoT 卡列表和设备列表,不处理 C 端资产信息接口或页面。 ## Impact @@ -30,6 +32,9 @@ - `src/views/asset-management/device-list/index.vue` - API contracts: - `GET /api/admin/assets/resolve/{identifier}` - - IoT 卡和设备资产列表接口 + - `GET /api/admin/iot-cards/standalone` + - `GET /api/admin/devices` - Dependencies: - 后端在资产详情与资产列表响应中返回预计最终到期字段。 +- Out of scope: + - `GET /api/c/v1/asset/info` 及 C 端资产信息页面 diff --git a/openspec/changes/add-asset-estimated-final-expiry-display/specs/asset-information/spec.md b/openspec/changes/add-asset-estimated-final-expiry-display/specs/asset-information/spec.md index cbe174b..69bf220 100644 --- a/openspec/changes/add-asset-estimated-final-expiry-display/specs/asset-information/spec.md +++ b/openspec/changes/add-asset-estimated-final-expiry-display/specs/asset-information/spec.md @@ -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 diff --git a/openspec/changes/add-asset-estimated-final-expiry-display/specs/device-management/spec.md b/openspec/changes/add-asset-estimated-final-expiry-display/specs/device-management/spec.md index 39c689d..50a4e9a 100644 --- a/openspec/changes/add-asset-estimated-final-expiry-display/specs/device-management/spec.md +++ b/openspec/changes/add-asset-estimated-final-expiry-display/specs/device-management/spec.md @@ -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 diff --git a/openspec/changes/add-asset-estimated-final-expiry-display/specs/iot-card-management/spec.md b/openspec/changes/add-asset-estimated-final-expiry-display/specs/iot-card-management/spec.md index eb6eb20..8b56e7f 100644 --- a/openspec/changes/add-asset-estimated-final-expiry-display/specs/iot-card-management/spec.md +++ b/openspec/changes/add-asset-estimated-final-expiry-display/specs/iot-card-management/spec.md @@ -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 diff --git a/openspec/changes/add-asset-estimated-final-expiry-display/tasks.md b/openspec/changes/add-asset-estimated-final-expiry-display/tasks.md index 7ce9184..4a41301 100644 --- a/openspec/changes/add-asset-estimated-final-expiry-display/tasks.md +++ b/openspec/changes/add-asset-estimated-final-expiry-display/tasks.md @@ -1,25 +1,26 @@ ## 1. API Contracts And Types -- [ ] 1.1 扩展资产详情响应和资产信息页面状态,支持 `estimated_final_expires_at`、`days_until_final_expiry`、`expiry_estimate_status`、`is_expiring`。 -- [ ] 1.2 扩展 IoT 卡和设备列表项类型,支持预计最终到期字段。 +- [x] 1.1 扩展资产详情响应和资产信息页面状态,支持 5 个预计最终到期字段:`estimated_final_expires_at`、`days_until_final_expiry`、`expiry_estimate_status`、`expiry_estimate_status_name`、`is_expiring`。 +- [x] 1.2 扩展 IoT 卡和设备列表项类型,支持 5 个预计最终到期字段;不处理 C 端字段。 +- [x] 1.3 校验四种状态及字段约束:`exact` 可返回日期和剩余天数,其他状态的 `estimated_final_expires_at` 与 `days_until_final_expiry` 必须为 `null`。 ## 2. Asset Information -- [ ] 2.1 将资产解析接口返回的预计最终到期字段映射到资产详情页面状态。 -- [ ] 2.2 在资产详情卡和设备基础信息中展示“预计套餐到期时间”。 -- [ ] 2.3 `expiry_estimate_status=exact` 时格式化显示 `estimated_final_expires_at`;待激活等不可预计状态显示“待激活后起算”。 -- [ ] 2.4 `is_expiring=true` 时按 `days_until_final_expiry` 应用临期样式,不根据日期或天数自行推导临期状态。 +- [x] 2.1 将资产解析接口返回的预计最终到期字段映射到资产详情页面状态。 +- [x] 2.2 在资产详情卡和设备基础信息中展示“预计套餐到期时间”。 +- [x] 2.3 按 `expiry_estimate_status` 展示:`exact` 显示日期,`waiting_activation` 显示“待激活后起算”,`none` 显示占位,`invalid_data` 显示“数据异常”。 +- [x] 2.4 `is_expiring=true` 时按 `days_until_final_expiry` 应用临期样式,不根据日期或天数自行推导临期状态。 ## 3. Asset Lists -- [ ] 3.1 在 IoT 卡列表新增“预计套餐到期时间”可配置列,显示接口返回的预计日期或“待激活后起算”。 -- [ ] 3.2 在设备列表新增“预计套餐到期时间”可配置列,显示接口返回的预计日期或“待激活后起算”。 -- [ ] 3.3 在两个列表对 `is_expiring=true` 的预计到期时间使用临期样式,且不改变现有列表排序。 +- [x] 3.1 在 IoT 卡列表新增“预计套餐到期时间”可配置列,显示接口返回的预计日期或“待激活后起算”。 +- [x] 3.2 在设备列表新增“预计套餐到期时间”可配置列,显示接口返回的预计日期或“待激活后起算”。 +- [x] 3.3 在两个列表对 `is_expiring=true` 的预计到期时间使用临期样式,且不改变现有列表排序。 ## 4. Verification -- [ ] 4.1 验证无套餐时不伪造预计日期并显示稳定占位内容。 -- [ ] 4.2 验证仅当前套餐和存在多个排队主套餐时,资产详情和两个列表均显示后端 `estimated_final_expires_at`。 -- [ ] 4.3 验证等待激活等不可预计状态显示“待激活后起算”,不显示计算出的日期。 -- [ ] 4.4 验证 `is_expiring=true` 时使用临期样式,且卡、设备列表顺序不变。 -- [ ] 4.5 运行相关类型检查、lint 或构建验证。 +- [x] 4.1 验证无套餐时不伪造预计日期并显示稳定占位内容。 +- [x] 4.2 验证仅当前套餐和存在多个排队主套餐时,资产详情和两个列表均显示后端 `estimated_final_expires_at`。 +- [x] 4.3 验证等待激活等不可预计状态显示“待激活后起算”,不显示计算出的日期。 +- [x] 4.4 验证 `is_expiring=true` 时使用临期样式,且卡、设备列表顺序不变。 +- [x] 4.5 运行相关类型检查、lint 或构建验证。 diff --git a/src/types/api/asset.ts b/src/types/api/asset.ts index a9b56a3..3914989 100644 --- a/src/types/api/asset.ts +++ b/src/types/api/asset.ts @@ -67,7 +67,7 @@ export interface AssetStartResponse { export type AssetRealnamePolicy = 'none' | 'before_order' | 'after_order' // 预计最终到期时间状态 -export type ExpiryEstimateStatus = 'exact' | 'waiting_activation' | string +export type ExpiryEstimateStatus = 'exact' | 'waiting_activation' | 'none' | 'invalid_data' // 批量更新资产实名认证策略请求 export interface BatchUpdateAssetRealnamePolicyRequest { @@ -120,6 +120,7 @@ export interface AssetResolveResponse { estimated_final_expires_at?: string | null // 当前及排队主套餐接续后的预计最终到期时间 days_until_final_expiry?: number | null // 距预计最终到期的剩余天数 expiry_estimate_status?: ExpiryEstimateStatus // 预计最终到期时间状态 + expiry_estimate_status_name?: string | null // 预计最终到期时间状态名称 is_expiring?: boolean // 是否临期,由后端判断 reduction_pct: number // 展示增幅比例(小数,如 0.428571) device_protect_status?: DeviceProtectStatus // 保护期状态:none / stop / start(仅 device) diff --git a/src/types/api/card.ts b/src/types/api/card.ts index 43f5a1b..16ee784 100644 --- a/src/types/api/card.ts +++ b/src/types/api/card.ts @@ -3,6 +3,7 @@ */ import { PaginationParams, ImportTask } from './common' +import type { ExpiryEstimateStatus } from './asset' // 运营商类型 export enum Operator { @@ -401,7 +402,8 @@ export interface StandaloneIotCard { current_month_start_date?: string | null // 本月开始日期 estimated_final_expires_at?: string | null // 当前及排队主套餐接续后的预计最终到期时间 days_until_final_expiry?: number | null // 距预计最终到期的剩余天数 - expiry_estimate_status?: string // 预计最终到期时间状态 + expiry_estimate_status?: ExpiryEstimateStatus // 预计最终到期时间状态 + expiry_estimate_status_name?: string | null // 预计最终到期时间状态名称 is_expiring?: boolean // 是否临期,由后端判断 last_month_total_mb?: number // 上月流量总量(MB) last_data_check_at?: string | null // 最后流量检查时间 diff --git a/src/types/api/device.ts b/src/types/api/device.ts index 2764d9e..697fe4c 100644 --- a/src/types/api/device.ts +++ b/src/types/api/device.ts @@ -3,6 +3,7 @@ */ import { PaginationParams } from './common' +import type { ExpiryEstimateStatus } from './asset' // ========== 设备状态枚举 ========== @@ -69,7 +70,8 @@ export interface Device { real_name_status_name: string // 实名状态名称 estimated_final_expires_at?: string | null // 当前及排队主套餐接续后的预计最终到期时间 days_until_final_expiry?: number | null // 距预计最终到期的剩余天数 - expiry_estimate_status?: string // 预计最终到期时间状态 + expiry_estimate_status?: ExpiryEstimateStatus // 预计最终到期时间状态 + expiry_estimate_status_name?: string | null // 预计最终到期时间状态名称 is_expiring?: boolean // 是否临期,由后端判断 authorized_enterprise_id?: number | null // 当前有效授权企业ID authorized_enterprise_name?: string | null // 当前有效授权企业名称 diff --git a/src/utils/business/expiryEstimate.ts b/src/utils/business/expiryEstimate.ts index 5d9655f..5e9560c 100644 --- a/src/utils/business/expiryEstimate.ts +++ b/src/utils/business/expiryEstimate.ts @@ -1,20 +1,28 @@ import { formatDateTime } from './format' +import type { ExpiryEstimateStatus } from '@/types/api' export interface ExpiryEstimate { estimated_final_expires_at?: string | null days_until_final_expiry?: number | null - expiry_estimate_status?: string | null + expiry_estimate_status?: ExpiryEstimateStatus | null + expiry_estimate_status_name?: string | null is_expiring?: boolean } export const getExpiryEstimateText = (estimate: ExpiryEstimate): string => { - if (estimate.expiry_estimate_status === 'exact') { - return estimate.estimated_final_expires_at - ? formatDateTime(estimate.estimated_final_expires_at) - : '-' + switch (estimate.expiry_estimate_status) { + case 'exact': + return estimate.estimated_final_expires_at + ? formatDateTime(estimate.estimated_final_expires_at) + : '-' + case 'waiting_activation': + return '待激活后起算' + case 'invalid_data': + return '数据异常' + case 'none': + default: + return '-' } - - return estimate.expiry_estimate_status ? '待激活后起算' : '-' } export const getExpiryEstimateTooltip = (estimate: ExpiryEstimate): string => { diff --git a/src/views/asset-management/asset-information/components/BasicInfoCard.vue b/src/views/asset-management/asset-information/components/BasicInfoCard.vue index 83dda5f..2803f76 100644 --- a/src/views/asset-management/asset-information/components/BasicInfoCard.vue +++ b/src/views/asset-management/asset-information/components/BasicInfoCard.vue @@ -588,7 +588,12 @@ ElMessage } from 'element-plus' import { CopyDocument } from '@element-plus/icons-vue' - import type { AssetExchangeTrace, AssetExchangeTraceAsset, AssetPollingStatus } from '@/types/api' + import type { + AssetExchangeTrace, + AssetExchangeTraceAsset, + AssetPollingStatus, + ExpiryEstimateStatus + } from '@/types/api' import { useAssetFormatters } from '../composables/useAssetFormatters' import { useAuth } from '@/composables/useAuth' import { useUserStore } from '@/store/modules/user' @@ -643,7 +648,8 @@ total_virtual_remaining_mb?: number | null estimated_final_expires_at?: string | null days_until_final_expiry?: number | null - expiry_estimate_status?: string + expiry_estimate_status?: ExpiryEstimateStatus + expiry_estimate_status_name?: string | null is_expiring?: boolean last_sync_time?: string | null last_data_check_at?: string | null diff --git a/src/views/asset-management/asset-information/composables/useAssetInfo.ts b/src/views/asset-management/asset-information/composables/useAssetInfo.ts index d11299b..fd34e27 100644 --- a/src/views/asset-management/asset-information/composables/useAssetInfo.ts +++ b/src/views/asset-management/asset-information/composables/useAssetInfo.ts @@ -143,6 +143,7 @@ export function useAssetInfo() { estimated_final_expires_at: data.estimated_final_expires_at ?? null, days_until_final_expiry: data.days_until_final_expiry ?? null, expiry_estimate_status: data.expiry_estimate_status, + expiry_estimate_status_name: data.expiry_estimate_status_name ?? null, is_expiring: data.is_expiring ?? false, bound_device_id: data.bound_device_id, bound_device_no: data.bound_device_no || '', diff --git a/src/views/asset-management/asset-information/types.ts b/src/views/asset-management/asset-information/types.ts index 1bca217..031955d 100644 --- a/src/views/asset-management/asset-information/types.ts +++ b/src/views/asset-management/asset-information/types.ts @@ -2,7 +2,7 @@ * 资产信息页面类型定义 */ -import type { AssetExchangeTrace, AssetPollingStatus } from '@/types/api' +import type { AssetExchangeTrace, AssetPollingStatus, ExpiryEstimateStatus } from '@/types/api' // 资产类型枚举 export type AssetType = 'card' | 'device' @@ -37,7 +37,8 @@ export interface AssetInfo { total_virtual_remaining_mb?: number | null estimated_final_expires_at?: string | null days_until_final_expiry?: number | null - expiry_estimate_status?: string + expiry_estimate_status?: ExpiryEstimateStatus + expiry_estimate_status_name?: string | null is_expiring?: boolean last_sync_time?: string | null last_data_check_at?: string | null