合同模版 / 正文 OnlyOffice 高保真在线编辑集成说明
生成日期:2026-06-18 用途:解决「导入 Word 合同后在线预览/编辑,格式与原文档不一致」的问题。通过集成 OnlyOffice Document Server,实现 docx/pdf 的高保真在线编辑、预览与原样导出。
1. 背景与选型
此前合同模版正文走 mammoth.js(docx → HTML)+ TinyMCE 富文本路线。mammoth 是语义化转换器,会丢弃绝大多数 Word「直接格式」(标题居中/字号、首行缩进、两端对齐、悬挂缩进、复杂编号等),因此导入后排版与原文不一致,且调参无法根治。
最终选型 OnlyOffice Document Server:真·在线 Word,docx 预览/编辑/导出完美往返,是「自由在线编辑 + 高保真」的行业标准方案。原 HTML 富文本路线作为降级保留(未部署 OnlyOffice 时仍可用)。
2. 架构与数据流
text
浏览器(管理端) 后端(yudao) OnlyOffice Document Server
│ GET /contract/onlyoffice/config │ │
│ ─────────────────────────────────>│ 构建配置 + JWT 签名 │
│ <──────── config(含 token) ───────│ │
│ 加载 api.js,new DocEditor(config)──────────────────────────────>│
│ │ GET /download?token= (拉原文)
│ │<─────────────────────────────│
│ (用户在线编辑) │ │
│ │ POST /callback?token= (回存) │
│ │<─────────────────────────────│
│ │ 下载编辑后文件→FileApi 存储 │
│ │ 更新 contract_template.doc_file_url- 下载/回调接口用 JWT 令牌自校验,已
@PermitAll + @TenantIgnore,无需登录态。 - 编辑器配置整体用 OnlyOffice 的
JWT_SECRET签名(config.token),与文档服务器一致才放行。 - 保存为「新建文件」语义:回调把编辑后的文件存为新
fileUrl,并回写模版的docFileUrl;key随 URL 变化,避免文档服务器缓存旧版。
3. 后端实现
| 类 | 说明 |
|---|---|
framework/onlyoffice/config/OnlyOfficeProperties | yudao.onlyoffice.* 配置绑定 |
service/onlyoffice/OnlyOfficeService(Impl) | 构建编辑器配置+JWT、下载、回调回存 |
controller/admin/onlyoffice/OnlyOfficeController | enabled / config / download / callback |
ContractTemplateService#updateTemplateDocFileUrl | 回调回存时更新模版源文件地址 |
接口一览(前缀 /admin-api):
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
| GET | /contract/onlyoffice/enabled | 登录 | 是否启用 |
| GET | /contract/onlyoffice/config | 登录 | 获取编辑器配置 |
| GET | /contract/onlyoffice/download | 放行(JWT) | 供文档服务器拉原文 |
| POST | /contract/onlyoffice/callback | 放行(JWT) | 文档服务器保存回调 |
4. 后端配置(application.yaml)
yaml
yudao:
onlyoffice:
enabled: false # 部署好后改为 true
server-url: http://localhost:8081 # 浏览器可访问的文档服务器地址
jwt-secret: ruoyi-office-onlyoffice-secret # 必须与 Document Server 的 JWT_SECRET 一致
callback-base-url: http://host.docker.internal:48080 # 文档服务器容器回访后端的地址callback-base-url:文档服务器容器视角能访问到后端的地址。- Windows/Mac 本机 Docker:
http://host.docker.internal:48080 - Linux 服务器:写后端的真实可达 IP,如
http://192.168.1.10:48080
- Windows/Mac 本机 Docker:
server-url:浏览器视角的文档服务器地址,生产建议域名 + HTTPS。
5. 部署 OnlyOffice Document Server
bash
cd ruoyi-office/script/docker
docker compose -f docker-compose.onlyoffice.yml up -d
# 访问 http://<宿主机IP>:8081/ 看到欢迎页即成功注意:
JWT_SECRET与后端jwt-secret必须完全一致。- 容器要能访问后端(验证:进容器
curl http://host.docker.internal:48080/admin-api/...)。 - Linux 用
host.docker.internal时,给服务加extra_hosts: ['host.docker.internal:host-gateway'](compose 内已注释,按需开启)。
6. 前端实现
| 文件 | 说明 |
|---|---|
src/api/contract/onlyoffice/index.ts | isOnlyOfficeEnabled / getOnlyOfficeConfig |
src/components/onlyoffice-editor/index.vue | 动态加载 api.js + new DocsAPI.DocEditor |
src/views/contract/template/editor/index.vue | 模版「配置」页集成:启用且有 Word 源文件时默认走高保真 |
模版配置页右上角提供「高保真(Word) / 富文本(HTML)」切换;Word 模式下编辑由文档服务器自动保存(autosave + forcesave)。
7. 占位符约定(与起草联动,二期)
在 Word 中以 文本标注占位符(排版 100% 保留)。起草选模版时,后端用占位值做 docx 文本替换生成合同正文,再用 OnlyOffice 预览/编辑。该填充能力(poi-tl/docx4j)将在二期补充,对应预留接口 ContractOnlyOfficeAdapter。
8. 排错速查
| 现象 | 排查 |
|---|---|
| 编辑器空白 / api.js 加载失败 | server-url 浏览器是否可达;是否被混合内容(HTTP/HTTPS)拦截 |
| 提示 token 无效 | 后端 jwt-secret 与容器 JWT_SECRET 是否一致 |
| 文档打不开(下载失败) | callback-base-url 在容器内是否可达后端;/download 是否被网关拦截 |
| 编辑后不保存 | 容器能否 POST 到 /callback;后端日志 [onlyoffice callback] |
| 中文乱码 | 容器时区/语言;本集成已设 lang=zh-CN |
