瀏覽代碼

feat: 新增download attachment页面

Jack Zhou 2 月之前
父節點
當前提交
92f24d80ef

+ 7 - 0
src/router/index.ts

@@ -41,6 +41,13 @@ const router = createRouter({
           meta: {
             activeMenu: '/tracking'
           }
+        }, {
+          path: '/tracking/download-attachment',
+          name: 'Tracking Download Attachment',
+          component: () => import('../views/Tracking/src/components/DownloadAttachment'),
+          meta: {
+            activeMenu: '/tracking'
+          }
         },
         {
           path: '/shipment/detail',

+ 5 - 3
src/stores/modules/breadCrumb.ts

@@ -12,6 +12,7 @@ interface BreadCrumb {
 const whiteList = [
   'Booking Detail',
   'Tracking Detail',
+  'Tracking Download Attachment',
   'Add VGM',
   'Public Tracking Detail',
   'Create New Rule',
@@ -99,7 +100,7 @@ export const useBreadCrumb = defineStore('breadCrumb', {
         ]
       } else if (toRoute.name === 'Destination Create New Rule') {
         let label = ''
-        if(toRoute.query.a != undefined) {
+        if (toRoute.query.a != undefined) {
           label = 'Modify Rule'
         } else {
           label = 'Create New Rule'
@@ -121,8 +122,9 @@ export const useBreadCrumb = defineStore('breadCrumb', {
             query: toRoute.query
           }
         ]
-      } else if (toRoute.name === 'Create New Booking') {let label = ''
-        if(toRoute.query.a != undefined) {
+      } else if (toRoute.name === 'Create New Booking') {
+        let label = ''
+        if (toRoute.query.a != undefined) {
           label = 'Modify Booking'
         } else {
           label = 'Create New Booking'

+ 4 - 0
src/styles/theme.scss

@@ -354,6 +354,8 @@
   --color-ant-picker-th: #b5b9bf;
 
   --color-json-item-hover: #e6f7ff;
+  
+  --color-attchment-summary-bg: #f9fafb;
 }
 
 :root.dark {
@@ -581,5 +583,7 @@
   --color-ant-picker-th: rgba(240, 241, 243,0.3);
 
   --color-json-item-hover: #3e5966;
+
+  --color-attchment-summary-bg: #f9fafb;
 }
   

+ 1 - 0
src/views/Tracking/src/components/DownloadAttachment/index.ts

@@ -0,0 +1 @@
+export { default } from './src/DownloadAttachment.vue'

+ 346 - 0
src/views/Tracking/src/components/DownloadAttachment/src/DownloadAttachment.vue

@@ -0,0 +1,346 @@
+<script setup lang="ts">
+const selectAll = ref(false)
+
+const attachmentData = [
+  {
+    id: 1,
+    no: 'Shipment No. S0000002841',
+    typeList: [
+      {
+        label: 'Customs Documents',
+        number: 2,
+        attachmentList: [
+          { name: 'Commercial Invoice.pdf' },
+          { name: 'Packing List.pdf' },
+          { name: 'Certificate of Origin.pdf' }
+        ]
+      },
+      {
+        label: 'House Bill of Lading',
+        number: 1,
+        attachmentList: [{ name: 'Commercial Invoice.pdf' }]
+      },
+      {
+        label: 'Master Bill of Lading',
+        number: 1,
+        attachmentList: [{ name: 'Commercial Invoice.pdf' }]
+      }
+    ]
+  },
+  {
+    id: 2,
+    no: 'Shipment No. S0000002841',
+    typeList: [
+      {
+        label: 'Customs Documents',
+        number: 2,
+        attachmentList: [
+          { name: 'Commercial Invoice.pdf' },
+          { name: 'Packing List.pdf' },
+          { name: 'Certificate of Origin.pdf' }
+        ]
+      },
+      {
+        label: 'House Bill of Lading',
+        number: 1,
+        attachmentList: [{ name: 'Commercial Invoice.pdf' }]
+      },
+      {
+        label: 'Master Bill of Lading',
+        number: 1,
+        attachmentList: [{ name: 'Commercial Invoice.pdf' }]
+      }
+    ]
+  }
+]
+
+const summaryList = [
+  {
+    label: 'Customs Documents',
+    number: 8,
+    attachmentList: [
+      {
+        name: 'Commercial Invoice.pdf'
+      },
+      {
+        name: 'Packing List.pdf'
+      },
+      {
+        name: 'Certificate of Origin.pdf'
+      }
+    ]
+  },
+  { label: 'House Bill of Lading', number: 4 },
+  { label: 'Master Bill of Lading', number: 4 }
+]
+
+const activeNames = ref(['1'])
+</script>
+
+<template>
+  <div class="tracking-download-attachment">
+    <div class="left-select-section">
+      <div class="header-select-all">
+        <el-checkbox v-model="selectAll"><span>Select All</span></el-checkbox>
+      </div>
+      <div class="attachment-list">
+        <div class="attachment-item" v-for="attItem in attachmentData" :key="attItem.id">
+          <div class="top-number">
+            <el-checkbox>
+              <span class="font_family icon-icon_ocean_b"></span>
+              <span class="label">Attachment {{ attItem.no }}</span></el-checkbox
+            >
+          </div>
+          <div class="attachment-content">
+            <div class="attachment-type" v-for="typeItem in attItem.typeList" :key="typeItem.label">
+              <div class="type-label">{{ typeItem.label }} ({{ typeItem.number }})</div>
+              <div class="type-attachment-list">
+                <div
+                  class="attachment-file"
+                  v-for="fileItem in typeItem.attachmentList"
+                  :key="fileItem.name"
+                >
+                  <el-checkbox>
+                    <span>{{ fileItem.name }}</span></el-checkbox
+                  >
+                  <span class="font_family icon-icon_download_b"></span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="right-summary-section">
+      <div class="title">Attachment Summary</div>
+      <div class="summary-content">
+        <el-button class="el-button--main el-button--pain-theme" style="width: 100%">
+          <span class="font_family icon-icon_download_b"></span> <span>Download Selected (12)</span>
+        </el-button>
+        <div class="type-collapse">
+          <el-collapse
+            style="margin: 5px 0"
+            expand-icon-position="left"
+            v-for="(typeItem, index) in summaryList"
+            :key="index"
+          >
+            <div class="right-download">
+              <div class="count">
+                <span>12</span>
+              </div>
+              <span class="font_family icon-icon_download_b"></span>
+            </div>
+            <el-collapse-item :title="typeItem.label" :name="index.toString()">
+              <template #icon="{ isActive }">
+                <span
+                  :class="{ 'is-active': isActive }"
+                  class="font_family icon-icon_up_b custom-arrow"
+                ></span>
+              </template>
+
+              <div class="attachment-list">
+                <div
+                  class="attachment-item"
+                  v-for="attItem in typeItem.attachmentList"
+                  :key="attItem.name"
+                >
+                  <span>{{ attItem.name }}</span>
+                </div>
+              </div>
+            </el-collapse-item>
+          </el-collapse>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.tracking-download-attachment {
+  display: flex;
+  height: 100%;
+  padding-left: 24px;
+  .left-select-section {
+    flex: 1;
+  }
+  .right-summary-section {
+    width: 340px;
+    height: 100%;
+    border: 1px solid var(--color-border);
+    margin-left: 24px;
+    min-height: 400px;
+    background-color: var(--color-attchment-summary-bg);
+  }
+}
+.left-select-section {
+  .header-select-all {
+    margin: 16px 0;
+    span {
+      font-size: 18px;
+      font-weight: 700;
+    }
+    :deep(.el-checkbox__inner) {
+      width: 24px;
+      height: 24px;
+    }
+  }
+  & > .attachment-list {
+    display: flex;
+    gap: 8px;
+    flex-wrap: wrap;
+  }
+}
+.left-select-section .attachment-list .attachment-item {
+  flex: 1 1 calc(50% - 4px);
+  width: calc(50% - 4px);
+  height: 320px;
+  border: 1px solid var(--color-border);
+  border-radius: 12px;
+  overflow: hidden;
+  // background-color: var(--color-mode);
+  .top-number {
+    display: flex;
+    align-items: center;
+    height: 48px;
+    padding: 13px 8px;
+    background-color: var(--color-dialog-header-bg);
+    .font_family {
+      font-size: 24px;
+      margin-right: 8px;
+    }
+    .label {
+      font-size: 18px;
+    }
+    :deep(.el-checkbox__inner) {
+      width: 16px;
+      height: 16px;
+    }
+  }
+  .attachment-content {
+    padding: 13px 8px;
+    overflow: auto;
+    height: calc(100% - 48px);
+  }
+  .attachment-type {
+    margin-bottom: 8px;
+    .type-label {
+      margin: 5px 0;
+      font-size: 12px;
+      color: var(--color-neutral-2);
+    }
+    .type-attachment-list {
+      display: flex;
+      flex-direction: column;
+      border-radius: 6px;
+      overflow: hidden;
+
+      .attachment-file {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        height: 40px;
+        padding: 0 8px;
+        background-color: var(--color-personal-preference-bg);
+        &:nth-child(n + 2) {
+          border-top: 1px solid var(--color-border);
+        }
+        :deep(.el-checkbox__inner) {
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          width: 16px;
+          height: 16px;
+        }
+        .icon-icon_file_pdf {
+          color: #e74c3c;
+          margin-right: 8px;
+        }
+      }
+    }
+  }
+}
+.right-summary-section {
+  .title {
+    font-size: 24px;
+    font-weight: 700;
+    padding: 16px 8px;
+    border-bottom: 1px solid var(--color-border);
+  }
+  .summary-content {
+    padding: 16px 8px;
+  }
+
+  .el-collapse {
+    position: relative;
+    padding: 0 8px;
+    background-color: var(--color-mode);
+    border: 1px solid var(--color-border);
+    border-radius: 12px;
+    overflow: hidden;
+    :deep(.el-collapse-item__wrap) {
+      border: none;
+    }
+    :deep(.el-collapse-item__header) {
+      gap: 3px;
+      border: none;
+    }
+    :deep(.el-collapse-item__title) {
+      font-weight: 700;
+    }
+    .right-download {
+      position: absolute;
+      right: 14px;
+      top: 14px;
+      display: flex;
+      align-items: center;
+      gap: 16px;
+    }
+    .count {
+      display: inline-flex;
+      align-items: center;
+      justify-content: center;
+      height: 16px;
+      padding-left: 5px;
+      padding-right: 4px;
+      min-width: 16px;
+      background-color: var(--color-theme);
+      border-radius: 9px;
+      font-size: 10px;
+      font-weight: 700;
+      line-height: 18px;
+      text-align: center;
+      span {
+        color: var(--color-white);
+        font-weight: 700;
+      }
+    }
+    .custom-arrow {
+      transform: rotate(90deg);
+      transition: transform 0.3s ease;
+      transform: rotate(90deg);
+    }
+
+    .custom-arrow.is-active {
+      transform: rotate(180deg);
+    }
+  }
+  .attachment-list {
+    margin: 8px 0;
+    border-radius: 8px;
+    overflow: hidden;
+    .attachment-item {
+      height: 32px;
+      line-height: 32px;
+      padding: 0 8px;
+      border-bottom: 1px solid var(--color-border);
+      background-color: var(--color-personal-preference-bg);
+      &:last-child {
+        border-bottom: none;
+      }
+      span {
+        color: var(--color-neutral-2);
+      }
+    }
+  }
+}
+</style>

+ 9 - 0
src/views/Tracking/src/components/TrackingTable/src/TrackingTable.vue

@@ -585,6 +585,12 @@ defineExpose({
   getLoadingData,
   pageInfo
 })
+
+const testA = () => {
+  router.push({
+    name: 'Tracking Download Attachment'
+  })
+}
 </script>
 
 <template>
@@ -599,6 +605,9 @@ defineExpose({
     <div class="table-tools">
       <div class="left-total-records">{{ selectedNumber }} Selected</div>
       <div class="right-tools-btn">
+        <el-button class="el-button--main el-button--pain-theme" @click="testA"
+          >Tracking Download Attachment</el-button
+        >
         <el-button
           class="el-button--main el-button--pain-theme"
           @click="handleDownload"