Browse Source

add: 删除签名域;查看签名详情弹窗UI;

wzl 11 months ago
parent
commit
805fed2d07

+ 4 - 5
packages/core/src/form/signature_fields.js

@@ -49,6 +49,7 @@ export default class signatureFields extends Base {
 
   render () {
     this.eventBus._on('setProperty', this.setProperty.bind(this))
+    this.eventBus._on('deleteSignature', this.onDelete)
 
     console.log(this.annotation)
     for (let key in this.annotation) {
@@ -571,8 +572,9 @@ export default class signatureFields extends Base {
     }
   }
 
-  handleDelete (event) {
-    if (!this.annotationContainer) return
+  handleDelete (data) {
+    const event = data instanceof Event ? data : null
+    if (!this.annotationContainer || data.name !== this.annotation.name) return
     if (this.layer.tool && event) {
       event.stopPropagation()
     }
@@ -589,9 +591,6 @@ export default class signatureFields extends Base {
       }
     }
     this.annotation.annotPtr && (annotationData.annotation.annotPtr = this.annotation.annotPtr)
-    if (!event) {
-      annotationData.type = 'empty'
-    }
     this.eventBus.dispatch('annotationChange', annotationData)
   }
 

+ 10 - 6
packages/core/src/index.js

@@ -393,16 +393,16 @@ class ComPDFKitViewer {
   }
 
   addAnnotations(annotation) {
-    this.handleAnnotationChange({
-      type: 'add',
-      annotation: [annotation]
+    const annotations = Array.isArray(annotation) ? annotation : [annotation]
+    annotations.forEach(item => {
+      this.handleAnnotationChange({ type: 'add', annotation: item })
     })
   }
 
   delAnnotations(annotation) {
-    this.handleAnnotationChange({
-      type: 'delete',
-      annotation: [annotation]
+    const annotations = Array.isArray(annotation) ? annotation : [annotation]
+    annotations.forEach(item => {
+      this.handleAnnotationChange({ type: 'delete', annotation: item })
     })
   }
 
@@ -3583,6 +3583,10 @@ class ComPDFKitViewer {
       })
     }
   }
+
+  deleteSignature (signature) {
+    this.eventBus.dispatch('deleteSignature', signature)
+  }
 }
 
 class PDFWorker {

+ 2 - 0
packages/webview/src/assets/base.css

@@ -32,6 +32,7 @@
   --c-bg: var(--c-black-11);
 
   --c-text: var(--c-black-5);
+  --c-black-text: var(--c-black);
   
   --c-divider: rgba(0, 0, 0, 0.12);
 
@@ -130,6 +131,7 @@ html.dark {
   --c-bg: var(--c-black-3);
   
   --c-text: var(--c-white);
+  --c-black-text: var(--c-white);
 
   --c-divider: rgba(255, 255, 255, 0.2);
 

+ 70 - 0
packages/webview/src/components/Dialogs/CertificationDetailsDialog.vue

@@ -0,0 +1,70 @@
+<template>
+  <div class="certification-details-dialog" v-if="show">
+    <Dialog :show="show" :dialogName="dialogName">
+      <template #header>
+        <p>Customize the Signature Appearance</p>
+        <CloseB class="close" @click="closePanel" />
+      </template>
+
+      <template #footer>
+        <div class="view-button">View</div>
+      </template>
+    </Dialog>
+  </div>
+</template>
+
+<script setup>
+import { computed } from 'vue'
+import { useViewerStore } from '@/stores/modules/viewer'
+
+const dialogName = 'certificationDetailsDialog'
+
+const useViewer = useViewerStore()
+
+const show = computed(() => useViewer.isElementOpen(dialogName))
+
+const closePanel = () => {
+  useViewer.closeElement(dialogName)
+}
+</script>
+
+<style lang="scss">
+.certification-details-dialog {
+
+  .dialog-container {
+    padding: 15px 23px;
+    width: 628px;
+    border-radius: 0;
+    position: relative;
+
+    header {
+      
+      p {
+        margin-left: -3px;
+        font-size: 14px;
+        line-height: 16px;
+        font-weight: 400;
+        color: var(--c-right-side-header-text);
+      }
+
+      .close {
+        position: absolute;
+        top: 8px;
+        right: 8px;
+        margin: 0;
+        cursor: pointer;
+      }
+    }
+
+    main {
+      margin-top: 24px;
+    }
+
+    footer {
+      .rect-button {
+        border-radius: 4px;
+      }
+    }
+  }
+}
+</style>

+ 38 - 0
packages/webview/src/components/Dialogs/DeleteSignatureDialog.vue

@@ -0,0 +1,38 @@
+<template>
+  <div class="delete-page-popup" v-if="show">
+    <Dialog :show="show" :dialogName="dialogName">
+      <Warning />
+      <p>{{ $t('signatures.deleteConfirm') }}</p>
+
+      <template #footer>
+        <div class="rect-button white" @click="closeDialog">{{ $t('cancel') }}</div>
+        <div class="rect-button blue" @click="handleDelete">{{ $t('ok') }}</div>
+      </template>
+    </Dialog>
+  </div>
+</template>
+
+<script setup>
+import { computed } from 'vue'
+import { useViewerStore } from '@/stores/modules/viewer'
+import { useDocumentStore } from '@/stores/modules/document'
+import core from '@/core'
+
+const dialogName = 'deleteConfirmDialog'
+
+const useViewer = useViewerStore()
+const useDocument = useDocumentStore()
+
+const show = computed(() => useViewer.isElementOpen(dialogName))
+const selectedSignature = computed(() => useDocument.getSelectedSignature)
+
+const closeDialog = () => {
+  useViewer.closeElement(dialogName)
+  useDocument.setSelectedSignature(null)
+}
+
+const handleDelete = () => {
+  core.deleteSignature(JSON.parse(JSON.stringify(selectedSignature.value)))
+  closeDialog()
+}
+</script>

+ 182 - 0
packages/webview/src/components/Dialogs/SignatureDetailsDialog.vue

@@ -0,0 +1,182 @@
+<template>
+  <div class="signature-details-dialog" v-if="show">
+    <Dialog :show="show" :dialogName="dialogName">
+      <template #header>
+        <p>Digital Signature Details</p>
+        <CloseB class="close" @click="closePanel" />
+      </template>
+
+      <div class="info">
+        <SignatureValid v-if="signature.state === 'valid'" />
+        <SignatureInvalid v-else-if="signature.state === 'invalid'" />
+        <SignatureUnknown v-else />
+        <div>
+          <p class="title">Valid signature,Signed by "ComPDFKit &lt;12341234@qq.com&gt;".</p>
+          <p class="desc">Signing Time:2023-8-11 05:00:53 PM/AM (EST)</p>
+        </div>
+      </div>
+
+      <div class="summary">
+        <div class="title">
+          <div class="line-left"></div>
+          <span>Validity Summary</span>
+          <div class="line-right"></div>
+        </div>
+        <div class="content">
+          The signer's identity is valid.
+          <br>
+          <br>
+          The signer's identity is invalid.
+          <br>
+          <br>
+          Signature validity is unknown because it has not been included in your list of trusted certificates and none of its parent certificates are trusted certificates.
+          <br>
+          <br>
+          The signature is valid.
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="view-button">View Certificate Details</div>
+      </template>
+    </Dialog>
+  </div>
+</template>
+
+<script setup>
+import { computed } from 'vue'
+import { useViewerStore } from '@/stores/modules/viewer'
+import { useDocumentStore } from '@/stores/modules/document'
+
+const dialogName = 'signatureDetailsDialog'
+
+const useViewer = useViewerStore()
+const useDocument = useDocumentStore()
+
+const show = computed(() => useViewer.isElementOpen(dialogName))
+const signature = computed(() => useDocument.getSelectedSignature)
+
+const closePanel = () => {
+  useViewer.closeElement(dialogName)
+}
+</script>
+
+<style lang="scss">
+.signature-details-dialog {
+
+  .dialog-container {
+    padding: 0;
+    width: 552px;
+    border-radius: 0;
+    position: relative;
+
+    header {
+      
+      p {
+        margin-top: 6px;
+        margin-left: 12px;
+        font-size: 14px;
+        line-height: 20px;
+        font-weight: 400;
+        color: var(--c-black-text);
+      }
+
+      .close {
+        position: absolute;
+        top: 8px;
+        right: 8px;
+        margin: 0;
+        cursor: pointer;
+      }
+    }
+
+    main {
+      margin-top: 40px;
+      margin-bottom: 15px;
+
+      .info {
+        margin: 0 26px 26px;
+        display: flex;
+        align-items: center;
+
+        svg {
+          margin-right: 16px;
+          min-width: 32px;
+          width: 32px;
+          height: 32px;
+        }
+
+        .title {
+          font-weight: 600;
+          font-size: 16px;
+          line-height: 24px;
+        }
+
+        .desc {
+          margin-top: 8px;
+          font-size: 14px;
+          line-height: 20px;
+        }
+      }
+
+      .summary {
+        margin: auto 24px;
+        height: 345px;
+        border: 1px solid var(--c-header-border);
+        border-top-width: 0px;
+        font-size: 14px;
+        line-height: 20px;
+        color: var(--c-black-text);
+
+        .title {
+          display: flex;
+
+          span {
+            margin: -10px 4px 0 4px;
+            font-weight: 600;
+          }
+
+          .line-left {
+            width: 12px;
+            border-top: 1px solid var(--c-header-border);
+          }
+
+          .line-right {
+            flex: 1;
+            border-top: 1px solid var(--c-header-border);
+          }
+        }
+
+        .content {
+          padding: 0 20px;
+          margin-top: 10px;
+          margin-bottom: 20px;
+          height: calc(100% - 40px);
+          overflow: auto;
+        }
+      }
+    }
+
+    footer {
+      .view-button {
+        margin-right: 26px;
+        margin-bottom: 20px;
+        padding: 6px 8px;
+        height: 32px;
+        border: 1px solid var(--c-header-border);
+        border-radius: 1px;
+        background: var(--c-header-button-active);
+        cursor: pointer;
+        font-size: 14px;
+        line-height: 20px;
+        color: var(--c-black-text);
+
+        &:hover {
+          background: var(--c-popup-bg-hover);
+          color: white;
+        }
+      }
+    }
+  }
+}
+</style>

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

@@ -50,8 +50,11 @@
   <MeasurePop />
   <SelectSignTypeDialog />
   <SignatureAppearanceDialog />
+  <SignatureDetailsDialog />
+  <CertificationDetailsDialog />
+  <DeleteSignatureDialog />
   <div v-if="loading && loadingPercent < 100" class="loading-state">{{ $t('loading') }}...</div>
-  <div v-show="!load && loadingPercent <= 0 && activePanelTab !== 'COMPARISON' && ['compare', 'document'].includes(toolMode)" class="upload-container">
+  <div v-show="loadingPercent <= 0 && !load && activePanelTab !== 'COMPARISON' && ['compare', 'document'].includes(toolMode)" class="upload-container">
     <input id="fileInput" type="file" accept=".pdf" @change="handleUpload" />
     <label for="fileInput">{{ $t('upload') }}</label>
   </div>

+ 23 - 8
packages/webview/src/components/SignatureContainer/SignatureContainer.vue

@@ -3,7 +3,7 @@
     <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)">
+        <div class="signature" :class="{ 'focus': selectedSignature && selectedSignature.name === signature.name }" @click="goToPage(signature.pageIndex)">
           <SignatureValid v-if="signature.state === 'valid'" />
           <SignatureInvalid v-else-if="signature.state === 'invalid'" />
           <SignatureUnknown v-else />
@@ -16,17 +16,18 @@
             :raw="true"
             :z-index="96"
             class="option-popover"
+            :show="selectedSignature?.name === signature.name && showPopover"
             @clickoutside="onOutsidePopover"
           >
             <template #trigger>
-              <Button class="more" @click.stop="showPopoverName = signature.name">
+              <Button class="more" @click.stop="selectSign(signature)">
                 <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 class="drop-item" @click="openDialog('signatureDetailsDialog')">{{ $t('leftPanel.signatureDetails') }}</div>
+              <div class="drop-item" @click="openDialog('certificationDetailsDialog')">{{ $t('leftPanel.certificationDetails') }}</div>
+              <div class="drop-item" @click="openDialog('deleteConfirmDialog')">{{ $t('delete') }}</div>
             </div>
           </n-popover>
         </div>
@@ -41,14 +42,17 @@
 <script setup>
 import { computed, ref } from 'vue'
 import core from '@/core'
+import { useViewerStore } from '@/stores/modules/viewer'
 import { useDocumentStore } from '@/stores/modules/document'
 import { NPopover } from 'naive-ui'
 
+const useViewer = useViewerStore()
 const useDocument = useDocumentStore()
 
 const signatures = computed(() => useDocument.getSignatures)
+const selectedSignature = computed(() => useDocument.getSelectedSignature)
 
-const showPopoverName = ref('')
+const showPopover = ref(false)
 
 const goToPage = (page) => {
   core.pageNumberChanged({
@@ -57,7 +61,18 @@ const goToPage = (page) => {
 }
 
 const onOutsidePopover = () => {
-  showPopoverName.value = ''
+  showPopover.value = false
+  useDocument.setSelectedSignature(null)
+}
+
+const openDialog = (name) => {
+  showPopover.value = false
+  useViewer.openElement(name)
+}
+
+const selectSign = (data) => {
+  showPopover.value = true
+  useDocument.setSelectedSignature(data)
 }
 </script>
 
@@ -84,7 +99,7 @@ const onOutsidePopover = () => {
       display: flex;
       align-items: center;
       padding: 6px 16px;
-      height: 32px;
+      // height: 32px;
       cursor: default;
 
       &:hover, &.focus {

+ 3 - 0
packages/webview/src/core/deleteSignature.js

@@ -0,0 +1,3 @@
+import core from '@/core'
+
+export default (signature) => core.getDocumentViewer().deleteSignature(signature)

+ 3 - 1
packages/webview/src/core/index.js

@@ -58,6 +58,7 @@ import getSelectedPage from './getSelectedPage'
 import pageToWindow from './pageToWindow'
 import windowToPage from './windowToPage'
 import addEditorImage from './addEditorImage'
+import deleteSignature from './deleteSignature'
 
 export default {
   getDocumentViewer,
@@ -122,5 +123,6 @@ export default {
   getSelectedPage,
   pageToWindow,
   windowToPage,
-  addEditorImage
+  addEditorImage,
+  deleteSignature
 }

+ 8 - 1
packages/webview/src/stores/modules/document.js

@@ -143,7 +143,8 @@ export const useDocumentStore = defineStore({
     activeOutlineId: null,
     searchResults: [],
     docEditorOperationList: [], // 页面编辑操作记录
-    signatures: []
+    signatures: [],
+    selectedSignature: null, // 在侧边栏签名面板选中的签名
   }),
   getters: {
     getTotalPages () {
@@ -273,6 +274,9 @@ export const useDocumentStore = defineStore({
     },
     getSignatures () {
       return this.signatures
+    },
+    getSelectedSignature () {
+      return this.selectedSignature
     }
   },
   actions: {
@@ -435,6 +439,9 @@ export const useDocumentStore = defineStore({
       } else if (operation) {
         this.docEditorOperationList.push(operation)
       }
+    },
+    setSelectedSignature (data) {
+      this.selectedSignature = data
     }
   }
 })

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

@@ -42,7 +42,10 @@ export const useViewerStore = defineStore({
       extractPageSettingDialog: false,
       movePageSettingDialog: false,
       selectSignTypeDialog: false,
-      signatureAppearanceDialog: false
+      signatureAppearanceDialog: false,
+      signatureDetailsDialog: false,
+      certificationDetailsDialog: false,
+      deleteSignatureDialog: false
     },
     activeElementsTab: {
       leftPanelTab: 'THUMBS',
@@ -381,7 +384,10 @@ export const useViewerStore = defineStore({
         extractPageSettingDialog: false,
         movePageSettingDialog: false,
         selectSignTypeDialog: false,
-        signatureAppearanceDialog: false
+        signatureAppearanceDialog: false,
+        signatureDetailsDialog: false,
+        certificationDetailsDialog: false,
+        deleteSignatureDialog: false
       },
       this.activeElementsTab = {
         leftPanelTab: 'THUMBS',