前端理解:本人使用onlyffice这个之前对接过weboffice,永中,金山wps这三个在线编辑文档工具.这个工具是后端中找到的。先说一下我使用的三个在线编辑文档对项目的需求的存在的问题。
- 金山wps
- 个人对接,需要注册金山账号通过接口授权获取code->获取token才可以进行编辑。文档存储在金山wps云盘。
- weboffice
- 满足基本需求,但是在线编辑的时候文档会存在水印,并且限制同时使用在线编辑的人数。文件存储在七牛云(单也并不是因为存在历史记录,没有仔细研究)。解决方法,花钱。
- 永中
- 满足基本需求,且在线编辑的时候不会存在水印,但是也限制同时使用在线编辑的人数,并且查看文档和编辑文档不是公用appid。文档存储在永中云盘。解决,查看文档使用office开放接口查看,在线编辑花钱。
了解onlyoffice
- 服务器需要安装一个工具!在线编辑使用的时候工具会生成一个实时文档。
- 触发保存回调后端会接收到实时文档,文档保存到七牛云。
- 查询需要查询数据库!
- 可以在线编辑线上的文档!
准备工作
- 后端装好东西(我不会,onlyoffice也是后端找得到的)
- index.html添加
<script type="text/javascript" src="后端装工具的地址/web-apps/apps/api/documents/api.js"></script>
测试是否可用
new DocsAPI.DocEditor("placeholder",//元素的id
{
"document": {
"fileType": "docx",
"key": "E7FAFC9C22A8",
"title": "Example Document Title.docx",
"url": "https://example.com/url-to-example-document.docx"//只要是能直接访问链接可以访问的就可以
},
"documentType": "text",
"editorConfig": {
"callbackUrl": "https://example.com/url-to-callback.ashx",
},
"height": "100%",
"width": "100%"
});
直接说逻辑吧
- 上传文件功能,js写的qiniu上传,成功后调用上传接口,key。
- 新建文档,编写弹出框new File()假文件。
- 在线编辑触发回调后后端需要更新key。
- 删除就是删除接口
贴代码
//在线编辑页面
<template>
<div id="placeholder"></div>
</template>
<script>
export default {
data() {
return {};
},
mounted() {
function onDocumentReady() {
console.log("onDocumentReady");
}
// function onDocumentStateChange(event) {
// console.log(
// "🚀 ~ file: onlyoffice.vue ~ line 16 ~ mounted ~ event",
// event
// );
// document.title = "liukai super man";
// if (event.data) {
// console.log("文档已更改");
// } else {
// console.log("文档编辑服务收集更改");
// }
// }
this.axios({
method: "get",
url: "/file/officeFile/getOfficeFileById",
params: { id: this.$route?.query?.id },
}).then((res) => {
let obj = {
word: ["doc", "docx", "txt", "pdf"],
cell: ["xls", "xlsx"],
slide: ["ppt", "pptx"],
};
let documentType;
Object.entries(obj).some((arr) => {
if (arr[1].includes(res.data.fileType)) {
documentType = arr[0];
return true;
}
});
new DocsAPI.DocEditor("placeholder", {
document: {
fileType: res.data.fileType,
key: +res.data.id + "-" + res.data.fileVersion,
title: res.data.originalName,
url: `${this.QNBaseurl}${res.data.downloadUrl}`,
},
documentType: documentType,
editorConfig: {
lang: "zh-CN",
mode: res.data.fileType == "pdf" ? "view" : "edit",
callbackUrl:
"https://www.zhilv.cloud/prod-api/file/officeFile/callback/save",
user: {
//用户信息
id: res.data.creater, //用户ID
name: JSON.parse(localStorage.getItem("user"))?.nickName || "游客", //用户全名称
},
customization: {
chat: false,
hideRightMenu: true, //定义在第一次加载时是显示还是隐藏右侧菜单。默认值为false。
plugins: false, //定义是否将启动插件并可用。默认值为true。
// customer: {
// address: "My City, 123a-45",
// info: "Some additional information",
// logo: "https://example.com/logo-big.png",
// logoDark: "https://example.com/dark-logo-big.png",
// mail: "john@example.com",
// name: "John Smith and Co.",
// www: "example.com",
// },
},
},
events: {
onDocumentReady: onDocumentReady, //文档初始化准备好后的回调
// onDocumentStateChange: onDocumentStateChange,
},
});
});
},
};
</script>
<style scoped lang="scss">
</style>
//表格展示页面
<template>
<div class="only-office">
<el-form :model="searchForm" inline label-width="80px">
<el-form-item label="文件名" size="mini">
<!-- 表单单个输入框回车刷新页面问题 -->
<input type="text" class="form-control" style="display: none" />
<el-input v-model="searchForm.originalName" size="mini"></el-input>
</el-form-item>
<el-button
type="primary"
icon="el-icon-search"
size="mini"
@click="getList"
>搜索</el-button
>
</el-form>
<el-table :data="data" size="mini">
<el-table-column
label="原始文件名"
prop="originalName"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="七牛文件名"
prop="newName"
show-overflow-tooltip
></el-table-column>
<el-table-column label="文件类型" prop="fileType" show-overflow-tooltip>
<template slot-scope="{ row }">
<svg-icon
:icon-class="row.fileType | svgIcon"
style="font-size: 20px"
/>
</template>
</el-table-column>
<el-table-column
label="创建时间"
prop="createTime"
show-overflow-tooltip
></el-table-column>
<el-table-column
label="版本"
prop="fileVersion"
width="80"
></el-table-column>
<el-table-column label="操作" width="400px">
<template slot-scope="{ row }">
<el-button
type="primary"
@click="toEditPage(row)"
size="mini"
icon="el-icon-edit"
>编辑</el-button
>
<el-button
type="danger"
@click="delFile(row)"
size="mini"
icon="el-icon-delete"
>删除</el-button
>
<el-button
type="success"
hidden
@click="officeYl(row)"
size="mini"
icon="el-icon-s-promotion"
>office预览</el-button
>
</template>
</el-table-column>
</el-table>
<div class="footer-box">
<qiniu-upload
@getList="getList"
style="margin-right: 20px"
></qiniu-upload>
<newFile @getList="getList"></newFile>
<el-pagination
size="mini"
style="text-align: right; padding: 18px 60px"
@current-change="handleCurrentChange"
:current-page.sync="page.pageNum"
:page-size="10"
layout="prev, pager, next, jumper"
:total="page.total"
>
</el-pagination>
</div>
</div>
</template>
<script>
import qiniuUpload from "../../components/qiniu-upload";
import newFile from "./components/onlyoffice-newFile.vue";
export default {
components: {
qiniuUpload,
newFile,
},
data() {
return {
page: {
pageNum: 1,
pageSize: 10,
total: 0,
},
aaa: "",
data: [],
searchForm: {
originalName: "",
},
};
},
mounted() {
this.getList();
document.addEventListener("visibilitychange", this.handleVisible);
},
destroyed() {
document.removeEventListener("visibilitychange", this.handleVisible);
},
filters: {
svgIcon(type) {
if (["txt", "docx"].includes(type)) {
return "doc";
} else if (["xlsx"].includes(type)) {
return "xls";
} else if (["pptx"].includes(type)) {
return "ppt";
}
return type;
},
},
methods: {
// 页面自动刷新
handleVisible(e) {
if (
e.target.visibilityState === "visible" ||
e.target.visibilityState === "unloaded"
) {
this.getList();
}
},
handleCurrentChange(val) {
this.page.pageNum = val;
this.getList();
},
officeYl(row) {
let url = `https://view.officeapps.live.com/op/embed.aspx?src=${this.QNBaseurl}${row.downloadUrl}`;
window.open(url);
},
delFile(row) {
this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then((res) => {
return this.axios({
method: "DELETE",
url: "/file/officeFile/deleteOfficeFileById",
params: { id: row.id },
});
})
.then(() => {
this.$message({
type: "success",
message: "删除成功!",
});
this.getList();
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
},
// http://localhost/onlyoffice?url=%2Fonlyoffice%2Fc9438eac-1a30-4b1e-8cd3-cb21bfcdc20d.doc
getList() {
this.axios({
method: "get",
url: "/file/officeFile/list",
params: { ...this.page, ...this.searchForm },
}).then((res) => {
this.data = res.data;
this.page.total = res.total;
});
},
toEditPage(row) {
// this.$router.push()
window.open(`/onlyoffice?id=${row.id}`);
},
},
};
</script>
<style scoped lang="scss">
.only-office {
padding: 20px;
box-sizing: border-box;
width: 100vw;
height: 100vh;
// outline: 2px solid #ff0000;
// outline-offset: -2px;
.footer-box {
width: 100%;
height: 70px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
</style>
//新建模板功能呢
<template>
<div class="newFile">
<el-button @click="toAdd()" size="mini"
>新建<i class="el-icon-plus el-icon--right"></i
></el-button>
<el-dialog title="新建文件" :visible.sync="isAdd">
<el-form
:model="FileForm"
size="mini"
label-width="100px"
:rules="fileRules"
ref="fileForm"
>
<el-form-item label="文件名称" prop="name">
<el-input
v-model="FileForm.name"
size="mini"
placeholder="请输入文件名称"
></el-input>
</el-form-item>
<el-form-item label="文件类型" prop="type">
<el-select v-model="FileForm.type" placeholder="请选择文件类型">
<el-option
v-for="(item, index) in typeList"
:key="index"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
</el-form>
<template slot="footer">
<el-button type="primary" size="mini" @click="newFile()"
>确定</el-button
>
</template>
</el-dialog>
</div>
</template>
<script>
import { uploadQN } from "@/utils/wuhan/qiniu";
export default {
name: "newFile",
data() {
return {
isAdd: false,
FileForm: {
name: "",
type: "",
},
typeList: [
{
label: "文字文档",
value: "application/msword",
suffix: ".doc",
},
{
label: "表格文档",
value: "application/vnd.ms-excel",
suffix: ".xls",
},
{
label: "演示文档",
value: "application/vnd.ms-powerpoint",
suffix: ".ppt",
},
],
fileRules: {
name: [{ required: true, message: "请输入文件名称", trigger: "blur" }],
type: [
{
required: true,
message: "请选择文件类型",
trigger: ["blur", "change"],
},
],
},
};
},
methods: {
toAdd() {
this.isAdd = true;
setTimeout((_) => {
this.$refs["fileForm"].resetFields();
}, 0);
},
newFile() {
this.$refs["fileForm"].validate((valid) => {
if (valid) {
let obj = this.typeList.find(
(item) => item.value == this.FileForm.type
);
var file = new File([], this.FileForm.name + obj.suffix, {
type: this.FileForm.type,
});
uploadQN(file, "onlyoffice").then((res) => {
console.log(res);
let data = {
newName: res.key.split("/").at(-1),
originalName: file.name,
fileType: file.name.split(".").at(-1),
size: file.size,
downloadUrl: "/" + res.key,
};
this.axios({
method: "post",
url: "/file/officeFile/addOfficeFile",
data: data,
}).then((res2) => {
this.isAdd = false;
this.$emit("getList");
});
});
} else {
console.log("error submit!!");
return false;
}
});
},
},
};
</script>
<style scoped lang="scss">
</style>
七牛上传网上随便找一个弄!