Files
ndm-web-client/src/pages/call-log-page.vue
2025-11-22 01:46:16 +08:00

266 lines
8.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { exportCallLogApi, pageCallLogApi, type NdmCallLogResultVO, type NdmCallLog, type PageQueryExtra } from '@/apis';
import { useStationStore } from '@/stores';
import { downloadByData } from '@/utils';
import { useMutation } from '@tanstack/vue-query';
import dayjs from 'dayjs';
import {
NButton,
NDataTable,
NDatePicker,
NForm,
NFormItemGi,
NGrid,
NGridItem,
NInput,
NSelect,
NSpace,
NTag,
type DataTableColumns,
type DataTableRowData,
type PaginationProps,
type SelectOption,
} from 'naive-ui';
import { storeToRefs } from 'pinia';
import { computed, h, reactive, ref, watch, watchEffect } from 'vue';
const stationStore = useStationStore();
const { stationList, onlineStationList } = storeToRefs(stationStore);
const stationSelectOptions = computed(() => {
return stationList.value.map<SelectOption>((station) => ({
label: station.name,
value: station.code,
disabled: !station.online,
}));
});
type SearchFields = PageQueryExtra<NdmCallLog> & { stationCode?: string; createdTime: [string, string] };
const searchFields = reactive<SearchFields>({
stationCode: undefined as string | undefined,
sourceGbId_like: undefined,
targetGbId_like: undefined,
method_like: undefined,
messageType_like: undefined,
cmdType_like: undefined,
createdTime: [dayjs().startOf('date').subtract(1, 'week').format('YYYY-MM-DD HH:mm:ss'), dayjs().endOf('date').format('YYYY-MM-DD HH:mm:ss')] as [string, string],
});
const resetSearchFields = () => {
searchFields.stationCode = stationList.value.find((station) => station.online)?.code;
searchFields.sourceGbId_like = undefined;
searchFields.targetGbId_like = undefined;
searchFields.method_like = undefined;
searchFields.messageType_like = undefined;
searchFields.cmdType_like = undefined;
searchFields.createdTime = [dayjs().startOf('date').subtract(1, 'week').format('YYYY-MM-DD HH:mm:ss'), dayjs().endOf('date').format('YYYY-MM-DD HH:mm:ss')];
};
const getExtraFields = () => {
const createdTime_precisest = searchFields.createdTime[0];
const createdTime_preciseed = searchFields.createdTime[1];
const sourceGbId_like = searchFields.sourceGbId_like;
const targetGbId_like = searchFields.targetGbId_like;
const method_like = searchFields.method_like;
const messageType_like = searchFields.messageType_like;
const cmdType_like = searchFields.cmdType_like;
return {
createdTime_precisest,
createdTime_preciseed,
sourceGbId_like,
targetGbId_like,
method_like,
messageType_like,
cmdType_like,
};
};
const searchFieldsChanged = ref(false);
watch(searchFields, () => {
searchFieldsChanged.value = true;
});
const tableColumns: DataTableColumns<NdmCallLogResultVO> = [
{ title: '时间', key: 'createdTime' },
{ title: '调用者国标码', key: 'sourceGbId' },
{ title: '被调用设备国标码', key: 'targetGbId' },
{ title: '调用方法', key: 'method' },
{ title: '消息类型', key: 'messageType' },
{ title: '操作类型', key: 'cmdType' },
];
const tableData = ref<DataTableRowData[]>([]);
const tablePagination = reactive<PaginationProps>({
showSizePicker: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 20, 50, 80, 100],
itemCount: 0,
prefix: ({ itemCount }) => {
return h('div', {}, { default: () => `${itemCount}` });
},
onUpdatePage: (page: number) => {
tablePagination.page = page;
getTableData();
},
onUpdatePageSize: (pageSize: number) => {
tablePagination.pageSize = pageSize;
tablePagination.page = 1;
getTableData();
},
});
const { mutate: getTableData, isPending: tableLoading } = useMutation({
mutationFn: async () => {
if (!searchFields.stationCode) throw Error('请选择车站');
const res = await pageCallLogApi(
{
model: {},
extra: getExtraFields(),
current: tablePagination.page ?? 1,
size: tablePagination.pageSize ?? 10,
order: 'descending',
sort: 'id',
},
{
stationCode: searchFields.stationCode,
},
);
return res;
},
onSuccess: (res) => {
const { records, size, total } = res;
tablePagination.pageSize = parseInt(size);
tablePagination.itemCount = parseInt(total);
tableData.value = records;
},
onError: (error) => {
console.error(error);
window.$message.error(error.message);
},
});
const onClickReset = () => {
resetSearchFields();
tablePagination.page = 1;
tablePagination.pageSize = 10;
tablePagination.itemCount = 0;
getTableData();
};
const onClickQuery = () => {
if (searchFieldsChanged.value) {
tablePagination.page = 1;
tablePagination.pageSize = 10;
searchFieldsChanged.value = false;
}
getTableData();
};
const { mutate: exportTableData, isPending: exporting } = useMutation({
mutationFn: async () => {
if (!searchFields.stationCode) throw Error('请选择车站');
const data = await exportCallLogApi(
{
model: {},
extra: getExtraFields(),
current: tablePagination.page ?? 1,
size: tablePagination.pageSize ?? 10,
order: 'descending',
sort: 'id',
},
{
stationCode: searchFields.stationCode,
},
);
return data;
},
onSuccess: (data) => {
const time = dayjs().format('YYYY-MM-DD_HH-mm-ss');
downloadByData(data, `上级调用日志_${time}.xlsx`);
},
onError: (error) => {
console.error(error);
window.$message.error(error.message);
},
});
const defaultStation = computed(() => onlineStationList.value.at(0));
watchEffect(() => {
if (defaultStation.value?.code && !searchFields.stationCode) {
searchFields.stationCode = defaultStation.value.code;
getTableData();
}
});
</script>
<template>
<!-- 容器上下布局表格自适应剩余高度 -->
<div style="height: 100%; display: flex; flex-direction: column">
<!-- 查询面板 -->
<div style="flex: 0 0 auto; padding: 8px">
<NForm>
<NGrid :cols="3" :x-gap="24">
<NFormItemGi :span="1" label="车站" label-placement="left">
<NSelect
v-model:value="searchFields.stationCode"
:options="stationSelectOptions"
:render-label="
(option: SelectOption) => {
return [
h(NTag, { type: option.disabled ? 'error' : 'success', size: 'tiny' }, { default: () => (option.disabled ? '离线' : '在线') }),
h('span', {}, { default: () => `${option.label}` }),
];
}
"
:multiple="false"
clearable
/>
</NFormItemGi>
<NFormItemGi :span="1" label="调用者国标码" label-placement="left">
<NInput v-model:value="searchFields.sourceGbId_like" placeholder="请输入调用者国标码" clearable />
</NFormItemGi>
<NFormItemGi :span="1" label="被调用设备国标码" label-placement="left">
<NInput v-model:value="searchFields.targetGbId_like" placeholder="请输入被调用设备国标码" clearable />
</NFormItemGi>
<NFormItemGi :span="1" label="调用方法" label-placement="left">
<NInput v-model:value="searchFields.method_like" placeholder="请输入调用方法" clearable />
</NFormItemGi>
<NFormItemGi :span="1" label="消息类型" label-placement="left">
<NInput v-model:value="searchFields.messageType_like" placeholder="请输入消息类型" clearable />
</NFormItemGi>
<NFormItemGi :span="1" label="操作类型" label-placement="left">
<NInput v-model:value="searchFields.cmdType_like" placeholder="请输入操作类型" clearable />
</NFormItemGi>
<NFormItemGi :span="1" label="时间" label-placement="left">
<NDatePicker v-model:formatted-value="searchFields.createdTime" type="datetimerange" @update:value="undefined" />
</NFormItemGi>
</NGrid>
<!-- 按钮 -->
<NGrid :cols="1">
<NGridItem>
<NSpace>
<NButton @click="onClickReset">重置</NButton>
<NButton type="primary" :loading="tableLoading" @click="onClickQuery">查询</NButton>
</NSpace>
</NGridItem>
</NGrid>
</NForm>
</div>
<!-- 工具栏:横向、右对齐按钮) -->
<div style="flex: 0 0 auto; display: flex; align-items: center; padding: 8px">
<div style="font-size: medium">视频平台日志</div>
<NSpace style="margin-left: auto">
<NButton type="primary" :loading="exporting" @click="() => exportTableData()">导出</NButton>
</NSpace>
</div>
<!-- 表格区域:填满剩余空间 -->
<div style="flex: 1 1 auto; min-height: 0; padding: 8px">
<NDataTable remote :columns="tableColumns" :data="tableData" :pagination="tablePagination" :loading="tableLoading" :single-line="false" flex-height style="height: 100%" />
</div>
</div>
</template>
<style scoped lang="scss"></style>