2025-06-09 15:39:06 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<el-dialog
|
|
|
|
|
|
v-model="dialogVisible"
|
|
|
|
|
|
:title="currentDeviceName"
|
|
|
|
|
|
width="80%"
|
|
|
|
|
|
:close-on-click-modal="false"
|
|
|
|
|
|
:close-on-press-escape="false"
|
|
|
|
|
|
:show-close="true"
|
|
|
|
|
|
class="ecg-dialog"
|
|
|
|
|
|
top="5vh"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="ecg-container">
|
|
|
|
|
|
<!-- 左侧人员列表 -->
|
|
|
|
|
|
<div class="person-list">
|
|
|
|
|
|
<el-card class="box-card">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="searchQuery"
|
2025-06-10 14:20:09 +08:00
|
|
|
|
placeholder="请输入姓名&ID"
|
2025-06-09 15:39:06 +08:00
|
|
|
|
prefix-icon="el-icon-search"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
/>
|
|
|
|
|
|
<el-scrollbar height="calc(100vh - 400px)">
|
|
|
|
|
|
<el-menu
|
|
|
|
|
|
:default-active="activePerson"
|
|
|
|
|
|
@select="handlePersonSelect"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-menu-item
|
|
|
|
|
|
v-for="person in filteredPersonList"
|
|
|
|
|
|
:key="person.id"
|
2025-06-10 14:20:09 +08:00
|
|
|
|
:index="person.id.toString()"
|
|
|
|
|
|
>
|
|
|
|
|
|
<span>{{ person.username }} (ID: {{ person.userid }})</span>
|
|
|
|
|
|
</el-menu-item>
|
|
|
|
|
|
</el-menu>
|
|
|
|
|
|
</el-scrollbar>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 中间时间列表 -->
|
|
|
|
|
|
<div class="time-list">
|
|
|
|
|
|
<el-card class="box-card">
|
|
|
|
|
|
<div class="time-list-header">
|
|
|
|
|
|
<el-date-picker
|
|
|
|
|
|
v-model="dateFilter"
|
|
|
|
|
|
type="date"
|
|
|
|
|
|
placeholder="请选择采集日期"
|
|
|
|
|
|
format="YYYY-MM-DD"
|
|
|
|
|
|
value-format="YYYY-MM-DD"
|
|
|
|
|
|
:clearable="true"
|
|
|
|
|
|
@change="handleDateFilter"
|
|
|
|
|
|
style="width: 100%; margin-bottom: 10px;"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-scrollbar height="400px">
|
|
|
|
|
|
<el-menu
|
|
|
|
|
|
:default-active="activeTime"
|
|
|
|
|
|
@select="handleTimeSelect"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-menu-item
|
|
|
|
|
|
v-for="(time, index) in filteredTimeList"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
:index="index.toString()"
|
2025-06-09 15:39:06 +08:00
|
|
|
|
>
|
2025-06-10 14:20:09 +08:00
|
|
|
|
<span>{{ formatTime(time.collecttime) }}</span>
|
2025-06-09 15:39:06 +08:00
|
|
|
|
</el-menu-item>
|
2025-06-10 14:20:09 +08:00
|
|
|
|
<div v-if="filteredTimeList.length === 0" class="no-time-data">
|
|
|
|
|
|
暂无采集时间
|
|
|
|
|
|
</div>
|
2025-06-09 15:39:06 +08:00
|
|
|
|
</el-menu>
|
|
|
|
|
|
</el-scrollbar>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 右侧数据展示区域 -->
|
|
|
|
|
|
<div class="data-display">
|
|
|
|
|
|
<el-card class="box-card">
|
2025-06-10 14:20:09 +08:00
|
|
|
|
<div class="ecg-data-content">
|
|
|
|
|
|
<div class="no-selection" v-if="!selectedPerson">
|
|
|
|
|
|
请从左侧选择人员查看数据
|
2025-06-09 15:39:06 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div v-else>
|
2025-06-10 14:20:09 +08:00
|
|
|
|
<div class="no-data" v-if="!hasData">
|
|
|
|
|
|
暂无数据
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-else>
|
2025-07-09 15:15:33 +08:00
|
|
|
|
<el-tabs v-model="activeTab" class="ecg-tabs" @tab-change="handleTabChange">
|
2025-06-10 14:20:09 +08:00
|
|
|
|
<el-tab-pane label="基础数据" name="basic">
|
|
|
|
|
|
<div class="ecg-fields-container">
|
|
|
|
|
|
<div class="ecg-grid">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="field in basicFields"
|
|
|
|
|
|
:key="field.key"
|
|
|
|
|
|
class="ecg-grid-item">
|
|
|
|
|
|
<div class="ecg-field-content">
|
|
|
|
|
|
<span class="ecg-label">{{ field.label }}</span>
|
|
|
|
|
|
<span class="ecg-value">{{ selectedPersonData && selectedPersonData[field.key] !== undefined ? selectedPersonData[field.key] : '-' }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
<el-tab-pane label="心电图" name="ecg">
|
|
|
|
|
|
<div class="ecg-image-container">
|
2025-08-26 14:24:11 +08:00
|
|
|
|
<template v-if="ecgImages && ecgImages.length > 0">
|
|
|
|
|
|
<!-- 心电图分页导航 -->
|
|
|
|
|
|
<div class="ecg-pagination-header" v-if="ecgImages.length > 1">
|
|
|
|
|
|
<div class="ecg-pagination-info">
|
|
|
|
|
|
第 {{ currentEcgIndex + 1 }} 张,共 {{ ecgImages.length }} 张
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="ecg-pagination-controls">
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
:icon="'el-icon-arrow-left'"
|
|
|
|
|
|
circle
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
:disabled="currentEcgIndex <= 0"
|
|
|
|
|
|
@click="prevEcgImage"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
:icon="'el-icon-arrow-right'"
|
|
|
|
|
|
circle
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
:disabled="currentEcgIndex >= ecgImages.length - 1"
|
|
|
|
|
|
@click="nextEcgImage"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 心电图显示 -->
|
|
|
|
|
|
<div class="ecg-image-display">
|
|
|
|
|
|
<el-image
|
|
|
|
|
|
:src="ecgImages[currentEcgIndex]"
|
|
|
|
|
|
:preview-src-list="ecgImages"
|
|
|
|
|
|
:initial-index="currentEcgIndex"
|
|
|
|
|
|
fit="contain"
|
|
|
|
|
|
class="ecg-image"
|
|
|
|
|
|
:preview-teleported="true"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 心电图缩略图导航 -->
|
|
|
|
|
|
<div class="ecg-thumbnails" v-if="ecgImages.length > 1">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="(image, index) in ecgImages"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
class="ecg-thumbnail"
|
|
|
|
|
|
:class="{ 'active': index === currentEcgIndex }"
|
|
|
|
|
|
@click="goToEcgImage(index)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-image
|
|
|
|
|
|
:src="image"
|
|
|
|
|
|
fit="cover"
|
|
|
|
|
|
class="thumbnail-image"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div class="thumbnail-index">{{ index + 1 }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-06-10 14:20:09 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
<template v-else>
|
|
|
|
|
|
<el-empty description="暂无心电图" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-if="selectedPersonData && selectedPersonData.diagnosis" style="margin-top: 20px;">
|
|
|
|
|
|
心电图诊断:{{ selectedPersonData.diagnosis }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-tab-pane>
|
2025-07-09 15:15:33 +08:00
|
|
|
|
<el-tab-pane label="精神压力" name="stress">
|
|
|
|
|
|
<div class="ecg-fields-container">
|
|
|
|
|
|
<div class="ecg-grid">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="field in stressFields"
|
|
|
|
|
|
:key="field.key"
|
|
|
|
|
|
class="ecg-grid-item">
|
|
|
|
|
|
<div class="ecg-field-content">
|
|
|
|
|
|
<span class="ecg-label">{{ field.label }}</span>
|
|
|
|
|
|
<span class="ecg-value">{{ selectedPersonData && selectedPersonData[field.key] !== undefined ? selectedPersonData[field.key] : '-' }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-tab-pane>
|
2025-06-10 14:20:09 +08:00
|
|
|
|
</el-tabs>
|
|
|
|
|
|
</div>
|
2025-06-09 15:39:06 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-06-16 16:49:57 +08:00
|
|
|
|
<!-- 添加医生通知输入框和发送按钮 -->
|
|
|
|
|
|
<div class="doctor-notification">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="doctorMessage"
|
|
|
|
|
|
type="textarea"
|
|
|
|
|
|
:rows="3"
|
|
|
|
|
|
placeholder="请输入医生通知内容"
|
|
|
|
|
|
resize="none"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
@click="sendDoctorNotification"
|
|
|
|
|
|
:disabled="!doctorMessage.trim()"
|
|
|
|
|
|
class="doctor-send-btn"
|
|
|
|
|
|
>
|
|
|
|
|
|
<span>发送</span>
|
|
|
|
|
|
<span>通知</span>
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
2025-06-09 15:39:06 +08:00
|
|
|
|
</el-card>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
2025-06-10 14:20:09 +08:00
|
|
|
|
import { DeviceuserApi } from '@/api/deviceuser'
|
|
|
|
|
|
import { EcgdataApi } from '@/api/ecgdata'
|
2025-06-17 16:24:43 +08:00
|
|
|
|
import { PersonApi } from '@/api/person'
|
|
|
|
|
|
import { useMessage } from '@/hooks/web/useMessage'
|
|
|
|
|
|
import { DoctornoticeApi } from '@/api/doctornotice'
|
|
|
|
|
|
import { getUserProfile } from '@/api/system/user/profile'
|
2025-07-09 15:15:33 +08:00
|
|
|
|
import * as echarts from 'echarts'
|
2025-06-10 14:20:09 +08:00
|
|
|
|
|
2025-06-09 15:39:06 +08:00
|
|
|
|
export default {
|
|
|
|
|
|
name: 'ECGDatas',
|
2025-06-17 16:24:43 +08:00
|
|
|
|
setup() {
|
|
|
|
|
|
const message = useMessage()
|
|
|
|
|
|
return { message }
|
|
|
|
|
|
},
|
2025-06-09 15:39:06 +08:00
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
searchQuery: '',
|
|
|
|
|
|
activePerson: '',
|
|
|
|
|
|
selectedPerson: null,
|
|
|
|
|
|
personList: [], // 这里需要从后端获取人员列表
|
|
|
|
|
|
hasData: false,
|
|
|
|
|
|
dialogVisible: false,
|
|
|
|
|
|
currentDeviceId: '',
|
2025-06-10 14:20:09 +08:00
|
|
|
|
currentDeviceName: '',
|
|
|
|
|
|
selectedPersonData: null, // 新增:存储选中人员的心电数据
|
|
|
|
|
|
activeTab: 'basic', // 新增:当前激活的标签页
|
2025-06-16 16:49:57 +08:00
|
|
|
|
doctorMessage: '', // 新增:医生通知内容
|
2025-06-17 16:24:43 +08:00
|
|
|
|
userProfile: null, // 新增:存储当前登录用户信息
|
2025-06-10 14:20:09 +08:00
|
|
|
|
basicFields: [
|
|
|
|
|
|
{ key: 'heartrate', label: '心率(次/分)' },
|
|
|
|
|
|
{ key: 'rhythm', label: '心律类型' },
|
|
|
|
|
|
{ key: 'printerval', label: 'PR间期(ms)' },
|
|
|
|
|
|
{ key: 'qrsduration', label: 'QRS时限(ms)' },
|
|
|
|
|
|
{ key: 'qtinterval', label: 'QT间期(ms)' },
|
|
|
|
|
|
{ key: 'qtcinterval', label: 'QTc间期(ms)' },
|
|
|
|
|
|
{ key: 'paxis', label: 'P电轴(度)' },
|
|
|
|
|
|
{ key: 'qrsaxis', label: 'QRS电轴(度)' },
|
|
|
|
|
|
{ key: 'taxis', label: 'T电轴(度)' },
|
|
|
|
|
|
{ key: 'rv5', label: 'RV5电压(mV)' },
|
|
|
|
|
|
{ key: 'sv1', label: 'SV1电压(mV)' },
|
|
|
|
|
|
{ key: 'rv5sv1', label: 'RV5+SV1电压(mV)' },
|
|
|
|
|
|
{ key: 'stsegment', label: 'ST段改变' },
|
|
|
|
|
|
{ key: 'twave', label: 'T波改变' }
|
|
|
|
|
|
],
|
2025-07-09 15:15:33 +08:00
|
|
|
|
stressFields: [
|
|
|
|
|
|
{ key: 'hrv_meannn', label: 'NN间期均值(ms)' },
|
|
|
|
|
|
{ key: 'hrv_sdnn', label: 'NN间期标准差(ms)' },
|
|
|
|
|
|
{ key: 'hrv_sdann', label: '5分钟NN间期均值标准差(ms)' },
|
|
|
|
|
|
{ key: 'hrv_rmssd', label: '相邻NN间期均方根(ms)' },
|
|
|
|
|
|
{ key: 'hrv_sdnnindex', label: '每5分钟NN间期标准差均值(ms)' },
|
|
|
|
|
|
{ key: 'hrv_pnn50', label: 'pNN50(%)' },
|
|
|
|
|
|
{ key: 'hrv_uflp', label: '超低频功率(ms²)' },
|
|
|
|
|
|
{ key: 'hrv_vlfp', label: '极低频功率(ms²)' },
|
|
|
|
|
|
{ key: 'hrv_lfp', label: '低频功率(ms²)' },
|
|
|
|
|
|
{ key: 'hrv_hfp', label: '高频功率(ms²)' },
|
|
|
|
|
|
{ key: 'hrv_tp', label: '总功率(ms²)' },
|
|
|
|
|
|
{ key: 'hrv_diagResult', label: '诊断结论' },
|
|
|
|
|
|
{ key: 'hrv_heartRisk', label: '心脏风险' }
|
|
|
|
|
|
],
|
2025-06-10 14:20:09 +08:00
|
|
|
|
ecgFields: [ // 修改:心电图字段映射
|
|
|
|
|
|
{ key: 'paxis', label: 'P电轴(度)' },
|
|
|
|
|
|
{ key: 'qrsaxis', label: 'QRS电轴(度)' },
|
|
|
|
|
|
{ key: 'taxis', label: 'T电轴(度)' },
|
|
|
|
|
|
{ key: 'rv5', label: 'RV5电压(mV)' },
|
|
|
|
|
|
{ key: 'sv1', label: 'SV1电压(mV)' },
|
|
|
|
|
|
{ key: 'rv5sv1', label: 'RV5+SV1电压(mV)' },
|
|
|
|
|
|
{ key: 'stsegment', label: 'ST段改变' },
|
|
|
|
|
|
{ key: 'twave', label: 'T波改变' },
|
|
|
|
|
|
{ key: 'diagnosis', label: '心电图诊断' }
|
|
|
|
|
|
],
|
|
|
|
|
|
timeList: [], // 新增:时间列表
|
|
|
|
|
|
activeTime: '', // 新增:当前激活的时间
|
|
|
|
|
|
dateFilter: null, // 新增:日期筛选值
|
2025-08-26 14:24:11 +08:00
|
|
|
|
currentEcgIndex: 0, // 新增:当前心电图索引
|
|
|
|
|
|
ecgImages: [], // 新增:心电图图片数组
|
2025-06-09 15:39:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
filteredPersonList() {
|
|
|
|
|
|
if (!this.searchQuery) return this.personList
|
|
|
|
|
|
return this.personList.filter(person =>
|
2025-06-10 14:20:09 +08:00
|
|
|
|
person.username.toLowerCase().includes(this.searchQuery.toLowerCase())
|
2025-06-09 15:39:06 +08:00
|
|
|
|
)
|
2025-06-10 14:20:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 新增:根据日期筛选时间列表
|
|
|
|
|
|
filteredTimeList() {
|
|
|
|
|
|
if (!this.dateFilter) return this.timeList
|
|
|
|
|
|
return this.timeList.filter(time => {
|
|
|
|
|
|
const timeDate = new Date(time.collecttime).toISOString().split('T')[0]
|
|
|
|
|
|
return timeDate === this.dateFilter
|
|
|
|
|
|
})
|
2025-06-09 15:39:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
// 打开组件
|
2025-06-17 16:24:43 +08:00
|
|
|
|
async open(deviceId, deviceName) {
|
2025-06-10 14:20:09 +08:00
|
|
|
|
// 重置所有数据
|
|
|
|
|
|
this.searchQuery = ''
|
|
|
|
|
|
this.activePerson = ''
|
|
|
|
|
|
this.selectedPerson = null
|
|
|
|
|
|
this.personList = []
|
|
|
|
|
|
this.hasData = false
|
|
|
|
|
|
this.selectedPersonData = null
|
|
|
|
|
|
this.activeTab = 'basic'
|
|
|
|
|
|
this.activeTime = ''
|
|
|
|
|
|
this.timeList = []
|
|
|
|
|
|
this.dateFilter = null // 重置日期筛选
|
2025-06-16 16:49:57 +08:00
|
|
|
|
this.doctorMessage = '' // 重置医生通知内容
|
2025-08-26 14:24:11 +08:00
|
|
|
|
this.currentEcgIndex = 0 // 重置心电图索引
|
|
|
|
|
|
this.ecgImages = [] // 重置心电图数组
|
2025-06-10 14:20:09 +08:00
|
|
|
|
|
|
|
|
|
|
// 打开对话框并设置设备信息
|
2025-06-09 15:39:06 +08:00
|
|
|
|
this.dialogVisible = true
|
|
|
|
|
|
this.currentDeviceId = deviceId
|
|
|
|
|
|
this.currentDeviceName = deviceName
|
2025-06-17 16:24:43 +08:00
|
|
|
|
// 获取当前登录用户信息
|
|
|
|
|
|
this.userProfile = await getUserProfile()
|
2025-06-09 15:39:06 +08:00
|
|
|
|
this.loadPersonList()
|
|
|
|
|
|
},
|
|
|
|
|
|
// 加载人员列表
|
|
|
|
|
|
async loadPersonList() {
|
|
|
|
|
|
try {
|
2025-06-10 14:20:09 +08:00
|
|
|
|
const response = await DeviceuserApi.getDeviceuserByDeviceId(this.currentDeviceId)
|
|
|
|
|
|
this.personList = response
|
2025-06-09 15:39:06 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取人员列表失败:', error)
|
|
|
|
|
|
this.$message.error('获取人员列表失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
handlePersonSelect(index) {
|
|
|
|
|
|
this.activePerson = index
|
2025-06-10 14:20:09 +08:00
|
|
|
|
this.selectedPerson = this.personList.find(person => person.id.toString() === index)
|
|
|
|
|
|
// 重置时间列表
|
|
|
|
|
|
this.timeList = []
|
2025-06-09 15:39:06 +08:00
|
|
|
|
this.loadPersonData()
|
2025-06-10 14:20:09 +08:00
|
|
|
|
// 重置数据展示状态
|
|
|
|
|
|
this.selectedPersonData = null
|
|
|
|
|
|
this.hasData = false
|
|
|
|
|
|
this.activeTime = ''
|
2025-08-26 14:24:11 +08:00
|
|
|
|
this.currentEcgIndex = 0 // 重置心电图索引
|
|
|
|
|
|
this.ecgImages = [] // 重置心电图数组
|
2025-06-09 15:39:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
async loadPersonData() {
|
|
|
|
|
|
try {
|
2025-06-10 14:20:09 +08:00
|
|
|
|
const response = await EcgdataApi.getEcgdataByUserId(this.selectedPerson.userid)
|
|
|
|
|
|
this.timeList = Array.isArray(response) ? response : [response]
|
2025-06-09 15:39:06 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取心电数据失败:', error)
|
|
|
|
|
|
this.$message.error('获取数据失败')
|
|
|
|
|
|
}
|
2025-06-10 14:20:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
async handleTimeSelect(index) {
|
|
|
|
|
|
this.activeTime = index
|
|
|
|
|
|
const selectedTime = this.timeList[parseInt(index)]
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await EcgdataApi.getEcgdataByTime(selectedTime.collecttime, this.selectedPerson.userid)
|
|
|
|
|
|
this.selectedPersonData = response
|
|
|
|
|
|
this.hasData = !!this.selectedPersonData
|
2025-08-26 14:24:11 +08:00
|
|
|
|
// 处理心电图图片数组
|
|
|
|
|
|
this.processEcgImages()
|
2025-06-10 14:20:09 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取指定时间的心电数据失败:', error)
|
|
|
|
|
|
this.$message.error('获取数据失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
formatTime(timestamp) {
|
|
|
|
|
|
const date = new Date(timestamp)
|
|
|
|
|
|
return date.toLocaleString()
|
|
|
|
|
|
},
|
|
|
|
|
|
// 新增:处理日期筛选
|
|
|
|
|
|
handleDateFilter() {
|
|
|
|
|
|
this.activeTime = ''
|
|
|
|
|
|
this.selectedPersonData = null
|
|
|
|
|
|
this.hasData = false
|
2025-08-26 14:24:11 +08:00
|
|
|
|
this.currentEcgIndex = 0 // 重置心电图索引
|
|
|
|
|
|
this.ecgImages = [] // 重置心电图数组
|
2025-06-10 14:20:09 +08:00
|
|
|
|
},
|
2025-06-16 16:49:57 +08:00
|
|
|
|
// 新增:发送医生通知方法
|
|
|
|
|
|
async sendDoctorNotification() {
|
2025-06-17 16:24:43 +08:00
|
|
|
|
if (!this.selectedPerson) {
|
|
|
|
|
|
this.message.warning('请先选择人员')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-16 16:49:57 +08:00
|
|
|
|
if (!this.doctorMessage.trim()) {
|
2025-06-17 16:24:43 +08:00
|
|
|
|
this.message.warning('请输入通知内容')
|
2025-06-16 16:49:57 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-06-17 16:24:43 +08:00
|
|
|
|
|
2025-06-16 16:49:57 +08:00
|
|
|
|
try {
|
2025-06-17 16:24:43 +08:00
|
|
|
|
// 检查用户是否为会员
|
|
|
|
|
|
const userResponse = await PersonApi.getPerson(this.selectedPerson.userid)
|
|
|
|
|
|
if (!userResponse || userResponse.isvip === 0) {
|
|
|
|
|
|
this.message.warning('该用户不是会员,无法发送通知')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建通知数据
|
|
|
|
|
|
const noticeData = {
|
|
|
|
|
|
id: 0, // 新增时后端会自动生成
|
|
|
|
|
|
deviceid: this.currentDeviceId,
|
|
|
|
|
|
userid: this.selectedPerson.userid,
|
|
|
|
|
|
username: this.selectedPerson.username,
|
2025-06-30 15:11:34 +08:00
|
|
|
|
orgid: this.userProfile.dept.orgid,
|
2025-06-17 16:24:43 +08:00
|
|
|
|
doctorid: this.userProfile.id,
|
|
|
|
|
|
datatime: new Date().getTime(),
|
|
|
|
|
|
noticetype: 2, // 建议提醒
|
|
|
|
|
|
noticetitle: '医生通知',
|
|
|
|
|
|
noticecontent: this.doctorMessage,
|
|
|
|
|
|
noticelevel: 1, // 普通级别
|
|
|
|
|
|
readstatus: 0, // 未读
|
|
|
|
|
|
readtime: null,
|
|
|
|
|
|
createtime: new Date().getTime(),
|
|
|
|
|
|
updatetime: new Date().getTime(),
|
|
|
|
|
|
createby: this.userProfile.nickname,
|
|
|
|
|
|
updateby: this.userProfile.nickname,
|
|
|
|
|
|
isdeleted: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 调用创建通知接口
|
|
|
|
|
|
await DoctornoticeApi.createDoctornotice(noticeData)
|
|
|
|
|
|
this.message.success('通知发送成功')
|
2025-06-16 16:49:57 +08:00
|
|
|
|
this.doctorMessage = '' // 清空输入框
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('发送通知失败:', error)
|
2025-06-17 16:24:43 +08:00
|
|
|
|
this.message.error('发送通知失败')
|
2025-06-16 16:49:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-07-09 15:15:33 +08:00
|
|
|
|
// 新增:处理标签页切换
|
|
|
|
|
|
handleTabChange(tabName) {
|
|
|
|
|
|
if (tabName === 'stress' && this.selectedPersonData) {
|
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
|
this.initStressChart()
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 新增:初始化压力图表
|
|
|
|
|
|
initStressChart() {
|
|
|
|
|
|
const chartContainer = this.$refs.stressChart
|
|
|
|
|
|
if (!chartContainer) return
|
|
|
|
|
|
|
|
|
|
|
|
// 销毁之前的图表实例
|
|
|
|
|
|
if (this.stressChartInstance) {
|
|
|
|
|
|
this.stressChartInstance.dispose()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建新的图表实例
|
|
|
|
|
|
this.stressChartInstance = echarts.init(chartContainer)
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟压力数据(实际项目中应该从后端获取)
|
|
|
|
|
|
const mockData = this.generateMockStressData()
|
|
|
|
|
|
|
|
|
|
|
|
const option = {
|
|
|
|
|
|
title: {
|
|
|
|
|
|
text: '压力指数趋势',
|
|
|
|
|
|
left: 'center',
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
|
fontWeight: 'normal'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
formatter: function(params) {
|
|
|
|
|
|
const data = params[0]
|
|
|
|
|
|
return `${data.name}<br/>压力指数: ${data.value}`
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
left: '3%',
|
|
|
|
|
|
right: '4%',
|
|
|
|
|
|
bottom: '3%',
|
|
|
|
|
|
containLabel: true
|
|
|
|
|
|
},
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
boundaryGap: false,
|
|
|
|
|
|
data: mockData.times,
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
fontSize: 10
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
name: '压力指数',
|
|
|
|
|
|
min: 0,
|
|
|
|
|
|
max: 100,
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
fontSize: 10
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '压力指数',
|
|
|
|
|
|
type: 'line',
|
|
|
|
|
|
smooth: true,
|
|
|
|
|
|
data: mockData.values,
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: '#409EFF'
|
|
|
|
|
|
},
|
|
|
|
|
|
areaStyle: {
|
|
|
|
|
|
color: {
|
|
|
|
|
|
type: 'linear',
|
|
|
|
|
|
x: 0,
|
|
|
|
|
|
y: 0,
|
|
|
|
|
|
x2: 0,
|
|
|
|
|
|
y2: 1,
|
|
|
|
|
|
colorStops: [
|
|
|
|
|
|
{ offset: 0, color: 'rgba(64, 158, 255, 0.3)' },
|
|
|
|
|
|
{ offset: 1, color: 'rgba(64, 158, 255, 0.1)' }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
width: 2
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.stressChartInstance.setOption(option)
|
|
|
|
|
|
|
|
|
|
|
|
// 监听窗口大小变化
|
|
|
|
|
|
window.addEventListener('resize', () => {
|
|
|
|
|
|
if (this.stressChartInstance) {
|
|
|
|
|
|
this.stressChartInstance.resize()
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
// 新增:生成模拟压力数据
|
|
|
|
|
|
generateMockStressData() {
|
|
|
|
|
|
const times = []
|
|
|
|
|
|
const values = []
|
|
|
|
|
|
const now = new Date()
|
|
|
|
|
|
|
|
|
|
|
|
// 生成最近7天的数据
|
|
|
|
|
|
for (let i = 6; i >= 0; i--) {
|
|
|
|
|
|
const date = new Date(now.getTime() - i * 24 * 60 * 60 * 1000)
|
|
|
|
|
|
times.push(date.toLocaleDateString())
|
|
|
|
|
|
|
|
|
|
|
|
// 生成30-80之间的随机压力值
|
|
|
|
|
|
const stressValue = Math.floor(Math.random() * 50) + 30
|
|
|
|
|
|
values.push(stressValue)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return { times, values }
|
|
|
|
|
|
},
|
2025-08-26 14:24:11 +08:00
|
|
|
|
// 新增:处理心电图图片数组
|
|
|
|
|
|
processEcgImages() {
|
|
|
|
|
|
this.currentEcgIndex = 0
|
|
|
|
|
|
this.ecgImages = []
|
|
|
|
|
|
|
|
|
|
|
|
if (this.selectedPersonData && this.selectedPersonData.ecgimageurls) {
|
|
|
|
|
|
// 检查是否是多个图片URL(数组形式)
|
|
|
|
|
|
if (Array.isArray(this.selectedPersonData.ecgimageurls)) {
|
|
|
|
|
|
this.ecgImages = this.selectedPersonData.ecgimageurls.filter(url => url && url.trim())
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (this.selectedPersonData && this.selectedPersonData.ecgimageurl) {
|
|
|
|
|
|
// 兼容旧的字段名 ecgimageurl
|
|
|
|
|
|
if (Array.isArray(this.selectedPersonData.ecgimageurl)) {
|
|
|
|
|
|
this.ecgImages = this.selectedPersonData.ecgimageurl.filter(url => url && url.trim())
|
|
|
|
|
|
} else if (typeof this.selectedPersonData.ecgimageurl === 'string') {
|
|
|
|
|
|
// 如果是字符串,可能包含多个URL,用逗号分隔
|
|
|
|
|
|
const urls = this.selectedPersonData.ecgimageurl.split(',').map(url => url.trim()).filter(url => url)
|
|
|
|
|
|
this.ecgImages = urls.length > 0 ? urls : [this.selectedPersonData.ecgimageurl]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 新增:上一张心电图
|
|
|
|
|
|
prevEcgImage() {
|
|
|
|
|
|
if (this.currentEcgIndex > 0) {
|
|
|
|
|
|
this.currentEcgIndex--
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 新增:下一张心电图
|
|
|
|
|
|
nextEcgImage() {
|
|
|
|
|
|
if (this.currentEcgIndex < this.ecgImages.length - 1) {
|
|
|
|
|
|
this.currentEcgIndex++
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// 新增:跳转到指定心电图
|
|
|
|
|
|
goToEcgImage(index) {
|
|
|
|
|
|
if (index >= 0 && index < this.ecgImages.length) {
|
|
|
|
|
|
this.currentEcgIndex = index
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-06-09 15:39:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.ecg-dialog :deep(.el-dialog) {
|
|
|
|
|
|
margin-top: 5vh !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-dialog :deep(.el-dialog__body) {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
height: calc(85vh - 100px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
gap: 20px;
|
|
|
|
|
|
padding: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.person-list {
|
|
|
|
|
|
width: 280px;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-10 14:20:09 +08:00
|
|
|
|
.time-list {
|
2025-06-10 14:45:22 +08:00
|
|
|
|
width: 200px;
|
2025-06-10 14:20:09 +08:00
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.time-list :deep(.el-card__body) {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.time-list-header {
|
|
|
|
|
|
padding: 15px;
|
|
|
|
|
|
border-bottom: 1px solid #EBEEF5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-title {
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.time-list :deep(.el-scrollbar__wrap) {
|
|
|
|
|
|
overflow-x: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.time-list :deep(.el-menu) {
|
|
|
|
|
|
border-right: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.time-list :deep(.el-menu-item) {
|
|
|
|
|
|
height: 40px;
|
|
|
|
|
|
line-height: 40px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-09 15:39:06 +08:00
|
|
|
|
.data-display {
|
|
|
|
|
|
flex: 1;
|
2025-06-16 16:49:57 +08:00
|
|
|
|
position: relative;
|
2025-06-09 15:39:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.box-card {
|
|
|
|
|
|
height: 100%;
|
2025-06-16 16:49:57 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2025-06-09 15:39:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 10px 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.no-selection,
|
|
|
|
|
|
.no-data {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
height: 200px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-data-content {
|
|
|
|
|
|
min-height: 200px;
|
2025-06-16 16:49:57 +08:00
|
|
|
|
flex: 1;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
padding-bottom: 120px;
|
2025-06-09 15:39:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.el-scrollbar {
|
|
|
|
|
|
height: calc(100vh - 400px) !important;
|
|
|
|
|
|
}
|
2025-06-10 14:20:09 +08:00
|
|
|
|
|
|
|
|
|
|
.ecg-fields-container {
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(3, 1fr);
|
|
|
|
|
|
gap: 15px;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-grid-item {
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
transition: all 0.3s ease;
|
2025-06-16 16:49:57 +08:00
|
|
|
|
min-width: 0;
|
2025-06-10 14:20:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-grid-item:hover {
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-field-content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-label {
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-value {
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-tabs {
|
|
|
|
|
|
padding: 0 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-tabs :deep(.el-tabs__header) {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-tabs :deep(.el-tabs__nav-wrap::after) {
|
|
|
|
|
|
height: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-image-container {
|
|
|
|
|
|
display: flex;
|
2025-08-26 14:24:11 +08:00
|
|
|
|
flex-direction: column;
|
2025-06-10 14:20:09 +08:00
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
min-height: 300px;
|
2025-08-26 14:24:11 +08:00
|
|
|
|
gap: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-pagination-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
padding: 0 20px;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-pagination-info {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-pagination-controls {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-image-display {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
width: 100%;
|
2025-06-10 14:20:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-image {
|
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
|
max-height: 400px;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.08);
|
2025-08-26 14:24:11 +08:00
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: transform 0.2s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-image:hover {
|
|
|
|
|
|
transform: scale(1.02);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-thumbnails {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
margin-top: 15px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
|
padding: 0 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-thumbnail {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
width: 80px;
|
|
|
|
|
|
height: 60px;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
border: 2px solid transparent;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-thumbnail:hover {
|
|
|
|
|
|
border-color: #409EFF;
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
box-shadow: 0 4px 8px rgba(64, 158, 255, 0.3);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ecg-thumbnail.active {
|
|
|
|
|
|
border-color: #409EFF;
|
|
|
|
|
|
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.4);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.thumbnail-image {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.thumbnail-index {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 2px;
|
|
|
|
|
|
right: 2px;
|
|
|
|
|
|
background: rgba(0, 0, 0, 0.7);
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
padding: 2px 4px;
|
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
|
min-width: 16px;
|
|
|
|
|
|
text-align: center;
|
2025-06-10 14:20:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.no-ecg-image {
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.no-time-data {
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
2025-06-16 16:49:57 +08:00
|
|
|
|
|
|
|
|
|
|
.doctor-notification {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 15px;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
z-index: 1;
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.doctor-notification :deep(.el-textarea__inner) {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
height: 80px !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.doctor-send-btn {
|
|
|
|
|
|
height: 80px !important;
|
|
|
|
|
|
min-width: 60px;
|
|
|
|
|
|
white-space: pre-line;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
line-height: 1.1;
|
|
|
|
|
|
padding: 0 16px;
|
|
|
|
|
|
}
|
2025-06-09 15:39:06 +08:00
|
|
|
|
</style>
|