Files
xh-medical-sign-web/clinical-web/src/views/workbench/signing/components/SigningDocumentPreview.vue
T
yelan 81922d774f feat(文档库): 打通模板正文真实模式并新增渲染验证
模板列表接口不返回正文,展示、编辑与发起签署前需再取版本详情获取 contentHtml,
为此新增 getTemplateContent、createTemplateWithContent、updateTemplateContent 与
deleteTemplate(归档),并在签署端按 contentSha256 缓存正文快照。

同时新增 scripts/login.cjs 与 scripts/verify-pages.cjs,通过真实登录与 CDP
渲染截图、断言关键内容并收集运行时错误,并补充 .gitignore、eslint 忽略与文档说明。
2026-09-17 14:10:45 +08:00

241 lines
6.1 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.
<script setup lang="ts">
/**
* 文书回退纸样。
*
* 只在任务缺少正文快照(documentContentHtml 为空)时使用:任务接口不返回正文,
* 正文由 hydrateSigningTaskContent 按 templateContentSha256 取回,取不到时才会走到这里。
*
* 这里的正文段落是通用告知语句,**不是任何一份真实模板的内容**,
* 因此页面必须明确标注"未取到模板正文",不能让医务人员误以为这就是要签的文书。
* 经治医师等应由现场填写的字段也不许写死:写死一个不存在的医生名,
* 等于在留痕材料上伪造了一个签署人。
*/
defineProps<{
task: SigningTaskRecord
}>()
import type { SigningTaskRecord } from '@/api/workbench/types'
</script>
<template>
<article class="paper-preview">
<div v-if="task.status === 'void'" class="void-stamp">已 作 废</div>
<div class="fallback-banner">
<strong>未能取到模板正文</strong>
<span>
本任务仅返回了模板版本哈希({{ task.contentSha256 || '未提供' }}),正文快照暂不可用。
请确认后端模板版本内容接口可访问,或联系信息科核对模板数据。
以下为占位版式,不是本任务实际签署的文书内容。
</span>
</div>
<h2>{{ task.documentName }}</h2>
<p class="paper-number">编号:{{ task.id }} · 就诊号:{{ task.visitNo }}</p>
<p class="paper-meta">
患者:<strong>{{ task.patientName }}</strong
>({{ task.sex }},{{ task.age }}岁) · 患者 ID:{{ task.patientId }}
</p>
<p class="paper-meta">
就诊信息:{{ task.visitType }} · {{ task.department }} · {{ task.visitDate }}
<span v-if="task.visitType === '住院'" class="current-badge">在院</span>
</p>
<p>
医务人员已就本项检查/治疗的适应证、禁忌证、医疗风险、替代方案及可能出现的不良后果向本人(或授权委托人)充分说明,本人已完全理解上述内容。
</p>
<p>
本人自愿接受上述检查/治疗,并同意在相关医疗文书中签署确认。所签署文件将作为医疗过程留痕依据,签署过程采用电子方式完成,签名图片与文档原件一并存档。
</p>
<div class="notice-block">
<strong>签署须知:</strong>
请仔细阅读全部内容后签名;签名图片将合成至本文档签名域;文档与签名原图双留存,可随时查验;如对内容有疑问,请先向医务人员咨询。
</div>
<div class="signature-grid">
<div class="signature-field">
<span>患者 / 授权委托人签名:</span>
<div class="signature-box">
<img v-if="task.signatureDataUrl" :src="task.signatureDataUrl" alt="患者签名" />
<span v-else>{{ task.status === 'void' ? '—' : '未签署' }}</span>
</div>
</div>
<div class="signature-field">
<span>日期:</span>
<div class="signature-box signature-box--date">
<span>{{ task.signedAt ?? '—' }}</span>
</div>
</div>
<!-- 经治医师不是任务快照里的字段,也无从由前端补齐:
这里不给占位人名,避免在留痕材料上凭空出现一个签署人 -->
<div class="signature-field">
<span>经治医师:</span>
<div class="signature-box signature-box--doctor">
<span>(以实际签署文书为准)</span>
</div>
</div>
</div>
</article>
</template>
<style scoped>
.paper-preview {
position: relative;
min-height: 560px;
padding: 34px 44px;
color: var(--ink);
font-size: 13.5px;
line-height: 1.9;
background: #fff;
border-radius: var(--r);
box-shadow: var(--sh);
}
/* 回退纸样必须在最显眼处声明"这不是真实文书内容",
否则医务人员会把占位段落当成要签的文书 */
.fallback-banner {
display: flex;
flex-direction: column;
gap: 4px;
padding: 10px 14px;
margin-bottom: 20px;
color: var(--warn);
font-size: 12px;
line-height: 1.7;
background: var(--warn-l);
border: 1px solid #f0dcae;
border-radius: 8px;
}
.fallback-banner strong {
font-size: 12.5px;
}
.paper-preview h2 {
margin: 0 0 6px;
font-size: 19px;
letter-spacing: 2px;
text-align: center;
}
.paper-number {
margin: 0 0 18px;
color: var(--mut);
font-size: 12px;
text-align: center;
}
.paper-preview p {
margin: 0 0 6px;
text-align: justify;
text-indent: 2em;
}
.paper-preview .paper-meta {
color: var(--mut);
text-indent: 0;
}
.paper-meta strong {
color: var(--ink);
}
.current-badge {
display: inline-block;
padding: 1px 7px;
margin-left: 4px;
color: var(--err);
font-size: 10px;
line-height: 1.5;
background: var(--err-l);
border-radius: 4px;
}
.notice-block {
padding: 10px 14px;
margin: 10px 0;
font-size: 12.5px;
background: #fafcfd;
border: 1px dashed var(--line);
border-radius: 8px;
}
.notice-block strong {
font-size: 12.5px;
}
.signature-grid {
display: flex;
gap: 40px;
align-items: flex-end;
flex-wrap: wrap;
margin-top: 22px;
}
.signature-field > span {
display: block;
margin-bottom: 6px;
color: var(--mut);
font-size: 12.5px;
}
.signature-box {
display: flex;
min-width: 200px;
min-height: 64px;
align-items: center;
justify-content: center;
border-bottom: 2px solid var(--ink);
}
.signature-box img {
max-width: 190px;
max-height: 60px;
}
.signature-box span {
color: var(--mut);
font-size: 12px;
}
.signature-box--date {
min-width: 150px;
}
.signature-box--doctor {
min-width: 120px;
}
/* 医师签名位是空的说明文字,不需要下划线,避免看起来像已填写 */
.signature-field:nth-child(3) .signature-box {
border-bottom-style: dashed;
}
.void-stamp {
position: absolute;
top: 34px;
right: 44px;
padding: 4px 12px;
color: rgb(208 83 79 / 70%);
font-size: 20px;
font-weight: 700;
letter-spacing: 4px;
border: 2.5px solid rgb(208 83 79 / 55%);
border-radius: 8px;
transform: rotate(-14deg);
}
@media (max-width: 700px) {
.paper-preview {
padding: 26px 24px;
}
.void-stamp {
top: 24px;
right: 24px;
}
}
</style>