农业科技站群如何集成TinyMCE插件实现Word公式一键粘贴?

部署运行你感兴趣的模型镜像

项目需求分析与技术选型评估记录
日期:2023年X月X日
项目名称:国企政务网站后台管理系统升级(Word/微信内容集成)
负责人:XXX(黄山某国企项目负责人)

一、需求梳理与核心指标

  1. 功能需求

    • Word粘贴:从Office/WPS复制内容到TinyMCE编辑器,自动上传图片至华为云OBS(二进制存储),保留表格/字体/颜色等样式;
    • 微信内容粘贴:解析公众号文章HTML,自动下载图片并上传至OBS;
    • 文档导入:支持Word/Excel/PPT/PDF导入,保留图片和样式;
    • 信创兼容:覆盖国产操作系统(麒麟/统信UOS)和CPU架构(龙芯/飞腾/鲲鹏)。
  2. 技术约束

    • 前端:Vue2 + TinyMCE 5.x;
    • 后端:SpringBoot 2.7 + MySQL 8.0;
    • 存储:华为云OBS(需兼容阿里云/腾讯云等对象存储);
    • 授权模式:一次性买断(预算≤50万元)。

二、技术选型评估

1. 编辑器插件方案对比
方案优势风险点信创兼容性成本
TinyMCE官方插件原生集成,支持Word粘贴(paste插件),但需二次开发图片上传逻辑微信内容解析需自定义,文档导入需额外插件(如powerpaste,但授权费高)部分支持高(年费)
第三方SDK(如UEditor)功能全(支持文档导入),但基于jQuery,与Vue2集成复杂信创环境测试不充分,可能存在兼容性问题中(买断)
开源方案(wangeditor + 自定义扩展)完全可控,可针对信创环境优化开发周期长,需自行实现Word/微信内容解析低(自研)
商业组件(如Froala + 信创适配版)功能完善,提供买断授权,支持信创环境价格接近预算上限,需确认龙芯/MIPS架构支持高(买断)
开源组件(如WordPaster + 信创适配版)功能完善
开放源码(下载源码)
支持信创环境
支持多种编辑器
支持多种开发语言需要终端安装插件低(买断)

最终选择

  • 核心方案WordPaster + 源码版(兼顾功能与成本控制);
  • 辅助工具
    • 使用mammoth.js解析Word文档(纯前端解析,避免后端依赖);
    • 使用html-docx-js实现导出功能;
    • 微信内容解析通过正则匹配图片URL,结合axios下载并上传至OBS。

三、开发过程记录

1. 前端实现(Vue2 + TinyMCE)

关键代码:自定义插件集成

// src/components/Editor.vue
import tinymce from 'tinymce/tinymce';
import 'tinymce/plugins/paste';
import 'tinymce/plugins/table';
import 'tinymce/themes/silver';

export default {
  mounted() {
    tinymce.init({
      selector: '#editor',
      plugins: 'paste table advlist',
      toolbar: 'paste | formatselect | bold italic | alignleft aligncenter alignright',
      paste_data_images: true, // 允许粘贴图片(需配合自定义处理)
      paste_preprocess: (plugin, args) => {
        // 拦截粘贴内容,处理微信图片和Word样式
        const html = args.content;
        this.processWeChatImages(html).then(processedHtml => {
          args.content = processedHtml;
        });
      },
      images_upload_handler: (blobInfo, success) => {
        // 上传图片至华为云OBS
        const formData = new FormData();
        formData.append('file', blobInfo.blob(), blobInfo.filename());
        
        axios.post('/api/upload/obs', formData, {
          headers: { 'Authorization': 'Bearer ' + localStorage.token }
        }).then(res => {
          success(res.data.url); // 返回OBS访问URL
        });
      }
    });
  },
  methods: {
    async processWeChatImages(html) {
      // 正则匹配微信图片URL并替换为OBS地址
      const imgRegex = /]+src="([^"]+)"[^>]*>/g;
      let match;
      while ((match = imgRegex.exec(html)) !== null) {
        const imgUrl = match[1];
        if (imgUrl.includes('mp.weixin.qq.com')) {
          const blob = await this.downloadImage(imgUrl);
          const obsUrl = await this.uploadToOBS(blob);
          html = html.replace(imgUrl, obsUrl);
        }
      }
      return html;
    },
    downloadImage(url) {
      return axios.get(url, { responseType: 'blob' }).then(res => res.data);
    }
  }
};
2. 后端实现(SpringBoot + OBS SDK)

关键代码:图片上传接口

// src/main/java/com/example/controller/UploadController.java
@RestController
@RequestMapping("/api/upload")
public class UploadController {
    
    @Value("${obs.endpoint}")
    private String obsEndpoint;
    
