feat(文档库): 打通模板正文真实模式并新增渲染验证

模板列表接口不返回正文,展示、编辑与发起签署前需再取版本详情获取 contentHtml,
为此新增 getTemplateContent、createTemplateWithContent、updateTemplateContent 与
deleteTemplate(归档),并在签署端按 contentSha256 缓存正文快照。

同时新增 scripts/login.cjs 与 scripts/verify-pages.cjs,通过真实登录与 CDP
渲染截图、断言关键内容并收集运行时错误,并补充 .gitignore、eslint 忽略与文档说明。
This commit is contained in:
yelan
2026-09-17 14:10:45 +08:00
parent 0d271d90be
commit 81922d774f
20 changed files with 1640 additions and 187 deletions
@@ -5,10 +5,11 @@ import {
buildSigningDocumentHtml,
describeFieldProgress,
readAnswersFromRoot,
type SigningDocumentData,
type SigningFieldProgress,
} from '@/utils/signing-document'
import { documentStatusLabels, signingPreviewPatient } from '../mock'
import { documentStatusLabels } from '../mock'
import type { DocumentTemplate } from '../types'
const props = defineProps<{
@@ -23,6 +24,24 @@ const emit = defineEmits<{
use: [template: DocumentTemplate]
}>()
/**
* 签署预览用的示例患者快照(脱敏演示数据)。
*
* 创建文书时还没有真实签署任务,用固定示例值让科室看到占位符被填充后的版式;
* 真实签署仍以任务创建时的患者/就诊快照为准。
* 这份数据只服务于「签署预览」这个演示页签,因此留在组件内,
* 不再从页面 mock.ts 导出——那会让"演示数据"渗透到文书库的其它部分。
*/
const previewPatient: SigningDocumentData = {
patientName: '李某某',
sex: '男',
age: 46,
visitNo: 'V20260914001',
visitDate: '2026-09-14',
phone: '138****5678',
signedAt: '',
}
/** 预览页签:「文书内容」看原始定稿,「签署预览」看占位符填充与勾选交互化后的样子 */
const activeTab = ref<'content' | 'signing'>('content')
/** 签署预览里科室试勾选的结果,仅用于预览反馈,不作为签署证据 */
@@ -63,6 +82,13 @@ const statusLabel = computed(() => {
return documentStatusLabels[props.template.status]
})
/** 与文书卡片保持同一口径:草稿与已归档不可发起签署 */
const canInitiate = computed(
() =>
Boolean(props.template?.contentHtml) &&
(props.template?.status === 'published' || props.template?.status === 'review'),
)
// 预置文书的 contentHtml 是完整 HTML 文档(自带版式样式);
// Word 自维护文书存的是编辑器产出的 HTML 片段,需要叠加文书基础渲染样式
// (表格边框、正文字体等),使导入路径的"裸表格"等语义结构也有合理的文书外观。
@@ -116,7 +142,7 @@ const previewSrcDoc = computed(() => {
// 患者/就诊数据用示例快照。interactive 传 true,科室可以在预览里试勾选、确认交互效果。
// 这里不用 iframe:需要读取勾选结果做汇总,iframe 的 sandbox 也不便于表单交互。
const signingPreviewHtml = computed(() =>
buildSigningDocumentHtml(props.template?.contentHtml ?? '', signingPreviewPatient, true),
buildSigningDocumentHtml(props.template?.contentHtml ?? '', previewPatient, true),
)
// 填写项与勾选汇总只在预览内展示(切页签、重开弹窗即重置),不作为签署证据。
@@ -192,7 +218,7 @@ function syncPreviewFields() {
</div>
<template v-else-if="template.contentHtml && activeTab === 'signing'">
<p class="preview-note">
按签署时效果渲染:占位符已用示例患者「{{ signingPreviewPatient.patientName }}」填充,
按签署时效果渲染:占位符已用示例患者「{{ previewPatient.patientName }}」填充,
表头含「勾选」的表格已转为勾选框,可直接勾选确认交互效果(预览不保存勾选结果)。
</p>
<!-- eslint-disable vue/no-v-html -- 内容为本系统定稿的文书 HTML(编辑器产出、仅医务人员可改),非任意用户输入 -->
@@ -264,8 +290,8 @@ function syncPreviewFields() {
<button
type="button"
class="footer-button primary"
:disabled="template.status !== 'enabled'"
:title="template.status === 'enabled' ? '用此模板发起签署' : '仅已启用模板可发起签署'"
:disabled="!canInitiate"
:title="canInitiate ? '用此模板发起签署' : '仅已发布或待复审的模板可发起签署'"
@click="emit('use', template)"
>
用此模板发起签署