liding
2026-09-21 94e0abbf193f9e1fc953716ca7868d74cd14a2cd
src/components/Onlyoffice/onlyoffice.vue
@@ -1,9 +1,49 @@
<!--onlyoffice 编辑器-->
<template>
  <div id="vabOnlyOffice"></div>
  <div class="document-preview">
    <iframe
      v-if="isPdf"
      :key="option.url"
      :src="option.url"
      class="native-pdf-preview"
      title="PDF预览"
    ></iframe>
    <div v-else id="vabOnlyOffice"></div>
  </div>
</template>
<script>
// OnlyOffice 文档服务地址,按环境配置;脚本在真正需要预览时才加载
const OFFICE_API_BASE = process.env.VUE_APP_ONLYOFFICE_API || "http://192.168.21.53:9001";
// 多个页面共用编辑器,api.js 只加载一次
let docsApiPromise = null;
function loadDocsApi() {
  if (window.DocsAPI) {
    return Promise.resolve(window.DocsAPI);
  }
  if (!docsApiPromise) {
    docsApiPromise = new Promise((resolve, reject) => {
      const script = document.createElement("script");
      script.src = OFFICE_API_BASE.replace(/\/$/, "") + "/web-apps/apps/api/documents/api.js";
      script.onload = () => {
        if (window.DocsAPI) {
          resolve(window.DocsAPI);
        } else {
          reject(new Error("api.js 加载完成但未注册 DocsAPI"));
        }
      };
      script.onerror = () => reject(new Error("OnlyOffice 文档服务脚本加载失败:" + script.src));
      document.head.appendChild(script);
    });
    // 加载失败后允许下次重试
    docsApiPromise.catch(() => {
      docsApiPromise = null;
    });
  }
  return docsApiPromise;
}
export default {
  name: "VabOnlyOffice",
  props: ['options'],
@@ -23,6 +63,11 @@
        editUrl: ""
      }
    };
  },
  computed: {
    isPdf() {
      return this.isPdfFile(this.option);
    }
  },
  created() {
    if(this.options){
@@ -50,10 +95,7 @@
    }
  },
  beforeDestroy() {
    if (this.docEditor !== null) {
      this.docEditor.destroyEditor();
      this.docEditor = null;
    }
    this.destroyEditor();
  },
  watch: {
    option: {
@@ -70,11 +112,20 @@
    }
  },
  methods: {
    async setEditor(option) {
    destroyEditor() {
      if (this.docEditor !== null) {
        this.docEditor.destroyEditor();
        this.docEditor = null;
      }
    },
    async setEditor(option) {
      this.destroyEditor();
      // PDF 使用浏览器原生预览;其他文档才初始化 OnlyOffice。
      if (!option || !option.url || this.isPdfFile(option)) {
        return;
      }
      // 等待 v-else 中的 OnlyOffice 容器完成渲染。
      await this.$nextTick();
      this.doctype = this.getFileType(option.fileType);
      let config = {
        document: {
@@ -116,8 +167,25 @@
        token: option.token || ""
      };
      // eslint-disable-next-line no-undef,no-unused-vars
      this.docEditor = new DocsAPI.DocEditor("vabOnlyOffice", config);
      try {
        await loadDocsApi();
      } catch (error) {
        console.error(error);
        this.$message.error("文档服务暂时不可用,无法预览");
        return;
      }
      if (this._isDestroyed) {
        return;
      }
      this.docEditor = new window.DocsAPI.DocEditor("vabOnlyOffice", config);
    },
    isPdfFile(option) {
      if (!option) {
        return false;
      }
      const fileType = String(option.fileType || "").toLowerCase();
      const url = String(option.url || "").split(/[?#]/)[0].toLowerCase();
      return fileType === "pdf" || url.endsWith(".pdf");
    },
    getFileType(fileType) {
      let docType = "";
@@ -182,7 +250,17 @@
};
</script>
<style>
<style scoped>
.document-preview,
.native-pdf-preview,
#vabOnlyOffice {
  width: 100%;
  height: 100%;
}
.native-pdf-preview {
  display: block;
  border: 0;
}
html,
body {
  height: 100%;