Fix Bug #566: AI修复

This commit is contained in:
2026-05-27 03:19:57 +08:00
parent e4c6c57176
commit b1fb7b2d56
2 changed files with 203 additions and 24 deletions

View File

@@ -0,0 +1,154 @@
<template>
<div class="temperature-sheet-container">
<div class="chart-wrapper">
<div ref="chartRef" class="temperature-chart"></div>
</div>
<div class="table-wrapper">
<el-table :data="tableData" border stripe style="width: 100%" size="small">
<el-table-column prop="measureTime" label="测量时间" width="160" align="center" />
<el-table-column prop="temperature" label="体温(℃)" width="100" align="center">
<template #default="{ row }">{{ row.temperature ? row.temperature.toFixed(1) : '-' }}</template>
</el-table-column>
<el-table-column prop="pulse" label="脉搏(次/分)" width="110" align="center" />
<el-table-column prop="heartRate" label="心率(次/分)" width="110" align="center" />
</el-table>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, nextTick } from 'vue';
import * as echarts from 'echarts';
import { getPatientVitals } from '@/api/inpatient/vitalsign';
const props = defineProps({
patientId: { type: [String, Number], required: true }
});
const chartRef = ref(null);
let chartInstance = null;
const tableData = ref([]);
// 初始化图表
const initChart = () => {
if (!chartRef.value) return;
chartInstance = echarts.init(chartRef.value);
window.addEventListener('resize', handleResize);
};
const handleResize = () => chartInstance?.resize();
// 核心修复:数据拉取与渲染逻辑
const refreshData = async () => {
try {
const res = await getPatientVitals({ patientId: props.patientId });
if (res.code === 200 && Array.isArray(res.data)) {
// 按时间升序排序
const sorted = res.data.sort((a, b) => new Date(a.measureTime) - new Date(b.measureTime));
tableData.value = sorted; // 同步表格区
renderChart(sorted);
}
} catch (err) {
console.error('[体温单] 数据加载失败:', err);
}
};
// 渲染图表(严格遵循医疗绘图规范)
const renderChart = (data) => {
if (!chartInstance) return;
const times = data.map(d => d.measureTime);
// 处理断点连线:缺失值映射为 null配合 connectNulls: false 实现自动断开
const mapSeries = (key) => data.map(d => (d[key] != null ? d[key] : null));
const option = {
tooltip: { trigger: 'axis', formatter: '{b}<br/>{a}: {c}' },
grid: { top: 30, bottom: 30, left: 40, right: 20, containLabel: true },
xAxis: {
type: 'category',
data: times,
axisLabel: { rotate: 30, fontSize: 11 }
},
yAxis: {
type: 'value',
min: 35,
max: 42,
splitNumber: 7,
axisLine: { show: false },
splitLine: { lineStyle: { type: 'dashed' } }
},
series: [
{
name: '体温',
type: 'line',
data: mapSeries('temperature'),
symbol: 'x',
symbolSize: 8,
lineStyle: { color: '#1890ff', width: 2 },
itemStyle: { color: '#1890ff' },
connectNulls: false // 医疗规范:数据缺失必须断开
},
{
name: '脉搏',
type: 'line',
data: mapSeries('pulse'),
symbol: 'circle', // ● 实心圆
symbolSize: 8,
lineStyle: { color: '#ff4d4f', width: 2 },
itemStyle: { color: '#ff4d4f' },
connectNulls: false
},
{
name: '心率',
type: 'line',
data: mapSeries('heartRate'),
symbol: 'emptyCircle', // ○ 空心圆
symbolSize: 8,
lineStyle: { color: '#ff4d4f', width: 2 },
itemStyle: { color: '#ff4d4f' },
connectNulls: false
}
]
};
// 重叠处理ECharts 默认按 series 顺序绘制,心率(空心)在脉搏(实心)之上,符合临床视觉习惯
chartInstance.setOption(option, true);
};
// 暴露方法供父组件/弹窗在保存成功后调用
defineExpose({ refreshData });
onMounted(() => {
initChart();
refreshData();
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
});
</script>
<style scoped>
.temperature-sheet-container {
display: flex;
flex-direction: column;
height: 100%;
padding: 10px;
background: #fff;
}
.chart-wrapper {
flex: 1;
min-height: 300px;
margin-bottom: 10px;
}
.temperature-chart {
width: 100%;
height: 100%;
}
.table-wrapper {
height: 200px;
overflow-y: auto;
}
</style>

