onlyoffice集成

This commit is contained in:
cwchen 2025-11-07 15:08:41 +08:00
parent 7d38fc745b
commit 7a5f1f359f
1 changed files with 258 additions and 36 deletions

View File

@ -1,6 +1,21 @@
<template>
<div class="onlyoffice-container">
<div id="placeholder" class="editor-placeholder"></div>
<!-- 加载状态 -->
<div v-if="loading" class="loading-state">
<div class="loading-spinner"></div>
<p>正在加载文档...</p>
</div>
<!-- 错误状态 -->
<div v-if="error" class="error-state">
<div class="error-icon"></div>
<h3>加载失败</h3>
<p>{{ error }}</p>
<button @click="retry" class="retry-btn">重试</button>
</div>
<!-- 编辑器容器始终存在通过样式控制显示 -->
<div v-show="!loading && !error" id="placeholder" class="editor-placeholder"></div>
</div>
</template>
@ -43,14 +58,26 @@ export default {
return {
docEditor: null,
onlyOfficeScriptLoaded: false,
editorConfig: {}
editorConfig: null,
configReady: false,
loading: false,
error: null
};
},
created() {
this.getConfig();
},
mounted() {
this.initOnlyOffice();
async mounted() {
try {
this.loading = true;
this.error = null;
//
await this.getConfig();
// OnlyOffice loading = false
await this.initOnlyOffice();
} catch (error) {
console.error('初始化失败:', error);
this.loading = false;
this.error = error.message || '初始化失败';
this.$emit('error', error);
}
},
beforeDestroy() {
@ -61,12 +88,22 @@ export default {
//
async getConfig() {
try {
console.log('开始获取编辑器配置...', {
fileId: this.documentKey,
fileName: this.fileName,
mode: this.mode,
type: this.type
});
const res = await getConfigAPI({
fileId: this.documentKey,
fileName: this.fileName,
mode: this.mode,
type: this.type
})
});
console.log('获取配置响应:', res);
if (res.code !== 200) {
throw new Error(res.msg || '获取编辑器配置失败');
}
@ -74,20 +111,28 @@ export default {
throw new Error('配置数据为空');
}
this.editorConfig = res.data;
this.$set(this.editorConfig, 'events', {
onDocumentReady: this.onDocumentReady,
onError: this.onEditorError,
onAppReady: this.onAppReady
});
console.log('编辑器配置', this.editorConfig);
//
if (!res.data.document || !res.data.document.url) {
throw new Error('配置中缺少文档URL');
}
catch (error) {
//
this.editorConfig = {
...res.data,
events: {
onDocumentReady: () => this.onDocumentReady(),
onError: (error) => this.onEditorError(error),
onAppReady: () => this.onAppReady()
}
};
this.configReady = true;
console.log('编辑器配置准备完成:', this.editorConfig);
} catch (error) {
console.error('获取编辑器配置失败:', error);
throw new Error('获取编辑器配置失败');
this.error = error.message || '获取编辑器配置失败';
throw error;
}
},
@ -96,14 +141,26 @@ export default {
*/
async initOnlyOffice() {
try {
//
if (!this.configReady || !this.editorConfig) {
throw new Error('编辑器配置未准备好,请先加载配置');
}
// OnlyOffice
console.log('开始加载 OnlyOffice 脚本...');
await this.loadOnlyOfficeScript();
console.log('OnlyOffice 脚本加载完成');
// DOM
await this.$nextTick();
//
this.initDocEditor();
await this.initDocEditor();
} catch (error) {
console.error('初始化 OnlyOffice 失败:', error);
this.error = error.message || '初始化 OnlyOffice 失败';
this.$emit('error', error);
throw error;
}
},
@ -133,8 +190,16 @@ export default {
//
const script = document.createElement('script');
// onlyOfficeUrl OnlyOffice
const onlyOfficeUrl = process.env.VUE_APP_ONLYOFFICE_URL;
script.src = `${onlyOfficeUrl}/web-apps/apps/api/documents/api.js`;
const onlyOfficeUrl = process.env.VUE_APP_ONLYOFFICE_URL || process.env.VUE_APP_BASE_API || '';
if (!onlyOfficeUrl) {
reject(new Error('OnlyOffice 服务地址未配置,请检查环境变量 VUE_APP_ONLYOFFICE_URL'));
return;
}
const scriptUrl = `${onlyOfficeUrl}/web-apps/apps/api/documents/api.js`;
console.log('加载 OnlyOffice 脚本URL:', scriptUrl);
script.src = scriptUrl;
script.setAttribute('data-onlyoffice', 'true');
script.onload = () => {
@ -160,18 +225,81 @@ export default {
/**
* 初始化文档编辑器
*/
initDocEditor() {
if (!window.DocsAPI) {
console.error('DocsAPI 未加载');
return;
async initDocEditor() {
// DocsAPI
if (!window.DocsAPI || !window.DocsAPI.DocEditor) {
throw new Error('OnlyOffice DocsAPI 未正确加载,请检查脚本是否已加载');
}
//
if (!this.editorConfig) {
throw new Error('编辑器配置不存在');
}
// v-show DOM
await this.$nextTick();
let container = document.getElementById('placeholder');
//
if (!container) {
console.warn('容器元素不存在,等待 DOM 渲染...');
await new Promise(resolve => setTimeout(resolve, 100));
await this.$nextTick();
container = document.getElementById('placeholder');
}
if (!container) {
throw new Error('找不到编辑器容器元素 #placeholder请确保容器已正确渲染');
}
// 使 v-show 便
container.style.display = 'block';
container.style.visibility = 'visible';
container.style.width = '100%';
container.style.height = '100%';
console.log('容器元素:', container);
console.log('容器尺寸:', {
width: container.offsetWidth,
height: container.offsetHeight,
rect: container.getBoundingClientRect()
});
//
if (container.offsetWidth === 0 || container.offsetHeight === 0) {
console.warn('容器尺寸为0等待尺寸调整...');
await new Promise(resolve => setTimeout(resolve, 300));
if (container.offsetWidth === 0 || container.offsetHeight === 0) {
console.warn('容器尺寸仍为0但继续尝试创建编辑器');
}
}
try {
this.docEditor = new window.DocsAPI.DocEditor("placeholder", this.editorConfig);
console.log('创建 OnlyOffice 编辑器,配置:', this.editorConfig);
//
container.innerHTML = '';
//
this.docEditor = new window.DocsAPI.DocEditor('placeholder', this.editorConfig);
console.log('编辑器实例创建成功:', this.docEditor);
//
this.loading = false;
this.$emit('initialized', this.docEditor);
} catch (error) {
console.error('创建 OnlyOffice 编辑器失败:', error);
console.error('错误详情:', {
message: error.message,
stack: error.stack,
config: this.editorConfig
});
this.loading = false;
this.error = error.message || '创建编辑器失败';
this.$emit('error', error);
throw error;
}
},
@ -216,8 +344,10 @@ export default {
/**
* 重新加载文档
*/
reloadDocument(newConfig = {}) {
async reloadDocument(newConfig = {}) {
this.destroyEditor();
this.configReady = false;
this.error = null;
//
if (newConfig.documentUrl) {
@ -230,10 +360,34 @@ export default {
this.mode = newConfig.mode;
}
// DOM
this.$nextTick(() => {
this.initDocEditor();
});
//
try {
this.loading = true;
await this.getConfig();
await this.initDocEditor();
} catch (error) {
console.error('重新加载文档失败:', error);
this.error = error.message || '重新加载失败';
} finally {
this.loading = false;
}
},
/**
* 重试
*/
async retry() {
this.error = null;
this.loading = true;
try {
await this.getConfig();
await this.initOnlyOffice();
} catch (error) {
console.error('重试失败:', error);
this.error = error.message || '重试失败';
} finally {
this.loading = false;
}
}
}
};
@ -245,11 +399,79 @@ export default {
height: 90vh;
display: flex;
flex-direction: column;
position: relative;
}
.editor-placeholder {
width: 100%;
height: 100vh;
height: 100%;
min-height: 600px;
}
.loading-state,
.error-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
min-height: 400px;
text-align: center;
padding: 40px;
}
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 16px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.error-icon {
font-size: 48px;
margin-bottom: 16px;
}
.error-state h3 {
margin: 0 0 8px 0;
color: #e74c3c;
font-size: 18px;
}
.error-state p {
margin: 0 0 16px 0;
color: #666;
font-size: 14px;
}
.retry-btn {
background: #3498db;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background 0.3s;
}
.retry-btn:hover {
background: #2980b9;
}
/* 确保 OnlyOffice iframe 正确显示 */
.editor-placeholder ::v-deep iframe {
width: 100% !important;
height: 100% !important;
border: none;
display: block;
}
</style>