病例库-问题修复

main
ysn 6 days ago
parent 605eecad17
commit 6ad7dbad6e
  1. 97
      public/report-template.html
  2. 17
      src/api/cases/index.js
  3. 14
      src/views/cases/components/CaseFormDialog.vue
  4. 390
      src/views/cases/components/UltrasoundReportPrint.vue
  5. 784
      src/views/cases/detail.vue
  6. 31
      src/views/cases/index.vue

@ -0,0 +1,97 @@
<html>
<head>
<meta content="text/html; charset=UTF-8">
<style type="text/css">
.footer{
position:absolute;
bottom:20px;
width: 98%;
}
</style>
</head>
<body>
<div align="left">
$$logo$$
<h1 align="center"> 青岛海信医疗设备股份有限公司 </h1>
<h2 align="center"> 彩色多普勒超声检查报告单 </h2>
</div>
<div style="margin-top:15px; ">
<table width="98%" align="left" style="border-color: red">
<tbody>
<tr>
<td style="font-size: 12pt;"><b>超声部位:</b> $$checkbody$$</td>
<td align="right" style="font-size: 12pt;"><b>检查号:</b> $$checknumber$$</td>
</tr>
</tbody>
</table>
<hr style="height:2px;border:none;border-top:2px solid #000000;" width="100%/">
</div>
<div style="margin-top:10px; ">
<table width="100%" align="left" style="margin-bottom: 10px; padding-bottom: 20px; border-color: red">
<tbody>
<tr>
<td style="font-size: 12pt;"><b>姓名:</b> $$name$$</td>
<td style="font-size: 12pt;"><b>性别:</b> $$sex$$ <b>年龄:</b> $$age$$</td>
<td style="font-size: 12pt;"><b>科别:</b> $$examroom$$</td>
<td style="font-size: 12pt;"><b>申请医师:</b> $$requestdoctor$$</td>
</tr>
<tr><td></td></tr>
<tr>
<td style="font-size: 12pt;"><b>病历号:</b> $$pid$$ </td>
<td style="font-size: 12pt;"><b>住院号:</b> $$hospitalnumber$$ </td>
<td style="font-size: 12pt;"><b>病区号:</b> $$areanumber$$ </td>
<td style="font-size: 12pt;"><b>床位号:</b> $$bednumber$$ </td>
</tr>
</tbody>
</table>
<hr style="height:2px;border:none;border-top:2px solid #000000;margin-bottom: 15px; width: 100%;">
</div>
<div style="margin-bottom:25px; " align="center" width="100%">
$$ctimgtable$$
<hr style="height:2px;border:none;border-top:2px solid #000000;margin-top: 15px;width: 100%;">
</div>
<div style="margin-top:25px; width: 100%; " align="center">
<table width="100%" align="center">
<tbody>
<tr>
<td style="font-size: 12pt;"><b>超声所见</b></td>
</tr>
<tr>
<td style="padding-top:16px;padding-left:36px;font-size: 12pt;"><code>$$checkview$$</code></td>
</tr>
</tbody>
</table>
</div>
<div style=" margin-top:50px; width:100%; " align="center">
<table width="100%" align="center">
<tbody>
<tr>
<td style="font-size: 12pt;"><b>超声提示</b></td>
</tr>
<tr>
<td style="padding-top:16px;padding-left:36px;font-size: 12pt;"><code>$$checkconclusion$$</code></td>
</tr>
</tbody>
</table>
</div>
<div class="footer">
<hr style="height:2px;border:none;border-top:2px solid #000000;" width="100%/">
<table width="100%" align="center">
<tbody>
<tr>
<td valign="bottom" style="font-size: 12pt;"><b>青岛海信医疗设备股份有限公司</b></td>
<td valign="bottom" style="font-size: 12pt;"><b>诊断医师:</b> $$reportor_sig$$ </td>
<td valign="bottom" style="font-size: 12pt;"><b>检查日期:</b> $$createtime$$</td>
</tr>
</tbody>
</table>
<table width="100%" align="left">
<tbody>
<tr>
<td style="font-size: 12pt;">仅供临床参考,不作证明材料!</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

