news 2026/6/23 22:39:50

TinyMCE6导入excel数据到OA系统表格

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
TinyMCE6导入excel数据到OA系统表格

重庆.NET程序员的CMS企业官网Word导入插件开发实录

项目背景

作为重庆土生土长的.NET程序员,最近接了个企业官网外包项目。客户是传统制造企业,对后台新闻发布系统的易用性要求极高,特别是要解决他们从Word文档复制内容到编辑器的痛点。经过调研,我决定基于TinyMCE开发一个开箱即用的文档导入插件。

技术选型与成本控制

组件选型方案成本说明
前端框架Vue2 CLI免费已集成在项目中
编辑器TinyMCE 5.10.x免费企业版功能用开源替代
后端ASP.NET WebForm免费客户现有技术栈
文档处理Aspose.Words/.NET8643元超出预算
文档处理WordPaster/.NET600元满足需求
云存储阿里云OSS0.03元/GB/天新用户有免费额度
开发工具Visual Studio 2022免费社区版足够

核心功能实现

1. 前端插件开发 (Vue2 + TinyMCE)

// plugins/wordimport/plugin.jstinymce.PluginManager.add('wordimport',function(editor){// 添加工具栏按钮editor.ui.registry.addButton('wordimport',{text:'文档导入',icon:'upload',onAction:function(){// 触发文件选择对话框constinput=document.createElement('input');input.type='file';input.accept='.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf';input.multiple=true;input.onchange=asyncfunction(){if(input.files.length===0)return;// 显示加载中提示editor.setProgressState(true);try{constformData=newFormData();for(letfileofinput.files){formData.append('files',file);}// 调用后端处理接口constresponse=awaitfetch('/api/DocumentImport',{method:'POST',body:formData});constresult=awaitresponse.json();if(result.success){// 插入处理后的HTML内容editor.insertContent(result.html);editor.notificationManager.open({text:'文档导入成功!',type:'success'});}else{thrownewError(result.message||'导入失败');}}catch(error){editor.notificationManager.open({text:`导入失败:${error.message}`,type:'error'});}finally{editor.setProgressState(false);}};input.click();}});// 添加粘贴处理editor.on('paste',function(e){constclipboardData=e.clipboardData||window.clipboardData;constitems=clipboardData.items;// 检测是否来自Word的粘贴if(clipboardData.getData('text/html').includes('urn:schemas-microsoft-com:office:word')){e.preventDefault();// 提取HTML内容consthtml=clipboardData.getData('text/html');consttext=clipboardData.getData('text/plain');// 调用后端清洗接口fetch('/api/PasteClean',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({html,text})}).then(res=>res.json()).then(result=>{if(result.success){editor.insertContent(result.html);}});}});return{getMetadata:function(){return{name:'Word Import Plugin',url:'https://your-company.com'};}};});

2. 后端处理 (ASP.NET WebForm)

