feat(文档库): 打通模板正文真实模式并新增渲染验证
模板列表接口不返回正文,展示、编辑与发起签署前需再取版本详情获取 contentHtml, 为此新增 getTemplateContent、createTemplateWithContent、updateTemplateContent 与 deleteTemplate(归档),并在签署端按 contentSha256 缓存正文快照。 同时新增 scripts/login.cjs 与 scripts/verify-pages.cjs,通过真实登录与 CDP 渲染截图、断言关键内容并收集运行时错误,并补充 .gitignore、eslint 忽略与文档说明。
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
modelValue: string
|
||||
total: number
|
||||
}>()
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
modelValue: string
|
||||
total: number
|
||||
/** 只在演示模式下展示「重置演示数据」:真实环境不该出现这个自测入口 */
|
||||
showReset?: boolean
|
||||
}>(),
|
||||
{ showReset: false },
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
@@ -28,7 +33,7 @@ function handleInput(event: Event) {
|
||||
|
||||
<div class="library-tools">
|
||||
<input
|
||||
:value="props.modelValue"
|
||||
:value="modelValue"
|
||||
class="library-search"
|
||||
type="search"
|
||||
placeholder="搜索模板名称 / 编号 / 科室"
|
||||
@@ -43,6 +48,7 @@ function handleInput(event: Event) {
|
||||
导出模板包
|
||||
</button>
|
||||
<button
|
||||
v-if="showReset"
|
||||
type="button"
|
||||
class="tool-button ghost"
|
||||
title="清除本地保存的演示文书与签署任务"
|
||||
|
||||
@@ -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)"
|
||||
>
|
||||
用此模板发起签署
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { documentStatusLabels } from '../mock'
|
||||
import type { DocumentTemplate } from '../types'
|
||||
import { documentStatusLabels } from '../mock'
|
||||
|
||||
const props = defineProps<{
|
||||
template: DocumentTemplate
|
||||
@@ -16,6 +16,15 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const statusLabel = computed(() => documentStatusLabels[props.template.status])
|
||||
|
||||
/** 只有已发布 / 待复审的模板可以发起签署;草稿与已归档不可用 */
|
||||
const canInitiate = computed(
|
||||
() => props.template.status === 'published' || props.template.status === 'review',
|
||||
)
|
||||
|
||||
const initiateTitle = computed(() =>
|
||||
canInitiate.value ? '用此模板发起签署' : '仅已发布或待复审的模板可发起签署',
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -44,8 +53,8 @@ const statusLabel = computed(() => documentStatusLabels[props.template.status])
|
||||
<button
|
||||
type="button"
|
||||
class="card-button primary"
|
||||
:disabled="template.status !== 'enabled'"
|
||||
:title="template.status === 'enabled' ? '用此模板发起签署' : '仅已启用模板可发起签署'"
|
||||
:disabled="!canInitiate"
|
||||
:title="initiateTitle"
|
||||
@click="emit('initiate', template)"
|
||||
>
|
||||
发起
|
||||
@@ -124,7 +133,7 @@ const statusLabel = computed(() => documentStatusLabels[props.template.status])
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.status-enabled {
|
||||
.status-published {
|
||||
color: var(--ok);
|
||||
background: var(--ok-l);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user