浏览代码

demo shortcut

gaoshuaixing 4 年之前
父节点
当前提交
9bb56bf35a
共有 45 个文件被更改,包括 348 次插入141 次删除
  1. 14 0
      .travis.yml
  2. 6 3
      app/controller/v1/example.js
  3. 0 1
      app/public/css/app.3886a9b8.css
  4. 0 0
      app/public/css/app.c79dd55d.css
  5. 1 1
      app/public/index.html
  6. 0 0
      app/public/js/app.888a1909.js
  7. 0 0
      app/public/js/app.888a1909.js.map
  8. 0 0
      app/public/js/app.b6046f35.js
  9. 0 0
      app/public/js/app.b6046f35.js.map
  10. 0 0
      app/public/js/chunk-0facd6c5.d60d4450.js
  11. 0 0
      app/public/js/chunk-0facd6c5.d60d4450.js.map
  12. 0 2
      app/public/js/chunk-23265f79.cf6a544a.js
  13. 0 0
      app/public/js/chunk-23265f79.cf6a544a.js.map
  14. 2 0
      app/public/js/chunk-23265f79.d92214d0.js
  15. 0 0
      app/public/js/chunk-23265f79.d92214d0.js.map
  16. 2 0
      app/public/js/chunk-2d21dff5.42546cd8.js
  17. 0 0
      app/public/js/chunk-2d21dff5.42546cd8.js.map
  18. 0 0
      app/public/js/chunk-707f4980.46929655.js
  19. 0 0
      app/public/js/chunk-707f4980.46929655.js.map
  20. 0 0
      app/public/js/chunk-85272794.640722ac.js
  21. 0 0
      app/public/js/chunk-85272794.640722ac.js.map
  22. 0 0
      app/public/js/chunk-85272794.a366dbbc.js
  23. 0 0
      app/public/js/chunk-85272794.a366dbbc.js.map
  24. 0 0
      app/public/js/chunk-ef3e31dc.31aef086.js
  25. 0 0
      app/public/js/chunk-ef3e31dc.31aef086.js.map
  26. 0 0
      app/public/js/chunk-ef3e31dc.3818e3b8.js
  27. 0 0
      app/public/js/chunk-ef3e31dc.3818e3b8.js.map
  28. 0 0
      app/public/js/chunk-vendors.3d275796.js.map
  29. 0 0
      app/public/js/chunk-vendors.9d7d716c.js
  30. 0 0
      app/public/js/chunk-vendors.9d7d716c.js.map
  31. 1 1
      app/view/index.ejs
  32. 16 0
      appveyor.yml
  33. 3 6
      electron/apis/example.js
  34. 10 27
      electron/lib/shortcut.js
  35. 38 5
      electron/lib/storage.js
  36. 59 0
      frontend/.eslintrc.js
  37. 1 1
      frontend/src/main.js
  38. 0 0
      frontend/src/utils/shortcut/hot-key-input/codeMap.js
  39. 10 0
      frontend/src/utils/shortcut/hot-key-input/index.js
  40. 150 89
      frontend/src/utils/shortcut/hot-key-input/index.vue
  41. 27 0
      frontend/src/utils/shortcut/index.js
  42. 0 0
      frontend/src/utils/shortcut/lib/index.min.js
  43. 0 0
      frontend/src/utils/shortcut/lib/index.min.js.map
  44. 6 3
      frontend/src/views/example/Shortcut.vue
  45. 2 2
      package.json

+ 14 - 0
.travis.yml

@@ -0,0 +1,14 @@
+
+language: node_js
+node_js:
+  - '8'
+  - '10'
+  - '12'
+before_install:
+  - npm i npminstall -g
+install:
+  - npminstall
+script:
+  - npm run ci
+after_script:
+  - npminstall codecov && codecov

+ 6 - 3
app/controller/v1/example.js

