Files
pqs-9100_client/frontend/src/views/home/components/realTimeDataAlign.vue
2025-08-12 20:17:37 +08:00

436 lines
14 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.

<template>
<el-dialog title="实时数据详情" v-model='dialogVisible' @close="handleClose" v-bind="dialogBig">
<el-tabs v-model="activeTab" type="card">
<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>
<div class="table-toolbar">
<el-form-item label="被检设备通道号" prop="createId">
<el-select
v-model="selectedChannels[deviceName]"
placeholder="选择通道"
style="width: 150px;"
@change="() => handleDutChannelChange(deviceName)">
<el-option
v-for="channel in device.channelDataList"
:key="channel.devNum"
:label="`通道${channel.devNum}`"
:value="`通道${channel.devNum}`">
</el-option>
</el-select>
<span style="margin-left: 20px; font-size: 14px; color: var(--el-color-primary);">
被检设备{{ deviceName }}-{{ selectedChannels[deviceName] }} ---> 标准设备{{ formatStandardChannelLabel(getMappedStandardChannel(deviceName, selectedChannels[deviceName])) }}
</span>
</el-form-item>
<el-button type="primary" @click="exportData">导出数据</el-button>
</div>
<el-table
:data="tableDataMap[deviceName]"
: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'}">
<el-table-column :label="`${deviceName}-${selectedChannels[deviceName] || '通道1'}`">
<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)"/>
</el-table-column>
<el-table-column :label="formatStandardChannelLabel(getMappedStandardChannel(deviceName, selectedChannels[deviceName]))">
<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)"/>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</el-dialog>
</template>
<script setup lang='tsx' name='realTimeDataAlign'>
import { dialogBig } from "@/utils/elementBind";
import { PropType, ref } from "vue";
import { ElMessage } from "element-plus";
import { CircleCheck, CircleClose } from '@element-plus/icons-vue';
const dialogVisible = ref(false);
const activeTab = ref('channel1');
// 在 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>>({});
// 重构后的 testDataStructure
// 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
// }
// ]
// }
// ]
// }
// });
// 每个设备选中的通道
const selectedChannels = ref<Record<string, string>>({});
// 通道映射关系:被检设备通道 -> 标准设备通道
const channelMapping = ref<Record<string, Record<string, string>>>({
// '被检1': {
// '通道1': '标准设备1通道2',
// '通道2': '标准设备2通道4',
// },
// '被检2': {
// '通道1': '标准设备1通道3',
// '通道3': '标准设备2通道1'
// }
});
// 每个设备的表格数据
const tableDataMap = ref<Record<string, any[]>>({});
// 每个tab的状态true表示有不完整数据false表示数据完整
const tabStatus = ref<Record<string, boolean>>({});
// 检查设备数据是否有不完整的行包含null的行
const hasIncompleteData = (deviceName: string) => {
const tableData = tableDataMap.value[deviceName];
if (!tableData || tableData.length === 0) return false;
// 检查每一行是否有缺失数据包含null的字段
return tableData.some(row => {
return row.Ua1 === '/' || row.Ub1 === '/' || row.Uc1 === '/' ||
row.Ua2 === '/' || row.Ub2 === '/' || row.Uc2 === '/';
});
};
// 获取映射的标准设备通道
const getMappedStandardChannel = (deviceName: string, dutChannel: string) => {
return channelMapping.value[deviceName][dutChannel];
};
// 格式化标准设备通道标签,将设备名称和通道号用"-"连接
const formatStandardChannelLabel = (standardChannel: string) => {
// 如果是"标准设备X通道Y"格式,则转换为"标准设备X-通道Y"
return standardChannel.replace(/(标准设备\d+)(通道\d+)/, '$1-$2');
};
// 处理被检设备通道切换
const handleDutChannelChange = (deviceName: string) => {
// 更新指定设备的表格数据但不改变tab图标状态
updateTableData(deviceName);
};
// 根据 testDataStructure 生成表格数据
const generateTableData = (deviceName: string, dutChannel: string) => {
const deviceData = testDataStructure.value[deviceName];
if (!deviceData) return [];
// 根据实际通道编号查找对应的数据
const channelData = deviceData.channelDataList.find(channel =>
`通道${channel.devNum}` === dutChannel
);
if (!channelData) return [];
// 生成表格数据
return channelData.dataList.map(dataItem => {
return {
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 : '/'
};
});
};
// 更新指定设备的表格数据
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 => {
// 默认选择第一个可用通道
const firstChannel = testDataStructure.value[deviceName].channelDataList[0];
selectedChannels.value[deviceName] = `通道${firstChannel.devNum}`;
// 生成表格数据
updateTableData(deviceName);
// 初始化tab状态只在初始化时设置一次
if (tabStatus.value[deviceName] === undefined) {
tabStatus.value[deviceName] = hasIncompleteData(deviceName);
}
});
};
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;
dialogVisible.value = true;
// 初始化数据和状态
initAllTableData();
// 设置默认激活的 tab
activeTab.value = 'channel1';
};
// 导出数据
const exportData = () => {
ElMessage.success('数据导出成功');
// 这里可以添加实际的数据导出逻辑
};
// 关闭弹窗
const handleClose = () => {
dialogVisible.value = false;
};
defineExpose({ open });
</script>
<style scoped lang="scss">
.table-toolbar {
display: flex;
justify-content: space-between;
}
:deep(.el-dialog__body) {
padding: 10px 20px 20px 20px;
}
</style>