This commit is contained in:
lxd 2025-07-25 15:28:33 +08:00
commit 7553f16226
4 changed files with 789 additions and 581 deletions

View File

@ -0,0 +1,61 @@
import request from '@/config/axios'
// 动脉硬化检测数据 VO
export interface arterialdataVO {
id: number // 主键ID
regid: string // 注册ID
examid: string // 检查ID
weartime: Date // 佩戴时间
measuretime: Date // 测量时间
deviceid: string // 设备ID
devicename: string // 设备名称
data: string // 检测数据
createtime: Date // 创建时间
updatetime: Date // 更新时间
diagnosis: string // 诊断结论
}
// 动脉硬化检测数据 API
export const arterialdataApi = {
// 查询动脉硬化检测数据分页
getarterialdataPage: async (params: any) => {
return await request.get({ url: `/system/arterialdata/page`, params })
},
// 查询动脉硬化检测数据详情
getarterialdata: async (id: number) => {
return await request.get({ url: `/system/arterialdata/get?id=` + id })
},
// 新增动脉硬化检测数据
createarterialdata: async (data: arterialdataVO) => {
return await request.post({ url: `/system/arterialdata/create`, data })
},
// 修改动脉硬化检测数据
updatearterialdata: async (data: arterialdataVO) => {
return await request.put({ url: `/system/arterialdata/update`, data })
},
// 删除动脉硬化检测数据
deletearterialdata: async (id: number) => {
return await request.delete({ url: `/system/arterialdata/delete?id=` + id })
},
// 导出动脉硬化检测数据 Excel
exportarterialdata: async (params) => {
return await request.download({ url: `/system/arterialdata/export-excel`, params })
},
// 根据检查ID&患者ID获取arterialdata数据
getarterialdataByExamidAndRegid: async (examid: string, regid: string) => {
return await request.get({
url: `/system/arterialdata/getByExamidAndRegid?examid=` + examid + '&regid=' + regid
})
},
//根据examid&regid保存诊断结论
savearterialdataDiagnosis: async (data: any) => {
return await request.put({ url: `/system/arterialdata/saveDiagnosisByExamidAndRegid`, data })
}
}

View File

