28 Revize dfd760360a ... 533db772cd

Autor SHA1 Zpráva Datum
  Jack Zhou 533db772cd Merge branch 'test_old_master' into master_zyh před 1 týdnem
  Jack Zhou ac33a22243 feat: 删除压缩文件 před 2 týdny
  Jack Zhou 3c9aebbbed Merge branch 'test_zyh' into feat_download_zyh před 2 týdny
  Jack Zhou c87814e4bb feat: 完整实现查看视频功能 před 2 týdny
  Jack Zhou 9afb1d37d1 feat: create new booking表格中实现将具有相同same_mbol的行同时选中或取消选中 před 2 týdny
  Jack Zhou 00711e9719 feat: 将视频嵌入页面 před 2 týdny
  Jack Zhou 9afaeff5bc style: 调整Tracking页各部分批量下载高度 před 3 týdny
  Jack Zhou 6d80004619 style: 调整Tracking页批量下载文件名宽度省略方式 před 3 týdny
  Jack Zhou 08da518e1c style: Tracking页批量下载加上loading动画 před 3 týdny
  Jack Zhou 01b8c939d8 feat: Tracking批量下载接口加上错误处理 před 3 týdny
  Jack Zhou 7455d3c3a0 feat: 调整批量下载页的样式和下载功能 před 3 týdny
  Jack Zhou c343462c22 Merge branch 'test' into feat_download_zyh před 3 týdny
  Jack Zhou 047a0a25e3 style: 调整Tracking批量下载卡片高度 před 3 týdny
  Jack Zhou 9db50fe615 feat: 调整Tracking批量下载复选框选中图标宽度 před 3 týdny
  Jack Zhou ec2be8d618 feat: 实现Tracking详情页多文件下载 před 1 měsícem
  Jack Zhou 28b9285439 style: 调整Tracking Download Attachment卡片样式 před 1 měsícem
  Jack Zhou d6b5a58031 feat: 实现文件下载 před 1 měsícem
  Jack Zhou 0165931ad4 Merge branch 'test_zyh' into feat_download_zyh před 1 měsícem
  Jack Zhou e83ec6d1ca feat: 接入Tracking文件批量下载页面接口 před 1 měsícem
  Jack Zhou c78859e010 feat: 整理Tracking批量下载数据格式 před 1 měsícem
  Jack Zhou 210e4d60ee feat: 实现Tracking批量下载页左侧选择file后右侧同步更新功能 před 1 měsícem
  Jack Zhou bfc07a2205 feat: 同步调整Tracking download功能修改后的page guide před 2 měsíci
  Jack Zhou db1ac1359f feat: 删除多余按钮 před 2 měsíci
  Jack Zhou 96d7a83156 feat: 完善Tracking页下载功能页面 před 2 měsíci
  Jack Zhou ef3304aaec feat: 加上空数据展示 před 2 měsíci
  Jack Zhou de91e864e0 Merge branch 'dev' into feat_download_zyh před 2 měsíci
  Jack Zhou 739d625316 feat: 实现Download Attachment页面summary部分样式 před 2 měsíci
  Jack Zhou 92f24d80ef feat: 新增download attachment页面 před 2 měsíci
29 změnil soubory, kde provedl 1386 přidání a 67 odebrání
  1. 1 0
      package.json
  2. binární
      public/videos/demo-video.mp4
  3. 5 1
      src/App.vue
  4. 37 0
      src/api/module/tracking.ts
  5. 1 0
      src/components/VEllipsisTooltip/index.ts
  6. 212 0
      src/components/VEllipsisTooltip/src/VEllipsisTooltip.vue
  7. 4 1
      src/main.ts
  8. 12 1
      src/router/index.ts
  9. 5 3
      src/stores/modules/breadCrumb.ts
  10. 20 0
      src/stores/modules/trackingDownloadData.ts
  11. 168 4
      src/styles/icons/iconfont.css
  12. 0 0
      src/styles/icons/iconfont.js
  13. 82 0
      src/styles/icons/iconfont.svg
  14. binární
      src/styles/icons/iconfont.ttf
  15. binární
      src/styles/icons/iconfont.woff
  16. binární
      src/styles/icons/iconfont.woff2
  17. 4 0
      src/styles/theme.scss
  18. 58 41
      src/views/DestinationDelivery/src/components/CreateNewBooking/src/components/NewbookingTable.vue
  19. 10 1
      src/views/Layout/src/components/Header/HeaderView.vue
  20. 1 0
      src/views/Tracking/src/components/DownloadAttachment/index.ts
  21. 616 0
      src/views/Tracking/src/components/DownloadAttachment/src/DownloadAttachment.vue
  22. binární
      src/views/Tracking/src/components/DownloadAttachment/src/images/empty-img.png
  23. 1 1
      src/views/Tracking/src/components/TrackingDetail/src/components/AttachmentView.vue
  24. 4 4
      src/views/Tracking/src/components/TrackingGuide.vue
  25. 123 10
      src/views/Tracking/src/components/TrackingTable/src/TrackingTable.vue
  26. binární
      src/views/Tracking/src/image/dark-download-guide.png
  27. binární
      src/views/Tracking/src/image/download-guide.png
  28. 1 0
      src/views/Video/index.ts
  29. 21 0
      src/views/Video/src/VideoView.vue

+ 1 - 0
package.json

@@ -40,6 +40,7 @@
     "moment": "^2.30.1",
     "moment-timezone": "^0.5.46",
     "pinia": "^2.2.2",
+    "pinia-plugin-persistedstate": "^4.5.0",
     "sass-loader": "^14.1.1",
     "vue": "^3.4.29",
     "vue-draggable-plus": "^0.5.3",

binární
public/videos/demo-video.mp4


+ 5 - 1
src/App.vue

@@ -1,9 +1,13 @@
 <script setup lang="ts">
 import { RouterView } from 'vue-router'
+import { useRoute } from 'vue-router'
+import VideoView from '@/views/Video/src/VideoView.vue'
+const route = useRoute()
 </script>
 
 <template>
-  <RouterView />
+  <VideoView v-if="route.name === 'Demo Video'" />
+  <RouterView v-else />
 </template>
 
 <style scoped></style>

+ 37 - 0
src/api/module/tracking.ts

@@ -1,4 +1,5 @@
 import HttpAxios from '@/utils/axios'
+import axios from 'axios'
 
 const base = import.meta.env.VITE_API_HOST
 const baseUrl = `${base}/main_new_version.php`
@@ -197,3 +198,39 @@ export const uploadFile = (params: any, config: any) => {
     config
   )
 }
+
+
+/**
+ * 获取Download Attachment页数据
+ */
+export const getDownloadAttachmentData = (params: any, config: any) => {
+  return HttpAxios.post(
+    `${baseUrl}`,
+    {
+      action: 'ocean_order',
+      operate: 'batch_download_load',
+      ...params
+    },
+    config
+  )
+}
+
+/**
+ * 下载对应的附件
+ */
+export const downloadAttachment = (params: any, config: any) => {
+  return axios.post(
+    baseUrl,
+    {
+      action: 'ocean_order',
+      operate: 'batch_download',
+      ...params
+    },
+    {
+      responseType: 'blob',
+      headers: {
+        'Content-Type': 'multipart/form-data'
+      }
+    }
+  )
+}

+ 1 - 0
src/components/VEllipsisTooltip/index.ts

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

+ 212 - 0
src/components/VEllipsisTooltip/src/VEllipsisTooltip.vue

@@ -0,0 +1,212 @@
+<template>
+  <el-tooltip
+    :disabled="!shouldShowTooltip"
+    :content="tooltipContent"
+    :popper-class="popperClass"
+    :placement="placement"
+    v-bind="tooltipProps"
+    ref="tooltipRef"
+  >
+    <div
+      ref="containerRef"
+      class="ellipsis-container"
+      :class="{ 'is-clamp-multi': lineClamp > 1 }"
+      :style="finalContainerStyle"
+      @mouseenter="handleMouseEnter"
+      @mouseleave="handleMouseLeave"
+    >
+      <slot>
+        <span ref="textRef" class="ellipsis-text" :style="textStyle">
+          {{ content }}
+        </span>
+      </slot>
+    </div>
+  </el-tooltip>
+</template>
+
+<script setup>
+import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
+
+const props = defineProps({
+  content: String,
+  maxWidth: {
+    type: Number,
+    default: 200
+  },
+  maxHeight: {
+    type: [Number, String],
+    default: ''
+  },
+  lineClamp: {
+    type: Number,
+    default: 1
+  },
+  tooltipProps: {
+    type: Object,
+    default: () => ({})
+  },
+  popperClass: {
+    type: String,
+    default: 'ellipsis-tooltip'
+  },
+  placement: {
+    type: String,
+    default: 'top'
+  },
+  containerStyle: {
+    type: Object,
+    default: () => ({})
+  },
+  textStyle: {
+    type: Object,
+    default: () => ({})
+  }
+})
+
+// --- DOM refs ---
+const containerRef = ref(null)
+const textRef = ref(null)
+const tooltipRef = ref(null)
+
+// --- 是否应显示 tooltip ---
+const shouldShowTooltip = ref(false)
+
+// --- 动态计算样式类 ---
+const containerClasses = computed(() => ({
+  'is-clamp-multi': props.lineClamp > 1
+}))
+
+// --- 实际用于 Tooltip 显示的内容 ---
+const tooltipContent = computed(() => props.content || '')
+
+// --- 容器样式(max-width / max-height)---
+const finalContainerStyle = computed(() => ({
+  maxWidth: props.maxWidth + 'px',
+  maxHeight: props.maxHeight
+    ? typeof props.maxHeight === 'number'
+      ? props.maxHeight + 'px'
+      : props.maxHeight
+    : 'none',
+  ...props.containerStyle
+}))
+
+// --- 文本样式(根据 lineClamp 应用不同 CSS)---
+const finalTextStyle = computed(() => {
+  const style = { ...props.textStyle }
+  if (props.lineClamp <= 1) {
+    return {
+      display: 'block',
+      overflow: 'hidden',
+      textOverflow: 'ellipsis',
+      whiteSpace: 'nowrap',
+      ...style
+    }
+  } else {
+    return {
+      display: '-webkit-box',
+      WebkitBoxOrient: 'vertical',
+      WebkitLineClamp: props.lineClamp,
+      overflow: 'hidden',
+      textOverflow: 'ellipsis',
+      wordBreak: 'break-all', // 多行建议启用
+      ...style
+    }
+  }
+})
+
+// --- 检查是否溢出 ---
+const checkOverflow = async () => {
+  await nextTick() // 确保 DOM 更新
+  const container = containerRef.value
+  const textEl = textRef.value || container?.querySelector('.ellipsis-text')
+
+  if (!container || !textEl) return
+
+  let isOverflowing = false
+
+  if (props.lineClamp <= 1) {
+    isOverflowing = textEl.scrollWidth > container.clientWidth
+  } else {
+    // 多行看高度是否溢出(line-clamp 截断)
+    isOverflowing = textEl.scrollHeight > container.clientHeight
+  }
+
+  shouldShowTooltip.value = isOverflowing
+}
+
+// --- 鼠标事件用于手动触发检查(防抖)---
+let resizeTimer
+const handleMouseEnter = () => {
+  clearTimeout(resizeTimer)
+  resizeTimer = setTimeout(checkOverflow, 50)
+}
+
+// 可选:也可监听 resize
+onMounted(() => {
+  window.addEventListener('resize', checkOverflow)
+  checkOverflow()
+})
+
+onUnmounted(() => {
+  window.removeEventListener('resize', checkOverflow)
+  clearTimeout(resizeTimer)
+})
+
+// 监听 props 变化
+watch(
+  () => [props.content, props.lineClamp, props.maxWidth, props.maxHeight],
+  () => {
+    checkOverflow()
+  },
+  { immediate: true }
+)
+</script>
+
+<style lang="scss" scoped>
+.ellipsis-container {
+  display: inline-block;
+  max-width: v-bind('finalContainerStyle.maxWidth');
+  max-height: v-bind('finalContainerStyle.maxHeight');
+  overflow: hidden;
+  vertical-align: top;
+  line-height: 32px;
+}
+
+.ellipsis-text {
+  width: 100%; // 利用父容器宽度
+}
+.ellipsis-container {
+  display: inline-block;
+  max-width: v-bind('finalContainerStyle.maxWidth');
+  max-height: v-bind('finalContainerStyle.maxHeight');
+  overflow: hidden;
+  line-height: 1.5;
+}
+
+.ellipsis-text {
+  width: 100%;
+  display: block;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.ellipsis-container.is-clamp-multi .ellipsis-text {
+  display: -webkit-box;
+  line-clamp: v-bind('lineClamp');
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: v-bind('lineClamp');
+  white-space: normal;
+  word-break: break-all;
+}
+</style>
+
+<!-- 全局样式建议提取到全局 SCSS 文件 -->
+<style>
+.ellipsis-tooltip {
+  max-width: 200px;
+  word-break: break-word;
+  white-space: pre-line;
+  margin-bottom: -15px;
+}
+</style>

+ 4 - 1
src/main.ts

@@ -22,6 +22,7 @@ import { createPinia } from 'pinia'
 import App from './App.vue'
 import router from './router'
 import { useThemeStore } from '@/stores/modules/theme'
+import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
 
 const app = createApp(App)
 
@@ -35,7 +36,9 @@ VXETable.use(VXETablePluginExportXLSX, {
 VXETable.setI18n('en-US', enUS)
 VXETable.setLanguage('en-US')
 
-app.use(createPinia())
+const pinia = createPinia()
+pinia.use(piniaPluginPersistedstate)
+app.use(pinia)
 app.use(VXETable)
 app.use(VxeUI)
 app.use(router)

+ 12 - 1
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',
@@ -171,7 +178,11 @@ const router = createRouter({
             breadName: 'Modify Booking',
             activeMenu: '/destination-delivery'
           }
-        }
+        }, {
+          path: '/demo-video',
+          name: 'Demo Video',
+          component: () => import('../views/Video'),
+        },
       ]
     }
   ]

