WEB前端实现在线预览、编辑Office文档

这篇文章介绍如何在web前端引入JS插件实现在线预览、编辑Office文档。

使用插件:Spire.Cloud在线Office文档编辑器(官网:冰蓝科技在线编辑

重点:该方案仅需浏览器支持HTML5,提供中英文双语界面,不需要安装Office或控件,也不需要做环境配置就可以直接调用插件,非常简单。

准备工作

首先,使用浏览器打开:https://cloud.e-iceblue.cn/,点击右上角头像注册/登录账号。

其次,点击菜单栏“我的应用”创建应用,获取APP ID和APP Key。

前端JavaScript代码实现

添加以下JavaScript代码到前端页面,来集成Spire.Cloud在线编辑器实现Office文档在线预览或编辑。参数对照表已放在文章末尾。

<!DOCTYPE html>
<html>
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="mobile-web-app-capable" content="yes" />
    <meta HTTP-EQUIV="pragma" CONTENT="no-cache"/>
    <meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"/>
    <meta HTTP-EQUIV="expires" CONTENT="0">
    <title>Spire.Cloud</title>
	<style>
	
html {
    height: 100%;
    width: 100%;
}

body {
    background: #fff;
    color: #333;
    font-family: Arial, Tahoma,sans-serif;
    font-size: 12px;
    font-weight: normal;
    height: 100%;
    margin: 0;
    overflow-y: hidden;
    padding: 0;
    text-decoration: none;
}
iframe {
    border: none !important;
}

.form {
    height: 100%;
}

div {
    margin: 0;
    padding: 0;
}

	</style>
</head>
<body>
<div class="form">
    <div id="iframeEditor">
    </div>
</div>
    <script type="text/javascript" src="https://api.e-iceblue.cn/web/editors/spireapi/SpireCloudEditor.js"></script>
    <script type="text/javascript" language="javascript">
        var docEditor;
        var appid = 'your app id';
        var appkey = 'your app key';
        var config = {
    "fileAttrs": {
    "fileInfo": {
      "name": "sample.docx",
      "ext": "docx",
      "primary": String(new Date().getTime()),//this is key
      "creator": "Jonn",
      "createTime": "2022-04-18 11:30:43"
    },
    "sourceUrl": "https://cloud.e-iceblue.cn/demo/sample.docx",
    "createUrl": "",
    "callbackUrl": "", 
	/*This item can be empty, but only if the 'onSave' callback function must be defined in events. If the callback function is undefined and this item is empty, Cloud Editor will not provide save function. */
    "verification": "",
    "templates": {}
  },
  "user": {
    "id": "uid-1",
    "name": "Jonn",
    "canSave": true,
    "customization" : {
      "public": { 
        "common": {
          "whiteLabel": false,
          "defaultZoom": 1,
          "openReviewChanges": false,
          "viewVersion": false,
          "tokenValue": "",
          "permGroups": ["everyone"],
          "socket_url": "", 
          "header": {
            "hideTitle": false,
            "defaultView": "full"
          },
          "goback": { "url" : "" }
        },
        "document": null, 
        "excel":null,
        "powerpoint":null
      },
       "private": { 
        "token": "", 
        "appid": "",
        "appkey": ""
      }
    }
  },
  "editorAttrs": {
    "editorMode": "edit",
    "editorWidth": "100%",
    "editorHeight": "100%",
    "editorType": "document", 
    "platform": "desktop", //desktop, mobile, embedded
    "viewLanguage": "zh", //en/zh
    "events": {}
  }
};
        var innerAlert = function (message) {
            if (console && console.log)
                console.log(message);
        };

        var onAppReady = function () {
        };

        var onDocumentStateChange = function (event) {
            var title = document.title.replace(/\*$/g, "");
            document.title = title + (event.data ? "*" : "");
        };

        var onRequestEditRights = function () {
            location.href = location.href.replace(RegExp("mode=view\&?", "i"), "");
        };

        var onRequestHistory = function (event) {
            var historyObj = null;

            docEditor.refreshHistory(
                {
                    currentVersion: "1",
                    history: historyObj
                });
        };

        var onRequestHistoryData = function (data) {
            var version = data.data;
            var historyData = null;

            docEditor.setHistoryData(historyData[version-1]);
        };

        var onRequestHistoryClose = function (event){
            document.location.reload();
        };

        var onError = function (event) {
            if (event)
                innerAlert(event.data);
        };

        var onOutdatedVersion = function (event) {
            location.reload(true);
        };
        var onDownload = function(props){
            alert('fileName:'+props.data[0]+'fileUrl:'+props.data[1]);
            console.log('fileName:'+props.data[0]);
            console.log('fileUrl:'+props.data[1]);
        };

        var reloadFrame = function(){
            docEditor.reload();
        };

	 var callbackfn = function (result) {
            if (result && result.data) {
                var data = result.data,
                    fileName = data[0],
                    url = data[1];
                if (fileName.indexOf('=') > -1)
                    fileName = fileName.split('=')[1];
                var host1 = location.hostname;
                var host ='';
                ajax({
                    url: '',
                    type: 'post',
                    data: { 'filename': fileName, 'fileuri': url },
                    dataType: 'json',
                    async: false,
                    success: function (json) {
                        if (json.code == 200 || json.code == '200') {
                            alert('保存成功');
                        } else {
                            this.error(json, '保存失败');
                        }
                    },
                    error: function (json, msg) {
                        alert(+msg);
                    }
                });
            }
        };

        var connectEditor = function () {
            config.editorAttrs.events = {
                "onReady": onAppReady,
                "onDocumentStateChange": onDocumentStateChange,
                'onRequestEditRights': onRequestEditRights,
                "onError": onError,
                "onRequestHistory":  onRequestHistory,
                "onRequestHistoryData": onRequestHistoryData,
                "onRequestHistoryClose": onRequestHistoryClose,
                "onOutdatedVersion": onOutdatedVersion,
                'onSave': callbackfn
            };
            docEditor = new SpireCloudEditor.OpenApi('iframeEditor', config,appid,appkey);
            fixSize();
        };

        var onSaveClick = function () {
            docEditor.onSaveClick();
        }
        var fixSize = function () {
            var wrapEl = document.getElementsByClassName("form");
            if (wrapEl.length) {
                wrapEl[0].style.height = screen.availHeight + "px";
                window.scrollTo(0, -1);
                wrapEl[0].style.height = window.innerHeight + "px";
            }
        };

        if (window.addEventListener) {
            window.addEventListener("load", connectEditor);
            window.addEventListener("resize", fixSize);
        } else if (window.attachEvent) {
            window.attachEvent("onload", connectEditor);
            window.attachEvent("onresize", fixSize);
        }
		
    </script>
</body>
</html>

以上代码中的appidappkey参数要更改为你自己的App IDApp Key"sourceUrl": "https://cloud.e-iceblue.cn/demo/sample.docx" 参数要改为你自己的文档地址,同时要确保路径存在并且有访问权限。

我这里只是介绍了简单的预览、编辑的前端实现代码,如果需要把文档保存到服务器,需要设置callBackUrl参数(回调URL),这块要配合后端代码去实现。

编辑Word文档效果图如下:

参数对照表:

配置参数

示例值解释

设置值

fileAttrs
fileInfo

文档信息

name

文档名称

可为空

ext

文档后缀

docx, xlsx, pptx

primary

This is the key

可为空

creator

作者

可为空

createTime

创建时间

可为空

sourceUrl

URL

不能为空,且需有访问权限

createUrl

URL

可为空

callbackUrl

回调 URL

可为空,若需使用在线编辑的保存功能,则必须定义回调URL

verification

验证信息

可为空。用户文件系统下载文件时若需要验证类似token的数据可以写在这里

templates

文档模板

可为空

user

用户

不能为空

Id/name

冰蓝云上的 ID 和名字

可为空

Appid/appkey

Token 和 AppID/APPkey
二者必有一项不能为空

冰蓝云网站注册账号获取该信息

canSave

保存属性

默认值为true,当设置为false时,不允许保存.

customization

自定义选项

docx

public
common
whiteLabel

白标

默认值为false,当设置为true时,
不显示E-iceblue Logo 图标

defaultZoom

缩放

1

OpenReviewChagnes

是否显示跟踪变化

默认值为false,当设置为true时,显示更改痕迹

viewVersion

查看属性

默认值为false,当设置为true时,不允许保存.

permGroups

限制编辑分组

全员

socket_url

URL

可为空

header
hideTitle

隐藏标题

默认值为false,当设置为true时,标题隐藏.

defaultView

默认视图

全屏

goback

URL

可为空

editorAttrs
editorMode

编辑模式
'edit'(编辑)
'view'(展示)

不能为空,必须赋值为“edit” 或 “view”

editorWidth

可为空,默认值100%.

editorHeight

可为空,默认值100%.

editorType

文件编辑器类型

可不配置,程序根据文件类型获取,必须设置为 document 或 spreadsheet 或 presentation

platform

编辑器平台类型
'desktop'(电脑端展示)
'mobile'(手机端展示)
'embedded'(嵌入展示)

不能为空,必须设置为 desktop 或 mobile 或 embedded 中的一种

viewLanguage

平台界面展示语言

可为空。“en” 或 “zh”. 若设置为空,则匹配浏览器默认语言

canChat

是否可聊天

默认值为true,当设置为false时,不可聊天.

canComment

是否可批注

默认值为true,当设置为false时,不可批注

events

事件

"onReady", //编辑器已加载完成
"onDocumentStateChange", //当前文档状态(已保存或未保存)
"onError", //报错(返回报错信息)
"onSave" //保存(返回保存事件)

版本修改记录: V2.2.0.2修改: 修改了HttpPost相对路径的一些问题。 V2.2.0.0增加: [id(0x00010041), helpstring("Get Rev Index")] HRESULT GetRevCount( [out,retval] long * pbool); [id(0x00010042), helpstring("Get Rev Index Info")] HRESULT GetRevInfo([in] long lIndex, [in] long lType, [out,retval] BSTR* pbool); [id(0x00010043), helpstring("Set Doc Prop")] HRESULT SetValue([in] BSTR strValue, [in] BSTR strName, [out,retval] long* pbool); [id(0x00010044), helpstring("Set Doc Variable")] HRESULT SetDocVariable([in] BSTR strVarName, [in] BSTR strValue,[in] long lOpt, [out,retval] long* pbool); [id(0x00010045), helpstring("Save page To Doc")] HRESULT SetPageAs([in] BSTR strLocalFile, [in] long lPageNum, [in] long lType,[out,retval] long* pbool); ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- LoadDso.js var s = "" s += "" s += "" document.write(s) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 接口文档: /* 1.新建 */ //新建Word document.all.FramerControl1.CreateNew("Word.Document"); //新建Excel document.all.FramerControl1.CreateNew("Excel.Sheet"); /* 2.打开文件 */ //打开制定的本地文件 document.all.FramerControl1.Open("C:\\TestBook.xls"); //制定用Word来打开c:\plain.txt文件 document.all.FramerControl1.Open("C:\\Plain.txt",false, "Word.Document"); //打开服务器的文件 document.all.FramerControl1.Open "https://secureserver/test/mytest.asp?id=123",true, "Excel.Sheet", "MyUserAccount", "MyPassword"); //打开服务器的文件 document.all.FramerControl1.Open("http://localhost/1.doc", true); /* 3.保存文件 */ //到本地 document.all.FramerControl1.Save("c:\\1.doc",true); //服务器 /*增加Http协议Post上传接口,可以Post一个动态页面(jsp,asp,php...),由动态页面负责解析数据 bool HttpInit(); bool HttpAddPostString(BSTR strName, BSTR strValue); bool HttpAddPostCurrFile(BSTR strFileID, BSTR strFileName); BSTR HttpPost(BSTR bstr); */ //初始化Http引擎 document.all.FramerControl1.HttpInit(); //增加Post变量 document.all.FramerControl1.HttpAddPostString("RecordID","20060102200"); document.all.FramerControl1.HttpAddPostString("UserID","李局长"); //上传打开的文件 document.all.FramerControl1.HttpAddPostCurrFile("FileData", "文档名.doc"); //执行上传动作 document.all.FramerControl1.HttpPost("http://xxxx.com/uploadfile.asp"); /* 4.修订留痕 */ //进入留痕状态 document.all.FramerControl1.SetTrackRevisions(1); //进入非留痕状态 document.all.FramerControl1.SetTrackRevisions(0); //接受当前修订 document.all.FramerControl1.SetTrackRevisions(4); /* 5.设置当前用户 */ document.all.FramerControl1.SetCurrUserName("张三"); /* 6.设置当前时间(笔迹留痕会显示("Like 2006:02:07 11:11:11") */ document.all.FramerControl1.SetCurrTime("2006:02:07 11:11:11"); /* 7.设置和创建书签,此功能比较强大,设置书签数据、添加书签和添加红头文件就靠他了 SetFieldValue(BSTR strFieldName, BSTR strValue, BSTR strCmdOrSheetName) strFieldName:书签名 strValue:要设置的值 strCmdOrSheetName: 命令 ::ADDMARK:: 添加BookMark ::DELMARK:: 删除这个BookMark ::GETMARK:: 定位到这个BookMark ::FILE:: 插入的是文件 ::JPG:: 插入的是图片 一般来说:WORD中书签是做好的,可以通过此接口把外界数据设置进书签中去。 */ //在当前WORD位置插入标签,标签名为"book1",数值为"test" document.all.FramerControl1.SetFieldValue("book1","test","::ADDMARK::"); //设置书签"Time",数值为"2006-03-16 22:22:22" document.all.FramerControl1.SetFieldValue("Time","2006-03-16 22:22:22",""); //在书签位置"hongtou",插入红头文件"http://222.222.222.222/hongtou1.doc" 这样,红头就自动插进去了 document.all.FramerControl1.SetFieldValue("hongtou","http://222.222.222.222/hongtou1.doc","::FILE::"); /* 8.设置菜单显示情况 BOOL SetMenuDisplay(long lMenuFlag) lMenuFlag为以下数值的组合 #define MNU_NEW 0x01 #define MNU_OPEN 0x02 #define MNU_CLOSE 0x04 #define MNU_SAVE 0x08 #define MNU_SAVEAS 0x16 #define MNU_PGSETUP 0x64 #define MNU_PRINT 0x256 #define MNU_PROPS 0x32 #define MNU_PRINTPV 0x126 */ //只有“新建”菜单可用 document.all.FramerControl1..SetMenuDisplay(1); //只有“打开”菜单可用 document.all.FramerControl1.SetMenuDisplay(2); //只有“打开”和“新建”菜单可用 document.all.FramerControl1.SetMenuDisplay(3); /* 9.保护文档和解保护文档 lProOrUn:1:保护文档;0:解除保护 lProType: wdNoProtection = -1, wdAllowOnlyRevisions = 0, wdAllowOnlyComments = 1, wdAllowOnlyFormFields = 2 strProPWD:密码 */ //完全保护文档,密码为"pwd" document.all.FramerControl1.ProtectDoc(1,1,"pwd"); //解除文档保护 document.all.FramerControl1.ProtectDoc(0,1,"pwd"); /* 10.显示或隐藏修订内容 ShowRevisions(long nNewValue) nNewValue = 0 则隐藏修订 = 1 则显示修订 */ //显示修订留痕 document.all.FramerControl1.ShowRevisions(1); //隐藏修订留痕 document.all.FramerControl1.ShowRevisions(0); /* 11.插入合并文件, strFieldPath 文件路径,可以是http,ftp的路径 pPos = 0 //当前鼠标位置 1;文件开头 2;文件末尾 pPos的第4位为1的时候,代表插入的是图片 InSertFile(BSTR strFieldPath, long lPos) */ //文件头部插入文件 document.all.FramerControl1.InSertFile("http://XX.com/XX.doc",1); //文件尾部插入文件 document.all.FramerControl1.InSertFile("http://XX.com/XX.doc",2); //当前光标位置插入文件 document.all.FramerControl1.InSertFile("http://XX.com/XX.doc",0); //文件头部插入图片 document.all.FramerControl1.InSertFile("http://XX.com/XX.jpg",9); //文件尾部插入图片 document.all.FramerControl1.InSertFile("http://XX.com/XX.jpg",10); //当前光标位置插入图片 document.all.FramerControl1.InSertFile("http://XX.com/XX.jpg",8); /* 0x31. 文档另存为 HRESULT SaveAs([in] VARIANT strFileName, [in] VARIANT dwFileFormat, [out,retval] long* pbool); 参数: strFileName:文件本地路径,如c:\\11.doc dwFileFormat: 文件格式 dwFileFormat的数值为: Excel: Type enum XlFileFormat { xlAddIn = 18, xlCSV = 6, xlCSVMac = 22, xlCSVMSDOS = 24, xlCSVWindows = 23, xlDBF2 = 7, xlDBF3 = 8, xlDBF4 = 11, xlDIF = 9, xlExcel2 = 16, xlExcel2FarEast = 27, xlExcel3 = 29, xlExcel4 = 33, xlExcel5 = 39, xlExcel7 = 39, xlExcel9795 = 43, xlExcel4Workbook = 35, xlIntlAddIn = 26, xlIntlMacro = 25, xlWorkbookNormal = -4143, xlSYLK = 2, xlTemplate = 17, xlCurrentPlatformText = -4158, xlTextMac = 19, xlTextMSDOS = 21, xlTextPrinter = 36, xlTextWindows = 20, xlWJ2WD1 = 14, xlWK1 = 5, xlWK1ALL = 31, xlWK1FMT = 30, xlWK3 = 15, xlWK4 = 38, xlWK3FM3 = 32, xlWKS = 4, xlWorks2FarEast = 28, xlWQ1 = 34, xlWJ3 = 40, xlWJ3FJ3 = 41, xlUnicodeText = 42, xlHtml = 44 }; Word: Type enum WdSaveFormat { wdFormatDocument = 0, wdFormatTemplate = 1, wdFormatText = 2, wdFormatTextLineBreaks = 3, wdFormatDOSText = 4, wdFormatDOSTextLineBreaks = 5, wdFormatRTF = 6, wdFormatUnicodeText = 7, wdFormatEncodedText = 7, wdFormatHTML = 8 }; PPT: enum PpSaveAsFileType { ppSaveAsPresentation = 1, ppSaveAsPowerPoint7 = 2, ppSaveAsPowerPoint4 = 3, ppSaveAsPowerPoint3 = 4, ppSaveAsTemplate = 5, ppSaveAsRTF = 6, ppSaveAsShow = 7, ppSaveAsAddIn = 8, ppSaveAsPowerPoint4FarEast = 10, ppSaveAsDefault = 11, ppSaveAsHTML = 12, ppSaveAsHTMLv3 = 13, ppSaveAsHTMLDual = 14, ppSaveAsMetaFile = 15, ppSaveAsGIF = 16, ppSaveAsJPG = 17, ppSaveAsPNG = 18, ppSaveAsBMP = 19 }; */ /* 0x32. 删除本地文件 HRESULT DeleteLocalFile([in] BSTR strFilePath); 参数: strFileName:文件本地路径,如c:\\11.doc */ /* 0x33.创建临时文件 HRESULT GetTempFilePath([out,retval] BSTR* strValue); 返回: 临时文件的路径地址。使用完后,用DeleteLocalFile 删除 */ /* 0x34.设置文档显示模式 HRESULT ShowView([in] long dwViewType, [out,retval] long * pbool); dwViewType的可取值为: enum WdViewType { wdNormalView = 1, wdOutlineView = 2, wdPrintView = 3, wdPrintPreview = 4, wdMasterView = 5, //这个是大纲 wdWebView = 6 }; */ //大纲模式 document.all.FramerControl1.ShowView(5); /* 0x39:下载远程文件 HRESULT DownloadFile( [in] BSTR strRemoteFile, [in] BSTR strLocalFile, [out,retval] BSTR* strValue); 参数: strRemoteFile:远程路径地址,http or Ftp strLocalFile: 本地保存地址,if strLocalFile == NULL then Create Temp File and return TempFile's Path */ /* 0x40:增加Http上传时候的,附加其他文件 HRESULT HttpAddPostFile([in] BSTR strFileID, [in] BSTR strFileName, [out,retval] long* pbool); 参数: strFileID:文件的ID,供服务器端页面解析 strFileName: 本地文件地址 */ /* 0x41,0x42.获取详细的修订信息。 GetRevCount( [out,retval] long * pbool); GetRevInfo([in] long lIndex, [in] long lType, [out,retval] BSTR* pbool); 例子如下 */ var vCount; vCount = document.all.FramerControl1.GetRevCount(); alert(vCount); var vOpt = 0; var vDate; for(var i=1; i<= vCount; i++){ vOpt = document.all.FramerControl1.GetRevInfo(i,2); if("1" == vOpt){ vOpt = "插入"; }else if("2" == vOpt){ vOpt = "删除"; }else{ vOpt = "未知操作"; } vDate = new String(document.all.FramerControl1.GetRevInfo(i,1)); vDate = parseFloat(vDate); alert(vDate); dateObj = new Date(vDate); alert(dateObj.getYear() + "年" + dateObj.getMonth() + 1 + "月" + dateObj.getDate() +"日" + dateObj.getHours() +"时" + dateObj.getMinutes() +"分" + dateObj.getSeconds() +"秒" ); alert("用户:"+document.all.FramerControl1.GetRevInfo(i,0) + "\r\n操作:" + vOpt + "\r\n内容:" + document.all.FramerControl1.GetRevInfo(i,3)); } /* 0x43.设置基本信息: HRESULT SetValue([in] BSTR strValue, [in] BSTR strName, [out,retval] long* pbool); 1.设置文件只读密码 SetValue("password","::DOCPROP:PassWord"); 2.设置文件修改密码 SetValue("password","::DOCPROP:WritePW"); 返回值: 0 正确 -1:不支持此命令,请确定您的第二个参数没有传错 -127:异常 */ //设置文件只读密码 document.all.FramerControl1.SetValue("password","::DOCPROP:PassWord"); //设置文件修改密码 document.all.FramerControl1.SetValue("password","::DOCPROP:WritePW"); /* 0x44.设置文档变量,这个很少能用到 HRESULT SetDocVariable([in] BSTR strVarName, [in] BSTR strValue,[in] long lOpt, [out,retval] long* pbool); strVarName: 变量名 strVlaue:变量值 lOpt: 操作类型, 按位 第一位为1: 表示update域关联的 第二位为1: 表示如果没有这个变量则添加 第三位为1: 未来支持 return: 0:OK -127:异常 */ /* 0x45: 分页保存 HRESULT SetPageAs([in] BSTR strLocalFile, [in] long lPageNum, [in] long lType,[out,retval] long* pbool); strLocalFile:本地路径 lPageNum:页数 */
WebOffice是一款由北京点聚信息技术有限公司提供的完全免费(商业用途也免费)且功能强大的在线Word/excel/wps编辑辅助控件,可以实现: 1.在线编辑Word、Excel、PPT、WPS... ... 2.全面支持MS Office的界面定制,包括对于Office2007的全面支持 3.修订留痕 4.限制打印、保存、复制 5.直接保存到服务器,支持标准Http Post协议 6.强大的书签管理 7.套红、文档保护 8.模板管理 9.其他功能扩展 10.提供开发论坛http://www.dianju.cn/forum/,在其中提供软件更新及问题回答服务 本控件不同于其它同类软件,不是基于微软的开放源码DsoFramer,也不基于OLE,可以解决DsoFramer及其派生产品的一些稳定性问题 本控件不同于其它同类收费软件,本控件完全免费和界面完全可控制。 点聚会定期更新本控件,并解答论坛上的询问,免费不代表免服务,每一个使用者都能得到及时服务。 安装包内包含: 1.WebOffice安装包(仅包含WebOffice控件) 2.WebOffice接口SDK 3.WebOffice网页接口调用例子 4.DES手写及签章系统(Office签章系统)试用版。 5.演示章及证书 6.点聚产品白皮书 WebOffice组件可以无缝集成点聚公司的电子签章和手写审批类产品。 点聚信息(http://www.dianju.com.cn)是国内专业的安全和文档中间件软件制造商。公司注重自主知识产权产品的研发,始终坚持技术为本、服务为先的原则,在电子印章、手写签批、安全版式文档和电子表单等领域处于国内领先水平。 点聚自主研发的版式文件系统独创性的将整个系统缩小为1M大小的组件,并在多项重要技术指标上领先PDF和其它版式格式。 点聚支持全系列手写及签章解决方案,可同时提供Office签章系统(Word/Excel/Wps)、网页签章系统、版式签章系统. 点聚是国内唯一一家同时拥有国密和军密资质的电子印章及安全文档产品提供商(国密、军密、公安部销售许可)。
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值