• vue2 集成 Onlyoffice


    缘起于进行了一次在线 Office 解决方案的调研,对比了 Office365、可道云、WPS Office、PageOffice 等厂商,最终敲定了使用 Onlyoffice,故整理了一份 Onlyoffice 从零开始系列教程,这是第一篇。

    一、Onlyoffice 是什么?

    Onlyoffice 是一个多端协同的 Office 办公套件,相当于微软的 Office365 全家桶。

    二、Onlyoffice 平台功能

    功能强大到什么程度呢?我列了一下 Onlyoffice 对我们需求的支持程度:

    需求支持程度
    终端支持全端支持,包含桌面端、PC 网页端、移动端等
    客户端操作系统Windows、Mac、Linux
    服务端操作系统Linux、Ubuntu、CentOS、Debian、Alibaba Cloud Image 等 Docker 镜像包
    基础功能具备 Word 基础的字体设置、字体大小、加粗、对齐、颜色、背景颜色等功能,同时还有等同于 Office 的各个高级功能
    插件支持支持自定义插件,官方提供了完整的插件开发文档
    二次开发官方开放了 1000+ API,支持根据业务二次开发、功能定制,甚至扩展或增强基础功能
    深度定制支持
    使用体验安装成本低,编辑体验与本地 Word 高度一致
    开发者社区官方维护了一个开发者社区,内容丰富,也比较活跃
    安全与稳定性文档加密保存、传输支持标准的 JWT 加密,多种场景测试未出现崩溃、卡死等情况
    协同支持多人协同编辑、历史记录查看,文档回滚等功能
    分布式部署支持

    三、服务宗旨

    社区版免费,企业版收费,10w 起步。

    四、适用场景

    预算、私有云、需要二次开发、需要文档协同等。

    正文

    本文使用docker进行安装,故:

    五、安装docker

    a、windows安装Windows10 Docker 安装教程-CSDN博客

    b、mac安装:【云原生丶Docker】MacOS系统安装Docker【保姆级教程】_mac安装docker-CSDN博客

    六、通过docker安装Onlyoffice

    1、使用JWT验证

    sudo docker run -i -t -d -p 8701:80 onlyoffice/documentserver

    2、不使用JWT验证

    sudo docker run -i -t -d -p 8701:80 --restart=always -e JWT_ENABLED=false onlyoffice/documentserver

    可以以后面加上版本号:
    sudo docker run -i -t -d -p 8701:80 --restart=always -e JWT_ENABLED=false onlyoffice/documentserver:7.1.1
     


    # -e JWT_ENABLED=false:不使用JWT
    sudo docker run -i -t -d -p 8701:80 --restart=always --name=onlyoffice_7.3.3 -e JWT_ENABLED=false onlyoffice/documentserver:7.3.3

    从7.2版本起,默认使用了JWT功能,安装Onlyoffice时,可以通过不同的命令参数启动服务,默认不使用JWT验证!如果是第 1 次执行这个命令,会先去下载 Onlyoffice,比较慢,约等待 3~10 分钟,网络畅通一点的会快一些。如果是已经安装过则直接进行启动。待其安装完成:

    安装完成后:

    七、启动服务

    1、等上述安装完成后执行命令 ,查看 Onlyoffice 容器 ID:

    docker ps

    2、执行以下命令进入容器,这里将获取到的 ID 替换为上个步骤你得到的自己的ID! 

    sudo docker exec -it ID /bin/bash 

    3、接着执行下面的这两个命令

    # 启动所有的内置服务
    supervisorctl restart all
    # 退出容器
    exit

    命令输出如下:

    4、最后访问 http://IP:8701/welcome 页面(网上其他人说IP 不能是 localhost 或 127.0.0.1,一定要用你自己本地真实 IP 来访问。但是我经过测试完全可以),看到下面的这个效果说明 Onlyoffice 启动成功。

    此页面提供了在线文档新增、编辑等功能,你可以点击生成一个文档,后续开发测试功能时会用到。

    八、在 Vue 中接入 Onlyoffice

    1、子组件准备,在你的项目的合适目录下新建如下两个文件,将下方的代码复制粘贴进去到你对应的文件中。

    index.vue页面代码:

    1. <script>
    2. import loadScript from './loadScript.js';
    3. export default {
    4. name: 'DocumentEditor',
    5. props: {
    6. id: {
    7. type: String,
    8. default: '',
    9. },
    10. documentServerUrl: {
    11. type: String,
    12. default: '',
    13. },
    14. config: {
    15. type: Object,
    16. default: () => { },
    17. },
    18. document_fileType: {
    19. type: String,
    20. default: '',
    21. },
    22. document_title: {
    23. type: String,
    24. default: '',
    25. },
    26. documentType: {
    27. type: String,
    28. default: '',
    29. },
    30. editorConfig_lang: {
    31. type: String,
    32. default: '',
    33. },
    34. height: {
    35. type: String,
    36. default: '',
    37. },
    38. type: {
    39. type: String,
    40. default: '',
    41. },
    42. width: {
    43. type: String,
    44. default: '',
    45. },
    46. events_onAppReady: {
    47. type: Function,
    48. default: () => { },
    49. },
    50. events_onDocumentStateChange: {
    51. type: Function,
    52. default: () => { },
    53. },
    54. events_onMetaChange: {
    55. type: Function,
    56. default: () => { },
    57. },
    58. events_onDocumentReady: {
    59. type: Function,
    60. default: () => { },
    61. },
    62. events_onInfo: {
    63. type: Function,
    64. default: () => { },
    65. },
    66. events_onWarning: {
    67. type: Function,
    68. default: () => { },
    69. },
    70. events_onError: {
    71. type: Function,
    72. default: () => { },
    73. },
    74. events_onRequestSharingSettings: {
    75. type: Function,
    76. default: () => { },
    77. },
    78. events_onRequestRename: {
    79. type: Function,
    80. default: () => { },
    81. },
    82. events_onMakeActionLink: {
    83. type: Function,
    84. default: () => { },
    85. },
    86. events_onRequestInsertImage: {
    87. type: Function,
    88. default: () => { },
    89. },
    90. events_onRequestSaveAs: {
    91. type: Function,
    92. default: () => { },
    93. },
    94. events_onRequestMailMergeRecipients: {
    95. type: Function,
    96. default: () => { },
    97. },
    98. events_onRequestCompareFile: {
    99. type: Function,
    100. default: () => { },
    101. },
    102. events_onRequestEditRights: {
    103. type: Function,
    104. default: () => { },
    105. },
    106. events_onRequestHistory: {
    107. type: Function,
    108. default: () => { },
    109. },
    110. events_onRequestHistoryClose: {
    111. type: Function,
    112. default: () => { },
    113. },
    114. events_onRequestHistoryData: {
    115. type: Function,
    116. default: () => { },
    117. },
    118. events_onRequestRestore: {
    119. type: Function,
    120. default: () => { },
    121. },
    122. },
    123. data() {
    124. return {};
    125. },
    126. watch: {
    127. config: {
    128. handler() {
    129. this.onChangeProps();
    130. },
    131. deep: true,
    132. },
    133. document_fileType() {
    134. this.onChangeProps();
    135. },
    136. document_title() {
    137. this.onChangeProps();
    138. },
    139. documentType() {
    140. this.onChangeProps();
    141. },
    142. editorConfig_lang() {
    143. this.onChangeProps();
    144. },
    145. height() {
    146. this.onChangeProps();
    147. },
    148. type() {
    149. this.onChangeProps();
    150. },
    151. width() {
    152. this.onChangeProps();
    153. },
    154. },
    155. mounted() {
    156. let url = this.documentServerUrl;
    157. if (!url.endsWith('/')) {
    158. url += '/';
    159. }
    160. const docApiUrl = `${url}web-apps/apps/api/documents/api.js`;
    161. loadScript(docApiUrl, 'onlyoffice-api-script')
    162. .then(() => this.onLoad())
    163. .catch((err) => console.error(err));
    164. },
    165. beforeDestroy() {
    166. const id = this.id || '';
    167. if (window?.DocEditor?.instances[id]) {
    168. window.DocEditor.instances[id].destroyEditor();
    169. window.DocEditor.instances[id] = undefined;
    170. }
    171. },
    172. methods: {
    173. onLoad() {
    174. try {
    175. const id = this.id || '';
    176. if (!window.DocsAPI) throw new Error('DocsAPI is not defined');
    177. if (window?.DocEditor?.instances[id]) {
    178. console.log('Skip loading. Instance already exists', id);
    179. return;
    180. }
    181. if (!window?.DocEditor?.instances) {
    182. window.DocEditor = { instances: {} };
    183. }
    184. const initConfig = {
    185. document: {
    186. fileType: this.document_fileType,
    187. title: this.document_title,
    188. },
    189. documentType: this.documentType,
    190. editorConfig: {
    191. lang: this.editorConfig_lang,
    192. },
    193. events: {
    194. onAppReady: this.onAppReady,
    195. onDocumentStateChange: this.events_onDocumentStateChange,
    196. onMetaChange: this.events_onMetaChange,
    197. onDocumentReady: this.events_onDocumentReady,
    198. onInfo: this.events_onInfo,
    199. onWarning: this.events_onWarning,
    200. onError: this.events_onError,
    201. onRequestSharingSettings: this.events_onRequestSharingSettings,
    202. onRequestRename: this.events_onRequestRename,
    203. onMakeActionLink: this.events_onMakeActionLink,
    204. onRequestInsertImage: this.events_onRequestInsertImage,
    205. onRequestSaveAs: this.events_onRequestSaveAs,
    206. onRequestMailMergeRecipients: this.events_onRequestMailMergeRecipients,
    207. onRequestCompareFile: this.events_onRequestCompareFile,
    208. onRequestEditRights: this.events_onRequestEditRights,
    209. onRequestHistory: this.events_onRequestHistory,
    210. onRequestHistoryClose: this.events_onRequestHistoryClose,
    211. onRequestHistoryData: this.events_onRequestHistoryData,
    212. onRequestRestore: this.events_onRequestRestore,
    213. },
    214. height: this.height,
    215. type: this.type,
    216. width: this.width,
    217. ...(this.config || {}),
    218. };
    219. const editor = window.DocsAPI.DocEditor(id, initConfig);
    220. window.DocEditor.instances[id] = editor;
    221. } catch (err) {
    222. console.error(err);
    223. this.events_onError(err);
    224. }
    225. },
    226. onAppReady() {
    227. const id = this.id || '';
    228. this.events_onAppReady(window.DocEditor.instances[id]);
    229. },
    230. onChangeProps() {
    231. const id = this.id || '';
    232. if (window?.DocEditor?.instances[id]) {
    233. window.DocEditor.instances[id].destroyEditor();
    234. window.DocEditor.instances[id] = undefined;
    235. console.log('Important props have been changed. Load new Editor.');
    236. this.onLoad();
    237. }
    238. },
    239. },
    240. };
    241. script>
    242. <style lang="scss" module="s">
    243. .view {
    244. width: 100%;
    245. height: 100%;
    246. iframe {
    247. width: 100%;
    248. height: 100%;
    249. }
    250. }
    251. style>

    loadScript.js文件:

    1. const loadScript = async (url, id) =>
    2. new Promise((resolve, reject) => {
    3. try {
    4. if (document.getElementById(id)) {
    5. if (window.DocsAPI) return resolve(null);
    6. const intervalHandler = setInterval(() => {
    7. if (!window.DocsAPI) return;
    8. clearInterval(intervalHandler);
    9. return resolve(null);
    10. }, 500);
    11. } else {
    12. const script = document.createElement("script");
    13. script.setAttribute("type", "text/javascript");
    14. script.setAttribute("id", id);
    15. script.onload = resolve;
    16. script.onerror = reject;
    17. script.src = url;
    18. script.async = true;
    19. document.body.appendChild(script);
    20. }
    21. } catch (e) {
    22. console.error(e);
    23. }
    24. });
    25. export default loadScript;

     2、在页面中使用。在合适的位置创建如下页面,将代码复制粘贴进去。

     docPreview.vue代码

    1. <script>
    2. import vabOnlyOffice from '@/components/docPreview/index.vue'
    3. export default {
    4. components: { vabOnlyOffice },
    5. data() {
    6. return {
    7. documentServerUrl: "http://192.168.0.15:8701/",
    8. config: {
    9. document: {
    10. fileType: "docx",
    11. key: "Khirz6zTPdfd7",
    12. title: "Example Document Title.docx",
    13. url: "http://192.168.0.15:8701/example/editor?fileName=new.docx"
    14. },
    15. documentType: "word",
    16. editorConfig: {
    17. callbackUrl: "https://example.com/url-to-callback.ashx"
    18. }
    19. }
    20. }
    21. },
    22. methods: {
    23. //这里的val是传递的参数
    24. loadOnlyOffice(val) {
    25. this.option.key = // key 默认置空则不走缓存
    26. this.option.title = '' // 该文件名在下载文档时也将用作文件名
    27. this.option.url = // 定义存储原始查看或编辑的文档的绝对URL
    28. this.option.fileType = 'docx' // 文件类型
    29. this.option.callbackUrl = '' // 回调地址
    30. this.show = true // 打开onlyOffice窗口
    31. console.log(val, '编辑word默认配置参数')
    32. },
    33. }
    34. }
    35. script>
    36. <style rel="stylesheet/scss" lang="scss">
    37. .qualityManual-container {
    38. padding: 0 !important;
    39. width: 100%;
    40. height: calc(100vh - 180px);
    41. }
    42. .qualityManual-container-office {
    43. width: 100%;
    44. height: calc(100% - 55px);
    45. }
    46. style>

    下来则是重点功能分析及使用:

    1. data() {
    2. return {
    3. //本地onlyoffice安装成功后的服务
    4. documentServerUrl: "http://192.168.0.15:8701/",
    5. config: {
    6. document: {
    7. fileType: "docx",
    8. key: "Khirz6zTPdfd7",
    9. title: "Example Document Title.docx",
    10. //你要打开的文档绝对路径,这里可以使用7.4页面左侧去生成文档并复制其文档地址进行开发测试!
    11. url: "http://192.168.0.15:8701/example/editor?fileName=new.docx"
    12. },
    13. documentType: "word",
    14. editorConfig: {
    15. callbackUrl: "https://example.com/url-to-callback.ashx"
    16. }
    17. }
    18. }
    19. },

     运行项目查看!祝你成功。

  • 相关阅读:
    SpringBoot 学习(八)异步任务,邮件发送和定时执行
    conda安装pyhanlp遇到的问题及解决方法
    012--python之文件操作
    无线耳机能不能设计成我想象的这样的?
    Linux C编译器从零开发二
    Docker12:Docker网络
    第7章 博客文章的前端渲染显示
    科目三基础四项(一)
    15.操作系统死锁处理
    安装黑群晖不求人,arpl在线编译安装群晖教程
  • 原文地址:https://blog.csdn.net/yunhuaikong/article/details/133905318