+ 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'

+ 20 - 0
src/stores/modules/trackingDownloadData.ts

@@ -0,0 +1,20 @@
+// stores/useDataStore.js
+import { defineStore } from 'pinia';
+
+export const useTrackingDownloadData = defineStore('trackingDownloadData', {
+  state: () => ({
+    serialNoArr: [],
+    schemasArr: []
+  }),
+  actions: {
+    setData(serial_no_arr: string[], schemas_arr: string[]) {
+      this.serialNoArr = serial_no_arr;
+      this.schemasArr = schemas_arr;
+    }
+  },
+  // 持久化配置
+  persist: {
+    storage: sessionStorage // 关闭浏览器就清掉
+    // 或 storage: localStorage // 永久保留
+  }
+});

+ 168 - 4
src/styles/icons/iconfont.css

@@ -1,9 +1,9 @@
 @font-face {
   font-family: "font_family"; /* Project id 4672385 */
-  src: url('iconfont.woff2?t=1750149505564') format('woff2'),
-       url('iconfont.woff?t=1750149505564') format('woff'),
-       url('iconfont.ttf?t=1750149505564') format('truetype'),
-       url('iconfont.svg?t=1750149505564#font_family') format('svg');
+  src: url('iconfont.woff2?t=1763520739011') format('woff2'),
+       url('iconfont.woff?t=1763520739011') format('woff'),
+       url('iconfont.ttf?t=1763520739011') format('truetype'),
+       url('iconfont.svg?t=1763520739011#font_family') format('svg');
 }
 
 .font_family {
@@ -14,6 +14,170 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-icon_video_b:before {
+  content: "\e743";
+}
+
+.icon-icon_filters_up_b:before {
+  content: "\e742";
+}
+
+.icon-icon_charge_trucking:before {
+  content: "\e741";
+}
+
+.icon-icon_charge_hubrouting:before {
+  content: "\e73a";
+}
+
+.icon-icon_charge_gatewayhandling:before {
+  content: "\e73b";
+}
+
+.icon-icon_charge_airfreight:before {
+  content: "\e73c";
+}
+
+.icon-icon_charge_localhandling:before {
+  content: "\e73d";
+}
+
+.icon-icon_charge_customs:before {
+  content: "\e73e";
+}
+
+.icon-icon_charge_terminalcharge:before {
+  content: "\e73f";
+}
+
+.icon-icon_charge_airfreightrouting:before {
+  content: "\e740";
+}
+
+.icon-icon_barcode_b:before {
+  content: "\e737";
+}
+
+.icon-icon_booking__fill_b1:before {
+  content: "\e738";
+}
+
+.icon-icon_customer_b:before {
+  content: "\e739";
+}
+
+.icon-icon_warning_b:before {
+  content: "\e72d";
+}
+
+.icon-icon_update_b:before {
+  content: "\e72e";
+}
+
+.icon-icon_purchase__order_b:before {
+  content: "\e72f";
+}
+
+.icon-icon_unshare_b:before {
+  content: "\e730";
+}
+
+.icon-icon_organization_b:before {
+  content: "\e731";
+}
+
+.icon-icon_sortingby_b:before {
+  content: "\e732";
+}
+
+.icon-icon_sales__order_b:before {
+  content: "\e733";
+}
+
+.icon-icon_sendtest_b:before {
+  content: "\e734";
+}
+
+.icon-icon_time_full_b:before {
+  content: "\e735";
+}
+
+.icon-icon_datasource_b:before {
+  content: "\e736";
+}
+
+.icon-icon_unpack_b:before {
+  content: "\e72c";
+}
+
+.icon-icon_vgm_n_b:before {
+  content: "\e72b";
+}
+
+.icon-icon_booking_resend:before {
+  content: "\e72a";
+}
+
+.icon-icon_hbl_reopen:before {
+  content: "\e728";
+}
+
+.icon-icon_eci_st_retrigger:before {
+  content: "\e729";
+}
+
+.icon-icon_next_b1:before {
+  content: "\e727";
+}
+
+.icon-icon_default_screen_b:before {
+  content: "\e726";
+}
+
+.icon-icon_update__detail_b:before {
+  content: "\e725";
+}
+
+.icon-icon_brno_b:before {
+  content: "\e71d";
+}
+
+.icon-icon_smart_b:before {
+  content: "\e71e";
+}
+
+.icon-icon_map_b:before {
+  content: "\e71f";
+}
+
+.icon-icon_template_b1:before {
+  content: "\e720";
+}
+
+.icon-icon_door_b:before {
+  content: "\e721";
+}
+
+.icon-icon_map_point_b:before {
+  content: "\e722";
+}
+
+.icon-icon_current__location_b:before {
+  content: "\e723";
+}
+
+.icon-icon_address_book_b:before {
+  content: "\e724";
+}
+
+.icon-icon_guideright_b:before {
+  content: "\e71b";
+}
+
+.icon-icon_guideleft_b:before {
+  content: "\e71c";
+}
+
 .icon-icon_guidelines_b:before {
   content: "\e719";
 }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
src/styles/icons/iconfont.js


+ 82 - 0
src/styles/icons/iconfont.svg

@@ -14,6 +14,88 @@
     />
       <missing-glyph />
       
+      <glyph glyph-name="icon_video_b" unicode="&#59203;" d="M871.104 818.24c47.744 0 86.4-38.656 86.4-86.4v-734.08a86.4 86.4 0 0 0-86.4-86.4H137.024a86.4 86.4 0 0 0-86.4 86.4V731.84c0 47.744 38.656 86.4 86.4 86.4h734.08z m-743.68-820.48c0-5.312 4.288-9.6 9.6-9.6h734.08a9.6 9.6 0 0 1 9.6 9.6V503.616H127.36v-505.856z m276.032 397.312a16 16 0 0 0 24 13.888l256.704-148.288a16 16 0 0 0 0-27.648L427.52 84.736a16 16 0 0 0-24 13.824V395.072zM136.96 741.504a9.6 9.6 0 0 1-9.6-9.6v-151.552h144l-12.608 36.992a22548.48 22548.48 0 0 0-41.792 124.16H136.96z m194.56-99.456l20.992-61.696h139.52l-12.608 36.992c-13.696 40.192-29.376 86.912-41.792 124.16H297.984c10.752-31.808 22.72-67.648 33.6-99.456z m220.672 0l20.992-61.696h139.52l-12.608 36.992c-13.632 40.192-29.376 86.912-41.792 124.16H518.656c10.752-31.872 22.784-67.648 33.6-99.456z m220.672 0l20.992-61.696h86.784V731.904a9.6 9.6 0 0 1-9.6 9.6h-131.712c10.688-31.872 22.72-67.648 33.536-99.456z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_filters_up_b" unicode="&#59202;" d="M267.648 79.68L512 324.032l244.416-244.352 54.272 54.336-271.552 271.488a38.4 38.4 0 0 1-54.272 0l-271.552-271.488 54.336-54.336z m0 271.488L512 595.584l244.416-244.416 54.272 54.336-271.552 271.488a38.4 38.4 0 0 1-54.272 0L213.312 405.504l54.336-54.336z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_charge_trucking" unicode="&#59201;" d="M629.12 706.944a32 32 0 0 0 32-32v-63.2h158.4a32 32 0 0 0 22.304-9.056l2.432-2.624 140.48-171.168c4.672-5.696 7.264-12.896 7.264-20.288v-297.408a32 32 0 0 0-32-32h-101.12a120.448 120.448 0 0 0-227.968-1.184l-1.792-0.064h-252.8a120.448 120.448 0 0 0-227.52 0H64a32 32 0 0 0-32 32V674.912a32 32 0 0 0 32 32h565.12zM262.56 173.952a56.448 56.448 0 1 1 0-112.896 56.448 56.448 0 0 1 0 112.864z m482.176 0a56.448 56.448 0 1 1 0-112.896 56.448 56.448 0 0 1 0 112.864zM96 141.952h48.608a120.48 120.48 0 0 0 235.936 0h215.904V579.744c0 2.24 0.224 4.448 0.672 6.56v56.64H96v-500.992z m565.12 62.208a120.48 120.48 0 0 0 201.28-60.96H928V397.12l-123.616 150.592H661.12V204.16z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_charge_hubrouting" unicode="&#59194;" d="M512 820.16a112.192 112.192 0 0 0 32-219.68v-67.968a184.8 184.8 0 0 0 133.344-99.712l90.592 30.848a112.192 112.192 0 1 0 22.56-59.904l-95.104-32.384a184 184 0 0 0-53.76-152l58.944-56.224a112.192 112.192 0 1 0-49.408-41.312l-63.424 60.512A183.872 183.872 0 0 0 512 166.08a183.936 183.936 0 0 0-75.776 16.32l-68.576-65.472a112.192 112.192 0 1 0-46.944 43.648l61.568 58.816a184.032 184.032 0 0 0-53.44 154.208l-93.984 32a112.192 112.192 0 1 0 21.376 60.32l91.392-31.104A184.8 184.8 0 0 0 480 532.48V600.48a112.224 112.224 0 0 0 32 219.712zM271.008 108.16a48.192 48.192 0 1 1 0-96.352 48.192 48.192 0 0 1 0 96.384z m473.792 0a48.192 48.192 0 1 1 0-96.352 48.192 48.192 0 0 1 0 96.384zM512 471.36a120.64 120.64 0 1 1 0-241.28 120.64 120.64 0 0 1 0 241.28zM144.192 519.808a48.192 48.192 0 1 1 0-96.384 48.192 48.192 0 0 1 0 96.384z m735.616 0a48.192 48.192 0 1 1 0-96.384 48.192 48.192 0 0 1 0 96.384zM512 756.192a48.192 48.192 0 1 1 0-96.384 48.192 48.192 0 0 1 0 96.384z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_charge_gatewayhandling" unicode="&#59195;" d="M967.008 846.88a32 32 0 0 0 32-32v-621.184a32 32 0 0 0-32-32H825.28v-232.48a32 32 0 0 0-32-32H71.008a32 32 0 0 0-32 32V481.984a32 32 0 0 0 32 32h248.16l3.136-0.128a32 32 0 0 0 19.488-9.216l64-64.032V814.88a32 32 0 0 0 32 32H967.04z m-864-885.664H761.28V336.992H432.16a32 32 0 0 0-22.624 9.376L305.92 449.984H103.008v-488.768z m366.816 439.776H793.28a32 32 0 0 0 32-32v-143.296h109.696V782.88H469.824V400.96z m363.84 84.384h-276.928v64h276.928v-64z m0 125.376h-276.928v64h276.928v-64z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_charge_airfreight" unicode="&#59196;" d="M513.568 864c55.264 0 100.064-44.8 100.064-100.064v-233.568l338.656-211.712a32 32 0 0 0 15.04-27.136v-88.416a32 32 0 0 0-41.632-30.496l-312.064 98.56v-185.28l76.288-58.208a32 32 0 0 0 12.576-25.44v-66.304a32 32 0 0 0-40.96-30.72l-148.192 43.072-147.52-43.072a32 32 0 0 0-40.96 30.72V2.24a32 32 0 0 0 12.736 25.536l75.904 57.376v187.008l-315.2-99.552a32 32 0 0 0-41.6 30.496V291.52a32 32 0 0 0 15.04 27.136l341.76 213.664V763.936C413.504 819.2 458.304 864 513.568 864z m0-64c-19.904 0-36.064-16.16-36.064-36.064v-249.376a32 32 0 0 0-15.04-27.136l-341.76-213.6v-27.072l315.2 99.52a32 32 0 0 0 41.6-30.496v-246.56a32 32 0 0 0-12.736-25.536l-75.904-57.344v-7.712l115.488 33.696c5.824 1.696 12.064 1.696 17.92 0l116.224-33.76v7.872l-73.504 56a31.936 31.936 0 0 0-15.36 27.328v245.024a32 32 0 0 0 41.6 30.496l312.096-98.56v27.104l-338.688 211.68a32 32 0 0 0-15.04 27.136V763.936c0 19.936-16.128 36.064-36.032 36.064z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_charge_localhandling" unicode="&#59197;" d="M434.304 815.488a32 32 0 0 0 23.584-1.312l386.144-179.392a32 32 0 0 0 11.264-8.32c0.224-0.192 0.384-0.416 0.576-0.64a30.656 30.656 0 0 0 1.984-2.688l0.64-0.992c0.576-0.96 1.12-1.92 1.6-2.912l0.384-0.896c0.48-1.056 0.864-2.144 1.216-3.232l0.288-0.896c0.32-1.152 0.544-2.304 0.736-3.456l0.192-0.896c0.192-1.44 0.32-2.88 0.32-4.352v-175.392h2.688a32 32 0 0 0 27.712-16l104-180.16a32 32 0 0 0 0-32l-104-180.16c-5.696-9.856-16.288-16-27.712-16l-207.968 0.064a32 32 0 0 0-27.712 16L624.32 32l-10.88-5.024-159.2-73.28a31.904 31.904 0 0 0-6.176-1.984c-0.448-0.096-0.896-0.256-1.376-0.32l-1.44-0.192c-2.176-0.32-4.384-0.48-6.592-0.32l-0.352 0.064a31.808 31.808 0 0 0-11.008 2.848L42.72 133.376a32 32 0 0 0-18.464 28.992V594.176a31.808 31.808 0 0 0 16.448 40.448L431.04 814.208l3.264 1.28z m38.592-410.112v-372.64l113.792 52.352 5.536 2.56-65.984 114.336a32 32 0 0 0 0 32l103.968 180.128 2.368 3.52a32 32 0 0 0 25.344 12.48h141.312V555.52l-326.336-150.144z m-384.64-222.624l320.608-149.696V405.472L88.256 554.4v-371.648z m502.624 35.2l85.504-148.096h171.072l85.504 148.128-85.504 148.128h-171.072l-85.504-148.16z m122.464 84.16a97.216 97.216 0 1 0 97.216-168.416 97.216 97.216 0 0 0-97.216 168.416z m77.344-67.584a33.184 33.184 0 1 1-57.472-33.248 33.184 33.184 0 0 1 57.472 33.28zM131.2 605.856l309.728-144.64 131.84 60.672-289.664 153.856L131.2 605.856z m224.992 103.488l289.728-153.824 108.96 50.112-310.56 144.256-88.128-40.544z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_charge_customs" unicode="&#59198;" d="M501.056 862.848a32 32 0 0 0 19.648-0.832L873.6 731.456a32 32 0 0 0 20.896-29.984v-404.48c0-21.952-7.04-44.032-17.056-64.64-10.112-20.864-24.192-42.176-40.384-63.04-32.384-41.792-75.36-84.576-118.816-122.784a1324.544 1324.544 0 0 0-125.344-97.792c-18.368-12.48-35.2-22.976-49.184-30.432a186.944 186.944 0 0 0-19.84-9.408 63.2 63.2 0 0 0-22.336-4.896c-7.936 0-15.584 2.24-20.864 4.032a179.104 179.104 0 0 0-19.232 8.128c-13.472 6.528-29.6 15.68-47.168 26.784a982.048 982.048 0 0 0-118.976 89.696c-41.184 36.16-81.92 78.24-112.608 122.368-30.304 43.584-53.184 92.608-53.184 141.952V701.472a32 32 0 0 0 20.736 29.952l348.096 130.56 2.72 0.864zM193.504 679.36V296.96c0-30.4 14.592-66.4 41.76-105.472 26.752-38.464 63.456-76.704 102.272-110.816a918.112 918.112 0 0 1 111.008-83.712c16.192-10.24 30.08-18.08 40.704-23.2 5.056-2.432 8.992-4.064 11.776-5.024 2.912 1.152 7.072 3.04 12.48 5.92 11.296 6.08 26.112 15.2 43.424 26.976 34.56 23.488 77.44 56.32 119.072 92.928 41.76 36.736 81.472 76.544 110.464 113.92 14.496 18.688 25.792 36.16 33.376 51.744 7.68 15.84 10.656 28.064 10.656 36.736V679.2L509.664 797.888l-316.16-118.56zM511.936 640a102.912 102.912 0 0 0 32-200.672v-61.184h64.288v-64h-64.32v-122.56c35.52 7.84 62.304 27.744 82.432 52.16 20.448 24.768 33.536 53.696 40.64 77.376h66.112c-7.52-33.728-25.28-79.232-57.376-118.112-35.68-43.264-89.792-79.04-165.536-79.04-75.648 0-130.304 35.712-166.784 78.72-33.024 38.976-51.808 84.704-60 118.432h66.496c7.712-23.616 21.44-52.384 42.368-77.056 21.536-25.44 50.048-45.952 87.68-53.216v123.296h-64.288v64h64.256V439.36A102.912 102.912 0 0 0 511.936 640z m0-64a38.912 38.912 0 1 1 0-77.824 38.912 38.912 0 0 1 0 77.824z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_charge_terminalcharge" unicode="&#59199;" d="M992 615.04v-645.312h-64V570.752l-422.496 159.04L96 571.008v-601.28H32V614.816L493.76 793.92l11.392 4.384L992 615.04zM454.464-30.208h-123.04V92.8h123.04v-123.008z m283.584 0h-123.04V92.8h123.04v-123.008z m-139.136 122.976H475.84v123.04h123.04V92.8z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_charge_airfreightrouting" unicode="&#59200;" d="M845.664 799.68A64 64 0 0 0 903.136 736v-155.776l-0.352-6.528a64 64 0 0 0-57.12-57.12l-6.528-0.352H455.232l-6.56 0.32a64 64 0 0 0-57.12 57.152l-0.32 6.528V627.424H275.808a106.08 106.08 0 0 1 0-212.16H748.8a169.504 169.504 0 0 0 0-338.976h-119.136v-44.32l-0.352-6.528a64 64 0 0 0-57.12-57.12l-6.528-0.352H181.728l-6.528 0.32a64 64 0 0 0-57.152 57.152l-0.32 6.528v155.776a64 64 0 0 0 57.472 63.68l6.528 0.32h383.904l6.528-0.32a64 64 0 0 0 57.472-63.68v-47.456h119.136a105.472 105.472 0 1 1 0 210.976H275.84a170.08 170.08 0 1 0 0 340.16h115.424V736a64 64 0 0 0 57.44 63.68l6.56 0.32h383.904l6.528-0.32zM181.728 31.936h383.904v155.776H181.728V32z m273.504 548.256h383.904V736H455.232v-155.776z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_barcode_b" unicode="&#59191;" d="M198.848 61.312h-86.4V706.624h86.4v-645.312z m151.296 0H281.152V706.624H350.08v-645.312z m160.896 0H407.424V706.624h103.68v-645.312z m122.112 0H564.096V706.624h69.056v-645.312z m123.072 0h-68.992V706.624h68.992v-645.312z m155.264 0h-103.616V706.624h103.68v-645.312z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_booking__fill_b1" unicode="&#59192;" d="M1000.32 2.56a96 96 0 0 0-96-96h-768a96 96 0 0 0-96 96V489.344h960v-486.784z m-539.072 133.76L339.328 258.176l-27.136 27.2-54.336-54.336 27.2-27.072 149.12-149.12a38.4 38.4 0 0 1 54.272 0l294.272 294.272-54.208 54.336-267.264-267.136zM312 791.68h432.896V861.504h76.736v-69.952h82.752a96 96 0 0 0 96-96v-131.968h-960V695.616a96 96 0 0 0 96 96h98.88V861.568h76.736v-69.952z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_customer_b" unicode="&#59193;" d="M663.744 277.312c65.536-25.024 196.672-83.2 236.032-131.328 40.32-49.344 56.96-121.536 60.288-151.424H64c1.472 30.016 15.168 102.272 58.24 151.424 41.792 47.808 168 106.112 230.72 131.264a6.4 6.4 0 0 0 7.872-2.752L460.16 102.4a6.4 6.4 0 0 1 11.52 0.832l12.608 31.552a6.4 6.4 0 0 1-0.384 5.568l-28.352 49.088a6.4 6.4 0 0 0 1.024 7.744l48.768 48.832a6.4 6.4 0 0 0 9.088 0l49.408-49.024a6.4 6.4 0 0 0 1.28-7.424l-24.96-49.472a6.464 6.464 0 0 1-0.32-4.992l10.496-30.464a6.4 6.4 0 0 1 11.648-1.024l93.952 170.88a6.4 6.4 0 0 0 7.808 2.88z m-151.68 496.064a216.576 216.576 0 1 0 0-433.152 216.576 216.576 0 0 0 0 433.152z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_warning_b" unicode="&#59181;" d="M910.976-115.2H113.024v76.8h797.952v-76.8zM512 635.392a297.664 297.664 0 0 0 297.664-297.728v-295.424H214.4V337.664A297.728 297.728 0 0 0 512 635.392z m0-76.8a220.864 220.864 0 0 1-220.864-220.928v-218.624h139.776v135.168h76.8v-135.168h225.152V337.664A220.864 220.864 0 0 1 512 558.592z m-327.232-11.968l-39.872-65.536L19.648 557.184 59.52 622.72l125.248-76.096z m819.648 10.56l-125.248-76.16-39.872 65.6 125.248 76.16 39.872-65.6zM551.808 736.64h-76.8V883.2h76.8v-146.56z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_update_b" unicode="&#59182;" d="M751.68 400.064h87.424a333.12 333.12 0 0 1-560.96 224l-26.304 27.968-26.432 27.968a409.792 409.792 0 0 0 690.496-279.936h88.512L878.08 274.944 751.68 400z m-234.24-423.68A409.792 409.792 0 0 0 108.032 368H19.584L145.92 493.056 272.32 368H184.896a333.12 333.12 0 0 1 560.96-224.064l26.304-27.904 26.368-27.968a408.64 408.64 0 0 0-281.088-111.552z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_purchase__order_b" unicode="&#59183;" d="M388.544 112.512a63.36 63.36 0 1 0 0-126.848 63.36 63.36 0 0 0 0 126.848z m440.448 0a63.36 63.36 0 1 0 0-126.848 63.36 63.36 0 0 0 0 126.848z m-562.56 704a38.4 38.4 0 0 0 30.848-28.544l27.328-110.272h516.8a96 96 0 0 0 92.928-120.128l-66.816-256.96a96 96 0 0 0-92.864-71.872H411.52l-22.4-29.44h503.232a38.4 38.4 0 1 0 0-76.8h-580.48a38.464 38.464 0 0 0-30.592 61.568l65.472 86.528-116.8 469.76H133.504a38.4 38.4 0 1 0 0 76.736h126.528l6.4-0.512z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_unshare_b" unicode="&#59184;" d="M512 800a416 416 0 1 0 0-832 416 416 0 0 0 0 832zM310.208 656.64a339.2 339.2 0 0 1 337.024-583.744L310.144 656.768zM512 723.2c-48.128 0-93.888-10.048-135.296-28.096l336.96-583.68A339.2 339.2 0 0 1 512 723.2z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_organization_b" unicode="&#59185;" d="M704.512 832a64 64 0 0 0 64-64v-177.6l-0.32-6.528a64 64 0 0 0-57.152-57.152l-6.528-0.32H550.656v-87.488h288.512a70.4 70.4 0 0 0 70.4-70.4v-126.912h50.944l6.464-0.32a64 64 0 0 0 57.536-63.68V0l-0.384-6.528a64 64 0 0 0-57.152-57.088l-6.464-0.384h-177.92l-6.592 0.384a64 64 0 0 0-57.152 57.088L718.528 0v177.6a64 64 0 0 0 57.472 63.68l6.528 0.32h50.304V362.112h-282.24v-120.512h50.688l6.464-0.32a64 64 0 0 0 57.536-63.68V0l-0.384-6.528a64 64 0 0 0-57.152-57.088L601.28-64h-177.92l-6.592 0.384a64 64 0 0 0-57.152 57.088L359.296 0v177.6a64 64 0 0 0 57.472 63.68l6.528 0.32h50.56V362.112H181.824v-120.512h60.16l6.4-0.32a64 64 0 0 0 57.6-63.68V0l-0.448-6.528a64 64 0 0 0-57.088-57.088L241.92-64H64l-6.592 0.384a64 64 0 0 0-57.088 57.088L0 0v177.6a64 64 0 0 0 57.408 63.68L64 241.664h40.96V368.64a70.4 70.4 0 0 0 70.464 70.4h298.432V526.336H320.512l-6.592 0.32a64 64 0 0 0-57.088 57.152l-0.32 6.528V768a64 64 0 0 0 64 64h384zM76.8 12.8h152.32v152H76.8V12.8z m359.296 0h152.32v152h-152.32V12.8z m359.296 0h152.32v152h-152.32V12.8z m-462.08 590.4h358.4V755.2h-358.4v-152z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_sortingby_b" unicode="&#59186;" d="M786.368 152.832L889.6 256l38.464-38.528 38.528-38.4-196.032-196.032a54.464 54.464 0 0 0-72.96-3.584l-3.968 3.584-196.032 196.032L574.464 256l103.168-103.168V746.496h108.8v-593.664zM291.968 800.896c14.464 0 28.352-5.76 38.528-16l196.032-195.968-38.528-38.4-38.4-38.528-103.232 103.232v-593.728h-108.8V615.232L134.528 512 57.536 588.928l196.032 196.032 3.904 3.584a54.4 54.4 0 0 0 34.56 12.352z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_sales__order_b" unicode="&#59187;" d="M817.664 753.6a64 64 0 0 0 63.104-63.04l5.12-353.408c0-0.256 0.128-0.512 0.32-0.64a1.024 1.024 0 0 0 0-1.408L522.176-28.8a64 64 0 0 0-90.496 0L99.136 303.744a64 64 0 0 0 0 90.496l364.032 364.16v0.256c0 0.064 0 0.192 0.128 0.192l354.368-5.248z m-110.016-174.208A128 128 0 1 1 526.72 398.336a128 128 0 0 1 181.056 181.056z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_sendtest_b" unicode="&#59188;" d="M928 833.6a38.4 38.4 0 0 0 38.4-38.4v-822.4a38.4 38.4 0 0 0-38.4-38.4h-832a38.4 38.4 0 0 0-38.4 38.4V795.136a38.4 38.4 0 0 0 38.4 38.4h832zM134.4 11.2h755.2V756.864H134.4v-745.664z m328.128 531.456a38.4 38.4 0 0 0 30.272-23.04l78.464-184.448 63.04 77.056a38.464 38.464 0 0 0 29.76 14.08h154.88v-76.8H682.24l-91.648-112.128a38.4 38.4 0 0 0-65.088 9.344L447.552 429.632l-63.104-80.64a38.4 38.4 0 0 0-30.272-14.784h-147.2v76.8h128.64l91.648 117.248 3.392 3.712a38.4 38.4 0 0 0 31.872 10.624z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_time_full_b" unicode="&#59189;" d="M512 800a416 416 0 1 0 0-832 416 416 0 0 0 0 832z m-62.08-176.576V355.84a38.464 38.464 0 0 1 38.336-38.464h187.776v76.8H526.72V623.424h-76.8z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_datasource_b" unicode="&#59190;" d="M96 800a64 64 0 0 1-64-64v-704l0.32-6.528a64 64 0 0 1 57.088-57.152l6.592-0.32h832l6.528 0.32a64 64 0 0 1 57.472 63.68v704a64 64 0 0 1-64 64h-832z m819.2-755.2H108.8v173.76h806.4V44.8z m-730.56 47.872h128v76.8h-128v-76.8zM915.2 295.296H108.8V470.4h806.4v-175.04zM184.64 344.448h128v76.8h-128v-76.8zM915.2 547.072H108.8V723.2h806.4v-176.128zM184.64 596.16h128v76.8h-128v-76.8z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_unpack_b" unicode="&#59180;" d="M668.16 844.032a38.4 38.4 0 0 0 31.232 2.112l4.224-1.92 333.76-172.16a38.4 38.4 0 0 0 0.512-67.968l-85.312-45.76 85.12-44.928a38.4 38.4 0 0 0 0.512-67.648l-129.92-70.976v-241.6a38.4 38.4 0 0 0-20.352-33.92l-328.448-175.296a38.4 38.4 0 0 0-35.84-0.128l-334.976 175.36a38.4 38.4 0 0 0-20.544 33.92V376.576L41.28 445.76a38.4 38.4 0 0 0 0.512 67.648l85.12 44.928L41.6 604.16a38.4 38.4 0 0 0 0.512 67.968L375.872 844.16l4.224 1.92a38.4 38.4 0 0 0 31.296-2.112L539.776 776.32 668.096 844.032zM244.8 156.416l260.736-136.32V318.72l-98.56-52.928a38.4 38.4 0 0 0-36.544 0.128L244.864 334.528v-178.112z m464.128 109.504a38.4 38.4 0 0 0-36.544-0.128L582.4 314.24v-290.816l249.024 132.864v176.64l-122.432-66.944zM140.992 478.912L389.12 343.36l69.312 37.184-249.92 134.08-67.52-35.712z m480-98.368l69.376-37.12 248.128 135.488-67.584 35.712-249.92-134.08z m-330.624 177.28l249.408-133.632 249.28 133.696-249.28 131.648-249.408-131.648zM142.208 637.376l66.56-35.712 248.768 131.328-64.256 33.92-251.072-129.536z m479.68 95.616L870.656 601.6l66.688 35.712-251.072 129.536-64.384-33.92z"  horiz-adv-x="1088" />
+      
+      <glyph glyph-name="icon_vgm_n_b" unicode="&#59179;" d="M615.04 753.6a32 32 0 0 0 32-32v-64c0-1.088-0.32-2.176-0.448-3.264h67.264l8.32-0.384a96 96 0 0 0 85.312-74.496l101.12-448a96 96 0 0 0-82.368-116.48l-11.328-0.64H223.04a96 96 0 0 0-95.488 105.92l1.92 11.2 100.992 448a96 96 0 0 0 93.632 74.88h67.2c-0.128 1.088-0.32 2.176-0.32 3.264v64a32 32 0 0 0 32 32h192zM324.032 577.472a19.2 19.2 0 0 1-18.752-14.912l-101.056-448a19.2 19.2 0 0 1 18.752-23.424h591.872a19.2 19.2 0 0 1 18.752 23.424l-101.056 448a19.2 19.2 0 0 1-18.752 14.912h-389.76z m320.32-211.2c23.04 0 40.32-2.112 51.776-6.272 11.52-4.16 21.056-10.688 28.544-19.584 7.616-8.704 13.312-19.84 17.152-33.344l-62.4-11.136a33.664 33.664 0 0 1-13.12 18.112 40.448 40.448 0 0 1-23.36 6.272 42.432 42.432 0 0 1-33.92-14.848c-8.384-9.792-12.608-25.28-12.608-46.592 0-22.592 4.224-38.784 12.672-48.512 8.576-9.664 20.48-14.528 35.712-14.528 7.232 0 14.08 1.024 20.672 3.072 6.592 2.112 14.08 5.696 22.528 10.688v19.712h-43.2v43.52h99.84v-89.152a206.656 206.656 0 0 0-50.752-26.688c-14.72-4.672-32.064-7.04-52.224-7.04-24.832 0-45.12 4.288-60.8 12.736a87.488 87.488 0 0 0-36.352 37.76 124.8 124.8 0 0 0-12.8 57.664c0 22.848 4.672 42.688 14.08 59.52 9.408 16.896 23.232 29.76 41.408 38.464 14.144 6.784 33.216 10.176 57.152 10.176z m-283.136-3.584v-78.976l67.776 78.976h85.888l-76.16-78.848 79.552-130.304H438.72l-44.032 86.08-33.408-35.008v-51.072h-64.64V362.688h64.64z"  horiz-adv-x="1088" />
+      
+      <glyph glyph-name="icon_booking_resend" unicode="&#59178;" d="M114.858667 750.506667a21.333333 21.333333 0 0 0 30.634666 21.077333l751.786667-368.384a21.333333 21.333333 0 0 0 0-38.314667L168.192 7.594667l-22.741333-11.136a21.333333 21.333333 0 0 0-30.634667 21.034666l0.554667 3.242667 6.186666 24.618667 83.072 333.482666a21.461333 21.461333 0 0 1 0 10.325334L115.413333 747.221333l-0.554666 3.285334z m153.429333-398.677334l-62.208-249.6 509.44 249.6H268.288z m-0.938667 68.266667h440.32L206.08 665.813333l61.269333-245.76z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_hbl_reopen" unicode="&#59176;" d="M631.381333-41.984l-64-1.28-3.669333 179.413333 64 1.28 3.669333-179.413333z m237.482667 92.714667l-48.256-42.026667-117.802667 135.424 48.213334 41.984 117.845333-135.381333zM372.48 444.458667l-130.688-133.333334a113.066667 113.066667 0 0 1 161.536-158.250666l130.56 133.290666 26.026667-25.386666 25.856-25.344-130.645334-133.290667a185.6 185.6 0 0 0-265.088 259.712l130.56 133.290667 51.882667-50.688z m556.714667-114.005334l-0.298667-64-179.498667 0.810667 0.298667 64 179.498667-0.810667zM574.293333 751.018667a185.6 185.6 0 0 0 262.442667-262.485334l-131.925333-131.968-51.285334 51.285334 131.968 131.968A113.066667 113.066667 0 0 1 625.578667 699.733333L493.653333 567.765333l-25.642666 25.6-25.6 25.685334 131.925333 131.968zM244.309333 546.56l-1.621333-64-179.413333 4.48 1.578666 64 179.456-4.48z m49.066667 122.154667l-49.109333-41.002667-115.029334 137.813333 49.066667 40.96 115.072-137.813333z m139.178667 5.12h-64V853.333333h64v-179.498666z"  horiz-adv-x="1066" />
+      
+      <glyph glyph-name="icon_eci_st_retrigger" unicode="&#59177;" d="M751.658667 400h89.6a335.274667 335.274667 0 0 1-564.693334 225.706667L226.816 678.4a406.528 406.528 0 0 0 279.68 111.018667c219.050667 0 397.696-172.714667 407.296-389.418667h90.666667l-126.421334-125.098667-126.378666 125.098667z m-234.282667-421.461333c-219.050667 0-397.696 172.714667-407.296 389.418666H19.541333l126.421334 125.098667 126.378666-125.098667H182.613333a335.274667 335.274667 0 0 1 564.693334-225.664l49.749333-52.736a406.528 406.528 0 0 0-279.68-111.018666z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_next_b1" unicode="&#59175;" d="M706.112 336l-144.32-144.32a48 48 0 0 1 67.84-67.84l226.304 226.24a48 48 0 0 1 0 67.84L629.632 644.288a48 48 0 0 1-67.84-67.84l144.32-144.384h-476.16a48 48 0 1 1 0-96h476.16z"  horiz-adv-x="1088" />
+      
+      <glyph glyph-name="icon_default_screen_b" unicode="&#59174;" d="M372.864 283.84a38.4 38.4 0 0 0 38.4-38.4v-246.912h-76.8v208.512H126.08v76.8h246.848z m525.12-76.8h-208.512v-208.512H612.736v246.912a38.4 38.4 0 0 0 38.4 38.4h246.848v-76.8z m-486.656 315.52a38.4 38.4 0 0 0-38.4-38.4H126.08v76.8h208.512V769.408h76.736v-246.848z m278.144 38.4h208.512v-76.8h-246.848a38.4 38.4 0 0 0-38.4 38.4V769.408h76.8v-208.448z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_update__detail_b" unicode="&#59173;" d="M272.32 367.936H184.896a333.12 333.12 0 0 1 560.96-224.064l26.304-27.904 26.368-27.968a409.792 409.792 0 0 0-690.56 279.936H19.648L145.92 493.056 272.32 368z m234.24 423.68a409.792 409.792 0 0 0 409.408-391.552h88.448L878.08 274.944 751.68 400h87.424a333.12 333.12 0 0 1-560.96 224l-26.304 27.968-26.432 27.968a408.64 408.64 0 0 0 281.152 111.552zM371.264 422.4A38.4 38.4 0 1 0 371.2 345.6a38.4 38.4 0 0 0 0 76.8z m140.8 0A38.4 38.4 0 1 0 512 345.6a38.4 38.4 0 0 0 0 76.8z m140.8 0a38.4 38.4 0 1 0 0-76.8 38.4 38.4 0 0 0 0 76.8z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_brno_b" unicode="&#59165;" d="M839.04 832a64 64 0 0 0 64-64v-768l-0.32-6.528a64 64 0 0 0-57.152-57.152l-6.592-0.32h-640l-6.528 0.32a64 64 0 0 0-57.152 57.152L135.04 0V768a64 64 0 0 0 64 64h640z m-627.2-819.2h614.4V755.2h-614.4v-742.4z m531.2 80h-448v76.8h448v-76.8z m0 150.336h-448V319.872h448v-76.8zM532.096 658.816c4.096-0.448 8.064-1.024 12.032-1.792 2.048-0.448 4.032-1.024 6.08-1.536 1.984-0.512 4.032-0.896 5.952-1.472l5.824-2.048 4.8-1.728 2.176-0.896c1.152-0.448 2.304-1.088 3.456-1.6 2.112-0.96 4.224-1.92 6.272-3.008a128.32 128.32 0 0 0 53.952-54.08l2.816-5.76 2.432-5.376 2.176-6.08 1.92-5.376 1.6-6.336c0.448-1.856 0.96-3.712 1.344-5.632 0.448-2.112 0.64-4.352 1.024-6.528 0.832-6.08 1.472-12.288 1.472-18.56a128.64 128.64 0 0 0-5.632-37.184c-0.64-2.048-1.28-4.096-2.048-6.08l-1.92-5.376c-0.64-1.6-1.472-3.2-2.176-4.8a128.768 128.768 0 0 0-2.88-5.952c-0.896-1.728-1.92-3.392-2.88-5.056a128.128 128.128 0 0 0-10.496-15.424c-1.088-1.408-2.24-2.688-3.392-4.032l-4.8-5.312-3.392-3.264a129.152 129.152 0 0 0-36.16-24.512l-3.968-1.792-5.76-2.112c-2.176-0.768-4.288-1.536-6.464-2.176-1.728-0.512-3.456-0.896-5.12-1.28a128.832 128.832 0 0 0-31.36-4.032 129.984 129.984 0 0 0-25.28 2.56 127.744 127.744 0 0 0-11.392 2.816c-1.792 0.448-3.52 1.152-5.312 1.728a128.064 128.064 0 0 0-16.64 7.04c-1.536 0.832-3.136 1.6-4.672 2.496-1.92 1.088-3.84 2.304-5.696 3.456l-4.352 2.88a128.64 128.64 0 0 0-5.12 3.84c-1.28 1.024-2.624 1.92-3.84 3.008a129.216 129.216 0 0 0-16.384 16.32l-2.816 3.584a128.896 128.896 0 0 0-4.096 5.568l-2.944 4.48a128.512 128.512 0 0 0-8.448 15.68l-2.24 5.12a127.68 127.68 0 0 0-4.032 11.776l-1.408 5.312A128.512 128.512 0 0 0 519.04 659.456l13.12-0.64z"  horiz-adv-x="1088" />
+      
+      <glyph glyph-name="icon_smart_b" unicode="&#59166;" d="M768.512 315.328a32 32 0 0 0 55.488 0l32.704-56.704c2.432-4.224 5.76-7.872 9.856-10.56l49.664-33.408a32 32 0 0 0 0-53.12L866.56 128a31.936 31.936 0 0 1-9.856-10.56l-32.704-56.704a32 32 0 0 0-55.488 0l-32.064 55.68a32 32 0 0 1-11.776 11.712l-55.68 32.192a32 32 0 0 0 0 55.424l55.68 32.128a32 32 0 0 1 11.776 11.712l32.128 55.68zM408.192 707.2a32 32 0 0 0 55.424 0l100.48-174.08a32 32 0 0 1 9.728-10.56l150.4-101.12a32 32 0 0 0 0-53.12l-150.4-101.12a32 32 0 0 1-9.792-10.56l-100.48-174.08a32 32 0 0 0-55.36 0l-99.84 173.056a32 32 0 0 1-11.712 11.712l-173.056 99.84a32 32 0 0 0 0 55.488l173.056 99.84a32 32 0 0 1 11.712 11.648l99.84 173.056z"  horiz-adv-x="1088" />
+      
+      <glyph glyph-name="icon_map_b" unicode="&#59167;" d="M532.032 840.96a254.848 254.848 0 0 0 241.664-254.464l-0.64-16.768a290.688 290.688 0 0 0-15.36-69.248l199.36 53.312a38.4 38.4 0 0 0 48.32-37.056v-461.056a38.4 38.4 0 0 0-27.52-36.8l-307.904-90.624a38.528 38.528 0 0 0-24.96 1.152l-310.592 122.56-247.68-111.104a38.4 38.4 0 0 0-54.08 35.008V436.928a38.4 38.4 0 0 0 22.656 35.072l209.92 94.08-0.384 3.328-0.704 17.088A254.848 254.848 0 0 0 518.912 841.344l13.056-0.32zM109.312 412.096v-376.832l208.384 93.44 7.296 2.432a38.528 38.528 0 0 0 22.528-1.728l313.28-123.648 267.776 78.72V466.752l-212.8-56.96c-72.384-126.976-188.16-238.336-196.928-238.592l-1.856 0.64c-21.12 11.52-178.56 166.08-233.792 318.144L109.376 412.032z m409.6 352.448a178.048 178.048 0 0 1-178.048-177.92c0-29.248 10.112-65.92 30.464-107.904 19.968-41.344 47.424-83.072 76.48-121.024 24.768-32.384 49.92-60.8 70.72-82.624 20.864 22.144 46.272 51.2 71.232 83.968 27.136 35.712 52.864 74.624 72.448 113.152l-0.704 2.56 2.304 0.64 2.624 5.12c20.416 42.112 30.4 78.144 30.4 106.048a177.984 177.984 0 0 1-177.92 177.984z m10.368-65.92c51.84-5.248 92.352-49.088 92.352-102.4l-0.512-10.496A102.848 102.848 0 0 0 518.848 493.44l-10.56 0.512A102.976 102.976 0 0 0 416.512 585.6L416 596.16c0 56.832 46.08 102.912 102.848 102.912l10.496-0.512z m-10.496-76.288a26.112 26.112 0 1 1 0.064-52.224 26.112 26.112 0 0 1 0 52.224z"  horiz-adv-x="1088" />
+      
+      <glyph glyph-name="icon_template_b1" unicode="&#59168;" d="M898.56 559.872v-13.44c0.128-1.088 0.064-2.176 0-3.328V32a134.4 134.4 0 0 0-134.336-134.4H273.728a134.4 134.4 0 0 0-134.4 134.4v704c0 74.24 60.16 134.4 134.4 134.4h314.368l310.528-310.528zM273.792 793.6a57.6 57.6 0 0 1-57.6-57.6v-704l0.32-5.888a57.6 57.6 0 0 1 57.28-51.712h490.496a57.6 57.6 0 0 1 57.344 51.712l0.32 5.888V505.6h-153.6a134.4 134.4 0 0 0-134.4 134.336V793.6H273.664zM610.624 640c0-29.824 22.72-54.4 51.712-57.28l5.888-0.32h99.456L610.56 739.392v-99.456z"  horiz-adv-x="1088" />
+      
+      <glyph glyph-name="icon_door_b" unicode="&#59169;" d="M446.912 784a96 96 0 0 0 131.328 0.96l394.624-364.288-43.392-46.976-42.24 39.04v-423.104a32 32 0 0 0-32-32H618.432a32 32 0 0 0-32 32v174.08H441.152v-174.08a32 32 0 0 0-32-32H185.344a32 32 0 0 0-32 32V416l-44.096-41.984-44.16 46.336L446.976 784z m87.872-46.016a32 32 0 0 1-43.712-0.384L217.344 476.928v-455.296h159.808v174.08a32 32 0 0 0 32 32h209.344a32 32 0 0 0 32-32v-174.08h172.672V471.872L534.784 737.92z m317.184 17.92a32 32 0 0 0 32-32v-144.64h-64v112.64h-129.024v64h161.024z"  horiz-adv-x="1088" />
+      
+      <glyph glyph-name="icon_map_point_b" unicode="&#59170;" d="M823.296 462.677333c0-220.202667-301.653333-516.906667-317.013333-516.906666-15.445333 0-317.098667 291.584-317.098667 516.906666a317.056 317.056 0 1 0 634.112 0zM506.24 474.709333m-128 0a128 128 0 1 1 256 0 128 128 0 1 1-256 0Z"  horiz-adv-x="1066" />
+      
+      <glyph glyph-name="icon_current__location_b" unicode="&#59171;" d="M852.608 796.288c55.04 13.44 104.96-43.2 80.128-97.792L620.16 11.008c-31.36-68.864-134.464-46.528-134.464 29.184v325.76H169.216c-76.992 0-98.112 105.792-27.072 135.36l699.392 291.392 11.072 3.584zM201.216 442.752h361.152v-373.12L856.064 715.52 201.216 442.752z"  horiz-adv-x="1088" />
+      
+      <glyph glyph-name="icon_address_book_b" unicode="&#59172;" d="M887.04 832a64 64 0 0 0 64-64v-768l-0.32-6.528a64 64 0 0 0-63.744-57.472H215.04l-6.528 0.32a64 64 0 0 0-57.152 57.152L151.04 0v165.504h-64v76.8h64V525.696h-64v76.8h64V768a64 64 0 0 0 57.472 63.68L214.976 832h672zM227.84 602.496h64v-76.8h-64v-283.456h64v-76.8h-64V12.8h646.4V755.2H227.84v-152.704z m527.936-466.688h-398.72v76.8h398.72v-76.8z m0 214.4h-398.72V426.88h398.72v-76.8z m0 214.4h-398.72V641.28h398.72v-76.8z"  horiz-adv-x="1088" />
+      
+      <glyph glyph-name="icon_guideright_b" unicode="&#59163;" d="M870.4 384.512a38.4 38.4 0 0 1-35.392 38.016 237.824 237.824 0 0 0-211.84 177.28l-14.144 54.336-74.368-19.392 14.144-54.4A313.28 313.28 0 0 1 647.04 422.4H192v-76.8h456.896a319.936 319.936 0 0 1-100.8-160.896l-13.376-50.88 74.24-19.648 13.44 51.008a244.096 244.096 0 0 0 213.248 180.8 38.4 38.4 0 0 1 34.752 38.528z"  horiz-adv-x="1024" />
+      
+      <glyph glyph-name="icon_guideleft_b" unicode="&#59164;" d="M181.44 384.512a38.4 38.4 0 0 0 35.392 38.016A237.824 237.824 0 0 1 428.8 599.808l14.08 54.336 74.368-19.392-14.08-54.4A313.28 313.28 0 0 0 404.736 422.4h455.04v-76.8H402.944a319.936 319.936 0 0 0 100.736-160.896l13.376-50.88-74.24-19.648-13.44 51.008A244.096 244.096 0 0 1 216.32 345.984a38.4 38.4 0 0 0-34.816 38.528z"  horiz-adv-x="1088" />
+      
       <glyph glyph-name="icon_guidelines_b" unicode="&#59161;" d="M603.84-2.88a38.4 38.4 0 0 0 0-75.264l-7.744-0.704h-160a38.4 38.4 0 1 0 0 76.736h160l7.68-0.768zM516.096 647.36a269.376 269.376 0 0 0 144.576-496.512c-0.896-2.432-1.92-6.144-3.008-11.2a324.672 324.672 0 0 1-5.12-43.712 72.128 72.128 0 0 0-71.04-68.224l-127.296-0.832a72.32 72.32 0 0 0-72.064 67.648 298.24 298.24 0 0 1-5.76 43.52 74.304 74.304 0 0 1-3.712 12.16 269.312 269.312 0 0 0 143.424 497.216z m-234.24-489.408l27.136-27.2-76.928-76.864-54.208 54.272 76.8 76.928 27.264-27.136z m572.608-49.792l-54.272-54.272-76.928 76.864 27.136 27.2 27.2 27.136 76.864-76.928zM516.096 570.624a192.64 192.64 0 0 1-99.008-357.76l4.8-3.2c10.496-8 16.512-18.56 19.968-25.92 4.288-9.216 7.296-19.264 9.408-28.48 3.968-17.152 5.952-36.096 7.104-51.52l117.76 0.768c1.024 15.296 2.816 33.92 6.272 50.688 1.92 9.024 4.48 18.944 8.448 27.968a62.848 62.848 0 0 0 24.256 29.632l10.24 6.72a192.64 192.64 0 0 1-109.312 351.104zM184.96 350.144H72.448V426.88H184.96v-76.8z m774.784 0H847.36V426.88h112.448v-76.8zM309.056 653.76l-27.072-27.2-27.2-27.136-76.864 76.928 54.208 54.272 76.928-76.864z m545.472 22.592L777.6 599.424l-27.2 27.136-27.136 27.2 76.928 76.864 54.272-54.272z m-300.608 22.912h-76.8V807.488h76.8v-108.224z"  horiz-adv-x="1088" />
       
       <glyph glyph-name="icon_cancelled_b" unicode="&#59162;" d="M906.56 191.936l-27.136-27.136-80.896-80.768 80.896-80.896 27.2-27.136-54.4-54.336-27.072 27.2-80.896 80.896-80.768-80.896-27.136-27.2-54.336 54.336 27.2 27.136 80.832 80.896-80.832 80.768L582.016 192l54.336 54.336 27.136-27.2 80.768-80.832 80.896 80.832 27.136 27.2 54.272-54.336zM788.288 846.4a102.4 102.4 0 0 0 102.4-102.4v-458.24h-76.8v458.24a25.6 25.6 0 0 1-25.6 25.6H233.792a25.6 25.6 0 0 1-25.6-25.6v-704c0-14.08 11.456-25.6 25.6-25.6h277.248v-76.8H233.792a102.4 102.4 0 0 0-102.4 102.4v704a102.4 102.4 0 0 0 102.4 102.4h554.496z m-91.136-550.592H335.488v76.8h361.664v-76.8z m0 205.632H335.488v76.8h361.664v-76.8z"  horiz-adv-x="1088" />

binární
src/styles/icons/iconfont.ttf


binární
src/styles/icons/iconfont.woff


binární
src/styles/icons/iconfont.woff2


+ 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: #2b2f36;
 }
   

