Files
pqs-9100_client/frontend/src/views/home/components/realTimeDataAlign.vue

436 lines
14 KiB
Vue
Raw Normal View History

2025-08-05 10:37:40 +08:00
<template>
2025-08-06 15:18:27 +08:00
<el-dialog title="实时数据详情" v-model='dialogVisible' @close="handleClose" v-bind="dialogBig">
2025-08-05 10:37:40 +08:00
<el-tabs v-model="activeTab" type="card">
2025-08-06 15:18:27 +08:00
<el-tab-pane
v-for="(device, deviceName, index) in testDataStructure"
:key="deviceName"
:name="`channel${index + 1}`">
<template #label>
<span>
{{ deviceName }}
<el-icon v-if="tabStatus[deviceName]" style="color: red; margin-left: 5px;">
<CircleClose />
</el-icon>
<el-icon v-else style="color: green; margin-left: 5px;">
<CircleCheck />
</el-icon>
</span>
</template>
2025-08-05 10:37:40 +08:00
<div class="table-toolbar">
<el-form-item label="被检设备通道号" prop="createId">
2025-08-06 15:18:27 +08:00
<el-select
v-model="selectedChannels[deviceName]"
placeholder="选择通道"
style="width: 150px;"
@change="() => handleDutChannelChange(deviceName)">
2025-08-07 14:43:56 +08:00
<el-option
v-for="channel in device.channelDataList"
:key="channel.devNum"
:label="`通道${channel.devNum}`"
:value="`通道${channel.devNum}`">
</el-option>
2025-08-06 15:18:27 +08:00
</el-select>
2025-08-08 13:18:01 +08:00
<span style="margin-left: 20px; font-size: 14px; color: var(--el-color-primary);">
被检设备{{ deviceName }}-{{ selectedChannels[deviceName] }} ---> 标准设备{{ formatStandardChannelLabel(getMappedStandardChannel(deviceName, selectedChannels[deviceName])) }}
</span>
2025-08-05 10:37:40 +08:00
</el-form-item>
<el-button type="primary" @click="exportData">导出数据</el-button>
</div>
<el-table
2025-08-06 15:18:27 +08:00
:data="tableDataMap[deviceName]"
2025-08-05 10:37:40 +08:00
:header-cell-style="{ textAlign: 'center',backgroundColor: 'var(--el-color-primary)',color: '#fff' } "
:cell-style="{ textAlign: 'center' }"
style="width: 100%"
:style="{ height: '400px',maxHeight: '400px',overflow:'hidden'}">
2025-08-12 20:17:37 +08:00
2025-08-07 14:43:56 +08:00
<el-table-column :label="`${deviceName}-${selectedChannels[deviceName] || '通道1'}`">
2025-08-12 20:17:37 +08:00
<el-table-column prop="timeDev" label="数据时标" width="200"/>
<el-table-column prop="uaDev" label="A相(V)"/>
<el-table-column prop="ubDev" label="B相(V)"/>
<el-table-column prop="ucDev" label="C相(V)"/>
2025-08-05 10:37:40 +08:00
</el-table-column>
2025-08-08 13:18:01 +08:00
<el-table-column :label="formatStandardChannelLabel(getMappedStandardChannel(deviceName, selectedChannels[deviceName]))">
2025-08-12 20:17:37 +08:00
<el-table-column prop="timeStdDev" label="数据时标" width="200"/>
<el-table-column prop="uaStdDev" label="A相(V)"/>
<el-table-column prop="uaStdDev" label="B相(V)"/>
<el-table-column prop="uaStdDev" label="C相(V)"/>
2025-08-05 10:37:40 +08:00
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</el-dialog>
</template>
<script setup lang='tsx' name='realTimeDataAlign'>
import { dialogBig } from "@/utils/elementBind";
2025-08-08 13:18:01 +08:00
import { PropType, ref } from "vue";
2025-08-05 10:37:40 +08:00
import { ElMessage } from "element-plus";
2025-08-06 15:18:27 +08:00
import { CircleCheck, CircleClose } from '@element-plus/icons-vue';
2025-08-05 10:37:40 +08:00
const dialogVisible = ref(false);
const activeTab = ref('channel1');
2025-08-06 15:18:27 +08:00
2025-08-12 20:17:37 +08:00
// 在 script setup 中定义接口
interface ChannelData {
devNum: string;
standardDevInfo: string;
dataList: {
timeDev: string | null;
uaDev: number | null;
ubDev: number | null;
ucDev: number | null;
timeStdDev: string | null;
uaStdDev: number | null;
ubStdDev: number | null;
ucStdDev: number | null;
}[];
}
interface DeviceData {
devName: string;
channelDataList: ChannelData[];
}
// 修改 testDataStructure 的类型声明
const testDataStructure = ref<Record<string, DeviceData>>({});
2025-08-08 13:18:01 +08:00
2025-08-07 14:43:56 +08:00
// 重构后的 testDataStructure
2025-08-12 20:17:37 +08:00
// const testDataStructure = ref({
// "被检1": {
// devName: "被检设备1",
// channelDataList: [
// {
// devNum: "1",
// standardDevInfo: "标准设备1通道1",
// dataList: [
// {
// timeDev: "2025-09-02 14:00:02.231",
// uaDev: 57.74,
// ubDev: 57.74,
// ucDev: 57.74,
// timeStdDev: "2025-09-02 14:00:02.231",
// uaStdDev: 57.73,
// ubStdDev: 57.73,
// ucStdDev: 57.74
// },
// {
// timeDev: "2025-09-02 14:00:02.234",
// uaDev: 57.74,
// ubDev: 57.74,
// ucDev: 57.74,
// timeStdDev: null,
// uaStdDev: null,
// ubStdDev: null,
// ucStdDev: null
// },
// {
// timeDev: null,
// uaDev: null,
// ubDev: null,
// ucDev: null,
// timeStdDev: "2025-09-02 14:00:02.237",
// uaStdDev: 57.74,
// ubStdDev: 57.74,
// ucStdDev: 57.74
// }
// ]
// },
// {
// devNum: "2",
// standardDevInfo: "标准设备2通道4",
// dataList: [
// {
// timeDev: "2025-09-02 14:00:02.231",
// uaDev: 57.74,
// ubDev: 57.74,
// ucDev: 57.74,
// timeStdDev: "2025-09-02 14:00:02.231",
// uaStdDev: 57.73,
// ubStdDev: 57.73,
// ucStdDev: 57.74
// },
// {
// timeDev: "2025-09-02 14:00:02.231",
// uaDev: 57.74,
// ubDev: 57.74,
// ucDev: 57.74,
// timeStdDev: "2025-09-02 14:00:02.231",
// uaStdDev: 57.73,
// ubStdDev: 57.73,
// ucStdDev: 57.74
// },
// {
// timeDev: "2025-09-02 14:00:02.231",
// uaDev: 57.74,
// ubDev: 57.74,
// ucDev: 57.74,
// timeStdDev: "2025-09-02 14:00:02.231",
// uaStdDev: 57.73,
// ubStdDev: 57.73,
// ucStdDev: 57.74
// }
// ]
// }
// ]
// },
// "被检2": {
// devName: "被检设备2",
// channelDataList: [
// {
// devNum: "1",
// standardDevInfo: "标准设备1通道1",
// dataList: [
// {
// timeDev: "2025-09-02 14:00:02.231",
// uaDev: 57.74,
// ubDev: 57.74,
// ucDev: 57.74,
// timeStdDev: "2025-09-02 14:00:02.231",
// uaStdDev: 57.73,
// ubStdDev: 57.73,
// ucStdDev: 57.74
// },
// {
// timeDev: "2025-09-02 14:00:02.234",
// uaDev: 57.74,
// ubDev: 57.74,
// ucDev: 57.74,
// timeStdDev: "2025-09-02 14:00:02.231",
// uaStdDev: 57.73,
// ubStdDev: 57.73,
// ucStdDev: 57.74
// },
// {
// timeDev: "2025-09-02 14:00:02.234",
// uaDev: 57.74,
// ubDev: 57.74,
// ucDev: 57.74,
// timeStdDev: "2025-09-02 14:00:02.237",
// uaStdDev: 57.74,
// ubStdDev: 57.74,
// ucStdDev: 57.74
// }
// ]
// },
// {
// devNum: "3",
// standardDevInfo: "标准设备2通道4",
// dataList: [
// {
// timeDev: "2025-09-02 14:00:02.231",
// uaDev: 57.74,
// ubDev: 57.74,
// ucDev: 57.74,
// timeStdDev: "2025-09-02 14:00:02.231",
// uaStdDev: 57.73,
// ubStdDev: 57.73,
// ucStdDev: 57.74
// },
// {
// timeDev: "2025-09-02 14:00:02.231",
// uaDev: 57.74,
// ubDev: 57.74,
// ucDev: 57.74,
// timeStdDev: "2025-09-02 14:00:02.231",
// uaStdDev: 57.73,
// ubStdDev: 57.73,
// ucStdDev: 57.74
// },
// {
// timeDev: "2025-09-02 14:00:02.231",
// uaDev: 57.74,
// ubDev: 57.74,
// ucDev: 57.74,
// timeStdDev: "2025-09-02 14:00:02.231",
// uaStdDev: 57.73,
// ubStdDev: 57.73,
// ucStdDev: 57.74
// }
// ]
// }
// ]
// }
// });
2025-08-06 15:18:27 +08:00
// 每个设备选中的通道
const selectedChannels = ref<Record<string, string>>({});
// 通道映射关系:被检设备通道 -> 标准设备通道
const channelMapping = ref<Record<string, Record<string, string>>>({
2025-08-12 20:17:37 +08:00
// '被检1': {
// '通道1': '标准设备1通道2',
// '通道2': '标准设备2通道4',
// },
// '被检2': {
// '通道1': '标准设备1通道3',
// '通道3': '标准设备2通道1'
// }
2025-08-06 15:18:27 +08:00
});
2025-08-05 10:37:40 +08:00
2025-08-06 15:18:27 +08:00
// 每个设备的表格数据
const tableDataMap = ref<Record<string, any[]>>({});
// 每个tab的状态true表示有不完整数据false表示数据完整
const tabStatus = ref<Record<string, boolean>>({});
2025-08-07 14:43:56 +08:00
// 检查设备数据是否有不完整的行包含null的行
2025-08-06 15:18:27 +08:00
const hasIncompleteData = (deviceName: string) => {
const tableData = tableDataMap.value[deviceName];
if (!tableData || tableData.length === 0) return false;
2025-08-07 14:43:56 +08:00
// 检查每一行是否有缺失数据包含null的字段
2025-08-06 15:18:27 +08:00
return tableData.some(row => {
2025-08-07 14:43:56 +08:00
return row.Ua1 === '/' || row.Ub1 === '/' || row.Uc1 === '/' ||
2025-08-06 15:18:27 +08:00
row.Ua2 === '/' || row.Ub2 === '/' || row.Uc2 === '/';
});
};
// 获取映射的标准设备通道
const getMappedStandardChannel = (deviceName: string, dutChannel: string) => {
2025-08-08 13:18:01 +08:00
return channelMapping.value[deviceName][dutChannel];
2025-08-05 10:37:40 +08:00
};
2025-08-08 13:18:01 +08:00
// 格式化标准设备通道标签,将设备名称和通道号用"-"连接
const formatStandardChannelLabel = (standardChannel: string) => {
// 如果是"标准设备X通道Y"格式,则转换为"标准设备X-通道Y"
return standardChannel.replace(/(标准设备\d+)(通道\d+)/, '$1-$2');
};
2025-08-06 15:18:27 +08:00
// 处理被检设备通道切换
const handleDutChannelChange = (deviceName: string) => {
// 更新指定设备的表格数据但不改变tab图标状态
updateTableData(deviceName);
};
// 根据 testDataStructure 生成表格数据
const generateTableData = (deviceName: string, dutChannel: string) => {
const deviceData = testDataStructure.value[deviceName];
if (!deviceData) return [];
2025-08-07 14:43:56 +08:00
// 根据实际通道编号查找对应的数据
const channelData = deviceData.channelDataList.find(channel =>
`通道${channel.devNum}` === dutChannel
);
2025-08-06 15:18:27 +08:00
2025-08-07 14:43:56 +08:00
if (!channelData) return [];
2025-08-06 15:18:27 +08:00
// 生成表格数据
2025-08-07 14:43:56 +08:00
return channelData.dataList.map(dataItem => {
2025-08-06 15:18:27 +08:00
return {
2025-08-12 20:17:37 +08:00
timeDev: dataItem.timeDev !== null ? dataItem.timeDev : '/',
uaDev: dataItem.uaDev !== null ? dataItem.uaDev : '/',
ubDev: dataItem.ubDev !== null ? dataItem.ubDev : '/',
ucDev: dataItem.ucDev !== null ? dataItem.ucDev : '/',
timeStdDev: dataItem.timeStdDev !== null ? dataItem.timeStdDev : '/',
uaStdDev: dataItem.uaStdDev !== null ? dataItem.uaStdDev : '/',
ubStdDev: dataItem.ubStdDev !== null ? dataItem.ubStdDev : '/',
ucStdDev: dataItem.ucStdDev !== null ? dataItem.ucStdDev : '/'
2025-08-06 15:18:27 +08:00
};
});
};
// 更新指定设备的表格数据
const updateTableData = (deviceName: string) => {
const selectedChannel = selectedChannels.value[deviceName];
if (selectedChannel) {
const tableData = generateTableData(deviceName, selectedChannel);
tableDataMap.value[deviceName] = tableData;
}
};
// 初始化所有设备的数据和状态
const initAllTableData = () => {
Object.keys(testDataStructure.value).forEach(deviceName => {
2025-08-07 14:43:56 +08:00
// 默认选择第一个可用通道
const firstChannel = testDataStructure.value[deviceName].channelDataList[0];
selectedChannels.value[deviceName] = `通道${firstChannel.devNum}`;
2025-08-06 15:18:27 +08:00
// 生成表格数据
updateTableData(deviceName);
// 初始化tab状态只在初始化时设置一次
if (tabStatus.value[deviceName] === undefined) {
tabStatus.value[deviceName] = hasIncompleteData(deviceName);
}
});
};
2025-08-12 20:17:37 +08:00
const open = async (mapping : Record<string, Record<string, string>>,data : any) => {
let parsedData = data;
// 如果 data 是字符串,先解析为对象
if (typeof data === 'string') {
try {
parsedData = JSON.parse(data);
} catch (error) {
console.error('数据解析失败:', error);
ElMessage.error('数据格式错误');
return;
}
}
// 转换数据格式以匹配组件期望的格式
const convertedData: Record<string, DeviceData> = {};
// 假设传入的数据是一个数组,需要转换为以设备名为键的对象
if (Array.isArray(parsedData)) {
parsedData.forEach((deviceItem: any) => {
const deviceName = deviceItem.devName;
convertedData[deviceName] = {
devName: deviceName,
channelDataList: deviceItem.channelDataList.map((channel: any) => ({
devNum: channel.devNum,
standardDevInfo: channel.standardDevInfo,
dataList: channel.dataList.map((dataItem: any) => ({
timeDev: dataItem.timeDev,
uaDev: dataItem.uaDev,
ubDev: dataItem.ubDev,
ucDev: dataItem.ucDev,
timeStdDev: dataItem.timeStdDev,
uaStdDev: dataItem.uaStdDev,
ubStdDev: dataItem.ubStdDev,
ucStdDev: dataItem.ucStdDev
}))
}))
};
});
} else if (parsedData && typeof parsedData === 'object') {
// 如果已经是期望的格式,直接使用
Object.assign(convertedData, parsedData);
}
testDataStructure.value = convertedData;
channelMapping.value = mapping;
2025-08-06 15:18:27 +08:00
dialogVisible.value = true;
// 初始化数据和状态
initAllTableData();
// 设置默认激活的 tab
activeTab.value = 'channel1';
2025-08-05 10:37:40 +08:00
};
// 导出数据
const exportData = () => {
ElMessage.success('数据导出成功');
// 这里可以添加实际的数据导出逻辑
};
// 关闭弹窗
const handleClose = () => {
dialogVisible.value = false;
};
defineExpose({ open });
</script>
<style scoped lang="scss">
.table-toolbar {
display: flex;
2025-08-06 15:18:27 +08:00
justify-content: space-between;
2025-08-05 10:37:40 +08:00
}
:deep(.el-dialog__body) {
padding: 10px 20px 20px 20px;
}
</style>