    @Value("${obs.accessKey}")
    private String accessKey;
    
    @PostMapping("/obs")
    public ResponseEntity> uploadToOBS(@RequestParam("file") MultipartFile file) {
        String objectKey = "images/" + UUID.randomUUID() + "_" + file.getOriginalFilename();
        
        // 初始化OBS客户端(华为云SDK)
        ObsClient obsClient = new ObsClient(accessKey, "secretKey", obsEndpoint);
        obsClient.putObject("your-bucket", objectKey, file.getInputStream());
        
        Map result = new HashMap<>();
        result.put("url", "https://your-bucket.obs.cn-east-3.myhuaweicloud.com/" + objectKey);
        return ResponseEntity.ok(result);
    }
}

四、信创环境适配方案

  1. 操作系统兼容

    • 使用Electron打包前端为桌面应用,通过Wine兼容麒麟/统信UOS;
    • 后端部署于CentOS 7/8(x86/ARM)或Kylin V10(龙芯)。
  2. CPU架构优化

    • 编译时指定目标架构(如-march=loongarch64);
    • 使用OpenJDK的信创版本(如麒麟JDK)。
  3. 测试验证

    • 通过QEMU模拟龙芯/飞腾环境;
    • 使用信创浏览器(如360安全浏览器信创版)测试前端功能。

五、预算与授权模式

  1. 成本构成

    • TinyMCE商业版买断:约15万元(含信创适配支持);
    • 华为云OBS存储:按需付费(预估每年2万元);
    • 自研开发成本:约20万元(含测试与文档)。
  2. 授权协商

    • 与TinyMCE厂商签订永久授权协议,明确支持未来5年信创环境更新;
    • 要求提供源码级二次开发权限,避免供应商锁定。

六、风险与应对

  1. 微信内容解析稳定性

    • 风险:公众号HTML结构变更导致解析失败;
    • 应对:定期更新正则表达式,提供手动修正入口。
  2. 信创环境性能

    • 风险:龙芯MIPS架构下JavaScript执行效率低;
    • 应对:优化图片处理逻辑,减少前端计算量。

下一步计划

  • 完成POC(概念验证)环境搭建,重点测试龙芯+统信UOS组合;
  • 与华为云团队确认OBS SDK的国产化支持情况;
  • 启动商务谈判,锁定TinyMCE买断价格。

记录人:XXX
日期:2023年X月X日

复制插件

WordPaster插件文件夹

安装jquery

npm install jquery

在组件中引入

  // 引入tinymce-vue
  import Editor from '@tinymce/tinymce-vue'
  import {WordPaster} from '../../static/WordPaster/js/w'
  import {zyOffice} from '../../static/zyOffice/js/o'
  import {zyCapture} from '../../static/zyCapture/z'

添加工具栏

