开发中

This commit is contained in:
wanglin2 2023-05-05 10:51:39 +08:00
parent ec9517c491
commit fbff68c635
26 changed files with 475 additions and 292 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 KiB

BIN
web/build/icons/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
web/build/icons/16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

BIN
web/build/icons/24x24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 B

BIN
web/build/icons/256x256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
web/build/icons/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 B

BIN
web/build/icons/48x48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
web/build/icons/512x512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
web/build/icons/64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
web/build/icons/icon.icns Normal file

Binary file not shown.

BIN
web/build/icons/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

BIN
web/build/icons/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

BIN
web/build/icons/menu@88.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

View File

@ -93,7 +93,7 @@
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
eval("const { contextBridge, ipcRenderer } = __webpack_require__(/*! electron */ \"electron\")\n\ncontextBridge.exposeInMainWorld('platform', process.platform)\ncontextBridge.exposeInMainWorld('IS_ELECTRON', true)\n\ncontextBridge.exposeInMainWorld('electronAPI', {\n minimize: () => ipcRenderer.send('minimize'),\n maximize: () => ipcRenderer.send('maximize'),\n unmaximize: () => ipcRenderer.send('unmaximize'),\n close: () => ipcRenderer.send('close'),\n create: (id) => ipcRenderer.send('create', id),\n getFileContent: (id) => ipcRenderer.invoke('getFileContent', id),\n save: (id, data) => ipcRenderer.invoke('save', id, data),\n rename: (id, name) => ipcRenderer.invoke('rename', id, name),\n openUrl: (url) => ipcRenderer.send('openUrl', url),\n getRecentFileList: () => ipcRenderer.invoke('getRecentFileList'),\n clearRecentFileList: () => ipcRenderer.invoke('clearRecentFileList'),\n openFileInDir: (file) => ipcRenderer.send('openFileInDir', file),\n deleteFile: (file) => ipcRenderer.invoke('deleteFile', file),\n onRefreshRecentFileList: (callback) => ipcRenderer.on('refreshRecentFileList', callback),\n openFile: (file) => ipcRenderer.send('openFile', file),\n selectOpenFile: () => ipcRenderer.send('selectOpenFile'),\n})\n\n//# sourceURL=webpack:///./src/electron/preload.js?");
eval("const { contextBridge, ipcRenderer } = __webpack_require__(/*! electron */ \"electron\")\r\n\r\ncontextBridge.exposeInMainWorld('platform', process.platform)\r\ncontextBridge.exposeInMainWorld('IS_ELECTRON', true)\r\n\r\ncontextBridge.exposeInMainWorld('electronAPI', {\r\n minimize: () => ipcRenderer.send('minimize'),\r\n maximize: () => ipcRenderer.send('maximize'),\r\n unmaximize: () => ipcRenderer.send('unmaximize'),\r\n close: () => ipcRenderer.send('close'),\r\n destroy: () => ipcRenderer.send('destroy'),\r\n create: id => ipcRenderer.send('create', id),\r\n getFileContent: id => ipcRenderer.invoke('getFileContent', id),\r\n save: (id, data, fileName) => ipcRenderer.invoke('save', id, data, fileName),\r\n rename: (id, name) => ipcRenderer.invoke('rename', id, name),\r\n openUrl: url => ipcRenderer.send('openUrl', url),\r\n addRecentFileList: (fileList) => ipcRenderer.invoke('addRecentFileList', fileList),\r\n getRecentFileList: () => ipcRenderer.invoke('getRecentFileList'),\r\n clearRecentFileList: () => ipcRenderer.invoke('clearRecentFileList'),\r\n openFileInDir: file => ipcRenderer.send('openFileInDir', file),\r\n deleteFile: file => ipcRenderer.invoke('deleteFile', file),\r\n onRefreshRecentFileList: callback =>\r\n ipcRenderer.on('refreshRecentFileList', callback),\r\n openFile: file => ipcRenderer.send('openFile', file),\r\n selectOpenFile: () => ipcRenderer.send('selectOpenFile'),\r\n copyFile: file => ipcRenderer.invoke('copyFile', file)\r\n})\r\n\n\n//# sourceURL=webpack:///./src/electron/preload.js?");
/***/ }),
@ -104,7 +104,7 @@ eval("const { contextBridge, ipcRenderer } = __webpack_require__(/*! electron */
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
eval("module.exports = __webpack_require__(/*! /Users/lisa/wanglin/github/mind-map/web/src/electron/preload.js */\"./src/electron/preload.js\");\n\n\n//# sourceURL=webpack:///multi_./src/electron/preload.js?");
eval("module.exports = __webpack_require__(/*! E:\\wanglin\\mind-map\\web\\src\\electron\\preload.js */\"./src/electron/preload.js\");\n\n\n//# sourceURL=webpack:///multi_./src/electron/preload.js?");
/***/ }),