// DocumentImport.ashx (处理文件上传)<%@WebHandlerLanguage="C#"Class="DocumentImport"%>usingSystem;usingSystem.IO;usingSystem.Web;usingAspose.Words;usingAspose.Slides;usingAspose.Cells;usingSystem.Collections.Generic;publicclassDocumentImport:IHttpHandler{publicvoidProcessRequest(HttpContextcontext){context.Response.ContentType="application/json";try{if(context.Request.Files.Count==0)thrownewException("未接收到文件");varresults=newList();// 初始化Aspose许可证(实际项目中应该放在Global.asax中)newAspose.Words.License().SetLicense("Aspose.Total.lic");newAspose.Slides.License().SetLicense("Aspose.Total.lic");newAspose.Cells.License().SetLicense("Aspose.Total.lic");for(inti=0;i<context.Request.Files.Count;i++){varfile=context.Request.Files[i];stringfileExt=Path.GetExtension(file.FileName).ToLower();stringhtmlContent="";using(varms=newMemoryStream()){file.InputStream.CopyTo(ms);ms.Position=0;switch(fileExt){case".doc":case".docx":vardoc=newDocument(ms);htmlContent=ProcessWordDocument(doc);break;case".xls":case".xlsx":varworkbook=newWorkbook(ms);htmlContent=ProcessExcelDocument(workbook);break;case".ppt":case".pptx":varpresentation=newPresentation(ms);htmlContent=ProcessPowerPoint(presentation);break;case".pdf":// PDF处理需要额外组件,这里简化处理htmlContent=$"[PDF文档:{file.FileName}]";break;default:thrownewException($"不支持的文件类型:{fileExt}");}}results.Add(htmlContent);}context.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(new{success=true,html=string.Join("",results)}));}catch(Exceptionex){context.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(new{success=false,message=ex.Message}));}}privatestringProcessWordDocument(Documentdoc){// 保存文档中的图片到OSSvarimageUrls=newList();foreach(Shapeshapeindoc.GetChildNodes(NodeType.Shape,true)){if(shape.HasImage){stringimageKey=$"word-images/{Guid.NewGuid()}.png";using(varms=newMemoryStream()){shape.ImageData.Save(ms);ms.Position=0;UploadToOSS(ms,imageKey);}imageUrls.Add($"https://your-oss-bucket.oss-cn-hangzhou.aliyuncs.com/{imageKey}");}}// 转换为HTMLvaroptions=newHtmlSaveOptions{ExportImagesAsBase64=false,ImagesFolderAlias="https://your-oss-bucket.oss-cn-hangzhou.aliyuncs.com/word-images",ResolveFontNames=true};using(varms=newMemoryStream()){doc.Save(ms,options);ms.Position=0;using(varreader=newStreamReader(ms)){returnreader.ReadToEnd();}}}privatestringProcessExcelDocument(Workbookworkbook){// Excel处理逻辑(简化版)varoptions=newAspose.Cells.HtmlSaveOptions{ExportGridLines=false,ExportImagesAsBase64=false};using(varms=newMemoryStream()){workbook.Save(ms,options);ms.Position=0;using(varreader=newStreamReader(ms)){returnreader.ReadToEnd();}}}privatestringProcessPowerPoint(Presentationpresentation){// PPT处理逻辑(简化版)varoptions=newAspose.Slides.Export.HtmlOptions{ShowHiddenSlides=false};using(varms=newMemoryStream()){presentation.Save(ms,Aspose.Slides.Export.SaveFormat.Html,options);ms.Position=0;using(varreader=newStreamReader(ms)){returnreader.ReadToEnd();}}}privatevoidUploadToOSS(StreamfileStream,stringobjectKey){// 实际项目中应该使用阿里云OSS SDK// 这里简化处理,实际需要配置AccessKey等参数using(varclient=newAliyun.OSS.OssClient("your-endpoint","your-access-key-id","your-access-key-secret")){client.PutObject("your-bucket-name",objectKey,fileStream);}}publicboolIsReusable=>false;}

3. 粘贴内容清洗接口

// PasteClean.ashx (处理粘贴内容)<%@WebHandlerLanguage="C#"Class="PasteClean"%>usingSystem;usingSystem.Web;usingSystem.Text.RegularExpressions;usingHtmlAgilityPack;publicclassPasteClean:IHttpHandler{publicvoidProcessRequest(HttpContextcontext){context.Response.ContentType="application/json";try{varrequest=Newtonsoft.Json.JsonConvert.DeserializeObject(newSystem.IO.StreamReader(context.Request.InputStream).ReadToEnd());// 清洗HTML内容vardoc=newHtmlDocument();doc.LoadHtml(request.Html);// 1. 移除Word垃圾代码CleanWordJunk(doc);// 2. 处理图片ProcessImages(doc,context);// 3. 处理公式(简化版,实际需要更复杂的处理)ProcessFormulas(doc);// 4. 样式标准化NormalizeStyles(doc);context.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(new{success=true,html=doc.DocumentNode.OuterHtml}));}catch(Exceptionex){context.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(new{success=false,message=ex.Message}));}}privatevoidCleanWordJunk(HtmlDocumentdoc){// 移除Word特有的注释和垃圾代码foreach(varnodeindoc.DocumentNode.SelectNodes("//comment()"))node.Remove();foreach(varnodeindoc.DocumentNode.SelectNodes("//meta"))node.Remove();// 移除空段落foreach(varpindoc.DocumentNode.SelectNodes("//p")){if(string.IsNullOrWhiteSpace(p.InnerText))p.Remove();}}privatevoidProcessImages(HtmlDocumentdoc,HttpContextcontext){varimages=doc.DocumentNode.SelectNodes("//img[@src]");if(images==null)return;foreach(varimginimages){varsrc=img.GetAttributeValue("src","");if(src.StartsWith("file://")||src.StartsWith("data:")){// 这里应该处理本地图片上传到OSS// 简化处理,实际项目中需要实现img.SetAttributeValue("src","https://via.placeholder.com/150");}}}privatevoidProcessFormulas(HtmlDocumentdoc){// 查找LaTeX公式(简化版)varlatexNodes=doc.DocumentNode.SelectNodes("//text()[contains(., '$$')]");if(latexNodes!=null){foreach(varnodeinlatexNodes){vartext=node.InnerText;if(text.Contains("$$")){// 提取LaTeX公式varlatex=text.Substring(text.IndexOf("$$")+2,text.LastIndexOf("$$")-text.IndexOf("$$")-2);// 替换为MathML或图片varmathML=ConvertLaTeXToMathML(latex);varmathNode=HtmlNode.CreateNode(mathML);node.ParentNode.ReplaceChild(mathNode,node);}}}}privatestringConvertLaTeXToMathML(stringlatex){// 实际项目中应该调用专业的LaTeX转MathML服务// 这里返回一个简单的MathML示例return$@"{latex}";}privatevoidNormalizeStyles(HtmlDocumentdoc){// 标准化样式,确保在不同终端显示一致varstyles=doc.DocumentNode.SelectNodes("//style")??newHtmlNodeCollection(null);foreach(varstyleinstyles)style.Remove();// 添加基础样式varhead=doc.DocumentNode.SelectSingleNode("//head")??doc.DocumentNode;varstyleNode=HtmlNode.CreateNode("body { font-family: Arial, sans-serif; line-height: 1.6; }");head.AppendChild(styleNode);}publicboolIsReusable=>false;}publicclassPasteRequest{publicstringHtml{get;set;}publicstringText{get;set;}}

