Browse Source

更新依赖

ZaiZai 6 months ago
parent
commit
1ee5af6c9c
27 changed files with 1233 additions and 428 deletions
  1. 7 7
      package.json
  2. 0 0
      public/plugins/element-plus/index.css
  3. 0 0
      public/plugins/element-plus/theme-chalk/el-color-picker.css
  4. 0 0
      public/plugins/element-plus/theme-chalk/el-date-picker.css
  5. 0 0
      public/plugins/element-plus/theme-chalk/el-drawer.css
  6. 0 0
      public/plugins/element-plus/theme-chalk/el-mention.css
  7. 0 0
      public/plugins/element-plus/theme-chalk/el-radio.css
  8. 0 0
      public/plugins/element-plus/theme-chalk/el-tabs.css
  9. 0 0
      public/plugins/element-plus/theme-chalk/el-upload.css
  10. 0 0
      public/plugins/element-plus/theme-chalk/index.css
  11. 5 0
      public/plugins/element-plus/theme-chalk/src/color-picker.scss
  12. 25 0
      public/plugins/element-plus/theme-chalk/src/common/var.scss
  13. 24 17
      public/plugins/element-plus/theme-chalk/src/date-picker/month-table.scss
  14. 41 12
      public/plugins/element-plus/theme-chalk/src/date-picker/year-table.scss
  15. 1 6
      public/plugins/element-plus/theme-chalk/src/drawer.scss
  16. 1 0
      public/plugins/element-plus/theme-chalk/src/index.scss
  17. 90 0
      public/plugins/element-plus/theme-chalk/src/mention.scss
  18. 1 1
      public/plugins/element-plus/theme-chalk/src/radio.scss
  19. 31 35
      public/plugins/element-plus/theme-chalk/src/tabs.scss
  20. 27 0
      public/plugins/element-plus/theme-chalk/src/upload.scss
  21. 0 0
      public/plugins/element-plus/v2.8.0
  22. 1 1
      public/version.json
  23. 472 0
      src/plugins/HcPdfSign-BAK.js
  24. 300 238
      src/plugins/HcPdfSign.js
  25. 97 0
      src/test/hc-pdf1.vue
  26. 10 20
      src/test/index.vue
  27. 100 91
      yarn.lock

+ 7 - 7
package.json

@@ -13,23 +13,23 @@
         "lint:fix": "eslint . --fix"
     },
     "dependencies": {
-        "axios": "^1.7.3",
+        "axios": "^1.7.4",
         "crypto-js": "^4.2.0",
         "dayjs": "^1.11.12",
         "echarts": "^5.5.1",
-        "element-plus": "^2.7.8",
-        "hc-vue3-ui": "^4.1.5",
+        "element-plus": "^2.8.0",
+        "hc-vue3-ui": "^4.1.6",
         "js-base64": "^3.7.7",
         "js-cookie": "^3.0.5",
         "js-fast-way": "^0.5.6",
         "js-md5": "^0.8.3",
         "js-web-screen-shot": "^1.9.9",
         "nprogress": "^0.2.0",
-        "pinia": "^2.2.1",
+        "pinia": "^2.2.2",
         "remixicon": "^4.3.0",
         "sortablejs": "^1.15.2",
         "split.js": "^1.6.5",
-        "vue": "3.4.36",
+        "vue": "3.4.38",
         "vue-router": "^4.4.3",
         "vue-virtual-scroll-list": "^2.3.5",
         "vue-virtual-scroller": "^2.0.0-beta.8",
@@ -38,7 +38,7 @@
     "devDependencies": {
         "@unocss/eslint-config": "0.58.9",
         "@vitejs/plugin-vue": "^5.1.2",
-        "@vue/compiler-sfc": "^3.4.36",
+        "@vue/compiler-sfc": "^3.4.38",
         "animate.css": "^4.1.1",
         "archiver": "^7.0.1",
         "autoprefixer": "^10.4.20",
@@ -47,6 +47,6 @@
         "sass": "^1.77.8",
         "unocss": "0.58.9",
         "unocss-preset-extra": "0.5.3",
-        "vite": "^5.3.5"
+        "vite": "^5.4.1"
     }
 }

File diff suppressed because it is too large
+ 0 - 0
public/plugins/element-plus/index.css


File diff suppressed because it is too large
+ 0 - 0
public/plugins/element-plus/theme-chalk/el-color-picker.css


File diff suppressed because it is too large
+ 0 - 0
public/plugins/element-plus/theme-chalk/el-date-picker.css


File diff suppressed because it is too large
+ 0 - 0
public/plugins/element-plus/theme-chalk/el-drawer.css


File diff suppressed because it is too large
+ 0 - 0
public/plugins/element-plus/theme-chalk/el-mention.css


File diff suppressed because it is too large
+ 0 - 0
public/plugins/element-plus/theme-chalk/el-radio.css


File diff suppressed because it is too large
+ 0 - 0
public/plugins/element-plus/theme-chalk/el-tabs.css


File diff suppressed because it is too large
+ 0 - 0
public/plugins/element-plus/theme-chalk/el-upload.css


File diff suppressed because it is too large
+ 0 - 0
public/plugins/element-plus/theme-chalk/index.css


+ 5 - 0
public/plugins/element-plus/theme-chalk/src/color-picker.scss

@@ -19,6 +19,11 @@ $color-picker-size: map.merge($common-component-size, $color-picker-size);
   border: 1px solid getCssVar('border-color', 'lighter');
   box-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
   z-index: 1;
+
+  &:focus-visible {
+    outline: 2px solid getCssVar('color-primary');
+    outline-offset: 1px;
+  }
 }
 
 @mixin bar-background($side: right) {

+ 25 - 0
public/plugins/element-plus/theme-chalk/src/common/var.scss

@@ -851,6 +851,31 @@ $segmented: map.merge(
   $segmented
 );
 
+// Mention
+// css3 var in packages/theme-chalk/src/mention.scss
+$mention: () !default;
+$mention: map.merge(
+  (
+    'font-size': getCssVar('font-size-base'),
+    'bg-color': getCssVar('bg-color', 'overlay'),
+    'shadow': getCssVar('box-shadow-light'),
+    'border': 1px solid getCssVar('border-color-light'),
+    'option-color': getCssVar('text-color-regular'),
+    'option-height': 34px,
+    'option-min-width': 100px,
+    'option-hover-background': getCssVar('fill-color', 'light'),
+    'option-selected-color': getCssVar('color-primary'),
+    'option-disabled-color': getCssVar('text-color-placeholder'),
+    'option-loading-color': getCssVar('text-color-secondary'),
+    'option-loading-padding': 10px 0,
+    'max-height': 174px,
+    'padding': 6px 0,
+    'header-padding': 10px,
+    'footer-padding': 10px,
+  ),
+  $mention
+);
+
 // Table
 // css3 var in packages/theme-chalk/src/table.scss
 $table: () !default;

+ 24 - 17
public/plugins/element-plus/theme-chalk/src/date-picker/month-table.scss

@@ -12,23 +12,26 @@
     padding: 8px 0;
     cursor: pointer;
     position: relative;
-    & div {
+
+    @include b(date-table-cell) {
       height: 48px;
       padding: 6px 0;
       box-sizing: border-box;
     }
+
     &.today {
-      .cell {
+      .#{$namespace}-date-table-cell__text {
         color: getCssVar('color-primary');
         font-weight: bold;
       }
-      &.start-date .cell,
-      &.end-date .cell {
+
+      &.start-date .#{$namespace}-date-table-cell__text,
+      &.end-date .#{$namespace}-date-table-cell__text {
         color: $color-white;
       }
     }
 
-    &.disabled .cell {
+    &.disabled .#{$namespace}-date-table-cell__text {
       background-color: getCssVar('fill-color', 'light');
       cursor: not-allowed;
       color: getCssVar('text-color', 'placeholder');
@@ -38,7 +41,7 @@
       }
     }
 
-    .cell {
+    @include b(date-table-cell__text) {
       width: 54px;
       height: 36px;
       display: block;
@@ -49,57 +52,61 @@
       position: absolute;
       left: 50%;
       transform: translateX(-50%);
+
       &:hover {
         color: getCssVar('datepicker-hover-text-color');
       }
     }
 
-    &.in-range div {
+    &.in-range .#{$namespace}-date-table-cell {
       background-color: getCssVar('datepicker-inrange-bg-color');
+
       &:hover {
         background-color: getCssVar('datepicker-inrange-hover-bg-color');
       }
     }
-    &.start-date div,
-    &.end-date div {
+
+    &.start-date .#{$namespace}-date-table-cell,
+    &.end-date .#{$namespace}-date-table-cell {
       color: $color-white;
     }
 
-    &.start-date .cell,
-    &.end-date .cell {
+    &.start-date .#{$namespace}-date-table-cell__text,
+    &.end-date .#{$namespace}-date-table-cell__text {
       color: $color-white;
       background-color: getCssVar('datepicker-active-color');
     }
 
-    &.start-date div {
+    &.start-date .#{$namespace}-date-table-cell {
       margin-left: 3px;
       border-top-left-radius: 24px;
       border-bottom-left-radius: 24px;
     }
 
-    &.end-date div {
+    &.end-date .#{$namespace}-date-table-cell {
       margin-right: 3px;
       border-top-right-radius: 24px;
       border-bottom-right-radius: 24px;
     }
 
-    &.current:not(.disabled) div {
+    &.current:not(.disabled) .#{$namespace}-date-table-cell {
       border-radius: 24px;
       margin-left: 3px;
       margin-right: 3px;
     }
 
-    &.current:not(.disabled) .cell {
+    &.current:not(.disabled) .#{$namespace}-date-table-cell__text {
       color: $color-white;
       background-color: getCssVar('datepicker-active-color');
     }
 
     &:focus-visible {
       outline: none;
-      .cell {
+
+      .#{$namespace}-date-table-cell__text {
         outline: 2px solid getCssVar('datepicker-active-color');
         outline-offset: 1px;
       }
     }
   }
-}
+}

+ 41 - 12
public/plugins/element-plus/theme-chalk/src/date-picker/year-table.scss

@@ -17,20 +17,25 @@
     cursor: pointer;
     position: relative;
 
