Files
his/openhis-ui-vue3/src/views/inpatientNurse/tprsheet/compoents/details.vue
chenqi abc0674531 ```
docs(release-notes): 添加住院护士站划价功能说明和发版记录

- 新增住院护士站划价服务流程说明文档,详细描述了从参数预处理到结果响应的五大阶段流程
- 包含耗材类医嘱和诊疗活动类医嘱的差异化处理逻辑
- 添加完整的发版内容记录,涵盖新增菜单功能和各模块优化点
- 记录了住院相关功能的新增和门诊业务流程的修复
```
2025-12-25 14:13:14 +08:00

756 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div style="display: flex">
<el-button type="primary" style="margin-left: 20px" @click="increaseAdd('0')"
>变更体温单</el-button
>
<!-- <el-button type="primary" style="margin-left: 20px" @click="increaseAdd('1')">修改</el-button> -->
<!-- <el-button type="primary" style="margin-left: 20px" @click="increaseAdd('2')">查询</el-button> -->
</div>
<div class="main">
<template v-if="isEmpty">
<div class="empty">
<el-empty description="暂无数据" />
</div>
</template>
<template v-else>
<div class="business-temperature-sheet">
<div class="custom-tooltip">
<el-tooltip content="首页" placement="right-end">
<el-button
style="margin-left: 12px"
icon="Upload"
size="default"
type="primary"
@click="toFirst"
/>
</el-tooltip>
<el-tooltip content="上一页" placement="right-end">
<el-button
style="margin-left: 12px; margin-top: 15px"
icon="ArrowUpBold"
size="default"
type="primary"
@click="lastWeek"
/>
</el-tooltip>
<el-tooltip content="下一页" placement="right-end">
<el-button
style="margin-left: 12px; margin-top: 15px"
icon="ArrowDown"
size="default"
type="primary"
@click="nextWeek"
/>
</el-tooltip>
<el-tooltip content="尾页" placement="right-end">
<el-button
style="margin-left: 12px; margin-top: 15px"
icon="Download"
size="default"
type="primary"
@click="toEnd"
/>
</el-tooltip>
<el-tooltip content="打印本页" placement="right-end">
<el-button
style="margin-left: 12px; margin-top: 15px"
icon="Printer"
size="default"
type="primary"
@click="printPage"
/>
</el-tooltip>
</div>
</div>
<div class="sheet">
<div id="my_dataviz" ref="printRef" style="width: 100%; background-color: white" />
</div>
</template>
</div>
<el-drawer v-model="isOpenDraw" :direction="direction" size="100%" :with-header="false">
<template #default>
<AddAttr ref="attrRef" @onSearcTem="onSearch"></AddAttr>
</template>
<template #footer>
<div style="flex: auto">
<el-button @click="cancelClick">取消</el-button>
<el-button v-if="actionType == '2'" type="primary" @click="confirmClick">查询</el-button>
<el-button v-if="actionType !== '2'" type="primary" @click="confirmClick">保存</el-button>
</div>
</template>
</el-drawer>
</template>
<script setup>
import { init } from '@/action/nurseStation/temperatureSheet/line.js';
import { patientInfo } from '../../../inpatientDoctor/home/store/patient';
import { getVitalSignsInfo } from '../../tprChart/components/api';
import { nextTick, onMounted, watch } from 'vue';
import { getTemperatureType, temChar } from '../api/api';
import moment from 'moment';
import AddAttr from './addAttr.vue';
import cloneDeep from 'lodash.clonedeep';
import { ElMessage } from 'element-plus';
import html2pdf from 'html2pdf.js';
const attrRef = ref('');
const actionType = ref('');
const printRef = ref(null);
const isTemplate = ref(false);
const data1 = reactive({
patientInfo: {},
grParamBOS: {
age: '',
birth: '',
cwh: '',
hosNum: '',
inDate: '',
inDiagName: '',
name: '',
// 科室
deptName: '',
operaDays: '',
sex: '',
weekNo: '',
beginDate: '',
hospDays: '',
total: '',
hospDate: '',
operaDate: '',
outdate: '',
},
rows: [],
types: [],
});
const isOpenDraw = ref(false);
const week = ref(0);
const patientId = ref('');
const patientData = ref({});
const integerPoints = [2, 6, 10, 14, 18, 22];
const closestPoint = ref(null);
const patientList = ref([]);
const chargeLoading = ref(false);
const addTprDialogRef = ref(null);
const definitionId = ref(''); //体温单类型
const isEmpty = ref(true);
const objTest = {
hospDate: '2025-11-20T08:13:00',
operaDate: null,
outdate: null,
temperaturePulses: [
{
chartsSmalls: [
{
collectionMode: null,
date: '2025-11-20',
times: '10:00:00',
typeCode: '9500',
typeValue: '入科,08:13',
weekNo: 1,
orderByDateTimes: '2025-11-20 08:13:00',
id: 'c3bafb02-4609-4b53-b307-ad6767f9ba9b',
},
],
weekNo: 1,
},
{
chartsSmalls: [
{
collectionMode: 1,
date: '2025-11-20',
times: '10:00:00',
typeCode: '003',
typeValue: '36.3',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-20',
times: '10:00:00',
typeCode: '002',
typeValue: '90',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-20',
times: '10:00:00',
typeCode: '001',
typeValue: '18',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
],
weekNo: 1,
},
{
chartsSmalls: [
{
collectionMode: 1,
date: '2025-11-20',
times: '14:00:00',
typeCode: '003',
typeValue: '36.6',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-20',
times: '14:00:00',
typeCode: '002',
typeValue: '84',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-20',
times: '14:00:00',
typeCode: '001',
typeValue: '20',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
],
weekNo: 1,
},
{
chartsSmalls: [
{
collectionMode: 1,
date: '2025-11-20',
times: '18:00:00',
typeCode: '003',
typeValue: '36.5',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-20',
times: '18:00:00',
typeCode: '002',
typeValue: '88',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-20',
times: '18:00:00',
typeCode: '001',
typeValue: '20',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
],
weekNo: 1,
},
{
chartsSmalls: [
{
collectionMode: 1,
date: '2025-11-21',
times: '06:00:00',
typeCode: '003',
typeValue: '36.5',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-21',
times: '06:00:00',
typeCode: '002',
typeValue: '88',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-21',
times: '06:00:00',
typeCode: '001',
typeValue: '18',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-21',
times: '06:00:00',
typeCode: '016',
typeValue: '2',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
],
weekNo: 1,
},
{
chartsSmalls: [
{
collectionMode: 1,
date: '2025-11-21',
times: '10:00:00',
typeCode: '003',
typeValue: '36.4',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-21',
times: '10:00:00',
typeCode: '002',
typeValue: '86',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-21',
times: '10:00:00',
typeCode: '001',
typeValue: '18',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
],
weekNo: 1,
},
{
chartsSmalls: [
{
collectionMode: 1,
date: '2025-11-21',
times: '14:00:00',
typeCode: '003',
typeValue: '36.5',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-21',
times: '14:00:00',
typeCode: '002',
typeValue: '82',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: 1,
date: '2025-11-21',
times: '14:00:00',
typeCode: '001',
typeValue: '18',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
],
weekNo: 1,
},
],
others: [
{
collectionMode: null,
date: '2025-11-20',
times: null,
typeCode: '030',
typeValue: '卧床',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: null,
date: '2025-11-20',
times: null,
typeCode: '009',
typeValue: '卧床',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: null,
date: '2025-11-20',
times: '14:00:00',
typeCode: '008',
typeValue: '112/54,',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: null,
date: '2025-11-20',
times: '6:00:00',
typeCode: '008',
typeValue: '110/54,',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: null,
date: '2025-11-20',
times: null,
typeCode: '011',
typeValue: '3000/22h',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: null,
date: '2025-11-20',
times: null,
typeCode: '004',
typeValue: 'C',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
{
collectionMode: null,
date: '2025-11-20',
times: null,
typeCode: '005',
typeValue: '0',
weekNo: 1,
orderByDateTimes: null,
id: null,
},
],
};
/**
* 点击患者列表行 获取患者体温单数据
*/
const inputData = ref({});
onMounted(() => {
console.log(
'onMountedonMountedonMountedonMountedonMountedonMounted========>',
JSON.stringify(patientInfo.value)
);
if (patientInfo.value) {
getTemRequset();
} else {
isEmpty.value = true;
}
});
watch(patientInfo, (newValue) => {
console.log('patientInfo========>', JSON.stringify(patientInfo.value));
isEmpty.value = false;
getTemRequset();
});
// 1.获取体温单类型
// 获取体温单类型
const getTemRequset = async () => {
const res = await getTemperatureType({ menuEnum: 4 });
//默认选中第一个
if (res?.data?.length > 0) {
const obj = res.data[0];
definitionId.value = obj.id;
viewPatient(patientInfo.value);
isTemplate.value = true;
} else {
isTemplate.value = false;
}
};
// 2.根据患者id和病历id获取详情绘制图表
function viewPatient(row = {}) {
chargeLoading.value = true;
patientId.value = row.patientId; // 接收子组件传来的数据
data1.patientInfo = row;
data1.grParamBOS.patientId = row.patientId;
data1.grParamBOS.age = row.age;
data1.grParamBOS.birth = row.birthDate;
// data1.grParamBOS.cwh = row.bedLocationId_dictText;
data1.grParamBOS.cwh = row.bedName;
data1.grParamBOS.deptName = row.wardName;
data1.grParamBOS.hosNum = row.encounterId;
data1.grParamBOS.sex = row.genderEnum_enumText;
// 入科时间存在的场合使用入科时间
data1.grParamBOS.inDate = row.admissionDate;
data1.grParamBOS.name = row.patientName;
data1.grParamBOS.operaDays = null;
data1.grParamBOS.weekNo = null;
data1.grParamBOS.beginDate = getCurrentDate();
data1.grParamBOS.hospDays = null;
data1.grParamBOS.total = null;
getSignsCharts();
}
function getSignsCharts() {
// data1.grParamBOS.hospDate =
// objTest.hospDate && objTest.hospDate.length > 10
// ? objTest.hospDate.substring(0, 10)
// : objTest.hospDate;
// data1.grParamBOS.operaDate = objTest.operaDate;
// data1.grParamBOS.outdate = objTest.outdate;
// data1.rows = objTest.temperaturePulses.map((item) => ({
// rowBOS: item.chartsSmalls,
// weekNo: item.weekNo - 1,
// }));
// data1.types = objTest.others.map((item) => ({
// ...item, // 保留其他属性
// weekNo: item.weekNo - 1, // 将 weekNo 减 1
// }));
// console.log('体温单查询this.data1', data1);
// init1(data1);
const params = {
patientId: patientId.value ?? '',
encounterId: patientInfo.value.encounterId ?? '',
definitionId: definitionId.value,
};
temChar(params).then((response) => {
console.log('体温单返回值', JSON.stringify(response));
if (response.code === 200) {
data1.grParamBOS.hospDate =
response.data.hospDate && response.data.hospDate.length > 10
? response.data.hospDate.substring(0, 10)
: response.data.hospDate;
data1.grParamBOS.operaDate = response.data.operaDate;
data1.grParamBOS.outdate = response.data.outdate;
data1.rows = response.data.temperaturePulses.map((item) => ({
rowBOS: item.chartsSmalls,
weekNo: item.weekNo - 1,
}));
data1.types = response.data.others.map((item) => ({
...item, // 保留其他属性
weekNo: item.weekNo - 1, // 将 weekNo 减 1
}));
console.log('体温单查询this.data1', data1);
init1(data1);
}
});
}
function init1(data) {
console.log('体温单初始化', data);
const inDate = data.grParamBOS.hospDate;
const outdate = data.grParamBOS.outdate;
// week.value = Math.floor(dateDiff(inDate, outdate) / 10);
week.value = Math.floor(dateDiff(inDate, outdate) / 7);
setTemperatureComp(data);
}
// 体温单控件数据设置
function setTemperatureComp(data) {
console.log(JSON.stringify(data), '体温单控件数据设置');
if (data !== undefined) {
inputData.value = data;
}
const inDate = inputData.value.grParamBOS.hospDate;
const outdate = inputData.value.grParamBOS.outdate;
const begin = moment(new Date(inDate))
.add(week.value * 7, 'day')
.format('YYYY-MM-DD HH:mm:ss');
inputData.value.grParamBOS.weekNo = week.value;
inputData.value.grParamBOS.beginDate = begin;
inputData.value.grParamBOS.hospDays = week.value * 7;
inputData.value.grParamBOS.total = Math.floor(dateDiff(inDate, outdate) / 7);
console.log('inputData============>', JSON.stringify(inputData));
init(sliceData(inputData.value));
}
function dateDiff(start, end) {
let diffTime = start ? moment(new Date()).diff(moment(start.substring(0, 10))) / 1000 : start;
if (end) {
diffTime = moment(end.substring(0, 10)).diff(moment(start.substring(0, 10))) / 1000;
}
if (diffTime > 24 * 3600) {
return Math.floor(diffTime / (24 * 3600));
} else if (diffTime > 3600) {
return '0';
} else {
return '0';
}
}
function getCurrentDate() {
// 获取当前日期
const today = new Date();
const year = today.getFullYear();
const month = (today.getMonth() + 1).toString().padStart(2, '0'); // 月份从0开始所以需要加1
const day = today.getDate().toString().padStart(2, '0');
return `${year}-${month}-${day}`; // 格式化为 YYYY-MM-DD
}
// 拆分当前周数据
function sliceData(data) {
const rows = data.rows.filter((item) => item.weekNo === week.value);
const types = data.types.filter((item) => item.weekNo === week.value);
// const datas = JSON.parse(JSON.stringify(data));
const datas = cloneDeep(data);
datas.rows = rows;
datas.types = types;
console.log(datas, '666666666666666666');
return datas;
}
function toFirst() {
week.value = 0;
setTemperatureComp();
}
function toEnd() {
week.value = inputData.value.grParamBOS.total;
setTemperatureComp();
}
function lastWeek() {
week.value--;
if (week.value < 0) {
week.value = 0;
}
setTemperatureComp();
}
function nextWeek() {
week.value = Number(week.value) + 1;
if (week.value > inputData.value.grParamBOS.total) {
week.value = inputData.value.grParamBOS.total;
}
setTemperatureComp();
}
// 新增
const increaseAdd = (type) => {
if (!patientInfo.value) {
ElMessage({
type: 'error',
message: '请选择患者',
});
return;
}
if (!isTemplate.value) {
ElMessage({
type: 'error',
message: '体温单未配置,请联系管理员',
});
return;
}
isOpenDraw.value = true;
nextTick(() => {
actionType.value = type;
if (attrRef.value) {
attrRef.value.onActionEdit(type);
}
});
};
// 打印体温单
function printPage() {
const element = printRef.value;
if (!element) {
console.error('未找到可打印的内容');
return;
}
// 创建一个克隆元素用于打印,避免修改原 DOM
const clone = element.cloneNode(true);
// 设置宽度为 A4780px ≈ 210mm高度自适应
clone.style.transform = 'scale(0.7)';
clone.style.transformOrigin = 'top left';
clone.style.width = 'calc(210mm * 1.11)';
clone.style.height = 'calc(297mm * 1.11)';
clone.style.marginLeft = '50px';
// 插入到 body 中以便 html2pdf 渲染
document.body.appendChild(clone);
// 设置 html2pdf 配置
const opt = {
margin: 0,
filename: '体温单.pdf',
image: { type: 'jpeg', quality: 1 },
html2canvas: { scale: 2, useCORS: true }, // 启用跨域资源支持
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
pagebreak: { mode: ['avoid-all'] },
onclone: (clonedDoc) => {
const chart = clonedDoc.getElementById(clone.id);
if (chart) {
chart.style.width = '210mm'; // 强制 A4 宽度
chart.style.margin = '0 auto';
}
},
};
// 导出为 PDF 并打印
html2pdf()
.from(clone)
.set(opt)
.toPdf()
.get('pdf')
.then(function (pdf) {
pdf.autoPrint(); // 自动打印
window.open(pdf.output('bloburl'), '_blank'); // 在新窗口打开 PDF以便用户确认
})
.finally(() => {
document.body.removeChild(clone); // 清理临时元素
});
}
const confirmClick = () => {
attrRef.value.saveData();
};
const cancelClick = () => {
isOpenDraw.value = false;
};
// 子组件查询方法
const onSearch = (value) => {
getTemRequset();
isOpenDraw.value = false;
};
</script>
<style scoped>
.main {
height: 100%;
display: flex;
flex-direction: row;
.empty {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.business-temperature-sheet {
height: 100%;
width: 100px;
.custom-tooltip {
height: 100%;
margin-left: 10px;
margin-right: 10px;
display: flex;
flex-direction: column;
justify-content: center;
}
}
.sheet {
flex: 1;
/* background: red; */
}
}
</style>