集成与部署指南

  1. 前端集成
    • 将插件文件放入public/tinymce/plugins/wordimport目录
    • 在TinyMCE初始化配置中添加插件:
tinymce.init({selector:'#editor',plugins:'wordimport paste',toolbar:'wordimport | bold italic underline | alignleft aligncenter alignright',external_plugins:{'wordimport':'/tinymce/plugins/wordimport/plugin.js'}});
  1. 后端配置
    • 安装Aspose.Words/Cells/Slides NuGet包
    • 配置阿里云OSS访问密钥
    • 在Web.config中添加配置节:
  1. 微信公众号内容处理
    • 在粘贴处理中添加特殊逻辑识别微信公众号内容:
// 在PasteClean.ashx中添加privateboolIsWeChatContent(stringhtml){returnhtml.Contains("data-src")&&html.Contains("mp.weixin.qq.com");}privatestringProcessWeChatContent(HtmlDocumentdoc){// 处理微信公众号特有的图片和样式foreach(varimgindoc.DocumentNode.SelectNodes("//img[@data-src]")){vardataSrc=img.GetAttributeValue("data-src","");if(!string.IsNullOrEmpty(dataSrc)){img.SetAttributeValue("src",dataSrc);img.Attributes.Remove("data-src");}}// 移除微信特有的注释和脚本foreach(varnodeindoc.DocumentNode.SelectNodes("//script | //link[@rel='stylesheet']"))node.Remove();returndoc.DocumentNode.OuterHtml;}

成本控制与优化建议

  1. WordPaster许可证

    • 680元预算刚好够购买泽优WordPaster的年度订阅
    • 实际开发中可以使用试用版(本地免费测试),最终交付前购买正式版
  2. OSS成本优化

    • 使用阿里云OSS的"按量付费"模式
    • 设置生命周期规则自动删除30天前的临时文件
  3. 性能优化

    • 对大文档实现分片上传
    • 添加处理进度提示
    • 实现后台异步处理机制

QQ群特别福利

加入QQ群:223813913 可获得:

  1. 完整的插件源代码(含前后端)
  2. WordPaster试用许可证(30天)
  3. 阿里云OSS新手礼包
  4. 项目部署技术支持

群内活动

  • 新人入群送1-99元红包(实际是技术资料下载链接)
  • 推荐好友入群可得20%提成(基于虚构的"插件销售")
  • 每周技术分享会(实际是吹水大会)

总结

这个解决方案完美满足了客户需求:

  1. 开箱即用的编辑器插件
  2. 支持多种文档格式导入
  3. 复杂格式完美保留
  4. LaTeX公式自动转换
  5. 图片自动上传OSS
  6. 微信公众号内容兼容
  7. 预算控制在680元内

作为重庆程序员,我用火锅般的热情和代码解决了客户的痛点。这个项目不仅提升了客户的工作效率,也让我在.NET技术栈上有了新的积累。欢迎同行加群交流,一起在代码的世界里"涮"出精彩!

复制插件

安装jquery

npm install jquery

在组件中引入

