Tinymce富文本添加word导入的支持

在前端使用导入Word文档并自动解析成html再插入到tinymce编辑器中,可以使用mammoth.js识别Word内容转换为Html并set到编辑器中,使用mammoth只可解析.docx格式的Word,目前的mammoth不支持.doc格式,后续升级也许会加上解析doc的功能。
mammoth.js转换word为html丢失了好多样式,因此不推荐使用,建议统一交由后端转换
如果使用了是Tinymce5,建议直接使用https://github.com/tinymce-plugin/tinymce-plugin 这个插件,效果也不错,但是只支持docx,官方示例地址:https://tinymce-plugin.gitee.io/packages/tp-importword/tpImporatwordDemo.html

为什么解析不了.doc
  • .docx 格式的 Word 文档是一种基于 XML 和 ZIP 压缩技术的文件格式,其文件结构相对固定并且较为简单,可以通过一些开源的 JavaScript 库进行解析和转换。`
    ·
  • .doc 格式的 Word 文档是一种相对来说版本比较老一点并且是二进制格式的文件,文件结构比较复杂,具有较高的私有性和细节,需要专用微软 Office 应用程序才能完整读取。

Tinymce 支持调整

1.添加按钮

在init的setup中添加按钮

import mammoth from "mammoth";
import { ContentTypeEnum } from '@/api/types'
import http from '@/api'

......
    // init中其余的配置[略]
    setup: function (editor: any) {
      editor.ui.registry.addIcon('importword','<svg t="1604625110140" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14669" width="24" height="24"><path d="M546.21184 76.9024a30.72 30.72 0 0 1 21.70368 8.9856l248.22784 247.75168a30.72 30.72 0 0 1 9.0112 21.74464v163.3792a10.24 10.24 0 0 1-10.24 10.24h-51.712a10.24 10.24 0 0 1-10.24-10.24v-109.568h-232.448a30.72 30.72 0 0 1-30.72-30.72v-229.888h-330.752v726.016h438.272a10.24 10.24 0 0 1 10.24 10.24v51.2a10.24 10.24 0 0 1-10.24 10.24h-478.72a30.72 30.72 0 0 1-30.72-30.72V107.6224a30.72 30.72 0 0 1 30.72-30.72h427.61728z m197.84192 531.712l-171.40736 141.43488a30.72 30.72 0 0 0 0 47.39072l171.40736 141.43488a10.24 10.24 0 0 0 14.2848-1.2288l36.01408-41.95328a10.24 10.24 0 0 0-1.6128-14.848l-94.68416-71.26016h232.43264a10.24 10.24 0 0 0 10.24-10.24v-51.2a10.24 10.24 0 0 0-10.24-10.24h-232.448l94.69952-71.26016a10.24 10.24 0 0 0 1.6128-14.848l-36.01408-41.95328a10.24 10.24 0 0 0-14.2848-1.2288z m-323.8912-224.512a10.24 10.24 0 0 1 10.24 10.24v51.2a10.24 10.24 0 0 1-10.24 10.24h-190.464a10.24 10.24 0 0 1-10.24-10.24v-51.2a10.24 10.24 0 0 1 10.24-10.24h190.464z m141.312-207.36v155.648a5.12 5.12 0 0 0 5.12 5.12h155.648l-160.768-160.768zM276.48 542.72l37.888 171.008 45.056-171.008h59.904l43.52 173.568 38.4-173.568h50.688l-60.928 248.832H437.76l-49.664-185.856-49.664 185.856H284.16L225.28 542.72h51.2z m143.68768-292.2496a10.24 10.24 0 0 1 10.24 10.24v51.2a10.24 10.24 0 0 1-10.24 10.24h-190.464a10.24 10.24 0 0 1-10.24-10.24v-51.2a10.24 10.24 0 0 1 10.24-10.24h190.464z" fill="#333"></path></svg>');
      // 注册自定义按钮
      editor.ui.registry.addButton("customImportwordBtn", {
        // text: "上传Word",
        icon: 'importword',
        onAction: function () {
          var input = document.createElement("input");
          input.type = "file";
          input.accept = ".doc,.docx";
          // 执行上传文件操作
          input.addEventListener("change", handleFileSelect, false);

          // 获取上传文件base64数据
          function arrayBufferToBase64(arrayBuffer: any) {
            var binary = "";
            var bytes = new Uint8Array(arrayBuffer);
            var len = bytes.byteLength;
            for (var i = 0; i < len; i++) {
              binary += String.fromCharCode(bytes[i]);
            }
            return window.btoa(binary);
          }

          function handleFileSelect(event) {
            var file = event.target.files[0];
            //获取上传文件后缀,如果是docx格式,则使用mammoth来进行解析,
            //如果不是则访问后台,将文件传输流base64传递到后台
            //生成文件,然后用java解析doc,并返回到前台
            var extension = file.name.slice(
              ((file.name.lastIndexOf(".") - 1) >>> 0) + 2
            );
            if (extension === "docx") {
              readFileInputEventAsArrayBuffer(event, function (arrayBuffer: any) {
                var base64Data = arrayBufferToBase64(arrayBuffer);
                console.log(base64Data);
                mammoth
                  .convertToHtml({ arrayBuffer: arrayBuffer }, { ignoreEmptyParagraphs: false, })
                  .then(displayResult, function (error: any) {
                    console.error(error);
                  });
              });
            } else if (extension === "doc") {
              let formData = new FormData()
              formData.append('file', file)
              http
                .post<string>(`/WordToHtml`, formData, {
                  headers: { 'Content-Type': ContentTypeEnum.FORM_DATA },
                })
                .then((json: any) => {
                  tinymceInstance.activeEditor.setContent(json.Data);
                })
                .catch((err) => {
                  console.log(err);
                })

              // readFileInputEventAsArrayBuffer(event, function (arrayBuffer:any) {
              //   //base64文件流
              //   var base64Data = arrayBufferToBase64(arrayBuffer);
              //   var result = "后台请求";
              //   alert(result);
              //   console.log(base64Data);
              // });
              // //tinymce的set方法将内容添加到编辑器中
              // tinymceInstance.activeEditor.setContent(result);
            }
          }

          function displayResult(result) {
            //tinymce的set方法将内容添加到编辑器中
            tinymceInstance.activeEditor.setContent(result.value);
          }

          function readFileInputEventAsArrayBuffer(event, callback) {
            var file = event.target.files[0];
            var reader = new FileReader();
            reader.onload = function (loadEvent) {
              var arrayBuffer = loadEvent.target.result;
              callback(arrayBuffer);
            };
            reader.readAsArrayBuffer(file);
          }

          // 触发点击事件,打开选择文件的对话框
          input.click();
        },
      });
    },
......

2.在按钮的栏目下显示新添加的按钮
  toolbar: () => [
    'print preview fullscreen | customImportwordBtn',
  ],

3.后端接口,使用.Net写的,分别尝试了Aspose和Spire,结果是Aspose的转换效果更好

        public IActionResult WordToHtml(IFormFile file)
        {
            string fileName = file.FileName;
            string fileExtension = fileName.Substring(fileName.LastIndexOf(".") + 1);

             Document document = null;
             if (fileExtension.Equals("doc"))
             {
                 document = new Document(file.OpenReadStream(),new LoadOptions(){LoadFormat = LoadFormat.Doc});
             }
             else if (fileExtension.Equals("docx"))
             {
                 document = new Document(file.OpenReadStream(),new LoadOptions(){LoadFormat = LoadFormat.Docx});
             }
             else
             {
                 return new JsonResult(new
                 {
                     Msg = "不被支持的文档类型!"
                 });
             }
             
             HtmlSaveOptions options = new (SaveFormat.Html);
             options.ExportImagesAsBase64 = true;
             MemoryStream stream = new();
             document.Save(stream, options);
             stream.Position = 0;

             StreamReader reader = new(stream);
             string html = reader.ReadToEnd();

            // Document document = new Document();
            // if (fileExtension.Equals("doc"))
            // {
            //     document.LoadFromStream(file.OpenReadStream(),FileFormat.Doc);
            // }
            // else if (fileExtension.Equals("docx"))
            // {
            //     document.LoadFromStream(file.OpenReadStream(),FileFormat.Docx);
            // }
            // else
            // {
            //     return new JsonResult(new
            //     {
            //         Msg = "不被支持的文档类型!"
            //     });
            // }
            // document.HtmlExportOptions.ImageEmbedded = true;
            // document.HtmlExportOptions.IsExportDocumentStyles = true;
            // document.HtmlExportOptions.HasHeadersFooters = true;
            // MemoryStream stream = new();
            // document.SaveToStream(stream, FileFormat.Html);
            // stream.Position = 0;
            //
            // StreamReader reader = new(stream);
            // string html = reader.ReadToEnd();
            return new JsonResult(new
            {
                Data = html,
            });
        }

如果是.NET 6的项目并且需要部署在Linux上,可能需要新建一个运行时配置文件
runtimeconfig.template.json,以启用Linux绘图的支持

{
  "configProperties": {
    "System.Drawing.EnableUnixSupport": true
  }
}
posted @ 2023-11-17 17:32  SpringCore  阅读(610)  评论(0编辑  收藏  举报