简介
本文介绍的 WebOffice 控件是由广州市华尔太科技有限公司开发的一款在网页里处理 Office 文件的产品。 WebOffice 控件支持几乎所有对在线文档功能的需求,如在线新建、编辑、保存、多人协作 Office 文件等。
它具有以下核心功能
1、远程打开、保存:WebOffice全自动,无需手动上传下载,遵守标准HTTP/HTTPS传输协议,支持服务器同步和异步方式保存文件。
2、智能填报/读取:可从数据库指定字段提取数据,填充文档指定位置,也可从文档指定位置读取数据到数据库指定字段。
3、强大的API接口和VBA扩展能力:高效API与VBA扩展,任意办公文档扩展功能均可用VBA整合JS满足业务需求。
优缺点
相比于 WPS 提供的 WebOffice,广州市华尔太科技有限公司的 WebOffice 控件具有价格低、接入简单(前端无需额外安装包)和 dome 丰富的优点。
WebOffice 控件也有很致命的缺点,即客户端需要在本地安装 WebOffice 控件。另外 WebOffice 控件的操作窗口是弹出一个单独的窗口,在这个窗口没法打开控制台,不方便调试,而且样式也很老旧。
WebOffice 控件好像没有文档(我没找到,这也是写这篇文章的原因),虽然提供了大量的实现各种功能的 demo,但是并没有涵盖所有的操作,所以有时候就得去翻 Microsoft Office 的文档。
几个可能用得着的文档地址
- Office 加载项 JavaScript API 参考
- Docs .NET .NET API browser Microsoft.Office.Interop.Word Table
- Office VBA 参考
- 在线演示(官网给的 demo,一般需要下载下载,然后设置正确的 UserName 和 Authorizer 才能运行)
备忘
WORD
WebOffice.ActiveDocument.Tables(1); // 返回文件的第一个表格对象
WebOffice.ActiveDocument.Tables.Count; // 返回文档中表格的数量
WebOffice.ActiveDocument.Tables(1).Rows.Count; // 返回文档中第一个表格的行数
WebOffice.ActiveDocument.Tables(1).Columns.Count; // 返回文档中第一个表格的列数
WebOffice.ActiveDocument.Tables(1).Rows(1).Delete(); // 删除表格的第一行
WebOffice.ActiveDocument.Application.Selection.Type // number 1 表示没有选中内容。 2 表示选中文本内容
console.log(WebOffice.IsDirty); // 只读属性,表示文档是否有修改
// 保护文档,使文档那个不可编辑
WebOffice.ActiveDocument.Protect(3,false,this.pwd,false,true);
// 先解除保护,使文档可编辑
WebOffice.ActiveDocument.Application.ActiveDocument.UnProtect(this.pwd);
dome
文档操作页面
<template>
<div class="web-edit">
<div class="left">
<div class="btn-area">
<el-button size="small" @click="quiteAction">退出</el-button>
<el-button size="small" type="primary" @click="HttpPostSave">保存</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: [], // 已选的字段列表
}
},
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:{
// 插入表格
/**
* data 表格的数据;
* columnsCount 列数;
* rowsCount 行数;
* isAdapt 是否自动调整表格中单元格的大小以适应单元格的内容(word 中)(可选)
*/
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("提示:两个表格之间至少有一行空行");
return;
}
data = Array.isArray(data) ? data : [];
if (rowsCount < 1) {
alert("表格的行数不能小于 1");
} else {
data.forEach((rows, rowIndex) => {
if (Array.isArray(rows)) {
// 二维数组,不止一行的情况下
rows.forEach((cell, columnIndex) => {
table.Cell(rowIndex + 1, columnIndex + 1).Range.InsertAfter(cell);
})
} else {
// 只有一行
table.Cell(1, rowIndex + 1).Range.InsertAfter(rows);
}
})
}
range = null;
table = null;
// WebOffice.ActiveDocument.Tables(1); // 返回文件的第一个表格对象
// WebOffice.ActiveDocument.Tables.Count; // 返回文档中表格的数量
// WebOffice.ActiveDocument.Tables(1).Rows.Count; // 返回文档中第一个表格的行数
// WebOffice.ActiveDocument.Tables(1).Columns.Count; // 返回文档中第一个表格的列数
// WebOffice.ActiveDocument.Tables(1).Rows(1).Delete(); // 删除表格的第一行
// WebOffice.ActiveDocument.Application.Selection.Type // number 1 表示没有选中内容。 2 表示选中文本内容
// console.log(WebOffice.IsDirty); // 只读属性,表示文档是否有修改
// 保护文档,使文档那个不可编辑
// WebOffice.ActiveDocument.Protect(3,false,this.pwd,false,true);
// 先解除保护,使文档可编辑
// WebOffice.ActiveDocument.Application.ActiveDocument.UnProtect(this.pwd);
},
unfoldAction(item) {
item.isUnfold = !item.isUnfold;
},
insertAction(field, type) {
let isRevise = WebOffice.ActiveDocument.Application.Selection.Type === 2;
// 先解除保护,使文档可编辑
// WebOffice.ActiveDocument.Application.ActiveDocument.UnProtect(this.pwd);
if (isRevise) {
WebOffice.ActiveDocument.Application.Selection.Cut(); // 删除所选内容,并将内容移至剪切板
}
if (type === "表格") {
let columnsCount = field.header.length, rowsCount = 2;
let data = [field.header, field.header.map(() => "")];
this.insertTable(data, columnsCount, rowsCount);
} else {
// 在光标处插入文本
WebOffice.ActiveDocument.Application.Selection.Range.InsertAfter(field.code);
}
if (!this.fields.includes(field.id)) {
this.fields.push(field.id);
}
// 保护文档,使文档不可编辑
// 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');
// 正确设置 UserName 和 Authorizer 才能正确打开
WebOffice.UserName="公司名称";
WebOffice.Authorizer="www.officectrl.com";
this.$nextTick(() => {
setTimeout(() => {
WebOffice.MenuBar = false;
WebOffice.Toolbars = true; // 是否显示工具栏
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();
},
// 保存文件(同步保存)
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","");//此句为固定语句,不管是保存word还是excel,ppt等都这样写
const strResults = WebOffice.HttpPost(strSaveUrl);
// console.log(strResults);
// strResults;//如果保存成功,编程时让服务器接收代码如upload.jsp,upload.aspx,upload.php等返回空值或OK字串。
// if(strResults.indexOf('ok') > 1)
alert('office文档保存成功!');
}
catch(e) {
alert('发生错误!请使用查阅返回值!');
}
},
// 获取可配置的字段
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('保存成功');
})
.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>
打开编辑页面的方法
// 编制动作
editAction(id) {
let pre = "weboffice://|Officectrl|"; // 这个很关键!!!
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');
}
},
// 检查浏览器类型
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;
},