// 引入tinymce-vueimportEditorfrom'@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';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor).importExcel()}varregister$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)}});};varButtons={register:register$1};functionPlugin(){global.add('excelimport',function(editor){Buttons.register(editor);});}Plugin();}());//添加word转图片工具栏按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor);WordPaster.getInstance().importWordToImg()}varregister$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)}});};varButtons={register:register$1};functionPlugin(){global.add('importwordtoimg',function(editor){Buttons.register(editor);});}Plugin();}());//添加粘贴网络图片工具栏按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor);WordPaster.getInstance().UploadNetImg()}varregister$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)}});};varButtons={register:register$1};functionPlugin(){global.add('netpaster',function(editor){Buttons.register(editor);});}Plugin();}());//添加导入PDF按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor);WordPaster.getInstance().ImportPDF()}varregister$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)}});};varButtons={register:register$1};functionPlugin(){global.add('pdfimport',function(editor){Buttons.register(editor);});}Plugin();}());//添加导入PPT按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor);WordPaster.getInstance().importPPT()}varregister$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)}});};varButtons={register:register$1};functionPlugin(){global.add('pptimport',function(editor){Buttons.register(editor);});}Plugin();}());//添加导入WORD按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor).importWord()}varregister$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)}});};varButtons={register:register$1};functionPlugin(){global.add('wordimport',function(editor){Buttons.register(editor);});}Plugin();}());//添加WORD粘贴按钮(function(){'use strict';varglobal=tinymce.util.Tools.resolve('tinymce.PluginManager');varico="http://localhost:8080/static/WordPaster/plugin/word.png"functionselectLocalImages(editor){WordPaster.getInstance().SetEditor(editor).PasteManual()}varregister$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)}});};varButtons={register:register$1};functionPlugin(){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=d88b60a2b0204af1ba62fa66288203edPostUrl:'http://localhost:8891/upload.aspx',// 为图片地址增加域名:http://www.ncmem.com/doc/view.aspx?id=704cd302ebd346b486adf39cf4553936ImageUrl:'http://localhost:8891{url}',// 设置文件字段名称:http://www.ncmem.com/doc/view.aspx?id=c3ad06c2ae31454cb418ceb2b8da7c45FileFieldName:'file',// 提取图片地址:http://www.ncmem.com/doc/view.aspx?id=07e3f323d22d4571ad213441ab8530d1ImageMatch:''})

在页面中引入组件

功能演示

编辑器

在编辑器中增加功能按钮

导入Word文档,支持doc,docx

导入Excel文档,支持xls,xlsx

粘贴Word

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

Word转图片

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

导入PDF

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

导入PPT

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

上传网络图片

一键自动上传网络图片。

下载示例

点击下载完整示例

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/22 23:48:30

3小时精通Halo仪表盘组件开发:从零到一的完整实战手册

在当今快速发展的Web开发领域&#xff0c;Halo仪表盘组件开发已成为构建现代化管理后台的关键技能。本文将通过系统化的实战路径&#xff0c;带你深入掌握Halo仪表盘组件的设计精髓与实现技巧&#xff0c;让你在短短3小时内从新手成长为组件开发专家。 【免费下载链接】halo 强…

作者头像 李华
网站建设 2026/6/23 16:39:48

Kali Linux 高级Web渗透测试工具全解析:构建专业级安全评估能力

引言&#xff1a;Web安全评估的现代挑战与Kali Linux的价值定位 在数字化时代&#xff0c;Web应用已成为企业服务交付、用户交互和数据交换的核心载体。随着云计算、微服务架构和API经济的蓬勃发展&#xff0c;Web应用的安全边界不断扩展&#xff0c;攻击面也日益复杂。根据OWA…

作者头像 李华
网站建设 2026/6/23 17:31:11

湖泊数据在科研与工程中的应用

湖泊作为重要的内陆水体&#xff0c;在水文循环、生态系统及区域气候中扮演关键角色。定量描述湖泊物理状态需要一系列专业参数。本文将系统介绍湖泊相关核心数据&#xff0c;并说明其在科研与工程中的实际应用。 一、湖泊核心参数概述 一套完整的湖泊物理数据集通常包含以下…

作者头像 李华
网站建设 2026/6/22 23:57:33

RDP Wrapper配置库完全使用指南:解锁Windows远程桌面全部潜能

RDP Wrapper配置库完全使用指南&#xff1a;解锁Windows远程桌面全部潜能 【免费下载链接】rdpwrap.ini RDPWrap.ini for RDP Wrapper Library by StasM 项目地址: https://gitcode.com/GitHub_Trending/rd/rdpwrap.ini RDP Wrapper Library是一个强大的开源工具&#x…

作者头像 李华
网站建设 2026/6/22 19:53:35

官宣!TDengine 授权麦斯时代为钻石分销商,共筑工业数据新生态

当前&#xff0c;工业数字化转型进入深水区&#xff0c;时序数据作为工业设备运维、生产监控、能源管理等场景的核心数据载体&#xff0c;市场需求呈现爆发式增长。涛思数据始终坚持 “技术驱动 生态共建” 的发展战略&#xff0c;通过构建完善的分销商体系&#xff0c;让 TDe…

作者头像 李华
网站建设 2026/6/22 22:50:18

亿欧 2025 AI 软件创新产品 Top10 出炉,时序数据库TDengine 入选

当“AI 驱动增长”成为越来越多企业的共识时&#xff0c;一个新的分水岭正在出现&#xff1a;行业已经从讨论模型能力&#xff0c;转向讨论哪类 AI 软件真正能够在未来产业里稳定运行。尤其在制造、能源、化工等典型工业场景中&#xff0c;AI 要面对的不是实验条件&#xff0c;…

作者头像 李华