-    & div {
+    @include b(date-table-cell) {
       height: 48px;
       padding: 6px 0;
       box-sizing: border-box;
     }
 
     &.today {
-      .cell {
+      .#{$namespace}-date-table-cell__text {
         color: getCssVar('color', 'primary');
         font-weight: bold;
       }
+
+      &.start-date .#{$namespace}-date-table-cell__text,
+      &.end-date .#{$namespace}-date-table-cell__text {
+        color: $color-white;
+      }
     }
 
-    &.disabled .cell {
+    &.disabled .#{$namespace}-date-table-cell__text {
       background-color: getCssVar('fill-color', 'light');
       cursor: not-allowed;
       color: getCssVar('text-color', 'placeholder');
@@ -40,8 +45,8 @@
       }
     }
 
-    .cell {
-      width: 54px;
+    @include b(date-table-cell__text) {
+      width: 60px;
       height: 36px;
       display: block;
       line-height: 36px;
@@ -57,23 +62,47 @@
       }
     }
 
-    &.current:not(.disabled) div {
-      border-radius: 24px;
-      margin-left: 3px;
-      margin-right: 3px;
+    &.in-range .#{$namespace}-date-table-cell {
+      background-color: getCssVar('datepicker-inrange-bg-color');
+
+      &:hover {
+        background-color: getCssVar('datepicker-inrange-hover-bg-color');
+      }
     }
 
-    &.current:not(.disabled) .cell {
+    &.start-date .#{$namespace}-date-table-cell,
+    &.end-date .#{$namespace}-date-table-cell {
+      color: $color-white;
+    }
+
+    &.start-date .#{$namespace}-date-table-cell__text,
+    &.end-date .#{$namespace}-date-table-cell__text {
+      color: $color-white;
+      background-color: getCssVar('datepicker-active-color');
+    }
+
+    &.start-date .#{$namespace}-date-table-cell {
+      border-top-left-radius: 24px;
+      border-bottom-left-radius: 24px;
+    }
+
+    &.end-date .#{$namespace}-date-table-cell {
+      border-top-right-radius: 24px;
+      border-bottom-right-radius: 24px;
+    }
+
+    &.current:not(.disabled) .#{$namespace}-date-table-cell__text {
       color: $color-white;
       background-color: getCssVar('datepicker-active-color');
     }
 
     &:focus-visible {
       outline: none;
-      .cell {
+
+      .#{$namespace}-date-table-cell__text {
         outline: 2px solid getCssVar('datepicker-active-color');
         outline-offset: 1px;
       }
     }
   }
-}
+}

+ 1 - 6
public/plugins/element-plus/theme-chalk/src/drawer.scss

@@ -127,12 +127,7 @@ $directions: rtl, ltr, ttb, btt;
 
   &-enter-from,
   &-leave-to {
-    opacity: 0;
-  }
-
-  &-enter-to,
-  &-leave-from {
-    opacity: 1;
+    background-color: transparent !important;
   }
 
   &-enter-from,

+ 1 - 0
public/plugins/element-plus/theme-chalk/src/index.scss

@@ -107,3 +107,4 @@
 @use './anchor.scss';
 @use './anchor-link.scss';
 @use './segmented.scss';
+@use './mention.scss';

+ 90 - 0
public/plugins/element-plus/theme-chalk/src/mention.scss

@@ -0,0 +1,90 @@
+@use 'sass:map';
+
+@use 'mixins/mixins' as *;
+@use 'mixins/var' as *;
+@use 'common/var' as *;
+
+@include b(mention) {
+  position: relative;
+  width: 100%;
+
+  @include e(popper) {
+    @include picker-popper(
+      map.get($mention, 'bg-color'),
+      map.get($mention, 'border'),
+      map.get($mention, 'shadow')
+    );
+  }
+
+}
+
+@include b(mention-dropdown) {
+
+  @include set-component-css-var('mention', $mention);
+
+  @include e(item) {
+    font-size: getCssVar('mention-font-size');
+    padding: 0 20px;
+    position: relative;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    color: getCssVar('mention-option-color');
+    height: getCssVar('mention-option-height');
+    line-height: getCssVar('mention-option-height');
+    box-sizing: border-box;
+    min-width: getCssVar('mention-option-min-width');
+    cursor: pointer;
+
+    @include when(hovering) {
+      background-color: getCssVar('mention-option-hover-background');
+    }
+
+    @include when(selected) {
+      color: getCssVar('mention-option-selected-color');
+      font-weight: bold;
+    }
+
+    @include when(disabled) {
+      color: getCssVar('mention-option-disabled-color');
+      cursor: not-allowed;
+      background-color: unset;
+    }
+  }
+}
+
+@include b(mention-dropdown) {
+  z-index: calc(#{getCssVar('index-top')} + 1);
+  border-radius: getCssVar('border-radius-base');
+  box-sizing: border-box;
+}
+
+@include b(mention-dropdown__loading) {
+  padding: 10px 0;
+  margin: 0;
+  text-align: center;
+  color: getCssVar('mention-option-loading-color');
+  font-size: 12px;
+  min-width: getCssVar('mention-option-min-width');
+}
+
+@include b(mention-dropdown__wrap) {
+  max-height: getCssVar('mention-max-height');
+}
+
+@include b(mention-dropdown__list) {
+  list-style: none;
+  padding: getCssVar('mention-padding');
+  margin: 0;
+  box-sizing: border-box;
+}
+
+@include b(mention-dropdown__header) {
+  padding: getCssVar('mention-header-padding');
+  border-bottom: getCssVar('mention-border');
+}
+
+@include b(mention-dropdown__footer) {
+  padding: getCssVar('mention-footer-padding');
+  border-top: getCssVar('mention-border');
+}

+ 1 - 1
public/plugins/element-plus/theme-chalk/src/radio.scss

@@ -30,7 +30,7 @@ $radio-font-size: map.merge(
   outline: none;
   font-size: getCssVar('font-size', 'base');
   user-select: none;
-  margin-right: 32px;
+  margin-right: 30px;
   height: map.get($radio-height, 'default');
 
   @each $size in (large, small) {

+ 31 - 35
public/plugins/element-plus/theme-chalk/src/tabs.scss

@@ -3,6 +3,7 @@
 
 @include b(tabs) {
   @include set-component-css-var('tabs', $tabs);
+  display: flex;
 
   @include e(header) {
     padding: 0;
@@ -176,6 +177,29 @@
   @include e(content) {
     overflow: hidden;
     position: relative;
+    flex-grow: 1;
+  }
+  @include m((top, bottom)) {
+    > .#{$namespace}-tabs__header {
+      .#{$namespace}-tabs__item:nth-child(2) {
+        padding-left: 0;
+      }
+      .#{$namespace}-tabs__item:last-child {
+        padding-right: 0;
+      }
+    }
+
+    &.#{$namespace}-tabs--border-card,
+    &.#{$namespace}-tabs--card {
+      > .#{$namespace}-tabs__header {
+        .#{$namespace}-tabs__item:nth-child(2) {
+          padding-left: 20px;
+        }
+        .#{$namespace}-tabs__item:last-child {
+          padding-right: 20px;
+        }
+      }
+    }
   }
   @include m(card) {
     > .#{$namespace}-tabs__header {
@@ -292,40 +316,9 @@
       margin-left: 0;
     }
   }
-  @include m((top, bottom)) {
-    .#{$namespace}-tabs__item.is-top:nth-child(2),
-    .#{$namespace}-tabs__item.is-bottom:nth-child(2) {
-      padding-left: 0;
-    }
-    .#{$namespace}-tabs__item.is-top:last-child,
-    .#{$namespace}-tabs__item.is-bottom:last-child {
-      padding-right: 0;
-    }
-
-    &.#{$namespace}-tabs--border-card,
-    &.#{$namespace}-tabs--card,
-    .#{$namespace}-tabs--left,
-    .#{$namespace}-tabs--right {
-      > .#{$namespace}-tabs__header {
-        .#{$namespace}-tabs__item:nth-child(2) {
-          padding-left: 20px;
-
-          &:not(.is-active).is-closable:hover {
-            padding-left: 13px;
-          }
-        }
-
-        .#{$namespace}-tabs__item:last-child {
-          padding-right: 20px;
-
-          &:not(.is-active).is-closable:hover {
-            padding-right: 13px;
-          }
-        }
-      }
-    }
-  }
   @include m(bottom) {
+    flex-direction: column;
+
     .#{$namespace}-tabs__header.is-bottom {
       margin-bottom: 0;
       margin-top: 10px;
@@ -422,8 +415,9 @@
     }
   }
   @include m(left) {
+    flex-direction: row-reverse;
+
     .#{$namespace}-tabs__header.is-left {
-      float: left;
       margin-bottom: 0;
       margin-right: 10px;
     }
@@ -506,7 +500,6 @@
   }
   @include m(right) {
     .#{$namespace}-tabs__header.is-right {
-      float: right;
       margin-bottom: 0;
       margin-left: 10px;
     }
@@ -577,6 +570,9 @@
       }
     }
   }
+  @include m(top) {
+    flex-direction: column-reverse;
+  }
 }
 
 .slideInRight-transition,

+ 27 - 0
public/plugins/element-plus/theme-chalk/src/upload.scss

@@ -29,6 +29,33 @@
   cursor: pointer;
   outline: none;
 
+  @include when(disabled){
+    cursor: not-allowed;
+    &:focus{
+      border-color: getCssVar('border-color', 'darker');
+      color: inherit;
+      .#{$namespace}-upload-dragger{
+        border-color: getCssVar('border-color', 'darker');
+      }
+    }
+    .#{$namespace}-upload-dragger {
+      cursor: not-allowed;
+      background-color: getCssVar('disabled-bg-color');
+
+      .#{bem('upload', 'text')} {
+        color: getCssVar('text-color-placeholder');
+
+        em {
+          color: getCssVar('disabled-text-color');
+        }
+      }
+
+      &:hover{
+        border-color: getCssVar('border-color', 'darker');
+      }
+    }
+  }
+
   @include e(input) {
     display: none;
   }

+ 0 - 0
public/plugins/element-plus/v2.7.8 → public/plugins/element-plus/v2.8.0


+ 1 - 1
public/version.json

@@ -1,3 +1,3 @@
 {
-  "value": "20240815104714"
+  "value": "20240816102221"
 }

+ 472 - 0
src/plugins/HcPdfSign-BAK.js