//添加导入excel工具栏按钮
(function () {
    'use strict';
    var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
    function selectLocalImages(editor) {        
      WordPaster.getInstance().SetEditor(editor).importExcel()
    }

    var register$1 = function (editor) {
      editor.ui.registry.addButton('excelimport', {
        text: '',
        tooltip: '导入Excel文档',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
      editor.ui.registry.addMenuItem('excelimport', {
        text: '',
        tooltip: '导入Excel文档',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
    };
    var Buttons = { register: register$1 };
    function Plugin () {
      global.add('excelimport', function (editor) {        
        Buttons.register(editor);
      });
    }
    Plugin();
}());

//添加word转图片工具栏按钮
(function () {
    'use strict';
    var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
    function selectLocalImages(editor) {        
      WordPaster.getInstance().SetEditor(editor);
      WordPaster.getInstance().importWordToImg()
    }

    var register$1 = function (editor) {
      editor.ui.registry.addButton('importwordtoimg', {
        text: '',
        tooltip: 'Word转图片',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
      editor.ui.registry.addMenuItem('importwordtoimg', {
        text: '',
        tooltip: 'Word转图片',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
    };
    var Buttons = { register: register$1 };
    function Plugin () {
      global.add('importwordtoimg', function (editor) {        
        Buttons.register(editor);
      });
    }
    Plugin();
}());

//添加粘贴网络图片工具栏按钮
(function () {
    'use strict';
    var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
    function selectLocalImages(editor) {        
      WordPaster.getInstance().SetEditor(editor);
      WordPaster.getInstance().UploadNetImg()
    }

    var register$1 = function (editor) {
      editor.ui.registry.addButton('netpaster', {
        text: '',
        tooltip: '网络图片一键上传',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
      editor.ui.registry.addMenuItem('netpaster', {
        text: '',
        tooltip: '网络图片一键上传',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
    };
    var Buttons = { register: register$1 };
    function Plugin () {
      global.add('netpaster', function (editor) {        
        Buttons.register(editor);
      });
    }
    Plugin();
}());

//添加导入PDF按钮
(function () {
    'use strict';
    var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
    function selectLocalImages(editor) {        
      WordPaster.getInstance().SetEditor(editor);
      WordPaster.getInstance().ImportPDF()
    }

    var register$1 = function (editor) {
      editor.ui.registry.addButton('pdfimport', {
        text: '',
        tooltip: '导入pdf文档',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
      editor.ui.registry.addMenuItem('pdfimport', {
        text: '',
        tooltip: '导入pdf文档',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
    };
    var Buttons = { register: register$1 };
    function Plugin () {
      global.add('pdfimport', function (editor) {        
        Buttons.register(editor);
      });
    }
    Plugin();
}());

//添加导入PPT按钮
(function () {
    'use strict';
    var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
    function selectLocalImages(editor) {        
      WordPaster.getInstance().SetEditor(editor);
      WordPaster.getInstance().importPPT()
    }

    var register$1 = function (editor) {
      editor.ui.registry.addButton('pptimport', {
        text: '',
        tooltip: '导入PowerPoint文档',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
      editor.ui.registry.addMenuItem('pptimport', {
        text: '',
        tooltip: '导入PowerPoint文档',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
    };
    var Buttons = { register: register$1 };
    function Plugin () {
      global.add('pptimport', function (editor) {        
        Buttons.register(editor);
      });
    }
    Plugin();
}());

//添加导入WORD按钮
(function () {
    'use strict';
    var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
    function selectLocalImages(editor) {        
      WordPaster.getInstance().SetEditor(editor).importWord()
    }

    var register$1 = function (editor) {
      editor.ui.registry.addButton('wordimport', {
        text: '',
        tooltip: '导入Word文档',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
      editor.ui.registry.addMenuItem('wordimport', {
        text: '',
        tooltip: '导入Word文档',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
    };
    var Buttons = { register: register$1 };
    function Plugin () {
      global.add('wordimport', function (editor) {        
        Buttons.register(editor);
      });
    }
    Plugin();
}());

//添加WORD粘贴按钮
(function () {
    'use strict';
    var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
    var ico = "http://localhost:8080/static/WordPaster/plugin/word.png"
    function selectLocalImages(editor) {
      WordPaster.getInstance().SetEditor(editor).PasteManual()
    }

    var register$1 = function (editor) {
      editor.ui.registry.addButton('wordpaster', {
        text: '',
        tooltip: 'Word一键粘贴',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
      editor.ui.registry.addMenuItem('wordpaster', {
        text: '',
        tooltip: 'Word一键粘贴',
        onAction: function () {
          selectLocalImages(editor)
        }
      });
    };
    var Buttons = { register: register$1 };
    function Plugin () {
      global.add('wordpaster', function (editor) {        
        Buttons.register(editor);
      });
    }
    Plugin();
}());

在线代码:

添加插件

// 插件
      plugins: {
          type: [String, Array],
          // default: 'advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars'
          default: 'autoresize code autolink autosave image imagetools paste preview table powertables'
      },

点击查看在线代码

初始化组件

// 初始化
WordPaster.getInstance({
    // 上传接口:http://www.ncmem.com/doc/view.aspx?id=d88b60a2b0204af1ba62fa66288203ed
    PostUrl: 'http://localhost:8891/upload.aspx',
    // 为图片地址增加域名:http://www.ncmem.com/doc/view.aspx?id=704cd302ebd346b486adf39cf4553936
    ImageUrl: 'http://localhost:8891{url}',
    // 设置文件字段名称:http://www.ncmem.com/doc/view.aspx?id=c3ad06c2ae31454cb418ceb2b8da7c45
    FileFieldName: 'file',
    // 提取图片地址:http://www.ncmem.com/doc/view.aspx?id=07e3f323d22d4571ad213441ab8530d1
    ImageMatch: ''
})

在页面中引入组件


功能演示

编辑器

在编辑器中增加功能按钮
TinyMCE编辑器界面

导入Word文档,支持doc,docx

粘贴Word和图片

导入Excel文档,支持xls,xlsx

粘贴Word和图片

粘贴Word

一键粘贴Word内容,自动上传Word中的图片,保留文字样式。
粘贴Word和图片

Word转图片

一键导入Word文件,并将Word文件转换成图片上传到服务器中。
导入Word转图片

导入PDF

一键导入PDF文件,并将PDF转换成图片上传到服务器中。
导入PDF转图片

导入PPT

一键导入PPT文件,并将PPT转换成图片上传到服务器中。
导入PPT转图片

上传网络图片

一键自动上传网络图片。
自动上传网络图片

下载示例

点击下载完整示例

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值