mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-17 14:04:47 +08:00
update
This commit is contained in:
14
README.md
14
README.md
@@ -362,6 +362,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/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>
|
||||
</table>
|
||||
|
||||
@@ -994,5 +1001,12 @@ 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>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -672,13 +672,11 @@ export const layoutGroupList = [
|
||||
list: [
|
||||
'timeline',
|
||||
'timeline2',
|
||||
'verticalTimeline2',
|
||||
'verticalTimeline3',
|
||||
'verticalTimeline'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Fishbone',
|
||||
list: ['fishbone', 'fishbone2', 'rightFishbone', 'rightFishbone2']
|
||||
list: ['fishbone']
|
||||
}
|
||||
]
|
||||
|
||||
@@ -695,13 +695,11 @@ export const layoutGroupList = [
|
||||
list: [
|
||||
'timeline',
|
||||
'timeline2',
|
||||
'verticalTimeline2',
|
||||
'verticalTimeline3',
|
||||
'verticalTimeline'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Bản đồ Fishbone',
|
||||
list: ['fishbone', 'fishbone2', 'rightFishbone', 'rightFishbone2']
|
||||
list: ['fishbone']
|
||||
}
|
||||
]
|
||||
|
||||
@@ -773,13 +773,11 @@ export const layoutGroupList = [
|
||||
list: [
|
||||
'timeline',
|
||||
'timeline2',
|
||||
'verticalTimeline2',
|
||||
'verticalTimeline3',
|
||||
'verticalTimeline'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: '鱼骨图',
|
||||
list: ['fishbone', 'fishbone2', 'rightFishbone', 'rightFishbone2']
|
||||
list: ['fishbone']
|
||||
}
|
||||
]
|
||||
|
||||
@@ -671,13 +671,11 @@ export const layoutGroupList = [
|
||||
list: [
|
||||
'timeline',
|
||||
'timeline2',
|
||||
'verticalTimeline2',
|
||||
'verticalTimeline3',
|
||||
'verticalTimeline'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: '魚骨圖',
|
||||
list: ['fishbone', 'fishbone2', 'rightFishbone', 'rightFishbone2']
|
||||
list: ['fishbone']
|
||||
}
|
||||
]
|
||||
|
||||
@@ -301,61 +301,6 @@
|
||||
>
|
||||
</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="row">
|
||||
@@ -933,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() {
|
||||
|
||||
@@ -62,41 +62,6 @@
|
||||
<div class="item" @click="exec('EXPAND_ALL')">
|
||||
<span class="name">{{ $t('contextmenu.expandNodeChild') }}</span>
|
||||
</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="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 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')">
|
||||
<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,12 +107,7 @@ 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'
|
||||
@@ -145,8 +118,6 @@ 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'
|
||||
@@ -155,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)
|
||||
@@ -208,8 +178,6 @@ export default {
|
||||
OutlineEdit,
|
||||
Scrollbar,
|
||||
FormulaSidebar,
|
||||
SourceCodeEdit,
|
||||
NodeAttachment,
|
||||
NodeOuterFrame,
|
||||
NodeTagStyle,
|
||||
Setting,
|
||||
@@ -217,8 +185,7 @@ export default {
|
||||
NodeImgPlacementToolbar,
|
||||
NodeNoteSidebar,
|
||||
AiCreate,
|
||||
AiChat,
|
||||
LinkNodeSelect
|
||||
AiChat
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -239,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: {
|
||||
@@ -262,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)
|
||||
@@ -295,9 +243,8 @@ export default {
|
||||
this.$bus.$on('showLoading', this.handleShowLoading)
|
||||
this.$bus.$on('localStorageExceeded', this.onLocalStorageExceeded)
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
document.body.addEventListener('click', this.onVipCheckClick)
|
||||
this.$bus.$on('showDownloadTip', this.showDownloadTip)
|
||||
this.$bus.$on('vipCheckClick', this.onVipCheckClick)
|
||||
this.webTip()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off('execCommand', this.execCommand)
|
||||
@@ -312,9 +259,7 @@ export default {
|
||||
this.$bus.$off('showLoading', this.handleShowLoading)
|
||||
this.$bus.$off('localStorageExceeded', this.onLocalStorageExceeded)
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
document.body.removeEventListener('click', this.onVipCheckClick)
|
||||
this.$bus.$off('showDownloadTip', this.showDownloadTip)
|
||||
this.$bus.$off('vipCheckClick', this.onVipCheckClick)
|
||||
this.mindMap.destroy()
|
||||
},
|
||||
methods: {
|
||||
@@ -425,7 +370,7 @@ export default {
|
||||
openRealtimeRenderOnNodeTextEdit: true,
|
||||
enableAutoEnterTextEditWhenKeydown: true,
|
||||
demonstrateConfig: {
|
||||
openBlankMode: true
|
||||
openBlankMode: false
|
||||
},
|
||||
...(config || {}),
|
||||
iconList: [...icon],
|
||||
@@ -500,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', () => {
|
||||
@@ -649,7 +484,6 @@ export default {
|
||||
})
|
||||
})
|
||||
this.bindSaveEvent()
|
||||
this.testDynamicCreateNodes()
|
||||
// 如果应用被接管,那么抛出事件传递思维导图实例
|
||||
if (window.takeOverApp) {
|
||||
this.$bus.$emit('app_inited', this.mindMap)
|
||||
@@ -666,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: 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中是否存在要打开的文件
|
||||
@@ -812,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
|
||||
@@ -849,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) {
|
||||
@@ -1022,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
|
||||
@@ -1034,30 +627,18 @@ export default {
|
||||
this.$bus.$emit('importFile', file)
|
||||
},
|
||||
|
||||
// 网页版功能试用提示
|
||||
onVipCheckClick(e) {
|
||||
const el = getParentWithClass(e.target, 'vip')
|
||||
if (el) {
|
||||
const className = el.classList.value.split(/\s+/).join('_')
|
||||
const storageKey = 'VIP_USAGE_TIP'
|
||||
let data = localStorage.getItem(storageKey)
|
||||
// 网页版试用提示
|
||||
webTip() {
|
||||
const storageKey = 'webUseTip'
|
||||
const data = localStorage.getItem(storageKey)
|
||||
if (data) {
|
||||
data = JSON.parse(data)
|
||||
} else {
|
||||
data = {}
|
||||
return
|
||||
}
|
||||
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))
|
||||
}
|
||||
localStorage.setItem(storageKey, 1)
|
||||
},
|
||||
|
||||
showDownloadTip(title, desc) {
|
||||
@@ -1065,7 +646,15 @@ export default {
|
||||
this.$msgbox({
|
||||
title,
|
||||
message: h('div', null, [
|
||||
h('p', null, desc),
|
||||
h(
|
||||
'p',
|
||||
{
|
||||
style: {
|
||||
marginBottom: '12px'
|
||||
}
|
||||
},
|
||||
desc
|
||||
),
|
||||
h('div', null, [
|
||||
h(
|
||||
'a',
|
||||
@@ -1137,11 +726,6 @@ export default {
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
// left: 100px;
|
||||
// top: 100px;
|
||||
// right: 100px;
|
||||
// bottom: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
v-for="item in downTypeList"
|
||||
:key="item.type"
|
||||
:class="{
|
||||
active: exportType === item.type,
|
||||
vip: ['mm', 'xlsx'].includes(item.type)
|
||||
active: exportType === item.type
|
||||
}"
|
||||
@click="exportType = item.type"
|
||||
>
|
||||
@@ -80,7 +79,6 @@
|
||||
<span class="name">{{ $t('export.format') }}</span>
|
||||
<el-radio-group v-model="imageFormat">
|
||||
<el-radio label="png">PNG</el-radio>
|
||||
<el-radio label="jpg" class="vip">JPG</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="valueSubItem">
|
||||
@@ -176,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
|
||||
}
|
||||
@@ -274,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)
|
||||
}
|
||||
|
||||
@@ -21,20 +21,13 @@
|
||||
<el-button slot="trigger" size="small" type="primary">{{
|
||||
$t('import.selectFile')
|
||||
}}</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">
|
||||
{{ $t('import.support') }}{{ supportFileStr }}{{ $t('import.file') }}
|
||||
</div>
|
||||
</el-upload>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancel">{{ $t('dialog.cancel') }}</el-button>
|
||||
<el-button class="vip" type="primary" @click="confirm">{{
|
||||
<el-button type="primary" @click="confirm">{{
|
||||
$t('dialog.confirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
@@ -60,34 +53,13 @@
|
||||
}}</el-button>
|
||||
</span>
|
||||
</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>
|
||||
</template>
|
||||
|
||||
<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'
|
||||
|
||||
// 导入
|
||||
@@ -100,24 +72,12 @@ export default {
|
||||
xmindCanvasSelectDialogVisible: false,
|
||||
selectCanvas: '',
|
||||
canvasList: [],
|
||||
mdImportDialogVisible: false,
|
||||
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: {
|
||||
@@ -145,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中是否操作需要打开的文件
|
||||
@@ -171,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)
|
||||
@@ -223,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)
|
||||
@@ -270,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
|
||||
@@ -315,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()
|
||||
@@ -351,29 +257,6 @@ export default {
|
||||
})
|
||||
if (this.fileList.length <= 0) return
|
||||
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'))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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 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>
|
||||
@@ -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>
|
||||
@@ -4,7 +4,6 @@
|
||||
class="sidebarContent customScrollbar"
|
||||
:class="{ isDark: isDark }"
|
||||
v-if="configData"
|
||||
@click="onClick"
|
||||
>
|
||||
<!-- 水印 -->
|
||||
<div class="row">
|
||||
@@ -257,40 +256,6 @@
|
||||
>
|
||||
</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="rowItem">
|
||||
@@ -439,10 +404,7 @@ export default {
|
||||
enableAutoEnterTextEditWhenKeydown: true,
|
||||
imgTextMargin: 0,
|
||||
textContentMargin: 0,
|
||||
enableInheritAncestorLineStyle: false,
|
||||
demonstrateConfig: {
|
||||
openBlankMode: false
|
||||
}
|
||||
enableInheritAncestorLineStyle: false
|
||||
},
|
||||
watermarkConfig: {
|
||||
show: false,
|
||||
@@ -461,8 +423,6 @@ export default {
|
||||
enableNodeRichText: true,
|
||||
localConfigs: {
|
||||
isShowScrollbar: false,
|
||||
isUseHandDrawnLikeStyle: false,
|
||||
isUseMomentum: false,
|
||||
enableDragImport: false,
|
||||
enableAi: false
|
||||
}
|
||||
@@ -472,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: {
|
||||
@@ -535,23 +493,10 @@ export default {
|
||||
|
||||
// 更新其他配置
|
||||
updateOtherConfig(key, value) {
|
||||
if (key === 'openBlankMode') {
|
||||
this.mindMap.updateConfig({
|
||||
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)
|
||||
if (
|
||||
[
|
||||
@@ -628,10 +573,6 @@ export default {
|
||||
this.setLocalConfig({
|
||||
[key]: value
|
||||
})
|
||||
},
|
||||
|
||||
onClick(e) {
|
||||
this.$bus.$emit('vipCheckClick', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 => {
|
||||
let list = [...group.list].filter(item => {
|
||||
return !['rightFishbone', 'rightFishbone2'].includes(item)
|
||||
})
|
||||
}
|
||||
return {
|
||||
name: group.name,
|
||||
list
|
||||
|
||||
@@ -437,49 +437,6 @@
|
||||
</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">{{ $t('style.nodePadding') }}</div>
|
||||
<div class="row noBottom">
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user