fix:历史记录界面后端对接
This commit is contained in:
@@ -1,133 +1,122 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import type { TableColumnsType } from 'ant-design-vue'
|
||||
import { HistoryOutlined } from '@ant-design/icons-vue'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import {useI18n} from "vue-i18n";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { fetchHistoricalDevices } from '@/service/api/auth';
|
||||
|
||||
const {t} = useI18n();
|
||||
const { t } = useI18n();
|
||||
|
||||
interface AccessRecord {
|
||||
key: string
|
||||
clientId: string
|
||||
clientName: string
|
||||
clientDeviceType: string
|
||||
clientMac: string
|
||||
startTime: string
|
||||
endTime: string
|
||||
// 格式化时间戳
|
||||
function formatTimestamp(timestamp: number): string {
|
||||
const date = new Date(timestamp);
|
||||
return date.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
});
|
||||
}
|
||||
|
||||
// 格式化流量
|
||||
function formatDataUsage(bytes: number): string {
|
||||
if (bytes < 1024) {
|
||||
return `${bytes}B`;
|
||||
} else if (bytes < 1024 * 1024) {
|
||||
return `${(bytes / 1024).toFixed(2)}KB`;
|
||||
} else if (bytes < 1024 * 1024 * 1024) {
|
||||
return `${(bytes / (1024 * 1024)).toFixed(2)}MB`;
|
||||
} else {
|
||||
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;
|
||||
}
|
||||
}
|
||||
|
||||
// 定义记录类型
|
||||
interface DeviceRecord {
|
||||
id: number;
|
||||
deviceName: string;
|
||||
macAddress: string;
|
||||
dataUsage: string;
|
||||
connectionTime: string;
|
||||
disconnectionTime: string;
|
||||
}
|
||||
|
||||
// 设备列表数据
|
||||
const deviceList = ref<DeviceRecord[]>([]);
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
const columns: TableColumnsType = [
|
||||
{
|
||||
title: t('page.records.clientID'),
|
||||
dataIndex: 'clientId',
|
||||
key: 'clientId',
|
||||
width: 100,
|
||||
responsive: ['md']
|
||||
},
|
||||
{
|
||||
title: t('page.records.clientname'),
|
||||
dataIndex: 'clientName',
|
||||
key: 'clientName',
|
||||
width: 90,
|
||||
className: 'wrap-cell'
|
||||
},
|
||||
{
|
||||
title: t('page.records.clienttype'),
|
||||
dataIndex: 'clientDeviceType',
|
||||
key: 'clientDeviceType',
|
||||
width: 90,
|
||||
responsive: ['lg']
|
||||
dataIndex: 'deviceName',
|
||||
key: 'deviceName',
|
||||
width: '30%'
|
||||
},
|
||||
{
|
||||
title: t('page.records.clientmac'),
|
||||
dataIndex: 'clientMac',
|
||||
key: 'clientMac',
|
||||
width: 140,
|
||||
responsive: ['md']
|
||||
dataIndex: 'macAddress',
|
||||
key: 'macAddress',
|
||||
width: '40%'
|
||||
},
|
||||
{
|
||||
title: t('page.records.starttime'),
|
||||
dataIndex: 'startTime',
|
||||
key: 'startTime',
|
||||
width: 110,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: t('page.records.endtime'),
|
||||
dataIndex: 'endTime',
|
||||
key: 'endTime',
|
||||
width: 110,
|
||||
ellipsis: true
|
||||
title: t('page.records.dataUsage'),
|
||||
dataIndex: 'dataUsage',
|
||||
key: 'dataUsage',
|
||||
width: '30%',
|
||||
align: 'right'
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
// 添加一个存储所有记录的数组和当前显示记录的数组
|
||||
const allRecords = ref<AccessRecord[]>([
|
||||
{
|
||||
key: '1',
|
||||
clientId: 'DEV001',
|
||||
clientName: 'iPhone 13',
|
||||
clientDeviceType: '手机',
|
||||
clientMac: '00:11:22:33:44:55',
|
||||
startTime: '2024-03-20 10:00:00',
|
||||
endTime: '2024-03-20 12:30:00'
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
clientId: 'DEV002',
|
||||
clientName: 'MacBook Pro',
|
||||
clientDeviceType: '笔记本',
|
||||
clientMac: '66:77:88:99:AA:BB',
|
||||
startTime: '2024-03-20 14:00:00',
|
||||
endTime: '2024-03-20 18:00:00'
|
||||
// 添加展开行控制
|
||||
const expandedRowKeys = ref<number[]>([]);
|
||||
|
||||
// 处理展开行变化
|
||||
function handleExpandChange(expanded: boolean, record: DeviceRecord) {
|
||||
if (expanded) {
|
||||
expandedRowKeys.value = [record.id];
|
||||
} else {
|
||||
expandedRowKeys.value = [];
|
||||
}
|
||||
])
|
||||
|
||||
const accessRecords = ref<AccessRecord[]>(allRecords.value)
|
||||
|
||||
// 日期范围变更处理函数
|
||||
const onRangeChange = (
|
||||
value: [Dayjs, Dayjs] | [string, string] | null,
|
||||
dateStrings: [string, string]
|
||||
) => {
|
||||
if (!value) {
|
||||
// 如果清空日期范围,显示所有记录
|
||||
accessRecords.value = allRecords.value
|
||||
return
|
||||
}
|
||||
|
||||
// 使用字符串数组进行过滤
|
||||
const [startStr, endStr] = dateStrings
|
||||
|
||||
// 筛选在选定时间范围内的记录
|
||||
accessRecords.value = allRecords.value.filter((record: AccessRecord) => {
|
||||
const recordStart = new Date(record.startTime).getTime()
|
||||
const recordEnd = new Date(record.endTime).getTime()
|
||||
const filterStart = new Date(startStr).getTime()
|
||||
const filterEnd = new Date(endStr).getTime()
|
||||
|
||||
// 记录的时间范围与选择的时间范围有重叠
|
||||
return !(recordEnd < filterStart || recordStart > filterEnd)
|
||||
})
|
||||
}
|
||||
|
||||
// 刷新数据的方法
|
||||
const refreshData = () => {
|
||||
|
||||
// 模拟刷新操作
|
||||
accessRecords.value = allRecords.value
|
||||
console.log('刷新数据')
|
||||
// 获取历史设备列表数据
|
||||
async function getHistoricalDeviceList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const { data, error } = await fetchHistoricalDevices();
|
||||
if (!error && data) {
|
||||
deviceList.value = data.rows.map(item => ({
|
||||
id: item.id,
|
||||
deviceName: item.clientName,
|
||||
macAddress: item.clientMac,
|
||||
dataUsage: formatDataUsage(item.duration),
|
||||
connectionTime: formatTimestamp(item.startTime),
|
||||
disconnectionTime: formatTimestamp(item.endTime)
|
||||
}));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch historical device list:', err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 确认选择时间范围
|
||||
const onRangeOk = (dates: [Dayjs, Dayjs] | [string, string]) => {
|
||||
console.log('确认选择时间范围: ', dates)
|
||||
// 刷新设备列表
|
||||
async function handleRefresh() {
|
||||
await getHistoricalDeviceList();
|
||||
}
|
||||
|
||||
// 组件挂载时获取数据
|
||||
onMounted(() => {
|
||||
getHistoricalDeviceList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="records-container">
|
||||
<div class="device-list-container">
|
||||
<a-card :bordered="false">
|
||||
<template #title>
|
||||
<div class="card-title">
|
||||
@@ -137,42 +126,33 @@ const onRangeOk = (dates: [Dayjs, Dayjs] | [string, string]) => {
|
||||
</template>
|
||||
|
||||
<template #extra>
|
||||
<a-space>
|
||||
<a-range-picker
|
||||
style="margin-right: 8px"
|
||||
:show-time="{ format: 'HH:mm' }"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
:placeholder="['开始时间', '结束时间']"
|
||||
@change="onRangeChange"
|
||||
@ok="onRangeOk"
|
||||
/>
|
||||
<a-button type="primary" @click="refreshData">
|
||||
<template #icon>
|
||||
<span class="i-carbon:refresh"></span>
|
||||
</template>
|
||||
{{ t('page.records.refresh') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
<a-button type="primary" :loading="loading" @click="handleRefresh">
|
||||
<template #icon>
|
||||
<span class="i-carbon:refresh"></span>
|
||||
</template>
|
||||
{{ t('page.records.refresh') }}
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<a-table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data-source="accessRecords"
|
||||
:scroll="{ x: 'max-content' }"
|
||||
size="small"
|
||||
:data-source="deviceList"
|
||||
:row-key="(record: DeviceRecord) => record.id"
|
||||
:expanded-row-keys="expandedRowKeys"
|
||||
@expand="handleExpandChange"
|
||||
:pagination="{
|
||||
total: accessRecords.length,
|
||||
total: deviceList.length,
|
||||
pageSize: 10,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
size: 'small',
|
||||
showTotal: (total) => `共 ${total} 条记录`
|
||||
showSizeChanger: false,
|
||||
showTotal: (total) => `共 ${total} 条`
|
||||
}"
|
||||
>
|
||||
<template #bodyCell="{ column, text }">
|
||||
<template v-if="column.key === 'clientDeviceType'">
|
||||
<a-tag :color="text === '手机' ? 'blue' : 'green'">{{ text }}</a-tag>
|
||||
</template>
|
||||
<template #expandedRowRender="{ record }">
|
||||
<div class="pl-4">
|
||||
<div>{{ t('page.records.starttime') }}: {{ record.connectionTime }}</div>
|
||||
<div>{{ t('page.records.endtime') }}: {{ record.disconnectionTime }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
@@ -180,7 +160,7 @@ const onRangeOk = (dates: [Dayjs, Dayjs] | [string, string]) => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.records-container {
|
||||
.device-list-container {
|
||||
padding: 8px;
|
||||
background-color: #f5f5f7;
|
||||
min-height: 100vh;
|
||||
@@ -194,6 +174,10 @@ const onRangeOk = (dates: [Dayjs, Dayjs] | [string, string]) => {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.pl-4 {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
:deep(.ant-card-head) {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
padding: 0 12px;
|
||||
@@ -208,89 +192,11 @@ const onRangeOk = (dates: [Dayjs, Dayjs] | [string, string]) => {
|
||||
}
|
||||
|
||||
:deep(.ant-table) {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:deep(.wrap-cell) {
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.records-container {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
:deep(.ant-card-head-wrapper) {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
:deep(.ant-card-extra) {
|
||||
margin-left: 0;
|
||||
margin-top: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-space) {
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:deep(.ant-space-item) {
|
||||
width: 100%;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
:deep(.ant-btn) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-table) {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-table th),
|
||||
:deep(.ant-table td:not(.wrap-cell)) {
|
||||
padding: 8px 4px !important;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:deep(.wrap-cell) {
|
||||
padding: 4px !important;
|
||||
}
|
||||
|
||||
:deep(.ant-tag) {
|
||||
margin-right: 0;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
:deep(.ant-picker-panels) {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:deep(.ant-picker-panel) {
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
:deep(.ant-picker-datetime-panel) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:deep(.ant-picker-time-panel) {
|
||||
width: auto !important;
|
||||
border-left: none !important;
|
||||
}
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.records-container {
|
||||
.device-list-container {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user