Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cfe07aa32e | ||
|
|
b8ac079009 | ||
|
|
040ce6601b | ||
|
|
77dd62477e | ||
|
|
b831d95063 | ||
|
|
bff6024e2e | ||
|
|
919b1517d9 | ||
|
|
2cbd08c532 | ||
|
|
5e300c0320 | ||
|
|
714567a733 | ||
|
|
28d6bb7d90 | ||
|
|
ecb2fbab48 | ||
|
|
a8c13b8f9a | ||
|
|
475dd4754a | ||
|
|
8a59185156 | ||
|
|
80ca74e477 | ||
|
|
c67bebb384 | ||
|
|
3a9002821c | ||
|
|
d0b289ed28 | ||
|
|
84782f924b | ||
|
|
2dd3db4c9d | ||
|
|
eb61e24746 | ||
|
|
abb332fd46 | ||
|
|
0c4fadb211 | ||
|
|
cd361c1f6e | ||
|
|
e0dc13c9f8 | ||
|
|
670114d8d8 | ||
|
|
c5b5fd86de | ||
|
|
493e0da7ae | ||
|
|
896121f6b6 | ||
|
|
b79076baa3 | ||
|
|
715627727e | ||
|
|
5ed5f0ff0d | ||
|
|
c12189ca87 | ||
|
|
be38eb2ca6 | ||
|
|
e80890aa7e | ||
|
|
e0ca3a5d12 | ||
|
|
30404721fa |
89
README.md
@@ -9,7 +9,21 @@
|
||||
|
||||
> 中文名:思绪思维导图。一个简单&强大的 Web 思维导图库和思维导图软件。
|
||||
|
||||
本项目主要包含以下内容:
|
||||
# 客户端和插件
|
||||
|
||||
- 思绪思维导图客户端
|
||||
|
||||
支持Windows、Mac及Linux系统。下载地址:[Github](https://github.com/wanglin2/mind-map/releases)、[百度网盘](https://pan.baidu.com/s/1C8phEJ5pagAAa-o1tU42Uw?pwd=jqfb)、[夸克网盘](https://pan.quark.cn/s/2733982f1976)
|
||||
|
||||
- Obsidian插件
|
||||
|
||||
下载地址:[Github](https://github.com/wanglin2/obsidian-simplemindmap/releases)
|
||||
|
||||
- UTools插件
|
||||
|
||||
已上架[uTools](https://www.u.tools/)插件应用市场,可直接在`uTools`插件应用市场中搜索`思绪`进行安装,也可以直接访问该地址:[主页](https://www.u-tools.cn/plugins/detail/%E6%80%9D%E7%BB%AA%E6%80%9D%E7%BB%B4%E5%AF%BC%E5%9B%BE/),点击右侧的【启动】按钮进行安装
|
||||
|
||||
# 库
|
||||
|
||||
- 一个 `js` 思维导图库,不依赖任何框架,可以用来快速完成 Web 思维导图产品的开发。
|
||||
|
||||
@@ -19,16 +33,6 @@
|
||||
|
||||
> 在线地址:[https://wanglin2.github.io/mind-map/](https://wanglin2.github.io/mind-map/)
|
||||
|
||||
- 客户端和插件
|
||||
|
||||
> 1.独立客户端,支持Windows、Mac及Linux系统。
|
||||
>
|
||||
> 下载地址:[Github](https://github.com/wanglin2/mind-map/releases)、[百度云盘](https://pan.baidu.com/s/1huasEbKsGNH2Af68dvWiOg?pwd=3bp3)
|
||||
|
||||
> 2.`uTools`插件,现已上架[uTools](https://www.u.tools/)插件应用市场。
|
||||
>
|
||||
> 可直接在`uTools`插件应用市场中搜索`思绪`进行安装,也可以直接访问该地址:[主页](https://www.u-tools.cn/plugins/detail/%E6%80%9D%E7%BB%AA%E6%80%9D%E7%BB%B4%E5%AF%BC%E5%9B%BE/),点击右侧的【启动】按钮进行安装。
|
||||
|
||||
- 云存储版本,如果你需要带后端的云存储版本,可以尝试我们开发的另一个项目[理想文档](https://github.com/wanglin2/lx-doc)。
|
||||
|
||||
# 特性
|
||||
@@ -55,9 +59,6 @@
|
||||
| TouchEvent(移动端触摸事件支持插件) | NodeImgAdjust(拖拽调整节点图片大小插件) | Search(搜索插件) | Painter(节点格式刷插件) |
|
||||
| Scrollbar(滚动条插件) | Formula(数学公式插件) | Cooperate(协同编辑插件) | RainbowLines(彩虹线条插件) |
|
||||
| Demonstrate(演示模式插件) | OuterFrame(外框插件) | MindMapLayoutPro(思维导图布局插件) | |
|
||||
| HandDrawnLikeStyle(手绘风格插件) | Notation(节点标记插件) | Numbers(节点编号插件)[收费] | Freemind(Freemind格式导入导出插件) |
|
||||
| Excel(Excel格式导入导出插件) | Checkbox(待办插件) | Lineflow(节点连线流动插件) | Momentum(动量效果插件) |
|
||||
| RightFishbone(向右鱼骨图插件) | NodeLink(节点链接插件) | | |
|
||||
|
||||
|
||||
本项目不会实现的特性:
|
||||
@@ -111,13 +112,15 @@ const mindMap = new MindMap({
|
||||
|
||||
# License
|
||||
|
||||
[MIT](./LICENSE)。保留`mind-map`版权声明和注明来源的情况下可随意商用,如有疑问或不想保留可联系作者通过付费的方式去除。
|
||||
[MIT](./LICENSE)。保留`simple-mind-map`版权声明和注明来源的情况下可随意商用,如有疑问或不想保留可联系作者(微信:wanglinguanfang)通过付费的方式去除。
|
||||
|
||||
# 微信交流群
|
||||
> 示例:可以在你应用中的关于页面、帮助页面、文档页面、开源声明等任何页面添加以下内容:
|
||||
>
|
||||
> 本产品思维导图基于SimpleMindMap项目开发,版权归源项目所有,[开源协议](https://github.com/wanglin2/mind-map/blob/main/LICENSE)。
|
||||
|
||||
微信添加`wanglinguanfang`拉你入群。根据过往的经验,大部分问题都可以通过查看issue列表或文档解决,所以提问前请确保你已经阅读完了所有文档,文档里没有的可在群里提问,不必私聊作者,如果你一定要私聊,请先发红包(¥9.9+每次)。
|
||||
# 开发帮助/技术支持/咨询等
|
||||
|
||||
如果你在杭州,也欢迎来找我面基。
|
||||
因精力有限,及重心转变,暂不提供任何开发支持(包括有偿),请见谅!
|
||||
|
||||
# star
|
||||
|
||||
@@ -143,20 +146,7 @@ const mindMap = new MindMap({
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
# 请作者喝杯咖啡
|
||||
|
||||
开源不易,如果本项目有帮助到你的话,可以考虑请作者喝杯咖啡~你的赞助对项目的可持续发展非常重要,是作者持续维护的最大动力。
|
||||
|
||||
> 推荐使用支付宝,微信获取不到头像。转账请备注【思维导图】。
|
||||
>
|
||||
> 也可以通过购买付费插件来支持我们:[付费插件](https://wanglin2.github.io/mind-map-docs/plugins/about.html)。
|
||||
>
|
||||
> 赞助等级:最强王者(¥500+)、星耀赞助(¥300+)、钻石赞助(¥150+)、黄金赞助(¥50+)、青铜赞助
|
||||
|
||||
<p>
|
||||
<img src="./web/src/assets/img/alipay.jpg" style="width: 300px" />
|
||||
<img src="./web/src/assets/img/wechat.jpg" style="width: 300px" />
|
||||
</p>
|
||||
# 感谢赞赏过本项目的人
|
||||
|
||||
## 最强王者
|
||||
|
||||
@@ -190,6 +180,13 @@ const mindMap = new MindMap({
|
||||
<sub style="font-size:14px"><b>沨沄</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" style="word-wrap: break-word; width: 75.0; height: 75.0">
|
||||
<a href="#">
|
||||
<img src="./web/src/assets/avatar/行.jpg" width="50;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px"/>
|
||||
<br />
|
||||
<sub style="font-size:14px"><b>行</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -362,6 +359,20 @@ const mindMap = new MindMap({
|
||||
<sub style="font-size:14px"><b>兔子快跑</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" style="word-wrap: break-word; width: 75.0; height: 75.0">
|
||||
<a href="#">
|
||||
<img src="./web/src/assets/avatar/default.png" width="50;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px"/>
|
||||
<br />
|
||||
<sub style="font-size:14px"><b>LSHM</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" style="word-wrap: break-word; width: 75.0; height: 75.0">
|
||||
<a href="#">
|
||||
<img src="./web/src/assets/avatar/default.png" width="50;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px"/>
|
||||
<br />
|
||||
<sub style="font-size:14px"><b>newplayer</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -994,5 +1005,19 @@ const mindMap = new MindMap({
|
||||
<sub style="font-size:14px"><b>神话</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" style="word-wrap: break-word; width: 75.0; height: 75.0">
|
||||
<a href="#">
|
||||
<img src="./web/src/assets/avatar/default.png" width="50;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px"/>
|
||||
<br />
|
||||
<sub style="font-size:14px"><b>Towards the future</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" style="word-wrap: break-word; width: 75.0; height: 75.0">
|
||||
<a href="#">
|
||||
<img src="./web/src/assets/avatar/default.png" width="50;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px"/>
|
||||
<br />
|
||||
<sub style="font-size:14px"><b>安嘉</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
2
dist/css/app.css
vendored
@@ -1 +1 @@
|
||||
*{margin:0;padding:0;box-sizing:border-box}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:#2c3e50}.customScrollbar{&::-webkit-scrollbar{width:7px;height:7px}&::-webkit-scrollbar-thumb{border-radius:7px;background-color:rgba(0,0,0,.3);cursor:pointer}&::-webkit-scrollbar-track{box-shadow:none;background:transparent;display:none}}@font-face{font-family:iconfont;src:url(../fonts/iconfont.woff2) format("woff2"),url(../fonts/iconfont.woff) format("woff"),url(../fonts/iconfont.ttf) format("truetype")}.iconfont{font-family:iconfont!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.iconAIshengcheng:before{content:"\e6b5"}.iconprinting:before{content:"\ea28"}.iconwenjianjia:before{content:"\e614"}.iconcontentleft:before{content:"\e8c9"}.iconjuzhongduiqi:before{content:"\ec80"}.iconfile-excel:before{content:"\e7b7"}.iconfreemind:before{content:"\e97d"}.iconwaikuang:before{content:"\e640"}.iconhighlight:before{content:"\e6b8"}.iconyanshibofang:before{content:"\e648"}.iconfujian:before{content:"\e88a"}.icongeshihua:before{content:"\e7a3"}.iconyuanma:before{content:"\e658"}.icongundongtiao:before{content:"\e670"}.iconxietongwendang:before{content:"\e60d"}.iconTXT:before{content:"\e6e1"}.iconwenjian1:before{content:"\e69f"}.icondodeparent:before{content:"\e70f"}.icongongshi:before{content:"\e617"}.icontouming:before{content:"\e60c"}.iconlieri:before{content:"\e60b"}.iconmoon_line:before{content:"\e745"}.iconsousuo:before{content:"\e693"}.iconjiantouyou:before{content:"\e62d"}.iconbianji1:before{content:"\e60a"}.icondaohang1:before{content:"\e632"}.iconyanjing:before{content:"\e8bf"}.iconwangzhan:before{content:"\e628"}.iconcsdn:before{content:"\e608"}.iconshejiaotubiao-10:before{content:"\e644"}.iconstar:before{content:"\e7df"}.iconfork:before{content:"\e641"}.iconxiazai:before{content:"\e613"}.iconteamwork:before{content:"\e870"}.iconshuiyin:before{content:"\e67a"}.iconxmind:before{content:"\ea57"}.iconmouseR:before{content:"\e6bd"}.iconmouseL:before{content:"\e6c0"}.iconwenjian:before{content:"\e607"}.iconpdf:before{content:"\e740"}.iconPNG:before{content:"\ec18"}.iconSVG:before{content:"\e621"}.iconmarkdown:before{content:"\ec04"}.iconjson:before{content:"\ea42"}.iconlianjiexian:before{content:"\e75b"}.iconbangzhu:before{content:"\e620"}.iconshezhi:before{content:"\e8b7"}.iconwushuju:before{content:"\e643"}.iconzuijinliulan:before{content:"\e62f"}.icon3zuidahua-3:before{content:"\e692"}.iconzuixiaohua:before{content:"\e650"}.iconzuidahua:before{content:"\e651"}.iconguanbi:before{content:"\e652"}.icondiannao:before{content:"\eac0"}.iconzhuye:before{content:"\e65c"}.iconbendi1x:before{content:"\e606"}.iconbeijingyanse:before{content:"\e6f8"}.iconqingchu:before{content:"\e605"}.iconcase:before{content:"\e6c6"}.iconxingzhuang-wenzi:before{content:"\eb99"}.iconzitijiacu:before{content:"\ec83"}.iconzitixiahuaxian:before{content:"\ec85"}.iconzitixieti:before{content:"\ec86"}.iconshanchuxian:before{content:"\e612"}.iconzitiyanse:before{content:"\e854"}.icongithub:before{content:"\e64f"}.iconchoose1:before{content:"\e6c5"}.iconzhuti:before{content:"\e7aa"}.icondaochu1:before{content:"\e63e"}.iconlingcunwei:before{content:"\e657"}.iconexport:before{content:"\e642"}.icondakai:before{content:"\ebdf"}.iconxinjian:before{content:"\e64e"}.iconjianqie:before{content:"\e601"}.iconzhengli:before{content:"\e83b"}.iconfuzhi:before{content:"\e604"}.iconniantie:before{content:"\e63f"}.iconshangyi:before{content:"\e6be"}.iconxiayi:before{content:"\e6bf"}.icongaikuozonglan:before{content:"\e609"}.iconquanxuan:before{content:"\f199"}.icondaoru:before{content:"\e6a3"}.iconhoutui-shi:before{content:"\e656"}.iconqianjin1:before{content:"\e654"}.iconwithdraw:before{content:"\e603"}.iconqianjin:before{content:"\e600"}.iconhuifumoren:before{content:"\e60e"}.iconhuanhang:before{content:"\e61e"}.iconsuoxiao:before{content:"\ec13"}.iconbianji:before{content:"\e626"}.iconfangda:before{content:"\e663"}.iconquanping1:before{content:"\e664"}.icondingwei:before{content:"\e616"}.icondaohang:before{content:"\e611"}.iconjianpan:before{content:"\e64d"}.iconquanping:before{content:"\e602"}.icondaochu:before{content:"\e63d"}.iconbiaoqian:before{content:"\e63c"}.iconflow-Mark:before{content:"\e65b"}.iconchaolianjie:before{content:"\e6f4"}.iconjingzi:before{content:"\e610"}.iconxiaolian:before{content:"\e60f"}.iconimage:before{content:"\e629"}.iconjiegou:before{content:"\e61d"}.iconyangshi:before{content:"\e631"}.iconfuhao-dagangshu:before{content:"\e71f"}.icontianjiazijiedian:before{content:"\e622"}.iconjiedian:before{content:"\e655"}.iconshanchu:before{content:"\e696"}.iconzhankai:before{content:"\e64c"}.iconzhankai1:before{content:"\e673"}
|
||||
*{margin:0;padding:0;box-sizing:border-box}#app{font-family:Avenir,Helvetica,Arial,sans-serif;color:#2c3e50}.customScrollbar::-webkit-scrollbar{width:7px;height:7px}.customScrollbar::-webkit-scrollbar-thumb{border-radius:7px;background-color:rgba(0,0,0,.3);cursor:pointer}.customScrollbar::-webkit-scrollbar-track{box-shadow:none;background:transparent;display:none}.el-dialog{border-radius:10px}@font-face{font-family:iconfont;src:url(../fonts/iconfont.woff2) format("woff2"),url(../fonts/iconfont.woff) format("woff"),url(../fonts/iconfont.ttf) format("truetype")}.iconfont{font-family:iconfont!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.iconAIshengcheng:before{content:"\e6b5"}.iconprinting:before{content:"\ea28"}.iconwenjianjia:before{content:"\e614"}.iconcontentleft:before{content:"\e8c9"}.iconjuzhongduiqi:before{content:"\ec80"}.iconfile-excel:before{content:"\e7b7"}.iconfreemind:before{content:"\e97d"}.iconwaikuang:before{content:"\e640"}.iconhighlight:before{content:"\e6b8"}.iconyanshibofang:before{content:"\e648"}.iconfujian:before{content:"\e88a"}.icongeshihua:before{content:"\e7a3"}.iconyuanma:before{content:"\e658"}.icongundongtiao:before{content:"\e670"}.iconxietongwendang:before{content:"\e60d"}.iconTXT:before{content:"\e6e1"}.iconwenjian1:before{content:"\e69f"}.icondodeparent:before{content:"\e70f"}.icongongshi:before{content:"\e617"}.icontouming:before{content:"\e60c"}.iconlieri:before{content:"\e60b"}.iconmoon_line:before{content:"\e745"}.iconsousuo:before{content:"\e693"}.iconjiantouyou:before{content:"\e62d"}.iconbianji1:before{content:"\e60a"}.icondaohang1:before{content:"\e632"}.iconyanjing:before{content:"\e8bf"}.iconwangzhan:before{content:"\e628"}.iconcsdn:before{content:"\e608"}.iconshejiaotubiao-10:before{content:"\e644"}.iconstar:before{content:"\e7df"}.iconfork:before{content:"\e641"}.iconxiazai:before{content:"\e613"}.iconteamwork:before{content:"\e870"}.iconshuiyin:before{content:"\e67a"}.iconxmind:before{content:"\ea57"}.iconmouseR:before{content:"\e6bd"}.iconmouseL:before{content:"\e6c0"}.iconwenjian:before{content:"\e607"}.iconpdf:before{content:"\e740"}.iconPNG:before{content:"\ec18"}.iconSVG:before{content:"\e621"}.iconmarkdown:before{content:"\ec04"}.iconjson:before{content:"\ea42"}.iconlianjiexian:before{content:"\e75b"}.iconbangzhu:before{content:"\e620"}.iconshezhi:before{content:"\e8b7"}.iconwushuju:before{content:"\e643"}.iconzuijinliulan:before{content:"\e62f"}.icon3zuidahua-3:before{content:"\e692"}.iconzuixiaohua:before{content:"\e650"}.iconzuidahua:before{content:"\e651"}.iconguanbi:before{content:"\e652"}.icondiannao:before{content:"\eac0"}.iconzhuye:before{content:"\e65c"}.iconbendi1x:before{content:"\e606"}.iconbeijingyanse:before{content:"\e6f8"}.iconqingchu:before{content:"\e605"}.iconcase:before{content:"\e6c6"}.iconxingzhuang-wenzi:before{content:"\eb99"}.iconzitijiacu:before{content:"\ec83"}.iconzitixiahuaxian:before{content:"\ec85"}.iconzitixieti:before{content:"\ec86"}.iconshanchuxian:before{content:"\e612"}.iconzitiyanse:before{content:"\e854"}.icongithub:before{content:"\e64f"}.iconchoose1:before{content:"\e6c5"}.iconzhuti:before{content:"\e7aa"}.icondaochu1:before{content:"\e63e"}.iconlingcunwei:before{content:"\e657"}.iconexport:before{content:"\e642"}.icondakai:before{content:"\ebdf"}.iconxinjian:before{content:"\e64e"}.iconjianqie:before{content:"\e601"}.iconzhengli:before{content:"\e83b"}.iconfuzhi:before{content:"\e604"}.iconniantie:before{content:"\e63f"}.iconshangyi:before{content:"\e6be"}.iconxiayi:before{content:"\e6bf"}.icongaikuozonglan:before{content:"\e609"}.iconquanxuan:before{content:"\f199"}.icondaoru:before{content:"\e6a3"}.iconhoutui-shi:before{content:"\e656"}.iconqianjin1:before{content:"\e654"}.iconwithdraw:before{content:"\e603"}.iconqianjin:before{content:"\e600"}.iconhuifumoren:before{content:"\e60e"}.iconhuanhang:before{content:"\e61e"}.iconsuoxiao:before{content:"\ec13"}.iconbianji:before{content:"\e626"}.iconfangda:before{content:"\e663"}.iconquanping1:before{content:"\e664"}.icondingwei:before{content:"\e616"}.icondaohang:before{content:"\e611"}.iconjianpan:before{content:"\e64d"}.iconquanping:before{content:"\e602"}.icondaochu:before{content:"\e63d"}.iconbiaoqian:before{content:"\e63c"}.iconflow-Mark:before{content:"\e65b"}.iconchaolianjie:before{content:"\e6f4"}.iconjingzi:before{content:"\e610"}.iconxiaolian:before{content:"\e60f"}.iconimage:before{content:"\e629"}.iconjiegou:before{content:"\e61d"}.iconyangshi:before{content:"\e631"}.iconfuhao-dagangshu:before{content:"\e71f"}.icontianjiazijiedian:before{content:"\e622"}.iconjiedian:before{content:"\e655"}.iconshanchu:before{content:"\e696"}.iconzhankai:before{content:"\e64c"}.iconzhankai1:before{content:"\e673"}
|
||||
BIN
dist/img/withBg1.jpg
vendored
|
Before Width: | Height: | Size: 51 KiB |
BIN
dist/img/withBg2.jpg
vendored
|
Before Width: | Height: | Size: 28 KiB |
BIN
dist/img/withBg3.jpg
vendored
|
Before Width: | Height: | Size: 48 KiB |
BIN
dist/img/withBg4.jpg
vendored
|
Before Width: | Height: | Size: 23 KiB |
BIN
dist/img/withBg5.jpg
vendored
|
Before Width: | Height: | Size: 20 KiB |
2
dist/js/app.js
vendored
65
dist/js/chunk-183b683c.js
vendored
Normal file
69
dist/js/chunk-27a8e520.js
vendored
8
dist/js/chunk-vendors.js
vendored
@@ -9,7 +9,7 @@
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}</script><link href="dist/css/chunk-vendors.css?b70e90f1bbbbeb12fd74" rel="stylesheet"><link href="dist/css/app.css?b70e90f1bbbbeb12fd74" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>const getDataFromBackend = () => {
|
||||
}</script><link href="dist/css/chunk-vendors.css?227f61428db154a5d9bc" rel="stylesheet"><link href="dist/css/app.css?227f61428db154a5d9bc" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>const getDataFromBackend = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve({
|
||||
@@ -83,4 +83,4 @@
|
||||
// 可以通过window.$bus.$on()来监听应用的一些事件
|
||||
// 实例化页面
|
||||
window.initApp()
|
||||
}</script><script src="dist/js/chunk-vendors.js?b70e90f1bbbbeb12fd74"></script><script src="dist/js/app.js?b70e90f1bbbbeb12fd74"></script></body></html>
|
||||
}</script><script src="dist/js/chunk-vendors.js?227f61428db154a5d9bc"></script><script src="dist/js/app.js?227f61428db154a5d9bc"></script></body></html>
|
||||
@@ -31,7 +31,7 @@ MindMap.markdown = markdown
|
||||
MindMap.iconList = icons.nodeIconList
|
||||
MindMap.constants = constants
|
||||
MindMap.defaultTheme = defaultTheme
|
||||
MindMap.version = '0.14.0'
|
||||
MindMap.version = '0.14.0-fix.1'
|
||||
|
||||
MindMap.usePlugin(MiniMap)
|
||||
.usePlugin(Watermark)
|
||||
|
||||
4
simple-mind-map/package-lock.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.12.1",
|
||||
"version": "0.14.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "0.12.1",
|
||||
"version": "0.14.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@svgdotjs/svg.js": "3.2.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.14.0",
|
||||
"version": "0.14.0-fix.1",
|
||||
"description": "一个简单的web在线思维导图",
|
||||
"authors": [
|
||||
{
|
||||
|
||||
@@ -613,6 +613,13 @@ class Render {
|
||||
this.emitNodeActiveEvent()
|
||||
}
|
||||
|
||||
// 当某个自定义节点内容改变后,可以调用该方法实时更新该节点大小和整体节点的定位
|
||||
renderByCustomNodeContentNode(node) {
|
||||
node.getSize()
|
||||
node.customNodeContentRealtimeLayout()
|
||||
this.mindMap.render()
|
||||
}
|
||||
|
||||
// 给当前被收起来的节点数据添加更新标志
|
||||
resetUnExpandNodeStyle() {
|
||||
if (!this.renderTree) return
|
||||
|
||||
@@ -32,9 +32,16 @@ const defaultTagStyle = {
|
||||
//width: 30 // 标签矩形的宽度,如果不设置,默认以文字的宽度+paddingX*2为宽度
|
||||
}
|
||||
|
||||
// 获取图片的真实url
|
||||
// 因为如果注册了NodeBase64ImageStorage插件,那么节点图片字段保存的实际是一个id,所以如果要获取图片真实的url可以通过该方法
|
||||
function getImageUrl() {
|
||||
const img = this.getData('image')
|
||||
return (this.mindMap.renderer.renderTree.data.imgMap || {})[img] || img
|
||||
}
|
||||
|
||||
// 创建图片节点
|
||||
function createImgNode() {
|
||||
let img = this.getData('image')
|
||||
const img = this.getImageUrl()
|
||||
if (!img) {
|
||||
return
|
||||
}
|
||||
@@ -570,6 +577,7 @@ function isUseCustomNodeContent() {
|
||||
}
|
||||
|
||||
export default {
|
||||
getImageUrl,
|
||||
createImgNode,
|
||||
getImgShowSize,
|
||||
createIconNode,
|
||||
|
||||
@@ -33,7 +33,9 @@ function getTagContentSize(space) {
|
||||
function getNodeRect() {
|
||||
// 自定义节点内容
|
||||
if (this.isUseCustomNodeContent()) {
|
||||
const rect = this.measureCustomNodeContentSize(this._customNodeContent)
|
||||
const rect = this.measureCustomNodeContentSize(
|
||||
this._customNodeContent.cloneNode(true)
|
||||
)
|
||||
return {
|
||||
width: this.hasCustomWidth() ? this.customTextWidth : rect.width,
|
||||
height: rect.height
|
||||
@@ -178,13 +180,54 @@ function getNodeRect() {
|
||||
}
|
||||
}
|
||||
|
||||
// 激活hover和激活边框
|
||||
function addHoverNode(width, height) {
|
||||
const { hoverRectPadding } = this.mindMap.opt
|
||||
this.hoverNode = new Rect()
|
||||
.size(width + hoverRectPadding * 2, height + hoverRectPadding * 2)
|
||||
.x(-hoverRectPadding)
|
||||
.y(-hoverRectPadding)
|
||||
this.hoverNode.addClass('smm-hover-node')
|
||||
this.style.hoverNode(this.hoverNode, width, height)
|
||||
this.group.add(this.hoverNode)
|
||||
}
|
||||
|
||||
// 当使用了完全自定义节点内容后,可以通过该方法实时更新节点大小
|
||||
function customNodeContentRealtimeLayout() {
|
||||
if (!this.group) return
|
||||
if (!this.isUseCustomNodeContent()) return
|
||||
// 删除除foreignObject外的其他元素
|
||||
if (this.shapeNode) this.shapeNode.remove()
|
||||
if (this._unVisibleRectRegionNode) this._unVisibleRectRegionNode.remove()
|
||||
if (this.hoverNode) this.hoverNode.remove()
|
||||
const { width, height } = this
|
||||
const halfBorderWidth = this.getBorderWidth() / 2
|
||||
// 节点形状
|
||||
this.shapeNode = this.shapeInstance.createShape()
|
||||
this.shapeNode.addClass('smm-node-shape')
|
||||
this.shapeNode.translate(halfBorderWidth, halfBorderWidth)
|
||||
this.style.shape(this.shapeNode)
|
||||
this.group.add(this.shapeNode)
|
||||
// 渲染一个隐藏的矩形区域,用来触发展开收起按钮的显示
|
||||
this.renderExpandBtnPlaceholderRect()
|
||||
// 概要节点添加一个带所属节点id的类名
|
||||
if (this.isGeneralization && this.generalizationBelongNode) {
|
||||
this.group.addClass('generalization_' + this.generalizationBelongNode.uid)
|
||||
}
|
||||
// 激活hover和激活边框
|
||||
this.addHoverNode(width, height)
|
||||
// 将形状元素移至底层,避免遮挡foreignObject
|
||||
this.shapeNode.back()
|
||||
// 更新foreignObject元素大小
|
||||
this.group.findOne('foreignObject').size(width, height)
|
||||
}
|
||||
|
||||
// 定位节点内容
|
||||
function layout() {
|
||||
if (!this.group) return
|
||||
// 清除之前的内容
|
||||
this.group.clear()
|
||||
const {
|
||||
hoverRectPadding,
|
||||
openRealtimeRenderOnNodeTextEdit,
|
||||
textContentMargin,
|
||||
addCustomContentToNode
|
||||
@@ -217,16 +260,6 @@ function layout() {
|
||||
if (this.isGeneralization && this.generalizationBelongNode) {
|
||||
this.group.addClass('generalization_' + this.generalizationBelongNode.uid)
|
||||
}
|
||||
// 激活hover和激活边框
|
||||
const addHoverNode = () => {
|
||||
this.hoverNode = new Rect()
|
||||
.size(width + hoverRectPadding * 2, height + hoverRectPadding * 2)
|
||||
.x(-hoverRectPadding)
|
||||
.y(-hoverRectPadding)
|
||||
this.hoverNode.addClass('smm-hover-node')
|
||||
this.style.hoverNode(this.hoverNode, width, height)
|
||||
this.group.add(this.hoverNode)
|
||||
}
|
||||
// 如果存在自定义节点内容,那么使用自定义节点内容
|
||||
if (this.isUseCustomNodeContent()) {
|
||||
const foreignObject = createForeignObjectNode({
|
||||
@@ -235,7 +268,7 @@ function layout() {
|
||||
height
|
||||
})
|
||||
this.group.add(foreignObject)
|
||||
addHoverNode()
|
||||
this.addHoverNode(width, height)
|
||||
return
|
||||
}
|
||||
const { IMG_PLACEMENT, TAG_PLACEMENT } = CONSTANTS
|
||||
@@ -453,7 +486,7 @@ function layout() {
|
||||
break
|
||||
}
|
||||
textContentNested.translate(translateX, translateY)
|
||||
addHoverNode()
|
||||
this.addHoverNode(width, height)
|
||||
if (this._customContentAddToNodeAdd && this._customContentAddToNodeAdd.el) {
|
||||
const foreignObject = createForeignObjectNode(
|
||||
this._customContentAddToNodeAdd
|
||||
@@ -477,5 +510,7 @@ export default {
|
||||
getImgTextMarin,
|
||||
getTagContentSize,
|
||||
getNodeRect,
|
||||
layout
|
||||
addHoverNode,
|
||||
layout,
|
||||
customNodeContentRealtimeLayout
|
||||
}
|
||||
|
||||
@@ -174,7 +174,8 @@ class Base {
|
||||
isResizeSource ||
|
||||
isNodeDataChange ||
|
||||
isLayerTypeChange ||
|
||||
newNode.getData('resetRichText') ||
|
||||
(newNode.getData('resetRichText') && // 自定义节点内容可以直接忽略resetRichText
|
||||
!newNode.isUseCustomNodeContent()) ||
|
||||
newNode.getData('needUpdate') ||
|
||||
isNodeInnerFixChange
|
||||
) {
|
||||
@@ -224,7 +225,8 @@ class Base {
|
||||
isResizeSource ||
|
||||
isNodeDataChange ||
|
||||
isLayerTypeChange ||
|
||||
newNode.getData('resetRichText') ||
|
||||
(newNode.getData('resetRichText') &&
|
||||
!newNode.isUseCustomNodeContent()) ||
|
||||
newNode.getData('needUpdate') ||
|
||||
isNodeInnerFixChange
|
||||
) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { fromMarkdown } from 'mdast-util-from-markdown'
|
||||
|
||||
const getNodeText = node => {
|
||||
if (node.type === 'list') return ''
|
||||
let textStr = ''
|
||||
|
||||
;(node.children || []).forEach(item => {
|
||||
|
||||
@@ -43,6 +43,18 @@ class Demonstrate {
|
||||
this.mindMap.opt.demonstrateConfig || {}
|
||||
)
|
||||
this.needRestorePerformanceMode = false
|
||||
this.onConfigUpdate = this.onConfigUpdate.bind(this)
|
||||
this.mindMap.on('after_update_config', this.onConfigUpdate)
|
||||
}
|
||||
|
||||
// 监听配置更新
|
||||
onConfigUpdate(opt) {
|
||||
if (typeof opt.demonstrateConfig !== 'undefined') {
|
||||
this.config = {
|
||||
...this.config,
|
||||
...opt.demonstrateConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 进入演示模式
|
||||
@@ -417,11 +429,13 @@ class Demonstrate {
|
||||
// 插件被移除前做的事情
|
||||
beforePluginRemove() {
|
||||
this.unBindEvent()
|
||||
this.mindMap.off('after_update_config', this.onConfigUpdate)
|
||||
}
|
||||
|
||||
// 插件被卸载前做的事情
|
||||
beforePluginDestroy() {
|
||||
this.unBindEvent()
|
||||
this.mindMap.off('after_update_config', this.onConfigUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,6 +144,7 @@ class Export {
|
||||
try {
|
||||
const canvas = document.createElement('canvas')
|
||||
const dpr = Math.max(window.devicePixelRatio, minExportImgCanvasScale)
|
||||
// 图片原始大小
|
||||
let imgWidth = img.width
|
||||
let imgHeight = img.height
|
||||
// 如果是裁减操作的话,那么需要手动添加内边距,及调整图片大小为实际的裁减区域的大小,不要忘了内边距哦
|
||||
@@ -184,6 +185,8 @@ class Export {
|
||||
}
|
||||
// 检查是否超出canvas支持的像素上限
|
||||
// canvas大小需要乘以dpr
|
||||
let scaleX = 1
|
||||
let scaleY = 1
|
||||
let canvasWidth = (fitBgImgWidth || imgWidth) * dpr
|
||||
let canvasHeight = (fitBgImgHeight || imgHeight) * dpr
|
||||
if (canvasWidth > maxCanvasSize || canvasHeight > maxCanvasSize) {
|
||||
@@ -203,6 +206,8 @@ class Export {
|
||||
newWidth,
|
||||
newHeight
|
||||
)
|
||||
scaleX = res[0] / canvasWidth
|
||||
scaleY = res[1] / canvasHeight
|
||||
canvasWidth = res[0]
|
||||
canvasHeight = res[1]
|
||||
}
|
||||
@@ -210,6 +215,7 @@ class Export {
|
||||
canvas.height = canvasHeight
|
||||
const styleWidth = canvasWidth / dpr
|
||||
const styleHeight = canvasHeight / dpr
|
||||
// canvas元素实际上的大小
|
||||
canvas.style.width = styleWidth + 'px'
|
||||
canvas.style.height = styleHeight + 'px'
|
||||
const ctx = canvas.getContext('2d')
|
||||
@@ -221,9 +227,9 @@ class Export {
|
||||
// 图片绘制到canvas里
|
||||
// 如果有裁减数据,那么需要进行裁减
|
||||
const fitBgLeft =
|
||||
fitBgImgWidth > 0 ? (fitBgImgWidth - imgWidth) / 2 : 0
|
||||
(fitBgImgWidth > 0 ? (fitBgImgWidth - imgWidth) / 2 : 0) * scaleX
|
||||
const fitBgTop =
|
||||
fitBgImgHeight > 0 ? (fitBgImgHeight - imgHeight) / 2 : 0
|
||||
(fitBgImgHeight > 0 ? (fitBgImgHeight - imgHeight) / 2 : 0) * scaleY
|
||||
if (clipData) {
|
||||
ctx.drawImage(
|
||||
img,
|
||||
@@ -231,13 +237,19 @@ class Export {
|
||||
clipData.top,
|
||||
clipData.width,
|
||||
clipData.height,
|
||||
paddingX + fitBgLeft,
|
||||
paddingY + fitBgTop,
|
||||
clipData.width,
|
||||
clipData.height
|
||||
paddingX * scaleX + fitBgLeft,
|
||||
paddingY * scaleY + fitBgTop,
|
||||
clipData.width * scaleX,
|
||||
clipData.height * scaleY
|
||||
)
|
||||
} else {
|
||||
ctx.drawImage(img, fitBgLeft, fitBgTop, imgWidth, imgHeight)
|
||||
ctx.drawImage(
|
||||
img,
|
||||
fitBgLeft,
|
||||
fitBgTop,
|
||||
imgWidth * scaleX,
|
||||
imgHeight * scaleY
|
||||
)
|
||||
}
|
||||
resolve(canvas.toDataURL(format))
|
||||
} catch (error) {
|
||||
|
||||
@@ -491,7 +491,10 @@ class RichText {
|
||||
})
|
||||
this.quill.on('selection-change', range => {
|
||||
// 刚创建的节点全选不需要显示操作条
|
||||
if (this.isInserting) return
|
||||
if (this.isInserting) {
|
||||
this.isInserting = false
|
||||
return
|
||||
}
|
||||
this.lastRange = this.range
|
||||
this.range = null
|
||||
if (range) {
|
||||
|
||||
11
web/package-lock.json
generated
@@ -15699,8 +15699,7 @@
|
||||
"node_modules/viewerjs": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/viewerjs/-/viewerjs-1.11.6.tgz",
|
||||
"integrity": "sha512-TlhdSp2oEOLFXvEp4psKaeTjR5zBjTRcM/sHUN8PkV1UWuY8HKC8n7GaVdW5Xqnwdr/F1OmzLik1QwDjI4w/nw==",
|
||||
"peer": true
|
||||
"integrity": "sha512-TlhdSp2oEOLFXvEp4psKaeTjR5zBjTRcM/sHUN8PkV1UWuY8HKC8n7GaVdW5Xqnwdr/F1OmzLik1QwDjI4w/nw=="
|
||||
},
|
||||
"node_modules/vm-browserify": {
|
||||
"version": "1.1.2",
|
||||
@@ -19258,6 +19257,7 @@
|
||||
"integrity": "sha512-VCNRiAt2P/bLo09rYt3DLe6xXUMlhJwrvU18Ddd/lYJgC7s8+wvhgYs+MTx4OiAXdu58drGwSBO9SPx7C6J82Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/core": "^7.11.0",
|
||||
"@babel/helper-compilation-targets": "^7.9.6",
|
||||
"@babel/helper-module-imports": "^7.8.3",
|
||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||
@@ -19270,6 +19270,7 @@
|
||||
"@vue/babel-plugin-jsx": "^1.0.3",
|
||||
"@vue/babel-preset-jsx": "^1.2.4",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"core-js": "^3.6.5",
|
||||
"core-js-compat": "^3.6.5",
|
||||
"semver": "^6.1.0"
|
||||
}
|
||||
@@ -29565,7 +29566,8 @@
|
||||
"resolved": "https://registry.npmjs.org/v-viewer/-/v-viewer-1.7.4.tgz",
|
||||
"integrity": "sha512-K3PQ8utnVXXBCa5IRXRAhk/m83fNIsK77gTSXqAmPJe8eDTaSY1nifAOWPUmQDjzuCxYfa14UjGftHR9MFV70Q==",
|
||||
"requires": {
|
||||
"lodash-es": "^4.17.21"
|
||||
"lodash-es": "^4.17.21",
|
||||
"viewerjs": "^1.11.6"
|
||||
}
|
||||
},
|
||||
"v8-compile-cache": {
|
||||
@@ -29630,8 +29632,7 @@
|
||||
"viewerjs": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/viewerjs/-/viewerjs-1.11.6.tgz",
|
||||
"integrity": "sha512-TlhdSp2oEOLFXvEp4psKaeTjR5zBjTRcM/sHUN8PkV1UWuY8HKC8n7GaVdW5Xqnwdr/F1OmzLik1QwDjI4w/nw==",
|
||||
"peer": true
|
||||
"integrity": "sha512-TlhdSp2oEOLFXvEp4psKaeTjR5zBjTRcM/sHUN8PkV1UWuY8HKC8n7GaVdW5Xqnwdr/F1OmzLik1QwDjI4w/nw=="
|
||||
},
|
||||
"vm-browserify": {
|
||||
"version": "1.1.2",
|
||||
|
||||
@@ -1,53 +1,81 @@
|
||||
const express = require('express')
|
||||
const axios = require('axios')
|
||||
const net = require('net')
|
||||
|
||||
const port = 3456
|
||||
|
||||
// 起个服务
|
||||
const app = express()
|
||||
app.use(express.json())
|
||||
app.use(express.urlencoded({ extended: true }))
|
||||
|
||||
// 允许跨域
|
||||
app.use((req, res, next) => {
|
||||
res.header('Access-Control-Allow-Origin', '*') // 允许所有来源的跨域请求,或者指定一个域名
|
||||
res.header('Access-Control-Allow-Methods', '*') // 允许的方法
|
||||
res.header('Access-Control-Allow-Headers', '*') // 允许的头部信息
|
||||
next()
|
||||
})
|
||||
|
||||
// 监听对话请求
|
||||
app.get('/ai/test', (req, res) => {
|
||||
res
|
||||
.json({
|
||||
code: 0,
|
||||
data: null,
|
||||
msg: '连接成功'
|
||||
const isPortUsed = port => {
|
||||
return new Promise(resolve => {
|
||||
const server = net.createServer()
|
||||
server.once('error', err => {
|
||||
if (err.code === 'EADDRINUSE') {
|
||||
resolve(true) // 端口被占用
|
||||
} else {
|
||||
resolve(false) // 其他错误
|
||||
}
|
||||
})
|
||||
.end()
|
||||
})
|
||||
app.post('/ai/chat', async (req, res, next) => {
|
||||
// 设置SSE响应头
|
||||
res.setHeader('Content-Type', 'text/event-stream')
|
||||
res.setHeader('Cache-Control', 'no-cache')
|
||||
res.setHeader('Connection', 'keep-alive')
|
||||
|
||||
const { api, method = 'POST', headers = {}, data } = req.body
|
||||
|
||||
try {
|
||||
const response = await axios({
|
||||
url: api,
|
||||
method,
|
||||
headers,
|
||||
data,
|
||||
responseType: 'stream'
|
||||
server.once('listening', () => {
|
||||
server.close(() => resolve(false)) // 端口可用
|
||||
})
|
||||
response.data.pipe(res)
|
||||
} catch (error) {
|
||||
next(error)
|
||||
server.listen(port) // 尝试监听端口
|
||||
})
|
||||
}
|
||||
|
||||
const createServe = () => {
|
||||
// 起个服务
|
||||
const app = express()
|
||||
app.use(express.json())
|
||||
app.use(express.urlencoded({ extended: true }))
|
||||
|
||||
// 允许跨域
|
||||
app.use((req, res, next) => {
|
||||
res.header('Access-Control-Allow-Origin', '*') // 允许所有来源的跨域请求,或者指定一个域名
|
||||
res.header('Access-Control-Allow-Methods', '*') // 允许的方法
|
||||
res.header('Access-Control-Allow-Headers', '*') // 允许的头部信息
|
||||
next()
|
||||
})
|
||||
|
||||
// 监听对话请求
|
||||
app.get('/ai/test', (req, res) => {
|
||||
res
|
||||
.json({
|
||||
code: 0,
|
||||
data: null,
|
||||
msg: '连接成功'
|
||||
})
|
||||
.end()
|
||||
})
|
||||
app.post('/ai/chat', async (req, res, next) => {
|
||||
// 设置SSE响应头
|
||||
res.setHeader('Content-Type', 'text/event-stream')
|
||||
res.setHeader('Cache-Control', 'no-cache')
|
||||
res.setHeader('Connection', 'keep-alive')
|
||||
|
||||
const { api, method = 'POST', headers = {}, data } = req.body
|
||||
|
||||
try {
|
||||
const response = await axios({
|
||||
url: api,
|
||||
method,
|
||||
headers,
|
||||
data,
|
||||
responseType: 'stream'
|
||||
})
|
||||
response.data.pipe(res)
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`app listening on port ${port}`)
|
||||
})
|
||||
}
|
||||
|
||||
isPortUsed(port).then(isUsed => {
|
||||
if (isUsed) {
|
||||
console.error('端口被占用')
|
||||
} else {
|
||||
createServe()
|
||||
}
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`app listening on port ${port}`)
|
||||
})
|
||||
|
||||
@@ -10,7 +10,7 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style lang="less">
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -18,8 +18,6 @@ export default {
|
||||
}
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
@@ -41,4 +39,8 @@ export default {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.el-dialog{
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
BIN
web/src/assets/avatar/行.jpg
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
web/src/assets/img/foramt/1.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
web/src/assets/img/foramt/10.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
web/src/assets/img/foramt/2.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
web/src/assets/img/foramt/3.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
web/src/assets/img/foramt/4.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
web/src/assets/img/foramt/5.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
web/src/assets/img/foramt/6.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
web/src/assets/img/foramt/7.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
web/src/assets/img/foramt/8.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
web/src/assets/img/foramt/9.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
web/src/assets/img/gzh.jpeg
Normal file
|
After Width: | Height: | Size: 39 KiB |
@@ -439,38 +439,32 @@ export const sidebarTriggerList = [
|
||||
value: 'outline',
|
||||
icon: 'iconfuhao-dagangshu'
|
||||
},
|
||||
// {
|
||||
// name: 'AI',
|
||||
// value: 'ai',
|
||||
// icon: 'iconAIshengcheng'
|
||||
// },
|
||||
{
|
||||
name: 'Setting',
|
||||
value: 'setting',
|
||||
icon: 'iconshezhi'
|
||||
},
|
||||
{
|
||||
name: 'AI',
|
||||
value: 'ai',
|
||||
icon: 'iconAIshengcheng'
|
||||
},
|
||||
{
|
||||
name: 'ShortcutKey',
|
||||
value: 'shortcutKey',
|
||||
icon: 'iconjianpan'
|
||||
}
|
||||
// {
|
||||
// name: 'ShortcutKey',
|
||||
// value: 'shortcutKey',
|
||||
// icon: 'iconjianpan'
|
||||
// }
|
||||
]
|
||||
|
||||
// 下载类型列表
|
||||
export const downTypeList = [
|
||||
{
|
||||
name: 'Dedicated file',
|
||||
name: '思绪 file',
|
||||
type: 'smm',
|
||||
icon: 'iconwenjian',
|
||||
desc:
|
||||
'SimpleMindMap private format, can be used for re import, and the client can directly edit it'
|
||||
},
|
||||
{
|
||||
name: 'JSON',
|
||||
type: 'json',
|
||||
icon: 'iconjson',
|
||||
desc: 'Popular data exchange format that can be used for re importing'
|
||||
},
|
||||
{
|
||||
name: 'Image',
|
||||
type: 'png',
|
||||
@@ -507,6 +501,12 @@ export const downTypeList = [
|
||||
icon: 'iconTXT',
|
||||
desc: 'Plain text file'
|
||||
},
|
||||
{
|
||||
name: 'Excel',
|
||||
type: 'xlsx',
|
||||
icon: 'iconfile-excel',
|
||||
desc: 'Table text format, editable with Excel software'
|
||||
},
|
||||
{
|
||||
name: 'FreeMind',
|
||||
type: 'mm',
|
||||
@@ -514,11 +514,11 @@ export const downTypeList = [
|
||||
desc: 'FreeMind software format'
|
||||
},
|
||||
{
|
||||
name: 'Excel',
|
||||
type: 'xlsx',
|
||||
icon: 'iconfile-excel',
|
||||
desc: 'Table text format, editable with Excel software'
|
||||
}
|
||||
name: 'JSON',
|
||||
type: 'json',
|
||||
icon: 'iconjson',
|
||||
desc: 'Popular data exchange format that can be used for re importing'
|
||||
},
|
||||
]
|
||||
|
||||
// 编号类型列表
|
||||
@@ -672,13 +672,11 @@ export const layoutGroupList = [
|
||||
list: [
|
||||
'timeline',
|
||||
'timeline2',
|
||||
'verticalTimeline2',
|
||||
'verticalTimeline3',
|
||||
'verticalTimeline'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Fishbone',
|
||||
list: ['fishbone', 'fishbone2', 'rightFishbone', 'rightFishbone2']
|
||||
list: ['fishbone']
|
||||
}
|
||||
]
|
||||
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
lineHeightList,
|
||||
store,
|
||||
langList,
|
||||
shapeListMap,
|
||||
lineStyleMap,
|
||||
fontFamilyList as fontFamilyListZh,
|
||||
borderDasharrayList as borderDasharrayListZh,
|
||||
lineStyleList as lineStyleListZh,
|
||||
@@ -18,8 +20,6 @@ import {
|
||||
sidebarTriggerList as sidebarTriggerListZh,
|
||||
backgroundSizeList as backgroundSizeListZh,
|
||||
downTypeList as downTypeListZh,
|
||||
shapeListMap as shapeListMapZh,
|
||||
lineStyleMap as lineStyleMapZh,
|
||||
numberTypeList as numberTypeListZh,
|
||||
numberLevelList as numberLevelListZh,
|
||||
linearGradientDirList as linearGradientDirListZh,
|
||||
@@ -62,113 +62,135 @@ import {
|
||||
alignList as alignListZhtw,
|
||||
layoutGroupList as layoutGroupListZhtw
|
||||
} from './zhtw'
|
||||
import {
|
||||
fontFamilyList as fontFamilyListVi,
|
||||
borderDasharrayList as borderDasharrayListVi,
|
||||
lineStyleList as lineStyleListVi,
|
||||
rootLineKeepSameInCurveList as rootLineKeepSameInCurveListVi,
|
||||
backgroundRepeatList as backgroundRepeatListVi,
|
||||
backgroundPositionList as backgroundPositionListVi,
|
||||
shortcutKeyList as shortcutKeyListVi,
|
||||
shapeList as shapeListVi,
|
||||
sidebarTriggerList as sidebarTriggerListVi,
|
||||
backgroundSizeList as backgroundSizeListVi,
|
||||
downTypeList as downTypeListVi,
|
||||
numberTypeList as numberTypeListVi,
|
||||
numberLevelList as numberLevelListVi,
|
||||
linearGradientDirList as linearGradientDirListVi,
|
||||
alignList as alignListVi,
|
||||
layoutGroupList as layoutGroupListVi
|
||||
} from './vi'
|
||||
|
||||
const fontFamilyList = {
|
||||
zh: fontFamilyListZh,
|
||||
en: fontFamilyListEn,
|
||||
zhtw: fontFamilyListZhtw
|
||||
zhtw: fontFamilyListZhtw,
|
||||
vi: fontFamilyListVi
|
||||
}
|
||||
|
||||
const borderDasharrayList = {
|
||||
zh: borderDasharrayListZh,
|
||||
en: borderDasharrayListEn,
|
||||
zhtw: borderDasharrayListZhtw
|
||||
zhtw: borderDasharrayListZhtw,
|
||||
vi: borderDasharrayListVi
|
||||
}
|
||||
|
||||
const lineStyleList = {
|
||||
zh: lineStyleListZh,
|
||||
en: lineStyleListEn,
|
||||
zhtw: lineStyleListZhtw
|
||||
}
|
||||
|
||||
const lineStyleMap = {
|
||||
zh: lineStyleMapZh,
|
||||
en: lineStyleMapZh,
|
||||
zhtw: lineStyleMapZh
|
||||
zhtw: lineStyleListZhtw,
|
||||
vi: lineStyleListVi
|
||||
}
|
||||
|
||||
const rootLineKeepSameInCurveList = {
|
||||
zh: rootLineKeepSameInCurveListZh,
|
||||
en: rootLineKeepSameInCurveListEn,
|
||||
zhtw: rootLineKeepSameInCurveListZhtw
|
||||
zhtw: rootLineKeepSameInCurveListZhtw,
|
||||
vi: rootLineKeepSameInCurveListVi
|
||||
}
|
||||
|
||||
const backgroundRepeatList = {
|
||||
zh: backgroundRepeatListZh,
|
||||
en: backgroundRepeatListEn,
|
||||
zhtw: backgroundRepeatListZhtw
|
||||
zhtw: backgroundRepeatListZhtw,
|
||||
vi: backgroundRepeatListVi
|
||||
}
|
||||
|
||||
const backgroundPositionList = {
|
||||
zh: backgroundPositionListZh,
|
||||
en: backgroundPositionListEn,
|
||||
zhtw: backgroundPositionListZhtw
|
||||
zhtw: backgroundPositionListZhtw,
|
||||
vi: backgroundPositionListVi
|
||||
}
|
||||
|
||||
const backgroundSizeList = {
|
||||
zh: backgroundSizeListZh,
|
||||
en: backgroundSizeListEn,
|
||||
zhtw: backgroundSizeListZhtw
|
||||
zhtw: backgroundSizeListZhtw,
|
||||
vi: backgroundSizeListVi
|
||||
}
|
||||
|
||||
const shortcutKeyList = {
|
||||
zh: shortcutKeyListZh,
|
||||
en: shortcutKeyListEn,
|
||||
zhtw: shortcutKeyListZhtw
|
||||
zhtw: shortcutKeyListZhtw,
|
||||
vi: shortcutKeyListVi
|
||||
}
|
||||
|
||||
const shapeList = {
|
||||
zh: shapeListZh,
|
||||
en: shapeListEn,
|
||||
zhtw: shapeListZhtw
|
||||
}
|
||||
|
||||
const shapeListMap = {
|
||||
zh: shapeListMapZh,
|
||||
en: shapeListMapZh,
|
||||
zhtw: shapeListMapZh
|
||||
zhtw: shapeListZhtw,
|
||||
vi: shapeListVi
|
||||
}
|
||||
|
||||
const sidebarTriggerList = {
|
||||
zh: sidebarTriggerListZh,
|
||||
en: sidebarTriggerListEn,
|
||||
zhtw: sidebarTriggerListZhtw
|
||||
zhtw: sidebarTriggerListZhtw,
|
||||
vi: sidebarTriggerListVi
|
||||
}
|
||||
|
||||
const downTypeList = {
|
||||
zh: downTypeListZh,
|
||||
en: downTypeListEn,
|
||||
zhtw: downTypeListZhtw
|
||||
zhtw: downTypeListZhtw,
|
||||
vi: downTypeListVi
|
||||
}
|
||||
|
||||
const numberTypeList = {
|
||||
zh: numberTypeListZh,
|
||||
en: numberTypeListEn,
|
||||
zhtw: numberTypeListZhtw
|
||||
zhtw: numberTypeListZhtw,
|
||||
vi: numberTypeListVi
|
||||
}
|
||||
|
||||
const numberLevelList = {
|
||||
zh: numberLevelListZh,
|
||||
en: numberLevelListEn,
|
||||
zhtw: numberLevelListZhtw
|
||||
zhtw: numberLevelListZhtw,
|
||||
vi: numberLevelListVi
|
||||
}
|
||||
|
||||
const linearGradientDirList = {
|
||||
zh: linearGradientDirListZh,
|
||||
en: linearGradientDirListEn,
|
||||
zhtw: linearGradientDirListZhtw
|
||||
zhtw: linearGradientDirListZhtw,
|
||||
vi: linearGradientDirListVi
|
||||
}
|
||||
|
||||
const alignList = {
|
||||
zh: alignListZh,
|
||||
en: alignListEn,
|
||||
zhtw: alignListZhtw
|
||||
zhtw: alignListZhtw,
|
||||
vi: alignListVi
|
||||
}
|
||||
|
||||
const layoutGroupList = {
|
||||
zh: layoutGroupListZh,
|
||||
en: layoutGroupListEn,
|
||||
zhtw: layoutGroupListZhtw
|
||||
zhtw: layoutGroupListZhtw,
|
||||
vi: layoutGroupListVi
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
705
web/src/config/vi.js
Normal file
@@ -0,0 +1,705 @@
|
||||
// Danh sách phông chữ
|
||||
export const fontFamilyList = [
|
||||
{
|
||||
name: 'Song Thân',
|
||||
value: '宋体, SimSun, Songti SC'
|
||||
},
|
||||
{
|
||||
name: 'Microsoft và Yahoo',
|
||||
value: '微软雅黑, Microsoft YaHei'
|
||||
},
|
||||
{
|
||||
name: 'Chữ Khải',
|
||||
value: '楷体, 楷体_GB2312, SimKai, STKaiti'
|
||||
},
|
||||
{
|
||||
name: 'Da đen',
|
||||
value: '黑体, SimHei, Heiti SC'
|
||||
},
|
||||
{
|
||||
name: 'Lệ Thư',
|
||||
value: '隶书, SimLi'
|
||||
},
|
||||
{
|
||||
name: 'Andale Mono',
|
||||
value: 'andale mono'
|
||||
},
|
||||
{
|
||||
name: 'Arial',
|
||||
value: 'arial, helvetica, sans-serif'
|
||||
},
|
||||
{
|
||||
name: 'arialBlack',
|
||||
value: 'arial black, avant garde'
|
||||
},
|
||||
{
|
||||
name: 'Comic Sans Ms',
|
||||
value: 'comic sans ms'
|
||||
},
|
||||
{
|
||||
name: 'Impact',
|
||||
value: 'impact, chicago'
|
||||
},
|
||||
{
|
||||
name: 'Times New Roman',
|
||||
value: 'times new roman'
|
||||
},
|
||||
{
|
||||
name: 'Sans-Serif',
|
||||
value: 'sans-serif'
|
||||
},
|
||||
{
|
||||
name: 'serif',
|
||||
value: 'serif'
|
||||
}
|
||||
]
|
||||
|
||||
// Kiểu viền
|
||||
export const borderDasharrayList = [
|
||||
{
|
||||
name: 'Dòng rắn',
|
||||
value: 'none'
|
||||
},
|
||||
{
|
||||
name: 'Đường chấm 1',
|
||||
value: '5,5'
|
||||
},
|
||||
{
|
||||
name: 'Đường chấm 2',
|
||||
value: '10,10'
|
||||
},
|
||||
{
|
||||
name: 'Đường chấm 3',
|
||||
value: '20,10,5,5,5,10'
|
||||
},
|
||||
{
|
||||
name: 'Đường chấm 4',
|
||||
value: '5,5,1,5'
|
||||
},
|
||||
{
|
||||
name: 'Đường chấm 5',
|
||||
value: '15,10,5,10,15'
|
||||
},
|
||||
{
|
||||
name: 'Đường chấm 6',
|
||||
value: '1,5'
|
||||
},
|
||||
{
|
||||
name: 'Đường chấm 7',
|
||||
value: '6,4'
|
||||
}
|
||||
]
|
||||
|
||||
// Kiểu kết nối
|
||||
export const lineStyleList = [
|
||||
{
|
||||
name: 'Đường thẳng',
|
||||
value: 'straight'
|
||||
},
|
||||
{
|
||||
name: 'Đường cong',
|
||||
value: 'curve'
|
||||
},
|
||||
{
|
||||
name: 'Trực tiếp',
|
||||
value: 'direct'
|
||||
}
|
||||
]
|
||||
|
||||
// Trong một kiểu đường cong, kiểu nút gốc có giống với các nút khác hay không
|
||||
export const rootLineKeepSameInCurveList = [
|
||||
{
|
||||
name: 'ngoặc đơn',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: 'ngoặc nhọn',
|
||||
value: true
|
||||
}
|
||||
]
|
||||
|
||||
// Cách lặp lại hình ảnh
|
||||
export const backgroundRepeatList = [
|
||||
{
|
||||
name: 'Không lặp lại',
|
||||
value: 'no-repeat'
|
||||
},
|
||||
{
|
||||
name: 'Lặp lại',
|
||||
value: 'repeat'
|
||||
},
|
||||
{
|
||||
name: 'Lặp lại hướng ngang',
|
||||
value: 'repeat-x'
|
||||
},
|
||||
{
|
||||
name: 'Lặp lại theo chiều dọc',
|
||||
value: 'repeat-y'
|
||||
}
|
||||
]
|
||||
|
||||
// Định vị ảnh nền
|
||||
export const backgroundPositionList = [
|
||||
{
|
||||
name: 'Mặc định',
|
||||
value: '0% 0%'
|
||||
},
|
||||
{
|
||||
name: 'Trái trên',
|
||||
value: 'left top'
|
||||
},
|
||||
{
|
||||
name: 'Trái giữa',
|
||||
value: 'left center'
|
||||
},
|
||||
{
|
||||
name: 'Trái dưới',
|
||||
value: 'left bottom'
|
||||
},
|
||||
{
|
||||
name: 'Phải trên',
|
||||
value: 'right top'
|
||||
},
|
||||
{
|
||||
name: 'Phải giữa',
|
||||
value: 'right center'
|
||||
},
|
||||
{
|
||||
name: 'Dưới bên phải',
|
||||
value: 'right bottom'
|
||||
},
|
||||
{
|
||||
name: 'Giữa trên',
|
||||
value: 'center top'
|
||||
},
|
||||
{
|
||||
name: 'Ở giữa',
|
||||
value: 'center center'
|
||||
},
|
||||
{
|
||||
name: 'Dưới',
|
||||
value: 'center bottom'
|
||||
}
|
||||
]
|
||||
|
||||
// Cỡ ảnh nền
|
||||
export const backgroundSizeList = [
|
||||
{
|
||||
name: 'Tự động',
|
||||
value: 'auto'
|
||||
},
|
||||
{
|
||||
name: 'Ghi đè',
|
||||
value: 'cover'
|
||||
},
|
||||
{
|
||||
name: 'Giữ',
|
||||
value: 'contain'
|
||||
}
|
||||
]
|
||||
|
||||
// Lưu trữ dữ liệu
|
||||
export const store = {
|
||||
sidebarZIndex: 1 //Thanh bên zIndex
|
||||
}
|
||||
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0
|
||||
const ctrl = isMac ? '⌘' : 'Ctrl'
|
||||
const enter = isMac ? 'Return' : 'Enter'
|
||||
const macFn = isMac ? 'fn + ' : ''
|
||||
|
||||
// Danh sách phím tắt
|
||||
export const shortcutKeyList = [
|
||||
{
|
||||
type: 'Hoạt động nút',
|
||||
list: [
|
||||
{
|
||||
icon: 'icontianjiazijiedian',
|
||||
name: 'Chèn nút thấp hơn',
|
||||
value: 'Tab | Insert'
|
||||
},
|
||||
{
|
||||
icon: 'iconjiedian',
|
||||
name: 'Chèn nút ngang hàng',
|
||||
value: enter
|
||||
},
|
||||
{
|
||||
icon: 'icondodeparent',
|
||||
name: 'Chèn nút cha',
|
||||
value: 'Shift + Tab'
|
||||
},
|
||||
{
|
||||
icon: 'iconshangyi',
|
||||
name: 'Chuyển nút lên',
|
||||
value: `${ctrl} + ↑`
|
||||
},
|
||||
{
|
||||
icon: 'iconxiayi',
|
||||
name: 'Di chuyển nút xuống',
|
||||
value: `${ctrl} + ↓`
|
||||
},
|
||||
{
|
||||
icon: 'icongaikuozonglan',
|
||||
name: 'Chèn tóm tắt',
|
||||
value: `${ctrl} + G`
|
||||
},
|
||||
{
|
||||
icon: 'iconzhankai',
|
||||
name: 'Mở rộng/thu gọn các nút',
|
||||
value: '/'
|
||||
},
|
||||
{
|
||||
icon: 'iconshanchu',
|
||||
name: 'Xóa nút',
|
||||
value: 'Delete | Backspace'
|
||||
},
|
||||
{
|
||||
icon: 'iconshanchu',
|
||||
name: 'Chỉ xóa nút hiện tại',
|
||||
value: 'Shift + Backspace'
|
||||
},
|
||||
{
|
||||
icon: 'iconfuzhi',
|
||||
name: 'Sao chép nút',
|
||||
value: `${ctrl} + C`
|
||||
},
|
||||
{
|
||||
icon: 'iconjianqie',
|
||||
name: 'Cắt nút',
|
||||
value: `${ctrl} + X`
|
||||
},
|
||||
{
|
||||
icon: 'iconniantie',
|
||||
name: 'Dán nút',
|
||||
value: `${ctrl} + V`
|
||||
},
|
||||
{
|
||||
icon: 'iconbianji',
|
||||
name: 'Sửa nút',
|
||||
value: macFn + 'F2'
|
||||
},
|
||||
{
|
||||
icon: 'iconhuanhang',
|
||||
name: 'Dòng mới',
|
||||
value: `Shift + ${enter}`
|
||||
},
|
||||
{
|
||||
icon: 'iconhoutui-shi',
|
||||
name: 'Lùi lại',
|
||||
value: `${ctrl} + Z`
|
||||
},
|
||||
{
|
||||
icon: 'iconqianjin1',
|
||||
name: 'Tiến lên!',
|
||||
value: `${ctrl} + Y`
|
||||
},
|
||||
{
|
||||
icon: 'iconquanxuan',
|
||||
name: 'Chọn tất cả',
|
||||
value: `${ctrl} + A`
|
||||
},
|
||||
{
|
||||
icon: 'iconquanxuan',
|
||||
name: 'Nhiều lựa chọn',
|
||||
value: `Phải / ${ctrl} + Trái`
|
||||
},
|
||||
{
|
||||
icon: 'iconzhengli',
|
||||
name: 'Name',
|
||||
value: `${ctrl} + L`
|
||||
},
|
||||
{
|
||||
icon: 'iconsousuo',
|
||||
name: 'Tìm kiếm và thay thế',
|
||||
value: `${ctrl} + F`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'Hoạt động Canvas',
|
||||
list: [
|
||||
{
|
||||
icon: 'iconfangda',
|
||||
name: 'Phóng to',
|
||||
value: `${ctrl} + +`
|
||||
},
|
||||
{
|
||||
icon: 'iconsuoxiao',
|
||||
name: 'Thu nhỏ',
|
||||
value: `${ctrl} + -`
|
||||
},
|
||||
{
|
||||
icon: 'iconfangda',
|
||||
name: 'Phóng to/Thu nhỏ',
|
||||
value: `${ctrl} + Cuộn chuột`
|
||||
},
|
||||
{
|
||||
icon: 'icondingwei',
|
||||
name: 'Trở lại Root Node',
|
||||
value: `${ctrl} + ${enter}`
|
||||
},
|
||||
{
|
||||
icon: 'iconquanping1',
|
||||
name: 'Thích nghi với Canvas',
|
||||
value: `${ctrl} + i`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'Hoạt động phác thảo',
|
||||
list: [
|
||||
{
|
||||
icon: 'iconhuanhang',
|
||||
name: 'Dòng mới',
|
||||
value: `Shift + ${enter}`
|
||||
},
|
||||
{
|
||||
icon: 'iconshanchu',
|
||||
name: 'Xóa nút',
|
||||
value: 'Delete'
|
||||
},
|
||||
{
|
||||
icon: 'icontianjiazijiedian',
|
||||
name: 'Chèn nút thấp hơn',
|
||||
value: 'Tab'
|
||||
},
|
||||
{
|
||||
icon: 'iconjiedian',
|
||||
name: 'Chèn nút ngang hàng',
|
||||
value: enter
|
||||
},
|
||||
{
|
||||
icon: 'icondodeparent',
|
||||
name: 'Di chuyển lên một cấp',
|
||||
value: 'Shift + Tab'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// Danh sách hình dạng
|
||||
export const shapeList = [
|
||||
{
|
||||
name: 'Hình chữ nhật',
|
||||
value: 'rectangle'
|
||||
},
|
||||
{
|
||||
name: 'Kim cương',
|
||||
value: 'diamond'
|
||||
},
|
||||
{
|
||||
name: 'Tứ giác song song',
|
||||
value: 'parallelogram'
|
||||
},
|
||||
{
|
||||
name: 'Hình chữ nhật tròn',
|
||||
value: 'roundedRectangle'
|
||||
},
|
||||
{
|
||||
name: 'Hình chữ nhật bát giác',
|
||||
value: 'octagonalRectangle'
|
||||
},
|
||||
{
|
||||
name: 'Hình chữ nhật tam giác ngoài',
|
||||
value: 'outerTriangularRectangle'
|
||||
},
|
||||
{
|
||||
name: 'Hình chữ nhật tam giác bên trong',
|
||||
value: 'innerTriangularRectangle'
|
||||
},
|
||||
{
|
||||
name: 'Hình elip',
|
||||
value: 'ellipse'
|
||||
},
|
||||
{
|
||||
name: 'Vòng tròn',
|
||||
value: 'circle'
|
||||
}
|
||||
]
|
||||
|
||||
// Danh sách đa ngôn ngữ
|
||||
export const langList = [
|
||||
{
|
||||
value: 'zh',
|
||||
name: '简体中文'
|
||||
},
|
||||
{
|
||||
value: 'zhtw',
|
||||
name: '繁體中文'
|
||||
},
|
||||
{
|
||||
value: 'en',
|
||||
name: 'English'
|
||||
},
|
||||
{
|
||||
value: 'vi',
|
||||
name: 'Tiếng Việt'
|
||||
}
|
||||
]
|
||||
|
||||
// Danh sách thanh bên
|
||||
export const sidebarTriggerList = [
|
||||
{
|
||||
name: 'Kiểu nút',
|
||||
value: 'nodeStyle',
|
||||
icon: 'iconzhuti'
|
||||
},
|
||||
{
|
||||
name: 'Kiểu nền tảng',
|
||||
value: 'baseStyle',
|
||||
icon: 'iconyangshi'
|
||||
},
|
||||
{
|
||||
name: 'Chủ đề',
|
||||
value: 'theme',
|
||||
icon: 'iconjingzi'
|
||||
},
|
||||
{
|
||||
name: 'Cấu trúc',
|
||||
value: 'structure',
|
||||
icon: 'iconjiegou'
|
||||
},
|
||||
{
|
||||
name: 'Trang chủ',
|
||||
value: 'outline',
|
||||
icon: 'iconfuhao-dagangshu'
|
||||
},
|
||||
// {
|
||||
// name: 'AI',
|
||||
// value: 'ai',
|
||||
// icon: 'iconAIshengcheng'
|
||||
// },
|
||||
{
|
||||
name: 'Thiết lập',
|
||||
value: 'setting',
|
||||
icon: 'iconshezhi'
|
||||
}
|
||||
// {
|
||||
// name: 'Phím tắt',
|
||||
// value: 'shortcutKey',
|
||||
// icon: 'iconjianpan'
|
||||
// }
|
||||
]
|
||||
|
||||
// Danh sách các loại tải xuống
|
||||
export const downTypeList = [
|
||||
{
|
||||
name: '思绪Tài liệu',
|
||||
type: 'smm',
|
||||
icon: 'iconwenjian',
|
||||
desc: 'SimpleMindMap Định dạng riêng tư, có thể được sử dụng để nhập lại, có thể được chỉnh sửa trực tiếp bởi khách hàng'
|
||||
},
|
||||
{
|
||||
name: 'Hình ảnh',
|
||||
type: 'png',
|
||||
icon: 'iconPNG',
|
||||
desc: 'Định dạng ảnh phổ biến, phù hợp để xem chia sẻ'
|
||||
},
|
||||
{
|
||||
name: 'SVG',
|
||||
type: 'svg',
|
||||
icon: 'iconSVG',
|
||||
desc: 'Thu phóng đồ họa vector'
|
||||
},
|
||||
{
|
||||
name: 'PDF',
|
||||
type: 'pdf',
|
||||
icon: 'iconpdf',
|
||||
desc: 'Thích hợp để xem trình duyệt và in'
|
||||
},
|
||||
{
|
||||
name: 'Markdown',
|
||||
type: 'md',
|
||||
icon: 'iconmarkdown',
|
||||
desc: 'Định dạng văn bản md để dễ dàng mở phần mềm khác'
|
||||
},
|
||||
{
|
||||
name: 'XMind',
|
||||
type: 'xmind',
|
||||
icon: 'iconxmind',
|
||||
desc: 'Định dạng phần mềm XMind'
|
||||
},
|
||||
{
|
||||
name: 'Txt',
|
||||
type: 'txt',
|
||||
icon: 'iconTXT',
|
||||
desc: 'Tập tin văn bản thuần túy'
|
||||
},
|
||||
{
|
||||
name: 'Excel',
|
||||
type: 'xlsx',
|
||||
icon: 'iconfile-excel',
|
||||
desc: 'Dạng văn bản bảng, có thể chỉnh sửa bằng phần mềm Excel'
|
||||
},
|
||||
{
|
||||
name: 'FreeMind',
|
||||
type: 'mm',
|
||||
icon: 'iconfreemind',
|
||||
desc: 'Định dạng phần mềm FreeMind'
|
||||
},
|
||||
{
|
||||
name: 'JSON',
|
||||
type: 'json',
|
||||
icon: 'iconjson',
|
||||
desc: 'Các định dạng trao đổi dữ liệu phổ biến có thể được sử dụng để nhập lại'
|
||||
}
|
||||
]
|
||||
|
||||
// Danh sách các loại số
|
||||
export const numberTypeList = [
|
||||
{
|
||||
name: 'Không có số',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
name: '1, 2, 3',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: '1., 2., 3.',
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
name: '(1), (2), (3)',
|
||||
value: 3
|
||||
},
|
||||
{
|
||||
name: 'a., b., c.',
|
||||
value: 4
|
||||
},
|
||||
{
|
||||
name: 'A., B., C.',
|
||||
value: 5
|
||||
},
|
||||
{
|
||||
name: 'i., ii., iii.',
|
||||
value: 6
|
||||
},
|
||||
{
|
||||
name: 'I., II., III.',
|
||||
value: 7
|
||||
},
|
||||
{
|
||||
name: '一、, 二、, 三、',
|
||||
value: 8
|
||||
}
|
||||
]
|
||||
|
||||
// Không. Danh sách phân cấp
|
||||
export const numberLevelList = [
|
||||
{
|
||||
name: 'Không. Tầng đầu tiên',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: 'Không. Hai tầng đầu tiên',
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
name: 'Không. Ba tầng đầu tiên',
|
||||
value: 3
|
||||
},
|
||||
{
|
||||
name: 'Không. Tất cả các lớp',
|
||||
value: 0
|
||||
}
|
||||
]
|
||||
|
||||
// Hướng gradient nền
|
||||
export const linearGradientDirList = [
|
||||
{
|
||||
name: 'Từ trái sang phải',
|
||||
value: '1',
|
||||
start: [0, 0],
|
||||
end: [1, 0]
|
||||
},
|
||||
{
|
||||
name: 'Từ phải sang trái',
|
||||
value: '2',
|
||||
start: [1, 0],
|
||||
end: [0, 0]
|
||||
},
|
||||
{
|
||||
name: 'Từ trên xuống dưới',
|
||||
value: '3',
|
||||
start: [0, 0],
|
||||
end: [0, 1]
|
||||
},
|
||||
{
|
||||
name: 'Từ dưới lên trên',
|
||||
value: '4',
|
||||
start: [0, 1],
|
||||
end: [0, 0]
|
||||
},
|
||||
{
|
||||
name: 'Từ trái lên phải xuống',
|
||||
value: '5',
|
||||
start: [0, 0],
|
||||
end: [1, 1]
|
||||
},
|
||||
{
|
||||
name: 'Từ trái xuống phải',
|
||||
value: '6',
|
||||
start: [0, 1],
|
||||
end: [1, 0]
|
||||
},
|
||||
{
|
||||
name: 'Từ trên xuống dưới',
|
||||
value: '7',
|
||||
start: [1, 0],
|
||||
end: [0, 1]
|
||||
},
|
||||
{
|
||||
name: 'Từ phải xuống trái',
|
||||
value: '8',
|
||||
start: [1, 1],
|
||||
end: [0, 0]
|
||||
}
|
||||
]
|
||||
|
||||
// Căn lề văn bản
|
||||
export const alignList = [
|
||||
{
|
||||
name: 'Trái:',
|
||||
value: 'left'
|
||||
},
|
||||
{
|
||||
name: 'Căn giữa',
|
||||
value: 'center'
|
||||
},
|
||||
{
|
||||
name: 'Phải',
|
||||
value: 'right'
|
||||
}
|
||||
]
|
||||
|
||||
// Danh sách cấu trúc
|
||||
export const layoutGroupList = [
|
||||
{
|
||||
name: 'Sơ đồ cấu trúc logic',
|
||||
list: ['logicalStructure', 'logicalStructureLeft']
|
||||
},
|
||||
{
|
||||
name: 'Bản đồ tư duy',
|
||||
list: ['mindMap']
|
||||
},
|
||||
{
|
||||
name: 'Sơ đồ tổ chức',
|
||||
list: ['organizationStructure']
|
||||
},
|
||||
{
|
||||
name: 'Sơ đồ tổ chức thư mục',
|
||||
list: ['catalogOrganization']
|
||||
},
|
||||
{
|
||||
name: 'Dòng thời gian',
|
||||
list: [
|
||||
'timeline',
|
||||
'timeline2',
|
||||
'verticalTimeline'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Bản đồ Fishbone',
|
||||
list: ['fishbone']
|
||||
}
|
||||
]
|
||||
@@ -507,6 +507,10 @@ export const langList = [
|
||||
{
|
||||
value: 'en',
|
||||
name: 'English'
|
||||
},
|
||||
{
|
||||
value: 'vi',
|
||||
name: 'Tiếng Việt'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -537,37 +541,31 @@ export const sidebarTriggerList = [
|
||||
value: 'outline',
|
||||
icon: 'iconfuhao-dagangshu'
|
||||
},
|
||||
{
|
||||
name: 'AI',
|
||||
value: 'ai',
|
||||
icon: 'iconAIshengcheng'
|
||||
},
|
||||
// {
|
||||
// name: 'AI',
|
||||
// value: 'ai',
|
||||
// icon: 'iconAIshengcheng'
|
||||
// },
|
||||
{
|
||||
name: '设置',
|
||||
value: 'setting',
|
||||
icon: 'iconshezhi'
|
||||
},
|
||||
{
|
||||
name: '快捷键',
|
||||
value: 'shortcutKey',
|
||||
icon: 'iconjianpan'
|
||||
}
|
||||
// {
|
||||
// name: '快捷键',
|
||||
// value: 'shortcutKey',
|
||||
// icon: 'iconjianpan'
|
||||
// }
|
||||
]
|
||||
|
||||
// 下载类型列表
|
||||
export const downTypeList = [
|
||||
{
|
||||
name: '专有文件',
|
||||
name: '思绪文件',
|
||||
type: 'smm',
|
||||
icon: 'iconwenjian',
|
||||
desc: 'SimpleMindMap私有格式,可用于再次导入,客户端可直接编辑'
|
||||
},
|
||||
{
|
||||
name: 'JSON',
|
||||
type: 'json',
|
||||
icon: 'iconjson',
|
||||
desc: '流行的数据交换格式,可用于再次导入'
|
||||
},
|
||||
{
|
||||
name: '图片',
|
||||
type: 'png',
|
||||
@@ -604,6 +602,12 @@ export const downTypeList = [
|
||||
icon: 'iconTXT',
|
||||
desc: '纯文本文件'
|
||||
},
|
||||
{
|
||||
name: 'Excel',
|
||||
type: 'xlsx',
|
||||
icon: 'iconfile-excel',
|
||||
desc: '表格文本形式,可用Excel软件编辑'
|
||||
},
|
||||
{
|
||||
name: 'FreeMind',
|
||||
type: 'mm',
|
||||
@@ -611,11 +615,11 @@ export const downTypeList = [
|
||||
desc: 'FreeMind软件格式'
|
||||
},
|
||||
{
|
||||
name: 'Excel',
|
||||
type: 'xlsx',
|
||||
icon: 'iconfile-excel',
|
||||
desc: '表格文本形式,可用Excel软件编辑'
|
||||
}
|
||||
name: 'JSON',
|
||||
type: 'json',
|
||||
icon: 'iconjson',
|
||||
desc: '流行的数据交换格式,可用于再次导入'
|
||||
},
|
||||
]
|
||||
|
||||
// 编号类型列表
|
||||
@@ -769,13 +773,11 @@ export const layoutGroupList = [
|
||||
list: [
|
||||
'timeline',
|
||||
'timeline2',
|
||||
'verticalTimeline2',
|
||||
'verticalTimeline3',
|
||||
'verticalTimeline'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: '鱼骨图',
|
||||
list: ['fishbone', 'fishbone2', 'rightFishbone', 'rightFishbone2']
|
||||
list: ['fishbone']
|
||||
}
|
||||
]
|
||||
|
||||
@@ -439,37 +439,31 @@ export const sidebarTriggerList = [
|
||||
value: 'outline',
|
||||
icon: 'iconfuhao-dagangshu'
|
||||
},
|
||||
{
|
||||
name: 'AI',
|
||||
value: 'ai',
|
||||
icon: 'iconAIshengcheng'
|
||||
},
|
||||
// {
|
||||
// name: 'AI',
|
||||
// value: 'ai',
|
||||
// icon: 'iconAIshengcheng'
|
||||
// },
|
||||
{
|
||||
name: '設置',
|
||||
value: 'setting',
|
||||
icon: 'iconshezhi'
|
||||
},
|
||||
{
|
||||
name: '快捷鍵',
|
||||
value: 'shortcutKey',
|
||||
icon: 'iconjianpan'
|
||||
}
|
||||
// {
|
||||
// name: '快捷鍵',
|
||||
// value: 'shortcutKey',
|
||||
// icon: 'iconjianpan'
|
||||
// }
|
||||
]
|
||||
|
||||
// 下載類型列表
|
||||
export const downTypeList = [
|
||||
{
|
||||
name: '專用檔案',
|
||||
name: '思緒檔案',
|
||||
type: 'smm',
|
||||
icon: 'iconwenjian',
|
||||
desc: 'SimpleMindMap私有格式,可用于再次導入,客戶端可直接編輯'
|
||||
},
|
||||
{
|
||||
name: 'JSON',
|
||||
type: 'json',
|
||||
icon: 'iconjson',
|
||||
desc: '流行的數據交換格式,可用于再次導入'
|
||||
},
|
||||
{
|
||||
name: '圖片',
|
||||
type: 'png',
|
||||
@@ -506,6 +500,12 @@ export const downTypeList = [
|
||||
icon: 'iconTXT',
|
||||
desc: '純文本文件'
|
||||
},
|
||||
{
|
||||
name: 'Excel',
|
||||
type: 'xlsx',
|
||||
icon: 'iconfile-excel',
|
||||
desc: '表格文本形式,可用Excel軟件編輯'
|
||||
},
|
||||
{
|
||||
name: 'FreeMind',
|
||||
type: 'mm',
|
||||
@@ -513,11 +513,11 @@ export const downTypeList = [
|
||||
desc: 'FreeMind軟件格式'
|
||||
},
|
||||
{
|
||||
name: 'Excel',
|
||||
type: 'xlsx',
|
||||
icon: 'iconfile-excel',
|
||||
desc: '表格文本形式,可用Excel軟件編輯'
|
||||
}
|
||||
name: 'JSON',
|
||||
type: 'json',
|
||||
icon: 'iconjson',
|
||||
desc: '流行的數據交換格式,可用于再次導入'
|
||||
},
|
||||
]
|
||||
|
||||
// 編號類型列表
|
||||
@@ -671,13 +671,11 @@ export const layoutGroupList = [
|
||||
list: [
|
||||
'timeline',
|
||||
'timeline2',
|
||||
'verticalTimeline2',
|
||||
'verticalTimeline3',
|
||||
'verticalTimeline'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: '魚骨圖',
|
||||
list: ['fishbone', 'fishbone2', 'rightFishbone', 'rightFishbone2']
|
||||
list: ['fishbone']
|
||||
}
|
||||
]
|
||||
|
||||
@@ -5,7 +5,8 @@ import messages from './lang'
|
||||
Vue.use(VueI18n)
|
||||
|
||||
const i18n = new VueI18n({
|
||||
messages
|
||||
messages,
|
||||
fallbackLocale: 'zh'
|
||||
})
|
||||
|
||||
export default i18n
|
||||
|
||||
@@ -64,6 +64,7 @@ export default {
|
||||
isShowScrollbar: 'Is show scrollbar',
|
||||
isUseHandDrawnLikeStyle: 'Is use hand drawn like style',
|
||||
isUseMomentum: 'Is open drag momentum',
|
||||
openBlankMode: 'Is open blank mode of the demonstrate',
|
||||
watermark: 'Watermark',
|
||||
showWatermark: 'Is show watermark',
|
||||
onlyExport: 'Only export',
|
||||
@@ -177,7 +178,8 @@ export default {
|
||||
options: 'Options',
|
||||
isFitBg:
|
||||
'Whether to display the complete background image (effective when a background image is used)',
|
||||
format: 'Format'
|
||||
format: 'Format',
|
||||
confirm: 'Export'
|
||||
},
|
||||
fullscreen: {
|
||||
fullscreenShow: 'Full screen show',
|
||||
@@ -197,7 +199,10 @@ export default {
|
||||
fileContentError: 'The file content is incorrect',
|
||||
importSuccess: 'Import success',
|
||||
fileParsingFailed: 'File parsing failed',
|
||||
xmindCanvasSelectDialogTitle: 'Select the canvas to import'
|
||||
xmindCanvasSelectDialogTitle: 'Select the canvas to import',
|
||||
mdImportDialogTitle: 'Paste Markdown content to import',
|
||||
mdPlaceholder: 'Please enter the content in Markdown format',
|
||||
mdEmptyTip: 'The content cannot be empty'
|
||||
},
|
||||
navigatorToolbar: {
|
||||
openMiniMap: 'Open mini map',
|
||||
@@ -205,7 +210,13 @@ export default {
|
||||
readonly: 'Change to Readonly',
|
||||
edit: 'Change to edit',
|
||||
backToRoot: 'Back to root node',
|
||||
changeSourceCodeEdit: 'Switch to source code editing mode'
|
||||
changeSourceCodeEdit: 'Switch to source code editing mode',
|
||||
shortcutKeys: 'Shortcut keys',
|
||||
ai: 'AI dialogue',
|
||||
downloadClient: 'Download client',
|
||||
site: 'Official website',
|
||||
current: 'Current:',
|
||||
downloadDesc: 'You can download it from the following address:'
|
||||
},
|
||||
nodeHyperlink: {
|
||||
title: 'Link',
|
||||
@@ -358,7 +369,13 @@ export default {
|
||||
autoOpenNodeRichTextTip:
|
||||
'Detected imported rich text content, automatically enabled rich text mode',
|
||||
localStorageExceededTip:
|
||||
'The volume of the mind map you created has exceeded the maximum storage limit allowed by the browser. Please export it immediately, otherwise the data will be lost! It is recommended to download the client for use, as there is no size limit for the client.'
|
||||
'The volume of the mind map you created has exceeded the maximum storage limit allowed by the browser. Please export it immediately, otherwise the data will be lost! It is recommended to download the client for use, as there is no size limit for the client.',
|
||||
withBg: 'With background image',
|
||||
tryTipTitle: 'Function trial prompt',
|
||||
tryTipDesc:
|
||||
'This feature is a trial feature in the web version. Please download the client to use it:',
|
||||
downBaidu: 'Go to Baidu Netdisk to download',
|
||||
downGithub: 'Download from Github'
|
||||
},
|
||||
mouseAction: {
|
||||
tip1:
|
||||
@@ -510,8 +527,7 @@ export default {
|
||||
aiCreatePartMsgPrefix: 'I have a theme for【',
|
||||
aiCreatePartMsgCenter:
|
||||
'】Can you help me continue writing one of the contents of the mind map【',
|
||||
aiCreatePartMsgPostfix:
|
||||
'】The subordinate content of the node',
|
||||
aiCreatePartMsgPostfix: '】The subordinate content of the node',
|
||||
aiCreatePartMsgHelp:
|
||||
'. Needs to be returned in Markdown format and can only use two syntax: Markdown title and unordered list. It can support multi-level nesting. Just return the content.',
|
||||
aiCreatePart: 'AI Continuation'
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import en from './en_us'
|
||||
import zh from './zh_cn'
|
||||
import zhtw from './zh_tw'
|
||||
import vi from './vi_vn'
|
||||
|
||||
export default {
|
||||
zh,
|
||||
zhtw,
|
||||
en
|
||||
en,
|
||||
vi
|
||||
}
|
||||
|
||||
545
web/src/lang/vi_vn.js
Normal file
@@ -0,0 +1,545 @@
|
||||
export default {
|
||||
baseStyle: {
|
||||
title: 'Kiểu cơ bản',
|
||||
background: 'Nền',
|
||||
color: 'Màu sắc',
|
||||
image: 'Hình ảnh',
|
||||
imageRepeat: 'Lặp lại hình ảnh',
|
||||
imagePosition: 'Vị trí hình ảnh',
|
||||
imageSize: 'Kích thước hình ảnh',
|
||||
line: 'Đường kẻ',
|
||||
width: 'Độ rộng',
|
||||
style: 'Kiểu dáng',
|
||||
lineRadius: 'Độ cong',
|
||||
lineOfOutline: 'Đường viền ngoài',
|
||||
showArrow: 'Hiển thị mũi tên',
|
||||
nodePadding: 'Đệm nút',
|
||||
nodeMargin: 'Lề nút',
|
||||
horizontal: 'Ngang',
|
||||
vertical: 'Dọc',
|
||||
maximumWidth: 'Độ rộng tối đa',
|
||||
maximumHeight: 'Độ cao tối đa',
|
||||
icon: 'Biểu tượng',
|
||||
size: 'Kích thước',
|
||||
level2Node: 'Nút cấp 2',
|
||||
belowLevel2Node: 'Nút dưới cấp 2',
|
||||
nodeBorderType: 'Kiểu viền nút',
|
||||
nodeUseLineStyle: 'Chỉ sử dụng kiểu viền dưới',
|
||||
otherConfig: 'Cấu hình khác',
|
||||
associativeLine: 'Đường liên kết',
|
||||
associativeLineWidth: 'Độ rộng',
|
||||
associativeLineColor: 'Màu sắc',
|
||||
associativeLineActiveWidth: 'Độ rộng khi kích hoạt',
|
||||
associativeLineActiveColor: 'Màu sắc khi kích hoạt',
|
||||
rootStyle: 'Nút gốc',
|
||||
associativeLineText: 'Văn bản đường liên kết',
|
||||
fontFamily: 'Phông chữ',
|
||||
fontSize: 'Cỡ chữ',
|
||||
rootLineStartPos: 'Vị trí bắt đầu đường nút gốc',
|
||||
center: 'Trung tâm',
|
||||
edge: 'Cạnh',
|
||||
rainbowLines: 'Đường cầu vồng',
|
||||
notUseRainbowLines: 'Không sử dụng đường cầu vồng',
|
||||
outerFramePadding: 'Đệm khung ngoài',
|
||||
associativeLineStyle: 'Kiểu đường liên kết',
|
||||
builtInBackgroundImage: 'Hình nền tích hợp'
|
||||
},
|
||||
setting: {
|
||||
title: 'Cài đặt',
|
||||
openPerformance: 'Bật chế độ hiệu suất',
|
||||
enableFreeDrag: 'Cho phép kéo thả tự do nút (Beta)',
|
||||
isEnableNodeRichText: 'Cho phép chỉnh sửa văn bản phong phú của nút',
|
||||
mousewheelAction: 'Hành vi của con lăn chuột',
|
||||
zoomView: 'Thu phóng',
|
||||
moveViewUpDown: 'Di chuyển lên xuống',
|
||||
mousewheelZoomActionReverse: 'Thu phóng con lăn chuột',
|
||||
mousewheelZoomActionReverse1: 'Thu nhỏ tiến tới và phóng to lùi lại',
|
||||
mousewheelZoomActionReverse2: 'Phóng to tiến tới và thu nhỏ lùi lại',
|
||||
createNewNodeBehavior: 'Hành vi tạo nút mới',
|
||||
default: 'Kích hoạt nút mới và chỉnh sửa',
|
||||
notActive: 'Không kích hoạt nút mới',
|
||||
activeOnly: 'Chỉ kích hoạt nút mới mà không chỉnh sửa',
|
||||
openRealtimeRenderOnNodeTextEdit:
|
||||
'Bật hiệu ứng kết xuất thời gian thực cho chỉnh sửa văn bản',
|
||||
isShowScrollbar: 'Hiển thị thanh cuộn',
|
||||
isUseHandDrawnLikeStyle: 'Sử dụng kiểu vẽ tay',
|
||||
isUseMomentum: 'Mở động lượng kéo',
|
||||
openBlankMode: 'Mở chế độ trống cho trình diễn',
|
||||
watermark: 'Hình mờ',
|
||||
showWatermark: 'Hiển thị hình mờ',
|
||||
onlyExport: 'Chỉ xuất',
|
||||
watermarkDefaultText: 'Văn bản hình mờ',
|
||||
watermarkText: 'Văn bản hình mờ',
|
||||
watermarkTextColor: 'Màu văn bản',
|
||||
watermarkLineSpacing: 'Khoảng cách dòng',
|
||||
watermarkTextSpacing: 'Khoảng cách văn bản',
|
||||
watermarkAngle: 'Góc',
|
||||
watermarkTextOpacity: 'Độ mờ văn bản',
|
||||
watermarkTextFontSize: 'Cỡ chữ',
|
||||
belowNode: 'Hiển thị nút bên dưới',
|
||||
alwaysShowExpandBtn: 'Luôn hiển thị nút mở rộng',
|
||||
enableAutoEnterTextEditWhenKeydown:
|
||||
'Tự động vào chế độ chỉnh sửa văn bản khi nhấn phím',
|
||||
confirm: 'Xác nhận',
|
||||
cancel: 'Hủy',
|
||||
changeRichTextTip:
|
||||
'Thao tác này sẽ xóa tất cả lịch sử chỉnh sửa và sửa đổi dữ liệu sơ đồ tư duy. Bạn có muốn tiếp tục?',
|
||||
changeRichTextTip2: 'Bạn có muốn chuyển sang chế độ văn bản phong phú?',
|
||||
changeRichTextTip3:
|
||||
'Bạn có muốn chuyển sang chế độ không phải văn bản phong phú?',
|
||||
enableDragImport: 'Cho phép kéo và thả tệp trực tiếp vào trang để nhập',
|
||||
imgTextMargin: 'Khoảng cách giữa hình ảnh và văn bản nút',
|
||||
textContentMargin: 'Khoảng cách nội dung nút',
|
||||
enableInheritAncestorLineStyle:
|
||||
'Kiểu kết nối nút kế thừa kiểu của nút tổ tiên',
|
||||
enableAi: 'Bật chức năng AI'
|
||||
},
|
||||
color: {
|
||||
moreColor: 'Thêm màu'
|
||||
},
|
||||
contextmenu: {
|
||||
insertSiblingNode: 'Chèn nút cùng cấp',
|
||||
insertChildNode: 'Chèn nút con',
|
||||
insertParentNode: 'Chèn nút cha',
|
||||
insertSummary: 'Chèn tóm tắt',
|
||||
moveUpNode: 'Di chuyển nút lên',
|
||||
moveDownNode: 'Di chuyển nút xuống',
|
||||
deleteNode: 'Xóa nút',
|
||||
deleteCurrentNode: 'Chỉ xóa nút hiện tại',
|
||||
copyNode: 'Sao chép nút',
|
||||
cutNode: 'Cắt nút',
|
||||
pasteNode: 'Dán nút',
|
||||
backCenter: 'Quay lại nút gốc',
|
||||
expandAll: 'Mở rộng tất cả',
|
||||
unExpandAll: 'Thu gọn tất cả',
|
||||
expandTo: 'Mở rộng đến',
|
||||
arrangeLayout: 'Sắp xếp bố cục',
|
||||
level1: 'Cấp 1',
|
||||
level2: 'Cấp 2',
|
||||
level3: 'Cấp 3',
|
||||
level4: 'Cấp 4',
|
||||
level5: 'Cấp 5',
|
||||
level6: 'Cấp 6',
|
||||
zenMode: 'Chế độ zen',
|
||||
fitCanvas: 'Vừa với khung vẽ',
|
||||
removeImage: 'Xóa hình ảnh',
|
||||
removeHyperlink: 'Xóa liên kết',
|
||||
removeNote: 'Xóa ghi chú',
|
||||
removeCustomStyles: 'Xóa kiểu tùy chỉnh',
|
||||
removeAllNodeCustomStyles: 'Xóa tất cả kiểu tùy chỉnh của nút',
|
||||
exportNodeToPng: 'Xuất nút thành png',
|
||||
copyToClipboard: 'Sao chép vào clipboard',
|
||||
copyToSmm: 'SMM',
|
||||
copyToJson: 'JSON',
|
||||
copyToMarkdown: 'Markdown',
|
||||
copyToTxt: 'Txt',
|
||||
copyToPng: 'Png',
|
||||
copySuccess: 'Sao chép thành công',
|
||||
copyFail: 'Sao chép thất bại',
|
||||
number: 'Đánh số các nút con',
|
||||
expandNodeChild: 'Mở rộng tất cả nút con',
|
||||
unExpandNodeChild: 'Thu gọn tất cả nút con',
|
||||
addToDo: 'Thêm việc cần làm',
|
||||
removeToDo: 'Xóa việc cần làm',
|
||||
aiCreate: 'AI Tiếp tục',
|
||||
modifyNodeLink: 'Sửa liên kết nút',
|
||||
linkToNode: 'Liên kết đến nút',
|
||||
removeNodeLink: 'Xóa liên kết nút'
|
||||
},
|
||||
count: {
|
||||
words: 'Từ',
|
||||
nodes: 'Nút'
|
||||
},
|
||||
dialog: {
|
||||
cancel: 'Hủy',
|
||||
confirm: 'Xác nhận'
|
||||
},
|
||||
export: {
|
||||
title: 'Xuất',
|
||||
filename: 'Tên tệp',
|
||||
include: 'Bao gồm cấu hình như chủ đề và cấu trúc',
|
||||
dedicatedFile: 'Tệp chuyên dụng',
|
||||
jsonFile: 'Tệp json',
|
||||
imageFile: 'Tệp hình ảnh',
|
||||
svgFile: 'Tệp svg',
|
||||
pdfFile: 'Tệp pdf',
|
||||
markdownFile: 'Tệp markdown',
|
||||
isTransparent: 'Nền là trong suốt',
|
||||
transformingDomToImages: 'Đang chuyển đổi nút: ',
|
||||
notifyTitle: 'Thông tin',
|
||||
notifyMessage:
|
||||
'Nếu tải xuống không được kích hoạt, hãy kiểm tra xem có bị chặn bởi trình duyệt hay không',
|
||||
paddingX: 'Đệm x',
|
||||
paddingY: 'Đệm y',
|
||||
useMultiPageExport: 'Xuất nhiều trang',
|
||||
defaultFileName: 'Sơ đồ tư duy',
|
||||
addFooterTextPlaceholder: 'Ví dụ: Từ simple-mind-map',
|
||||
addFooterText: 'Thêm văn bản ở chân trang',
|
||||
desc: 'Mô tả',
|
||||
options: 'Tùy chọn',
|
||||
isFitBg: 'Hiển thị đầy đủ hình nền (có hiệu lực khi dùng hình nền)',
|
||||
format: 'Định dạng'
|
||||
},
|
||||
fullscreen: {
|
||||
fullscreenShow: 'Hiển thị toàn màn hình',
|
||||
fullscreenEdit: 'Chỉnh sửa toàn màn hình'
|
||||
},
|
||||
demonstrate: {
|
||||
demonstrate: 'Vào chế độ trình diễn'
|
||||
},
|
||||
import: {
|
||||
title: 'Nhập',
|
||||
selectFile: 'Chọn tệp',
|
||||
support: 'Hỗ trợ',
|
||||
file: 'tệp',
|
||||
pleaseSelect: 'Vui lòng chọn',
|
||||
maxFileNum: 'Nhiều nhất chọn một tệp',
|
||||
notSelectTip: 'Vui lòng chọn tệp để nhập',
|
||||
fileContentError: 'Nội dung tệp không chính xác',
|
||||
importSuccess: 'Nhập thành công',
|
||||
fileParsingFailed: 'Phân tích tệp thất bại',
|
||||
xmindCanvasSelectDialogTitle: 'Chọn canvas để nhập',
|
||||
mdImportDialogTitle: 'Dán nội dung Markdown để nhập',
|
||||
mdPlaceholder: 'Vui lòng nhập nội dung ở định dạng Markdown',
|
||||
mdEmptyTip: 'Nội dung không được trống'
|
||||
},
|
||||
navigatorToolbar: {
|
||||
openMiniMap: 'Mở bản đồ thu nhỏ',
|
||||
closeMiniMap: 'Đóng bản đồ thu nhỏ',
|
||||
readonly: 'Chuyển sang chế độ chỉ đọc',
|
||||
edit: 'Chuyển sang chế độ chỉnh sửa',
|
||||
backToRoot: 'Quay lại nút gốc',
|
||||
changeSourceCodeEdit: 'Chuyển sang chế độ chỉnh sửa mã nguồn',
|
||||
shortcutKeys: 'Phím tắt',
|
||||
ai: 'Đối thoại AI',
|
||||
downloadClient: 'Tải về khách hàng',
|
||||
site: 'Trang web chính thức',
|
||||
current: 'Hiện tại:',
|
||||
downloadDesc: 'Có thể download từ địa chỉ sau:'
|
||||
},
|
||||
nodeHyperlink: {
|
||||
title: 'Liên kết',
|
||||
link: 'Href',
|
||||
name: 'Tên'
|
||||
},
|
||||
nodeIcon: {
|
||||
title: 'Biểu tượng'
|
||||
},
|
||||
nodeImage: {
|
||||
title: 'Hình ảnh',
|
||||
imgTitle: 'Tiêu đề'
|
||||
},
|
||||
nodeNote: {
|
||||
title: 'Ghi chú'
|
||||
},
|
||||
nodeTag: {
|
||||
title: 'Thẻ',
|
||||
addTip: 'Nhấn Enter để thêm'
|
||||
},
|
||||
outline: {
|
||||
title: 'Dàn bài',
|
||||
nodeDefaultText: 'Nhánh nút',
|
||||
print: 'In',
|
||||
fullscreen: 'Toàn màn hình'
|
||||
},
|
||||
scale: {
|
||||
zoomIn: 'Phóng to',
|
||||
zoomOut: 'Thu nhỏ'
|
||||
},
|
||||
shortcutKey: {
|
||||
title: 'Phím tắt'
|
||||
},
|
||||
strusture: {
|
||||
title: 'Cấu trúc'
|
||||
},
|
||||
style: {
|
||||
title: 'Kiểu nút',
|
||||
normal: 'Bình thường',
|
||||
active: 'Kích hoạt',
|
||||
text: 'Văn bản',
|
||||
fontFamily: 'Phông chữ',
|
||||
fontSize: 'Cỡ chữ',
|
||||
color: 'Màu sắc',
|
||||
addFontWeight: 'Thêm độ đậm chữ',
|
||||
italic: 'Nghiêng',
|
||||
textDecoration: 'Trang trí văn bản',
|
||||
underline: 'Gạch dưới',
|
||||
none: 'Không',
|
||||
lineThrough: 'Gạch ngang',
|
||||
overline: 'Gạch trên',
|
||||
border: 'Viền',
|
||||
style: 'Kiểu dáng',
|
||||
width: 'Độ rộng',
|
||||
borderRadius: 'Độ cong viền',
|
||||
background: 'Nền',
|
||||
shape: 'Hình dạng',
|
||||
line: 'Đường kẻ',
|
||||
nodePadding: 'Đệm nút',
|
||||
horizontal: 'Ngang',
|
||||
vertical: 'Dọc',
|
||||
gradientStyle: 'Gradient',
|
||||
startColor: 'Bắt đầu',
|
||||
endColor: 'Kết thúc',
|
||||
arrowDir: 'Hướng mũi tên',
|
||||
arrowDirStart: 'Bắt đầu',
|
||||
arrowDirEnd: 'Kết thúc',
|
||||
direction: 'Hướng',
|
||||
selectNodeTip: 'Vui lòng chọn một nút',
|
||||
openLineFlow: 'Mở luồng đường kẻ',
|
||||
lineFlowDuration: 'Thời lượng luồng đường kẻ',
|
||||
forward: 'Tiến tới',
|
||||
reverse: 'Đảo ngược',
|
||||
img: 'Hình ảnh',
|
||||
placement: 'Vị trí',
|
||||
top: 'Trên',
|
||||
bottom: 'Dưới',
|
||||
left: 'Trái',
|
||||
right: 'Phải',
|
||||
tag: 'Thẻ'
|
||||
},
|
||||
theme: {
|
||||
title: 'Chủ đề',
|
||||
classics: 'Cổ điển',
|
||||
dark: 'Tối',
|
||||
simple: 'Đơn giản',
|
||||
coverTip: 'Bạn hiện đã tùy chỉnh kiểu cơ bản, bạn có muốn ghi đè không?',
|
||||
tip: 'Mẹo',
|
||||
cover: 'Ghi đè',
|
||||
reserve: 'Giữ lại'
|
||||
},
|
||||
toolbar: {
|
||||
undo: 'Hoàn tác',
|
||||
redo: 'Làm lại',
|
||||
insertSiblingNode: 'Nút cùng cấp',
|
||||
insertChildNode: 'Nút con',
|
||||
deleteNode: 'Xóa nút',
|
||||
image: 'Hình ảnh',
|
||||
icon: 'Biểu tượng',
|
||||
link: 'Liên kết',
|
||||
note: 'Ghi chú',
|
||||
tag: 'Thẻ',
|
||||
summary: 'Tóm tắt',
|
||||
displayOutline: 'Hiển thị dàn bài',
|
||||
baseStyle: 'Kiểu cơ bản',
|
||||
theme: 'Chủ đề',
|
||||
strusture: 'Cấu trúc',
|
||||
newFile: 'Tệp mới',
|
||||
openFile: 'Mở tệp',
|
||||
saveAs: 'Lưu thành',
|
||||
import: 'Nhập',
|
||||
export: 'Xuất',
|
||||
shortcutKey: 'Phím tắt',
|
||||
associativeLine: 'Đường liên kết',
|
||||
painter: 'Bút vẽ',
|
||||
formula: 'Công thức',
|
||||
attachment: 'Đính kèm',
|
||||
outerFrame: 'Khung ngoài',
|
||||
more: 'Thêm',
|
||||
selectFileTip: 'Vui lòng chọn một tệp',
|
||||
notSupportTip:
|
||||
'Trình duyệt của bạn không hỗ trợ tính năng này, hoặc trang hiện tại không sử dụng giao thức HTTPS',
|
||||
tip: 'Mẹo',
|
||||
editingLocalFileTipFront: 'Hiện đang chỉnh sửa tệp cục bộ【',
|
||||
editingLocalFileTipEnd: '】của bạn',
|
||||
fileContentError: 'Lỗi nội dung tệp',
|
||||
fileOpenFailed: 'Mở tệp thất bại',
|
||||
defaultFileName: 'Sơ đồ tư duy',
|
||||
creatingTip: 'Đang tạo tệp',
|
||||
directory: 'Thư mục',
|
||||
newFileTip:
|
||||
'Vui lòng xuất tệp đang chỉnh sửa trước khi tạo mới, Cẩn thận mất nội dung',
|
||||
openFileTip:
|
||||
'Vui lòng xuất tệp đang chỉnh sửa trước khi mở tệp, Cẩn thận mất nội dung',
|
||||
ai: 'AI'
|
||||
},
|
||||
edit: {
|
||||
newFeatureNoticeTitle: 'Nhắc nhở tính năng mới',
|
||||
newFeatureNoticeMessage:
|
||||
'Cập nhật này hỗ trợ chỉnh sửa văn bản phong phú cho nút, Nhưng có một số thiếu sót, Tác động quan trọng nhất là thời gian xuất hình ảnh tỷ lệ thuận với số lượng nút, Do đó, nếu bạn phụ thuộc nhiều vào yêu cầu xuất, bạn có thể sử dụng【Kiểu cơ bản】-【Cấu hình khác】-【Cho phép chỉnh sửa văn bản phong phú của nút】Đặt để tắt chế độ chỉnh sửa văn bản phong phú.',
|
||||
root: 'Nút gốc',
|
||||
splitByWrap: 'Tự động tách nút dựa trên ngắt dòng?',
|
||||
tip: 'Mẹo',
|
||||
yes: 'Có',
|
||||
no: 'Không',
|
||||
exportError: 'Xuất thất bại',
|
||||
dragTip: 'Thả ở đây để nhập tệp',
|
||||
deleteNodeImgTip: 'Bạn có chắc xóa hình ảnh nút?',
|
||||
autoOpenNodeRichTextTip:
|
||||
'Phát hiện nội dung văn bản phong phú nhập vào, tự động bật chế độ văn bản phong phú',
|
||||
localStorageExceededTip:
|
||||
'Dung lượng sơ đồ tư duy bạn tạo đã vượt quá giới hạn lưu trữ tối đa cho phép của trình duyệt. Vui lòng xuất ngay lập tức, nếu không dữ liệu sẽ bị mất! Nên tải xuống ứng dụng khách để sử dụng, vì không có giới hạn kích thước khi sử dụng ứng dụng khách.',
|
||||
withBg: 'Với Background',
|
||||
tryTipTitle: 'Mẹo dùng thử chức năng',
|
||||
tryTipDesc:
|
||||
'Chức năng này là chức năng dùng thử trong phiên bản web, xin vui lòng tải xuống để khách hàng sử dụng:',
|
||||
downBaidu: 'Tải xuống Baidu',
|
||||
downGithub: 'Tải xuống Github'
|
||||
},
|
||||
mouseAction: {
|
||||
tip1:
|
||||
'Hiện tại: Nhấp chuột trái để kéo canvas, nhấp chuột phải để chọn nút theo hộp',
|
||||
tip2:
|
||||
'Hiện tại: Nhấp chuột trái để chọn nút theo hộp, nhấp chuột phải để kéo canvas'
|
||||
},
|
||||
search: {
|
||||
searchPlaceholder: 'Nhập nội dung tìm kiếm và nhấn Enter',
|
||||
replacePlaceholder: 'Vui lòng nhập nội dung thay thế',
|
||||
replace: 'Thay thế',
|
||||
replaceAll: 'Thay thế tất cả',
|
||||
cancel: 'Hủy',
|
||||
noResult: 'Không có kết quả'
|
||||
},
|
||||
nodeIconSidebar: {
|
||||
title: 'Biểu tượng/Sticker',
|
||||
icon: 'Biểu tượng',
|
||||
sticker: 'Sticker'
|
||||
},
|
||||
formulaSidebar: {
|
||||
title: 'Công thức',
|
||||
placeholder: 'Vui lòng nhập cú pháp LaTeX',
|
||||
confirm: 'Xác nhận',
|
||||
common: 'Công thức phổ biến',
|
||||
tip: 'Không hỗ trợ chèn công thức trong chế độ không phải văn bản phong phú'
|
||||
},
|
||||
richTextToolbar: {
|
||||
bold: 'Đậm',
|
||||
italic: 'Nghiêng',
|
||||
underline: 'Gạch dưới',
|
||||
strike: 'Gạch ngang',
|
||||
fontFamily: 'Phông chữ',
|
||||
fontSize: 'Cỡ chữ',
|
||||
color: 'Màu sắc',
|
||||
backgroundColor: 'Màu nền',
|
||||
removeFormat: 'Xóa định dạng',
|
||||
textAlign: 'Căn chỉnh văn bản'
|
||||
},
|
||||
other: {
|
||||
loading: 'Đang tải, vui lòng đợi...'
|
||||
},
|
||||
sourceCodeEdit: {
|
||||
sourceCodeTip:
|
||||
'Không nên sửa kiểu trong chế độ văn bản phong phú vì cần phải đồng bộ sửa đổi dữ liệu và cấu trúc HTML.',
|
||||
format: 'Định dạng',
|
||||
copy: 'Sao chép',
|
||||
confirm: 'Hoàn thành',
|
||||
close: 'Đóng',
|
||||
formatErrorTip:
|
||||
'Định dạng JSON không chính xác. Vui lòng kiểm tra và thử lại',
|
||||
copyTip: 'Đã sao chép vào clipboard',
|
||||
formatTip: 'Định dạng hoàn thành'
|
||||
},
|
||||
attachment: {
|
||||
deleteAttachment: 'Xóa đính kèm',
|
||||
tip: 'Chức năng đính kèm chỉ có sẵn ở phía máy khách'
|
||||
},
|
||||
annotation: {
|
||||
mark: 'Đánh dấu',
|
||||
show: 'Hiển thị đánh dấu',
|
||||
type: 'Loại',
|
||||
color: 'Màu sắc',
|
||||
lineWidth: 'Độ rộng đường kẻ',
|
||||
padding: 'Đệm',
|
||||
animate: 'Hoạt ảnh'
|
||||
},
|
||||
nodeOuterFrame: {
|
||||
outerFrameSetting: 'Cài đặt khung ngoài',
|
||||
deleteOuterFrame: 'Xóa khung ngoài',
|
||||
boxStyle: 'Kiểu hộp',
|
||||
boxColor: 'Màu hộp',
|
||||
fillColor: 'Màu lấp đầy',
|
||||
nodeOuterFrameStyle: 'Kiểu khung ngoài',
|
||||
outerFrameText: 'Văn bản khung ngoài',
|
||||
deleteOuterFrameText: 'Xóa văn bản khung ngoài',
|
||||
fontFamily: 'Phông chữ',
|
||||
color: 'Màu sắc',
|
||||
fontSize: 'Cỡ chữ',
|
||||
radius: 'Độ cong',
|
||||
fontBold: 'Đậm chữ',
|
||||
italic: 'Nghiêng',
|
||||
lineHeight: 'Chiều cao dòng',
|
||||
textFillRadius: 'Độ cong lấp đầy văn bản',
|
||||
textFill: 'Màu lấp đầy văn bản',
|
||||
textAlign: 'Căn chỉnh văn bản',
|
||||
left: 'Trái',
|
||||
center: 'Giữa',
|
||||
right: 'Phải',
|
||||
paddingX: 'Đệm x',
|
||||
paddingY: 'Đệm y'
|
||||
},
|
||||
nodeTagStyle: {
|
||||
placeholder: 'Vui lòng nhập nội dung thẻ',
|
||||
delete: 'Xóa thẻ này'
|
||||
},
|
||||
ai: {
|
||||
chatTitle: 'Đối thoại AI',
|
||||
clearRecords: 'Xóa lịch sử',
|
||||
connectFailedTitle: 'Thông báo lỗi kết nối máy khách',
|
||||
connectFailedTip: 'Kết nối máy khách thất bại, vui lòng kiểm tra:',
|
||||
connectFailedCheckTip1:
|
||||
'1. Bạn đã cài đặt ứng dụng khách sơ đồ tư duy chưa? Nếu chưa, vui lòng nhấp vào đây để cài đặt:',
|
||||
connectFailedCheckTip2:
|
||||
'2. Nếu đã cài đặt ứng dụng khách, vui lòng xác nhận xem ứng dụng khách đã được mở chưa.',
|
||||
connectFailedCheckTip3:
|
||||
'Nếu đã được cài đặt và khởi động, bạn có thể thử đóng và khởi động lại nó.',
|
||||
connectFailedCheckTip4:
|
||||
'Sau khi hoàn thành các bước trên, bạn có thể nhấp vào:',
|
||||
baiduNetdisk: 'Baidu Netdisk',
|
||||
createMindMapTitle: 'Tạo sơ đồ tư duy một nhấp',
|
||||
createTip:
|
||||
'Vui lòng nhập chủ đề, và AI sẽ tạo sơ đồ tư duy dựa trên chủ đề của bạn, chẳng hạn như: Kế hoạch du lịch cuối tuần Hà Nội.',
|
||||
importantTip:
|
||||
'Lưu ý quan trọng: Tạo một nhấp sẽ ghi đè dữ liệu hiện có. Nên xuất dữ liệu hiện tại trước.',
|
||||
wantModifyAiConfigTip: 'Bạn muốn sửa đổi cấu hình AI? Vui lòng nhấp vào:',
|
||||
modifyAIConfiguration: 'Sửa đổi cấu hình AI',
|
||||
chatInputPlaceholder: 'Nhấn Enter để gửi, Shift+Enter để xuống dòng.',
|
||||
send: 'Gửi',
|
||||
stopGenerating: 'Dừng tạo',
|
||||
generationFailed: 'Tạo thất bại',
|
||||
aiGenerationSuccess: 'Tạo AI hoàn thành',
|
||||
stoppedGenerating: 'Đã dừng tạo',
|
||||
AIConfiguration: 'Cấu hình AI',
|
||||
VolcanoArkLargeModelConfiguration: 'Cấu hình mô hình lớn Volcano Ark:',
|
||||
configTip:
|
||||
'Hiện tại, chỉ hỗ trợ mô hình Volcano Ark, và bạn cần tự mình lấy khóa. Để biết các bước thực hiện chi tiết, vui lòng tham khảo:',
|
||||
course: 'Khóa học',
|
||||
inferenceAccessPoint: 'Điểm truy cập suy luận',
|
||||
mindMappingClientConfiguration: 'Cấu hình ứng dụng khách sơ đồ tư duy:',
|
||||
port: 'Cổng',
|
||||
cancel: 'Hủy',
|
||||
confirm: 'Xác nhận',
|
||||
close: 'Đóng',
|
||||
configSaveSuccessTip: 'Lưu cấu hình thành công',
|
||||
apiValidateTip: 'Vui lòng nhập giao diện',
|
||||
keyValidateTip: 'Vui lòng nhập API Key',
|
||||
modelValidateTip: 'Vui lòng nhập điểm truy cập suy luận',
|
||||
portValidateTip: 'Vui lòng nhập cổng',
|
||||
methodValidateTip: 'Vui lòng chọn phương thức yêu cầu',
|
||||
noInputTip: 'Vui lòng nhập nội dung',
|
||||
connectSuccessful: 'Kết nối thành công',
|
||||
connectFailed: 'Kết nối thất bại',
|
||||
connectionDetection: 'Phát hiện kết nối',
|
||||
configurationMissing: 'Thiếu cấu hình',
|
||||
aiCreateMsgPrefix: 'Giúp tôi viết một【',
|
||||
aiCreateMsgPostfix:
|
||||
'】. Nó cần được trả về ở định dạng Markdown và chỉ có thể sử dụng hai cú pháp: tiêu đề Markdown và danh sách không có thứ tự. Nó có thể hỗ trợ nhiều lớp lồng nhau. Chỉ cần trả về nội dung.',
|
||||
aiCreatePartMsgPrefix: 'Tôi có một chủ đề là【',
|
||||
aiCreatePartMsgCenter:
|
||||
'】Bạn có thể giúp tôi tiếp tục viết một trong những nội dung của sơ đồ tư duy【',
|
||||
aiCreatePartMsgPostfix: '】Nội dung phụ thuộc của nút',
|
||||
aiCreatePartMsgHelp:
|
||||
'. Cần được trả về ở định dạng Markdown và chỉ có thể sử dụng hai cú pháp: tiêu đề Markdown và danh sách không có thứ tự. Nó có thể hỗ trợ lồng ghép nhiều cấp độ. Chỉ cần trả về nội dung.',
|
||||
aiCreatePart: 'AI Tiếp tục'
|
||||
},
|
||||
note: {
|
||||
title: 'Ghi chú'
|
||||
},
|
||||
nodeLink: {
|
||||
linkToNode: 'Liên kết đến nút',
|
||||
addReturn: 'Thêm liên kết trở lại',
|
||||
tip1: 'Vui lòng chọn nút để liên kết đến',
|
||||
tip2: 'Không thể liên kết đến chính mình',
|
||||
tip3: 'Liên kết thành công',
|
||||
tip4: 'Xóa thành công',
|
||||
tip5: 'Nút liên kết không tồn tại. Có nên xóa liên kết không?'
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,7 @@ export default {
|
||||
isShowScrollbar: '是否显示滚动条',
|
||||
isUseHandDrawnLikeStyle: '是否开启手绘风格',
|
||||
isUseMomentum: '是否开启拖动画布的动量效果',
|
||||
openBlankMode: '是否开启演示模式的填空功能',
|
||||
watermark: '水印',
|
||||
showWatermark: '是否显示水印',
|
||||
watermarkDefaultText: '水印文字',
|
||||
@@ -145,8 +146,8 @@ export default {
|
||||
nodes: '节点'
|
||||
},
|
||||
dialog: {
|
||||
cancel: '取 消',
|
||||
confirm: '确 定'
|
||||
cancel: '取消',
|
||||
confirm: '确定'
|
||||
},
|
||||
export: {
|
||||
title: '导出',
|
||||
@@ -171,7 +172,8 @@ export default {
|
||||
desc: '说明',
|
||||
options: '选项',
|
||||
isFitBg: '是否显示完整背景图片(使用了背景图片时生效)',
|
||||
format: '格式'
|
||||
format: '格式',
|
||||
confirm: '导出'
|
||||
},
|
||||
fullscreen: {
|
||||
fullscreenShow: '全屏查看',
|
||||
@@ -191,7 +193,10 @@ export default {
|
||||
fileContentError: '文件内容有误',
|
||||
importSuccess: '导入成功',
|
||||
fileParsingFailed: '文件解析失败',
|
||||
xmindCanvasSelectDialogTitle: '选择要导入的画布'
|
||||
xmindCanvasSelectDialogTitle: '选择要导入的画布',
|
||||
mdImportDialogTitle: '粘贴Markdown内容导入',
|
||||
mdPlaceholder: '请输入Markdown格式的内容',
|
||||
mdEmptyTip: '内容不能为空'
|
||||
},
|
||||
navigatorToolbar: {
|
||||
openMiniMap: '开启小地图',
|
||||
@@ -199,7 +204,13 @@ export default {
|
||||
readonly: '切换为只读模式',
|
||||
edit: '切换为编辑模式',
|
||||
backToRoot: '回到根节点',
|
||||
changeSourceCodeEdit: '切换为源码编辑模式'
|
||||
changeSourceCodeEdit: '切换为源码编辑模式',
|
||||
shortcutKeys: '快捷键',
|
||||
ai: 'AI对话',
|
||||
downloadClient: '下载客户端',
|
||||
site: '官方网站',
|
||||
current: '当前:',
|
||||
downloadDesc: '可从如下地址下载:'
|
||||
},
|
||||
nodeHyperlink: {
|
||||
title: '超链接',
|
||||
@@ -347,7 +358,12 @@ export default {
|
||||
deleteNodeImgTip: '是否确认删除该节点图片?',
|
||||
autoOpenNodeRichTextTip: '检测到导入了富文本内容,已自动开启富文本模式',
|
||||
localStorageExceededTip:
|
||||
'你创建的思维导图体积已经超过浏览器允许存储的上限,请立即导出,否则数据将丢失!建议下载客户端进行使用,客户端无大小限制。'
|
||||
'你创建的思维导图体积已经超过浏览器允许存储的上限,请立即导出,否则数据将丢失!建议下载客户端进行使用,客户端无大小限制。',
|
||||
withBg: '带背景',
|
||||
tryTipTitle: '功能试用提示',
|
||||
tryTipDesc: '该功能在网页版中为试用功能,请下载客户端使用:',
|
||||
downBaidu: '去百度网盘下载',
|
||||
downGithub: '去Github下载'
|
||||
},
|
||||
mouseAction: {
|
||||
tip1: '当前:左键拖动画布,右键框选节点',
|
||||
|
||||
@@ -63,6 +63,7 @@ export default {
|
||||
isShowScrollbar: '顯示捲軸',
|
||||
isUseHandDrawnLikeStyle: '使用手繪風格',
|
||||
isUseMomentum: '是否開啓拖動畫布的動量效果',
|
||||
openBlankMode: '是否開啓演示模式的填空功能',
|
||||
watermark: '浮水印',
|
||||
showWatermark: '顯示浮水印',
|
||||
onlyExport: '僅在匯出時顯示',
|
||||
@@ -172,7 +173,8 @@ export default {
|
||||
desc: '說明',
|
||||
options: '選項',
|
||||
isFitBg: '是否顯示完整背景圖片(使用了背景圖片時生效)',
|
||||
format: '格式'
|
||||
format: '格式',
|
||||
confirm: '匯出'
|
||||
},
|
||||
fullscreen: {
|
||||
fullscreenShow: '全螢幕檢視',
|
||||
@@ -192,7 +194,10 @@ export default {
|
||||
fileContentError: '檔案內容有誤',
|
||||
importSuccess: '匯入成功',
|
||||
fileParsingFailed: '檔案解析失敗',
|
||||
xmindCanvasSelectDialogTitle: '選擇要匯入的畫布'
|
||||
xmindCanvasSelectDialogTitle: '選擇要匯入的畫布',
|
||||
mdImportDialogTitle: '粘貼Markdown內容導入',
|
||||
mdPlaceholder: '請輸入Markdown格式的內容',
|
||||
mdEmptyTip: '內容不能爲空'
|
||||
},
|
||||
navigatorToolbar: {
|
||||
openMiniMap: '開啟小地圖',
|
||||
@@ -200,7 +205,13 @@ export default {
|
||||
readonly: '切換為唯讀模式',
|
||||
edit: '切換為編輯模式',
|
||||
backToRoot: '回到根節點',
|
||||
changeSourceCodeEdit: '切換為原始碼編輯模式'
|
||||
changeSourceCodeEdit: '切換為原始碼編輯模式',
|
||||
shortcutKeys: '快捷鍵',
|
||||
ai: 'AI對話',
|
||||
downloadClient: '下載客戶端',
|
||||
site: '官方網站',
|
||||
current: '當前:',
|
||||
downloadDesc: '可從如下地址下載:'
|
||||
},
|
||||
nodeHyperlink: {
|
||||
title: '超連結',
|
||||
@@ -347,7 +358,12 @@ export default {
|
||||
dragTip: '在此釋放以匯入檔案',
|
||||
autoOpenNodeRichTextTip: '檢測到導入了富文本內容,已自動開啓富文本模式',
|
||||
localStorageExceededTip:
|
||||
'你創建的思維導圖體積已經超過浏覽器允許存儲的上限,請立即導出,否則數據將丟失!建議下載客戶端進行使用,客戶端無大小限制。'
|
||||
'你創建的思維導圖體積已經超過浏覽器允許存儲的上限,請立即導出,否則數據將丟失!建議下載客戶端進行使用,客戶端無大小限制。',
|
||||
withBg: '帶背景',
|
||||
tryTipTitle: '功能試用提示',
|
||||
tryTipDesc: '該功能在網頁版中為試用功能,請下載用戶端使用:',
|
||||
downBaidu: '去百度網盤下載',
|
||||
downGithub: '去Github下載'
|
||||
},
|
||||
mouseAction: {
|
||||
tip1: '目前:左鍵拖曳畫布,右鍵框選節點',
|
||||
@@ -491,9 +507,8 @@ export default {
|
||||
'】,需要以Markdown格式返回,並且只能使用Markdown的標題和無序列表兩種語法,可以支持多層嵌套。只需返回內容即可。',
|
||||
aiCreatePartMsgPrefix: '我有一個主題爲【',
|
||||
aiCreatePartMsgCenter: '】的思維導圖,幫我續寫其中一個內容爲【',
|
||||
aiCreatePartMsgPostfix:
|
||||
'】的節點的下級內容',
|
||||
aiCreatePartMsgHelp:
|
||||
aiCreatePartMsgPostfix: '】的節點的下級內容',
|
||||
aiCreatePartMsgHelp:
|
||||
'。需要以Markdown格式返回,並且只能使用Markdown的標題和無序列表兩種語法,可以支持多層嵌套。只需返回內容即可。',
|
||||
aiCreatePart: 'AI續寫'
|
||||
},
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
</el-tabs>
|
||||
</div>
|
||||
<!-- 连线 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.line') }}</div>
|
||||
<div class="title">{{ $t('baseStyle.line') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('baseStyle.color') }}</span>
|
||||
@@ -301,63 +301,8 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 流动效果 -->
|
||||
<div class="row" v-if="supportLineFlow">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('style.openLineFlow') }}</span>
|
||||
<el-checkbox
|
||||
v-model="style.lineFlow"
|
||||
@change="
|
||||
value => {
|
||||
update('lineFlow', value)
|
||||
}
|
||||
"
|
||||
></el-checkbox>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('style.direction') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
v-model="style.lineFlowForward"
|
||||
placeholder=""
|
||||
@change="
|
||||
value => {
|
||||
update('lineFlowForward', value)
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-option
|
||||
key="1"
|
||||
:label="$t('style.forward')"
|
||||
:value="true"
|
||||
></el-option>
|
||||
<el-option
|
||||
key="2"
|
||||
:label="$t('style.reverse')"
|
||||
:value="false"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="supportLineFlow">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('style.lineFlowDuration') }}</span>
|
||||
<el-input-number
|
||||
v-model="style.lineFlowDuration"
|
||||
@change="
|
||||
value => {
|
||||
update('lineFlowDuration', value)
|
||||
}
|
||||
"
|
||||
:min="0.1"
|
||||
size="mini"
|
||||
:step="0.5"
|
||||
></el-input-number>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 彩虹线条 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.rainbowLines') }}</div>
|
||||
<div class="title">{{ $t('baseStyle.rainbowLines') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<el-popover
|
||||
@@ -401,7 +346,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 概要连线 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.lineOfOutline') }}</div>
|
||||
<div class="title">{{ $t('baseStyle.lineOfOutline') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('baseStyle.color') }}</span>
|
||||
@@ -451,7 +396,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 关联线 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.associativeLine') }}</div>
|
||||
<div class="title">{{ $t('baseStyle.associativeLine') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('baseStyle.associativeLineColor') }}</span>
|
||||
@@ -594,7 +539,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 关联线文字 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.associativeLineText') }}</div>
|
||||
<div class="title">{{ $t('baseStyle.associativeLineText') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('baseStyle.fontFamily') }}</span>
|
||||
@@ -656,7 +601,7 @@
|
||||
</div>
|
||||
<!-- 节点边框风格 -->
|
||||
<template v-if="showNodeUseLineStyle">
|
||||
<div class="title noTop">{{ $t('baseStyle.nodeBorderType') }}</div>
|
||||
<div class="title">{{ $t('baseStyle.nodeBorderType') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<el-checkbox
|
||||
@@ -672,8 +617,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内边距 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.nodePadding') }}</div>
|
||||
<div class="row">
|
||||
<div class="title">{{ $t('baseStyle.nodePadding') }}</div>
|
||||
<div class="row noBottom">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('baseStyle.horizontal') }}</span>
|
||||
<el-slider
|
||||
@@ -702,8 +647,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 图片 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.image') }}</div>
|
||||
<div class="row">
|
||||
<div class="title">{{ $t('baseStyle.image') }}</div>
|
||||
<div class="row noBottom">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('baseStyle.maximumWidth') }}</span>
|
||||
<el-slider
|
||||
@@ -736,7 +681,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 图标 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.icon') }}</div>
|
||||
<div class="title">{{ $t('baseStyle.icon') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('baseStyle.size') }}</span>
|
||||
@@ -754,8 +699,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 二级节点外边距 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.nodeMargin') }}</div>
|
||||
<div class="row column">
|
||||
<div class="title">{{ $t('baseStyle.nodeMargin') }}</div>
|
||||
<div class="row column noBottom">
|
||||
<el-tabs
|
||||
class="tab"
|
||||
v-model="marginActiveTab"
|
||||
@@ -798,8 +743,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 外框内边距 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.outerFramePadding') }}</div>
|
||||
<div class="row">
|
||||
<div class="title">{{ $t('baseStyle.outerFramePadding') }}</div>
|
||||
<div class="row noBottom">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('baseStyle.horizontal') }}</span>
|
||||
<el-slider
|
||||
@@ -880,6 +825,7 @@ export default {
|
||||
rainbowLinesOptions,
|
||||
lineWidthList,
|
||||
fontSizeList,
|
||||
lineStyleMap,
|
||||
activeTab: 'color',
|
||||
marginActiveTab: 'second',
|
||||
style: {
|
||||
@@ -932,7 +878,6 @@ export default {
|
||||
activeSidebar: state => state.activeSidebar,
|
||||
localConfig: state => state.localConfig,
|
||||
isDark: state => state.localConfig.isDark,
|
||||
supportLineFlow: state => state.supportLineFlow,
|
||||
bgList: state => state.bgList
|
||||
}),
|
||||
lineStyleList() {
|
||||
@@ -958,9 +903,6 @@ export default {
|
||||
fontFamilyList() {
|
||||
return fontFamilyList[this.$i18n.locale] || fontFamilyList.zh
|
||||
},
|
||||
lineStyleMap() {
|
||||
return lineStyleMap[this.$i18n.locale] || lineStyleMap.zh
|
||||
},
|
||||
showNodeUseLineStyle() {
|
||||
return supportNodeUseLineStyleLayouts.includes(this.currentLayout)
|
||||
},
|
||||
@@ -1167,7 +1109,7 @@ export default {
|
||||
font-weight: 500;
|
||||
color: rgba(26, 26, 26, 0.9);
|
||||
margin-bottom: 10px;
|
||||
margin-top: 20px;
|
||||
margin-top: 35px;
|
||||
|
||||
&.noTop {
|
||||
margin-top: 0;
|
||||
@@ -1179,6 +1121,10 @@ export default {
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&.noBottom {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.column {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@@ -62,41 +62,6 @@
|
||||
<div class="item" @click="exec('EXPAND_ALL')">
|
||||
<span class="name">{{ $t('contextmenu.expandNodeChild') }}</span>
|
||||
</div>
|
||||
<div class="item" v-if="supportNumbers">
|
||||
<span class="name">{{ $t('contextmenu.number') }}</span>
|
||||
<span class="el-icon-arrow-right"></span>
|
||||
<div
|
||||
class="subItems listBox"
|
||||
:class="{ isDark: isDark, showLeft: subItemsShowLeft }"
|
||||
style="top: -170px"
|
||||
>
|
||||
<div
|
||||
class="item"
|
||||
v-for="item in numberTypeList"
|
||||
:key="'type' + item.value"
|
||||
@click="setNodeNumber('type', item.value)"
|
||||
>
|
||||
<span class="name">{{ item.name }}</span>
|
||||
{{ numberType === item.value ? '√' : '' }}
|
||||
</div>
|
||||
<div class="splitLine"></div>
|
||||
<div
|
||||
class="item"
|
||||
v-for="item in numberLevelList"
|
||||
:key="'level' + item.value"
|
||||
:class="{ disabled: numberType === '' }"
|
||||
@click="setNodeNumber('level', item.value)"
|
||||
>
|
||||
<span class="name">{{ item.name }}</span>
|
||||
{{ numberLevel === item.value ? '√' : '' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item" @click="setCheckbox" v-if="supportCheckbox">
|
||||
<span class="name">{{
|
||||
hasCheckbox ? $t('contextmenu.removeToDo') : $t('contextmenu.addToDo')
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="splitLine"></div>
|
||||
<div class="item danger" @click="exec('REMOVE_NODE')">
|
||||
<span class="name">{{ $t('contextmenu.deleteNode') }}</span>
|
||||
@@ -134,16 +99,6 @@
|
||||
<div class="item" @click="exec('REMOVE_NOTE')" v-if="hasNote">
|
||||
<span class="name">{{ $t('contextmenu.removeNote') }}</span>
|
||||
</div>
|
||||
<div class="item" @click="exec('LINK_NODE')">
|
||||
<span class="name">{{
|
||||
hasNodeLink
|
||||
? $t('contextmenu.modifyNodeLink')
|
||||
: $t('contextmenu.linkToNode')
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="item" @click="exec('REMOVE_LINK_NODE')" v-if="hasNodeLink">
|
||||
<span class="name">{{ $t('contextmenu.removeNodeLink') }}</span>
|
||||
</div>
|
||||
<div class="item" @click="exec('REMOVE_CUSTOM_STYLES')">
|
||||
<span class="name">{{ $t('contextmenu.removeCustomStyles') }}</span>
|
||||
</div>
|
||||
@@ -262,8 +217,6 @@ export default {
|
||||
...mapState({
|
||||
isZenMode: state => state.localConfig.isZenMode,
|
||||
isDark: state => state.localConfig.isDark,
|
||||
supportNumbers: state => state.supportNumbers,
|
||||
supportCheckbox: state => state.supportCheckbox,
|
||||
enableAi: state => state.localConfig.enableAi
|
||||
}),
|
||||
expandList() {
|
||||
@@ -491,13 +444,6 @@ export default {
|
||||
case 'REMOVE_NOTE':
|
||||
this.node.setNote('')
|
||||
break
|
||||
case 'LINK_NODE':
|
||||
this.$bus.$emit('show_link_node', this.node)
|
||||
this.hide()
|
||||
break
|
||||
case 'REMOVE_LINK_NODE':
|
||||
this.$bus.$emit('execCommand', 'SET_NODE_LINK', this.node, null)
|
||||
break
|
||||
case 'EXPORT_CUR_NODE_TO_PNG':
|
||||
this.mindMap.export(
|
||||
'png',
|
||||
@@ -521,45 +467,6 @@ export default {
|
||||
this.hide()
|
||||
},
|
||||
|
||||
// 设置节点编号
|
||||
setNodeNumber(prop, value) {
|
||||
if (prop === 'type') {
|
||||
this.numberType = value
|
||||
if (value === '') {
|
||||
// 无编号
|
||||
this.numberLevel = ''
|
||||
this.mindMap.execCommand('SET_NUMBER', [], null)
|
||||
return
|
||||
} else {
|
||||
// 有编号
|
||||
if (this.numberLevel === '') {
|
||||
this.numberLevel = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prop === 'level') {
|
||||
this.numberLevel = value
|
||||
}
|
||||
this.mindMap.execCommand('SET_NUMBER', [], {
|
||||
[prop]: value
|
||||
})
|
||||
this.hide()
|
||||
},
|
||||
|
||||
// 设置待办
|
||||
setCheckbox() {
|
||||
this.mindMap.execCommand(
|
||||
'SET_CHECKBOX',
|
||||
[],
|
||||
this.hasCheckbox
|
||||
? null
|
||||
: {
|
||||
done: false
|
||||
}
|
||||
)
|
||||
this.hide()
|
||||
},
|
||||
|
||||
// 复制到剪贴板
|
||||
async copyToClipboard(type) {
|
||||
try {
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<div class="customNodeContent">
|
||||
<p>{{ title }}</p>
|
||||
<p v-html="html"></p>
|
||||
<p :style="{ backgroundColor: color }" @click="onClick">点击我会变色</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
html: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: '我是自定义节点',
|
||||
color: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
this.color = 'red'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.customNodeContent {
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -34,7 +34,6 @@
|
||||
v-if="mindMap"
|
||||
:mindMap="mindMap"
|
||||
></NodeNoteContentShow>
|
||||
<NodeAttachment v-if="mindMap" :mindMap="mindMap"></NodeAttachment>
|
||||
<NodeImgPreview v-if="mindMap" :mindMap="mindMap"></NodeImgPreview>
|
||||
<SidebarTrigger v-if="!isZenMode"></SidebarTrigger>
|
||||
<Search v-if="mindMap" :mindMap="mindMap"></Search>
|
||||
@@ -43,7 +42,6 @@
|
||||
<OutlineEdit v-if="mindMap" :mindMap="mindMap"></OutlineEdit>
|
||||
<Scrollbar v-if="isShowScrollbar && mindMap" :mindMap="mindMap"></Scrollbar>
|
||||
<FormulaSidebar v-if="mindMap" :mindMap="mindMap"></FormulaSidebar>
|
||||
<SourceCodeEdit v-if="mindMap" :mindMap="mindMap"></SourceCodeEdit>
|
||||
<NodeOuterFrame v-if="mindMap" :mindMap="mindMap"></NodeOuterFrame>
|
||||
<NodeTagStyle v-if="mindMap" :mindMap="mindMap"></NodeTagStyle>
|
||||
<Setting :configData="mindMapConfig" :mindMap="mindMap"></Setting>
|
||||
@@ -54,10 +52,6 @@
|
||||
<NodeNoteSidebar v-if="mindMap" :mindMap="mindMap"></NodeNoteSidebar>
|
||||
<AiCreate v-if="mindMap && enableAi" :mindMap="mindMap"></AiCreate>
|
||||
<AiChat v-if="enableAi"></AiChat>
|
||||
<LinkNodeSelect
|
||||
v-if="mindMap && supportNodeLink"
|
||||
:mindMap="mindMap"
|
||||
></LinkNodeSelect>
|
||||
<div
|
||||
class="dragMask"
|
||||
v-if="showDragMask"
|
||||
@@ -96,22 +90,6 @@ import NodeBase64ImageStorage from 'simple-mind-map/src/plugins/NodeBase64ImageS
|
||||
import Themes from 'simple-mind-map-plugin-themes'
|
||||
// 协同编辑插件
|
||||
// import Cooperate from 'simple-mind-map/src/plugins/Cooperate.js'
|
||||
// 以下插件为付费插件,详情请查看开发文档。依次为:手绘风格插件、标记插件、编号插件、Freemind软件格式导入导出插件、Excel软件格式导入导出插件、待办插件、节点连线流动效果插件、动量效果插件、向右鱼骨图插件、节点链接插件、扩展节点形状插件、扩展主题列表插件
|
||||
import HandDrawnLikeStyle from 'simple-mind-map-plugin-handdrawnlikestyle'
|
||||
import Notation from 'simple-mind-map-plugin-notation'
|
||||
import Numbers from 'simple-mind-map-plugin-numbers'
|
||||
import Freemind from 'simple-mind-map-plugin-freemind'
|
||||
import Excel from 'simple-mind-map-plugin-excel'
|
||||
import Checkbox from 'simple-mind-map-plugin-checkbox'
|
||||
import LineFlow from 'simple-mind-map-plugin-lineflow'
|
||||
import Momentum from 'simple-mind-map-plugin-momentum'
|
||||
import RightFishbone from 'simple-mind-map-plugin-right-fishbone'
|
||||
import NodeLink from 'simple-mind-map-plugin-node-link'
|
||||
import MoreShapes from 'simple-mind-map-plugin-more-shapes'
|
||||
import MoreThemes from 'simple-mind-map-plugin-more-themes'
|
||||
// npm link simple-mind-map simple-mind-map-plugin-excel simple-mind-map-plugin-freemind simple-mind-map-plugin-numbers simple-mind-map-plugin-notation simple-mind-map-plugin-handdrawnlikestyle simple-mind-map-plugin-checkbox simple-mind-map-plugin-lineflow simple-mind-map-plugin-momentum simple-mind-map-plugin-right-fishbone simple-mind-map-plugin-node-link
|
||||
// simple-mind-map-plugin-themes
|
||||
// simple-mind-map-plugin-more-themes simple-mind-map-plugin-more-shapes
|
||||
import OutlineSidebar from './OutlineSidebar.vue'
|
||||
import Style from './Style.vue'
|
||||
import BaseStyle from './BaseStyle.vue'
|
||||
@@ -129,23 +107,17 @@ import NodeImgPreview from './NodeImgPreview.vue'
|
||||
import SidebarTrigger from './SidebarTrigger.vue'
|
||||
import { mapState } from 'vuex'
|
||||
import icon from '@/config/icon'
|
||||
import CustomNodeContent from './CustomNodeContent.vue'
|
||||
import Color from './Color.vue'
|
||||
import Vue from 'vue'
|
||||
import router from '../../../router'
|
||||
import store from '../../../store'
|
||||
import i18n from '../../../i18n'
|
||||
import Search from './Search.vue'
|
||||
import NodeIconSidebar from './NodeIconSidebar.vue'
|
||||
import NodeIconToolbar from './NodeIconToolbar.vue'
|
||||
import OutlineEdit from './OutlineEdit.vue'
|
||||
import { showLoading, hideLoading } from '@/utils/loading'
|
||||
import handleClipboardText from '@/utils/handleClipboardText'
|
||||
import { getParentWithClass } from '@/utils'
|
||||
import Scrollbar from './Scrollbar.vue'
|
||||
import exampleData from 'simple-mind-map/example/exampleData'
|
||||
import FormulaSidebar from './FormulaSidebar.vue'
|
||||
import SourceCodeEdit from './SourceCodeEdit.vue'
|
||||
import NodeAttachment from './NodeAttachment.vue'
|
||||
import NodeOuterFrame from './NodeOuterFrame.vue'
|
||||
import NodeTagStyle from './NodeTagStyle.vue'
|
||||
import Setting from './Setting.vue'
|
||||
@@ -154,7 +126,6 @@ import NodeImgPlacementToolbar from './NodeImgPlacementToolbar.vue'
|
||||
import NodeNoteSidebar from './NodeNoteSidebar.vue'
|
||||
import AiCreate from './AiCreate.vue'
|
||||
import AiChat from './AiChat.vue'
|
||||
import LinkNodeSelect from './LinkNodeSelect.vue'
|
||||
|
||||
// 注册插件
|
||||
MindMap.usePlugin(MiniMap)
|
||||
@@ -207,8 +178,6 @@ export default {
|
||||
OutlineEdit,
|
||||
Scrollbar,
|
||||
FormulaSidebar,
|
||||
SourceCodeEdit,
|
||||
NodeAttachment,
|
||||
NodeOuterFrame,
|
||||
NodeTagStyle,
|
||||
Setting,
|
||||
@@ -216,8 +185,7 @@ export default {
|
||||
NodeImgPlacementToolbar,
|
||||
NodeNoteSidebar,
|
||||
AiCreate,
|
||||
AiChat,
|
||||
LinkNodeSelect
|
||||
AiChat
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -238,13 +206,9 @@ export default {
|
||||
enableDragImport: state => state.localConfig.enableDragImport,
|
||||
useLeftKeySelectionRightKeyDrag: state =>
|
||||
state.localConfig.useLeftKeySelectionRightKeyDrag,
|
||||
isUseHandDrawnLikeStyle: state =>
|
||||
state.localConfig.isUseHandDrawnLikeStyle,
|
||||
isUseMomentum: state => state.localConfig.isUseMomentum,
|
||||
extraTextOnExport: state => state.extraTextOnExport,
|
||||
isDragOutlineTreeNode: state => state.isDragOutlineTreeNode,
|
||||
enableAi: state => state.localConfig.enableAi,
|
||||
supportNodeLink: state => state.supportNodeLink
|
||||
enableAi: state => state.localConfig.enableAi
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
@@ -261,25 +225,10 @@ export default {
|
||||
} else {
|
||||
this.removeScrollbarPlugin()
|
||||
}
|
||||
},
|
||||
isUseHandDrawnLikeStyle() {
|
||||
if (this.isUseHandDrawnLikeStyle) {
|
||||
this.addHandDrawnLikeStylePlugin()
|
||||
} else {
|
||||
this.removeHandDrawnLikeStylePlugin()
|
||||
}
|
||||
},
|
||||
isUseMomentum() {
|
||||
if (this.isUseMomentum) {
|
||||
this.addMomentumPlugin()
|
||||
} else {
|
||||
this.removeMomentumPlugin()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
showLoading()
|
||||
// this.showNewFeatureInfo()
|
||||
this.getData()
|
||||
this.init()
|
||||
this.$bus.$on('execCommand', this.execCommand)
|
||||
@@ -294,6 +243,8 @@ export default {
|
||||
this.$bus.$on('showLoading', this.handleShowLoading)
|
||||
this.$bus.$on('localStorageExceeded', this.onLocalStorageExceeded)
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
this.$bus.$on('showDownloadTip', this.showDownloadTip)
|
||||
this.webTip()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off('execCommand', this.execCommand)
|
||||
@@ -308,6 +259,7 @@ export default {
|
||||
this.$bus.$off('showLoading', this.handleShowLoading)
|
||||
this.$bus.$off('localStorageExceeded', this.onLocalStorageExceeded)
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
this.$bus.$off('showDownloadTip', this.showDownloadTip)
|
||||
this.mindMap.destroy()
|
||||
},
|
||||
methods: {
|
||||
@@ -417,6 +369,9 @@ export default {
|
||||
},
|
||||
openRealtimeRenderOnNodeTextEdit: true,
|
||||
enableAutoEnterTextEditWhenKeydown: true,
|
||||
demonstrateConfig: {
|
||||
openBlankMode: false
|
||||
},
|
||||
...(config || {}),
|
||||
iconList: [...icon],
|
||||
useLeftKeySelectionRightKeyDrag: this.useLeftKeySelectionRightKeyDrag,
|
||||
@@ -490,116 +445,6 @@ export default {
|
||||
})
|
||||
})
|
||||
}
|
||||
// createNodePrefixContent: node => {
|
||||
// const el = document.createElement('div')
|
||||
// el.style.width = '50px'
|
||||
// el.style.height = '50px'
|
||||
// el.style.background = 'red'
|
||||
// return {
|
||||
// el,
|
||||
// width: 50,
|
||||
// height: 50
|
||||
// }
|
||||
// },
|
||||
// createNodePostfixContent: node => {
|
||||
// const domparser = new DOMParser()
|
||||
// const doc = domparser.parseFromString(
|
||||
// '<b style="background-color: rgb(214, 239, 214);">白日依山尽</b>',
|
||||
// 'text/html'
|
||||
// )
|
||||
// const el = doc.querySelector('b')
|
||||
// return {
|
||||
// el,
|
||||
// width: 50,
|
||||
// height: 50
|
||||
// }
|
||||
// },
|
||||
// addContentToHeader: () => {
|
||||
// const el = document.createElement('div')
|
||||
// el.className = 'footer'
|
||||
// el.innerHTML = '理想青年实验室'
|
||||
// const cssText = `
|
||||
// .header {
|
||||
// width: 100%;
|
||||
// height: 50px;
|
||||
// background: #f5f5f5;
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center
|
||||
// }
|
||||
// `
|
||||
// return {
|
||||
// el,
|
||||
// cssText,
|
||||
// height: 50
|
||||
// }
|
||||
// },
|
||||
// beforeShortcutRun: (key, activeNodeList) => {
|
||||
// console.log(key, activeNodeList)
|
||||
// // 阻止删除快捷键行为
|
||||
// if (key === 'Backspace') {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// handleNodePasteImg: img => {
|
||||
// console.log(img)
|
||||
// return new Promise(resolve => {
|
||||
// setTimeout(() => {
|
||||
// resolve({
|
||||
// url: require('../../../assets/img/themes/autumn.jpg'),
|
||||
// size: {
|
||||
// width: 100,
|
||||
// height: 100
|
||||
// }
|
||||
// })
|
||||
// }, 200)
|
||||
// })
|
||||
// }
|
||||
// isUseCustomNodeContent: true,
|
||||
// 示例1:组件里用到了router、store、i18n等实例化vue组件时需要用到的东西
|
||||
// customCreateNodeContent: (node) => {
|
||||
// let el = document.createElement('div')
|
||||
// let Comp = Vue.extend(Color)
|
||||
// let comp = new Comp({
|
||||
// router,
|
||||
// store,
|
||||
// i18n
|
||||
// })
|
||||
// comp.$mount(el)
|
||||
// return comp.$el
|
||||
// },
|
||||
// 示例2:组件里没有用到示例1的东西
|
||||
// customCreateNodeContent: (node) => {
|
||||
// let el = document.createElement('div')
|
||||
// let Comp = Vue.extend(CustomNodeContent)
|
||||
// let comp = new Comp({
|
||||
// propsData: {
|
||||
// html: node.nodeData.data.text
|
||||
// }
|
||||
// })
|
||||
// comp.$mount(el)
|
||||
// return comp.$el
|
||||
// },
|
||||
// 示例3:普通元素
|
||||
// customCreateNodeContent: node => {
|
||||
// let el = document.createElement('div')
|
||||
// el.style.cssText = `
|
||||
// width: 203px;
|
||||
// height: 78px;
|
||||
// opacity: 0.8;
|
||||
// background-image: linear-gradient(0deg, rgba(53,130,172,0.06) 0%, rgba(24,75,116,0.06) 100%);
|
||||
// box-shadow: inset 0 1px 15px 0 rgba(119,196,255,0.40);
|
||||
// border-radius: 2px;
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
// `
|
||||
// el.innerHTML = `
|
||||
// ${node.nodeData.data.text}
|
||||
// <img crossOrigin="anonymous" src="/img/cactus.jpg" />
|
||||
// `
|
||||
// return el
|
||||
// }
|
||||
})
|
||||
this.loadPlugins()
|
||||
this.mindMap.keyCommand.addShortcut('Control+s', () => {
|
||||
@@ -639,7 +484,6 @@ export default {
|
||||
})
|
||||
})
|
||||
this.bindSaveEvent()
|
||||
this.testDynamicCreateNodes()
|
||||
// 如果应用被接管,那么抛出事件传递思维导图实例
|
||||
if (window.takeOverApp) {
|
||||
this.$bus.$emit('app_inited', this.mindMap)
|
||||
@@ -656,93 +500,12 @@ export default {
|
||||
}
|
||||
// 协同测试
|
||||
this.cooperateTest()
|
||||
// 销毁
|
||||
// setTimeout(() => {
|
||||
// console.log('销毁')
|
||||
// this.mindMap.destroy()
|
||||
// }, 10000)
|
||||
// 测试
|
||||
// setTimeout(() => {
|
||||
// console.log(this.mindMap.renderer.root.getRect())
|
||||
// console.log(this.mindMap.renderer.root.getRectInSvg())
|
||||
// }, 5000);
|
||||
// setTimeout(() => {
|
||||
// this.mindMap.renderer.renderTree.data.fillColor = 'red'
|
||||
// this.mindMap.render()
|
||||
// this.mindMap.reRender()
|
||||
// this.mindMap.render()
|
||||
// }, 5000)
|
||||
},
|
||||
|
||||
// 加载相关插件
|
||||
loadPlugins() {
|
||||
if (this.openNodeRichText) this.addRichTextPlugin()
|
||||
if (this.isShowScrollbar) this.addScrollbarPlugin()
|
||||
if (typeof HandDrawnLikeStyle !== 'undefined') {
|
||||
this.$store.commit('setSupportHandDrawnLikeStyle', true)
|
||||
if (this.isUseHandDrawnLikeStyle) this.addHandDrawnLikeStylePlugin()
|
||||
}
|
||||
if (typeof Momentum !== 'undefined') {
|
||||
this.$store.commit('setSupportMomentum', true)
|
||||
if (this.isUseMomentum) this.addMomentumPlugin()
|
||||
}
|
||||
if (typeof Notation !== 'undefined') {
|
||||
this.mindMap.addPlugin(Notation)
|
||||
this.$store.commit('setSupportMark', true)
|
||||
}
|
||||
if (typeof Numbers !== 'undefined') {
|
||||
this.mindMap.addPlugin(Numbers)
|
||||
this.$store.commit('setSupportNumbers', true)
|
||||
}
|
||||
if (typeof Freemind !== 'undefined') {
|
||||
this.mindMap.addPlugin(Freemind)
|
||||
this.$store.commit('setSupportFreemind', true)
|
||||
Vue.prototype.Freemind = Freemind
|
||||
}
|
||||
if (typeof Excel !== 'undefined') {
|
||||
this.mindMap.addPlugin(Excel)
|
||||
this.$store.commit('setSupportExcel', true)
|
||||
Vue.prototype.Excel = Excel
|
||||
}
|
||||
if (typeof Checkbox !== 'undefined') {
|
||||
this.mindMap.addPlugin(Checkbox)
|
||||
this.$store.commit('setSupportCheckbox', true)
|
||||
}
|
||||
if (typeof LineFlow !== 'undefined') {
|
||||
this.mindMap.addPlugin(LineFlow)
|
||||
this.$store.commit('setSupportLineFlow', true)
|
||||
}
|
||||
if (typeof RightFishbone !== 'undefined') {
|
||||
this.mindMap.addPlugin(RightFishbone)
|
||||
this.$store.commit('setSupportRightFishbone', true)
|
||||
}
|
||||
if (typeof NodeLink !== 'undefined') {
|
||||
this.mindMap.addPlugin(NodeLink)
|
||||
this.$store.commit('setSupportNodeLink', true)
|
||||
}
|
||||
if (typeof MoreShapes !== 'undefined') {
|
||||
this.mindMap.addPlugin(MoreShapes)
|
||||
this.$store.commit('setSupportMoreShapes', true)
|
||||
}
|
||||
// 扩展侧边主题列表
|
||||
if (typeof MoreThemes !== 'undefined') {
|
||||
const extendThemeGroupList = [
|
||||
{
|
||||
name: '带背景', // 主题组名称
|
||||
// 主题列表
|
||||
list: [...MoreThemes.lightList, ...MoreThemes.darkList].map(
|
||||
item => {
|
||||
return {
|
||||
...item,
|
||||
img: MoreThemes.themeImgMap[item.value]
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
]
|
||||
this.$store.commit('setExtendThemeGroupList', extendThemeGroupList)
|
||||
this.$store.commit('setBgList', MoreThemes.bgList)
|
||||
}
|
||||
},
|
||||
|
||||
// url中是否存在要打开的文件
|
||||
@@ -802,21 +565,6 @@ export default {
|
||||
this.mindMap.updateConfig(data)
|
||||
},
|
||||
|
||||
// 显示新特性提示
|
||||
showNewFeatureInfo() {
|
||||
let showed = localStorage.getItem('SIMPLE_MIND_MAP_NEW_FEATURE_TIP_1')
|
||||
if (!showed) {
|
||||
this.$notify.info({
|
||||
title: this.$t('edit.newFeatureNoticeTitle'),
|
||||
message: this.$t('edit.newFeatureNoticeMessage'),
|
||||
duration: 0,
|
||||
onClose: () => {
|
||||
localStorage.setItem('SIMPLE_MIND_MAP_NEW_FEATURE_TIP_1', true)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 加载节点富文本编辑插件
|
||||
addRichTextPlugin() {
|
||||
if (!this.mindMap) return
|
||||
@@ -839,153 +587,6 @@ export default {
|
||||
this.mindMap.removePlugin(ScrollbarPlugin)
|
||||
},
|
||||
|
||||
// 加载手绘风格插件
|
||||
addHandDrawnLikeStylePlugin() {
|
||||
try {
|
||||
if (!this.mindMap) return
|
||||
this.mindMap.addPlugin(HandDrawnLikeStyle)
|
||||
this.mindMap.reRender()
|
||||
} catch (error) {
|
||||
console.log('手绘风格插件不存在')
|
||||
}
|
||||
},
|
||||
|
||||
// 移除手绘风格插件
|
||||
removeHandDrawnLikeStylePlugin() {
|
||||
try {
|
||||
this.mindMap.removePlugin(HandDrawnLikeStyle)
|
||||
this.mindMap.reRender()
|
||||
} catch (error) {
|
||||
console.log('手绘风格插件不存在')
|
||||
}
|
||||
},
|
||||
|
||||
// 加载动量效果插件
|
||||
addMomentumPlugin() {
|
||||
try {
|
||||
if (!this.mindMap) return
|
||||
this.mindMap.addPlugin(Momentum)
|
||||
} catch (error) {
|
||||
console.log('动量效果插件不存在')
|
||||
}
|
||||
},
|
||||
|
||||
// 移除动量效果插件
|
||||
removeMomentumPlugin() {
|
||||
try {
|
||||
this.mindMap.removePlugin(Momentum)
|
||||
} catch (error) {
|
||||
console.log('动量效果插件不存在')
|
||||
}
|
||||
},
|
||||
|
||||
// 测试动态插入节点
|
||||
testDynamicCreateNodes() {
|
||||
// return
|
||||
setTimeout(() => {
|
||||
// 动态给指定节点添加子节点
|
||||
// this.mindMap.execCommand(
|
||||
// 'INSERT_CHILD_NODE',
|
||||
// false,
|
||||
// null,
|
||||
// {
|
||||
// text: '自定义内容'
|
||||
// },
|
||||
// [
|
||||
// {
|
||||
// data: {
|
||||
// text: '自定义子节点'
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// )
|
||||
// 动态给指定节点添加同级节点
|
||||
// this.mindMap.execCommand(
|
||||
// 'INSERT_NODE',
|
||||
// false,
|
||||
// null,
|
||||
// {
|
||||
// text: '自定义内容'
|
||||
// },
|
||||
// [
|
||||
// {
|
||||
// data: {
|
||||
// text: '自定义同级节点'
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// data: {
|
||||
// text: '自定义同级节点2'
|
||||
// },
|
||||
// children: []
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// )
|
||||
// 动态插入多个子节点
|
||||
// this.mindMap.execCommand('INSERT_MULTI_CHILD_NODE', null, [
|
||||
// {
|
||||
// data: {
|
||||
// text: '自定义节点1'
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// data: {
|
||||
// text: '自定义节点1-1'
|
||||
// },
|
||||
// children: []
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// data: {
|
||||
// text: '自定义节点2'
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// data: {
|
||||
// text: '自定义节点2-1'
|
||||
// },
|
||||
// children: []
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ])
|
||||
// 动态插入多个同级节点
|
||||
// this.mindMap.execCommand('INSERT_MULTI_NODE', null, [
|
||||
// {
|
||||
// data: {
|
||||
// text: '自定义节点1'
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// data: {
|
||||
// text: '自定义节点1-1'
|
||||
// },
|
||||
// children: []
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// data: {
|
||||
// text: '自定义节点2'
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// data: {
|
||||
// text: '自定义节点2-1'
|
||||
// },
|
||||
// children: []
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ])
|
||||
// 动态删除指定节点
|
||||
// this.mindMap.execCommand('REMOVE_NODE', this.mindMap.renderer.root.children[0])
|
||||
}, 5000)
|
||||
},
|
||||
|
||||
// 协同测试
|
||||
cooperateTest() {
|
||||
if (this.mindMap.cooperate && this.$route.query.userName) {
|
||||
@@ -1012,9 +613,11 @@ export default {
|
||||
if (!this.enableDragImport || this.isDragOutlineTreeNode) return
|
||||
this.showDragMask = true
|
||||
},
|
||||
|
||||
onDragleave() {
|
||||
this.showDragMask = false
|
||||
},
|
||||
|
||||
onDrop(e) {
|
||||
if (!this.enableDragImport) return
|
||||
this.showDragMask = false
|
||||
@@ -1022,6 +625,70 @@ export default {
|
||||
const file = dt.files && dt.files[0]
|
||||
if (!file) return
|
||||
this.$bus.$emit('importFile', file)
|
||||
},
|
||||
|
||||
// 网页版试用提示
|
||||
webTip() {
|
||||
const storageKey = 'webUseTip'
|
||||
const data = localStorage.getItem(storageKey)
|
||||
if (data) {
|
||||
return
|
||||
}
|
||||
this.showDownloadTip(
|
||||
'重要提示',
|
||||
'网页版已暂停更新,部分功能缺失,请下载客户端获得完整体验~'
|
||||
)
|
||||
localStorage.setItem(storageKey, 1)
|
||||
},
|
||||
|
||||
showDownloadTip(title, desc) {
|
||||
const h = this.$createElement
|
||||
this.$msgbox({
|
||||
title,
|
||||
message: h('div', null, [
|
||||
h(
|
||||
'p',
|
||||
{
|
||||
style: {
|
||||
marginBottom: '12px'
|
||||
}
|
||||
},
|
||||
desc
|
||||
),
|
||||
h('div', null, [
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
attrs: {
|
||||
href:
|
||||
'https://pan.baidu.com/s/1huasEbKsGNH2Af68dvWiOg?pwd=3bp3',
|
||||
target: '_blank'
|
||||
},
|
||||
style: {
|
||||
color: '#409eff',
|
||||
marginRight: '12px'
|
||||
}
|
||||
},
|
||||
this.$t('edit.downBaidu')
|
||||
),
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
attrs: {
|
||||
href: 'https://github.com/wanglin2/mind-map/releases',
|
||||
target: '_blank'
|
||||
},
|
||||
style: {
|
||||
color: '#409eff'
|
||||
}
|
||||
},
|
||||
this.$t('edit.downGithub')
|
||||
)
|
||||
])
|
||||
]),
|
||||
showCancelButton: false,
|
||||
showConfirmButton: false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1059,11 +726,6 @@ export default {
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
// left: 100px;
|
||||
// top: 100px;
|
||||
// right: 100px;
|
||||
// bottom: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,16 +12,6 @@
|
||||
:top="isMobile ? '20px' : '15vh'"
|
||||
>
|
||||
<div class="exportContainer" :class="{ isDark: isDark }">
|
||||
<!-- 文件名称输入 -->
|
||||
<div class="nameInputBox">
|
||||
<span class="name">{{ $t('export.filename') }}</span>
|
||||
<el-input
|
||||
style="max-width: 300px"
|
||||
v-model="fileName"
|
||||
size="mini"
|
||||
@keydown.native.stop
|
||||
></el-input>
|
||||
</div>
|
||||
<!-- 导出类型选择 -->
|
||||
<div class="downloadTypeSelectBox">
|
||||
<!-- 类型列表 -->
|
||||
@@ -30,100 +20,127 @@
|
||||
class="downloadTypeItem"
|
||||
v-for="item in downTypeList"
|
||||
:key="item.type"
|
||||
:class="{ active: exportType === item.type }"
|
||||
:class="{
|
||||
active: exportType === item.type
|
||||
}"
|
||||
@click="exportType = item.type"
|
||||
>
|
||||
<div class="icon iconfont" :class="[item.icon, item.type]"></div>
|
||||
<div class="typeIcon" :class="[item.type]"></div>
|
||||
<div class="name">{{ item.name }}</div>
|
||||
<div class="icon checked el-icon-check"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 类型内容 -->
|
||||
<div class="downloadTypeContent customScrollbar">
|
||||
<div class="contentRow">
|
||||
<div class="contentName">{{ $t('export.desc') }}</div>
|
||||
<div class="contentValue">
|
||||
{{ currentTypeData ? currentTypeData.desc : '' }}
|
||||
<div class="downloadTypeContent">
|
||||
<!-- 文件名称输入 -->
|
||||
<div class="nameInputBox">
|
||||
<div class="nameInput">
|
||||
<span class="name">{{ $t('export.filename') }}</span>
|
||||
<el-input
|
||||
style="max-width: 250px"
|
||||
v-model="fileName"
|
||||
size="mini"
|
||||
@keydown.native.stop
|
||||
></el-input>
|
||||
</div>
|
||||
<span class="closeBtn el-icon-close" @click="cancel"></span>
|
||||
</div>
|
||||
<div class="contentRow">
|
||||
<div class="contentName">{{ $t('export.options') }}</div>
|
||||
<div class="contentValue">
|
||||
<div
|
||||
class="valueItem"
|
||||
v-show="['smm', 'json'].includes(exportType)"
|
||||
>
|
||||
<el-checkbox v-model="widthConfig">{{
|
||||
$t('export.include')
|
||||
}}</el-checkbox>
|
||||
<!-- 配置 -->
|
||||
<div class="contentBox customScrollbar">
|
||||
<div class="contentRow">
|
||||
<div class="contentName">{{ $t('export.format') }}</div>
|
||||
<div class="contentValue info">
|
||||
{{ currentTypeData ? '.' + currentTypeData.type : '' }}
|
||||
</div>
|
||||
<div
|
||||
class="valueItem"
|
||||
v-show="['svg', 'png', 'pdf'].includes(exportType)"
|
||||
>
|
||||
<div class="valueSubItem" v-if="['png'].includes(exportType)">
|
||||
<span class="name">{{ $t('export.format') }}</span>
|
||||
<el-radio-group v-model="imageFormat">
|
||||
<el-radio label="png">PNG</el-radio>
|
||||
<el-radio label="jpg">JPG</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="valueSubItem">
|
||||
<span class="name">{{ $t('export.paddingX') }}</span>
|
||||
<el-input
|
||||
style="width: 200px"
|
||||
v-model="paddingX"
|
||||
size="mini"
|
||||
@change="onPaddingChange"
|
||||
@keydown.native.stop
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="valueSubItem">
|
||||
<span class="name">{{ $t('export.paddingY') }}</span>
|
||||
<el-input
|
||||
style="width: 200px"
|
||||
v-model="paddingY"
|
||||
size="mini"
|
||||
@change="onPaddingChange"
|
||||
@keydown.native.stop
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="valueSubItem">
|
||||
<span class="name">{{
|
||||
this.$t('export.addFooterText')
|
||||
}}</span>
|
||||
<el-input
|
||||
style="width: 200px"
|
||||
v-model="extraText"
|
||||
size="mini"
|
||||
:placeholder="$t('export.addFooterTextPlaceholder')"
|
||||
@keydown.native.stop
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="valueSubItem">
|
||||
<el-checkbox
|
||||
v-show="['png', 'pdf'].includes(exportType)"
|
||||
v-model="isTransparent"
|
||||
>{{ $t('export.isTransparent') }}</el-checkbox
|
||||
>
|
||||
</div>
|
||||
<div class="valueSubItem">
|
||||
<el-checkbox v-show="showFitBgOption" v-model="isFitBg">{{
|
||||
$t('export.isFitBg')
|
||||
</div>
|
||||
<div class="contentRow">
|
||||
<div class="contentName">{{ $t('export.desc') }}</div>
|
||||
<div class="contentValue info">
|
||||
{{ currentTypeData ? currentTypeData.desc : '' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="contentRow">
|
||||
<div class="contentName">{{ $t('export.options') }}</div>
|
||||
<div class="contentValue info" v-if="noOptions">无</div>
|
||||
<div class="contentValue" v-else>
|
||||
<div
|
||||
class="valueItem"
|
||||
v-show="['smm', 'json'].includes(exportType)"
|
||||
>
|
||||
<el-checkbox v-model="widthConfig">{{
|
||||
$t('export.include')
|
||||
}}</el-checkbox>
|
||||
</div>
|
||||
<div
|
||||
class="valueItem"
|
||||
v-show="['svg', 'png', 'pdf'].includes(exportType)"
|
||||
>
|
||||
<div class="valueSubItem" v-if="['png'].includes(exportType)">
|
||||
<span class="name">{{ $t('export.format') }}</span>
|
||||
<el-radio-group v-model="imageFormat">
|
||||
<el-radio label="png">PNG</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="valueSubItem">
|
||||
<span class="name">{{ $t('export.paddingX') }}</span>
|
||||
<el-input
|
||||
style="width: 200px"
|
||||
v-model="paddingX"
|
||||
size="mini"
|
||||
@change="onPaddingChange"
|
||||
@keydown.native.stop
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="valueSubItem">
|
||||
<span class="name">{{ $t('export.paddingY') }}</span>
|
||||
<el-input
|
||||
style="width: 200px"
|
||||
v-model="paddingY"
|
||||
size="mini"
|
||||
@change="onPaddingChange"
|
||||
@keydown.native.stop
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="valueSubItem">
|
||||
<span class="name">{{
|
||||
this.$t('export.addFooterText')
|
||||
}}</span>
|
||||
<el-input
|
||||
style="width: 200px"
|
||||
v-model="extraText"
|
||||
size="mini"
|
||||
:placeholder="$t('export.addFooterTextPlaceholder')"
|
||||
@keydown.native.stop
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="valueSubItem">
|
||||
<el-checkbox
|
||||
v-show="['png', 'pdf'].includes(exportType)"
|
||||
v-model="isTransparent"
|
||||
>{{ $t('export.isTransparent') }}</el-checkbox
|
||||
>
|
||||
</div>
|
||||
<div class="valueSubItem">
|
||||
<el-checkbox v-show="showFitBgOption" v-model="isFitBg">{{
|
||||
$t('export.isFitBg')
|
||||
}}</el-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 按钮 -->
|
||||
<div class="btnList">
|
||||
<el-button @click="cancel" size="small">{{
|
||||
$t('dialog.cancel')
|
||||
}}</el-button>
|
||||
<el-button type="primary" @click="confirm" size="small">{{
|
||||
$t('export.confirm')
|
||||
}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{
|
||||
$t('dialog.confirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -157,18 +174,16 @@ export default {
|
||||
...mapState({
|
||||
openNodeRichText: state => state.localConfig.openNodeRichText,
|
||||
isDark: state => state.localConfig.isDark,
|
||||
supportFreemind: state => state.supportFreemind,
|
||||
supportExcel: state => state.supportExcel
|
||||
}),
|
||||
|
||||
downTypeList() {
|
||||
const list = downTypeList[this.$i18n.locale] || downTypeList.zh
|
||||
return list.filter(item => {
|
||||
if (item.type === 'mm') {
|
||||
return this.supportFreemind
|
||||
return false
|
||||
}
|
||||
if (item.type === 'xlsx') {
|
||||
return this.supportExcel
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
@@ -184,6 +199,10 @@ export default {
|
||||
|
||||
showFitBgOption() {
|
||||
return ['png', 'pdf'].includes(this.exportType) && !this.isTransparent
|
||||
},
|
||||
|
||||
noOptions() {
|
||||
return ['md', 'xmind', 'txt', 'xlsx', 'mm'].includes(this.exportType)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -251,22 +270,6 @@ export default {
|
||||
this.isTransparent,
|
||||
this.isFitBg
|
||||
)
|
||||
} else if (this.exportType === 'mm') {
|
||||
this.$bus.$emit('export', this.exportType, true, this.fileName, {
|
||||
transformNote: note => {
|
||||
if (!md) {
|
||||
md = new MarkdownIt()
|
||||
}
|
||||
return md.render(note)
|
||||
},
|
||||
transformImage: img => {
|
||||
if (/^https?:\/\//.test(img)) {
|
||||
return img
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$bus.$emit('export', this.exportType, true, this.fileName)
|
||||
}
|
||||
@@ -284,14 +287,10 @@ export default {
|
||||
.nodeExportDialog {
|
||||
.exportContainer {
|
||||
&.isDark {
|
||||
.nameInputBox {
|
||||
.name {
|
||||
color: hsla(0, 0%, 100%, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.downloadTypeSelectBox {
|
||||
.downloadTypeList {
|
||||
background-color: #363b3f;
|
||||
|
||||
.downloadTypeItem {
|
||||
background-color: #363b3f;
|
||||
|
||||
@@ -306,15 +305,39 @@ export default {
|
||||
}
|
||||
|
||||
.downloadTypeContent {
|
||||
.contentRow {
|
||||
.contentName {
|
||||
color: hsla(0, 0%, 100%, 0.6);
|
||||
.nameInputBox {
|
||||
border-bottom: 1px solid hsla(0, 0%, 100%, 0.6);
|
||||
|
||||
.nameInput {
|
||||
.name {
|
||||
color: hsla(0, 0%, 100%, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.contentValue {
|
||||
.closeBtn {
|
||||
color: hsla(0, 0%, 100%, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.contentBox {
|
||||
.contentRow {
|
||||
.contentName {
|
||||
color: hsla(0, 0%, 100%, 0.6);
|
||||
}
|
||||
|
||||
.contentValue {
|
||||
color: hsla(0, 0%, 100%, 0.6);
|
||||
|
||||
&.info {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btnList {
|
||||
border-top: 1px solid hsla(0, 0%, 100%, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -332,10 +355,17 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .el-dialog {
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
|
||||
.el-dialog__header {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .el-dialog__body {
|
||||
padding: 0;
|
||||
border-top: 1px solid #f2f4f7;
|
||||
border-bottom: 1px solid #f2f4f7;
|
||||
|
||||
.el-checkbox__input.is-checked + .el-checkbox__label {
|
||||
color: #409eff !important;
|
||||
@@ -359,11 +389,13 @@ export default {
|
||||
align-items: center;
|
||||
overflow-x: auto;
|
||||
height: 60px;
|
||||
overflow-y: hidden;
|
||||
|
||||
.downloadTypeItem {
|
||||
width: 100px;
|
||||
flex-shrink: 0;
|
||||
padding-left: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
|
||||
.icon {
|
||||
margin-right: 5px;
|
||||
@@ -376,21 +408,33 @@ export default {
|
||||
}
|
||||
|
||||
.downloadTypeContent {
|
||||
.contentRow {
|
||||
flex-direction: column;
|
||||
.nameInputBox {
|
||||
height: 70px;
|
||||
|
||||
.contentName {
|
||||
margin-bottom: 10px;
|
||||
.nameInput {
|
||||
.name {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contentValue {
|
||||
.valueItem {
|
||||
.valueSubItem {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.contentBox {
|
||||
.contentRow {
|
||||
flex-direction: column;
|
||||
|
||||
.name {
|
||||
margin-bottom: 5px;
|
||||
.contentName {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.contentValue {
|
||||
.valueItem {
|
||||
.valueSubItem {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.name {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -403,25 +447,11 @@ export default {
|
||||
|
||||
.exportContainer {
|
||||
width: 100%;
|
||||
height: 450px;
|
||||
height: 552px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.nameInputBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
height: 50px;
|
||||
flex-shrink: 0;
|
||||
border-bottom: 1px solid #f2f4f7;
|
||||
|
||||
.name {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.downloadTypeSelectBox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -429,17 +459,18 @@ export default {
|
||||
display: flex;
|
||||
|
||||
.downloadTypeList {
|
||||
width: 210px;
|
||||
width: 208px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
background-color: #f2f4f7;
|
||||
flex-shrink: 0;
|
||||
padding: 16px 0;
|
||||
|
||||
.downloadTypeItem {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
padding-left: 28px;
|
||||
height: 52px;
|
||||
padding: 0 30px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -457,40 +488,7 @@ export default {
|
||||
|
||||
.icon {
|
||||
font-size: 25px;
|
||||
margin-right: 15px;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.png {
|
||||
color: #ffc038;
|
||||
}
|
||||
|
||||
&.pdf {
|
||||
color: #ff6c4d;
|
||||
}
|
||||
|
||||
&.md {
|
||||
color: #2b2b2b;
|
||||
}
|
||||
|
||||
&.json {
|
||||
color: #12c87e;
|
||||
}
|
||||
|
||||
&.svg {
|
||||
color: #4380ff;
|
||||
}
|
||||
|
||||
&.smm {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
&.xmind {
|
||||
color: #f55e5e;
|
||||
}
|
||||
|
||||
&.txt {
|
||||
color: #70798e;
|
||||
}
|
||||
font-weight: 700;
|
||||
|
||||
&.checked {
|
||||
color: #409eff;
|
||||
@@ -500,53 +498,183 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
.typeIcon {
|
||||
margin-right: 18px;
|
||||
flex-shrink: 0;
|
||||
width: 23px;
|
||||
height: 26px;
|
||||
background-size: cover;
|
||||
|
||||
&.png {
|
||||
background-image: url('../../../assets/img/foramt/2.png');
|
||||
}
|
||||
|
||||
&.pdf {
|
||||
background-image: url('../../../assets/img/foramt/4.png');
|
||||
}
|
||||
|
||||
&.md {
|
||||
background-image: url('../../../assets/img/foramt/5.png');
|
||||
}
|
||||
|
||||
&.json {
|
||||
background-image: url('../../../assets/img/foramt/10.png');
|
||||
}
|
||||
|
||||
&.svg {
|
||||
background-image: url('../../../assets/img/foramt/3.png');
|
||||
}
|
||||
|
||||
&.smm {
|
||||
background-image: url('../../../assets/img/foramt/1.png');
|
||||
}
|
||||
|
||||
&.xmind {
|
||||
background-image: url('../../../assets/img/foramt/6.png');
|
||||
}
|
||||
|
||||
&.txt {
|
||||
background-image: url('../../../assets/img/foramt/7.png');
|
||||
}
|
||||
|
||||
&.mm {
|
||||
background-image: url('../../../assets/img/foramt/8.png');
|
||||
}
|
||||
|
||||
&.xlsx {
|
||||
background-image: url('../../../assets/img/foramt/9.png');
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
color: #1a1a1a;
|
||||
color: #333;
|
||||
font-size: 15px;
|
||||
margin-bottom: 5px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.downloadTypeContent {
|
||||
padding: 30px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.contentRow {
|
||||
.nameInputBox {
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 67px;
|
||||
flex-shrink: 0;
|
||||
border-bottom: 1px solid #f2f4f7;
|
||||
padding-left: 40px;
|
||||
padding-right: 20px;
|
||||
padding-top: 16px;
|
||||
|
||||
.contentName {
|
||||
width: 80px;
|
||||
color: #666;
|
||||
.nameInput {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
font-weight: bold;
|
||||
|
||||
.name {
|
||||
margin-right: 10px;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.contentValue {
|
||||
color: #1a1a1a;
|
||||
.closeBtn {
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.valueItem {
|
||||
.valueSubItem {
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
.contentBox {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 15px 40px;
|
||||
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
.contentRow {
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.name {
|
||||
margin-right: 12px;
|
||||
width: 100px;
|
||||
&:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.contentName {
|
||||
min-width: 40px;
|
||||
color: #808080;
|
||||
flex-shrink: 0;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
line-height: 25px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.contentValue {
|
||||
color: #808080;
|
||||
line-height: 23px;
|
||||
font-weight: 500;
|
||||
border: 1px solid transparent;
|
||||
font-size: 14px;
|
||||
|
||||
&.info {
|
||||
color: rgb(90, 158, 247);
|
||||
background-color: rgb(245, 248, 249);
|
||||
border: 1px solid rgb(90, 158, 247);
|
||||
border-radius: 5px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.valueItem {
|
||||
.valueSubItem {
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&.alignCenter {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.name {
|
||||
margin-right: 12px;
|
||||
min-width: 85px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btnList {
|
||||
padding: 0 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
height: 69px;
|
||||
flex-shrink: 0;
|
||||
border-top: 1px solid #f2f4f7;
|
||||
|
||||
/deep/ .el-button--small {
|
||||
height: 25px;
|
||||
padding: 0 30px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class="nodeImportDialog"
|
||||
:title="$t('import.title')"
|
||||
:visible.sync="dialogVisible"
|
||||
width="300px"
|
||||
width="350px"
|
||||
>
|
||||
<el-upload
|
||||
ref="upload"
|
||||
@@ -59,7 +59,7 @@
|
||||
<script>
|
||||
import xmind from 'simple-mind-map/src/parse/xmind.js'
|
||||
import markdown from 'simple-mind-map/src/parse/markdown.js'
|
||||
import { mapMutations, mapState } from 'vuex'
|
||||
import { mapMutations } from 'vuex'
|
||||
import Vue from 'vue'
|
||||
|
||||
// 导入
|
||||
@@ -71,23 +71,13 @@ export default {
|
||||
selectPromiseResolve: null,
|
||||
xmindCanvasSelectDialogVisible: false,
|
||||
selectCanvas: '',
|
||||
canvasList: []
|
||||
canvasList: [],
|
||||
mdStr: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
supportFreemind: state => state.supportFreemind,
|
||||
supportExcel: state => state.supportExcel
|
||||
}),
|
||||
supportFileStr() {
|
||||
let res = '.smm,.json,.xmind,.md'
|
||||
if (this.supportFreemind) {
|
||||
res += ',.mm'
|
||||
}
|
||||
if (this.supportExcel) {
|
||||
res += ',.xlsx'
|
||||
}
|
||||
return res
|
||||
return '.smm,.json,.xmind,.md'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -115,11 +105,7 @@ export default {
|
||||
},
|
||||
|
||||
getRegexp() {
|
||||
return new RegExp(
|
||||
`\.(smm|json|xmind|md${this.supportFreemind ? '|mm' : ''}${
|
||||
this.supportExcel ? '|xlsx' : ''
|
||||
})$`
|
||||
)
|
||||
return new RegExp(`\.(smm|json|xmind|md)$`)
|
||||
},
|
||||
|
||||
// 检查url中是否操作需要打开的文件
|
||||
@@ -141,12 +127,8 @@ export default {
|
||||
this.handleSmm(data)
|
||||
} else if (type === 'xmind') {
|
||||
this.handleXmind(data)
|
||||
} else if (type === 'xlsx') {
|
||||
this.handleExcel(data)
|
||||
} else if (type === 'md') {
|
||||
this.handleMd(data)
|
||||
} else if (type === 'mm') {
|
||||
this.handleMm(data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
@@ -193,12 +175,8 @@ export default {
|
||||
this.handleSmm(file)
|
||||
} else if (/\.xmind$/.test(file.name)) {
|
||||
this.handleXmind(file)
|
||||
} else if (/\.xlsx$/.test(file.name)) {
|
||||
this.handleExcel(file)
|
||||
} else if (/\.md$/.test(file.name)) {
|
||||
this.handleMd(file)
|
||||
} else if (/\.mm$/.test(file.name)) {
|
||||
this.handleMm(file)
|
||||
}
|
||||
this.cancel()
|
||||
this.setActiveSidebar(null)
|
||||
@@ -240,36 +218,6 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
// 处理Freemind格式
|
||||
handleMm(file) {
|
||||
const fileReader = new FileReader()
|
||||
fileReader.readAsText(file.raw)
|
||||
fileReader.onload = async evt => {
|
||||
try {
|
||||
const data = await Vue.prototype.Freemind.freemindToSmm(
|
||||
evt.target.result,
|
||||
{
|
||||
// withStyle: true,
|
||||
transformImg: image => {
|
||||
return new Promise(resolve => {
|
||||
if (/^https?:\/\//.test(image)) {
|
||||
resolve({ url: image })
|
||||
} else {
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
this.$bus.$emit('setData', data)
|
||||
this.$message.success(this.$t('import.importSuccess'))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
this.$message.error(this.$t('import.fileParsingFailed'))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 显示xmind文件的多个画布选择弹窗
|
||||
showSelectXmindCanvasDialog(content) {
|
||||
this.canvasList = content
|
||||
@@ -285,18 +233,6 @@ export default {
|
||||
this.selectCanvas = 0
|
||||
},
|
||||
|
||||
// 处理.xlsx文件
|
||||
async handleExcel(file) {
|
||||
try {
|
||||
const res = await Vue.prototype.Excel.excelTo(file.raw)
|
||||
this.$bus.$emit('setData', res)
|
||||
this.$message.success(this.$t('import.importSuccess'))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
this.$message.error(this.$t('import.fileParsingFailed'))
|
||||
}
|
||||
},
|
||||
|
||||
// 处理markdown文件
|
||||
async handleMd(file) {
|
||||
let fileReader = new FileReader()
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="nodeLinkSelectDialog"
|
||||
:title="$t('nodeLink.linkToNode')"
|
||||
:visible.sync="dialogVisible"
|
||||
:show-close="false"
|
||||
append-to-body
|
||||
width="400px"
|
||||
>
|
||||
<div class="nodeTreeWrap customScrollbar">
|
||||
<el-tree
|
||||
ref="treeRef"
|
||||
class="outlineTree"
|
||||
node-key="uid"
|
||||
default-expand-all
|
||||
:class="{ isDark: isDark }"
|
||||
:data="treeData"
|
||||
:props="defaultProps"
|
||||
:highlight-current="true"
|
||||
:expand-on-click-node="false"
|
||||
@current-change="onCurrentChange"
|
||||
>
|
||||
</el-tree>
|
||||
</div>
|
||||
<div slot="footer" class="footer">
|
||||
<el-checkbox v-model="isAddReturn" style="margin-right: auto;">{{
|
||||
$t('nodeLink.addReturn')
|
||||
}}</el-checkbox>
|
||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{
|
||||
$t('dialog.confirm')
|
||||
}}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
nodeRichTextToTextWithWrap,
|
||||
htmlEscape
|
||||
} from 'simple-mind-map/src/utils'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
mindMap: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
treeData: [],
|
||||
defaultProps: {
|
||||
label: 'label'
|
||||
},
|
||||
currentNodeData: null,
|
||||
node: null,
|
||||
isAddReturn: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isDark: state => state.localConfig.isDark
|
||||
})
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on('show_link_node', this.onShowDialog)
|
||||
this.mindMap.on('node_link_not_find', this.onNodeLinkNotFind)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off('show_link_node', this.onShowDialog)
|
||||
this.mindMap.off('node_link_not_find', this.onNodeLinkNotFind)
|
||||
},
|
||||
methods: {
|
||||
onShowDialog(node) {
|
||||
this.node = node
|
||||
let data = this.mindMap.getData()
|
||||
let walk = root => {
|
||||
let text = root.data.richText
|
||||
? nodeRichTextToTextWithWrap(root.data.text)
|
||||
: root.data.text
|
||||
text = htmlEscape(text)
|
||||
text = text.replace(/\n/g, '<br>')
|
||||
root.label = text
|
||||
root.uid = root.data.uid
|
||||
if (root.children && root.children.length > 0) {
|
||||
root.children.forEach(item => {
|
||||
walk(item)
|
||||
})
|
||||
}
|
||||
}
|
||||
walk(data)
|
||||
this.treeData = [data]
|
||||
this.dialogVisible = true
|
||||
this.$nextTick(() => {
|
||||
const linkUid = node.getData('nodeLink')
|
||||
if (linkUid) {
|
||||
this.$refs.treeRef.setCurrentKey(linkUid)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
close() {
|
||||
this.dialogVisible = false
|
||||
this.node = null
|
||||
this.treeData = []
|
||||
this.currentNodeData = null
|
||||
this.isAddReturn = false
|
||||
},
|
||||
|
||||
// 当前选中的树节点变化事件
|
||||
onCurrentChange(data) {
|
||||
this.currentNodeData = data
|
||||
},
|
||||
|
||||
cancel() {
|
||||
this.close()
|
||||
},
|
||||
|
||||
confirm() {
|
||||
if (!this.currentNodeData) {
|
||||
this.$message.warning(this.$t('nodeLink.tip1'))
|
||||
return
|
||||
}
|
||||
if (this.currentNodeData.uid === this.node.getData('uid')) {
|
||||
this.$message.warning(this.$t('nodeLink.tip2'))
|
||||
return
|
||||
}
|
||||
this.$bus.$emit(
|
||||
'execCommand',
|
||||
'SET_NODE_LINK',
|
||||
this.node,
|
||||
this.currentNodeData.uid,
|
||||
this.isAddReturn
|
||||
)
|
||||
this.$message.success(this.$t('nodeLink.tip3'))
|
||||
this.close()
|
||||
},
|
||||
|
||||
onNodeLinkNotFind(node) {
|
||||
this.$confirm(this.$t('nodeLink.tip5'), this.$t('edit.tip'), {
|
||||
confirmButtonText: this.$t('setting.confirm'),
|
||||
cancelButtonText: this.$t('setting.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$bus.$emit('execCommand', 'SET_NODE_LINK', node, null)
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: this.$t('nodeLink.tip4')
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.nodeLinkSelectDialog {
|
||||
/deep/ .el-dialog__body {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
.nodeTreeWrap {
|
||||
height: 400px;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
@import url('../../../style/outlineTree.less');
|
||||
</style>
|
||||
@@ -80,7 +80,7 @@
|
||||
@click="toggleDark"
|
||||
></div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<!-- <div class="item">
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('navigatorToolbar.changeSourceCodeEdit')"
|
||||
@@ -88,19 +88,39 @@
|
||||
>
|
||||
<div class="btn iconfont iconyuanma" @click="openSourceCodeEdit"></div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="item">
|
||||
<Demonstrate :isDark="isDark" :mindMap="mindMap"></Demonstrate>
|
||||
</div>
|
||||
<div class="item">
|
||||
<el-dropdown @command="handleCommand">
|
||||
<div class="btn iconfont iconbangzhu"></div>
|
||||
<div class="btn el-icon-more"></div>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="client">下载客户端</el-dropdown-item>
|
||||
<el-dropdown-item command="github">Github</el-dropdown-item>
|
||||
<el-dropdown-item command="site">官方网站</el-dropdown-item>
|
||||
<el-dropdown-item command="issue">意见反馈</el-dropdown-item>
|
||||
<el-dropdown-item disabled>当前:v{{ version }}</el-dropdown-item>
|
||||
<el-dropdown-item command="shortcutKey">
|
||||
<span class="iconfont iconjianpan"></span>
|
||||
{{ $t('navigatorToolbar.shortcutKeys') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="aiChat">
|
||||
<span class="iconfont iconAIshengcheng"></span>
|
||||
{{ $t('navigatorToolbar.ai') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="client">
|
||||
<span class="iconfont iconxiazai"></span>
|
||||
{{ $t('navigatorToolbar.downloadClient') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="github">
|
||||
<span class="iconfont icongithub"></span>
|
||||
Github
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="site">
|
||||
<span class="iconfont iconwangzhan"></span>
|
||||
{{ $t('navigatorToolbar.site') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item disabled
|
||||
>{{ $t('navigatorToolbar.current') }}v{{
|
||||
version
|
||||
}}</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
@@ -149,7 +169,12 @@ export default {
|
||||
this.lang = getLang()
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setLocalConfig', 'setIsReadonly', 'setIsSourceCodeEdit']),
|
||||
...mapMutations([
|
||||
'setLocalConfig',
|
||||
'setIsReadonly',
|
||||
'setIsSourceCodeEdit',
|
||||
'setActiveSidebar'
|
||||
]),
|
||||
|
||||
readonlyChange() {
|
||||
this.setIsReadonly(!this.isReadonly)
|
||||
@@ -178,6 +203,20 @@ export default {
|
||||
},
|
||||
|
||||
handleCommand(command) {
|
||||
if (command === 'shortcutKey') {
|
||||
this.setActiveSidebar('shortcutKey')
|
||||
return
|
||||
} else if (command === 'aiChat') {
|
||||
this.setActiveSidebar('ai')
|
||||
return
|
||||
} else if (command === 'client') {
|
||||
this.$bus.$emit(
|
||||
'showDownloadTip',
|
||||
this.$t('navigatorToolbar.downloadClient'),
|
||||
this.$t('navigatorToolbar.downloadDesc')
|
||||
)
|
||||
return
|
||||
}
|
||||
let url = ''
|
||||
switch (command) {
|
||||
case 'github':
|
||||
@@ -196,8 +235,7 @@ export default {
|
||||
case 'issue':
|
||||
url = 'https://github.com/wanglin2/mind-map/issues/new'
|
||||
break
|
||||
case 'client':
|
||||
url = 'https://pan.baidu.com/s/1huasEbKsGNH2Af68dvWiOg?pwd=3bp3'
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
<template>
|
||||
<el-popover placement="bottom" width="200" trigger="click">
|
||||
<div class="annotationConfigBox" :class="{ isDark: isDark }">
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.show') }}</span>
|
||||
<el-switch
|
||||
v-model="show"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949"
|
||||
@change="onChange"
|
||||
>
|
||||
</el-switch>
|
||||
</div>
|
||||
<template v-if="show">
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.type') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
v-model="annotationConfig.type"
|
||||
@change="onChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in annotationTypeList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.color') }}</span>
|
||||
<span
|
||||
class="block"
|
||||
v-popover:popover
|
||||
:style="{ backgroundColor: annotationConfig.color }"
|
||||
></span>
|
||||
<el-popover ref="popover" placement="bottom" trigger="hover">
|
||||
<Color
|
||||
:color="annotationConfig.color"
|
||||
@change="onColorChange"
|
||||
></Color>
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.lineWidth') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
v-model="annotationConfig.strokeWidth"
|
||||
placeholder=""
|
||||
@change="onChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in lineWidthList"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
>
|
||||
<span
|
||||
v-if="item > 0"
|
||||
class="borderLine"
|
||||
:class="{ isDark: isDark }"
|
||||
:style="{ height: item + 'px' }"
|
||||
></span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.padding') }}</span>
|
||||
<el-input-number
|
||||
v-model="annotationConfig.padding"
|
||||
:step="5"
|
||||
size="mini"
|
||||
@change="onChange"
|
||||
></el-input-number>
|
||||
</div>
|
||||
<div class="annotationConfigItem">
|
||||
<span class="name">{{ $t('annotation.animate') }}</span>
|
||||
<el-switch
|
||||
v-model="annotationConfig.animate"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949"
|
||||
@change="onChange"
|
||||
>
|
||||
</el-switch>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div
|
||||
slot="reference"
|
||||
class="toolbarBtn"
|
||||
:style="{
|
||||
marginLeft: dir === 'v' || rightHasBtn ? '0px' : '20px',
|
||||
marginTop: dir === 'v' ? '10px' : '0px',
|
||||
marginRight: rightHasBtn ? '20px' : '0px',
|
||||
marginBottom: dir === 'v' && rightHasBtn ? '10px' : '0px'
|
||||
}"
|
||||
:class="{
|
||||
disabled: activeNodes.length <= 0 || hasGeneralization
|
||||
}"
|
||||
>
|
||||
<span class="icon iconfont iconhighlight"></span>
|
||||
<span class="text">{{ $t('annotation.mark') }}</span>
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { lineWidthList } from '@/config'
|
||||
import Color from './Color.vue'
|
||||
|
||||
const defaultConfig = {
|
||||
type: 'circle',
|
||||
color: '',
|
||||
strokeWidth: 1,
|
||||
animate: true,
|
||||
padding: 20
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Color
|
||||
},
|
||||
props: {
|
||||
isDark: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
dir: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
rightHasBtn: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lineWidthList: lineWidthList.slice(1),
|
||||
activeNodes: [],
|
||||
show: false,
|
||||
annotationConfig: {
|
||||
...defaultConfig
|
||||
},
|
||||
annotationTypeList: [
|
||||
{
|
||||
label: '圆',
|
||||
value: 'circle'
|
||||
},
|
||||
{
|
||||
label: '边框',
|
||||
value: 'box'
|
||||
},
|
||||
{
|
||||
label: '高亮',
|
||||
value: 'highlight'
|
||||
},
|
||||
{
|
||||
label: '下划线',
|
||||
value: 'underline'
|
||||
},
|
||||
{
|
||||
label: '删除线',
|
||||
value: 'strike-through'
|
||||
},
|
||||
{
|
||||
label: '叉',
|
||||
value: 'crossed-off'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasGeneralization() {
|
||||
return (
|
||||
this.activeNodes.findIndex(node => {
|
||||
return node.isGeneralization
|
||||
}) !== -1
|
||||
)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$bus.$on('node_active', this.onNodeActive)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off('node_active', this.onNodeActive)
|
||||
},
|
||||
methods: {
|
||||
onNodeActive(...args) {
|
||||
this.activeNodes = [...args[1]]
|
||||
const node = this.activeNodes[0]
|
||||
if (node) {
|
||||
const notationData = node.getData('notation')
|
||||
if (notationData) {
|
||||
const { show, config } = notationData
|
||||
this.show = show
|
||||
this.annotationConfig = {
|
||||
...defaultConfig,
|
||||
...config
|
||||
}
|
||||
} else {
|
||||
this.reset()
|
||||
}
|
||||
} else {
|
||||
this.reset()
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.show = false
|
||||
this.annotationConfig = {
|
||||
...defaultConfig
|
||||
}
|
||||
},
|
||||
|
||||
onChange() {
|
||||
this.$emit('setAnnotation', this.show, {
|
||||
...this.annotationConfig
|
||||
})
|
||||
},
|
||||
|
||||
onColorChange(color) {
|
||||
this.annotationConfig.color = color
|
||||
this.onChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.annotationConfigBox {
|
||||
&.isDark {
|
||||
.annotationConfigItem {
|
||||
.name {
|
||||
color: hsla(0, 0%, 100%, 0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.annotationConfigItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.name {
|
||||
flex-shrink: 0;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.block {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.borderLine {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
background-color: #000;
|
||||
|
||||
&.isDark {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,133 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="nodeAttachmentContextMenu"
|
||||
:style="{
|
||||
left: this.left + 'px',
|
||||
top: this.top + 'px',
|
||||
visibility: show ? 'visible' : 'hidden'
|
||||
}"
|
||||
@click.stop="deleteAttachment"
|
||||
>
|
||||
<div class="menuItem">{{ $t('attachment.deleteAttachment') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
mindMap: {
|
||||
type: Object,
|
||||
default() {
|
||||
return null
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
left: 0,
|
||||
top: 0,
|
||||
node: null,
|
||||
icon: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on('node_attachmentClick', this.onNodeAttachmentClick)
|
||||
this.$bus.$on('selectAttachment', this.onSelectAttachment)
|
||||
this.$bus.$on(
|
||||
'node_attachmentContextmenu',
|
||||
this.onNodeAttachmentContextmenu
|
||||
)
|
||||
this.$bus.$on('hide', this.hide)
|
||||
document.body.addEventListener('click', this.hide)
|
||||
this.$bus.$on('node_active', this.hide)
|
||||
this.$bus.$on('scale', this.onScale)
|
||||
this.$bus.$on('translate', this.onScale)
|
||||
this.$bus.$on('svg_mousedown', this.hide)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off('node_attachmentClick', this.onNodeAttachmentClick)
|
||||
this.$bus.$off('selectAttachment', this.onSelectAttachment)
|
||||
this.$bus.$off(
|
||||
'node_attachmentContextmenu',
|
||||
this.onNodeAttachmentContextmenu
|
||||
)
|
||||
this.$bus.$off('hide', this.hide)
|
||||
document.body.removeEventListener('click', this.hide)
|
||||
this.$bus.$off('node_active', this.hide)
|
||||
this.$bus.$off('scale', this.onScale)
|
||||
this.$bus.$off('translate', this.onScale)
|
||||
this.$bus.$off('svg_mousedown', this.hide)
|
||||
},
|
||||
methods: {
|
||||
// 选择附件
|
||||
onSelectAttachment(activeNodes) {
|
||||
// activeNodes.forEach(node => {
|
||||
// node.setAttachment('/test.md', '我去')
|
||||
// })
|
||||
},
|
||||
|
||||
// 点击附件图标,一般用来打开或下载附件
|
||||
onNodeAttachmentClick(node, e, icon) {
|
||||
// console.log(node.getData('attachmentUrl'))
|
||||
this.$message.info(this.$t('attachment.tip'))
|
||||
},
|
||||
|
||||
// 显示删除浮层
|
||||
onNodeAttachmentContextmenu(node, e, icon) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
this.node = node
|
||||
this.icon = icon
|
||||
this.updatePosition()
|
||||
this.show = true
|
||||
},
|
||||
|
||||
// 更新位置
|
||||
updatePosition() {
|
||||
const iconSize = this.mindMap.themeConfig.iconSize
|
||||
const { x, y } = this.icon.rbox()
|
||||
this.left = x + iconSize
|
||||
this.top = y
|
||||
},
|
||||
|
||||
// 画布缩放事件
|
||||
onScale() {
|
||||
if (!this.node || !this.show) return
|
||||
this.updatePosition()
|
||||
},
|
||||
|
||||
// 删除附件
|
||||
deleteAttachment() {
|
||||
if (!this.node || !this.show) return
|
||||
this.node.setAttachment('', '')
|
||||
this.hide()
|
||||
},
|
||||
|
||||
// 隐藏浮层
|
||||
hide() {
|
||||
this.show = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.nodeAttachmentContextMenu {
|
||||
position: fixed;
|
||||
background-color: #fff;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 16px 0 rgba(0, 0, 0, 0.06);
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
|
||||
.menuItem {
|
||||
font-size: 14px;
|
||||
font-family: PingFangSC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -72,7 +72,7 @@ export default {
|
||||
this.reset()
|
||||
if (this.activeNodes.length > 0) {
|
||||
let firstNode = this.activeNodes[0]
|
||||
let img = firstNode.getData('image') || ''
|
||||
let img = firstNode.getImageUrl() || ''
|
||||
if (img) {
|
||||
if (/^https?:\/\//.test(img)) {
|
||||
this.imgUrl = img
|
||||
|
||||
@@ -29,7 +29,7 @@ export default {
|
||||
onNodeTmgDblclick(node, e) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
this.images = [node.nodeData.data.image]
|
||||
this.images = [node.getImageUrl()]
|
||||
this.$viewerApi({
|
||||
images: this.images
|
||||
})
|
||||
|
||||
@@ -256,26 +256,6 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 是否开启手绘风格 -->
|
||||
<div class="row" v-if="supportHandDrawnLikeStyle">
|
||||
<div class="rowItem">
|
||||
<el-checkbox
|
||||
v-model="localConfigs.isUseHandDrawnLikeStyle"
|
||||
@change="updateLocalConfig('isUseHandDrawnLikeStyle', $event)"
|
||||
>{{ $t('setting.isUseHandDrawnLikeStyle') }}</el-checkbox
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 是否开启动量效果 -->
|
||||
<div class="row" v-if="supportMomentum">
|
||||
<div class="rowItem">
|
||||
<el-checkbox
|
||||
v-model="localConfigs.isUseMomentum"
|
||||
@change="updateLocalConfig('isUseMomentum', $event)"
|
||||
>{{ $t('setting.isUseMomentum') }}</el-checkbox
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 配置鼠标滚轮行为 -->
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
@@ -443,8 +423,6 @@ export default {
|
||||
enableNodeRichText: true,
|
||||
localConfigs: {
|
||||
isShowScrollbar: false,
|
||||
isUseHandDrawnLikeStyle: false,
|
||||
isUseMomentum: false,
|
||||
enableDragImport: false,
|
||||
enableAi: false
|
||||
}
|
||||
@@ -454,9 +432,7 @@ export default {
|
||||
...mapState({
|
||||
activeSidebar: state => state.activeSidebar,
|
||||
localConfig: state => state.localConfig,
|
||||
isDark: state => state.localConfig.isDark,
|
||||
supportHandDrawnLikeStyle: state => state.supportHandDrawnLikeStyle,
|
||||
supportMomentum: state => state.supportMomentum
|
||||
isDark: state => state.localConfig.isDark
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
@@ -483,7 +459,13 @@ export default {
|
||||
// 初始化其他配置
|
||||
initConfig() {
|
||||
Object.keys(this.config).forEach(key => {
|
||||
this.config[key] = this.mindMap.getConfig(key)
|
||||
if (typeof this.config[key] === 'object') {
|
||||
this.config[key] = {
|
||||
...(this.mindMap.getConfig(key) || {})
|
||||
}
|
||||
} else {
|
||||
this.config[key] = this.mindMap.getConfig(key)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="sourceCodeEditContainer"
|
||||
:class="{ isDark: isDark }"
|
||||
ref="sourceCodeEditContainer"
|
||||
v-if="isSourceCodeEdit"
|
||||
>
|
||||
<div class="closeBtn">
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('sourceCodeEdit.copy')"
|
||||
placement="top"
|
||||
>
|
||||
<span
|
||||
class="icon iconfont iconfuzhi"
|
||||
style="font-size: 26px"
|
||||
@click="copy"
|
||||
></span>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('sourceCodeEdit.format')"
|
||||
placement="top"
|
||||
>
|
||||
<span
|
||||
class="icon iconfont icongeshihua"
|
||||
style="font-size: 24px"
|
||||
@click="format"
|
||||
></span>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('sourceCodeEdit.sourceCodeTip')"
|
||||
placement="top"
|
||||
>
|
||||
<span class="icon el-icon-info"></span>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('sourceCodeEdit.confirm')"
|
||||
placement="top"
|
||||
>
|
||||
<span class="icon el-icon-circle-check" @click="onConfirm"></span>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="$t('sourceCodeEdit.close')"
|
||||
placement="top"
|
||||
>
|
||||
<span class="icon iconfont iconguanbi" @click="onClose"></span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="sourceCodeEditBox">
|
||||
<div class="outlineEdit" ref="outlineEditRef" @keydown.stop></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
import CodeMirror from 'codemirror'
|
||||
import 'codemirror/mode/javascript/javascript'
|
||||
import 'codemirror/lib/codemirror.css'
|
||||
import { copy } from '@/utils/index'
|
||||
|
||||
let editor = null
|
||||
|
||||
// 源码编辑
|
||||
export default {
|
||||
props: {
|
||||
mindMap: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isReadonly: state => state.isReadonly,
|
||||
isDark: state => state.localConfig.isDark,
|
||||
isSourceCodeEdit: state => state.isSourceCodeEdit
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
isSourceCodeEdit(val) {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
document.body.appendChild(this.$refs.sourceCodeEditContainer)
|
||||
this.initEditor()
|
||||
this.initData()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setIsSourceCodeEdit']),
|
||||
|
||||
// 初始化编辑器
|
||||
initEditor() {
|
||||
editor = CodeMirror(this.$refs.outlineEditRef, {
|
||||
mode: { name: 'javascript', json: true },
|
||||
lineWrapping: true,
|
||||
lineNumbers: true
|
||||
})
|
||||
},
|
||||
|
||||
// 初始化数据
|
||||
initData() {
|
||||
editor.setValue(JSON.stringify(this.mindMap.getData(), null, 2))
|
||||
},
|
||||
|
||||
// 完成
|
||||
onConfirm() {
|
||||
try {
|
||||
const content = editor.getValue()
|
||||
const data = JSON.parse(content)
|
||||
this.setIsSourceCodeEdit(false)
|
||||
this.$bus.$emit('setData', data)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
this.$message.error(this.$t('sourceCodeEdit.formatErrorTip'))
|
||||
}
|
||||
},
|
||||
|
||||
// 关闭
|
||||
onClose() {
|
||||
this.setIsSourceCodeEdit(false)
|
||||
},
|
||||
|
||||
// 复制
|
||||
copy() {
|
||||
const content = editor.getValue()
|
||||
copy(content)
|
||||
this.$message.success(this.$t('sourceCodeEdit.copyTip'))
|
||||
},
|
||||
|
||||
// 格式化
|
||||
format() {
|
||||
try {
|
||||
const content = editor.getValue()
|
||||
const data = JSON.parse(content)
|
||||
editor.setValue(JSON.stringify(data, null, 2))
|
||||
this.$message.success(this.$t('sourceCodeEdit.formatTip'))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
this.$message.error(this.$t('sourceCodeEdit.formatErrorTip'))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.sourceCodeEditContainer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1999;
|
||||
background-color: #f5f5f5;
|
||||
overflow: hidden;
|
||||
|
||||
&.isDark {
|
||||
background-color: #262a2e;
|
||||
|
||||
.closeBtn {
|
||||
.icon {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.closeBtn {
|
||||
position: absolute;
|
||||
right: 40px;
|
||||
top: 20px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
font-size: 28px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.sourceCodeEditBox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
padding: 50px 0;
|
||||
|
||||
.outlineEdit {
|
||||
width: 1000px;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
font-size: 17px;
|
||||
background-color: #fff;
|
||||
font-family: Menlo, Monaco, Consolas, Andale Mono, Ubuntu Mono,
|
||||
Courier New, monospace;
|
||||
padding: 12px;
|
||||
border-radius: 5px;
|
||||
|
||||
/deep/ .CodeMirror {
|
||||
height: 100%;
|
||||
font-family: Menlo, Monaco, Consolas, Andale Mono, Ubuntu Mono,
|
||||
Courier New, monospace;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -49,19 +49,15 @@ export default {
|
||||
computed: {
|
||||
...mapState({
|
||||
isDark: state => state.localConfig.isDark,
|
||||
activeSidebar: state => state.activeSidebar,
|
||||
supportRightFishbone: state => state.supportRightFishbone
|
||||
activeSidebar: state => state.activeSidebar
|
||||
}),
|
||||
|
||||
layoutGroupList() {
|
||||
const groupList = layoutGroupList[this.$i18n.locale] || layoutGroupList.zh
|
||||
return groupList.map(group => {
|
||||
let list = [...group.list]
|
||||
if (!this.supportRightFishbone) {
|
||||
list = list.filter(item => {
|
||||
return !['rightFishbone', 'rightFishbone2'].includes(item)
|
||||
})
|
||||
}
|
||||
let list = [...group.list].filter(item => {
|
||||
return !['rightFishbone', 'rightFishbone2'].includes(item)
|
||||
})
|
||||
return {
|
||||
name: group.name,
|
||||
list
|
||||
|
||||
@@ -437,52 +437,9 @@
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 流动效果 -->
|
||||
<div class="row" v-if="supportLineFlow">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('style.openLineFlow') }}</span>
|
||||
<el-checkbox
|
||||
v-model="style.lineFlow"
|
||||
@change="update('lineFlow')"
|
||||
></el-checkbox>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('style.direction') }}</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
v-model="style.lineFlowForward"
|
||||
placeholder=""
|
||||
@change="update('lineFlowForward')"
|
||||
>
|
||||
<el-option
|
||||
key="1"
|
||||
:label="$t('style.forward')"
|
||||
:value="true"
|
||||
></el-option>
|
||||
<el-option
|
||||
key="2"
|
||||
:label="$t('style.reverse')"
|
||||
:value="false"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="supportLineFlow">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('style.lineFlowDuration') }}</span>
|
||||
<el-input-number
|
||||
v-model="style.lineFlowDuration"
|
||||
@change="update('lineFlowDuration')"
|
||||
:min="0.1"
|
||||
size="mini"
|
||||
:step="0.5"
|
||||
></el-input-number>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 节点内边距 -->
|
||||
<div class="title noTop">{{ $t('style.nodePadding') }}</div>
|
||||
<div class="row">
|
||||
<div class="title">{{ $t('style.nodePadding') }}</div>
|
||||
<div class="row noBottom">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('style.horizontal') }}</span>
|
||||
<el-slider
|
||||
@@ -503,7 +460,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 节点图片布局 -->
|
||||
<div class="title noTop">{{ $t('style.img') }}</div>
|
||||
<div class="title">{{ $t('style.img') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('style.placement') }}</span>
|
||||
@@ -528,7 +485,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 节点标签布局 -->
|
||||
<div class="title noTop">{{ $t('style.tag') }}</div>
|
||||
<div class="title">{{ $t('style.tag') }}</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">{{ $t('style.placement') }}</span>
|
||||
@@ -623,8 +580,7 @@ export default {
|
||||
computed: {
|
||||
...mapState({
|
||||
isDark: state => state.localConfig.isDark,
|
||||
activeSidebar: state => state.activeSidebar,
|
||||
supportLineFlow: state => state.supportLineFlow
|
||||
activeSidebar: state => state.activeSidebar
|
||||
}),
|
||||
fontFamilyList() {
|
||||
return fontFamilyList[this.$i18n.locale] || fontFamilyList.zh
|
||||
@@ -635,23 +591,26 @@ export default {
|
||||
shapeList() {
|
||||
return [
|
||||
...(shapeList[this.$i18n.locale] || shapeList.zh),
|
||||
...this.mindMap.extendShapeList.map(item => {
|
||||
return {
|
||||
width: '40px',
|
||||
name: item.nameShow,
|
||||
value: item.name
|
||||
}
|
||||
})
|
||||
...this.mindMap.extendShapeList
|
||||
.filter(item => {
|
||||
return !['fishHead'].includes(item.name)
|
||||
})
|
||||
.map(item => {
|
||||
return {
|
||||
width: '40px',
|
||||
name: item.nameShow,
|
||||
value: item.name
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
shapeListMap() {
|
||||
const map = shapeListMap[this.$i18n.locale] || shapeListMap.zh
|
||||
const map2 = {}
|
||||
this.mindMap.extendShapeList.forEach(item => {
|
||||
map2[item.name] = item.path
|
||||
})
|
||||
return {
|
||||
...map,
|
||||
...shapeListMap,
|
||||
...map2
|
||||
}
|
||||
},
|
||||
@@ -854,7 +813,7 @@ export default {
|
||||
font-weight: 500;
|
||||
color: rgba(26, 26, 26, 0.9);
|
||||
margin-bottom: 10px;
|
||||
margin-top: 20px;
|
||||
margin-top: 35px;
|
||||
|
||||
&.noTop {
|
||||
margin-top: 0;
|
||||
@@ -866,6 +825,10 @@ export default {
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&.noBottom {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.btnGroup {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
@@ -178,13 +178,6 @@
|
||||
<span class="icon iconfont iconwaikuang"></span>
|
||||
<span class="text">{{ $t('toolbar.outerFrame') }}</span>
|
||||
</div>
|
||||
<NodeAnnotationBtn
|
||||
v-if="item === 'annotation' && supportMark"
|
||||
:isDark="isDark"
|
||||
:dir="dir"
|
||||
:rightHasBtn="annotationRightHasBtn"
|
||||
@setAnnotation="onSetAnnotation"
|
||||
></NodeAnnotationBtn>
|
||||
<div
|
||||
v-if="item === 'ai'"
|
||||
class="toolbarBtn"
|
||||
@@ -202,10 +195,8 @@
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
import NodeAnnotationBtn from './NodeAnnotationBtn.vue'
|
||||
|
||||
export default {
|
||||
components: { NodeAnnotationBtn },
|
||||
props: {
|
||||
dir: {
|
||||
type: String,
|
||||
@@ -231,8 +222,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
isDark: state => state.localConfig.isDark,
|
||||
supportMark: state => state.supportMark
|
||||
isDark: state => state.localConfig.isDark
|
||||
}),
|
||||
hasRoot() {
|
||||
return (
|
||||
|
||||
@@ -16,10 +16,6 @@ const store = new Vuex.Store({
|
||||
useLeftKeySelectionRightKeyDrag: false,
|
||||
// 是否显示滚动条
|
||||
isShowScrollbar: false,
|
||||
// 是否开启手绘风格
|
||||
isUseHandDrawnLikeStyle: false,
|
||||
// 是否开启动量效果
|
||||
isUseMomentum: true,
|
||||
// 是否是暗黑模式
|
||||
isDark: false,
|
||||
// 是否开启AI功能
|
||||
@@ -30,17 +26,6 @@ const store = new Vuex.Store({
|
||||
isReadonly: false, // 是否只读
|
||||
isSourceCodeEdit: false, // 是否是源码编辑模式
|
||||
extraTextOnExport: '', // 导出时底部添加的文字
|
||||
supportHandDrawnLikeStyle: false, // 是否支持设置手绘风格
|
||||
supportMark: false, // 是否支持标记
|
||||
supportNumbers: false, // 是否支持编号
|
||||
supportFreemind: false, // 是否支持Freemind插件
|
||||
supportExcel: false, // 是否支持Excel插件
|
||||
supportCheckbox: false, // 是否支持Checkbox插件
|
||||
supportLineFlow: false, // 是否支持LineFlow插件
|
||||
supportMomentum: false, // 是否支持Momentum插件
|
||||
supportRightFishbone: false, // 是否支持RightFishbone插件
|
||||
supportNodeLink: false, // 是否支持NodeLink插件
|
||||
supportMoreShapes: false, // 是否支持MoreShapes插件
|
||||
isDragOutlineTreeNode: false, // 当前是否正在拖拽大纲树的节点
|
||||
aiConfig: {
|
||||
api: 'http://ark.cn-beijing.volces.com/api/v3/chat/completions',
|
||||
@@ -101,61 +86,6 @@ const store = new Vuex.Store({
|
||||
state.extraTextOnExport = data
|
||||
},
|
||||
|
||||
// 设置是否支持手绘风格
|
||||
setSupportHandDrawnLikeStyle(state, data) {
|
||||
state.supportHandDrawnLikeStyle = data
|
||||
},
|
||||
|
||||
// 设置是否支持标记
|
||||
setSupportMark(state, data) {
|
||||
state.supportMark = data
|
||||
},
|
||||
|
||||
// 设置是否支持编号
|
||||
setSupportNumbers(state, data) {
|
||||
state.supportNumbers = data
|
||||
},
|
||||
|
||||
// 设置是否支持Freemind插件
|
||||
setSupportFreemind(state, data) {
|
||||
state.supportFreemind = data
|
||||
},
|
||||
|
||||
// 设置是否支持Excel插件
|
||||
setSupportExcel(state, data) {
|
||||
state.supportExcel = data
|
||||
},
|
||||
|
||||
// 设置是否支持Checkbox插件
|
||||
setSupportCheckbox(state, data) {
|
||||
state.supportCheckbox = data
|
||||
},
|
||||
|
||||
// 设置是否支持Lineflow插件
|
||||
setSupportLineFlow(state, data) {
|
||||
state.supportLineFlow = data
|
||||
},
|
||||
|
||||
// 设置是否支持Momentum插件
|
||||
setSupportMomentum(state, data) {
|
||||
state.supportMomentum = data
|
||||
},
|
||||
|
||||
// 设置是否支持RightFishbone插件
|
||||
setSupportRightFishbone(state, data) {
|
||||
state.supportRightFishbone = data
|
||||
},
|
||||
|
||||
// 设置是否支持NodeLink插件
|
||||
setSupportNodeLink(state, data) {
|
||||
state.supportNodeLink = data
|
||||
},
|
||||
|
||||
// 设置是否支持MoreShapes插件
|
||||
setSupportMoreShapes(state, data) {
|
||||
state.supportMoreShapes = data
|
||||
},
|
||||
|
||||
// 设置树节点拖拽
|
||||
setIsDragOutlineTreeNode(state, data) {
|
||||
state.isDragOutlineTreeNode = data
|
||||
|
||||
@@ -83,3 +83,13 @@ export const printOutline = el => {
|
||||
document.body.removeChild(iframe)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
export const getParentWithClass = (el, className) => {
|
||||
if (el.classList.contains(className)) {
|
||||
return el
|
||||
}
|
||||
if (el.parentNode && el.parentNode !== document.body) {
|
||||
return getParentWithClass(el.parentNode, className)
|
||||
}
|
||||
return null
|
||||
}
|
||||