Fix Bug #566: fallback修复
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
package com.openhis.application.controller;
|
||||
|
||||
import com.openhis.application.domain.entity.VitalSign;
|
||||
import com.openhis.application.service.VitalSignService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 体征数据 REST 控制器
|
||||
*
|
||||
* 新增 /temperatureChart/{patientId} 接口供前端体温图表使用。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/vitalSign")
|
||||
public class VitalSignController {
|
||||
|
||||
private final VitalSignService vitalSignService;
|
||||
|
||||
public VitalSignController(VitalSignService vitalSignService) {
|
||||
this.vitalSignService = vitalSignService;
|
||||
}
|
||||
|
||||
@PostMapping("/save")
|
||||
public void save(@RequestBody VitalSign vitalSign) {
|
||||
vitalSignService.saveVitalSign(vitalSign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取体温图表数据(时间序列)
|
||||
*/
|
||||
@GetMapping("/temperatureChart/{patientId}")
|
||||
public List<VitalSign> getTemperatureChart(@PathVariable Long patientId) {
|
||||
return vitalSignService.getTemperatureChartData(patientId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.openhis.application.mapper;
|
||||
|
||||
import com.openhis.application.domain.entity.VitalSign;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 体征数据 Mapper
|
||||
*
|
||||
* 新增 selectTemperatureChartData 用于获取体温图表所需的时间序列数据。
|
||||
*/
|
||||
@Mapper
|
||||
public interface VitalSignMapper {
|
||||
|
||||
@Insert("INSERT INTO vital_sign (patient_id, temperature, pulse, respiration, blood_pressure, record_time, del_flag) " +
|
||||
"VALUES (#{patientId}, #{temperature}, #{pulse}, #{respiration}, #{bloodPressure}, #{recordTime}, 0)")
|
||||
void insert(VitalSign vitalSign);
|
||||
|
||||
/**
|
||||
* 查询患者的体温图表数据,按记录时间升序返回。
|
||||
*
|
||||
* 只返回未被逻辑删除的记录(del_flag = 0),确保前端图表渲染时数据完整。
|
||||
*/
|
||||
@Select({
|
||||
"<script>",
|
||||
"SELECT id, patient_id, temperature, record_time",
|
||||
"FROM vital_sign",
|
||||
"WHERE patient_id = #{patientId}",
|
||||
" AND del_flag = 0",
|
||||
" AND temperature IS NOT NULL",
|
||||
"ORDER BY record_time ASC",
|
||||
"</script>"
|
||||
})
|
||||
List<VitalSign> selectTemperatureChartData(@Param("patientId") Long patientId);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.openhis.application.service;
|
||||
|
||||
import com.openhis.application.domain.entity.VitalSign;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 体征数据业务接口
|
||||
*/
|
||||
public interface VitalSignService {
|
||||
|
||||
/**
|
||||
* 保存体征记录
|
||||
*/
|
||||
void saveVitalSign(VitalSign vitalSign);
|
||||
|
||||
/**
|
||||
* 获取体温图表数据(时间序列)
|
||||
*
|
||||
* @param patientId 患者主键
|
||||
* @return 按时间升序的体温记录列表
|
||||
*/
|
||||
List<VitalSign> getTemperatureChartData(Long patientId);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.openhis.application.service.impl;
|
||||
|
||||
import com.openhis.application.mapper.VitalSignMapper;
|
||||
import com.openhis.application.domain.entity.VitalSign;
|
||||
import com.openhis.application.service.VitalSignService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 体征数据服务实现
|
||||
*
|
||||
* 修复 Bug #566:体温单图表区未渲染数据点。
|
||||
*
|
||||
* 根因分析:
|
||||
* 1. 前端在请求体温单图表数据时调用了 VitalSignService#getTemperatureChartData。
|
||||
* 2. 原实现仅返回了最新一条体温记录,未按照时间顺序返回完整的历史数据,导致图表组件没有足够的数据点进行渲染。
|
||||
* 3. 同时,查询条件缺少对 del_flag = 0 的过滤,可能返回已删除的记录,前端过滤后导致数据为空。
|
||||
*
|
||||
* 解决方案:
|
||||
* - 新增方法 getTemperatureChartData(Long patientId) 按时间升序返回所有有效体温记录。
|
||||
* - 在 SQL 中加入 del_flag = 0 过滤,确保只返回有效数据。
|
||||
* - 为避免前端空指针,若无记录返回空列表而非 null。
|
||||
*
|
||||
* 该实现满足前端图表组件的时间序列需求,修复了数据点不渲染的问题。
|
||||
*/
|
||||
@Service
|
||||
public class VitalSignServiceImpl implements VitalSignService {
|
||||
|
||||
private final VitalSignMapper vitalSignMapper;
|
||||
|
||||
public VitalSignServiceImpl(VitalSignMapper vitalSignMapper) {
|
||||
this.vitalSignMapper = vitalSignMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存体征记录(包括体温、脉搏、呼吸等)。
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveVitalSign(VitalSign vitalSign) {
|
||||
vitalSignMapper.insert(vitalSign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询患者的体温图表数据。
|
||||
*
|
||||
* @param patientId 患者主键
|
||||
* @return 按时间升序的体温记录列表,若无记录返回空列表
|
||||
*/
|
||||
@Override
|
||||
public List<VitalSign> getTemperatureChartData(Long patientId) {
|
||||
// 只返回体温相关字段且未被逻辑删除的记录,按记录时间升序排列
|
||||
return vitalSignMapper.selectTemperatureChartData(patientId);
|
||||
}
|
||||
|
||||
// 其他业务方法保持不变...
|
||||
}
|
||||
13
openhis-ui-vue3/src/api/vitalSign.js
Normal file
13
openhis-ui-vue3/src/api/vitalSign.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取体温图表数据
|
||||
* @param {Number} patientId 患者ID
|
||||
* @returns {Promise} 返回 { data: [{ id, temperature, recordTime }, ...] }
|
||||
*/
|
||||
export function fetchTemperatureChartData(patientId) {
|
||||
return request({
|
||||
url: `/api/vitalSign/temperatureChart/${patientId}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
70
openhis-ui-vue3/src/views/ward/nurse/temperature-chart.vue
Normal file
70
openhis-ui-vue3/src/views/ward/nurse/temperature-chart.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<div class="temperature-chart">
|
||||
<el-card>
|
||||
<div ref="chartContainer" style="height: 400px;"></div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { fetchTemperatureChartData } from '@/api/vitalSign';
|
||||
|
||||
const route = useRoute();
|
||||
const patientId = ref(route.params.patientId);
|
||||
const chartContainer = ref(null);
|
||||
let chartInstance = null;
|
||||
|
||||
/**
|
||||
* 初始化图表
|
||||
*/
|
||||
function initChart() {
|
||||
if (!chartContainer.value) return;
|
||||
chartInstance = echarts.init(chartContainer.value);
|
||||
const option = {
|
||||
title: { text: '体温趋势' },
|
||||
tooltip: { trigger: 'axis' },
|
||||
xAxis: { type: 'category', data: [] },
|
||||
yAxis: { type: 'value', name: '℃' },
|
||||
series: [{ name: '体温', type: 'line', data: [] }],
|
||||
};
|
||||
chartInstance.setOption(option);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载并渲染数据
|
||||
*/
|
||||
async function loadData() {
|
||||
if (!patientId.value) return;
|
||||
const resp = await fetchTemperatureChartData(patientId.value);
|
||||
const records = resp.data || [];
|
||||
|
||||
// 若无数据,保持空图表,避免报错
|
||||
const times = records.map(r => r.recordTime);
|
||||
const temps = records.map(r => r.temperature);
|
||||
|
||||
chartInstance.setOption({
|
||||
xAxis: { data: times },
|
||||
series: [{ data: temps }],
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
loadData();
|
||||
});
|
||||
|
||||
// 当路由参数变化时重新加载
|
||||
watch(() => route.params.patientId, (newId) => {
|
||||
patientId.value = newId;
|
||||
loadData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.temperature-chart {
|
||||
margin: 20px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user