Bladeren bron

add: 自定义签名外观弹窗及绘制弹窗、上传数字身份证弹窗 UI

wzl 11 maanden geleden
bovenliggende
commit
d1b9bd826b

+ 1 - 1
packages/core/src/ink_sign.js

@@ -24,7 +24,7 @@ class InkSign {
   }
 
   init () {
-    this.canvas = document.getElementById('trackpadCanvas')
+    this.canvas = document.getElementById('electronicTrackpadCanvas')
     this.ctx = this.canvas.getContext('2d')
     this.canvas.style.cursor = 'crosshair'
 

+ 38 - 1
packages/webview/locales/en.json

@@ -191,6 +191,7 @@
   },
   "ok": "OK",
   "cancel": "Cancel",
+  "continue": "Continue",
 
   "signatures": {
     "trackpad": "Trackpad",
@@ -202,6 +203,8 @@
     "image": "Image",
     "selectFile": "Select a File",
 
+    "none": "None",
+
     "clear": "Clear",
     "save": "Save and Apply",
     "uploadError": "Please upload images less than 1MB",
@@ -264,7 +267,41 @@
       "done": "Done"
     },
 
-    "deleteConfirm": "Are you sure to delete it?"
+    "deleteConfirm": "Are you sure to delete it?",
+
+    "addDigitalFileDialog": {
+      "title": "Add a Digital ID",
+      "desc": "Browse a digital ID file. Digital IDs are password-protected. If you do not know the password, you cannot obtain a digital ID.",
+      "certificateFile": "Certificate File",
+      "uploadFile": "Upload your certificate file",
+      "upload": "Upload",
+      "password": "Password",
+      "enterPassword": "Enter the password of the certificate file",
+      "invalidPassword": "Invalid Password"
+    },
+
+    "appearanceDialog": {
+      "title": "Customize the Signature Appearance",
+      "signHere": "Sign Here!",
+
+      "includeText": "Include Text",
+      "name": "Name",
+      "dName": "Distinguishable name",
+      "date": "Date",
+      "ComPDFKitVersion": "ComPDFKit Version",
+      "logo": "Logo",
+      "location": "Location",
+      "reason": "Reason",
+      "signReason": "Reason",
+      "docOwner": "I am the owner of the document",
+      "approvingDoc": "I am approving the document",
+      "reviewedDoc": "I have reviewed this document",
+      "labels": "Labels",
+
+      "text": "Text",
+      "type": "Type",
+      "textAlignment": "Text Alignment"
+    }
   },
   "color": "Color",
   "opacity": "Opacity",

+ 38 - 1
packages/webview/locales/zh-CN.json

@@ -191,6 +191,7 @@
   },
   "ok": "确定",
   "cancel": "取消",
+  "continue": "继续",
 
   "signatures": {
     "trackpad": "触摸板",
@@ -202,6 +203,8 @@
     "image": "图片",
     "selectFile": "选择文件",
 
+    "none": "无",
+
     "clear": "清除",
     "save": "保存",
     "uploadError": "请上传1M以内的图片",
@@ -264,7 +267,41 @@
       "done": "关闭"
     },
 
-    "deleteConfirm": "确定删除该内容?"
+    "deleteConfirm": "确定删除该内容?",
+
+    "addDigitalFileDialog": {
+      "title": "添加数字身份证",
+      "desc": "浏览数字身份证文件。数字身份证受密码保护。如果你不知道密码,你就无法获取数字身份证。",
+      "certificateFile": "证书文件",
+      "uploadFile": "上传你的证书文件",
+      "upload": "浏览",
+      "password": "证书密码",
+      "enterPassword": "请输入证书密码",
+      "invalidPassword": "密码错误,请重试"
+    },
+
+    "appearanceDialog": {
+      "title": "自定义签名外观",
+      "signHere": "请在此处输入签名!",
+
+      "includeText": "包含文本",
+      "name": "名称",
+      "dName": "辨别名",
+      "date": "日期",
+      "ComPDFKitVersion": "ComPDFKit 版本",
+      "logo": "徽标",
+      "location": "位置",
+      "reason": "原因",
+      "signReason": "签署原因",
+      "docOwner": "我是该文档的作者",
+      "approvingDoc": "我正在批准该文档",
+      "reviewedDoc": "我已审阅该文档",
+      "labels": "标签",
+
+      "text": "字体",
+      "type": "字形",
+      "textAlignment": "对齐方式"
+    }
   },
   "color": "颜色",
   "opacity": "不透明度",

