From 1d20f529a0b778b1aee1cdf71932a5d319d4a68c Mon Sep 17 00:00:00 2001 From: kuaifan Date: Mon, 10 Jan 2022 23:54:48 +0800 Subject: [PATCH] no message --- electron/build.js | 112 +------- electron/main.js | 77 +++++- electron/utils.js | 155 ++++++++++- resources/assets/js/components/AppDown.vue | 241 ++++++++++-------- resources/assets/js/pages/login.vue | 4 +- .../assets/sass/components/app-down.scss | 4 + resources/assets/sass/pages/page-login.scss | 6 - 7 files changed, 364 insertions(+), 235 deletions(-) diff --git a/electron/build.js b/electron/build.js index e9a1301b..05fa95c2 100644 --- a/electron/build.js +++ b/electron/build.js @@ -3,103 +3,11 @@ const fse = require('fs-extra'); const path = require('path') const inquirer = require('inquirer'); const child_process = require('child_process'); +const utils = require('./utils'); const config = require('../package.json') const argv = process.argv; const env = require('dotenv').config({ path: './.env' }) -/** - * 删除文件夹及文件 - * @param path - */ -function deleteFile(path) { - let files = []; - if (fs.existsSync(path)) { - files = fs.readdirSync(path); - files.forEach(function (file, index) { - let curPath = path + "/" + file; - if (fs.statSync(curPath).isDirectory()) { - deleteFile(curPath); - } else { - fs.unlinkSync(curPath); - } - }); - fs.rmdirSync(path); - } -} - -/** - * 复制文件 - * @param srcPath - * @param tarPath - * @param cb - */ -function copyFile(srcPath, tarPath, cb) { - let rs = fs.createReadStream(srcPath) - rs.on('error', function (err) { - if (err) { - console.log('read error', srcPath) - } - cb && cb(err) - }) - let ws = fs.createWriteStream(tarPath) - ws.on('error', function (err) { - if (err) { - console.log('write error', tarPath) - } - cb && cb(err) - }) - ws.on('close', function (ex) { - cb && cb(ex) - }) - rs.pipe(ws) -} - -/** - * 给地址加上前后 - * @param str - * @returns {string} - */ -function formatUrl(str) { - let url; - if (str.substring(0, 7) === "http://" || - str.substring(0, 8) === "https://") { - url = str.trim(); - } else { - url = "http://" + str.trim(); - } - if (url.substring(url.length - 1) != "/") { - url += "/" - } - return url; -} - -/** - * 正则提取域名 - * @param weburl - * @returns {string|string} - */ -function getDomain(weburl) { - let urlReg = /http(s)?:\/\/([^\/]+)/i; - let domain = weburl.match(urlReg); - return ((domain != null && domain.length > 0) ? domain[2] : ""); -} - -/** - * 右边是否包含 - * @param string - * @param find - * @returns {boolean} - */ -function rightExists(string, find) { - string += ""; - find += ""; - return (string.substring(string.length - find.length) === find); -} - -/** ***************************************************************************************************/ -/** ***************************************************************************************************/ -/** ***************************************************************************************************/ - const electronDir = path.resolve(__dirname, "public"); const nativeCachePath = path.resolve(__dirname, ".native"); const devloadCachePath = path.resolve(__dirname, ".devload"); @@ -108,7 +16,7 @@ const packageBakFile = path.resolve(__dirname, "package-bak.json"); const platform = ["build-mac", "build-mac-arm", "build-win"]; // 生成配置、编译应用 -function start(data, publish) { +function startBuild(data, publish) { console.log("Name: " + data.name); console.log("AppId: " + data.id); console.log("Version: " + config.version); @@ -117,10 +25,10 @@ function start(data, publish) { title: data.name, version: config.version, origin: "./", - apiUrl: formatUrl(data.url) + "api/", + apiUrl: utils.formatUrl(data.url) + "api/", } fs.writeFileSync(electronDir + "/config.js", "window.systemInformation = " + JSON.stringify(systemInfo, null, 2), 'utf8'); - fs.writeFileSync(nativeCachePath, formatUrl(data.url)); + fs.writeFileSync(nativeCachePath, utils.formatUrl(data.url)); fs.writeFileSync(devloadCachePath, "", 'utf8'); // index.html let indexFile = path.resolve(electronDir, "index.html"); @@ -134,8 +42,8 @@ function start(data, publish) { econfig.name = data.name; econfig.version = config.version; econfig.build.appId = data.id; - econfig.build.artifactName = getDomain(data.url) + "-v${version}-${os}-${arch}.${ext}"; - econfig.build.nsis.artifactName = getDomain(data.url) + "-v${version}-${os}-${arch}.${ext}"; + econfig.build.artifactName = utils.getDomain(data.url) + "-v${version}-${os}-${arch}.${ext}"; + econfig.build.nsis.artifactName = utils.getDomain(data.url) + "-v${version}-${os}-${arch}.${ext}"; econfig.build.pkg.mustClose = [data.id]; fs.writeFileSync(packageFile, JSON.stringify(econfig, null, 2), 'utf8'); // build @@ -146,7 +54,7 @@ function start(data, publish) { if (["dev"].includes(argv[2])) { // 开发模式 - fs.writeFileSync(devloadCachePath, formatUrl("127.0.0.1:" + env.parsed.APP_PORT), 'utf8'); + fs.writeFileSync(devloadCachePath, utils.formatUrl("127.0.0.1:" + env.parsed.APP_PORT), 'utf8'); child_process.spawn("npx", ["mix", "watch", "--hot", "--", "--env", "--electron"], {stdio: "inherit"}); child_process.spawn("npm", ["run", "start-quiet"], {stdio: "inherit", cwd: "electron"}); } else if (platform.includes(argv[2])) { @@ -154,7 +62,7 @@ if (["dev"].includes(argv[2])) { config.app.sites.forEach((data) => { if (data.name && data.id && data.url) { data.platform = argv[2]; - start(data, true) + startBuild(data, true) } }) } else { @@ -171,7 +79,7 @@ if (["dev"].includes(argv[2])) { return undefined; }, validate: function (value) { - if (!rightExists(value, "/")) { + if (!utils.rightExists(value, "/")) { return '网址必须以 "/" 结尾'; } return value !== '' @@ -198,7 +106,7 @@ if (["dev"].includes(argv[2])) { ]; inquirer.prompt(questions).then(answers => { answers.platform.forEach(platform => { - start({ + startBuild({ "name": config.name, "id": config.app.id, "url": answers.website, diff --git a/electron/main.js b/electron/main.js index cf6ee411..6eabb198 100644 --- a/electron/main.js +++ b/electron/main.js @@ -4,19 +4,24 @@ const path = require('path') const XLSX = require('xlsx'); const {app, BrowserWindow, ipcMain, dialog} = require('electron') const utils = require('./utils'); +const config = require('./package.json'); const log = require("electron-log"); let mainWindow = null, subWindow = [], - downloadList = [], willQuitApp = false, inheritClose = false, + devloadUrl = "", devloadCachePath = path.resolve(__dirname, ".devload"), - devloadUrl = ""; + downloadList = [], + downloadCacheFile = path.join(app.getPath('cache'), config.name + '.downloadCache'); if (fs.existsSync(devloadCachePath)) { devloadUrl = fs.readFileSync(devloadCachePath, 'utf8') } +if (fs.existsSync(downloadCacheFile)) { + downloadList = utils.jsonParse(fs.readFileSync(downloadCacheFile, 'utf8'), []) +} function createMainWindow() { mainWindow = new BrowserWindow({ @@ -64,7 +69,7 @@ function createMainWindow() { }) mainWindow.webContents.session.on('will-download', (event, item) => { - item.setSavePath(path.join(app.getPath('temp'), item.getFilename())); + item.setSavePath(path.join(app.getPath('cache'), item.getFilename())); item.on('done', (event, state) => { try { const info = { @@ -87,15 +92,14 @@ function createMainWindow() { download.info = info } }) + fs.writeFileSync(downloadCacheFile, utils.jsonStringify(downloadList), 'utf8'); } else { // 下载失败 info.chain.some(url => { downloadList = downloadList.filter(item => item.url != url) }) } - } catch (e) { - // - } + } catch (e) { } }) }) } @@ -184,12 +188,19 @@ app.on('before-quit', () => { willQuitApp = true }) +/** + * 继承关闭窗口事件 + */ ipcMain.on('inheritClose', (event) => { inheritClose = true event.returnValue = "ok" }) -ipcMain.on('downloadURL', (event, args) => { +/** + * 下载文件 + * @param args {url} + */ +ipcMain.on('downloadFile', (event, args) => { const download = downloadList.find(({url}) => url == args.url); if (download) { if (download.status == "completed") { @@ -212,21 +223,35 @@ ipcMain.on('downloadURL', (event, args) => { event.returnValue = "ok" }) +/** + * 打开文件 + * @param args {path} + */ ipcMain.on('openFile', (event, args) => { utils.openFile(args.path) event.returnValue = "ok" }) +/** + * 退出客户端 + */ ipcMain.on('windowQuit', (event) => { event.returnValue = "ok" app.quit(); }) +/** + * 创建路由窗口 + * @param args {path, ?} + */ ipcMain.on('windowRouter', (event, args) => { createSubWindow(args) event.returnValue = "ok" }) +/** + * 隐藏窗口(mac隐藏,其他关闭) + */ ipcMain.on('windowHidden', (event) => { if (process.platform === 'darwin') { app.hide(); @@ -236,12 +261,19 @@ ipcMain.on('windowHidden', (event) => { event.returnValue = "ok" }) +/** + * 关闭窗口 + */ ipcMain.on('windowClose', (event) => { const win = BrowserWindow.fromWebContents(event.sender); win.close() event.returnValue = "ok" }) +/** + * 设置窗口尺寸 + * @param args {width, height, autoZoom, minWidth, minHeight, maxWidth, maxHeight} + */ ipcMain.on('windowSize', (event, args) => { const win = BrowserWindow.fromWebContents(event.sender); if (win) { @@ -277,23 +309,34 @@ ipcMain.on('windowSize', (event, args) => { event.returnValue = "ok" }) +/** + * 设置窗口最小尺寸 + * @param args {minWidth, minHeight} + */ ipcMain.on('windowMinSize', (event, args) => { const win = BrowserWindow.fromWebContents(event.sender); if (win) { - win.setMinimumSize(args.width || win.getMinimumSize()[0], args.height || win.getMinimumSize()[1]) + win.setMinimumSize(args.minWidth || win.getMinimumSize()[0], args.minHeight || win.getMinimumSize()[1]) } event.returnValue = "ok" }) +/** + * 设置窗口最大尺寸 + * @param args {maxWidth, maxHeight} + */ ipcMain.on('windowMaxSize', (event, args) => { const win = BrowserWindow.fromWebContents(event.sender); if (win) { - win.setMaximumSize(args.width || win.getMaximumSize()[0], args.height || win.getMaximumSize()[1]) + win.setMaximumSize(args.maxWidth || win.getMaximumSize()[0], args.maxHeight || win.getMaximumSize()[1]) } event.returnValue = "ok" }) -ipcMain.on('windowCenter', (event, args) => { +/** + * 窗口居中 + */ +ipcMain.on('windowCenter', (event) => { const win = BrowserWindow.fromWebContents(event.sender); if (win) { win.center(); @@ -301,6 +344,9 @@ ipcMain.on('windowCenter', (event, args) => { event.returnValue = "ok" }) +/** + * 窗口最大化或恢复 + */ ipcMain.on('windowMax', (event) => { const win = BrowserWindow.fromWebContents(event.sender); if (win.isMaximized()) { @@ -311,6 +357,10 @@ ipcMain.on('windowMax', (event) => { event.returnValue = "ok" }) +/** + * 给主窗口发送信息 + * @param args {channel, data} + */ ipcMain.on('sendForwardMain', (event, args) => { if (mainWindow) { mainWindow.webContents.send(args.channel, args.data) @@ -318,6 +368,10 @@ ipcMain.on('sendForwardMain', (event, args) => { event.returnValue = "ok" }) +/** + * 设置Dock标记 + * @param args + */ ipcMain.on('setDockBadge', (event, args) => { if(process.platform !== 'darwin'){ // Mac only @@ -331,6 +385,9 @@ ipcMain.on('setDockBadge', (event, args) => { event.returnValue = "ok" }) +/** + * 保存sheets + */ ipcMain.on('saveSheet', (event, data, filename, opts) => { const EXTENSIONS = "xls|xlsx|xlsm|xlsb|xml|csv|txt|dif|sylk|slk|prn|ods|fods|htm|html".split("|"); dialog.showSaveDialog({ diff --git a/electron/utils.js b/electron/utils.js index 60792cad..0383539e 100644 --- a/electron/utils.js +++ b/electron/utils.js @@ -2,18 +2,73 @@ const fs = require("fs"); const {shell} = require("electron"); module.exports = { + /** + * 是否数组 + * @param obj + * @returns {boolean} + */ + isArray(obj) { + return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == '[object array]' && typeof obj.length == "number"; + }, + + /** + * 是否数组对象 + * @param obj + * @returns {boolean} + */ + isJson(obj) { + return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && typeof obj.length == "undefined"; + }, + + /** + * 将一个 JSON 字符串转换为对象(已try) + * @param str + * @param defaultVal + * @returns {*} + */ + jsonParse(str, defaultVal = undefined) { + if (str === null) { + return defaultVal ? defaultVal : {}; + } + if (typeof str === "object") { + return str; + } + try { + return JSON.parse(str.replace(/\n/g,"\\n").replace(/\r/g,"\\r")); + } catch (e) { + return defaultVal ? defaultVal : {}; + } + }, + + /** + * 将 JavaScript 值转换为 JSON 字符串(已try) + * @param json + * @param defaultVal + * @returns {string} + */ + jsonStringify(json, defaultVal = undefined) { + if (typeof json !== 'object') { + return json; + } + try{ + return JSON.stringify(json); + }catch (e) { + return defaultVal ? defaultVal : ""; + } + }, + /** * 随机数字 * @param str * @param fixed * @returns {number} */ - runNum(str, fixed) { + runNum(str, fixed = null) { let _s = Number(str); if (_s + "" === "NaN") { _s = 0; } - if (/^[0-9]*[1-9][0-9]*$/.test(fixed)) { + if (fixed && /^[0-9]*[1-9][0-9]*$/.test(fixed)) { _s = _s.toFixed(fixed); let rs = _s.indexOf('.'); if (rs < 0) { @@ -43,7 +98,7 @@ module.exports = { }, /** - * 字符串包含 + * 字符串是否包含 * @param string * @param find * @param lower @@ -92,6 +147,23 @@ module.exports = { return string ? string : ''; }, + /** + * 字符串是否右边包含 + * @param string + * @param find + * @param lower + * @returns {boolean} + */ + rightExists(string, find, lower = false) { + string += ""; + find += ""; + if (lower !== true) { + string = string.toLowerCase(); + find = find.toLowerCase(); + } + return (string.substring(string.length - find.length) === find); + }, + /** * 打开文件 * @param path @@ -103,4 +175,81 @@ module.exports = { shell.openPath(path).then(() => { }) }, + + /** + * 删除文件夹及文件 + * @param path + */ + deleteFile(path) { + let files = []; + if (fs.existsSync(path)) { + files = fs.readdirSync(path); + files.forEach(function (file, index) { + let curPath = path + "/" + file; + if (fs.statSync(curPath).isDirectory()) { + deleteFile(curPath); + } else { + fs.unlinkSync(curPath); + } + }); + fs.rmdirSync(path); + } + }, + + /** + * 复制文件 + * @param srcPath + * @param tarPath + * @param cb + */ + copyFile(srcPath, tarPath, cb) { + let rs = fs.createReadStream(srcPath) + rs.on('error', function (err) { + if (err) { + console.log('read error', srcPath) + } + cb && cb(err) + }) + let ws = fs.createWriteStream(tarPath) + ws.on('error', function (err) { + if (err) { + console.log('write error', tarPath) + } + cb && cb(err) + }) + ws.on('close', function (ex) { + cb && cb(ex) + }) + rs.pipe(ws) + }, + + /** + * 给地址加上前后 + * @param str + * @returns {string} + */ + formatUrl(str) { + let url; + if (str.substring(0, 7) === "http://" || + str.substring(0, 8) === "https://") { + url = str.trim(); + } else { + url = "http://" + str.trim(); + } + if (url.substring(url.length - 1) != "/") { + url += "/" + } + return url; + }, + + /** + * 正则提取域名 + * @param weburl + * @returns {string|string} + */ + getDomain(weburl) { + let urlReg = /http(s)?:\/\/([^\/]+)/i; + let domain = weburl.match(urlReg); + return ((domain != null && domain.length > 0) ? domain[2] : ""); + }, } diff --git a/resources/assets/js/components/AppDown.vue b/resources/assets/js/components/AppDown.vue index a78db8b4..36ca97b2 100644 --- a/resources/assets/js/components/AppDown.vue +++ b/resources/assets/js/components/AppDown.vue @@ -1,6 +1,6 @@ diff --git a/resources/assets/sass/components/app-down.scss b/resources/assets/sass/components/app-down.scss index fc522459..785fb68f 100644 --- a/resources/assets/sass/components/app-down.scss +++ b/resources/assets/sass/components/app-down.scss @@ -5,6 +5,10 @@ z-index: 1; display: flex; align-items: center; + transition: bottom 0.3s; + &[data-route=login] { + bottom: 75px; + } } .common-app-down-notification { diff --git a/resources/assets/sass/pages/page-login.scss b/resources/assets/sass/pages/page-login.scss index 91027149..dab531e1 100644 --- a/resources/assets/sass/pages/page-login.scss +++ b/resources/assets/sass/pages/page-login.scss @@ -114,11 +114,5 @@ z-index: 1; display: flex; align-items: center; - .common-app-down { - position: static; - bottom: auto; - right: auto; - margin-left: 12px; - } } }