Browse Source

签名组件

刘洋 1 year ago
parent
commit
2a7f1abb89

+ 2 - 0
package.json

@@ -19,6 +19,7 @@
     "lint:stylelint": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/"
   },
   "dependencies": {
+    "@chenfengyuan/vue-qrcode": "^2.0.0",
     "@tinymce/tinymce-vue": "^5.1.1",
     "@vueuse/core": "^9.13.0",
     "autoprefixer": "^10.4.14",
@@ -34,6 +35,7 @@
     "nprogress": "^0.2.0",
     "pinia": "^2.0.27",
     "pinia-plugin-persistedstate": "^3.2.0",
+    "qrcode": "^1.5.3",
     "qs": "^6.11.2",
     "spark-md5": "^3.0.2",
     "tdesign-vue-next": "^1.5.1",

+ 5 - 0
src/api/user.js

@@ -153,3 +153,8 @@ export const getAttachmentList = (ids) =>
     url: '/api/admin/common/file/preview',
     data: ids,
   });
+export const getAttachmentListByKey = (key) =>
+  request({
+    url: '/api/admin/common/file/preview/app',
+    params: { key },
+  });

+ 3 - 2
src/views/login/forget-pwd.vue

@@ -37,6 +37,7 @@
             style="width: 110px"
             :loading="loading"
             @click="getCode"
+            :disabled="isActive"
             >{{ isActive ? lastSeconds + 's' : '获取验证码' }}</t-button
           >
         </div>
@@ -99,9 +100,10 @@ const form = ref();
 const { run, loading } = useRequest(getVerifyCode, {
   onSuccess: () => {
     MessagePlugin.success('验证码已发送');
+    resume();
   },
 });
