Explorar o código

add: 左侧边栏添加签名面板

wzl hai 11 meses
pai
achega
19ddd85829

+ 12 - 2
packages/webview/locales/en.json

@@ -87,7 +87,13 @@
     "previousPhrase": "Find the previous occurrence of the phrase",
     "nextPhrase": "Find the next occurrence of the phrase",
     "results": "Results",
-    "noResults": "No results"
+    "noResults": "No results",
+
+    "signature": "Signature",
+    "signatureList": "Signature List",
+    "signatureDetails": "Signature Details",
+    "certificationDetails": "Certification Details",
+    "noSignatures": "No Signatures"
   },
 
   "pageModePanel": {
@@ -207,7 +213,9 @@
       "signWithDigital": "Sign with Digital Signatures",
       "signWithDigitalDesc": "Create or upload a digital certificate with a unique digital ID to sign files.",
       "startSigning": "Start Signing"
-    }
+    },
+
+    "deleteConfirm": "Are you sure to delete it?"
   },
   "color": "Color",
   "opacity": "Opacity",
@@ -216,6 +224,8 @@
   "oblique": "Oblique",
   "bold": "Bold",
   "boldOblique": "Bold Oblique",
+  "delete": "Delete",
+  "warning": "Warning",
 
   "compare": {
     "startCompare": "Start to Compare",

+ 12 - 2
packages/webview/locales/zh-CN.json

@@ -87,7 +87,13 @@
     "previousPhrase": "查看上一个结果",
     "nextPhrase": "查看下一个结果",
     "results": "结果",
-    "noResults": "无搜索结果"
+    "noResults": "无搜索结果",
+
+    "signature": "签名",
+    "signatureList": "签名列表",
+    "signatureDetails": "查看签名详情",
+    "certificationDetails": "查看证书详情",
+    "noSignatures": "没有签名"
   },
 
   "pageModePanel": {
@@ -207,7 +213,9 @@
       "signWithDigital": "数字签名(数字证书签署)",
       "signWithDigitalDesc": "通过创建或上传带有唯一数字ID的数字证书签署文件。",
       "startSigning": "开始签名"
-    }
+    },
+
+    "deleteConfirm": "确定删除该内容?"
   },
   "color": "颜色",
   "opacity": "不透明度",
@@ -216,6 +224,8 @@
   "oblique": "斜体",
   "bold": "粗体",
   "boldOblique": "粗斜体",
