feat(文档库): 编辑器内渲染占位符与勾选框胶囊

This commit is contained in:
yelan
2026-09-18 13:03:11 +08:00
parent 8b1cbee16f
commit 9062d0b3c5
8 changed files with 841 additions and 11 deletions
@@ -7,6 +7,7 @@ import {
buildFieldToken,
collectFieldDefs,
findDuplicateFields,
SIGNING_FIELD_KIND_LABELS,
SIGNING_FIELD_PRESETS,
} from '@/utils/signing-fields'
@@ -138,13 +139,8 @@ const placeholderHints = computed(() => {
return hints
})
const kindLabels: Record<string, string> = {
text: '文本',
date: '日期',
choice: '单选',
checkbox: '勾选',
signature: '签名',
}
// 类型中文名与编辑器胶囊、签署端提示共用一份(utils/signing-fields)
const kindLabels = SIGNING_FIELD_KIND_LABELS
async function handleDocxChange(event: Event) {
const input = event.target as HTMLInputElement
@@ -349,6 +345,7 @@ function save() {
<span v-else class="docx-hint">
建议从 Word/WPS
中全选复制文书后直接粘贴到下方编辑区;需要患者勾选的内容可点上方「插入勾选框」按钮插入(光标停在表格单元格里就插到该单元格),或用表头含「勾选」列的表格承载。
占位符与勾选框在编辑区会显示成带类型标签的胶囊,便于和正文区分。
</span>
</div>
<p class="docx-header-note">
@@ -6,6 +6,11 @@ import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import type { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor/editor'
import { normalizePastedHtml } from '@/utils/rich-text'
import { decorateSigningMarkers, registerSigningEditorMarks } from '@/utils/signing-editor-marks'
// 渲染钩子是 wangEditor 的全局注册表,必须在编辑器创建前挂上,
// 否则首帧渲染出来的占位符/勾选框还是普通文字(要等下一次重渲染才变胶囊)。
registerSigningEditorMarks()
const props = defineProps<{
modelValue: string
@@ -58,6 +63,10 @@ const toolbarConfig: Partial<IToolbarConfig> = {
const editorConfig: Partial<IEditorConfig> = {
placeholder: '将 Word / WPS 中的文书内容直接粘贴到此处(保留表格与基本格式)。',
// 把 {患者姓名} 这类占位符与 □ 勾选框在编辑器里渲染成可辨识的胶囊,
// 而不是和正文一样的裸文字。只影响显示,不改 getHtml() 的输出,
// 保存 / 签署链路口径不变,细节见 utils/signing-editor-marks。
decorate: decorateSigningMarkers,
// 接管粘贴:优先使用剪贴板中的富 HTML(保留居中、加粗、表格等结构),
// 但先做归一化——Word 表格的绝对列宽与 nowrap 会让整表在窄容器里被裁切;
// 纯文本粘贴(无富 HTML)时返回 true 走默认处理。
@@ -194,4 +203,81 @@ onBeforeUnmount(() => {
.pane-content :deep(td p) {
margin: 0;
}
/* ---- 占位符 / 勾选框胶囊 ----
utils/signing-editor-marks 把 {患者姓名} 切成「{ / 患者姓名 / }」三段叶子、
把 □ 切成一 段叶子,这里负责把它们渲染成一眼能认出是"待签署内容"的形态。 */
/* 大括号:只缩小调淡,不移除。这两个字符必须留在 DOM 里参与光标偏移计算,
隐藏它们会让点击胶囊时的落点整体算错,也会让退格静默删掉看不见的字符 */
.pane-content :deep(.ms-sign-brace) {
color: var(--brand-m);
font-size: 0.78em;
opacity: 0.55;
}
/* 全角大括号自带很宽的边距,负外边距把它收紧到贴着胶囊,读起来才像一对括号 */
.pane-content :deep(.ms-sign-brace--open) {
margin-right: -0.18em;
}
.pane-content :deep(.ms-sign-brace--close) {
margin-left: -0.18em;
}
/* 占位符主体:带类型角标的胶囊 */
.pane-content :deep(.ms-sign-chip) {
display: inline-block;
padding: 0 6px;
color: var(--brand-d);
font-size: 0.92em;
font-weight: 700;
line-height: 1.65;
background: var(--brand-l);
border: 1px solid #bcd9e3;
border-radius: 4px;
}
/* 类型角标:签名/日期/文本……让科室不点开也知道这一项要填什么 */
.pane-content :deep(.ms-sign-chip)::after {
padding-left: 5px;
margin-left: 5px;
color: inherit;
font-size: 0.8em;
font-weight: 400;
content: attr(data-sign-tag);
border-left: 1px solid rgb(0 0 0 / 10%);
opacity: 0.7;
}
/* 必填项:角标转红并补一个星号,和下方「占位符检查」面板的口径一致 */
.pane-content :deep(.ms-sign-chip[data-sign-required='true'])::after {
color: var(--err);
content: attr(data-sign-tag) ' *';
opacity: 1;
}
/* 签名位是最不能漏的一项:与「插入签署占位符」按钮里的橙色区分保持一致 */
.pane-content :deep(.ms-sign-chip[data-sign-kind='signature']) {
color: #a96900;
background: #fff4e2;
border-color: #f0d5a8;
}
.pane-content :deep(.ms-sign-brace[data-sign-kind='signature']) {
color: #c08a3e;
opacity: 0.7;
}
/* 勾选框:签署时会转成可勾选控件,这里给它一个"框"的观感。
只上底色不加边框——□ 本身就是个方框,外面再套一圈边框会变成"框中框" */
.pane-content :deep(.ms-sign-box) {
padding: 0 4px;
color: var(--brand);
font-size: 1.05em;
font-weight: 700;
line-height: 1.45;
background: var(--brand-l);
border-radius: 3px;
}
</style>