gaoshuaixing 4 tahun lalu
induk
melakukan
35dfbcb563

+ 256 - 0
frontend/src/components/hotkeyInput.vue

@@ -0,0 +1,256 @@
+<template>
+  <div
+    class="shortcut-key-input"
+    :class="{ cursor: focus }"
+    :style="$props.style"
+    tabindex="0"
+    @focus="handleFocus"
+    @blur="focus = false"
+    @keydown="handleKeydown"
+  >
+    <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>
+</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_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_CONTROL = [
+  "Shift",
+  "ShiftLeft",
+  "ShiftRight",
+  "Control",
+  "ControlLeft",
+  "ControlRight",
+  "Alt",
+  "AltLeft",
+  "AltRight",
+]; // ShiftKey Control(Ctrl) Alt
+
+export default {
+  name: "HotKeyInput",
+  props: {
+    // 默认绑定值
+    // 传入 ['Ctrl+d'] 格式时会自动处理成 [{ text: 'Ctrl+d', controlKey: { altKey: false, ctrlKey: true, shiftKey: false, key: 'd', code: 'KeyD } }]
+    hotkey: {
+      type: Array,
+      required: true,
+    },
+    // 校验函数 判断是否允许显示快捷键
+    verify: {
+      type: Function,
+      default: () => true,
+    },
+    // 无绑定时提示文字
+    placeholder: {
+      type: String,
+      default: "",
+    },
+    // 限制最大数量
+    max: {
+      type: [String, Number],
+      default: 0,
+    },
+    // 快捷键使用范围
+    range: {
+      type: Array,
+      default: () => ["NUMBER", "NUMPAD", "ABC", "FN"],
+    },
+  },
+  data() {
+    return {
+      focus: false,
+      list: this.hotkey,
+      keyRange: [],
+    };
+  },
+  watch: {
+    list: function (list) {
+      if (list.length) this.focus = false;
+      this.$emit("update:hotkey", this.list);
+    },
+    hotkey: {
+      handler: function (val) {
+        if (!val.length) return;
+        const list = [];
+        val.forEach((item) => {
+          const arr = item.split("+");
+          const controlKey = {
+            altKey: arr.includes("Alt"),
+            ctrlKey: arr.includes("Control"),
+            shiftKey: arr.includes("Shift"),
+            key: arr[arr.length - 1],
+            code: `Key${arr[arr.length - 1].toUpperCase()}`,
+          };
+          list.push({
+            text: arr.reduce((text, item, i) => {
+              if (i) text += "+";
+              if (controlKey.key === item) text += item.toUpperCase();
+              else text += item;
+              return text;
+            }, ""),
+            controlKey,
+          });
+        });
+        this.list = list;
+      },
+      immediate: true,
+    },
+    range: {
+      handler: function (val) {
+        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: {
+    handleFocus() {
+      if (!this.list.length) this.focus = true;
+    },
+    handleDeleteKey(index) {
+      this.list.splice(index, 1);
+    },
+    handleKeydown(e) {
+      const { altKey, ctrlKey, shiftKey, key, code } = e;
+      if (!CODE_CONTROL.includes(key)) {
+        if (!this.keyRange.includes(code)) return;
+        let controlKey = "";
+        [
+          { key: altKey, text: "Alt" },
+          { key: ctrlKey, text: "Ctrl" },
+          { key: shiftKey, text: "Shift" },
+        ].forEach((curKey) => {
+          if (curKey.key) {
+            if (controlKey) controlKey += "+";
+            controlKey += curKey.text;
+          }
+        });
+        if (key) {
+          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);
+    },
+  },
+};
+</script>
+
+<style scoped>
+@keyframes Blink {
+  0% {
+    opacity: 0;
+  }
+  100% {
+    opacity: 1;
+  }
+}
+
+.shortcut-key-input {
+  position: relative;
+  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);
+}
+
+.shortcut-key-input.cursor::after {
+  content: "|";
+  animation: Blink 1.2s ease 0s infinite;
+  font-size: 18px;
+  position: absolute;
+  top: 7px;
+  left: 8px;
+}
+
+.shortcut-key-input span {
+  position: relative;
+  display: inline-block;
+  box-sizing: border-box;
+  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;
+}
+
+.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;
+  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;
+  background-size: contain;
+  width: 14px;
+  height: 14px;
+  transform: scale(0.9);
+  opacity: 0.6;
+}
+
+.shortcut-key-input span i:hover {
+  cursor: pointer;
+  opacity: 1;
+}
+</style>

+ 5 - 0
frontend/src/config/router.config.js

@@ -23,6 +23,11 @@ export const constantRouterMap = [
         component: () => import('@/views/example/Ipc')
       },
       {
+        path: 'shortcut',
+        name: 'Shortcut',
+        component: () => import('@/views/example/Shortcut')
+      },
+      {
         path: 'setting',
         name: 'Setting',
         component: () => import('@/views/Setting')

+ 5 - 0
frontend/src/views/Layout.vue

@@ -68,6 +68,11 @@ export default {
             title: '通信',
             pageName: 'Ipc',
             params: {},
+          },
+          'subMenu_4' : {
+            title: '快捷键',
+            pageName: 'Shortcut',
+            params: {},
           }
         },
         'menu_2' : {

+ 2 - 2
frontend/src/views/example/Ipc.vue

@@ -2,7 +2,7 @@
   <div>
     <div>
       <h3 :style="{ marginBottom: '16px' }">
-        demo3 渲染进程与主进程IPC通信
+        demo3-1 渲染进程与主进程IPC通信
       </h3>
       <a-list bordered>
         <!-- <a-button @click="helloHandle">打招呼</a-button> -->
@@ -15,7 +15,7 @@
     </div>
     <div style="margin-top: 20px;">
       <h3 :style="{ marginBottom: '16px' }">
-        demo4 主进程API执行网页函数
+        demo3-2 主进程API执行网页函数
       </h3>
       <a-list bordered>
         <a-input-search v-model="content2" @search="executeJSHandle">

+ 93 - 0
frontend/src/views/example/Shortcut.vue

@@ -0,0 +1,93 @@
+<template>
+  <div>
+    <h3 :style="{ marginBottom: '16px' }">
+      demo4 快捷键
+    </h3>
+    <a-row :gutter="[16,16]">
+      <a-col :span="12">
+        显示窗口
+        <!-- <HotkeyInput
+          :hotkey.sync="hotKeyObj.keys"
+          :verify="handleHotkeyVerify"
+          placeholder="请按需要绑定的按键,支持组合按键"
+        /> -->
+        <a-input-search
+          style="width: 272px;"
+          v-model="cmd"
+          @search="handleSetting"
+          placeholder="快捷键">
+          <a-button slot="enterButton">
+            保存
+          </a-button>
+        </a-input-search>
+      </a-col>
+      <a-col :span="12">
+        隐藏窗口
+        <a-input-search
+          style="width: 272px;"
+          v-model="cmd"
+          @search="handleSetting"
+          placeholder="快捷键">
+          <a-button slot="enterButton">
+            保存
+          </a-button>
+        </a-input-search>
+      </a-col>
+    </a-row>  
+    <a-row :gutter="[16,16]">
+      <a-col :span="12">
+        窗口最小化
+        <a-input-search
+          style="width: 272px;"
+          v-model="cmd"
+          @search="handleSetting"
+          placeholder="快捷键">
+          <a-button slot="enterButton">
+            保存
+          </a-button>
+        </a-input-search>
+      </a-col>
+      <a-col :span="12">
+        窗口还原
+        <a-input-search
+          style="width: 272px;"
+          v-model="cmd"
+          @search="handleSetting"
+          placeholder="快捷键">
+          <a-button slot="enterButton">
+            保存
+          </a-button>
+        </a-input-search>
+      </a-col>
+    </a-row>
+  </div>
+</template>
+<script>
+// import VHotkey from "v-hotkey";
+// import { openDir } from '@/api/main'
+
+export default {
+  components: {},
+  data() {
+    return {
+      cmd: '',
+      hotKeyObj: {
+        tab: 'save',
+        // keys: undefined
+        keys: ["Ctrl+A", "Alt+D"]
+      },
+    };
+  },
+  methods: {
+    handleSetting (value) {
+      console.log('cmd:', value)
+      //this.cmd = ''
+    },
+    handleHotkeyVerify(hotkey) {
+      console.log('验证:', hotkey, this.hotKeyObj)
+      return true;
+    },
+  }
+};
+</script>
+<style></style>