Compare commits
No commits in common. "c1138766c83919b5aa03de7883477a90d7f01c31" and "71acd3814b7466717d7cd4d4680cb4457c5246da" have entirely different histories.
c1138766c8
...
71acd3814b
22
README.md
22
README.md
@ -29,8 +29,6 @@
|
|||||||
>
|
>
|
||||||
> 可直接在`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/),点击右侧的【启动】按钮进行安装。
|
> 可直接在`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/),点击右侧的【启动】按钮进行安装。
|
||||||
|
|
||||||
> 3.`obsidian`插件,正在开发中,敬请期待~
|
|
||||||
|
|
||||||
- 云存储版本,如果你需要带后端的云存储版本,可以尝试我们开发的另一个项目[理想文档](https://github.com/wanglin2/lx-doc)。
|
- 云存储版本,如果你需要带后端的云存储版本,可以尝试我们开发的另一个项目[理想文档](https://github.com/wanglin2/lx-doc)。
|
||||||
|
|
||||||
# 特性
|
# 特性
|
||||||
@ -57,7 +55,7 @@
|
|||||||
| TouchEvent(移动端触摸事件支持插件) | NodeImgAdjust(拖拽调整节点图片大小插件) | Search(搜索插件) | Painter(节点格式刷插件) |
|
| TouchEvent(移动端触摸事件支持插件) | NodeImgAdjust(拖拽调整节点图片大小插件) | Search(搜索插件) | Painter(节点格式刷插件) |
|
||||||
| Scrollbar(滚动条插件) | Formula(数学公式插件) | Cooperate(协同编辑插件) | RainbowLines(彩虹线条插件) |
|
| Scrollbar(滚动条插件) | Formula(数学公式插件) | Cooperate(协同编辑插件) | RainbowLines(彩虹线条插件) |
|
||||||
| Demonstrate(演示模式插件) | OuterFrame(外框插件) | MindMapLayoutPro(思维导图布局插件) | |
|
| Demonstrate(演示模式插件) | OuterFrame(外框插件) | MindMapLayoutPro(思维导图布局插件) | |
|
||||||
| HandDrawnLikeStyle(手绘风格插件) | Notation(节点标记插件) | Numbers(节点编号插件) | Freemind(Freemind格式导入导出插件) |
|
| HandDrawnLikeStyle(手绘风格插件) | Notation(节点标记插件) | Numbers(节点编号插件)[收费] | Freemind(Freemind格式导入导出插件) |
|
||||||
| Excel(Excel格式导入导出插件) | Checkbox(待办插件) | Lineflow(节点连线流动插件) | Momentum(动量效果插件) |
|
| Excel(Excel格式导入导出插件) | Checkbox(待办插件) | Lineflow(节点连线流动插件) | Momentum(动量效果插件) |
|
||||||
| RightFishbone(向右鱼骨图插件) | NodeLink(节点链接插件) | | |
|
| RightFishbone(向右鱼骨图插件) | NodeLink(节点链接插件) | | |
|
||||||
|
|
||||||
@ -117,7 +115,9 @@ const mindMap = new MindMap({
|
|||||||
|
|
||||||
# 微信交流群
|
# 微信交流群
|
||||||
|
|
||||||
微信添加`wanglinguanfang`拉你入群。根据过往的经验,大部分问题都可以通过查看issue列表或文档解决,所以提问前请确保你已经阅读完了所有文档,文档里没有的可在群里提问,不必私聊作者,如果你一定要私聊,请先赞助本项目(¥150+)。
|
微信添加`wanglinguanfang`拉你入群。根据过往的经验,大部分问题都可以通过查看issue列表或文档解决,所以提问前请确保你已经阅读完了所有文档,文档里没有的可在群里提问,不必私聊作者,如果你一定要私聊,请先发红包(¥9.9+每次)。
|
||||||
|
|
||||||
|
如果你在杭州,也欢迎来找我面基。
|
||||||
|
|
||||||
# star
|
# star
|
||||||
|
|
||||||
@ -362,13 +362,6 @@ const mindMap = new MindMap({
|
|||||||
<sub style="font-size:14px"><b>兔子快跑</b></sub>
|
<sub style="font-size:14px"><b>兔子快跑</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</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>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -1001,12 +994,5 @@ const mindMap = new MindMap({
|
|||||||
<sub style="font-size:14px"><b>神话</b></sub>
|
<sub style="font-size:14px"><b>神话</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</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>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
23
dist/css/chunk-c8ebd342.css
vendored
23
dist/css/chunk-c8ebd342.css
vendored
File diff suppressed because one or more lines are too long
1
dist/js/app.js
vendored
1
dist/js/app.js
vendored
File diff suppressed because one or more lines are too long
65
dist/js/chunk-c8ebd342.js
vendored
65
dist/js/chunk-c8ebd342.js
vendored
File diff suppressed because one or more lines are too long
@ -9,7 +9,7 @@
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}</script><link href="dist/css/chunk-vendors.css?685589f1058f5fbca0d2" rel="stylesheet"><link href="dist/css/app.css?685589f1058f5fbca0d2" 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?73afc6e4a541cb0744ee" rel="stylesheet"><link href="dist/css/app.css?73afc6e4a541cb0744ee" 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) => {
|
return new Promise((resolve, reject) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resolve({
|
resolve({
|
||||||
@ -83,4 +83,4 @@
|
|||||||
// 可以通过window.$bus.$on()来监听应用的一些事件
|
// 可以通过window.$bus.$on()来监听应用的一些事件
|
||||||
// 实例化页面
|
// 实例化页面
|
||||||
window.initApp()
|
window.initApp()
|
||||||
}</script><script src="dist/js/chunk-vendors.js?685589f1058f5fbca0d2"></script><script src="dist/js/app.js?685589f1058f5fbca0d2"></script></body></html>
|
}</script><script src="dist/js/chunk-vendors.js?73afc6e4a541cb0744ee"></script><script src="dist/js/app.js?73afc6e4a541cb0744ee"></script></body></html>
|
||||||
@ -676,11 +676,13 @@ export const layoutGroupList = [
|
|||||||
list: [
|
list: [
|
||||||
'timeline',
|
'timeline',
|
||||||
'timeline2',
|
'timeline2',
|
||||||
|
'verticalTimeline2',
|
||||||
|
'verticalTimeline3',
|
||||||
'verticalTimeline'
|
'verticalTimeline'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Fishbone',
|
name: 'Fishbone',
|
||||||
list: ['fishbone']
|
list: ['fishbone', 'fishbone2', 'rightFishbone', 'rightFishbone2']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -699,11 +699,13 @@ export const layoutGroupList = [
|
|||||||
list: [
|
list: [
|
||||||
'timeline',
|
'timeline',
|
||||||
'timeline2',
|
'timeline2',
|
||||||
|
'verticalTimeline2',
|
||||||
|
'verticalTimeline3',
|
||||||
'verticalTimeline'
|
'verticalTimeline'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Bản đồ Fishbone',
|
name: 'Bản đồ Fishbone',
|
||||||
list: ['fishbone']
|
list: ['fishbone', 'fishbone2', 'rightFishbone', 'rightFishbone2']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -777,11 +777,13 @@ export const layoutGroupList = [
|
|||||||
list: [
|
list: [
|
||||||
'timeline',
|
'timeline',
|
||||||
'timeline2',
|
'timeline2',
|
||||||
|
'verticalTimeline2',
|
||||||
|
'verticalTimeline3',
|
||||||
'verticalTimeline'
|
'verticalTimeline'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '鱼骨图',
|
name: '鱼骨图',
|
||||||
list: ['fishbone']
|
list: ['fishbone', 'fishbone2', 'rightFishbone', 'rightFishbone2']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -675,11 +675,13 @@ export const layoutGroupList = [
|
|||||||
list: [
|
list: [
|
||||||
'timeline',
|
'timeline',
|
||||||
'timeline2',
|
'timeline2',
|
||||||
|
'verticalTimeline2',
|
||||||
|
'verticalTimeline3',
|
||||||
'verticalTimeline'
|
'verticalTimeline'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '魚骨圖',
|
name: '魚骨圖',
|
||||||
list: ['fishbone']
|
list: ['fishbone', 'fishbone2', 'rightFishbone', 'rightFishbone2']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -301,6 +301,61 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</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">{{ $t('baseStyle.rainbowLines') }}</div>
|
<div class="title">{{ $t('baseStyle.rainbowLines') }}</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -878,6 +933,7 @@ export default {
|
|||||||
activeSidebar: state => state.activeSidebar,
|
activeSidebar: state => state.activeSidebar,
|
||||||
localConfig: state => state.localConfig,
|
localConfig: state => state.localConfig,
|
||||||
isDark: state => state.localConfig.isDark,
|
isDark: state => state.localConfig.isDark,
|
||||||
|
supportLineFlow: state => state.supportLineFlow,
|
||||||
bgList: state => state.bgList
|
bgList: state => state.bgList
|
||||||
}),
|
}),
|
||||||
lineStyleList() {
|
lineStyleList() {
|
||||||
|
|||||||
@ -62,6 +62,41 @@
|
|||||||
<div class="item" @click="exec('EXPAND_ALL')">
|
<div class="item" @click="exec('EXPAND_ALL')">
|
||||||
<span class="name">{{ $t('contextmenu.expandNodeChild') }}</span>
|
<span class="name">{{ $t('contextmenu.expandNodeChild') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="item vip" 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 vip" @click="setCheckbox" v-if="supportCheckbox">
|
||||||
|
<span class="name">{{
|
||||||
|
hasCheckbox ? $t('contextmenu.removeToDo') : $t('contextmenu.addToDo')
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
<div class="splitLine"></div>
|
<div class="splitLine"></div>
|
||||||
<div class="item danger" @click="exec('REMOVE_NODE')">
|
<div class="item danger" @click="exec('REMOVE_NODE')">
|
||||||
<span class="name">{{ $t('contextmenu.deleteNode') }}</span>
|
<span class="name">{{ $t('contextmenu.deleteNode') }}</span>
|
||||||
@ -99,6 +134,16 @@
|
|||||||
<div class="item" @click="exec('REMOVE_NOTE')" v-if="hasNote">
|
<div class="item" @click="exec('REMOVE_NOTE')" v-if="hasNote">
|
||||||
<span class="name">{{ $t('contextmenu.removeNote') }}</span>
|
<span class="name">{{ $t('contextmenu.removeNote') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="item vip" @click="exec('LINK_NODE')">
|
||||||
|
<span class="name">{{
|
||||||
|
hasNodeLink
|
||||||
|
? $t('contextmenu.modifyNodeLink')
|
||||||
|
: $t('contextmenu.linkToNode')
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="item vip" @click="exec('REMOVE_LINK_NODE')" v-if="hasNodeLink">
|
||||||
|
<span class="name">{{ $t('contextmenu.removeNodeLink') }}</span>
|
||||||
|
</div>
|
||||||
<div class="item" @click="exec('REMOVE_CUSTOM_STYLES')">
|
<div class="item" @click="exec('REMOVE_CUSTOM_STYLES')">
|
||||||
<span class="name">{{ $t('contextmenu.removeCustomStyles') }}</span>
|
<span class="name">{{ $t('contextmenu.removeCustomStyles') }}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -217,6 +262,8 @@ export default {
|
|||||||
...mapState({
|
...mapState({
|
||||||
isZenMode: state => state.localConfig.isZenMode,
|
isZenMode: state => state.localConfig.isZenMode,
|
||||||
isDark: state => state.localConfig.isDark,
|
isDark: state => state.localConfig.isDark,
|
||||||
|
supportNumbers: state => state.supportNumbers,
|
||||||
|
supportCheckbox: state => state.supportCheckbox,
|
||||||
enableAi: state => state.localConfig.enableAi
|
enableAi: state => state.localConfig.enableAi
|
||||||
}),
|
}),
|
||||||
expandList() {
|
expandList() {
|
||||||
@ -444,6 +491,13 @@ export default {
|
|||||||
case 'REMOVE_NOTE':
|
case 'REMOVE_NOTE':
|
||||||
this.node.setNote('')
|
this.node.setNote('')
|
||||||
break
|
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':
|
case 'EXPORT_CUR_NODE_TO_PNG':
|
||||||
this.mindMap.export(
|
this.mindMap.export(
|
||||||
'png',
|
'png',
|
||||||
@ -467,6 +521,45 @@ export default {
|
|||||||
this.hide()
|
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) {
|
async copyToClipboard(type) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
36
web/src/pages/Edit/components/CustomNodeContent.vue
Normal file
36
web/src/pages/Edit/components/CustomNodeContent.vue
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<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,6 +34,7 @@
|
|||||||
v-if="mindMap"
|
v-if="mindMap"
|
||||||
:mindMap="mindMap"
|
:mindMap="mindMap"
|
||||||
></NodeNoteContentShow>
|
></NodeNoteContentShow>
|
||||||
|
<NodeAttachment v-if="mindMap" :mindMap="mindMap"></NodeAttachment>
|
||||||
<NodeImgPreview v-if="mindMap" :mindMap="mindMap"></NodeImgPreview>
|
<NodeImgPreview v-if="mindMap" :mindMap="mindMap"></NodeImgPreview>
|
||||||
<SidebarTrigger v-if="!isZenMode"></SidebarTrigger>
|
<SidebarTrigger v-if="!isZenMode"></SidebarTrigger>
|
||||||
<Search v-if="mindMap" :mindMap="mindMap"></Search>
|
<Search v-if="mindMap" :mindMap="mindMap"></Search>
|
||||||
@ -42,6 +43,7 @@
|
|||||||
<OutlineEdit v-if="mindMap" :mindMap="mindMap"></OutlineEdit>
|
<OutlineEdit v-if="mindMap" :mindMap="mindMap"></OutlineEdit>
|
||||||
<Scrollbar v-if="isShowScrollbar && mindMap" :mindMap="mindMap"></Scrollbar>
|
<Scrollbar v-if="isShowScrollbar && mindMap" :mindMap="mindMap"></Scrollbar>
|
||||||
<FormulaSidebar v-if="mindMap" :mindMap="mindMap"></FormulaSidebar>
|
<FormulaSidebar v-if="mindMap" :mindMap="mindMap"></FormulaSidebar>
|
||||||
|
<SourceCodeEdit v-if="mindMap" :mindMap="mindMap"></SourceCodeEdit>
|
||||||
<NodeOuterFrame v-if="mindMap" :mindMap="mindMap"></NodeOuterFrame>
|
<NodeOuterFrame v-if="mindMap" :mindMap="mindMap"></NodeOuterFrame>
|
||||||
<NodeTagStyle v-if="mindMap" :mindMap="mindMap"></NodeTagStyle>
|
<NodeTagStyle v-if="mindMap" :mindMap="mindMap"></NodeTagStyle>
|
||||||
<Setting :configData="mindMapConfig" :mindMap="mindMap"></Setting>
|
<Setting :configData="mindMapConfig" :mindMap="mindMap"></Setting>
|
||||||
@ -52,6 +54,10 @@
|
|||||||
<NodeNoteSidebar v-if="mindMap" :mindMap="mindMap"></NodeNoteSidebar>
|
<NodeNoteSidebar v-if="mindMap" :mindMap="mindMap"></NodeNoteSidebar>
|
||||||
<AiCreate v-if="mindMap && enableAi" :mindMap="mindMap"></AiCreate>
|
<AiCreate v-if="mindMap && enableAi" :mindMap="mindMap"></AiCreate>
|
||||||
<AiChat v-if="enableAi"></AiChat>
|
<AiChat v-if="enableAi"></AiChat>
|
||||||
|
<LinkNodeSelect
|
||||||
|
v-if="mindMap && supportNodeLink"
|
||||||
|
:mindMap="mindMap"
|
||||||
|
></LinkNodeSelect>
|
||||||
<div
|
<div
|
||||||
class="dragMask"
|
class="dragMask"
|
||||||
v-if="showDragMask"
|
v-if="showDragMask"
|
||||||
@ -90,6 +96,22 @@ import NodeBase64ImageStorage from 'simple-mind-map/src/plugins/NodeBase64ImageS
|
|||||||
import Themes from 'simple-mind-map-plugin-themes'
|
import Themes from 'simple-mind-map-plugin-themes'
|
||||||
// 协同编辑插件
|
// 协同编辑插件
|
||||||
// import Cooperate from 'simple-mind-map/src/plugins/Cooperate.js'
|
// 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 OutlineSidebar from './OutlineSidebar.vue'
|
||||||
import Style from './Style.vue'
|
import Style from './Style.vue'
|
||||||
import BaseStyle from './BaseStyle.vue'
|
import BaseStyle from './BaseStyle.vue'
|
||||||
@ -107,7 +129,12 @@ import NodeImgPreview from './NodeImgPreview.vue'
|
|||||||
import SidebarTrigger from './SidebarTrigger.vue'
|
import SidebarTrigger from './SidebarTrigger.vue'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
import icon from '@/config/icon'
|
import icon from '@/config/icon'
|
||||||
|
import CustomNodeContent from './CustomNodeContent.vue'
|
||||||
|
import Color from './Color.vue'
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
|
import router from '../../../router'
|
||||||
|
import store from '../../../store'
|
||||||
|
import i18n from '../../../i18n'
|
||||||
import Search from './Search.vue'
|
import Search from './Search.vue'
|
||||||
import NodeIconSidebar from './NodeIconSidebar.vue'
|
import NodeIconSidebar from './NodeIconSidebar.vue'
|
||||||
import NodeIconToolbar from './NodeIconToolbar.vue'
|
import NodeIconToolbar from './NodeIconToolbar.vue'
|
||||||
@ -118,6 +145,8 @@ import { getParentWithClass } from '@/utils'
|
|||||||
import Scrollbar from './Scrollbar.vue'
|
import Scrollbar from './Scrollbar.vue'
|
||||||
import exampleData from 'simple-mind-map/example/exampleData'
|
import exampleData from 'simple-mind-map/example/exampleData'
|
||||||
import FormulaSidebar from './FormulaSidebar.vue'
|
import FormulaSidebar from './FormulaSidebar.vue'
|
||||||
|
import SourceCodeEdit from './SourceCodeEdit.vue'
|
||||||
|
import NodeAttachment from './NodeAttachment.vue'
|
||||||
import NodeOuterFrame from './NodeOuterFrame.vue'
|
import NodeOuterFrame from './NodeOuterFrame.vue'
|
||||||
import NodeTagStyle from './NodeTagStyle.vue'
|
import NodeTagStyle from './NodeTagStyle.vue'
|
||||||
import Setting from './Setting.vue'
|
import Setting from './Setting.vue'
|
||||||
@ -126,6 +155,7 @@ import NodeImgPlacementToolbar from './NodeImgPlacementToolbar.vue'
|
|||||||
import NodeNoteSidebar from './NodeNoteSidebar.vue'
|
import NodeNoteSidebar from './NodeNoteSidebar.vue'
|
||||||
import AiCreate from './AiCreate.vue'
|
import AiCreate from './AiCreate.vue'
|
||||||
import AiChat from './AiChat.vue'
|
import AiChat from './AiChat.vue'
|
||||||
|
import LinkNodeSelect from './LinkNodeSelect.vue'
|
||||||
|
|
||||||
// 注册插件
|
// 注册插件
|
||||||
MindMap.usePlugin(MiniMap)
|
MindMap.usePlugin(MiniMap)
|
||||||
@ -178,6 +208,8 @@ export default {
|
|||||||
OutlineEdit,
|
OutlineEdit,
|
||||||
Scrollbar,
|
Scrollbar,
|
||||||
FormulaSidebar,
|
FormulaSidebar,
|
||||||
|
SourceCodeEdit,
|
||||||
|
NodeAttachment,
|
||||||
NodeOuterFrame,
|
NodeOuterFrame,
|
||||||
NodeTagStyle,
|
NodeTagStyle,
|
||||||
Setting,
|
Setting,
|
||||||
@ -185,7 +217,8 @@ export default {
|
|||||||
NodeImgPlacementToolbar,
|
NodeImgPlacementToolbar,
|
||||||
NodeNoteSidebar,
|
NodeNoteSidebar,
|
||||||
AiCreate,
|
AiCreate,
|
||||||
AiChat
|
AiChat,
|
||||||
|
LinkNodeSelect
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -206,9 +239,13 @@ export default {
|
|||||||
enableDragImport: state => state.localConfig.enableDragImport,
|
enableDragImport: state => state.localConfig.enableDragImport,
|
||||||
useLeftKeySelectionRightKeyDrag: state =>
|
useLeftKeySelectionRightKeyDrag: state =>
|
||||||
state.localConfig.useLeftKeySelectionRightKeyDrag,
|
state.localConfig.useLeftKeySelectionRightKeyDrag,
|
||||||
|
isUseHandDrawnLikeStyle: state =>
|
||||||
|
state.localConfig.isUseHandDrawnLikeStyle,
|
||||||
|
isUseMomentum: state => state.localConfig.isUseMomentum,
|
||||||
extraTextOnExport: state => state.extraTextOnExport,
|
extraTextOnExport: state => state.extraTextOnExport,
|
||||||
isDragOutlineTreeNode: state => state.isDragOutlineTreeNode,
|
isDragOutlineTreeNode: state => state.isDragOutlineTreeNode,
|
||||||
enableAi: state => state.localConfig.enableAi
|
enableAi: state => state.localConfig.enableAi,
|
||||||
|
supportNodeLink: state => state.supportNodeLink
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -225,10 +262,25 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.removeScrollbarPlugin()
|
this.removeScrollbarPlugin()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
isUseHandDrawnLikeStyle() {
|
||||||
|
if (this.isUseHandDrawnLikeStyle) {
|
||||||
|
this.addHandDrawnLikeStylePlugin()
|
||||||
|
} else {
|
||||||
|
this.removeHandDrawnLikeStylePlugin()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isUseMomentum() {
|
||||||
|
if (this.isUseMomentum) {
|
||||||
|
this.addMomentumPlugin()
|
||||||
|
} else {
|
||||||
|
this.removeMomentumPlugin()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
showLoading()
|
showLoading()
|
||||||
|
// this.showNewFeatureInfo()
|
||||||
this.getData()
|
this.getData()
|
||||||
this.init()
|
this.init()
|
||||||
this.$bus.$on('execCommand', this.execCommand)
|
this.$bus.$on('execCommand', this.execCommand)
|
||||||
@ -243,8 +295,9 @@ export default {
|
|||||||
this.$bus.$on('showLoading', this.handleShowLoading)
|
this.$bus.$on('showLoading', this.handleShowLoading)
|
||||||
this.$bus.$on('localStorageExceeded', this.onLocalStorageExceeded)
|
this.$bus.$on('localStorageExceeded', this.onLocalStorageExceeded)
|
||||||
window.addEventListener('resize', this.handleResize)
|
window.addEventListener('resize', this.handleResize)
|
||||||
|
document.body.addEventListener('click', this.onVipCheckClick)
|
||||||
this.$bus.$on('showDownloadTip', this.showDownloadTip)
|
this.$bus.$on('showDownloadTip', this.showDownloadTip)
|
||||||
this.webTip()
|
this.$bus.$on('vipCheckClick', this.onVipCheckClick)
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.$bus.$off('execCommand', this.execCommand)
|
this.$bus.$off('execCommand', this.execCommand)
|
||||||
@ -259,7 +312,9 @@ export default {
|
|||||||
this.$bus.$off('showLoading', this.handleShowLoading)
|
this.$bus.$off('showLoading', this.handleShowLoading)
|
||||||
this.$bus.$off('localStorageExceeded', this.onLocalStorageExceeded)
|
this.$bus.$off('localStorageExceeded', this.onLocalStorageExceeded)
|
||||||
window.removeEventListener('resize', this.handleResize)
|
window.removeEventListener('resize', this.handleResize)
|
||||||
|
document.body.removeEventListener('click', this.onVipCheckClick)
|
||||||
this.$bus.$off('showDownloadTip', this.showDownloadTip)
|
this.$bus.$off('showDownloadTip', this.showDownloadTip)
|
||||||
|
this.$bus.$off('vipCheckClick', this.onVipCheckClick)
|
||||||
this.mindMap.destroy()
|
this.mindMap.destroy()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -370,7 +425,7 @@ export default {
|
|||||||
openRealtimeRenderOnNodeTextEdit: true,
|
openRealtimeRenderOnNodeTextEdit: true,
|
||||||
enableAutoEnterTextEditWhenKeydown: true,
|
enableAutoEnterTextEditWhenKeydown: true,
|
||||||
demonstrateConfig: {
|
demonstrateConfig: {
|
||||||
openBlankMode: false
|
openBlankMode: true
|
||||||
},
|
},
|
||||||
...(config || {}),
|
...(config || {}),
|
||||||
iconList: [...icon],
|
iconList: [...icon],
|
||||||
@ -445,6 +500,116 @@ 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.loadPlugins()
|
||||||
this.mindMap.keyCommand.addShortcut('Control+s', () => {
|
this.mindMap.keyCommand.addShortcut('Control+s', () => {
|
||||||
@ -484,6 +649,7 @@ export default {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
this.bindSaveEvent()
|
this.bindSaveEvent()
|
||||||
|
this.testDynamicCreateNodes()
|
||||||
// 如果应用被接管,那么抛出事件传递思维导图实例
|
// 如果应用被接管,那么抛出事件传递思维导图实例
|
||||||
if (window.takeOverApp) {
|
if (window.takeOverApp) {
|
||||||
this.$bus.$emit('app_inited', this.mindMap)
|
this.$bus.$emit('app_inited', this.mindMap)
|
||||||
@ -500,12 +666,93 @@ export default {
|
|||||||
}
|
}
|
||||||
// 协同测试
|
// 协同测试
|
||||||
this.cooperateTest()
|
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() {
|
loadPlugins() {
|
||||||
if (this.openNodeRichText) this.addRichTextPlugin()
|
if (this.openNodeRichText) this.addRichTextPlugin()
|
||||||
if (this.isShowScrollbar) this.addScrollbarPlugin()
|
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: this.$t('edit.withBg'), // 主题组名称
|
||||||
|
// 主题列表
|
||||||
|
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中是否存在要打开的文件
|
// url中是否存在要打开的文件
|
||||||
@ -517,6 +764,7 @@ export default {
|
|||||||
|
|
||||||
// 动态设置思维导图数据
|
// 动态设置思维导图数据
|
||||||
setData(data) {
|
setData(data) {
|
||||||
|
console.log('data ===>>>' , data)
|
||||||
this.handleShowLoading()
|
this.handleShowLoading()
|
||||||
let rootNodeData = null
|
let rootNodeData = null
|
||||||
if (data.root) {
|
if (data.root) {
|
||||||
@ -565,6 +813,21 @@ export default {
|
|||||||
this.mindMap.updateConfig(data)
|
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() {
|
addRichTextPlugin() {
|
||||||
if (!this.mindMap) return
|
if (!this.mindMap) return
|
||||||
@ -587,6 +850,153 @@ export default {
|
|||||||
this.mindMap.removePlugin(ScrollbarPlugin)
|
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() {
|
cooperateTest() {
|
||||||
if (this.mindMap.cooperate && this.$route.query.userName) {
|
if (this.mindMap.cooperate && this.$route.query.userName) {
|
||||||
@ -613,11 +1023,9 @@ export default {
|
|||||||
if (!this.enableDragImport || this.isDragOutlineTreeNode) return
|
if (!this.enableDragImport || this.isDragOutlineTreeNode) return
|
||||||
this.showDragMask = true
|
this.showDragMask = true
|
||||||
},
|
},
|
||||||
|
|
||||||
onDragleave() {
|
onDragleave() {
|
||||||
this.showDragMask = false
|
this.showDragMask = false
|
||||||
},
|
},
|
||||||
|
|
||||||
onDrop(e) {
|
onDrop(e) {
|
||||||
if (!this.enableDragImport) return
|
if (!this.enableDragImport) return
|
||||||
this.showDragMask = false
|
this.showDragMask = false
|
||||||
@ -627,18 +1035,30 @@ export default {
|
|||||||
this.$bus.$emit('importFile', file)
|
this.$bus.$emit('importFile', file)
|
||||||
},
|
},
|
||||||
|
|
||||||
// 网页版试用提示
|
// 网页版功能试用提示
|
||||||
webTip() {
|
onVipCheckClick(e) {
|
||||||
const storageKey = 'webUseTip'
|
const el = getParentWithClass(e.target, 'vip')
|
||||||
const data = localStorage.getItem(storageKey)
|
if (el) {
|
||||||
if (data) {
|
const className = el.classList.value.split(/\s+/).join('_')
|
||||||
return
|
const storageKey = 'VIP_USAGE_TIP'
|
||||||
|
let data = localStorage.getItem(storageKey)
|
||||||
|
if (data) {
|
||||||
|
data = JSON.parse(data)
|
||||||
|
} else {
|
||||||
|
data = {}
|
||||||
|
}
|
||||||
|
if (!data[className]) {
|
||||||
|
data[className] = 0
|
||||||
|
}
|
||||||
|
data[className]++
|
||||||
|
if (data[className] > 3) {
|
||||||
|
this.showDownloadTip(
|
||||||
|
this.$t('edit.tryTipTitle'),
|
||||||
|
this.$t('edit.tryTipDesc')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
localStorage.setItem(storageKey, JSON.stringify(data))
|
||||||
}
|
}
|
||||||
this.showDownloadTip(
|
|
||||||
'重要提示',
|
|
||||||
'网页版已暂停更新,部分功能缺失,请下载客户端获得完整体验~'
|
|
||||||
)
|
|
||||||
localStorage.setItem(storageKey, 1)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
showDownloadTip(title, desc) {
|
showDownloadTip(title, desc) {
|
||||||
@ -646,15 +1066,7 @@ export default {
|
|||||||
this.$msgbox({
|
this.$msgbox({
|
||||||
title,
|
title,
|
||||||
message: h('div', null, [
|
message: h('div', null, [
|
||||||
h(
|
h('p', null, desc),
|
||||||
'p',
|
|
||||||
{
|
|
||||||
style: {
|
|
||||||
marginBottom: '12px'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
desc
|
|
||||||
),
|
|
||||||
h('div', null, [
|
h('div', null, [
|
||||||
h(
|
h(
|
||||||
'a',
|
'a',
|
||||||
@ -726,6 +1138,11 @@ export default {
|
|||||||
top: 0px;
|
top: 0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
// left: 100px;
|
||||||
|
// top: 100px;
|
||||||
|
// right: 100px;
|
||||||
|
// bottom: 100px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -21,7 +21,8 @@
|
|||||||
v-for="item in downTypeList"
|
v-for="item in downTypeList"
|
||||||
:key="item.type"
|
:key="item.type"
|
||||||
:class="{
|
:class="{
|
||||||
active: exportType === item.type
|
active: exportType === item.type,
|
||||||
|
vip: ['mm', 'xlsx'].includes(item.type)
|
||||||
}"
|
}"
|
||||||
@click="exportType = item.type"
|
@click="exportType = item.type"
|
||||||
>
|
>
|
||||||
@ -79,6 +80,7 @@
|
|||||||
<span class="name">{{ $t('export.format') }}</span>
|
<span class="name">{{ $t('export.format') }}</span>
|
||||||
<el-radio-group v-model="imageFormat">
|
<el-radio-group v-model="imageFormat">
|
||||||
<el-radio label="png">PNG</el-radio>
|
<el-radio label="png">PNG</el-radio>
|
||||||
|
<el-radio label="jpg" class="vip">JPG</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<div class="valueSubItem">
|
<div class="valueSubItem">
|
||||||
@ -174,16 +176,18 @@ export default {
|
|||||||
...mapState({
|
...mapState({
|
||||||
openNodeRichText: state => state.localConfig.openNodeRichText,
|
openNodeRichText: state => state.localConfig.openNodeRichText,
|
||||||
isDark: state => state.localConfig.isDark,
|
isDark: state => state.localConfig.isDark,
|
||||||
|
supportFreemind: state => state.supportFreemind,
|
||||||
|
supportExcel: state => state.supportExcel
|
||||||
}),
|
}),
|
||||||
|
|
||||||
downTypeList() {
|
downTypeList() {
|
||||||
const list = downTypeList[this.$i18n.locale] || downTypeList.zh
|
const list = downTypeList[this.$i18n.locale] || downTypeList.zh
|
||||||
return list.filter(item => {
|
return list.filter(item => {
|
||||||
if (item.type === 'mm') {
|
if (item.type === 'mm') {
|
||||||
return false
|
return this.supportFreemind
|
||||||
}
|
}
|
||||||
if (item.type === 'xlsx') {
|
if (item.type === 'xlsx') {
|
||||||
return false
|
return this.supportExcel
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -272,6 +276,22 @@ export default {
|
|||||||
this.isTransparent,
|
this.isTransparent,
|
||||||
this.isFitBg
|
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 {
|
} else {
|
||||||
this.$bus.$emit('export', this.exportType, true, this.fileName)
|
this.$bus.$emit('export', this.exportType, true, this.fileName)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,13 +21,20 @@
|
|||||||
<el-button slot="trigger" size="small" type="primary">{{
|
<el-button slot="trigger" size="small" type="primary">{{
|
||||||
$t('import.selectFile')
|
$t('import.selectFile')
|
||||||
}}</el-button>
|
}}</el-button>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
style="margin-left: 10px;"
|
||||||
|
@click="mdImportDialogVisible = true"
|
||||||
|
class="vip"
|
||||||
|
>{{ $t('import.mdImportDialogTitle') }}</el-button
|
||||||
|
>
|
||||||
<div slot="tip" class="el-upload__tip">
|
<div slot="tip" class="el-upload__tip">
|
||||||
{{ $t('import.support') }}{{ supportFileStr }}{{ $t('import.file') }}
|
{{ $t('import.support') }}{{ supportFileStr }}{{ $t('import.file') }}
|
||||||
</div>
|
</div>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<span slot="footer" class="dialog-footer">
|
<span slot="footer" class="dialog-footer">
|
||||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||||
<el-button type="primary" @click="confirm">{{
|
<el-button class="vip" type="primary" @click="confirm">{{
|
||||||
$t('dialog.confirm')
|
$t('dialog.confirm')
|
||||||
}}</el-button>
|
}}</el-button>
|
||||||
</span>
|
</span>
|
||||||
@ -53,13 +60,34 @@
|
|||||||
}}</el-button>
|
}}</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
class="mdImportDialog"
|
||||||
|
:title="$t('import.mdImportDialogTitle')"
|
||||||
|
:visible.sync="mdImportDialogVisible"
|
||||||
|
width="500px"
|
||||||
|
:show-close="false"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
type="textarea"
|
||||||
|
:rows="10"
|
||||||
|
:placeholder="$t('import.mdPlaceholder')"
|
||||||
|
v-model="mdStr"
|
||||||
|
>
|
||||||
|
</el-input>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="cancelImportMd">{{ $t('dialog.cancel') }}</el-button>
|
||||||
|
<el-button type="primary" @click="confirmImportFromMd">{{
|
||||||
|
$t('dialog.confirm')
|
||||||
|
}}</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import xmind from 'simple-mind-map/src/parse/xmind.js'
|
import xmind from 'simple-mind-map/src/parse/xmind.js'
|
||||||
import markdown from 'simple-mind-map/src/parse/markdown.js'
|
import markdown from 'simple-mind-map/src/parse/markdown.js'
|
||||||
import { mapMutations } from 'vuex'
|
import { mapMutations, mapState } from 'vuex'
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
|
|
||||||
// 导入
|
// 导入
|
||||||
@ -72,12 +100,24 @@ export default {
|
|||||||
xmindCanvasSelectDialogVisible: false,
|
xmindCanvasSelectDialogVisible: false,
|
||||||
selectCanvas: '',
|
selectCanvas: '',
|
||||||
canvasList: [],
|
canvasList: [],
|
||||||
|
mdImportDialogVisible: false,
|
||||||
mdStr: ''
|
mdStr: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
supportFreemind: state => state.supportFreemind,
|
||||||
|
supportExcel: state => state.supportExcel
|
||||||
|
}),
|
||||||
supportFileStr() {
|
supportFileStr() {
|
||||||
return '.smm,.json,.xmind,.md'
|
let res = '.smm,.json,.xmind,.md'
|
||||||
|
if (this.supportFreemind) {
|
||||||
|
res += ',.mm'
|
||||||
|
}
|
||||||
|
if (this.supportExcel) {
|
||||||
|
res += ',.xlsx'
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -105,7 +145,11 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getRegexp() {
|
getRegexp() {
|
||||||
return new RegExp(`\.(smm|json|xmind|md)$`)
|
return new RegExp(
|
||||||
|
`\.(smm|json|xmind|md${this.supportFreemind ? '|mm' : ''}${
|
||||||
|
this.supportExcel ? '|xlsx' : ''
|
||||||
|
})$`
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
// 检查url中是否操作需要打开的文件
|
// 检查url中是否操作需要打开的文件
|
||||||
@ -127,8 +171,12 @@ export default {
|
|||||||
this.handleSmm(data)
|
this.handleSmm(data)
|
||||||
} else if (type === 'xmind') {
|
} else if (type === 'xmind') {
|
||||||
this.handleXmind(data)
|
this.handleXmind(data)
|
||||||
|
} else if (type === 'xlsx') {
|
||||||
|
this.handleExcel(data)
|
||||||
} else if (type === 'md') {
|
} else if (type === 'md') {
|
||||||
this.handleMd(data)
|
this.handleMd(data)
|
||||||
|
} else if (type === 'mm') {
|
||||||
|
this.handleMm(data)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
@ -175,8 +223,12 @@ export default {
|
|||||||
this.handleSmm(file)
|
this.handleSmm(file)
|
||||||
} else if (/\.xmind$/.test(file.name)) {
|
} else if (/\.xmind$/.test(file.name)) {
|
||||||
this.handleXmind(file)
|
this.handleXmind(file)
|
||||||
|
} else if (/\.xlsx$/.test(file.name)) {
|
||||||
|
this.handleExcel(file)
|
||||||
} else if (/\.md$/.test(file.name)) {
|
} else if (/\.md$/.test(file.name)) {
|
||||||
this.handleMd(file)
|
this.handleMd(file)
|
||||||
|
} else if (/\.mm$/.test(file.name)) {
|
||||||
|
this.handleMm(file)
|
||||||
}
|
}
|
||||||
this.cancel()
|
this.cancel()
|
||||||
this.setActiveSidebar(null)
|
this.setActiveSidebar(null)
|
||||||
@ -218,6 +270,36 @@ 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文件的多个画布选择弹窗
|
// 显示xmind文件的多个画布选择弹窗
|
||||||
showSelectXmindCanvasDialog(content) {
|
showSelectXmindCanvasDialog(content) {
|
||||||
this.canvasList = content
|
this.canvasList = content
|
||||||
@ -233,6 +315,18 @@ export default {
|
|||||||
this.selectCanvas = 0
|
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文件
|
// 处理markdown文件
|
||||||
async handleMd(file) {
|
async handleMd(file) {
|
||||||
let fileReader = new FileReader()
|
let fileReader = new FileReader()
|
||||||
@ -257,6 +351,29 @@ export default {
|
|||||||
})
|
})
|
||||||
if (this.fileList.length <= 0) return
|
if (this.fileList.length <= 0) return
|
||||||
this.confirm()
|
this.confirm()
|
||||||
|
},
|
||||||
|
|
||||||
|
cancelImportMd() {
|
||||||
|
this.mdImportDialogVisible = false
|
||||||
|
this.mdStr = ''
|
||||||
|
},
|
||||||
|
|
||||||
|
confirmImportFromMd() {
|
||||||
|
if (!this.mdStr.trim()) {
|
||||||
|
this.$message.warning(this.$t('import.mdEmptyTip'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const data = markdown.transformMarkdownTo(this.mdStr.trim())
|
||||||
|
this.$bus.$emit('setData', data)
|
||||||
|
this.$message.success(this.$t('import.importSuccess'))
|
||||||
|
this.cancelImportMd()
|
||||||
|
this.cancel()
|
||||||
|
this.setActiveSidebar(null)
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
this.$message.error(this.$t('import.fileParsingFailed'))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
177
web/src/pages/Edit/components/LinkNodeSelect.vue
Normal file
177
web/src/pages/Edit/components/LinkNodeSelect.vue
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<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>
|
||||||
275
web/src/pages/Edit/components/NodeAnnotationBtn.vue
Normal file
275
web/src/pages/Edit/components/NodeAnnotationBtn.vue
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
<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 vip"
|
||||||
|
: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>
|
||||||
133
web/src/pages/Edit/components/NodeAttachment.vue
Normal file
133
web/src/pages/Edit/components/NodeAttachment.vue
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<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>
|
||||||
@ -4,6 +4,7 @@
|
|||||||
class="sidebarContent customScrollbar"
|
class="sidebarContent customScrollbar"
|
||||||
:class="{ isDark: isDark }"
|
:class="{ isDark: isDark }"
|
||||||
v-if="configData"
|
v-if="configData"
|
||||||
|
@click="onClick"
|
||||||
>
|
>
|
||||||
<!-- 水印 -->
|
<!-- 水印 -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -256,6 +257,40 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 是否开启手绘风格 -->
|
||||||
|
<div class="row vip" 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 vip" 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 vip">
|
||||||
|
<div class="rowItem">
|
||||||
|
<el-checkbox
|
||||||
|
v-model="config.demonstrateConfig.openBlankMode"
|
||||||
|
@change="
|
||||||
|
value => {
|
||||||
|
updateOtherConfig('openBlankMode', value)
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>{{ $t('setting.openBlankMode') }}</el-checkbox
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 配置鼠标滚轮行为 -->
|
<!-- 配置鼠标滚轮行为 -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="rowItem">
|
<div class="rowItem">
|
||||||
@ -404,7 +439,10 @@ export default {
|
|||||||
enableAutoEnterTextEditWhenKeydown: true,
|
enableAutoEnterTextEditWhenKeydown: true,
|
||||||
imgTextMargin: 0,
|
imgTextMargin: 0,
|
||||||
textContentMargin: 0,
|
textContentMargin: 0,
|
||||||
enableInheritAncestorLineStyle: false
|
enableInheritAncestorLineStyle: false,
|
||||||
|
demonstrateConfig: {
|
||||||
|
openBlankMode: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watermarkConfig: {
|
watermarkConfig: {
|
||||||
show: false,
|
show: false,
|
||||||
@ -423,6 +461,8 @@ export default {
|
|||||||
enableNodeRichText: true,
|
enableNodeRichText: true,
|
||||||
localConfigs: {
|
localConfigs: {
|
||||||
isShowScrollbar: false,
|
isShowScrollbar: false,
|
||||||
|
isUseHandDrawnLikeStyle: false,
|
||||||
|
isUseMomentum: false,
|
||||||
enableDragImport: false,
|
enableDragImport: false,
|
||||||
enableAi: false
|
enableAi: false
|
||||||
}
|
}
|
||||||
@ -432,7 +472,9 @@ export default {
|
|||||||
...mapState({
|
...mapState({
|
||||||
activeSidebar: state => state.activeSidebar,
|
activeSidebar: state => state.activeSidebar,
|
||||||
localConfig: state => state.localConfig,
|
localConfig: state => state.localConfig,
|
||||||
isDark: state => state.localConfig.isDark
|
isDark: state => state.localConfig.isDark,
|
||||||
|
supportHandDrawnLikeStyle: state => state.supportHandDrawnLikeStyle,
|
||||||
|
supportMomentum: state => state.supportMomentum
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -493,10 +535,24 @@ export default {
|
|||||||
|
|
||||||
// 更新其他配置
|
// 更新其他配置
|
||||||
updateOtherConfig(key, value) {
|
updateOtherConfig(key, value) {
|
||||||
this.mindMap.updateConfig({
|
console.log({key, value})
|
||||||
[key]: value
|
if (key === 'openBlankMode') {
|
||||||
})
|
this.mindMap.updateConfig({
|
||||||
this.configData[key] = value
|
demonstrateConfig: {
|
||||||
|
...(this.mindMap.getConfig('demonstrateConfig') || {}),
|
||||||
|
openBlankMode: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!this.configData.demonstrateConfig) {
|
||||||
|
this.configData.demonstrateConfig = {}
|
||||||
|
}
|
||||||
|
this.configData.demonstrateConfig[key] = value
|
||||||
|
} else {
|
||||||
|
this.mindMap.updateConfig({
|
||||||
|
[key]: value
|
||||||
|
})
|
||||||
|
this.configData[key] = value
|
||||||
|
}
|
||||||
storeConfig(this.configData)
|
storeConfig(this.configData)
|
||||||
if (
|
if (
|
||||||
[
|
[
|
||||||
@ -573,6 +629,10 @@ export default {
|
|||||||
this.setLocalConfig({
|
this.setLocalConfig({
|
||||||
[key]: value
|
[key]: value
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onClick(e) {
|
||||||
|
this.$bus.$emit('vipCheckClick', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
214
web/src/pages/Edit/components/SourceCodeEdit.vue
Normal file
214
web/src/pages/Edit/components/SourceCodeEdit.vue
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
<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>
|
||||||
@ -50,15 +50,19 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
isDark: state => state.localConfig.isDark,
|
isDark: state => state.localConfig.isDark,
|
||||||
activeSidebar: state => state.activeSidebar
|
activeSidebar: state => state.activeSidebar,
|
||||||
|
supportRightFishbone: state => state.supportRightFishbone
|
||||||
}),
|
}),
|
||||||
|
|
||||||
layoutGroupList() {
|
layoutGroupList() {
|
||||||
const groupList = layoutGroupList[this.$i18n.locale] || layoutGroupList.zh
|
const groupList = layoutGroupList[this.$i18n.locale] || layoutGroupList.zh
|
||||||
return groupList.map(group => {
|
return groupList.map(group => {
|
||||||
let list = [...group.list].filter(item => {
|
let list = [...group.list]
|
||||||
return !['rightFishbone', 'rightFishbone2'].includes(item)
|
if (!this.supportRightFishbone) {
|
||||||
})
|
list = list.filter(item => {
|
||||||
|
return !['rightFishbone', 'rightFishbone2'].includes(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
name: group.name,
|
name: group.name,
|
||||||
list
|
list
|
||||||
|
|||||||
@ -437,6 +437,49 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</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">{{ $t('style.nodePadding') }}</div>
|
<div class="title">{{ $t('style.nodePadding') }}</div>
|
||||||
<div class="row noBottom">
|
<div class="row noBottom">
|
||||||
@ -580,7 +623,8 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
isDark: state => state.localConfig.isDark,
|
isDark: state => state.localConfig.isDark,
|
||||||
activeSidebar: state => state.activeSidebar
|
activeSidebar: state => state.activeSidebar,
|
||||||
|
supportLineFlow: state => state.supportLineFlow
|
||||||
}),
|
}),
|
||||||
fontFamilyList() {
|
fontFamilyList() {
|
||||||
return fontFamilyList[this.$i18n.locale] || fontFamilyList.zh
|
return fontFamilyList[this.$i18n.locale] || fontFamilyList.zh
|
||||||
|
|||||||
@ -178,6 +178,13 @@
|
|||||||
<span class="icon iconfont iconwaikuang"></span>
|
<span class="icon iconfont iconwaikuang"></span>
|
||||||
<span class="text">{{ $t('toolbar.outerFrame') }}</span>
|
<span class="text">{{ $t('toolbar.outerFrame') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<NodeAnnotationBtn
|
||||||
|
v-if="item === 'annotation' && supportMark"
|
||||||
|
:isDark="isDark"
|
||||||
|
:dir="dir"
|
||||||
|
:rightHasBtn="annotationRightHasBtn"
|
||||||
|
@setAnnotation="onSetAnnotation"
|
||||||
|
></NodeAnnotationBtn>
|
||||||
<div
|
<div
|
||||||
v-if="item === 'ai'"
|
v-if="item === 'ai'"
|
||||||
class="toolbarBtn"
|
class="toolbarBtn"
|
||||||
@ -195,8 +202,10 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapMutations } from 'vuex'
|
import { mapState, mapMutations } from 'vuex'
|
||||||
|
import NodeAnnotationBtn from './NodeAnnotationBtn.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: { NodeAnnotationBtn },
|
||||||
props: {
|
props: {
|
||||||
dir: {
|
dir: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -222,7 +231,8 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
isDark: state => state.localConfig.isDark
|
isDark: state => state.localConfig.isDark,
|
||||||
|
supportMark: state => state.supportMark
|
||||||
}),
|
}),
|
||||||
hasRoot() {
|
hasRoot() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -16,6 +16,10 @@ const store = new Vuex.Store({
|
|||||||
useLeftKeySelectionRightKeyDrag: false,
|
useLeftKeySelectionRightKeyDrag: false,
|
||||||
// 是否显示滚动条
|
// 是否显示滚动条
|
||||||
isShowScrollbar: false,
|
isShowScrollbar: false,
|
||||||
|
// 是否开启手绘风格
|
||||||
|
isUseHandDrawnLikeStyle: false,
|
||||||
|
// 是否开启动量效果
|
||||||
|
isUseMomentum: true,
|
||||||
// 是否是暗黑模式
|
// 是否是暗黑模式
|
||||||
isDark: false,
|
isDark: false,
|
||||||
// 是否开启AI功能
|
// 是否开启AI功能
|
||||||
@ -26,6 +30,17 @@ const store = new Vuex.Store({
|
|||||||
isReadonly: false, // 是否只读
|
isReadonly: false, // 是否只读
|
||||||
isSourceCodeEdit: false, // 是否是源码编辑模式
|
isSourceCodeEdit: false, // 是否是源码编辑模式
|
||||||
extraTextOnExport: '', // 导出时底部添加的文字
|
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, // 当前是否正在拖拽大纲树的节点
|
isDragOutlineTreeNode: false, // 当前是否正在拖拽大纲树的节点
|
||||||
aiConfig: {
|
aiConfig: {
|
||||||
api: 'http://ark.cn-beijing.volces.com/api/v3/chat/completions',
|
api: 'http://ark.cn-beijing.volces.com/api/v3/chat/completions',
|
||||||
@ -86,6 +101,61 @@ const store = new Vuex.Store({
|
|||||||
state.extraTextOnExport = data
|
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) {
|
setIsDragOutlineTreeNode(state, data) {
|
||||||
state.isDragOutlineTreeNode = data
|
state.isDragOutlineTreeNode = data
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user