Fix Bug #566: AI修复

This commit is contained in:
2026-05-27 06:55:16 +08:00
parent 16d375473d
commit bce650a6ba
2 changed files with 180 additions and 21 deletions

View File

@@ -0,0 +1,160 @@
<template>
<div class="temperature-chart-wrapper">
<div class="toolbar">
<el-button id="add-vital-sign-btn" type="primary" @click="openAddDialog">新增体征</el-button>
<el-date-picker v-model="dateRange" type="daterange" @change="fetchChartData" />
</div>
<div class="temperature-chart-container" ref="chartRef" style="height: 400px; margin-bottom: 20px;"></div>
<el-table class="vital-sign-table" :data="tableData" border stripe>
<el-table-column prop="recordTime" label="时间" width="180" />
<el-table-column prop="temperature" label="体温(℃)" width="120" />
<el-table-column prop="pulse" label="脉搏(次/分)" width="120" />
<el-table-column prop="heartRate" label="心率(次/分)" width="120" />
</el-table>
<el-dialog v-model="dialogVisible" title="录入生命体征" width="500px">
<el-form :model="form" label-width="80px">
<el-form-item label="测量时间">
<el-date-picker v-model="form.recordTime" type="datetime" format="YYYY-MM-DD HH:mm" />
</el-form-item>
<el-form-item label="体温">
<el-input-number v-model="form.temperature" :precision="1" :step="0.1" />
</el-form-item>
<el-form-item label="脉搏">
<el-input-number v-model="form.pulse" :step="1" />
</el-form-item>
<el-form-item label="心率">
<el-input-number v-model="form.heartRate" :step="1" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, nextTick } from 'vue';
import * as echarts from 'echarts';
import { ElMessage } from 'element-plus';
import { saveVitalSign, getVitalSignChartData } from '@/api/inpatient/vitalSign';
const chartRef = ref(null);
let chartInstance = null;
const dialogVisible = ref(false);
const dateRange = ref([]);
const tableData = ref([]);
const form = ref({ recordTime: new Date(), temperature: null, pulse: null, heartRate: null });
const openAddDialog = () => { dialogVisible.value = true; };
const handleSave = async () => {
try {
const res = await saveVitalSign(form.value);
if (res.code === 200) {
ElMessage.success('保存成功');
dialogVisible.value = false;
// 修复 #566保存成功后立即刷新图表与表格数据无需手动刷新
await fetchChartData();
}
} catch (err) {
ElMessage.error('保存失败');
}
};
const fetchChartData = async () => {
try {
const [start, end] = dateRange.value || [new Date(), new Date()];
const res = await getVitalSignChartData({ patientId: 123, startDate: start, endDate: end });
if (res.code === 200) {
const rawData = res.data || [];
// 同步表格数据
tableData.value = rawData.map(item => ({
recordTime: item.recordTime,
temperature: item.temperature ?? '-',
pulse: item.pulse ?? '-',
heartRate: item.heartRate ?? '-'
}));
renderChart(rawData);
}
} catch (err) {
console.error('获取体温单数据失败', err);
}
};
const renderChart = (data) => {
if (!chartInstance) {
chartInstance = echarts.init(chartRef.value);
}
// 提取时间轴
const xAxisData = data.map(d => d.recordTime);
// 构建系列数据,缺失值填 null 触发断点逻辑
const tempData = data.map(d => d.temperature ?? null);
const pulseData = data.map(d => d.pulse ?? null);
const hrData = data.map(d => d.heartRate ?? null);
const option = {
tooltip: { trigger: 'axis' },
legend: { data: ['体温', '脉搏', '心率'], bottom: 0 },
grid: { left: '3%', right: '4%', bottom: '10%', containLabel: true },
xAxis: { type: 'category', data: xAxisData, axisLabel: { rotate: 30 } },
yAxis: { type: 'value', name: '数值' },
series: [
{
name: '体温',
type: 'line',
data: tempData,
symbol: 'rect', // 映射为 'x' 视觉效果
symbolRotate: 45,
symbolSize: 8,
itemStyle: { color: '#1890ff' },
lineStyle: { color: '#1890ff', width: 2 },
connectNulls: false // 修复 #566数据缺失自动断开连线严禁跨时段强行连接
},
{
name: '脉搏',
type: 'line',
data: pulseData,
symbol: 'circle', // 映射为 '●'
symbolSize: 8,
itemStyle: { color: '#ff4d4f' },
lineStyle: { color: '#ff4d4f', width: 2 },
connectNulls: false
},
{
name: '心率',
type: 'line',
data: hrData,
symbol: 'circle', // 映射为 '○'
symbolSize: 8,
itemStyle: { color: '#ff4d4f', borderColor: '#ff4d4f', borderWidth: 2, fill: 'transparent' },
lineStyle: { color: '#ff4d4f', width: 2 },
connectNulls: false
}
]
};
chartInstance.setOption(option, true);
};
onMounted(() => {
fetchChartData();
window.addEventListener('resize', () => chartInstance?.resize());
});
onUnmounted(() => {
window.removeEventListener('resize', () => chartInstance?.resize());
chartInstance?.dispose();
});
</script>
<style scoped>
.temperature-chart-wrapper { padding: 20px; background: #fff; }
.toolbar { display: flex; gap: 10px; margin-bottom: 15px; align-items: center; }
</style>