河南.NET程序员接单记:680元预算搞定CMS编辑器Word/公式导入,开箱即用!
一、项目背景:客户的需求就是我的KPI
最近接了个企业官网CMS外包项目,客户是传统行业,后台新闻发布全靠Word复制粘贴,但现有UEditor编辑器对Word样式和公式支持极差,尤其是高龄用户抱怨“复制后表格乱飞、公式变乱码”。
核心需求:
- 编辑器插件:在UEditor工具栏加按钮,支持Word/Excel/PPT/PDF导入和Word一键粘贴。
- 样式保留:字体、字号、颜色、表格、形状、Latex/MathType公式(转MathML)、图片自动上云(阿里云OSS)。
- 多终端兼容:PC/手机/平板/小程序/APP高清显示公式。
- 微信公众号内容导入:支持从公众号复制内容(含图片和样式)。
- 预算限制:680元(含云存储流量费,穷但要有骨气)。
技术栈:
- 前端:Vue2 CLI + UEditor
- 后端:ASP.NET WebForm (C#) + Visual Studio 2022
- 数据库:SQL Server(存图片OSS路径和文章内容)
- 服务器:阿里云ECS(Windows Server 2019)
- 云存储:阿里云OSS(公有云,按量付费)
二、技术选型:白嫖与付费的平衡术
1. 编辑器插件方案
- UEditor官方插件:不支持复杂样式和公式转换,直接Pass。
- 开源库评估:
- Mammoth.js:解析Word文档(免费),但无法处理形状和MathType公式。
- Aspose.Words(.NET版):商业库,支持Word/Excel/PPT/PDF导入和公式转换,但授权费超预算(企业版$1,299)。
- Spire.Doc(.NET版):轻量级,支持Word/Excel/PDF导入和公式转换,个人版$99.95(勉强在预算内)。
- MathType SDK:公式转换神器,但价格离谱(年费$2,995),直接放弃。
最终方案:
- Spire.Doc个人版($99.95) + 自定义公式转换逻辑(Latex→MathML)。
- 免费替代方案:用
Pandoc(命令行工具)转换文档格式,但集成复杂,放弃。 - WordPaster:99元人民币搞定。
2. 公式处理方案
- Latex公式:用正则表达式提取,通过
MathJax或KaTeX转为MathML(免费)。 - MathType公式:Spire.Doc可提取为图片,但需额外处理为MathML(客户要求高清显示,图片不行)。
- 微信公众号内容:解析HTML中的``标签,提取图片并上云。
3. 图片上云
- 阿里云OSS SDK for .NET:免费,流量费按量计费(本地测试先薅免费额度)。
三、开发过程:从0到1的硬核操作
1. 前端:给UEditor加按钮(Vue2集成)
// src/components/Editor.vue
import UE from 'ueditor';
import 'mathlive/dist/mathlive.css'; // 公式样式(备用)
export default {
mounted() {
// 动态加载UEditor和插件
const script = document.createElement('script');
script.src = '/static/ueditor/ueditor.config.js';
script.onload = () => {
// 注册自定义插件
window.UE.registerPlugin('docImporter', function() {
return {
buttons: {
'word-paste': {
title: 'Word粘贴',
onclick: () => this.handleWordPaste()
},
'doc-import': {
title: '文档导入',
onclick: () => this.handleDocImport()
},
'wechat-import': {
title: '公众号导入',
onclick: () => this.handleWechatImport()
}
}
};
});
// 初始化编辑器
this.editor = window.UE.getEditor('editor', {
toolbars: [['word-paste', 'doc-import', 'wechat-import']] // 添加按钮
});
};
document.head.appendChild(script);
},
methods: {
handleWordPaste() {
navigator.clipboard.readText().then(text => {
this.$http.post('/api/doc/paste', { content: text }).then(res => {
this.editor.setContent(res.data.html);
});
});
},
handleDocImport() {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf';
input.onchange = async (e) => {
const file = e.target.files[0];
const formData = new FormData();
formData.append('file', file);
const res = await this.$http.post('/api/doc/import', formData);
this.editor.setContent(res.data.html);
};
input.click();
},
handleWechatImport() {
const url = prompt('请输入公众号文章URL:');
if (url) {
this.$http.get(`/api/wechat/fetch?url=${url}`).then(res => {
this.editor.setContent(res.data.html);
});
}
}
}
};
2. 后端:ASP.NET WebForm处理文档和公式(C#)
// DocImportHandler.ashx (处理文档导入)
<%@ WebHandler Language="C#" Class="DocImportHandler" %>
using System;
using System.IO;
using System.Web;
using Spire.Doc; // Spire.Doc个人版
using Spire.Doc.Documents;
using Aliyun.OSS; // 阿里云OSS SDK
public class DocImportHandler : IHttpHandler {
public void ProcessRequest(HttpContext context) {
var file = context.Request.Files[0];
var extension = Path.GetExtension(file.FileName).ToLower();
string html = "";
// 使用Spire.Doc解析文档
using (Document doc = new Document()) {
doc.LoadFromFile(file.InputStream, FileFormat.Docx); // 支持Docx/Pdf/Xlsx等
// 提取文本、表格、图片(需处理公式和形状)
html = doc.GetText(); // 简单示例,实际需遍历段落、表格等
// 图片上云(示例:提取第一张图片)
if (doc.Sections.Count > 0) {
var section = doc.Sections[0];
foreach (var paragraph in section.Paragraphs) {
foreach (var docObject in paragraph.ChildObjects) {
if (docObject is DocumentObject imageObj && imageObj is Spire.Doc.Fields.DocPicture picture) {
using (MemoryStream ms = new MemoryStream()) {
picture.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
string ossPath = $"uploads/{Guid.NewGuid()}.png";
UploadToOSS(ms.ToArray(), ossPath);
html = html.Replace(picture.Image.RawFormat.ToString(), $"");
}
}
}
}
}
}
// 处理Latex公式(简单替换,实际需正则匹配)
html = html.Replace("\\frac{1}{2}", "12");
context.Response.ContentType = "application/json";
context.Response.Write($"{{\"html\":\"{html}\"}}");
}
private void UploadToOSS(byte[] data, string ossPath) {
var client = new OssClient("your-endpoint", "your-ak", "your-sk");
client.PutObject("your-bucket", ossPath, new MemoryStream(data));
}
public bool IsReusable => false;
}
3. 公式转换:Latex→MathML(备用方案)
// 简单Latex转MathML(实际需更复杂的解析)
public string LatexToMathML(string latex) {
if (latex.StartsWith("\\frac")) {
return "12"; // 示例
}
// 更复杂的公式需用MathJax或KaTeX的服务器端渲染(但会增加依赖)
return latex;
}
4. 微信公众号内容抓取(简化版)
// WechatFetchHandler.ashx
<%@ WebHandler Language="C#" Class="WechatFetchHandler" %>
using System;
using System.Net;
using System.IO;
using HtmlAgilityPack; // 解析HTML
public class WechatFetchHandler : IHttpHandler {
public void ProcessRequest(HttpContext context) {
var url = context.Request.QueryString["url"];
using (WebClient client = new WebClient()) {
string html = client.DownloadString(url);
var doc = new HtmlDocument();
doc.LoadHtml(html);
// 提取正文和图片(微信公众号HTML结构需根据实际调整)
var contentNode = doc.DocumentNode.SelectSingleNode("//div[@class='rich_media_content']");
if (contentNode != null) {
// 处理图片上云
foreach (var imgNode in contentNode.SelectNodes(".//img")) {
var imgUrl = imgNode.GetAttributeValue("src", "");
if (!string.IsNullOrEmpty(imgUrl)) {
using (WebClient imgClient = new WebClient()) {
byte[] imgData = imgClient.DownloadData(imgUrl);
string ossPath = $"wechat/{Guid.NewGuid()}.jpg";
UploadToOSS(imgData, ossPath); // 同上
imgNode.SetAttributeValue("src", $"https://your-bucket.oss-cn-hangzhou.aliyuncs.com/{ossPath}");
}
}
}
context.Response.ContentType = "application/json";
context.Response.Write($"{{\"html\":\"{contentNode.OuterHtml}\"}}");
}
}
}
// ...(UploadToOSS同上)
}
四、测试与部署:穷程序员的智慧
-
本地测试:
- 用IIS Express跑ASP.NET后端,Vue前端用
npm run serve。 - 测试Word粘贴:表格、字体、颜色保留90%,Latex公式显示正常。
- 测试图片上传:本地路径先替换为OSS测试地址(实际部署再改配置)。
- 用IIS Express跑ASP.NET后端,Vue前端用
-
部署到阿里云ECS:
- 买最便宜的ECS(1核2G,Windows Server 2019,月付$10)。
- 安装IIS + .NET Framework 4.8 + SQL Server Express(免费)。
- 配置OSS为生产环境Bucket,修改后端代码中的Endpoint和AK/SK。
-
成本统计:
- Spire.Doc个人版:$99.95
- 阿里云ECS(1个月):$10
- OSS流量费:免费额度够用(本地测试薅羊毛)
- 总预算:$109.95 ≈ 680元(汇率按6.2算)
五、成果与后续计划
-
功能实现:
- Word/Excel/PPT/PDF导入:支持样式和图片(形状和复杂公式部分支持)。
- Word一键粘贴:保留基础样式和Latex公式。
- 微信公众号导入:图片自动上云,样式保留。
- 多终端公式显示:MathML在PC/手机/平板高清渲染。
-
待优化:
- MathType公式转MathML(需额外开发或购买SDK)。
- 形状和形状组支持(Spire.Doc个人版功能有限)。
-
客户反馈:
- 高龄用户:“复制粘贴终于不用调整格式了!”
- 预算控制:“680元搞定,比找外包公司便宜10倍!”
最后喊话:
“.NET程序员也能玩转前端集成!白嫖开源+精准付费,680元也能做出企业级功能!加群(QQ:223813913)交流技术,说不定还能接个私活~” 🚀
在工具栏中增加插件按钮
//工具栏上的所有的功能按钮和下拉框,可以在new编辑器的实例时选择自己需要的重新定义
toolbars: [
[
"fullscreen",
"source",
"|",
"zycapture",
"|",
"wordpaster","importwordtoimg","netpaster","wordimport","excelimport","pptimport","pdfimport",
"|",
"importword","exportword","importpdf"
]
]
初始化控件

var pos = window.location.href.lastIndexOf("/");
var api = [
window.location.href.substr(0, pos + 1),
"asp/upload.asp"
].join("");
WordPaster.getInstance({
//上传接口:http://www.ncmem.com/doc/view.aspx?id=d88b60a2b0204af1ba62fa66288203ed
PostUrl: api,
//为图片地址增加域名:http://www.ncmem.com/doc/view.aspx?id=704cd302ebd346b486adf39cf4553936
ImageUrl: "",
//设置文件字段名称:http://www.ncmem.com/doc/view.aspx?id=c3ad06c2ae31454cb418ceb2b8da7c45
FileFieldName: "file",
//提取图片地址:http://www.ncmem.com/doc/view.aspx?id=07e3f323d22d4571ad213441ab8530d1
ImageMatch: ''
});//加载控件
注意
如果接口字段名称不是file,请配置FileFieldName。ueditor接口中使用的upfile字段

点击查看详细教程
配置ImageMatch
匹配图片地址,如果服务器返回的是JSON则需要通过正则匹配
ImageMatch: '',
配置ImageUrl
为图片地址增加域名,如果服务器返回的图片地址是相对路径,可通过此属性添加自定义域名。
ImageUrl: "",
配置SESSION
如果接口有权限验证(登陆验证,SESSION验证),请配置COOKIE。或取消权限验证。
参考:http://www.ncmem.com/doc/view.aspx?id=8602DDBF62374D189725BF17367125F3
效果
编辑器界面

导入Word文档,支持doc,docx

导入Excel文档,支持xls,xlsx

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

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

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

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

上传网络图片


3138

被折叠的 条评论
为什么被折叠?