+ 58 - 41
src/views/DestinationDelivery/src/components/CreateNewBooking/src/components/NewbookingTable.vue

@@ -30,7 +30,7 @@ const tableData = ref<VxeGridProps<any>>({
     backgroundColor: 'var(--color-table-header-bg)'
   },
   columnConfig: { resizable: true, useKey: true },
-  rowConfig: { isHover: true, isCurrent: true },
+  rowConfig: { isHover: true, isCurrent: true }
 })
 
 const tableRef = ref<VxeGridInstance | null>(null)
@@ -48,7 +48,7 @@ const handleColumns = (columns: any) => {
         ...curColumn,
         formatter: ({ cellValue }: any) => formatTimezone(cellValue)
       }
-    }  else if (item.type === 'link') {
+    } else if (item.type === 'link') {
       curColumn = {
         ...curColumn,
         slots: { default: 'trackingNo' }
@@ -57,7 +57,7 @@ const handleColumns = (columns: any) => {
       curColumn = {
         ...curColumn,
         formatter: ({ cellValue }: any) => {
-          const array = cellValue.split("-")
+          const array = cellValue.split('-')
           return `${formatTimezone(array[0])} - ${formatTimezone(array[1])}`
         }
       }
@@ -71,15 +71,13 @@ const getTableColumns = async () => {
   tableLoadingColumn.value = true
   await $api.BookingTableColumn().then((res: any) => {
     if (res.code === 200) {
-      if(a == undefined) {
+      if (a == undefined) {
         tableData.value.columns = [
           { type: 'checkbox', width: 50, fixed: 'left' },
           ...handleColumns(res.data.TrackingTableColumns)
         ]
-      }else {
-        tableData.value.columns = [
-          ...handleColumns(res.data.TrackingTableColumns)
-        ]
+      } else {
+        tableData.value.columns = [...handleColumns(res.data.TrackingTableColumns)]
       }
     }
   })
@@ -96,15 +94,15 @@ const getTableData = (val: any) => {
 const searchTableData = (val: any) => {
   tableLoadingTable.value = true
   $api
-  .BookingTableSearch({
-    ...val
-  })
-  .then((res: any) => {
-    if (res.code === 200) {
-      tableLoadingTable.value = false
-      tableData.value.data = res.data.data
-    }
-  })
+    .BookingTableSearch({
+      ...val
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        tableLoadingTable.value = false
+        tableData.value.data = res.data.data
+      }
+    })
 }
 
 const emits = defineEmits(['selectChangeEvent'])
@@ -116,78 +114,100 @@ let checkShipmentsdata = []
 let checkShipmentsInfo = {}
 let checkShipmentsSubmitInfo = {}
 const checkUniformArray = (arrary: Array<{ consignee_id: any; country: any }>) => {
-  if (arrary.length === 0) return false;
-  const first = arrary[0];
+  if (arrary.length === 0) return false
+  const first = arrary[0]
   for (let i = 1; i < arrary.length; i++) {
     if (arrary[i].consignee_id !== first.consignee_id) {
-        return false;
+      return false
     }
   }
-  return [first];
+  return [first]
 }
-const selectChangeEvent = () => {
+
+// 将具有相同same_mbol的行选中或取消选中
+const selectRowsWithSameMbol = ({ row, checked }) => {
+  const key = row.same_mbol
+  if (!key) return
+  const tableRowData = tableRef.value?.getTableData().fullData || []
+  tableRowData.forEach((item, index) => {
+    if (item.same_mbol === key) {
+      tableRef.value?.setCheckboxRow(item, checked)
+    }
+  })
+}
+const selectChangeEvent = (selectItem) => {
+  selectRowsWithSameMbol(selectItem)
   const $grid = tableRef.value
   if ($grid) {
     const records = $grid.getCheckboxRecords()
-    checkShipments = records.map(item => ({ consignee_id: item.consignee_id, country: item.dc_country }))
-    checkRecommend = records.map(item => ({ date_range: item.date_range.split('-'), Hbol: item.h_bol  }))
+    checkShipments = records.map((item) => ({
+      consignee_id: item.consignee_id,
+      country: item.dc_country
+    }))
+    checkRecommend = records.map((item) => ({
+      date_range: item.date_range.split('-'),
+      Hbol: item.h_bol
+    }))
     const array = checkUniformArray(checkShipments)
-    if(array != false) {
+    if (array != false) {
       checkShipmentsdata = Object.keys(checkUniformArray(checkShipments)?.[0])
       checkShipmentsSubmit = Object.keys(records?.[0])
       checkShipmentsdata.forEach((item) => {
         Object.assign(checkShipmentsInfo, {
-          [item]: array.map((row) => row[item] )
+          [item]: array.map((row) => row[item])
         })
       })
       checkShipmentsSubmit.forEach((item) => {
         Object.assign(checkShipmentsSubmitInfo, {
           [item]: records.map((row) => {
-            if(row[item] == null){
+            if (row[item] == null) {
               return ''
             } else {
               return row[item]
             }
-          } )
+          })
         })
       })
     } else {
       checkShipmentsSubmitInfo = {}
       checkShipmentsInfo = {}
     }
-    emits('selectChangeEvent',checkShipmentsInfo, checkRecommend,checkShipmentsSubmitInfo)
+    emits('selectChangeEvent', checkShipmentsInfo, checkRecommend, checkShipmentsSubmitInfo)
   }
 }
 // 全选
-const selectAllChangeEvent= () => {
+const selectAllChangeEvent = () => {
   const $grid = tableRef.value
   if ($grid) {
     const records = $grid.getCheckboxRecords()
-    checkShipments = records.map(item => ({ consignee_id: item.consignee_id }))
-    checkRecommend = records.map(item => ({ date_range: item.date_range.split('-'), Hbol: item.h_bol }))
-    if(checkShipments.length != 0) {
+    checkShipments = records.map((item) => ({ consignee_id: item.consignee_id }))
+    checkRecommend = records.map((item) => ({
+      date_range: item.date_range.split('-'),
+      Hbol: item.h_bol
+    }))
+    if (checkShipments.length != 0) {
       checkShipmentsdata = Object.keys(checkShipments?.[0])
       checkShipmentsSubmit = Object.keys(records?.[0])
       checkShipmentsdata.forEach((item) => {
         Object.assign(checkShipmentsInfo, {
-          [item]: checkShipments.map((row) => row[item] )
+          [item]: checkShipments.map((row) => row[item])
         })
       })
       checkShipmentsSubmit.forEach((item) => {
         Object.assign(checkShipmentsSubmitInfo, {
           [item]: records.map((row) => {
-            if(row[item] == null){
+            if (row[item] == null) {
               return ''
             } else {
               return row[item]
             }
-          } )
+          })
         })
       })
     } else {
       checkShipmentsSubmitInfo = {}
     }
-    emits('selectChangeEvent',checkShipmentsInfo, checkRecommend,checkShipmentsSubmitInfo)
+    emits('selectChangeEvent', checkShipmentsInfo, checkRecommend, checkShipmentsSubmitInfo)
   }
 }
 
@@ -201,7 +221,6 @@ defineExpose({
   getTableData,
   searchTableData
 })
-
 </script>
 
 <template>
@@ -218,9 +237,7 @@ defineExpose({
         <div v-if="isNotActivated" class="empty-text">
           This service isn't activated yet. Please contact our team to enable it.
         </div>
-        <div v-else class="empty-text">
-          No eligible shipments found to create a new booking.
-        </div>
+        <div v-else class="empty-text">No eligible shipments found to create a new booking.</div>
       </template>
     </vxe-grid>
   </div>

+ 10 - 1
src/views/Layout/src/components/Header/HeaderView.vue

@@ -215,6 +215,11 @@ const handleCloseThemePopover = () => {
   isPopoverVisible.value = false
   document.removeEventListener('click', handleClickOutside)
 }
+
+const handleDemoVideo = () => {
+  const { href } = router.resolve({ name: 'Demo Video' })
+  window.open(href, '_blank')
+}
 </script>
 
 <template>
@@ -352,7 +357,11 @@ const handleCloseThemePopover = () => {
             <span class="font_family icon-icon_manual_b"></span>
             User Manual
           </div>
-          <div class="item" @click="handleLogout">
+          <div class="item" style="margin-left: 1px" @click="handleDemoVideo">
+            <span class="font_family icon-icon_video_b"></span>
+            Demo Video
+          </div>
+          <div class="item" style="margin-left: 2px" @click="handleLogout">
             <span class="font_family icon-icon_export_b"></span>
             Logout
           </div>

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

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

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

@@ -0,0 +1,616 @@
+<script setup lang="ts">
+import { useTrackingDownloadData } from '@/stores/modules/trackingDownloadData'
+import emitter from '@/utils/bus'
+import { useRouter } from 'vue-router'
+import { useUserStore } from '@/stores/modules/user'
+
+const userStore = useUserStore()
+const router = useRouter()
+const trackingDownloadData = useTrackingDownloadData()
+const attachmentData = ref([])
+const bodyLoading = ref(false)
+const pageLoading = ref(false)
+
+// const shipments = ref(attachmentData)
+const getAttachmentData = () => {
+  pageLoading.value = true
+  $api
+    .getDownloadAttachmentData({
+      serial_no_arr: trackingDownloadData.serialNoArr,
+      schemas_arr: trackingDownloadData.schemasArr
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        attachmentData.value = res.data
+      }
+    })
+    .finally(() => {
+      pageLoading.value = false
+    })
+}
+onMounted(() => {
+  getAttachmentData()
+})
+
+// === 1. 全选状态计算 ===
+const isAllSelected = computed({
+  get() {
+    return attachmentData.value.every((item) => item.isSelect || item.typeList?.length === 0)
+  },
+  set(val) {
+    attachmentData.value.forEach((item) => {
+      if (item.typeList?.length === 0) return
+      item.isSelect = val
+      // 同步子级
+      if (item.typeList) {
+        item.typeList.forEach((type) => {
+          if (type.attachmentList) {
+            type.attachmentList.forEach((att) => {
+              att.isSelect = val
+            })
+          }
+        })
+      }
+    })
+  }
+})
+
+// 父级变化时,更新子级状态
+const handleParentToggle = (ship) => {
+  const newVal = ship.isSelect
+  ship.typeList.forEach((type) => {
+    if (type.attachmentList) {
+      type.attachmentList.forEach((att) => {
+        att.isSelect = newVal
+      })
+    }
+  })
+}
+
+// 子级变化时,更新父级状态
+const handleChildToggle = (ship) => {
+  if (!ship.typeList || ship.typeList.length === 0) {
+    // 如果没有子项,直接返回当前状态或设为 false
+    ship.isSelect = false
+    return
+  }
+
+  // 判断所有 attachment 是否都选中
+  const allSelected = ship.typeList.every((type) =>
+    type.attachmentList?.every((att) => att.isSelect)
+  )
+
+  ship.isSelect = allSelected
+}
+
+// === 3. 初始化数据结构(确保每个 attachment 都有 isSelect)
+// 如果原始数据不完整,可以预处理
+const initShipments = () => {
+  attachmentData.value.forEach((item) => {
+    if (!item.isSelect) item.isSelect = false
+    if (item.typeList) {
+      item.typeList.forEach((type) => {
+        if (type.attachmentList) {
+          type.attachmentList.forEach((att) => {
+            if (!att.isSelect) att.isSelect = false
+          })
+        }
+      })
+    }
+  })
+}
+
+initShipments()
+const summaryList = ref([])
+const allChooseFiles = computed(() => {
+  return summaryList.value.reduce((acc, curr) => {
+    acc += curr.attachmentList.length
+    return acc
+  }, 0)
+})
+
+const generateSummary = () => {
+  const map = new Map() // 用 label 作为 key
+
+  attachmentData.value.forEach((item) => {
+    item?.typeList?.forEach((type) => {
+      // 遍历该类型下的所有附件
+      type?.attachmentList?.forEach((attach) => {
+        if (attach.isSelect) {
+          const label = type.label
+          if (!map.has(label)) {
+            map.set(label, {
+              label,
+              number: 0,
+              attachmentList: []
+            })
+          }
+          const group = map.get(label)
+          group.number += 1 // 每选中一个就 +1
+
+          group.attachmentList.push({ name: attach.name })
+        }
+      })
+    })
+  })
+
+  // 转为数组
+  summaryList.value = Array.from(map.values())
+}
+
+// 👇 监听 attachmentData 中所有 isSelect 的变化
+watch(
+  () => {
+    // 创建一个扁平化的路径数组,用于监听所有 isSelect
+    return attachmentData.value.map((item) =>
+      item.typeList?.map((type) => type.attachmentList?.map((att) => att.isSelect))
+    )
+  },
+  () => {
+    generateSummary()
+  },
+  { deep: true }
+)
+
+const handleFileDownload = (row: any) => {
+  // 如果from_system的值是TOPOCEAN_KSMART,不需要拼接url
+  const url = row?.url
+  // 创建一个隐藏的 <a> 标签
+  const link = document.createElement('a')
+  link.href = row?.is_topocean ? url : import.meta.env.VITE_API_HOST + '/' + url
+  link.target = '_blank'
+
+  // 指定下载文件名(可选)
+  // link.download = row?.file_name || 'file'
+
+  // 添加到 DOM 中,触发点击事件,然后移除
+  document.body.appendChild(link)
+  link.click()
+  document.body.removeChild(link)
+}
+
+const getFileNameFromContentDisposition = (contentDisposition) => {
+  const filenameStart = contentDisposition.indexOf('filename=')
+  if (filenameStart === -1) return null // 如果没有找到,直接返回
+
+  const substring = contentDisposition.slice(filenameStart + 9) // 9 是 'filename='.length
+
+  const firstQuote = substring.indexOf('"')
+
+  if (firstQuote === -1) return null // 如果没有找到开始引号,直接返回
+
+  const secondQuote = substring.indexOf('"', firstQuote + 1)
+
+  if (secondQuote === -1) return null // 如果没有找到结束引号,直接返回
+
+  return substring.slice(firstQuote + 1, secondQuote)
+}
+const handleDownloadAllSelectedFiles = (label?: string) => {
+  const selectedFiles = []
+  attachmentData.value.forEach((item) => {
+    item?.typeList?.forEach((type) => {
+      // 如果选择了 label,则只下载该类型的附件
+      if (label && type.label !== label) return
+      type?.attachmentList?.forEach((attach) => {
+        if (attach.isSelect) {
+          selectedFiles.push(attach)
+        }
+      })
+    })
+  })
+  if (selectedFiles.length === 0) {
+    ElMessage.warning('Please select at least one file to download.')
+    return
+  }
+  bodyLoading.value = true
+
+  $api
+    .downloadAttachment({
+      data: selectedFiles
+    })
+    .then((res: any) => {
+      if (res.status !== 200) {
+        ElMessageBox.alert('The request failed. Please try again later', 'Prompt', {
+          confirmButtonText: 'OK',
+          confirmButtonClass: 'el-button--dark'
+        })
+        return
+      }
+      if (res.data?.code === 403) {
+        sessionStorage.clear()
+        emitter.emit('login-out')
+        router.push('/login')
+        userStore.logout()
+        ElMessage.warning({
+          message: 'Please log in to use this feature.',
+          grouping: true
+        })
+        return
+      } else if (res.data?.code === 500) {
+        ElMessageBox.alert(res.data.message, 'Prompt', {
+          confirmButtonText: 'OK',
+          confirmButtonClass: 'el-button--dark'
+        })
+        return
+      }
+      const fileName = getFileNameFromContentDisposition(res.headers['content-disposition'])
+      const blob = new Blob([res.data], { type: 'application/zip' })
+      const downloadUrl = window.URL.createObjectURL(blob)
+      const a = document.createElement('a')
+      a.download = fileName
+      a.href = downloadUrl
+      document.body.appendChild(a)
+      a.click()
+      window.URL.revokeObjectURL(downloadUrl)
+      document.body.removeChild(a)
+    })
+    .finally(() => {
+      bodyLoading.value = false
+    })
+}
+</script>
+
+<template>
+  <div
+    class="tracking-download-attachment"
+    v-loading.fullscreen.lock="bodyLoading"
+    element-loading-text="Loading..."
+    element-loading-custom-class="element-loading"
+    element-loading-background="rgb(43, 47, 54, 0.7)"
+    v-vloading="pageLoading"
+  >
+    <div class="left-select-section">
+      <div class="header-select-all">
+        <el-checkbox v-model="isAllSelected"><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
+              :disabled="!attItem?.typeList?.length"
+              @change="handleParentToggle(attItem)"
+              v-model="attItem.isSelect"
+            >
+              <span class="font_family icon-icon_ocean_b"></span>
+              <el-tooltip effect="dark" :content="`Attachment ${attItem.no}`" placement="top">
+                <span class="label ellipsis-text">Attachment {{ attItem.no }}</span>
+              </el-tooltip>
+            </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.attachmentList.length }})
+              </div>
+              <div class="type-attachment-list">
+                <div
+                  class="attachment-file"
+                  v-for="fileItem in typeItem.attachmentList"
+                  :key="fileItem.name"
+                >
+                  <el-checkbox v-model="fileItem.isSelect" @change="handleChildToggle(attItem)">
+                    <span>{{ fileItem.name }}</span></el-checkbox
+                  >
+                  <span
+                    @click="handleFileDownload(fileItem)"
+                    class="font_family icon-icon_download_b"
+                  ></span>
+                </div>
+              </div>
+            </div>
+            <div class="empty-attachment" v-if="!attItem?.typeList?.length">no file</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%; margin-bottom: 8px"
+          @click="handleDownloadAllSelectedFiles()"
+        >
+          <span class="font_family icon-icon_download_b"></span>
+          <span>Download Selected ({{ allChooseFiles }})</span>
+        </el-button>
+        <el-collapse
+          style="margin: 8px 0"
+          expand-icon-position="left"
+          v-for="(typeItem, index) in summaryList"
+          :key="index"
+        >
+          <div class="right-download">
+            <div class="count" v-if="typeItem?.attachmentList?.length">
+              <span>{{ typeItem?.attachmentList?.length }}</span>
+            </div>
+            <span
+              @click="handleDownloadAllSelectedFiles(typeItem.label)"
+              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"
+              >
+                <v-ellipsis-tooltip
+                  :max-width="276"
+                  :max-height="32"
+                  :line-clamp="1"
+                  :content="attItem.name"
+                ></v-ellipsis-tooltip>
+              </div>
+            </div>
+          </el-collapse-item>
+        </el-collapse>
+        <div class="empty-file-data" v-if="!summaryList?.length">
+          <img src="./images/empty-img.png" alt="empty-data" />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.tracking-download-attachment {
+  display: flex;
+  height: 100%;
+  padding-left: 24px;
+  .left-select-section {
+    flex: 1;
+    .header-select-all {
+      :deep(.el-checkbox__inner) {
+        &::after {
+          top: 1px;
+          left: 7px;
+          height: 14px;
+          width: 6px;
+          border-width: 2.5px;
+        }
+      }
+    }
+  }
+  :deep(.el-checkbox__inner) {
+    &::after {
+      top: 1px;
+      left: 4px;
+      height: 9px;
+      width: 4px;
+      border-width: 2px;
+    }
+  }
+  .right-summary-section {
+    width: 340px;
+    height: 100%;
+    border: 1px solid var(--color-border);
+    min-height: 400px;
+    background-color: var(--color-attchment-summary-bg);
+    .empty-file-data {
+      padding-top: 68px;
+      text-align: center;
+    }
+  }
+}
+.left-select-section {
+  height: 100%;
+  overflow: auto;
+  .header-select-all {
+    margin: 16px 0;
+    span {
+      font-size: 18px;
+      font-weight: 700;
+    }
+    :deep(.el-checkbox__inner) {
+      width: 24px;
+      height: 24px;
+    }
+  }
+  & > .attachment-list {
+    display: grid;
+    grid-template-columns: repeat(auto-fill, minmax(326px, 1fr));
+    grid-template-rows: 320px;
+    gap: 8px;
+    padding-bottom: 36px;
+    padding-right: 24px;
+    height: calc(100% - 64px);
+    overflow: auto;
+    :deep(.el-checkbox__label) {
+      display: flex;
+      align-items: center;
+      & > .label {
+        margin-top: 3px;
+      }
+    }
+  }
+}
+.left-select-section .attachment-list .attachment-item {
+  height: 320px;
+  border: 1px solid var(--color-border);
+  border-radius: 12px;
+  overflow: hidden;
+
+  .top-number {
+    display: flex;
+    align-items: center;
+    height: 48px;
+    padding: 13px 8px;
+    background-color: var(--color-dialog-header-bg);
+    :deep(.el-checkbox) {
+      width: 100%;
+      .el-checkbox__label {
+        width: calc(100% - 8px);
+      }
+    }
+
+    .font_family {
+      font-size: 24px;
+      margin-right: 8px;
+    }
+    .label {
+      font-size: 18px;
+    }
+    .ellipsis-text {
+      width: calc(100% - 50px);
+      display: block;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+    :deep(.el-checkbox__inner) {
+      width: 16px;
+      height: 16px;
+    }
+  }
+  .attachment-content {
+    padding: 13px 8px;
+    overflow: auto;
+    height: calc(100% - 48px);
+    .empty-attachment {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      height: 100%;
+      color: var(--color-neutral-2);
+    }
+  }
+  .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 {
+    height: calc(100% - 64px);
+    padding: 16px 8px;
+    padding-bottom: 20px;
+    overflow: auto;
+  }
+
+  .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-top: 1px;
+      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 {
+        height: 17px;
+        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-bottom: 8px;
+    border-radius: 8px;
+    overflow: hidden;
+    .attachment-item {
+      height: 32px;
+      padding: 7px 8px 0;
+      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>

binární
src/views/Tracking/src/components/DownloadAttachment/src/images/empty-img.png


+ 1 - 1
src/views/Tracking/src/components/TrackingDetail/src/components/AttachmentView.vue

@@ -97,7 +97,7 @@ const handleDownload = (row: any) => {
   link.click()
   document.body.removeChild(link)
 }
-const handleDelete = (row: any) => {}
+
 const uploadFilesRef = ref<InstanceType<typeof UploadFilesDialog> | null>(null)
 
 const openUploadFilesDialog = () => {

+ 4 - 4
src/views/Tracking/src/components/TrackingGuide.vue

@@ -234,14 +234,14 @@ defineExpose({
 
 <style lang="scss" scoped>
 .download-file-guide-class {
-  right: 187px;
+  right: 183px;
   top: 246px;
-  width: 431px;
+  width: 692px;
   height: 304px;
   transform: translate(0.7px, -0.3px);
   &.download-file-guide-dark-class {
-    right: 187px;
-    width: 431px;
+    right: 183px;
+    width: 695px;
     height: 304px;
   }
 }

+ 123 - 10
src/views/Tracking/src/components/TrackingTable/src/TrackingTable.vue

@@ -10,9 +10,11 @@ import { useLoadingState } from '@/stores/modules/loadingState'
 import { useThemeStore } from '@/stores/modules/theme'
 import { useVisitedRowState } from '@/stores/modules/visitedRow'
 import { formatTimezone, formatNumber } from '@/utils/tools'
+import { useTrackingDownloadData } from '@/stores/modules/trackingDownloadData'
 
 const visitedRowState = useVisitedRowState()
 const themeStore = useThemeStore()
+const trackingDownloadData = useTrackingDownloadData()
 
 const router = useRouter()
 const props = defineProps({
@@ -375,6 +377,7 @@ onMounted(() => {
   tableRef.value && autoWidth(trackingTable.value, tableRef.value)
 })
 
+const upIcon = ref(false)
 const downloadDialogRef = ref()
 const handleDownload = () => {
   const curSelectedColumns: string[] = []
@@ -389,6 +392,30 @@ const handleDownload = () => {
     selectedNumber.value || pageInfo.value.total
   )
 }
+const handleDownloadAttachments = () => {
+  const serial_no_arr: string[] = []
+  const schemas_arr: string[] = []
+  // 将选中的记录的 serial_no 和 _schemas 收集到数组中
+  const selectedRecords = tableRef.value.getCheckboxRecords()
+
+  if (selectedRecords.length === 0) {
+    ElMessageBox.alert('Please select at least one record to download attachments', {
+      confirmButtonText: 'OK',
+      confirmButtonClass: 'el-button--dark',
+      customClass: 'tracking-table-download-alert-popup'
+    })
+    return
+  }
+  selectedRecords.forEach((item: any) => {
+    serial_no_arr.push(item.serial_no)
+    schemas_arr.push(item._schemas)
+  })
+  trackingDownloadData.setData(serial_no_arr, schemas_arr)
+
+  router.push({
+    name: 'Tracking Download Attachment'
+  })
+}
 
 const exportLoading = ref(false)
 // 获取导出表格数据
@@ -599,17 +626,44 @@ 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="handleDownload"
-          :style="{
-            paddingRight: themeStore.theme === 'dark' ? '13px' : '16px',
-            paddingLeft: themeStore.theme === 'dark' ? '13px' : '11px'
-          }"
+        <el-popover
+          trigger="click"
+          top="15vh"
+          class="box-item"
+          :width="226"
+          placement="bottom-start"
         >
-          <span style="margin-right: 7px" class="font_family icon-icon_download_b"></span>
-          Download
-        </el-button>
+          <template #reference>
+            <el-button
+              class="el-button--main el-button--pain-theme download-btn"
+              @click="upIcon = !upIcon"
+              :style="{
+                paddingRight: themeStore.theme === 'dark' ? '13px' : '16px',
+                paddingLeft: themeStore.theme === 'dark' ? '13px' : '11px'
+              }"
+            >
+              <span style="margin-right: 7px" class="font_family icon-icon_download_b"></span>
+              Download
+              <span
+                class="font_family icon-icon_up_b download-up-icon"
+                :class="{ 'rotate-icon': upIcon }"
+              ></span>
+            </el-button>
+          </template>
+          <template #default>
+            <div style="width: 226px; padding: 8px">
+              <div class="download-option-item" @click="handleDownload">
+                <span class="font_family icon-icon_download_b"></span>
+                <span>Download Shipment Details</span>
+              </div>
+              <div class="download-option-item" @click="handleDownloadAttachments">
+                <span class="font_family icon-icon_download__template_b"></span>
+                <span>Download Attachments</span>
+              </div>
+            </div>
+          </template>
+        </el-popover>
+
         <el-button style="padding-left: 10px" type="default" @click="handleCustomizeColumns">
           <span style="margin-right: 6px" class="font_family icon-icon_column_b"></span>
           Customize Columns
@@ -716,6 +770,29 @@ defineExpose({
 </template>
 
 <style lang="scss" scoped>
+.download-option-item {
+  display: flex;
+  align-items: center;
+  padding: 6px 8px;
+  border-radius: 4px;
+  cursor: pointer;
+  &:hover {
+    background-color: var(--color-btn-action-bg-hover);
+    span {
+      color: var(--color-theme);
+    }
+  }
+  span {
+    &:first-child {
+      font-size: 16px;
+      margin-right: 4px;
+      line-height: 18px;
+    }
+    line-height: 22px;
+    color: var(--color-text-secondary);
+  }
+}
+
 .table-tools {
   position: relative;
   display: flex;
@@ -728,6 +805,23 @@ defineExpose({
     font-weight: 700;
     line-height: 32px;
   }
+  .right-tools-btn {
+    // .download-btn {
+    //   &:hover {
+    //     .download-up-icon {
+    //       transform: rotate(360deg);
+    //     }
+    //   }
+    // }
+    .download-up-icon {
+      margin-left: 2px;
+      transition: all 0.5s ease;
+      transform: rotate(180deg);
+      &.rotate-icon {
+        transform: rotate(0deg);
+      }
+    }
+  }
 }
 
 .bottom-pagination {
@@ -782,3 +876,22 @@ defineExpose({
   }
 }
 </style>
+<style lang="scss">
+.tracking-table-download-alert-popup {
+  width: 400px;
+
+  .el-message-box__header {
+    display: none;
+  }
+  .el-message-box__content {
+    padding-top: 9px;
+  }
+  div.el-message-box__btns {
+    border: none;
+    .el-button--dark {
+      width: 100px;
+      height: 40px;
+    }
+  }
+}
+</style>

binární
src/views/Tracking/src/image/dark-download-guide.png


binární
src/views/Tracking/src/image/download-guide.png


+ 1 - 0
src/views/Video/index.ts

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

+ 21 - 0
src/views/Video/src/VideoView.vue

@@ -0,0 +1,21 @@
+<script setup lang="ts"></script>
+
+<template>
+  <div class="video-view">
+    <video controls style="width: calc(100% - 20px); height: 100%">
+      <source src="/videos/demo-video.mp4" type="video/mp4" />
+    </video>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.video-view {
+  width: 100%;
+  height: 100%;
+  padding: 25px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background-color: #000;
+}
+</style>

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů