From bcfed5c9c8edbc3554e987be1ba11140aafa2ecd Mon Sep 17 00:00:00 2001
From: Flow <958079825@qq.com>
Date: Thu, 17 Jul 2025 16:57:39 +0800
Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=9B=BE=E6=A0=B7=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/abpm-report-template.html | 363 ++++++++++++++++++++++++---
src/views/analysis/ABPM/analysis.vue | 271 +++++++++++++++-----
2 files changed, 537 insertions(+), 97 deletions(-)
diff --git a/public/abpm-report-template.html b/public/abpm-report-template.html
index 39b4cc0..d1d1900 100644
--- a/public/abpm-report-template.html
+++ b/public/abpm-report-template.html
@@ -204,7 +204,7 @@
.scatter-chart-item .chart {
width: 100%;
- height: 240px;
+ height: 320px;
border: 1px solid #000;
}
@@ -219,7 +219,7 @@
}
.data-table-container {
- max-height: calc(100vh - 200px);
+ max-height: 1000px;
overflow-y: auto;
margin: 20px 0;
height: auto;
@@ -234,8 +234,9 @@
.data-table th,
.data-table td {
border: 1px solid #000;
- padding: 5px;
+ padding: 3px;
text-align: center;
+ line-height: 1.2;
}
.data-table th {
@@ -1639,52 +1640,290 @@
function renderTrendChart() {
const chart = echarts.init(document.getElementById('trend-chart'));
- const timeLabels = chartDataTable.map(item =>
- new Date(item.originalTime).toLocaleDateString('zh-CN', {
- month: 'short',
- day: 'numeric',
- hour: '2-digit',
- minute: '2-digit'
- })
- );
+ // 完全参考analysis.vue的实现,使用value类型的X轴显示精确时间位置
+ const createBloodPressureXAxis = () => {
+ if (chartDataTable.length === 0) return { xAxisTicks: [], xAxisLabels: [], seriesMap: {} };
+
+ // 1. 取所有时间戳
+ const times = chartDataTable.map(item => new Date(item.originalTime).getTime());
+ const minTime = Math.min(...times);
+ const maxTime = Math.max(...times);
+
+ // 2. 计算起止整点
+ const start = new Date(minTime);
+ start.setMinutes(0, 0, 0);
+ const end = new Date(maxTime);
+ if (end.getMinutes() > 0 || end.getSeconds() > 0) {
+ end.setHours(end.getHours() + 1);
+ }
+ end.setMinutes(0, 0, 0);
+
+ // 3. 生成刻度(整点+半点)
+ const xAxisTicks = [];
+ const xAxisLabels = [];
+ let cur = new Date(start);
+ while (cur <= end) {
+ xAxisTicks.push(cur.getTime());
+ xAxisLabels.push(formatTimeLabel(cur));
+ // 半点
+ const half = new Date(cur);
+ half.setMinutes(30);
+ if (half < end) {
+ xAxisTicks.push(half.getTime());
+ xAxisLabels.push(''); // 半点不显示label
+ }
+ cur.setHours(cur.getHours() + 1);
+ cur.setMinutes(0);
+ }
+
+ // 4. 生成series数据,每个数据点都有精确的时间戳位置
+ const getSeriesData = (key) => {
+ return chartDataTable.map(item => ({
+ value: [new Date(item.originalTime).getTime(), item[key] || null],
+ itemTime: item.originalTime
+ }));
+ };
+
+ return {
+ xAxisTicks,
+ xAxisLabels,
+ seriesMap: {
+ systolic: getSeriesData('systolic'),
+ diastolic: getSeriesData('diastolic'),
+ heartRate: getSeriesData('heartRate')
+ }
+ };
+ };
+ const formatTimeLabel = (date) => {
+ const day = date.getDate();
+ const hour = date.getHours();
+ return `${hour.toString().padStart(2, '0')}`;
+ };
+
+ const { xAxisTicks, xAxisLabels, seriesMap } = createBloodPressureXAxis();
+
+ // 计算夜间遮罩区域(每一天的22点到次日8点),使用时间戳方式
+ const calculateNightAreas = () => {
+ const nightAreas = [];
+ const startTime = new Date(Math.min(...chartDataTable.map(item => new Date(item.originalTime).getTime())));
+ const endTime = new Date(Math.max(...chartDataTable.map(item => new Date(item.originalTime).getTime())));
+
+ // 从第一天开始循环,为每一天生成夜间区域
+ let currentDate = new Date(startTime);
+ currentDate.setHours(0, 0, 0, 0); // 设置为当天0点
+
+ while (currentDate <= endTime) {
+ // 当天22点
+ const nightStart = new Date(currentDate);
+ nightStart.setHours(22, 0, 0, 0);
+
+ // 次日8点
+ const nightEnd = new Date(currentDate);
+ nightEnd.setDate(nightEnd.getDate() + 1);
+ nightEnd.setHours(8, 0, 0, 0);
+
+ // 只有当夜间时段与数据时间范围有交集时才添加
+ if (nightStart <= endTime && nightEnd >= startTime) {
+ nightAreas.push([
+ { xAxis: Math.max(nightStart.getTime(), startTime.getTime()) },
+ { xAxis: Math.min(nightEnd.getTime(), endTime.getTime()) }
+ ]);
+ }
+
+ // 移动到下一天
+ currentDate.setDate(currentDate.getDate() + 1);
+ }
+
+ return nightAreas;
+ };
+ const nightAreas = calculateNightAreas();
+
+ // 完全参考analysis.vue的图表配置,使用value类型X轴
const option = {
- tooltip: { trigger: 'axis' },
- legend: { data: ['收缩压', '舒张压', '心率'], top: 10 },
- xAxis: { type: 'category', data: timeLabels },
+ grid: {
+ left: 50,
+ right: 50,
+ bottom: 60,
+ top: 50,
+ containLabel: true
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'cross'
+ },
+ backgroundColor: 'rgba(50,50,50,0.7)',
+ borderWidth: 0,
+ textStyle: {
+ color: '#fff'
+ },
+ formatter: function(params) {
+ if (params && params.length > 0) {
+ let html = '';
+ params.forEach((param) => {
+ if (param.data && param.data.itemTime) {
+ const time = new Date(param.data.itemTime);
+ const timeStr = time.toLocaleString('zh-CN', {
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit'
+ });
+ html += `${param.seriesName}: ${param.data.value[1] || '--'}
`;
+ if (param.seriesIndex === 0) {
+ html += `时间: ${timeStr}
`;
+ }
+ }
+ });
+ return html;
+ }
+ return '';
+ }
+ },
+ legend: {
+ data: ['收缩压', '舒张压', '心率'],
+ top: 10,
+ left: 'center'
+ },
+ xAxis: {
+ type: 'value',
+ min: xAxisTicks[0],
+ max: xAxisTicks[xAxisTicks.length - 1],
+ interval: (60 * 60 * 1000) / 2, // 半小时
+ minInterval: (60 * 60 * 1000) / 2, // 半小时
+ axisLabel: {
+ formatter: (value) => {
+ const date = new Date(value);
+ // 只在整点显示
+ if (date.getMinutes() === 0) {
+ return `${date.getHours().toString().padStart(2, '0')}`;
+ }
+ return '';
+ },
+ rotate: 0,
+ color: '#666'
+ },
+ axisLine: {
+ lineStyle: {
+ color: '#e0e0e0'
+ }
+ },
+ axisTick: {
+ show: false
+ },
+ splitLine: {
+ show: false,
+ lineStyle: {
+ color: '#e0e0e0',
+ type: 'solid'
+ }
+ }
+ },
yAxis: [
- { type: 'value', name: 'mmHg', position: 'left', min: 0, max: 200 },
- { type: 'value', name: '次/分', position: 'right', min: 50, max: 120 }
+ {
+ type: 'value',
+ name: 'mmHg',
+ position: 'left',
+ min: 0,
+ max: 200,
+ interval: 20,
+ axisLabel: {
+ color: '#666'
+ },
+ axisLine: {
+ lineStyle: {
+ color: '#e0e0e0'
+ }
+ },
+ splitLine: {
+ show: true,
+ lineStyle: {
+ color: '#f0f0f0',
+ type: 'dashed'
+ }
+ }
+ },
+ {
+ type: 'value',
+ name: '次/分',
+ position: 'right',
+ min: 50,
+ max: 120,
+ interval: 10,
+ axisLabel: {
+ color: '#666'
+ },
+ axisLine: {
+ lineStyle: {
+ color: '#e0e0e0'
+ }
+ },
+ splitLine: {
+ show: false
+ }
+ }
],
series: [
{
name: '收缩压',
type: 'line',
- symbol: 'none',
+ symbol: 'circle',
+ symbolSize: 6,
lineStyle: { width: 2 },
- data: chartDataTable.map(item => item.systolic),
- itemStyle: { color: '#409eff' }
+ connectNulls: false,
+ smooth: false,
+ data: seriesMap.systolic,
+ itemStyle: {
+ color: '#409eff',
+ borderWidth: 1,
+ borderColor: '#fff'
+ },
+ markArea: {
+ silent: true,
+ itemStyle: {
+ color: 'rgba(128, 128, 128, 0.2)',
+ borderWidth: 0
+ },
+ data: nightAreas,
+ label: {
+ show: false
+ }
+ }
},
{
name: '舒张压',
type: 'line',
- symbol: 'none',
+ symbol: 'circle',
+ symbolSize: 6,
lineStyle: { width: 2 },
- data: chartDataTable.map(item => item.diastolic),
- itemStyle: { color: '#67c23a' }
+ connectNulls: false,
+ smooth: false,
+ data: seriesMap.diastolic,
+ itemStyle: {
+ color: '#67c23a',
+ borderWidth: 1,
+ borderColor: '#fff'
+ }
},
{
name: '心率',
type: 'line',
- symbol: 'none',
+ symbol: 'circle',
+ symbolSize: 6,
lineStyle: { width: 2 },
+ connectNulls: false,
+ smooth: false,
yAxisIndex: 1,
- data: chartDataTable.map(item => item.heartRate),
- itemStyle: { color: '#e6a23c' }
+ data: seriesMap.heartRate,
+ itemStyle: {
+ color: '#e6a23c',
+ borderWidth: 1,
+ borderColor: '#fff'
+ }
}
]
};
-
chart.setOption(option);
}
@@ -1826,31 +2065,59 @@
let normalCount, abnormalCount;
if (field === 'heartRate') {
- normalCount = data.filter(item => item[field] >= 60 && item[field] <= 100).length;
+ normalCount = data.filter(item => item[field] >=60 && item[field] <= 100).length;
abnormalCount = data.length - normalCount;
} else {
normalCount = data.filter(item => item[field] < threshold).length;
abnormalCount = data.length - normalCount;
}
- const normalPercent = data.length > 0 ? Math.round((normalCount / data.length) * 100) : 0;
- const abnormalPercent = 100 - normalPercent;
+ // 构建数据数组,只包含有数据的类别
+ const pieData = [];
+
+ // 只有当正常数据存在时才添加
+ if (normalCount > 0) pieData.push({
+ value: normalCount,
+ name: '正常',
+ itemStyle: { color: '#7fc7ff' }
+ });
+
+ // 只有当异常数据存在时才添加
+ if (abnormalCount > 0) pieData.push({
+ value: abnormalCount,
+ name: '异常',
+ itemStyle: { color: '#ff7f7f' }
+ });
+
+ // 如果没有任何数据,显示提示
+ if (pieData.length === 0) pieData.push({
+ value: 1,
+ name: '暂无数据',
+ itemStyle: { color: '#f0f0f0' }
+ });
const option = {
tooltip: {
trigger: 'item',
- formatter: '{b}: {c}次 ({d}%)'
+ formatter: function(params) {
+ if (params.name === '暂无数据') {
+ return '暂无数据';
+ }
+ return params.name + ': ' + params.value + '次 (' + params.percent + '%)';
+ }
},
series: [{
type: 'pie',
radius: '60%',
- data: [
- { value: normalCount, itemStyle: { color: '#7fc7ff' } },
- { value: abnormalCount, itemStyle: { color: '#ff7f7f' } }
- ],
+ data: pieData,
label: {
show: true,
- formatter: '{b}\n{c}次\n{d}%',
+ formatter: function(params) {
+ if (params.name === '暂无数据') {
+ return '暂无数据';
+ }
+ return params.name + '\n' + params.value + '次\n' + params.percent + '%';
+ },
fontSize: 10,
position: 'inside'
},
@@ -2063,23 +2330,41 @@
name: '收缩压',
type: 'line',
smooth: true,
+ symbol: 'circle',
+ symbolSize: 6, // 增加点的大小
data: hourlyData.map(d => d.systolic),
- itemStyle: { color: '#409eff' }
+ itemStyle: {
+ color: '#409eff',
+ borderWidth: 1,
+ borderColor: '#fff' // 添加白色边框使点更明显
+ }
},
{
name: '舒张压',
type: 'line',
smooth: true,
+ symbol: 'circle',
+ symbolSize: 6, // 增加点的大小
data: hourlyData.map(d => d.diastolic),
- itemStyle: { color: '#67c23a' }
+ itemStyle: {
+ color: '#67c23a',
+ borderWidth: 1,
+ borderColor: '#fff' // 添加白色边框使点更明显
+ }
},
{
name: '心率',
type: 'line',
smooth: true,
+ symbol: 'circle',
+ symbolSize: 6, // 增加点的大小
yAxisIndex: 1,
data: hourlyData.map(d => d.heartRate),
- itemStyle: { color: '#e6a23c' }
+ itemStyle: {
+ color: '#e6a23c',
+ borderWidth: 1,
+ borderColor: '#fff' // 添加白色边框使点更明显
+ }
}
]
};
@@ -2356,4 +2641,4 @@