+  "delete": "删除",
+  "warning": "注意",
 
   "compare": {
     "startCompare": "开始对比",

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 3 - 0
packages/webview/src/assets/icons/icon-signature.svg


+ 5 - 0
packages/webview/src/components/Icon/MoreB.vue

@@ -0,0 +1,5 @@
+<template>
+  <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M11 6C11 6.55228 10.5523 7 10 7C9.44772 7 9 6.55228 9 6C9 5.44772 9.44772 5 10 5C10.5523 5 11 5.44772 11 6ZM11 10C11 10.5523 10.5523 11 10 11C9.44772 11 9 10.5523 9 10C9 9.44772 9.44772 9 10 9C10.5523 9 11 9.44772 11 10ZM10 15C10.5523 15 11 14.5523 11 14C11 13.4477 10.5523 13 10 13C9.44772 13 9 13.4477 9 14C9 14.5523 9.44772 15 10 15Z" fill="currentColor"/>
+  </svg>
+</template>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 5 - 0
packages/webview/src/components/Icon/Signature.vue


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 8 - 0
packages/webview/src/components/Icon/SignatureInvalid.vue


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 7 - 0
packages/webview/src/components/Icon/SignatureUnknown.vue


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 7 - 0
packages/webview/src/components/Icon/SignatureValid.vue


+ 3 - 0
packages/webview/src/components/LeftPanel/LeftPanel.vue

@@ -25,6 +25,9 @@
       <div class="compare-container" :class="{ hidden: activePanelTab !== 'COMPARISON' }">
         <Compare />
       </div>
+      <div class="signature-container" :class="{ hidden: activePanelTab !== 'SIGNATURE' }">
+        <SignatureContainer />
+      </div>
     </div>
     <div class="findbar-container" :class="{ hidden: activePanelTab !== 'SEARCH' }">
       <SearchContainer />

+ 10 - 0
packages/webview/src/components/LeftPanel/LeftPanelTabs.vue

@@ -49,6 +49,16 @@
     :isActive="activePanelTab === 'COMPARISON'"
     @click="setActiveLeftPanelTab('COMPARISON')"
   />
+  <Button
+    :className="activePanelTab === 'SIGNATURE' ? 'active' : ''"
+    img="icon-signature"
+    :title="$t('leftPanel.signature')"
+    dataElement="Signature"
+    :isActive="activePanelTab === 'SIGNATURE'"
+    @click="setActiveLeftPanelTab('SIGNATURE', 'none')"
+  >
+    <Signature />
+  </Button>
   <Button
     :className="activePanelTab === 'SEARCH' ? 'active' : ''"
     img="icon-search"

+ 132 - 0
packages/webview/src/components/SignatureContainer/SignatureContainer.vue

@@ -0,0 +1,132 @@
+<template>
+  <div class="signature-container">
+    <div class="signature-title">{{ $t('leftPanel.signatureList') }}</div>
+    <div v-if="signatures.length" class="signatures">
+      <template v-for="signature in signatures">
+        <div class="signature" :class="{ 'focus': showPopoverName === signature.name }" @click="goToPage(signature.pageIndex)">
+          <SignatureValid v-if="signature.state === 'valid'" />
+          <SignatureInvalid v-else-if="signature.state === 'invalid'" />
+          <SignatureUnknown v-else />
+          <span :title="signature.name">{{ signature.type }}</span>
+          <n-popover
+            placement="bottom-start"
+            trigger="click"
+            :show-arrow="false"
+            to="#outerContainer"
+            :raw="true"
+            :z-index="96"
+            class="option-popover"
+            @clickoutside="onOutsidePopover"
+          >
+            <template #trigger>
+              <Button class="more" @click.stop="showPopoverName = signature.name">
+                <MoreB />
+              </Button>
+            </template>
+            <div class="drop-down">
+              <div class="drop-item" @click="">{{ $t('leftPanel.signatureDetails') }}</div>
+              <div class="drop-item" @click="">{{ $t('leftPanel.certificationDetails') }}</div>
+              <div class="drop-item" @click="deleteSignature">{{ $t('delete') }}</div>
+            </div>
+          </n-popover>
+        </div>
+      </template>
+    </div>
+    <div v-else class="no-signatures">
+      {{ $t('leftPanel.noSignatures') }}
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { computed, ref } from 'vue'
+import core from '@/core'
+import { useDocumentStore } from '@/stores/modules/document'
+import { NPopover } from 'naive-ui'
+
+const useDocument = useDocumentStore()
+
+const signatures = computed(() => useDocument.getSignatures)
+
+const showPopoverName = ref('')
+
+const goToPage = (page) => {
+  core.pageNumberChanged({
+    value: (page * 1 + 1).toString()
+  })
+}
+
+const onOutsidePopover = () => {
+  showPopoverName.value = ''
+}
+</script>
+
+<style lang="scss">
+.signature-container {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+
+  .signature-title {
+    margin: 0;
+    padding: 9px 16px;
+    line-height: 17px;
+    font-size: 14px;
+    font-weight: bold;
+    color: var(--c-side-title);
+  }
+
+  .signatures {
+    flex-grow: 1;
+    overflow-y: auto;
+
+    .signature {
+      display: flex;
+      align-items: center;
+      padding: 6px 16px;
+      height: 32px;
+      cursor: default;
+
+      &:hover, &.focus {
+        background-color: var(--c-side-header-active);
+      }
+
+      span {
+        margin-left: 8px;
+        text-wrap: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        font-size: 14px;
+        line-height: 16px;
+        color: var(--c-right-side-header-text);
+      }
+
+      svg {
+        min-width: 20px;
+      }
+
+      .more {
+        margin-left: auto;
+        padding: 0;
+        margin-right: 0;
+        border-radius: 2px;
+      }
+    }
+  }
+
+  .no-signatures {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, 50%);
+    text-align: center;
+    font-weight: 700;
+    color: var(--c-side-text);
+    font-size: 14px;
+    line-height: 16px;
+  }
+}
+.option-popover .drop-down .drop-item {
+  padding: 6px 8px;
+}
+</style>

+ 11 - 0
packages/webview/src/stores/modules/document.js

@@ -143,6 +143,7 @@ export const useDocumentStore = defineStore({
     activeOutlineId: null,
     searchResults: [],
     docEditorOperationList: [], // 页面编辑操作记录
+    signatures: []
   }),
   getters: {
     getTotalPages () {
@@ -189,6 +190,8 @@ export const useDocumentStore = defineStore({
         annotationsCount: 0
       }
       const annotations = this.annotations
+      this.signatures = []
+
       for (const page in annotations) {
         const pageAnnotations = annotations[page]
         const len = pageAnnotations.length
@@ -226,6 +229,10 @@ export const useDocumentStore = defineStore({
               annotationsContainers.annotationsCount++
               annotationsContainers.annotations[page].annotations.push(pageAnnotations[i])
             }
+
+            if (pageAnnotations[i].type === 'signatureFields') {
+              this.signatures.push(pageAnnotations[i])
+            }
           }
         }
       }
@@ -263,6 +270,9 @@ export const useDocumentStore = defineStore({
     },
     getDocEditorOperationList () {
       return this.docEditorOperationList
+    },
+    getSignatures () {
+      return this.signatures
     }
   },
   actions: {
@@ -275,6 +285,7 @@ export const useDocumentStore = defineStore({
       this.activeOutlineId = null
       this.searchResults = []
       this.docEditorOperationList = []
+      this.signatures = []
     },
     setTotalPages (totalPages) {
       this.totalPages = totalPages