231 lines
5.9 KiB
Vue
231 lines
5.9 KiB
Vue
<script setup lang="tsx">
|
|
import { useTable } from '@/hooks/common/table';
|
|
import { SimpleScrollbar } from '~/packages/materials/src';
|
|
import CdrSearch from './modules/cdr-search.vue';
|
|
import { computed, shallowRef } from 'vue';
|
|
import { useElementSize } from '@vueuse/core';
|
|
import { fetchCdrHistory } from '@/service/api/auth';
|
|
import { formatStorage } from '@/utils/units';
|
|
import { useI18n } from 'vue-i18n';
|
|
const { t } = useI18n();
|
|
|
|
|
|
// 搜索模型
|
|
type SearchModel = {
|
|
pageNum: number;
|
|
pageSize: number;
|
|
userName?: string;
|
|
clientName?: string;
|
|
endTimeS?:string;
|
|
endTimeE?:string;
|
|
};
|
|
|
|
// 格式化通话时长
|
|
const formatDuration = (seconds: number) => {
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
const remainingSeconds = seconds % 60;
|
|
|
|
const parts = [];
|
|
if (hours > 0) parts.push(`${hours}${t('page.cdr.hour')}`);
|
|
if (minutes > 0) parts.push(`${minutes}${t('page.cdr.min')}`);
|
|
parts.push(`${remainingSeconds}${t('page.cdr.sec')}`);
|
|
|
|
return parts.join('');
|
|
};
|
|
|
|
const doGetCdrInfo = async (params: SearchModel) => {
|
|
try {
|
|
const response = await fetchCdrHistory(params);
|
|
console.log('API Response:', response);
|
|
const rows = response.data?.rows || [];
|
|
const total = response.data?.total || 0;
|
|
return {
|
|
data: {
|
|
rows,
|
|
total
|
|
}
|
|
};
|
|
} catch (error) {
|
|
console.error('API Error:', error);
|
|
return {
|
|
data: {
|
|
rows: [],
|
|
total: 0
|
|
},
|
|
error
|
|
};
|
|
}
|
|
};
|
|
|
|
const wrapperEl = shallowRef<HTMLElement | null>(null);
|
|
const { height: wrapperElHeight } = useElementSize(wrapperEl);
|
|
|
|
const scrollConfig = computed(() => ({
|
|
y: wrapperElHeight.value - 72,
|
|
x: 1200
|
|
}));
|
|
|
|
const { columns, columnChecks, data, loading, getData, mobilePagination, searchParams } = useTable({
|
|
apiFn: doGetCdrInfo,
|
|
immediate: true,
|
|
apiParams: {
|
|
pageNum: 1,
|
|
pageSize: 10
|
|
} as SearchModel,
|
|
rowKey: 'id',
|
|
pagination: true,
|
|
columns: (): AntDesign.TableColumn<Api.Auth.CdrHistory>[] => [
|
|
{
|
|
key: 'userName',
|
|
dataIndex: 'userName',
|
|
title: t('page.cdr.username'),
|
|
align: 'center',
|
|
width: 150
|
|
},
|
|
{
|
|
key: 'clientName',
|
|
dataIndex: 'clientName',
|
|
title: t('page.cdr.clientname'),
|
|
align: 'center',
|
|
width: 120
|
|
},
|
|
{
|
|
key: 'clientMac',
|
|
dataIndex: 'clientMac',
|
|
title: t('page.cdr.clientmac'),
|
|
align: 'center',
|
|
width: 120
|
|
},
|
|
{
|
|
key: 'trafficUp',
|
|
dataIndex: 'trafficUp',
|
|
title: t('page.cdr.up'),
|
|
align: 'center',
|
|
width: 120,
|
|
sorter: (a, b) => a.trafficUp - b.trafficUp,
|
|
customRender: ({ text }) => {
|
|
const { value, unit } = formatStorage(text);
|
|
return `${value.toFixed(2)} ${unit}`;
|
|
}
|
|
},
|
|
{
|
|
key: 'trafficDown',
|
|
dataIndex: 'trafficDown',
|
|
title: t('page.cdr.down'),
|
|
align: 'center',
|
|
width: 120,
|
|
sorter: (a, b) => a.trafficDown - b.trafficDown,
|
|
customRender: ({ text }) => {
|
|
const { value, unit } = formatStorage(text);
|
|
return `${value.toFixed(2)} ${unit}`;
|
|
}
|
|
},
|
|
{
|
|
key: 'startTime',
|
|
dataIndex: 'startTime',
|
|
title: t('page.cdr.start'),
|
|
align: 'center',
|
|
width: 180,
|
|
customRender: ({ text }) => {
|
|
const timestamp = String(text).length === 13 ? Number(text) : Number(text) * 1000;
|
|
return new Date(timestamp).toLocaleString();
|
|
}
|
|
},
|
|
{
|
|
key: 'endTime',
|
|
dataIndex: 'endTime',
|
|
title: t('page.cdr.end'),
|
|
align: 'center',
|
|
width: 180,
|
|
customRender: ({ text }) => {
|
|
const timestamp = String(text).length === 13 ? Number(text) : Number(text) * 1000;
|
|
return new Date(timestamp).toLocaleString();
|
|
}
|
|
},
|
|
{
|
|
key: 'duration',
|
|
dataIndex: 'duration',
|
|
title: t('page.cdr.duration'),
|
|
align: 'center',
|
|
width: 120,
|
|
sorter: (a, b) => a.duration - b.duration,
|
|
customRender: ({ text }) => formatDuration(text)
|
|
},
|
|
]
|
|
});
|
|
|
|
const handleTableChange = (
|
|
pagination: any,
|
|
filters: any,
|
|
sorter: any
|
|
) => {
|
|
searchParams.pageNum = pagination.current;
|
|
searchParams.pageSize = pagination.pageSize;
|
|
getData();
|
|
};
|
|
const handleReset = () => {
|
|
// 保存当前的 pageSize
|
|
const currentPageSize = searchParams.pageSize;
|
|
|
|
// 重置搜索参数
|
|
searchParams.userName = '';
|
|
searchParams.clientName = '';
|
|
searchParams.endTimeS = undefined;
|
|
searchParams.endTimeE = undefined;
|
|
searchParams.pageNum = 1;
|
|
searchParams.pageSize = currentPageSize;
|
|
|
|
// 重新获取数据
|
|
getData();
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<SimpleScrollbar>
|
|
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
|
<CdrSearch
|
|
v-model:model="searchParams"
|
|
@reset="handleReset"
|
|
@search="getData"
|
|
/>
|
|
<ACard
|
|
:title="t('page.cdr.title')"
|
|
:bordered="false"
|
|
:body-style="{ flex: 1, overflow: 'hidden' }"
|
|
class="flex-col-stretch sm:flex-1-hidden card-wrapper"
|
|
>
|
|
<template #extra>
|
|
<TableHeaderOperation
|
|
v-model:columns="columnChecks"
|
|
:loading="loading"
|
|
:show-delete="false"
|
|
:not-show-add="true"
|
|
@refresh="getData"
|
|
/>
|
|
</template>
|
|
<ATable
|
|
ref="wrapperEl"
|
|
:columns="columns"
|
|
:data-source="data"
|
|
:loading="loading"
|
|
row-key="id"
|
|
size="small"
|
|
:pagination="{
|
|
...mobilePagination,
|
|
total: mobilePagination.total,
|
|
current: searchParams.pageNum,
|
|
pageSize: searchParams.pageSize,
|
|
showTotal: (total: number) => `${t('page.cdr.total')} ${total} `
|
|
}"
|
|
:scroll="scrollConfig"
|
|
class="h-full"
|
|
@change="handleTableChange"
|
|
/>
|
|
</ACard>
|
|
</div>
|
|
</SimpleScrollbar>
|
|
</template>
|
|
|
|
<style scoped></style>
|