2025-07-17 08:48:10 +08:00

412 lines
12 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 type { VbenFormProps } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import { computed, nextTick, ref, watch, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { Page } from '@vben/common-ui';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { postMetersPage, postTreeModelDeviceDataInfoPage } from '#/api-client';
import { $t } from '#/locales';
import { generateDynamicColumns } from './dynamicColumns';
import { querySchema } from './schema';
defineOptions({
name: 'DeviceData',
});
// 存储设备信息选项的完整数据
const deviceOptions = ref<any[]>([]);
// 当前选中的设备信息
const selectedDeviceInfo = ref<any>(null);
// 获取设备信息的完整数据用于根据设备ID获取设备信息
const fetchDeviceOptions = async () => {
try {
const { data } = await postMetersPage({
body: {
pageIndex: 1,
pageSize: 1000,
},
});
if (data?.items) {
deviceOptions.value = data.items;
}
} catch (error) {
console.error('获取设备信息失败:', error);
}
};
// 根据设备ID获取设备信息对象
const getDeviceInfoById = (deviceId: string) => {
if (!deviceId || !deviceOptions.value || deviceOptions.value.length === 0) {
return null;
}
return deviceOptions.value.find((device) => device.id === deviceId);
};
const route = useRoute();
const { DeviceType, DeviceId, FocusAddress, SystemName } = route.query;
// 动态列定义
const dynamicColumns = ref<any[]>([]);
// 固定列定义(始终显示)- 基于 IoTDBTreeModelDeviceDataDto 类型
const fixedColumns = [
{ title: '序号', type: 'seq', width: 50, field: 'seq', slots: {} },
{ field: 'Timestamps', title: $t('abp.IoTDBBase.Timestamps'), minWidth: 150, showOverflow: true, slots: {} },
{ field: 'SystemName', title: $t('abp.IoTDBBase.SystemName'), minWidth: 150, showOverflow: true, slots: {} },
{ field: 'ProjectId', title: $t('abp.IoTDBBase.ProjectId'), minWidth: 150, showOverflow: true, slots: {} },
{ field: 'DeviceType', title: $t('abp.IoTDBBase.DeviceType'), minWidth: 150, showOverflow: true, slots: {} },
{
field: 'IoTDataType',
title: $t('abp.IoTDBBase.IoTDataType'),
minWidth: 150,
showOverflow: true,
slots: {},
},
{ field: 'DeviceId', title: $t('abp.IoTDBBase.DeviceId'), minWidth: 150, showOverflow: true, slots: {} },
];
// 合并固定列和动态列 - 使用计算属性确保响应式
const allColumns = computed(() => {
// 如果表格未初始化,只返回固定列
if (!isGridInitialized.value) {
return [...fixedColumns];
}
const columns = [...fixedColumns];
// 安全地添加动态列
if (dynamicColumns.value && Array.isArray(dynamicColumns.value)) {
const validDynamicColumns = dynamicColumns.value.filter(col =>
col && typeof col === 'object' && col.field && col.title
).map(col => ({
...col,
slots: col.slots || {} // 确保每个列都有slots属性
}));
columns.push(...validDynamicColumns);
}
return columns;
});
// 初始化默认列(防止表格空白)
const initDefaultColumns = () => {
// 确保dynamicColumns是一个有效的数组
if (!Array.isArray(dynamicColumns.value)) {
dynamicColumns.value = [];
}
};
// 表格是否已初始化
const isGridInitialized = ref(false);
// 初始化默认列
initDefaultColumns();
const formOptions: VbenFormProps = {
schema: querySchema.value,
initialValues: {
FocusAddress: FocusAddress as string,
DeviceType: DeviceType ? Number(DeviceType) : undefined,
DeviceId: DeviceId as string,
SystemName: SystemName as string,
},
// 禁用表单值变化时自动提交,使用自定义处理函数
submitOnChange: false,
// 添加表单值变化的处理函数
handleValuesChange: async (values, changedFields) => {
// 当任何相关字段发生变化时,刷新表格数据
const relevantFields = new Set([
'DeviceId',
'DeviceType',
'FocusAddress',
'IoTDataType',
'SystemName',
]);
const hasRelevantChange = changedFields.some((field) =>
relevantFields.has(field),
);
// 新增DeviceId变化时同步selectedDeviceInfo
if (changedFields.includes('DeviceId')) {
const deviceId = values.DeviceId;
if (deviceId) {
// 先尝试从 deviceOptions 中查找(备用方案)
let device = deviceOptions.value.length > 0 ? deviceOptions.value.find(d => d.id === deviceId) : null;
// 如果没找到,尝试从 DeviceSelect 组件中获取
if (!device && gridApi?.formApi) {
try {
// 获取 DeviceSelect 组件的实例
const deviceSelectRef = gridApi.formApi.getFieldComponentRef('DeviceId');
if (deviceSelectRef && deviceSelectRef.getSelectedDevice) {
device = deviceSelectRef.getSelectedDevice();
}
} catch (error) {
// 静默处理错误
}
}
if (device) {
selectedDeviceInfo.value = device;
} else {
// 如果还是没找到,尝试延迟获取(组件可能还没完全更新)
setTimeout(() => {
try {
const deviceSelectRef = gridApi.formApi.getFieldComponentRef('DeviceId');
if (deviceSelectRef && deviceSelectRef.getSelectedDevice) {
const delayedDevice = deviceSelectRef.getSelectedDevice();
if (delayedDevice) {
selectedDeviceInfo.value = delayedDevice;
}
}
} catch (error) {
// 静默处理错误
}
}, 100);
}
} else {
selectedDeviceInfo.value = null;
}
}
if (hasRelevantChange) {
// 使用 setTimeout 确保表单值已经完全更新
setTimeout(async () => {
const latestValues = await gridApi.formApi.getValues();
gridApi.reload(latestValues);
}, 0);
}
},
};
const gridOptions: VxeGridProps<any> = {
checkboxConfig: {
highlight: true,
labelField: 'name',
},
columns: fixedColumns, // 初始化时只使用固定列
height: 'auto',
keepSource: true,
// 确保分页功能正常工作
pager: true,
pagerConfig: {
currentPage: 1,
pageSize: 20,
},
toolbarConfig: {
custom: true,
},
customConfig: {
storage: true,
},
// 添加调试配置
showOverflow: true,
showHeaderOverflow: true,
proxyConfig: {
ajax: {
query: async ({ page, sorts, filters }, formValues) => {
// 确保page参数存在
if (!page) {
return { items: [], totalCount: 0 };
}
// 获取当前表单值如果formValues为空则从表单API获取
const currentFormValues = formValues || (gridApi?.formApi ? await gridApi.formApi.getValues() : {}) || {};
// 处理DeviceType和IoTDataType确保传递数字类型
const deviceTypeValue = currentFormValues.DeviceType || DeviceType;
const deviceTypeNumber = deviceTypeValue
? Number(deviceTypeValue)
: undefined;
const ioTDataTypeValue = currentFormValues.IoTDataType;
// 处理DeviceId当设备类型为集中器(10)时使用focusId
let finalDeviceId = currentFormValues.DeviceId || DeviceId || '';
let finalFocusAddress = currentFormValues.FocusAddress || '';
// 优先使用选中的设备信息
const deviceInfo = selectedDeviceInfo.value || (currentFormValues.DeviceId && deviceOptions.value.length > 0 ? getDeviceInfoById(currentFormValues.DeviceId) : null);
if (deviceInfo) {
finalFocusAddress = deviceInfo.focusAddress || '';
if (deviceTypeNumber === 10) {
// 集中器类型使用focusId
if (deviceInfo.focusId) {
finalDeviceId = deviceInfo.focusId;
}
} else {
// 其他设备类型使用meterId
if (deviceInfo.meterId) {
finalDeviceId = deviceInfo.meterId;
}
}
}
try {
const { data } = await postTreeModelDeviceDataInfoPage({
body: {
pageIndex: page.currentPage,
pageSize: page.pageSize,
// 优先使用表单中的值,如果没有则使用路由参数
DeviceType: deviceTypeNumber || undefined,
DeviceId: finalDeviceId ? finalDeviceId.toString() : '',
FocusAddress: finalFocusAddress || FocusAddress || '',
// 添加其他表单参数
SystemName: currentFormValues.SystemName || SystemName || '',
IoTDataType: ioTDataTypeValue || undefined,
},
});
// 简化处理逻辑,直接使用接口返回的数据
if (data?.items && data.items.length > 0) {
try {
// 动态生成列定义
const generatedColumns = generateDynamicColumns(data.items);
// 更新动态列
dynamicColumns.value = generatedColumns;
// 使用setState更新整个gridOptions确保列定义能够正确更新
await nextTick();
if (gridApi && gridApi.setState) {
gridApi.setState({
gridOptions: {
...gridOptions,
columns: allColumns.value,
// 保持分页配置
pager: true,
pagerConfig: gridOptions.pagerConfig,
},
});
}
} catch (error) {
console.error('更新列定义时出错:', error);
// 如果列更新失败,使用空数组
dynamicColumns.value = [];
}
// 直接使用接口返回的totalCount
const result = {
items: data.items || [],
totalCount: data.totalCount || 0,
};
return result;
}
return {
items: [],
totalCount: 0,
};
} catch (error) {
console.error('API调用出错:', error);
throw error;
}
},
},
},
};
const [Grid, gridApi] = useVbenVxeGrid({ formOptions, gridOptions });
// 监听分页器状态变化
watch(
() => gridApi?.pagerApi?.pageSize,
(newSize, oldSize) => {
if (newSize !== oldSize && oldSize) {
// 重置到第一页
gridApi.pagerApi.currentPage = 1;
// 触发数据重新加载
gridApi.reload();
}
},
);
// 监听当前页变化
watch(
() => gridApi?.pagerApi?.currentPage,
(newPage, oldPage) => {
if (newPage !== oldPage && oldPage) {
// 触发数据重新加载
gridApi.reload();
}
},
);
// 初始化函数
const initializeGrid = async () => {
try {
// 获取设备信息数据
await fetchDeviceOptions();
// 标记表格已初始化
isGridInitialized.value = true;
// 更新表格列定义
if (gridApi && gridApi.setState) {
await nextTick();
gridApi.setState({
gridOptions: {
...gridOptions,
columns: allColumns.value,
// 保持分页配置
pager: true,
pagerConfig: gridOptions.pagerConfig,
},
});
}
// 如果有路由参数,自动触发查询
if (DeviceType || DeviceId || FocusAddress || SystemName) {
// 延迟一下确保表格已完全初始化
setTimeout(() => {
if (gridApi) {
gridApi.reload();
}
}, 300);
}
} catch (error) {
console.error('初始化表格失败:', error);
}
};
// 监听路由参数变化,当有路由参数时自动触发查询
watch(
() => [DeviceType, DeviceId, FocusAddress, SystemName],
async (newValues, oldValues) => {
// 如果有路由参数,等待设备信息加载完成后自动触发查询
if (newValues.some(val => val) && gridApi && isGridInitialized.value) {
// 延迟一下确保表单值已经设置
setTimeout(() => {
gridApi.reload();
}, 100);
}
},
{ immediate: false } // 改为false避免立即触发
);
// 页面初始化时,延迟初始化表格
onMounted(async () => {
// 延迟初始化确保VXE表格组件已完全挂载
setTimeout(async () => {
await initializeGrid();
}, 100);
});
</script>
<template>
<Page auto-content-height>
<Grid />
</Page>
</template>