feat(signing): 正文手打方框在导入粘贴时转为结构化勾选项
This commit is contained in:
@@ -26,6 +26,6 @@
|
|||||||
* 工具栏、悬浮菜单、表格操作手柄等没有对应规则的地方仍按 vendor 自己的样式渲染。
|
* 工具栏、悬浮菜单、表格操作手柄等没有对应规则的地方仍按 vendor 自己的样式渲染。
|
||||||
*
|
*
|
||||||
* ⚠️ 换成别的编辑器引擎时,这里要跟着换成那个引擎的样式入口
|
* ⚠️ 换成别的编辑器引擎时,这里要跟着换成那个引擎的样式入口
|
||||||
* (EditorWangPane 的注释里列了换引擎要一并处理的三件事)。
|
* (换引擎要一并处理的几件事,列在 WordEditorDialog 里 EditorPaneHandle 的注释上)。
|
||||||
*/
|
*/
|
||||||
@import '@wangeditor/editor/dist/css/style.css' layer(vendor-editor);
|
@import '@wangeditor/editor/dist/css/style.css' layer(vendor-editor);
|
||||||
|
|||||||
@@ -199,6 +199,14 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 无名称的单个勾选框:正文里只剩一个 ☐(表格勾选列、无选项的勾选项),
|
||||||
|
点击区域会从上百像素缩到二十来像素,签署时不好点。
|
||||||
|
补一圈内边距把可点范围拉回来,外观上仍是"一个待勾的方框"。 */
|
||||||
|
.docopt.bare {
|
||||||
|
padding: 1px 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
/* ============ 存量兼容:表格勾选列与行内方框 ============ */
|
/* ============ 存量兼容:表格勾选列与行内方框 ============ */
|
||||||
|
|
||||||
.sign-doc-checkbox {
|
.sign-doc-checkbox {
|
||||||
|
|||||||
@@ -91,6 +91,13 @@ const OPTION_CLASS = 'docopt'
|
|||||||
const OPTION_TICK_CLASS = 'tick'
|
const OPTION_TICK_CLASS = 'tick'
|
||||||
/** 已勾选标记(原型 .docopt.on) */
|
/** 已勾选标记(原型 .docopt.on) */
|
||||||
const OPTION_ON_CLASS = 'on'
|
const OPTION_ON_CLASS = 'on'
|
||||||
|
/**
|
||||||
|
* 无名称的单个勾选框的附加类名。
|
||||||
|
*
|
||||||
|
* 去掉「待患者勾选」那句说明文字后,这一格只剩一个 ☐,点击区域从上百像素缩到二十来像素,
|
||||||
|
* 签署时患者不好点。样式里靠这个类把内边距补回来(见 styles/signing-document.css)。
|
||||||
|
*/
|
||||||
|
const OPTION_BARE_CLASS = 'bare'
|
||||||
/** 选项取值的载体属性;表格勾选列与行内方框也用同一个,回读时只认它 */
|
/** 选项取值的载体属性;表格勾选列与行内方框也用同一个,回读时只认它 */
|
||||||
const OPTION_VALUE_ATTR = 'data-sign-item'
|
const OPTION_VALUE_ATTR = 'data-sign-item'
|
||||||
/**
|
/**
|
||||||
@@ -101,7 +108,7 @@ const OPTION_VALUE_ATTR = 'data-sign-item'
|
|||||||
const GROUP_ATTR = 'data-sign-group'
|
const GROUP_ATTR = 'data-sign-group'
|
||||||
/**
|
/**
|
||||||
* 选项的显示名。与取值标识(data-sign-item)分开存:
|
* 选项的显示名。与取值标识(data-sign-item)分开存:
|
||||||
* 表格勾选列的取值标识是项目名,但那一格显示的是「待患者勾选」。
|
* 表格勾选列的取值标识是项目名,但那一格只显示一个 ☐。
|
||||||
* 切换勾选状态时要按显示名重建文案,所以它必须落成属性,不能从取值推。
|
* 切换勾选状态时要按显示名重建文案,所以它必须落成属性,不能从取值推。
|
||||||
*/
|
*/
|
||||||
const OPTION_TEXT_ATTR = 'data-sign-text'
|
const OPTION_TEXT_ATTR = 'data-sign-text'
|
||||||
@@ -236,20 +243,21 @@ function isMultiOptionGroup(field: SigningFieldDef): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选项的显示文案(原型 fillDocHtml / tickDocOpt 的同一口径):
|
* 选项的显示文案:勾选态用 ☑、未勾选用 ☐,空一格后跟选项名。
|
||||||
* 勾选态用 ☑、未勾选用 ☐,空一格后跟选项名。
|
|
||||||
*
|
*
|
||||||
* 没有选项名的单个勾选框(占位符只写了 kind=checkbox 却没配选项)用固定文案
|
* **没有选项名的单个勾选框只落一个符号**,不再补说明文字。
|
||||||
* 说明它的语义——原型就是这么写的,也让科室一眼看出这一处是"待勾"而不是漏了内容。
|
*
|
||||||
|
* 这是**有意偏离原型 V10.2**(2026-10-06 定):原型给无选项名的勾选框补
|
||||||
|
* 「☐ 待患者勾选」/「☑ 已勾选(结果固化归档)」,等于把方框当正文写。
|
||||||
|
* 而方框本身就是"这里要勾",这一处在勾什么由旁边的文字(表格的其它列、
|
||||||
|
* 正文的上一句)交代,补一句说明只会把版面挤开;编辑层同一处也只显示一个 ☑,
|
||||||
|
* 签署层补一句中文会让同一处控件两副长相。
|
||||||
|
* 字段名仍留在宿主 title 里,悬停可见。**别照原型改回去。**
|
||||||
*/
|
*/
|
||||||
function optionDisplay(value: string, on: boolean): string {
|
function optionDisplay(value: string, on: boolean): string {
|
||||||
const mark = on ? '☑' : '☐'
|
const mark = on ? '☑' : '☐'
|
||||||
|
|
||||||
if (value) {
|
return value ? `${mark} ${value}` : mark
|
||||||
return `${mark} ${value}`
|
|
||||||
}
|
|
||||||
|
|
||||||
return on ? `${mark} 已勾选(结果固化归档)` : `${mark} 待患者勾选`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -261,7 +269,7 @@ function optionDisplay(value: string, on: boolean): string {
|
|||||||
* 交互由签署端的事件委托完成(见 toggleOptionAt),所以这里只落一个 .tick 标记。
|
* 交互由签署端的事件委托完成(见 toggleOptionAt),所以这里只落一个 .tick 标记。
|
||||||
*
|
*
|
||||||
* displayValue 与 itemValue 分开:表格勾选列的项目名要写进 data-sign-item 当取值标识,
|
* displayValue 与 itemValue 分开:表格勾选列的项目名要写进 data-sign-item 当取值标识,
|
||||||
* 但那一格显示的是「待患者勾选」——项目名在左边那一列已经写过了,重复一遍反而挤。
|
* 但那一格只显示一个 ☐——项目名在左边那一列已经写过了,重复一遍反而挤。
|
||||||
*/
|
*/
|
||||||
function buildOptionItem(
|
function buildOptionItem(
|
||||||
doc: Document,
|
doc: Document,
|
||||||
@@ -271,7 +279,12 @@ function buildOptionItem(
|
|||||||
displayValue: string = itemValue,
|
displayValue: string = itemValue,
|
||||||
): HTMLElement {
|
): HTMLElement {
|
||||||
const item = doc.createElement('span')
|
const item = doc.createElement('span')
|
||||||
item.className = [OPTION_CLASS, on ? OPTION_ON_CLASS : '', interactive ? OPTION_TICK_CLASS : '']
|
item.className = [
|
||||||
|
OPTION_CLASS,
|
||||||
|
on ? OPTION_ON_CLASS : '',
|
||||||
|
interactive ? OPTION_TICK_CLASS : '',
|
||||||
|
displayValue ? '' : OPTION_BARE_CLASS,
|
||||||
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(' ')
|
.join(' ')
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
@@ -533,7 +546,7 @@ function renderStructuredFields(
|
|||||||
* 两种外观混在一篇文书里,会让人以为有一处没生效。
|
* 两种外观混在一篇文书里,会让人以为有一处没生效。
|
||||||
*
|
*
|
||||||
* 项目名仍写在 data-sign-item 上:它是这项勾选的**取值标识**,
|
* 项目名仍写在 data-sign-item 上:它是这项勾选的**取值标识**,
|
||||||
* 显示成「待患者勾选」只是因为它左边那一列已经写着项目名了。
|
* 格子里只显示一个 ☐——项目名在左边那一列已经写着,重复一遍反而挤。
|
||||||
*/
|
*/
|
||||||
function convertCheckboxTables(root: Element, interactive: boolean, selected: Set<string>) {
|
function convertCheckboxTables(root: Element, interactive: boolean, selected: Set<string>) {
|
||||||
const doc = root.ownerDocument
|
const doc = root.ownerDocument
|
||||||
|
|||||||
@@ -849,6 +849,167 @@ export function convertCheckboxColumnsToFields(contentHtml: string): string {
|
|||||||
return changed ? root.innerHTML : contentHtml
|
return changed ? root.innerHTML : contentHtml
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 匹配单个方框符号(SIGNING_OPTION_MARKERS 里的任意一个) */
|
||||||
|
const BOX_TEST_PATTERN = new RegExp(`[${SIGNING_OPTION_MARKERS}]`)
|
||||||
|
/** 方框转出来的勾选项取不到上下文名称时的兜底名称(与工具栏「勾选项」按钮同名) */
|
||||||
|
const DEFAULT_BOX_LABEL = '勾选项'
|
||||||
|
/** 选项名最长取多少字:方框后面若是一整句话,别把整句当成字段名 */
|
||||||
|
const BOX_LABEL_MAX_LENGTH = 20
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方框后第一段文字(到标点 / 空白为止)就是选项名。
|
||||||
|
*
|
||||||
|
* 与签署渲染期的 replaceOptionMarkers 用**同一条规则** —— 两边认出来的选项名必须一致,
|
||||||
|
* 否则「导入时按一套切分成组、签署渲染时又按另一套切分」会得到对不上的选项。
|
||||||
|
*/
|
||||||
|
function readOptionAfter(text: string, from: number): { label: string; end: number } {
|
||||||
|
const match = /^(\s*)([^\s。,、;:,.;:]*)/.exec(text.slice(from))
|
||||||
|
const leading = match?.[1]?.length ?? 0
|
||||||
|
const raw = match?.[2] ?? ''
|
||||||
|
|
||||||
|
return { label: raw.slice(0, BOX_LABEL_MAX_LENGTH), end: from + leading + raw.length }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取一个在本文书里没被占用的勾选项字段键。
|
||||||
|
* 与 allocateCustomFieldId 同款规则:同名的第二处往后编号,两处方框不会共用一份取值。
|
||||||
|
*/
|
||||||
|
function nextBoxField(
|
||||||
|
claimed: Set<string>,
|
||||||
|
label: string,
|
||||||
|
options: string[],
|
||||||
|
multi?: boolean,
|
||||||
|
): SigningFieldDef {
|
||||||
|
let sequence = 1
|
||||||
|
|
||||||
|
while (claimed.has(createCustomField(label, 'checkbox', options, sequence).id)) {
|
||||||
|
sequence += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const field = createCustomField(label, 'checkbox', options, sequence, multi)
|
||||||
|
claimed.add(field.id)
|
||||||
|
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 把一个文本节点里的方框换成结构化占位符;没有方框时返回 null,调用方据此跳过替换 */
|
||||||
|
function rewriteBoxesInText(
|
||||||
|
doc: Document,
|
||||||
|
text: string,
|
||||||
|
claimed: Set<string>,
|
||||||
|
): DocumentFragment | null {
|
||||||
|
const pattern = new RegExp(`[${SIGNING_OPTION_MARKERS}]`, 'g')
|
||||||
|
const boxes: Array<{ index: number; end: number; label: string }> = []
|
||||||
|
let match: RegExpExecArray | null
|
||||||
|
|
||||||
|
while ((match = pattern.exec(text)) !== null) {
|
||||||
|
const option = readOptionAfter(text, pattern.lastIndex)
|
||||||
|
boxes.push({ index: match.index, end: option.end, label: option.label })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!boxes.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const fragment = doc.createDocumentFragment()
|
||||||
|
const first = boxes[0]
|
||||||
|
const last = boxes[boxes.length - 1]
|
||||||
|
const options = boxes.map((box) => box.label).filter(Boolean)
|
||||||
|
|
||||||
|
// 同一处出现多个方框时合成一个勾选组:签署渲染期对这种情况本来就是按「互斥单选」处理的
|
||||||
|
// (convertInlineOptions 数方框个数 > 1 → radio),拆成两个独立勾选框会让患者把
|
||||||
|
// 「是」「否」同时勾上。
|
||||||
|
if (first && last && boxes.length > 1 && options.length > 1) {
|
||||||
|
fragment.appendChild(doc.createTextNode(text.slice(0, first.index)))
|
||||||
|
fragment.appendChild(
|
||||||
|
createFieldElement(doc, nextBoxField(claimed, DEFAULT_BOX_LABEL, options, false)),
|
||||||
|
)
|
||||||
|
fragment.appendChild(doc.createTextNode(text.slice(last.end)))
|
||||||
|
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单个方框:只换掉方框本身,后面的文字原样留在正文里(「□ 已阅读」→「[勾选框] 已阅读」)
|
||||||
|
let cursor = 0
|
||||||
|
|
||||||
|
boxes.forEach((box) => {
|
||||||
|
fragment.appendChild(doc.createTextNode(text.slice(cursor, box.index)))
|
||||||
|
fragment.appendChild(
|
||||||
|
createFieldElement(doc, nextBoxField(claimed, box.label || DEFAULT_BOX_LABEL, [])),
|
||||||
|
)
|
||||||
|
cursor = box.index + 1
|
||||||
|
})
|
||||||
|
|
||||||
|
fragment.appendChild(doc.createTextNode(text.slice(cursor)))
|
||||||
|
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把正文里科室手打的方框(□ / ☐ / Wingdings 私有区码位,见 SIGNING_OPTION_MARKERS)
|
||||||
|
* 替换成**结构化勾选占位符** —— 与工具栏「勾选项」按钮插出来的是同一种东西。
|
||||||
|
*
|
||||||
|
* 为什么要在导入 / 粘贴时转,而不是留到签署渲染再转(见 signing-document 的 convertInlineOptions):
|
||||||
|
* ① 渲染期那一步只改签署态的外观,编辑层里它始终是一段普通文字 —— 科室看到的是
|
||||||
|
* 「浅蓝小方块」,与插入的绿色胶囊两副长相,也点不开填写项配置;
|
||||||
|
* ② 转成占位符后它就是一个正常的填写项,可以改名称、类型、选项,与手工插入的没有区别。
|
||||||
|
*
|
||||||
|
* 取值规则照抄签署渲染期:方框后第一段文字(到标点为止)就是选项名。于是
|
||||||
|
* - 一块里只有一个方框 → 一个无选项的勾选框,方框被替换、后面的文字留在正文里;
|
||||||
|
* - 一块里有多个方框 → 合成一个勾选组(选项名进 data-options,显式 multi=false)。
|
||||||
|
*
|
||||||
|
* 只处理**同一个文本节点内**的方框:跨节点的方框(如 `<td>□<b>是</b> □否</td>`)罕见,
|
||||||
|
* 要重建多个文本节点才能合并,留给签署渲染期的启发式兜底,不做半吊子的合并。
|
||||||
|
*
|
||||||
|
* 已经结构化的占位符内部不扫:它的标签文字里可能带方框字符(如 {□} 那种旧写法)。
|
||||||
|
*/
|
||||||
|
export function convertInlineBoxesToFields(contentHtml: string): string {
|
||||||
|
if (!contentHtml || !BOX_TEST_PATTERN.test(contentHtml)) {
|
||||||
|
return contentHtml
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = new DOMParser().parseFromString(
|
||||||
|
`<div id="${SCAN_ROOT_ID}">${contentHtml}</div>`,
|
||||||
|
'text/html',
|
||||||
|
)
|
||||||
|
const root = parsed.getElementById(SCAN_ROOT_ID)
|
||||||
|
|
||||||
|
if (!root) {
|
||||||
|
return contentHtml
|
||||||
|
}
|
||||||
|
|
||||||
|
const claimed = collectStructuredIdsFrom(root)
|
||||||
|
const walker = parsed.createTreeWalker(root, NodeFilter.SHOW_TEXT)
|
||||||
|
const targets: Text[] = []
|
||||||
|
let node = walker.nextNode()
|
||||||
|
|
||||||
|
while (node) {
|
||||||
|
const text = node.textContent ?? ''
|
||||||
|
|
||||||
|
// 结构化占位符内部的文字是它自己的标签,不再当方框扫一遍
|
||||||
|
if (BOX_TEST_PATTERN.test(text) && !node.parentElement?.closest(FIELD_ELEMENT_SELECTOR)) {
|
||||||
|
targets.push(node as Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
node = walker.nextNode()
|
||||||
|
}
|
||||||
|
|
||||||
|
let changed = false
|
||||||
|
|
||||||
|
targets.forEach((textNode) => {
|
||||||
|
const replacement = rewriteBoxesInText(parsed, textNode.textContent ?? '', claimed)
|
||||||
|
|
||||||
|
if (!replacement) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
textNode.replaceWith(replacement)
|
||||||
|
changed = true
|
||||||
|
})
|
||||||
|
|
||||||
|
return changed ? root.innerHTML : contentHtml
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 给新插入的自定义文本项分配一个在本文书里唯一的字段键。
|
* 给新插入的自定义文本项分配一个在本文书里唯一的字段键。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
allocateCustomFieldId,
|
allocateCustomFieldId,
|
||||||
collectFieldDefs,
|
collectFieldDefs,
|
||||||
convertCheckboxColumnsToFields,
|
convertCheckboxColumnsToFields,
|
||||||
|
convertInlineBoxesToFields,
|
||||||
SIGNING_FIELD_KIND_LABELS,
|
SIGNING_FIELD_KIND_LABELS,
|
||||||
SIGNING_FIELD_PRESETS,
|
SIGNING_FIELD_PRESETS,
|
||||||
upgradeFieldTokensToStructured,
|
upgradeFieldTokensToStructured,
|
||||||
@@ -249,7 +250,11 @@ watch(
|
|||||||
// 打开时统一升级成结构化占位符(原子节点、一次退格整块删除)。
|
// 打开时统一升级成结构化占位符(原子节点、一次退格整块删除)。
|
||||||
// 升级沿用同一套解析口径,字段键前后完全一致,历史 fieldAnswers 不受影响;
|
// 升级沿用同一套解析口径,字段键前后完全一致,历史 fieldAnswers 不受影响;
|
||||||
// 正文里没有 { 时这一步原样返回,不会白白做一次 DOM 往返。
|
// 正文里没有 { 时这一步原样返回,不会白白做一次 DOM 往返。
|
||||||
valueHtml.value = upgradeFieldTokensToStructured(rawContent)
|
//
|
||||||
|
// 再把手打的方框(□)也换成结构化勾选项:这一步会改写正文,但存量模板里的 □
|
||||||
|
// 在签署渲染期本来就会被 convertInlineOptions 转成勾选控件,换成占位符只是把
|
||||||
|
// 同一件事提前到编辑期做,让科室在保存前就能核对、能改名称。
|
||||||
|
valueHtml.value = convertInlineBoxesToFields(upgradeFieldTokensToStructured(rawContent))
|
||||||
needConfirm.value = Boolean(props.template?.needConfirm)
|
needConfirm.value = Boolean(props.template?.needConfirm)
|
||||||
message.text = ''
|
message.text = ''
|
||||||
message.tone = ''
|
message.tone = ''
|
||||||
@@ -481,8 +486,11 @@ async function handleDocxChange(event: Event) {
|
|||||||
const mammoth = await import('mammoth/mammoth.browser')
|
const mammoth = await import('mammoth/mammoth.browser')
|
||||||
const result = await mammoth.convertToHtml({ arrayBuffer })
|
const result = await mammoth.convertToHtml({ arrayBuffer })
|
||||||
// 表头含「勾选」的表格在导入时就转成结构化占位符(原型 docCheckboxize 的口径),
|
// 表头含「勾选」的表格在导入时就转成结构化占位符(原型 docCheckboxize 的口径),
|
||||||
// 这样科室在保存前就能点开核对每一项勾选,而不是留一张看不出要勾哪儿的空表格
|
// 这样科室在保存前就能点开核对每一项勾选,而不是留一张看不出要勾哪儿的空表格。
|
||||||
const html = convertCheckboxColumnsToFields(result.value || '<p><br></p>')
|
// 再扫一遍手打的方框(表头不叫「勾选」、或直接写在格子里的 □),同样换成结构化勾选项。
|
||||||
|
const html = convertInlineBoxesToFields(
|
||||||
|
convertCheckboxColumnsToFields(result.value || '<p><br></p>'),
|
||||||
|
)
|
||||||
|
|
||||||
valueHtml.value = html
|
valueHtml.value = html
|
||||||
previewing.value = false
|
previewing.value = false
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
SIGN_FIELD_TYPE,
|
SIGN_FIELD_TYPE,
|
||||||
updateSignFieldNodes,
|
updateSignFieldNodes,
|
||||||
} from '@/utils/signing-field-node'
|
} from '@/utils/signing-field-node'
|
||||||
|
import { convertInlineBoxesToFields } from '@/utils/signing-fields'
|
||||||
|
|
||||||
// 这两个都是 wangEditor 的全局注册表,必须在编辑器创建前挂上:
|
// 这两个都是 wangEditor 的全局注册表,必须在编辑器创建前挂上:
|
||||||
// - 渲染钩子决定旧式 {…} 占位符与 □ 勾选框的显示(要等下一次重渲染才生效就晚了);
|
// - 渲染钩子决定旧式 {…} 占位符与 □ 勾选框的显示(要等下一次重渲染才生效就晚了);
|
||||||
@@ -131,7 +132,10 @@ const editorConfig: Partial<IEditorConfig> = {
|
|||||||
const html = event.clipboardData?.getData('text/html')
|
const html = event.clipboardData?.getData('text/html')
|
||||||
|
|
||||||
if (html) {
|
if (html) {
|
||||||
editor.dangerouslyInsertHtml(normalizePastedHtml(html))
|
// 归一化之后还要把科室手打的方框转成结构化勾选项:否则粘进来的 □ 只是被 decorate
|
||||||
|
// 标了个底色,与工具栏「勾选项」插出来的绿色胶囊两副长相,也点不开填写项配置。
|
||||||
|
// 放在这里而不是等保存,是为了让科室粘完当场就能看到、能核对。
|
||||||
|
editor.dangerouslyInsertHtml(convertInlineBoxesToFields(normalizePastedHtml(html)))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,7 +468,7 @@ onBeforeUnmount(() => {
|
|||||||
border-color: #c07f00;
|
border-color: #c07f00;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 勾选 / 选择:绿,并在标签前补一个 ☑(原型 .docfld.k-checkbox::before) */
|
/* 勾选 / 选择:绿(原型 .docfld.k-checkbox) */
|
||||||
.pane-content :deep(.ms-sign-node[data-sign-kind='checkbox']),
|
.pane-content :deep(.ms-sign-node[data-sign-kind='checkbox']),
|
||||||
.pane-content :deep(.ms-sign-node[data-sign-kind='choice']) {
|
.pane-content :deep(.ms-sign-node[data-sign-kind='choice']) {
|
||||||
color: #0b7a4b;
|
color: #0b7a4b;
|
||||||
@@ -472,7 +476,17 @@ onBeforeUnmount(() => {
|
|||||||
border-color: #0f9d6c;
|
border-color: #0f9d6c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pane-content :deep(.ms-sign-node[data-sign-kind='checkbox'])::before,
|
/* 勾选项在正文里就是**一个待勾的方框**,不带名称。
|
||||||
|
这是**有意偏离原型 V10.2**(2026-10-06 定):原型给勾选胶囊带【名称】,
|
||||||
|
而这一处在勾什么由旁边的文字交代(表格的其它列、正文的上一句),
|
||||||
|
自带一个【名称】只会把版面挤开;签署层渲染出来也只有一个 ☐,
|
||||||
|
编辑层挂着名称会让同一处控件在两层两副长相。
|
||||||
|
名称仍留在 title 里(见 utils/signing-field-node 的 renderSignField),悬停可见。 */
|
||||||
|
.pane-content :deep(.ms-sign-node[data-sign-kind='checkbox'])::before {
|
||||||
|
content: '\2611';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 单选仍带名称:一组单选(是 / 否)要靠名字才能分辨,去掉就只剩一个认不出的符号 */
|
||||||
.pane-content :deep(.ms-sign-node[data-sign-kind='choice'])::before {
|
.pane-content :deep(.ms-sign-node[data-sign-kind='choice'])::before {
|
||||||
content: '\2611 【' attr(data-sign-label) '】';
|
content: '\2611 【' attr(data-sign-label) '】';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user