|
|
@@ -1,219 +1,61 @@
|
|
|
<template>
|
|
|
- <el-container class="layout-container">
|
|
|
- <!-- 主体左右分栏 -->
|
|
|
- <el-container>
|
|
|
- <!-- 左侧树区域 -->
|
|
|
- <el-aside width="300px" class="aside-tree">
|
|
|
- <div class="tree-header">
|
|
|
- <el-input
|
|
|
- v-model="filterText"
|
|
|
- placeholder="搜索模板"
|
|
|
- size="small"
|
|
|
- prefix-icon="el-icon-search"
|
|
|
- clearable
|
|
|
- />
|
|
|
- <el-button-group style="display: flex;">
|
|
|
- <el-button size="mini" icon="el-icon-arrow-down" @click="expandAll">展开</el-button>
|
|
|
- <el-button size="mini" icon="el-icon-arrow-up" @click="collapseAll">折叠</el-button>
|
|
|
- </el-button-group>
|
|
|
- </div>
|
|
|
-
|
|
|
- <el-tree
|
|
|
- ref="tree"
|
|
|
- :data="treeData"
|
|
|
- :props="defaultProps"
|
|
|
- :filter-node-method="filterNode"
|
|
|
- node-key="id"
|
|
|
- highlight-current
|
|
|
- @node-click="handleNodeClick"
|
|
|
- class="tree-content"
|
|
|
- >
|
|
|
- <span slot-scope="{ node, data }" class="custom-tree-node">
|
|
|
- <i :class="data.isFolder ? 'el-icon-menu' : 'el-icon-document'"></i>
|
|
|
- <span>{{ node.label }}</span>
|
|
|
- </span>
|
|
|
- </el-tree>
|
|
|
- </el-aside>
|
|
|
-
|
|
|
- <!-- 右侧编辑器区域 -->
|
|
|
- <el-main class="main-editor">
|
|
|
- <div v-if="!currentFile" class="placeholder">
|
|
|
- 请从左侧选择一个模板文档
|
|
|
- </div>
|
|
|
- <div v-else class="editor-wrapper">
|
|
|
- <OnlyofficeEditor
|
|
|
- :key="editorKey"
|
|
|
- :document-url="documentUrl"
|
|
|
- :title="currentFile.name"
|
|
|
- :file-type="currentFile.ext"
|
|
|
- :callback-url="callbackUrl"
|
|
|
- :data="{ templateId: currentFile.id }"
|
|
|
- @document-ready="onDocumentReady"
|
|
|
- />
|
|
|
- <div class="editor-footer">
|
|
|
- <span>当前编辑:{{ currentFile.name }}</span>
|
|
|
- <el-button type="primary" size="small" @click="handleSave">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-main>
|
|
|
- </el-container>
|
|
|
- </el-container>
|
|
|
+ <div class="onlyoffice-container">
|
|
|
+ <iframe
|
|
|
+ ref="editorIframe"
|
|
|
+ :src="editorUrl"
|
|
|
+ frameborder="0"
|
|
|
+ @load="handleIframeLoad"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import OnlyofficeEditor from './OnlyofficeEditor.vue'
|
|
|
-
|
|
|
+import { getCookie } from '@/utils/util.js';
|
|
|
export default {
|
|
|
- name: 'TemplateEditor',
|
|
|
- components: { OnlyofficeEditor },
|
|
|
+ name: 'OnlyofficeWrapper',
|
|
|
data() {
|
|
|
return {
|
|
|
- filterText: '', // 搜索关键字
|
|
|
- treeData: [], // 树数据
|
|
|
- defaultProps: {
|
|
|
- children: 'children',
|
|
|
- label: 'label',
|
|
|
- isFolder: 'isFolder' // 标识是否为文件夹
|
|
|
- },
|
|
|
- currentFile: null, // 当前选中的文件节点
|
|
|
- documentUrl: '', // 传递给编辑器的签名URL
|
|
|
- editorKey: 0, // 用于强制刷新编辑器
|
|
|
- callbackUrl: process.env.VUE_APP_API_BASE + '/api/onlyoffice/callback' // 保存回调地址
|
|
|
- }
|
|
|
- },
|
|
|
- watch: {
|
|
|
- filterText(val) {
|
|
|
- this.$refs.tree.filter(val)
|
|
|
- }
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- this.loadTreeData()
|
|
|
+ editorUrl: 'http://192.168.254.6:8888', // 替换为你的 Vue 3 项目地址
|
|
|
+ isIframeLoaded: false,
|
|
|
+ };
|
|
|
},
|
|
|
methods: {
|
|
|
- // 加载左侧树
|
|
|
- async loadTreeData() {
|
|
|
- try {
|
|
|
- const { data } = await this.getTemplateTree()
|
|
|
- this.treeData = data
|
|
|
- } catch (error) {
|
|
|
- this.$message.error('加载模板树失败')
|
|
|
- }
|
|
|
- },
|
|
|
- getTemplateTree() {
|
|
|
- return this.axios.get('pass/baseManagement/v1/limsisofileds/getFiletree')
|
|
|
- },
|
|
|
- // 树节点过滤
|
|
|
- filterNode(value, data) {
|
|
|
- if (!value) return true
|
|
|
- return data.label.toLowerCase().includes(value.toLowerCase())
|
|
|
- },
|
|
|
-
|
|
|
- // 展开所有节点
|
|
|
- expandAll() {
|
|
|
- const nodes = this.$refs.tree.store.nodesMap
|
|
|
- Object.values(nodes).forEach(node => node.expand())
|
|
|
+ handleIframeLoad() {
|
|
|
+ this.isIframeLoaded = true;
|
|
|
+ console.log('编辑器 iframe 已加载');
|
|
|
+ this.sendAuthCookieToIframe();
|
|
|
},
|
|
|
+ sendAuthCookieToIframe() {
|
|
|
+ if (!this.isIframeLoaded) return;
|
|
|
|
|
|
- // 折叠所有节点
|
|
|
- collapseAll() {
|
|
|
- const nodes = this.$refs.tree.store.nodesMap
|
|
|
- Object.values(nodes).forEach(node => node.collapse())
|
|
|
- },
|
|
|
-
|
|
|
- // 点击树节点
|
|
|
- async handleNodeClick(data) {
|
|
|
- if (data.isFolder) return // 文件夹不可编辑
|
|
|
- this.currentFile = {
|
|
|
- id: data.id,
|
|
|
- name: data.label,
|
|
|
- ext: this.getFileExt(data.label),
|
|
|
- path: "http://192.168.254.22:9002/files/" + data.url // 假设后端返回了文件路径
|
|
|
- }
|
|
|
+ const accessToken = getCookie('accessToken'); // 假设你有一个获取特定 cookie 的函数
|
|
|
+ const targetOrigin = 'http://192.168.254.6:8888'; // 必须与 editorUrl 的源保持一致
|
|
|
|
|
|
- // 获取签名URL
|
|
|
try {
|
|
|
- this.documentUrl = this.currentFile.path
|
|
|
- console.log('文件访问链接:', this.documentUrl)
|
|
|
+ this.$refs.editorIframe.contentWindow.postMessage(
|
|
|
+ {
|
|
|
+ type: 'AUTH_COOKIE',
|
|
|
+ data: accessToken,
|
|
|
+ },
|
|
|
+ targetOrigin
|
|
|
+ );
|
|
|
+ console.log('已向编辑器发送 accessToken');
|
|
|
} catch (error) {
|
|
|
- this.$message.error('获取文件访问链接失败')
|
|
|
+ console.error('向编辑器发送 accessToken 失败:', error);
|
|
|
}
|
|
|
},
|
|
|
-
|
|
|
- // 获取文件扩展名
|
|
|
- getFileExt(filename) {
|
|
|
- return filename.split('.').pop().toLowerCase()
|
|
|
- },
|
|
|
-
|
|
|
- // 编辑器加载完成事件
|
|
|
- onDocumentReady() {
|
|
|
- console.log('编辑器已就绪')
|
|
|
- },
|
|
|
-
|
|
|
- // 手动触发保存(可选)
|
|
|
- handleSave() {
|
|
|
- // 由于ONLYOFFICE自带保存功能(通过回调),此按钮可保留用于提示
|
|
|
- this.$message.info('编辑后请稍等,自动保存中...')
|
|
|
- // 如果需要强制触发ONLYOFFICE的保存,可以调用编辑器实例的方法(如果有)
|
|
|
- // 但通常自动保存已足够
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
+ },
|
|
|
+};
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-.layout-container {
|
|
|
- height: 100vh;
|
|
|
-}
|
|
|
-.header {
|
|
|
- background-color: #409EFF;
|
|
|
- color: white;
|
|
|
- line-height: 60px;
|
|
|
- padding-left: 20px;
|
|
|
-}
|
|
|
-.aside-tree {
|
|
|
- background-color: #f5f7fa;
|
|
|
- border-right: 1px solid #e6e9ed;
|
|
|
- padding: 10px;
|
|
|
- overflow-y: auto;
|
|
|
-}
|
|
|
-.tree-header {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 8px;
|
|
|
- margin-bottom: 10px;
|
|
|
-}
|
|
|
-.tree-content {
|
|
|
- background-color: transparent;
|
|
|
-}
|
|
|
-.custom-tree-node {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 6px;
|
|
|
-}
|
|
|
-.main-editor {
|
|
|
- padding: 0;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
-}
|
|
|
-.placeholder {
|
|
|
+.onlyoffice-container {
|
|
|
+ width: 100%;
|
|
|
height: 100%;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- color: #909399;
|
|
|
- font-size: 16px;
|
|
|
}
|
|
|
-.editor-wrapper {
|
|
|
+iframe {
|
|
|
+ width: 100%;
|
|
|
height: 100%;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
-}
|
|
|
-.editor-footer {
|
|
|
- padding: 8px 16px;
|
|
|
- background-color: #f5f7fa;
|
|
|
- border-top: 1px solid #e6e9ed;
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
+ border: none;
|
|
|
}
|
|
|
</style>
|