Files
pqs-9100_client/frontend/src/views/home/components/compareDataCheckSingleChannelSingleTestPopup.vue
2025-12-10 11:17:19 +08:00

714 lines
26 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
:append-to-body="appendToBody"
class="dialog"
title="数据查询"
:model-value="visible"
@close="close"
v-bind="dialogBig"
:draggable="false"
width="1400px"
>
<div class="data-check-dialog">
<div>
<el-form :model="formContent" label-width="auto" class="form-three">
<el-form-item label="误差体系">
<el-select
:disabled="checkStore.showDetailType === 2 || checkStore.showDetailType === 0"
v-model="formContent.errorSysId"
placeholder="请选择误差体系"
autocomplete="off"
@change="handleErrorSysChange"
>
<el-option
v-for="option in pqErrorList"
:key="option.id"
:label="option.name"
:value="option.id"
/>
</el-select>
</el-form-item>
<el-form-item label="数据原则">
<el-input v-model="formContent.dataRule" :disabled="true" />
</el-form-item>
<el-form-item label="设备名称">
<el-input v-model="formContent.deviceName" :disabled="true" />
</el-form-item>
<el-form-item label="通道号">
<el-select v-model="formContent.chnNum" @change="handleChnNumChange" :disabled="sourceKey == 1">
<el-option v-for="item in chnList" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item label="检测次数">
<el-select
v-model="formContent.num"
clearable
@change="handleNumChange"
:disabled="sourceKey == 1"
>
<el-option
v-for="item in chnMapList[formContent.chnNum]"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item v-if="checkStore.showDetailType === 1">
<el-button type="primary" :icon="Postcard">报告生成</el-button>
</el-form-item>
<el-form-item v-if="checkStore.showDetailType === 0">
<el-button type="primary" :icon="Histogram" @click="handleReCalculate">重新计算</el-button>
</el-form-item>
</el-form>
</div>
<div class="data-check-body">
<div class="content-left-tree" v-if="sourceKey == 2">
<el-tree
style="width: 200px"
:data="scriptData"
:props="defaultProps"
highlight-current
node-key="id"
ref="treeRef"
@node-click="handleNodeClick"
class="custom-tree"
>
<template #default="{ node, data }">
<div class="custom-tree-node">
<span v-if="data.resultFlag === 1">{{ node.label }}</span>
<span v-else-if="data.resultFlag === 2" style="color: #ee6666;">{{ node.label }}</span>
<span v-else-if="data.resultFlag === 4" style="color: #fac858;">{{ node.label }}</span>
</div>
</template>
</el-tree>
</div>
<div class="content-right">
<div class="content-right-title">
<div style="width: 840px">
<span class="content-right-title-text">当前检测项目</span>
<!-- 当code为'wave_data'时显示下拉框 -->
<el-select
v-if="isWaveData"
v-model="selectedScriptName"
style="width: 200px"
@change="handleScriptNameChange"
>
<el-option
v-for="item in scriptNameOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>
<div style="display: flex; align-items: center; justify-content: space-between">
<span v-if="item.resultFlag === 1" >{{ item.label }}</span>
<span v-else-if="item.resultFlag === 2" style="color: #ee6666;">{{ item.label }}</span>
<span v-else-if="item.resultFlag === 4" style="color: #fac858;">{{ item.label }}</span>
</div>
</el-option>
</el-select>
<!-- 否则显示原来的文本 -->
<span v-else style="color: var(--el-color-primary)">{{ rowList.scriptName }}</span>
</div>
<el-form-item
style="
margin: 0 auto;
margin-bottom: 0px !important;
width: 200px;
position: absolute;
left: 50%;
transform: translateX(-50%);
"
label="录波次数"
v-if="isWaveData"
>
<el-select v-model="waveNumber" @change="handleWaveNumberChange">
<el-option v-for="i in waveNumCount" :key="i" :label="i" :value="i" />
</el-select>
</el-form-item>
<el-form-item
style="margin-left: 280px; margin-bottom: 0px !important; width: 300px"
label="测试项"
>
<el-select v-model="currentCheckItem">
<el-option
v-for="item in tesList"
:key="item"
:label="item.replace(/\.0$/, '')"
:value="item"
/>
</el-select>
</el-form-item>
</div>
<div class="content-right-Tabs">
<el-tabs type="border-card" v-model="activeTab">
<el-tab-pane label="检测结果" name="resultTab">
<CompareDataCheckResultTable
:tableData="checkResultData.length == 0 ? [] : currentCheckResultData"
:currentCheckItem="currentCheckItem"
:currentScriptTypeName="currentScriptTypeName"
v-if="activeTab === 'resultTab'"
/>
</el-tab-pane>
<el-tab-pane label="原始数据" name="rawDataTab">
<CompareDataCheckRawDataTable
v-if="activeTab === 'rawDataTab'"
:tableData="rawTableData.length == 0 ? [] : currentRawTableData"
:currentCheckItem="currentCheckItem"
:currentScriptTypeName="currentScriptTypeName"
/>
</el-tab-pane>
<el-tab-pane label="历史趋势" name="chartTab">
<CompareDataCheckChart
v-if="activeTab === 'chartTab'"
:tableData="rawTableData.length == 0 ? [] : currentRawTableData"
/>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { dialogBig } from '@/utils/elementBind'
import { computed, reactive, ref } from 'vue'
import CompareDataCheckResultTable from './compareDataCheckResultTable.vue'
import CompareDataCheckRawDataTable from './compareDataCheckRawDataTable.vue'
import CompareDataCheckChart from './compareDataCheckChart.vue'
import { CheckData } from '@/api/check/interface'
import { useCheckStore } from '@/stores/modules/check'
import { Histogram, Postcard } from '@element-plus/icons-vue'
import { getPqErrSysList } from '@/api/plan/plan'
import { useModeStore } from '@/stores/modules/mode' // 引入模式 store
import { useDictStore } from '@/stores/modules/dict'
import {
changeErrorSystem,
deleteTempTable,
getContrastFormContent,
getContrastResult,
getScriptList,
reCalculate
} from '@/api/check/test'
import { ElMessage } from 'element-plus'
import { ResultEnum } from '@/enums/httpEnum'
const { appendToBody = true } = defineProps<{
appendToBody: boolean
}>()
const checkStore = useCheckStore()
const modeStore = useModeStore()
const dictStore = useDictStore()
const visible = ref(false)
const treeRef = ref()
const pqErrorList = reactive<{ id: string; name: string }[]>([])
const activeTab = ref('resultTab')
const currentCheckItem = ref<any>()
const rowList: any = ref([])
let scriptType: string | null = null
const defaultProps = {
children: 'children',
label: 'scriptName'
}
const chnMapList: any = ref({})
const waveNumCount = ref(0)
const waveNumber = ref(1)
const selectedScriptName = ref('')
const pattern = ref('')
// 添加以下内容
const isWaveData = ref(false)
const scriptNameOptions = ref<{ label: string; value: string;resultFlag:number }[]>([])
// 表单数据
const formContent = reactive<CheckData.DataCheck>({
scriptName: '',
errorSysId: '',
dataRule: '',
deviceName: '',
chnNum: '',
deviceId: '',
num: ''
})
const sourceKey = ref(1) //1:正式检测进入页面 2:检测数据查询进入
// 通道下拉列表
const chnList: any = ref([])
// 当前检测项目名称
const currentScriptTypeName = ref('')
// 检测结果表格数据
const checkResultData = ref<CheckData.CheckResult[]>([])
// 检测脚本配置数据
const scriptData = ref<CheckData.ScriptItem[]>([])
//录波对应当前检测项下拉框
const selectScript = ref<CheckData.ScriptItem[]>([])
// 原始数据表格数据
const rawTableData = ref<CheckData.RawDataItem[]>([])
const tesList: any = ref([])
// 检测结果
const currentCheckResultData = computed(() => {
const data = checkResultData.value[currentCheckItem.value]
return Array.isArray(data) ? data : []
})
const currentRawTableData = computed(() => {
const data = rawTableData.value[currentCheckItem.value]
return Array.isArray(data) ? data : []
})
const open = async (row: any, chnNum: string, deviceId: string | null, source: number) => {
isWaveData.value = false
pattern.value = dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id ?? '' //获取数据字典中对应的id
rowList.value = {}
formContent.deviceId = deviceId || ''
formContent.chnNum = chnNum
sourceKey.value = source
// 获取基本信息
await getBasicInformation(row.scriptType)
if (source == 1) {
// 正式检测进入页面 - 创建新的对象避免引用共享
rowList.value = {
scriptName: row.scriptName,
scriptType: row.scriptType,
// 复制其他需要的属性
devices: row.devices ? [...row.devices] : []
}
}
// 检测数据查询进入---不区分检测数据查询和正式检测
await initScriptData()
visible.value = true
scriptType = null
formContent.errorSysId = checkStore.plan.errorSysId
pqErrorList.length = 0
// 获取误差体系
let { data: resPqErrorList } = await getPqErrSysList()
Object.assign(pqErrorList, resPqErrorList)
initGetResult()
}
const initGetResult = async () => {
// 判断是否为录波数据
const isLuoboData =
(sourceKey.value == 1 && rowList.value.scriptName == '录波数据') ||
(sourceKey.value == 2 && scriptData.value[0]?.code == 'wave_data')
if (isLuoboData) {
isWaveData.value = true
// 设置录波数据相关的选项
scriptNameOptions.value = selectScript.value.map(item => ({
label: item.scriptName,
value: item.scriptName,
resultFlag: item.resultFlag?? 0
}))
// 默认选中第一个选项
if (scriptNameOptions.value.length > 0) {
selectedScriptName.value = scriptNameOptions.value[0].value
// 更新rowList以匹配选中的script
const selectedItem = selectScript.value.find(item => item.scriptName === selectedScriptName.value)
if (selectedItem) {
rowList.value.scriptName = selectedScriptName.value
rowList.value.scriptType = selectedItem.id
}
}
await getResults('wave_data')
} else {
await getResults('')
}
}
// 查询大项树
const initScriptData = async () => {
let response: any = await getScriptList({
devId: formContent.deviceId,
chnNum: formContent.chnNum,
num: formContent.num,
planId: checkStore.plan.id
})
// 格式化脚本数据
let temp = response.data.map((item: any) => {
return {
...item,
scriptName: item.scriptName
}
})
// 保存脚本数据
scriptData.value = temp
// 查找code为"录波"的项
let luoboItem = response.data.find((item: any) => item.code === 'wave_data')
// 如果找到了"录波"项则使用其subitems否则使用空数组
let temp2 = []
if (luoboItem && luoboItem.subItems) {
// 格式化脚本数据
temp2 = luoboItem.subItems.map((item: any) => {
return {
...item,
scriptName: item.scriptName,
resultFlag: item.resultFlag ?? 0 // 假设默认值为 0
}
})
}
selectScript.value = temp2
// 只有在sourceKey == 2时才设置rowList和tree相关属性
if (sourceKey.value === 2 && temp.length > 0) {
rowList.value.scriptName = temp[0].scriptName
rowList.value.scriptType = temp[0].id
selectedScriptName.value = temp[0].scriptName
setTimeout(() => {
treeRef.value?.setCurrentKey(temp[0].id)
}, 0)
}
}
// 获取基本信息
const getBasicInformation = async (scriptType: any) => {
checkResultData.value = []
rawTableData.value = []
const scriptType2 = ref('')
if (sourceKey.value == 1) {
scriptType2.value = scriptType
} else {
scriptType2.value = ''
}
//确保scriptData已初始化
// if (scriptData.value.length === 0) {
// await initScriptData()
// }
try {
const res: any = await getContrastFormContent({
planId: checkStore.plan.id,
scriptType: scriptType2.value,
deviceId: formContent.deviceId,
chnNum: formContent.chnNum,
num: formContent.num == '' ? null : parseInt(formContent.num),
patternId: pattern.value
})
formContent.dataRule = res.data.dataRule
formContent.deviceName = res.data.deviceName
formContent.errorSysId = res.data.errorSysId
chnMapList.value = res.data.chnMap
let chnMap: string[] = []
for (let key in res.data.chnMap) {
chnMap.push(key)
}
chnList.value = chnMap
formContent.chnNum = formContent.chnNum == null ? chnList.value[0] : formContent.chnNum
// 设置检测次数默认值为chnMap数组的最后一位
if (chnMapList.value[formContent.chnNum] && chnMapList.value[formContent.chnNum].length > 0) {
// 获取当前通道号对应的检测次数数组,并设置为最后一个值(最大值)
const numList = chnMapList.value[formContent.chnNum]
formContent.num = numList[numList.length - 1]
}
waveNumCount.value = res.data.waveNumTotal
} catch (error) {
console.error('获取基本信息失败:', error)
}
}
const handleChnNumChange = async (value: string) => {
formContent.chnNum = value
// 更新检测次数为当前通道的最后一条记录
updateCheckNumForChn(value)
// 执行通用变更处理逻辑
await handleCommonChange()
}
// 处理检测次数变更
const handleNumChange = async (value: string) => {
formContent.num = value
// 执行通用变更处理逻辑
await handleCommonChange()
}
// 通用的变更处理函数
const handleCommonChange = async () => {
// 重新初始化脚本数据(更新左侧树)
await initScriptData()
// 触发当前选中节点的点击事件,保持界面状态一致
if (sourceKey.value === 2 && scriptData.value.length > 0) {
// 查找当前选中的节点
const currentNode = scriptData.value.find((item: any) => item.id === rowList.value.scriptType)
if (currentNode) {
// 如果找到了当前节点,则触发点击事件
handleNodeClick(currentNode)
} else {
// 如果没有找到当前节点,则默认触发第一个节点的点击事件
handleNodeClick(scriptData.value[0])
}
} else if (sourceKey.value === 1 && rowList.value.scriptType) {
// 对于正式检测进入的情况创建一个临时节点对象来触发handleNodeClick
const tempNode = {
scriptName: rowList.value.scriptName,
id: rowList.value.scriptType,
code: rowList.value.scriptName === '录波数据' ? 'wave_data' : ''
}
handleNodeClick(tempNode)
}
}
// 更新检测次数为指定通道的最后一条记录
const updateCheckNumForChn = (chnNum: string) => {
if (chnMapList.value[chnNum] && chnMapList.value[chnNum].length > 0) {
// 获取当前通道号对应的检测次数数组,并设置为最后一个值(最大值)
const numList = chnMapList.value[chnNum]
formContent.num = numList[numList.length - 1]
}
}
// 左边树变化
const handleNodeClick = (data: any) => {
rowList.value.scriptName = data.scriptName
rowList.value.scriptType = data.id
// 判断是否为录波数据
if (data.code === 'wave_data') {
isWaveData.value = true
// 过滤掉"录波"选项,设置下拉框数据
scriptNameOptions.value = selectScript.value
//.filter(item => item.code !== 'wave_data' && item.code !== 'FREQ')
.map(item => ({
label: item.scriptName,
value: item.scriptName,
resultFlag: item.resultFlag ?? 0
}))
// 每次选中录波数据时都重置为第一个选项并触发getResults
if (scriptNameOptions.value.length > 0) {
selectedScriptName.value = scriptNameOptions.value[0].value
// 更新rowList并触发getResults
rowList.value.scriptName = selectedScriptName.value
const selectedItem = selectScript.value.find(item => item.scriptName === selectedScriptName.value)
if (selectedItem) {
rowList.value.scriptType = selectedItem.id
getResults('wave_data')
}
}
} else {
isWaveData.value = false
getResults(data.code)
}
}
// 获取结果
const getResults = async (code: any) => {
checkResultData.value = []
rawTableData.value = []
// 判断是否为录波数据请求
const isWaveDataRequest = code === 'wave_data' || isWaveData.value
getContrastResult({
planId: checkStore.plan.id,
scriptType: rowList.value.scriptType,
deviceId: formContent.deviceId,
chnNum: formContent.chnNum,
num: formContent.num == '' ? null : formContent.num,
waveNum: isWaveDataRequest ? waveNumber.value : null,
isWave: isWaveDataRequest,
patternId: pattern.value
}).then((res: any) => {
let list: string[] = []
for (let key in res.data.resultMap) {
list.push(key)
}
currentCheckItem.value = list[0]
tesList.value = list
checkResultData.value = res.data.resultMap
rawTableData.value = res.data.rawDataMap
})
}
// 添加处理scriptName变化的方法
const handleScriptNameChange = (value: string) => {
selectedScriptName.value = value
rowList.value.scriptName = value
// 查找选中项的scriptType
const selectedItem = selectScript.value.find(item => item.scriptName === value)
if (selectedItem) {
rowList.value.scriptType = selectedItem.id
getResults('wave_data')
}
}
// 添加处理waveNumber变化的方法
const handleWaveNumberChange = (value: number) => {
waveNumber.value = value
// 当录波次数改变时,重新获取结果
getResults('wave_data')
}
const close = async () => {
visible.value = false
formContent.num = ''
// 可以在这里添加其他清理逻辑
if (checkStore.showDetailType === 1) {
await deleteTempTable(checkStore.plan.code + '')
}
}
const handleErrorSysChange = async () => {
changeErrorSystem({
planId: checkStore.plan.id,
scriptId: '',
errorSysId: formContent.errorSysId,
deviceId: formContent.deviceId,
code: checkStore.plan.code + '',
patternId: dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id ?? '',
chnNum: formContent.chnNum
}).then(res => {
if (res.code === ResultEnum.SUCCESS) {
ElMessage.success('切换误差体系成功')
handleChnNumChange(formContent.chnNum)
}
})
}
const handleReCalculate = async () => {
reCalculate({
planId: checkStore.plan.id,
scriptId: '',
errorSysId: formContent.errorSysId,
deviceId: formContent.deviceId,
code: checkStore.plan.code + '',
patternId: dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id ?? '',
chnNum: formContent.chnNum
}).then(res => {
if (res.code === ResultEnum.SUCCESS) {
ElMessage.success('重新计算成功!')
handleChnNumChange(formContent.chnNum)
}
})
}
defineExpose({
open
})
</script>
<style lang="scss" scoped>
.custom-tree {
:deep(.el-tree-node__content) {
.custom-tree-node {
display: flex;
align-items: center;
width: 100%;
}
// 根据 resultFlag 设置不同颜色
&[data-result-flag="2"] {
color: #ee6666; // 红色 - 不符合
}
&[data-result-flag="4"] {
color: #fac858; // 橙色 - 警告
}
}
}
.dialog {
display: flex;
flex-direction: column;
.data-check-dialog {
display: flex;
flex-direction: column;
.data-check-head {
display: flex;
flex-direction: row;
width: 100%;
}
.data-check-body {
height: 500px;
width: 100%;
display: flex;
flex-direction: row;
.content-left-tree {
width: 18%;
display: flex;
flex-direction: column;
align-items: center;
max-height: 495px;
padding: 10px 0.5% 0px 0.5%;
border: 1px solid #ccc;
overflow-y: auto;
overflow-x: auto;
margin-right: 10px;
.content-tree {
width: 100%;
height: 100%;
margin-top: 10px;
.custom-tree-node {
overflow-x: hidden !important;
white-space: nowrap !important;
text-overflow: ellipsis !important;
}
}
}
.content-right {
width: 82%;
flex: 1;
.content-right-title {
display: flex;
padding: 10px 0;
margin-top: 0px;
line-height: 1.5;
.content-right-title-text {
font-size: 14px;
font-weight: bold;
}
}
}
.content-right-Tabs {
box-sizing: border-box;
margin-top: 10px;
margin-bottom: 10px;
display: flex;
.el-tabs {
width: 100%;
}
}
.content-left {
height: 100%;
border: 1px solid #e0e0e0;
padding: 10px;
margin-right: 10px;
height: 410px;
overflow-y: auto;
}
}
}
}
:deep(.el-tabs--border-card > .el-tabs__content) {
height: 367px;
}
</style>