农业大数据平台如何通过TinyMCE实现Excel动态图表导入?

我的CMS新闻系统升级历险记:与Word文档大战三百回合

一、需求分析:甲方爸爸的"小"要求

作为一个苦逼的软件工程大三学生,我做的CMS新闻系统本来只是课程作业级别,没想到被学校宣传部看中了!现在他们提了个"小"需求:

“小王啊,能不能加个功能让我们直接从Word粘贴内容?最好还能直接导入整个文档,图片自动上传那种~对了,公式表格什么的都不能丢哦~”

预算?99块!没错,就是比我的奶茶月预算还少的价格…(内心OS:这就是社会毒打吗?)

二、技术选型:穷学生的生存智慧

1. 编辑器选择(TinyMCE 4老古董改造计划)

// 我的编辑器现状
const myEditor = {
  version: 'TinyMCE 4',
  mood: '有点老但还能用',
  plugins: ['基本够用'],
  budget: '99元'
}

调研结果:

方案优点缺点价格
TinyMCE PowerPaste官方出品不支持PPT/PDF$80(肉疼)
CKEditor PasteFromOffice功能强大要换编辑器免费
Mammoth.js专注Word仅限.docx免费
自研方案完全可控可能猝死时间成本
WordPaster完全开源(下载源码)需要安装插件时间成本

最终选择:WordPaster基础版 + 魔改!

2. 图片处理方案(阿里云OSS白嫖指南)

// 我的钱包类
class MyWallet {
    public $balance = 99;
    public function canAfford($price) {
        return $this->balance >= $price;
    }
}
// 使用示例
$wallet = new MyWallet();
$wallet->canAfford(100); // false (扎心了)

OSS配置秘笈:

  1. 申请学生认证(9.9/年真香)
  2. 用内网传输省流量费
  3. 设置生命周期自动清理

三、开发实录:从入门到放弃再到真香

Day 1:安装插件差点把我送走

# 真实发生的惨案
npm install tinymce-powerpaste
# ERROR: 需要TinyMCE 5+
# 我:可我用的是4啊!!!

解决方案:
在GitHub考古找到兼容版本:


Day 3:图片上传的奇幻漂流

前端代码(Vue版):

// 在编辑器初始化中加入
tinymce.init({
  selector: '#editor',
  plugins: 'powerpaste',
  powerpaste_word_import: 'clean',
  powerpaste_html_import: 'clean',
  images_upload_handler: function (blobInfo, success, failure) {
    const formData = new FormData();
    formData.append('file', blobInfo.blob(), blobInfo.filename());
    
    axios.post('/api/upload', formData).then(res => {
      success(res.data.url); // 返回OSS地址
    }).catch(err => {
      failure('上传失败:' + err);
    });
  }
});

后端PHP处理(简陋但能用版):

public function upload() {
    $file = $_FILES['file'];
    $fileName = uniqid().'.'.pathinfo($file['name'], PATHINFO_EXTENSION);
    
    try {
        $ossClient = new OSS\OssClient(
            config('oss.access_key_id'),
            config('oss.access_key_secret'),
            config('oss.endpoint')
        );
        
        $ossClient->uploadFile(
            config('oss.bucket'),
            'uploads/'.$fileName,
            $file['tmp_name']
        );
        
        return json(['url' => 'https://'.config('oss.bucket').'.'.config('oss.endpoint').'/uploads/'.$fileName]);
    } catch (\Exception $e) {
        return json(['error' => $e->getMessage()], 500);
    }
}

Day 5:表格样式保卫战

发现的问题:

  1. Word表格转成HTML后样式全丢
  2. 合并单元格全乱套

解决方案:

/* 魔改样式表 */
.mce-item-table {
  border-collapse: collapse !important;
  width: 100% !important;
}
.mce-item-table td, 
.mce-item-table th {
  border: 1px solid #ddd !important;
  padding: 8px !important;
}
/* 强行保留Word样式 */
.msonormal {
  font-family: "Times New Roman", serif !important;
  font-size: 12pt !important;
}

Day 7:公式支持的血泪史

Latex公式处理方案:

// 用正则匹配Word公式并替换为Latex
content = content.replace(/]*data-latex="([^"]*)"[^>]*>/g, 
  (match, latex) => `\\(${latex}\\)`);
  
// 然后在前端引入MathJax
const mathJax = document.createElement('script');
mathJax.src = 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js';
document.head.appendChild(mathJax);

四、成果展示:真香警告!

![功能演示图]

  1. 一键粘贴Word内容 ✔
  2. 图片自动上传OSS ✔
  3. 表格基本保留样式 ✔
  4. 简单公式支持 ✔
  5. 预算控制在99元内 ✔

五、经验分享(血泪教训)

  1. Windows和macOS兼容性坑

    • Windows的Word复制内容带奇怪样式
    • macOS的剪贴板处理方式不同
  2. 性能优化技巧

    // 上传前压缩图片
    function compressImage($file) {
        $image = imagecreatefromstring(file_get_contents($file));
        imagejpeg($image, $file, 75); // 75%质量
        imagedestroy($image);
    }
    
  3. 加QQ群交流的好处

    • 群友"秃头哥"教我绕过PowerPaste版本限制
    • "键盘侠老李"分享了他的OSS优化配置
    • 大家一起吐槽甲方真解压(不是)

六、未来计划(如果我还活着)

  1. PPT/PDF导入功能
  2. 微信公众号文章抓取
  3. 增加Markdown支持
  4. 写个详细的使用文档(咕咕咕)

最后呼吁:欢迎加入QQ群223813913一起交流!群里已经有:

  • 5个被Word折磨疯的开发者
  • 3个OSS配置高手
  • 若干和我一样的苦逼学生
  • 以及1个神秘的阿里云技术小哥(偶尔出现发优惠券)

复制插件

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: ''
})

在页面中引入组件


功能演示

编辑器

在编辑器中增加功能按钮
WordPaster-TinyMCE5

导入Word文档,支持doc,docx

粘贴Word和图片

导入Excel文档,支持xls,xlsx

粘贴Word和图片

粘贴Word

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

Word转图片

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

导入PDF

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

导入PPT

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

上传网络图片

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

下载示例

点击下载完整示例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值