WebOffice document online editing

Keywords: Front-end Vue.js

brief introduction

The WebOffice control introduced in this paper is a product developed by Guangzhou waltai Technology Co., Ltd. to process Office files in web pages. WebOffice controls support almost all the requirements for online document functions, such as online new creation, editing, saving, multi person collaboration, Office files, etc.
It has the following core functions

1. Remote opening and saving: WebOffice is fully automatic without manual uploading and downloading. It complies with the standard HTTP/HTTPS transmission protocol and supports the server to save files synchronously and asynchronously.
2. Intelligent filling / reading: you can extract data from the specified fields in the database, fill in the specified location of the document, or read data from the specified location of the document to the specified fields in the database.
3. Strong API interface and VBA expansion capability: efficient API and VBA expansion. Any office document expansion function can be integrated with JS by VBA to meet business needs.

  Official website portal

Advantages and disadvantages

Compared with the WebOffice provided by WPS, the WebOffice control of Guangzhou waltai Technology Co., Ltd. has the advantages of low price, simple access (no additional installation package is required for the front end) and rich dom.

WebOffice control also has a fatal disadvantage, that is, the client needs to install WebOffice control locally. In addition, the operation window of WebOffice control is to pop up a separate window. In this window, the console cannot be opened, which is inconvenient for debugging, and the style is very old.

