diff --git a/.babelrc b/.babelrc index d5876c1..f72838d 100644 --- a/.babelrc +++ b/.babelrc @@ -1,4 +1,13 @@ { - "presets": ["es2015", "stage-0"], - "plugins": ["transform-runtime"] + "presets": [ + "es2015", + "stage-2" + ], + "plugins": ["transform-runtime"], + "comments": false, + "env": { + "test": { + "plugins": ["istanbul"] + } + } } diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..82da0b1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..8ce8de6 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,6 @@ +{ + "extends": "eslint-config-o2team", + "rules": { + "no-multiple-empty-lines": [ 1,{ "max": 1 } ] + } +} diff --git a/app/crashTempate.js b/app/crashTempate.js index 36a9b74..0be66d6 100644 --- a/app/crashTempate.js +++ b/app/crashTempate.js @@ -1,12 +1,11 @@ const electron = require('electron') const crashReporter = electron.crashReporter - exports.start = function () { - crashReporter.start({ - productName: 'xcel', - companyName: 'o2team', - submitURL: 'http://localhost:4000/crash/', - autoSubmit: true - }) -} \ No newline at end of file + crashReporter.start({ + productName: 'xcel', + companyName: 'o2team', + submitURL: 'http://localhost:4000/crash/', + autoSubmit: true + }) +} diff --git a/app/electron.js b/app/electron.js index 275c8f3..5c1a5be 100644 --- a/app/electron.js +++ b/app/electron.js @@ -11,97 +11,90 @@ const Menu = electron.Menu let mainWindow // 主窗口 let backgroundWindow // 执行耗时运算的 背后窗口 -let updateWindow // 更新的下载窗口 -var windowBounds = {} // 主窗口的尺寸信息 let config = {} if (process.env.NODE_ENV === 'development') { - config = require('../config') - config.mainUrl = `http://localhost:${config.port}` + config = require('../config') + config.mainUrl = `http://localhost:${config.port}` } else { - config.devtron = false - config.mainUrl = `file://${__dirname}/dist/index.html` + config.devtron = false + config.mainUrl = `file://${__dirname}/dist/index.html` } config.backUrl = `file://${__dirname}/dist/background/index.html` config.isDev = process.env.NODE_ENV === 'development' - -function createMainWindow() { - var win = new BrowserWindow({ - height: 850, - width: 1280, - minWidth: 1120, - minHeight: 768, - backgroundColor: "#f5f5f5", - fullscreenable: false, - frame: false, - show: false - }) - windowBounds = win.getBounds() - win.loadURL(config.mainUrl) - - if (config.isDev) { - BrowserWindow.addDevToolsExtension(path.join(__dirname, '../node_modules/devtron')) - - let installExtension = require('electron-devtools-installer') - - installExtension.default(installExtension.VUEJS_DEVTOOLS) - .then((name) => win.webContents.openDevTools()) - .catch((err) => console.log('An error occurred: ', err)) - } - - win.on('closed', () => { - console.log("触发 closed") - mainWindow = null - backgroundWindow = null +function createMainWindow () { + const win = new BrowserWindow({ + height: 850, + width: 1280, + minWidth: 1120, + minHeight: 768, + backgroundColor: '#f5f5f5', + fullscreenable: false, + frame: false, + show: false + }) + win.loadURL(config.mainUrl) + + if (config.isDev) { + BrowserWindow.addDevToolsExtension(path.join(__dirname, '../node_modules/devtron')) + + const installExtension = require('electron-devtools-installer') + + installExtension.default(installExtension.VUEJS_DEVTOOLS) + .then(name => win.webContents.openDevTools()) + .catch(err => console.log('An error occurred: ', err)) + } + + win.on('closed', () => { + console.log('触发 closed') + mainWindow = null + backgroundWindow = null // 在Mac中完全退出程序,而不会留在dock中 - app.quit() - }) - - win.on('ready-to-show', () => { - win.show() - win.focus() - }) - console.log('mainWindow opened') - return win + app.quit() + }) + + win.on('ready-to-show', () => { + win.show() + win.focus() + }) + console.log('mainWindow opened') + return win } -function createBackgroundWindow() { - var win = new BrowserWindow({ - show: config.isDev - }) - win.loadURL(config.backUrl) - console.log("backgroundWindow opened") - return win +function createBackgroundWindow () { + const win = new BrowserWindow({ + show: config.isDev + }) + win.loadURL(config.backUrl) + console.log('backgroundWindow opened') + return win } - app.on('ready', () => { - console.log("ready") - mainWindow = createMainWindow() - backgroundWindow = createBackgroundWindow() - ipcMainSets(mainWindow, backgroundWindow) - const menu = Menu.buildFromTemplate(menuTemplate) - Menu.setApplicationMenu(menu) + console.log('ready') + mainWindow = createMainWindow() + backgroundWindow = createBackgroundWindow() + ipcMainSets(mainWindow, backgroundWindow) + const menu = Menu.buildFromTemplate(menuTemplate) + Menu.setApplicationMenu(menu) }) - - app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit() - } + if (process.platform !== 'darwin') { + app.quit() + } }) // 当应用被激活时触发,常用于点击应用的 dock 图标的时候。 // 现在取消保留在Dock中,完全退出 app.on('activate', () => { - if (mainWindow.isDestroyed()) { - mainWindow = createMainWindow() - backgroundWindow = createBackgroundWindow() - } + if (mainWindow.isDestroyed()) { + mainWindow = createMainWindow() + backgroundWindow = createBackgroundWindow() + } }) crashTempate.start() -console.log("主进程pid:", process.pid) +console.log('主进程pid:', process.pid) diff --git a/app/ipcMainSets.js b/app/ipcMainSets.js index ed6f9c0..63aae18 100644 --- a/app/ipcMainSets.js +++ b/app/ipcMainSets.js @@ -2,252 +2,250 @@ const shortid = require('shortid') const xlsx = require('xlsx') const path = require('path') const electron = require('electron') -const os = require('os') const app = electron.app const BrowserWindow = electron.BrowserWindow const dialog = electron.dialog const ipcMain = electron.ipcMain const shell = electron.shell -let savePath = '', - downloadsPath = app.getPath('downloads'), - platform = os.platform() + '_' + os.arch(), - version = app.getVersion(), - updateWindow, - updateItem, - downloadsFullPath +let savePath = '' +const downloadsPath = app.getPath('downloads') +let updateWindow +let updateItem +let downloadsFullPath shortid.characters('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$@') module.exports = function (mainWindow, backgroundWindow) { - - ipcMain.on('will-download-handler', (ipcEvent, arg) => { - if (!updateWindow || updateWindow.isDestroyed()) { - updateWindow = createUpdateWindow() - } - if (!updateWindow.isDestroyed()) { - updateWindow.webContents.session.removeAllListeners() - updateWindow.webContents.session.on('will-download', (event, item, webContents) => { - updateItem = item - downloadsFullPath = downloadsPath + item.getFilename() - item.setSavePath(downloadsFullPath) - console.log(downloadsFullPath) - console.log('getTotalBytes', item.getTotalBytes()) - item.on('updated', (event, state) => { - if (state === 'interrupted') { - console.log('Download is interrupted but can be resumed') - } else if (state === 'progressing') { - if (item.isPaused()) { - console.log('Download is paused') - } else { - console.log(`Received bytes: ${item.getReceivedBytes()}`) - } - } - if (!updateWindow.isDestroyed()) { - updateWindow.webContents.send('will-download-response', { - curReceivedBytes: item.getReceivedBytes(), - totalBytes: item.getTotalBytes(), - downloadStatus: state - }) - } - }) - - item.once('done', (event, state) => { - if (state === 'completed') { - console.log('Download successfully') - if (!shell.openItem(downloadsFullPath)) { - shell.showItemInFolder(downloadsPath) - } - if (!updateWindow.isDestroyed()) { - updateWindow.close() - } - } else { - console.log(`Download failed: ${state}`) - } - item.removeAllListeners() - updateItem = null - item = null - }) - }) - console.log('uodate.url', arg.url) - if (process.env.NODE_ENV === 'development') { - updateWindow.webContents.downloadURL(arg.url) - } else { - updateWindow.webContents.downloadURL(arg.url) - } - } - }) - function createUpdateWindow() { - var win = new BrowserWindow({ - height: 160, - width: 550, - minWidth: 550, - minHeight: 160, - title: '下载最新版的XCel', - backgroundColor: "#f5f5f5" - }) - win.loadURL(`file://${__dirname}/dist/update/index.html`) - win.once('closed', closeUpdateWindow) - return win - } - function closeUpdateWindow(event) { - console.log(updateItem) - if (updateItem) { - updateItem.removeAllListeners() - updateItem.cancel() // cancel 后,DownloadItem 就是 null 了 - updateItem = null - } + ipcMain.on('will-download-handler', (ipcEvent, arg) => { + if (!updateWindow || updateWindow.isDestroyed()) { + updateWindow = createUpdateWindow() } - ipcMain.on('update-switch', (event, arg) => { - if (updateItem) { - let status = '' - if (updateItem.isPaused()) { - if (updateItem.canResume()) { - updateItem.resume() - status = '暂停' - } + if (!updateWindow.isDestroyed()) { + updateWindow.webContents.session.removeAllListeners() + updateWindow.webContents.session.on('will-download', (event, item, webContents) => { + updateItem = item + downloadsFullPath = downloadsPath + item.getFilename() + item.setSavePath(downloadsFullPath) + console.log(downloadsFullPath) + console.log('getTotalBytes', item.getTotalBytes()) + item.on('updated', (event, state) => { + if (state === 'interrupted') { + console.log('Download is interrupted but can be resumed') + } else if (state === 'progressing') { + if (item.isPaused()) { + console.log('Download is paused') } else { - updateItem.pause() - status = '继续' + console.log(`Received bytes: ${item.getReceivedBytes()}`) } - event.sender.send('update-switch-response', { - text: status + } + if (!updateWindow.isDestroyed()) { + updateWindow.webContents.send('will-download-response', { + curReceivedBytes: item.getReceivedBytes(), + totalBytes: item.getTotalBytes(), + downloadStatus: state }) - } - }) - - ipcMain.on('update-cancel', (event, arg) => { - if (updateItem) { - updateItem.removeAllListeners() - updateItem.cancel() - updateWindow.close() - updateItem = null - } - }) - - ipcMain.on('update-checkout', (event, arg) => { - if (updateItem) { - updateItem.cancel() - shell.openExternal('https://xcel.aotu.io/') - updateWindow.close() - updateItem = null - } - }) - - ipcMain.on("readFile-response", (event, arg) => { - console.log("触发readFile-response") - mainWindow.webContents.send("readFile-response", arg) - }) - ipcMain.on("readFile-start", (event, arg) => { - console.log("读取文件emit") - savePath = getSavePath(arg.data.path) - console.log(savePath) - backgroundWindow.webContents.send("readFile-start", arg) - }) - - ipcMain.on("generate-htmlstring-response", (event, arg) => { - mainWindow.webContents.send("generate-htmlstring-response", arg) - }) - - ipcMain.on("filter-response", (event, arg) => { - mainWindow.webContents.send("filter-response", arg) - }) - ipcMain.on("filter-start", (event, arg) => { - backgroundWindow.webContents.send("filter-start", arg) - }) - - ipcMain.on("changeTab-start", (event, arg) => { - backgroundWindow.webContents.send("changeTab-start", arg) - }) - - ipcMain.on("exportFile-response", (event, arg) => { - mainWindow.webContents.send("exportFile-response", arg) - }) - ipcMain.on("exportFile-start", (event, arg) => { - backgroundWindow.webContents.send("exportFile-start", arg) - }) - - ipcMain.on("delAllFilterTag-start", (event, arg) => { - backgroundWindow.webContents.send("delAllFilterTag-start", arg) - }) - - ipcMain.on("sync-openFile-dialog", (event, arg) => { - dialog.showOpenDialog({ - title: "请选择Excel文件", - filters: [{ name: 'Excel File', extensions: ['xls', "xlsx"] }], - properties: ["openFile"] - }, function (arr) { - if (arr !== undefined) { - // arr 是一个文件路径 数组 - // console.log("event", event) - // 正常触发 - if (event) { - event.sender.send("open-file-response", arr[0]) - } - // 通过 emit 触发(如快捷键) - else { - var mainWindow = BrowserWindow.fromId(1) - if (mainWindow) { - mainWindow.webContents.send("open-file-response", arr[0]) - } - } - } + } }) - }) - ipcMain.on("sync-saveFile-dialog", (event, arg) => { - console.log("sync-saveFile-dialog") - dialog.showSaveDialog({ - title: "请选择保存路径", - defaultPath: savePath, - filters: [{ - name: "Excel", - extensions: ["xlsx"] - }] - }, function (p) { - if (p !== undefined) { - xlsx.writeFile(arg.data, p) + item.once('done', (event, state) => { + if (state === 'completed') { + console.log('Download successfully') + if (!shell.openItem(downloadsFullPath)) { + shell.showItemInFolder(downloadsPath) } - // p 是用户输入的路径名 - console.log("p", p); - }) - }) - - - ipcMain.on("sync-alert-dialog", (event, arg) => { - dialog.showMessageBox({ - type: "warning", - buttons: ["确定"], - defaultId: 0, // dialog 打开是默认选中哪个按钮 - title: arg.title || "xcel", - message: arg.content || "", - detail: arg.detail || "" + if (!updateWindow.isDestroyed()) { + updateWindow.close() + } + } else { + console.log(`Download failed: ${state}`) + } + item.removeAllListeners() + updateItem = null + item = null }) - }) - - // 接受窗口的最小化、最大化、关闭 事件 - ipcMain.on("sync-close", (event, arg) => { - mainWindow.close() - }) - ipcMain.on("sync-maximize", (event, arg) => { - if (mainWindow.isMaximized()) { - mainWindow.setBounds(windowBounds) - } else { - windowBounds = mainWindow.getBounds() - mainWindow.maximize() + }) + console.log('uodate.url', arg.url) + if (process.env.NODE_ENV === 'development') { + updateWindow.webContents.downloadURL(arg.url) + } else { + updateWindow.webContents.downloadURL(arg.url) + } + } + }) + function createUpdateWindow () { + const win = new BrowserWindow({ + height: 160, + width: 550, + minWidth: 550, + minHeight: 160, + title: '下载最新版的XCel', + backgroundColor: '#f5f5f5' + }) + win.loadURL(`file://${__dirname}/dist/update/index.html`) + win.once('closed', closeUpdateWindow) + return win + } + function closeUpdateWindow (event) { + console.log(updateItem) + if (updateItem) { + updateItem.removeAllListeners() + updateItem.cancel() // cancel 后,DownloadItem 就是 null 了 + updateItem = null + } + } + ipcMain.on('update-switch', (event, arg) => { + if (updateItem) { + let status = '' + if (updateItem.isPaused()) { + if (updateItem.canResume()) { + updateItem.resume() + status = '暂停' } - event.sender.send("send-isMax", mainWindow.isMaximized()) - }) - ipcMain.on("sync-minimize", (event, arg) => { - if (!mainWindow.isMinimized()) { - mainWindow.minimize() - console.log("可以最小化") + } else { + updateItem.pause() + status = '继续' + } + event.sender.send('update-switch-response', { + text: status + }) + } + }) + + ipcMain.on('update-cancel', (event, arg) => { + if (updateItem) { + updateItem.removeAllListeners() + updateItem.cancel() + updateWindow.close() + updateItem = null + } + }) + + ipcMain.on('update-checkout', (event, arg) => { + if (updateItem) { + updateItem.cancel() + shell.openExternal('https://xcel.aotu.io/') + updateWindow.close() + updateItem = null + } + }) + + ipcMain.on('readFile-response', (event, arg) => { + console.log('触发readFile-response') + mainWindow.webContents.send('readFile-response', arg) + }) + ipcMain.on('readFile-start', (event, arg) => { + console.log('读取文件emit') + savePath = getSavePath(arg.data.path) + console.log(savePath) + backgroundWindow.webContents.send('readFile-start', arg) + }) + + ipcMain.on('generate-htmlstring-response', (event, arg) => { + mainWindow.webContents.send('generate-htmlstring-response', arg) + }) + + ipcMain.on('filter-response', (event, arg) => { + mainWindow.webContents.send('filter-response', arg) + }) + ipcMain.on('filter-start', (event, arg) => { + backgroundWindow.webContents.send('filter-start', arg) + }) + + ipcMain.on('changeTab-start', (event, arg) => { + backgroundWindow.webContents.send('changeTab-start', arg) + }) + + ipcMain.on('exportFile-response', (event, arg) => { + mainWindow.webContents.send('exportFile-response', arg) + }) + ipcMain.on('exportFile-start', (event, arg) => { + backgroundWindow.webContents.send('exportFile-start', arg) + }) + + ipcMain.on('delAllFilterTag-start', (event, arg) => { + backgroundWindow.webContents.send('delAllFilterTag-start', arg) + }) + + ipcMain.on('sync-openFile-dialog', (event, arg) => { + dialog.showOpenDialog({ + title: '请选择Excel文件', + filters: [{ name: 'Excel File', extensions: ['xls', 'xlsx'] }], + properties: ['openFile'] + }, function (arr) { + if (typeof arr !== 'undefined') { + // arr 是一个文件路径 数组 + // console.log("event", event) + // 正常触发 + if (event) { + event.sender.send('open-file-response', arr[0]) } else { - console.log("不可最小化,因为已经最小化了") + // 通过 emit 触发(如快捷键) + const mainWindow = BrowserWindow.fromId(1) + if (mainWindow) { + mainWindow.webContents.send('open-file-response', arr[0]) + } } - }) + } + }) + }) + + ipcMain.on('sync-saveFile-dialog', (event, arg) => { + console.log('sync-saveFile-dialog') + dialog.showSaveDialog({ + title: '请选择保存路径', + defaultPath: savePath, + filters: [{ + name: 'Excel', + extensions: ['xlsx'] + }] + }, function (p) { + if (typeof p !== 'undefined') { + xlsx.writeFile(arg.data, p) + } + // p 是用户输入的路径名 + console.log('p', p) + }) + }) + + ipcMain.on('sync-alert-dialog', (event, arg) => { + dialog.showMessageBox({ + type: 'warning', + buttons: ['确定'], + defaultId: 0, // dialog 打开是默认选中哪个按钮 + title: arg.title || 'xcel', + message: arg.content || '', + detail: arg.detail || '' + }) + }) + + // 接受窗口的最小化、最大化、关闭 事件 + ipcMain.on('sync-close', (event, arg) => { + mainWindow.close() + }) + ipcMain.on('sync-maximize', (event, arg) => { + let windowBounds = { + width: 1280, + height: 850 + } + if (mainWindow.isMaximized()) { + mainWindow.setBounds(windowBounds) + } else { + windowBounds = mainWindow.getBounds() + mainWindow.maximize() + } + event.sender.send('send-isMax', mainWindow.isMaximized()) + }) + ipcMain.on('sync-minimize', (event, arg) => { + if (!mainWindow.isMinimized()) { + mainWindow.minimize() + console.log('可以最小化') + } else { + console.log('不可最小化,因为已经最小化了') + } + }) } -function getSavePath(uPath) { - var file = path.parse(uPath) - return path.join(file.dir, file.name + '-' + shortid.generate() + file.ext) -} \ No newline at end of file +function getSavePath (uPath) { + const file = path.parse(uPath) + return path.join(file.dir, `${file.name}-${shortid.generate()}${file.ext}`) +} diff --git a/app/menuTemplate.js b/app/menuTemplate.js index 87a9438..decbc13 100644 --- a/app/menuTemplate.js +++ b/app/menuTemplate.js @@ -2,163 +2,159 @@ const electron = require('electron') const BrowserWindow = electron.BrowserWindow const ipcMain = electron.ipcMain -var template = [ - { - label: 'File', - submenu: [ - { - label: 'Open File', - accelerator: 'CmdOrCtrl+O', - click: function (item, focusedWindow) { - ipcMain.emit('sync-openFile-dialog') - } - } - ] - }, - { - label: 'View', - submenu: [ - { - label: 'Reload', - accelerator: 'CmdOrCtrl+R', - click: function (item, focusedWindow) { - // console.log("BrowserWindow.getAllWindows()", BrowserWindow.getAllWindows()); - Array.prototype.forEach.call(BrowserWindow.getAllWindows(), (win, i) => { - win.reload() - }) - // if (focusedWindow) focusedWindow.reload() - } - }, - { - label: 'Toggle Developer Tools', - accelerator: (function () { - if (process.platform === 'darwin') { - return 'Alt+Command+I' - } else { - return 'Ctrl+Shift+I' - } - })(), - click: function (item, focusedWindow) { - if (focusedWindow) focusedWindow.toggleDevTools() - } - }, - { - label: 'Toggle Background Renderer', - accelerator: (function () { - if (process.platform === 'darwin') { - return 'Alt+Command+B' - } else { - return 'Ctrl+Shift+B' - } - })(), - click: function (item, focusedWindow) { - var backWin = BrowserWindow.fromId(2) - if (backWin.isVisible()) { - backWin.hide() - } else { - backWin.show() - backWin.focus() - } - } - } - ] - }, - { - label: 'Help', - role: 'help'/*, +const template = [ + { + label: 'File', + submenu: [ + { + label: 'Open File', + accelerator: 'CmdOrCtrl+O', + click (item, focusedWindow) { + ipcMain.emit('sync-openFile-dialog') + } + } + ] + }, + { + label: 'View', + submenu: [ + { + label: 'Reload', + accelerator: 'CmdOrCtrl+R', + click (item, focusedWindow) { + Array.prototype.forEach.call(BrowserWindow.getAllWindows(), (win, i) => { + win.reload() + }) + } + }, + { + label: 'Toggle Developer Tools', + accelerator: (function () { + if (process.platform === 'darwin') { + return 'Alt+Command+I' + } + return 'Ctrl+Shift+I' + })(), + click (item, focusedWindow) { + if (focusedWindow) focusedWindow.toggleDevTools() + } + }, + { + label: 'Toggle Background Renderer', + accelerator: (function () { + if (process.platform === 'darwin') { + return 'Alt+Command+B' + } + return 'Ctrl+Shift+B' + })(), + click (item, focusedWindow) { + const backWin = BrowserWindow.fromId(2) + if (backWin.isVisible()) { + backWin.hide() + } else { + backWin.show() + backWin.focus() + } + } + } + ] + }, + { + label: 'Help', + role: 'help'/*, submenu: [ { label: 'Learn More', click: function () { require('electron').shell.openExternal('http://electron.atom.io') } } - ]*/ - } + ] */ + } ] if (process.platform === 'darwin') { - var name = electron.app.getName() - console.log("appname", name) - template.unshift({ - label: 'Edit', - submenu: [ - { - label: 'Undo', - accelerator: 'CmdOrCtrl+Z', - role: 'undo' - }, - { - label: 'Redo', - accelerator: 'Shift+CmdOrCtrl+Z', - role: 'redo' - }, - { - type: 'separator' - }, - { - label: 'Cut', - accelerator: 'CmdOrCtrl+X', - role: 'cut' - }, - { - label: 'Copy', - accelerator: 'CmdOrCtrl+C', - role: 'copy' - }, - { - label: 'Paste', - accelerator: 'CmdOrCtrl+V', - role: 'paste' - }, - { - label: 'Select All', - accelerator: 'CmdOrCtrl+A', - role: 'selectall' - } - ] - }) - template.unshift({ - label: name, - submenu: [ - { - label: 'About ' + name, - role: 'about' - }, - { - type: 'separator' - }, - { - label: 'Services', - role: 'services', - submenu: [] - }, - { - type: 'separator' - }, - { - label: 'Hide ' + name, - accelerator: 'Command+H', - role: 'hide' - }, - { - label: 'Hide Others', - accelerator: 'Command+Alt+H', - role: 'hideothers' - }, - { - label: 'Show All', - role: 'unhide' - }, - { - type: 'separator' - }, - { - label: 'Quit', - accelerator: 'Command+Q', - click: function () { electron.app.quit() } - } - ] - }) - template.unshift() + const name = electron.app.getName() + console.log('appname', name) + template.unshift({ + label: 'Edit', + submenu: [ + { + label: 'Undo', + accelerator: 'CmdOrCtrl+Z', + role: 'undo' + }, + { + label: 'Redo', + accelerator: 'Shift+CmdOrCtrl+Z', + role: 'redo' + }, + { + type: 'separator' + }, + { + label: 'Cut', + accelerator: 'CmdOrCtrl+X', + role: 'cut' + }, + { + label: 'Copy', + accelerator: 'CmdOrCtrl+C', + role: 'copy' + }, + { + label: 'Paste', + accelerator: 'CmdOrCtrl+V', + role: 'paste' + }, + { + label: 'Select All', + accelerator: 'CmdOrCtrl+A', + role: 'selectall' + } + ] + }) + template.unshift({ + label: name, + submenu: [ + { + label: `About ${name}`, + role: 'about' + }, + { + type: 'separator' + }, + { + label: 'Services', + role: 'services', + submenu: [] + }, + { + type: 'separator' + }, + { + label: `Hide ${name}`, + accelerator: 'Command+H', + role: 'hide' + }, + { + label: 'Hide Others', + accelerator: 'Command+Alt+H', + role: 'hideothers' + }, + { + label: 'Show All', + role: 'unhide' + }, + { + type: 'separator' + }, + { + label: 'Quit', + accelerator: 'Command+Q', + click () { electron.app.quit() } + } + ] + }) + template.unshift() } -module.exports = template \ No newline at end of file +module.exports = template diff --git a/app/src/App.vue b/app/src/App.vue index 1c80f15..58d1c9c 100644 --- a/app/src/App.vue +++ b/app/src/App.vue @@ -1,68 +1,66 @@ \ No newline at end of file +@import './components/assets/common.scss'; +@import './components/assets/content.scss'; +@import './components/assets/table.scss'; +@import './components/assets/tabs.scss'; +@import './components/assets/select.scss'; +@import './components/assets/markdown.scss'; + diff --git a/app/src/background/excelUtils.js b/app/src/background/excelUtils.js index fa0cd48..8df6b54 100644 --- a/app/src/background/excelUtils.js +++ b/app/src/background/excelUtils.js @@ -1,171 +1,175 @@ -'use strict'; - -module.exports = Excel - -function Excel() { - this.workbook = null, - this.sheetNameList = null +'use strict' + +const xlsx = require('xlsx') +const electron = require('electron') +const ipcRenderer = electron.ipcRenderer +const SUFFIX_COLKEYS = '_headers' +function Excel () { + this.workbook = null + this.sheetNameList = null } Excel.prototype = { - constructor: Excel, - - init({ type, path }) { - let isParseSuccess = true - try { - if (!!type) { - if (type === 'node') { - this.readByPath(path) - } else if (type === 'data') { - this.readByData(data) - } - } - } catch (e) { - isParseSuccess = false - ipcRenderer.send('sync-alert-dialog', { - content: '不支持该文件格式' - }) - } - if (isParseSuccess) { - try { - this.initData() - } catch (e) { - console.log(e) - ipcRenderer.send('sync-alert-dialog', { - content: 'Excel内容的格式不符合要求,故导致文件解析失败' - }) - } - return this - } else { - return {} - } - - }, - readByData(data) { + constructor: Excel, + + init ({ type, path }) { + let isParseSuccess = true + try { + if (type) { + if (type === 'node') { + this.readByPath(path) + }/* else if (type === 'data') { + this.readByData(data) + } */ + } + } catch (e) { + isParseSuccess = false + ipcRenderer.send('sync-alert-dialog', { + content: '不支持该文件格式' + }) + } + if (isParseSuccess) { + try { + this.initData() + } catch (e) { + console.log(e) + ipcRenderer.send('sync-alert-dialog', { + content: 'Excel内容的格式不符合要求,故导致文件解析失败' + }) + } + return this + } + return {} + }, + readByData (data) { // 用于前端上传文件,如:上传按钮和拖拽上传 - this.workbook = xlsx.read(data, { type: 'binary' }) - }, - readByPath(filename) { + this.workbook = xlsx.read(data, { type: 'binary' }) + }, + readByPath (filename) { // 用于 Node 直接通过路径读取文件 - this.workbook = xlsx.readFile(filename) - }, - initData() { + this.workbook = xlsx.readFile(filename) + }, + initData () { // 表名列表 - this.sheetNameList = this.workbook.SheetNames + this.sheetNameList = this.workbook.SheetNames // 插入每个sheet的数据(json格式) - this.sheetNameList.forEach((curSheetName, index) => { - this[curSheetName] = xlsx.utils.sheet_to_json(this.workbook.Sheets[curSheetName]) - }) + this.sheetNameList.forEach((curSheetName, index) => { + this[curSheetName] = xlsx.utils.sheet_to_json(this.workbook.Sheets[curSheetName]) + }) // 获取表头 - this.sheetNameList.forEach((curSheetName, index) => { - let curSheetData = this.workbook.Sheets[curSheetName], - scope = this.workbook.Sheets[curSheetName]['!ref'].split(':'), // A1 F5 - startIndex = getNumCol(extractLetters(scope[0])), // Excel 是从 1 开始 - endIndex = getNumCol(extractLetters(scope[1])) - - this[curSheetName + '_headers'] = [] - - for (let i = startIndex, emptyIndex = 0; i <= endIndex; i++) { - let curColKey = curSheetData[getCharCol(i) + '1'] === undefined ? `表头空${emptyIndex++}` : curSheetData[getCharCol(i) + '1'].v - this[curSheetName + '_headers'].push(curColKey) - } - }) - }, - exportFileByWB(args) { - let { filteredData, excelData, writeOpts } = args, - finalWB = { - SheetNames: [], - Sheets: {} - }, - sheetNameList = this.sheetNameList - - sheetNameList.forEach((sheetName, i) => { - let wbTem = this.jsonToWBForOneSheet(filteredData[sheetName], excelData[sheetName + SUFFIX_COLKEYS], sheetName) - finalWB.SheetNames.push(wbTem.SheetNames[0]) - finalWB.Sheets[sheetName] = wbTem['Sheets'][sheetName] - wbTem = null - }) - sheetNameList = null + this.sheetNameList.forEach((curSheetName, index) => { + const curSheetData = this.workbook.Sheets[curSheetName] + const scope = this.workbook.Sheets[curSheetName]['!ref'].split(':') // A1 F5 + const startIndex = getNumCol(extractLetters(scope[0])) // Excel 是从 1 开始 + const endIndex = getNumCol(extractLetters(scope[1])) + + this[`${curSheetName}_headers`] = [] + + for (let i = startIndex, emptyIndex = 0; i <= endIndex; i++) { + const curColKey = typeof curSheetData[`${getCharCol(i)}1`] === 'undefined' ? `表头空${emptyIndex++}` : curSheetData[`${getCharCol(i)}1`].v + this[`${curSheetName}_headers`].push(curColKey) + } + }) + }, + exportFileByWB ({ filteredData, excelData, writeOpts }) { + const finalWB = { + SheetNames: [], + Sheets: {} + } + let sheetNameList = this.sheetNameList + + sheetNameList.forEach((sheetName, i) => { + let wbTem = this.jsonToWBForOneSheet(filteredData[sheetName], excelData[sheetName + SUFFIX_COLKEYS], sheetName) + finalWB.SheetNames.push(wbTem.SheetNames[0]) + finalWB.Sheets[sheetName] = wbTem.Sheets[sheetName] + wbTem = null + }) + sheetNameList = null // console.log(finalWB) - ipcRenderer.send('sync-saveFile-dialog', { - filename: '过滤后的文件.xlsx', - data: finalWB - }) + ipcRenderer.send('sync-saveFile-dialog', { + filename: '过滤后的文件.xlsx', + data: finalWB + }) // console.log(xlsx.writeFile(finalWB, fileName)) // Node导出 // let wbout = XLSX.write(finalWB, {bookType:'xlsx', bookSST:false, type: 'binary'}); // saveAs(new Blob([s2ab(wbout)],{type:'application/octet-stream'}), fileName) - }, - - jsonToWBForOneSheet(json, colkeys, sheetName) { - let _headers = colkeys, // 获取表头 - data = {}, - step1 - - let headers = _headers - .map((v, i) => Object.assign({}, { v: v, position: getCharCol(i) + 1 })) - .reduce((prev, next) => Object.assign({}, prev, { - [next.position]: { v: next.v } - }), {}) - - step1 = json.map((v, i) => _headers.map((k, j) => Object.assign({}, { v: v[k], position: getCharCol(j) + (i + 2) }))) - if (step1.length === 0) { - step1.forEach((v, i) => data[v.position] = { v: v.v }) - } else { - let step2 = step1.reduce((prev, next) => prev.concat(next)) - step2.forEach((v, i) => data[v.position] = { v: v.v }) - } - - let output = Object.assign({}, headers, data), - outputPos = Object.keys(output), - ref = outputPos[0] + ':' + outputPos[outputPos.length - 1], - wb = { - SheetNames: [sheetName], - Sheets: { - [sheetName]: Object.assign({}, output, { '!ref': ref }) - } - } - - headers = data = null - return wb + }, + + jsonToWBForOneSheet (json, colkeys, sheetName) { + const _headers = colkeys // 获取表头 + let data = {} + + let headers = _headers + .map((v, i) => Object.assign({}, { v, position: getCharCol(i) + 1 })) + .reduce((prev, next) => Object.assign({}, prev, { + [next.position]: { v: next.v } + }), {}) + + const step1 = json.map((v, i) => _headers.map((k, j) => Object.assign({}, { v: v[k], position: getCharCol(j) + (i + 2) }))) + if (step1.length === 0) { + for (let i = 0, len = step1.length; i < len; i++) { + const v = step1[i] + data[v.position] = { v: v.v } + } + } else { + const step2 = step1.reduce((prev, next) => prev.concat(next)) + for (let i = 0, len = step2.length; i < len; i++) { + const v = step2[i] + data[v.position] = { v: v.v } + } } -} + const output = Object.assign({}, headers, data) + const outputPos = Object.keys(output) + const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}` + const wb = { + SheetNames: [sheetName], + Sheets: { + [sheetName]: Object.assign({}, output, { '!ref': ref }) + } + } + headers = null + data = null + return wb + } +} // 提取字母 -function extractLetters(str) { - return str.replace(/[^a-zA-Z]+/g, '') +function extractLetters (str) { + return str.replace(/[^a-zA-Z]+/g, '') } // 通过前端方式导出文件时用到 -function s2ab(s) { - let buf = new ArrayBuffer(s.length), - view = new Uint8Array(buf) - for (let i = 0; i !== s.length; i++) { - view[i] = s.charCodeAt(i) & 0xFF - } - return buf; +/* function s2ab (s) { + const buf = new ArrayBuffer(s.length) + const view = new Uint8Array(buf) + for (let i = 0; i !== s.length; i++) { + view[i] = s.charCodeAt(i) & 0xFF + } + return buf +} */ +function getCharCol (n) { + let s = '' + let m = 0 + while (n >= 0) { + m = (n % 26) + 1 + s = String.fromCharCode(m + 64) + s + n = (n - m) / 26 + } + return s } -function getCharCol(n) { - let temCol = '', - s = '', - m = 0 - while (n >= 0) { - m = n % 26 + 1 - s = String.fromCharCode(m + 64) + s - n = (n - m) / 26 - } - return s +function getNumCol (s) { + if (!s) return 0 + let n = 0 + for (let i = s.length - 1, j = 1; i >= 0; i--, j *= 26) { + const c = s[i].toUpperCase() + if (c < 'A' || c > 'Z') return 0 + n += (c.charCodeAt() - 64) * j + } + return n - 1 } -function getNumCol(s) { - if (!s) return 0 - let n = 0 - for (let i = s.length - 1, j = 1; i >= 0; i-- , j *= 26) { - let c = s[i].toUpperCase() - if (c < 'A' || c > 'Z') return 0 - n += (c.charCodeAt() - 64) * j - } - return n - 1 -} \ No newline at end of file + +module.exports = Excel diff --git a/app/src/background/filterUtils.js b/app/src/background/filterUtils.js index 7a2a225..b78ac56 100644 --- a/app/src/background/filterUtils.js +++ b/app/src/background/filterUtils.js @@ -1,144 +1,175 @@ -'use strict'; +'use strict' const moment = require('moment') -const zh = require('moment/locale/zh-cn') moment.locale('zh') // 设置时间格式为中文 -let filterUtils = { - mathOperaArr: ['>', '<', '>=', '<='], - conditionArr: ['=', '!=', 'contain', 'notContain', 'startsWith', 'endsWith', 'regexp'], +const filterUtils = { + mathOperaArr: ['>', '<', '>=', '<='], + conditionArr: ['=', '!=', 'contain', 'notContain', 'startsWith', 'endsWith', 'regexp'], - filterByOneOperator(args) { - let { row, colKeys, filterCol, operator, target } = args, - selectKey = colKeys[filterCol], - curVal = row[selectKey], - isNotBelongEmpty = !(operator === 'empty' || operator === 'notEmpty') - if (isNotBelongEmpty && curVal === undefined) { - return false - } else { - return this.filterUnit({ operator, curVal, target }) - } - }, + filterByOneOperator ({ row, colKeys, filterCol, operator, target }) { + const selectKey = colKeys[filterCol] + const curVal = row[selectKey] + const isNotBelongEmpty = !(operator === 'empty' || operator === 'notEmpty') + if (isNotBelongEmpty && typeof curVal === 'undefined') { + return false + } + return this.filterUnit({ operator, curVal, target }) + }, // 双列范围逻辑的【非or、and】,即表单3.1 - filterByDoubleColsRange(args) { - let { row, colKeys, filterCol, operator, target, needConformColIndex } = args, - passCounter = 0 + filterByDoubleColsRange ({ row, colKeys, filterCol, operator, target, needConformColIndex }) { + let passCounter = 0 // 判断每列中是否有一列符合单一逻辑,即3.1 - for (let i = 0, len = filterCol.length; i < len; i++) { - let selectKey = filterCol[i], - curKey = colKeys[selectKey], - isCurColPassed = this.filterUnit({ - operator, - curVal: row[curKey], - target: target - }) + for (let i = 0, len = filterCol.length; i < len; i++) { + const selectKey = filterCol[i] + const curKey = colKeys[selectKey] + const isCurColPassed = this.filterUnit({ + operator, + curVal: row[curKey], + target + }) - if (isCurColPassed) { - passCounter++ - } - if (passCounter >= needConformColIndex) { - return true - } - } - return false - }, + if (isCurColPassed) { + passCounter++ + } + if (passCounter >= needConformColIndex) { + return true + } + } + return false + }, // 第二个表单:多列运算逻辑 - filterByMultiColCalc(args) { + filterByMultiColCalc ({ row, colKeys, filterCol, operator, target, colOperator }) { // 此处 filterCol 是数组 - let { row, colKeys, filterCol, operator, target, colOperator } = args, - rowCalcResult = this.calcMultiCol({ - row, - colOperator, - filterCol, - colKeys - }) + const rowCalcResult = this.calcMultiCol({ + row, + colOperator, + filterCol, + colKeys + }) - return this.filterUnit({ - operator, - curVal: rowCalcResult, - target - }) - }, + return this.filterUnit({ + operator, + curVal: rowCalcResult, + target + }) + }, // 计算每行是否符合要求 - calcMultiCol(args) { - let { row, colOperator, colKeys, filterCol } = args, - calcResult + calcMultiCol ({ row, colOperator, colKeys, filterCol }) { + let calcResult - if (!colOperator.includes('time')) { - calcResult = this.calcNum({ row, colOperator, filterCol, colKeys }) - } else { - let date0 = moment(row[colKeys[filterCol[0]]], 'm/d/y hh:mm'), - date1 = moment(row[colKeys[filterCol[1]]], 'm/d/y hh:mm'), - diff = Math.abs(date1.diff(date0, 'seconds')) - // minutes - calcResult = Math.floor(diff / 60) - } - return calcResult - }, - calcNum(args) { - let { colOperator, row, filterCol, colKeys } = args, - result = row[colKeys[filterCol[0]]] + if (!colOperator.includes('time')) { + calcResult = this.calcNum({ row, colOperator, filterCol, colKeys }) + } else { + const date0 = moment(row[colKeys[filterCol[0]]], 'm/d/y hh:mm') + const date1 = moment(row[colKeys[filterCol[1]]], 'm/d/y hh:mm') + const diff = Math.abs(date1.diff(date0, 'seconds')) + // minutes + calcResult = Math.floor(diff / 60) + } + return calcResult + }, + calcNum ({ colOperator, row, filterCol, colKeys }) { + let result = row[colKeys[filterCol[0]]] - result = result === undefined ? 0 : +result - if (isNaN(result)) return undefined - for (let i = 1, len = filterCol.length; i < len; i++) { - let cKey = colKeys[filterCol[i]], - curVal = row[cKey] === undefined ? 0 : +row[cKey] + result = typeof result === 'undefined' ? 0 : +result + if (isNaN(result)) return + for (let i = 1, len = filterCol.length; i < len; i++) { + const cKey = colKeys[filterCol[i]] + const curVal = typeof row[cKey] === 'undefined' ? 0 : +row[cKey] - if (isNaN(curVal)) return undefined + if (isNaN(curVal)) return - switch (colOperator) { - case '+': result += curVal; break; - case '-': result -= curVal; break; - case '*': result *= curVal; break; - case '/': result /= curVal; break; - case '%': result %= curVal; break; - default: console.log('calcNumSet未匹配操作符') - } - } - return isNaN(result) ? undefined : result - }, - filterUnit(args) { - let { operator, curVal, target } = args, - isNotBelongEmpty = !(operator === 'empty' || operator === 'notEmpty') - if (operator == undefined || (isNotBelongEmpty && target == undefined) || (isNotBelongEmpty && curVal == undefined)) { - return false - } - if (!isNaN(+curVal) || !isNaN(+target)) { // +'a' 是 NaN,另外:toFixed是为了避免浮点数的不精确表示,如 0.1+0.2 = 0.30000000000000004 - // 另外toFixed 返回的是字符串类型 - curVal = typeof (+curVal) === 'number' ? +(+curVal).toFixed(12) : (+curVal) - target = typeof (+target) === 'number' ? +(+target).toFixed(12) : (+target) - } - // console.log(typeof curVal, typeof operator, typeof target) - - switch (operator) { - case '>': return (curVal > target); break; - case '<': return (curVal < target); break; - case '<=': return (curVal <= target); break; - case '>=': return (curVal >= target); break; - // 上面是逻辑操作符 - // 下面是字符串操作符 - // 因为= !=可用于字符串的对比,因此不放在逻辑操作符内 - // 下面的字符串方法对参数是Number也适用 - case '=': return (curVal == target); break; - case '!=': return (curVal != target); break; - case 'contain': return curVal.includes(target); break; - case 'notContain': return !curVal.includes(target); break; - case 'startsWith': return curVal.startsWith(target); break; - case 'endsWith': return curVal.endsWith(target); break; - case 'regexp': - let regexp = new RegExp(target, 'ig') - return curVal.match(regexp); break; - case 'empty': console.log(curVal === undefined); return curVal === undefined; break; - case 'notEmpty': return curVal !== undefined; break; - default: - console.log('未匹配操作符') - return true - } + switch (colOperator) { + case '+': result += curVal; break + case '-': result -= curVal; break + case '*': result *= curVal; break + case '/': result /= curVal; break + case '%': result %= curVal; break + default: console.log('calcNumSet未匹配操作符') + } } -} + if (isNaN(result)) return + return result + }, + filterUnit ({ operator, curVal, target }) { + const isNotBelongEmpty = !(operator === 'empty' || operator === 'notEmpty') + let result + if (typeof operator === 'undefined' + || (isNotBelongEmpty && typeof target === 'undefined') + || (isNotBelongEmpty && typeof curVal === 'undefined')) { + return false + } + if (!isNaN(+curVal) || !isNaN(+target)) { // +'a' 是 NaN,另外:toFixed是为了避免浮点数的不精确表示,如 0.1+0.2 = 0.30000000000000004 + // 另外toFixed 返回的是字符串类型 + curVal = typeof (+curVal) === 'number' ? +(+curVal).toFixed(12) : (+curVal) + target = typeof (+target) === 'number' ? +(+target).toFixed(12) : (+target) + } + // console.log(typeof curVal, typeof operator, typeof target) + switch (operator) { + case '>': { + result = (curVal > target) + break + } + case '<': { + result = (curVal < target) + break + } + case '<=': { + result = (curVal <= target) + break + } + case '>=': { + result = (curVal >= target) + break + } + case '=': { + result = (curVal.toString() === target.toString()) + break + } + case '!=': { + result = (curVal.toString() !== target.toString()) + break + } + case 'contain': { + result = curVal.includes(target) + break + } + case 'notContain': { + result = !curVal.includes(target) + break + } + case 'startsWith': { + result = curVal.startsWith(target) + break + } + case 'endsWith': { + result = curVal.endsWith(target) + break + } + case 'regexp': { + const regexp = new RegExp(target, 'ig') + result = curVal.match(regexp) + break + } + case 'empty': { + result = (typeof curVal === 'undefined') + break + } + case 'notEmpty': { + result = (typeof curVal !== 'undefined') + break + } + default: { + console.log('未匹配操作符') + result = true + } + } + return result + } +} -module.exports = filterUtils \ No newline at end of file +module.exports = filterUtils diff --git a/app/src/background/generateHTMLString.js b/app/src/background/generateHTMLString.js index 1c9b7be..d83b0a0 100644 --- a/app/src/background/generateHTMLString.js +++ b/app/src/background/generateHTMLString.js @@ -1,44 +1,39 @@ -'use strict'; +'use strict' -module.exports = function generateHTMLString({ sheetData, colKeys }) { - let resultHeadStr = '1', - resultBodyStr = '' +module.exports = function generateHTMLString ({ sheetData, colKeys }) { + let resultHeadStr = '1' + let resultBodyStr = '' - colKeys.forEach((row, index) => { - resultHeadStr += `${row}` - }) - resultHeadStr += '' + colKeys.forEach((row, index) => { + resultHeadStr += `${row}` + }) + resultHeadStr += '' - for (let i = 0, len = Math.min(sheetData.length, 30); i < len; i++) { - let resultTrStr = '' - colKeys.forEach((key, index) => { - if (index === 0) { - resultTrStr += `${i + 2}` - } - }) + for (let i = 0, len = Math.min(sheetData.length, 30); i < len; i++) { + let resultTrStr = `${i + 2}` - colKeys.forEach((col, index) => { - let val = sheetData[i][col] - if (val == undefined) val = "" - resultTrStr += `${val}` - }) - resultTrStr += '' - resultBodyStr += resultTrStr - } + for (let j = 0, len = colKeys.length; j < len; j++) { + const col = colKeys[j] + let val = sheetData[i][col] + if (typeof val === 'undefined') val = '' + resultTrStr += `${val}` + } + resultTrStr += '' + resultBodyStr += resultTrStr + } - sheetData = colKeys = null - return (resultHeadStr + resultBodyStr) + sheetData = null + colKeys = null + return (resultHeadStr + resultBodyStr) } - -function getCharCol(n) { - let temCol = '', - s = '', - m = 0 - while (n >= 0) { - m = n % 26 + 1 - s = String.fromCharCode(m + 64) + s - n = (n - m) / 26 - } - return s -} \ No newline at end of file +function getCharCol (n) { + let s = '' + let m = 0 + while (n >= 0) { + m = (n % 26) + 1 + s = String.fromCharCode(m + 64) + s + n = (n - m) / 26 + } + return s +} diff --git a/app/src/background/index.js b/app/src/background/index.js index 3abc03b..7b0b2e1 100644 --- a/app/src/background/index.js +++ b/app/src/background/index.js @@ -1,20 +1,19 @@ -'use strict'; +'use strict' const { ipcRenderer } = require('electron') -const xlsx = require('xlsx') const filterUtils = require('./filterUtils') const Excel = require('./excelUtils') const generateHTMLString = require('./generateHTMLString') const SUFFIX_COLKEYS = '_headers' console.log('background进程pid:', process.pid) -let excelData, - filteredData, - colKeys = {}, - oriRow = {}, - filRow = {} +let excelData +let filteredData +const colKeys = {} +let oriRow = {} +let filRow = {} -window.addEventListener('load', (event) => { - ipcRenderer.on('readFile-start', (event, { data, activeSheetIndex }) => { +window.addEventListener('load', event => { + ipcRenderer.on('readFile-start', (event, { data, activeSheetIndex }) => { /* excelData 的数据结构 { sheetNameN: [] 所有行 @@ -23,175 +22,173 @@ window.addEventListener('load', (event) => { workbook: {} Excel 相关 } */ - excelData = new Excel().init(data) - oriRow = {} - filRow = {} - activeSheetIndex = activeSheetIndex || 0 - let filterTagList = {}, - activeSheetName = excelData.sheetNameList[activeSheetIndex], - curColKeys = excelData[activeSheetName + SUFFIX_COLKEYS], - curSheetData = excelData[activeSheetName]; - - excelData.sheetNameList.forEach(function (sheetName, index) { - oriRow[sheetName] = excelData[sheetName].length - filRow[sheetName] = excelData[sheetName].length - colKeys[sheetName] = excelData[sheetName + SUFFIX_COLKEYS] - filterTagList[sheetName] = [] - }) - - ipcRenderer.send('generate-htmlstring-response', { - sheetHTML: generateHTMLString({ - sheetData: curSheetData, - colKeys: curColKeys - }) - }) - - ipcRenderer.send('readFile-response', { - oriRow, - filRow, - colKeys, - filterTagList, - sheetNameList: excelData.sheetNameList - }) + excelData = new Excel().init(data) + oriRow = {} + filRow = {} + activeSheetIndex = activeSheetIndex || 0 + const filterTagList = {} + const activeSheetName = excelData.sheetNameList[activeSheetIndex] + const curColKeys = excelData[activeSheetName + SUFFIX_COLKEYS] + const curSheetData = excelData[activeSheetName] + + excelData.sheetNameList.forEach(function (sheetName, index) { + oriRow[sheetName] = excelData[sheetName].length + filRow[sheetName] = excelData[sheetName].length + colKeys[sheetName] = excelData[sheetName + SUFFIX_COLKEYS] + filterTagList[sheetName] = [] }) - ipcRenderer.on('filter-start', (event, { activeSheetName, filterTagList, filterWay, uniqueCols }) => { - filteredData = filterHandler({ filterTagList, filterWay, uniqueCols }) - let curColKeys = colKeys[activeSheetName], - tempFilRow = {} - - excelData.sheetNameList.forEach((sheetName, index) => { - tempFilRow[sheetName] = filteredData[sheetName].length - }) - - ipcRenderer.send('filter-response', { - filRow: tempFilRow - }) - - ipcRenderer.send('generate-htmlstring-response', { - sheetHTML: generateHTMLString({ - sheetData: filteredData[activeSheetName], - colKeys: curColKeys - }) - }) + + ipcRenderer.send('generate-htmlstring-response', { + sheetHTML: generateHTMLString({ + sheetData: curSheetData, + colKeys: curColKeys + }) }) - ipcRenderer.on('changeTab-start', (event, { activeSheetName, filterTagList, filterWay, uniqueCols }) => { - filteredData = filterHandler({ filterTagList, filterWay, uniqueCols }) - let curColKeys = colKeys[activeSheetName], - tempFilRow = {} - - ipcRenderer.send('generate-htmlstring-response', { - sheetHTML: generateHTMLString({ - sheetData: filteredData[activeSheetName], - colKeys: curColKeys - }) - }) + ipcRenderer.send('readFile-response', { + oriRow, + filRow, + colKeys, + filterTagList, + sheetNameList: excelData.sheetNameList + }) + }) + ipcRenderer.on('filter-start', (event, { activeSheetName, filterTagList, filterWay, uniqueCols }) => { + filteredData = filterHandler({ filterTagList, filterWay, uniqueCols }) + const curColKeys = colKeys[activeSheetName] + const tempFilRow = {} + + excelData.sheetNameList.forEach((sheetName, index) => { + tempFilRow[sheetName] = filteredData[sheetName].length }) - ipcRenderer.on('exportFile-start', (event) => { - excelData.exportFileByWB({ - filteredData, - excelData - }) - ipcRenderer.send('exportFile-response', { info: '成功导出' }) + ipcRenderer.send('filter-response', { + filRow: tempFilRow }) - ipcRenderer.on('delAllFilterTag-start', (event, { activeSheetName }) => { - let curColKeys = colKeys[activeSheetName], - curSheetData = excelData[activeSheetName] + ipcRenderer.send('generate-htmlstring-response', { + sheetHTML: generateHTMLString({ + sheetData: filteredData[activeSheetName], + colKeys: curColKeys + }) + }) + }) + + ipcRenderer.on('changeTab-start', (event, { activeSheetName, filterTagList, filterWay, uniqueCols }) => { + filteredData = filterHandler({ filterTagList, filterWay, uniqueCols }) + const curColKeys = colKeys[activeSheetName] - ipcRenderer.send('generate-htmlstring-response', { - sheetHTML: generateHTMLString({ - sheetData: curSheetData, - colKeys: curColKeys - }) - }) + ipcRenderer.send('generate-htmlstring-response', { + sheetHTML: generateHTMLString({ + sheetData: filteredData[activeSheetName], + colKeys: curColKeys + }) + }) + }) + ipcRenderer.on('exportFile-start', event => { + excelData.exportFileByWB({ + filteredData, + excelData }) + ipcRenderer.send('exportFile-response', { info: '成功导出' }) + }) + + ipcRenderer.on('delAllFilterTag-start', (event, { activeSheetName }) => { + const curColKeys = colKeys[activeSheetName] + const curSheetData = excelData[activeSheetName] + + ipcRenderer.send('generate-htmlstring-response', { + sheetHTML: generateHTMLString({ + sheetData: curSheetData, + colKeys: curColKeys + }) + }) + }) }, false) -function filterHandler({ filterTagList, filterWay, uniqueCols }) { - let tempFilteredData = Object.assign({}, excelData) - for (let i = 0, len = excelData.sheetNameList.length; i < len; i++) { - let curSheetName = excelData.sheetNameList[i], - curFilterTagList = filterTagList[curSheetName], - colKeys = excelData[curSheetName + SUFFIX_COLKEYS], - curUniqueCols = uniqueCols[curSheetName] - - if (curFilterTagList.length !== 0) { - tempFilteredData[curSheetName] = tempFilteredData[curSheetName].filter((row, index) => { - let rowExpStr = '' - for (let i = 0, len = curFilterTagList.length; i < len; i++) { - let cTag = curFilterTagList[i], - cFilters = cTag.filters, - groupId = cTag.groupId, - tagLogicChar = cTag.logicOperator === 'and' ? '&&' : '||', - oneTagResult, - groupExpStr = '' +function filterHandler ({ filterTagList, filterWay, uniqueCols }) { + const tempFilteredData = Object.assign({}, excelData) + for (let i = 0, len = excelData.sheetNameList.length; i < len; i++) { + const curSheetName = excelData.sheetNameList[i] + const curFilterTagList = filterTagList[curSheetName] + const colKeys = excelData[curSheetName + SUFFIX_COLKEYS] + const curUniqueCols = uniqueCols[curSheetName] + + if (curFilterTagList.length !== 0) { + tempFilteredData[curSheetName] = tempFilteredData[curSheetName].filter((row, index) => { + let rowExpStr = '' + for (let i = 0, len = curFilterTagList.length; i < len; i++) { + const cTag = curFilterTagList[i] + const cFilters = cTag.filters + const tagLogicChar = cTag.logicOperator === 'and' ? '&&' : '||' + let groupExpStr = '' // 遍历当前组的 filters - cFilters.forEach((cF, index) => { - let filterLogicChar = cF.logicOperator === 'and' ? '&&' : '||', - filterType = cF.filterType, - filterCol = cF.col, - operator = cF.operator, - colOperator = cF.colOperator, - target = cF.value, - needConformColIndex = cF.needConformColIndex, - oneFilterResult - - if (filterType === 0) { - oneFilterResult = (filterUtils.filterByOneOperator({ row, colKeys, filterCol, operator, target })) - } else if (filterType === 1) { - oneFilterResult = (filterUtils.filterByMultiColCalc({ row, colKeys, filterCol, operator, target, colOperator })) - } else if (filterType === 2) { - oneFilterResult = (filterUtils.filterByDoubleColsRange({ row, colKeys, filterCol, operator, target, needConformColIndex })) - } - groupExpStr = groupExpStr + filterLogicChar + oneFilterResult - - if (filterLogicChar === '||' && oneFilterResult === true) { - return true // as break - } - }) - groupExpStr = groupExpStr.replace(/^[|&]*/ig, '') - oneTagResult = eval(groupExpStr) - - rowExpStr = rowExpStr + tagLogicChar + oneTagResult - if (tagLogicChar === '||' && oneTagResult === true) { - break; - } - } - rowExpStr = rowExpStr.replace(/^[|&]*/ig, '') - let rowResult = eval(rowExpStr) - // return rowResult - return filterWay == 0 ? rowResult : !rowResult - }) + cFilters.forEach((cF, index) => { + const filterLogicChar = cF.logicOperator === 'and' ? '&&' : '||' + const filterType = cF.filterType + const filterCol = cF.col + const operator = cF.operator + const colOperator = cF.colOperator + const target = cF.value + const needConformColIndex = cF.needConformColIndex + let oneFilterResult + + if (filterType === 0) { + oneFilterResult = (filterUtils.filterByOneOperator({ row, colKeys, filterCol, operator, target })) + } else if (filterType === 1) { + oneFilterResult = (filterUtils.filterByMultiColCalc({ row, colKeys, filterCol, operator, target, colOperator })) + } else if (filterType === 2) { + oneFilterResult = (filterUtils.filterByDoubleColsRange({ row, colKeys, filterCol, operator, target, needConformColIndex })) + } + groupExpStr = groupExpStr + filterLogicChar + oneFilterResult + + if (filterLogicChar === '||' && oneFilterResult === true) { + return true // as break + } + }) + groupExpStr = groupExpStr.replace(/^[|&]*/ig, '') + /* eslint-disable no-eval */ + const oneTagResult = eval(groupExpStr) + /* eslint-enable no-eval */ + + rowExpStr = rowExpStr + tagLogicChar + oneTagResult + if (tagLogicChar === '||' && oneTagResult === true) { + break + } } + rowExpStr = rowExpStr.replace(/^[|&]*/ig, '') + /* eslint-disable no-eval */ + const rowResult = eval(rowExpStr) + /* eslint-enable no-eval */ + + // return rowResult + return (filterWay === 0 || filterWay === '0') ? rowResult : !rowResult + }) + } - if (curUniqueCols.length !== 0) { - let curUniqueColKeys = curUniqueCols.map((item) => { - return colKeys[item] - }) - tempFilteredData[curSheetName] = uniqBy(tempFilteredData[curSheetName], curUniqueColKeys) - } + if (curUniqueCols.length !== 0) { + const curUniqueColKeys = curUniqueCols.map(item => colKeys[item]) + tempFilteredData[curSheetName] = uniqBy(tempFilteredData[curSheetName], curUniqueColKeys) } - return tempFilteredData + } + return tempFilteredData } - -function uniqBy(arr, selectedColKeys) { - let seen = {} - return arr.filter((item) => { - let k = key(item, selectedColKeys) - return seen.hasOwnProperty(k) ? false : (seen[k] = true) - }) +function uniqBy (arr, selectedColKeys) { + const seen = {} + return arr.filter(item => { + const k = key(item, selectedColKeys) + return seen.hasOwnProperty(k) ? false : (seen[k] = true) + }) } -function key(item, selectedColKeys) { - let filterItem = {} - for (var i = 0, len = selectedColKeys.length; i < len; i++) { - let key = selectedColKeys[i] - filterItem[key] = item[key] - } - return JSON.stringify(filterItem) -} \ No newline at end of file +function key (item, selectedColKeys) { + const filterItem = {} + for (let i = 0, len = selectedColKeys.length; i < len; i++) { + const key = selectedColKeys[i] + filterItem[key] = item[key] + } + return JSON.stringify(filterItem) +} diff --git a/app/src/components/FirstScreenPageView.vue b/app/src/components/FirstScreenPageView.vue index 2cb04f5..748dff5 100644 --- a/app/src/components/FirstScreenPageView.vue +++ b/app/src/components/FirstScreenPageView.vue @@ -1,72 +1,75 @@ \ No newline at end of file +.first_screen { + display: flex; + flex-direction: column; + height: calc(100vh - 32px); + justify-content: space-between; +} + +main { + position: relative; + overflow: hidden; + flex-grow: 1; + flex-shrink: 1; + display: flex; + flex-direction: column; + justify-content: space-between +} + +.header, +.footer { + flex-grow: 0; + flex-shrink: 0; +} + diff --git a/app/src/components/FirstScreenPageView/ColSelDialog.vue b/app/src/components/FirstScreenPageView/ColSelDialog.vue index 020a26b..e20c7ff 100644 --- a/app/src/components/FirstScreenPageView/ColSelDialog.vue +++ b/app/src/components/FirstScreenPageView/ColSelDialog.vue @@ -8,23 +8,23 @@

