onlyoffice前端对接(vue)

4,121 阅读2分钟

前端理解:本人使用onlyffice这个之前对接过weboffice,永中,金山wps这三个在线编辑文档工具.这个工具是后端中找到的。先说一下我使用的三个在线编辑文档对项目的需求的存在的问题。

  • 金山wps
    • 个人对接,需要注册金山账号通过接口授权获取code->获取token才可以进行编辑。文档存储在金山wps云盘。
  • weboffice
    • 满足基本需求,但是在线编辑的时候文档会存在水印,并且限制同时使用在线编辑的人数。文件存储在七牛云(单也并不是因为存在历史记录,没有仔细研究)。解决方法,花钱。
  • 永中
    • 满足基本需求,且在线编辑的时候不会存在水印,但是也限制同时使用在线编辑的人数,并且查看文档和编辑文档不是公用appid。文档存储在永中云盘。解决,查看文档使用office开放接口查看,在线编辑花钱。

了解onlyoffice

  1. 服务器需要安装一个工具!在线编辑使用的时候工具会生成一个实时文档。
  2. 触发保存回调后端会接收到实时文档,文档保存到七牛云。
  3. 查询需要查询数据库!
  4. 可以在线编辑线上的文档!

准备工作

  1. 后端装好东西(我不会,onlyoffice也是后端找得到的)
  2. 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>

七牛上传网上随便找一个弄!