feat: 新增全部已使用流量和全部总流量字段
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m30s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 2m30s
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
# Change: 更新资产解析流量汇总展示
|
||||
|
||||
## Why
|
||||
|
||||
后台“资产信息”页需要展示当前世代下所有套餐的虚流量已用量和剩余量,方便运营人员在查看资产基础信息时快速判断整体流量消耗情况。
|
||||
|
||||
后端通过 `GET /api/admin/assets/resolve/:identifier` 新增可选查询参数控制是否返回汇总字段;前端需要明确请求契约、类型契约和展示位置,避免默认查询缺失汇总数据。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 更新资产解析接口请求契约:
|
||||
- `GET /api/admin/assets/resolve/:identifier` 支持可选 Query 参数 `include_usage_summary: boolean`
|
||||
- 参数含义为是否返回当前世代流量汇总字段 `total_virtual_used_mb` / `total_virtual_remaining_mb`
|
||||
- 后端未传时默认不返回汇总数据;后台“资产信息”页发起解析请求时默认传 `include_usage_summary=true`
|
||||
- 更新资产解析接口响应契约:
|
||||
- 新增 `total_virtual_used_mb?: number | null`,表示所有套餐已用量(MB),未请求时为 `null`
|
||||
- 新增 `total_virtual_remaining_mb?: number | null`,表示所有套餐剩余量(MB),未请求时为 `null`
|
||||
- 更新后台“资产信息”基础信息展示:
|
||||
- 卡资产在“运营商状态”字段后新增“所有套餐已用量”和“所有套餐剩余量”
|
||||
- 设备资产在“SN”字段后新增“所有套餐已用量”和“所有套餐剩余量”
|
||||
- 字段值使用上述两个响应字段,并按流量大小格式化展示
|
||||
- 字段为空或未请求时显示稳定占位内容
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs:
|
||||
- `asset-information`
|
||||
- Affected code:
|
||||
- `src/api/modules/asset.ts`
|
||||
- `src/types/api/asset.ts`
|
||||
- `src/views/asset-management/asset-information/types.ts`
|
||||
- `src/views/asset-management/asset-information/composables/useAssetInfo.ts`
|
||||
- `src/views/asset-management/asset-information/components/BasicInfoCard.vue`
|
||||
- Dependencies:
|
||||
- `GET /api/admin/assets/resolve/:identifier` 后端支持 `include_usage_summary` Query 参数及响应字段
|
||||
- Breaking changes:
|
||||
- 无;新增请求参数和响应字段均为可选,前端资产信息页仅主动请求并展示新增数据
|
||||
@@ -0,0 +1,60 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Admin Asset Resolve Usage Summary Contract
|
||||
|
||||
The admin asset information integration SHALL request usage summary data from `GET /api/admin/assets/resolve/:identifier` by default and preserve the returned current-generation virtual usage summary fields.
|
||||
|
||||
#### Scenario: Asset information requests usage summary by default
|
||||
|
||||
- **GIVEN** 用户在后台“资产信息”页查询资产标识符
|
||||
- **WHEN** 前端调用 `GET /api/admin/assets/resolve/:identifier`
|
||||
- **THEN** 请求 Query MUST include `include_usage_summary=true`
|
||||
- **AND** `include_usage_summary` MUST be treated as a boolean query parameter
|
||||
|
||||
#### Scenario: Preserve usage summary fields from resolve response
|
||||
|
||||
- **GIVEN** `GET /api/admin/assets/resolve/:identifier?include_usage_summary=true` 返回 `total_virtual_used_mb` 和 `total_virtual_remaining_mb`
|
||||
- **WHEN** 前端解析资产详情响应
|
||||
- **THEN** 页面状态 MUST preserve `total_virtual_used_mb` as a `number | null` field
|
||||
- **AND** 页面状态 MUST preserve `total_virtual_remaining_mb` as a `number | null` field
|
||||
- **AND** `total_virtual_used_mb` MUST represent 所有套餐已用量(MB)
|
||||
- **AND** `total_virtual_remaining_mb` MUST represent 所有套餐剩余量(MB)
|
||||
|
||||
#### Scenario: Usage summary not requested
|
||||
|
||||
- **GIVEN** a caller invokes `GET /api/admin/assets/resolve/:identifier` without `include_usage_summary=true`
|
||||
- **WHEN** the response is parsed
|
||||
- **THEN** `total_virtual_used_mb` MAY be absent or `null`
|
||||
- **AND** `total_virtual_remaining_mb` MAY be absent or `null`
|
||||
|
||||
### Requirement: Admin Asset Usage Summary Display
|
||||
|
||||
The admin asset information view SHALL display current-generation virtual usage summary fields in both card and device asset information sections using asset-type-specific placement.
|
||||
|
||||
#### Scenario: Show card usage summary after carrier status
|
||||
|
||||
- **GIVEN** 用户正在查看后台“资产信息”中的卡资产详情
|
||||
- **AND** 当前资产详情状态中存在 `total_virtual_used_mb` 和 `total_virtual_remaining_mb`
|
||||
- **WHEN** 页面渲染“卡信息”区域
|
||||
- **THEN** 页面 MUST keep `运营商状态` visible
|
||||
- **AND** 页面 MUST display `所有套餐已用量` immediately after `运营商状态`, using `total_virtual_used_mb`
|
||||
- **AND** 页面 MUST display `所有套餐剩余量` immediately after `所有套餐已用量`, using `total_virtual_remaining_mb`
|
||||
- **AND** both values MUST be formatted as traffic sizes based on MB values
|
||||
|
||||
#### Scenario: Show device usage summary after SN
|
||||
|
||||
- **GIVEN** 用户正在查看后台“资产信息”中的设备资产详情
|
||||
- **AND** 当前资产详情状态中存在 `total_virtual_used_mb` 和 `total_virtual_remaining_mb`
|
||||
- **WHEN** 页面渲染“设备信息”区域
|
||||
- **THEN** 页面 MUST keep `SN` visible
|
||||
- **AND** 页面 MUST display `所有套餐已用量` immediately after `SN`, using `total_virtual_used_mb`
|
||||
- **AND** 页面 MUST display `所有套餐剩余量` immediately after `所有套餐已用量`, using `total_virtual_remaining_mb`
|
||||
- **AND** both values MUST be formatted as traffic sizes based on MB values
|
||||
|
||||
#### Scenario: Show placeholder when usage summary is unavailable
|
||||
|
||||
- **GIVEN** 用户正在查看后台“资产信息”中的卡资产详情或设备资产详情
|
||||
- **AND** `total_virtual_used_mb` or `total_virtual_remaining_mb` is `null` or absent
|
||||
- **WHEN** 页面渲染对应汇总字段
|
||||
- **THEN** 页面 MUST display `-` for the unavailable field
|
||||
- **AND** 页面 MUST NOT display `0` solely because the field is unavailable
|
||||
19
openspec/changes/update-asset-resolve-usage-summary/tasks.md
Normal file
19
openspec/changes/update-asset-resolve-usage-summary/tasks.md
Normal file
@@ -0,0 +1,19 @@
|
||||
## 1. Contract
|
||||
|
||||
- [x] 1.1 扩展资产解析接口方法,支持传入 `include_usage_summary` Query 参数。
|
||||
- [x] 1.2 扩展资产解析响应类型,新增 `total_virtual_used_mb?: number | null` 和 `total_virtual_remaining_mb?: number | null`。
|
||||
- [x] 1.3 确保后台“资产信息”页调用 `GET /api/admin/assets/resolve/:identifier` 时默认传 `include_usage_summary=true`。
|
||||
|
||||
## 2. State And Display
|
||||
|
||||
- [x] 2.1 在资产信息页面状态中保留 `total_virtual_used_mb` 和 `total_virtual_remaining_mb`。
|
||||
- [x] 2.2 在卡资产“卡信息”区域的“运营商状态”后新增“所有套餐已用量”和“所有套餐剩余量”。
|
||||
- [x] 2.3 在设备资产“设备信息”区域的“SN”后新增“所有套餐已用量”和“所有套餐剩余量”。
|
||||
- [x] 2.4 新增字段按流量大小格式化展示;当响应字段为 `null`、`undefined` 或未请求时显示 `-`。
|
||||
|
||||
## 3. Verification
|
||||
|
||||
- [ ] 3.1 验证资产信息页请求解析接口时 URL 包含 `include_usage_summary=true`。
|
||||
- [ ] 3.2 验证解析接口返回两个汇总字段时,卡资产详情在“运营商状态”后正确展示。
|
||||
- [ ] 3.3 验证解析接口返回两个汇总字段时,设备资产详情在“SN”后正确展示。
|
||||
- [ ] 3.4 验证两个汇总字段为 `null` 或缺失时,页面显示 `-` 且不报错。
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from '@/utils/business/apiRateLimit'
|
||||
import type {
|
||||
BaseResponse,
|
||||
AssetResolveParams,
|
||||
AssetResolveResponse,
|
||||
AssetRealtimeStatusResponse,
|
||||
AssetRefreshResponse,
|
||||
@@ -49,9 +50,13 @@ export class AssetService extends BaseService {
|
||||
* 支持虚拟号、ICCID、IMEI、SN、MSISDN
|
||||
* GET /api/admin/assets/resolve/:identifier
|
||||
* @param identifier 资产标识符(虚拟号、ICCID、IMEI、SN、MSISDN)
|
||||
* @param params 查询参数
|
||||
*/
|
||||
static resolveAsset(identifier: string): Promise<BaseResponse<AssetResolveResponse>> {
|
||||
return this.getOne<AssetResolveResponse>(`/api/admin/assets/resolve/${identifier}`)
|
||||
static resolveAsset(
|
||||
identifier: string,
|
||||
params?: AssetResolveParams
|
||||
): Promise<BaseResponse<AssetResolveResponse>> {
|
||||
return this.getOne<AssetResolveResponse>(`/api/admin/assets/resolve/${identifier}`, params)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,10 @@ export type UsageType = 'single_card' | 'device'
|
||||
|
||||
// ========== 资产详情响应 ==========
|
||||
|
||||
export interface AssetResolveParams {
|
||||
include_usage_summary?: boolean // 是否返回当前世代流量汇总字段
|
||||
}
|
||||
|
||||
/**
|
||||
* 资产解析/详情响应
|
||||
* 对应接口:GET /api/admin/assets/resolve/:identifier
|
||||
@@ -67,6 +71,8 @@ export interface AssetResolveResponse {
|
||||
real_used_mb: number // 真流量已用
|
||||
virtual_total_mb: number // 业务停机阈值(展示用)
|
||||
virtual_used_mb: number // 展示已用量
|
||||
total_virtual_used_mb?: number | null // 所有套餐已用量(MB),未请求时为 null
|
||||
total_virtual_remaining_mb?: number | null // 所有套餐剩余量(MB),未请求时为 null
|
||||
reduction_pct: number // 展示增幅比例(小数,如 0.428571)
|
||||
device_protect_status?: DeviceProtectStatus // 保护期状态:none / stop / start(仅 device)
|
||||
activated_at: string // 激活时间
|
||||
|
||||
@@ -82,6 +82,12 @@
|
||||
<ElDescriptionsItem label="运营商状态" :span="1">
|
||||
<span class="gateway-extend-text">{{ cardInfo?.gateway_extend || '-' }}</span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="所有套餐已用量">
|
||||
{{ formatUsageSummaryMb(cardInfo?.total_virtual_used_mb) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="所有套餐剩余量">
|
||||
{{ formatUsageSummaryMb(cardInfo?.total_virtual_remaining_mb) }}
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<template v-if="cardInfo?.bound_device_id">
|
||||
<ElDescriptionsItem label="绑定设备号">
|
||||
@@ -163,6 +169,12 @@
|
||||
formatDateTime(deviceRealtime?.last_sync_time) || '-'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="SN">{{ cardInfo?.sn || '-' }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="所有套餐已用量">
|
||||
{{ formatUsageSummaryMb(cardInfo?.total_virtual_used_mb) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="所有套餐剩余量">
|
||||
{{ formatUsageSummaryMb(cardInfo?.total_virtual_remaining_mb) }}
|
||||
</ElDescriptionsItem>
|
||||
</template>
|
||||
</ElDescriptions>
|
||||
|
||||
@@ -532,6 +544,8 @@
|
||||
supplier?: string
|
||||
gateway_card_imei?: string
|
||||
gateway_extend?: string
|
||||
total_virtual_used_mb?: number | null
|
||||
total_virtual_remaining_mb?: number | null
|
||||
last_sync_time?: string | null
|
||||
last_data_check_at?: string | null
|
||||
last_real_name_check_at?: string | null
|
||||
@@ -710,6 +724,11 @@
|
||||
props.cardInfo?.last_card_status_check_at !== undefined
|
||||
)
|
||||
|
||||
const formatUsageSummaryMb = (value?: number | null) => {
|
||||
if (value === undefined || value === null) return '-'
|
||||
return formatDataSize(value)
|
||||
}
|
||||
|
||||
// 处理轮询开关变化
|
||||
const handlePollingChange = (value: string | number | boolean) => {
|
||||
emit('update:pollingEnabled', Boolean(value))
|
||||
|
||||
@@ -92,7 +92,7 @@ export function useAssetInfo() {
|
||||
const fetchAssetDetail = async (identifier: string) => {
|
||||
try {
|
||||
loading.value = true
|
||||
const response = await AssetService.resolveAsset(identifier)
|
||||
const response = await AssetService.resolveAsset(identifier, { include_usage_summary: true })
|
||||
|
||||
if (response.code === 0 && response.data) {
|
||||
const data = response.data
|
||||
@@ -136,6 +136,8 @@ export function useAssetInfo() {
|
||||
gateway_card_imei: resolvedGatewayCardImei,
|
||||
resolved_gateway_card_imei: resolvedGatewayCardImei,
|
||||
gateway_extend: data.gateway_extend ?? '',
|
||||
total_virtual_used_mb: data.total_virtual_used_mb ?? null,
|
||||
total_virtual_remaining_mb: data.total_virtual_remaining_mb ?? null,
|
||||
bound_device_id: data.bound_device_id,
|
||||
bound_device_no: data.bound_device_no || '',
|
||||
bound_device_name: data.bound_device_name || '',
|
||||
|
||||
@@ -30,6 +30,8 @@ export interface AssetInfo {
|
||||
status?: number
|
||||
gateway_card_imei?: string
|
||||
gateway_extend?: string
|
||||
total_virtual_used_mb?: number | null
|
||||
total_virtual_remaining_mb?: number | null
|
||||
last_sync_time?: string | null
|
||||
last_data_check_at?: string | null
|
||||
last_real_name_check_at?: string | null
|
||||
|
||||
@@ -991,6 +991,7 @@
|
||||
:identifier="operationLogsIdentifier"
|
||||
download-permission="iot_card:download_log_file"
|
||||
/>
|
||||
|
||||
<ExportTaskCreateDialog
|
||||
v-model="exportDialogVisible"
|
||||
scene="iot_card"
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
:loading="loading"
|
||||
:data="packageList"
|
||||
:marginTop="10"
|
||||
:pagination="false"
|
||||
:actions="getActions"
|
||||
:actionsWidth="150"
|
||||
height="70vh"
|
||||
:inlineActionsCount="2"
|
||||
>
|
||||
<template #default>
|
||||
@@ -134,7 +134,6 @@
|
||||
ElCard,
|
||||
ElButton,
|
||||
ElIcon,
|
||||
ElTable,
|
||||
ElTableColumn,
|
||||
ElTag,
|
||||
ElDialog,
|
||||
|
||||
Reference in New Issue
Block a user