feat(sign): 补齐医护端与患者端签署流程

This commit is contained in:
xy
2026-09-28 19:57:57 +08:00
parent a25716c861
commit 8024075439
22 changed files with 1082 additions and 163 deletions
+43 -6
View File
@@ -48,6 +48,12 @@ export const FIELD_REQUIRED_ATTR = 'data-required'
export const FIELD_OPTIONS_ATTR = 'data-options'
export const FIELD_MULTI_ATTR = 'data-multi'
export const FIELD_RISK_ATTR = 'data-risk'
export const FIELD_PDF_PAGE_ATTR = 'data-pdf-page'
export const FIELD_PDF_X_ATTR = 'data-pdf-x'
export const FIELD_PDF_Y_ATTR = 'data-pdf-y'
export const FIELD_PDF_WIDTH_ATTR = 'data-pdf-width'
export const FIELD_PDF_HEIGHT_ATTR = 'data-pdf-height'
export const FIELD_PDF_COORDINATE_SYSTEM_ATTR = 'data-pdf-coordinate-system'
/** 结构化占位符的选择器:渲染端与解析端必须用同一个。 */
export const FIELD_ELEMENT_SELECTOR = `${FIELD_ELEMENT_TAG}[${FIELD_ID_ATTR}]`
@@ -81,6 +87,15 @@ export function createFieldElement(doc: Document, field: SigningFieldDef): HTMLE
element.setAttribute(FIELD_RISK_ATTR, field.risk)
}
if (field.pdfPosition) {
element.setAttribute(FIELD_PDF_PAGE_ATTR, String(field.pdfPosition.page))
element.setAttribute(FIELD_PDF_X_ATTR, String(field.pdfPosition.x))
element.setAttribute(FIELD_PDF_Y_ATTR, String(field.pdfPosition.y))
element.setAttribute(FIELD_PDF_WIDTH_ATTR, String(field.pdfPosition.width))
element.setAttribute(FIELD_PDF_HEIGHT_ATTR, String(field.pdfPosition.height))
element.setAttribute(FIELD_PDF_COORDINATE_SYSTEM_ATTR, field.pdfPosition.coordinateSystem)
}
element.textContent = field.label
return element
@@ -109,10 +124,35 @@ export function readFieldFromElement(element: Element): SigningFieldDef | null {
// 没有 data-field 时用标签反查目录,签名位这类字段至少还能还原成正确的控件
const resolved = id ? null : resolveFieldByLabel(label)
const pdfPositionValues = [
element.getAttribute(FIELD_PDF_PAGE_ATTR),
element.getAttribute(FIELD_PDF_X_ATTR),
element.getAttribute(FIELD_PDF_Y_ATTR),
element.getAttribute(FIELD_PDF_WIDTH_ATTR),
element.getAttribute(FIELD_PDF_HEIGHT_ATTR),
]
const pdfNumbers = pdfPositionValues.map((value) => Number(value))
const hasPdfPosition = pdfPositionValues.every((value) => value !== null && value.trim() !== '')
const pdfCoordinateSystem = element.getAttribute(FIELD_PDF_COORDINATE_SYSTEM_ATTR)
const pdfPosition =
hasPdfPosition && pdfNumbers.every(Number.isFinite)
? {
page: pdfNumbers[0],
x: pdfNumbers[1],
y: pdfNumbers[2],
width: pdfNumbers[3],
height: pdfNumbers[4],
coordinateSystem:
pdfCoordinateSystem === 'PDF_BOTTOM_LEFT'
? ('PDF_BOTTOM_LEFT' as const)
: ('TOP_LEFT' as const),
}
: undefined
return {
id: id || (resolved as SigningFieldDef).id,
label: label || id,
kind: ((element.getAttribute(FIELD_KIND_ATTR) ?? resolved?.kind ?? 'text') as SigningFieldKind),
kind: (element.getAttribute(FIELD_KIND_ATTR) ?? resolved?.kind ?? 'text') as SigningFieldKind,
required:
element.getAttribute(FIELD_REQUIRED_ATTR) === 'true' ||
(!element.hasAttribute(FIELD_REQUIRED_ATTR) && resolved?.required === true),
@@ -122,6 +162,7 @@ export function readFieldFromElement(element: Element): SigningFieldDef | null {
.filter(Boolean),
multi: readMultiAttribute(element, resolved),
risk: element.getAttribute(FIELD_RISK_ATTR)?.trim() || resolved?.risk || undefined,
pdfPosition,
}
}
@@ -375,11 +416,7 @@ export interface ScannedFieldToken {
* 只对自定义文本项有意义(调用方保证),目录里的字段同名共用一份取值是刻意的。
* claimed 是有限集合、next 严格递增,所以循环一定收敛。
*/
function nextFreeCustomSequence(
label: string,
sequence: number,
claimed: Set<string>,
): number {
function nextFreeCustomSequence(label: string, sequence: number, claimed: Set<string>): number {
let next = sequence
while (claimed.has(createCustomField(label, 'text', [], next).id)) {