Document online editing and development experience

1. Background
In this company's development task, I came across the integrated development of Changshu Office's document online editing by chance. I encountered some problems during the development. I found this thing very interesting. I wrote this article to save my development experience.
2. Pre-preparation
The document online editing function has only one api. file, which is saved in my download. The company uses the layui framework, and the development document address: development document address 3.
Code display
fileEdit.js

/**
 * author:fzt
 * date:2022-11-16
 * describe:File viewing and editing
 */
let baseUrl = "/api";
layui.extend({
    
    
    mapletrutil: '../../../../../static/js/util/mapletrutil',
    fileService: '../../../../../static/js/components/fileUpload/fileService',
   /* dfExtendUtil: '../../../../../static/js/tdmproject/dftdm/public/dfExtendUtil',*/
});

layui.define(['layer','mapletrutil','fileService', 'jquery'],function (exports) {
    
    
    let layer = layui.layer;
    let $ = layui.$;
    let mapletrutil = layui.mapletrutil;
    let fileService = layui.fileService;
    /*let dfExtendUtil = layui.dfExtendUtil;*/

    //定义参数:
    //要打开的文件类型,具体格式见下方注释
    let fileType = "";
    //定义是否可编辑,默认为false
    let isEdit = "view";
    //定义文档id
    let fileId = "";
    //指定打开文档的唯一ID,畅写Office以key为依据决定是否加载上次编辑过程产生的缓存记录。
    let key = "";
    //标题,可使用文档名称
    let title = "";
    //指定要打开的文档的地址
    let url = "";
    //指明文档类型,文字处理:"word"、电子表格:"cell"、演示文稿:"slide"
    let documentType = "";
    //回调接口地址
    let callbackUrl = "http://tdm-backend-sit.tc.dfmc.com.cn/online/callback";
    /*
    * fileType
    * 描述 指明要打开的具体文件类型
    * 数据类型string
    * 参数
    * 文字处理 (.doc, .docm, .docx, .dot, .dotm, .dotx, .epub, .fodt, .htm, .html, .mht, .odt, .ott, .pdf, .rtf, .txt,.xps, wps)
    * 电子表格 (.csv, .fods, .ods, .ots, .xls, .xlsm, .xlsx, .xlt, .xltm, .xltx,.et) 演示文稿
    *(fodp, .odp, .otp, .pot, .potm, .potx, .pps, .ppsm, .ppsx, .ppt, .pptm, .pptx,dps)
    * */
    let wordType = ["doc","docm","docx","dot","dotm","dotx","epub","fodt","htm","html","mht","odt","ott","pdf","rtf","txt","xps","wps"];
    let excelType = ["csv","fods","ods","ots","xls","xlsm","xlsx","xlt","xltm","xltx","et"];
    let pptType = ["fodp","odp","otp","pot","potm","potx","pps","ppsm","ppsx","ppt","pptm","pptx","dps"];

    let init = function(){
    
    
        let param = getUrlParam();
        fileId = param.get("fileId");
        let edit = param.get("isEdit");
        let fileInfo = fileService.getFileInfoByFileIds(fileId);
        let metaUrl = fileService.getMetaUrl();
        key=fileId;
        if(edit=="true"){
    
    
            isEdit="edit";
        }
        if(!fileId||fileId==""||fileId==null){
    
    
            layer.msg("文件ID不能为空",{
    
    'icon':5});
            return false;
        }

        title = fileInfo.originalname;
        let fileSuffix = fileInfo.fileSuffix;
        if(!fileSuffix||!fileSuffix==""|!fileSuffix==undefined||!fileSuffix==null||!fileSuffix.indexOf(".")==-1){
    
    
            fileType= fileSuffix.substr(fileSuffix.lastIndexOf(".") + 1);
        }
        if(documentType==""){
    
    
            for(let i=0;i<wordType.length;i++) {
    
    
                if(fileType==wordType[i]){
    
    
                    documentType=="word";
                    break;
                }
            }
        }
        if(documentType=="") {
    
    
            for (let i = 0; i < excelType.length; i++) {
    
    
                if (fileType == excelType[i]) {
    
    
                    documentType == "cell";
                    break;
                }
            }
        }
        if(documentType=="") {
    
    
            for (let i = 0; i < pptType.length; i++) {
    
    
                if (fileType == pptType[i]) {
    
    
                    documentType == "slide";
                    break;
                }
            }
        }

        let fileServerUri = fileInfo.fileServerUri;
        url=fileServerUri+"/file/down?metaUrl="+metaUrl+"&fileId="+fileId;


        debugger;

        let editor_SDK = new CXO_API.CXEditor("CXO_Editor_SDK",{
    
    
            "document": {
    
     //文档参数集
                "fileType": fileType, //指明要打开的文件类型,例如"xlsx"、"pptx"
                "key": key, //文档唯一ID
                "title": title, //文档标题名称
                "usePdfjs":true,//是否使用pdf.js插件打开pdf类型文档
                "url": url //文档存放路径
            },
            "documentType": documentType,//指明文档类型,文字处理:"word"、电子表格:"cell"、演示文稿:"slide"
            "height": "100%",//设置文档编辑器在浏览器中的高度,默认"100%"
            "type": "desktop",//设置平台类型:PC端"desktop",手机端"mobile"
            "width": "100%",//设置文档编辑器在浏览器中的宽度,默认"100%"
            "token":"2333333333333331", //设置访问服务token
            "editorConfig": {
    
    
                "callbackUrl": callbackUrl,//回调接口URL
                "mode": isEdit,//指定文档打开模式,默认值"edit"。只读模式"view",编辑模式"edit"
                "limitEditMode":"nolimit", //部分编辑模式,"nolimit"无限制,"ctctrl"只能对未设置只读的内容域进行编辑

                "customization": {
    
    
                    "chat": true,  //是否开启IM,默认true
                    "disabledAddTypeData":false,
                    "disabledDeleteTypeData":false,
                    "leftMenu": true,//是否显示左侧菜单,默认true
                    "rightMenu": true,//是否显示右侧菜单,默认true
                    "toolbar": true,//是否显示顶部菜单栏,默认true
                    "statusBar": true,//是否开启状态栏,默认true
                    "autosave": true,//是否开启自动保存,默认true
                    "logo":{
    
    
                        "image":""//image为空隐藏logo,授权后也可以替换logo地址
                    },
                    "about":false,//设置是否显示关于畅写,默认true不隐藏
                    "forcesave":true,//是否开启强制保存,默认false,开启后用户点击保存直接触发回调接口
                    "displayTitle":true,//是否显示标题,默认true
                    "plugins":true,//是否显示扩展菜单,默认true
                    "reviewDisplay":'markup',//修订显示模式,"final"最终状态、"markup"标记状态、"original"原始状态
                    "hideDownLoadOnMobile":false, //移动端是否隐藏下载按钮
                    "isCompareWithUrl":false,//开启在文档加载完成后与参数compareWithUrl指向的文档进行比较
                    "compareWithUrl":'http://exampke.com/aa.docx', //要进行比较的目标文档地址(该地址要能下载到文档)
                    "goback": {
    
    
                        "blank": true,//是否在新窗口打开
                        "text": "Go to Documents",//显示文字
                        "url": "https://example.com"//回跳的url地址
                    },
                    "watermark":{
    
    
                        "transparent" : 0.5, //透明度,默认为 0.3,范围是0-1
                        "type" : "rect",//水印类型,"rect"为矩形,"ellipse"为椭圆
                        "width" : 150,//水印宽度,单位mm
                        "height" : 150,//水印高度,单位mm
                        "rotate" : 0,//水印旋转角度,360为旋转一周,正数为顺时针旋转,负数逆时针旋转
                        "margins" : [ 10, 2, 5, 0 ],//段落距边框的留白区域[l,t,r,b]
                        "fill" : [255, 0, 0],//水印填充颜色
                        "stroke-width" : 1,//描边,宽度单位mm
                        "stroke" : [0, 0, 255],//描边的颜色
                        "align" : 1,// 垂直方向文本对齐方式,4顶端对齐,1居中对齐,0底端对齐
                        "paragraphs" : [ {
    
    //整个水印段落设置
                            "align" : 0,//水平方向文本对齐方式,1左对齐,2居中对齐,0右对齐
                            "fill" : [255, 255, 0],//段落背景色
                            "linespacing" : 10.0, //行间距(倍数)
                            "runs" : [ //可以换行,不同行可以设置不同样式,目前写在前面的元素会后显示,写在后面的会先显示,也就是说显示结果和书写顺序成倒序
                                {
    
    
                                    "text" : "%user_name%!",//文字内容,其中%user_name%会被替换为当前用户的名字
                                    "fill" : [0, 255, 0],//文字颜色
                                    "font-family" : "simsun",//文字使用的字体属性
                                    "font-size" : 10,//文字字号
                                    "bold" : true,//是否加粗
                                    "italic" : false,//是否倾斜
                                    "strikeout" : false,//是否加删除线
                                    "underline" : false//是否加下划线
                                },
                                {
    
    "text" : "%<br>%"},//新起一行,需单独书写,不可和其它文本内容写到一起
                                {
    
    "text" : "textcontent"}//另一行内容设置
                            ]
                        }]
                    },
                    "zoom": 100//指定文档缩放大小,0-100,文字处理和演示文稿可以设置为-1(文档适应页面)或-2(文档页面适应编辑器页面),默认值100
                }
            },
            
        });

        let forceSave = function(){
    
    
                   editor_SDK.forceSave();
               };
        let destroyEditor = function(){
    
    
            editor_SDK.destroyEditor();
        };
        let selected = function(){
    
    
            editor_SDK.getDocumentContent({
    
    
                "object":"text",    //操作文本内容,必填项
                "type":"selected",  //操作类型是选择,必填项
            });
        };


        let onGetDocumentContent = function(event){
    
    
            console.log(event.data);
        };
        let hyperlink = function(){
    
    
            editor_SDK.setDocumentContent({
    
    
                "object":"hyperlink",   //表示是超链接对象,必填项
                "type":"insert",        //表示是插入操作,目前只支持插入,必填项
                "link":"https://www.baidu.com",  //超链接的链接地址,必填项
                "text":"百度浏览器",  //在文档中显示的内容,如果不设置则以超链接的文字内容做为内容插入
                "tip":"tip", //鼠标放到超链接时显示的提示信息
            });
        };
        let text = function(){
    
    
            editor_SDK.setDocumentContent({
    
    
                "object":"text",  //表示是文字,必填项
                "type":"insert",  //表示是插入操作必填项
                "text":"新文本",   //插入的文字内容,必填项
            });
        };
        let bookmark = function () {
    
    
            editor_SDK.setDocumentContent({
    
    
                "object":"bookmark", //表示操作对象为书签,必填项
                "type":"insert",     //表示操作行为是插入,必填项
                "name":"book",       //书签的名字,书签名字只能为数字、字母及下划线,且以字母开头,必填项
                "value":"书签内容"     //在文档中书签位置要插入的文本内容
            });
        };
        let getAllbookmark = function () {
    
    
            editor_SDK.getDocumentContent({
    
    
                "object":"bookmark", //表示操作对象为书签,必填项
                "type":"names",      //提取书签名字,必填项
            });
        };

        let getProperty = function () {
    
    
            editor_SDK.getDocumentContent({
    
    
                "object":"content",  //表示操作对象为内容域,必填项
                "type":"property",   //提取内容域属性,必填项
                "name":"",           //提取指定标签名称内容域的属性,name和id互斥,name优先级高于id,如name及id都未填写,则获取当前文档全部内容域
                "id":""              //提取指定id内容域的属性,name和id互斥,name优先级低于id,如name及id都未填写,则获取当前文档全部内容域
            });
        };
        let getText = function () {
    
    
            editor_SDK.getDocumentContent({
    
    
                "object":"content",  //表示操作对象为内容域,必填项
                "type":"text",       //提取类型为文本,必填项
                "name":"",           //提取指定标签名称内容域的属性,name和id互斥,name优先级高于id,如name及id都未填写,则获取当前文档全部内容域
                "id":""              //提取指定id内容域的属性,name和id互斥,name优先级低于id,如name及id都未填写,则获取当前文档全部内容域
            });
        };
        let getAll = function () {
    
    
            editor_SDK.getDocumentContent({
    
    
                "object":"content",  //表示操作对象为内容域,必填项
                "type":"all",       //提取类型,必填项 all全部提取 table提取表格 image提取图片
                "name":"con",           //内容域的标签,name和id互斥,name优先级高于id,如name及id都未填写,则获取当前文档全部内容域
                "id":""              //内容域的id,name和id互斥,name优先级低于id,如name及id都未填写,则获取当前文档全部内容域
            });
        };
        let replace = function () {
    
    
            editor_SDK.setDocumentContent({
    
    
                "object":"content", //表示操作对象为内容域,必填项
                "type":"replace",   //表示操作行为是替换内容,必填项
                "name":"con",       //内容域的标签,可以是英文数字,优先级高于ID
                "id":"",            //内容域的ID,name和id必须有一
                "value":"新内容"     //替换完成后内容域内的文字内容
            });
        };
        let replaceall = function () {
    
    
            editor_SDK.setDocumentContent({
    
    
                "object":"content",  //表示操作对象为内容域,必填项
                "type":"replaceAll", //表示操作行为是替换内容,必填项
                "value":[{
    
    
                    "name":"con",    //内容域标签
                    "id":"",         //内容域ID
                    "value":"新内容1" //内容域内容
                }]
            });
        };
        let appendAll = function () {
    
    
            editor_SDK.setDocumentContent({
    
    
                object: 'content',
                type: 'appendAll',
                value:[
                    {
    
    
                        name : 'xxxxx',
                        id : '0000',
                        text : '追加的内容'
                    }
                ]
            });
        };
        let select = function () {
    
    
            editor_SDK.setDocumentContent({
    
    
                "object":"content",   //表示操作对象为内容域,必填项
                "type":"select",      //表示是选中操作,必填项
                "id":"370312776"      //内容域的id

            });
        };
        let clear = function () {
    
    
            editor_SDK.setDocumentContent({
    
    
                "object":"content",   //表示操作对象为内容域,必填项
                "type":"clear",       //表示是清除内容域内容,必填项
                "name":"con" ,        //内容域的标签
                "id":""               //内容域的id

            });
        };
        /*let editor= new CXO_API.CXEditor("CXO_Editor_SDK", {
            "events": {
                "forceSave":forceSave,
                "destroyEditor":destroyEditor,
                "selected":selected,
                "hyperlink":hyperlink,
                "bookmark":bookmark,
                "getAllbookmark":getAllbookmark,
                "getProperty":getProperty,
                "getText":getText,
                "getAll":getAll,
                "replace":replace,
                "replaceall":replaceall,
                "select":select,
                "clear":clear
            },
        });*/
        editor_SDK.setDocumentContent({
    
    
            object: 'content',
            type: 'dropdownValue',
            value:[
                {
    
    
                    name : 'xxxxx',
                    id : '0000',
                    value : 'v1'   //要选中选项的值(value)
                }
            ]
        })
        editor_SDK.setDocumentContent({
    
    
            object: 'content',
            type: 'comboboxValue',
            value:[
                {
    
    
                    name : 'xxxxx',
                    id : '0000',
                    value : 'v1'  //要选中选项的值(value)
                }
            ]
        });
        editor_SDK.setDocumentContent({
    
    
            object: 'content',
            type: 'checkboxValue',
            value:[
                {
    
    
                    name : 'xxxxx',
                    id : '0000',
                    value : true   //true勾选 false不勾选
                }
            ]
        });
        editor_SDK.setDocumentContent({
    
    
            object: 'content',
            type: 'pictureValue',
            value:[
                {
    
    
                    name : 'xxxxx',
                    id : '0000',
                    value : ''   //可访问图片网络地址 如:http://image.xxxx.com/a.jpg
                }
            ]
        });

        editor_SDK.setDocumentContent({
    
    
            object: 'content',
            type: 'empty',       //表示是清空内容域内容,必填项
            id: '0000',
            name: 'xxxxx',
        })

    };
    getUrlParam = function () {
    
    
        let data = new Map();
        let url=window.location.search; //获取url中"?"符后的字串
        if(url.indexOf("?")!=-1){
    
    
            let result = url.substr(url.indexOf("?")+1);
            /*result = url.substr(url.indexOf("=")+1);*/
            /*result = result.substr(url.indexOf("&")+1);*/
            let params=new URLSearchParams(result);
            data.set("fileId",params.get("fileId"));
            data.set("isEdit",params.get("isEdit"));

        }
        return data;

    };


    let getFileInfoByFileId = function(fileId) {
    
    
        let fileInfo = {
    
    };
        mapletrutil.ajax({
    
    
            type: 'post',
            url: baseUrl+'/fileinfo/find/' + fileId,
            async: false,
            success: function(result) {
    
    
                if (result.status == 0) {
    
    
                    fileInfo = result.data;
                } else {
    
    
                    layer.msg("获取文件信息失败,失败原因:" + result.msg, {
    
    
                        icon: 5
                    });
                }
            },
            error: function(XMLHttpRequest, textStatus,
                            errorThrown) {
    
    
                layer.open({
    
    
                    title: '获取文件信息失败',
                    content: "请求异常,错误码:" + XMLHttpRequest.status,
                    icon: 5
                });
            }
        });
        return fileInfo;
    };

    let fileChecked = {
    
    
        init:init
    }
    exports("fileChecked", fileChecked);
});

fileEdit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="../../../../../lib/layui-v2.6.7/layui.js" type="text/javascript" charset="utf-8"></script>
    <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;
            padding: 0;
            text-decoration: none;
        }

    </style>
    <script type = "text/javascript" src="http://10.4.10.20:8080/web-apps/apps/api/documents/api.js"></script>
    <!--<script type = "text/javascript" src="../../../../../static/js/tdmproject/dftdm/public/api.js"></script>-->
    <title>Document</title>
</head>
<body>
<div  id = "CXO_Editor_SDK" ></div>
<script>
    layui.extend
    ({
      
      
        fileChecked:"../../../../../static/js/tdmproject/dftdm/fileChecked/fileChecked"
    });
    layui.use('fileChecked', function(){
      
      
        var fileChecked = layui.fileChecked;
        fileChecked.init();

    });
</script>
</body>
</html>

Guess you like

Origin blog.csdn.net/fzt12138/article/details/128471606