BodyBalanceEvaluation/frontend/src/renderer/src/views/GenerateReport.vue
2025-12-05 15:23:19 +08:00

569 lines
19 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>
<div class="generateReport-container">
<div class="generateReport-container-header">
<div class="generateReport-container-headertitle">生成报告</div>
<div style="display: flex;">
<div class="generateReport-container-cancelbutton" @click="closeCancel">取消</div>
<div class="generateReport-container-confirmbutton" @click="closeCancel">确定</div>
</div>
<img src="@/assets/archive/close.png" alt="" @click="closeCancel" style="cursor: pointer;">
</div>
<div class="generateReport-container-body">
<el-scrollbar height="calc(100%)" style="padding:0 100px">
<div class="generateReport-container-bodytitle">体态测量报告单</div>
<div class="generateReport-container-display">
<div class="generateReport-container-userinfotext">检测时间{{ detectionInfo.start_time }}</div>
<div class="generateReport-container-userinfotext">ID{{ detectionInfo.id }}</div>
</div>
<div class="generateReport-container-userinfodisplay">
<div class="generateReport-container-userinfotext2">
ID{{ selectedPatient.id }}
</div>
<div class="generateReport-container-userinfotext2 width-210">
姓名{{ selectedPatient.name }}
</div>
<div class="generateReport-container-userinfotext2 width-195">
性别{{ selectedPatient.gender }}
</div>
<div class="generateReport-container-userinfotext2 width-195">
年龄{{ calculateAge(selectedPatient.birth_date) }}
</div>
<div class="generateReport-container-userinfotext2 width-235">
身高{{ selectedPatient.height }}cm
</div>
<div class="generateReport-container-userinfotext2 width-215">
体重{{ selectedPatient.weight }}kg
</div>
<div class="generateReport-container-userinfotext2 width-95">
鞋码{{ selectedPatient.shoe_size }}
</div>
<div class="generateReport-container-userinfotext2">
电话{{ selectedPatient.phone }}
</div>
<div class="generateReport-container-userinfotext2 width-405">
邮箱{{ selectedPatient.email }}
</div>
<div class="generateReport-container-userinfotext2 width-430">
居住地{{ selectedPatient.residence }}
</div>
<div class="generateReport-container-userinfotext2 width-310">
职业{{ selectedPatient.occupation }}
</div>
</div>
<div class="generateReport-container-testdatatitle">检测数据</div>
<div class="generateReport-containerdisplay">
<div class="generateReport-container-leftbox">
<div class="displayflex">
<div class="displayflextext1">选择原始数据</div>
<div class="displayflexselect" @click="getRawData('left')">
{{ rawData.order }}
<img src="@/assets/archive/selectbottom.png" class="displayflexselect-icon" alt="">
</div>
</div>
<!-- 选中后显示内容 -->
<div v-if="rawData.order && rawData.order!=''">
<div class="generateReport-content-title">整体数据</div>
<div style="width: 600px;height: 337px;">
<img :src="BACKEND_URL+'/' + rawData.screen_image" alt="" srcset="" style="width: 100%;height: 100%;">
</div>
<div class="generateReport-content-title">身体姿态</div>
<div style="width: 100%;height: 454px; display: flex;justify-content: center;">
<img :src="BACKEND_URL+'/' + rawData.body_image" alt="" srcset="" style="width: 100%;height: 100%;
object-fit:contain; ">
</div>
<div class="generateReport-content-title">头部姿态</div>
<div style="width: 555px;padding:20px 0; display: flex;justify-content: space-between;">
<img src="@/assets/archive/roll.png">
<img src="@/assets/archive/yaw.png">
<img src="@/assets/archive/pitch.png">
</div>
<div style="width: 630px;padding:20px 0; display: flex;justify-content: space-between;">
<div class="rollyawpitchtext">左:<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesLeft.rotationLeftMax}}°
</span>
</div>
<div class="rollyawpitchtext">左:<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesLeft.tiltLeftMax}}°
</span></div>
<div class="rollyawpitchtext">俯:<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesLeft.pitchDownMax}}°
</span></div>
</div>
<div style="width: 630px;padding:20px 0; display: flex;justify-content: space-between;">
<div class="rollyawpitchtext">右:<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesLeft.rotationRightMax}}°
</span></div>
<div class="rollyawpitchtext">右:
<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesLeft.tiltRightMax}}°
</span>
</div>
<div class="rollyawpitchtext">仰:
<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesLeft.pitchUpMax}}°
</span>
</div>
</div>
<div class="generateReport-content-title">足底压力</div>
<div style="width: 600px;height: 270px; display: flex;">
<img :src="BACKEND_URL+'/' + rawData.foot_data_image" alt="" srcset="" style="width: 100%;height: 100%;
object-fit:contain; ">
</div>
<div class="generateReport-content-title">视频1图片</div>
<div style="width: 600px;height: 338px; display: flex;">
<img :src="BACKEND_URL+'/' + rawData.foot1_image" alt="" srcset="" style="width: 100%;height: 100%;">
</div>
<div class="generateReport-content-title">视频2图片</div>
<div style="width: 600px;height: 338px; display: flex;">
<img :src="BACKEND_URL+'/' + rawData.foot2_image" alt="" srcset="" style="width: 100%;height: 100%;">
</div>
</div>
</div>
<div class="generateReport-container-rightbox">
<div class="displayflex">
<div class="displayflextext1">选择矫正数据</div>
<div class="displayflexselect" @click="getRawData('right')">
{{ calibrationData.order }}
<img src="@/assets/archive/selectbottom.png" class="displayflexselect-icon" alt="">
</div>
</div>
<!-- 选中后显示内容 -->
<div v-if="calibrationData.order && calibrationData.order!=''">
<div class="generateReport-content-title">整体数据</div>
<div style="width: 600px;height: 337px;">
<img :src="BACKEND_URL+'/' + calibrationData.screen_image" alt="" srcset="" style="width: 100%;height: 100%;">
</div>
<div class="generateReport-content-title">身体姿态</div>
<div style="width: 100%;height: 454px; display: flex;justify-content: center;">
<img :src="BACKEND_URL+'/' + calibrationData.body_image" alt="" srcset="" style="width: 100%;height: 100%;
object-fit:contain; ">
</div>
<div class="generateReport-content-title">头部姿态</div>
<div style="width: 555px;padding:20px 0; display: flex;justify-content: space-between;">
<img src="@/assets/archive/roll.png">
<img src="@/assets/archive/yaw.png">
<img src="@/assets/archive/pitch.png">
</div>
<div style="width: 630px;padding:20px 0; display: flex;justify-content: space-between;">
<div class="rollyawpitchtext">左:<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesRight.rotationLeftMax}}°
</span>
</div>
<div class="rollyawpitchtext">左:<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesRight.tiltLeftMax}}°
</span></div>
<div class="rollyawpitchtext">俯:<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesRight.pitchDownMax}}°
</span></div>
</div>
<div style="width: 630px;padding:20px 0; display: flex;justify-content: space-between;">
<div class="rollyawpitchtext">右:<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesRight.rotationRightMax}}°
</span></div>
<div class="rollyawpitchtext">右:
<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesRight.tiltRightMax}}°
</span>
</div>
<div class="rollyawpitchtext">仰:
<span class="rollyawpitchtextcolor">
{{headPoseMaxValuesRight.pitchUpMax}}°
</span>
</div>
</div>
<div class="generateReport-content-title">足底压力</div>
<div style="width: 600px;height: 270px; display: flex;">
<img :src="BACKEND_URL+'/' + calibrationData.foot_data_image" alt="" srcset="" style="width: 100%;height: 100%;
object-fit:contain; ">
</div>
<div class="generateReport-content-title">视频1图片</div>
<div style="width: 600px;height: 338px; display: flex;">
<img :src="BACKEND_URL+'/' + calibrationData.foot1_image" alt="" srcset="" style="width: 100%;height: 100%;">
</div>
<div class="generateReport-content-title">视频2图片</div>
<div style="width: 600px;height: 338px; display: flex;">
<img :src="BACKEND_URL+'/' + calibrationData.foot2_image" alt="" srcset="" style="width: 100%;height: 100%;">
</div>
</div>
</div>
</div>
<div class="generateReport-container-testdatatitle">【诊断结果】</div>
<div class="generateReport-title2">记录</div>
<div class="generateReport-border1">记录信息</div>
<div class="generateReport-title2">处理</div>
<div class="generateReport-border2">保持观察,不予处理</div>
<div class="generateReport-title2">备注</div>
<div class="generateReport-border3">备注信息</div>
</el-scrollbar>
</div>
<SelectData v-if="isSelectData" :imageList="imageList" @closeSelectData="closeSelectData"/>
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { patientAPI, detectionAPI,historyAPI,getBackendUrl } from '@/services/api.js'
import SelectData from '@/views/SelectData.vue'
const emit = defineEmits([ 'closeGenerateReport' ]);
const props = defineProps({
selectedPatient: {
required: false,
type: Object,
default: null
},
detectionId: {
required: false,
type: String,
default: ""
}
})
const BACKEND_URL = getBackendUrl()
const rawData = ref({}) // 原始数据
const calibrationData = ref({}) // 校准数据
const isSelectData = ref(false) // 是否选择原始数据列表
const imageList = ref([])
const detectionInfo= ref({})
const headPoseMaxValuesLeft = ref({
rotationLeftMax: 0, // 旋转-左旋最大值
rotationRightMax: 0, // 旋转-右旋最大值
tiltLeftMax: 0, // 倾斜-左倾最大值
tiltRightMax: 0, // 倾斜-右倾最大值
pitchUpMax: 0, // 俯仰-上仰最大值
pitchDownMax: 0 })
const headPoseMaxValuesRight= ref({
rotationLeftMax: 0, // 旋转-左旋最大值
rotationRightMax: 0, // 旋转-右旋最大值
tiltLeftMax: 0, // 倾斜-左倾最大值
tiltRightMax: 0, // 倾斜-右倾最大值
pitchUpMax: 0, // 俯仰-上仰最大值
pitchDownMax: 0 })
function getNo(order) {
if(order<10){
return '0'+order
}else{
return order
}
}
const calculateAge = (birthDate) => { // 获取年龄
if (!birthDate) return '—'
const today = new Date()
const birth = new Date(birthDate)
let age = today.getFullYear() - birth.getFullYear()
const monthDiff = today.getMonth() - birth.getMonth()
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--
}
return age
}
const sessionsById = async (session_id) => {
try {
// 导出报告逻辑
const response = await historyAPI.sessionsById(session_id)
if (response.success) {
response.data.data.forEach((element,index) => {
element.order ='D-'+ (getNo(index + 1))
});
detectionInfo.value = response.data
imageList.value = response.data.data
}
} catch (error) {
ElMessage.error('获取失败')
}
}
// 生命周期
onMounted(() => {
sessionsById(props.detectionId)
})
function closeCancel() {
emit("closeGenerateReport",false)
}
onUnmounted(() => {
})
const selectIndex = ref('left')
function getRawData(e){
selectIndex.value = e
isSelectData.value = true
}
function closeSelectData(is,val){
if(is == true){
if(selectIndex.value == 'left'){
rawData.value = val
if(val.head_pose !=null){
headPoseMaxValuesLeft.value = JSON.parse(val.head_pose).headPoseMaxValues
}
}else if(selectIndex.value == 'right'){
calibrationData.value = val
if(val.head_pose !=null){
headPoseMaxValuesRight.value = JSON.parse(val.head_pose).headPoseMaxValues
}
}
}
isSelectData.value = false
}
</script>
<style scoped>
.generateReport-container{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: #0b0c0f;
z-index: 50;
}
.generateReport-container-header{
width: 1920px;
height: 60px;
background: inherit;
background-color: #191d28;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30px;
}
.generateReport-container-headertitle{
font-weight: 700;
font-style: normal;
font-size: 20px;
color: #FFFFFF;
}
.generateReport-container-cancelbutton{
width: 100px;
height: 40px;
background-color: #597194;
border-radius: 4px;
color: rgba(255, 255, 255, 0.6);
font-weight: 400;
font-style: normal;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20px;
cursor: pointer;
}
.generateReport-container-cancelbutton:hover{
background-color: #14aaff;
color: #fff;
}
.generateReport-container-confirmbutton{
width: 100px;
height: 40px;
background-color: #0b94d5;
border-radius: 4px;
font-weight: 400;
font-style: normal;
font-size: 16px;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.generateReport-container-confirmbutton:hover{
background-color: #14aaff;
}
.generateReport-container-body{
margin:20px auto 0;
width: 1600px;
height: calc(100vh - 80px);
background: #fff;
border-radius: 5px;
box-shadow: 0px 0px 10px rgba(219, 225, 236, 0.3);
padding: 50px 0 20px;
}
.generateReport-container-display{
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 25px;
border-bottom: 1px solid #333;
}
.generateReport-container-bodytitle{
font-family: 'Arial Negreta', 'Arial Normal', 'Arial';
font-weight: 700;
font-style: normal;
font-size: 36px;
color: #282828;
text-align: center;
padding-bottom: 20px;
}
.generateReport-container-userinfotext{
font-family: 'Arial Negreta', 'Arial Normal', 'Arial';
font-weight: 700;
font-style: normal;
color: #282828;
font-size: 18px;
}
.generateReport-container-userinfodisplay{
display: flex;
flex-wrap: wrap;
align-content:flex-start ;
padding: 20px 0;
padding-top: 30px;
border-bottom: 1px solid #333;
}
.generateReport-container-userinfotext2{
width: 240px;
font-family: 'Arial Negreta', 'Arial Normal', 'Arial';
font-weight: 700;
font-style: normal;
color: #282828;
font-size: 18px;
padding-bottom: 10px;
}
.width-210{ width: 210px; }
.width-195{ width: 195px; }
.width-215{ width: 215px; }
.width-235{ width: 235px; }
.width-95{ width: 95px; }
.width-405{ width: 405px; }
.width-430{ width: 430px; }
.width-300{ width: 300px; }
.generateReport-container-testdatatitle{
font-weight: 700;
font-style: normal;
color: #14AAFF;
font-size: 18px;
text-align: left;
padding: 20px 0;
}
.generateReport-containerdisplay{
display: flex;
}
.generateReport-container-leftbox{
width: 50%;
border-right:1px solid rgb(208, 208, 208) ;
box-sizing: border-box;
}
.generateReport-container-rightbox{
width: 50%;
box-sizing: border-box;
padding-left: 80px;
}
.displayflex{
display: flex;
align-items: center;
}
.displayflextext1{
font-weight: 400;
font-style: normal;
color: #282828;
font-size: 18px;
text-align: left;
}
.displayflexselect{
position: relative;
width: 200px;
height: 40px;
background: rgba(255, 255, 255, 1);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(220, 223, 230, 1);
border-radius: 4px;
font-weight: 400;
font-style: normal;
font-size: 16px;
display: flex;
align-items: center;
padding-left: 10px;
margin-left: 20px;
cursor: pointer;
}
.displayflexselect-icon{
position: absolute;
top: 15px;
right: 10px;
}
.generateReport-content-title{
font-weight: 700;
font-style: normal;
color: #282828;
font-size: 18px;
padding-top:30px;
padding-bottom: 15px;
}
.rollyawpitchtext{
font-style: normal;
color: #282828;
font-size: 24px;
width: 170px;
}
.rollyawpitchtextcolor{
color:#14AAFF;
}
.generateReport-title2{
font-weight: 700;
font-style: normal;
font-size: 18px;
color: #282828;
padding-top: 20px;
padding-bottom: 20px;
}
.generateReport-border1{
padding: 5px;
width: 100%;
height: 200px;
background: rgba(255, 255, 255, 1);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(220, 223, 230, 1);
border-radius: 4px;
font-weight: 400;
font-style: normal;
font-size: 18px;
text-decoration: none;
color: #383838;
}
.generateReport-border2{
width: 100%;
height: 40px;
background: rgba(255, 255, 255, 1);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(220, 223, 230, 1);
border-radius: 4px;
font-style: normal;
font-size: 18px;
text-decoration: none;
color: #383838;
padding: 5px;
}
.generateReport-border3{
width: 100%;
height: 120px;
background: rgba(255, 255, 255, 1);
box-sizing: border-box;
border-width: 1px;
border-style: solid;
border-color: rgba(220, 223, 230, 1);
border-radius: 4px;
font-style: normal;
font-size: 18px;
text-decoration: none;
color: #383838;
padding: 5px;
}
</style>