mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-17 14:04:47 +08:00
Demo:支持导入导出Excel
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2479351 */
|
||||
src: url('iconfont.woff2?t=1719815803051') format('woff2'),
|
||||
url('iconfont.woff?t=1719815803051') format('woff'),
|
||||
url('iconfont.ttf?t=1719815803051') format('truetype');
|
||||
src: url('iconfont.woff2?t=1726022313538') format('woff2'),
|
||||
url('iconfont.woff?t=1726022313538') format('woff'),
|
||||
url('iconfont.ttf?t=1726022313538') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -13,6 +13,14 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconfile-excel:before {
|
||||
content: "\e7b7";
|
||||
}
|
||||
|
||||
.iconfreemind:before {
|
||||
content: "\e97d";
|
||||
}
|
||||
|
||||
.iconwaikuang:before {
|
||||
content: "\e640";
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -499,8 +499,14 @@ export const downTypeList = [
|
||||
{
|
||||
name: 'FreeMind',
|
||||
type: 'mm',
|
||||
icon: 'iconTXT',
|
||||
icon: 'iconfreemind',
|
||||
desc: 'FreeMind software format'
|
||||
},
|
||||
{
|
||||
name: 'Excel',
|
||||
type: 'xlsx',
|
||||
icon: 'iconfile-excel',
|
||||
desc: 'Excel software format'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -593,8 +593,14 @@ export const downTypeList = [
|
||||
{
|
||||
name: 'FreeMind',
|
||||
type: 'mm',
|
||||
icon: 'iconTXT',
|
||||
icon: 'iconfreemind',
|
||||
desc: 'FreeMind软件格式'
|
||||
},
|
||||
{
|
||||
name: 'Excel',
|
||||
type: 'xlsx',
|
||||
icon: 'iconfile-excel',
|
||||
desc: 'Excel软件格式'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -157,8 +157,9 @@ export default {
|
||||
import: {
|
||||
title: 'Import',
|
||||
selectFile: 'Select file',
|
||||
supportFile: 'Support .smm、.json、.xmind、.xlsx、.md、 .mm file',
|
||||
enableFileTip: 'Please select .smm、.json、.xmind、.xlsx、.md、 .mm file',
|
||||
support: 'Support',
|
||||
file: 'file',
|
||||
pleaseSelect: 'Please select',
|
||||
maxFileNum: 'At most one file can be selected',
|
||||
notSelectTip: 'Please select the file to import',
|
||||
fileContentError: 'The file content is incorrect',
|
||||
|
||||
@@ -155,8 +155,9 @@ export default {
|
||||
import: {
|
||||
title: '导入',
|
||||
selectFile: '选取文件',
|
||||
supportFile: '支持.smm、.json、.xmind、.xlsx、.md、 .mm文件',
|
||||
enableFileTip: '请选择.smm、.json、.xmind、.xlsx、.md、 .mm文件',
|
||||
support: '支持',
|
||||
file: '文件',
|
||||
pleaseSelect: '请选择',
|
||||
maxFileNum: '最多只能选择一个文件',
|
||||
notSelectTip: '请选择要导入的文件',
|
||||
fileContentError: '文件内容有误',
|
||||
|
||||
@@ -80,7 +80,10 @@ import OuterFrame from 'simple-mind-map/src/plugins/OuterFrame.js'
|
||||
// 编号插件,该插件为付费插件,详情请查看开发文档
|
||||
// import Numbers from 'simple-mind-map-plugin-numbers'
|
||||
// Freemind软件格式导入导出插件,该插件为付费插件,详情请查看开发文档
|
||||
import Freemind from 'simple-mind-map-plugin-freemind'
|
||||
// import Freemind from 'simple-mind-map-plugin-freemind'
|
||||
// Excel软件格式导入导出插件,该插件为付费插件,详情请查看开发文档
|
||||
// import Excel from 'simple-mind-map-plugin-excel'
|
||||
// npm link 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
|
||||
import OutlineSidebar from './OutlineSidebar'
|
||||
import Style from './Style'
|
||||
import BaseStyle from './BaseStyle'
|
||||
@@ -137,7 +140,6 @@ MindMap.usePlugin(MiniMap)
|
||||
.usePlugin(RainbowLines)
|
||||
.usePlugin(Demonstrate)
|
||||
.usePlugin(OuterFrame)
|
||||
.usePlugin(Freemind)
|
||||
// .usePlugin(Cooperate) // 协同插件
|
||||
|
||||
// 注册自定义主题
|
||||
@@ -566,6 +568,16 @@ export default {
|
||||
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
|
||||
}
|
||||
this.mindMap.keyCommand.addShortcut('Control+s', () => {
|
||||
this.manualSave()
|
||||
})
|
||||
|
||||
@@ -126,11 +126,23 @@ export default {
|
||||
computed: {
|
||||
...mapState({
|
||||
openNodeRichText: state => state.localConfig.openNodeRichText,
|
||||
isDark: state => state.localConfig.isDark
|
||||
isDark: state => state.localConfig.isDark,
|
||||
supportFreemind: state => state.supportFreemind,
|
||||
supportExcel: state => state.supportExcel
|
||||
}),
|
||||
|
||||
downTypeList() {
|
||||
return downTypeList[this.$i18n.locale] || downTypeList.zh
|
||||
const list = downTypeList[this.$i18n.locale] || downTypeList.zh
|
||||
return list.filter(item => {
|
||||
if (item.type === 'mm') {
|
||||
return this.supportFreemind
|
||||
}
|
||||
if (item.type === 'xlsx') {
|
||||
return this.supportExcel
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<el-upload
|
||||
ref="upload"
|
||||
action="x"
|
||||
accept=".smm,.json,.xmind,.xlsx,.md,.mm"
|
||||
:accept="supportFileStr"
|
||||
:file-list="fileList"
|
||||
:auto-upload="false"
|
||||
:multiple="false"
|
||||
@@ -22,7 +22,7 @@
|
||||
$t('import.selectFile')
|
||||
}}</el-button>
|
||||
<div slot="tip" class="el-upload__tip">
|
||||
{{ $t('import.supportFile') }}
|
||||
{{ $t('import.support') }}{{ supportFileStr }}{{ $t('import.file') }}
|
||||
</div>
|
||||
</el-upload>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
@@ -59,10 +59,8 @@
|
||||
<script>
|
||||
import xmind from 'simple-mind-map/src/parse/xmind.js'
|
||||
import markdown from 'simple-mind-map/src/parse/markdown.js'
|
||||
import { freemindToSmm } from 'simple-mind-map-plugin-freemind/freemindTo.js'
|
||||
import { fileToBuffer } from '@/utils'
|
||||
import { read, utils } from 'xlsx'
|
||||
import { mapMutations } from 'vuex'
|
||||
import { mapMutations, mapState } from 'vuex'
|
||||
import Vue from 'vue'
|
||||
|
||||
/**
|
||||
* @Author: 王林
|
||||
@@ -81,6 +79,22 @@ export default {
|
||||
canvasList: []
|
||||
}
|
||||
},
|
||||
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
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dialogVisible(val, oldVal) {
|
||||
if (!val && oldVal) {
|
||||
@@ -105,12 +119,20 @@ export default {
|
||||
this.dialogVisible = true
|
||||
},
|
||||
|
||||
getRegexp() {
|
||||
return new RegExp(
|
||||
`\.(smm|json|xmind|md${this.supportFreemind ? '|mm' : ''}${
|
||||
this.supportExcel ? '|xlsx' : ''
|
||||
})$`
|
||||
)
|
||||
},
|
||||
|
||||
// 检查url中是否操作需要打开的文件
|
||||
async handleFileURL() {
|
||||
try {
|
||||
const fileURL = this.$route.query.fileURL
|
||||
if (!fileURL) return
|
||||
const macth = /\.(smm|json|xmind|md|xlsx|mm)$/.exec(fileURL)
|
||||
const macth = this.getRegexp().exec(fileURL)
|
||||
if (!macth) {
|
||||
return
|
||||
}
|
||||
@@ -138,9 +160,12 @@ export default {
|
||||
|
||||
// 文件选择
|
||||
onChange(file) {
|
||||
let reg = /\.(smm|xmind|json|xlsx|md|mm)$/
|
||||
if (!reg.test(file.name)) {
|
||||
this.$message.error(this.$t('import.enableFileTip'))
|
||||
if (!this.getRegexp().test(file.name)) {
|
||||
this.$message.error(
|
||||
this.$t('import.pleaseSelect') +
|
||||
this.supportFileStr +
|
||||
this.$t('import.file')
|
||||
)
|
||||
this.fileList = []
|
||||
} else {
|
||||
this.fileList.push(file)
|
||||
@@ -226,18 +251,21 @@ export default {
|
||||
fileReader.readAsText(file.raw)
|
||||
fileReader.onload = async evt => {
|
||||
try {
|
||||
const data = await freemindToSmm(evt.target.result, {
|
||||
// withStyle: true,
|
||||
transformImg: image => {
|
||||
return new Promise(resolve => {
|
||||
if (/^https?:\/\//.test(image)) {
|
||||
resolve({ url: image })
|
||||
} else {
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
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) {
|
||||
@@ -265,59 +293,8 @@ export default {
|
||||
// 处理.xlsx文件
|
||||
async handleExcel(file) {
|
||||
try {
|
||||
const wb = read(await fileToBuffer(file.raw))
|
||||
const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {
|
||||
header: 1
|
||||
})
|
||||
if (data.length <= 0) {
|
||||
return
|
||||
}
|
||||
let max = 0
|
||||
data.forEach(arr => {
|
||||
if (arr.length > max) {
|
||||
max = arr.length
|
||||
}
|
||||
})
|
||||
let layers = []
|
||||
let walk = layer => {
|
||||
if (!layers[layer]) {
|
||||
layers[layer] = []
|
||||
}
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i][layer]) {
|
||||
let node = {
|
||||
data: {
|
||||
text: data[i][layer]
|
||||
},
|
||||
children: [],
|
||||
_row: i
|
||||
}
|
||||
layers[layer].push(node)
|
||||
}
|
||||
}
|
||||
if (layer < max - 1) {
|
||||
walk(layer + 1)
|
||||
}
|
||||
}
|
||||
walk(0)
|
||||
let getParent = (arr, row) => {
|
||||
for (let i = arr.length - 1; i >= 0; i--) {
|
||||
if (row >= arr[i]._row) {
|
||||
return arr[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 1; i < layers.length; i++) {
|
||||
let arr = layers[i]
|
||||
for (let j = 0; j < arr.length; j++) {
|
||||
let item = arr[j]
|
||||
let parent = getParent(layers[i - 1], item._row)
|
||||
if (parent) {
|
||||
parent.children.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$bus.$emit('setData', layers[0][0])
|
||||
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)
|
||||
|
||||
@@ -31,6 +31,8 @@ const store = new Vuex.Store({
|
||||
supportHandDrawnLikeStyle: false, // 是否支持设置手绘风格
|
||||
supportMark: false, // 是否支持标记
|
||||
supportNumbers: false, // 是否支持编号
|
||||
supportFreemind: false, // 是否支持Freemind插件
|
||||
supportExcel: false, // 是否支持Excel插件
|
||||
isDragOutlineTreeNode: false // 当前是否正在拖拽大纲树的节点
|
||||
},
|
||||
mutations: {
|
||||
@@ -93,6 +95,16 @@ const store = new Vuex.Store({
|
||||
state.supportNumbers = data
|
||||
},
|
||||
|
||||
// 设置是否支持Freemind插件
|
||||
setSupportFreemind(state, data) {
|
||||
state.supportFreemind = data
|
||||
},
|
||||
|
||||
// 设置是否支持Excel插件
|
||||
setSupportExcel(state, data) {
|
||||
state.supportExcel = data
|
||||
},
|
||||
|
||||
// 设置树节点拖拽
|
||||
setIsDragOutlineTreeNode(state, data) {
|
||||
state.isDragOutlineTreeNode = data
|
||||
|
||||
Reference in New Issue
Block a user