diff --git a/web/public/index.html b/web/public/index.html index 4a1e5342..dde07de9 100644 --- a/web/public/index.html +++ b/web/public/index.html @@ -6,6 +6,10 @@ 思绪思维导图 +
+ diff --git a/web/src/api/index.js b/web/src/api/index.js index b36ffddd..d3f4a7b5 100644 --- a/web/src/api/index.js +++ b/web/src/api/index.js @@ -6,6 +6,8 @@ const SIMPLE_MIND_MAP_DATA = 'SIMPLE_MIND_MAP_DATA' const SIMPLE_MIND_MAP_LANG = 'SIMPLE_MIND_MAP_LANG' const SIMPLE_MIND_MAP_LOCAL_CONFIG = 'SIMPLE_MIND_MAP_LOCAL_CONFIG' +let mindMapData = null + /** * @Author: 王林 * @Date: 2021-08-02 22:36:48 @@ -29,6 +31,10 @@ const copyMindMapTreeData = (tree, root) => { * @Desc: 获取缓存的思维导图数据 */ export const getData = () => { + if (window.takeOverApp) { + mindMapData = window.takeOverAppMethods.getMindMapData() + return mindMapData + } let store = localStorage.getItem(SIMPLE_MIND_MAP_DATA) if (store === null) { return simpleDeepClone(exampleData) @@ -48,8 +54,18 @@ export const getData = () => { */ export const storeData = data => { try { - let originData = getData() + let originData = null + if (window.takeOverApp) { + originData = mindMapData + } else { + originData = getData() + } originData.root = copyMindMapTreeData({}, data) + if (window.takeOverApp) { + mindMapData = originData + window.takeOverAppMethods.saveMindMapData(originData) + return + } Vue.prototype.$bus.$emit('write_local_file', originData) let dataStr = JSON.stringify(originData) localStorage.setItem(SIMPLE_MIND_MAP_DATA, dataStr) @@ -65,11 +81,21 @@ export const storeData = data => { */ export const storeConfig = config => { try { - let originData = getData() + let originData = null + if (window.takeOverApp) { + originData = mindMapData + } else { + originData = getData() + } originData = { ...originData, ...config } + if (window.takeOverApp) { + mindMapData = originData + window.takeOverAppMethods.saveMindMapData(originData) + return + } Vue.prototype.$bus.$emit('write_local_file', originData) let dataStr = JSON.stringify(originData) localStorage.setItem(SIMPLE_MIND_MAP_DATA, dataStr) @@ -85,6 +111,10 @@ export const storeConfig = config => { * @Desc: 存储语言 */ export const storeLang = lang => { + if (window.takeOverApp) { + window.takeOverAppMethods.saveLanguage(lang) + return + } localStorage.setItem(SIMPLE_MIND_MAP_LANG, lang) } @@ -95,6 +125,9 @@ export const storeLang = lang => { * @Desc: 获取存储的语言 */ export const getLang = () => { + if (window.takeOverApp) { + return window.takeOverAppMethods.getLanguage() || 'zh' + } let lang = localStorage.getItem(SIMPLE_MIND_MAP_LANG) if (lang) { return lang @@ -110,6 +143,9 @@ export const getLang = () => { * @Desc: 存储本地配置 */ export const storeLocalConfig = config => { + if (window.takeOverApp) { + return window.takeOverAppMethods.saveLocalConfig(config) + } localStorage.setItem(SIMPLE_MIND_MAP_LOCAL_CONFIG, JSON.stringify(config)) } @@ -120,6 +156,9 @@ export const storeLocalConfig = config => { * @Desc: 获取本地配置 */ export const getLocalConfig = () => { + if (window.takeOverApp) { + return window.takeOverAppMethods.getLocalConfig() + } let config = localStorage.getItem(SIMPLE_MIND_MAP_LOCAL_CONFIG) if (config) { return JSON.parse(config) diff --git a/web/src/i18n.js b/web/src/i18n.js index 24559442..0ce8f4b6 100644 --- a/web/src/i18n.js +++ b/web/src/i18n.js @@ -1,12 +1,10 @@ import Vue from 'vue' import VueI18n from 'vue-i18n' import messages from './lang' -import { getLang } from '@/api' Vue.use(VueI18n) const i18n = new VueI18n({ - locale: getLang(), messages }) diff --git a/web/src/main.js b/web/src/main.js index 346c5f02..22261c40 100644 --- a/web/src/main.js +++ b/web/src/main.js @@ -8,17 +8,31 @@ import '@/assets/icon-font/iconfont.css' import 'viewerjs/dist/viewer.css' import VueViewer from 'v-viewer' import i18n from './i18n' +import { getLang } from '@/api' // import VConsole from 'vconsole' // const vConsole = new VConsole() Vue.config.productionTip = false -Vue.prototype.$bus = new Vue() +const bus = new Vue() +Vue.prototype.$bus = bus Vue.use(ElementUI) Vue.use(VueViewer) -new Vue({ - render: h => h(App), - router, - store, - i18n -}).$mount('#app') +const initApp = () => { + i18n.locale = getLang() + new Vue({ + render: h => h(App), + router, + store, + i18n + }).$mount('#app') +} + +// 是否处于接管应用模式 +if (window.takeOverApp) { + window.initApp = initApp + window.$bus = bus +} else { + initApp() +} + diff --git a/web/src/pages/Doc/en/deploy/index.md b/web/src/pages/Doc/en/deploy/index.md index 44f11bb9..0385d36a 100644 --- a/web/src/pages/Doc/en/deploy/index.md +++ b/web/src/pages/Doc/en/deploy/index.md @@ -63,4 +63,130 @@ However, this requires backend support, as our application is a single page clie ## Docker -In writing... \ No newline at end of file +## Docker + +> Thank you very much [水车](https://github.com/shuiche-it), This section is written by him, and the corresponding Docker package is also maintained by him. + +Install directly from Docker Hub: + +``` +docker run -d -p 8081:8080 shuiche/mind-map:latest +``` + +Mindmap has activated port 8080 as the web service entry point in the container. When running the container through Docker, it is necessary to specify a local mapping port. In the above case, we mapped the local port 8081 to the container port 8080. + +After the installation is completed, check the container's running status through 'Docker PS'. + +Open 127.0.0.1:8081 in the browser to use the Web mind map function. + +## Docking with one's own storage services + +The application data is stored locally in the browser by default, and the local storage capacity of the browser is relatively small, so it is easy to trigger restrictions when inserting more images in the mind map. Therefore, a better choice is to dock with your own storage service, which usually has two ways: + +### The first + +Simply clone the warehouse code and modify the relevant methods in 'web/src/API/index.js' to obtain data from your database and store it in your data. + +### The second + +Many times, you may want to always use the latest code from this repository, so the first method is not very convenient because you need to manually merge the code, so the second method is provided. + +Specific operating steps: + +1. Copy the packaged resources of the web application + +This includes the 'dist' directory and the 'index.html' file. + +2. Modify the copied 'index.html' file + +Firstly, insert the following code into the 'head' tag: + +```js + +``` + +This line of code will prompt the application not to initialize the application 'i.e.: new Vue()', but to give control to you. Next, insert your own 'js' code at the end of the 'body', either inline or out of chain. The inline example is as follows: + +```js + +``` + +As shown above, when you set the 'window.takeOverApp=true' flag, the application will no longer actively instantiate, but will expose the instantiated methods for you to call. You can first request the data of the mind map from the backend, and then register the relevant methods. The application will call internally at the appropriate time to achieve the purpose of echo and save. + +The advantage of doing this is that whenever the code in this repository is updated, you can simply copy the packaged files to your own server. With a slight modification of the 'index. html' page, you can achieve synchronous updates and use your own storage service. + +Of course, there are also certain limitations at present, as' Vue CLI 'does not support' webpack '`__ Webpack_ Public_ Path__` Variable, so it is not possible to meet the requirement of setting static resource paths at runtime. The default 'publicPath' is 'dist', so you should place the 'dist' directory and the 'index.html' file at the same level as the server. + +If you want to modify the 'publicPath', such as placing static resources in the 'cdn', you can only 'clone' the code of this repository and modify the 'publicPath' configuration of 'web/vue.config.js'. After the code of this repository is updated, you need to pull it again, package it with the modified configuration, and then perform the modification operation of the ' index.html' file earlier. It is recommended to write a 'Node.js' script to complete this task. \ No newline at end of file diff --git a/web/src/pages/Doc/en/deploy/index.vue b/web/src/pages/Doc/en/deploy/index.vue index b12696d2..64cb417e 100644 --- a/web/src/pages/Doc/en/deploy/index.vue +++ b/web/src/pages/Doc/en/deploy/index.vue @@ -39,7 +39,112 @@ npm link simple-mind-map

However, this requires backend support, as our application is a single page client application. If the backend is not properly configured, users will return 404 when accessing sub routes directly in the browser. Therefore, you need to add a candidate resource on the server that covers all situations: if the 'URL' cannot match any static resources, the same 'index. html' page should be returned.

Docker

-

In writing...

+

Docker

+
+

Thank you very much 水车, This section is written by him, and the corresponding Docker package is also maintained by him.

+
+

Install directly from Docker Hub:

+
docker run -d -p 8081:8080 shuiche/mind-map:latest
+
+

Mindmap has activated port 8080 as the web service entry point in the container. When running the container through Docker, it is necessary to specify a local mapping port. In the above case, we mapped the local port 8081 to the container port 8080.

+

After the installation is completed, check the container's running status through 'Docker PS'.

+

Open 127.0.0.1:8081 in the browser to use the Web mind map function.

+

Docking with one's own storage services

+

The application data is stored locally in the browser by default, and the local storage capacity of the browser is relatively small, so it is easy to trigger restrictions when inserting more images in the mind map. Therefore, a better choice is to dock with your own storage service, which usually has two ways:

+

The first

+

Simply clone the warehouse code and modify the relevant methods in 'web/src/API/index.js' to obtain data from your database and store it in your data.

+

The second

+

Many times, you may want to always use the latest code from this repository, so the first method is not very convenient because you need to manually merge the code, so the second method is provided.

+

Specific operating steps:

+
    +
  1. Copy the packaged resources of the web application
  2. +
+

This includes the 'dist' directory and the 'index.html' file.

+
    +
  1. Modify the copied 'index.html' file
  2. +
+

Firstly, insert the following code into the 'head' tag:

+
<script>
+  window.takeOverApp = true
+</script>
+
+

This line of code will prompt the application not to initialize the application 'i.e.: new Vue()', but to give control to you. Next, insert your own 'js' code at the end of the 'body', either inline or out of chain. The inline example is as follows:

+
<script>
+  // Your own method of requesting data
+  const getDataFromBackend = () => {
+    return new Promise((resolve, reject) => {
+      setTimeout(() => {
+        resolve({
+          // MindMap data
+          mindMapData: {
+            root: {
+              "data": {
+                  "text": "根节点"
+              },
+              "children": []
+            },
+            theme: { "template":"avocado","config":{} },
+            layout: "logicalStructure",
+            config: {},
+            view: {}
+          },
+          // Page language, supporting Chinese (zh) and English (en)
+          lang: 'zh',
+          // Page Section Configuration
+          localConfig: null
+        })
+      }, 200)
+    })
+  }
+  // Register Global Method
+  const setTakeOverAppMethods = (data) => {
+    window.takeOverAppMethods = {}
+    // Function for obtaining mind map data
+    window.takeOverAppMethods.getMindMapData = () => {
+      return data.mindMapData
+    } 
+    // Functions for Saving Mind Map Data
+    window.takeOverAppMethods.saveMindMapData = (data) => {
+      console.log(data)
+      // The trigger frequency of this function may be high, so you should do throttling or anti shaking measures
+    }
+    // Function to obtain language
+    window.takeOverAppMethods.getLanguage = () => {
+      return data.lang
+    }
+    // Functions for Saving Languages
+    window.takeOverAppMethods.saveLanguage = (lang) => {
+      console.log(lang)
+    }
+    // Get locally configured functions
+    window.takeOverAppMethods.getLocalConfig = () => {
+      return data.localConfig
+    }
+    // Save locally configured functions
+    window.takeOverAppMethods.saveLocalConfig = (config) => {
+      console.log(config)
+    }
+  }
+  window.onload = async () => {
+    if (!window.takeOverApp) return
+    // request data
+    const data = await getDataFromBackend()
+    // Method for setting global
+    setTakeOverAppMethods(data)
+    // Mind Map Instance Creation Completion Event
+    window.$bus.$on('app_inited', (mindMap) => {
+      console.log(mindMap)
+    })
+    // You can use window$ Bus$ On() to listen for some events in the application
+    // Instantiate Page
+    window.initApp()
+  }
+</script>
+
+

As shown above, when you set the 'window.takeOverApp=true' flag, the application will no longer actively instantiate, but will expose the instantiated methods for you to call. You can first request the data of the mind map from the backend, and then register the relevant methods. The application will call internally at the appropriate time to achieve the purpose of echo and save.

+

The advantage of doing this is that whenever the code in this repository is updated, you can simply copy the packaged files to your own server. With a slight modification of the 'index. html' page, you can achieve synchronous updates and use your own storage service.

+

Of course, there are also certain limitations at present, as' Vue CLI 'does not support' webpack '__ Webpack_ Public_ Path__ Variable, so it is not possible to meet the requirement of setting static resource paths at runtime. The default 'publicPath' is 'dist', so you should place the 'dist' directory and the 'index.html' file at the same level as the server.

+

If you want to modify the 'publicPath', such as placing static resources in the 'cdn', you can only 'clone' the code of this repository and modify the 'publicPath' configuration of 'web/vue.config.js'. After the code of this repository is updated, you need to pull it again, package it with the modified configuration, and then perform the modification operation of the ' index.html' file earlier. It is recommended to write a 'Node.js' script to complete this task.

diff --git a/web/src/pages/Doc/zh/deploy/index.md b/web/src/pages/Doc/zh/deploy/index.md index a9ac7f0c..f5141da7 100644 --- a/web/src/pages/Doc/zh/deploy/index.md +++ b/web/src/pages/Doc/zh/deploy/index.md @@ -63,4 +63,128 @@ const router = new VueRouter({ ## Docker -编写中。。。 \ No newline at end of file +> 非常感谢[水车](https://github.com/shuiche-it),本小节由他编写,对应的 Docker 包也由他维护。 + +直接从 Docker hup 中安装: + +``` +docker run -d -p 8081:8080 shuiche/mind-map:latest +``` + +mind-map在容器中启动了8080端口作为web服务入口,通过docker运行容器时,需要指定本地映射端口,上面案例中,我们通过本地的8081端口映射到容器端口8080。 + +安装完成后,通过 `docker ps` 查看容器运行状态。 + +浏览器打开 127.0.0.1:8081 即可使用Web 思维导图功能。 + +## 对接自己的存储服务 + +应用数据默认存储在浏览器本地,浏览器本地存储容量是比较小的,所以当在思维导图中插入更多图片后很容易触发限制,所以更好的选择是对接你自己的存储服务,这通常有两种方式: + +### 第一种 + +直接clone本仓库代码,然后修改`web/src/api/index.js`内的相关方法即可实现从你的数据库里获取数据,以及存储到你的数据中。 + +### 第二种 + +很多时候,你可能想始终使用本仓库的最新代码,那么第一种方式就不太方便,因为你要手动去合并代码,所以提供了第二种方式。 + +具体操作步骤: + +1.复制web应用打包后的资源 + +包括:`dist`目录和`index.html`文件。 + +2.修改复制后的`index.html`文件 + +首先在`head`标签里插入如下代码: + +```js + +``` + +这行代码会提示应用不要初始化应用`即:new Vue()`,而是把控制权交给你,接下来再在`body`的最后插入你自己的`js`代码,内联或则外链都可以,内联示例如下: + +```js + +``` + +如上所示,当你设置了`window.takeOverApp = true`标志,应用不再主动进行实例化,而是会将实例化的方法暴露出来由你调用,那么你可以先从后端请求思维导图的数据,然后再注册相关的方法,应用内部会在合适的时机进行调用,从而达到回显和保存的目的。 + +这样做的好处是,每当本仓库代码更新了,你可以简单的复制打包后的文件到你自己的服务器,只要稍微修改一下`index.html`页面即可达到同步更新且使用自己的存储服务的目的。 + +当然,目前也有一定限制,因为`Vue CLI`不支持`webpack`的`__webpack_public_path__`变量,所以无法实现运行时设置静态资源路径的需求,默认的`publicPath`为`dist`,所以你应该将`dist`目录和`index.html`文件放在服务器的同一层级。 + +如果你想修改`publicPath`,比如想把静态资源放到`cdn`,那么你只能`clone`本仓库的代码,然后修改一下`web/vue.config.js`的`publicPath`配置,后续当本仓库的代码更新后,你需要重新拉取,用你修改过的配置进行打包,再进行前面的`index.html`文件的修改操作,推荐写一个`Node.js`脚本来完成该任务。 \ No newline at end of file diff --git a/web/src/pages/Doc/zh/deploy/index.vue b/web/src/pages/Doc/zh/deploy/index.vue index b3ca8173..c30b7ba4 100644 --- a/web/src/pages/Doc/zh/deploy/index.vue +++ b/web/src/pages/Doc/zh/deploy/index.vue @@ -39,7 +39,107 @@ npm link simple-mind-map

不过这需要后台支持,因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问子路由时会返回404,所以呢你要在服务端增加一个覆盖所有情况的候选资源:如果URL匹配不到任何静态资源,则应该返回同一个index.html页面。

Docker

-

编写中。。。

+
+

非常感谢水车,本小节由他编写,对应的 Docker 包也由他维护。

+
+

直接从 Docker hup 中安装:

+
docker run -d -p 8081:8080 shuiche/mind-map:latest
+
+

mind-map在容器中启动了8080端口作为web服务入口,通过docker运行容器时,需要指定本地映射端口,上面案例中,我们通过本地的8081端口映射到容器端口8080。

+

安装完成后,通过 docker ps 查看容器运行状态。

+

浏览器打开 127.0.0.1:8081 即可使用Web 思维导图功能。

+

对接自己的存储服务

+

应用数据默认存储在浏览器本地,浏览器本地存储容量是比较小的,所以当在思维导图中插入更多图片后很容易触发限制,所以更好的选择是对接你自己的存储服务,这通常有两种方式:

+

第一种

+

直接clone本仓库代码,然后修改web/src/api/index.js内的相关方法即可实现从你的数据库里获取数据,以及存储到你的数据中。

+

第二种

+

很多时候,你可能想始终使用本仓库的最新代码,那么第一种方式就不太方便,因为你要手动去合并代码,所以提供了第二种方式。

+

具体操作步骤:

+

1.复制web应用打包后的资源

+

包括:dist目录和index.html文件。

+

2.修改复制后的index.html文件

+

首先在head标签里插入如下代码:

+
<script>
+  window.takeOverApp = true
+</script>
+
+

这行代码会提示应用不要初始化应用即:new Vue(),而是把控制权交给你,接下来再在body的最后插入你自己的js代码,内联或则外链都可以,内联示例如下:

+
<script>
+  // 你自己的请求数据的方法
+  const getDataFromBackend = () => {
+    return new Promise((resolve, reject) => {
+      setTimeout(() => {
+        resolve({
+          // 思维导图数据
+          mindMapData: {
+            root: {
+              "data": {
+                  "text": "根节点"
+              },
+              "children": []
+            },
+            theme: { "template":"avocado","config":{} },
+            layout: "logicalStructure",
+            config: {},
+            view: {}
+          },
+          // 页面语言,支持中文(zh)、英文(en)
+          lang: 'zh',
+          // 页面部分配置
+          localConfig: null
+        })
+      }, 200)
+    })
+  }
+  // 注册全局方法
+  const setTakeOverAppMethods = (data) => {
+    window.takeOverAppMethods = {}
+    // 获取思维导图数据的函数
+    window.takeOverAppMethods.getMindMapData = () => {
+      return data.mindMapData
+    } 
+    // 保存思维导图数据的函数
+    window.takeOverAppMethods.saveMindMapData = (data) => {
+      console.log(data)
+      // 该函数触发频率可能会很高,所以你应该做一下节流或防抖
+    }
+    // 获取语言的函数
+    window.takeOverAppMethods.getLanguage = () => {
+      return data.lang
+    }
+    // 保存语言的函数
+    window.takeOverAppMethods.saveLanguage = (lang) => {
+      console.log(lang)
+    }
+    // 获取本地配置的函数
+    window.takeOverAppMethods.getLocalConfig = () => {
+      return data.localConfig
+    }
+    // 保存本地配置的函数
+    window.takeOverAppMethods.saveLocalConfig = (config) => {
+      console.log(config)
+    }
+  }
+  window.onload = async () => {
+    if (!window.takeOverApp) return
+    // 请求数据
+    const data = await getDataFromBackend()
+    // 设置全局的方法
+    setTakeOverAppMethods(data)
+    // 思维导图实例创建完成事件
+    window.$bus.$on('app_inited', (mindMap) => {
+      console.log(mindMap)
+    })
+    // 可以通过window.$bus.$on()来监听应用的一些事件
+    // 实例化页面
+    window.initApp()
+  }
+</script>
+
+

如上所示,当你设置了window.takeOverApp = true标志,应用不再主动进行实例化,而是会将实例化的方法暴露出来由你调用,那么你可以先从后端请求思维导图的数据,然后再注册相关的方法,应用内部会在合适的时机进行调用,从而达到回显和保存的目的。

+

这样做的好处是,每当本仓库代码更新了,你可以简单的复制打包后的文件到你自己的服务器,只要稍微修改一下index.html页面即可达到同步更新且使用自己的存储服务的目的。

+

当然,目前也有一定限制,因为Vue CLI不支持webpack__webpack_public_path__变量,所以无法实现运行时设置静态资源路径的需求,默认的publicPathdist,所以你应该将dist目录和index.html文件放在服务器的同一层级。

+

如果你想修改publicPath,比如想把静态资源放到cdn,那么你只能clone本仓库的代码,然后修改一下web/vue.config.jspublicPath配置,后续当本仓库的代码更新后,你需要重新拉取,用你修改过的配置进行打包,再进行前面的index.html文件的修改操作,推荐写一个Node.js脚本来完成该任务。

diff --git a/web/src/pages/Edit/components/Edit.vue b/web/src/pages/Edit/components/Edit.vue index 617c8646..1c6fd47c 100644 --- a/web/src/pages/Edit/components/Edit.vue +++ b/web/src/pages/Edit/components/Edit.vue @@ -384,6 +384,10 @@ export default { // 动态删除指定节点 // this.mindMap.execCommand('REMOVE_NODE', this.mindMap.renderer.root.children[0]) // }, 5000); + // 如果应用被接管,那么抛出事件传递思维导图实例 + if (window.takeOverApp) { + this.$bus.$emit('app_inited', this.mindMap) + } }, /** diff --git a/web/src/pages/Edit/components/NavigatorToolbar.vue b/web/src/pages/Edit/components/NavigatorToolbar.vue index 54886c26..52e4ae4f 100644 --- a/web/src/pages/Edit/components/NavigatorToolbar.vue +++ b/web/src/pages/Edit/components/NavigatorToolbar.vue @@ -108,7 +108,7 @@ export default { data() { return { langList, - lang: getLang(), + lang: '', isReadonly: false, openMiniMap: false } @@ -116,6 +116,9 @@ export default { computed: { ...mapState(['isDark']) }, + created () { + this.lang = getLang() + }, methods: { ...mapMutations(['setIsDark']), diff --git a/web/vue.config.js b/web/vue.config.js index 54c939b0..765ae60a 100644 --- a/web/vue.config.js +++ b/web/vue.config.js @@ -6,6 +6,10 @@ module.exports = { outputDir: '../dist', lintOnSave: false, productionSourceMap: false, + chainWebpack: config => { + // 移除 prefetch 插件 + config.plugins.delete('prefetch') + }, configureWebpack: { resolve: { alias: {