smart-bid-web/src/views/common/OnlyOfficeViewer.vue

255 lines
6.1 KiB
Vue
Raw Normal View History

2025-11-04 13:22:28 +08:00
<template>
2025-11-07 13:34:04 +08:00
<div class="onlyoffice-container">
<div id="placeholder" class="editor-placeholder"></div>
2025-11-04 13:22:28 +08:00
</div>
</template>
<script>
2025-11-07 13:34:04 +08:00
import { getConfigAPI, generateCallbackTokenAPI } from '@/api/common/onlyOfficeViewer'
2025-11-04 13:22:28 +08:00
export default {
name: 'OnlyOfficeViewer',
props: {
2025-11-07 13:34:04 +08:00
// 可以添加 props 来动态配置
documentUrl: {
2025-11-04 13:22:28 +08:00
type: String,
2025-11-07 13:34:04 +08:00
default: 'http://192.168.0.14:9090/smart-bid/technicalSolutionDatabase/2025/11/03/716d9f3d89434c56bc49296dbbccc226.docx'
2025-11-04 13:22:28 +08:00
},
2025-11-07 13:34:04 +08:00
documentTitle: {
2025-11-04 13:22:28 +08:00
type: String,
2025-11-07 13:34:04 +08:00
default: '716d9f3d89434c56bc49296dbbccc226.docx'
2025-11-04 13:22:28 +08:00
},
2025-11-07 13:34:04 +08:00
documentKey: {
2025-11-04 13:22:28 +08:00
type: String,
2025-11-07 13:34:04 +08:00
default: '1'
2025-11-04 13:22:28 +08:00
},
2025-11-07 13:34:04 +08:00
fileName: {
type: String,
default: 'technicalSolutionDatabase/2025/11/03/716d9f3d89434c56bc49296dbbccc226.docx'
2025-11-04 13:22:28 +08:00
},
mode: {
type: String,
2025-11-07 13:34:04 +08:00
default: 'view', // 'view' 或 'edit'
2025-11-04 13:22:28 +08:00
validator: (value) => ['view', 'edit'].includes(value)
},
2025-11-07 13:34:04 +08:00
type: {
2025-11-04 13:22:28 +08:00
type: String,
2025-11-07 13:34:04 +08:00
default: 'desktop', // 'desktop', 'mobile', 'embedded'
validator: (value) => ['desktop', 'mobile', 'embedded'].includes(value)
2025-11-04 13:22:28 +08:00
}
},
2025-11-07 13:34:04 +08:00
2025-11-04 13:22:28 +08:00
data() {
return {
2025-11-07 13:34:04 +08:00
docEditor: null,
onlyOfficeScriptLoaded: false,
editorConfig: {}
2025-11-04 13:22:28 +08:00
};
},
2025-11-07 13:34:04 +08:00
created() {
this.getConfig();
2025-11-04 13:22:28 +08:00
},
mounted() {
2025-11-07 13:34:04 +08:00
this.initOnlyOffice();
2025-11-04 13:22:28 +08:00
},
beforeDestroy() {
2025-11-07 13:34:04 +08:00
this.destroyEditor();
2025-11-04 13:22:28 +08:00
},
methods: {
2025-11-07 13:34:04 +08:00
// 加载编辑器配置
async getConfig() {
2025-11-04 13:22:28 +08:00
try {
2025-11-07 13:34:04 +08:00
const res = await getConfigAPI({
fileId: this.documentKey,
fileName: this.fileName,
mode: this.mode,
type: this.type
})
if (res.code !== 200) {
throw new Error(res.msg || '获取编辑器配置失败');
2025-11-05 09:47:20 +08:00
}
2025-11-07 13:34:04 +08:00
if (!res.data) {
throw new Error('配置数据为空');
2025-11-04 13:22:28 +08:00
}
2025-11-07 13:34:04 +08:00
2025-11-04 13:22:28 +08:00
2025-11-07 13:34:04 +08:00
this.editorConfig = res.data;
this.$set(this.editorConfig, 'events', {
onDocumentReady: this.onDocumentReady,
onError: this.onEditorError,
onAppReady: this.onAppReady
});
console.log('编辑器配置', this.editorConfig);
2025-11-05 09:47:20 +08:00
2025-11-07 13:34:04 +08:00
}
catch (error) {
console.error('获取编辑器配置失败:', error);
throw new Error('获取编辑器配置失败');
}
},
2025-11-05 09:47:20 +08:00
2025-11-07 13:34:04 +08:00
/**
* 初始化 OnlyOffice
*/
async initOnlyOffice() {
try {
// 加载 OnlyOffice 脚本
await this.loadOnlyOfficeScript();
2025-11-05 09:47:20 +08:00
2025-11-07 13:34:04 +08:00
// 初始化编辑器
this.initDocEditor();
2025-11-04 13:22:28 +08:00
} catch (error) {
2025-11-07 13:34:04 +08:00
console.error('初始化 OnlyOffice 失败:', error);
this.$emit('error', error);
2025-11-04 13:22:28 +08:00
}
},
/**
* 加载 OnlyOffice 脚本
*/
loadOnlyOfficeScript() {
return new Promise((resolve, reject) => {
// 如果已经加载,直接返回
if (window.DocsAPI) {
2025-11-07 13:34:04 +08:00
this.onlyOfficeScriptLoaded = true;
2025-11-04 13:22:28 +08:00
resolve();
return;
}
// 检查是否正在加载
2025-11-07 13:34:04 +08:00
const existingScript = document.querySelector('script[data-onlyoffice]');
2025-11-04 13:22:28 +08:00
if (existingScript) {
2025-11-07 13:34:04 +08:00
existingScript.addEventListener('load', () => {
this.onlyOfficeScriptLoaded = true;
resolve();
2025-11-04 13:22:28 +08:00
});
2025-11-07 13:34:04 +08:00
existingScript.addEventListener('error', reject);
2025-11-04 13:22:28 +08:00
return;
}
2025-11-07 13:34:04 +08:00
// 创建新的脚本元素
2025-11-04 13:22:28 +08:00
const script = document.createElement('script');
2025-11-07 13:34:04 +08:00
// onlyOfficeUrl 是 OnlyOffice 服务地址
const onlyOfficeUrl = process.env.VUE_APP_ONLYOFFICE_URL;
script.src = `${onlyOfficeUrl}/web-apps/apps/api/documents/api.js`;
script.setAttribute('data-onlyoffice', 'true');
2025-11-04 13:22:28 +08:00
script.onload = () => {
2025-11-07 13:34:04 +08:00
this.onlyOfficeScriptLoaded = true;
// 等待 API 完全初始化
setTimeout(() => {
if (window.DocsAPI) {
resolve();
} else {
reject(new Error('OnlyOffice API 未正确加载'));
}
}, 100);
2025-11-04 13:22:28 +08:00
};
2025-11-07 13:34:04 +08:00
2025-11-04 13:22:28 +08:00
script.onerror = () => {
2025-11-07 13:34:04 +08:00
reject(new Error('加载 OnlyOffice 脚本失败'));
2025-11-04 13:22:28 +08:00
};
document.head.appendChild(script);
});
},
/**
2025-11-07 13:34:04 +08:00
* 初始化文档编辑器
2025-11-04 13:22:28 +08:00
*/
2025-11-07 13:34:04 +08:00
initDocEditor() {
if (!window.DocsAPI) {
console.error('DocsAPI 未加载');
2025-11-04 13:22:28 +08:00
return;
}
try {
2025-11-07 13:34:04 +08:00
this.docEditor = new window.DocsAPI.DocEditor("placeholder", this.editorConfig);
this.$emit('initialized', this.docEditor);
2025-11-04 13:22:28 +08:00
} catch (error) {
2025-11-07 13:34:04 +08:00
console.error('创建 OnlyOffice 编辑器失败:', error);
this.$emit('error', error);
2025-11-04 13:22:28 +08:00
}
},
/**
2025-11-07 13:34:04 +08:00
* 文档准备就绪回调
2025-11-04 13:22:28 +08:00
*/
2025-11-07 13:34:04 +08:00
onDocumentReady() {
console.log("文档准备好了");
this.$emit('document-ready');
2025-11-04 13:22:28 +08:00
},
/**
2025-11-07 13:34:04 +08:00
* 应用准备就绪回调
2025-11-04 13:22:28 +08:00
*/
2025-11-07 13:34:04 +08:00
onAppReady() {
console.log("OnlyOffice 应用准备就绪");
this.$emit('app-ready');
2025-11-04 13:22:28 +08:00
},
/**
2025-11-07 13:34:04 +08:00
* 编辑器错误回调
2025-11-04 13:22:28 +08:00
*/
2025-11-07 13:34:04 +08:00
onEditorError(error) {
console.error("OnlyOffice 错误:", error);
this.$emit('error', error);
2025-11-04 13:22:28 +08:00
},
/**
* 销毁编辑器
*/
destroyEditor() {
2025-11-07 13:34:04 +08:00
if (this.docEditor && typeof this.docEditor.destroy === 'function') {
try {
this.docEditor.destroy();
} catch (error) {
console.warn('销毁编辑器时出错:', error);
2025-11-04 13:22:28 +08:00
}
}
2025-11-07 13:34:04 +08:00
this.docEditor = null;
2025-11-04 13:22:28 +08:00
},
/**
2025-11-07 13:34:04 +08:00
* 重新加载文档
2025-11-04 13:22:28 +08:00
*/
2025-11-07 13:34:04 +08:00
reloadDocument(newConfig = {}) {
this.destroyEditor();
2025-11-04 13:22:28 +08:00
2025-11-07 13:34:04 +08:00
// 可以在这里更新配置
if (newConfig.documentUrl) {
this.documentUrl = newConfig.documentUrl;
2025-11-04 13:22:28 +08:00
}
2025-11-07 13:34:04 +08:00
if (newConfig.documentTitle) {
this.documentTitle = newConfig.documentTitle;
}
if (newConfig.mode) {
this.mode = newConfig.mode;
2025-11-04 13:22:28 +08:00
}
2025-11-07 13:34:04 +08:00
// 等待 DOM 更新后重新初始化
this.$nextTick(() => {
this.initDocEditor();
});
2025-11-04 13:22:28 +08:00
}
}
};
</script>
2025-11-07 13:34:04 +08:00
<style scoped>
.onlyoffice-container {
width: 100%;
height: 90vh;
2025-11-04 13:22:28 +08:00
display: flex;
flex-direction: column;
}
2025-11-07 13:34:04 +08:00
.editor-placeholder {
2025-11-04 13:22:28 +08:00
width: 100%;
height: 100vh;
2025-11-07 13:34:04 +08:00
min-height: 600px;
2025-11-04 13:22:28 +08:00
}
</style>