{{ selectedGroupStr }}

-
-

请先上传Excel文件或该文件未含有列

@@ -26,129 +26,131 @@ \ No newline at end of file +.logo { + cursor: pointer; +} + +.slide-fade-enter-active { + animation: slide-fade-in .3s; +} + +.slide-fade-leave-active { + animation: slide-fade-out .3s; +} + +@keyframes slide-fade-in { + 0% { + transform: translate3d(-100%, 0, 0); + opacity: 0; + } + 80% { + opacity: 1; + } + 100% { + transform: translateX(0, 0, 0); + } +} + +@keyframes slide-fade-out { + 0% { + transform: translateX(0); + opacity: 1; + } + 100% { + transform: translateX(-100%); + opacity: 0; + } +} + diff --git a/app/src/components/common/UpdateDialog.vue b/app/src/components/common/UpdateDialog.vue index cc25620..64cefb2 100644 --- a/app/src/components/common/UpdateDialog.vue +++ b/app/src/components/common/UpdateDialog.vue @@ -1,204 +1,196 @@ \ No newline at end of file +.update_dialog { + position: absolute; + left: 50%; + transform: translate(-50%, -80%); + width: 500px; + height: 400px; + background-color: #fff; + box-shadow: 0 2px 4px rgba(0, 0, 0, .5); + display: flex; + flex-direction: column; + justify-content: space-between; + transition: all .3s; + opacity: 0; + &.no_new { + height: 400px; + } + .update_modal.active & { + transform: translate(-50%, 0); + opacity: 1; + } + &_header { + flex-grow: 0; + flex-shrink: 0; + height: 60px; + padding: 0 20px; + background-color: #262626; + h4 { + display: inline-block; + font-size: 16px; + color: #fff; + line-height: 60px; + } + } + &_content { + .has_new & { + display: flex; + } + .no_new & { + padding: 15px 20px; + p { + margin-bottom: 10px; + } + } + + overflow: auto; + flex-grow: 1; + flex-shrink: 1; + padding: 0 20px; + position: relative; + } + &_footer { + flex-grow: 0; + flex-shrink: 0; + >div { + display: flex; + align-item: stretch; + height: 50px; + } + button { + flex-basis: 30%; + flex-grow: 1; + flex-shrink: 0; + -webkit-appearance: normal; + appearance: normal; + font-size: 14px; + outline: none; + border: 0; + background-color: #D8D8D8; + cursor: pointer; + &.update_btn { + background-color: #4285F4; + color: #fff; + } + } + } +} + diff --git a/app/src/components/common/WindowTop.vue b/app/src/components/common/WindowTop.vue index 28103a1..9ce9a1d 100644 --- a/app/src/components/common/WindowTop.vue +++ b/app/src/components/common/WindowTop.vue @@ -1,77 +1,74 @@ \ No newline at end of file + &:hover { + background-color: #555; + } + } + } +} + diff --git a/app/src/main.js b/app/src/main.js index 26c8a87..31076ce 100644 --- a/app/src/main.js +++ b/app/src/main.js @@ -14,9 +14,11 @@ window.eventBus = new Vue() const router = new Router(routes) +/* eslint-disable */ new Vue({ - el: '#app', - router: router, - store, - render: h => h(App) -}) \ No newline at end of file + el: '#app', + router, + store, + render: h => h(App) +}) +/* eslint-enable */ diff --git a/app/src/routes.js b/app/src/routes.js index 630ab27..0389fc6 100644 --- a/app/src/routes.js +++ b/app/src/routes.js @@ -1,15 +1,15 @@ export default { - routes: [{ - path: '/', - name: 'index', - component: require('./components/FirstScreenPageView') - }, - { - path: '/instructions', - name: 'instructions', - component: require('./components/InstructionsPageView') - }, { - path: '*', - redirect: '/' - }] + routes: [{ + path: '/', + name: 'index', + component: require('./components/FirstScreenPageView') + }, + { + path: '/instructions', + name: 'instructions', + component: require('./components/InstructionsPageView') + }, { + path: '*', + redirect: '/' + }] } diff --git a/app/src/store/actions.js b/app/src/store/actions.js index fe3c083..6896397 100644 --- a/app/src/store/actions.js +++ b/app/src/store/actions.js @@ -3,37 +3,37 @@ import * as types from './mutation-types' // action 和 getter 的 context 参数共6个对象 // state(rootState)会分模块、getters(rootGetters)不分模块(扁平化) -export const checkFilterAndUnqiueCount = ({commit, dispatch, getters, rootGetters, rootState, state}) => { - let activeSheetName = getters.getActiveSheet.name, - curFilterTagList = getters.getFilterTagList[activeSheetName], - curUniqueCols = getters.getUniqueCols[activeSheetName] - - if(curFilterTagList.length === 0 && curUniqueCols.length === 0) { - ipcRenderer.send('delAllFilterTag-start', { - activeSheetName: activeSheetName - }) - commit(types.SET_FILTERED_DATA, null) - } +export const checkFilterAndUnqiueCount = ({ commit, dispatch, getters, rootGetters, rootState, state }) => { + const activeSheetName = getters.getActiveSheet.name + const curFilterTagList = getters.getFilterTagList[activeSheetName] + const curUniqueCols = getters.getUniqueCols[activeSheetName] + + if (curFilterTagList.length === 0 && curUniqueCols.length === 0) { + ipcRenderer.send('delAllFilterTag-start', { + activeSheetName + }) + commit(types.SET_FILTERED_DATA, null) + } } export const initAfterImportFile = ({ state, commit, rootState }, excelObj) => { - commit(types.SET_FILE_STATUS, 0) - ipcRenderer.send('readFile-start', { - data: excelObj - }) - ipcRenderer.once('readFile-response', (event, excelObj) => { - // excel - commit(types.SET_EXCEL_BASE_INFO, excelObj) - commit(types.SET_ACTIVE_SHEET, 0) + commit(types.SET_FILE_STATUS, 0) + ipcRenderer.send('readFile-start', { + data: excelObj + }) + ipcRenderer.once('readFile-response', (event, excelObj) => { + // excel + commit(types.SET_EXCEL_BASE_INFO, excelObj) + commit(types.SET_ACTIVE_SHEET, 0) - // unique - commit(types.INIT_UNIQUE, excelObj.sheetNameList) + // unique + commit(types.INIT_UNIQUE, excelObj.sheetNameList) - // file - commit(types.SET_FILE_STATUS, -1) + // file + commit(types.SET_FILE_STATUS, -1) - // filter - commit(types.TOGGLE_FILTER_PANEL_STATUS, true) - commit(types.INIT_FILTER_TAG_LIST, excelObj.filterTagList) - }) -} \ No newline at end of file + // filter + commit(types.TOGGLE_FILTER_PANEL_STATUS, true) + commit(types.INIT_FILTER_TAG_LIST, excelObj.filterTagList) + }) +} diff --git a/app/src/store/index.js b/app/src/store/index.js index b8fa15f..a083438 100644 --- a/app/src/store/index.js +++ b/app/src/store/index.js @@ -15,16 +15,16 @@ Vue.use(Vuex) const isDev = process.env.NODE_ENV !== 'production' export default new Vuex.Store({ - actions, - getters, - modules: { - clientUpdate, - excel, - file, - filter, - unique, - programWindow - }, - strict: isDev, - plugins: isDev ? [createLogger()] : [] + actions, + getters, + modules: { + clientUpdate, + excel, + file, + filter, + unique, + programWindow + }, + strict: isDev, + plugins: isDev ? [createLogger()] : [] }) diff --git a/app/src/store/modules/clientUpdate.js b/app/src/store/modules/clientUpdate.js index 927cf38..e27b33b 100644 --- a/app/src/store/modules/clientUpdate.js +++ b/app/src/store/modules/clientUpdate.js @@ -2,89 +2,90 @@ import * as types from '../mutation-types' import { getLocal, setLocal } from '../../utils/localStorageSet' import _ from 'lodash' -let isKeepCurVersion = (function initIsKeepVersion() { - let isKeepCurVersionTemp = getLocal('isKeepCurVersion') - if (!_.isBoolean(isKeepCurVersionTemp)) { - isKeepCurVersionTemp = false - } - return isKeepCurVersionTemp -})(); +const isKeepCurVersion = (function initIsKeepVersion () { + let isKeepCurVersionTemp = getLocal('isKeepCurVersion') + if (!_.isBoolean(isKeepCurVersionTemp)) { + isKeepCurVersionTemp = false + } + return isKeepCurVersionTemp +})() const state = { - url: '', - version: '', - log: '', - pubDate: '', - isShowUpdateDialog: false, - isKeepCurVersion: isKeepCurVersion, - isHasNewVersion: false + url: '', + version: '', + log: '', + pubDate: '', + isShowUpdateDialog: false, + isKeepCurVersion, + isHasNewVersion: false } const getters = { - getUpdateDialogStatus: state => state.isShowUpdateDialog, - getUpdateUrl: state => state.url, - getUpdateVersion: state => state.version, - getUpdateLog: state => state.log, - getUpdatePubDate: state => state.pubDate, - getKeepCurVersion: state => state.isKeepCurVersion, - getHasNewVersionStatus: state => state.isHasNewVersion + getUpdateDialogStatus: state => state.isShowUpdateDialog, + getUpdateUrl: state => state.url, + getUpdateVersion: state => state.version, + getUpdateLog: state => state.log, + getUpdatePubDate: state => state.pubDate, + getKeepCurVersion: state => state.isKeepCurVersion, + getHasNewVersionStatus: state => state.isHasNewVersion } const actions = { - toggleUpdateDialog({ state, commit, rootState }, isShowUpdateDialog) { - commit(types.TOGGLE_UPDATE_DIALOG, isShowUpdateDialog) - }, - setUpdateUrl({ state, commit, rootState }, url) { - commit(types.SET_UPDATE_URL, url) - }, - setUpdateVersion({ state, commit, rootState }, version) { - commit(types.SET_UPDATE_VERSION, version) - }, - setUpdateLog({ state, commit, rootState }, notes) { - commit(types.SET_UPDATE_LOG, notes) - }, - setUpdatePubDate({ state, commit, rootState }, pubDate) { - commit(types.SET_UPDATE_PUB_DATE, pubDate) - }, - setKeepVersionStatus({ state, commit, rootState }, isKeepCurVersion) { - commit(types.SET_KEEP_VERSION_STATUS, isKeepCurVersion) - }, - setHasNewStatus({ state, commit, rootState }, isHasNewVersion) { - commit(types.SET_HAS_NEW_VERSION, isHasNewVersion) - } + toggleUpdateDialog ({ state, commit, rootState }, isShowUpdateDialog) { + commit(types.TOGGLE_UPDATE_DIALOG, isShowUpdateDialog) + }, + setUpdateUrl ({ state, commit, rootState }, url) { + commit(types.SET_UPDATE_URL, url) + }, + setUpdateVersion ({ state, commit, rootState }, version) { + commit(types.SET_UPDATE_VERSION, version) + }, + setUpdateLog ({ state, commit, rootState }, notes) { + commit(types.SET_UPDATE_LOG, notes) + }, + setUpdatePubDate ({ state, commit, rootState }, pubDate) { + commit(types.SET_UPDATE_PUB_DATE, pubDate) + }, + setKeepVersionStatus ({ state, commit, rootState }, isKeepCurVersion) { + commit(types.SET_KEEP_VERSION_STATUS, isKeepCurVersion) + }, + setHasNewStatus ({ state, commit, rootState }, isHasNewVersion) { + commit(types.SET_HAS_NEW_VERSION, isHasNewVersion) + } } const mutations = { - [types.TOGGLE_UPDATE_DIALOG](state, isShowUpdateDialog) { - if (_.isBoolean(isShowUpdateDialog)) - state.isShowUpdateDialog = isShowUpdateDialog - else - state.isShowUpdateDialog = !state.isShowUpdateDialog - }, - [types.SET_UPDATE_URL](state, url) { - state.url = url - }, - [types.SET_UPDATE_VERSION](state, version) { - state.version = version - }, - [types.SET_UPDATE_LOG](state, log) { - state.log = log - }, - [types.SET_UPDATE_PUB_DATE](state, pubDate) { - state.pubDate = pubDate - }, - [types.SET_KEEP_VERSION_STATUS](state, isKeepCurVersion) { - state.isKeepCurVersion = isKeepCurVersion - setLocal('isKeepCurVersion', state.isKeepCurVersion) - }, - [types.SET_HAS_NEW_VERSION](state, isHasNewVersion) { - state.isHasNewVersion = isHasNewVersion + [types.TOGGLE_UPDATE_DIALOG] (state, isShowUpdateDialog) { + if (_.isBoolean(isShowUpdateDialog)) { + state.isShowUpdateDialog = isShowUpdateDialog + } else { + state.isShowUpdateDialog = !state.isShowUpdateDialog } + }, + [types.SET_UPDATE_URL] (state, url) { + state.url = url + }, + [types.SET_UPDATE_VERSION] (state, version) { + state.version = version + }, + [types.SET_UPDATE_LOG] (state, log) { + state.log = log + }, + [types.SET_UPDATE_PUB_DATE] (state, pubDate) { + state.pubDate = pubDate + }, + [types.SET_KEEP_VERSION_STATUS] (state, isKeepCurVersion) { + state.isKeepCurVersion = isKeepCurVersion + setLocal('isKeepCurVersion', state.isKeepCurVersion) + }, + [types.SET_HAS_NEW_VERSION] (state, isHasNewVersion) { + state.isHasNewVersion = isHasNewVersion + } } export default { - state, - getters, - actions, - mutations -} \ No newline at end of file + state, + getters, + actions, + mutations +} diff --git a/app/src/store/modules/excel.js b/app/src/store/modules/excel.js index 0014ff9..e2c8d06 100644 --- a/app/src/store/modules/excel.js +++ b/app/src/store/modules/excel.js @@ -1,73 +1,73 @@ import * as types from '../mutation-types' const state = { - oriRow: {}, - filRow: {}, - colKeys: {}, - activeSheet: { - index: 0, - name: '' - }, - sheetNameList: [] + oriRow: {}, + filRow: {}, + colKeys: {}, + activeSheet: { + index: 0, + name: '' + }, + sheetNameList: [] } const getters = { - getSheetNameList: (state, getters, rootState) => state.sheetNameList, - getActiveSheet: (state, getters, rootState) => state.activeSheet, - getActiveSheetName: (state, getters, rootState) => state.activeSheet.name, - getCurOriRowCount: (state, getters, rootState) => { - let activeSheetName = getters.getActiveSheetName - return state.oriRow[activeSheetName] || 0 - }, - getCurFilRowCount: (state, getters, rootState) => { - let activeSheetName = getters.getActiveSheetName - return state.filRow[activeSheetName] || 0 - }, - getCurColCount: (state, getters, rootState) => { - let activeSheetName = getters.getActiveSheetName, - curColKeys = state.colKeys[activeSheetName] - return curColKeys && curColKeys.length || 0 - }, - getCurColKeys: (state, getters, rootState) => { - let activeSheetName = getters.getActiveSheetName - return state.colKeys[activeSheetName] - } + getSheetNameList: (state, getters, rootState) => state.sheetNameList, + getActiveSheet: (state, getters, rootState) => state.activeSheet, + getActiveSheetName: (state, getters, rootState) => state.activeSheet.name, + getCurOriRowCount: (state, getters, rootState) => { + const activeSheetName = getters.getActiveSheetName + return state.oriRow[activeSheetName] || 0 + }, + getCurFilRowCount: (state, getters, rootState) => { + const activeSheetName = getters.getActiveSheetName + return state.filRow[activeSheetName] || 0 + }, + getCurColCount: (state, getters, rootState) => { + const activeSheetName = getters.getActiveSheetName + const curColKeys = state.colKeys[activeSheetName] + return (curColKeys && curColKeys.length) || 0 + }, + getCurColKeys: (state, getters, rootState) => { + const activeSheetName = getters.getActiveSheetName + return state.colKeys[activeSheetName] + } } const actions = { - setActiveSheet({ state, commit, rootState }, index) { - commit(types.SET_ACTIVE_SHEET, index) - }, + setActiveSheet ({ state, commit, rootState }, index) { + commit(types.SET_ACTIVE_SHEET, index) + }, // 筛选后的数据,目前只有 行数 - setFilteredData({ state, commit, rootState }, filRow) { - commit(types.SET_FILTERED_DATA, filRow) - } + setFilteredData ({ state, commit, rootState }, filRow) { + commit(types.SET_FILTERED_DATA, filRow) + } } const mutations = { - [types.SET_EXCEL_BASE_INFO](state, excelBaseInfoObj) { - Object.keys(excelBaseInfoObj).forEach((key, index) => { - if(key !== 'filterTagList') - state[key] = excelBaseInfoObj[key] - }) - }, - [types.SET_ACTIVE_SHEET](state, index) { - state.activeSheet = { - index, - name: state.sheetNameList[index] - } - }, - [types.SET_FILTERED_DATA](state, filRow) { - if(filRow === undefined || filRow === null) - state.filRow = state.oriRow - else - state.filRow = filRow + [types.SET_EXCEL_BASE_INFO] (state, excelBaseInfoObj) { + Object.keys(excelBaseInfoObj).forEach((key, index) => { + if (key !== 'filterTagList') { state[key] = excelBaseInfoObj[key] } + }) + }, + [types.SET_ACTIVE_SHEET] (state, index) { + state.activeSheet = { + index, + name: state.sheetNameList[index] } + }, + [types.SET_FILTERED_DATA] (state, filRow) { + if (typeof filRow === 'undefined' || filRow === null) { + state.filRow = state.oriRow + } else { + state.filRow = filRow + } + } } export default { - state, - getters, - actions, - mutations -} \ No newline at end of file + state, + getters, + actions, + mutations +} diff --git a/app/src/store/modules/file.js b/app/src/store/modules/file.js index 1f67ea5..406627b 100644 --- a/app/src/store/modules/file.js +++ b/app/src/store/modules/file.js @@ -3,105 +3,106 @@ import * as types from '../mutation-types' import { getLocal, setLocal } from '../../utils/localStorageSet' import _ from 'lodash' -let uploadFiles = (function initUploadFiles() { - let localUploadFiles = getLocal('uploadFiles') - if (_.isArray(localUploadFiles)) { - return localUploadFiles - } else { - return [] - } -})(); - +const uploadFiles = (function initUploadFiles () { + const localUploadFiles = getLocal('uploadFiles') + if (_.isArray(localUploadFiles)) { + return localUploadFiles + } + return [] +})() const state = { - fileList: uploadFiles, - searchVal: '', - isShowSideBar: false, - fileStatus: -1 // 0: 正在导入中 1: 过滤中 2: 导出中 + fileList: uploadFiles, + searchVal: '', + isShowSideBar: false, + fileStatus: -1 // 0: 正在导入中 1: 过滤中 2: 导出中 } const getters = { // getters 包含所有模块的getters(扁平化后),rootState 与 actions 相同 - getUploadFiles: (state, getters, rootState) => state.fileList, - getSearchVal: (state, getters, rootState) => state.searchVal, - getFileStatus: (state, getters, rootState) => state.fileStatus, - getSideBarStatus: (state, getters, rootState) => state.isShowSideBar + getUploadFiles: (state, getters, rootState) => state.fileList, + getSearchVal: (state, getters, rootState) => state.searchVal, + getFileStatus: (state, getters, rootState) => state.fileStatus, + getSideBarStatus: (state, getters, rootState) => state.isShowSideBar } const actions = { - setSearchVal({ state, commit, rootState }, searchVal) { - commit(types.CHANGE_SEARCH_VALUE, searchVal) - }, - setUploadFiles({ state, commit, rootState }, fpath) { - let fileObj = { - path: fpath, - name: pathModule.basename(fpath), - extname: pathModule.extname(fpath) - } - commit(types.SET_UPLOAD_FILES, fileObj) - }, - delUploadFile({ state, commit, rootState }, fileObj) { - commit(types.DEL_UPLOAD_FILES, fileObj) - }, - toggleSideBar({ state, commit, rootState }, isShowSideBar) { - commit(types.TOGGLE_SIDEBAR, isShowSideBar) - }, - setFileStatus({ state, commit, rootState }, fileStatus) { - commit(types.SET_FILE_STATUS, fileStatus) + setSearchVal ({ state, commit, rootState }, searchVal) { + commit(types.CHANGE_SEARCH_VALUE, searchVal) + }, + setUploadFiles ({ state, commit, rootState }, fpath) { + const fileObj = { + path: fpath, + name: pathModule.basename(fpath), + extname: pathModule.extname(fpath) } + commit(types.SET_UPLOAD_FILES, fileObj) + }, + delUploadFile ({ state, commit, rootState }, fileObj) { + commit(types.DEL_UPLOAD_FILES, fileObj) + }, + toggleSideBar ({ state, commit, rootState }, isShowSideBar) { + commit(types.TOGGLE_SIDEBAR, isShowSideBar) + }, + setFileStatus ({ state, commit, rootState }, fileStatus) { + commit(types.SET_FILE_STATUS, fileStatus) + } } const mutations = { - [types.TOGGLE_SIDEBAR](state, isShowSideBar) { - if (_.isBoolean(isShowSideBar)) - state.isShowSideBar = isShowSideBar - else - state.isShowSideBar = !state.isShowSideBar - }, - [types.CHANGE_SEARCH_VALUE](state, searchVal) { - state.searchVal = searchVal - }, - [types.SET_UPLOAD_FILES](state, fileObj) { - let isExistent = false, - existentIndex = 0 + [types.TOGGLE_SIDEBAR] (state, isShowSideBar) { + if (_.isBoolean(isShowSideBar)) { + state.isShowSideBar = isShowSideBar + } else { + state.isShowSideBar = !state.isShowSideBar + } + }, + [types.CHANGE_SEARCH_VALUE] (state, searchVal) { + state.searchVal = searchVal + }, + [types.SET_UPLOAD_FILES] (state, fileObj) { + let isExistent = false + let existentIndex = 0 - state.fileList.some((file, index) => { - if (file.path === fileObj.path) { - isExistent = true - existentIndex = index + for (let i = 0, len = state.fileList.length; i < len; i++) { + const file = state.fileList[i] + if (file.path === fileObj.path) { + isExistent = true + existentIndex = i - return true - } - }) + break + } + } - if (isExistent) { - state.fileList.splice(existentIndex, 1) - state.fileList.unshift(fileObj) - } else { - state.fileList.unshift(fileObj) - } + if (isExistent) { + state.fileList.splice(existentIndex, 1) + state.fileList.unshift(fileObj) + } else { + state.fileList.unshift(fileObj) + } - setLocal('uploadFiles', state.fileList) - }, + setLocal('uploadFiles', state.fileList) + }, // 去掉复数 - [types.DEL_UPLOAD_FILES](state, fileObj) { - state.fileList.some((file, index) => { - if(file.name === fileObj.name && file.path === fileObj.path) { - state.fileList.splice(index, 1) - return true - } - }) - setLocal('uploadFiles', state.fileList) - }, - // 命名要改 - [types.SET_FILE_STATUS](state, status) { - state.fileStatus = status + [types.DEL_UPLOAD_FILES] (state, fileObj) { + for (let i = 0, len = state.fileList.length; i < len; i++) { + const file = state.fileList[i] + if (file.name === fileObj.name && file.path === fileObj.path) { + state.fileList.splice(i, 1) + break + } } + setLocal('uploadFiles', state.fileList) + }, + // 命名要改 + [types.SET_FILE_STATUS] (state, status) { + state.fileStatus = status + } } export default { - state, - getters, - actions, - mutations -} \ No newline at end of file + state, + getters, + actions, + mutations +} diff --git a/app/src/store/modules/filter.js b/app/src/store/modules/filter.js index f9e7560..1608808 100644 --- a/app/src/store/modules/filter.js +++ b/app/src/store/modules/filter.js @@ -1,5 +1,4 @@ import * as types from '../mutation-types' -import * as Excel from '../../utils/ExcelSet' import { getLocal, setLocal } from '../../utils/localStorageSet' import _ from 'lodash' import { ipcRenderer } from 'electron' @@ -8,12 +7,12 @@ let filterWay = getLocal('filterWay') if (!filterWay) filterWay = 0 const state = { - filterTagList: {}, - filterWay, // 0 保留、1 剔除 - isShowFilterPanel: false, - isShowColSelectDialog: false, - colSelecType: -1, // 0 单列、1 多列、2 双列范围、3 去重 - filterOptions: [ + filterTagList: {}, + filterWay, // 0 保留、1 剔除 + isShowFilterPanel: false, + isShowColSelectDialog: false, + colSelecType: -1, // 0 单列、1 多列、2 双列范围、3 去重 + filterOptions: [ { char: '>', words: '大于' }, { char: '<', words: '小于' }, { char: '>=', words: '大于或等于' }, @@ -27,133 +26,129 @@ const state = { { char: 'regexp', words: '正则表达式' }, { char: 'empty', words: '为空' }, { char: 'notEmpty', words: '不为空' } - ] + ] } const getters = { - getFilterOptions: (state, getters, rootState) => state.filterOptions, - getFilterTagList: (state, getters, rootState) => state.filterTagList, - getFilterWay: (state, getters, rootState) => state.filterWay, - getFilterPanelStatus: (state, getters, rootState) => state.isShowFilterPanel, - getCurFilterTagListCount: (state, getters, rootState) => { - let activeSheetName = getters.getActiveSheetName, - curFilterTagList = state.filterTagList[activeSheetName] - return curFilterTagList && curFilterTagList.length || 0 - }, - getColSelectDialogStatus: (state, getters, rootState) => { - return state.isShowColSelectDialog - }, - getColSelectType: (state, getters, rootState) => state.colSelecType + getFilterOptions: (state, getters, rootState) => state.filterOptions, + getFilterTagList: (state, getters, rootState) => state.filterTagList, + getFilterWay: (state, getters, rootState) => state.filterWay, + getFilterPanelStatus: (state, getters, rootState) => state.isShowFilterPanel, + getCurFilterTagListCount: (state, getters, rootState) => { + const activeSheetName = getters.getActiveSheetName + const curFilterTagList = state.filterTagList[activeSheetName] + return (curFilterTagList && curFilterTagList.length) || 0 + }, + getColSelectDialogStatus: (state, getters, rootState) => state.isShowColSelectDialog, + getColSelectType: (state, getters, rootState) => state.colSelecType } const actions = { - // 对于内部 action,context.state 是局部状态,根节点的状态是context.rootState - // 还能有 getters,这样就可以简化 activeSheetName - addFilter({ state, commit, rootState, getters }, filter) { - console.log('getters', getters) - commit(types.ADD_FILTER, { - activeSheetName: getters.getActiveSheetName, - filter - }) - }, - delFilter({ state, commit, rootState, getters }, index) { - let activeSheetName = getters.getActiveSheetName - commit(types.DEL_FILTER, { - activeSheetName, - index, - curUniqueCols: rootState.unique.cols[activeSheetName] - }) - }, - setFilterWay({ state, commit, rootState }, filterWay) { - commit(types.SET_FILTER_WAY, filterWay) - }, - toggleFilterPanelStatus({ state, commit, rootState }, isShowFilterPanel) { - commit(types.TOGGLE_FILTER_PANEL_STATUS, isShowFilterPanel) - }, - setColSelectDialogStatus({ state, commit, rootState }, isShowColSelectDialog) { - commit(types.SET_COL_SELECT_DIALOG_STATUS, isShowColSelectDialog) - if (isShowColSelectDialog === true) { - commit(types.TOGGLE_SIDEBAR, false) - } - }, - setColSelectType({ state, commit, rootState }, colSelecType) { - commit(types.SET_COL_SELECT_TYPE, colSelecType) + // 对于内部 action,context.state 是局部状态,根节点的状态是context.rootState + // 还能有 getters,这样就可以简化 activeSheetName + addFilter ({ state, commit, rootState, getters }, filter) { + console.log('getters', getters) + commit(types.ADD_FILTER, { + activeSheetName: getters.getActiveSheetName, + filter + }) + }, + delFilter ({ state, commit, rootState, getters }, index) { + const activeSheetName = getters.getActiveSheetName + commit(types.DEL_FILTER, { + activeSheetName, + index, + curUniqueCols: rootState.unique.cols[activeSheetName] + }) + }, + setFilterWay ({ state, commit, rootState }, filterWay) { + commit(types.SET_FILTER_WAY, filterWay) + }, + toggleFilterPanelStatus ({ state, commit, rootState }, isShowFilterPanel) { + commit(types.TOGGLE_FILTER_PANEL_STATUS, isShowFilterPanel) + }, + setColSelectDialogStatus ({ state, commit, rootState }, isShowColSelectDialog) { + commit(types.SET_COL_SELECT_DIALOG_STATUS, isShowColSelectDialog) + if (isShowColSelectDialog === true) { + commit(types.TOGGLE_SIDEBAR, false) } + }, + setColSelectType ({ state, commit, rootState }, colSelecType) { + commit(types.SET_COL_SELECT_TYPE, colSelecType) + } } const mutations = { - [types.ADD_FILTER](state, { activeSheetName, filter }) { - if (activeSheetName) { - console.log('state.filterTagList', state.filterTagList) - console.log('curTagList', curTagList) - console.log('activeSheetName', activeSheetName) - let tempTagList = Object.assign({}, state.filterTagList), - curTagList = tempTagList[activeSheetName], - isHasSameGroup = false - - // 判断当前filter是否存在组 - // 若存在,则判断是否存在同类组 - if (filter.groupId != '-1') { - curTagList.some((item, index) => { - if (filter.groupId === item.groupId) { - console.log(item.filters) - item.filters.push('filter', filter) - isHasSameGroup = true - return true - } - }) - } + [types.ADD_FILTER] (state, { activeSheetName, filter }) { + if (activeSheetName) { + let tempTagList = Object.assign({}, state.filterTagList) + const curTagList = tempTagList[activeSheetName] + let isHasSameGroup = false - // 若不存在 或 找不到同类组 - if (!isHasSameGroup) { - let filterObj = { - groupId: filter.groupId, - logicOperator: filter.logicOperator, - filters: [filter] - } - console.log('curTagList', curTagList) - curTagList.push(filterObj) - } - - state.filterTagList = tempTagList - tempTagList = null - } else { - ipcRenderer.send('sync-alert-dialog', { - content: '还没上传相应的Excel文件' - }) + // 判断当前filter是否存在组 + // 若存在,则判断是否存在同类组 + if (filter.groupId !== '-1' || filter.groupId !== -1) { + for (let i = 0, len = curTagList.length; i < len; i++) { + const item = curTagList[i] + if (filter.groupId === item.groupId) { + console.log(item.filters) + item.filters.push('filter', filter) + isHasSameGroup = true + return true + } } - }, - [types.DEL_FILTER](state, { activeSheetName, index, curUniqueCols }) { - let tempTagList = Object.assign({}, state.filterTagList) + } - tempTagList[activeSheetName].splice(index, 1) - state.filterTagList = tempTagList - }, - [types.SET_FILTER_WAY](state, filterWay) { - state.filterWay = filterWay - setLocal('filterWay', filterWay) - }, - [types.TOGGLE_FILTER_PANEL_STATUS](state, isShowFilterPanel) { - if (_.isBoolean(isShowFilterPanel)) { - state.isShowFilterPanel = isShowFilterPanel - } else { - state.isShowFilterPanel = !state.isShowFilterPanel + // 若不存在 或 找不到同类组 + if (!isHasSameGroup) { + const filterObj = { + groupId: filter.groupId, + logicOperator: filter.logicOperator, + filters: [filter] } - }, - [types.SET_COL_SELECT_DIALOG_STATUS](state, isShowColSelectDialog) { - state.isShowColSelectDialog = isShowColSelectDialog - }, - [types.SET_COL_SELECT_TYPE](state, colSelecType) { - state.colSelecType = colSelecType - }, - [types.INIT_FILTER_TAG_LIST](state, filterTagList) { - state.filterTagList = filterTagList + console.log('curTagList', curTagList) + curTagList.push(filterObj) + } + + state.filterTagList = tempTagList + tempTagList = null + } else { + ipcRenderer.send('sync-alert-dialog', { + content: '还没上传相应的Excel文件' + }) } + }, + [types.DEL_FILTER] (state, { activeSheetName, index, curUniqueCols }) { + const tempTagList = Object.assign({}, state.filterTagList) + + tempTagList[activeSheetName].splice(index, 1) + state.filterTagList = tempTagList + }, + [types.SET_FILTER_WAY] (state, filterWay) { + state.filterWay = filterWay + setLocal('filterWay', filterWay) + }, + [types.TOGGLE_FILTER_PANEL_STATUS] (state, isShowFilterPanel) { + if (_.isBoolean(isShowFilterPanel)) { + state.isShowFilterPanel = isShowFilterPanel + } else { + state.isShowFilterPanel = !state.isShowFilterPanel + } + }, + [types.SET_COL_SELECT_DIALOG_STATUS] (state, isShowColSelectDialog) { + state.isShowColSelectDialog = isShowColSelectDialog + }, + [types.SET_COL_SELECT_TYPE] (state, colSelecType) { + state.colSelecType = colSelecType + }, + [types.INIT_FILTER_TAG_LIST] (state, filterTagList) { + state.filterTagList = filterTagList + } } export default { - state, - getters, - actions, - mutations -} \ No newline at end of file + state, + getters, + actions, + mutations +} diff --git a/app/src/store/modules/programWindow.js b/app/src/store/modules/programWindow.js index 438ba09..882adae 100644 --- a/app/src/store/modules/programWindow.js +++ b/app/src/store/modules/programWindow.js @@ -2,8 +2,8 @@ import * as types from '../mutation-types' import { ipcRenderer } from 'electron' const state = { - isMaximize: false, - isMinimize: false + isMaximize: false, + isMinimize: false } const getters = { @@ -12,28 +12,28 @@ const getters = { const actions = { // 对于内部 action,context.state 是局部状态,根节点的状态是context.rootState - toggleWindowMax({ state, commit, rootState }) { - commit(types.TOGGLE_WINDOW_MAX) - }, - toggleWindowMin({ state, commit, rootState }) { - commit(types.TOGGLE_WINDOW_MIN) - } + toggleWindowMax ({ state, commit, rootState }) { + commit(types.TOGGLE_WINDOW_MAX) + }, + toggleWindowMin ({ state, commit, rootState }) { + commit(types.TOGGLE_WINDOW_MIN) + } } const mutations = { - [types.TOGGLE_WINDOW_MAX](state) { - ipcRenderer.send('sync-maximize') - state.isMaximize = !state.isMaximize - }, - [types.TOGGLE_WINDOW_MIN](state) { - ipcRenderer.send('sync-minimize') - state.isMinimize = !state.isMinimize - } + [types.TOGGLE_WINDOW_MAX] (state) { + ipcRenderer.send('sync-maximize') + state.isMaximize = !state.isMaximize + }, + [types.TOGGLE_WINDOW_MIN] (state) { + ipcRenderer.send('sync-minimize') + state.isMinimize = !state.isMinimize + } } export default { - state, - getters, - actions, - mutations -} \ No newline at end of file + state, + getters, + actions, + mutations +} diff --git a/app/src/store/modules/unique.js b/app/src/store/modules/unique.js index eb1deb2..b116d94 100644 --- a/app/src/store/modules/unique.js +++ b/app/src/store/modules/unique.js @@ -1,44 +1,42 @@ import * as types from '../mutation-types' import Vue from 'vue' const state = { - cols: {} // ...sheetNameList + cols: {} // ...sheetNameList } const getters = { // getters 包含所有模块的getters(扁平化后),rootState 与 actions 相同 - getUniqueCols: (state, getters, rootState) => { - return state.cols - }, - getCurUniqueColsCount: (state, getters, rootState) => { - let activeSheetName = getters.getActiveSheetName, - curCols = state.cols[activeSheetName] - return curCols && curCols.length || 0 - }, + getUniqueCols: (state, getters, rootState) => state.cols, + getCurUniqueColsCount: (state, getters, rootState) => { + const activeSheetName = getters.getActiveSheetName + const curCols = state.cols[activeSheetName] + return (curCols && curCols.length) || 0 + }, } const actions = { - setUniqueCols({ state, commit, rootState, getters }, cols) { - commit(types.SET_UNIQUE_COLS, { - activeSheetName: getters.getActiveSheetName, - cols - }) - } + setUniqueCols ({ state, commit, rootState, getters }, cols) { + commit(types.SET_UNIQUE_COLS, { + activeSheetName: getters.getActiveSheetName, + cols + }) + } } const mutations = { - [types.SET_UNIQUE_COLS](state, { activeSheetName, cols }) { - state.cols[activeSheetName] = cols - }, - [types.INIT_UNIQUE](state, sheetNameList) { - sheetNameList.forEach((sheetName) => { - Vue.set(state.cols, sheetName, []) - }) - } + [types.SET_UNIQUE_COLS] (state, { activeSheetName, cols }) { + state.cols[activeSheetName] = cols + }, + [types.INIT_UNIQUE] (state, sheetNameList) { + sheetNameList.forEach(sheetName => { + Vue.set(state.cols, sheetName, []) + }) + } } export default { - state, - getters, - actions, - mutations -} \ No newline at end of file + state, + getters, + actions, + mutations +} diff --git a/app/src/store/mutation-types.js b/app/src/store/mutation-types.js index 3754a01..bb67630 100644 --- a/app/src/store/mutation-types.js +++ b/app/src/store/mutation-types.js @@ -40,4 +40,4 @@ export const INIT_FILTER_TAG_LIST = 'INIT_FILTER_TAG_LIST' // S unique.js export const SET_UNIQUE_COLS = 'SET_UNIQUE_COLS' export const INIT_UNIQUE = 'INIT_UNIQUE' -// E unique.js \ No newline at end of file +// E unique.js diff --git a/app/src/utils/ExcelSet.js b/app/src/utils/ExcelSet.js index 48a33a1..eee9e13 100644 --- a/app/src/utils/ExcelSet.js +++ b/app/src/utils/ExcelSet.js @@ -5,109 +5,111 @@ import pathModule from 'path' // Excel 横向坐标的转换 0 <--> A /* 来自 http://www.cnblogs.com/lavezhang/archive/2012/05/14/2499000.html */ -export function getCharCol(n) { - let temCol = '', - s = '', - m = 0 - while (n >= 0) { - m = n % 26 + 1 - s = String.fromCharCode(m + 64) + s - n = (n - m) / 26 - } - return s +export function getCharCol (n) { + let s = '' + let m = 0 + while (n >= 0) { + m = (n % 26) + 1 + s = String.fromCharCode(m + 64) + s + n = (n - m) / 26 + } + return s } -export function getNumCol(s) { - if (!s) return 0 - let n = 0 - for (let i = s.length - 1, j = 1; i >= 0; i-- , j *= 26) { - let c = s[i].toUpperCase() - if (c < 'A' || c > 'Z') return 0 - n += (c.charCodeAt() - 64) * j - } - return n - 1 +export function getNumCol (s) { + if (!s) return 0 + let n = 0 + for (let i = s.length - 1, j = 1; i >= 0; i--, j *= 26) { + const c = s[i].toUpperCase() + if (c < 'A' || c > 'Z') return 0 + n += (c.charCodeAt() - 64) * j + } + return n - 1 } -export function isExcelFile(filePath) { - let extname = pathModule.extname(filePath) - let regexp = /\.xlsx?$/ig +export function isExcelFile (filePath) { + const extname = pathModule.extname(filePath) + const regexp = /\.xlsx?$/ig - return extname.search(regexp) !== -1 + return extname.search(regexp) !== -1 } - export const colOperator = [{ - char: '+', - words: '相加' + char: '+', + words: '相加' }, { - char: '-', - words: '相减' + char: '-', + words: '相减' }, { - char: '*', - words: '相乘' + char: '*', + words: '相乘' }, { - char: '/', - words: '相除' + char: '/', + words: '相除' }, { - char: '%', - words: '求余' + char: '%', + words: '求余' }, { - char: '-(time)', - words: '时间相减' -}/*,{ + char: '-(time)', + words: '时间相减' +}/*, { char: '+()', words: '字符串拼接' - }*/] -export function getColArithmeticOperatorWords(sets, char) { - for (let i = 0, len = sets.length; i < len; i++) { - let curColOperator = sets[i] - if (curColOperator.char === char) { - return curColOperator.words - } +} */] +export function getColArithmeticOperatorWords (sets, char) { + for (let i = 0, len = sets.length; i < len; i++) { + const curColOperator = sets[i] + if (curColOperator.char === char) { + return curColOperator.words } - return '匹配失败' + } + return '匹配失败' } -export function getLogicOperatorWords(char) { - return char === 'and' ? '且' : '或' +export function getLogicOperatorWords (char) { + return char === 'and' ? '且' : '或' } -export function getOperatorWords(sets, char) { - for (let i = 0, len = sets.length; i < len; i++) { - let obj = sets[i] - if (obj.char === char) - return obj.words - } - return '匹配失败' +export function getOperatorWords (sets, char) { + for (let i = 0, len = sets.length; i < len; i++) { + const obj = sets[i] + if (obj.char === char) { return obj.words } + } + return '匹配失败' } -export function getColOperatorWords(sets, char) { - for (let i = 0, len = sets.length; i < len; i++) { - let obj = sets[i] - if (obj.char === char) - return obj.words - } - return '匹配失败' +export function getColOperatorWords (sets, char) { + for (let i = 0, len = sets.length; i < len; i++) { + const obj = sets[i] + if (obj.char === char) { return obj.words } + } + return '匹配失败' } -export function getFilterWordsPrimitive(args) { - let { operator, operatorCol, operatorWords, val, colOperatorSelect, filterType } = args, - primitiveFilterWords = '' +export function getFilterWordsPrimitive ({ + operator, + operatorCol, + operatorWords, + val, + colOperatorSelect, + filterType + }) { + let primitiveFilterWords = '' // 判断是选择哪个操作符 - switch (operator) { - case 'startsWith': ; - case 'ends': primitiveFilterWords = `的${operatorWords}为“${val}”`; break; - case 'regexp': primitiveFilterWords = `应用了正则表达式"/${val}/ig"`; break; - default: - if (operator === 'empty' || operator === 'notEmpty') { - primitiveFilterWords = `${operatorWords}` - } else { - primitiveFilterWords = `${operatorWords}"${val}"` - } + switch (operator) { + case 'startsWith': + case 'ends': primitiveFilterWords = `的${operatorWords}为“${val}”`; break + case 'regexp': primitiveFilterWords = `应用了正则表达式"/${val}/ig"`; break + default: + if (operator === 'empty' || operator === 'notEmpty') { + primitiveFilterWords = `${operatorWords}` + } else { + primitiveFilterWords = `${operatorWords}"${val}"` + } - if (colOperatorSelect && colOperatorSelect.includes('time')) { - primitiveFilterWords += '分钟' - } - } - return primitiveFilterWords + if (colOperatorSelect && colOperatorSelect.includes('time')) { + primitiveFilterWords += '分钟' + } + } + return primitiveFilterWords } diff --git a/app/src/utils/appInfo.js b/app/src/utils/appInfo.js index 8c3986a..3abd87a 100644 --- a/app/src/utils/appInfo.js +++ b/app/src/utils/appInfo.js @@ -2,7 +2,6 @@ import { remote } from 'electron' import os from 'os' -import path from 'path' import packageJSON from '../../package.json' const UPDATE_HOST = 'http://nuts-xcel.aotu.io/' @@ -11,43 +10,42 @@ const UPDATE_HOST_DEV = 'http://nuts-xcel.aotu.io/' const DOWNLOAD_HOST = 'http://jdc.jd.com/lab/xcel/download/' // dev 时显示了 app.getName()、app.getVersion()都返回Electron的信息,但打包后正常 -let app = remote.app, - isDev = process.env.NODE_ENV === 'development', - app_version = isDev ? packageJSON.version : app.getVersion(), - name = isDev ? packageJSON.name : app.getName(), - platform = os.platform(), - arch = os.arch(), - updateUrl = isDev ? UPDATE_HOST_DEV + 'update/' + platform + '_' + arch + '/' + app_version - : UPDATE_HOST + 'update/' + platform + '_' + arch + '/' + app_version +const app = remote.app +const isDev = process.env.NODE_ENV === 'development' +const appVersion = isDev ? packageJSON.version : app.getVersion() +const name = isDev ? packageJSON.name : app.getName() +const platform = os.platform() +const arch = os.arch() +const updateUrl = isDev ? + `${UPDATE_HOST_DEV}update/${platform}_${arch}/${appVersion}` : + `${UPDATE_HOST}update/${platform}_${arch}/${appVersion}` export const appInfo = { - platform, - name, - app_version, - ele_version: process.versions.electron, // electron 版本 - chrome_version: process.versions.chrome, // chrome 版本 - locales: app.getLocale(), // 本地化 - updateUrl, - downloadUrl: DOWNLOAD_HOST -}; + platform, + name, + app_version: appVersion, + ele_version: process.versions.electron, // electron 版本 + chrome_version: process.versions.chrome, // chrome 版本 + locales: app.getLocale(), // 本地化 + updateUrl, + downloadUrl: DOWNLOAD_HOST +} - -export function getDownloadUrl(version) { - let prefix = `${DOWNLOAD_HOST}${version}/` - if (platform === 'darwin') { - return `${prefix}${name}-${version}.dmg` - } else if (platform === 'win32') { - if (arch === 'ia32' || arch === 'x86') { - return `${prefix}${name} Setup ${version}-ia32.exe` - } else if (arch === 'x64') { - return `${prefix}${name} Setup ${version}.exe` - } - } else if (platform === 'linux') { - if (arch === 'ia32' || arch === 'x86') { - return `${prefix}${name}-${version}-linux-ia32.zip` - } else if (arch === 'x64') { - return `${prefix}${name}-${version}-linux-x64.zip` - } - } - return undefined -} \ No newline at end of file +export function getDownloadUrl (version) { + const prefix = `${DOWNLOAD_HOST}${version}/` + if (platform === 'darwin') { + return `${prefix}${name}-${version}.dmg` + } else if (platform === 'win32') { + if (arch === 'ia32' || arch === 'x86') { + return `${prefix}${name} Setup ${version}-ia32.exe` + } else if (arch === 'x64') { + return `${prefix}${name} Setup ${version}.exe` + } + } else if (platform === 'linux') { + if (arch === 'ia32' || arch === 'x86') { + return `${prefix}${name}-${version}-linux-ia32.zip` + } else if (arch === 'x64') { + return `${prefix}${name}-${version}-linux-x64.zip` + } + } +} diff --git a/app/src/utils/localStorageSet.js b/app/src/utils/localStorageSet.js index bf031a9..f745105 100644 --- a/app/src/utils/localStorageSet.js +++ b/app/src/utils/localStorageSet.js @@ -1,38 +1,37 @@ -export function getLocal(key) { - let localStorage = window.localStorage, - valStr +export function getLocal (key) { + const localStorage = window.localStorage + let valStr - if (key !== undefined && key !== null) { - valStr = localStorage.getItem(key) - } else { - return false - } + if (typeof key !== 'undefined' && key !== null) { + valStr = localStorage.getItem(key) + } else { + return false + } - if (valStr !== 'undefined' && valStr !== 'null') { - try { - return JSON.parse(valStr) - } catch (e) { - console.log(`localStorage 的 ${key} 属性解析失败`) - return false - } - } else { - return false - } + if (valStr !== 'undefined' && valStr !== 'null') { + try { + return JSON.parse(valStr) + } catch (e) { + console.log(`localStorage 的 ${key} 属性解析失败`) + return false + } + } else { + return false + } } +export function setLocal (key, val) { + const localStorage = window.localStorage -export function setLocal(key, val) { - let localStorage = window.localStorage - - if (key !== undefined && key !== null) { - try { - localStorage.setItem(key, JSON.stringify(val)) - } catch (e) { - console.log(`localStorage 的 ${key}:${val}序列化失败`) - return false - } - } else { - console.log(`localStorage 的 ${key} 是非法值 undefined/null`) - return false - } -} \ No newline at end of file + if (typeof key !== 'undefined' && key !== null) { + try { + localStorage.setItem(key, JSON.stringify(val)) + } catch (e) { + console.log(`localStorage 的 ${key}:${val}序列化失败`) + return false + } + } else { + console.log(`localStorage 的 ${key} 是非法值 undefined/null`) + return false + } +} diff --git a/app/src/utils/openExternal.js b/app/src/utils/openExternal.js index 3af96db..8fa8dfd 100644 --- a/app/src/utils/openExternal.js +++ b/app/src/utils/openExternal.js @@ -8,21 +8,21 @@ const GITHUB_URL = 'https://github.com/o2team/xcel' const GITHUB_ISSUES_URL = 'https://github.com/o2team/xcel/issues' const XCEL_LANDING_PAGE = 'https://xcel.aotu.io/' -export function openExternal(uri) { - if (uri === undefined || uri === null) { - return - } - if (_.isString(uri) && uri.trim() !== '') { - switch (uri.toLowerCase()) { - case 'ascii': shell.openExternal(ASCII_URL); break; - case 'aotu': shell.openExternal(AOTU_URL); break; - case 'issues': shell.openExternal(GITHUB_ISSUES_URL); break; - case 'github': shell.openExternal(GITHUB_URL); break; - case 'xcel': shell.openExternal(XCEL_LANDING_PAGE); break; - default: { - console.log('无匹配的地址') - shell.openExternal(AOTU_URL) - } - } - } -} \ No newline at end of file +export function openExternal (uri) { + if (typeof uri === 'undefined' || uri === null) { + return + } + if (_.isString(uri) && uri.trim() !== '') { + switch (uri.toLowerCase()) { + case 'ascii': shell.openExternal(ASCII_URL); break + case 'aotu': shell.openExternal(AOTU_URL); break + case 'issues': shell.openExternal(GITHUB_ISSUES_URL); break + case 'github': shell.openExternal(GITHUB_URL); break + case 'xcel': shell.openExternal(XCEL_LANDING_PAGE); break + default: { + console.log('无匹配的地址') + shell.openExternal(AOTU_URL) + } + } + } +} diff --git a/config.js b/config.js index 910b4f1..225a39a 100644 --- a/config.js +++ b/config.js @@ -2,7 +2,7 @@ const path = require('path') const pkg = require('./app/package.json') -let config = { +const config = { // Name of electron app // Will be used in production builds name: pkg.product, @@ -11,12 +11,12 @@ let config = { port: 9080, // electron-packager options - // Docs: https://simulatedgreg.gitbooks.io/electron-vue/content/docs/building_your_app.html + // Docs: https://github.com/electron-userland/electron-packager/blob/master/docs/api.md building: { - 'app-version': pkg.version, + appVersion: pkg.version, arch: ['x64', 'ia32'], // ia32, x64, armv7l, all asar: true, - dir: path.join(__dirname, 'app'), + dir: path.join(__dirname, 'app'), // Directory of the app icon: path.join(__dirname, 'app/icons/icon'), ignore: /src|main.ejs|icons/, out: path.join(__dirname, 'builds'), @@ -29,7 +29,7 @@ let config = { backUrl: `file://${__dirname}/app/dist/background/index.html` } -config.mainUrl = `http://localhost:${config.port}`; +config.mainUrl = `http://localhost:${config.port}` if (!config.isDev) { config.devtron = false diff --git a/package.json b/package.json index 52fc333..439fd48 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,10 @@ "electron-devtools-installer": "^1.1.4", "electron-packager": "^8.7.0", "electron-rebuild": "^1.1.3", + "eslint": "^3.19.0", + "eslint-config-o2team": "^0.1.6", + "eslint-friendly-formatter": "^3.0.0", + "eslint-loader": "^1.7.1", "extract-text-webpack-plugin": "^1.0.1", "file-loader": "^0.8.5", "html-webpack-plugin": "^2.16.1", diff --git a/tasks/release.js b/tasks/release.js index 4356752..a1f3709 100644 --- a/tasks/release.js +++ b/tasks/release.js @@ -3,40 +3,46 @@ const exec = require('child_process').exec const packager = require('electron-packager') +// ANSI color codes +// http://pueblo.sourceforge.net/doc/manual/ansi_color_codes.html +const RED = '\x1b[31m' +const YELLOW = '\x1b[33m' +const BLUE = '\x1b[34m' +const END = '\x1b[0m' + if (process.env.PLATFORM_TARGET === 'clean') { require('del').sync(['builds/*', '!.gitkeep']) - console.log('\x1b[33m`builds` directory cleaned.\n\x1b[0m') + console.log(`${RED}builds\` directory cleaned.\n${END}`) } else pack() /** * Build webpack in production */ function pack () { - console.log('\x1b[33mBuilding webpack in production mode...\n\x1b[0m') - let pack = exec('npm run pack_ori:electron-packager') + console.log(`${YELLOW}Building webpack in production mode...\n${END}`) + const pack = exec('npm run pack_ori:electron-packager') pack.stdout.on('data', data => console.log(data)) pack.stderr.on('data', data => console.error(data)) pack.on('exit', code => build()) } - /** * Use electron-packager to build electron app */ function build () { - let options = require('../config').building + const options = require('../config').building - console.log('\x1b[34mBuilding electron app(s)...\n\x1b[0m') + console.log(`${BLUE}Building electron app(s)...\n${END}`) packager(options, (err, appPaths) => { - if(err) { - console.error('\x1b[31mError from `electron-packager` when building app...\x1b[0m') + if (err) { + console.error(`${RED}Error from \`electron-packager\` when building app...${END}`) console.error(err) } else { console.log('Build(s) successful!') console.log(appPaths) - console.log('\n\x1b[34mDONE\n\x1b[0m') + console.log(`\n${BLUE}DONE\n${END}`) } }) } diff --git a/tasks/runner.js b/tasks/runner.js index d82a449..9f89beb 100644 --- a/tasks/runner.js +++ b/tasks/runner.js @@ -7,27 +7,27 @@ const config = require('../config') const exec = require('child_process').exec const treeKill = require('tree-kill') -let YELLOW = '\x1b[33m' -let BLUE = '\x1b[34m' -let END = '\x1b[0m' +const YELLOW = '\x1b[33m' +const BLUE = '\x1b[34m' +const END = '\x1b[0m' let isElectronOpen = false function format (command, data, color) { - return color + command + END + - ' ' + // Two space offset - data.toString().trim().replace(/\n/g, '\n' + repeat(' ', command.length + 2)) + - '\n' + return `${color + command + END} + ${ // Two space offset + data.toString().trim().replace(/\n/g, `\n${repeat(' ', command.length + 2)}`) + }\n` } function repeat (str, times) { return (new Array(times + 1)).join(str) } -let children = [] +const children = [] function run (command, color, name) { - let child = exec(command) + const child = exec(command) child.stdout.on('data', data => { console.log(format(name, data, color)) @@ -38,12 +38,12 @@ function run (command, color, name) { * * NOTE: needs more testing for stability */ - /*if (/VALID/g.test(data.toString().trim().replace(/\n/g, '\n' + repeat(' ', command.length + 2))) && !isElectronOpen) { + /* if (/VALID/g.test(data.toString().trim().replace(/\n/g, '\n' + repeat(' ', command.length + 2))) && !isElectronOpen) { console.log(`${BLUE}Starting electron...\n${END}`) run('cross-env NODE_ENV=development electron app/electron.js', BLUE, 'electron') isElectronOpen = true - }*/ - if (/Compiled/g.test(data.toString().trim().replace(/\n/g, '\n' + repeat(' ', command.length + 2))) && !isElectronOpen) { + } */ + if (/Compiled/g.test(data.toString().trim().replace(/\n/g, `\n${repeat(' ', command.length + 2)}`)) && !isElectronOpen) { console.log(`${BLUE}Starting electron...\n${END}`) run('cross-env NODE_ENV=development electron app/electron.js', BLUE, 'electron') isElectronOpen = true diff --git a/tasks/vue/route.js b/tasks/vue/route.js deleted file mode 100644 index 3a24bb9..0000000 --- a/tasks/vue/route.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict' - -const fs = require('fs') -const path = require('path') - -let routeName = process.argv[2] -let routes = fs.readFileSync( - path.join(__dirname, '../../app/src/routes.js'), - 'utf8' -).split('\n') -let routeTemplate = fs.readFileSync( - path.join(__dirname, 'route.template.txt'), - 'utf8' -) -let routesTemplate = fs.readFileSync( - path.join(__dirname, 'routes.template.txt'), - 'utf8' -) - -routes[routes.length - 3] = routes[routes.length - 3] + ',' -routes.splice( - routes.length - 2, - 0, - routesTemplate - .replace(//g, routeName) - .replace(/\n$/, '') -) - -fs.writeFileSync( - path.join(__dirname, `../../app/src/components/${routeName}View.vue`), - routeTemplate -) - -fs.mkdirSync(path.join(__dirname, `../../app/src/components/${routeName}View`)) - -fs.writeFileSync( - path.join(__dirname, '../../app/src/routes.js'), - routes.join('\n') -) - -console.log(`\n\x1b[33m[vue]\x1b[0m route "${routeName}" has been created`) -console.log(' [ \n' + [ - ' ' + path.join(__dirname, `../../app/src/components/${routeName}View.vue`), - path.join(__dirname, `../../app/src/components/${routeName}View`), - path.join(__dirname, '../../app/src/routes.js'), -].join(',\n ') + '\n ]') diff --git a/tasks/vue/route.template.txt b/tasks/vue/route.template.txt deleted file mode 100644 index bc27f48..0000000 --- a/tasks/vue/route.template.txt +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/tasks/vue/routes.template.txt b/tasks/vue/routes.template.txt deleted file mode 100644 index ec9584f..0000000 --- a/tasks/vue/routes.template.txt +++ /dev/null @@ -1,4 +0,0 @@ - '/': { - component: require('./components/View'), - name: '' - } diff --git a/webpack.config.js b/webpack.config.js index e8a7c23..9aa28ab 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,8 +1,6 @@ 'use strict' -const fs = require('fs') const path = require('path') -const pkg = require('./app/package.json') const settings = require('./config.js') const webpack = require('webpack') @@ -10,12 +8,23 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin') const CopyWebpackPlugin = require('copy-webpack-plugin') -let config = { +const config = { devtool: '#eval-source-map', entry: { build: path.join(__dirname, 'app/src/main.js') }, + eslint: { + formatter: require('eslint-friendly-formatter'), + configFile: './.eslintrc' + }, module: { + preloaders: [ + { + test: /\.js$/, + loader: 'babel!eslint', + exclude: /node_modules/ + } + ], loaders: [ { test: /\.css$/, @@ -68,8 +77,8 @@ let config = { }), new webpack.NoErrorsPlugin(), new CopyWebpackPlugin([ - {from: path.join(__dirname, 'app/src/background'), to: path.join(__dirname, "app/dist/background")}, - {from: path.join(__dirname, 'app/src/update'), to: path.join(__dirname, "app/dist/update")} + { from: path.join(__dirname, 'app/src/background'), to: path.join(__dirname, 'app/dist/background') }, + { from: path.join(__dirname, 'app/src/update'), to: path.join(__dirname, 'app/dist/update') } ]) ], output: { @@ -94,7 +103,8 @@ let config = { }, loaders: { sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', - scss: 'vue-style-loader!css-loader!sass-loader' + scss: 'vue-style-loader!css-loader!sass-loader', + js: 'babel!eslint' } }, node: {