fix(document): 统一编辑器与文书纸的排版和字体口径

This commit is contained in:
yelan
2026-09-30 11:20:27 +08:00
parent 3628c5ed86
commit 1d271ef1bd
10 changed files with 268 additions and 63 deletions
@@ -1,11 +1,24 @@
<script setup lang="ts">
import '@wangeditor/editor/dist/css/style.css'
/**
* 文书编辑器(WangEditor 引擎)。
*
* **编辑面就是一张「纸」**:编辑器根节点同时挂 `pane-content`(纸壳里的白纸)与
* `doc-paper`(utils/document-paper.ts 里那份唯一排版)—— 编辑时看到的段落间距、
* 表格内边距、字号字体,与签署预览、签署工作台、导出的 PDF 完全同一份来源。
*
* 为什么还要绕一层 styles/editor-vendor.css:WangEditor 自带一套权重更高的正文默认
* (`p{margin:15px 0}` 等),会把那份排版盖掉。它整包被压进最低优先级的 cascade layer,
* 于是 `.doc-paper p` 这类规则不必写 !important 也能生效。细节见那个文件。
*/
import '@/styles/editor-vendor.css'
import { onBeforeUnmount, shallowRef } from 'vue'
import { onBeforeUnmount, ref, shallowRef } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { DomEditor } from '@wangeditor/editor'
import type { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor/editor'
import { loadDocumentFont } from '../../../../../../../packages/document-fonts'
import { getDefaultDocumentFont } from '@/api/management/document-fonts'
import type { SigningFieldDef } from '@/api/workbench/types'
import { normalizePastedHtml } from '@/utils/rich-text'
import { decorateSigningMarkers, registerSigningEditorMarks } from '@/utils/signing-editor-marks'
@@ -40,6 +53,34 @@ const editorRef = shallowRef<IDomEditor>()
const editableRef = shallowRef<Element | null>(null)
const editorMode = 'default'
/**
* 文书字体(后台「文书字体设置」里配置的默认字体)。
*
* 加载口径与 DocumentPaper 完全一致:**同一个默认字体**。少了这一道,
* 后台配了仿宋/楷体时会出现「编辑器里是微软雅黑、签出来是仿宋」——
* 同一份文书两副长相,而且换行位置也会跟着变。
*
* 用 ref 而不是直接等:字体是网络请求,加载完再挂 .managed-font,
* 加载失败就退回全局字体(编辑不受影响,只是字体与签署态不一致)。
* 不做「转圈等字体」:编辑器要能立刻编辑,不能因为一个字体把人挡在门外。
*/
const fontFamily = ref('')
async function prepareFont() {
try {
const font = await getDefaultDocumentFont()
const family = await loadDocumentFont(font, import.meta.env.VITE_API_BASE_URL || '/api')
if (family) {
fontFamily.value = family
}
} catch {
fontFamily.value = ''
}
}
void prepareFont()
/**
* 用户是否真的把光标放进过正文。
*
@@ -258,11 +299,17 @@ onBeforeUnmount(() => {
`.pane-desk` 提供灰底与唯一滚动条;
`.pane-sheet` 负责限宽居中 —— % 页边距以**包含块**宽度为基准,
限宽必须落在这里,落到纸上就会按更宽的桌面算(页边距偏大);
`.pane-content` 才是白纸本身(A4 比例 + 页边距)。 -->
`.pane-content` 才是白纸本身(A4 比例 + 页边距)。
`doc-paper` 是**唯一那份正文排版**的根类(utils/document-paper.ts):
白纸壳与编辑面各自挂一次,段落 / 标题 / 表格 / 字体的口径因此只有一份。
WangEditor 自己的 DOM(`.w-e-text-container`、`[data-slate-editor]`)会挂在
这层下面,所以那份排版是**继承**进去的,不是另抄一份。 -->
<div class="pane-desk">
<div class="pane-sheet">
<Editor
class="pane-content"
class="pane-content doc-paper"
:class="{ 'managed-font': Boolean(fontFamily) }"
:style="{ '--document-font': fontFamily }"
:model-value="props.modelValue"
:default-config="editorConfig"
:mode="editorMode"
@@ -328,9 +375,13 @@ onBeforeUnmount(() => {
}
/* 空文档提示绝对定位于纸的内层容器,WangEditor 自带一点偏移(实测右下各偏 ~10/17px),
这里拉回版心原点,否则空文档时提示文字不与正文左边界对齐 */
这里拉回版心原点,否则空文档时提示文字不与正文左边界对齐。
`color: inherit` 同理:WangEditor 在这个容器上写死了自己的正文色(#333),
而纸的正文色是 #1c2b33 —— 与字号字体一样,正文色也只该有纸那一份口径。
这里用 inherit 透传、不复述颜色值,颜色仍然只有 .doc-paper 一处定义。 */
.pane-content :deep(.w-e-text-container) {
padding: 0;
color: inherit;
}
.pane-content :deep(.w-e-text-placeholder) {
@@ -342,27 +393,11 @@ onBeforeUnmount(() => {
padding: 0;
}
/* 粘贴的 Word 表格:解除绝对列宽、允许单元格换行,
超出容器时横向滚动而不是被裁切 */
.pane-content :deep(table) {
width: 100%;
border-collapse: collapse;
table-layout: auto;
}
.pane-content :deep(th),
.pane-content :deep(td) {
padding: 4px 6px;
vertical-align: top;
border: 1px solid #52646e;
overflow-wrap: anywhere;
word-break: break-word;
}
.pane-content :deep(th p),
.pane-content :deep(td p) {
margin: 0;
}
/* 表格(width / border-collapse / table-layout / 边框色 / 单元格内边距 / 换行策略)
不再在这里写第二份 —— 编辑面挂着 doc-paper,吃的是 utils/document-paper.ts 里
唯一那一份。这里曾经各写一套(4px 6px / vertical-align: top),
结果「编辑时看到的表格」与「预览、签署时看到的表格」不是同一张。
粘进来的 Word 表格的绝对列宽由 utils/rich-text.ts 的 normalizePastedHtml 解除。 */
/* ---- 占位符 / 勾选框胶囊 ----
配色与形状照原型 V10.2 的 .docfld(见 styles/signing-document.css 里签署态的同一套色):