fix: 记录查询列表显示 ICCID、设备号、套餐名称、运营商名称与操作人,不再显示内部 ID
Some checks failed
构建并部署前端到测试环境 / deploy (push) Has been cancelled
Some checks failed
构建并部署前端到测试环境 / deploy (push) Has been cancelled
- 卡 / 设备列优先显示 ICCID、设备号(IMEI),后端未返回时才退回内部 ID - 运营商账户筛选改为按名称搜索
This commit is contained in:
@@ -110,3 +110,37 @@ test('退款后处理状态与权限码常量', () => {
|
||||
assert.equal(constants.labelOf(constants.TRAFFIC_DECISION_LABELS, 'new_value'), 'new_value')
|
||||
assert.equal(constants.labelOf(constants.TRAFFIC_DECISION_LABELS, ''), '-')
|
||||
})
|
||||
|
||||
test('卡 / 设备展示优先用 ICCID、设备号,没有时才显示内部 ID', () => {
|
||||
assert.equal(
|
||||
utils.assetDisplay({ iot_card_id: 367218, iccid: '89860624660030813727' }),
|
||||
'89860624660030813727'
|
||||
)
|
||||
assert.equal(
|
||||
utils.assetDisplay({
|
||||
device_id: 49323,
|
||||
device_virtual_no: '60003081372',
|
||||
device_imei: '869555083099518'
|
||||
}),
|
||||
'60003081372(IMEI 869555083099518)'
|
||||
)
|
||||
assert.equal(
|
||||
utils.assetDisplay({
|
||||
device_id: 1,
|
||||
device_virtual_no: '862639078983683',
|
||||
device_imei: '862639078983683'
|
||||
}),
|
||||
'862639078983683'
|
||||
)
|
||||
assert.equal(
|
||||
utils.assetDisplay({ device_id: 1, device_imei: '869555083099518' }),
|
||||
'869555083099518'
|
||||
)
|
||||
assert.equal(utils.assetDisplay({ iot_card_id: 367218 }), '卡ID 367218')
|
||||
assert.equal(utils.assetDisplay({ device_id: 49323 }), '设备ID 49323')
|
||||
assert.equal(utils.assetDisplay({}), '-')
|
||||
assert.equal(utils.nameOrId('移动账户A', 3), '移动账户A')
|
||||
assert.equal(utils.nameOrId('', 3), 'ID 3')
|
||||
assert.equal(utils.nameOrId('', 7, '账号ID'), '账号ID 7')
|
||||
assert.equal(utils.nameOrId(undefined, 0), '-')
|
||||
})
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
<ElTableColumn label="ICCID / 卡 ID" min-width="190">
|
||||
<template #default="{ row }">{{ row.iccid || row.iot_card_id }}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="运营商账户" prop="carrier_id" width="100" />
|
||||
<ElTableColumn label="运营商账户" min-width="140" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ nameOrId(row.carrier_name, row.carrier_id) }}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="当日用量" min-width="110">
|
||||
<template #default="{ row }">{{ formatMb(row.settled_mb) }}</template>
|
||||
</ElTableColumn>
|
||||
@@ -47,10 +49,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive } from 'vue'
|
||||
import { computed, reactive } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { TrafficRecordsService } from '@/api/modules/trafficRecords'
|
||||
import { useRecordList } from '@/composables/useRecordList'
|
||||
import { useCarrierFilterItem, useRecordList } from '@/composables/useRecordList'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import type { CardDailyUsage } from '@/types/api/trafficRecords'
|
||||
@@ -58,7 +60,7 @@
|
||||
import {
|
||||
compactQuery,
|
||||
formatMb,
|
||||
optionalPositiveInt,
|
||||
nameOrId,
|
||||
recentDateRange,
|
||||
requireIdentifierForNonPlatform,
|
||||
toDateQuery
|
||||
@@ -68,7 +70,7 @@
|
||||
const { info: userInfo } = storeToRefs(useUserStore())
|
||||
const emptyFilters = () => ({
|
||||
identifier: '',
|
||||
carrier_id: '',
|
||||
carrier_id: undefined as number | undefined,
|
||||
min_usage_mb: '',
|
||||
range: recentDateRange(7) as [string, string] | null
|
||||
})
|
||||
@@ -87,13 +89,14 @@
|
||||
...page,
|
||||
...toDateQuery(filters.range),
|
||||
identifier,
|
||||
carrier_id: optionalPositiveInt(filters.carrier_id, '运营商账户 ID'),
|
||||
carrier_id: filters.carrier_id,
|
||||
min_usage_mb: minUsage
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
const searchItems: SearchFormItem[] = [
|
||||
const { item: carrierItem } = useCarrierFilterItem()
|
||||
const searchItems = computed<SearchFormItem[]>(() => [
|
||||
{
|
||||
label: '资产标识',
|
||||
prop: 'identifier',
|
||||
@@ -113,14 +116,14 @@
|
||||
clearable: false
|
||||
}
|
||||
},
|
||||
{ label: '运营商账户ID', prop: 'carrier_id', type: 'input', config: { clearable: true } },
|
||||
{
|
||||
label: '当日用量≥(MB)',
|
||||
prop: 'min_usage_mb',
|
||||
type: 'input',
|
||||
config: { clearable: true, placeholder: '排查异常大流量' }
|
||||
}
|
||||
]
|
||||
},
|
||||
carrierItem.value
|
||||
])
|
||||
|
||||
function reset() {
|
||||
Object.assign(filters, emptyFilters())
|
||||
|
||||
@@ -31,23 +31,23 @@
|
||||
<ElTableColumn label="冲正时间" min-width="170">
|
||||
<template #default="{ row }">{{ formatDateTime(row.created_at) }}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn
|
||||
v-if="!isFixed"
|
||||
label="ICCID / 设备号"
|
||||
min-width="200"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">{{ assetDisplay(row) }}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn v-if="!isFixed" label="套餐" min-width="180" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ row.package_name || '-' }}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn
|
||||
v-if="!isFixed"
|
||||
label="套餐使用记录ID"
|
||||
prop="package_usage_id"
|
||||
min-width="130"
|
||||
/>
|
||||
<ElTableColumn v-if="!isFixed" label="卡ID / 设备ID" min-width="120">
|
||||
<template #default="{ row }">
|
||||
{{
|
||||
row.iot_card_id
|
||||
? `卡 ${row.iot_card_id}`
|
||||
: row.device_id
|
||||
? `设备 ${row.device_id}`
|
||||
: '-'
|
||||
}}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="调整量" min-width="110">
|
||||
<template #default="{ row }">
|
||||
<span :class="row.delta_mb > 0 ? 'delta-deduct' : 'delta-refund'">
|
||||
@@ -66,7 +66,11 @@
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="原因" prop="reason" min-width="200" show-overflow-tooltip />
|
||||
<ElTableColumn label="操作人ID" prop="operator_id" width="100" />
|
||||
<ElTableColumn label="操作人" min-width="120">
|
||||
<template #default="{ row }">{{
|
||||
nameOrId(row.operator_name, row.operator_id, '账号ID')
|
||||
}}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn
|
||||
label="关联采集 ID"
|
||||
prop="ref_observation_id"
|
||||
@@ -98,7 +102,9 @@
|
||||
import { ADJUSTMENT_DIRECTION_OPTIONS } from '@/config/constants/trafficRecords'
|
||||
import {
|
||||
compactQuery,
|
||||
assetDisplay,
|
||||
formatMb,
|
||||
nameOrId,
|
||||
optionalPositiveInt,
|
||||
recentTimeRange,
|
||||
requireIdentifierForNonPlatform,
|
||||
|
||||
@@ -21,13 +21,15 @@
|
||||
>
|
||||
<ElTable v-loading="loading" :data="rows" row-key="id" border empty-text="暂无套餐日流量">
|
||||
<ElTableColumn label="日期" prop="date" width="120" />
|
||||
<ElTableColumn label="套餐使用记录ID" prop="package_usage_id" min-width="130" />
|
||||
<ElTableColumn label="套餐ID" prop="package_id" width="100" />
|
||||
<ElTableColumn label="卡ID / 设备ID" min-width="130">
|
||||
<template #default="{ row }">
|
||||
{{ row.iot_card_id ? `卡 ${row.iot_card_id}` : `设备 ${row.device_id}` }}
|
||||
</template>
|
||||
<ElTableColumn label="ICCID / 设备号" min-width="200" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ assetDisplay(row) }}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="套餐" min-width="200" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{
|
||||
nameOrId(row.package_name, row.package_id, '套餐ID')
|
||||
}}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="套餐使用记录ID" prop="package_usage_id" min-width="130" />
|
||||
<ElTableColumn label="当日流量" min-width="110">
|
||||
<template #default="{ row }">{{ formatMb(row.daily_usage_mb) }}</template>
|
||||
</ElTableColumn>
|
||||
@@ -44,17 +46,19 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive } from 'vue'
|
||||
import { computed, reactive } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { TrafficRecordsService } from '@/api/modules/trafficRecords'
|
||||
import { useRecordList } from '@/composables/useRecordList'
|
||||
import { useCarrierFilterItem, useRecordList } from '@/composables/useRecordList'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import type { PackageUsageDailyRecord } from '@/types/api/trafficRecords'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import {
|
||||
compactQuery,
|
||||
assetDisplay,
|
||||
formatMb,
|
||||
nameOrId,
|
||||
optionalPositiveInt,
|
||||
recentDateRange,
|
||||
requireIdentifierForNonPlatform,
|
||||
@@ -67,7 +71,7 @@
|
||||
identifier: '',
|
||||
package_usage_id: '',
|
||||
package_id: '',
|
||||
carrier_id: '',
|
||||
carrier_id: undefined as number | undefined,
|
||||
range: recentDateRange(7) as [string, string] | null
|
||||
})
|
||||
const filters = reactive(emptyFilters())
|
||||
@@ -86,12 +90,13 @@
|
||||
identifier,
|
||||
package_usage_id: packageUsageId,
|
||||
package_id: optionalPositiveInt(filters.package_id, '套餐 ID'),
|
||||
carrier_id: optionalPositiveInt(filters.carrier_id, '运营商账户 ID')
|
||||
carrier_id: filters.carrier_id
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
const searchItems: SearchFormItem[] = [
|
||||
const { item: carrierItem } = useCarrierFilterItem()
|
||||
const searchItems = computed<SearchFormItem[]>(() => [
|
||||
{
|
||||
label: '资产标识',
|
||||
prop: 'identifier',
|
||||
@@ -118,8 +123,8 @@
|
||||
config: { clearable: true }
|
||||
},
|
||||
{ label: '套餐ID', prop: 'package_id', type: 'input', config: { clearable: true } },
|
||||
{ label: '运营商账户ID', prop: 'carrier_id', type: 'input', config: { clearable: true } }
|
||||
]
|
||||
carrierItem.value
|
||||
])
|
||||
|
||||
function reset() {
|
||||
Object.assign(filters, emptyFilters())
|
||||
|
||||
@@ -37,7 +37,15 @@
|
||||
<ElTableColumn label="资产" min-width="200">
|
||||
<template #default="{ row }">
|
||||
{{ row.asset_type === 'device' ? '设备' : '单卡' }}
|
||||
{{ row.iccid || row.asset_id || '' }}
|
||||
{{
|
||||
row.asset_type === 'device'
|
||||
? assetDisplay({
|
||||
device_id: row.asset_id,
|
||||
device_virtual_no: row.device_virtual_no,
|
||||
device_imei: row.device_imei
|
||||
})
|
||||
: assetDisplay({ iot_card_id: row.asset_id, iccid: row.iccid })
|
||||
}}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="第几次" prop="attempt" width="80" />
|
||||
@@ -94,6 +102,7 @@
|
||||
} from '@/config/constants/trafficRecords'
|
||||
import {
|
||||
compactQuery,
|
||||
assetDisplay,
|
||||
isPlatformAccount,
|
||||
optionalPositiveInt,
|
||||
recentTimeRange,
|
||||
|
||||
@@ -46,7 +46,9 @@
|
||||
<ElTableColumn v-if="!isAsset" label="ICCID / 卡 ID" min-width="190">
|
||||
<template #default="{ row }">{{ row.iccid || row.iot_card_id || '-' }}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn v-if="!isAsset" label="运营商账户" prop="carrier_id" width="100" />
|
||||
<ElTableColumn v-if="!isAsset" label="运营商账户" min-width="140" show-overflow-tooltip>
|
||||
<template #default="{ row }">{{ nameOrId(row.carrier_name, row.carrier_id) }}</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="来源" width="90">
|
||||
<template #default="{ row }">{{ labelOf(TRAFFIC_SOURCE_LABELS, row.source) }}</template>
|
||||
</ElTableColumn>
|
||||
@@ -135,7 +137,7 @@
|
||||
import { computed, reactive, watch } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { TrafficRecordsService } from '@/api/modules/trafficRecords'
|
||||
import { useRecordList } from '@/composables/useRecordList'
|
||||
import { useCarrierFilterItem, useRecordList } from '@/composables/useRecordList'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import type { RawDataBlock, TrafficCollectionRecord } from '@/types/api/trafficRecords'
|
||||
@@ -155,8 +157,8 @@
|
||||
import {
|
||||
compactQuery,
|
||||
formatMb,
|
||||
nameOrId,
|
||||
optionalBoolean,
|
||||
optionalPositiveInt,
|
||||
recentTimeRange,
|
||||
requireIdentifierForNonPlatform,
|
||||
toTimeQuery
|
||||
@@ -174,6 +176,7 @@
|
||||
)
|
||||
|
||||
const isAsset = computed(() => props.mode === 'asset')
|
||||
const { item: carrierItem } = useCarrierFilterItem(props.mode !== 'asset')
|
||||
const { info: userInfo } = storeToRefs(useUserStore())
|
||||
const pageSizes = computed(() => (isAsset.value ? [50, 100] : [20, 50, 100]))
|
||||
const emptyText = computed(() => (props.mode === 'failure' ? '暂无采集失败记录' : '暂无采集记录'))
|
||||
@@ -185,7 +188,7 @@
|
||||
|
||||
const emptyFilters = () => ({
|
||||
identifier: '',
|
||||
carrier_id: '' as string | number,
|
||||
carrier_id: undefined as number | undefined,
|
||||
decision: '',
|
||||
source: '',
|
||||
scene: '',
|
||||
@@ -222,7 +225,7 @@
|
||||
...page,
|
||||
...time,
|
||||
identifier,
|
||||
carrier_id: optionalPositiveInt(filters.carrier_id, '运营商账户 ID'),
|
||||
carrier_id: filters.carrier_id,
|
||||
source: filters.source,
|
||||
scene: filters.scene.trim()
|
||||
}
|
||||
@@ -288,7 +291,7 @@
|
||||
const common = [
|
||||
input('资产标识', 'identifier', 'ICCID / 虚拟号 / MSISDN / IMEI / SN'),
|
||||
rangeItem,
|
||||
input('运营商账户ID', 'carrier_id'),
|
||||
carrierItem.value,
|
||||
select('来源', 'source', TRAFFIC_SOURCE_OPTIONS),
|
||||
input('场景', 'scene')
|
||||
]
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { onBeforeUnmount, reactive, ref, shallowRef } from 'vue'
|
||||
import { computed, onBeforeUnmount, reactive, ref, shallowRef } from 'vue'
|
||||
import { useGatewayCarriers } from '@/composables/useGateway'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import type { BaseResponse } from '@/types/api/common'
|
||||
import type { RecordPage } from '@/types/api/trafficRecords'
|
||||
import { errorMessage } from '@/utils/business/trafficRecords'
|
||||
@@ -66,3 +68,24 @@ export function useRecordList<T>(
|
||||
|
||||
return { rows, total, loading, error, pagination, load, search, changePage, changeSize, clear }
|
||||
}
|
||||
|
||||
/** 运营商账户筛选:按名称远程搜索,提交的是账户 ID(复用网关页面的运营商候选)。 */
|
||||
export function useCarrierFilterItem(loadOnMount = true) {
|
||||
const carriers = useGatewayCarriers(loadOnMount)
|
||||
const item = computed<SearchFormItem>(() => ({
|
||||
label: '运营商账户',
|
||||
prop: 'carrier_id',
|
||||
type: 'select',
|
||||
options: carriers.options.value,
|
||||
onChange: ({ val }: { val: unknown }) => carriers.select(val),
|
||||
config: {
|
||||
clearable: true,
|
||||
filterable: true,
|
||||
remote: true,
|
||||
remoteMethod: carriers.search,
|
||||
loading: carriers.loading.value,
|
||||
placeholder: '输入运营商名称搜索'
|
||||
}
|
||||
}))
|
||||
return { item, carriers }
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ export interface TrafficCollectionRecord {
|
||||
iot_card_id?: number
|
||||
iccid?: string
|
||||
carrier_id?: number
|
||||
carrier_name?: string
|
||||
source?: string
|
||||
scene?: string
|
||||
result?: string
|
||||
@@ -99,6 +100,7 @@ export interface CardDailyUsage {
|
||||
iot_card_id: number
|
||||
iccid?: string
|
||||
carrier_id?: number
|
||||
carrier_name?: string
|
||||
settled_mb: number
|
||||
month_used_mb: number
|
||||
vendor_used_mb: number
|
||||
@@ -119,8 +121,12 @@ export interface PackageUsageDailyRecord {
|
||||
date: string
|
||||
package_usage_id: number
|
||||
package_id: number
|
||||
package_name?: string
|
||||
iot_card_id: number
|
||||
iccid?: string
|
||||
device_id: number
|
||||
device_virtual_no?: string
|
||||
device_imei?: string
|
||||
daily_usage_mb: number
|
||||
cumulative_usage_mb: number
|
||||
updated_at?: string
|
||||
@@ -137,8 +143,12 @@ export interface PackageTrafficAdjustment {
|
||||
id: number
|
||||
created_at: string
|
||||
package_usage_id: number
|
||||
package_name?: string
|
||||
iot_card_id?: number
|
||||
iccid?: string
|
||||
device_id?: number
|
||||
device_virtual_no?: string
|
||||
device_imei?: string
|
||||
delta_mb: number
|
||||
before_usage_mb: number
|
||||
after_usage_mb: number
|
||||
@@ -146,6 +156,7 @@ export interface PackageTrafficAdjustment {
|
||||
after_status?: number
|
||||
reason: string
|
||||
operator_id?: number
|
||||
operator_name?: string
|
||||
ref_event_id?: string
|
||||
ref_observation_id?: string
|
||||
}
|
||||
@@ -175,6 +186,8 @@ export interface RefundPostProcessAttempt {
|
||||
asset_type?: string
|
||||
asset_id?: number
|
||||
iccid?: string
|
||||
device_virtual_no?: string
|
||||
device_imei?: string
|
||||
attempt: number
|
||||
step: string
|
||||
result: string
|
||||
|
||||
@@ -125,6 +125,30 @@ export function formatMb(value: unknown): string {
|
||||
return `${Number.isInteger(number) ? number : number.toFixed(2)} MB`
|
||||
}
|
||||
|
||||
/** 卡 / 设备展示:优先 ICCID、设备号(IMEI),都没有时才显示内部 ID */
|
||||
export function assetDisplay(row: {
|
||||
iot_card_id?: number | null
|
||||
iccid?: string
|
||||
device_id?: number | null
|
||||
device_virtual_no?: string
|
||||
device_imei?: string
|
||||
}): string {
|
||||
if (row.iccid) return row.iccid
|
||||
if (row.device_virtual_no || row.device_imei) {
|
||||
const no = row.device_virtual_no || row.device_imei
|
||||
return row.device_imei && row.device_imei !== no
|
||||
? `${no}(IMEI ${row.device_imei})`
|
||||
: String(no)
|
||||
}
|
||||
if (row.iot_card_id) return `卡ID ${row.iot_card_id}`
|
||||
if (row.device_id) return `设备ID ${row.device_id}`
|
||||
return '-'
|
||||
}
|
||||
|
||||
/** 名称为空时退回显示 ID */
|
||||
export const nameOrId = (name?: string, id?: number | null, idLabel = 'ID'): string =>
|
||||
name || (id ? `${idLabel} ${id}` : '-')
|
||||
|
||||
export function errorMessage(error: unknown): string {
|
||||
const data = (error as { response?: { data?: { msg?: string; message?: string } } })?.response
|
||||
?.data
|
||||
|
||||
Reference in New Issue
Block a user