WebOffice controls seem to have no documents (I didn't find them, which is the reason for writing this article). Although they provide a large number of demo s to realize various functions, they don't cover all operations, so sometimes you have to turn to Microsoft Office documents.

Several possible document addresses

Memo

WORD
	WebOffice.ActiveDocument.Tables(1); // Returns the first table object of the file
    WebOffice.ActiveDocument.Tables.Count; // Returns the number of tables in the document
    WebOffice.ActiveDocument.Tables(1).Rows.Count; // Returns the number of rows of the first table in the document
    WebOffice.ActiveDocument.Tables(1).Columns.Count; // Returns the number of columns of the first table in the document
    WebOffice.ActiveDocument.Tables(1).Rows(1).Delete(); // Delete the first row of the table
    WebOffice.ActiveDocument.Application.Selection.Type // number 1 means nothing is selected. 2 indicates the selected text content
    console.log(WebOffice.IsDirty); // Read only attribute, indicating whether the document has been modified
    // Protect the document so that it is not editable
    WebOffice.ActiveDocument.Protect(3,false,this.pwd,false,true);
    // Unprotect first to make the document editable
    WebOffice.ActiveDocument.Application.ActiveDocument.UnProtect(this.pwd);

dome

Document operation page
<template>
<div class="web-edit">
    <div class="left">
        <div class="btn-area">
            <el-button size="small" @click="quiteAction">sign out</el-button>
            <el-button size="small" type="primary" @click="HttpPostSave">preservation</el-button>
        </div>
        <div class="content-warp">
            <template v-for="classifyLevel1 in fieldList" >
                <p class="title max-title" :key="classifyLevel1.type">
                    <span @click="unfoldAction(classifyLevel1)" class="can-click">
                        {{classifyLevel1.type}}
                        <i v-if="classifyLevel1.isUnfold" class="el-icon-caret-bottom"></i>
                        <i v-else class="el-icon-caret-right"></i>
                    </span>
                </p>
                <template v-if="classifyLevel1.isUnfold">
                    <div class="field-box" v-for="classifyLevel2 in classifyLevel1.fieldList" :key="classifyLevel2.classifyName">
                        <p class="title">
                            <span @click="unfoldAction(classifyLevel2)" class="can-click">
                                {{classifyLevel2.classifyName}}
                                <i v-if="classifyLevel2.isUnfold" class="el-icon-caret-bottom"></i>
                                <i v-else class="el-icon-caret-right"></i>
                            </span>
                        </p>
                        <div class="field-list" v-if="classifyLevel2.isUnfold">
                            <span @click="insertAction(item, classifyLevel1.type)" class="item can-click" :class="{'is-checked': item.checked}" v-for="item in classifyLevel2.fieldList" :key="item.id">{{item.name}}</span>
                        </div>
                    </div>
                </template>
            </template>
            
        </div>
    </div>
    <div class="right">
        <object classid="clsid:FF09E4FA-BFAA-486E-ACB4-86EB0AE875D5" codebase="http://www.officectrl.com/weboffice/WebOffice.ocx#Version=2018,1,6,2" id="WebOffice" width="100%" height="100%" ></object>
    </div>
 </div>
</template>
<script>
import { temDetail, getFieldList, saveFieldsList } from "@/api/baseInfo";
import { setToken } from '@/utils/auth'

export default {
    data () {
        return {
            strUrl: '',
            doctype: '',
            imgList: [],
            WebOffice: '',
            fileName: '',
            orderId: null,
            editId: null,
            pwd: Date.now().toString(),
            fieldList: [],
            fields: [], // List of selected fields
        }
    },
    created() {
        let query = this.$route.query;
        let token = query.token;
        setToken(token, false);
        if (query.id) {
            this.editId = query.id;
            this.getFieldList();
            this.temDetail();
        }
    },
    mounted() {
        
    },
    methods:{
        // Insert table
        /**
         * data Table data;
         * columnsCount Number of columns;
         * rowsCount Number of rows;
         * isAdapt Whether to automatically resize the cells in the table to fit the contents of the cells (in word) (optional)
         */
        insertTable(data, columnsCount, rowsCount=1, isAdapt=true) {
            const range = WebOffice.ActiveDocument.Application.Selection.Range;
            const table = WebOffice.ActiveDocument.Tables.Add(range, rowsCount, columnsCount, isAdapt);
            if (table.Rows.Count > rowsCount) {
                table.Rows(table.Rows.Count).Delete();
                alert("Tip: there is at least one blank row between two tables");
                return;
            }
            data = Array.isArray(data) ? data : [];
            if (rowsCount < 1) {
                alert("The number of rows in the table cannot be less than 1");
            } else {
                data.forEach((rows, rowIndex) => {
                    if (Array.isArray(rows)) {
                        // Two dimensional array, in case of more than one row
                        rows.forEach((cell, columnIndex) => {
                            table.Cell(rowIndex + 1, columnIndex + 1).Range.InsertAfter(cell);
                        })
                    } else {
                        // Only one line
                        table.Cell(1, rowIndex + 1).Range.InsertAfter(rows);
                    }
                })
            }
            range = null;
            table = null;
            // WebOffice.ActiveDocument.Tables(1); //  Returns the first table object of the file
            // WebOffice.ActiveDocument.Tables.Count; //  Returns the number of tables in the document
            // WebOffice.ActiveDocument.Tables(1).Rows.Count; //  Returns the number of rows of the first table in the document
            // WebOffice.ActiveDocument.Tables(1).Columns.Count; //  Returns the number of columns of the first table in the document
            // WebOffice.ActiveDocument.Tables(1).Rows(1).Delete(); //  Delete the first row of the table
            // WebOffice.ActiveDocument.Application.Selection.Type // number 1 indicates that nothing is selected. 2 indicates the selected text content
            // console.log(WebOffice.IsDirty); //  Read only attribute, indicating whether the document has been modified
            // Protect the document so that it is not editable
            // WebOffice.ActiveDocument.Protect(3,false,this.pwd,false,true);
            // Unprotect first to make the document editable
            // WebOffice.ActiveDocument.Application.ActiveDocument.UnProtect(this.pwd);
        },
        unfoldAction(item) {
            item.isUnfold = !item.isUnfold;
        },
        insertAction(field, type) {
            let isRevise = WebOffice.ActiveDocument.Application.Selection.Type === 2;
            // Unprotect first to make the document editable
            // WebOffice.ActiveDocument.Application.ActiveDocument.UnProtect(this.pwd);
            if (isRevise) {
                WebOffice.ActiveDocument.Application.Selection.Cut(); // Deletes the selection and moves it to the clipboard
            }
            if (type === "form") {
                let columnsCount = field.header.length, rowsCount = 2;
                let data = [field.header, field.header.map(() => "")];
                this.insertTable(data, columnsCount, rowsCount);
            } else {
                // Insert text at the cursor
                WebOffice.ActiveDocument.Application.Selection.Range.InsertAfter(field.code);
            }
            if (!this.fields.includes(field.id)) {
                this.fields.push(field.id);
            }
            // Protect the document so that it is not editable
            // WebOffice.ActiveDocument.Protect(3,false,this.pwd,false,true);
        },
        temDetail() {
            temDetail(this.editId)
            .then(res => {
                let strUrl = res.alioss.attachmentUrl;
                let fileName = res.alioss.fileName;
                this.fileName = fileName;
                let doctype = '';
                let index = fileName.lastIndexOf('.');
                doctype = fileName.substring( index + 1, fileName.length);
                const WebOffice = document.getElementById('WebOffice');
                // The UserName and Authorizer must be set correctly to open correctly
                WebOffice.UserName="corporate name";
                WebOffice.Authorizer="www.officectrl.com";
                this.$nextTick(() => {
                    setTimeout(() => {
                        WebOffice.MenuBar = false;
                        WebOffice.Toolbars = true; // Show toolbar
                        WebOffice.Titlebar = false;
                        WebOffice.Open(strUrl, true, doctype);
                        // WebOffice.ActiveDocument.Protect(3,false,this.pwd,false,true);
                    }, 1000)
                })
            })
            .catch(error => {
                console.log(error);
            })
        },
        quiteAction() {
            window.close();
        },
       	// Save file (sync save)
        HttpPostSave() {
            this.saveFieldsList();
            const strSaveUrl = process.env.VUE_APP_BASE_API + '/api/retemplate/upload';
            try { 
                WebOffice.HttpInit();
                WebOffice.HttpAddPostString('id', this.editId);
                WebOffice.HttpAddPostCurrFile("docfile","");//This sentence is a fixed sentence. It is written in this way whether saving word, excel,ppt, etc
                const strResults = WebOffice.HttpPost(strSaveUrl);
                // console.log(strResults);
                // strResults;// If the save is successful, let the server receive codes such as upload.jsp,upload.aspx,upload.php and return null values or OK strings during programming.
                // if(strResults.indexOf('ok') > 1)
                alert('office The document was saved successfully!');
            }
            catch(e) {
                alert('An error occurred! Please use to check the return value!');
            }	
        },
        // Get configurable fields
        getFieldList() {
            getFieldList(this.editId)
            .then(res =>{
                this.fieldList = res.map(item => {
                    this.$set(item, "isUnfold", true);
                    if(item.fieldList && item.fieldList.length) {
                        item.fieldList.forEach(el => {
                            this.$set(el, "isUnfold", true);
                        })
                    }
                    return item;
                });
            })
            .catch(err => {
                console.log(err);
            })
        },
        saveFieldsList() {
            let params = {
                id: this.editId,
                fields: this.fields
            }
            saveFieldsList(params)
            .then(res => {
                alert('Saved successfully');
            })
            .catch(err => {
                console.log(err);
            })
        },
    }
} 
</script> 
<style lang="scss" scoped>
.web-edit {
    display: flex;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    overflow: hidden;
    background-color: #fff;
    .can-click {
        cursor: pointer;
    }
    .left {
        display: flex;
        flex-direction: column;
        font-size: 14px;
        width: 400px;
        padding-left: 10px;
        .btn-area {
            padding: 30px 0 20px;
            text-align: center;
            .el-button {
                width: 100px;
                & + .el-button {
                    margin-left: 20px;
                }
            }
        }
        .content-warp {
            flex: 1;
            overflow-x: hidden;
            overflow-y: auto;
        }
        .title {
            .el-icon-caret-right, .el-icon-caret-bottom {
                color: #409eff;
            }
        }
        .max-title {
            margin-top: 10px;
            font-size: 16px;
        }
        .field-box {
            padding: 10px 15px 0;
            .field-list {
                padding: 10px 10px 0;
                .item {
                    display: inline-block;
                    padding: 0 8px;
                    margin: 5px 15px 5px 0;
                    font-size: 14px;
                    line-height: 23px;
                    background-color: #eee;
                    white-space: nowrap;
                    border-radius: 3px;
                    &:hover, .is-checked{
                        color: #fff;
                        background-color: #409eff;
                    }
                }
            }
        }
    }
    .right {
        flex: 1;
        height: 100%;
        #WebOffice {
            width: 100%!important;
            height: 100%!important;
        }
    }
    
}
</style>
How to open an edit page
// Preparation action
      editAction(id) {
        let pre = "weboffice://|Officectrl | / / this is very important!!!
        let host = window.location.host;
        let browerType = this.getBrowser();
        let token = getToken();
        if (browerType == 0) {
          const { href } = this.$router.resolve({
            name: "edit",
            query: { 'id': id, 'token': token}
          });
          window.open(href, '_blank');
        } else {
          let strUrl = pre + 'http://' + host + '/#/edit?id=' + id + '&token=' + token;
          window.open(strUrl, '_blank');
        }
      },
      // Check browser type
      getBrowser() {	
        let Sys = {};
        let ua = navigator.userAgent.toLowerCase();
        let s;
        let ver;
        (s = ua.match(/edge\/([\d.]+)/)) ? Sys.edge = s[1] :
        (s = ua.match(/rv:([\d.]+)\) like gecko/)) ? Sys.ie = s[1] :
        (s = ua.match(/msie ([\d.]+)/)) ? Sys.ie = s[1] :
        (s = ua.match(/firefox\/([\d.]+)/)) ? Sys.firefox = s[1] :
        (s = ua.match(/chrome\/([\d.]+)/)) ? Sys.chrome = s[1] :
        (s = ua.match(/opera.([\d.]+)/)) ? Sys.opera = s[1] :
        (s = ua.match(/version\/([\d.]+).*safari/)) ? Sys.safari = s[1] : 0;
        if (Sys.edge) return 1;
        if (Sys.ie) return 0;
        if (Sys.firefox) return 1;
        if (Sys.chrome){ ver = Sys.chrome;ver.toLowerCase();var arr = ver.split('.');if(parseInt(arr[0])>43){return 1;}else{return 0;}}
        if (Sys.opera) return 1;
        if (Sys.safari) return 1;
        return 1;
      },
effect

Posted by jonathen on Thu, 28 Oct 2021 04:16:24 -0700