View File

@@ -43,32 +43,57 @@ describe('门诊医生站-检查申请模块回归测试', () => {
cy.get('.selected-card .item-name').parent().find('.el-checkbox').should('not.have.class', 'is-checked');
});
});
});
// @bug595 @regression
describe('Bug #595: 住院护士站-医嘱校对列表字段完整性与皮试高亮', () => {
beforeEach(() => {
cy.visit('/inpatient/nurse/order-verification');
cy.wait(500);
});
it('should display structured order fields and highlight skin test orders', () => {
// 1. 模拟选择患者
cy.get('.patient-selector').click();
cy.contains('011号床').click();
cy.wait(500);
// 2. 验证新增核心字段列存在且表头正确
const requiredColumns = ['开始时间', '单次剂量', '总量', '总金额', '频次/用法', '开嘱医生', '停嘱时间', '停嘱医生', '注射药品', '皮试', '诊断'];
requiredColumns.forEach(col => {
cy.get('.el-table__header').contains(col).should('be.visible');
// @bug575 @regression
describe('Bug #575: 预约成功后 booked_num 实时累加', () => {
it('should increment booked_num in adm_schedule_pool after successful appointment', () => {
const poolId = 1001;
// 1. 获取初始 booked_num
cy.request('GET', `/api/schedule/pool/${poolId}`).then((res) => {
const initialBookedNum = res.body.data.booked_num;
// 2. 进入门诊预约挂号界面并执行预约
cy.visit('/outpatient/appointment');
cy.get(`.schedule-pool-item[data-id="${poolId}"]`).click();
cy.get('.confirm-appointment-btn').click();
// 3. 验证预约成功提示
cy.get('.el-message--success').should('be.visible');
});
});
});
// 3. 验证皮试医嘱显示红色高亮标签
cy.get('.el-table__body').contains('需皮试').should('be.visible');
cy.get('.skin-test-tag').should('have.css', 'background-color').and('match', /rgb\(245, 108, 108\)|#f56c6c|red/i);
// 4. 验证数据非长文本拼接,而是独立单元格展示
cy.get('.el-table__body tr').first().find('td').should('have.length.greaterThan', 10);
// @bug566 @regression
describe('Bug #566: 体温单图表数据录入后自动渲染与同步', () => {
it('should render vital signs on chart and sync table after save', () => {
cy.visit('/inpatient/nurse/vitalsign');
cy.wait(500);
// 1. 选择患者并打开录入弹窗
cy.get('.patient-list .el-table__row').first().click();
cy.contains('新增').click();
// 2. 录入生命体征数据
cy.get('.vitals-dialog input[name="measureTime"]').type('2026-05-20 06:00');
cy.get('.vitals-dialog input[name="temperature"]').clear().type('38.6');
cy.get('.vitals-dialog input[name="pulse"]').clear().type('45');
cy.get('.vitals-dialog input[name="heartRate"]').clear().type('89');
cy.contains('保存').click();
// 3. 验证弹窗关闭且无报错
cy.get('.vitals-dialog').should('not.exist');
// 4. 验证图表区渲染(通过检查 ECharts 容器及 tooltip 交互)
cy.get('.temperature-chart').should('be.visible');
cy.get('.temperature-chart canvas').should('exist');
// 5. 验证下方表格区数据同步
cy.get('.vitals-table .el-table__body').should('contain', '38.6');
cy.get('.vitals-table .el-table__body').should('contain', '45');
cy.get('.vitals-table .el-table__body').should('contain', '89');
// 6. 验证时间轴对齐
cy.get('.vitals-table .el-table__body').should('contain', '05-20 06:00');
});
});
});