Merge branch 'master' of http://114.55.171.231:3000/Euni4U/shanghai_vue3
This commit is contained in:
commit
38d7256439
@ -1,10 +1,14 @@
|
||||
import request from '@/config/axios'
|
||||
import { patientinfoVO } from '../patientinfo'
|
||||
|
||||
// ABPM动态血压监测 VO
|
||||
export interface abpmVO {
|
||||
id: number // 主键ID
|
||||
examid: string // 检查ID
|
||||
regid: string // 患者注册ID
|
||||
name: string // 患者姓名
|
||||
gender: string // 性别
|
||||
age: number // 年龄
|
||||
orgid: string // 机构ID
|
||||
orgname: string // 机构名称
|
||||
managerorg: string // 管理机构
|
||||
@ -48,5 +52,10 @@ export const abpmApi = {
|
||||
// 导出ABPM动态血压监测 Excel
|
||||
exportabpm: async (params) => {
|
||||
return await request.download({ url: `/system/abpm/export-excel`, params })
|
||||
},
|
||||
|
||||
// 批量新增ABPM患者数据
|
||||
insertAbpmPatientData: async (data: patientinfoVO[]) => {
|
||||
return await request.post({ url: `/system/abpm/insertAbpmPatientData`, data })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,11 +107,11 @@
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
:type="
|
||||
scope.row.gender === 1 ? 'primary' : scope.row.gender === 2 ? 'danger' : 'info'
|
||||
scope.row.gender === '1' ? 'primary' : scope.row.gender === '2' ? 'danger' : 'info'
|
||||
"
|
||||
size="small"
|
||||
>
|
||||
{{ scope.row.gender === 1 ? '男' : scope.row.gender === 2 ? '女' : '未知' }}
|
||||
{{ scope.row.gender === '1' ? '男' : scope.row.gender === '2' ? '女' : '未知' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -201,6 +201,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { abpmApi } from '@/api/abpm'
|
||||
import { ecgdataApi } from '@/api/ecgdata'
|
||||
import { patientinfoApi, patientinfoVO } from '@/api/patientinfo'
|
||||
import { getUserProfile, ProfileVO } from '@/api/system/user/profile'
|
||||
@ -348,6 +349,10 @@ const handleConfirm = async () => {
|
||||
// 批量新增心电图动态数据基本信息
|
||||
await ecgdataApi.insertEcgPatientData(selectedPatients.value)
|
||||
}
|
||||
if (props.type === 'abpm') {
|
||||
// 批量新增ABPM患者数据
|
||||
await abpmApi.insertAbpmPatientData(selectedPatients.value)
|
||||
}
|
||||
handleCancel()
|
||||
} catch (error) {
|
||||
message.error('操作失败,请重试')
|
||||
|
||||
@ -2,26 +2,43 @@
|
||||
<div class="abpm-analysis">
|
||||
<!-- 分析弹窗组件 -->
|
||||
<AnalysisDialog ref="analysisDialogRef" />
|
||||
|
||||
<!-- 患者选择组件 -->
|
||||
<PatientSelect
|
||||
ref="patientSelectRef"
|
||||
title="选择患者"
|
||||
type="abpm"
|
||||
:multiple="true"
|
||||
:max-select="50"
|
||||
@confirm="handlePatientConfirm"
|
||||
@cancel="handlePatientCancel"
|
||||
/>
|
||||
|
||||
<!-- 顶部筛选区 -->
|
||||
<el-card class="filter-card" shadow="never">
|
||||
<el-form :inline="true" :model="filters" class="filter-form">
|
||||
<el-form :inline="true" :model="queryParams" class="filter-form">
|
||||
<el-form-item label="姓名:">
|
||||
<el-input
|
||||
v-model="filters.name"
|
||||
v-model="queryParams.name"
|
||||
placeholder="请输入姓名"
|
||||
clearable
|
||||
style="width: 120px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别:">
|
||||
<el-select v-model="filters.gender" placeholder="请选择" clearable style="width: 100px">
|
||||
<el-select
|
||||
v-model="queryParams.gender"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
style="width: 100px"
|
||||
>
|
||||
<el-option label="男" value="男" />
|
||||
<el-option label="女" value="女" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="日期:">
|
||||
<el-date-picker
|
||||
v-model="filters.dateRange"
|
||||
v-model="queryParams.dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
@ -32,7 +49,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="佩戴时间:">
|
||||
<el-date-picker
|
||||
v-model="filters.wearTime"
|
||||
v-model="queryParams.wearTime"
|
||||
type="datetime"
|
||||
placeholder="选择时间"
|
||||
style="width: 180px"
|
||||
@ -40,12 +57,10 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery" :loading="loading">
|
||||
<Icon icon="ep:search" />搜索
|
||||
</el-button>
|
||||
<el-button @click="handleQuery"> <Icon icon="ep:search" />搜索 </el-button>
|
||||
<el-button @click="resetQuery"> <Icon icon="ep:refresh" />重置 </el-button>
|
||||
<el-button type="primary" @click="handleAddPatient">
|
||||
<Icon icon="ep:select" />选择患者
|
||||
<el-button type="primary" @click="handleSelectPatients">
|
||||
<Icon icon="ep:user" />选择患者
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -59,7 +74,11 @@
|
||||
<el-table :data="tableData" border stripe style="width: 100%">
|
||||
<el-table-column type="index" label="序号" align="center" min-width="60" />
|
||||
<el-table-column prop="name" label="姓名" align="center" min-width="90" />
|
||||
<el-table-column prop="gender" label="性别" align="center" min-width="60" />
|
||||
<el-table-column prop="gender" label="性别" align="center" min-width="60">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.gender === '1' ? '男' : row.gender === '2' ? '女' : '未知' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="age" label="年龄" align="center" min-width="60" />
|
||||
<el-table-column prop="wearTime" label="佩戴时间" align="center" min-width="120" />
|
||||
<el-table-column prop="device" label="设备" align="center" min-width="150">
|
||||
@ -99,7 +118,7 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="org" label="机构" align="center" min-width="120" />
|
||||
<el-table-column prop="orgname" label="机构" align="center" min-width="120" />
|
||||
<el-table-column label="分析" align="center" min-width="70">
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click="onAnalyze(row)">分析</el-link>
|
||||
@ -116,20 +135,35 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Icon } from '@/components/Icon'
|
||||
import AnalysisDialog from './analysis.vue'
|
||||
import PatientSelect from '@/patientcom/index.vue'
|
||||
import { abpmApi, abpmVO } from '@/api/abpm'
|
||||
|
||||
const loading = ref(false)
|
||||
const analysisDialogRef = ref()
|
||||
const patientSelectRef = ref()
|
||||
const total = ref(0)
|
||||
|
||||
const filters = ref({
|
||||
// 查询参数
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
name: '',
|
||||
gender: '',
|
||||
dateRange: [],
|
||||
@ -137,6 +171,9 @@ const filters = ref({
|
||||
device: ''
|
||||
})
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref<abpmVO[]>([])
|
||||
|
||||
// 设备列表响应式
|
||||
const deviceList = ref<any[]>([])
|
||||
|
||||
@ -153,64 +190,61 @@ const fetchDeviceList = () => {
|
||||
|
||||
onMounted(() => {
|
||||
fetchDeviceList()
|
||||
getList()
|
||||
})
|
||||
|
||||
// tableData 设备字段用 value
|
||||
const tableData = ref([
|
||||
{
|
||||
name: '张晓宁',
|
||||
gender: '男',
|
||||
age: 45,
|
||||
createdAt: '2025/7/09',
|
||||
wearTime: '2025/7/14 11:23',
|
||||
device: '1001',
|
||||
org: '廊坊华康',
|
||||
editingDevice: false
|
||||
},
|
||||
{
|
||||
name: '李小明',
|
||||
gender: '女',
|
||||
age: 32,
|
||||
createdAt: '2025/7/10',
|
||||
wearTime: '2025/7/15 09:30',
|
||||
device: '1002',
|
||||
org: '北京协和',
|
||||
editingDevice: false
|
||||
},
|
||||
{
|
||||
name: '王大力',
|
||||
gender: '男',
|
||||
age: 58,
|
||||
createdAt: '2025/7/11',
|
||||
wearTime: '2025/7/16 14:15',
|
||||
device: '1001',
|
||||
org: '上海瑞金',
|
||||
editingDevice: false
|
||||
}
|
||||
])
|
||||
|
||||
// 设备label显示辅助函数
|
||||
const getDeviceLabel = (value: string) => {
|
||||
const found = deviceList.value.find((item) => item.value === value)
|
||||
return found ? found.label : value
|
||||
}
|
||||
|
||||
const handleQuery = () => {
|
||||
// 获取列表数据
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
// 模拟API调用延迟
|
||||
setTimeout(() => {
|
||||
ElMessage.success('查询功能待接入')
|
||||
try {
|
||||
const data = await abpmApi.getabpmPage(queryParams)
|
||||
tableData.value = data.list
|
||||
total.value = data.total
|
||||
} catch (error) {
|
||||
console.error('获取ABPM数据失败:', error)
|
||||
ElMessage.error('获取数据失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
const resetQuery = () => {
|
||||
filters.value = { name: '', gender: '', dateRange: [], wearTime: '', device: '' }
|
||||
ElMessage.info('已清除筛选条件')
|
||||
Object.assign(queryParams, {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
name: '',
|
||||
gender: '',
|
||||
dateRange: [],
|
||||
wearTime: '',
|
||||
device: ''
|
||||
})
|
||||
getList()
|
||||
}
|
||||
|
||||
const handleAddPatient = () => {
|
||||
ElMessage.success('新增患者功能待开发')
|
||||
const handleSelectPatients = () => {
|
||||
patientSelectRef.value?.open()
|
||||
}
|
||||
|
||||
const handlePatientConfirm = (selectedPatients: any[]) => {
|
||||
ElMessage.success(`已成功添加 ${selectedPatients.length} 位患者到ABPM系统`)
|
||||
// 患者数据已在组件内部通过API添加到后端
|
||||
// 这里可以刷新表格数据以显示新添加的患者
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
const handlePatientCancel = () => {
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
// 设备编辑相关方法
|
||||
|
||||
@ -105,7 +105,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<Echart v-if="showChart" :options="chartOption" :height="350" />
|
||||
<Echart v-if="showChart" :key="chartMode" :options="chartOption" :height="550" />
|
||||
<div v-else class="chart-loading">
|
||||
<el-icon style="margin-right: 8px"><Loading /></el-icon>
|
||||
图表加载中...
|
||||
@ -115,22 +115,24 @@
|
||||
|
||||
<!-- 分析结果 -->
|
||||
<el-card class="result-section" shadow="never">
|
||||
<div class="result-title">分析结果</div>
|
||||
<div class="result-content">
|
||||
最高收缩压245mmHg,最低收缩压194mmHg,发生于09日 20:02; 最高舒张压119mmHg,发生于09日
|
||||
10:31;最低舒张压76mmHg,发生于09日 18:42。
|
||||
平均收缩压151mmHg(理想<130mmHg);平均舒张压106mmHg(理想<80);
|
||||
平均脉压120mmHg;平均心率106次/分。
|
||||
血压高峰概率56.41%,血压高峰概率66.67%,夜间血压下降率4.63%。
|
||||
<div class="result-title"> 分析结果 </div>
|
||||
<el-input
|
||||
v-model="analysisResult"
|
||||
type="textarea"
|
||||
class="result-textarea"
|
||||
:autosize="false"
|
||||
resize="none"
|
||||
placeholder="请输入分析结果..."
|
||||
:rows="10"
|
||||
/>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="result-action-buttons">
|
||||
<el-button type="primary">保存</el-button>
|
||||
<el-button @click="handleClose">关闭</el-button>
|
||||
<el-button type="success">报告浏览</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="action-section">
|
||||
<el-button type="primary">保存</el-button>
|
||||
<el-button @click="handleClose">关闭</el-button>
|
||||
<el-button type="success">报告浏览</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -149,6 +151,20 @@ const showChart = ref(false)
|
||||
// 筛选模式
|
||||
const chartMode = ref<'all' | 'bp' | 'hr'>('all')
|
||||
|
||||
// 分析结果内容
|
||||
const analysisResult =
|
||||
ref(`最高收缩压245mmHg,最低收缩压194mmHg,发生于09日 20:02; 最高舒张压119mmHg,发生于09日 10:31;最低舒张压76mmHg,发生于09日 18:42。
|
||||
平均收缩压151mmHg(理想<130mmHg);平均舒张压106mmHg(理想<80);
|
||||
平均脉压120mmHg;平均心率106次/分。
|
||||
血压高峰概率56.41%,血压高峰概率66.67%,夜间血压下降率4.63%。
|
||||
|
||||
分析建议:
|
||||
1. 患者血压明显偏高,建议立即调整降压药物治疗方案。
|
||||
2. 夜间血压下降率偏低,提示可能存在非杓型血压模式。
|
||||
3. 血压变异性较大,需要密切监测并调整用药时间。
|
||||
4. 建议患者改善生活方式,包括低盐饮食、适量运动、控制体重。
|
||||
5. 定期复查24小时动态血压监测,评估治疗效果。`)
|
||||
|
||||
// 打开弹窗方法
|
||||
const open = () => {
|
||||
visible.value = true
|
||||
@ -189,6 +205,7 @@ const allSeries = [
|
||||
name: '收缩压统计',
|
||||
type: 'line' as const,
|
||||
smooth: false,
|
||||
symbol: 'none',
|
||||
data: [
|
||||
120, 130, 125, 140, 135, 150, 160, 245, 200, 210, 220, 180, 170, 160, 150, 140, 130, 120, 125,
|
||||
130, 140, 150, 200
|
||||
@ -204,6 +221,7 @@ const allSeries = [
|
||||
name: '舒张压统计',
|
||||
type: 'line' as const,
|
||||
smooth: false,
|
||||
symbol: 'none',
|
||||
data: [
|
||||
80, 85, 90, 95, 100, 105, 110, 119, 100, 110, 115, 100, 95, 90, 85, 80, 76, 80, 85, 90, 95,
|
||||
100, 110
|
||||
@ -219,6 +237,7 @@ const allSeries = [
|
||||
name: '心率统计',
|
||||
type: 'line' as const,
|
||||
smooth: false,
|
||||
symbol: 'none',
|
||||
data: [
|
||||
70, 72, 75, 78, 80, 82, 85, 90, 88, 86, 84, 82, 80, 78, 76, 74, 72, 70, 71, 73, 75, 77, 79
|
||||
],
|
||||
@ -233,10 +252,10 @@ const allSeries = [
|
||||
|
||||
const chartOption = ref<any>({
|
||||
grid: {
|
||||
left: 60,
|
||||
right: 40,
|
||||
bottom: 60,
|
||||
top: 80,
|
||||
left: 30,
|
||||
right: 20,
|
||||
bottom: 50,
|
||||
top: 50,
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
@ -321,21 +340,31 @@ const chartOption = ref<any>({
|
||||
})
|
||||
|
||||
function updateChartSeries() {
|
||||
// 只有当图表已经显示时才更新
|
||||
if (!showChart.value) return
|
||||
|
||||
let newSeries: any[] = []
|
||||
let newLegendData: string[] = []
|
||||
let yAxisConfig: any = {}
|
||||
|
||||
if (chartMode.value === 'all') {
|
||||
newSeries = [...allSeries]
|
||||
newLegendData = ['收缩压统计', '舒张压统计', '心率统计']
|
||||
yAxisConfig = {
|
||||
min: 0,
|
||||
max: 260
|
||||
}
|
||||
} else if (chartMode.value === 'bp') {
|
||||
newSeries = allSeries.slice(0, 2)
|
||||
newLegendData = ['收缩压统计', '舒张压统计']
|
||||
yAxisConfig = {
|
||||
min: 0,
|
||||
max: 260
|
||||
}
|
||||
} else if (chartMode.value === 'hr') {
|
||||
newSeries = [allSeries[2]]
|
||||
newLegendData = ['心率统计']
|
||||
yAxisConfig = {
|
||||
min: 60,
|
||||
max: 120
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新的配置对象,确保响应式更新
|
||||
@ -345,6 +374,10 @@ function updateChartSeries() {
|
||||
legend: {
|
||||
...chartOption.value.legend,
|
||||
data: newLegendData
|
||||
},
|
||||
yAxis: {
|
||||
...chartOption.value.yAxis,
|
||||
...yAxisConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -354,7 +387,7 @@ function updateChartSeries() {
|
||||
.abpm-analysis-dialog {
|
||||
:deep(.el-dialog__body) {
|
||||
padding: 0;
|
||||
height: calc(100vh - 60px);
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
:deep(.el-dialog) {
|
||||
@ -364,8 +397,7 @@ function updateChartSeries() {
|
||||
height: 100% !important;
|
||||
}
|
||||
:deep(.el-dialog__header) {
|
||||
padding: 16px 24px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@ -456,18 +488,18 @@ function updateChartSeries() {
|
||||
margin-bottom: 20px;
|
||||
:deep(.echart) {
|
||||
width: 100% !important;
|
||||
height: 350px !important;
|
||||
height: 550px !important;
|
||||
}
|
||||
:deep(.echart div) {
|
||||
width: 100% !important;
|
||||
height: 350px !important;
|
||||
height: 550px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 350px;
|
||||
min-height: 350px;
|
||||
height: 550px;
|
||||
min-height: 550px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@ -496,23 +528,50 @@ function updateChartSeries() {
|
||||
font-weight: bold;
|
||||
margin-bottom: 16px;
|
||||
color: #333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.result-content {
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
line-height: 1.8;
|
||||
padding: 16px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
.result-subtitle {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.action-section {
|
||||
.result-textarea {
|
||||
:deep(.el-textarea__inner) {
|
||||
height: 350px !important;
|
||||
min-height: 350px !important;
|
||||
max-height: 350px !important;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
line-height: 1.8;
|
||||
padding: 16px;
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 8px;
|
||||
resize: none;
|
||||
overflow-y: auto;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
:deep(.el-textarea__inner:focus) {
|
||||
border-color: #409eff;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
:deep(.el-textarea__inner:hover) {
|
||||
border-color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
|
||||
.result-action-buttons {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
margin-top: 20px;
|
||||
padding: 16px 0;
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user