-const lastSeconds = ref(10);
+const lastSeconds = ref(60);
 const countdown = () => {
   if (lastSeconds.value == 0) {
     pause();
@@ -124,7 +126,6 @@ const getCode = () => {
   run({
     mobileNumber: formData.mobileNumber,
   });
-  // resume();
 };
 const formData = reactive({
   mobileNumber: '',

+ 3 - 1
src/views/login/index.vue

@@ -108,6 +108,7 @@
                 class="m-l-20px"
                 style="width: 110px"
                 :loading="loading"
+                :disabled="isActive"
                 @click="getCode"
                 >{{ isActive ? lastSeconds + 's' : '获取验证码' }}</t-button
               >
@@ -153,9 +154,10 @@ import { useIntervalFn } from '@vueuse/core';
 const { run, loading } = useRequest(getVerifyCode, {
   onSuccess: () => {
     MessagePlugin.success('验证码已发送');
+    resume();
   },
 });
-const lastSeconds = ref(10);
+const lastSeconds = ref(60);
 const countdown = () => {
   if (lastSeconds.value == 0) {
     pause();

+ 51 - 84
src/views/sop/components/dynamic-form-item/SIGN.vue

@@ -1,14 +1,29 @@
 <template>
-  <div :class="['sign-box', { 'is-disabled': disabled }]">
-    <div v-if="!disabled">
-      <t-button size="small" @click="clear">清除</t-button>
-    </div>
-    <canvas ref="canvasRef" width="600" height="300"></canvas>
+  <div class="sign-box">
+    <img class="sign-result-img" v-if="valueData" />
+    <t-popup trigger="click" v-else>
+      <template #triggerElement>
+        <t-button>添加签名</t-button>
+      </template>
+      <template #content>
+        <vue-qrcode
+          :value="createQrcodeValue"
+          :options="{ width: 200 }"
+        ></vue-qrcode>
+      </template>
+    </t-popup>
   </div>
 </template>
 
 <script setup name="SIGN">
-import { computed, onMounted, ref, watch } from 'vue';
+import { computed, onMounted, ref, watch, onBeforeUnmount } from 'vue';
+import VueQrcode from '@chenfengyuan/vue-qrcode';
+import { useUserStore } from '@/store';
+import { useIntervalFn } from '@vueuse/core';
+import { getAttachmentListByKey } from '@/api/user';
+const key = ref('');
+
+const userStore = useUserStore();
 const props = defineProps({
   config: { type: Object },
   modelValue: { type: String },
@@ -16,102 +31,54 @@ const props = defineProps({
 const emit = defineEmits(['update:modelValue', 'change']);
 
 const valueData = ref('');
-const canvasRef = ref(null);
-
-const disabled = computed(() => {
-  return !props.config?.writable;
-});
-
-const emitChange = () => {
-  emit('update:modelValue', valueData.value);
-  emit('change', valueData.value);
-};
-
-const initCanvas = () => {
-  const ctx = canvasRef.value.getContext('2d');
-  let isDrawing = false;
-  canvasRef.value.addEventListener('mousedown', (e) => {
-    isDrawing = true;
-    ctx.moveTo(e.offsetX, e.offsetY);
-  });
-  canvasRef.value.addEventListener('mousemove', (e) => {
-    if (isDrawing) {
-      ctx.lineTo(e.offsetX, e.offsetY);
-      ctx.lineWidth = 1;
-      // ctx.strokeStyle = '#000';
-      ctx.stroke();
+const getSignResultImg = () => {
+  getAttachmentListByKey(key.value).then((res) => {
+    if (res && res?.url) {
+      valueData.value = res.url;
+      emitChange();
+      pause();
     }
   });
-  canvasRef.value.addEventListener('mouseup', (e) => {
-    isDrawing = false;
-
-    valueData.value = canvasRef.value.toDataURL();
-    emitChange();
-  });
-};
-
-const clear = () => {
-  canvasRef.value.width = canvasRef.value.width;
-  canvasRef.value.height = canvasRef.value.height;
-  valueData.value = '';
-  emitChange();
-};
-
-const drawImg = () => {
-  if (!valueData.value) return;
-
-  const img = new Image();
-  img.onload = function () {
-    const ctx = canvasRef.value.getContext('2d');
-    ctx.drawImage(img, 0, 0);
-  };
-  img.onerror = function (e) {
-    reject(e);
-  };
-  img.src = valueData.value;
 };
-
+const { pause, resume, isActive } = useIntervalFn(
+  () => {
+    getSignResultImg();
+  },
+  3000,
+  { immediate: false }
+);
+onBeforeUnmount(() => {
+  pause();
+});
 onMounted(() => {
-  if (disabled.value) return;
-  initCanvas();
+  key.value = userStore.user?.id + '_' + new Date().getTime();
+  valueData.value = props.modelValue;
+  if (!valueData.value) {
+    resume();
+  }
 });
-
+const emitChange = () => {
+  emit('update:modelValue', valueData.value);
+  emit('change', valueData.value);
+};
 watch(
   () => props.modelValue,
   (val, oldval) => {
-    if (val === oldval) return;
     valueData.value = val;
-
-    if (val) {
-      drawImg();
-    }
   },
   {
     immediate: true,
   }
 );
+const createQrcodeValue = computed(() => {
+  return location.origin + '/sign?key=' + key.value;
+});
 </script>
 
 <style lang="less" scoped>
 .sign-box {
-  position: relative;
-  > canvas {
-    box-shadow: 0 0 1px #333;
-    margin-top: 10px;
-  }
-
-  &.is-disabled {
-    &::after {
-      cursor: not-allowed;
-      display: block;
-      content: '';
-      position: absolute;
-      top: 0;
-      left: 0;
-      right: 0;
-      bottom: 0;
-      z-index: 99;
-    }
+  .sign-result-img {
+    height: 80px;
   }
 }
 </style>

+ 117 - 0
src/views/sop/components/dynamic-form-item/SIGN_PC.vue

@@ -0,0 +1,117 @@
+<template>
+  <div :class="['sign-box', { 'is-disabled': disabled }]">
+    <div v-if="!disabled">
+      <t-button size="small" @click="clear">清除</t-button>
+    </div>
+    <canvas ref="canvasRef" width="600" height="300"></canvas>
+  </div>
+</template>
+
+<script setup name="SIGNPC">
+import { computed, onMounted, ref, watch } from 'vue';
+const props = defineProps({
+  config: { type: Object },
+  modelValue: { type: String },
+});
+const emit = defineEmits(['update:modelValue', 'change']);
+
+const valueData = ref('');
+const canvasRef = ref(null);
+
+const disabled = computed(() => {
+  return !props.config?.writable;
+});
+
+const emitChange = () => {
+  emit('update:modelValue', valueData.value);
+  emit('change', valueData.value);
+};
+
+const initCanvas = () => {
+  const ctx = canvasRef.value.getContext('2d');
+  let isDrawing = false;
+  canvasRef.value.addEventListener('mousedown', (e) => {
+    isDrawing = true;
+    ctx.moveTo(e.offsetX, e.offsetY);
+  });
+  canvasRef.value.addEventListener('mousemove', (e) => {
+    if (isDrawing) {
+      ctx.lineTo(e.offsetX, e.offsetY);
+      ctx.lineWidth = 1;
+      // ctx.strokeStyle = '#000';
+      ctx.stroke();
+    }
+  });
+  canvasRef.value.addEventListener('mouseup', (e) => {
+    isDrawing = false;
+
+    valueData.value = canvasRef.value.toDataURL();
+    emitChange();
+  });
+};
+
+const clear = () => {
+  canvasRef.value.width = canvasRef.value.width;
+  canvasRef.value.height = canvasRef.value.height;
+  valueData.value = '';
+  emitChange();
+};
+
+const drawImg = () => {
+  if (!valueData.value) return;
+
+  const img = new Image();
+  img.onload = function () {
+    const ctx = canvasRef.value.getContext('2d');
+    ctx.drawImage(img, 0, 0);
+  };
+  img.onerror = function (e) {
+    reject(e);
+  };
+  img.src = valueData.value;
+};
+
+onMounted(() => {
+  if (disabled.value) return;
+  initCanvas();
+});
+
+watch(
+  () => props.modelValue,
+  (val, oldval) => {
+    if (val === oldval) return;
+    valueData.value = val;
+
+    if (val) {
+      drawImg();
+    }
+  },
+  {
+    immediate: true,
+  }
+);
+</script>
+
+<style lang="less" scoped>
+.sign-box {
+  position: relative;
+  > canvas {
+    box-shadow: 0 0 1px #333;
+    margin-top: 10px;
+  }
+
+  &.is-disabled {
+    &::after {
+      cursor: not-allowed;
+      display: block;
+      content: '';
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      z-index: 99;
+    }
+  }
+}
+</style>