@@ -0,0 +1,472 @@
+import { getArrValue, getRandom, isNullES, isNumber, isString } from 'js-fast-way'
+
+//PDF签章
+export default class HcPdfSign {
+
+    static iframeDom = null
+    static pdfViewer = null
+    static signImgCss = {}
+    static signType = ''
+    static disX = 0
+    static disY = 0
+    static curSignDom = null
+    static signList = []
+    static signChange = null
+    static pdfLoadFunc = null
+    static batchSign = false
+    static signNum = 0
+
+    /**
+     * 初始化创建PDF预览
+     * @param ele   元素的ref,或id值
+     * @param url   pdf的url
+     * @param img   签章图片url
+     * @param func  回调函数
+     */
+    static createPdf({ ele, url, img, change, load, isShowYinzhang }) {
+        this.initVarNull()
+        //判断参数是否合法
+        if (isNullES(ele)) {
+            console.warn('请传入参数,必须是,ref的dom元素,或id值')
+            return false
+        }
+        //是否为字符串或数值类型
+        let dom = null, errTip = 'ele参数不合法,必须是ref的dom元素,或id值'
+        if (isString(ele) || isNumber(ele)) {
+            try {
+                dom = document.getElementById(ele)
+            } catch (e) {
+                console.error(errTip)
+                return false
+            }
+        } else {
+            try {
+                ele.cloneNode(true)
+                if (ele.nodeType === 1 || ele.nodeType === 9) {
+                    dom = ele
+                } else {
+                    console.error(errTip)
+                    return false
+                }
+            } catch (e) {
+                console.error(errTip)
+                return false
+            }
+        }
+        //清空dom
+        const children = dom.children
+        if (children.length > 0) {
+            for (let i = children.length - 1; i >= 0; i--) {
+                dom.removeChild(children[i])
+            }
+        }
+        if (isNullES(url)) {
+            console.warn('请传入Pdf的url参数')
+            return false
+        }
+        //创建iframe
+        const iframe = document.createElement('iframe')
+        iframe.setAttribute('id', 'pdf-sign-' + getRandom(6))
+        iframe.src = `/plugins/pdfjs/sign/web/viewer.html?file=${url}#zoom=100`
+        iframe.style.width = '100%'
+        iframe.style.height = '100%'
+        iframe.style.border = '1px solid #ccc'
+        iframe.name = 'HcPdfSign'
+        iframe.addEventListener('load', () => {
+            this.iframeLoad(isShowYinzhang)
+        })
+        dom.appendChild(iframe)
+        this.iframeDom = iframe
+        //设置签章图片
+        if (isNullES(img)) {
+            console.warn('请传入签章图片')
+            return false
+        }
+        this.signImage(img).then()
+        //设置回调事件
+        if (!isNullES(change)) {
+            this.addEventFunc(change)
+        }
+        //设置回调事件
+        if (!isNullES(load)) {
+            this.addPdfLoadFunc(load)
+        }
+    }
+
+    //初始化空值
+    static initVarNull() {
+        this.iframeDom = null
+        this.pdfViewer = null
+        this.signImgCss = {}
+        this.signType = ''
+        this.disX = 0
+        this.disY = 0
+        this.curSignDom = null
+        this.signList = []
+        this.signChange = null
+        this.pdfLoadFunc = null
+        this.signNum = 0
+    }
+
+    //设置回调事件
+    static addEventFunc(func) {
+        if (typeof func !== 'function') {
+            console.warn('请传入函数')
+            return false
+        } else {
+            this.signChange = func
+        }
+    }
+
+    //触发回调事件
+    static signChangeFunc() {
+        if (typeof this.signChange !== 'function') {
+            return false
+        } else {
+            this.signChange(this.signList)
+        }
+    }
+
+    //设置加载完成的回调事件
+    static addPdfLoadFunc(func) {
+        if (typeof func !== 'function') {
+            console.warn('请传入函数')
+            return false
+        } else {
+            this.pdfLoadFunc = func
+        }
+    }
+
+    //加载完成
+    static setPdfLoadFunc(val) {
+        if (typeof this.pdfLoadFunc !== 'function') {
+            return false
+        } else {
+            this.pdfLoadFunc(val)
+        }
+    }
+
+    //设置签章图片
+    static async signImage(url) {
+        const res = await this.getImageSize(url)
+        if (res.width === res.height) {
+            this.signImgCss = { url: url, width: 170, height: 170 }
+        } else if (res.width > res.height) {
+            const scaleFactor = 30 / res.height
+            const newWidth = res.width * scaleFactor
+            this.signImgCss = { url: url, width: newWidth, height: 30 }
+        } else {
+            const scaleFactor = 170 / res.height
+            const newWidth = res.width * scaleFactor
+            this.signImgCss = { url: url, width: newWidth, height: 170 }
+        }
+    }
+
+    //获取网络图片的高宽
+    static async getImageSize(url) {
+        return new Promise((resolve) => {
+            let img = new Image()
+            img.onload = function () {
+                let width = img.width
+                let height = img.height
+                resolve({ width, height })
+            }
+            img.src = url
+        })
+    }
+
+    //创建签章图片
+    static async createSignImage(event) {
+        //创建图片元素
+        const { url, width, height } = this.signImgCss
+        const uuid = 'pdf-sign-img-' + getRandom(6)
+        const signImg = document.createElement('img')
+        signImg.setAttribute('id', uuid)
+        signImg.src = url
+        signImg.style.position = 'absolute'
+        signImg.style.width = width + 'px'
+        signImg.style.height = height + 'px'
+        signImg.style.left = (event.layerX - (width / 2)) + 'px'
+        signImg.style.top = (event.layerY - (height / 2)) + 'px'
+        signImg.style.pointerEvents = 'auto'
+        signImg.style.zIndex = 999
+        return signImg
+    }
+
+    /**
+     * 是否批量签章
+     * @param val   true/false
+     */
+    static setBatchSign(val = false) {
+        console.log('111', val)
+        this.batchSign = val
+        this.setPageScrolling()
+    }
+
+    //让PDF页面全部渲染一下
+    static async setPageScrolling() {
+        const pageDom = this.pdfViewer?.children ?? []
+        await this.toPdfPage('firstPage')
+        for (let i = 0; i < pageDom.length; i++) {
+            await this.toPdfPage('next')
+        }
+        await this.toPdfPage('firstPage')
+    }
+
+    /**
+     * 跳转pdf的页面
+     * @param pageId 最后一页:lastPage,第一页:firstPage,上一页:previous,下一页:next
+     */
+    static async toPdfPage(pageId) {
+        return new Promise((resolve) => {
+            this.iframeDom?.contentDocument?.getElementById(pageId)?.click()
+            setTimeout(() => {
+                resolve(true)
+            }, 100)
+        })
+    }
+
+    //PDF加载完成
+    static iframeLoad(isShowYinzhang) {
+        const viewer = this.iframeDom?.contentDocument?.getElementById('viewer')
+        if (isShowYinzhang) {
+            viewer.classList.add('stamp-cursor')
+        }
+
+        //页面被点击
+        viewer.addEventListener('click', (event) => {
+            this.viewerClick(event).then()
+        })
+        //鼠标移动
+        viewer.addEventListener('mousemove', (event) => {
+            event.preventDefault()
+            if (this.signType !== '移动' || !this.curSignDom) {
+                return
+            }
+            //鼠标位置
+            const left = (event.clientX - this.disX) + 'px'
+            const top = (event.clientY - this.disY) + 'px'
+            this.curSignDom.style.left = left
+            this.curSignDom.style.top = top
+            //批量处理
+            if (this.batchSign) {
+                const curDom = this.curSignDom
+                let { data: curSign } = this.getSignImgDom(curDom)
+                if (!curSign) return
+                const newArr = this.signList.filter(item => {
+                    return item.type === curSign.type
+                })
+                newArr.forEach(item => {
+                    item.dom.style.left = left
+                    item.dom.style.top = top
+                })
+            }
+        })
+        //鼠标抬起
+        viewer.addEventListener('mouseup', () => {
+            if (!this.curSignDom) return
+            this.signType = '签名'
+            this.curSignDom.style.cursor = 'default'
+            const curDom = this.curSignDom
+            //获取数据
+            let { data: curSign } = this.getSignImgDom(curDom)
+            if (!curSign) return
+            //计算坐标
+            const left = curDom.style.left.replace('px', '')
+            const top = curDom.style.top.replace('px', '')
+            const { width, height } = this.signImgCss
+            const lefts = Number(left) + Number(width / 2)
+            const tops = Number(top) + Number(height / 2)
+            const lx = ((lefts * 100) / curDom.parentNode.clientWidth).toFixed(4)
+            const ly = ((tops * 100) / curDom.parentNode.clientHeight).toFixed(4)
+            //批量处理
+            if (this.batchSign) {
+                const newArr = this.signList.filter(item => {
+                    return item.type === curSign.type
+                })
+                newArr.forEach(item => {
+                    item.lx = lx
+                    item.ly = ly
+                    item.width = curDom.clientWidth
+                    item.height = curDom.clientHeight
+                })
+            } else {
+                curSign.lx = lx
+                curSign.ly = ly
+                curSign.width = curDom.clientWidth
+                curSign.height = curDom.clientHeight
+            }
+            this.signChangeFunc()
+        })
+        //监听按键
+        const container = this.iframeDom?.contentDocument?.getElementById('outerContainer')
+        container.addEventListener('keyup', (event) => {
+            //删除签章
+            if (event.keyCode === 8 && event.key === 'Backspace') {
+                const curDom = this.curSignDom
+                const { index } = this.getSignImgDom(curDom)
+                if (index <= -1) return
+                this.delSignImg(index).then()
+            }
+        })
+        this.pdfViewer = viewer
+        //处理pdf渲染
+        if (this.batchSign) {
+            setTimeout(async () => {
+                await this.setPageScrolling()
+                this.setPdfLoadFunc(true)
+            }, 500)
+        } else {
+            setTimeout(async () => {
+                this.setPdfLoadFunc(true)
+            }, 100)
+        }
+    }
+
+    //删除签章
+    static async delSignImg(index) {
+        if (index <= -1) return
+        if (this.batchSign) {
+            const list = this.signList, curDom = list[index]
+            //倒序删除签章
+            for (let i = list.length - 1; i >= 0; i--) {
+                if (list[i].type === curDom.type) {
+                    list[i].dom.remove()
+                    delete list[i].dom
+                    list.splice(i, 1)
+                }
+            }
+            this.signList = list
+            this.signChangeFunc()
+        } else {
+            this.signList[index].dom.remove()
+            this.signList.splice(index, 1)
+            this.signChangeFunc()
+        }
+    }
+
+
+    //获取签章图片的数据
+    static getSignImgDom(curDom) {
+        if (isNullES(curDom)) {
+            return { data: null, index: -1 }
+        }
+        //获取数据
+        const id = curDom?.getAttribute('id')
+        let curSign = null, index = -1
+        for (let i = 0; i < this.signList.length; i++) {
+            const item = this.signList[i]
+            if (item.id === id) {
+                curSign = item
+                index = i
+                break
+            }
+        }
+        return { data: curSign, index }
+    }
+
+    //页面被点击
+    static async viewerClick(event) {
+        const target = event.target
+        //当前为移动模式
+        if (this.signType === '移动') {
+            return
+        }
+        //不在PDF页面上点击
+        if (target.className !== 'textLayer') {
+            return
+        }
+        //批量签章
+        this.signNum ++
+        console.log(this.batchSign)
+        if (this.batchSign) {
+            const parent = target?.parentNode?.parentNode?.children ?? []
+            console.log(parent)
+            for (let i = 0; i < parent.length; i++) {
+                await this.setPdfNodeSign(parent[i], parent[i]?.children[1], event)
+            }
+            this.signChangeFunc()
+        } else {
+            await this.setPdfNodeSign(target?.parentNode, target, event)
+            this.signChangeFunc()
+        }
+    }
+
+    //设置PDF节点签章
+    static async setPdfNodeSign(node, textLayer, event) {
+        if (isNullES(node) || isNullES(textLayer) || isNullES(event)) {
+            return
+        }
+
+        // if (node.children.length < 3) {
+        //     node.prepend('<div class="signLayer" style="position: absolute;height: 100%;width: 100%;z-index: 999;pointer-events: none;overflow: hidden"></div>')
+        // }
+        //插入图片
+        const signImgDom = await this.createSignImage(event)
+        node.children[0].append(signImgDom)
+        //鼠标按下
+        signImgDom.addEventListener('mousedown', (e) => {
+            //新的当前选中项
+            this.curSignDom = e.target
+            this.signType = '移动'
+            e.target.style.cursor = 'move'
+            //鼠标相对于图片的位置
+            this.disX = e.clientX - e.target.offsetLeft
+            this.disY = e.clientY - e.target.offsetTop
+        })
+        //保存签章信息
+        this.signList.push({
+            type: this.signNum,
+            url: this.signImgCss?.url ?? '',
+            page: node.getAttribute('data-page-number'),
+            id: signImgDom.getAttribute('id'),
+            lx: ((event.layerX * 100) / textLayer.clientWidth).toFixed(4),
+            ly: ((event.layerY * 100) / textLayer.clientHeight).toFixed(4),
+            width: signImgDom.clientWidth,
+            height: signImgDom.clientHeight,
+            dom: signImgDom,
+        })
+        return signImgDom
+    }
+
+    //设置PDF签章图片
+    static async setPdfSignImg(arr) {
+        const list = getArrValue(arr)
+        if (list.length <= 0) return
+        const pageDom = this.pdfViewer?.children ?? []
+        for (let i = 0; i < list.length; i++) {
+            const page = Number(list[i].page) - 1
+            const dom = pageDom[page]?.getElementsByClassName('canvasWrapper')[0]
+            //创建图片元素
+            const signImg = document.createElement('img')
+            signImg.setAttribute('id', list[i].id)
+            signImg.src = list[i].url
+            signImg.style.position = 'absolute'
+            signImg.style.width = list[i].dom.style.width
+            signImg.style.height = list[i].dom.style.height
+            signImg.style.left = list[i].dom.style.left
+            signImg.style.top = list[i].dom.style.top
+            signImg.style.pointerEvents = 'auto'
+            signImg.style.zIndex = 999
+            dom.append(signImg)
+            //鼠标按下
+            signImg.addEventListener('mousedown', (e) => {
+                //新的当前选中项
+                this.curSignDom = e.target
+                this.signType = '移动'
+                e.target.style.cursor = 'move'
+                //鼠标相对于图片的位置
+                this.disX = e.clientX - e.target.offsetLeft
+                this.disY = e.clientY - e.target.offsetTop
+            })
+            //保存签章信息
+            this.signList.push({
+                ...list[i],
+                width: signImg.clientWidth,
+                height: signImg.clientHeight,
+                dom: signImg,
+            })
+        }
+    }
+
+}

