海信医疗-远程超声管理平台-信创国产化
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

222 lines
6.7 KiB

<template>
<el-dialog
title="打印预览"
:visible.sync="visible"
width="800px"
:close-on-click-modal="false"
>
<!-- 外层容器预留底部footer高度防止遮挡 -->
<div id="print" class="print-container">
<div
v-if="templateContent && templateLoaded"
v-html="renderedTemplate"
class="report-body"
/>
<div v-else class="loading">模板加载中...</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="visible = false">取 消</el-button>
<el-button type="primary" @click="handlePrint" v-print="'#print'">
打 印
</el-button>
</div>
</el-dialog>
</template>
<script>
import {
patientSexList,
patientAgeTypeList,
postReportPrint,
} from "@/api/cases/index.js";
import { mapGetters } from "vuex";
export default {
name: "UltrasoundReportPrint",
data() {
return {
visible: false,
report: {},
templateContent: "",
templateLoaded: false,
patientSexList: patientSexList(),
patientAgeTypeList: patientAgeTypeList(),
};
},
computed: {
...mapGetters(["userInfo", "loginInfo", "netConfig"]),
renderedTemplate() {
if (!this.templateContent || !this.report) return "";
let content = this.templateContent;
const data = this.report;
// 占位符映射 + 空值兜底
const mappings = {
$$logo$$: this.renderLogo(),
$$checkbody$$: data.positions.length
? data.positions.map((item) => item.level2.name).join("|") +
(data.position_text ? "|" + data.position_text : "")
: data.position_text,
$$checknumber$$: data.id || "",
$$name$$: data.patient_name || "",
$$sex$$:
this.patientSexList.find((i) => i.value == data.patient_sex).label ||
"",
$$age$$:
data.patient_age + data.patient_age_type
? this.patientAgeTypeList.find(
(i) => i.value == data.patient_age_type
).label || ""
: "" || "",
$$examroom$$: data.exam_rooms.map((item) => item.name).join(", "),
$$requestdoctor$$: data.request_doctor || "",
$$pid$$: data.patient_id || "",
$$hospitalnumber$$: data.hospitalization_number || "",
$$areanumber$$: data.area_number || "",
$$bednumber$$: data.bed_number || "",
$$ctimgtable$$: this.renderImages(),
$$checkview$$: data.text_comment || "",
$$checkconclusion$$: data.text_conclusion || "",
$$reportor_sig$$: this.renderSignature(),
$$createtime$$: data.create_time || "",
$$creati$$: data.create_time || "",
};
// 转义$符号,安全全局替换
Object.keys(mappings).forEach((key) => {
const reg = new RegExp(key.replace(/\$/g, "\\$"), "g");
content = content.replace(reg, mappings[key]);
});
return content;
},
},
methods: {
async print(report) {
this.report = JSON.parse(JSON.stringify(report));
this.templateLoaded = false;
this.templateContent = "";
await this.loadTemplate();
this.visible = true;
},
async loadTemplate() {
const tpl = this.loginInfo?.report_tpl;
if (tpl) {
const templateUrl =
this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS + tpl;
try {
const res = await fetch(templateUrl);
if (res.ok) {
this.templateContent = await res.text();
this.templateLoaded = true;
return;
}
} catch (e) {
console.warn("远程模板加载失败");
}
}
await this.loadLocalTemplate();
this.templateLoaded = true;
},
async loadLocalTemplate() {
try {
const res = await fetch("/report-template.html");
this.templateContent = res.ok ? await res.text() : "";
} catch (e) {
console.error("本地模板加载失败", e);
this.templateContent = "";
}
},
renderLogo() {
const logoSrc = this.loginInfo?.report_logo;
if (!logoSrc) return "";
const baseUrl =
this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS || "";
// 关键:设置Logo高度和对齐方式,和第二张图一致
return `<img src="${baseUrl}${logoSrc}" style="float: left;height: 100px;width: auto;margin: 0 auto;display: block;" alt="医院logo"/>`;
},
renderImages() {
const images =
this.report.attachment?.filter((x) => x.showInDoc === 1) || [];
if (images.length === 0)
return '<div style="text-align:center;padding:20px;">未附超声图像</div>';
const baseUrl =
this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS || "";
let html =
'<div style="display:flex;flex-wrap:wrap;gap:10px;justify-content:center;">';
images.forEach((item) => {
html += `<img src="${baseUrl}${item.bucket_compress}/${item.object_compress}" style="width:100px;height:80px;object-fit:cover;">`;
});
return html + "</div>";
},
renderSignature() {
const sign = this.loginInfo?.signature;
if (!sign) return "";
const baseUrl =
this.$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS || "";
return `<img src="${baseUrl}${sign}" style="height:13px;vertical-align:middle;">`;
},
handlePrint() {
postReportPrint(this.report.id);
setTimeout(() => (this.visible = false), 300);
},
},
};
</script>
<style scoped lang="scss">
/* 预览容器核心 - 底部留出足够间距防止绝对定位footer被遮挡 */
.print-container {
position: relative;
/* 给底部footer预留高度正文内容永远不会盖住它 */
padding-bottom: 120px;
min-height: 600px;
box-sizing: border-box;
}
.report-body {
width: 100%;
font-family: "宋体", SimSun, sans-serif;
}
.loading {
text-align: center;
padding: 60px 0;
color: #999;
}
/* ========== 标准打印样式修复页眉页脚 ========== */
@media print {
@page {
size: A4;
margin: 15mm;
}
html,
body {
margin: 0;
padding: 0;
background: #fff;
}
/* 隐藏弹窗头部底部按钮栏 */
.el-dialog__header,
.el-dialog__footer {
display: none !important;
}
/* 打印时取消内边距还原真实报表 */
.print-container {
padding-bottom: 0 !important;
}
/* 打印时footer固定在页面底部不分页不遮挡 */
::v-deep .footer {
position: fixed !important;
bottom: 15mm !important;
left: 0;
width: 98% !important;
}
/* 清除code默认样式避免报告单样式错乱 */
::v-deep code {
background: transparent !important;
padding: 0 !important;
font-family: inherit !important;
}
}
</style>