@@ -77,11 +77,14 @@ class ExampleController extends BaseController {
   async setShortcut() {
     const self = this;
     const { ctx, service } = this;
-    const body = ctx.request.body;
-    const shortcutStr = body.shortcutStr;
+    const shortcutObj = ctx.request.body;
     const data = {};
 
-    await service.example.setShortcut(shortcutStr);
+    if (!shortcutObj['id'] || !shortcutObj['name'] || !shortcutObj['cmd']) {
+      self.sendFail({}, 'param error', 100);
+    }
+
+    await service.example.setShortcut(shortcutObj);
 
     self.sendSuccess(data);
   }

+ 0 - 1
app/public/css/app.3886a9b8.css

@@ -1 +0,0 @@
-#components-layout-demo-responsive .logo[data-v-8e59b2f6]{border-bottom:1px solid #e8e8e8}#components-layout-demo-responsive .pic-logo[data-v-8e59b2f6]{height:32px;margin:10px}#components-layout-demo-responsive .layout-sider[data-v-8e59b2f6]{border-right:1px solid #e8e8e8}#components-layout-demo-responsive .menu-item .ant-menu-item[data-v-8e59b2f6]{background-color:#fff;margin-top:0;margin-bottom:0}#components-layout-demo-responsive .sub-layout-sider[data-v-8e59b2f6]{background-color:#fafafa}#components-layout-demo-responsive .sub-menu-item .ant-menu-item[data-v-8e59b2f6]{margin-top:0;margin-bottom:0}#components-layout-demo-responsive .sub-menu-item .ant-menu-item[data-v-8e59b2f6]:after{border-right:3px solid #f2f2f2}#components-layout-demo-responsive .sub-menu-item .ant-menu-item-selected[data-v-8e59b2f6]{background-color:#f2f2f2}#components-layout-demo-responsive .sub-menu-item .ant-menu-item-selected span[data-v-8e59b2f6]{color:#111}#components-layout-demo-responsive .sub-menu-item.ant-menu[data-v-8e59b2f6]{background:#fafafa}#components-layout-demo-responsive .sub-menu-item.ant-menu-inline[data-v-8e59b2f6]{border-right:0 solid #fafafa}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50}

文件差异内容过多而无法显示
+ 0 - 0
app/public/css/app.c79dd55d.css


+ 1 - 1
app/public/index.html

@@ -1 +1 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>electron-egg</title><link href="/css/chunk-85272794.56abef7d.css" rel="prefetch"><link href="/js/chunk-0facd6c5.d60d4450.js" rel="prefetch"><link href="/js/chunk-23265f79.cf6a544a.js" rel="prefetch"><link href="/js/chunk-85272794.a366dbbc.js" rel="prefetch"><link href="/js/chunk-ef3e31dc.31aef086.js" rel="prefetch"><link href="/css/app.3886a9b8.css" rel="preload" as="style"><link href="/css/chunk-vendors.a1538f74.css" rel="preload" as="style"><link href="/js/app.b6046f35.js" rel="preload" as="script"><link href="/js/chunk-vendors.3d275796.js" rel="preload" as="script"><link href="/css/chunk-vendors.a1538f74.css" rel="stylesheet"><link href="/css/app.3886a9b8.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but electron-egg doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/js/chunk-vendors.3d275796.js"></script><script src="/js/app.b6046f35.js"></script></body></html>
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>electron-egg</title><link href="/css/chunk-85272794.56abef7d.css" rel="prefetch"><link href="/js/chunk-23265f79.d92214d0.js" rel="prefetch"><link href="/js/chunk-2d21dff5.42546cd8.js" rel="prefetch"><link href="/js/chunk-707f4980.46929655.js" rel="prefetch"><link href="/js/chunk-85272794.640722ac.js" rel="prefetch"><link href="/js/chunk-ef3e31dc.3818e3b8.js" rel="prefetch"><link href="/css/app.c79dd55d.css" rel="preload" as="style"><link href="/css/chunk-vendors.a1538f74.css" rel="preload" as="style"><link href="/js/app.888a1909.js" rel="preload" as="script"><link href="/js/chunk-vendors.9d7d716c.js" rel="preload" as="script"><link href="/css/chunk-vendors.a1538f74.css" rel="stylesheet"><link href="/css/app.c79dd55d.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but electron-egg doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/js/chunk-vendors.9d7d716c.js"></script><script src="/js/app.888a1909.js"></script></body></html>

文件差异内容过多而无法显示
+ 0 - 0
app/public/js/app.888a1909.js


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/app.888a1909.js.map


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/app.b6046f35.js


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/app.b6046f35.js.map


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-0facd6c5.d60d4450.js


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-0facd6c5.d60d4450.js.map


+ 0 - 2
app/public/js/chunk-23265f79.cf6a544a.js

@@ -1,2 +0,0 @@
-(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-23265f79"],{"5cb9":function(t,n,e){"use strict";e.r(n);var o=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("div",[e("h3",{style:{marginBottom:"16px"}},[t._v(" demo1 打开文件夹实现 ")]),e("a-list",{attrs:{bordered:"","data-source":t.data},scopedSlots:t._u([{key:"renderItem",fn:function(n){return e("a-list-item",{on:{click:function(e){return t.openDirectry(n.id)}}},[t._v(" "+t._s(n.content)+" "),e("a-button",{attrs:{type:"link"}},[t._v(" 打开 ")])],1)}}])})],1)},a=[],u=e("a358"),c=[{content:"【下载】目录",id:"download"},{content:"【图片】目录",id:"picture"},{content:"【文档】目录",id:"doc"},{content:"【音乐】目录",id:"music"}],i={data:function(){return{data:c}},methods:{openDirectry:function(t){console.log("id:",t);var n={id:t};Object(u["c"])(n).then((function(t){if(0!==t.code)return!1})).catch((function(t){console.log("err:",t)}))}}},r=i,d=e("2877"),l=Object(d["a"])(r,o,a,!1,null,null,null);n["default"]=l.exports},a358:function(t,n,e){"use strict";e.d(n,"b",(function(){return u})),e.d(n,"c",(function(){return c})),e.d(n,"a",(function(){return i}));var o=e("b775"),a={outApi:"/api/v1/outApi",openDir:"/api/v1/example/openLocalDir",uploadFile:"/api/v1/example/uploadFile",executeJS:"/api/v1/example/executeJS",autoLaunchEnable:"/api/v1/setting/autoLaunchEnable",autoLaunchDisable:"/api/v1/setting/autoLaunchDisable",autoLaunchIsEnabled:"/api/v1/setting/autoLaunchIsEnabled"};function u(t,n){return Object(o["b"])({url:a[t],method:"post",data:n})}function c(t){return Object(o["b"])({url:a.openDir,method:"post",data:t})}function i(t){return Object(o["b"])({url:a.executeJS,method:"post",data:t})}}}]);
-//# sourceMappingURL=chunk-23265f79.cf6a544a.js.map

文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-23265f79.cf6a544a.js.map


+ 2 - 0
app/public/js/chunk-23265f79.d92214d0.js

@@ -0,0 +1,2 @@
+(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-23265f79"],{"5cb9":function(t,e,n){"use strict";n.r(e);var o=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",[n("h3",{style:{marginBottom:"16px"}},[t._v(" demo1 打开文件夹实现 ")]),n("a-list",{attrs:{bordered:"","data-source":t.data},scopedSlots:t._u([{key:"renderItem",fn:function(e){return n("a-list-item",{on:{click:function(n){return t.openDirectry(e.id)}}},[t._v(" "+t._s(e.content)+" "),n("a-button",{attrs:{type:"link"}},[t._v(" 打开 ")])],1)}}])})],1)},a=[],u=n("a358"),c=[{content:"【下载】目录",id:"download"},{content:"【图片】目录",id:"picture"},{content:"【文档】目录",id:"doc"},{content:"【音乐】目录",id:"music"}],i={data:function(){return{data:c}},methods:{openDirectry:function(t){console.log("id:",t);var e={id:t};Object(u["c"])(e).then((function(t){if(0!==t.code)return!1})).catch((function(t){console.log("err:",t)}))}}},r=i,d=n("2877"),l=Object(d["a"])(r,o,a,!1,null,null,null);e["default"]=l.exports},a358:function(t,e,n){"use strict";n.d(e,"b",(function(){return u})),n.d(e,"c",(function(){return c})),n.d(e,"a",(function(){return i}));var o=n("b775"),a={outApi:"/api/v1/outApi",openDir:"/api/v1/example/openLocalDir",uploadFile:"/api/v1/example/uploadFile",executeJS:"/api/v1/example/executeJS",setShortcut:"/api/v1/example/setShortcut",autoLaunchEnable:"/api/v1/setting/autoLaunchEnable",autoLaunchDisable:"/api/v1/setting/autoLaunchDisable",autoLaunchIsEnabled:"/api/v1/setting/autoLaunchIsEnabled"};function u(t,e){return Object(o["b"])({url:a[t],method:"post",data:e})}function c(t){return Object(o["b"])({url:a.openDir,method:"post",data:t})}function i(t){return Object(o["b"])({url:a.executeJS,method:"post",data:t})}}}]);
+//# sourceMappingURL=chunk-23265f79.d92214d0.js.map