BIN
packages/webview/public/images/logo-backgroud.png


BIN
packages/webview/public/images/logo-backgroud@2x.png


+ 150 - 0
packages/webview/src/components/Dialogs/AddDigitalFileDialog.vue

@@ -0,0 +1,150 @@
+<template>
+  <div class="add-digital-file-dialog" v-if="show">
+    <Dialog :show="show" :dialogName="dialogName" :close="true">
+      <template #header>{{ $t('signatures.addDigitalFileDialog.title') }}</template>
+
+      <p>{{ $t('signatures.addDigitalFileDialog.desc') }}</p>
+      <div class="input-file row">
+        <span>{{ $t('signatures.addDigitalFileDialog.certificateFile') }}</span>
+        <div class="addition">
+          <div class="file-input-underbox">
+            <span :class="{ 'uploaded': inputFile?.name }">{{ inputFile?.name || $t('signatures.addDigitalFileDialog.uploadFile') }}</span>
+            <FileFolder />
+          </div>
+          <input type="file" @change="handleFile" accept=".pdf">
+        </div>
+      </div>
+      <div class="input-pwd row">
+        <span>{{ $t('signatures.addDigitalFileDialog.password') }}</span>
+        <div>
+          <input type="text" :placeholder="$t('signatures.addDigitalFileDialog.enterPassword')">
+          <p v-if="isError" class="error-text">{{ $t('signatures.addDigitalFileDialog.invalidPassword') }}</p>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="rect-button white" @click="closeDialog">{{ $t('cancel') }}</div>
+        <div class="rect-button blue" @click="next">{{ $t('continue') }}</div>
+      </template>
+    </Dialog>
+  </div>
+</template>
+
+<script setup>
+import { computed, ref, watch } from 'vue'
+import { useViewerStore } from '@/stores/modules/viewer'
+import { useDocumentStore } from '@/stores/modules/document'
+import core from '@/core'
+
+const dialogName = 'addDigitalFileDialog'
+
+const useViewer = useViewerStore()
+const useDocument = useDocumentStore()
+
+const show = computed(() => useViewer.isElementOpen(dialogName))
+
+const inputFile = ref(null)
+const isError = ref(false)
+
+watch(() => show.value, (newVal, oldVal) => {
+  if (newVal) {
+    inputFile.value = null
+    isError.value = false
+  }
+})
+
+const closeDialog = () => {
+  useViewer.closeElement(dialogName)
+}
+
+const next = () => {
+  if (!validatePwd()) return
+  closeDialog()
+  useViewer.openElement('signatureAppearanceDialog')
+}
+
+const validatePwd = () => {
+  return true
+  // isError.value = true
+  // return false
+}
+</script>
+
+<style lang="scss">
+.add-digital-file-dialog {
+
+  .dialog-container {
+    width: 450px;
+
+    .close {
+      float: right;
+      margin-top: 4px;
+    }
+  }
+
+  .row {
+    display: flex;
+    justify-content: space-between;
+  }
+
+  .input-file {
+    margin: 20px 0;
+
+    .addition {
+      position: relative;
+      display: flex;
+      align-items: center;
+
+      .file-input-underbox {
+        display: flex;
+        align-items: center;
+        color: #999;
+
+        .uploaded {
+          color: var(--c-text);
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+
+        svg {
+          position: absolute;
+          right: 4px;
+          pointer-events: none;
+          color: var(--c-side-outline-text);
+        }
+      }
+    }
+  }
+
+  input,
+  .file-input-underbox {
+    padding: 0 20px 0 8px;
+    width: 300px;
+    height: 24px;
+    background: var(--c-right-side-content-fillbox-bg);
+    border: 1px solid var(--c-right-side-content-fillbox-border);
+    border-radius: 1px;
+    font-size: 14px;
+    line-height: 16px;
+  }
+
+  input[type="file"] {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    opacity: 0;
+    cursor: pointer;
+
+    &::file-selector-button {
+      cursor: pointer;
+    }
+  }
+  
+  .input-pwd {
+
+    .error-text {
+      color: red;
+    }
+  }
+}
+</style>

+ 2 - 2
packages/webview/src/components/Dialogs/SelectSignTypeDialog.vue

@@ -43,7 +43,7 @@ const activeTool = computed(() => useDocument.getActiveTool)
 const type = ref('electronic')
 
 const showDialog = () => {
-  if (activeTool.value === 'addDigitalSign') useViewer.openElement('signatureAppearanceDialog')
+  if (activeTool.value === 'addDigitalSign') useViewer.openElement('addDigitalFileDialog')
   else if (activeTool.value === 'addElectronicSign') openSignCreatePanel()
   else useViewer.openElement('selectSignTypeDialog')
 }
@@ -51,7 +51,7 @@ core.addEvent('openSelectSignTypeDialog', showDialog)
 
 const toSign = () => {
   useViewer.closeElement(dialogName)
-  if (type.value === 'digital') useViewer.openElement('signatureAppearanceDialog')
+  if (type.value === 'digital') useViewer.openElement('addDigitalFileDialog')
   else openSignCreatePanel()
 }
 

+ 382 - 51
packages/webview/src/components/Dialogs/SignatureAppearanceDialog.vue

@@ -1,8 +1,8 @@
 <template>
   <div class="signature-appearance-dialog" v-if="show">
-    <Dialog :show="show" :dialogName="dialogName">
+    <Dialog :show="show" :dialogName="dialogName" class="appearance-dialog">
       <template #header>
-        <p>Customize the Signature Appearance</p>
+        <p>{{ $t('signatures.appearanceDialog.title') }}</p>
         <CloseB class="close" @click="closePanel" />
       </template>
 
@@ -10,33 +10,132 @@
         <div @click="changeActiveSignWay('trackpad')" :class="{ active: activeSignWay === 'trackpad' }">{{ $t('signatures.trackpad') }}</div>
         <div @click="changeActiveSignWay('keyboard')" :class="{ active: activeSignWay === 'keyboard' }">{{ $t('signatures.keyboard') }}</div>
         <div @click="changeActiveSignWay('image')" :class="{ active: activeSignWay === 'image' }">{{ $t('signatures.image') }}</div>
+        <div @click="changeActiveSignWay('none')" :class="{ active: activeSignWay === 'none' }">{{ $t('signatures.none') }}</div>
+      </div>
+
+      <div class="preview-area" @click="drawDialogShow = activeSignWay === 'trackpad' ? true : drawDialogShow"></div>
+
+      <div class="preview-options" v-if="!(activeSignWay === 'none')">
+        <span v-if="activeSignWay === 'image'" class="upload">{{ $t('upload') }}<input type="file" @change="handleFile" accept=".png, .jpg, .jpeg" @click="clickUpload"></span>
+        <span @click="clearData">{{ $t('signatures.clear') }}</span>
       </div>
-      <div class="paint-container">
-        <!-- 手绘签名 -->
-        <canvas v-show="activeSignWay === 'trackpad'" id="trackpadCanvas" width="578" height="240"></canvas>
 
-        <!-- 文本签名 -->
-        <div class="keyboard-paint" v-show="activeSignWay === 'keyboard'">
-          <input type="text" :placeholder="$t('signatures.signHere')" v-model="textSgin">
+      <p class="title">{{ $t('signatures.appearanceDialog.includeText') }}</p>
+      <div class="configurations">
+        <div class="left">
+          <div class="checkboxes">
+            <div class="check-box" @click="configurations.name = !configurations.name">
+              <div class="check" :class="{'active': configurations.name}"><Checkbox v-show="configurations.name" /></div>
+              <span>{{ $t('signatures.appearanceDialog.name') }}</span>
+            </div>
+            <div class="check-box" @click="configurations.dName = !configurations.dName">
+              <div class="check" :class="{'active': configurations.dName}"><Checkbox v-show="configurations.dName" /></div>
+              <span>{{ $t('signatures.appearanceDialog.dName') }}</span>
+            </div>
+            <div class="check-box" @click="configurations.date = !configurations.date">
+              <div class="check" :class="{'active': configurations.date}"><Checkbox v-show="configurations.date" /></div>
+              <span>{{ $t('signatures.appearanceDialog.date') }}</span>
+            </div>
+            <div class="check-box" @click="configurations.version = !configurations.version">
+              <div class="check" :class="{'active': configurations.version}"><Checkbox v-show="configurations.version" /></div>
+              <span>{{ $t('signatures.appearanceDialog.ComPDFKitVersion') }}</span>
+            </div>
+            <div class="check-box" @click="configurations.logo = !configurations.logo">
+              <div class="check" :class="{'active': configurations.logo}"><Checkbox v-show="configurations.logo" /></div>
+              <span>{{ $t('signatures.appearanceDialog.logo') }}</span>
+            </div>
+            <div class="check-box" @click="configurations.location = !configurations.location">
+              <div class="check" :class="{'active': configurations.location}"><Checkbox v-show="configurations.location" /></div>
+              <span>{{ $t('signatures.appearanceDialog.location') }}</span>
+            </div>
+            <div class="check-box" @click="configurations.reason = !configurations.reason">
+              <div class="check" :class="{'active': configurations.reason}"><Checkbox v-show="configurations.reason" /></div>
+              <span>{{ $t('signatures.appearanceDialog.reason') }}</span>
+            </div>
+            <div class="check-box" @click="configurations.labels = !configurations.labels">
+              <div class="check" :class="{'active': configurations.labels}"><Checkbox v-show="configurations.labels" /></div>
+              <span>{{ $t('signatures.appearanceDialog.labels') }}</span>
+            </div>
+          </div>
+
+          <div class="addition" v-if="configurations.reason || configurations.location">
+            <div v-if="configurations.reason">
+              <span>{{ $t('signatures.appearanceDialog.reason') }}</span>
+              <div class="select-box">
+                <select v-model="configurations.reasonSelectVal">
+                  <option value="none">&lt;None&gt;</option>
+                  <option value="Courier">Courier</option>
+                  <option value="Times">Times-Roman</option>
+                </select>
+                <ArrowDown />
+              </div>
+            </div>
+            <div v-if="configurations.location">
+              <span>{{ $t('signatures.appearanceDialog.location') }}</span>
+              <input type="text" v-model="configurations.locationInputVal">
+            </div>
+          </div>
         </div>
 
-        <!-- 图片签名 -->
-        <div class="image-paint" v-show="activeSignWay === 'image'">
-          <a>{{ $t('signatures.selectFile') }}<input type="file" id="signImageInput" @change="handleFile" accept=".png, .jpg, .jpeg" @click="clickUpload"></a>
+        <div class="right">
+          <div class="grid-box">
+            <span>{{ $t('signatures.appearanceDialog.text') }}</span>
+            <div class="select-box">
+              <select v-model="configurations.text">
+                <option value="Helvetica">Helvetica</option>
+                <option value="Courier">Courier</option>
+                <option value="Times">Times-Roman</option>
+              </select>
+              <ArrowDown />
+            </div>
+            <span>{{ $t('signatures.appearanceDialog.type') }}</span>
+            <div class="select-box">
+              <select v-model="configurations.type" class="font-family-select">
+                <option value="normal">{{ $t('regular') }}</option>
+                <option value="bold">{{ $t('bold') }}</option>
+                <option value="italic">{{ $t('oblique') }}</option>
+                <option value="boldItalic">{{ $t('boldOblique') }}</option>
+              </select>
+              <ArrowDown />
+            </div>
+          </div>
+          <div class="text-align">
+            <span>{{ $t('signatures.appearanceDialog.textAlignment') }}</span>
+            <div class="buttons">
+              <div :class="{ active: configurations.alignment === 'left' }" @click="configurations.alignment = 'left'"><TextLeft /></div>
+              <div :class="{ active: configurations.alignment === 'right' }" @click="configurations.alignment = 'right'"><TextRight /></div>
+            </div>
+          </div>
         </div>
       </div>
-      <span class="clear" @click="clearData">{{ $t('signatures.clear') }}</span>
 
-      <template #footer>
+      <template #footer class="upper">
         <div class="rect-button white" @click="closePanel('cancel')">{{ $t('cancel') }}</div>
         <div class="rect-button blue" @click="save">{{ $t('ok') }}</div>
       </template>
     </Dialog>
+
+    <Dialog :show="drawDialogShow" class="draw-dialog">
+      <template #header>
+        <CloseB class="close" @click="drawDialogShow = false" />
+      </template>
+
+      <div class="paint-container">
+        <canvas v-show="activeSignWay === 'trackpad'" id="digitalTrackpadCanvas" width="578" height="240"></canvas>
+        <p>{{ $t('signatures.signHere') }}</p>
+      </div>
+
+      <template #footer>
+        <div class="rect-button white" @click="clearData">{{ $t('signatures.clear') }}</div>
+        <div class="rect-button white" @click="drawDialogShow = false">{{ $t('cancel') }}</div>
+        <div class="rect-button blue" @click="save">{{ $t('ok') }}</div>
+      </template>
+    </Dialog>
   </div>
 </template>
 
 <script setup>
-import { ref, computed, h, watch, getCurrentInstance } from 'vue'
+import { ref, computed, h, watch, getCurrentInstance, reactive } from 'vue'
 import { useViewerStore } from '@/stores/modules/viewer'
 import { useDocumentStore } from '@/stores/modules/document'
 import core from '@/core'
@@ -59,6 +158,25 @@ const widthValue = ref(5)
 const fontColor = ref('#000000')
 const fontFamily = ref('Courier New')
 
+const drawDialogShow = ref(false)
+const configurations = reactive({
+  name: false,
+  dName: false,
+  date: false,
+  version: false,
+  logo: false,
+  location: false,
+  reason: false,
+  labels: false,
+
+  reasonSelectVal: 'none',
+  locationInputVal: '',
+
+  text: 'Helvetica',
+  type: 'bold',
+  alignment: 'left',
+})
+
 watch(() => toolMode.value, (newValue, oldValue) => {
   if (!(oldValue === 'sign' && newValue === 'view') && newValue !== oldValue) {
     clearData()
@@ -320,9 +438,11 @@ const save = () => {
 
     main {
       margin-top: 24px;
+      margin-bottom: 20px;
     }
 
     footer {
+
       .rect-button {
         border-radius: 4px;
       }
@@ -349,62 +469,273 @@ const save = () => {
     }
   }
 
-  .paint-container {
+  .preview-area {
+    height: 187px;
+    background: #F4F7FF url('/images/logo-backgroud@2x.png') no-repeat center center / 104px 104px;
+  }
+
+  .preview-options {
+
+    span {
+      font-size: 12px;
+      line-height: 16px;
+      color: #1460F3;
+      cursor: pointer;
+
+      & + span {
+        margin-left: 16px;
+      }
+    }
+
+    .upload {
+      position: relative;
+      display: inline-flex;
+      align-items: center;
+
+      input[type="file"] {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+        opacity: 0;
+        cursor: pointer;
+
+        &::file-selector-button {
+          cursor: pointer;
+        }
+      }
+    }
+  }
+
+  .title {
+    margin: 16px 0;
+    font-size: 14px;
+    line-height: 16px;
+    font-weight: 700;
+    color: #43474D;
+  }
+
+  .configurations {
     display: flex;
-    justify-content: center;
-    align-items: center;
-    height: 240px;
-    background-color: #F2F3F5;
+    justify-content: space-between;
+
+    span {
+      font-size: 14px;
+      line-height: 16px;
+      text-wrap: nowrap;
+    }
 
-    .keyboard-paint {
+    .left {
       flex: 1;
 
-      input {
-        width: 100%;
-        font-size: 46px;
-        line-height: 64px;
-        font-weight: 400;
-        color: #000;
-        border: none;
-        background: transparent;
-        text-align: center;
-        font-family: 'Courier New', Courier, monospace;
+      .checkboxes {
+        display: grid;
+        grid-template-columns: auto auto;
+        justify-content: space-between;
+        grid-gap: 8px 12px;
+        margin-right: 48px;
+      }
+
+      .addition {
+        margin-top: 12px;
+        margin-bottom: 38px;
+        width: 240px;
+
+        > div {
+          display: flex;
+          align-items: center;
+          justify-content: space-between;
+
+          select,
+          input {
+            margin-left: 8px;
+            flex: 1;
+          }
+
+          & + div {
+            margin-top: 8px;
+          }
+        }
       }
     }
 
-    .image-paint {
-      a {
-        position: relative;
-        font-size: 14px;
-        line-height: 20px;
-        font-weight: 400;
-        color: #1460F3;
-        text-decoration: underline;
-
-        input[type="file"] {
-          position: absolute;
-          left: 0;
-          width: 100%;
-          height: 100%;
-          opacity: 0;
-          font-size: 0;
+    .check-box {
+      padding: 6px 0;
+      display: inline-flex;
+      align-items: center;
+      cursor: pointer;
+
+      .check {
+        margin-right: 4px;
+        width: 14px;
+        height: 14px;
+        background: var(--c-right-side-content-fillbox-bg);
+        border: 1px solid var(--c-right-side-content-fillbox-border);
+        border-radius: 1px;
+        overflow: hidden;
+
+        &.active {
+          border: none;
+        }
+
+        svg {
+          vertical-align: top;
+        }
+      }
+    }
+
+    .right {
+      margin-top: -32px;
+      width: 42%;
+
+      .grid-box {
+        display: grid;
+        grid-template-columns: auto minmax(80px, 192px);
+        align-items: center;
+        gap: 8px;
+      }
+    }
+
+    select,
+    input {
+      padding: 0 8px;
+      width: 100%;
+      height: 32px;
+      background: var(--c-right-side-content-fillbox-bg);
+      border: 1px solid var(--c-right-side-content-fillbox-border);
+      border-radius: 1px;
+      font-size: 14px;
+      line-height: 20px;
+      color: var(--c-text);
+      font-family: 'Helvetica';
+
+      &::placeholder {
+        color: var(--c-text);
+        opacity: 0.6;
+      }
+    }
+
+    .select-box {
+      position: relative;
+      display: flex;
+      align-items: center;
+      width: 100%;
+
+      svg {
+        position: absolute;
+        right: 4px;
+        pointer-events: none;
+      }
+    }
+
+    select {
+      padding-right: 20px;
+      -webkit-appearance: none;
+      -moz-appearance: none;
+      appearance: none;
+    }
+
+    .text-align {
+      margin-top: 8px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      .buttons {
+        margin-left: 8px;
+        flex: 1;
+        display: inline-flex;
+        max-width: 140px;
+        border: 1px solid #0000001F;
+        background: var(--c-right-side-content-fillbox-bg);
+
+        div {
+          padding: 7px;
+          flex: 1;
+          height: 30px;
+          text-align: center;
           cursor: pointer;
         }
+
+        .active {
+          background: #DDE9FF;
+
+          svg {
+            color: #43474D;
+          }
+        }
       }
     }
   }
 
-  .clear {
-    font-size: 12px;
-    line-height: 16px;
-    color: #1460F3;
-    cursor: pointer;
+  .appearance-dialog footer {
+    margin-top: -38px;
+  }
+}
+
+.draw-dialog {
+
+  .dialog-container {
+    padding: 16px 24px;
+
+    main {
+      margin-top: 40px;
+      margin-bottom: 12px;
+    }
+
+    footer {
+
+      .rect-button.white {
+        border-radius: 2px;
+      }
+
+      .rect-button:first-child {
+        margin-right: auto;
+      }
+    }
+  }
+
+  .paint-container {
+    position: relative;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    height: 240px;
+    background-color: #F2F3F5;
+
+    canvas {
+      z-index: 1;
+    }
+
+    p {
+      position: absolute;
+      font-size: 14px;
+      line-height: 16px;
+      color: #757780;
+    }
   }
 }
 
 @media screen and (max-width: 628px) {
   .signature-appearance-dialog .dialog-container {
     width: 100%;
+
+    footer {
+      margin-top: 0;
+    }
+  }
+
+  .signature-appearance-dialog .configurations .left {
+
+    .checkboxes {
+      margin-right: 20px;
+      justify-content: left;
+      grid-gap: 8px;
+    }
+
+    .addition {
+      max-width: 200px;
+      width: 100%;
+    }
   }
 }
 </style>

+ 1 - 0
packages/webview/src/components/DocumentContainer/DocumentContainer.vue

@@ -53,6 +53,7 @@
   <SignatureDetailsDialog />
   <CertificationViewerDialog />
   <DeleteSignatureDialog />
+  <AddDigitalFileDialog />
   <div v-if="loading && loadingPercent < 100" class="loading-state">{{ $t('loading') }}...</div>
   <div v-show="loadingPercent <= 0 && !load && activePanelTab !== 'COMPARISON' && ['compare', 'document'].includes(toolMode)" class="upload-container">
     <input id="fileInput" type="file" accept=".pdf" @change="handleUpload" />

+ 13 - 4
packages/webview/src/components/SignatureToolBar/SignatureToolBar.vue

@@ -1,16 +1,20 @@
 <template>
   <div class="signature-tool">
     <Button id="createSignFieldButton" :class="{ active: activeTool === 'signatureFields' }" @click="changeActiveTool('signatureFields')" :title="$t('header.createSignField')">
-      <CreateSignField />{{ $t('header.createSignField') }}
+      <CreateSignField />
+      <span>{{ $t('header.createSignField') }}</span>
     </Button>
     <Button :class="{ active: activeTool === 'addDigitalSign' }" @click="changeActiveTool('addDigitalSign')" :title="$t('header.addDigitalSign')">
-      <AddDigitalSign />{{ $t('header.addDigitalSign') }}
+      <AddDigitalSign />
+      <span>{{ $t('header.addDigitalSign') }}</span>
     </Button>
     <Button :class="{ active: activeTool === 'addElectronicSign' }" @click="changeActiveTool('addElectronicSign')" :title="$t('header.addElectronicSign')">
-      <AddElectronicSign />{{ $t('header.addElectronicSign') }}
+      <AddElectronicSign />
+      <span>{{ $t('header.addElectronicSign') }}</span>
     </Button>
     <Button @click="verifyDigitalSign" :title="$t('header.verifyDigitalSign')">
-      <VerifyDigitalSign />{{ $t('header.verifyDigitalSign') }}
+      <VerifyDigitalSign />
+      <span>{{ $t('header.verifyDigitalSign') }}</span>
     </Button>
   </div>
 </template>
@@ -73,8 +77,13 @@
     }
 
     svg {
+      min-width: 20px;
       margin-right: 8px;
     }
+
+    span {
+      text-wrap: nowrap;
+    }
   }
 }
 </style>

+ 1 - 1
packages/webview/src/components/Signatures/SignCreatePanel.vue

@@ -7,7 +7,7 @@
     </div>
     <div class="paint-container">
       <!-- 手绘签名 -->
-      <canvas v-show="activeSignWay === 'trackpad'" id="trackpadCanvas" width="578" height="240"></canvas>
+      <canvas v-show="activeSignWay === 'trackpad'" id="electronicTrackpadCanvas" width="578" height="240"></canvas>
 
       <!-- 文本签名 -->
       <div class="keyboard-paint" v-show="activeSignWay === 'keyboard'">

+ 4 - 2
packages/webview/src/stores/modules/viewer.js

@@ -45,7 +45,8 @@ export const useViewerStore = defineStore({
       signatureAppearanceDialog: false,
       signatureDetailsDialog: false,
       certificateViewerDialog: false,
-      deleteSignatureDialog: false
+      deleteSignatureDialog: false,
+      addDigitalFileDialog: false
     },
     activeElementsTab: {
       leftPanelTab: 'THUMBS',
@@ -387,7 +388,8 @@ export const useViewerStore = defineStore({
         signatureAppearanceDialog: false,
         signatureDetailsDialog: false,
         certificateViewerDialog: false,
-        deleteSignatureDialog: false
+        deleteSignatureDialog: false,
+        addDigitalFileDialog: false
       },
       this.activeElementsTab = {
         leftPanelTab: 'THUMBS',