官方文档地址:快速开始-WebOffice 知识库
首先按照文档写的方式将包引入项目了
util.js
import WebOfficeSDK from "../../public/JSEditor/open-jssdk-v0.0.13.umd"
export function WordSDK(url, isEdit, mountDom, isShowTopArea, isShowHeader) {
const el = document.querySelector(mountDom)
if (!el) return null
const instance = WebOfficeSDK.config({
url,
mount: el,
commandBars: [
{
cmbId: 'HeaderMiddle', // 组件 ID
attributes: {
enable: isEdit, // 禁用组件(组件显示但不响应点击事件)
},
},
],
wordOptions: {
enableReadOnlyComment: isEdit,
isBestScale: false, // 打开文档时,默认以最佳比例显示
},
commonOptions: {
isShowTopArea, // 隐藏顶部区域(头部和工具栏)
isShowHeader, // 隐藏头部区域
// isBrowserViewFullscreen: false, // 是否在浏览器区域全屏
// isIframeViewFullscreen: false, // 是否在 iframe 区域内全屏
// acceptVisualViewportResizeEvent: true, // 控制 WebOffice 是否接受外部的 VisualViewport
},
});
instance.setToken({
// token: `bearer ${getToken('token')}`,
token: '',
timeout: 10 * 60 * 1000,
});
return instance;
}
封装编辑器组件:KSEditor.vue
<template>
<div ref="editorContainer" class="editor-container"></div>
</template>
<script>
import {WordSDK} from "@/utils/util"
export default {
name: 'JsEditorComponent',
props: {
KSfile: {
type: String,
default: ''
},
isShowHeader: {
type: Boolean,
default: true
},
isShowTopArea: {
type: Boolean,
default: true
},
isEditable: {
type: Boolean,
default: true
}
},
data() {
return {
editorInstance: null,
ksConfig: {
// 在这里配置金山在线文档编辑器的初始化参数
// 比如 token、文档ID 等
}
};
},
mounted() {
// 在组件加载完成后初始化编辑器
this.initEditor()
},
methods: {
initEditor() {
let KSInstance = WordSDK(
this.KSfile,
this.isEditable,
'.editor-container',
this.isShowTopArea,
this.isShowHeader,
)
this.$emit('setInstance', KSInstance)
},
createDocument() {
// 在点击按钮时触发新建文档操作
// 假设SDK提供了相应的方法来新建文档
if (this.editor) {
this.editor.createDocument(); // 假设SDK方法名为createDocument
} else {
console.error('编辑器尚未初始化');
}
}
}
};
</script>
<style scoped>
/* 可能需要一些样式来控制编辑器容器的宽度和高度 */
.editor-container {
width: 100%;
height: 600px;
}
</style>
页面testKSEditor.vue
<template>
<div style="width: 100%">
<el-upload
class="compare-uploader"
ref="upload"
:with-credentials="true"
:show-file-list="false"
withCredentials
:http-request="httpRequest"
:on-progress="onProgress"
:multiple="false"
>
<!-- 文件上传-->
<el-button
type="ghost"
slot="trigger"
size="mini"
>
导入文件
</el-button>
</el-upload>
id:<el-input v-model="ksFileInfoCopy.id"/><br/>
文件类型:<el-input v-model="ksFileInfoCopy.ext"/><br/>
文件名称:<el-input v-model="ksFileInfoCopy.name"/><br/>
<el-button
@click="()=>getFileUrl(this.ksFileInfoCopy.id, this.ksFileInfoCopy.ext)"
>
刷新
</el-button>
<el-button
@click="()=>destroyKS()"
>
销毁
</el-button>
<el-button
@click="()=>insertBookmark('TEXT')"
>
插入书签
</el-button>
<el-button
@click="()=>insertBookmark('TABLE')"
>
插入表格类型书签
</el-button>
<el-button
@click="() => this.bookmarks = []"
>
清空
</el-button>
<el-button
@click="()=>changeMode()"
>
{{mode === 'edit'?'预览':'编辑'}}
</el-button>
<el-button
@click="()=>replaceBookmarkValue()"
>
替换书签值
</el-button>
<JSEditor
v-if="showKS"
@setInstance="setInstance"
:KSfile="KSfile"
:isShowTopArea="isShowTopArea"
:isShowHeader="isShowHeader"
:isEditable="isEditableFile"
/>
</div>
</template>
<script>
import axios from "axios";
import JSEditor from 'lib@/components/KSEditor'
import {userTableMap} from "@/modules/testKSeditor/fieldMap";
const userTable = userTableMap
export default {
name: "index",
components: {
JSEditor
},
data () {
// supplementRules:
return {
userId: this.$store.getters.userId,
fileLoading: false,
app: null,
bookmark: null,
KSfile: '',
KSurl: '',
showKS: false,
isShowHeader: true,
isShowTopArea: true,
isEditableFile: true,
ksFileInfo: {
ext: 'docx',
id: '0af2cc2e1da145f48667a6bd09d30e77',
// id: '6170f21b9fe94db78bc2e56d8f543c1e',
name: '工治具报修管理.docx',
url: ''
},
ksFileInfoCopy: {
ext: 'docx',
id: '0af2cc2e1da145f48667a6bd09d30e77',
// id: '6170f21b9fe94db78bc2e56d8f543c1e',
name: '工治具报修管理.docx',
url: ''
},
tableData: [
{
number: '1',
name: 'yy',
sex: 'b',
age: '11'
},
{
number: '2',
name: 'ee',
sex: 'g',
age: '22'
},
{
number: '3',
name: 'ss',
sex: 'b',
age: '33'
},
{
index: '4',
name: 'ff',
sex: 'g',
age: '44'
},
],
mode: 'edit',
bookmarks: [],
KSInstance: null
}
},
methods: {
async setInstance(instance){
// console.log(instance, '1111')
this.KSInstance = instance
await instance.ready()
if(this.mode === 'preview'){
const app = instance.Application
await app.ActiveDocument.SetReadOnly({
Value: true
})
}
// console.log(app, 'this.KSInstance.Application')
},
httpRequest(fileObj) {
const formData = new FormData();
formData.append("file", fileObj.file);
axios({
url: 'https://sdap-dev.sunwoda.com/api/platform-oss/public/upload?bucket=sdap',
method: "post",
data: formData,
})
.then(res => {
this.ksFileInfo = res.data.datas
this.ksFileInfoCopy = res.data.datas
this.getFileUrl(res.data.datas.id, res.data.datas.ext)
})
.catch(error => {
console.log(error);
});
},
getFileUrl(fileId, ext, isPreview) {
this.showKS = false
this.fileLoading = true
axios({
url: 'https://sdap-dev.sunwoda.com/api/platform-system/public/wps-api/edit-url',
method: "get",
params: { fileId, ext, previewMode: 'high_definition' }
})
.then(res => {
this.fileLoading = false
this.KSfile = res.data.datas
this.KSurl = res.data.datas
this.ksFileInfoCopy.url = isPreview ? this.ksFileInfo.url : res.data.datas
this.ksFileInfo.url = res.data.datas
this.showKS = true
})
.catch(error => {
console.log(error);
});
},
destroyKS(){
this.KSInstance.destroy()
},
async insertBookmark(type){
const bookmark = await this.KSInstance.Application.ActiveDocument.Bookmarks;
const selection = await this.KSInstance.Application.ActiveDocument.ActiveWindow.Selection
// 区域对象
let mark = 'mark' + Date.now()
const range = await selection.Range
const start = await range.Start
let content = type + '书签'+ mark
const end = start + content.length
// 在选区后面插入内容
await selection.InsertAfter(content)
await bookmark.Add({
Name: mark,
Range: {
Start: start,
End: end
}
})
this.bookmarks.push({
markName: mark,
type: type,
value: mark + '的值'
})
},
changeMode(){
if(this.mode === 'edit'){
this.mode = 'preview'
this.isShowHeader = false
this.isShowTopArea = false
this.isEditableFile = false
let replaceData = []
let modelLines = this.bookmarks // 合同元素相关信息
// let allMarks = await this.KSInstance.Application.ActiveDocument.Bookmarks.Json()
for (const i of modelLines) {
replaceData.push({
bookmark: i.markName,
type: i.type,
text: i.value
})
}
let template_url = 'https://sdap-dev.sunwoda.com/api/platform-oss/public/download/' + this.ksFileInfo.id
let data = {
task_id: this.userId,
template_url: template_url,
template_filename: this.ksFileInfo.name,
use_template_section_property:true,
flatten_source_style: true,
sample_list: replaceData
}
axios({
url: 'https://sdap-dev.sunwoda.com/api/platform-system/public/wps-api/wrap-header',
method: 'post',
data
}).then(res => {
if(res.data.resp_code === 200){
this.getReviewFile(res.data.datas.download_id)
}
})
} else {
this.mode = 'edit'
this.ksFileInfoCopy = this.ksFileInfo
this.isShowHeader = true
this.isShowTopArea = true
this.isEditableFile = true
this.getFileUrl(this.ksFileInfo.id, this.ksFileInfo.ext)
}
},
getReviewFile(id){
let data = {
bucket: 'sdap',
downloadId: id,
fileName: id + '测试文档.docx'
}
axios({
url: ' https://sdap-dev.sunwoda.com/api/platform-system/public/wps-api/upload-file',
method: 'post',
params: data
}).then(res => {
this.ksFileInfoCopy = res.data.datas
this.getFileUrl(res.data.datas.id, res.data.datas.ext, true)
})
},
async replaceBookmarkValue(){
let modelLines = this.bookmarks // 合同元素相关信息
let allMarks = await this.KSInstance.Application.ActiveDocument.Bookmarks.Json()
let replaceData = []
for (const i of modelLines) {
if (i.type === 'TABLE') {
let tableData = JSON.parse(JSON.stringify(this.tableData))
let header = ["序号", "姓名", "性别", "年龄"]
await this.insertTable(header, tableData, userTable, i)
} else {
replaceData.push({
name: i.markName,
type: 'text',
value: i.value
})
}
}
this.KSInstance.Application.ActiveDocument.Bookmarks.ReplaceBookmark(replaceData)
},
async insertTable(tableHead, tableBodyData, fieldMap, eleInfo){
const tables = await this.KSInstance.Application.ActiveDocument.Tables // 编辑器的表格对象
let tableData = JSON.parse(JSON.stringify(tableBodyData))
tableData.map((i, ind) => {
i.number = ind + 1 + ''
})
let headerData = {}
let fields = tableHead.map((elmKey, index) => {
if (!!elmKey) {
headerData[fieldMap.get(elmKey)] = elmKey
return {
name: elmKey,
field: fieldMap.get(elmKey)
}
}
})
tableData.unshift(headerData)
let rowCount = tableData.length, colCount = tableHead.length
// 插入表格
await tables.Add(
this.KSInstance.Application.ActiveDocument.Bookmarks.Item(eleInfo.markName).Range, // 位置信息
rowCount, // 新增表格的行数
colCount, // 新增表格的列数
1, // 启用自动调整功能
1 // 根据表格中包含的内容自动调整表格的大小
)
const count = await tables.Count // 表格数量
const curTable = await tables.Item(count)
console.log(count, 'count')
// console.log(tableData, 'tableData')
// console.log(headerData, 'headerData')
// console.log(fields, 'fields')
for (let j = 1; j < rowCount + 1; j++) { // 遍历行
let row = tableData[j-1]
for (let f = 1; f < colCount + 1; f++) { // 遍历列
let fieldsInfo = fields[f-1]
// console.log(fieldsInfo, 'fieldsInfo')
let field = row[fieldsInfo.field] || ''
const cell = await curTable.Rows.Item(j).Cells.Item(f).Range
cell.Text = field + ''
}
}
this.KSInstance.Application.ActiveDocument.ReplaceText([ // 将书签的内容替换成空字符串
{
key: 'TABLE书签' + eleInfo.markName,
value: ''
}
])
}
}
}
</script>
<style scoped>
</style>
fieldMap.js
export const userTableMap = new Map();
userTableMap.set('序号', "number");
userTableMap.set('姓名', "name");
userTableMap.set("性别", "sex");
userTableMap.set("年龄", "age");
前端代码实现书签替换页面效果:
两张截图是分开截的,效果差不多是这样。是有bug的,给表格赋值不太稳定。书签替换也不稳定,没截到连续的图就是因为这个,老有问题,不想截了,不稳定的原因不明。
还可以调用在线编辑的接口实现书签替换,这种方式不支持替换成表格,但支持替换成在线文档,就是可以建一个在线文档,里面加表格,然后将这个在线文档引入进来。我用的接口是我们的后端封装过的,具体的找金山的询问,毕竟要用这个肯定得买,他们肯定会派人支持。
调用接口的方式,可以在“编辑”“预览”之前多次跳转,因为这个方法替换书签不是在原文档上修改,是后台会新建一个文件来替换书签,并且这个新文档会缓存24小时,在这时间内可以下载。