@ -121,6 +121,15 @@ export function postReportViewers(data) {
data
})
}
// 审批操作(通过/驳回)
export function postReportReview(data) {
return request({
url: '/report/review',
method: 'post',
data
})
}
// <EFBFBD>病例库-修改
export function postReportEdit(data) {
return request({
@ -129,6 +138,14 @@ export function postReportEdit(data) {
data
})
}
// 打印
export function postReportPrint(data) {
return request({
url: '/report/print',
method: 'post',
data
})
}
// 修改预约时间
export function postReportTimeSectionEdit(data) {
return request({

@ -392,10 +392,16 @@ export default {
},
],
patient_age: [
{ required: true, message: "年龄不能为空", trigger: "change" },
{ required: true, message: "年龄不能为空", trigger: "blur" },
{
type: "number",
min: 0,
message: "年龄不能为负数",
trigger: "blur",
},
],
patient_age_type: [
{ required: true, message: "年龄类型不能为空", trigger: "change" },
{ required: true, message: "年龄类型不能为空", trigger: "blur" },
],
patient_sex: [
{ required: true, message: "性别不能为空", trigger: "change" },
@ -495,9 +501,11 @@ export default {
postReportTimeSections({ exam_room_id: exam_rooms_id }).then(
(response) => {
this.timeSectionList = response.data || [];
if (this.timeSectionList.length > 0) {
if (this.form.id == undefined && this.timeSectionList.length > 0) {
this.form.time_section = this.timeSectionList[0];
console.log(this.form.time_section);
}
console.log(this.form.time_section);
}
);
},

@ -5,189 +5,14 @@
width="800px"
:close-on-click-modal="false"
>
<div id="print">
<el-form ref="form" :model="report" label-width="90px" class="report-form">
<el-row>
<el-col :span="4">
<img
src="@/assets/images/cases/logo.jpg"
alt="医院logo"
style="width: 40px"
/>
</el-col>
<el-col :span="20" style="text-align: center">
<h2 style="margin: 0">海伦普济医院</h2>
<h3 style="margin: 4px 0 0; font-weight: normal">
彩色多普勒超声检查报告单
</h3>
</el-col>
</el-row>
<el-row style="border-bottom: 1px solid #333; margin: 6px 0">
<el-col :span="16">
<el-form-item label="超声部位" prop="positions">
{{
report.positions.length
? report.positions.map((item) => item.level2.name).join("|") +
(report.position_text ? "|" + report.position_text : "")
: report.position_text
}}
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="检查号">
{{ report.id }}
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-form-item label="患者姓名" prop="patient_name">
{{ report.patient_name }}
</el-form-item>
</el-col>
<el-col :span="3">
<el-form-item label="性别" prop="patient_sex">
{{
report.patient_sex
? patientSexList.find((i) => i.value == report.patient_sex)
.label || ""
: ""
}}
</el-form-item>
</el-col>
<el-col :span="3">
<el-form-item label="年龄" prop="patient_age" label-width="60px">
{{ report.patient_age }}
{{
report.patient_age_type
? patientAgeTypeList.find(
(i) => i.value == report.patient_age_type
).label || ""
: ""
}}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="科别" prop="exam_rooms">
{{ report.exam_rooms.map((i) => i.name).join("|") }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="申请医师" prop="request_doctor">
{{ report.request_doctor }}
</el-form-item>
</el-col>
</el-row>
<el-row style="border-bottom: 1px solid #333; margin: 6px 0">
<el-col :span="6">
<el-form-item label="门诊号" prop="outpatient_number">
{{ report.outpatient_number }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="住院号" prop="hospitalization_number">
{{ report.hospitalization_number }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="病区号" prop="area_number">
{{ report.area_number }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="床位号" prop="bed_number">
{{ report.bed_number }}
</el-form-item>
</el-col>
</el-row>
<el-row style="border-bottom: 1px solid #333; margin: 6px 0">
<el-col :span="24">
<div
v-if="
report.attachment &&
report.attachment.filter((x) => x.showInDoc === 1).length > 0
"
>
<el-row :gutter="10">
<el-col
:span="6"
v-for="(item, idx) in report.attachment.filter(
(x) => x.showInDoc === 1
)"
:key="idx"
>
<el-form-item>
<el-image
:src="
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
item.bucket_compress +
'/' +
item.object_compress
"
fit="cover"
:preview-src-list="[
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
item.bucket_compress +
'/' +
item.object_compress,
]"
style="width: 100px; height: 80px"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<el-form-item label="未附超声图像" label-width="120px" v-else />
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="超声所见">
<el-input
v-model="report.text_comment"
type="textarea"
:rows="9"
:disabled="report.status != 1 && report.status != 5"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="检查结论">
<el-input
v-model="report.text_conclusion"
type="textarea"
:rows="4"
:disabled="report.status != 1 && report.status != 5"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
style="margin-top: 120px; border-top: 1px solid #333; margin: 6px 0"
>
<el-col :span="8">
<el-form-item
label="青岛海信医疗设备股份有限公司"
label-width="200"
/>
<el-form-item label="" label-width="0">
仅供临床参考,不作证明材料!
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="诊断医师">
{{ report.reporter_name }}
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="检查日期">
{{ report.create_time }}
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 外层容器预留底部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>
@ -198,53 +23,200 @@
</el-dialog>
</template>
<script>
import { patientSexList, patientAgeTypeList } from "@/api/cases/index.js";
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: {
print(report) {
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() {
let print = document.getElementById("#printContent");
// print.title = this.form.personName + "";
print.extraHead =
'<meta http-equiv="Content-Language"content="zh-cn"/>,<style> #printContent { height: auto !important;padding: 20px; width: 100%; } <style>';
print.extraCss = "https://www.google.com,https://www.google.com";
postReportPrint(this.report.id);
setTimeout(() => (this.visible = false), 300);
},
},
};
</script>
<!-- 去除打印的页眉页脚 -->
<style media="printContent" scoped lang="scss">
/*去除页眉页脚*/
@page {
size: auto;
/* auto is the initial value */
margin: 8mm;
<style scoped lang="scss">
/* 预览容器:核心 - 底部留出足够间距,防止绝对定位footer被遮挡 */
.print-container {
position: relative;
/* 给底部footer预留高度,正文内容永远不会盖住它 */
padding-bottom: 120px;
min-height: 600px;
box-sizing: border-box;
}
html {
/* background-color: #FFFFFF; */
margin: 0;
/* this affects the margin on the html before sending to printer */
.report-body {
width: 100%;
font-family: "宋体", SimSun, sans-serif;
}
body {
/* border: solid 1px blue ; */
margin: 10mm 15mm 10mm 15mm;
/* margin you want for the content */
.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>
</style>

@ -10,7 +10,9 @@
type="text"
icon="el-icon-plus"
@click="handleOpenFile"
:disabled="form.status != 1 && form.status != 5"
:disabled="
form.status != 1 && form.status != 5 && form.status != 15
"
>
新增
</el-button>
@ -44,7 +46,9 @@
type="text"
icon="el-icon-delete"
@click="handleDeleteImg(scope.row, scope.$index)"
v-if="form.status == 1 || form.status == 5"
v-if="
form.status == 1 || form.status == 5 || form.status == 15
"
>
删除
</el-button>
@ -72,8 +76,33 @@
? statusList.find((i) => i.value == form.status).label || ""
: ""
}}
{{
form.status && form.status == 15
? "(" +
statusList.find((i) => i.value == form.status).label +
"理由:" +
form.status_comment +
")"
: ""
}}
</span>
<div class="btn-group">
<el-button
type="text"
icon="el-icon-check"
@click="handlePass()"
v-if="form.status == 10 && form.reviewer_id == userInfo.id"
>
审核通过
</el-button>
<el-button
type="text"
icon="el-icon-close"
@click="handleReject()"
v-if="form.status == 10 && form.reviewer_id == userInfo.id"
>
审核拒绝
</el-button>
<el-button
type="text"
icon="el-icon-check"
@ -84,7 +113,7 @@
'暂存成功'
)
"
v-if="form.status == 1 || form.status == 5"
v-if="form.status == 1 || form.status == 5 || form.status == 15"
>
暂存
</el-button>
@ -98,7 +127,7 @@
'提交成功'
)
"
v-if="form.status == 1 || form.status == 5"
v-if="form.status == 1 || form.status == 5 || form.status == 15"
>
提交
</el-button>
@ -106,6 +135,7 @@
type="text"
icon="el-icon-printer"
@click="handlePrint"
v-if="form.status == 10 || form.status == 20"
>
打印
</el-button>
@ -117,243 +147,319 @@
</el-button>
</div>
</div>
<el-form
ref="form"
:model="form"
label-width="90px"
class="report-form"
>
<el-row :gutter="20" style="border-bottom: 2px solid #44931e">
<el-col :span="20">
<div
style="
text-align: center;
vertical-align: middle;
color: #606266;
box-sizing: border-box;
font-weight: 700;
"
>
远程超声检查报告
</div>
</el-col>
<el-col :span="4">
<el-form-item label="检查号">
{{ form.id }}
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="患者姓名" prop="patient_name">
{{ form.patient_name }}
</el-form-item>
</el-col>
<el-col :span="3">
<el-form-item label="性别" prop="patient_sex">
{{
form.patient_sex
? patientSexList.find((i) => i.value == form.patient_sex)
.label || ""
: ""
}}
</el-form-item>
</el-col>
<el-col :span="3">
<el-form-item
label="年龄"
prop="patient_age"
label-width="60px"
>
{{ form.patient_age }}
{{
form.patient_age_type
? patientAgeTypeList.find(
(i) => i.value == form.patient_age_type
).label || ""
: ""
}}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="申请医师" prop="request_doctor">
{{ form.request_doctor }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="病例号" prop="patient_id">
{{ form.patient_id }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="门诊号" prop="outpatient_number">
{{ form.outpatient_number }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="住院号" prop="hospitalization_number">
{{ form.hospitalization_number }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="病区号" prop="area_number">
{{ form.area_number }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="床位号" prop="bed_number">
{{ form.bed_number }}
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="检查设备" prop="equipments">
{{ form.equipments.map((i) => i.name).join("|") }}
</el-form-item>
</el-col>
<el-col :span="24" style="border-bottom: 2px solid #44931e">
<el-form-item label="检查部位" prop="positions">
{{
form.positions.length
? form.positions
.map((item) => item.level2.name)
.join("|") +
(form.position_text ? "|" + form.position_text : "")
: form.position_text
}}
</el-form-item>
</el-col>
<el-col
:span="6"
v-for="(item, idx) in form.attachment"
:key="idx"
v-show="item.showInDoc == 1"
style="margin-top: 10px"
>
<el-form-item>
<el-image
:src="
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
item.bucket_compress +
'/' +
item.object_compress
"
fit="cover"
:preview-src-list="[
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
item.bucket_compress +
'/' +
item.object_compress,
]"
style="width: 100px; height: 80px"
/>
</el-form-item>
</el-col>
<el-col :span="24" style="">
<el-form-item label="超声所见">
<el-input
v-model="form.text_comment"
type="textarea"
:rows="9"
:disabled="form.status != 1 && form.status != 5"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="检查结论">
<el-input
v-model="form.text_conclusion"
type="textarea"
:rows="4"
:disabled="form.status != 1 && form.status != 5"
/>
</el-form-item>
</el-col>
<el-col :span="24" v-if="form.experts.length != 0">
<el-form-item label="专家意见" />
</el-col>
<el-col
:span="24"
v-for="(item, idx) in form.experts"
:key="idx"
class="expert-item"
>
<el-form-item :label="item.expert_name">
<el-input
v-model="item.user_comment"
type="textarea"
:rows="3"
:disabled="form.status != 1 && form.status != 5"
/>
<div class="expert-btns">
<el-button
type="text"
icon="el-icon-document-copy"
:disabled="form.status != 1 && form.status != 5"
>
全部复制
</el-button>
<el-button
type="text"
icon="el-icon-check"
:disabled="form.status != 1 && form.status != 5"
v-if="item.confirm == 0"
<div class="report-container">
<div class="report-form">
<el-form ref="form" :model="form" label-width="90px">
<el-row :gutter="20" class="green-line" id="anchor-top">
<el-col :span="20">
<div
style="
text-align: center;
vertical-align: middle;
color: #606266;
box-sizing: border-box;
font-weight: 700;
"
>
一键同意
</el-button>
<el-button
type="text"
icon="el-icon-warning"
:disabled="form.status != 1 && form.status != 5"
远程超声检查报告
</div>
</el-col>
<el-col :span="4">
<el-form-item label="检查号">
{{ form.id }}
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="患者姓名" prop="patient_name">
{{ form.patient_name }}
</el-form-item>
</el-col>
<el-col :span="3">
<el-form-item label="性别" prop="patient_sex">
{{
form.patient_sex
? patientSexList.find(
(i) => i.value == form.patient_sex
).label || ""
: ""
}}
</el-form-item>
</el-col>
<el-col :span="3">
<el-form-item
label="年龄"
prop="patient_age"
label-width="60px"
>
待确认
</el-button>
</div>
</el-form-item>
</el-col>
{{ form.patient_age }}
{{
form.patient_age_type
? patientAgeTypeList.find(
(i) => i.value == form.patient_age_type
).label || ""
: ""
}}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="申请医师" prop="request_doctor">
{{ form.request_doctor }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="病例号" prop="patient_id">
{{ form.patient_id }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="门诊号" prop="outpatient_number">
{{ form.outpatient_number }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="住院号" prop="hospitalization_number">
{{ form.hospitalization_number }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="病区号" prop="area_number">
{{ form.area_number }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="床位号" prop="bed_number">
{{ form.bed_number }}
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="检查设备" prop="equipments">
{{ form.equipments.map((i) => i.name).join("|") }}
</el-form-item>
</el-col>
<el-col :span="24" class="green-line">
<el-form-item label="检查部位" prop="positions">
{{
form.positions.length
? form.positions
.map((item) => item.level2.name)
.join("|") +
(form.position_text ? "|" + form.position_text : "")
: form.position_text
}}
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col
:span="6"
v-for="(item, idx) in form.attachment"
:key="idx"
v-show="item.showInDoc == 1"
>
<el-form-item>
<el-image
:src="
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
item.bucket_compress +
'/' +
item.object_compress
"
fit="cover"
:preview-src-list="[
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
item.bucket_compress +
'/' +
item.object_compress,
]"
style="width: 100px; height: 80px"
/>
</el-form-item>
</el-col>
<el-col :span="24" id="anchor-comment">
<el-form-item label="超声所见">
<el-input
v-model="form.text_comment"
type="textarea"
:rows="9"
:disabled="
form.status != 1 &&
form.status != 5 &&
form.status != 15
"
/>
</el-form-item>
</el-col>
<el-col :span="24" id="anchor-conclusion">
<el-form-item label="检查结论">
<el-input
v-model="form.text_conclusion"
type="textarea"
:rows="4"
:disabled="
form.status != 1 &&
form.status != 5 &&
form.status != 15
"
/>
</el-form-item>
</el-col>
<el-col :span="24" id="anchor-expert">
<el-form-item label="专家意见" />
</el-col>
<el-col
:span="24"
v-for="(item, idx) in form.experts"
:key="idx"
class="expert-item"
>
<el-form-item :label="item.expert_name">
<el-input
v-model="item.user_comment"
type="textarea"
:rows="3"
:disabled="
form.status != 1 &&
form.status != 5 &&
form.status != 15
"
/>
<div class="expert-btns">
<el-button
type="text"
icon="el-icon-document-copy"
:disabled="
form.status != 1 &&
form.status != 5 &&
form.status != 15
"
>
全部复制
</el-button>
<el-button
type="text"
icon="el-icon-check"
:disabled="
form.status != 1 &&
form.status != 5 &&
form.status != 15
"
v-if="item.confirm == 0"
>
一键同意
</el-button>
<el-button
type="text"
icon="el-icon-warning"
:disabled="
form.status != 1 &&
form.status != 5 &&
form.status != 15
"
>
待确认
</el-button>
</div>
</el-form-item>
</el-col>
<el-col :span="18">
<el-form-item label="报告人">
{{ form.reporter_name }}
</el-form-item>
</el-col>
<el-col :span="18">
<el-form-item label="报告人">
{{ form.reporter_name }}
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="审核人">
<el-select
v-model="form.reviewer_id"
clearable
filterable
style="width: 100%"
:disabled="form.status != 1 && form.status != 5"
>
<el-option
v-for="item in reviewersList"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span style="float: left">{{ item.name }}</span>
<span
style="float: right; color: #8492a6; font-size: 13px"
<el-col :span="6">
<el-form-item label="审核人">
<el-select
v-model="form.reviewer_id"
clearable
filterable
style="width: 100%"
:disabled="
form.status != 1 &&
form.status != 5 &&
form.status != 15
"
>
{{ item.username }}
</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<el-checkbox
v-model="form.isPositive"
:disabled="form.status != 1 && form.status != 5"
>
阳性
</el-checkbox>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-option
v-for="item in reviewersList"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span style="float: left">{{ item.name }}</span>
<span
style="
float: right;
color: #8492a6;
font-size: 13px;
"
>
{{ item.username }}
</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" id="anchor-bottom">
<el-form-item>
<el-checkbox
:checked="form.negative === 0"
:disabled="
form.status != 1 &&
form.status != 5 &&
form.status != 15
"
@change="(val) => (form.negative = val ? 0 : 1)"
>
阳性
</el-checkbox>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<div class="anchor-nav">
<el-button type="text" />
<el-button
type="primary"
circle
@click="scrollToAnchor('anchor-top')"
>
</el-button>
<el-button
type="primary"
circle
@click="scrollToAnchor('anchor-comment')"
>
</el-button>
<el-button
type="primary"
circle
@click="scrollToAnchor('anchor-conclusion')"
>
</el-button>
<el-button
type="primary"
circle
@click="scrollToAnchor('anchor-expert')"
>
</el-button>
<el-button
type="primary"
circle
@click="scrollToAnchor('anchor-bottom')"
>
</el-button>
</div>
</div>
</el-card>
</el-col>
<!-- 右侧部位模板 + 片语 -->
@ -366,7 +472,9 @@
type="text"
icon="el-icon-plus"
@click="openTemplateDialog({})"
:disabled="form.status != 1 && form.status != 5"
:disabled="
form.status != 1 && form.status != 5 && form.status != 15
"
>
新增
</el-button>
@ -405,7 +513,9 @@
v-model="templateForm.id"
style="width: 100%"
@change="changeTemplate"
:disabled="form.status != 1 && form.status != 5"
:disabled="
form.status != 1 && form.status != 5 && form.status != 15
"
>
<el-option
v-for="item in templateList"
@ -428,7 +538,9 @@
icon="el-icon-check"
@click="handleComment"
style="float: right"
:disabled="form.status != 1 && form.status != 5"
:disabled="
form.status != 1 && form.status != 5 && form.status != 15
"
>
应用
</el-button>
@ -446,7 +558,9 @@
icon="el-icon-check"
@click="handleCnclusion"
style="float: right"
:disabled="form.status != 1 && form.status != 5"
:disabled="
form.status != 1 && form.status != 5 && form.status != 15
"
>
应用
</el-button>
@ -465,7 +579,9 @@
phrase: '',
})
"
:disabled="form.status != 1 && form.status != 5"
:disabled="
form.status != 1 && form.status != 5 && form.status != 15
"
>
新增
</el-button>
@ -484,7 +600,11 @@
<el-table-column label="操作" width="50">
<template slot-scope="scope">
<el-dropdown
:disabled="form.status != 1 && form.status != 5"
:disabled="
form.status != 1 &&
form.status != 5 &&
form.status != 15
"
@command="
(command) => handlePhraseCommand(command, scope.row)
"
@ -608,6 +728,28 @@
:min-select-count="1"
@confirm="handleShareToContacts"
/>
<!-- 驳回原因弹窗 -->
<el-dialog title="审核拒绝" :visible.sync="rejectDialogOpen" width="30%">
<el-form
:model="rejectReason"
label-width="80px"
ref="rejectFormRef"
:rules="rejectRules"
>
<el-form-item label="拒绝理由" prop="comment">
<el-input
type="textarea"
:rows="4"
v-model="rejectReason.comment"
placeholder="请输入拒绝理由"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="rejectDialogOpen = false"> </el-button>
<el-button type="primary" @click="confirmReject"> </el-button>
</div>
</el-dialog>
<!-- 打印预览弹窗 -->
<UltrasoundReportPrint ref="UltrasoundReportPrintRef" />
</div>
@ -635,6 +777,7 @@ import {
postReportPhraseCount,
postReportTemplateTree,
postReportPrint,
postReportReview,
} from "@/api/cases/index.js";
import { postMessagePushToUser } from "@/api/knowledge";
import { mapGetters } from "vuex";
@ -662,6 +805,8 @@ export default {
positions: [],
experts: [],
},
//
originalForm: null,
//
//
patientSexList: patientSexList(),
@ -710,6 +855,14 @@ export default {
// ====================== ======================
phraseTitle: "新增片语",
phraseOpen: false,
// ====================== ======================
rejectDialogOpen: false,
rejectReason: { comment: "" },
rejectRules: {
comment: [
{ required: true, message: "请输入审核拒绝理由", trigger: "blur" },
],
},
phraseList: [],
phraseForm: {
id: 0,
@ -727,6 +880,13 @@ export default {
this.getReportInfo(id);
},
methods: {
//
scrollToAnchor(anchorId) {
const element = document.getElementById(anchorId);
if (element) {
element.scrollIntoView({ behavior: "smooth", block: "start" });
}
},
//
handleOpenFile() {
this.$refs.fileInput.click();
@ -805,6 +965,44 @@ export default {
})
.catch(() => {});
},
//
handlePass() {
this.$modal
.confirm("点击确定,病例将审核通过")
.then(() => {
return postReportReview({
report_id: this.form.id,
status: 1,
comment: "",
});
})
.then(() => {
this.$modal.msgSuccess("审核通过成功");
this.getReportInfo(this.form.id);
})
.catch(() => {});
},
// -
handleReject() {
this.rejectReason.comment = "";
this.rejectDialogOpen = true;
},
//
confirmReject() {
this.$refs.rejectFormRef.validate((valid) => {
if (valid) {
postReportReview({
report_id: this.form.id,
status: 0,
comment: this.rejectReason.comment,
}).then(() => {
this.$modal.msgSuccess("审核拒绝成功");
this.rejectDialogOpen = false;
this.getReportInfo(this.form.id);
});
}
});
},
//
getReportInfo(id) {
if (id) {
@ -817,6 +1015,8 @@ export default {
this.form.attachment = Array.isArray(res.data.attachment)
? res.data.attachment
: [];
//
this.originalForm = JSON.parse(JSON.stringify(this.form));
this.getReviewers();
this.loadTemplateList();
this.loadPhraseList();
@ -855,7 +1055,7 @@ export default {
patient_type: form.patient_type || 0,
request_doctor: form.request_doctor || "",
reviewer_id: form.reviewer_id || 0,
negative: form.negative || 1,
negative: form.negative ? 0 : 1,
position_text: form.position_text || "",
text_comment: form.text_comment || "",
text_conclusion: form.text_conclusion || "",
@ -888,7 +1088,8 @@ export default {
});
})
.then(() => {
this.handleClose();
//
this.getReportInfo(form.id);
this.$modal.msgSuccess(msg);
})
.catch(() => {});
@ -897,13 +1098,46 @@ export default {
handlePrint() {
this.$refs.UltrasoundReportPrintRef.print(this.form);
},
//
isFormModified() {
if (!this.originalForm) return false;
//
const compareKeys = [
"text_comment",
"text_conclusion",
"reviewer_id",
"isPositive",
"attachment",
"experts",
];
for (const key of compareKeys) {
const current = this.form[key];
const original = this.originalForm[key];
// JSON
if (Array.isArray(current) || Array.isArray(original)) {
const currentStr = JSON.stringify(current || []);
const originalStr = JSON.stringify(original || []);
if (currentStr !== originalStr) {
return true;
}
} else if (current !== original) {
return true;
}
}
return false;
},
handleClose() {
this.$modal
.confirm("尚有修改未提交,是否确定退出")
.then(() => {
this.$router.back();
})
.catch(() => {});
//
if (this.isFormModified()) {
this.$modal
.confirm("尚有修改未提交,是否确定退出")
.then(() => {
this.$router.back();
})
.catch(() => {});
} else {
this.$router.back();
}
},
handleShare() {
this.$refs.createGroupDialogRef.show();
@ -1005,6 +1239,12 @@ export default {
.then((response) => {
if (response.code === 200 && response.data) {
this.partIdList = response.data;
if (
this.partIdList.length > 0 &&
this.newTemplateForm.id == undefined
) {
this.newTemplateForm.part_id = this.partIdList[0].child[0].id;
}
}
})
.catch((error) => {
@ -1132,6 +1372,15 @@ export default {
</script>
<style lang="scss" scoped>
.center-card,
.left-card {
::v-deep .el-card__body {
background: #f0f0f0 !important;
}
}
.el-form-item {
margin-bottom: 5px !important;
}
/* 内部滚动区域高度自适应 */
.report-form {
height: calc(100vh - 239px);
@ -1139,6 +1388,7 @@ export default {
overflow-x: hidden;
width: 100%;
box-sizing: border-box;
padding: 5px;
}
.template-form {
@ -1191,4 +1441,38 @@ export default {
justify-content: flex-end;
gap: 8px;
}
/* 绿色分割线 */
.green-line {
margin-left: 5px;
margin-right: 5px;
margin-bottom: 5px;
border-bottom: 2px solid #44931e;
}
/* 报告容器:弹性布局,表单居左,锚点居右 */
.report-container {
display: flex;
gap: 12px;
width: 100%;
}
/* 表单区域:占满剩余空间,纵向滚动 */
.report-form {
flex: 1;
height: calc(100vh - 239px);
overflow-y: auto;
overflow-x: hidden;
padding: 5px;
box-sizing: border-box;
}
/* 锚点导航:垂直排列,靠右固定,不滚动 */
.anchor-nav {
display: flex;
flex-direction: column;
gap: 10px;
width: 48px;
align-self: center;
flex-shrink: 0;
}
</style>

@ -276,7 +276,9 @@
<el-button
type="text"
@click="handleTimeSectionUpdate(scope.row)"
:disabled="scope.row.reporter_name != userInfo.name"
:disabled="
scope.row.reporter_id != userInfo.id || ![1, 5].includes(scope.row.status)
"
>
{{ scope.row.date_time }} {{ scope.row.time_section }}
<i class="el-icon-edit el-icon--right"></i>
@ -327,7 +329,7 @@
show-overflow-tooltip
>
<template slot-scope="scope">
{{ scope.row.exam_rooms.map((item) => item.name).join(", ") || "-" }}
{{ scope.row.exam_rooms.map((item) => item.name).join(", ") }}
</template>
</el-table-column>
<el-table-column
@ -442,7 +444,7 @@ import CaseFormDialog from "./components/CaseFormDialog.vue";
import { mapGetters } from "vuex";
export default {
name: "Case",
name: "Cases",
components: {
CaseFormDialog,
},
@ -497,13 +499,24 @@ export default {
const start = new Date();
const day = start.getDay();
start.setDate(start.getDate() - day + (day === 0 ? -6 : 1));
//
end.setDate(start.getDate() + 6);
end.setHours(23, 59, 59, 999);
picker.$emit("pick", [start, end]);
},
},
{
text: "本月",
onClick: (picker) => {
const end = new Date();
const end = new Date(
new Date().getFullYear(),
new Date().getMonth() + 1,
0,
23,
59,
59,
999
);
const start = new Date(
new Date().getFullYear(),
new Date().getMonth(),
@ -531,7 +544,15 @@ export default {
{
text: "今年",
onClick: (picker) => {
const end = new Date();
const end = new Date(
new Date().getFullYear(),
11,
31,
23,
59,
59,
999
);
const start = new Date(new Date().getFullYear(), 0, 1);
picker.$emit("pick", [start, end]);
},

Loading…
Cancel
Save