feat(签署): 保存并还原患者勾选结果

签署完成时将患者勾选的条目固化到任务记录,重新打开已签署文书时还原勾选状态,重新发起签署则清空历史勾选。
This commit is contained in:
yelan
2026-09-14 15:36:19 +08:00
parent d34ef0a0ce
commit c7da24cef6
6 changed files with 93 additions and 9 deletions
+26 -5
View File
@@ -21,6 +21,8 @@ export interface SigningDocumentData {
visitDate: string
signedAt?: string
signatureDataUrl?: string
/** 已勾选的条目名:签署完成后重新打开文书时用来还原勾选状态 */
selectedItems?: string[]
}
const SIGNATURE_PLACEHOLDER = '{患者签名}'
@@ -105,7 +107,7 @@ function fillPatientPlaceholders(root: Element, data: SigningDocumentData) {
})
}
function convertCheckboxes(root: Element, interactive: boolean) {
function convertCheckboxes(root: Element, interactive: boolean, selected: Set<string>) {
root.querySelectorAll('table').forEach((table) => {
// 不能只认 <thead>:WangEditor 的表格节点是 <table><tbody><tr>,它导出时不会生成
// thead,粘贴带 thead 的表格时其 preParseHtml 也把 thead 拆掉;.docx 经 mammoth
@@ -148,6 +150,13 @@ function convertCheckboxes(root: Element, interactive: boolean) {
checkbox.setAttribute('data-sign-item', itemName)
checkbox.disabled = !interactive
// 必须写成 attribute:innerHTML 只序列化 HTML 属性,只设 .checked 这个
// property 会在生成 HTML 时被丢掉,渲染回来就成了未勾选
if (selected.has(itemName)) {
checkbox.checked = true
checkbox.setAttribute('checked', '')
}
checkCell.textContent = ''
checkCell.appendChild(checkbox)
})
@@ -180,6 +189,7 @@ function replaceOptionMarkers(
type: 'radio' | 'checkbox',
groupName: string,
interactive: boolean,
selected: Set<string>,
) {
const parts = (textNode.textContent ?? '').split(OPTION_SPLIT_PATTERN)
const fragment = document.createDocumentFragment()
@@ -206,6 +216,12 @@ function replaceOptionMarkers(
input.disabled = !interactive
input.setAttribute('data-sign-item', label)
// 同表格勾选:只设 property 不会出现在生成的 HTML 里,必须落成属性
if (label !== '' && selected.has(label)) {
input.checked = true
input.setAttribute('checked', '')
}
if (type === 'radio') {
input.name = groupName
input.value = label
@@ -234,7 +250,7 @@ function replaceOptionMarkers(
* 同一段/同一单元格里出现两个及以上方框时按「二选一」处理成互斥单选;
* 只有一个方框则保持多选语义,避免把「□高血压」这类单项确认误判成互斥组。
*/
function convertInlineOptions(root: Element, interactive: boolean) {
function convertInlineOptions(root: Element, interactive: boolean, selected: Set<string>) {
const groups = new Map<Element, Text[]>()
collectOptionTextNodes(root).forEach((textNode) => {
@@ -261,7 +277,9 @@ function convertInlineOptions(root: Element, interactive: boolean) {
const type = markerCount > 1 ? 'radio' : 'checkbox'
const groupName = `sign-option-${groupSeq}`
textNodes.forEach((textNode) => replaceOptionMarkers(textNode, type, groupName, interactive))
textNodes.forEach((textNode) =>
replaceOptionMarkers(textNode, type, groupName, interactive, selected),
)
})
}
@@ -297,8 +315,11 @@ export function buildSigningDocumentHtml(
replaceTextPlaceholder(root, SIGNATURE_PLACEHOLDER, '(待患者签署)')
}
convertCheckboxes(root, interactive)
convertInlineOptions(root, interactive)
// 已签署的文书再次打开时,把上次记录的勾选状态还原出来
const selected = new Set(data.selectedItems ?? [])
convertCheckboxes(root, interactive, selected)
convertInlineOptions(root, interactive, selected)
return root.innerHTML
}