实时数据对齐

This commit is contained in:
sjl
2025-08-07 14:43:56 +08:00
parent d2f92ecde4
commit 022d80f30e
7 changed files with 1410 additions and 310 deletions

View File

@@ -32,3 +32,11 @@ export const pauseTest = () => {
export const resumeTest = (params) => { export const resumeTest = (params) => {
return http.post(`/prepare/restartTemTest/`, params, {loading: false}) return http.post(`/prepare/restartTemTest/`, params, {loading: false})
} }
/**
* 比对式通道配对
* @param params
*/
export const contrastTest = (params: any) => {
return http.post(`/prepare/startContrastTest`,params)
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
<template> <template>
<el-dialog title="设备通道配对" v-model='dialogVisible' v-bind="dialogBig"> <el-dialog title="设备通道配对" v-model='dialogVisible' v-bind="dialogBig" >
<div class="flow-container" style="overflow: hidden; position: relative;"> <div class="flow-container" style="overflow: hidden; position: relative" :style="{ height: dialogHeight + 'px' }">
<el-button @click="logConnections">打印当前配对</el-button> <!-- <el-button @click="logConnections">打印当前配对</el-button> -->
<VueFlow <VueFlow
:nodes="nodes" :nodes="nodes"
:edges="edges" :edges="edges"
@@ -36,7 +36,7 @@
</el-dialog> </el-dialog>
<!-- 手动检测-勾选检测项弹窗 --> <!-- 手动检测-勾选检测项弹窗 -->
<SelectTestItemPopup ref="selectTestItemPopupRef" @openTestDialog="openTestDialog"></SelectTestItemPopup> <SelectTestItemPopup ref="selectTestItemPopupRef" @openTestDialog="openTestDialog" ></SelectTestItemPopup>
<CompareTestPopup ref='testPopup'></CompareTestPopup> <CompareTestPopup ref='testPopup'></CompareTestPopup>
</template> </template>
@@ -51,11 +51,16 @@ import SelectTestItemPopup from "@/views/home/components/selectTestItemPopup.vue
import CompareTestPopup from './compareTestPopup.vue' import CompareTestPopup from './compareTestPopup.vue'
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import CustomEdge from './RemoveableEdge.vue' // 导入自定义连接线组件 import CustomEdge from './RemoveableEdge.vue' // 导入自定义连接线组件
import {contrastTest} from '@/api/socket/socket'
import { jwtUtil } from "@/utils/jwtUtil";
const dialogVisible = ref(false) const dialogVisible = ref(false)
const selectTestItemPopupRef = ref<InstanceType<typeof SelectTestItemPopup>>() const selectTestItemPopupRef = ref<InstanceType<typeof SelectTestItemPopup>>()
const testPopup = ref() const testPopup = ref()
const dialogTitle = ref('手动检测') const dialogTitle = ref('手动检测')
// 计算对话框高度
const dialogHeight = ref(600)
// 初始化 VueFlow注册自定义连线类型 // 初始化 VueFlow注册自定义连线类型
const { edges, setViewport } = useVueFlow({ const { edges, setViewport } = useVueFlow({
@@ -213,7 +218,7 @@ const handleNext = () => {
selectTestItemPopupRef.value?.open(sourceIdArray.value) selectTestItemPopupRef.value?.open(sourceIdArray.value)
} }
const openTestDialog = () => { const openTestDialog = async () => {
testPopup.value?.open(dialogTitle.value,sourceIdArray.value) testPopup.value?.open(dialogTitle.value,sourceIdArray.value)
} }
@@ -365,6 +370,10 @@ const createNodes = (device: Device.ResPqDev[], standardDev: StandardDevice.ResP
} }
}) })
console.log(newNodes)
return newNodes return newNodes
} }
@@ -373,7 +382,6 @@ defineExpose({ open })
<style> <style>
.flow-container { .flow-container {
height: 600px;
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
} }

View File

