Files
pqs-9100_client/frontend/src/views/machine/freqConverter/components/freqConverterTestPopup.vue

407 lines
10 KiB
Vue
Raw Normal View History

2026-04-17 09:15:58 +08:00
<template>
<el-dialog
:model-value="dialogVisible"
:title="dialogTitle"
:width="dialogWidth"
:style="dialogStyle"
:close-on-click-modal="dialogBig.closeOnClickModal"
:draggable="dialogBig.draggable"
:class="dialogBig.class"
:show-close="true"
:close-on-press-escape="false"
:before-close="handleBeforeClose"
destroy-on-close
align-center
>
<div class="freq-converter-test-popup">
<el-steps :active="currentStep - 1" finish-status="success" simple>
<el-step title="准备" />
<el-step title="检测" />
</el-steps>
<FreqConverterDetectChannelPairing
v-if="dialogVisible && currentStep === 1"
ref="channelPairingRef"
:freq-converter="currentFreqConverter"
/>
<FreqConverterDipChart
v-else-if="dialogVisible && currentStep === 2"
:selected-mapping="selectedMapping"
:web-msg-send="webSocketMessage"
:result-data="historyResultData"
2026-05-06 10:53:30 +08:00
:auto-draw-curve="false"
2026-04-17 09:15:58 +08:00
/>
</div>
<template #footer>
<div class="dialog-footer">
<el-button
v-if="!startDetectSuccess"
type="primary"
:disabled="currentStep !== 1 || startLoading"
:loading="startLoading"
@click="handleStart"
>
开始检测
</el-button>
<el-button type="danger" plain @click="handleExit">退出检测</el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import {ElMessage, ElMessageBox} from 'element-plus'
import {computed, onBeforeUnmount, onMounted, ref} from 'vue'
import {dialogBig} from '@/utils/elementBind'
import {type FreqConverter} from '@/api/device/interface/freqConverter'
import {getFreqConverterResult, startFreqConverterDetect, stopFreqConverterDetect} from '@/api/device/freqConverter'
import {JwtUtil} from '@/utils/jwtUtil'
import FreqConverterDetectChannelPairing from '@/views/machine/freqConverter/components/freqConverterDetectChannelPairing.vue'
import FreqConverterDipChart from '@/views/machine/freqConverter/components/freqConverterDipChart.vue'
import socketClient from '@/utils/webSocketClient'
const SOCKET_CALLBACK_KEY = 'aaa'
const props = defineProps<{
refreshTable?: (() => Promise<void>) | (() => void) | undefined;
}>()
const dialogVisible = ref(false)
const currentStep = ref(1)
const currentFreqConverter = ref<FreqConverter.ResFreqConverter | null>(null)
const channelPairingRef = ref<InstanceType<typeof FreqConverterDetectChannelPairing>>()
const webSocketMessage = ref<any>(null)
const historyResultData = ref<any>(null)
const socketServe = ref<typeof socketClient.Instance | null>(null)
const selectedMapping = ref<Record<string, any> | null>(null)
const startLoading = ref(false)
const startDetectSuccess = ref(false)
const hasSocketError = ref(false)
const viewportWidth = ref(typeof window === 'undefined' ? 1280 : window.innerWidth)
const dialogTitle = computed(() => '变频器检测')
const dialogWidth = computed(() => (viewportWidth.value < 820 ? 'calc(100vw - 24px)' : dialogBig.width))
const dialogStyle = computed(() => ({
maxWidth: dialogBig.maxWidth,
minWidth: viewportWidth.value < 820 ? '320px' : dialogBig.minWidth
}))
const SOCKET_ERROR_MESSAGE_MAP: Record<number, string> = {
10550: '设备连接异常',
10551: '设备触发报告异常',
10552: '重复的初始化操作',
10553: '通讯模块通讯异常',
10554: '报文解析异常',
10556: '不存在上线的设备',
400:'请求格式或者参数错误',
404:'未知错误',
// 408:'超时',
// 409:'业务执行不符合预期',
500:'未知错误'
2026-04-17 09:15:58 +08:00
}
const normalizeFormalRealPayload = (payload: any) => {
if (!payload || typeof payload !== 'object') {
return payload
}
if (typeof payload.data !== 'string') {
return payload
}
try {
return {
...payload,
data: JSON.parse(payload.data)
}
} catch (error) {
console.error('formal_real 数据解析失败:', error, payload.data)
return payload
}
}
const extractResultArray = (payload: any) => {
if (Array.isArray(payload)) {
return payload
}
if (Array.isArray(payload?.data)) {
return payload.data
}
if (Array.isArray(payload?.data?.records)) {
return payload.data.records
}
if (Array.isArray(payload?.records)) {
return payload.records
}
if (Array.isArray(payload?.list)) {
return payload.list
}
return [] as any[]
}
2026-04-17 09:15:58 +08:00
const handleSocketMessage = (payload: any) => {
const requestId = `${payload?.requestId ?? ''}`
const normalizedRequestId = requestId.trim().toLowerCase()
const code = Number(payload?.code)
if (requestId === 'yjc_sbtxjy' && code !== 10200 || code in SOCKET_ERROR_MESSAGE_MAP) {
2026-04-17 09:15:58 +08:00
hasSocketError.value = true
ElMessage.error(SOCKET_ERROR_MESSAGE_MAP[code] || `检测异常,错误码:${code}`)
return
}
if (normalizedRequestId.startsWith('formal_real')) {
webSocketMessage.value = normalizeFormalRealPayload(payload)
}
}
const updateViewportWidth = () => {
viewportWidth.value = window.innerWidth
}
const connectWebSocket = () => {
try {
if (socketServe.value) {
socketServe.value.unRegisterCallBack?.(SOCKET_CALLBACK_KEY)
if (socketServe.value.connected) {
socketServe.value.closeWs()
}
}
socketClient.Instance.connect()
socketServe.value = socketClient.Instance
socketServe.value.registerCallBack(SOCKET_CALLBACK_KEY, handleSocketMessage)
} catch (error) {
console.error('WebSocket连接处理失败:', error)
ElMessage.error('WebSocket连接建立失败请重试')
}
}
const closeWebSocket = () => {
try {
if (socketServe.value) {
socketServe.value.unRegisterCallBack?.(SOCKET_CALLBACK_KEY)
if (socketServe.value.connected) {
socketServe.value.closeWs()
}
socketServe.value = null
}
} catch (error) {
console.error('WebSocket关闭失败:', error)
socketServe.value = null
}
}
const resetState = () => {
currentStep.value = 1
webSocketMessage.value = null
historyResultData.value = null
currentFreqConverter.value = null
selectedMapping.value = null
startLoading.value = false
startDetectSuccess.value = false
hasSocketError.value = false
}
const closeDialog = () => {
dialogVisible.value = false
closeWebSocket()
resetState()
}
const stopDetect = async () => {
if (!startDetectSuccess.value) {
return
}
try {
await stopFreqConverterDetect({
userId: JwtUtil.getLoginName()
})
} catch (error) {
console.error('停止变频器检测失败:', error)
}
}
const confirmExit = async () => {
await ElMessageBox.confirm(
'检测未完成,是否退出当前检测流程?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
}
const isFreqConverterDetected = () => {
return Number(currentFreqConverter.value?.testStatus) === 1
}
const confirmResetLastDetectData = async () => {
if (!isFreqConverterDetected()) {
return true
}
try {
await ElMessageBox.confirm(
'是否覆盖上次检测数据',
'提示',
{
confirmButtonText: '是',
cancelButtonText: '否',
distinguishCancelAndClose: true,
type: 'warning'
}
)
return true
} catch (action) {
if (action === 'cancel') {
return false
}
return null
}
}
const handleBeforeClose = async (done: () => void) => {
if (hasSocketError.value) {
await stopDetect()
closeDialog()
await props.refreshTable?.()
done()
return
}
try {
await confirmExit()
await stopDetect()
closeDialog()
await props.refreshTable?.()
done()
} catch {
// 用户取消关闭
}
}
const handleStart = async () => {
if (currentStep.value === 1) {
const mapping = channelPairingRef.value?.getChannelMapping()
if (!mapping || !channelPairingRef.value?.hasValidConnection()) {
ElMessage.warning('请先选择设备通道并完成连线')
return
}
const reset = await confirmResetLastDetectData()
if (reset === null) {
return
}
startLoading.value = true
try {
if (reset === false) {
const historyResult = await getFreqConverterResult({
converterId: mapping.freqConverterId
})
historyResultData.value = extractResultArray(historyResult?.data ?? historyResult)
2026-04-17 09:15:58 +08:00
} else {
historyResultData.value = null
}
const res = await startFreqConverterDetect({
converterId: mapping.freqConverterId,
monitorId: `${mapping.deviceId}_${mapping.deviceChannel}`,
userId: JwtUtil.getLoginName(),
reset
})
if (res.code === 'A0000') {
selectedMapping.value = mapping
currentStep.value = 2
startDetectSuccess.value = true
return
}
} catch (error) {
console.error('开始变频器检测失败:', error)
ElMessage.error('开始检测失败')
} finally {
startLoading.value = false
}
return
}
}
const handleExit = async () => {
if (!hasSocketError.value) {
try {
await confirmExit()
} catch {
return
}
}
await stopDetect()
closeDialog()
await props.refreshTable?.()
}
const open = (row: FreqConverter.ResFreqConverter) => {
resetState()
currentFreqConverter.value = {...row}
dialogVisible.value = true
connectWebSocket()
}
onMounted(() => {
window.addEventListener('resize', updateViewportWidth)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', updateViewportWidth)
closeWebSocket()
})
defineExpose({open, channelPairingRef})
</script>
<style scoped>
.freq-converter-test-popup {
display: flex;
flex-direction: column;
gap: 10px;
}
.section-card {
border: 1px solid var(--el-border-color-light);
}
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
.section-tip {
color: var(--el-text-color-secondary);
font-size: 12px;
}
:deep(.el-dialog__body) {
padding-top: 10px;
padding-bottom: 10px;
overflow: hidden;
}
</style>