diff --git a/clinical-web/README.md b/clinical-web/README.md
index c831bc1..92c97b3 100644
--- a/clinical-web/README.md
+++ b/clinical-web/README.md
@@ -143,7 +143,7 @@ ClinicalLayout(实际导航和页面路由由授权菜单资源树提供)
- 占位符分两类,写法都是 `{…}`:
- **系统预填项**:`{患者姓名}`、`{性别}`、`{年龄}`、`{就诊号}`、`{签署日期}`、`{患者签名}`、`{医师签名}` 等,字段键与取值来源固定,由签署任务的患者与就诊快照填充,目录见 `utils/signing-fields.ts` 的 `SIGNING_FIELD_PRESETS`;
- **通用文本项**:现场手填的输入框,默认写 `{文本框}`,签署时渲染成一个空文本框。**每个占位符各自是一个填写项**,字段键按出现位置编号(`custom:名称`、第 2 个起是 `custom:名称#2`……),所以同一份文书里放几个文本框就是几份取值,不需要为了区分而改名字;名称只决定文书里显示的文字,直接把正文里的「文本框」改成「与患者关系」「受托人姓名」即可(仅为可读性,不影响取值归属)。
- - 只有上面那类系统预填项按字段键去重、同名共用一份取值——页眉的患者姓名、每页的签名位反复出现,取值本来就该是同一个。
+ - 只有上面那类系统预填项按字段键去重、同名共用一份取值——每页的签名位、正文里反复提到的患者姓名,取值本来就该是同一个。
- 勾选表:做成表格,第一行表头写「勾选」,另设一列写「项目」作为勾选条目名,签署时「勾选」列每个单元格变成复选框;
- 行内选项:正文里直接写方框符号,如 `□否 □是`、`□同意 □不同意`。同一段落或同一单元格内出现两个及以上方框时按二选一(互斥单选)处理,只有一个方框时保持独立复选框语义。
diff --git a/clinical-web/src/api/workbench/signing.ts b/clinical-web/src/api/workbench/signing.ts
index 3e56bda..6208006 100644
--- a/clinical-web/src/api/workbench/signing.ts
+++ b/clinical-web/src/api/workbench/signing.ts
@@ -494,15 +494,15 @@ const defaultMockRecords: SigningTaskRecord[] = [
* 给演示任务补齐渲染所需的数据:文书正文快照 + 已签署任务的签名图。
*
* ① 正文:预置任务(以及历史上从写死模板创建的任务)只记了 documentId,没有正文快照;
- * 缺正文时详情会退化成前端写死的回退纸样——内容与模板无关、没有签名位、
- * 也没有固定页眉。这里按 documentId 从文书库取正文补上;
+ * 缺正文时详情会退化成前端写死的回退纸样——内容与模板无关、也没有签名位。
+ * 这里按 documentId 从文书库取正文补上;
* 实在取不到的保持原样,由详情页走回退分支,不伪造正文。
* ② 签名图:种子任务里标了「已签署」却不带签名,会出现「列表说已签署、打开没有签名、
* 产物列表也是空的」这种自相矛盾的状态,下载的 PDF 也缺签名。
* 这里给缺签名的已签署任务补一张示意签名;真实签署过的任务已有签名图,不会被覆盖。
* ③ 文书绑定:种子的 documentId 是按早期「一类文书一个任务」写死的(tpl-001…tpl-006)。
* 演示文书库现在只保留一份麻精知情同意书,那些模板已经不在库里——不重绑的话
- * 每个任务详情都会落到「未能取到模板正文」的占位版式,签名位、勾选项、页眉
+ * 每个任务详情都会落到「未能取到模板正文」的占位版式,签名位、勾选项、填写项回填
* 这些签署链路在演示环境里一次都走不到。重绑按序号在库里取,库里以后增删文书
* 任务会跟着走,不会再脱钩。
*/
diff --git a/clinical-web/src/components/document/DocumentPaper.vue b/clinical-web/src/components/document/DocumentPaper.vue
index 56e6ef1..a106b8a 100644
--- a/clinical-web/src/components/document/DocumentPaper.vue
+++ b/clinical-web/src/components/document/DocumentPaper.vue
@@ -324,7 +324,7 @@ onMounted(() => {
syncFromDom()
})
-/** 供「导出 PDF」使用:拿到已渲染的文书容器(含固定页眉与签署态取值) */
+/** 供「导出 PDF」使用:拿到已渲染的文书容器(含签署态取值) */
function getDocumentElement() {
if (!fontReady.value) return null
return containerRef.value
diff --git a/clinical-web/src/components/signing/SigningDocumentInteractive.vue b/clinical-web/src/components/signing/SigningDocumentInteractive.vue
index 8d8b93b..64415ee 100644
--- a/clinical-web/src/components/signing/SigningDocumentInteractive.vue
+++ b/clinical-web/src/components/signing/SigningDocumentInteractive.vue
@@ -89,7 +89,7 @@ function handleFieldChange(answers: SigningAnswers, next: SigningFieldProgress)
emit('field-change', answers, next)
}
-/** 供「导出 PDF」使用:拿到已渲染的文书容器(含固定页眉与签署态取值) */
+/** 供「导出 PDF」使用:拿到已渲染的文书容器(含签署态取值) */
function getDocumentElement() {
return paperRef.value?.getDocumentElement() ?? null
}
@@ -256,6 +256,6 @@ defineExpose({ getDocumentElement })
}
/* 正文字号、表格边框、字体等基础排版在 components/document/DocumentPaper.vue 的
- DOCUMENT_PAPER_CSS 里(全项目唯一一份)。填写项胶囊、选项 ☑☐、系统页眉在
+ DOCUMENT_PAPER_CSS 里(全项目唯一一份)。填写项胶囊、选项 ☑☐ 在
styles/signing-document.css。这里只保留"这份文书外壳"自己的东西。 */
diff --git a/clinical-web/src/styles/index.css b/clinical-web/src/styles/index.css
index a527f57..f2095d1 100644
--- a/clinical-web/src/styles/index.css
+++ b/clinical-web/src/styles/index.css
@@ -1,5 +1,5 @@
@import './theme.css';
-/* 文书渲染(签署态)的通用样式:占位符胶囊、选项、系统页眉。
+/* 文书渲染(签署态)的通用样式:占位符胶囊、选项。
文书库预览 / 签署工作台 / 编辑器三处共用一份,避免各写一套后配色漂移 */
@import './signing-document.css';
/* 文书预览弹窗的公共类(页脚按钮等):插槽内容带父组件 scope id,
diff --git a/clinical-web/src/styles/signing-document.css b/clinical-web/src/styles/signing-document.css
index d910cf8..eb7deef 100644
--- a/clinical-web/src/styles/signing-document.css
+++ b/clinical-web/src/styles/signing-document.css
@@ -10,8 +10,7 @@
* (颜色按 kind 走:文本=品牌色、签名=橙、勾选=绿),只把底色转透明、字重转 normal。
* 即「有框 = 这一处是系统管理的填写位」,空/满都保留框——2026-09-27 按原型改回,
* 此前曾把框设成透明,那会让 HIS 带出的值与正文文字完全看不出区别;
- * - `.docopt` = 一组选项里的单项,用 ☑ / ☐ 文本而不是 input;
- * - `.sign-doc-header` = 系统页眉(患者信息由 HIS 带出,不进签署证据)。
+ * - `.docopt` = 一组选项里的单项,用 ☑ / ☐ 文本而不是 input。
*
* 约定:`.docfld` / `.docopt` 的配色只在原型基础上做**一处**改动——
* 原型的 `#8aa4b0` 下划线、`#c07f00` 签名橙、`#0f9d6c` 勾选绿都原样保留,
@@ -230,36 +229,6 @@
border-collapse: collapse;
}
-/* ============ 系统页眉 ============ */
-
-/* 患者姓名 / 性别 / 年龄 / 住院号·门诊号,取值全部来自 HIS。
- 只读展示,不挂 data-sign-field —— 页眉不是"待填写项",也不进签署证据。
- 四项要在一行内放下,取值下划线的宽度由字段定义给出(内联 min-width) */
-.sign-doc-header {
- display: flex;
- flex-wrap: wrap;
- gap: 10px 18px;
- padding-bottom: 10px;
- margin-bottom: 16px;
- border-bottom: 1.5px solid #52646e;
-}
-
-.sign-doc-header__item {
- display: inline-flex;
- gap: 3px;
- align-items: baseline;
-}
-
-.sign-doc-header__label {
- flex-shrink: 0;
- color: #52646e;
- font-size: 12.5px;
-}
-
-.sign-doc-header__value {
- padding: 0 5px 1px;
- color: #1c2b33;
- font-size: 12.5px;
- text-align: center;
- border-bottom: 1px solid #52646e;
-}
+/* 这里曾有「系统页眉」(患者姓名 / 性别 / 年龄 / 住院号·门诊号 的一行)。
+ 2026-09-30 去掉:编辑器里没有这一条,编辑时看不到、签出来却多一行。
+ 患者信息要出现在文书上,就在正文里插对应的 HIS 占位符。 */
diff --git a/clinical-web/src/utils/document-paper.ts b/clinical-web/src/utils/document-paper.ts
index 72f2497..e446835 100644
--- a/clinical-web/src/utils/document-paper.ts
+++ b/clinical-web/src/utils/document-paper.ts
@@ -23,7 +23,7 @@
* 例外只有一处:A4 规格的 `--doc-paper-*` 变量放在 `:root`(见下),
* 因为变量要在纸壳与编辑面上都能取到。
*
- * 注意:填写项胶囊 / 选项 ☑☐ / 系统页眉的样式**不在这里**,
+ * 注意:填写项胶囊 / 选项 ☑☐ 的样式**不在这里**,
* 它们与「签署态」语义强相关,统一在 styles/signing-document.css。
*/
@@ -261,11 +261,6 @@ export const DOCUMENT_PAPER_CSS = `
max-width: 100%;
}
-/* 系统页眉是 flex 排的一行患者信息,纸内边距由容器给,这里只补下间距 */
-.doc-paper > .sign-doc-header:first-child {
- margin-top: 0;
-}
-
/* ============ 文书字体(后台可配置) ============
谁的根上挂了 .managed-font,谁就换上 --document-font(由调用方挂内联变量)。
纸(DocumentPaper)与编辑器编辑面(EditorWangPane)都挂它 ——
diff --git a/clinical-web/src/utils/signing-document.ts b/clinical-web/src/utils/signing-document.ts
index ac50ff5..244636f 100644
--- a/clinical-web/src/utils/signing-document.ts
+++ b/clinical-web/src/utils/signing-document.ts
@@ -31,7 +31,6 @@ import {
readFieldFromElement,
resolveAnswersFromSystem,
scanFieldTokens,
- SIGNING_DOCUMENT_HEADER,
SIGNING_OPTION_MARKERS,
type SigningSystemSnapshot,
} from './signing-fields'
@@ -714,39 +713,6 @@ function convertInlineOptions(root: Element, interactive: boolean, selected: Set
})
}
-/**
- * 生成固定页眉:患者姓名 / 性别 / 年龄 / 住院号·门诊号,取值全部来自 HIS。
- * 只读展示,不挂 data-sign-field —— 页眉不是"待填写项",也不进签署证据,
- * 患者信息以任务快照为准,页眉只负责把快照呈现出来。
- */
-function buildDocumentHeader(doc: Document, answers: SigningAnswers): HTMLElement {
- const header = doc.createElement('header')
- header.className = 'sign-doc-header'
-
- SIGNING_DOCUMENT_HEADER.forEach(({ id, label, valueWidthEm }) => {
- const item = doc.createElement('span')
- item.className = 'sign-doc-header__item'
-
- const labelElement = doc.createElement('span')
- labelElement.className = 'sign-doc-header__label'
- labelElement.textContent = `${label}:`
-
- const value = answers[id]
- const valueElement = doc.createElement('span')
- valueElement.className = 'sign-doc-header__value'
- valueElement.textContent = typeof value === 'string' ? value : ''
- // 宽度随字段走(而不是写死在样式里):页眉四项要挤在一行,
- // 各字段需要的下划线长度差别很大,样式里只能给一个统一值,容易撑到换行
- valueElement.style.minWidth = `${valueWidthEm}em`
-
- item.appendChild(labelElement)
- item.appendChild(valueElement)
- header.appendChild(item)
- })
-
- return header
-}
-
/** 渲染开关。默认全部关闭,只读展示是"安全侧"缺省。 */
export interface SigningDocumentRenderOptions {
/**
@@ -825,9 +791,10 @@ export function buildSigningDocumentHtml(
convertCheckboxTables(root, interactive, selected)
convertInlineOptions(root, interactive, selected)
- // 页眉最后插入:保证 HIS 取值不会被当成文书内容参与占位符/方框识别
- root.insertBefore(buildDocumentHeader(doc, answers), root.firstChild)
-
+ // 渲染只**填值**,不往正文里添任何内容:文书长什么样就是编辑器里那一份。
+ // 这里曾经最后插入一条系统页眉(患者姓名 / 性别 / 年龄 / 住院号),2026-09-30 去掉:
+ // 编辑器里没有它,编辑时看不到、签出来和下载的 PDF 上却多一条。
+ // 患者信息要出现在文书上,就在正文里插对应占位符(编辑器「HIS 自动填充」里有这几个按钮)。
return root.innerHTML
}
@@ -1099,7 +1066,7 @@ export function applySignatureToRoot(root: HTMLElement, fieldId: string, dataUrl
/**
* 统计填写项进度:已填数量、未填的必填项、命中的异常项。
*
- * 按字段键去重:同一个字段在文书里可能出现多次(页眉的患者姓名/就诊号与正文重复是常态),
+ * 按字段键去重:同一个字段在文书里可能出现多次(签名位每页都有、患者姓名在正文里反复提到),
* 它们共用一份取值,只能算一个填写项,否则分母会被重复计数撑大。
*
* 「已填」的判据见 isEmptyFieldValue:多选取值只有空数组才算没填——
diff --git a/clinical-web/src/utils/signing-fields.ts b/clinical-web/src/utils/signing-fields.ts
index 967dd51..c9e9849 100644
--- a/clinical-web/src/utils/signing-fields.ts
+++ b/clinical-web/src/utils/signing-fields.ts
@@ -250,40 +250,6 @@ export const SIGNING_FIELD_PRESETS: SigningFieldDef[] = [
{ id: 'doctor', label: '医师签名', kind: 'signature', required: false, options: [] },
]
-/**
- * 固定页眉的一项。
- * valueWidthEm 是取值下划线的宽度(em):页眉要在一行内放下四项,
- * 按内容长度分配比统一宽度更省地方——性别、年龄只有一个字/两位数字,
- * 用和「住院号/门诊号」一样的长度就会把整行挤到换行。
- */
-export interface SigningHeaderField {
- /** 字段键,与 SIGNING_FIELD_PRESETS 对应 */
- id: string
- label: string
- valueWidthEm: number
-}
-
-/**
- * 文书固定页眉。
- *
- * 页眉不由模板正文承载,也不给操作人员编辑:内容全部来自 HIS,
- * 签署时按字段键自动填充,正式 PDF 由服务端按页重复同一份页眉。
- * 字段键复用 SIGNING_FIELD_PRESETS,取值映射与正文共用一套,不会出现两处口径。
- *
- * 因为页眉是系统渲染的只读展示(不挂 data-sign-field),
- * 它既不会出现在"填写项"统计里,也不会被写进签署证据——
- * 患者信息以任务快照为准,页眉只是把快照展示出来。
- *
- * 宽度预算:A4 版心约 680px,四项标签合计约 250px、项间距约 54px,
- * 取值下划线合计控制在约 290px 以内,留出余量保证一行放得下。
- */
-export const SIGNING_DOCUMENT_HEADER: SigningHeaderField[] = [
- { id: 'patient', label: '患者姓名', valueWidthEm: 5.5 },
- { id: 'sex', label: '性别', valueWidthEm: 2.8 },
- { id: 'age', label: '年龄', valueWidthEm: 3.2 },
- { id: 'visit', label: '住院号/门诊号', valueWidthEm: 9 },
-]
-
/**
* 同一字段在不同文书里的常见写法。
* 各科室历史文书用词不统一(患者签名 / 患方签名 / 患者(或家属)签名),
@@ -376,8 +342,8 @@ export function buildGenericTextToken(label: string = GENERIC_TEXT_FIELD_LABEL):
*
* sequence 是**同名占位符在本文书里的第几次出现**(从 1 开始),只有自定义文本项用得上:
*
- * - 目录里的字段按 id 去重,同名共用一份取值是刻意的——页眉的患者姓名、每页的签名位
- * 反复出现,取值只能是同一个;
+ * - 目录里的字段按 id 去重,同名共用一份取值是刻意的——每页都出现的签名位、
+ * 正文里反复提到的患者姓名,取值只能是同一个;
* - 自定义文本项没有取值来源,两个 {文本框} 是两处要填的内容,共用一个值才是错的。
* 而占位符是纯文本,正文里只有文字可依据,所以用"第几次出现"给它们各自编号:
* 第 1 个 custom:文本框,第 2 个 custom:文本框#2……位置就是它们的身份。
diff --git a/clinical-web/src/utils/signing-pdf.ts b/clinical-web/src/utils/signing-pdf.ts
index 4da763e..b82feb2 100644
--- a/clinical-web/src/utils/signing-pdf.ts
+++ b/clinical-web/src/utils/signing-pdf.ts
@@ -5,14 +5,16 @@
* 再按 A4 分页拼进 jsPDF,让前端能先看到成品效果:
* ① 截图用固定版心宽度:实时容器有固定高度、内边距,且宽度随工作台面板变化,
* 直接截图既截不全、版面也会跟着变;
- * ② 固定页眉在每页重复:页眉是系统按 HIS 数据渲染的,服务端生成 PDF 时同样要按页重复;
- * ③ 页码只写 "1 / 2" 这类 ASCII:jsPDF 内置字体不含中文,
+ * ② 页码只写 "1 / 2" 这类 ASCII:jsPDF 内置字体不含中文,
* 画中文页码需要内嵌字体(体积会明显变大),这一步留给服务端用真字体实现;
- * ④ 导出前对 flex 容器做一次兼容降级:html2canvas 不实现 flex 布局,
- * 填写项胶囊里的文字、输入框取值、签名图会被整块丢掉,见 applyExportFlexFallback。
- * ⑤ 「只读副本」的水印在克隆体上平铺(injectWatermark):屏幕上那份文书不出现水印,
+ * ③ 「只读副本」的水印在克隆体上平铺(injectWatermark):屏幕上那份文书不出现水印,
* 只有导出的 PDF 带;水印烙进截图,每一页都有,且改不掉文本层。
*
+ * **每页只有正文,没有页眉**(2026-09-30 去掉):原先会在每页顶部重复文书那条
+ * 系统页眉(患者姓名 / 性别 / 年龄 / 住院号),而编辑器里根本没有它 ——
+ * 编辑时看不到、签出来和下载的 PDF 上却多一条,是"渲染端自己长出来的"东西。
+ * 患者信息要出现在文书上,就在正文里插对应的占位符。
+ *
* 输出为位图 PDF:文本不可选中,仅供原型演示;正式文书以服务端生成的 PDF 为准。
*/
@@ -43,13 +45,9 @@ const CONTENT_HEIGHT_MM = PAGE_HEIGHT_MM - MARGIN_TOP_MM - MARGIN_BOTTOM_MM
const CAPTURE_WIDTH_PX = A4_CONTENT_WIDTH_PX
/** 截图倍率:2 倍下正文与小字都还清晰 */
const CAPTURE_SCALE = 2
-/** 量不到页眉时的兜底高度(px) */
-const FALLBACK_HEADER_PX = 46
-/** 页眉高到每页留不出正文时的下限(mm),低于它就不再重复页眉,避免切出上百页 */
-const MIN_BODY_HEIGHT_MM = 60
export interface SigningPdfInput {
- /** 已渲染的文书容器(含固定页眉与签署态取值) */
+ /** 已渲染的文书容器(含签署态取值) */
element: HTMLElement
/** 文件名,不带扩展名 */
fileName: string
@@ -120,50 +118,16 @@ function injectWatermark(root: HTMLElement, text: string) {
}
/**
- * html2canvas 兼容处理:flex 容器里的文字与控件取值会被整块丢掉。
+ * ⚠️ html2canvas **不实现 flex 布局**:纸里若出现 flex 容器,容器内的文字、输入框取值
+ * 与签名 `
` 会被整块丢掉(实测 html2canvas 1.4:页面上明明印着「与患者关系:配偶」、
+ * 签名图也画出来了,导出的位图里却只剩胶囊的边框和底色)。
*
- * 实测(签署工作台导出的 PDF,html2canvas 1.4):页面上明明印着「与患者关系:文本框 配偶」、
- * 签名图也画出来了,导出的位图里这些却全是空白,只剩胶囊的边框和底色——
- * 当时填写项胶囊与它的控件容器都是 `display: inline-flex`,html2canvas 算不出容器内
- * 文本的落点,于是连同取值与签名 `
` 一起被丢掉。
- *
- * 现在填写项已按原型口径改成 `display: inline-block`(.docfld / .docopt,
- * 见 styles/signing-document.css),这条降级只剩系统页眉那一层:
- * 它是 flex 排的一行患者信息,导出前改成 block + inline-block,
- * 并用等效的 margin 补回原来的项间距,保证页眉在 PDF 里不丢字。
- *
- * **只在导出克隆体上改**:屏幕上的版式一行不动。
+ * 所以能在纸上用 block / inline-block 表达的排版就别用 flex —— 填写项胶囊(`.docfld`)
+ * 正是按这个口径落成 inline-block 的(见 styles/signing-document.css)。
+ * 历史上系统页眉是 flex 排的一行患者信息,导出前要在克隆体上降级成 block + inline-block、
+ * 再用 margin 补回间距;页眉已在 2026-09-30 去掉,那段降级代码一并删了。
+ * 若以后又要在纸上排 flex,记得把同样的降级加回 `onclone` 里。
*/
-function applyExportFlexFallback(root: HTMLElement) {
- const header = root.querySelector('.sign-doc-header')
-
- if (!header) {
- return
- }
-
- header.style.display = 'block'
-
- // gap: 10px 18px 在 inline-block 下失效,用 margin 补回来
- root.querySelectorAll('.sign-doc-header__item').forEach((item) => {
- item.style.display = 'inline-block'
- item.style.marginRight = '18px'
- item.style.marginBottom = '6px'
- })
-}
-
-/** 量固定页眉的高度(含下外边距)——它是每页要重复的那一条 */
-function measureHeaderHeight(element: HTMLElement) {
- const header = element.querySelector('.sign-doc-header')
-
- if (!header) {
- return FALLBACK_HEADER_PX
- }
-
- const marginBottom = Number.parseFloat(window.getComputedStyle(header).marginBottom) || 0
- const height = header.getBoundingClientRect().height + marginBottom
-
- return height > 0 ? Math.round(height) : FALLBACK_HEADER_PX
-}
export async function createSigningPdf(input: SigningPdfInput): Promise {
// 按需加载:这两个库合计约 600KB,只在真正导出 PDF 时才拉取,
@@ -174,17 +138,13 @@ export async function createSigningPdf(input: SigningPdfInput): Promise {
])
const { element } = input
- // 克隆体在目标版心下重新排版,页眉高度以克隆体为准(实时容器可能更窄,页眉会换行)
- let clonedHeaderPx = 0
const canvas = await html2canvas(element, {
scale: CAPTURE_SCALE,
backgroundColor: '#ffffff',
useCORS: true,
logging: false,
- onclone: (clonedDocument, clonedElement) => {
- applyExportFlexFallback(clonedElement)
-
+ onclone: (_clonedDocument, clonedElement) => {
clonedElement.style.width = `${CAPTURE_WIDTH_PX}px`
clonedElement.style.height = 'auto'
clonedElement.style.maxHeight = 'none'
@@ -193,7 +153,7 @@ export async function createSigningPdf(input: SigningPdfInput): Promise {
clonedElement.style.margin = '0'
clonedElement.style.background = '#ffffff'
- // 水印在量页眉之前注入:它是绝对定位层,不参与布局,不会影响页眉高度
+ // 水印是绝对定位层,不参与布局,注入前后都不影响分页切片的位置
if (input.watermark) {
injectWatermark(clonedElement, input.watermark)
}
@@ -209,41 +169,17 @@ export async function createSigningPdf(input: SigningPdfInput): Promise {
paper.style.boxShadow = 'none'
paper.style.borderRadius = '0'
}
-
- const header = clonedElement.querySelector('.sign-doc-header')
-
- if (!header) {
- return
- }
-
- const marginBottom =
- Number.parseFloat(
- clonedDocument.defaultView?.getComputedStyle(header).marginBottom ?? '0',
- ) || 0
-
- clonedHeaderPx = Math.round(header.getBoundingClientRect().height + marginBottom)
},
})
const mmPerPx = CONTENT_WIDTH_MM / canvas.width
- const headerPx = clonedHeaderPx > 0 ? clonedHeaderPx : measureHeaderHeight(element)
- let headerCanvasPx = Math.min(Math.max(Math.round(headerPx * CAPTURE_SCALE), 0), canvas.height)
-
- if (CONTENT_HEIGHT_MM - headerCanvasPx * mmPerPx < MIN_BODY_HEIGHT_MM) {
- headerCanvasPx = 0
- }
-
- const bodyTopPx = headerCanvasPx
- const bodyTotalPx = Math.max(canvas.height - bodyTopPx, 1)
- const bodyPagePx = Math.max(
- Math.floor((CONTENT_HEIGHT_MM - headerCanvasPx * mmPerPx) / mmPerPx),
- 1,
- )
- const pageCount = Math.max(Math.ceil(bodyTotalPx / bodyPagePx), 1)
+ // 一页的版心高(px):正文按它连续切片,第 N 页从 (N-1) × 这个值开始
+ const bodyPagePx = Math.max(Math.floor(CONTENT_HEIGHT_MM / mmPerPx), 1)
+ const pageCount = Math.max(Math.ceil(canvas.height / bodyPagePx), 1)
const pageCanvas = document.createElement('canvas')
pageCanvas.width = canvas.width
- pageCanvas.height = headerCanvasPx + bodyPagePx
+ pageCanvas.height = bodyPagePx
const context = pageCanvas.getContext('2d')
@@ -258,23 +194,8 @@ export async function createSigningPdf(input: SigningPdfInput): Promise {
context.fillStyle = '#ffffff'
context.fillRect(0, 0, pageCanvas.width, pageCanvas.height)
- // 页眉:每页重复文书顶部那一条
- if (headerCanvasPx > 0) {
- context.drawImage(
- canvas,
- 0,
- 0,
- canvas.width,
- headerCanvasPx,
- 0,
- 0,
- canvas.width,
- headerCanvasPx,
- )
- }
-
- // 正文:按页连续切片,接在页眉下面
- const sourceY = bodyTopPx + page * bodyPagePx
+ // 正文:从上一页的断点接着切,整页铺满版心(页眉已去掉,不再为它留位置)
+ const sourceY = page * bodyPagePx
const sliceHeight = Math.min(bodyPagePx, canvas.height - sourceY)
if (sliceHeight > 0) {
@@ -285,7 +206,7 @@ export async function createSigningPdf(input: SigningPdfInput): Promise {
canvas.width,
sliceHeight,
0,
- headerCanvasPx,
+ 0,
canvas.width,
sliceHeight,
)
diff --git a/clinical-web/src/views/management/documents/components/WordEditorDialog.vue b/clinical-web/src/views/management/documents/components/WordEditorDialog.vue
index 17c94e4..c8414c5 100644
--- a/clinical-web/src/views/management/documents/components/WordEditorDialog.vue
+++ b/clinical-web/src/views/management/documents/components/WordEditorDialog.vue
@@ -72,9 +72,8 @@ const message = reactive({ text: '', tone: '' as '' | 'ok' | 'warn' })
* - HIS 自动填充:签署时按患者与就诊快照自动填,科室只需要把位置放对;
* - 自行填写 / 签名:签名与勾选必须现场采集,没有系统取值来源。
*
- * 患者姓名 / 性别 / 年龄 / 就诊号在原型里也能插,这里同样保留——
- * 页眉虽然会自动带出这四项,但正文里再出现一次(如"患者 X 因……")也是常态,
- * 那种位置必须有占位符,否则签署时不会回填。
+ * 患者姓名 / 性别 / 年龄 / 就诊号同样保留:正文里写"患者 X 因……"这类句子很常见,
+ * 那种位置必须有占位符,否则签署时不会回填(系统不会另外在文书上插患者信息)。
*/
const AUTO_FILL_LABELS = ['患者姓名', '性别', '年龄', '就诊号', '与患者关系', '签署日期']
const MANUAL_LABELS = ['患者签名', '勾选项']