@@ -23,12 +23,12 @@
placeholder="选择通道" placeholder="选择通道"
style="width: 150px;" style="width: 150px;"
@change="() => handleDutChannelChange(deviceName)"> @change="() => handleDutChannelChange(deviceName)">
<el-option <el-option
v-for="(channelData, channelName) in device.dutData" v-for="channel in device.channelDataList"
:key="channelName" :key="channel.devNum"
:label="channelName.replace('被检', '')" :label="`通道${channel.devNum}`"
:value="channelName"> :value="`通道${channel.devNum}`">
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-button type="primary" @click="exportData">导出数据</el-button> <el-button type="primary" @click="exportData">导出数据</el-button>
@@ -40,7 +40,7 @@
style="width: 100%" style="width: 100%"
:style="{ height: '400px',maxHeight: '400px',overflow:'hidden'}"> :style="{ height: '400px',maxHeight: '400px',overflow:'hidden'}">
<el-table-column prop="monitorNum" label="数据时标" width="180"/> <el-table-column prop="monitorNum" label="数据时标" width="180"/>
<el-table-column :label="`${deviceName}-${selectedChannels[deviceName]?.replace('被检', '') || '通道1'}`"> <el-table-column :label="`${deviceName}-${selectedChannels[deviceName] || '通道1'}`">
<el-table-column prop="Ua1" label="A相(V)"> <el-table-column prop="Ua1" label="A相(V)">
</el-table-column> </el-table-column>
<el-table-column prop="Ub1" label="B相(V)"> <el-table-column prop="Ub1" label="B相(V)">
@@ -48,7 +48,7 @@
<el-table-column prop="Uc1" label="C相(V)"> <el-table-column prop="Uc1" label="C相(V)">
</el-table-column> </el-table-column>
</el-table-column> </el-table-column>
<el-table-column :label="`标准设备-${getMappedStandardChannel(deviceName, selectedChannels[deviceName])?.replace('标准', '') || '通道1'}`"> <el-table-column :label="`${getMappedStandardChannel(deviceName, selectedChannels[deviceName])}`">
<el-table-column prop="Ua2" label="A相(V)"> <el-table-column prop="Ua2" label="A相(V)">
</el-table-column> </el-table-column>
<el-table-column prop="Ub2" label="B相(V)"> <el-table-column prop="Ub2" label="B相(V)">
@@ -71,158 +71,161 @@ import { CircleCheck, CircleClose } from '@element-plus/icons-vue';
const dialogVisible = ref(false); const dialogVisible = ref(false);
const activeTab = ref('channel1'); const activeTab = ref('channel1');
// 重构后的 testDataStructure
const testDataStructure = ref({ const testDataStructure = ref({
// 第一层:多个被检设备 "被检设备1": {
'被检设备1': { devName: "被检设备1",
// 被检设备数据 channelDataList: [
dutData: { {
'被检通道1': { devNum: "1",
// 第三层各个时间点的ABC三相数据 standardDevInfo: "标准设备1通道1",
'2023-05-20 10:30:01': { dataList: [
Ua: '1', {
Ub: '2', timeDev: "2025-09-02 14:00:02.231",
Uc: '3', uaDev: 57.74,
}, ubDev: 57.74,
'2023-05-20 10:30:04': { ucDev: 57.74,
Ua: '4', timeStdDev: "2025-09-02 14:00:02.231",
Ub: '5', uaStdDev: 57.73,
Uc: '6', ubStdDev: 57.73,
}, ucStdDev: 57.74
'2023-05-20 10:30:07': { },
Ua: '7', {
Ub: '8', timeDev: "2025-09-02 14:00:02.234",
Uc: '9', uaDev: 57.74,
}, ubDev: 57.74,
'2023-05-20 10:30:10': { ucDev: 57.74,
Ua: '10', timeStdDev: null,
Ub: '11', uaStdDev: null,
Uc: '12', ubStdDev: null,
}, ucStdDev: null
'2023-05-20 10:30:13': { },
Ua: '13', {
Ub: '14', timeDev: null,
Uc: '15', uaDev: null,
} ubDev: null,
ucDev: null,
timeStdDev: "2025-09-02 14:00:02.237",
uaStdDev: 57.74,
ubStdDev: 57.74,
ucStdDev: 57.74
}
]
}, },
'被检通道2': { {
'2023-05-20 10:30:01': { devNum: "2",
Ua: '7', standardDevInfo: "标准设备2通道4",
Ub: '8', dataList: [
Uc: '9', {
}, timeDev: "2025-09-02 14:00:02.231",
'2023-05-20 10:30:04': { uaDev: 57.74,
Ua: '10', ubDev: 57.74,
Ub: '11', ucDev: 57.74,
Uc: '12', timeStdDev: "2025-09-02 14:00:02.231",
}, uaStdDev: 57.73,
'2023-05-20 10:30:07': { ubStdDev: 57.73,
Ua: '13', ucStdDev: 57.74
Ub: '14', },
Uc: '15', {
}, timeDev: "2025-09-02 14:00:02.231",
'2023-05-20 10:30:10': { uaDev: 57.74,
Ua: '16', ubDev: 57.74,
Ub: '17', ucDev: 57.74,
Uc: '18', timeStdDev: "2025-09-02 14:00:02.231",
}, uaStdDev: 57.73,
'2023-05-20 10:30:13': { ubStdDev: 57.73,
Ua: '19', ucStdDev: 57.74
Ub: '20', },
Uc: '21', {
} 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
}
]
} }
}, ]
// 标准设备数据
standardData: {
'标准通道1': {
'2023-05-20 10:30:00': {
Ua: '01',
Ub: '02',
Uc: '03',
},
'2023-05-20 10:30:03': {
Ua: '04',
Ub: '05',
Uc: '06',
},
'2023-05-20 10:30:06': {
Ua: '07',
Ub: '08',
Uc: '09',
},
'2023-05-20 10:30:09': {
Ua: '010',
Ub: '011',
Uc: '012',
},
'2023-05-20 10:30:12': {
Ua: '013',
Ub: '014',
Uc: '015',
}
},
'标准通道2': {
'2023-05-20 10:30:01': {
Ua: '07',
Ub: '08',
Uc: '09',
},
'2023-05-20 10:30:04': {
Ua: '010',
Ub: '011',
Uc: '012',
},
'2023-05-20 10:30:07': {
Ua: '013',
Ub: '014',
Uc: '015',
},
'2023-05-20 10:30:10': {
Ua: '016',
Ub: '017',
Uc: '018',
},
'2023-05-20 10:30:13': {
Ua: '019',
Ub: '020',
Uc: '021',
}
}
}
}, },
'被检设备2': { "被检设备2": {
dutData: { devName: "被检设备2",
'被检通道1': { channelDataList: [
'2023-05-20 10:30:01': { {
Ua: '11', devNum: "1",
Ub: '12', standardDevInfo: "标准设备1通道1",
Uc: '13', 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
}
]
}, },
'被检通道2': { {
'2023-05-20 10:30:01': { devNum: "3",
Ua: '14', standardDevInfo: "标准设备2通道4",
Ub: '15', dataList: [
Uc: '16', {
} 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
}
]
} }
}, ]
standardData: {
'标准通道1': {
'2023-05-20 10:30:01': {
Ua: '011',
Ub: '012',
Uc: '013',
}
},
'标准通道2': {
'2023-05-20 10:30:01': {
Ua: '014',
Ub: '015',
Uc: '016',
}
}
}
} }
}); });
@@ -230,15 +233,14 @@ const testDataStructure = ref({
const selectedChannels = ref<Record<string, string>>({}); const selectedChannels = ref<Record<string, string>>({});
// 通道映射关系:被检设备通道 -> 标准设备通道 // 通道映射关系:被检设备通道 -> 标准设备通道
// 格式被检设备1-被检通道1标准设备1-标准通道2
const channelMapping = ref<Record<string, Record<string, string>>>({ const channelMapping = ref<Record<string, Record<string, string>>>({
'被检设备1': { '被检设备1': {
'被检通道1': '标准通道1', '通道1': '标准设备1通道1',
'被检通道2': '标准通道2' '通道2': '标准设备2通道4',
}, },
'被检设备2': { '被检设备2': {
'被检通道1': '标准通道2', '通道1': '标准设备1通道1',
'被检通道2': '标准通道1' '通道3': '标准设备2通道4'
} }
}); });
@@ -248,14 +250,14 @@ const tableDataMap = ref<Record<string, any[]>>({});
// 每个tab的状态true表示有不完整数据false表示数据完整 // 每个tab的状态true表示有不完整数据false表示数据完整
const tabStatus = ref<Record<string, boolean>>({}); const tabStatus = ref<Record<string, boolean>>({});
// 检查设备数据是否有不完整的行(包含/的行) // 检查设备数据是否有不完整的行(包含null的行)
const hasIncompleteData = (deviceName: string) => { const hasIncompleteData = (deviceName: string) => {
const tableData = tableDataMap.value[deviceName]; const tableData = tableDataMap.value[deviceName];
if (!tableData || tableData.length === 0) return false; if (!tableData || tableData.length === 0) return false;
// 检查每一行是否有缺失数据(包含/的字段) // 检查每一行是否有缺失数据(包含null的字段)
return tableData.some(row => { return tableData.some(row => {
return row.Ua1 === '/' || row.Ub1 === '/' || row.Uc1 === '/' || return row.Ua1 === '/' || row.Ub1 === '/' || row.Uc1 === '/' ||
row.Ua2 === '/' || row.Ub2 === '/' || row.Uc2 === '/'; row.Ua2 === '/' || row.Ub2 === '/' || row.Uc2 === '/';
}); });
}; };
@@ -263,9 +265,10 @@ const hasIncompleteData = (deviceName: string) => {
// 获取映射的标准设备通道 // 获取映射的标准设备通道
const getMappedStandardChannel = (deviceName: string, dutChannel: string) => { const getMappedStandardChannel = (deviceName: string, dutChannel: string) => {
if (!channelMapping.value[deviceName]) { if (!channelMapping.value[deviceName]) {
return '标准通道1'; // 默认值 // 默认值
return dutChannel === '通道1' ? '标准设备1通道1' : '标准设备2通道4';
} }
return channelMapping.value[deviceName][dutChannel] || '标准通道1'; return channelMapping.value[deviceName][dutChannel] || '标准设备1通道1';
}; };
// 处理被检设备通道切换 // 处理被检设备通道切换
@@ -279,31 +282,24 @@ const generateTableData = (deviceName: string, dutChannel: string) => {
const deviceData = testDataStructure.value[deviceName]; const deviceData = testDataStructure.value[deviceName];
if (!deviceData) return []; if (!deviceData) return [];
const dutData = deviceData.dutData[dutChannel];
// 获取映射的标准设备通道 // 根据实际通道编号查找对应的数据
const standardChannel = getMappedStandardChannel(deviceName, dutChannel); const channelData = deviceData.channelDataList.find(channel =>
const standardData = deviceData.standardData[standardChannel]; `通道${channel.devNum}` === dutChannel
);
if (!dutData || !standardData) return []; if (!channelData) return [];
// 获取所有时间戳并去重排序
const dutTimestamps = Object.keys(dutData);
const standardTimestamps = Object.keys(standardData);
const allTimestamps = Array.from(new Set([...dutTimestamps, ...standardTimestamps])).sort();
// 生成表格数据 // 生成表格数据
return allTimestamps.map(timestamp => { return channelData.dataList.map(dataItem => {
const dutValues = dutData[timestamp];
const standardValues = standardData[timestamp];
return { return {
monitorNum: timestamp, monitorNum: dataItem.timeDev || dataItem.timeStdDev || '',
Ua1: dutValues ? dutValues.Ua : '/', Ua1: dataItem.uaDev !== null ? dataItem.uaDev : '/',
Ub1: dutValues ? dutValues.Ub : '/', Ub1: dataItem.ubDev !== null ? dataItem.ubDev : '/',
Uc1: dutValues ? dutValues.Uc : '/', Uc1: dataItem.ucDev !== null ? dataItem.ucDev : '/',
Ua2: standardValues ? standardValues.Ua : '/', Ua2: dataItem.uaStdDev !== null ? dataItem.uaStdDev : '/',
Ub2: standardValues ? standardValues.Ub : '/', Ub2: dataItem.ubStdDev !== null ? dataItem.ubStdDev : '/',
Uc2: standardValues ? standardValues.Uc : '/' Uc2: dataItem.ucStdDev !== null ? dataItem.ucStdDev : '/'
}; };
}); });
}; };
@@ -320,9 +316,10 @@ const updateTableData = (deviceName: string) => {
// 初始化所有设备的数据和状态 // 初始化所有设备的数据和状态
const initAllTableData = () => { const initAllTableData = () => {
Object.keys(testDataStructure.value).forEach(deviceName => { Object.keys(testDataStructure.value).forEach(deviceName => {
// 默认选择第一个通道
const firstChannel = Object.keys(testDataStructure.value[deviceName].dutData)[0]; // 默认选择第一个可用通道
selectedChannels.value[deviceName] = firstChannel; const firstChannel = testDataStructure.value[deviceName].channelDataList[0];
selectedChannels.value[deviceName] = `通道${firstChannel.devNum}`;
// 生成表格数据 // 生成表格数据
updateTableData(deviceName); updateTableData(deviceName);

View File

@@ -33,6 +33,8 @@ import {useCheckStore} from "@/stores/modules/check";
import type {CheckData} from "@/api/check/interface"; import type {CheckData} from "@/api/check/interface";
import {ElMessageBox} from "element-plus"; import {ElMessageBox} from "element-plus";
import {useAppSceneStore,useModeStore} from "@/stores/modules/mode"; import {useAppSceneStore,useModeStore} from "@/stores/modules/mode";
const AppSceneStore = useAppSceneStore() const AppSceneStore = useAppSceneStore()
const emit = defineEmits(['openTestDialog']) const emit = defineEmits(['openTestDialog'])
const checkStore = useCheckStore(); const checkStore = useCheckStore();
@@ -66,7 +68,7 @@ const resetFormContent = () => {
Object.assign(formContent, {preTest: !hasResult, channelsTest: false, timeTest: false, test: hasResult}) Object.assign(formContent, {preTest: !hasResult, channelsTest: false, timeTest: false, test: hasResult})
} }
const handleStart = () => { const handleStart = async () => {
let count = 0 let count = 0
for (let key in formContent) { for (let key in formContent) {
if (formContent[key]) { if (formContent[key]) {
@@ -100,6 +102,9 @@ const handleStart = () => {
} }
checkStore.setCheckType(0) checkStore.setCheckType(0)
checkStore.setSelectTestItems({...formContent}) checkStore.setSelectTestItems({...formContent})
handleClose() handleClose()
emit('openTestDialog',checkStore.selectTestItems.test) emit('openTestDialog',checkStore.selectTestItems.test)

View File

@@ -636,7 +636,7 @@ onBeforeMount(async () => {
// 比对模式下加载额外的计划表格数据 // 比对模式下加载额外的计划表格数据
const patternId2 = dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id const patternId2 = dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id
if (patternId2 !== undefined) { if (patternId2 !== undefined) {
planTable.value = await getPlanList({ 'patternId': patternId2 }) planTable.value = await getPlanList({ 'patternId': patternId2 } )
} }
}) })

View File

@@ -118,7 +118,7 @@ const refreshTable = async () => {
try { try {
console.log("表格刷新") console.log("表格刷新")
patternId.value = dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id; patternId.value = dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id;
const result = await getPlanList({'patternId' : patternId.value}); const result = await getPlanList({'patternId' : patternId.value} );
tableData.value = buildTree(result.data as any[]); tableData.value = buildTree(result.data as any[]);
pageTotal.value = tableData.value.length; pageTotal.value = tableData.value.length;
updateCurrentPageData(tableData.value) updateCurrentPageData(tableData.value)