View File

@ -15,6 +15,10 @@
"autoBuildDoc": "node ./scripts/autoBuildDoc.js",
"buildDoc": "node ./scripts/buildDoc.js",
"electron:build": "vue-cli-service electron:build",
"electron:build-all": "vue-cli-service electron:build -p never -mwl",
"electron:build-mac": "vue-cli-service electron:build -p never -m",
"electron:build-win": "vue-cli-service electron:build -p never -w",
"electron:build-linux": "vue-cli-service electron:build -p never -l",
"electron:serve": "vue-cli-service electron:serve",
"buildLibrary": "vue-cli-service build --target lib --name simpleMindMap ../simple-mind-map/full.js --dest ../simple-mind-map/dist && esbuild ../simple-mind-map/full.js --bundle --external:buffer --format=esm --outfile=../simple-mind-map/dist/simpleMindMap.esm.js",
"format": "prettier --write src/* src/*/* src/*/*/* src/*/*/*/*",

View File

@ -1,18 +1,14 @@
'use strict'
import {
app,
protocol,
BrowserWindow,
} from 'electron'
import { app, protocol, BrowserWindow } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import path from 'path'
import { bindFileHandleEvent } from './electron/fileHandle'
import { bindOtherHandleEvent } from './electron/otherHandle';
import { bindOtherHandleEvent } from './electron/otherHandle'
const isDevelopment = process.env.NODE_ENV !== 'production'
// Scheme must be registered before the app is ready
// 在应用程序准备就绪之前,必须注册方案
protocol.registerSchemesAsPrivileged([
{ scheme: 'app', privileges: { secure: true, standard: true } }
])
@ -35,12 +31,14 @@ async function createMainWindow() {
})
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
await mainWindow.loadURL(process.env.WEBPACK_DEV_SERVER_URL + '/#/workbenche')
// if (!process.env.IS_TEST) mainWindow.webContents.openDevTools()
// 如果处于开发模式则加载开发服务器的url
await mainWindow.loadURL(
process.env.WEBPACK_DEV_SERVER_URL + '/#/workbenche'
)
if (!process.env.IS_TEST) mainWindow.webContents.openDevTools()
} else {
createProtocol('app')
// Load the index.html when not in development
// 非开发环境时加载index.html
mainWindow.loadURL('app://./index.html/#/workbenche')
}
}
@ -53,19 +51,17 @@ const bindEvent = () => {
// 关闭所有窗口后退出
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
// 在macOS上应用程序及其菜单栏通常保持活动状态直到用户使用Cmd+Q明确退出
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
// 在macOS上当点击dock图标且没有其他窗口打开时通常会在应用程序中重新创建一个窗口。
if (BrowserWindow.getAllWindows().length === 0) {
createMainWindow()
bindEvent()
// bindEvent()
}
})
@ -74,7 +70,7 @@ app.on('ready', async () => {
bindEvent()
})
// Exit cleanly on request from parent process in development mode.
// 在开发模式下,应父进程的请求干净地退出。
if (isDevelopment) {
if (process.platform === 'win32') {
process.on('message', data => {

View File

@ -1,196 +1,246 @@
import {
BrowserWindow,
ipcMain,
dialog,
shell
} from 'electron'
import { BrowserWindow, ipcMain, dialog, shell } from 'electron'
import fs from 'fs-extra'
import path from 'path'
import { saveToRecent, clearRecent, removeFileInRecent, replaceFileInRecent, getRecent } from './storage'
import {
saveToRecent,
clearRecent,
removeFileInRecent,
replaceFileInRecent,
getRecent,
saveFileListToRecent
} from './storage'
import { v4 as uuid } from 'uuid'
export const bindFileHandleEvent = ({ mainWindow }) => {
// 通知主页面刷新最近文件列表
const notifyMainWindowRefreshRecentFileList = () => {
mainWindow.webContents.send('refreshRecentFileList')
}
// 通知主页面刷新最近文件列表
const notifyMainWindowRefreshRecentFileList = () => {
mainWindow.webContents.send('refreshRecentFileList')
}
// 新建编辑页面
const openIds = []
const createEditWindow = async (event, id) => {
openIds.push(id)
const win = new BrowserWindow({
width: 1200,
height: 800,
frame: false,
titleBarStyle: 'hiddenInset',
webPreferences: {
webSecurity: false,
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
// 新建编辑页面
const openIds = []
const createEditWindow = async (event, id) => {
openIds.push(id)
const win = new BrowserWindow({
width: 1200,
height: 800,
frame: false,
titleBarStyle: 'hiddenInset',
webPreferences: {
webSecurity: false,
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
})
win.on('closed', () => {
// 从openIds数组中删除
let index = openIds.find(item => {
return item === id
})
if (index !== -1) {
openIds.splice(index, 1)
}
// 从idToFilePath中删除
delete idToFilePath[id]
})
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
win.loadURL(
process.env.WEBPACK_DEV_SERVER_URL + '/#/workbenche/edit/' + id
)
if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
// Load the index.html when not in development
win.loadURL('app://./index.html/#/workbenche/edit/' + id)
}
}
ipcMain.on('create', createEditWindow)
// 保存文件
const idToFilePath = {}
ipcMain.handle('save', async (event, id, data, fileName = '未命名') => {
if (!idToFilePath[id]) {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
const res = dialog.showSaveDialogSync(win, {
title: '保存',
defaultPath: fileName + '.smm',
filters: [{ name: '思维导图', extensions: ['smm'] }]
})
if (res) {
idToFilePath[id] = res
fs.writeFile(res, data)
saveToRecent(res).then(() => {
notifyMainWindowRefreshRecentFileList()
})
win.on('closed', () => {
let index = openIds.find(item => {
return item === id
})
if (index !== -1) {
openIds.splice(index, 1)
}
return path.parse(idToFilePath[id]).name
}
} else {
fs.writeFile(idToFilePath[id], data)
}
})
// 打开文件
const openFile = (event, file) => {
let id = uuid()
idToFilePath[id] = file
saveToRecent(file).then(() => {
notifyMainWindowRefreshRecentFileList()
})
createEditWindow(null, id)
}
ipcMain.on('openFile', openFile)
// 选择打开本地文件
ipcMain.on('selectOpenFile', event => {
const res = dialog.showOpenDialogSync({
title: '选择',
filters: [{ name: '思维导图', extensions: ['smm'] }]
})
if (res && res[0]) {
openFile(null, res[0])
}
})
// 获取文件内容
ipcMain.handle('getFileContent', (event, id) => {
return new Promise(resolve => {
let file = idToFilePath[id]
if (!file) {
resolve(null)
return
}
fs.readFile(file, { encoding: 'utf-8' }, (err, data) => {
resolve({
name: path.parse(file).name,
content: JSON.parse(data)
})
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
win.loadURL(
process.env.WEBPACK_DEV_SERVER_URL + '/#/workbenche/edit/' + id
)
if (!process.env.IS_TEST) win.webContents.openDevTools()
})
})
})
// 重命名文件
ipcMain.handle('rename', (event, id, name) => {
return new Promise(resolve => {
if (!idToFilePath[id]) {
resolve('文件不存在')
return
}
let oldPath = idToFilePath[id]
let { base, ...oldPathData } = path.parse(oldPath)
oldPathData.name = name
let newPath = path.format(oldPathData)
idToFilePath[id] = newPath
fs.rename(oldPath, newPath, err => {
if (err) {
resolve('重命名失败')
} else {
// Load the index.html when not in development
win.loadURL('app://./index.html/#/workbenche/edit/' + id)
replaceFileInRecent(oldPath, newPath).then(() => {
notifyMainWindowRefreshRecentFileList()
resolve()
})
}
}
ipcMain.on('create', createEditWindow)
})
})
})
// 保存文件
const idToFilePath = {}
ipcMain.handle('save', async (event, id, data) => {
if (!idToFilePath[id]) {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
const res = dialog.showSaveDialogSync(win, {
title: '保存',
defaultPath: '未命名.smm',
filters: [{ name: '思维导图', extensions: ['smm'] }]
})
if (res) {
idToFilePath[id] = res
fs.writeFile(res, data)
saveToRecent(res)
.then(() => {
notifyMainWindowRefreshRecentFileList()
})
return path.parse(idToFilePath[id]).name
}
// 获取最近文件列表
ipcMain.handle('getRecentFileList', () => {
return getRecent().map(item => {
let data = path.parse(item)
return {
url: item,
dir: data.dir,
name: data.name
}
})
})
// 清空最近文件列表
ipcMain.handle('clearRecentFileList', async () => {
try {
clearRecent()
return ''
} catch (error) {
return '清空失败'
}
})
// 添加到最近文件列表
ipcMain.handle('addRecentFileList', async (event, fileList) => {
try {
console.log(fileList);
await saveFileListToRecent(fileList)
notifyMainWindowRefreshRecentFileList()
} catch (error) {
return error
}
})
// 打开指定目录
ipcMain.on('openFileInDir', (event, file) => {
shell.showItemInFolder(file)
})
// 删除指定文件
ipcMain.handle('deleteFile', (event, file) => {
let res = ''
let id = Object.keys(idToFilePath).find(item => {
return idToFilePath[item] === file
})
let index = -1
if (id) {
index = openIds.findIndex(item => {
return item === id
})
}
if (index === -1) {
try {
fs.rmSync(file)
} catch (error) {}
removeFileInRecent(file)
} else {
res = '该文件正在编辑,请关闭后再试'
}
return res
})
// 复制文件
ipcMain.handle('copyFile', async (event, file) => {
return new Promise((resolve, reject) => {
fs.pathExists(file, (err, exists) => {
if (err) {
reject(err)
} else {
fs.writeFile(idToFilePath[id], data)
}
})
// 打开文件
const openFile = (event, file) => {
let id = uuid()
idToFilePath[id] = file
saveToRecent(file)
.then(() => {
notifyMainWindowRefreshRecentFileList()
})
createEditWindow(null, id)
}
ipcMain.on('openFile', openFile)
// 选择打开本地文件
ipcMain.on('selectOpenFile', (event) => {
const res = dialog.showOpenDialogSync({
title: '选择',
filters: [{ name: '思维导图', extensions: ['smm'] }],
})
if (res && res[0]) {
openFile(null, res[0])
}
})
// 获取文件内容
ipcMain.handle('getFileContent', (event, id) => {
return new Promise((resolve) => {
let file = idToFilePath[id]
if (!file) {
resolve(null)
return
}
fs.readFile(file, { encoding: 'utf-8' }, (err, data) => {
resolve({
name: path.parse(file).name,
content: JSON.parse(data)
})
})
})
})
// 重命名文件
ipcMain.handle('rename', (event, id, name) => {
return new Promise((resolve) => {
if (!idToFilePath[id]) {
resolve('文件不存在')
return
}
let oldPath = idToFilePath[id]
let { base, ...oldPathData } = path.parse(oldPath)
oldPathData.name = name
if (exists) {
let { base, ...oldPathData } = path.parse(file)
let newName = oldPathData.name + '-复制'
let index = 1
oldPathData.name = newName
let newPath = path.format(oldPathData)
idToFilePath[id] = newPath
fs.rename(oldPath, newPath, (err) => {
if (err) {
resolve('重命名失败')
} else {
replaceFileInRecent(oldPath, newPath).then(() => {
notifyMainWindowRefreshRecentFileList()
resolve()
})
}
})
})
})
// 获取最近文件列表
ipcMain.handle('getRecentFileList', () => {
return getRecent().map(item => {
console.log(item);
let data = path.parse(item)
return {
url: item,
dir: data.dir,
name: data.name
// 检查新路径是否已存在
while (fs.pathExistsSync(newPath)) {
oldPathData.name = newName + index
newPath = path.format(oldPathData)
index++
}
})
})
// 清空最近文件列表
ipcMain.handle('clearRecentFileList', async () => {
try {
clearRecent()
return ''
} catch (error) {
return '清空失败'
}
})
// 打开指定目录
ipcMain.on('openFileInDir', (event, file) => {
shell.showItemInFolder(file)
})
// 删除指定文件
ipcMain.handle('deleteFile', (event, file) => {
let res = ''
let id = Object.keys(idToFilePath).find(item => {
return idToFilePath[item] === file
})
let index = -1
if (id) {
index = openIds.findIndex(item => {
return item === id
fs.copy(file, newPath, err => {
if (err) {
reject(err)
} else {
saveToRecent(newPath).then(() => {
notifyMainWindowRefreshRecentFileList()
})
resolve()
}
})
} else {
reject('文件不存在')
}
}
if (index === -1) {
res = fs.rmSync(file)
if (!res) {
removeFileInRecent(file)
}
} else {
res = '该文件正在编辑,请关闭后再试'
}
return res
})
})
}
})
}

View File

@ -1,21 +1,18 @@
import {
BrowserWindow,
ipcMain,
} from 'electron'
import { BrowserWindow, ipcMain } from 'electron'
import open from 'open'
export const bindOtherHandleEvent = () => {
// 处理缩放事件
;['minimize', 'maximize', 'unmaximize', 'close'].forEach(item => {
ipcMain.on(item, event => {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
win[item]()
})
// 处理缩放事件
;['minimize', 'maximize', 'unmaximize', 'close', 'destroy'].forEach(item => {
ipcMain.on(item, event => {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
win[item]()
})
})
// 使用默认浏览器打开指定url
ipcMain.on('openUrl', (event, url) => {
open(url)
})
}
// 使用默认浏览器打开指定url
ipcMain.on('openUrl', (event, url) => {
open(url)
})
}

View File

@ -4,20 +4,24 @@ contextBridge.exposeInMainWorld('platform', process.platform)
contextBridge.exposeInMainWorld('IS_ELECTRON', true)
contextBridge.exposeInMainWorld('electronAPI', {
minimize: () => ipcRenderer.send('minimize'),
maximize: () => ipcRenderer.send('maximize'),
unmaximize: () => ipcRenderer.send('unmaximize'),
close: () => ipcRenderer.send('close'),
create: (id) => ipcRenderer.send('create', id),
getFileContent: (id) => ipcRenderer.invoke('getFileContent', id),
save: (id, data) => ipcRenderer.invoke('save', id, data),
rename: (id, name) => ipcRenderer.invoke('rename', id, name),
openUrl: (url) => ipcRenderer.send('openUrl', url),
getRecentFileList: () => ipcRenderer.invoke('getRecentFileList'),
clearRecentFileList: () => ipcRenderer.invoke('clearRecentFileList'),
openFileInDir: (file) => ipcRenderer.send('openFileInDir', file),
deleteFile: (file) => ipcRenderer.invoke('deleteFile', file),
onRefreshRecentFileList: (callback) => ipcRenderer.on('refreshRecentFileList', callback),
openFile: (file) => ipcRenderer.send('openFile', file),
selectOpenFile: () => ipcRenderer.send('selectOpenFile'),
})
minimize: () => ipcRenderer.send('minimize'),
maximize: () => ipcRenderer.send('maximize'),
unmaximize: () => ipcRenderer.send('unmaximize'),
close: () => ipcRenderer.send('close'),
destroy: () => ipcRenderer.send('destroy'),
create: id => ipcRenderer.send('create', id),
getFileContent: id => ipcRenderer.invoke('getFileContent', id),
save: (id, data, fileName) => ipcRenderer.invoke('save', id, data, fileName),
rename: (id, name) => ipcRenderer.invoke('rename', id, name),
openUrl: url => ipcRenderer.send('openUrl', url),
addRecentFileList: (fileList) => ipcRenderer.invoke('addRecentFileList', fileList),
getRecentFileList: () => ipcRenderer.invoke('getRecentFileList'),
clearRecentFileList: () => ipcRenderer.invoke('clearRecentFileList'),
openFileInDir: file => ipcRenderer.send('openFileInDir', file),
deleteFile: file => ipcRenderer.invoke('deleteFile', file),
onRefreshRecentFileList: callback =>
ipcRenderer.on('refreshRecentFileList', callback),
openFile: file => ipcRenderer.send('openFile', file),
selectOpenFile: () => ipcRenderer.send('selectOpenFile'),
copyFile: file => ipcRenderer.invoke('copyFile', file)
})

View File

@ -13,7 +13,30 @@ export const saveToRecent = file => {
list.splice(index, 1)
}
list.push(file)
storage.set(RECENT_FILE_LIST, list, (err) => {
storage.set(RECENT_FILE_LIST, list, err => {
if (err) {
reject(err)
} else {
resolve()
}
})
})
}
// 保存到最近文件
export const saveFileListToRecent = fileList => {
return new Promise((resolve, reject) => {
let list = getRecent()
fileList.forEach(file => {
let index = list.findIndex(item => {
return item === file
})
if (index !== -1) {
list.splice(index, 1)
}
list.push(file)
})
storage.set(RECENT_FILE_LIST, list, err => {
if (err) {
reject(err)
} else {
@ -26,7 +49,7 @@ export const saveToRecent = file => {
// 获取最近文件列表
export const getRecent = () => {
let res = storage.getSync(RECENT_FILE_LIST)
return (Array.isArray(res) ? res : []).filter((item) => {
return (Array.isArray(res) ? res : []).filter(item => {
return !!item
})
}
@ -34,7 +57,7 @@ export const getRecent = () => {
// 清除最近文件列表
export const clearRecent = () => {
return new Promise((resolve, reject) => {
storage.remove(RECENT_FILE_LIST, (err) => {
storage.remove(RECENT_FILE_LIST, err => {
if (err) {
reject(err)
} else {
@ -45,7 +68,7 @@ export const clearRecent = () => {
}
// 从最近文件列表中移除指定文件
export const removeFileInRecent = (file) => {
export const removeFileInRecent = file => {
return new Promise((resolve, reject) => {
let list = getRecent()
let index = list.findIndex(item => {
@ -54,7 +77,7 @@ export const removeFileInRecent = (file) => {
if (index !== -1) {
list.splice(index, 1)
}
storage.set(RECENT_FILE_LIST, list, (err) => {
storage.set(RECENT_FILE_LIST, list, err => {
if (err) {
reject(err)
} else {
@ -75,7 +98,7 @@ export const replaceFileInRecent = (oldFile, newFile) => {
list.splice(index, 1)
}
list.push(newFile)
storage.set(RECENT_FILE_LIST, list, (err) => {
storage.set(RECENT_FILE_LIST, list, err => {
if (err) {
reject(err)
} else {
@ -83,4 +106,4 @@ export const replaceFileInRecent = (oldFile, newFile) => {
}
})
})
}
}

View File

@ -241,6 +241,7 @@ export default {
this.setFileName(data.name)
storeData = data.content
} else {
this.setFileName('未命名')
storeData = getData()
}
this.mindMapData = storeData
@ -264,7 +265,6 @@ export default {
storeData(data)
})
this.$bus.$on('view_data_change', data => {
console.log(2);
this.setIsUnSave(true)
storeConfig({
view: data
@ -437,7 +437,7 @@ export default {
let id = this.$route.params.id
let data = this.mindMap.getData(true)
console.log('保存', id, data)
let res = await window.electronAPI.save(id, JSON.stringify(data))
let res = await window.electronAPI.save(id, JSON.stringify(data), this.fileName)
if (res) {
this.setFileName(res)
}

View File

@ -11,11 +11,31 @@
<el-table-column prop="url" label="文件路径"> </el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button icon="el-icon-edit" circle size="mini" @click="openFile(scope.row.url)"></el-button>
<el-button icon="el-icon-document-copy" circle size="mini"></el-button>
<el-button type="danger" icon="el-icon-delete" circle size="mini"
@click="deleteFile(scope.row.url, scope.$index)"></el-button>
<el-button icon="el-icon-folder-opened" circle size="mini" @click="openFileInDir(scope.row.url)"></el-button>
<el-button
icon="el-icon-edit"
circle
size="mini"
@click="openFile(scope.row.url)"
></el-button>
<el-button
icon="el-icon-document-copy"
circle
size="mini"
@click="copyFile(scope.row.url)"
></el-button>
<el-button
type="danger"
icon="el-icon-delete"
circle
size="mini"
@click="deleteFile(scope.row.url, scope.$index)"
></el-button>
<el-button
icon="el-icon-folder-opened"
circle
size="mini"
@click="openFileInDir(scope.row.url)"
></el-button>
</template>
</el-table-column>
</el-table>
@ -42,49 +62,68 @@ export default {
})
},
methods: {
//
async getRecentFileList() {
let list = await window.electronAPI.getRecentFileList()
this.list = list.reverse()
},
//
openFileInDir(file) {
window.electronAPI.openFileInDir(file)
},
//
deleteFile(file, index) {
this.$confirm('确定删除该文件?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
let res = await window.electronAPI.deleteFile(file)
if (res) {
this.$message.error('删除失败')
} else {
this.list.splice(index, 1)
this.$message.success('删除成功');
}
}).catch(() => { });
})
.then(async () => {
let res = await window.electronAPI.deleteFile(file)
if (res) {
this.$message.error('删除失败')
} else {
this.list.splice(index, 1)
this.$message.success('删除成功')
}
})
.catch(() => {})
},
//
openFile(file) {
window.electronAPI.openFile(file)
},
//
clear() {
this.$confirm('确定清空最近文件?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
let res = await window.electronAPI.clearRecentFileList()
if (res) {
this.$message.error('清空失败')
} else {
this.list = []
this.$message.success('清空成功');
}
}).catch(() => { });
})
.then(async () => {
let res = await window.electronAPI.clearRecentFileList()
if (res) {
this.$message.error('清空失败')
} else {
this.list = []
this.$message.success('清空成功')
}
})
.catch(() => {})
},
//
async copyFile(file) {
try {
window.electronAPI.copyFile(file)
this.$message.success('复制成功')
} catch (error) {
this.$message.error('复制失败')
}
}
}
}

View File

@ -4,7 +4,13 @@
<MacControl></MacControl>
<WinControl></WinControl>
<div class="inputBox">
<el-input v-model="name" size="mini" placeholder=""></el-input>
<el-input
v-model="name"
size="mini"
placeholder=""
@blur="rename"
@keyup.enter="rename"
></el-input>
<div class="modifyDotBox">
<div class="modifyDot" v-show="isUnSave"></div>
</div>
@ -41,37 +47,46 @@ export default {
name(val) {
if (!val.trim()) return
this.setFileName(val.trim())
// let id = this.$route.params.id
// window.electronAPI.rename(id, val.trim())
}
},
created() {
// window.onbeforeunload = async (e) => {
// e.returnValue = false
// if (!this.isUnSave) {
// window.electronAPI.close()
// } else {
// try {
// await this.checkIsClose()
// window.electronAPI.close()
// } catch (error) {}
// }
// }
window.onbeforeunload = async e => {
e.returnValue = false
//
if (!this.isUnSave) {
window.electronAPI.destroy()
} else {
try {
//
await this.checkIsClose()
window.electronAPI.destroy()
} catch (error) {}
}
}
},
methods: {
...mapMutations(['setFileName']),
//
rename() {
let id = this.$route.params.id
window.electronAPI.rename(id, this.name.trim())
},
//
checkIsClose() {
return new Promise((resolve, reject) => {
this.$confirm('有操作尚未保存,是否确认关闭?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
resolve()
}).catch(() => {
reject()
});
})
.then(async () => {
resolve()
})
.catch(() => {
reject()
})
})
}
}

View File

@ -1,5 +1,11 @@
<template>
<div class="workbencheHomeContainer">
<div
class="workbencheHomeContainer"
@drop="onDrop"
@dragenter="onDragenter"
@dragover="onDragover"
@dragleave="onDragleave"
>
<div class="workbencheHomeHeader">
<MacControl></MacControl>
<WinControl></WinControl>
@ -23,6 +29,51 @@ export default {
MacControl,
Sidebar,
FileList
},
methods: {
onDrop(e) {
e.preventDefault()
e.stopPropagation()
let df = e.dataTransfer
let dropFiles = []
if (df.items !== undefined) {
for (let i = 0; i < df.items.length; i++) {
let item = df.items[i]
if (item.kind === 'file' && item.webkitGetAsEntry().isFile) {
let file = item.getAsFile()
if (/\.smm$/.test(file.name)) {
dropFiles.push(file)
}
}
}
}
if (dropFiles.length === 1) {
//
window.electronAPI.openFile(dropFiles[0].path)
} else if (dropFiles.length > 1) {
//
window.electronAPI.addRecentFileList(dropFiles.map((file) => {
return file.path
}))
}
},
onDragenter(e) {
e.preventDefault()
e.stopPropagation()
},
onDragover(e) {
e.preventDefault()
e.stopPropagation()
},
onDragleave(e) {
e.preventDefault()
e.stopPropagation()
}
}
}
</script>

View File

@ -17,10 +17,14 @@ module.exports = {
electronBuilder: {
preload: 'src/electron/preload.js',
builderOptions: {
productName: 'SimpleMindMap',
copyright: 'Copyright © SimpleMindMap',
productName: '思绪思维导图',
copyright: 'Copyright © 思绪思维导图',
// compression: "maximum", // 机器好的可以打开,配置压缩,开启后会让 .AppImage 格式的客户端启动缓慢
asar: true,
fileAssociations: {
ext: 'smm',
icon: './build/icons/icon.ico'
},
publish: [
{
provider: 'github',
@ -55,7 +59,7 @@ module.exports = {
arch: ['x64'],
},
],
publisherName: 'SimpleMindMap',
publisherName: '思绪思维导图',
icon: 'build/icons/icon.ico',
publish: ['github'],
},