This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
# Change: 更新设备激活状态筛选与展示
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
|
当前后台设备管理和企业设备授权流程还没有完整接入新的设备激活状态字段,导致运营人员无法按“已激活 / 未激活”筛选设备,也无法在资产详情中直接看到设备激活状态名称。
|
||||||
|
|
||||||
|
最新接口契约补充了以下内容:
|
||||||
|
- 设备列表接口新增可选过滤参数 `activation_status`
|
||||||
|
- 设备列表与资产解析相关响应新增 `activation_status_name`
|
||||||
|
- 企业设备授权弹窗中的可选设备列表也需要沿用这套激活状态筛选与展示规则
|
||||||
|
|
||||||
|
如果前端不补齐这套契约和展示规范,设备筛选口径、资产详情口径和企业设备授权口径会继续不一致,影响运营筛选和授权判断。
|
||||||
|
|
||||||
|
## What Changes
|
||||||
|
|
||||||
|
- 为后台设备管理新增设备激活状态接入规范:
|
||||||
|
- `GET /api/admin/devices` 支持可选查询参数 `activation_status`
|
||||||
|
- 设备列表响应支持 `activation_status_name`
|
||||||
|
- 设备管理页新增“激活状态”筛选,并展示激活状态名称
|
||||||
|
- 为后台资产信息新增设备激活状态展示规范:
|
||||||
|
- `GET /api/admin/assets/resolve/:identifier` 支持 `activation_status_name`
|
||||||
|
- 设备资产详情在“实名状态”后展示“激活状态”
|
||||||
|
- 为“授权设备给企业”弹窗新增可选设备筛选规范:
|
||||||
|
- 可选设备列表支持 `activation_status` 筛选与 `activation_status_name` 展示
|
||||||
|
- 原有 `status` 条件改为固定隐藏条件,默认始终传 `status=2`
|
||||||
|
- 弹窗中不再向用户显示可编辑的 `status` 筛选项
|
||||||
|
- 激活状态定义沿用后端口径:
|
||||||
|
- `0`: 未激活
|
||||||
|
- `1`: 已激活,且需满足“有生效中主套餐且任意绑定卡已实名”
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
|
||||||
|
- Affected specs:
|
||||||
|
- `device-management`
|
||||||
|
- `asset-information`
|
||||||
|
- `enterprise-device-authorization`
|
||||||
|
- Affected code:
|
||||||
|
- `src/types/api/device.ts`
|
||||||
|
- `src/views/asset-management/device-list/index.vue`
|
||||||
|
- `src/types/api/asset.ts`
|
||||||
|
- `src/views/asset-management/asset-information/composables/useAssetInfo.ts`
|
||||||
|
- `src/views/asset-management/asset-information/components/BasicInfoCard.vue`
|
||||||
|
- `src/views/asset-management/enterprise-devices/index.vue`
|
||||||
|
- Dependencies:
|
||||||
|
- 依赖后端设备列表接口和资产解析接口已返回 `activation_status_name`
|
||||||
|
- Breaking changes:
|
||||||
|
- 无外部接口破坏性变更;本次主要是后台查询与展示契约的增量调整
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Admin Device Activation Status Visibility
|
||||||
|
|
||||||
|
The admin asset information view SHALL display backend-provided device activation status after the device real-name status.
|
||||||
|
|
||||||
|
#### Scenario: Show activation status after real-name status on device asset page
|
||||||
|
|
||||||
|
- **GIVEN** 用户正在后台“资产信息”中查看设备资产详情
|
||||||
|
- **AND** 资产解析接口返回 `activation_status_name`
|
||||||
|
- **WHEN** 页面渲染设备基础信息区域
|
||||||
|
- **THEN** 页面 MUST 在“实名状态”后展示“激活状态”
|
||||||
|
- **AND** 页面 MUST 使用后端返回的 `activation_status_name` 作为展示文案
|
||||||
|
- **AND** 当 `activation_status_name` 为空时页面 MUST 显示稳定占位内容
|
||||||
|
|
||||||
|
#### Scenario: Asset information contract accepts activation_status_name
|
||||||
|
|
||||||
|
- **GIVEN** `GET /api/admin/assets/resolve/:identifier` 返回设备资产详情
|
||||||
|
- **WHEN** 前端解析资产详情响应
|
||||||
|
- **THEN** 前端类型契约 MUST 支持 `activation_status_name`
|
||||||
|
- **AND** 前端页面状态 MUST 保留该字段以供设备基础信息区域直接消费
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Device Activation Status Query Contract
|
||||||
|
|
||||||
|
The device management list integration SHALL support the backend activation-status query and display contract for devices.
|
||||||
|
|
||||||
|
#### Scenario: Query devices by activation_status
|
||||||
|
|
||||||
|
- **GIVEN** 用户正在后台设备管理页查询设备列表
|
||||||
|
- **WHEN** 用户选择激活状态筛选条件
|
||||||
|
- **THEN** 系统 MUST 支持向设备列表接口传递可选参数 `activation_status`
|
||||||
|
- **AND** `activation_status=0` MUST 表示“未激活”
|
||||||
|
- **AND** `activation_status=1` MUST 表示“已激活”
|
||||||
|
- **AND** 前端 MUST NOT 自行推导“已激活”的业务含义,而是直接使用后端口径
|
||||||
|
|
||||||
|
#### Scenario: Accept activation_status_name from device list response
|
||||||
|
|
||||||
|
- **GIVEN** 设备列表接口返回设备记录
|
||||||
|
- **WHEN** 前端解析设备列表响应
|
||||||
|
- **THEN** 前端类型契约 MUST 支持 `activation_status_name`
|
||||||
|
- **AND** 前端 MUST 保留该中文名称用于列表展示
|
||||||
|
|
||||||
|
### Requirement: Device Activation Status Filter And Display
|
||||||
|
|
||||||
|
The device management page SHALL provide activation-status filtering and render the backend activation-status name for each device.
|
||||||
|
|
||||||
|
#### Scenario: Filter devices by activation status on device management page
|
||||||
|
|
||||||
|
- **GIVEN** 用户正在后台设备管理页使用搜索表单
|
||||||
|
- **WHEN** 用户选择“激活状态”为“未激活”或“已激活”并执行搜索
|
||||||
|
- **THEN** 系统 MUST 将对应的 `activation_status` 传给设备列表接口
|
||||||
|
- **AND** 系统 MUST 使用新的筛选结果刷新设备列表
|
||||||
|
- **AND** 重置搜索条件后系统 MUST 清空显式设置的 `activation_status`
|
||||||
|
|
||||||
|
#### Scenario: Show activation status name in device list
|
||||||
|
|
||||||
|
- **GIVEN** 设备列表接口返回某条设备记录的 `activation_status_name`
|
||||||
|
- **WHEN** 设备列表表格完成渲染
|
||||||
|
- **THEN** 页面 MUST 显示该设备的激活状态名称
|
||||||
|
- **AND** 页面 MUST 优先展示后端返回的 `activation_status_name`
|
||||||
|
- **AND** 当该字段为空时页面 MUST 显示稳定占位内容
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Enterprise Device Authorization Available-Device Activation Filter
|
||||||
|
|
||||||
|
The enterprise device authorization dialog SHALL support filtering available devices by activation status while keeping the distributed-device status constraint hidden and fixed.
|
||||||
|
|
||||||
|
#### Scenario: Authorization dialog always queries distributed devices with hidden status=2
|
||||||
|
|
||||||
|
- **GIVEN** 用户打开“授权设备给企业”弹窗
|
||||||
|
- **WHEN** 系统首次加载可选设备列表,或用户执行搜索、重置、分页切换
|
||||||
|
- **THEN** 系统 MUST 始终向可选设备列表接口传递 `status=2`
|
||||||
|
- **AND** 该 `status=2` 条件 MUST 作为隐藏固定条件存在
|
||||||
|
- **AND** 弹窗搜索表单 MUST NOT 再向用户展示可编辑的 `status` 筛选项
|
||||||
|
|
||||||
|
#### Scenario: Authorization dialog filters available devices by activation status
|
||||||
|
|
||||||
|
- **GIVEN** 用户正在“授权设备给企业”弹窗中筛选可选设备
|
||||||
|
- **WHEN** 用户选择“激活状态”为“未激活”或“已激活”并执行搜索
|
||||||
|
- **THEN** 系统 MUST 在保留隐藏固定条件 `status=2` 的同时传递所选 `activation_status`
|
||||||
|
- **AND** 重置搜索条件后系统 MUST 恢复隐藏固定条件 `status=2`
|
||||||
|
- **AND** 重置搜索条件后系统 MUST 清空显式设置的 `activation_status`
|
||||||
|
|
||||||
|
### Requirement: Enterprise Device Authorization Available-Device Activation Display
|
||||||
|
|
||||||
|
The enterprise device authorization dialog SHALL render backend-provided activation-status names for available devices.
|
||||||
|
|
||||||
|
#### Scenario: Available device response accepts activation_status_name
|
||||||
|
|
||||||
|
- **GIVEN** “授权设备给企业”弹窗中的可选设备列表接口返回设备记录
|
||||||
|
- **WHEN** 前端解析可选设备列表响应
|
||||||
|
- **THEN** 前端类型契约 MUST 支持 `activation_status_name`
|
||||||
|
- **AND** 前端 MUST 保留该字段用于弹窗列表展示
|
||||||
|
|
||||||
|
#### Scenario: Available device table shows activation status name
|
||||||
|
|
||||||
|
- **GIVEN** 可选设备列表中的某条设备记录返回 `activation_status_name`
|
||||||
|
- **WHEN** 弹窗中的可选设备表格完成渲染
|
||||||
|
- **THEN** 表格 MUST 显示该设备的激活状态名称
|
||||||
|
- **AND** 表格 MUST 优先展示后端返回的 `activation_status_name`
|
||||||
|
- **AND** 当该字段为空时表格 MUST 显示稳定占位内容
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
## 1. Contract Alignment
|
||||||
|
|
||||||
|
- [x] 1.1 扩展设备管理相关类型,支持设备列表查询参数 `activation_status` 与响应字段 `activation_status_name`
|
||||||
|
- [x] 1.2 扩展资产详情相关类型和数据映射,支持设备资产的 `activation_status_name`
|
||||||
|
- [x] 1.3 调整企业设备授权弹窗可选设备查询契约,确保隐藏固定条件 `status=2` 与可选条件 `activation_status` 可以同时生效
|
||||||
|
|
||||||
|
## 2. UI Display
|
||||||
|
|
||||||
|
- [x] 2.1 在设备管理页新增“激活状态”筛选,并展示设备激活状态名称
|
||||||
|
- [x] 2.2 在资产信息页设备详情中,将“激活状态”展示在“实名状态”后面
|
||||||
|
- [x] 2.3 在“授权设备给企业”弹窗中新增“激活状态”筛选和激活状态名称展示,同时移除用户可见的 `status` 筛选项
|
||||||
|
|
||||||
|
## 3. Verification
|
||||||
|
|
||||||
|
- [ ] 3.1 验证设备管理页按 `activation_status=0/1` 查询时,请求参数和结果展示都正确
|
||||||
|
- [ ] 3.2 验证设备资产详情返回 `activation_status_name` 时,页面在“实名状态”后正确展示该字段
|
||||||
|
- [ ] 3.3 验证企业设备授权弹窗打开、搜索、重置和分页时始终隐式传递 `status=2`
|
||||||
|
- [ ] 3.4 验证企业设备授权弹窗按 `activation_status` 过滤时,可选设备列表与激活状态名称展示正确
|
||||||
18
src/types/api/device-activation-status.d.ts
vendored
Normal file
18
src/types/api/device-activation-status.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export {}
|
||||||
|
|
||||||
|
declare module '@/types/api/device' {
|
||||||
|
interface Device {
|
||||||
|
activation_status?: number
|
||||||
|
activation_status_name?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeviceQueryParams {
|
||||||
|
activation_status?: number | null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@/types/api/asset' {
|
||||||
|
interface AssetResolveResponse {
|
||||||
|
activation_status_name?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -102,6 +102,9 @@
|
|||||||
{{ getRealNameStatusName(currentCard?.real_name_status) }}
|
{{ getRealNameStatusName(currentCard?.real_name_status) }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</ElDescriptionsItem>
|
</ElDescriptionsItem>
|
||||||
|
<ElDescriptionsItem label="激活状态">
|
||||||
|
{{ cardInfo?.activation_status_name || '-' }}
|
||||||
|
</ElDescriptionsItem>
|
||||||
|
|
||||||
<ElDescriptionsItem label="设备型号">{{
|
<ElDescriptionsItem label="设备型号">{{
|
||||||
cardInfo?.device_model || '-'
|
cardInfo?.device_model || '-'
|
||||||
@@ -457,6 +460,7 @@
|
|||||||
msisdn?: string
|
msisdn?: string
|
||||||
carrier_name?: string
|
carrier_name?: string
|
||||||
real_name_status?: number
|
real_name_status?: number
|
||||||
|
activation_status_name?: string
|
||||||
realname_policy?: string
|
realname_policy?: string
|
||||||
network_status?: number
|
network_status?: number
|
||||||
current_month_usage_mb?: number
|
current_month_usage_mb?: number
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ export function useAssetInfo() {
|
|||||||
real_name_status: data.real_name_status,
|
real_name_status: data.real_name_status,
|
||||||
realname_policy: data.realname_policy,
|
realname_policy: data.realname_policy,
|
||||||
real_name_at: data.real_name_at,
|
real_name_at: data.real_name_at,
|
||||||
|
activation_status_name: data.activation_status_name || '',
|
||||||
activated_at: data.activated_at,
|
activated_at: data.activated_at,
|
||||||
created_at: data.created_at,
|
created_at: data.created_at,
|
||||||
updated_at: data.updated_at,
|
updated_at: data.updated_at,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export interface AssetInfo {
|
|||||||
msisdn?: string
|
msisdn?: string
|
||||||
carrier_name?: string
|
carrier_name?: string
|
||||||
real_name_status?: number
|
real_name_status?: number
|
||||||
|
activation_status_name?: string
|
||||||
realname_policy?: string
|
realname_policy?: string
|
||||||
network_status?: string
|
network_status?: string
|
||||||
current_month_used_data?: number
|
current_month_used_data?: number
|
||||||
|
|||||||
@@ -904,6 +904,7 @@
|
|||||||
virtual_no: '',
|
virtual_no: '',
|
||||||
device_name: '',
|
device_name: '',
|
||||||
status: undefined as DeviceStatus | undefined,
|
status: undefined as DeviceStatus | undefined,
|
||||||
|
activation_status: undefined as number | undefined,
|
||||||
batch_no: '',
|
batch_no: '',
|
||||||
device_type: '',
|
device_type: '',
|
||||||
manufacturer: '',
|
manufacturer: '',
|
||||||
@@ -980,6 +981,19 @@
|
|||||||
{ label: '已停用', value: 4 }
|
{ label: '已停用', value: 4 }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '激活状态',
|
||||||
|
prop: 'activation_status',
|
||||||
|
type: 'select',
|
||||||
|
config: {
|
||||||
|
clearable: true,
|
||||||
|
placeholder: '请选择激活状态'
|
||||||
|
},
|
||||||
|
options: () => [
|
||||||
|
{ label: '未激活', value: 0 },
|
||||||
|
{ label: '已激活', value: 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '批次号',
|
label: '批次号',
|
||||||
prop: 'batch_no',
|
prop: 'batch_no',
|
||||||
@@ -1084,6 +1098,7 @@
|
|||||||
{ label: '设备类型', prop: 'device_type' },
|
{ label: '设备类型', prop: 'device_type' },
|
||||||
{ label: '状态', prop: 'status' },
|
{ label: '状态', prop: 'status' },
|
||||||
{ label: '状态名称', prop: 'status_name' },
|
{ label: '状态名称', prop: 'status_name' },
|
||||||
|
{ label: '激活状态', prop: 'activation_status_name' },
|
||||||
{ label: '在线状态', prop: 'online_status' },
|
{ label: '在线状态', prop: 'online_status' },
|
||||||
{ label: '实名策略', prop: 'realname_policy' },
|
{ label: '实名策略', prop: 'realname_policy' },
|
||||||
{ label: '切卡模式', prop: 'switch_mode' },
|
{ label: '切卡模式', prop: 'switch_mode' },
|
||||||
@@ -1391,6 +1406,12 @@
|
|||||||
width: 100,
|
width: 100,
|
||||||
formatter: (row: Device) => row.status_name || '-'
|
formatter: (row: Device) => row.status_name || '-'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
prop: 'activation_status_name',
|
||||||
|
label: '激活状态',
|
||||||
|
width: 120,
|
||||||
|
formatter: (row: Device) => row.activation_status_name || '-'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
prop: 'online_status',
|
prop: 'online_status',
|
||||||
label: '在线状态',
|
label: '在线状态',
|
||||||
@@ -1561,6 +1582,7 @@
|
|||||||
virtual_no: searchForm.virtual_no || undefined,
|
virtual_no: searchForm.virtual_no || undefined,
|
||||||
device_name: searchForm.device_name || undefined,
|
device_name: searchForm.device_name || undefined,
|
||||||
status: searchForm.status,
|
status: searchForm.status,
|
||||||
|
activation_status: searchForm.activation_status ?? undefined,
|
||||||
batch_no: searchForm.batch_no || undefined,
|
batch_no: searchForm.batch_no || undefined,
|
||||||
device_type: searchForm.device_type || undefined,
|
device_type: searchForm.device_type || undefined,
|
||||||
manufacturer: searchForm.manufacturer || undefined,
|
manufacturer: searchForm.manufacturer || undefined,
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
v-model:filter="deviceSearchForm"
|
v-model:filter="deviceSearchForm"
|
||||||
:items="deviceSearchFormItems"
|
:items="deviceSearchFormItems"
|
||||||
label-width="85"
|
label-width="85"
|
||||||
:show-expand="false"
|
show-expand
|
||||||
@reset="handleDeviceSearchReset"
|
@reset="handleDeviceSearchReset"
|
||||||
@search="handleDeviceSearch"
|
@search="handleDeviceSearch"
|
||||||
></ArtSearchBar>
|
></ArtSearchBar>
|
||||||
@@ -108,6 +108,7 @@
|
|||||||
:pageSize="devicePagination.pageSize"
|
:pageSize="devicePagination.pageSize"
|
||||||
:total="devicePagination.total"
|
:total="devicePagination.total"
|
||||||
:marginTop="10"
|
:marginTop="10"
|
||||||
|
height="40vh"
|
||||||
@size-change="handleDevicePageSizeChange"
|
@size-change="handleDevicePageSizeChange"
|
||||||
@current-change="handleDevicePageChange"
|
@current-change="handleDevicePageChange"
|
||||||
@selection-change="handleAvailableDevicesSelectionChange"
|
@selection-change="handleAvailableDevicesSelectionChange"
|
||||||
@@ -261,9 +262,9 @@
|
|||||||
|
|
||||||
// 设备搜索表单初始值
|
// 设备搜索表单初始值
|
||||||
const initialDeviceSearchState = {
|
const initialDeviceSearchState = {
|
||||||
status: 2,
|
|
||||||
virtual_no: '',
|
virtual_no: '',
|
||||||
device_name: '',
|
device_name: '',
|
||||||
|
activation_status: undefined as number | undefined,
|
||||||
device_type: '',
|
device_type: '',
|
||||||
manufacturer: '',
|
manufacturer: '',
|
||||||
batch_no: undefined,
|
batch_no: undefined,
|
||||||
@@ -334,18 +335,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '状态',
|
label: '激活状态',
|
||||||
prop: 'status',
|
prop: 'activation_status',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
config: {
|
config: {
|
||||||
clearable: true,
|
clearable: true,
|
||||||
placeholder: '请选择状态'
|
placeholder: '请选择激活状态'
|
||||||
},
|
},
|
||||||
options: () => [
|
options: () => [
|
||||||
{ label: '在库', value: 1 },
|
{ label: '未激活', value: 0 },
|
||||||
{ label: '已分销', value: 2 },
|
{ label: '已激活', value: 1 }
|
||||||
{ label: '已激活', value: 3 },
|
|
||||||
{ label: '已停用', value: 4 }
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -644,6 +643,12 @@
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
prop: 'activation_status_name',
|
||||||
|
label: '激活状态',
|
||||||
|
width: 120,
|
||||||
|
formatter: (row: Device) => row.activation_status_name || '-'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
prop: 'online_status',
|
prop: 'online_status',
|
||||||
label: '在线状态',
|
label: '在线状态',
|
||||||
@@ -791,7 +796,8 @@
|
|||||||
const params: any = {
|
const params: any = {
|
||||||
page: devicePagination.page,
|
page: devicePagination.page,
|
||||||
page_size: devicePagination.pageSize,
|
page_size: devicePagination.pageSize,
|
||||||
...deviceSearchForm
|
...deviceSearchForm,
|
||||||
|
status: 2
|
||||||
}
|
}
|
||||||
// 清理空值
|
// 清理空值
|
||||||
Object.keys(params).forEach((key) => {
|
Object.keys(params).forEach((key) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user