feat(签署文书): 统一签署态文书样式并精简演示种子为单份麻精同意书
This commit is contained in:
+32
-199
@@ -4,11 +4,15 @@ import { computed, onMounted, ref, watch } from 'vue'
|
||||
import type { SigningAnswers, SigningTaskRecord } from '@/api/workbench/types'
|
||||
import {
|
||||
applyAnswerToFieldHost,
|
||||
applySelectedItemsToRoot,
|
||||
applySignatureToRoot,
|
||||
buildSigningDocumentHtml,
|
||||
collectSelectedItemsFromRoot,
|
||||
describeFieldProgress,
|
||||
OPTION_TICK_SELECTOR,
|
||||
readAnswersFromRoot,
|
||||
SIGNATURE_ACTION_SELECTOR,
|
||||
toggleOptionAt,
|
||||
type SigningDocumentData,
|
||||
type SigningFieldProgress,
|
||||
type SigningSignatureRequest,
|
||||
@@ -92,8 +96,8 @@ const signatureStateLabel = computed(() => {
|
||||
})
|
||||
|
||||
/**
|
||||
* 从渲染后的 DOM 读回填写项取值。
|
||||
* 生成 HTML 时已把取值写成 attribute,这里再按取值同步一次 DOM 状态,
|
||||
* 从渲染后的 DOM 读回填写项取值与勾选清单。
|
||||
* 生成 HTML 时已把取值写成属性/文本,这里再按取值同步一次 DOM 状态,
|
||||
* 保证「签完再打开时填写项/勾选还在」这件事不依赖序列化细节。
|
||||
*/
|
||||
function syncFromDom() {
|
||||
@@ -106,17 +110,13 @@ function syncFromDom() {
|
||||
const answers = readAnswersFromRoot(container)
|
||||
fieldAnswers.value = answers
|
||||
progress.value = describeFieldProgress(container, answers)
|
||||
|
||||
const checked = Array.from(
|
||||
container.querySelectorAll<HTMLInputElement>('input.sign-doc-checkbox:checked'),
|
||||
)
|
||||
selectedItems.value = checked.map((item) => item.getAttribute('data-sign-item') ?? '')
|
||||
selectedItems.value = collectSelectedItemsFromRoot(container)
|
||||
|
||||
emit('field-change', { ...answers }, { ...progress.value })
|
||||
emit('selection-change', [...selectedItems.value])
|
||||
}
|
||||
|
||||
/** 按已固化的取值还原 DOM 控件状态(存量勾选表 + 新填写项都覆盖) */
|
||||
/** 按已固化的取值还原 DOM 状态(存量勾选表 + 新填写项都覆盖) */
|
||||
function applyStoredValues() {
|
||||
const container = containerRef.value
|
||||
|
||||
@@ -124,11 +124,7 @@ function applyStoredValues() {
|
||||
return
|
||||
}
|
||||
|
||||
const selected = new Set(props.task.selectedItems ?? [])
|
||||
|
||||
container.querySelectorAll<HTMLInputElement>('input.sign-doc-checkbox').forEach((input) => {
|
||||
input.checked = selected.has(input.getAttribute('data-sign-item') ?? '')
|
||||
})
|
||||
applySelectedItemsToRoot(container, props.task.selectedItems ?? [])
|
||||
|
||||
const answers: SigningAnswers = { ...(props.task.fieldAnswers ?? {}) }
|
||||
|
||||
@@ -145,7 +141,7 @@ function applyStoredValues() {
|
||||
}
|
||||
|
||||
// 读写的判据都在 signing-document 里(readAnswersFromRoot 的镜像),
|
||||
// 这里不自己写 data-sign-* 选择器,否则多选组这类"同 DOM 不同语义"的控件会两处漂移
|
||||
// 这里不自己写 data-sign-* 选择器,否则选项组这类"同 DOM 不同语义"的控件会两处漂移
|
||||
applyAnswerToFieldHost(host, value)
|
||||
})
|
||||
}
|
||||
@@ -189,11 +185,30 @@ function requestSignature(host: HTMLElement) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击文书里的 ☑ / ☐ 选项。
|
||||
*
|
||||
* 与签名位分开处理:签名位是"请求采集"(要弹签字板),选项是就地切换。
|
||||
* 切换逻辑本身在 utils/signing-document 的 toggleOptionAt 里,
|
||||
* 组件只负责把点击翻译成一次调用 —— 单选互斥的判据不该在组件里再推一遍。
|
||||
*/
|
||||
function handleDocumentClick(event: MouseEvent) {
|
||||
if (!props.interactive) {
|
||||
return
|
||||
}
|
||||
|
||||
const target = event.target
|
||||
|
||||
if (target instanceof Element) {
|
||||
const option = target.closest<HTMLElement>(OPTION_TICK_SELECTOR)
|
||||
const container = containerRef.value
|
||||
|
||||
if (option && container && toggleOptionAt(container, option)) {
|
||||
syncFromDom()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const host = resolveSignatureHost(event.target)
|
||||
|
||||
if (host) {
|
||||
@@ -439,189 +454,7 @@ defineExpose({ getDocumentElement })
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* 固定页眉:患者基本信息由 HIS 自动带出,与正文之间用一条横线分隔。
|
||||
四项要在一行内放下,取值下划线的宽度由字段定义给出(内联 min-width),样式里不再写死 */
|
||||
.sign-doc-body :deep(.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-body :deep(.sign-doc-header__item) {
|
||||
display: inline-flex;
|
||||
gap: 3px;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-doc-header__label) {
|
||||
flex-shrink: 0;
|
||||
color: #52646e;
|
||||
font-size: 12.5px;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-doc-header__value) {
|
||||
padding: 0 5px 1px;
|
||||
color: #1c2b33;
|
||||
font-size: 12.5px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #52646e;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-doc-checkbox) {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
accent-color: var(--brand);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-doc-checkbox:disabled) {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
/* 正文行内选项(□否 □是):用 label 包住方框与选项文字,点文字也能选中 */
|
||||
.sign-doc-body :deep(.sign-doc-option) {
|
||||
display: inline-flex;
|
||||
gap: 3px;
|
||||
align-items: center;
|
||||
margin-right: 14px;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-doc-signature) {
|
||||
max-width: 150px;
|
||||
max-height: 52px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* ===== 填写项 ===== */
|
||||
.sign-doc-body :deep(.sign-field) {
|
||||
display: inline-flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
padding: 2px 7px;
|
||||
margin: 0 2px;
|
||||
vertical-align: middle;
|
||||
background: #f7fbfd;
|
||||
border: 1px solid #d4e3e8;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field__label) {
|
||||
flex-shrink: 0;
|
||||
color: #587786;
|
||||
font-size: 11.5px;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field__required) {
|
||||
margin-left: 2px;
|
||||
color: var(--err);
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field__control) {
|
||||
display: inline-flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field__input) {
|
||||
width: 9em;
|
||||
min-width: 0;
|
||||
padding: 1px 5px;
|
||||
color: #1c2b33;
|
||||
font: inherit;
|
||||
font-size: 12.5px;
|
||||
background: #fff;
|
||||
border: 1px solid #cfe0e6;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field__input:focus) {
|
||||
border-color: var(--brand);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field__input:disabled) {
|
||||
color: #1c2b33;
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
opacity: 1;
|
||||
-webkit-text-fill-color: #1c2b33;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field__choices) {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field__radio),
|
||||
.sign-doc-body :deep(.sign-field__checkbox) {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
accent-color: var(--brand);
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field__signature-empty) {
|
||||
padding: 12px 18px;
|
||||
color: #a96900;
|
||||
font-size: 11px;
|
||||
background: #fff9ec;
|
||||
border: 1px dashed #f0a21a;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 可点击采集的签名位:整块胶囊都是点击热区(子节点会冒泡到宿主),
|
||||
hover / 聚焦给出明确反馈,否则操作人员不知道这里能点 */
|
||||
.sign-doc-body :deep(.sign-field--actionable) {
|
||||
cursor: pointer;
|
||||
background: #fffaf0;
|
||||
border-color: #f0a21a;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field--actionable:hover) {
|
||||
background: #fff3d8;
|
||||
border-color: #d98c05;
|
||||
box-shadow: 0 0 0 2px rgb(240 162 26 / 20%);
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field--actionable:focus-visible) {
|
||||
outline: 2px solid var(--brand);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field--actionable .sign-field__signature-empty) {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 签名位比其他填写项更宽,避免签名图被压扁 */
|
||||
.sign-doc-body :deep(.sign-field--signature) {
|
||||
padding: 3px 8px;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field--signature .sign-field__control) {
|
||||
min-width: 150px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field--abnormal) {
|
||||
background: #fdf0f0;
|
||||
border-color: #efb9bb;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field--abnormal .sign-field__label) {
|
||||
color: #a42e34;
|
||||
}
|
||||
|
||||
.sign-doc-body :deep(.sign-field__badge) {
|
||||
padding: 1px 6px;
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
background: var(--err);
|
||||
border-radius: 8px;
|
||||
}
|
||||
/* 填写项胶囊、选项 ☑ / ☐、系统页眉的样式在 styles/signing-document.css(全局):
|
||||
它们同时出现在文书库预览、签署工作台与编辑器里,各写一份必然漂移。
|
||||
这里只保留"这份文书外壳"自己的版式(正文字号、表格边框等)。 */
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user