Some checks failed
构建并部署前端到测试环境 / deploy (push) Failing after 4m30s
- 套餐日流量详单按套餐名称搜索选择,操作人按账号用户名搜索选择 - 去掉套餐使用记录ID、退款单ID 等手填 ID 的筛选与列;从退款详情进入时仍按该退款单过滤
205 lines
7.0 KiB
Vue
205 lines
7.0 KiB
Vue
<template>
|
|
<div class="traffic-records">
|
|
<ElAlert
|
|
v-if="!allowed"
|
|
type="warning"
|
|
title="退款资产后处理尝试记录仅平台账号可查看"
|
|
:closable="false"
|
|
show-icon
|
|
/>
|
|
<template v-else>
|
|
<ArtSearchBar
|
|
:filter="filters"
|
|
:items="searchItems"
|
|
:show-expand="true"
|
|
label-width="110px"
|
|
@update:filter="(value: Record<string, unknown>) => Object.assign(filters, value)"
|
|
@search="search"
|
|
@reset="reset"
|
|
/>
|
|
<ElCard shadow="never">
|
|
<RecordTableShell
|
|
:error="error"
|
|
hint="时间范围必填,跨度不超过 31 天,结束时间不含;按时间倒序。"
|
|
:page="pagination.page"
|
|
:page-size="pagination.page_size"
|
|
:total="total"
|
|
@page-change="changePage"
|
|
@size-change="changeSize"
|
|
>
|
|
<ElTable v-loading="loading" :data="rows" row-key="id" border empty-text="暂无尝试记录">
|
|
<ElTableColumn label="记录时间" min-width="170">
|
|
<template #default="{ row }">{{ formatDateTime(row.created_at) }}</template>
|
|
</ElTableColumn>
|
|
<ElTableColumn label="退款单号" min-width="180">
|
|
<template #default="{ row }">{{ row.refund_no || row.refund_id }}</template>
|
|
</ElTableColumn>
|
|
<ElTableColumn label="资产" min-width="200">
|
|
<template #default="{ row }">
|
|
{{ row.asset_type === 'device' ? '设备' : '单卡' }}
|
|
{{
|
|
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" />
|
|
<ElTableColumn label="步骤" width="110">
|
|
<template #default="{ row }">{{
|
|
labelOf(REFUND_POST_STEP_LABELS, row.step)
|
|
}}</template>
|
|
</ElTableColumn>
|
|
<ElTableColumn label="结果" width="80">
|
|
<template #default="{ row }">
|
|
<ElTag :type="row.result === 'success' ? 'success' : 'danger'" size="small">
|
|
{{ labelOf(REFUND_POST_RESULT_LABELS, row.result) }}
|
|
</ElTag>
|
|
</template>
|
|
</ElTableColumn>
|
|
<ElTableColumn label="错误码" prop="error_code" min-width="120" show-overflow-tooltip />
|
|
<ElTableColumn
|
|
label="错误信息"
|
|
prop="error_message"
|
|
min-width="220"
|
|
show-overflow-tooltip
|
|
/>
|
|
<ElTableColumn label="触发方式" width="90">
|
|
<template #default="{ row }">{{
|
|
labelOf(REFUND_POST_TRIGGER_LABELS, row.trigger)
|
|
}}</template>
|
|
</ElTableColumn>
|
|
<ElTableColumn label="耗时(ms)" prop="duration_ms" width="90" />
|
|
</ElTable>
|
|
</RecordTableShell>
|
|
</ElCard>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, reactive, watch } from 'vue'
|
|
import { storeToRefs } from 'pinia'
|
|
import { TrafficRecordsService } from '@/api/modules/trafficRecords'
|
|
import { useRecordList } from '@/composables/useRecordList'
|
|
import { useUserStore } from '@/store/modules/user'
|
|
import type { SearchFormItem } from '@/types'
|
|
import type { RefundPostProcessAttempt } from '@/types/api/trafficRecords'
|
|
import { formatDateTime } from '@/utils/business/format'
|
|
import {
|
|
REFUND_POST_RESULT_LABELS,
|
|
REFUND_POST_RESULT_OPTIONS,
|
|
REFUND_POST_STEP_LABELS,
|
|
REFUND_POST_STEP_OPTIONS,
|
|
REFUND_POST_TRIGGER_LABELS,
|
|
REFUND_POST_TRIGGER_OPTIONS,
|
|
RECORD_MAX_SPAN_DAYS,
|
|
labelOf
|
|
} from '@/config/constants/trafficRecords'
|
|
import {
|
|
compactQuery,
|
|
assetDisplay,
|
|
isPlatformAccount,
|
|
recentTimeRange,
|
|
toTimeQuery
|
|
} from '@/utils/business/trafficRecords'
|
|
import RecordTableShell from './RecordTableShell.vue'
|
|
|
|
/** refundId 来自退款详情入口:自动按该退款单筛选,时间范围取最近 31 天 */
|
|
const props = defineProps<{ refundId?: number }>()
|
|
const { info: userInfo } = storeToRefs(useUserStore())
|
|
const allowed = computed(() => isPlatformAccount(userInfo.value.user_type))
|
|
|
|
const emptyFilters = () => ({
|
|
refund_no: '',
|
|
identifier: '',
|
|
step: '',
|
|
result: '',
|
|
error_code: '',
|
|
trigger: '',
|
|
range: recentTimeRange(props.refundId ? RECORD_MAX_SPAN_DAYS : 7) as [string, string] | null
|
|
})
|
|
const filters = reactive(emptyFilters())
|
|
|
|
const { rows, total, loading, error, pagination, load, search, changePage, changeSize, clear } =
|
|
useRecordList<RefundPostProcessAttempt>((page) =>
|
|
TrafficRecordsService.getRefundPostProcessAttempts(
|
|
compactQuery({
|
|
...page,
|
|
...toTimeQuery(filters.range, true),
|
|
// 从退款详情进入时固定按该退款单筛选,不让用户手填内部 ID
|
|
refund_id: props.refundId || undefined,
|
|
refund_no: filters.refund_no.trim(),
|
|
identifier: filters.identifier.trim(),
|
|
step: filters.step,
|
|
result: filters.result,
|
|
error_code: filters.error_code.trim(),
|
|
trigger: filters.trigger
|
|
})
|
|
)
|
|
)
|
|
|
|
const select = (label: string, prop: string, options: SearchFormItem['options']) => ({
|
|
label,
|
|
prop,
|
|
type: 'select' as const,
|
|
options,
|
|
config: { clearable: true }
|
|
})
|
|
const searchItems: SearchFormItem[] = [
|
|
{
|
|
label: '记录时间',
|
|
prop: 'range',
|
|
type: 'datetimerange',
|
|
config: {
|
|
type: 'datetimerange',
|
|
rangeSeparator: '至',
|
|
startPlaceholder: '开始时间',
|
|
endPlaceholder: '结束时间',
|
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
|
clearable: true
|
|
}
|
|
},
|
|
{ label: '退款单号', prop: 'refund_no', type: 'input', config: { clearable: true } },
|
|
{
|
|
label: '资产标识',
|
|
prop: 'identifier',
|
|
type: 'input',
|
|
config: { clearable: true, maxlength: 64, placeholder: 'ICCID / 虚拟号 / IMEI / SN' }
|
|
},
|
|
select('处理步骤', 'step', REFUND_POST_STEP_OPTIONS),
|
|
select('结果', 'result', REFUND_POST_RESULT_OPTIONS),
|
|
{ label: '错误码', prop: 'error_code', type: 'input', config: { clearable: true } },
|
|
select('触发方式', 'trigger', REFUND_POST_TRIGGER_OPTIONS)
|
|
]
|
|
|
|
function reset() {
|
|
Object.assign(filters, emptyFilters())
|
|
void search()
|
|
}
|
|
|
|
watch(
|
|
() => [props.refundId, allowed.value],
|
|
() => {
|
|
clear()
|
|
Object.assign(filters, emptyFilters())
|
|
pagination.page = 1
|
|
if (allowed.value) void load()
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.traffic-records {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
min-width: 0;
|
|
}
|
|
</style>
|