+ 300 - 238
src/plugins/HcPdfSign.js

@@ -1,8 +1,7 @@
 import { getArrValue, getRandom, isNullES, isNumber, isString } from 'js-fast-way'
 
-//PDF签章
+// PDF签章
 export default class HcPdfSign {
-
     static iframeDom = null
     static pdfViewer = null
     static signImgCss = {}
@@ -18,26 +17,57 @@ export default class HcPdfSign {
 
     /**
      * 初始化创建PDF预览
-     * @param ele   元素的ref,或id值
-     * @param url   pdf的url
-     * @param img   签章图片url
-     * @param func  回调函数
+     * @param {Object} options 配置选项
+     * @param {HTMLElement|string} options.ele 元素的ref,或id值
+     * @param {string} options.url PDF的url
+     * @param {string} options.img 签章图片url
+     * @param {Function} options.change 回调函数
+     * @param {Function} options.load 加载完成回调函数
+     * @param {boolean} options.isShowYinzhang 是否显示印章
      */
     static createPdf({ ele, url, img, change, load, isShowYinzhang }) {
         this.initVarNull()
-        //判断参数是否合法
+        const dom = this.getDomElement(ele)
+        if (!dom) return false
+
+        if (isNullES(url)) {
+            console.warn('请传入PDF的url参数')
+            return false
+        }
+
+        this.createIframe(dom, url, isShowYinzhang)
+
+        if (isNullES(img)) {
+            console.warn('请传入签章图片')
+            return false
+        }
+        this.signImage(img)
+
+        if (!isNullES(change)) {
+            this.addEventFunc(change)
+        }
+
+        if (!isNullES(load)) {
+            this.addPdfLoadFunc(load)
+        }
+    }
+
+    // 获取DOM元素
+    static getDomElement(ele) {
         if (isNullES(ele)) {
             console.warn('请传入参数,必须是,ref的dom元素,或id值')
-            return false
+            return null
         }
-        //是否为字符串或数值类型
-        let dom = null, errTip = 'ele参数不合法,必须是ref的dom元素,或id值'
+
+        let dom = null
+        const errTip = 'ele参数不合法,必须是ref的dom元素,或id值'
+
         if (isString(ele) || isNumber(ele)) {
             try {
                 dom = document.getElementById(ele)
             } catch (e) {
                 console.error(errTip)
-                return false
+                return null
             }
         } else {
             try {
@@ -46,28 +76,33 @@ export default class HcPdfSign {
                     dom = ele
                 } else {
                     console.error(errTip)
-                    return false
+                    return null
                 }
             } catch (e) {
                 console.error(errTip)
-                return false
+                return null
             }
         }
-        //清空dom
+
+        this.clearDomChildren(dom)
+        return dom
+    }
+
+    // 清空DOM子元素
+    static clearDomChildren(dom) {
         const children = dom.children
         if (children.length > 0) {
             for (let i = children.length - 1; i >= 0; i--) {
                 dom.removeChild(children[i])
             }
         }
-        if (isNullES(url)) {
-            console.warn('请传入Pdf的url参数')
-            return false
-        }
-        //创建iframe
+    }
+
+    // 创建iframe
+    static createIframe(dom, url, isShowYinzhang) {
         const iframe = document.createElement('iframe')
         iframe.setAttribute('id', 'pdf-sign-' + getRandom(6))
-        iframe.src = `/plugins/pdfjs/sign/web/viewer.html?file=${url}#zoom=100`
+        iframe.src = `/plugins/pdfjs/sign/web/viewer.html?file=${encodeURIComponent(url)}#zoom=100`
         iframe.style.width = '100%'
         iframe.style.height = '100%'
         iframe.style.border = '1px solid #ccc'
@@ -77,23 +112,9 @@ export default class HcPdfSign {
         })
         dom.appendChild(iframe)
         this.iframeDom = iframe
-        //设置签章图片
-        if (isNullES(img)) {
-            console.warn('请传入签章图片')
-            return false
-        }
-        this.signImage(img).then()
-        //设置回调事件
-        if (!isNullES(change)) {
-            this.addEventFunc(change)
-        }
-        //设置回调事件
-        if (!isNullES(load)) {
-            this.addPdfLoadFunc(load)
-        }
     }
 
-    //初始化空值
+    // 初始化变量
     static initVarNull() {
         this.iframeDom = null
         this.pdfViewer = null
@@ -108,45 +129,39 @@ export default class HcPdfSign {
         this.signNum = 0
     }
 
-    //设置回调事件
+    // 设置回调事件
     static addEventFunc(func) {
         if (typeof func !== 'function') {
             console.warn('请传入函数')
             return false
-        } else {
-            this.signChange = func
         }
+        this.signChange = func
     }
 
-    //触发回调事件
+    // 触发回调事件
     static signChangeFunc() {
-        if (typeof this.signChange !== 'function') {
-            return false
-        } else {
+        if (typeof this.signChange === 'function') {
             this.signChange(this.signList)
         }
     }
 
-    //设置加载完成的回调事件
+    // 设置加载完成的回调事件
     static addPdfLoadFunc(func) {
         if (typeof func !== 'function') {
             console.warn('请传入函数')
             return false
-        } else {
-            this.pdfLoadFunc = func
         }
+        this.pdfLoadFunc = func
     }
 
-    //加载完成
+    // 加载完成
     static setPdfLoadFunc(val) {
-        if (typeof this.pdfLoadFunc !== 'function') {
-            return false
-        } else {
+        if (typeof this.pdfLoadFunc === 'function') {
             this.pdfLoadFunc(val)
         }
     }
 
-    //设置签章图片
+    // 设置签章图片
     static async signImage(url) {
         const res = await this.getImageSize(url)
         if (res.width === res.height) {
@@ -162,22 +177,23 @@ export default class HcPdfSign {
         }
     }
 
-    //获取网络图片的高宽
-    static async getImageSize(url) {
+    // 获取网络图片的高宽
+    static getImageSize(url) {
         return new Promise((resolve) => {
             let img = new Image()
             img.onload = function () {
-                let width = img.width
-                let height = img.height
-                resolve({ width, height })
+                resolve({ width: img.width, height: img.height })
+            }
+            img.onerror = function () {
+                console.error('图片加载失败')
+                resolve({ width: 0, height: 0 })
             }
             img.src = url
         })
     }
 
-    //创建签章图片
-    static async createSignImage(event) {
-        //创建图片元素
+    // 创建签章图片
+    static createSignImage(event) {
         const { url, width, height } = this.signImgCss
         const uuid = 'pdf-sign-img-' + getRandom(6)
         const signImg = document.createElement('img')
@@ -189,21 +205,20 @@ export default class HcPdfSign {
         signImg.style.left = (event.layerX - (width / 2)) + 'px'
         signImg.style.top = (event.layerY - (height / 2)) + 'px'
         signImg.style.pointerEvents = 'auto'
-        signImg.style.zIndex = 999
+        signImg.style.zIndex = '999'
         return signImg
     }
 
     /**
-     * 是否批量签章
-     * @param val   true/false
+     * 设置是否批量签章
+     * @param {boolean} val 是否批量签章
      */
     static setBatchSign(val = false) {
-        console.log('111', val)
         this.batchSign = val
         this.setPageScrolling()
     }
 
-    //让PDF页面全部渲染一下
+    // 让PDF页面全部渲染一下
     static async setPageScrolling() {
         const pageDom = this.pdfViewer?.children ?? []
         await this.toPdfPage('firstPage')
@@ -215,9 +230,9 @@ export default class HcPdfSign {
 
     /**
      * 跳转pdf的页面
-     * @param pageId 最后一页:lastPage,第一页:firstPage,上一页:previous,下一页:next
+     * @param {string} pageId 最后一页:lastPage,第一页:firstPage,上一页:previous,下一页:next
      */
-    static async toPdfPage(pageId) {
+    static toPdfPage(pageId) {
         return new Promise((resolve) => {
             this.iframeDom?.contentDocument?.getElementById(pageId)?.click()
             setTimeout(() => {
@@ -226,138 +241,197 @@ export default class HcPdfSign {
         })
     }
 
-    //PDF加载完成
+    // PDF加载完成
     static iframeLoad(isShowYinzhang) {
         const viewer = this.iframeDom?.contentDocument?.getElementById('viewer')
+        if (!viewer) {
+            console.error('无法获取PDF查看器元素')
+            return
+        }
+
         if (isShowYinzhang) {
             viewer.classList.add('stamp-cursor')
         }
 
-        //页面被点击
-        viewer.addEventListener('click', (event) => {
-            this.viewerClick(event).then()
-        })
-        //鼠标移动
-        viewer.addEventListener('mousemove', (event) => {
-            event.preventDefault()
-            if (this.signType !== '移动' || !this.curSignDom) {
-                return
-            }
-            //鼠标位置
-            const left = (event.clientX - this.disX) + 'px'
-            const top = (event.clientY - this.disY) + 'px'
-            this.curSignDom.style.left = left
-            this.curSignDom.style.top = top
-            //批量处理
-            if (this.batchSign) {
-                const curDom = this.curSignDom
-                let { data: curSign } = this.getSignImgDom(curDom)
-                if (!curSign) return
-                const newArr = this.signList.filter(item => {
-                    return item.type === curSign.type
-                })
-                newArr.forEach(item => {
-                    item.dom.style.left = left
-                    item.dom.style.top = top
-                })
-            }
-        })
-        //鼠标抬起
-        viewer.addEventListener('mouseup', () => {
-            if (!this.curSignDom) return
-            this.signType = '签名'
-            this.curSignDom.style.cursor = 'default'
-            const curDom = this.curSignDom
-            //获取数据
-            let { data: curSign } = this.getSignImgDom(curDom)
-            if (!curSign) return
-            //计算坐标
-            const left = curDom.style.left.replace('px', '')
-            const top = curDom.style.top.replace('px', '')
-            const { width, height } = this.signImgCss
-            const lefts = Number(left) + Number(width / 2)
-            const tops = Number(top) + Number(height / 2)
-            const lx = ((lefts * 100) / curDom.parentNode.clientWidth).toFixed(4)
-            const ly = ((tops * 100) / curDom.parentNode.clientHeight).toFixed(4)
-            //批量处理
+        viewer.addEventListener('click', (event) => this.viewerClick(event))
+        viewer.addEventListener('mousemove', (event) => this.viewerMouseMove(event))
+        viewer.addEventListener('mouseup', () => this.viewerMouseUp())
+
+        const container = this.iframeDom?.contentDocument?.getElementById('outerContainer')
+        if (container) {
+            container.addEventListener('keyup', (event) => this.containerKeyUp(event))
+        }
+
+        this.pdfViewer = viewer
+        this.handlePdfRendering()
+    }
+
+    // 处理PDF渲染
+    static handlePdfRendering() {
+        setTimeout(async () => {
             if (this.batchSign) {
-                const newArr = this.signList.filter(item => {
-                    return item.type === curSign.type
-                })
-                newArr.forEach(item => {
-                    item.lx = lx
-                    item.ly = ly
-                    item.width = curDom.clientWidth
-                    item.height = curDom.clientHeight
-                })
-            } else {
-                curSign.lx = lx
-                curSign.ly = ly
-                curSign.width = curDom.clientWidth
-                curSign.height = curDom.clientHeight
+                await this.setPageScrolling()
             }
-            this.signChangeFunc()
-        })
-        //监听按键
-        const container = this.iframeDom?.contentDocument?.getElementById('outerContainer')
-        container.addEventListener('keyup', (event) => {
-            //删除签章
-            if (event.keyCode === 8 && event.key === 'Backspace') {
-                const curDom = this.curSignDom
-                const { index } = this.getSignImgDom(curDom)
-                if (index <= -1) return
-                this.delSignImg(index).then()
+            this.setPdfLoadFunc(true)
+        }, this.batchSign ? 500 : 100)
+    }
+
+    // 查看器点击事件
+    static async viewerClick(event) {
+        const target = event.target
+        if (this.signType === '移动' || target.className !== 'textLayer') {
+            return
+        }
+
+        this.signNum++
+        if (this.batchSign) {
+            const parent = target?.parentNode?.parentNode?.children ?? []
+            for (let i = 0; i < parent.length; i++) {
+                await this.setPdfNodeSign(parent[i], parent[i]?.children[1], event)
             }
+        } else {
+            await this.setPdfNodeSign(target?.parentNode, target, event)
+        }
+        this.signChangeFunc()
+    }
+
+    // 查看器鼠标移动事件
+    static viewerMouseMove(event) {
+        event.preventDefault()
+        if (this.signType !== '移动' || !this.curSignDom) {
+            return
+        }
+
+        const left = (event.clientX - this.disX) + 'px'
+        const top = (event.clientY - this.disY) + 'px'
+        this.curSignDom.style.left = left
+        this.curSignDom.style.top = top
+
+        if (this.batchSign) {
+            this.updateBatchSignPositions(left, top)
+        }
+    }
+
+    // 更新批量签章位置
+    static updateBatchSignPositions(left, top) {
+        const { data: curSign } = this.getSignImgDom(this.curSignDom)
+        if (!curSign) return
+
+        const newArr = this.signList.filter(item => item.type === curSign.type)
+        newArr.forEach(item => {
+            item.dom.style.left = left
+            item.dom.style.top = top
         })
-        this.pdfViewer = viewer
-        //处理pdf渲染
+    }
+
+    // 查看器鼠标抬起事件
+    static viewerMouseUp() {
+        if (!this.curSignDom) return
+
+        this.signType = '签名'
+        this.curSignDom.style.cursor = 'default'
+
+        const { data: curSign } = this.getSignImgDom(this.curSignDom)
+        if (!curSign) return
+
+        const { left, top } = this.calculatePosition(this.curSignDom)
+
         if (this.batchSign) {
-            setTimeout(async () => {
-                await this.setPageScrolling()
-                this.setPdfLoadFunc(true)
-            }, 500)
+            this.updateBatchSignData(curSign, left, top)
         } else {
-            setTimeout(async () => {
-                this.setPdfLoadFunc(true)
-            }, 100)
+            this.updateSignData(curSign, left, top)
+        }
+
+        this.signChangeFunc()
+    }
+
+    // 计算位置
+    static calculatePosition(dom) {
+        const left = parseFloat(dom.style.left)
+        const top = parseFloat(dom.style.top)
+        const { width, height } = this.signImgCss
+        const lefts = left + width / 2
+        const tops = top + height / 2
+        const lx = ((lefts * 100) / dom.parentNode.clientWidth).toFixed(4)
+        const ly = ((tops * 100) / dom.parentNode.clientHeight).toFixed(4)
+        return { lx, ly }
+    }
+
+    // 更新批量签章数据
+    static updateBatchSignData(curSign, lx, ly) {
+        const newArr = this.signList.filter(item => item.type === curSign.type)
+        newArr.forEach(item => {
+            item.lx = lx
+            item.ly = ly
+            item.width = this.curSignDom.clientWidth
+            item.height = this.curSignDom.clientHeight
+        })
+    }
+
+    // 更新签章数据
+    static updateSignData(curSign, lx, ly) {
+        curSign.lx = lx
+        curSign.ly = ly
+        curSign.width = this.curSignDom.clientWidth
+        curSign.height = this.curSignDom.clientHeight
+    }
+
+    // 容器键盘抬起事件
+    static containerKeyUp(event) {
+        if (event.key === 'Backspace') {
+            const { index } = this.getSignImgDom(this.curSignDom)
+            if (index > -1) {
+                this.delSignImg(index)
+            }
         }
     }
 
-    //删除签章
+    // 删除签章
     static async delSignImg(index) {
         if (index <= -1) return
+
         if (this.batchSign) {
-            const list = this.signList, curDom = list[index]
-            //倒序删除签章
-            for (let i = list.length - 1; i >= 0; i--) {
-                if (list[i].type === curDom.type) {
-                    list[i].dom.remove()
-                    delete list[i].dom
-                    list.splice(i, 1)
-                }
-            }
-            this.signList = list
-            this.signChangeFunc()
+            this.deleteBatchSign(index)
         } else {
-            this.signList[index].dom.remove()
-            this.signList.splice(index, 1)
-            this.signChangeFunc()
+            this.deleteSingleSign(index)
+        }
+
+        this.signChangeFunc()
+    }
+
+    // 删除批量签章
+    static deleteBatchSign(index) {
+        const list = this.signList
+        const curDom = list[index]
+        for (let i = list.length - 1; i >= 0; i--) {
+            if (list[i].type === curDom.type) {
+                list[i].dom.remove()
+                delete list[i].dom
+                list.splice(i, 1)
+            }
         }
+        this.signList = list
     }
 
+    // 删除单个签章
+    static deleteSingleSign(index) {
+        this.signList[index].dom.remove()
+        this.signList.splice(index, 1)
+    }
 
-    //获取签章图片的数据
+    // 获取签章图片的数据
     static getSignImgDom(curDom) {
         if (isNullES(curDom)) {
             return { data: null, index: -1 }
         }
-        //获取数据
+
         const id = curDom?.getAttribute('id')
         let curSign = null, index = -1
         for (let i = 0; i < this.signList.length; i++) {
             const item = this.signList[i]
             if (item.id === id) {
                 curSign = item
+                // 获取签章图片的数据(续)
                 index = i
                 break
             }
@@ -365,57 +439,45 @@ export default class HcPdfSign {
         return { data: curSign, index }
     }
 
-    //页面被点击
-    static async viewerClick(event) {
-        const target = event.target
-        //当前为移动模式
-        if (this.signType === '移动') {
-            return
-        }
-        //不在PDF页面上点击
-        if (target.className !== 'textLayer') {
-            return
-        }
-        //批量签章
-        this.signNum ++
-        console.log(this.batchSign)
-        if (this.batchSign) {
-            const parent = target?.parentNode?.parentNode?.children ?? []
-            console.log(parent)
-            for (let i = 0; i < parent.length; i++) {
-                await this.setPdfNodeSign(parent[i], parent[i]?.children[1], event)
-            }
-            this.signChangeFunc()
-        } else {
-            await this.setPdfNodeSign(target?.parentNode, target, event)
-            this.signChangeFunc()
-        }
-    }
-
-    //设置PDF节点签章
+    // 设置PDF节点签章
     static async setPdfNodeSign(node, textLayer, event) {
         if (isNullES(node) || isNullES(textLayer) || isNullES(event)) {
             return
         }
 
-        // if (node.children.length < 3) {
-        //     node.prepend('<div class="signLayer" style="position: absolute;height: 100%;width: 100%;z-index: 999;pointer-events: none;overflow: hidden"></div>')
-        // }
-        //插入图片
+        // 确保有一个容器来放置签名
+        if (node.children.length < 3) {
+            const signLayer = document.createElement('div')
+            signLayer.className = 'signLayer'
+            signLayer.style.cssText = 'position: absolute;height: 100%;width: 100%;z-index: 999;pointer-events: none;overflow: hidden'
+            node.insertBefore(signLayer, node.firstChild)
+        }
+
+        // 插入图片
         const signImgDom = await this.createSignImage(event)
-        node.children[0].append(signImgDom)
-        //鼠标按下
-        signImgDom.addEventListener('mousedown', (e) => {
-            //新的当前选中项
-            this.curSignDom = e.target
-            this.signType = '移动'
-            e.target.style.cursor = 'move'
-            //鼠标相对于图片的位置
-            this.disX = e.clientX - e.target.offsetLeft
-            this.disY = e.clientY - e.target.offsetTop
-        })
-        //保存签章信息
-        this.signList.push({
+        node.children[0].appendChild(signImgDom)
+
+        // 添加鼠标按下事件监听器
+        signImgDom.addEventListener('mousedown', this.handleSignImgMouseDown.bind(this))
+
+        // 保存签章信息
+        this.signList.push(this.createSignInfo(node, textLayer, event, signImgDom))
+
+        return signImgDom
+    }
+
+    // 处理签名图片的鼠标按下事件
+    static handleSignImgMouseDown(e) {
+        this.curSignDom = e.target
+        this.signType = '移动'
+        e.target.style.cursor = 'move'
+        this.disX = e.clientX - e.target.offsetLeft
+        this.disY = e.clientY - e.target.offsetTop
+    }
+
+    // 创建签名信息对象
+    static createSignInfo(node, textLayer, event, signImgDom) {
+        return {
             type: this.signNum,
             url: this.signImgCss?.url ?? '',
             page: node.getAttribute('data-page-number'),
@@ -425,43 +487,27 @@ export default class HcPdfSign {
             width: signImgDom.clientWidth,
             height: signImgDom.clientHeight,
             dom: signImgDom,
-        })
-        return signImgDom
+        }
     }
 
-    //设置PDF签章图片
+    // 设置PDF签章图片
     static async setPdfSignImg(arr) {
         const list = getArrValue(arr)
         if (list.length <= 0) return
+
         const pageDom = this.pdfViewer?.children ?? []
-        for (let i = 0; i < list.length; i++) {
-            const page = Number(list[i].page) - 1
+        for (const item of list) {
+            const page = Number(item.page) - 1
             const dom = pageDom[page]?.getElementsByClassName('canvasWrapper')[0]
-            //创建图片元素
-            const signImg = document.createElement('img')
-            signImg.setAttribute('id', list[i].id)
-            signImg.src = list[i].url
-            signImg.style.position = 'absolute'
-            signImg.style.width = list[i].dom.style.width
-            signImg.style.height = list[i].dom.style.height
-            signImg.style.left = list[i].dom.style.left
-            signImg.style.top = list[i].dom.style.top
-            signImg.style.pointerEvents = 'auto'
-            signImg.style.zIndex = 999
-            dom.append(signImg)
-            //鼠标按下
-            signImg.addEventListener('mousedown', (e) => {
-                //新的当前选中项
-                this.curSignDom = e.target
-                this.signType = '移动'
-                e.target.style.cursor = 'move'
-                //鼠标相对于图片的位置
-                this.disX = e.clientX - e.target.offsetLeft
-                this.disY = e.clientY - e.target.offsetTop
-            })
-            //保存签章信息
+            if (!dom) continue
+
+            const signImg = this.createSignImgElement(item)
+            dom.appendChild(signImg)
+
+            signImg.addEventListener('mousedown', this.handleSignImgMouseDown.bind(this))
+
             this.signList.push({
-                ...list[i],
+                ...item,
                 width: signImg.clientWidth,
                 height: signImg.clientHeight,
                 dom: signImg,
@@ -469,4 +515,20 @@ export default class HcPdfSign {
         }
     }
 
+    // 创建签名图片元素
+    static createSignImgElement(item) {
+        const signImg = document.createElement('img')
+        signImg.setAttribute('id', item.id)
+        signImg.src = item.url
+        signImg.style.cssText = `
+            position: absolute;
+            width: ${item.dom.style.width};
+            height: ${item.dom.style.height};
+            left: ${item.dom.style.left};
+            top: ${item.dom.style.top};
+            pointer-events: auto;
+            z-index: 999;
+        `
+        return signImg
+    }
 }

+ 97 - 0
src/test/hc-pdf1.vue

@@ -0,0 +1,97 @@
+<template>
+    <div v-loading="loading" element-loading-text="加载文件并初始渲染中..." class="h-full">
+        <div :id="`pdf-view-${uuid}`" class="h-full" />
+    </div>
+</template>
+
+<script setup>
+import { onMounted, ref, watch } from 'vue'
+import HcPdfSign from '~src/plugins/HcPdfSign'
+import { getArrValue, getRandom } from 'js-fast-way'
+
+//参数
+const props = defineProps({
+    sign: {
+        type: [String, Number],
+        default: '',
+    },
+    src: {
+        type: [String, Number],
+        default: '',
+    },
+    batch: {
+        type: Boolean,
+        default: false,
+    },
+    dom: {
+        type: Array,
+        default: () => ([]),
+    },
+})
+
+//事件
+const emit = defineEmits(['change'])
+const pdf = ref(props.src)
+const uuid = getRandom(6)
+const signImg = ref(props.sign)
+const loading = ref(false)
+
+//监听PDFurl
+watch(() => props.src, (src) => {
+    if (src) {
+        loading.value = true
+        pdf.value = src
+        getPdf()
+    } else {
+        noPdfUrl()
+    }
+})
+
+//监听签章图片
+watch(() => props.sign, (val) => {
+    signImg.value = val
+    getPdf()
+})
+
+//监听是否批量签章
+watch(() => props.batch, (val) => {
+    HcPdfSign.setBatchSign(val)
+}, { immediate: true })
+
+//渲染完成
+onMounted(()=> {
+    getPdf()
+})
+
+//设置PDF签章实例
+const getPdf = () => {
+    if (!pdf.value) {
+        noPdfUrl()
+        return false
+    }
+    HcPdfSign.createPdf({
+        ele: 'pdf-view-' + uuid, //挂载元素的id
+        url: pdf.value, //pdf的url地址
+        img: signImg.value, //签章图片的url地址
+        //加载完成
+        load: () => {
+            //恢复签章记录
+            setTimeout(()=> {
+                HcPdfSign.setPdfSignImg(getArrValue(props.dom))
+                loading.value = false
+            }, 500)
+        },
+        //签章数据改变
+        change: (data) => {
+            emit('change', data)
+        },
+        isShowYinzhang: signImg.value.length > 0,
+    })
+}
+
+const noPdfUrl = () => {
+    pdf.value = ''
+    loading.value = false
+    document.getElementById('pdf-view-' + uuid).innerHTML = ''
+}
+</script>

+ 10 - 20
src/test/index.vue

@@ -1,32 +1,22 @@
 <template>
     <div class="hc-page-box">
-        <hc-new-card title="测试">
-            <template #extra>
-                <hc-upload-file use-file :options="upFileOpt" @success="upFileSuc" @item="upFileItem">
-                    <el-button type="primary" hc-btn>上传文件</el-button>
-                </hc-upload-file>
-            </template>
+        <hc-new-card title="测试签章">
+            <HcSignPdf :batch="isBatch" :dom="hcSignImageArr" :sign="logoName" :src="pdfUrl" @change="pdfChange" />
         </hc-new-card>
     </div>
 </template>
 
 <script setup>
-import { getHeader } from 'hc-vue3-ui'
+import { ref } from 'vue'
+import HcSignPdf from './hc-pdf1.vue'
 
-//上传配置
-const upFileOpt = {
-    accept: '*',
-    accept_tip: '',
-    headers: getHeader(),
-}
+const isBatch = ref(true)
+const pdfUrl = 'https://blade-oss-chongqing.oss-cn-shenzhen.aliyuncs.com//upload/20240816/c584d958a8cbcd7e3e3a163dc0976339.pdf'
 
-// 文件上传成功的回调
-const upFileSuc = (res) => {
-    console.log('上传成功:', res?.resData?.link)
-}
+const hcSignImageArr = ref([])
+const logoName = ref('https://blade-oss-chongqing.oss-cn-shenzhen.aliyuncs.com//upload/20231019/5cd4978468e45c123a37fd9515cb535f.png')
 
-// 点击了使用此文件的事件
-const upFileItem = ({ item }) => {
-    console.log(item?.resData?.link)
+const pdfChange = (data) => {
+    console.log('签章数据', data)
 }
 </script>

+ 100 - 91
yarn.lock

@@ -1022,90 +1022,90 @@
   resolved "http://39.108.216.210:9000/@vitejs/plugin-vue/-/plugin-vue-5.1.2.tgz#f11091e0130eca6c1ca8cfb85ee71ea53b255d31"
   integrity sha512-nY9IwH12qeiJqumTCLJLE7IiNx7HZ39cbHaysEUd+Myvbz9KAqd2yq+U01Kab1R/H1BmiyM2ShTYlNH32Fzo3A==
 
-"@vue/compiler-core@3.4.36":
-  version "3.4.36"
-  resolved "http://39.108.216.210:9000/@vue/compiler-core/-/compiler-core-3.4.36.tgz#4e28dfcbaa8a85e135f7a94c44372b6d52329e42"
-  integrity sha512-qBkndgpwFKdupmOPoiS10i7oFdN7a+4UNDlezD0GlQ1kuA1pNrscg9g12HnB5E8hrWSuEftRsbJhL1HI2zpJhg==
+"@vue/compiler-core@3.4.38":
+  version "3.4.38"
+  resolved "http://39.108.216.210:9000/@vue/compiler-core/-/compiler-core-3.4.38.tgz#326dfe3c92fa2b0f1dc9b39a948a231980253496"
+  integrity sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==
   dependencies:
     "@babel/parser" "^7.24.7"
-    "@vue/shared" "3.4.36"
-    entities "^5.0.0"
+    "@vue/shared" "3.4.38"
+    entities "^4.5.0"
     estree-walker "^2.0.2"
     source-map-js "^1.2.0"
 
-"@vue/compiler-dom@3.4.36":
-  version "3.4.36"
-  resolved "http://39.108.216.210:9000/@vue/compiler-dom/-/compiler-dom-3.4.36.tgz#32f5f65d1fb242211df2ddc65a336779cd8b974c"
-  integrity sha512-eEIjy4GwwZTFon/Y+WO8tRRNGqylaRlA79T1RLhUpkOzJ7EtZkkb8MurNfkqY6x6Qiu0R7ESspEF7GkPR/4yYg==
+"@vue/compiler-dom@3.4.38":
+  version "3.4.38"
+  resolved "http://39.108.216.210:9000/@vue/compiler-dom/-/compiler-dom-3.4.38.tgz#90348fac1130e0bbd408b650635cb626b3b9df06"
+  integrity sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==
   dependencies:
-    "@vue/compiler-core" "3.4.36"
-    "@vue/shared" "3.4.36"
+    "@vue/compiler-core" "3.4.38"
+    "@vue/shared" "3.4.38"
 
-"@vue/compiler-sfc@3.4.36", "@vue/compiler-sfc@^3.4.36":
-  version "3.4.36"
-  resolved "http://39.108.216.210:9000/@vue/compiler-sfc/-/compiler-sfc-3.4.36.tgz#887809183a273dc0ef8337d5e84ef6a781727ccc"
-  integrity sha512-rhuHu7qztt/rNH90dXPTzhB7hLQT2OC4s4GrPVqmzVgPY4XBlfWmcWzn4bIPEWNImt0CjO7kfHAf/1UXOtx3vw==
+"@vue/compiler-sfc@3.4.38", "@vue/compiler-sfc@^3.4.38":
+  version "3.4.38"
+  resolved "http://39.108.216.210:9000/@vue/compiler-sfc/-/compiler-sfc-3.4.38.tgz#954c3f6777bbbcca28771ba59b795f12f76ef188"
+  integrity sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==
   dependencies:
     "@babel/parser" "^7.24.7"
-    "@vue/compiler-core" "3.4.36"
-    "@vue/compiler-dom" "3.4.36"
-    "@vue/compiler-ssr" "3.4.36"
-    "@vue/shared" "3.4.36"
+    "@vue/compiler-core" "3.4.38"
+    "@vue/compiler-dom" "3.4.38"
+    "@vue/compiler-ssr" "3.4.38"
+    "@vue/shared" "3.4.38"
     estree-walker "^2.0.2"
     magic-string "^0.30.10"
     postcss "^8.4.40"
     source-map-js "^1.2.0"
 
-"@vue/compiler-ssr@3.4.36":
-  version "3.4.36"
-  resolved "http://39.108.216.210:9000/@vue/compiler-ssr/-/compiler-ssr-3.4.36.tgz#5881f9303ad6a4fdf04fb4238ebb483caf040707"
-  integrity sha512-Wt1zyheF0zVvRJyhY74uxQbnkXV2Le/JPOrAxooR4rFYKC7cFr+cRqW6RU3cM/bsTy7sdZ83IDuy/gLPSfPGng==
+"@vue/compiler-ssr@3.4.38":
+  version "3.4.38"
+  resolved "http://39.108.216.210:9000/@vue/compiler-ssr/-/compiler-ssr-3.4.38.tgz#9ded18f6d9c8b2440039a58492cfff36fa1a7774"
+  integrity sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==
   dependencies:
-    "@vue/compiler-dom" "3.4.36"
-    "@vue/shared" "3.4.36"
+    "@vue/compiler-dom" "3.4.38"
+    "@vue/shared" "3.4.38"
 
 "@vue/devtools-api@^6.6.3":
   version "6.6.3"
   resolved "http://39.108.216.210:9000/@vue/devtools-api/-/devtools-api-6.6.3.tgz#b23a588154cba8986bba82b6e1d0248bde3fd1a0"
   integrity sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==
 
-"@vue/reactivity@3.4.36":
-  version "3.4.36"
-  resolved "http://39.108.216.210:9000/@vue/reactivity/-/reactivity-3.4.36.tgz#f0797308b1639db7f303e91fdd20577ad538a817"
-  integrity sha512-wN1aoCwSoqrt1yt8wO0gc13QaC+Vk1o6AoSt584YHNnz6TGDhh1NCMUYgAnvp4HEIkLdGsaC1bvu/P+wpoDEXw==
+"@vue/reactivity@3.4.38":
+  version "3.4.38"
+  resolved "http://39.108.216.210:9000/@vue/reactivity/-/reactivity-3.4.38.tgz#ec2d549f4b831cd03d0baabf7d77e840b8536000"
+  integrity sha512-4vl4wMMVniLsSYYeldAKzbk72+D3hUnkw9z8lDeJacTxAkXeDAP1uE9xr2+aKIN0ipOL8EG2GPouVTH6yF7Gnw==
   dependencies:
-    "@vue/shared" "3.4.36"
+    "@vue/shared" "3.4.38"
 
-"@vue/runtime-core@3.4.36":
-  version "3.4.36"
-  resolved "http://39.108.216.210:9000/@vue/runtime-core/-/runtime-core-3.4.36.tgz#7d956671800b2567deebf4a5f92cb476404dfa94"
-  integrity sha512-9+TR14LAVEerZWLOm/N/sG2DVYhrH2bKgFrbH/FVt/Q8Jdw4OtdcGMRC6Tx8VAo0DA1eqAqrZaX0fbOaOxxZ4A==
+"@vue/runtime-core@3.4.38":
+  version "3.4.38"
+  resolved "http://39.108.216.210:9000/@vue/runtime-core/-/runtime-core-3.4.38.tgz#bead9085e9a1c5a446e27d74ffb450f9261cf097"
+  integrity sha512-21z3wA99EABtuf+O3IhdxP0iHgkBs1vuoCAsCKLVJPEjpVqvblwBnTj42vzHRlWDCyxu9ptDm7sI2ZMcWrQqlA==
   dependencies:
-    "@vue/reactivity" "3.4.36"
-    "@vue/shared" "3.4.36"
+    "@vue/reactivity" "3.4.38"
+    "@vue/shared" "3.4.38"
 
-"@vue/runtime-dom@3.4.36":
-  version "3.4.36"
-  resolved "http://39.108.216.210:9000/@vue/runtime-dom/-/runtime-dom-3.4.36.tgz#e4eeeba2cb2b9645de45eebd023939a35fff5e30"
-  integrity sha512-2Qe2fKkLxgZBVvHrG0QMNLL4bsx7Ae88pyXebY2WnQYABpOnGYvA+axMbcF9QwM4yxnsv+aELbC0eiNVns7mGw==
+"@vue/runtime-dom@3.4.38":
+  version "3.4.38"
+  resolved "http://39.108.216.210:9000/@vue/runtime-dom/-/runtime-dom-3.4.38.tgz#52678ba0b85f94400a0a9c8dd23ddef4dd65657d"
+  integrity sha512-afZzmUreU7vKwKsV17H1NDThEEmdYI+GCAK/KY1U957Ig2NATPVjCROv61R19fjZNzMmiU03n79OMnXyJVN0UA==
   dependencies:
-    "@vue/reactivity" "3.4.36"
-    "@vue/runtime-core" "3.4.36"
-    "@vue/shared" "3.4.36"
+    "@vue/reactivity" "3.4.38"
+    "@vue/runtime-core" "3.4.38"
+    "@vue/shared" "3.4.38"
     csstype "^3.1.3"
 
-"@vue/server-renderer@3.4.36":
-  version "3.4.36"
-  resolved "http://39.108.216.210:9000/@vue/server-renderer/-/server-renderer-3.4.36.tgz#352138e6a31a5eeabcbb75e66f6919f607f8c870"
-  integrity sha512-2XW90Rq8+Y7S1EIsAuubZVLm0gCU8HYb5mRAruFdwfC3XSOU5/YKePz29csFzsch8hXaY5UHh7ZMddmi1XTJEA==
+"@vue/server-renderer@3.4.38":
+  version "3.4.38"
+  resolved "http://39.108.216.210:9000/@vue/server-renderer/-/server-renderer-3.4.38.tgz#457401ef2b0f969156702061e56915acecc9fe2c"
+  integrity sha512-NggOTr82FbPEkkUvBm4fTGcwUY8UuTsnWC/L2YZBmvaQ4C4Jl/Ao4HHTB+l7WnFCt5M/dN3l0XLuyjzswGYVCA==
   dependencies:
-    "@vue/compiler-ssr" "3.4.36"
-    "@vue/shared" "3.4.36"
+    "@vue/compiler-ssr" "3.4.38"
+    "@vue/shared" "3.4.38"
 
-"@vue/shared@3.4.36":
-  version "3.4.36"
-  resolved "http://39.108.216.210:9000/@vue/shared/-/shared-3.4.36.tgz#7551f41684966acb6a307152b49a8308e7f69203"
-  integrity sha512-fdPLStwl1sDfYuUftBaUVn2pIrVFDASYerZSrlBvVBfylObPA1gtcWJHy5Ox8jLEJ524zBibss488Q3SZtU1uA==
+"@vue/shared@3.4.38":
+  version "3.4.38"
+  resolved "http://39.108.216.210:9000/@vue/shared/-/shared-3.4.38.tgz#552a6770098bfd556fa3e2c686c9d3b4f4cd94c2"
+  integrity sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==
 
 "@vueuse/core@^9.1.0":
   version "9.13.0"
@@ -1261,10 +1261,10 @@ autoprefixer@^10.4.20:
     picocolors "^1.0.1"
     postcss-value-parser "^4.2.0"
 
-axios@^1.7.3:
-  version "1.7.3"
-  resolved "http://39.108.216.210:9000/axios/-/axios-1.7.3.tgz#a1125f2faf702bc8e8f2104ec3a76fab40257d85"
-  integrity sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==
+axios@^1.7.4:
+  version "1.7.4"
+  resolved "http://39.108.216.210:9000/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2"
+  integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==
   dependencies:
     follow-redirects "^1.15.6"
     form-data "^4.0.0"
@@ -1620,10 +1620,10 @@ electron-to-chromium@^1.5.4:
   resolved "http://39.108.216.210:9000/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz#cd477c830dd6fca41fbd5465c1ff6ce08ac22343"
   integrity sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==
 
-element-plus@^2.7.8:
-  version "2.7.8"
-  resolved "http://39.108.216.210:9000/element-plus/-/element-plus-2.7.8.tgz#5de53bbcb455653a27b43418e3569a22ead59866"
-  integrity sha512-h6dx2XihAbQaud0v+6O7Fy0b0G3YNplNVH7QnK3csTcvQd4y4raiyMRQpf9EKbRbTMdNrFsqAZrs9ok9DMcJHg==
+element-plus@^2.8.0:
+  version "2.8.0"
+  resolved "http://39.108.216.210:9000/element-plus/-/element-plus-2.8.0.tgz#122685f9f1e01784f511dd4858fe005677ad1b95"
+  integrity sha512-7ngapVlVlQAjocVqD4MUKvKXlBneT9DSDk2mmBOSLRFWNm/HLDT15ozmsvUBfy18sajnyUeSIHTtINE8gfrGMg==
   dependencies:
     "@ctrl/tinycolor" "^3.4.1"
     "@element-plus/icons-vue" "^2.3.1"
@@ -1651,10 +1651,10 @@ emoji-regex@^9.2.2:
   resolved "http://39.108.216.210:9000/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
   integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
 
-entities@^5.0.0:
-  version "5.0.0"
-  resolved "http://39.108.216.210:9000/entities/-/entities-5.0.0.tgz#b2ab51fe40d995817979ec79dd621154c3c0f62b"
-  integrity sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==
+entities@^4.5.0:
+  version "4.5.0"
+  resolved "http://39.108.216.210:9000/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
+  integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
 
 esbuild@^0.21.3:
   version "0.21.5"
@@ -2053,19 +2053,19 @@ has-flag@^4.0.0:
   resolved "http://39.108.216.210:9000/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
   integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
 
-hc-vue3-ui@^4.1.5:
-  version "4.1.5"
-  resolved "http://39.108.216.210:9000/hc-vue3-ui/-/hc-vue3-ui-4.1.5.tgz#a2e0310678d1568f0ad2e12439434682efdff382"
-  integrity sha512-eFDKqhp0g1urOD0tO5nq+IEtPNl/sble6bahjRN6N7k+i9znS8XSC1T+o9bpVsIqyxqaFTJKn9/R9I+gNXq3kw==
+hc-vue3-ui@^4.1.6:
+  version "4.1.6"
+  resolved "http://39.108.216.210:9000/hc-vue3-ui/-/hc-vue3-ui-4.1.6.tgz#8997a29c818a009e3436b8ed9cad269fe3776b6c"
+  integrity sha512-g3GTPNcoH9NblPCSqki1aKpHaW7CPqOwMGDBqgxhAtvZU0lD7xaV86zINyTeYiVNTszOow+1Jea2Hl25LTeUHQ==
   dependencies:
-    axios "^1.7.3"
+    axios "^1.7.4"
     dayjs "^1.11.12"
     js-base64 "^3.7.7"
     js-fast-way "^0.5.6"
     js-md5 "^0.8.3"
     sortablejs "^1.15.1"
     split.js "^1.6.5"
-    vue "3.4.36"
+    vue "3.4.38"
 
 html2canvas@1.4.1:
   version "1.4.1"
@@ -2612,10 +2612,10 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
   resolved "http://39.108.216.210:9000/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
   integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
 
-pinia@^2.2.1:
-  version "2.2.1"
-  resolved "http://39.108.216.210:9000/pinia/-/pinia-2.2.1.tgz#7cf860f6a23981c23e58605cee45496ce46d15d1"
-  integrity sha512-ltEU3xwiz5ojVMizdP93AHi84Rtfz0+yKd8ud75hr9LVyWX2alxp7vLbY1kFm7MXFmHHr/9B08Xf8Jj6IHTEiQ==
+pinia@^2.2.2:
+  version "2.2.2"
+  resolved "http://39.108.216.210:9000/pinia/-/pinia-2.2.2.tgz#dcf576c9a778187d1542c5e6a9f8b8cd5b6aea14"
+  integrity sha512-ja2XqFWZC36mupU4z1ZzxeTApV7DOw44cV4dhQ9sGwun+N89v/XP7+j7q6TanS1u1tdbK4r+1BUx7heMaIdagA==
   dependencies:
     "@vue/devtools-api" "^6.6.3"
     vue-demi "^0.14.10"
@@ -2651,7 +2651,7 @@ postcss@^8.4.38:
     picocolors "^1.0.0"
     source-map-js "^1.2.0"
 
-postcss@^8.4.39, postcss@^8.4.40:
+postcss@^8.4.40:
   version "8.4.40"
   resolved "http://39.108.216.210:9000/postcss/-/postcss-8.4.40.tgz#eb81f2a4dd7668ed869a6db25999e02e9ad909d8"
   integrity sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==
@@ -2660,6 +2660,15 @@ postcss@^8.4.39, postcss@^8.4.40:
     picocolors "^1.0.1"
     source-map-js "^1.2.0"
 
+postcss@^8.4.41:
+  version "8.4.41"
+  resolved "http://39.108.216.210:9000/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681"
+  integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==
+  dependencies:
+    nanoid "^3.3.7"
+    picocolors "^1.0.1"
+    source-map-js "^1.2.0"
+
 prelude-ls@^1.2.1:
   version "1.2.1"
   resolved "http://39.108.216.210:9000/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@@ -3134,13 +3143,13 @@ utrie@^1.0.2:
   dependencies:
     base64-arraybuffer "^1.0.2"
 
-vite@^5.3.5:
-  version "5.3.5"
-  resolved "http://39.108.216.210:9000/vite/-/vite-5.3.5.tgz#b847f846fb2b6cb6f6f4ed50a830186138cb83d8"
-  integrity sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==
+vite@^5.4.1:
+  version "5.4.1"
+  resolved "http://39.108.216.210:9000/vite/-/vite-5.4.1.tgz#2aa72370de824d23f53658affd807e4c9905b058"
+  integrity sha512-1oE6yuNXssjrZdblI9AfBbHCC41nnyoVoEZxQnID6yvQZAFBzxxkqoFLtHUMkYunL8hwOLEjgTuxpkRxvba3kA==
   dependencies:
     esbuild "^0.21.3"
-    postcss "^8.4.39"
+    postcss "^8.4.41"
     rollup "^4.13.0"
   optionalDependencies:
     fsevents "~2.3.3"
@@ -3199,16 +3208,16 @@ vue-virtual-scroller@^2.0.0-beta.8:
     vue-observe-visibility "^2.0.0-alpha.1"
     vue-resize "^2.0.0-alpha.1"
 
-vue@3.4.36:
-  version "3.4.36"
-  resolved "http://39.108.216.210:9000/vue/-/vue-3.4.36.tgz#b2d9af110c8e9afdf08f4eec0d9196949877447c"
-  integrity sha512-mIFvbLgjODfx3Iy1SrxOsiPpDb8Bo3EU+87ioimOZzZTOp15IEdAels70IjBOLO3ZFlLW5AhdwY4dWbXVQKYow==
+vue@3.4.38:
+  version "3.4.38"
+  resolved "http://39.108.216.210:9000/vue/-/vue-3.4.38.tgz#0ccbb64ed03ef3c4ab73e540793290b18e7c4236"
+  integrity sha512-f0ZgN+mZ5KFgVv9wz0f4OgVKukoXtS3nwET4c2vLBGQR50aI8G0cqbFtLlX9Yiyg3LFGBitruPHt2PxwTduJEw==
   dependencies:
-    "@vue/compiler-dom" "3.4.36"
-    "@vue/compiler-sfc" "3.4.36"
-    "@vue/runtime-dom" "3.4.36"
-    "@vue/server-renderer" "3.4.36"
-    "@vue/shared" "3.4.36"
+    "@vue/compiler-dom" "3.4.38"
+    "@vue/compiler-sfc" "3.4.38"
+    "@vue/runtime-dom" "3.4.38"
+    "@vue/server-renderer" "3.4.38"
+    "@vue/shared" "3.4.38"
 
 vuedraggable@^4.1.0:
   version "4.1.0"

Some files were not shown because too many files changed in this diff