feat(font): 新增字体设置并统一医护端与患者端文书字体

This commit is contained in:
xy
2026-09-30 08:35:02 +08:00
parent fe8cb01d4d
commit c2984bfd98
18 changed files with 511 additions and 5 deletions
@@ -14,6 +14,9 @@
*/
import { computed, onMounted, ref, watch } from 'vue'
import { loadDocumentFont, type DocumentFont } from '../../../../packages/document-fonts'
import { getDefaultDocumentFont } from '@/api/management/document-fonts'
import type { SigningAnswers } from '@/api/workbench/types'
import {
applyAnswerToFieldHost,
@@ -36,6 +39,8 @@ const props = withDefaults(
defineProps<{
/** 文书正文(模板定稿 / 任务固化快照) */
contentHtml: string
/** undefined: template preview uses default; null: historical task retains legacy font. */
documentFont?: DocumentFont | null
/** 回填上下文:患者信息 / 签名 / 勾选 / 已填取值 */
data?: SigningDocumentData
/** 填写项可否改动、签名位可否点击采集 */
@@ -62,6 +67,7 @@ const props = withDefaults(
variant?: 'plain' | 'card'
}>(),
{
documentFont: undefined,
data: () => ({}),
interactive: false,
signatureActionable: undefined,
@@ -80,6 +86,26 @@ const emit = defineEmits<{
signatureRequest: [request: SigningSignatureRequest]
}>()
const fontReady = ref(false)
const fontError = ref('')
const fontFamily = ref('')
let fontLoadVersion = 0
async function prepareFont() {
const version = ++fontLoadVersion
fontReady.value = false
fontError.value = ''
try {
const font =
props.documentFont === undefined ? await getDefaultDocumentFont() : props.documentFont
const family = await loadDocumentFont(font, import.meta.env.VITE_API_BASE_URL || '/api')
if (version !== fontLoadVersion) return
fontFamily.value = family
fontReady.value = true
} catch {
if (version === fontLoadVersion) fontError.value = '文书字体加载失败,请重试。'
}
}
watch(() => props.documentFont, prepareFont, { immediate: true })
const containerRef = ref<HTMLElement | null>(null)
/**
@@ -300,6 +326,7 @@ onMounted(() => {
/** 供「导出 PDF」使用:拿到已渲染的文书容器(含固定页眉与签署态取值) */
function getDocumentElement() {
if (!fontReady.value) return null
return containerRef.value
}
@@ -310,7 +337,16 @@ defineExpose({ getDocumentElement })
<!-- eslint-disable vue/no-v-html -- 内容为本系统定稿的文书 HTML(编辑器产出、仅医务人员可改),非任意用户输入 -->
<!-- doc-paper--a4:无论哪种 variant 都是「一页 A4」(比例 + 一般文书页边距),
variant 只决定盒子装饰 —— card 自带圆角阴影,plain 交给调用方 -->
<article class="doc-paper doc-paper--a4" :class="{ 'doc-paper--card': variant === 'card' }">
<p v-if="!fontReady" role="status">
{{ fontError || '正在加载文书字体…' }}
<button v-if="fontError" type="button" @click="prepareFont">重试</button>
</p>
<article
class="doc-paper doc-paper--a4"
:class="{ 'doc-paper--card': variant === 'card', 'managed-font': Boolean(fontFamily) }"
:style="{ '--document-font': fontFamily, visibility: fontReady ? 'visible' : 'hidden' }"
:inert="!fontReady"
>
<div
ref="containerRef"
class="doc-paper__body"
@@ -325,6 +361,12 @@ defineExpose({ getDocumentElement })
</template>
<style scoped>
.managed-font,
.managed-font :deep(*) {
font-family: var(--document-font) !important;
font-synthesis: none;
}
/* 基础排版(p / h2 / h3 / table / th / td / img)在 utils/document-paper.ts 的
DOCUMENT_PAPER_CSS 里,运行期注入 head —— 那里是唯一一份。
这里只保留容器自己的盒子。 */