<script lang="ts" setup>
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
|
import {
|
computed,
|
onBeforeUnmount,
|
onMounted,
|
reactive,
|
ref,
|
watch,
|
} from 'vue';
|
|
import { Page } from '..\..\..\..\..\..\packages\effects\common-ui\src';
|
import { DICT_TYPE, IotDeviceMessageMethodEnum } from '..\..\..\..\..\..\packages\constants\src';
|
import { IconifyIcon } from '..\..\..\..\..\..\packages\icons\src';
|
import { formatDateTime } from '..\..\..\..\..\..\packages\utils\src';
|
|
import { Button, Select, Space, Switch, Tag } from 'ant-design-vue';
|
|
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
import { getDeviceMessagePage } from '#/api/iot/device/device';
|
|
const props = defineProps<{
|
deviceId: number;
|
}>();
|
|
const queryParams = reactive({
|
method: undefined,
|
upstream: undefined,
|
}); // 查询参数
|
|
const autoRefresh = ref(false); // 自动刷新开关
|
let autoRefreshTimer: any = null; // 自动刷新定时器
|
let refreshTimer: ReturnType<typeof setTimeout> | undefined; // 延迟刷新定时器
|
|
/** 消息方法选项 */
|
const methodOptions = computed(() => {
|
return Object.values(IotDeviceMessageMethodEnum).map((item) => ({
|
label: item.name,
|
value: item.method,
|
}));
|
});
|
|
/** Grid 列定义 */
|
function useGridColumns(): VxeTableGridOptions<Record<string, any>>['columns'] {
|
return [
|
{
|
field: 'ts',
|
title: '时间',
|
width: 160,
|
slots: { default: 'ts' },
|
},
|
{
|
field: 'upstream',
|
title: '上行/下行',
|
width: 100,
|
slots: { default: 'upstream' },
|
},
|
{
|
field: 'reply',
|
title: '是否回复',
|
width: 100,
|
cellRender: {
|
name: 'CellDict',
|
props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
|
},
|
},
|
{
|
field: 'requestId',
|
title: '请求编号',
|
width: 280,
|
showOverflow: 'tooltip',
|
},
|
{
|
field: 'method',
|
title: '请求方法',
|
width: 120,
|
slots: { default: 'method' },
|
},
|
{
|
field: 'params',
|
title: '请求/响应数据',
|
minWidth: 200,
|
showOverflow: 'tooltip',
|
slots: { default: 'params' },
|
},
|
];
|
}
|
|
/** 创建 Grid 实例 */
|
const [Grid, gridApi] = useVbenVxeGrid({
|
gridOptions: {
|
columns: useGridColumns(),
|
height: 'auto',
|
proxyConfig: {
|
ajax: {
|
query: async ({ page }) => {
|
if (!props.deviceId) {
|
return { list: [], total: 0 };
|
}
|
return await getDeviceMessagePage({
|
pageNo: page.currentPage,
|
pageSize: page.pageSize,
|
deviceId: props.deviceId,
|
method: queryParams.method,
|
upstream: queryParams.upstream,
|
});
|
},
|
},
|
},
|
toolbarConfig: {
|
refresh: false,
|
search: false,
|
},
|
pagerConfig: {
|
enabled: true,
|
},
|
} as VxeTableGridOptions,
|
});
|
|
/** 搜索操作 */
|
function handleQuery() {
|
gridApi.query();
|
}
|
|
/** 监听自动刷新 */
|
watch(autoRefresh, (newValue) => {
|
if (newValue) {
|
autoRefreshTimer = setInterval(() => {
|
gridApi.query();
|
}, 5000);
|
} else {
|
clearInterval(autoRefreshTimer);
|
autoRefreshTimer = null;
|
}
|
});
|
|
/** 监听设备标识变化 */
|
watch(
|
() => props.deviceId,
|
(newValue) => {
|
if (newValue) {
|
handleQuery();
|
}
|
},
|
);
|
|
/** 组件卸载时清除定时器 */
|
onBeforeUnmount(() => {
|
if (autoRefreshTimer) {
|
clearInterval(autoRefreshTimer);
|
autoRefreshTimer = null;
|
}
|
if (refreshTimer) {
|
clearTimeout(refreshTimer);
|
refreshTimer = undefined;
|
}
|
});
|
|
/** 初始化 */
|
onMounted(() => {
|
if (props.deviceId) {
|
handleQuery();
|
}
|
});
|
|
/** 刷新消息列表 */
|
function refresh(delay = 0) {
|
if (refreshTimer) {
|
clearTimeout(refreshTimer);
|
refreshTimer = undefined;
|
}
|
if (delay > 0) {
|
refreshTimer = setTimeout(() => {
|
gridApi.query();
|
refreshTimer = undefined;
|
}, delay);
|
} else {
|
gridApi.query();
|
}
|
}
|
|
/** 暴露方法给父组件 */
|
defineExpose({
|
refresh,
|
});
|
</script>
|
|
<template>
|
<Page auto-content-height>
|
<!-- 搜索区域 -->
|
<div class="mb-4 flex flex-wrap items-center gap-3">
|
<Select
|
v-model:value="queryParams.method"
|
allow-clear
|
placeholder="所有方法"
|
style="width: 160px"
|
>
|
<Select.Option
|
v-for="item in methodOptions"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
>
|
{{ item.label }}
|
</Select.Option>
|
</Select>
|
<Select
|
v-model:value="queryParams.upstream"
|
allow-clear
|
placeholder="上行/下行"
|
style="width: 160px"
|
>
|
<Select.Option label="上行" value="true">上行</Select.Option>
|
<Select.Option label="下行" value="false">下行</Select.Option>
|
</Select>
|
<Space>
|
<Button type="primary" @click="handleQuery">
|
<IconifyIcon icon="ep:search" class="mr-[5px]" /> 搜索
|
</Button>
|
<Switch
|
v-model:checked="autoRefresh"
|
checked-children="定时刷新"
|
un-checked-children="定时刷新"
|
/>
|
</Space>
|
</div>
|
|
<!-- 消息列表 -->
|
<Grid>
|
<template #ts="{ row }">
|
{{ formatDateTime(row.ts) }}
|
</template>
|
<template #upstream="{ row }">
|
<Tag :color="row.upstream ? 'blue' : 'green'">
|
{{ row.upstream ? '上行' : '下行' }}
|
</Tag>
|
</template>
|
<template #method="{ row }">
|
{{ methodOptions.find((item) => item.value === row.method)?.label }}
|
</template>
|
<template #params="{ row }">
|
<span v-if="row.reply">
|
{{ `{"code":${row.code},"msg":"${row.msg}","data":${row.data}\}` }}
|
</span>
|
<span v-else>{{ row.params }}</span>
|
</template>
|
</Grid>
|
</Page>
|
</template>
|