@ -1,116 +1,97 @@
<template>
<Dialog
<el-dialog
v-model="dialogVisible"
:title="`动脉硬化分析 - ${patientData.name}`"
width="90%"
:before-close="handleClose"
title="动脉硬化分析"
:fullscreen="true"
:close-on-click-modal="false"
:close-on-press-escape="false"
class="arterial-analysis-dialog"
@close="handleClose"
>
<div class="arteriosclerosis-analysis-container">
<!-- 患者信息 -->
<div class="patient-info">
<el-row :gutter="20">
<el-col :span="6">
<div class="info-item">
<span class="label">姓名</span>
<span class="value">{{ patientData.name }}</span>
<!-- 主要内容区域 -->
<div class="main-content">
<!-- 左侧图片展示区域 (3/4) -->
<div class="left-panel">
<!-- 图片展示区域 -->
<div class="image-display-section">
<div class="image-container full-height">
<!-- 图片展示区域 -->
<div v-if="arterialData && arterialData.data" class="image-wrapper">
<img
:src="arterialData.data"
alt="动脉硬化检测图像"
class="detection-image"
@error="handleImageError"
/>
</div>
</el-col>
<el-col :span="6">
<div class="info-item">
<span class="label">性别</span>
<span class="value">{{ patientData.gender }}</span>
<!-- 占位符 -->
<div v-else class="no-image-placeholder">
<el-empty description="暂无影像" />
</div>
</el-col>
<el-col :span="6">
<div class="info-item">
<span class="label">年龄</span>
<span class="value">{{ patientData.age }}</span>
</div>
</el-col>
<el-col :span="6">
<div class="info-item">
<span class="label">检测时间</span>
<span class="value">{{ formatDateTime(patientData.measuretime) }}</span>
</div>
</el-col>
</el-row>
</div>
</div>
</div>
<!-- 动脉硬化趋势图 -->
<div class="chart-section">
<h3>动脉硬化指标趋势</h3>
<div ref="chartContainer" class="chart-container"></div>
</div>
<!-- 右侧诊断模板和结论区域 (1/4) -->
<div class="right-panel">
<!-- 诊断模板选择区域 -->
<div class="diagnosis-selector">
<h5 class="selector-title">
诊断模板
<el-input
v-model="searchKeyword"
placeholder="请输入关键词"
clearable
style="height: 40px; margin-top: 5px"
size="medium"
prefix-icon="Search"
/>
</h5>
<!-- 数据统计表格 -->
<div class="statistics-section">
<h3>检测数据统计</h3>
<el-table :data="statisticsData" border style="width: 100%">
<el-table-column prop="parameter" label="参数" width="200" />
<el-table-column prop="value" label="数值" width="150" />
<el-table-column prop="unit" label="单位" width="100" />
<el-table-column prop="reference" label="参考范围" width="200" />
<el-table-column prop="status" label="状态" width="120">
<template #default="{ row }">
<el-tag :type="getStatusType(row.status)" size="small">
{{ row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="description" label="说明" />
</el-table>
</div>
<div class="diagnosis-list">
<div
v-for="diag in filteredDiagnoses"
:key="diag.code"
class="diagnosis-item"
@click="insertDiagnosis(diag.name)"
>
{{ diag.name }}
</div>
<div v-if="filteredDiagnoses.length == 0" class="no-results"> 暂无匹配的诊断模板 </div>
</div>
</div>
<!-- 分析结果 -->
<div class="analysis-section">
<h3>分析结果</h3>
<el-form :model="analysisResult" label-width="120px">
<el-form-item label="总体评估:">
<!-- 诊断结论输入区域 -->
<div class="analysis-section">
<h3>诊断结论</h3>
<el-form :model="analysisResult" label-width="80px" size="medium">
<el-input
v-model="analysisResult.overallAssessment"
type="textarea"
:rows="3"
placeholder="请输入总体评估结果"
:rows="8"
resize="none"
placeholder="请输入诊断结论"
/>
</el-form-item>
<el-form-item label="风险等级:">
<el-select v-model="analysisResult.riskLevel" placeholder="请选择风险等级">
<el-option label="低风险" value="low" />
<el-option label="中风险" value="medium" />
<el-option label="高风险" value="high" />
</el-select>
</el-form-item>
<el-form-item label="建议措施:">
<el-input
v-model="analysisResult.recommendations"
type="textarea"
:rows="4"
placeholder="请输入建议措施"
/>
</el-form-item>
<el-form-item label="医生签名:">
<el-input v-model="analysisResult.doctorSignature" placeholder="请输入医生姓名" />
</el-form-item>
</el-form>
</el-form>
</div>
</div>
</div>
<!-- 操作按钮 -->
<!-- 底部操作按钮 -->
<template #footer>
<div class="dialog-footer">
<div class="bottom-actions">
<el-button @click="handleClose">关闭</el-button>
<el-button type="primary" @click="handleSave">保存分析结果</el-button>
<el-button type="success" @click="handlePreviewReport">报告预览</el-button>
<el-button type="primary" @click="handleSave">保存结论</el-button>
</div>
</template>
</Dialog>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, nextTick, watch, onUnmounted } from 'vue'
import * as echarts from 'echarts'
import { ref, reactive, nextTick, watch, computed } from 'vue'
import { formatDate } from '@/utils/formatTime'
import { ElMessage, ElMessageBox } from 'element-plus'
import { ElMessage } from 'element-plus'
import { arterialdataApi } from '@/api/arterialdata'
//
interface Props {
@ -129,52 +110,93 @@ const emit = defineEmits(['update:modelValue', 'saved'])
//
const dialogVisible = ref(false)
const chartContainer = ref()
let chartInstance: echarts.ECharts | null = null
const currentRowData = ref<any>(null) //
const searchKeyword = ref('') //
//
// -
const analysisResult = reactive({
overallAssessment: '',
riskLevel: '',
recommendations: '',
doctorSignature: ''
overallAssessment: ''
})
//
const statisticsData = ref([
{
parameter: 'PWV (脉搏波传导速度)',
value: '8.5',
unit: 'm/s',
reference: '<10.0',
status: '正常',
description: '反映动脉弹性'
},
{
parameter: 'ABI (踝臂指数)',
value: '1.12',
unit: '',
reference: '0.9-1.3',
status: '正常',
description: '下肢血管状况'
},
{
parameter: 'IMT (内膜中层厚度)',
value: '0.8',
unit: 'mm',
reference: '<1.0',
status: '正常',
description: '颈动脉内膜厚度'
},
{
parameter: 'AI (增强指数)',
value: '25',
unit: '%',
reference: '<30',
status: '正常',
description: '动脉硬化程度'
//
const arterialData = ref<any>(null)
//
interface ArterialDiagnosis {
name: string
code: string
category: string
}
const arterialDiagnoses: ArterialDiagnosis[] = [
//
{ name: '动脉硬化程度正常', code: 'ART001', category: 'normal' },
{ name: '血管弹性良好', code: 'ART002', category: 'normal' },
{ name: '血管壁厚度正常', code: 'ART003', category: 'normal' },
{ name: '无明显斑块形成', code: 'ART004', category: 'normal' },
{ name: '血流动力学指标正常', code: 'ART005', category: 'normal' },
//
{ name: '轻度动脉硬化', code: 'ART006', category: 'mild' },
{ name: '血管壁轻度增厚', code: 'ART007', category: 'mild' },
{ name: '少量软斑块', code: 'ART008', category: 'mild' },
{ name: '血管弹性轻度下降', code: 'ART009', category: 'mild' },
{ name: '内膜中膜厚度轻度增加', code: 'ART010', category: 'mild' },
//
{ name: '中度动脉硬化', code: 'ART011', category: 'moderate' },
{ name: '血管壁明显增厚', code: 'ART012', category: 'moderate' },
{ name: '混合性斑块', code: 'ART013', category: 'moderate' },
{ name: '轻度管腔狭窄', code: 'ART014', category: 'moderate' },
{ name: '血管弹性明显下降', code: 'ART015', category: 'moderate' },
{ name: '内膜中膜厚度明显增加', code: 'ART016', category: 'moderate' },
//
{ name: '重度动脉硬化', code: 'ART017', category: 'severe' },
{ name: '血管壁严重增厚', code: 'ART018', category: 'severe' },
{ name: '大量钙化斑块', code: 'ART019', category: 'severe' },
{ name: '中重度管腔狭窄', code: 'ART020', category: 'severe' },
{ name: '血管弹性严重下降', code: 'ART021', category: 'severe' },
{ name: '多发性斑块', code: 'ART022', category: 'severe' },
//
{ name: '血管钙化', code: 'ART023', category: 'calcification' },
{ name: '钙化斑块', code: 'ART024', category: 'calcification' },
{ name: '多发性钙化灶', code: 'ART025', category: 'calcification' },
{ name: '钙化积分增高', code: 'ART026', category: 'calcification' },
{ name: '冠状动脉钙化', code: 'ART027', category: 'calcification' },
{ name: '颈动脉钙化', code: 'ART028', category: 'calcification' },
//
{ name: '血管狭窄', code: 'ART029', category: 'stenosis' },
{ name: '轻度狭窄(<50%', code: 'ART030', category: 'stenosis' },
{ name: '中度狭窄50-70%', code: 'ART031', category: 'stenosis' },
{ name: '重度狭窄(>70%', code: 'ART032', category: 'stenosis' },
{ name: '管腔直径减少', code: 'ART033', category: 'stenosis' },
{ name: '血流速度增快', code: 'ART034', category: 'stenosis' },
//
{ name: '内膜剥脱', code: 'ART035', category: 'other' },
{ name: '血管迂曲', code: 'ART036', category: 'other' },
{ name: '血管扩张', code: 'ART037', category: 'other' },
{ name: '动脉瘤样改变', code: 'ART038', category: 'other' },
{ name: '血栓形成', code: 'ART039', category: 'other' },
{ name: '纤维斑块', code: 'ART040', category: 'other' },
{ name: '脂质斑块', code: 'ART041', category: 'other' },
{ name: '不稳定斑块', code: 'ART042', category: 'other' },
{ name: '易损斑块', code: 'ART043', category: 'other' },
{ name: '血管重构', code: 'ART044', category: 'other' }
]
//
const filteredDiagnoses = computed(() => {
if (!searchKeyword.value) {
return arterialDiagnoses
}
])
return arterialDiagnoses.filter((diag) =>
diag.name.toLowerCase().includes(searchKeyword.value.toLowerCase())
)
})
//
watch(
@ -183,7 +205,6 @@ watch(
dialogVisible.value = newVal
if (newVal) {
nextTick(() => {
initChart()
loadAnalysisData()
})
}
@ -198,119 +219,61 @@ watch(
}
)
//
const initChart = () => {
if (!chartContainer.value) return
chartInstance = echarts.init(chartContainer.value)
const option = {
title: {
text: '动脉硬化指标变化趋势',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
legend: {
data: ['PWV', 'ABI', 'IMT', 'AI'],
top: 30
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['检测点1', '检测点2', '检测点3', '检测点4', '检测点5']
},
yAxis: [
{
type: 'value',
name: 'PWV (m/s)',
position: 'left'
},
{
type: 'value',
name: '其他指标',
position: 'right'
}
],
series: [
{
name: 'PWV',
type: 'line',
yAxisIndex: 0,
data: [8.2, 8.5, 8.3, 8.7, 8.5],
itemStyle: { color: '#5470c6' }
},
{
name: 'ABI',
type: 'line',
yAxisIndex: 1,
data: [1.1, 1.12, 1.08, 1.15, 1.12],
itemStyle: { color: '#91cc75' }
},
{
name: 'IMT',
type: 'line',
yAxisIndex: 1,
data: [0.7, 0.8, 0.75, 0.85, 0.8],
itemStyle: { color: '#fac858' }
},
{
name: 'AI',
type: 'line',
yAxisIndex: 1,
data: [22, 25, 23, 28, 25],
itemStyle: { color: '#ee6666' }
}
]
}
chartInstance.setOption(option)
}
//
//
const loadAnalysisData = async () => {
try {
// TODO: API
// const response = await ArterApi.getAnalysis(props.recordId)
// analysisResult.overallAssessment = response.data.overallAssessment
// analysisResult.riskLevel = response.data.riskLevel
// analysisResult.recommendations = response.data.recommendations
// analysisResult.doctorSignature = response.data.doctorSignature
if (!currentRowData.value) {
ElMessage.warning('缺少必要的检查数据')
return
}
//
analysisResult.overallAssessment =
'根据检测结果,患者动脉硬化程度处于正常范围内,各项指标均在参考值范围内。'
analysisResult.riskLevel = 'low'
analysisResult.recommendations = '建议保持健康的生活方式,定期进行体检,注意饮食和运动。'
analysisResult.doctorSignature = ''
const { examid, regid } = currentRowData.value
if (!examid || !regid) {
ElMessage.warning('缺少检查ID或患者ID')
return
}
// // APIarterialdata
const response = await arterialdataApi.getarterialdataByExamidAndRegid(examid, regid)
if (response) {
arterialData.value = response
// data
if (arterialData.value && arterialData.value.data) {
// data
if (typeof arterialData.value.data === 'string') {
arterialData.value.data = arterialData.value.data.trim().replace(/^`|`$/g, '')
}
} else if (typeof arterialData.value === 'string') {
// response.dataURLdata
const imageUrl = arterialData.value.trim().replace(/^`|`$/g, '')
arterialData.value = {
data: imageUrl
}
}
//
if (arterialData.value.diagnosis) {
// diagnosisJSON
analysisResult.overallAssessment = arterialData.value.diagnosis
} else {
//
analysisResult.overallAssessment = ''
}
} else {
//
analysisResult.overallAssessment = ''
}
//
} catch (error) {
console.error('加载分析数据失败:', error)
ElMessage.error('加载分析数据失败')
}
}
//
const getStatusType = (status: string) => {
switch (status) {
case '正常':
return 'success'
case '异常':
return 'danger'
case '临界':
return 'warning'
default:
return 'info'
}
}
// getStatusType
//
const formatDateTime = (dateTime: string | Date) => {
@ -318,120 +281,371 @@ const formatDateTime = (dateTime: string | Date) => {
return formatDate(dateTime, 'YYYY-MM-DD HH:mm:ss')
}
//
const handleSave = async () => {
try {
if (!analysisResult.overallAssessment.trim()) {
ElMessage.warning('请输入总体评估')
return
}
if (!analysisResult.riskLevel) {
ElMessage.warning('请选择风险等级')
return
}
if (!analysisResult.doctorSignature.trim()) {
ElMessage.warning('请输入医生签名')
return
}
// TODO: API
// await ArterApi.saveAnalysis({
// recordId: props.recordId,
// ...analysisResult
// })
ElMessage.success('分析结果保存成功')
emit('saved')
} catch (error) {
console.error('保存分析结果失败:', error)
ElMessage.error('保存分析结果失败')
}
//
const handleImageError = (event: Event) => {
console.log('图片加载失败:', event)
ElMessage.warning('图片加载失败')
}
//
const handlePreviewReport = () => {
//
const handleSave = async () => {
if (!analysisResult.overallAssessment.trim()) {
ElMessage.warning('请先完成分析结果填写')
ElMessage.warning('请输入诊断结论')
return
}
// TODO:
ElMessage.info('报告预览功能开发中')
if (!currentRowData.value?.examid || !currentRowData.value?.regid) {
ElMessage.warning('缺少必要的患者信息')
return
}
try {
// examidregid
const saveData = {
examid: currentRowData.value.examid,
regid: currentRowData.value.regid,
diagnosis: analysisResult.overallAssessment.trim()
}
await arterialdataApi.savearterialdataDiagnosis(saveData)
ElMessage.success('诊断结论已保存')
} catch (error) {
console.error('保存诊断失败:', error)
ElMessage.error('保存诊断失败')
}
}
//
const insertDiagnosis = (diagnosis: string) => {
const cursorPosition = analysisResult.overallAssessment.length
if (
analysisResult.overallAssessment &&
!analysisResult.overallAssessment.endsWith('。') &&
!analysisResult.overallAssessment.endsWith('')
) {
analysisResult.overallAssessment += '' + diagnosis
} else {
analysisResult.overallAssessment += diagnosis
}
}
//
const applyTemplate = (templateType: string) => {
//
//
ElMessage.success('模板应用成功')
}
//
const handleClose = () => {
dialogVisible.value = false
if (chartInstance) {
chartInstance.dispose()
chartInstance = null
}
//
const open = async (rowData?: any) => {
dialogVisible.value = true
//
if (rowData) {
currentRowData.value = rowData
//
await loadAnalysisData()
} else {
//
analysisResult.overallAssessment = ''
arterialData.value = null
}
}
//
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose()
chartInstance = null
}
//
defineExpose({
open
})
</script>
<style scoped>
.arteriosclerosis-analysis-container {
padding: 20px;
.arterial-analysis-dialog {
--el-dialog-padding-primary: 0;
}
.patient-info {
background: #f5f7fa;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
.arterial-analysis-dialog .el-dialog__body {
padding: 0;
height: calc(100vh - 120px);
overflow: hidden;
}
.info-item {
.arterial-analysis-dialog .el-dialog__footer {
padding: 15px 20px;
border-top: 1px solid #e4e7ed;
}
.main-content {
height: 100%;
display: flex;
align-items: center;
margin-bottom: 8px;
overflow: hidden;
}
.info-item .label {
font-weight: bold;
color: #606266;
margin-right: 8px;
.left-panel {
width: 75%;
overflow-y: auto;
border-right: 1px solid #e4e7ed;
}
.info-item .value {
color: #303133;
.right-panel {
width: 25%;
overflow-y: auto;
background: #fafafa;
}
.chart-section,
.statistics-section,
.image-display-section,
.analysis-section {
margin-bottom: 30px;
margin-left: 20px;
}
.chart-section h3,
.statistics-section h3,
.analysis-section h3 {
margin-bottom: 15px;
.section-title {
margin: 0 0 15px 0;
color: #303133;
font-size: 16px;
font-weight: bold;
}
.chart-container {
.image-display-section {
height: 100%;
margin-bottom: 0;
}
.image-container {
width: 100%;
height: 400px;
border: 1px solid #e4e7ed;
border-radius: 4px;
background: #fafafa;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
}
.dialog-footer {
.image-container.full-height {
height: calc(100vh - 160px);
}
.placeholder-image {
text-align: center;
color: #909399;
}
.placeholder-image p {
margin: 10px 0 0 0;
font-size: 14px;
}
.placeholder-image .sub-text {
font-size: 12px;
color: #c0c4cc;
margin-top: 5px;
}
/* 数据展示样式 */
.data-display {
width: 100%;
height: 100%;
padding: 20px;
overflow-y: auto;
text-align: left;
}
.data-display h3 {
margin: 0 0 20px 0;
color: #303133;
font-size: 18px;
font-weight: bold;
border-bottom: 2px solid #409eff;
padding-bottom: 10px;
}
/* 图片展示区域样式 */
.image-section {
margin-bottom: 30px;
}
.image-section h4 {
margin: 0 0 15px 0;
color: #606266;
font-size: 16px;
font-weight: bold;
}
.image-wrapper {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
position: relative;
}
.detection-image {
max-width: 100%;
max-height: 100%;
object-fit: contain;
display: block;
}
.no-image-placeholder {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
color: #909399;
background: #fafafa;
}
.no-image-placeholder p {
margin: 10px 0 0 0;
font-size: 14px;
}
.data-content {
display: flex;
flex-direction: column;
gap: 15px;
}
.data-item {
display: flex;
flex-direction: column;
gap: 5px;
}
.data-item label {
font-weight: bold;
color: #606266;
font-size: 14px;
}
.data-item span {
color: #303133;
font-size: 14px;
padding: 5px 10px;
background: #f5f7fa;
border-radius: 4px;
}
.data-json {
max-height: 300px;
overflow-y: auto;
border: 1px solid #e4e7ed;
border-radius: 4px;
background: #fafafa;
}
.data-json pre {
margin: 0;
padding: 10px;
font-size: 12px;
color: #303133;
white-space: pre-wrap;
word-wrap: break-word;
}
.diagnosis-selector {
margin-bottom: 20px;
padding: 15px;
border: 1px solid #e0e0e0;
border-radius: 6px;
background: #fafafa;
}
.selector-title {
font-size: 16px;
margin-bottom: 10px;
color: #333;
font-weight: 600;
}
.diagnosis-list {
max-height: 45vh;
overflow-y: auto;
border: 1px solid #e0e0e0;
border-radius: 4px;
background: white;
}
.diagnosis-item {
padding: 8px 12px;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
font-size: 14px;
transition: background-color 0.2s;
}
.diagnosis-item:hover {
background-color: #e6f7ff;
color: #1890ff;
}
.diagnosis-item:last-child {
border-bottom: none;
}
.no-results {
padding: 20px;
text-align: center;
color: #999;
font-size: 14px;
}
.analysis-section {
margin-bottom: 0;
}
.analysis-section h3 {
margin: 0 0 15px 0;
color: #303133;
font-size: 16px;
font-weight: bold;
}
.bottom-actions {
background: #f5f7fa;
padding: 15px 20px;
border-top: 1px solid #e4e7ed;
text-align: right;
flex-shrink: 0;
}
.dialog-footer .el-button {
.bottom-actions .el-button {
margin-left: 10px;
}
/* 响应式调整 */
@media (max-width: 1200px) {
.left-panel {
width: 70%;
}
.right-panel {
width: 30%;
}
}
@media (max-width: 768px) {
.main-content {
flex-direction: column;
}
.left-panel,
.right-panel {
width: 100%;
}
.patient-info-inline {
gap: 15px;
}
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div class="arteriosclerosis-analysis">
<!-- 动脉硬化分析弹窗组件 -->
<Arter_analysis ref="arterAnalysisRef" />
<Arter_analysis ref="arterAnalysisRef" v-model="showAnalysisDialog" />
<!-- 患者选择组件后续可补充 -->
<PatientSelect
@ -193,12 +193,14 @@ import PatientSelect from '@/patientcom/index.vue'
import { getUserProfile } from '@/api/system/user/profile'
import { OrgApi } from '@/api/org'
import { arterialApi } from '@/api/arterial'
import { arterialdataApi } from '@/api/arterialdata'
import { Search, Refresh, Plus, Edit, Check, Close } from '@element-plus/icons-vue'
import dayjs from 'dayjs'
import Arter_analysis from './Arter_analysis.vue'
const loading = ref(false)
const total = ref(0)
const showAnalysisDialog = ref(false)
//
const queryParams = reactive({
@ -324,17 +326,15 @@ const handlePatientCancel = () => {
const onAnalyze = async (row: any) => {
try {
//
const res = await arterialApi.getArterialAnalysis(row.examid)
const res = await arterialdataApi.getarterialdataByExamidAndRegid(row.examid, row.regid)
if (res) {
arterAnalysisRef.value?.open(row)
showAnalysisDialog.value = true
await arterAnalysisRef.value?.open(row)
} else {
ElMessage.error('暂无分析数据')
ElMessage.error('暂无数据')
}
} catch (error) {
console.error('获取分析数据失败:', error)
//
arterAnalysisRef.value?.open(row)
}
}

View File

@ -10,101 +10,92 @@
class="ecg-workstation-dialog"
@close="handleClose"
>
<!-- 主要内容区域 -->
<div class="workstation-container">
<!-- 工作区域 -->
<!-- 左侧图片展示区域 (3/4) -->
<div class="work-area">
<el-row :gutter="16" style="height: 90vh">
<!-- 左侧ECG报告图片显示区 (3/4) -->
<el-col :span="18">
<el-card shadow="never" class="ecg-image-display">
<div class="ecg-image-container">
<!-- ECG报告图片显示区域 -->
<div
class="image-viewer"
v-loading="loading"
element-loading-text="正在加载ECG数据..."
>
<img
v-if="ecgImageUrl"
:src="ecgImageUrl"
alt="ECG报告"
class="ecg-report-image"
@load="handleImageLoad"
@error="handleImageError"
/>
<div v-else class="image-placeholder">
<el-empty description="暂无影像" />
</div>
</div>
</div>
</el-card>
</el-col>
<!-- 图片展示区域 -->
<div class="image-display-section">
<div class="image-container full-height">
<!-- 图片展示区域 -->
<div v-if="ecgImageUrl" class="image-wrapper">
<img
:src="ecgImageUrl"
alt="ECG报告"
class="ecg-report-image"
@load="handleImageLoad"
@error="handleImageError"
/>
</div>
<!-- 占位符 -->
<div v-else class="no-image-placeholder">
<el-empty description="暂无影像" />
</div>
</div>
</div>
</div>
<!-- 右侧诊断信息区 (1/4) -->
<el-col :span="6">
<el-card
shadow="never"
class="diagnosis-panel"
v-loading="loading"
element-loading-text="正在加载..."
<!-- 右侧诊断模板和结论区域 (1/4) -->
<div class="diagnosis-panel">
<!-- 诊断模板选择区域 -->
<div class="diagnosis-selector">
<h5 class="selector-title">
诊断模板
<el-input
v-model="searchKeyword"
placeholder="请输入关键词"
clearable
style="height: 40px; margin-top: 5px"
size="medium"
prefix-icon="Search"
/>
</h5>
<div class="diagnosis-list">
<div
v-for="diag in filteredDiagnoses"
:key="diag.code"
class="diagnosis-item"
@click="insertDiagnosis(diag.name)"
>
<div class="diagnosis-content">
<!-- 诊断结果 -->
<div class="diagnosis-section">
<!-- 诊断结论选择列表 -->
<div class="diagnosis-selector">
<h5 class="selector-title"
>诊断模板
<el-input
v-model="searchKeyword"
placeholder="请输入关键词"
clearable
style="height: 40px; margin-top: 5px"
size="small"
prefix-icon="Search"
/>
</h5>
{{ diag.name }}
</div>
<div v-if="filteredDiagnoses.length === 0" class="no-results">
暂无匹配的诊断模板
</div>
</div>
</div>
<div class="diagnosis-list">
<div
v-for="diag in filteredDiagnoses"
:key="diag.code"
class="diagnosis-item"
@click="insertDiagnosis(diag.name)"
>
{{ diag.name }}
</div>
<div v-if="filteredDiagnoses.length === 0" class="no-results">
暂无匹配的诊断模板
</div>
</div>
</div>
<h4 class="section-title">诊断结论 </h4>
<el-input
v-model="diagnosisText"
type="textarea"
placeholder="请输入诊断结论..."
:disabled="loading"
:rows="5"
resize="none"
/>
</div>
<div class="diagnosis-actions">
<el-button
type="primary"
@click="handleSaveAnalysis"
:loading="loading"
:disabled="!patientData.examid || !patientData.regid"
>
保存结论
</el-button>
</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 诊断结论输入区域 -->
<div class="analysis-section">
<h3>诊断结论</h3>
<el-form label-width="80px" size="medium">
<el-input
v-model="diagnosisText"
type="textarea"
:rows="8"
resize="none"
placeholder="请输入诊断结论"
/>
</el-form>
</div>
</div>
</div>
<!-- 底部操作按钮 -->
<template #footer>
<div class="bottom-actions">
<el-button @click="handleClose">关闭</el-button>
<el-button
type="primary"
@click="handleSaveAnalysis"
:loading="loading"
:disabled="!patientData.examid || !patientData.regid"
>
保存结论
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
@ -200,7 +191,6 @@ const loadEcgData = async (examid: string, regid: string) => {
if (response.ecgdata) {
ecgImageUrl.value = response.ecgdata
}
ElMessage.success('数据加载成功')
}
} catch (error) {
console.error('数据加载失败:', error)
@ -289,252 +279,195 @@ defineExpose({
</script>
<style scoped>
.ecg-workstation-dialog :deep(.el-dialog__wrapper),
.ecg-workstation-dialog :deep(.el-dialog),
.ecg-workstation-dialog :deep(.el-dialog__body) {
height: 90vh !important;
box-sizing: border-box;
padding: 0;
.ecg-workstation-dialog {
--el-dialog-padding-primary: 0;
}
.workstation-container,
.work-area,
.el-row,
.el-col,
.ecg-image-display,
.diagnosis-panel {
height: 100%;
}
.ecg-image-display :deep(.el-card__body),
.diagnosis-panel :deep(.el-card__body) {
height: 100%;
.ecg-workstation-dialog .el-dialog__body {
padding: 0;
height: calc(100vh - 120px);
overflow: hidden;
}
.ecg-workstation-dialog .el-dialog__footer {
padding: 15px 20px;
border-top: 1px solid #e4e7ed;
}
.workstation-container {
display: flex;
flex-direction: column;
height: 100%;
display: flex;
overflow: hidden;
}
.work-area {
flex: 1;
height: 100%;
padding: 16px;
overflow: hidden;
width: 75%;
overflow-y: auto;
border-right: 1px solid #e4e7ed;
}
.patient-info {
padding: 16px;
background: #f6f8fa;
}
.info-card {
border: none;
}
.info-content {
display: flex;
gap: 24px;
align-items: center;
flex-wrap: wrap;
}
.info-item {
display: flex;
align-items: center;
}
.label {
font-weight: 500;
color: #666;
margin-right: 8px;
}
.value {
color: #333;
font-weight: 500;
}
.patient-info-header {
padding: 16px;
background: #f8f9fb;
border-bottom: 1px solid #e4e7ed;
}
.patient-info-header :deep(.el-descriptions) {
background: white;
}
.patient-info-header :deep(.el-descriptions__label) {
font-weight: 500;
color: #606266;
.diagnosis-panel {
width: 25%;
overflow-y: auto;
background: #fafafa;
}
.patient-info-header :deep(.el-descriptions__content) {
.image-display-section,
.analysis-section {
margin-left: 20px;
}
.section-title {
margin: 0 0 15px 0;
color: #303133;
font-weight: 500;
font-size: 16px;
font-weight: bold;
}
.display-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.display-controls {
display: flex;
gap: 8px;
}
.ecg-image-container {
.image-display-section {
height: 100%;
position: relative;
overflow: hidden;
background: #f5f5f5;
margin-bottom: 0;
}
.image-viewer {
.image-container {
width: 100%;
height: 400px;
border: 1px solid #e4e7ed;
border-radius: 4px;
background: #fafafa;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
}
.image-container.full-height {
height: calc(100vh - 180px);
}
.image-wrapper {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
overflow: auto;
overflow: hidden;
position: relative;
}
.ecg-report-image {
max-width: 100%;
max-height: 100%;
object-fit: contain;
border: 1px solid #ddd;
background: white;
display: block;
}
.image-placeholder {
text-align: center;
color: #666;
}
.diagnosis-content {
.no-image-placeholder {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.diagnosis-section {
flex: 1;
display: flex;
flex-direction: column;
}
.measurement-section,
.diagnosis-section,
.action-section {
margin-bottom: 20px;
}
.section-title {
font-weight: 600;
margin-bottom: 12px;
color: #333;
font-size: 14px;
margin-left: 11px;
}
.measurement-grid {
display: grid;
gap: 8px;
}
.measurement-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 0;
border-bottom: 1px solid #f0f0f0;
justify-content: center;
text-align: center;
color: #909399;
background: #fafafa;
}
.param-label {
color: #666;
font-size: 13px;
font-weight: 500;
}
.param-value {
color: #333;
font-weight: 600;
font-size: 13px;
}
.diagnosis-text {
margin-bottom: 12px;
}
.action-buttons {
display: flex;
flex-direction: column;
gap: 8px;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
}
.diagnosis-actions {
display: flex;
justify-content: flex-end;
padding-bottom: 5px;
padding-right: 5px;
.no-image-placeholder p {
margin: 10px 0 0 0;
font-size: 14px;
}
.diagnosis-selector {
margin-bottom: 12px;
border: 1px solid #e4e7ed;
border-radius: 4px;
background-color: #fff;
margin-bottom: 20px;
padding: 15px;
border: 1px solid #e0e0e0;
border-radius: 6px;
background: #fafafa;
}
.selector-title {
font-size: 14px;
font-weight: 600;
font-size: 16px;
margin-bottom: 10px;
color: #333;
margin: 0;
padding: 12px 16px 8px;
border-bottom: 1px solid #f0f0f0;
font-weight: 600;
}
.diagnosis-list {
max-height: 50vh;
max-height: 45vh;
overflow-y: auto;
padding: 8px;
border: 1px solid #e0e0e0;
border-radius: 4px;
background: white;
}
.diagnosis-item {
font-size: 13px;
color: #333;
padding: 6px 12px;
border-radius: 4px;
padding: 8px 12px;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
transition: all 0.2s ease;
border: 1px solid transparent;
margin-bottom: 2px;
font-size: 14px;
transition: background-color 0.2s;
}
.diagnosis-item:hover {
background-color: #e6f7ff;
border-color: #b3d8ff;
color: #409eff;
color: #1890ff;
}
.diagnosis-item:last-child {
border-bottom: none;
}
.no-results {
padding: 20px;
text-align: center;
color: #909399;
font-size: 13px;
padding: 8px 0;
color: #999;
font-size: 14px;
}
.analysis-section {
margin-bottom: 0;
}
.analysis-section h3 {
margin: 0 0 15px 0;
color: #303133;
font-size: 16px;
font-weight: bold;
}
.bottom-actions {
background: #f5f7fa;
padding: 15px 20px;
border-top: 1px solid #e4e7ed;
text-align: right;
flex-shrink: 0;
}
.bottom-actions .el-button {
margin-left: 10px;
}
/* 响应式调整 */
@media (max-width: 1200px) {
.work-area {
width: 70%;
}
.diagnosis-panel {
width: 30%;
}
}
@media (max-width: 768px) {
.workstation-container {
flex-direction: column;
}
.work-area,
.diagnosis-panel {
width: 100%;
}
}
</style>