From 1c336fc6c9bcba4328e918c4692e35ecc2f22ab8 Mon Sep 17 00:00:00 2001 From: jingna <1264204245@qq.com> Date: Wed, 6 Aug 2025 16:08:44 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/renderer/src/services/api.js | 5 + frontend/src/renderer/src/views/Detection.vue | 300 ++++++++++-------- 2 files changed, 174 insertions(+), 131 deletions(-) diff --git a/frontend/src/renderer/src/services/api.js b/frontend/src/renderer/src/services/api.js index 8d2c1896..22c23e23 100644 --- a/frontend/src/renderer/src/services/api.js +++ b/frontend/src/renderer/src/services/api.js @@ -112,6 +112,11 @@ export const deviceAPI = { return api.post('/api/devices/calibrate') }, + // 校准IMU头部姿态传感器 + calibrateIMU() { + return api.post('/api/devices/calibrate/imu') + }, + // 测试设备 testDevice() { return api.post('/api/devices/test') diff --git a/frontend/src/renderer/src/views/Detection.vue b/frontend/src/renderer/src/views/Detection.vue index f80c01b1..27aa45a9 100644 --- a/frontend/src/renderer/src/views/Detection.vue +++ b/frontend/src/renderer/src/views/Detection.vue @@ -83,11 +83,7 @@
{{ imuStatus }}
- 清零并保存 @@ -99,40 +95,36 @@
-
- +
-
旋转
-
左:{{ headPoseMaxValues.rotationLeftMax.toFixed(1) }}°
-
右:{{ headPoseMaxValues.rotationRightMax.toFixed(1) }}°
+
左:{{ + headPoseMaxValues.rotationLeftMax.toFixed(1) }}°
+
右:{{ + headPoseMaxValues.rotationRightMax.toFixed(1) }}°
- +
-
倾斜
-
左:{{ headPoseMaxValues.tiltLeftMax.toFixed(1) }}°
-
右:{{ headPoseMaxValues.tiltRightMax.toFixed(1) }}°
+
左:{{ + headPoseMaxValues.tiltLeftMax.toFixed(1) }}°
+
右:{{ + headPoseMaxValues.tiltRightMax.toFixed(1) }}°
- +
-
俯仰
-
下:{{ headPoseMaxValues.pitchDownMax.toFixed(1) }}°
-
上:{{ headPoseMaxValues.pitchUpMax.toFixed(1) }}°
+
下:{{ + headPoseMaxValues.pitchDownMax.toFixed(1) }}°
+
上:{{ + headPoseMaxValues.pitchUpMax.toFixed(1) }}°
-
- 历史数据.. -
-
- +
+ @@ -167,11 +159,11 @@
左前足 - 54% + {{ footPressure.left_front }}
左后足 - 54% + {{ footPressure.left_rear }}
@@ -183,26 +175,28 @@ 右足
- +
左足总压力 - 54% + {{ footPressure.left_total }}
右足总压力 - 54% + {{ footPressure.right_total }}
右前足 - 54% + {{ footPressure.right_front }}
右后足 - 54% + {{ footPressure.right_rear }}
@@ -404,9 +398,9 @@ const handleClose = () => { const diagnosticForm = ref({}) // 模拟历史数据 const historyData = ref([ - { id: 3, rotLeft: '-55.2°', rotRight: '54.2°', tiltLeft: '-17.7°', tiltRight: '18.2°', pitchDown: '-20.2°', pitchUp: '10.5°' }, - { id: 2, rotLeft: '-55.8°', rotRight: '56.2°', tiltLeft: '-17.5°', tiltRight: '17.9°', pitchDown: '-21.2°', pitchUp: '12.1°' }, - { id: 1, rotLeft: '-56.1°', rotRight: '55.7°', tiltLeft: '-17.5°', tiltRight: '18.5°', pitchDown: '-22.2°', pitchUp: '11.5°' } + // { id: 3, rotLeft: '-55.2°', rotRight: '54.2°', tiltLeft: '-17.7°', tiltRight: '18.2°', pitchDown: '-20.2°', pitchUp: '10.5°' }, + // { id: 2, rotLeft: '-55.8°', rotRight: '56.2°', tiltLeft: '-17.5°', tiltRight: '17.9°', pitchDown: '-21.2°', pitchUp: '12.1°' }, + // { id: 1, rotLeft: '-56.1°', rotRight: '55.7°', tiltLeft: '-17.5°', tiltRight: '18.5°', pitchDown: '-22.2°', pitchUp: '11.5°' } ]) const chartoption = ref({ backgroundColor: '#000000', @@ -435,26 +429,26 @@ const chartoption = ref({ length: '85%', width: 2, offsetCenter: [0, '5%'], - itemStyle:{ - color:'#ff8d00' + itemStyle: { + color: '#ff8d00' }, }, anchor: { show: true, showAbove: true, size: 18, - icon:'circle', + icon: 'circle', itemStyle: { borderWidth: 3, - color:'#ff8d00', - borderColor:'#ff8d00', + color: '#ff8d00', + borderColor: '#ff8d00', } }, axisLine: { roundCap: true, lineStyle: { width: 3, - color:[[1, '#0089ff']] + color: [[1, '#0089ff']] } }, axisTick: { @@ -523,6 +517,8 @@ function connectWebSocket() { startVideoStream() startIMUStreaming(); startPressureStreaming(); + //绘制头部仪表盘 + initchart() }) // 连接失败事件 @@ -694,6 +690,7 @@ const headPoseMaxValues = ref({ // 头部姿态历史最值记录数组 const headPoseHistory = ref([]) +const headPoseData = ref({}) // 最值跟踪状态 const isTrackingMaxValues = ref(false) @@ -703,22 +700,48 @@ function handleIMUData(data) { try { if (data && data.head_pose) { const headPose = data.head_pose - + // 更新头部姿态数据 console.log('🎯 更新IMU头部姿态数据:', { rotation: headPose.rotation, // 旋转角:左旋(-), 右旋(+) tilt: headPose.tilt, // 倾斜角:左倾(-), 右倾(+) pitch: headPose.pitch // 俯仰角:俯角(-), 仰角(+) }) - - // 显示角度值(保留一位小数) - console.log(`📐 头部姿态角度 - 旋转: ${headPose.rotation.toFixed(1)}°, 倾斜: ${headPose.tilt.toFixed(1)}°, 俯仰: ${headPose.pitch.toFixed(1)}°`) - - // 如果正在跟踪最值,则更新最值数据 - if (isTrackingMaxValues.value) { - updateHeadPoseMaxValues(headPose) + if (rotationCharts) { + rotationCharts.setOption({ + series: [{ + data: [{ + value:headPose.rotation.toFixed(1) + }] + }] + }) } - + if (pitchCharts) { + pitchCharts.setOption({ + series: [{ + data: [{ + value:headPose.pitch.toFixed(1) + }] + }] + }) + } + if (tiltCharts) { + tiltCharts.setOption({ + series: [{ + data: [{ + value:headPose.tilt.toFixed(1) + }] + }] + }) + } + // 显示角度值(保留一位小数) + // console.log(`📐 头部姿态角度 - 旋转: ${headPose.rotation.toFixed(1)}°, 倾斜: ${headPose.tilt.toFixed(1)}°, 俯仰: ${headPose.pitch.toFixed(1)}°`) + + // 如果正在跟踪最值,则更新最值数据 + // if (isTrackingMaxValues.value) { + updateHeadPoseMaxValues(headPose) + // } + // 这里可以添加数据可视化逻辑 // 例如更新图表或显示数值 @@ -751,7 +774,7 @@ function updateHeadPoseMaxValues(headPose) { headPose.rotation ) } - + // 更新倾斜角最值 if (headPose.tilt < 0) { // 左倾(负值),取绝对值的最大值 @@ -766,7 +789,7 @@ function updateHeadPoseMaxValues(headPose) { headPose.tilt ) } - + // 更新俯仰角最值 if (headPose.pitch < 0) { // 下俯(负值),取绝对值的最大值 @@ -781,16 +804,16 @@ function updateHeadPoseMaxValues(headPose) { headPose.pitch ) } - - // 输出当前最值(用于调试) - console.log('📊 当前头部姿态最值:', { - rotationLeft: headPoseMaxValues.value.rotationLeftMax.toFixed(1), - rotationRight: headPoseMaxValues.value.rotationRightMax.toFixed(1), - tiltLeft: headPoseMaxValues.value.tiltLeftMax.toFixed(1), - tiltRight: headPoseMaxValues.value.tiltRightMax.toFixed(1), - pitchUp: headPoseMaxValues.value.pitchUpMax.toFixed(1), - pitchDown: headPoseMaxValues.value.pitchDownMax.toFixed(1) - }) + + // // 输出当前最值(用于调试) + // console.log('📊 当前头部姿态最值:', { + // rotationLeft: headPoseMaxValues.value.rotationLeftMax.toFixed(1), + // rotationRight: headPoseMaxValues.value.rotationRightMax.toFixed(1), + // tiltLeft: headPoseMaxValues.value.tiltLeftMax.toFixed(1), + // tiltRight: headPoseMaxValues.value.tiltRightMax.toFixed(1), + // pitchUp: headPoseMaxValues.value.pitchUpMax.toFixed(1), + // pitchDown: headPoseMaxValues.value.pitchDownMax.toFixed(1) + // }) } catch (error) { console.error('❌ 更新头部姿态最值失败:', error) } @@ -800,7 +823,7 @@ function updateHeadPoseMaxValues(headPose) { function clearAndStartTracking() { try { saveMaxValuesToHistory() - + // 重置所有最值为0 headPoseMaxValues.value = { rotationLeftMax: 0, @@ -810,26 +833,21 @@ function clearAndStartTracking() { pitchUpMax: 0, pitchDownMax: 0 } - + // 开始跟踪 isTrackingMaxValues.value = true - - console.log('🔄 头部姿态最值已清零,开始跟踪') - ElMessage.success('头部姿态最值已清零,开始跟踪') + + // console.log('🔄 头部姿态最值已清零,开始跟踪') + // ElMessage.success('头部姿态最值已清零,开始跟踪') } catch (error) { - console.error('❌ 清零最值失败:', error) - ElMessage.error('清零最值失败') + // console.error('❌ 清零最值失败:', error) + ElMessage.error('清零失败') } } // 保存当前最值到历史记录 function saveMaxValuesToHistory() { try { - if (!isTrackingMaxValues.value) { - ElMessage.warning('请先点击清零开始跟踪') - return - } - // 创建当前最值的副本 const currentMaxValues = { id: headPoseHistory.value.length + 1, @@ -841,20 +859,20 @@ function saveMaxValuesToHistory() { pitchDownMax: Number(headPoseMaxValues.value.pitchDownMax.toFixed(1)), timestamp: new Date().toLocaleString() } - + // 添加到历史记录 headPoseHistory.value.push(currentMaxValues) - + // 停止跟踪 isTrackingMaxValues.value = false - - console.log('💾 头部姿态最值已保存:', currentMaxValues) - ElMessage.success(`头部姿态最值已保存(第${currentMaxValues.id}组)`) - + + // console.log('💾 头部姿态最值已保存:', currentMaxValues) + // ElMessage.success(`头部姿态最值已保存(第${currentMaxValues.id}组)`) + // 更新历史数据表格(如果存在的话) updateHistoryTable() } catch (error) { - console.error('❌ 保存最值失败:', error) + // console.error('❌ 保存最值失败:', error) ElMessage.error('保存最值失败') } } @@ -865,7 +883,7 @@ function updateHistoryTable() { // 将头部姿态最值数据合并到现有的历史数据中 if (headPoseHistory.value.length > 0) { const latestData = headPoseHistory.value[headPoseHistory.value.length - 1] - + // 更新historyData数组,添加头部姿态最值数据 const newHistoryItem = { id: latestData.id, @@ -877,66 +895,64 @@ function updateHistoryTable() { pitchUp: latestData.pitchUpMax, timestamp: latestData.timestamp } - // 如果historyData数组存在,则添加新数据 if (historyData.value) { historyData.value.push(newHistoryItem) } - + console.log('📋 历史数据表格已更新') } } catch (error) { console.error('❌ 更新历史数据表格失败:', error) } } - +const footPressure = ref({ + left_front: '', + left_rear: '', + right_front: '', + right_rear: '', + left_total: '', + right_total: '', + total_pressure: '' +}) +const footImgSrc = ref('') // 处理压力传感器足部压力数据 function handlePressureData(data) { try { if (data && data.foot_pressure) { const pressureData = data.foot_pressure - + // 更新足部压力数据 - console.log('👣 接收到压力传感器数据:') - // 显示分区压力值 if (pressureData.pressure_zones) { - const zones = pressureData.pressure_zones - console.log(' 分区压力值:') - console.log(` 左前足: ${zones.left_front} N`) - console.log(` 左后足: ${zones.left_rear} N`) - console.log(` 右前足: ${zones.right_front} N`) - console.log(` 右后足: ${zones.right_rear} N`) - console.log(` 左足总压力: ${zones.left_total} N`) - console.log(` 右足总压力: ${zones.right_total} N`) - console.log(` 总压力: ${zones.total_pressure} N`) + footPressure.value = pressureData.pressure_zones } - // 显示平衡分析 - if (pressureData.balance_analysis) { - const balance = pressureData.balance_analysis - console.log(' 平衡分析:') - console.log(` 平衡比例: ${(balance.balance_ratio * 100).toFixed(1)}%`) - console.log(` 压力中心偏移: ${balance.pressure_center_offset}%`) - console.log(` 平衡状态: ${balance.balance_status}`) - console.log(` 左足前后比: ${(balance.left_front_ratio * 100).toFixed(1)}%`) - console.log(` 右足前后比: ${(balance.right_front_ratio * 100).toFixed(1)}%`) - } - + // if (pressureData.balance_analysis) { + // const balance = pressureData.balance_analysis + // console.log(' 平衡分析:') + // console.log(` 平衡比例: ${(balance.balance_ratio * 100).toFixed(1)}%`) + // console.log(` 压力中心偏移: ${balance.pressure_center_offset}%`) + // console.log(` 平衡状态: ${balance.balance_status}`) + // console.log(` 左足前后比: ${(balance.left_front_ratio * 100).toFixed(1)}%`) + // console.log(` 右足前后比: ${(balance.right_front_ratio * 100).toFixed(1)}%`) + // } + // 处理压力图片 if (pressureData.pressure_image) { - console.log(' 📊 接收到压力分布图片 (base64格式)') + // console.log(' 📊 接收到压力分布图片 (base64格式)') // 这里可以将图片显示在界面上 - updatePressureImage(pressureData.pressure_image) + if (pressureData.pressure_image && pressureData.pressure_image.length > 0) { + footImgSrc.value = pressureData.pressure_image + } else { + console.warn('⚠️ 收到空的压力传感器数据图') + } } - - } } catch (error) { console.error('❌ 处理压力传感器数据失败:', error) } } - // 启动IMU头部姿态数据推流 function startIMUStreaming() { if (socket && socket.connected) { @@ -1429,21 +1445,19 @@ async function saveRecording() { mimeType: currentMimeType || 'video/webm;codecs=vp9' }) }) - if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`) } - const result = await response.json() - if (result.success) { + //诊断信息说明 + dialogVisible.value = true console.log('🎬 录像保存成功:', result.filepath) ElMessage.success({ message: `录像保存成功!文件路径: ${result.filepath}`, duration: 5000 }) isRecording.value = false - dialogVisible.value = true // 更新会话的视频路径 if (patientInfo.value.sessionId) { try { @@ -1460,7 +1474,6 @@ async function saveRecording() { // patientInfo.value.sessionId = null console.log('✅ 会话正式结束,会话ID已清空') } else { - dialogVisible.value = false throw new Error(result.message || '保存失败') } @@ -1470,7 +1483,6 @@ async function saveRecording() { message: `保存录像失败: ${error.message}`, duration: 5000 }) - dialogVisible.value = false // 即使保存失败,也要清空会话ID,避免状态混乱 patientInfo.value.sessionId = null console.log('⚠️ 录像保存失败,但会话已结束,会话ID已清空') @@ -1639,27 +1651,51 @@ const handleBeforeUnload = () => { } } const creatorId = ref('') -let headCharts = null; +let rotationCharts = null; +let pitchCharts = null; +let tiltCharts = null; const initchart = () => { // 确保 DOM 元素已经渲染 nextTick(() => { - const chartDom = document.getElementById('headChart1'); + const chartDom = document.getElementById('rotationChartId'); if (chartDom) { // 如果图表已经存在,先销毁 - if (headCharts) { - headCharts.dispose(); + if (rotationCharts) { + rotationCharts.dispose(); } - headCharts = echarts.init(chartDom); - headCharts.setOption(chartoption.value); + rotationCharts = echarts.init(chartDom); + rotationCharts.setOption(chartoption.value); // 添加窗口大小调整监听器 window.addEventListener('resize', () => { - if (headCharts) { - headCharts.resize(); + if (rotationCharts) { + rotationCharts.resize(); } }); } else { - console.warn('找不到 ID 为 headChart1 的 DOM 元素'); + console.warn('找不到 ID 为 的 DOM 元素'); + } + const chartDom2 = document.getElementById('pitchChartId'); + if (chartDom2) { + // 如果图表已经存在,先销毁 + if (pitchCharts) { + pitchCharts.dispose(); + } + pitchCharts = echarts.init(chartDom2); + pitchCharts.setOption(chartoption.value); + } else { + console.warn('找不到 ID 为 的 DOM 元素'); + } + const chartDom3 = document.getElementById('tiltChartId'); + if (chartDom3) { + // 如果图表已经存在,先销毁 + if (tiltCharts) { + tiltCharts.dispose(); + } + tiltCharts = echarts.init(chartDom3); + tiltCharts.setOption(chartoption.value); + } else { + console.warn('找不到 ID 为 的 DOM 元素'); } }); } @@ -1669,7 +1705,7 @@ onMounted(() => { loadPatientInfo() // 组件挂载时连接WebSocket并自动开始推流 - // connectWebSocket() + connectWebSocket() // 监听页面关闭或刷新事件 window.addEventListener('beforeunload', handleBeforeUnload) @@ -1677,7 +1713,6 @@ onMounted(() => { console.log(authStore.currentUser) creatorId.value = authStore.currentUser.id } - initchart() }) onUnmounted(() => { @@ -2175,6 +2210,9 @@ onUnmounted(() => { :deep(.el-table .el-table__cell) { padding: 4px 0px; } +:deep(.el-table__body-wrapper) { + border-bottom: 1px solid #ffffff !important; +} @@ -1153,7 +1157,7 @@ function delClick(id) { } .dashboard-container.dashboard-container-home .el-dialog { - background-color: rgba(85, 85, 85, 0.9); + background-color: rgba(85, 85, 85, 1); } .dashboard-container.dashboard-container-home .el-dialog__title { diff --git a/frontend/src/renderer/src/views/Detection.vue b/frontend/src/renderer/src/views/Detection.vue index 27aa45a9..7d1a9b54 100644 --- a/frontend/src/renderer/src/views/Detection.vue +++ b/frontend/src/renderer/src/views/Detection.vue @@ -11,9 +11,10 @@ 实时检测 - +
+ +
{{ formattedTime }}
+
左前足 - {{ footPressure.left_front }} + {{ footPressure.left_front + }}
左后足 @@ -179,24 +181,26 @@
左足总压力 - {{ footPressure.left_total }} + {{ footPressure.left_total + }}
右足总压力 - {{ footPressure.right_total }} + {{ footPressure.right_total + }}
右前足 - {{ footPressure.right_front }} + {{ footPressure.right_front + }}
右后足 - {{ footPressure.right_rear }} + {{ footPressure.right_rear + }}
@@ -342,7 +346,7 @@ \ No newline at end of file