package jnpf.bizcommon.onlyoffice.service.impl; import java.util.LinkedHashMap; import java.util.Map; /** Shared UI policy: preview and comparison must inherit the same menu defaults. */ final class OnlyOfficeUiConfig { private OnlyOfficeUiConfig() { } static Map previewCustomization() { return customization(false, false, true); } static Map previewPermissions() { return permissions(false, true, false, false); } /** 签批页禁止用户下载和打印,编辑器仍可在会话关闭时通过回调回写最终文件。 */ static Map qianpiyePermissions(boolean editable, boolean hideComments) { return permissions(editable, hideComments, false, false); } static Map permissions(boolean editable, boolean hideComments, boolean allowDownload, boolean allowPrint) { Map permissions = new LinkedHashMap<>(); permissions.put("edit", editable); // Both permission and customization switches are needed to hide comments. if (hideComments) { permissions.put("comment", false); permissions.put("review", false); } permissions.put("chat", false); permissions.put("download", allowDownload); permissions.put("print", allowPrint); // This supported permission hides Protection without white-label layout settings. permissions.put("protect", false); return permissions; } static void applyReviewPermissions(Map permissions) { permissions.put("edit", false); permissions.put("review", true); permissions.put("fillForms", false); permissions.put("comment", true); permissions.put("reviewGroups", java.util.Collections.emptyList()); permissions.put("editCommentAuthorOnly", true); permissions.put("deleteCommentAuthorOnly", true); permissions.put("modifyContentControl", false); } static void applyCommentPreviewPermissions(Map permissions) { permissions.put("edit", false); permissions.put("review", false); // With editorConfig.mode=view this exposes existing comments, never a writable session. permissions.put("comment", true); permissions.put("fillForms", false); permissions.put("modifyContentControl", false); } static void showReviewComments(Map customization, boolean writable) { customization.put("comments", true); customization.put("hideRightMenu", false); Map review = new LinkedHashMap<>(); review.put("showReviewChanges", true); review.put("reviewDisplay", "markup"); if (writable) review.put("trackChanges", true); customization.put("review", review); } /** * 编辑器界面裁剪。**必须在后端拼进 config**:customization 在 JWT 签名范围内, * 前端往 config 里塞字段会让 DS 验签失败(前端只能追加 events,函数不参与序列化)。 * *

两类考虑分开看: *

    *
  • 安全:{@code macros}/{@code plugins}。附件是用户上传的外来文档, * 可能带宏;插件(含 AI 入口)会把文档内容发往第三方,都不该默认开着。
  • *
  • 界面噪音:帮助、反馈、顶栏文件名(弹窗标题已经有了)、右侧面板。 * 这些纯属观感,改动无风险。
  • *
* *

⚠️ logo / about / layout 那一类属**白标定制**,社区版镜像大概率不生效,故此处不设—— * 需要的话得先实测再加,别写了以为生效。 * * @param editable 是否可编辑;forcesave/autosave 只在编辑态有意义,顶栏展开与否也随它变 */ static Map customization(boolean editable, boolean pluginsEnabled, boolean hideComments) { Map customization = new LinkedHashMap<>(); // ── 安全 ── // 外来 docx 可能带宏:不自动运行,且不给用户开的入口 customization.put("macros", false); customization.put("macrosMode", "disable"); // 仅后端白名单场景开启指定插件;空场景仍关闭全部插件入口。 customization.put("plugins", pluginsEnabled); // ── 界面收敛 ── // 默认关闭拼写检查;用户在界面修改后,localStorage 仍会覆盖这个初始值。 Map features = new LinkedHashMap<>(); features.put("spellcheck", false); customization.put("features", features); if (hideComments) { // 批注面板的另一半开关,与 permissions.comment=false 必须成对出现。 customization.put("comments", false); Map review = new LinkedHashMap<>(); review.put("trackChanges", false); review.put("showReviewChanges", false); customization.put("review", review); } customization.put("help", false); customization.put("feedback", false); // 左下角那个「提出功能建议」归 suggestFeature 管,不是 feedback(实测得知) customization.put("suggestFeature", false); // 顶栏不再重复显示文件名——我们的弹窗标题已经有了 customization.put("toolbarHideFileName", true); customization.put("hideRightMenu", true); // 顶栏形态按模式分:编辑态展开成完整功能区(工具找得到),只读态收成单行紧凑版 // (没有可用的编辑按钮,展开只是白占垂直空间)。这与 DS 自己的默认取向一致, // 但仍显式写出——默认值随版本变过,别指望省略。 // // ⚠️ 本项会被浏览器 localStorage 覆盖:用户手动折叠过顶栏,之后打开就一直是折叠的, // 后端传什么都不算数。验证时请换无痕窗口,别以为配置没生效。 customization.put("compactToolbar", !editable); customization.put("autosave", false); if (editable) { // forcesave:点保存即触发 status 6 回调,不必等全员退出才落盘 customization.put("forcesave", true); } return customization; } /** * 签批页保留后端签发并自动启动的标注插件,不保存中间版本。 * Docs 9.4 将 {@code customization.plugins} 同时用作插件运行时总开关;设为 false * 会让 autostart 失效,不能用它单独隐藏插件管理器入口。 */ static Map qianpiyeCustomization(boolean editable, boolean hideComments) { Map customization = customization(editable, true, hideComments); customization.put("autosave", false); customization.put("forcesave", false); return customization; } }