Files
xh-medical-sign-web/clinical-web/src/views/workbench/signing/components/SignedDocumentDialog.vue
T
yelan 3cb174ce0c refactor(文书预览): 抽出统一的文书纸与预览弹窗,消除五处重复渲染
预览原先在 5 个地方各写一遍(文书库预览、编辑器签署预览、发起签署弹窗预览、
工作台在线预览、工作台文书区),基础排版已经分叉:表格边框 #52646e 与 #c8d7dd
两套色、单元格内边距 5px 7px 与 5px 9px 两个值、只有两处带宋体。
原型本身是「一处渲染(.paper + fillDocHtml)、两种外框」,这次按那个形状收口。

新增
- utils/document-paper.ts:基础排版的**唯一一份** CSS(p / h1-h4 / 表格 / 宋体)。
  运行期幂等注入 head —— 因为同一份纸有两条渲染通道:v-html(吃全局样式)与
  iframe srcdoc(隔离模板自带 style,只能吃字符串),各写一份必然漂移。
- components/document/DocumentPaper.vue:唯一的纸渲染器。
  signing / raw 两模式、interactive、取值还原、☑☐ 就地切换、签名位请求采集、
  填写项与勾选上报、getDocumentElement()(供导出 PDF)。
- components/document/DocumentPreviewDialog.vue:唯一的预览外框。
  标题/副标题/徽标、可选页签、加载与错误态、纸舞台(浅色卡片 / 深灰 A4)、
  #footer 与 #empty 插槽。
- styles/document-preview.css:页脚按钮等**插槽内容**要用的类。
  插槽节点带的是父组件 scope id,弹窗的 scoped 样式命中不了 —— 与
  signing-document.css 同一类问题,同一套解法。

迁移
- 文书库预览、编辑器签署预览、发起签署弹窗预览、工作台在线预览全部改走统一组件;
  SigningDocumentInteractive 的纸换成 DocumentPaper,只留任务外壳
  (横幅 / 作废章 / 填写项进度)。
- 删除四处基础排版副本;SimSun 与 :deep(table) 现在各只剩一处。

行为保持
- 文书库预览仍是两个页签(文书内容走 iframe 隔离、签署预览走 v-html),
  没有正文时仍给占位版式(占位符写成 {患者姓名} 原始形态,不预填示例值)。
- 工作台预览的深灰 A4 舞台、页脚说明与两个出口按钮不变。
- 作废章原先是纸的兄弟节点、DOM 顺序在前,纸改成自带白底后会被盖住 ——
  给章补 z-index,并在探针里加命中测试锁死。

验证
- 新增 probe-doc-paper.cjs:31/31 PASS。核心是**计算样式**断言
  (边框色 / 内边距 / 宋体 / border-collapse),并断言文书库预览与编辑器预览
  两份纸的样式**逐项一致** —— 只看 DOM 存在证明不了"只有一份排版"。
- 回归:probe-new-task 104/104、probe-workbench-lib 46/46(新增作废章命中测试)、
  probe-dept-confirm 36/36、probe-method-domain 14/14、probe-report-analytics 92/92。
- vue-tsc 与 eslint 0 错。

净减 888 行(309 增 / 1197 删)。
2026-09-26 20:56:02 +08:00

85 lines
3.0 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">
/**
* 已签署 / 待科室确认文书的在线预览(原型 openPdfView 的 mdPdfView)。
*
* 它只是**统一预览弹窗**在签署工作台这一处的配置:
* 深灰 A4 舞台 + 「只读副本 / 下载 PDF 原件」两个出口。
* 纸的渲染在 components/document/DocumentPaper.vue、弹窗外壳在 DocumentPreviewDialog.vue,
* 这里不重复实现任何渲染逻辑 —— 预览看到的版式必须与工作台里、与导出的 PDF 完全一致。
*/
import { computed } from 'vue'
import type { SigningTaskRecord } from '@/api/workbench/types'
import DocumentPreviewDialog from '@/components/document/DocumentPreviewDialog.vue'
import SigningDocumentPreview from '@/components/signing/SigningDocumentPreview.vue'
import type { SigningDocumentData } from '@/utils/signing-document'
const props = defineProps<{
visible: boolean
task: SigningTaskRecord | null
/** 导出中:两个下载按钮一起禁用,避免重复点出多份 PDF */
exporting: boolean
}>()
const emit = defineEmits<{
close: []
download: []
'download-readonly-copy': []
}>()
const subtitle = computed(() =>
props.task ? `${props.task.documentName} · ${props.task.id} · ${props.task.patientName}` : '',
)
/** 只挑渲染真正需要的字段显式映射,不直接透传整个任务对象 */
const documentData = computed<SigningDocumentData>(() => ({
patientName: props.task?.patientName ?? '',
sex: props.task?.sex ?? '',
age: props.task?.age ?? '',
visitNo: props.task?.visitNo ?? '',
visitDate: props.task?.visitDate ?? '',
signedAt: props.task?.signedAt ?? '',
signatureDataUrl: props.task?.signatureDataUrl,
selectedItems: props.task?.selectedItems,
fieldAnswers: props.task?.fieldAnswers,
}))
</script>
<template>
<DocumentPreviewDialog
:visible="visible && Boolean(task)"
title="在线预览(PDF)"
:subtitle="subtitle"
:content-html="task?.documentContentHtml ?? ''"
:data="documentData"
stage="stage"
:width="900"
@close="emit('close')"
>
<!-- 正文取不到时用带任务信息的回退纸样,而不是一句「暂无正文」:
那会把「后端没给正文」和「这份文书本来就是空的」混为一谈 -->
<template #empty>
<SigningDocumentPreview v-if="task" :task="task" />
</template>
<template #footer>
<span class="preview-note-footer">
正式文书以服务端生成的 PDF 原件为准;此处预览按任务固化的文书版本渲染。
</span>
<span class="preview-spacer" />
<button
type="button"
class="preview-button preview-button--ghost"
:disabled="exporting"
title="生成带水印与审计编号的副本,对外提供时使用"
@click="emit('download-readonly-copy')"
>
只读副本
</button>
<button type="button" class="preview-button" :disabled="exporting" @click="emit('download')">
{{ exporting ? '生成中…' : '下载 PDF 原件' }}
</button>
</template>
</DocumentPreviewDialog>
</template>