文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-23265f79.d92214d0.js.map


+ 2 - 0
app/public/js/chunk-2d21dff5.42546cd8.js

@@ -0,0 +1,2 @@
+(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d21dff5"],{d44c:function(e,a,t){"use strict";t.r(a);var l=function(){var e=this,a=e.$createElement,t=e._self._c||a;return t("div",[t("h3",{style:{marginBottom:"16px"}},[e._v(" demo2 上传文件到sm图床实现 ")]),t("a-upload-dragger",{attrs:{name:"file",multiple:!0,action:e.action_url},on:{change:e.handleChange}},[t("p",{staticClass:"ant-upload-drag-icon"},[t("a-icon",{attrs:{type:"inbox"}})],1),t("p",{staticClass:"ant-upload-text"},[e._v(" Click or drag file to this area to upload ")]),t("p",{staticClass:"ant-upload-hint"},[e._v(" Support for a single or bulk upload. Strictly prohibit from uploading company data or other band files ")])]),t("p"),0!==e.image_info.length?t("a-list",{attrs:{size:"small",bordered:"","data-source":e.image_info},scopedSlots:e._u([{key:"renderItem",fn:function(a){return t("a-list-item",{staticStyle:{"text-align":"left"}},[e._v(" "+e._s(a.id)+". "+e._s(a.imageUrlText)+": "),t("a",{attrs:{href:a.url,target:"_blank"}},[e._v(e._s(a.url))])])}}],null,!1,1795190281)}):e._e()],1)},i=[],o=(t("b0c0"),{data:function(){return{action_url:"/api/v1/example/uploadFile",image_info:[],num:0}},methods:{handleChange:function(e){var a=e.file.status;if("uploading"!==a&&console.log(e.file),"done"===a){var t=e.file.response;if(console.log("uploadRes:",t),"success"!==t.code)return this.$message.error("file upload failed ".concat(t.code," .")),!1;this.num++;var l=t.data;l.id=this.num,l.imageUrlText="image url",this.image_info.push(l),this.$message.success("".concat(e.file.name," file uploaded successfully."))}else"error"===a&&this.$message.error("".concat(e.file.name," file upload failed."))}}}),n=o,s=t("2877"),r=Object(s["a"])(n,l,i,!1,null,null,null);a["default"]=r.exports}}]);
+//# sourceMappingURL=chunk-2d21dff5.42546cd8.js.map

文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-2d21dff5.42546cd8.js.map


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-707f4980.46929655.js


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-707f4980.46929655.js.map


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-85272794.640722ac.js


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-85272794.640722ac.js.map


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-85272794.a366dbbc.js


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-85272794.a366dbbc.js.map


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-ef3e31dc.31aef086.js


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-ef3e31dc.31aef086.js.map


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-ef3e31dc.3818e3b8.js


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-ef3e31dc.3818e3b8.js.map


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-vendors.3d275796.js.map


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-vendors.9d7d716c.js


文件差异内容过多而无法显示
+ 0 - 0
app/public/js/chunk-vendors.9d7d716c.js.map


+ 1 - 1
app/view/index.ejs

@@ -1 +1 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>electron-egg</title><link href="/css/chunk-85272794.56abef7d.css" rel="prefetch"><link href="/js/chunk-0facd6c5.d60d4450.js" rel="prefetch"><link href="/js/chunk-23265f79.cf6a544a.js" rel="prefetch"><link href="/js/chunk-85272794.a366dbbc.js" rel="prefetch"><link href="/js/chunk-ef3e31dc.31aef086.js" rel="prefetch"><link href="/css/app.3886a9b8.css" rel="preload" as="style"><link href="/css/chunk-vendors.a1538f74.css" rel="preload" as="style"><link href="/js/app.b6046f35.js" rel="preload" as="script"><link href="/js/chunk-vendors.3d275796.js" rel="preload" as="script"><link href="/css/chunk-vendors.a1538f74.css" rel="stylesheet"><link href="/css/app.3886a9b8.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but electron-egg doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/js/chunk-vendors.3d275796.js"></script><script src="/js/app.b6046f35.js"></script></body></html>
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>electron-egg</title><link href="/css/chunk-85272794.56abef7d.css" rel="prefetch"><link href="/js/chunk-23265f79.d92214d0.js" rel="prefetch"><link href="/js/chunk-2d21dff5.42546cd8.js" rel="prefetch"><link href="/js/chunk-707f4980.46929655.js" rel="prefetch"><link href="/js/chunk-85272794.640722ac.js" rel="prefetch"><link href="/js/chunk-ef3e31dc.3818e3b8.js" rel="prefetch"><link href="/css/app.c79dd55d.css" rel="preload" as="style"><link href="/css/chunk-vendors.a1538f74.css" rel="preload" as="style"><link href="/js/app.888a1909.js" rel="preload" as="script"><link href="/js/chunk-vendors.9d7d716c.js" rel="preload" as="script"><link href="/css/chunk-vendors.a1538f74.css" rel="stylesheet"><link href="/css/app.c79dd55d.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but electron-egg doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/js/chunk-vendors.9d7d716c.js"></script><script src="/js/app.888a1909.js"></script></body></html>

+ 16 - 0
appveyor.yml

@@ -0,0 +1,16 @@
+environment:
+  matrix:
+    - nodejs_version: '8'
+    - nodejs_version: '10'
+    - nodejs_version: '12'
+
+install:
+  - ps: Install-Product node $env:nodejs_version
+  - npm i npminstall && node_modules\.bin\npminstall
+
+test_script:
+  - node --version
+  - npm --version
+  - npm run test
+
+build: off

+ 3 - 6
electron/apis/example.js

@@ -29,12 +29,9 @@ exports.executeJS = function (str) {
   return webContents.fromId(1).executeJavaScript(jscode);
 }
 
-exports.setShortcut = function (shortcutStr = "") {
-  if (!shortcutStr || shortcutStr == "") {
-    return false;
-  }
-  shortcut.register(shortcutStr, true, function (){
-    MAIN_WINDOW.show()
+exports.setShortcut = function (shortcutObj) {
+  shortcut.register(shortcutObj, true, function (){
+    MAIN_WINDOW.hide()
   });
   
   return true;

+ 10 - 27
electron/lib/shortcut.js

@@ -3,31 +3,22 @@
 const { globalShortcut } = require('electron');
 const storage = require('./storage');
 
-const shortcutList = {
-  'CommandOrControl+Shift+s': 'showWindow',
-  'CommandOrControl+Shift+h': 'hideWindow',
-}
-
 exports.setup = function () {
   // default
-  //const preferences = storage.getPreferences();
-  // const shortcuts = preferences.hasOwnProperty('shortcuts') ? preferences.shortcuts : {};
-  // storage.setShortcuts(shortcuts);
-
-  // for (let key in shortcuts) {
-  //   const fn = this.shortcuts[key]();
-  //   console.log(fn.toString());
-  //   this.register(key, fn);
-  // }
+  storage.iniPreferences();
 }
 
-exports.register = function (cmd, force = true, fn) {
-  const isRegistered = this.isRegistered(cmd);
-  console.log('[shortcut] [register] cmd:', [cmd, isRegistered]);
+exports.register = function (shortcutObj, force = true, fn) {
+  if (!shortcutObj['id'] || !shortcutObj['name'] || !shortcutObj['cmd']) {
+    return false;
+  }
+  const isRegistered = this.isRegistered(shortcutObj['cmd']);
+  console.log('[shortcut] [register] cmd:', [shortcutObj['cmd'], isRegistered]);
   if (isRegistered && !force) {
-    return;
+    return false;
   }
-  globalShortcut.register(cmd, fn)
+  storage.setShortcuts(shortcutObj);
+  globalShortcut.register(shortcutObj['cmd'], fn)
 }
 
 exports.isRegistered = function (cmd) {
@@ -38,12 +29,4 @@ exports.unregister = function (cmd) {
   globalShortcut.unregister(cmd)
 }
 
-// function showWindow () {
-//   MAIN_WINDOW.show()
-// }
-
-// function hideWindow () {
-//   MAIN_WINDOW.hide()
-// }
-
 exports = module.exports;

+ 38 - 5
electron/lib/storage.js

@@ -10,6 +10,7 @@ const storageKey = require('../../app/const/storageKey');
 const os = require('os');
 const pkg = require('../../package.json');
 const storageDb = 'db.json';
+const _ = require('lodash');
 
 exports.setup = function () {
   const storageDir = this.getStorageDir();
@@ -83,7 +84,7 @@ exports.getStorageDir = function () {
   return storageDir;
 }
 
-exports.getPreferences = function () {
+exports.iniPreferences = function () {
   const key = storageKey.PREFERENCES;
   if (!this.instance().has(key).value()) {
     this.instance().set(key, {}).write();
@@ -97,11 +98,43 @@ exports.getPreferences = function () {
 
 exports.setShortcuts = function (data) {
   const key = storageKey.PREFERENCES + '.shortcuts';
-  const res = this.instance()
-  .set(key, data)
-  .write();
+  if (!this.instance().has(key).value()) {
+    this.instance().set(key, []).write();
+  }
+  const item = this.instance().get(key).find({id: data.id}).value();
+  if (_.isEmpty(item)) {
+    this.instance()
+    .get(key)
+    .push(data)
+    .write();
+  } else {
+    this.instance()
+    .get(key)
+    .find({id: data.id})
+    .assign(data)
+    .write();
+  }
+  // const count = this.instance()
+  // .get(key)
+  // .filter(function(o) {
+  //   let isHas = false;
+  //   if (o.cmd == data.cmd) {
+  //     isHas = true;
+  //   }
+  //   return isHas;
+  // })
+  // .size()
+  // .value();
+  // if (count > 0) {
+  //   return false;
+  // }
+
+  // this.instance()
+  // .get(key)
+  // .push(data)
+  // .write();
 
-  return res;
+  return true;
 };
 
 exports = module.exports;

+ 59 - 0
frontend/.eslintrc.js

@@ -0,0 +1,59 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true
+  },
+  'extends': [],
+  rules: {
+    //"parser": "vue-eslint-parser",
+    'no-console': 'off',
+    "no-unused-vars":"off", //重要 var 变量为引入
+    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
+    'generator-star-spacing': 'off',
+    'no-mixed-operators': 0,
+    // 'vue/max-attributes-per-line': [
+    //   2,
+    //   {
+    //     'singleline': 5,
+    //     'multiline': {
+    //       'max': 1,
+    //       'allowFirstLine': false
+    //     }
+    //   }
+    // ],
+    'vue/attribute-hyphenation': 0,
+    'vue/html-self-closing': 0,
+    'vue/component-name-in-template-casing': 0,
+    'vue/html-closing-bracket-spacing': 0,
+    'vue/singleline-html-element-content-newline': 0,
+    'vue/no-unused-components': 0,
+    'vue/multiline-html-element-content-newline': 0,
+    'vue/no-use-v-if-with-v-for': 0,
+    'vue/html-closing-bracket-newline': 0,
+    'vue/no-parsing-error': 0,
+    'no-tabs': 0,
+    'quotes': 0,
+    'semi': 0,
+    'no-delete-var': 2,
+    'prefer-const': 0,
+    'template-curly-spacing': 'off',
+    //'indent': 'off',
+    'indent': ["off", 2]
+  },
+  parserOptions: {
+    ecmaVersion: 2015,
+    "sourceType": "module"
+  },
+  "parser": "vue-eslint-parser",
+  overrides: [
+    {
+      files: [
+        '**/__tests__/*.{j,t}s?(x)',
+        '**/tests/unit/**/*.spec.{j,t}s?(x)'
+      ],
+      env: {
+        jest: true
+      }
+    }
+  ]
+}

+ 1 - 1
frontend/src/main.js

@@ -5,7 +5,7 @@ import App from './App'
 import router from './router'
 import { VueAxios } from './utils/request'
 import InjectIpc from '@/utils/injectIpc'
-import HotKeyInput from '@/utils/shortcut/lib/index.min.js'
+import HotKeyInput from '@/utils/shortcut/index.js'
 
 Vue.use(antd)
 // mount axios to `Vue.$http` and `this.$http`

+ 0 - 0
frontend/src/utils/shortcut/hot-key-input/codeMap.js


+ 10 - 0
frontend/src/utils/shortcut/hot-key-input/index.js

@@ -0,0 +1,10 @@
+// 导入组件,组件必须声明 name
+import myComponent from './index.vue'
+
+// 为组件提供 install 安装方法,供按需引入
+myComponent.install = function (Vue) {
+  Vue.component(myComponent.name, myComponent)
+}
+
+// 默认导出组件
+export default myComponent

+ 150 - 89
frontend/src/components/hotkeyInput.vue → frontend/src/utils/shortcut/hot-key-input/index.vue

@@ -1,32 +1,29 @@
 <template>
   <div
-    class="shortcut-key-input"
-    :class="{ cursor: focus }"
+    class="hot-key-input-component"
+    :class="{ cursor: focus, 'hot-key-input-shark': isShark }"
     :style="$props.style"
     tabindex="0"
     @focus="handleFocus"
     @blur="focus = false"
-    @keydown="handleKeydown"
+    @keydown.prevent="handleKeydown"
+    :placeholder="list.length ? '' : placeholder"
   >
-    <template v-if="list.length">
-      <template v-for="(item, index) in list">
-        <span :key="`${item.text}_${index}`"
-          >{{ item.text }} <i @click="handleDeleteKey(index)"></i
-        ></span>
-      </template>
-    </template>
-    <div v-else class="placeholder">{{ placeholder }}</div>
+    <div class="hot-item" v-for="(item, index) in list" :key="index">
+      <span class="hot-text">{{ formatItemText(item.text) }} </span>
+      <i class="icon-close" @click="handleDeleteKey(index)"></i>
+    </div>
   </div>
 </template>
 
 <script>
-const CODE_NUMBER = Array.from({ length: 10 }, (v, k) => `Digit${k + 1}`);
-const CODE_NUMPAD = Array.from({ length: 10 }, (v, k) => `Numpad${k + 1}`);
+const CODE_NUMBER = Array.from({ length: 10 }, (v, k) => `Digit${k + 1}`)
+const CODE_NUMPAD = Array.from({ length: 10 }, (v, k) => `Numpad${k + 1}`)
 const CODE_ABC = Array.from(
   { length: 26 },
   (v, k) => `Key${String.fromCharCode(k + 65).toUpperCase()}`
-);
-const CODE_FN = Array.from({ length: 12 }, (v, k) => `F${k + 1}`);
+)
+const CODE_FN = Array.from({ length: 12 }, (v, k) => `F${k + 1}`)
 const CODE_CONTROL = [
   "Shift",
   "ShiftLeft",
@@ -37,15 +34,20 @@ const CODE_CONTROL = [
   "Alt",
   "AltLeft",
   "AltRight",
-]; // ShiftKey Control(Ctrl) Alt
+] // ShiftKey Control(Ctrl) Alt
 
 export default {
   name: "HotKeyInput",
   props: {
+    type: {
+      type: String,
+      // lowser upper
+      default: ()=> 'defalut'
+    },
     // 默认绑定值
     // 传入 ['Ctrl+d'] 格式时会自动处理成 [{ text: 'Ctrl+d', controlKey: { altKey: false, ctrlKey: true, shiftKey: false, key: 'd', code: 'KeyD } }]
     hotkey: {
-      type: Array,
+      type: Array | Object,
       required: true,
     },
     // 校验函数 判断是否允许显示快捷键
@@ -63,6 +65,15 @@ export default {
       type: [String, Number],
       default: 0,
     },
+    // 当max时,再次输入快捷键 - true: 清空后输入,false:无操作
+    reset: {
+      type: Boolean,
+      default: false,
+    },
+    shake: {
+      type: Boolean,
+      default: true,
+    },
     // 快捷键使用范围
     range: {
       type: Array,
@@ -71,17 +82,30 @@ export default {
   },
   data() {
     return {
+      isShark: false,
       focus: false,
-      list: this.hotkey,
+      hotkeyBackups: this.hotkey || '' ,
+      list: [],
       keyRange: [],
-    };
+    }
   },
   watch: {
     list: function (list) {
-      if (list.length) this.focus = false;
-      this.$emit("update:hotkey", this.list);
+      list.length ? (this.focus = false) : (this.focus = true)
+      // .sync修饰符
+      this.$emit(
+        "update:hotkey",
+        this.list.map((item) => {
+          return this.formatItemText(item.text)
+          // if(item.text && this.type != 'default'){
+          //   return this.type == 'lowser' ? item.text.toLowerCase():item.text.toUpperCase()
+          // }
+          // return item.text
+        })
+      )
     },
-    hotkey: {
+    
+    hotkeyBackups: {
       handler: function (val) {
         if (!val.length) return;
         const list = [];
@@ -110,70 +134,101 @@ export default {
     },
     range: {
       handler: function (val) {
+        if(val === null){
+          this.keyRange = null
+          return
+        }
         const keyRangeList = {
           NUMBER: CODE_NUMBER,
           NUMPAD: CODE_NUMPAD,
           ABC: CODE_ABC,
           FN: CODE_FN,
-        };
+        }
         val.forEach((item) => {
           this.keyRange = this.keyRange.concat(
             keyRangeList[item.toUpperCase()]
-          );
-        });
+          )
+        })
       },
       immediate: true,
     },
   },
   methods: {
+    formatItemText(text){
+      if(text && this.type != 'default'){
+        return this.type == 'lowser' ? text.toLowerCase() : text.toUpperCase()
+      }
+      return text
+    },
     handleFocus() {
-      if (!this.list.length) this.focus = true;
+      if (!this.list.length) this.focus = true
     },
     handleDeleteKey(index) {
-      this.list.splice(index, 1);
+      this.list.splice(index, 1)
     },
     handleKeydown(e) {
-      const { altKey, ctrlKey, shiftKey, key, code } = e;
+      console.log('e: ',e)
+      e.preventDefault()
+      e.stopPropagation()
+      const { altKey, ctrlKey, shiftKey, key, code } = e
       if (!CODE_CONTROL.includes(key)) {
-        if (!this.keyRange.includes(code)) return;
-        let controlKey = "";
-        [
+        if (this.keyRange !== null && !this.keyRange.includes(code)){
+          this.shakeAction()
+          return
+        }
+        let controlKey = ''
+        let temps = [
           { key: altKey, text: "Alt" },
           { key: ctrlKey, text: "Ctrl" },
           { key: shiftKey, text: "Shift" },
-        ].forEach((curKey) => {
+        ]
+        temps.forEach((curKey) => {
           if (curKey.key) {
-            if (controlKey) controlKey += "+";
-            controlKey += curKey.text;
+            if (controlKey) controlKey += "+"
+            controlKey += curKey.text
           }
-        });
+        })
         if (key) {
-          if (controlKey) controlKey += "+";
-          controlKey += key.toUpperCase();
+          if (controlKey) controlKey += "+"
+          controlKey += key.toUpperCase()
         }
         this.addHotkey({
           text: controlKey,
           controlKey: { altKey, ctrlKey, shiftKey, key, code },
-        });
+        })
       }
-      e.preventDefault();
     },
     addHotkey(data) {
-      if (this.list.length && this.list.some((item) => data.text === item.text))
-        return;
-      if (
-        this.list.length &&
-        this.list.length.toString() === this.max.toString()
-      )
-        return;
-      if (!this.verify(data)) return;
-      this.list.push(data);
+      if (this.list.length) {
+        if (this.list.length.toString() >= this.max.toString()) {
+          if (this.reset) {
+            this.list = []
+          } else {
+            return
+          }
+        } else if (this.list.some((item) => data.text === item.text)) {
+          this.shakeAction()
+          return
+        }
+      }
+      if (!this.verify(data)) {
+        this.shakeAction()
+        return
+      }
+      this.list.push(data)
     },
+    shakeAction(){
+      if(this.shake){
+            this.isShark = true
+            setTimeout(()=>{
+              this.isShark = false
+            }, 800)
+          }
+    }
   },
-};
+}
 </script>
-
-<style scoped>
+<style lang="less">
 @keyframes Blink {
   0% {
     opacity: 0;
@@ -183,62 +238,68 @@ export default {
   }
 }
 
-.shortcut-key-input {
-  position: relative;
+@keyframes hot-key-input-shake {
+  0% {
+    transform: scale(1);
+  }
+  10%,
+  20% {
+    transform: scale(0.9) rotate(-1deg);
+  }
+  30%,
+  50%,
+  70%,
+  90% {
+    transform: scale(1.1) rotate(1deg);
+  }
+  40%,
+  60%,
+  80% {
+    transform: scale(1.1) rotate(-1deg);
+  }
+  100% {
+    transform: scale(1) rotate(0);
+  }
+}
+
+.hot-key-input-shark {
+  animation: hot-key-input-shake 0.8s 1 ease-in;
+}
+
+.hot-key-input-component {
+  display: flex;
+  padding: 5px;
   border: 1px solid #dcdcdc;
-  border-radius: 4px;
   background-color: #fff;
   color: #333;
-  width: 100%;
-  height: 40px;
-  padding: 2px 0;
   cursor: text;
   transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
 }
 
-.shortcut-key-input:focus {
-  border-color: #188cff;
-  box-shadow: 0 0 4px rgba(24, 140, 255, 0.38);
+.hot-key-input-component:before {
+  content: attr(placeholder);
+  color: #afafaf;
 }
 
-.shortcut-key-input.cursor::after {
+.hot-key-input-component.cursor::after {
   content: "|";
   animation: Blink 1.2s ease 0s infinite;
-  font-size: 18px;
   position: absolute;
-  top: 7px;
-  left: 8px;
+  left: 10px;
 }
 
-.shortcut-key-input span {
-  position: relative;
-  display: inline-block;
-  box-sizing: border-box;
+.hot-item {
+  display: flex;
+  align-items: center;
   background-color: #f4f4f5;
   border-color: #e9e9eb;
   color: #909399;
-  padding: 0 22px 0 8px;
-  height: 28px;
-  font-size: 13px;
-  line-height: 28px;
-  border-radius: 4px;
-  margin: 5px;
+  padding: 0 5px;
+  margin-right: 5px;
 }
 
-.shortcut-key-input .placeholder {
-  position: absolute;
-  top: 12px;
-  left: 11px;
-  color: #c0c4cc;
-  font-size: 13px;
-  text-indent: 4px;
-  font: 400 13.3333px Arial;
-}
-
-.shortcut-key-input span i {
-  position: absolute;
-  top: 6px;
-  right: 4px;
+.hot-key-input-component .hot-item .icon-close {
+  display: block;
   content: "";
   background: url("data:image/svg+xml,%3Csvg class='icon' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cpath d='M512 64C264.58 64 64 264.58 64 512s200.58 448 448 448 448-200.58 448-448S759.42 64 512 64zm0 832c-212.08 0-384-171.92-384-384s171.92-384 384-384 384 171.92 384 384-171.92 384-384 384z' fill='%23909399'/%3E%3Cpath d='M625.14 353.61L512 466.75 398.86 353.61a32 32 0 0 0-45.25 45.25L466.75 512 353.61 625.14a32 32 0 0 0 45.25 45.25L512 557.25l113.14 113.14a32 32 0 0 0 45.25-45.25L557.25 512l113.14-113.14a32 32 0 0 0-45.25-45.25z' fill='%23909399'/%3E%3C/svg%3E")
     no-repeat center;
@@ -249,7 +310,7 @@ export default {
   opacity: 0.6;
 }
 
-.shortcut-key-input span i:hover {
+.hot-key-input-component .hot-item .icon-close:hover {
   cursor: pointer;
   opacity: 1;
 }

+ 27 - 0
frontend/src/utils/shortcut/index.js

@@ -0,0 +1,27 @@
+// 导入颜色选择器组件
+import HotKeyInput from './hot-key-input'
+
+// 存储组件列表
+const components = [
+  HotKeyInput
+]
+
+// 定义 install 方法,接收 Vue 作为参数。如果使用 use 注册插件,则所有的组件都将被注册
+const install = function (Vue) {
+  // 判断是否安装
+  if (install.installed) return
+  // 遍历注册全局组件
+  components.map(component => Vue.component(component.name, component))
+}
+
+// 判断是否是直接引入文件
+if (typeof window !== 'undefined' && window.Vue) {
+  install(window.Vue)
+}
+
+export default {
+  // 导出的对象必须具有 install,才能被 Vue.use() 方法安装
+  install,
+  // 以下是具体的组件列表
+  HotKeyInput
+}

文件差异内容过多而无法显示
+ 0 - 0
frontend/src/utils/shortcut/lib/index.min.js


文件差异内容过多而无法显示
+ 0 - 0
frontend/src/utils/shortcut/lib/index.min.js.map


+ 6 - 3
frontend/src/views/example/Shortcut.vue

@@ -42,7 +42,7 @@ export default {
       cmd: '',
       hotKeyObj: {
         tab: 'save',
-        keys: ["Ctrl+q"]
+        keys: ['Ctrl+k']
       },
     };
   },
@@ -56,13 +56,16 @@ export default {
       console.log('submit 验证:', this.hotKeyObj)
       const shortcutStr = this.hotKeyObj.keys[0];
       const params = {
-        'shortcutStr': shortcutStr
+        id: 'mini_window',
+        name: '窗口最小化',
+        cmd: shortcutStr
       }
       localApi('setShortcut', params).then(res => {
         if (res.code !== 0) {
+          // this.$message.info('error')
           return false
         }
-        this.autoLaunchChecked = res.data.isEnabled;
+        this.$message.info('设置成功,请按【设置的快捷键】查看效果')
       }).catch(err => {
         console.log('err:', err)
       })

+ 2 - 2
package.json

@@ -1,6 +1,6 @@
 {
   "name": "electron-egg",
-  "version": "1.9.4",
+  "version": "1.10.0",
   "description": "A fast, desktop software development framework",
   "main": "main.js",
   "softName": "electron-egg",
@@ -100,7 +100,7 @@
     "egg-ci": "^1.11.0",
     "egg-mock": "^3.21.0",
     "electron": "^12.0.10",
-    "electron-builder": "^22.7.0",
+    "electron-builder": "22.7.0",
     "eslint": "^5.13.0",
     "eslint-config-egg": "^7.1.0",
     "eslint-plugin-prettier": "^3.0.1",

部分文件因为文件数量过多而无法显示