فهرست منبع

Merge branch 'dev' into dev_g

AmandaG 1 سال پیش
والد
کامیت
6bc861e5fa

+ 2 - 1
src/auto-imports.d.ts

@@ -3,6 +3,7 @@
 // @ts-nocheck
 // noinspection JSUnusedGlobalSymbols
 // Generated by unplugin-auto-import
+// biome-ignore lint: disable
 export {}
 declare global {
   const $api: typeof import('@/api/index')['default']
@@ -68,6 +69,6 @@ declare global {
 // for type re-export
 declare global {
   // @ts-ignore
-  export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
+  export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
   import('vue')
 }

+ 2 - 0
src/components/VBox/src/VBox.vue

@@ -116,6 +116,8 @@ const vBoxPopoverRef = ref()
       display: flex;
       align-items: center;
       justify-content: center;
+      height: 32px;
+      width: 32px;
       span.icon-icon_dragsort__b {
         color: var(--color-neutral-1);
       }

+ 36 - 0
src/hooks/useOverflow.ts

@@ -0,0 +1,36 @@
+import { ref, watch, onMounted, nextTick } from 'vue'
+
+export const useOverflow = (elementRef, dataRef) => {
+  const isOverflow = ref(false)
+  const checkOverflow = (element) => {
+    if (element) {
+      return element.scrollWidth > element.clientWidth
+    }
+    return false
+  }
+
+  // 初次 mounted 时检查是否溢出
+  onMounted(() => {
+    nextTick(() => {
+      isOverflow.value = checkOverflow(elementRef.value)
+    })
+  })
+
+  // 监听数据变化,更新溢出状态
+  watch(
+    () => dataRef.value,
+    () => {
+      nextTick(() => {
+        isOverflow.value = checkOverflow(elementRef.value)
+      })
+    },
+    {
+      deep: true,
+      immediate: true
+    }
+  )
+
+  return {
+    isOverflow
+  }
+}

+ 19 - 3
src/styles/elementui.scss

@@ -318,6 +318,10 @@ div.el-drawer {
   .el-drawer__body {
     padding: 16px;
   }
+  .el-drawer__close-btn:focus i,
+  .el-drawer__close-btn:hover i {
+    color: var(--color-theme);
+  }
 }
 
 div .el-input__inner {
@@ -491,6 +495,9 @@ div .el-badge {
 .el-year-table td span.el-date-table-cell__text:hover {
   color: var(--color-theme);
 }
+div.el-date-picker {
+  --el-datepicker-header-text-color: #b5b9bf;
+}
 div.el-date-picker__header {
   padding-top: 4px;
 }
@@ -527,9 +534,18 @@ div .el-range-editor.is-active,
   box-shadow: 0 0 0 1px var(--color-theme) !important;
   border-color: var(--color-theme);
 }
-div .el-date-table td.today .el-date-table-cell__text,
-.el-date-table td.available:hover {
-  color: var(--color-theme);
+
+table.el-date-table td.available:hover {
+  span {
+    color: var(--color-theme);
+  }
+}
+div .el-date-table td.today .el-date-table-cell__text {
+  color: var(--color-neutral-1);
+  font-weight: 400;
+}
+.el-date-table td .el-date-table-cell span.el-date-table-cell__text {
+  border-radius: 6px;
 }
 div .el-date-table td.in-range .el-date-table-cell {
   background-color: var(--color-orange-6) !important;

+ 5 - 7
src/views/Booking/src/components/BookingDetail/src/BookingDetail.vue

@@ -248,7 +248,8 @@ const formatTime = (time: string) => {
       margin: 0 8px;
       // border-bottom: 1px solid var(--color-border);
       & > .item {
-        flex: 1;
+        flex: 1 1 33%;
+        max-width: 40%;
         display: flex;
         flex-direction: column;
         justify-content: center;
@@ -272,15 +273,12 @@ const formatTime = (time: string) => {
         flex-direction: row;
         justify-content: flex-start;
         gap: 16px;
-        max-width: 500px;
         .origin {
-          width: 60%;
+          flex: 1;
+          width: calc(60% - 16px);
         }
         .destination {
-          width: 40%;
-          .info {
-            width: calc(100% - 16px);
-          }
+          max-width: 40%;
         }
         .title {
           margin-top: 11px;

+ 13 - 7
src/views/Booking/src/components/BookingDetail/src/components/EmailView.vue

@@ -22,7 +22,7 @@ watch(
   (newVal) => {
     if (newVal) {
       const email = newVal?.email
-      emailData.value.email = email?.email?.em
+      emailData.value.email = email?.email
       emailData.value.ccEmail = email?.cc_email
       emailData.value.serial_no = newVal?.serial_no
       emailRecords.value = email?.emailRecords
@@ -216,7 +216,7 @@ const sendEmail = () => {
       <div class="record-item" v-for="(item, index) in emailRecords" :key="index">
         <div class="header">
           <div class="avatar">
-            <span>{{ item.name?.slice(0, 1) }}</span>
+            <div>{{ item.name?.slice(0, 1) }}</div>
           </div>
           <div class="name">{{ item.name }}</div>
           <div class="date">{{ dayjs(item.creatTime).format('MM-DD-YYYY HH:mm:ss') }}</div>
@@ -255,17 +255,22 @@ const sendEmail = () => {
 
 .email-path {
   display: flex;
-  align-items: center;
+  align-items: flex-start;
   margin-bottom: 12px;
   font-weight: 600;
 
   & > .label {
     margin-left: 8px;
+    padding-top: 2px;
     color: var(--color-neutral-1);
+    white-space: nowrap;
   }
 
   & > .content {
+    padding-top: 2px;
+    line-height: 18px;
     color: var(--color-theme);
+    word-break: break-all;
   }
 }
 
@@ -285,14 +290,15 @@ const sendEmail = () => {
     padding-left: 0px;
 
     .avatar {
-      display: flex;
-      justify-content: center;
-      align-items: center;
       width: 24px;
       height: 24px;
+      padding-top: 5px;
+      text-align: center;
       border-radius: 50%;
       background-color: var(--color-theme);
-      span {
+      div {
+        height: 14px;
+        line-height: 14px;
         color: #fff;
         font-weight: 700;
       }

+ 12 - 11
src/views/Layout/src/components/Header/HeaderView.vue

@@ -92,7 +92,6 @@ const handleSearch = () => {
   }
 }
 onBeforeRouteUpdate((to, from, next) => {
-  console.log(to, from)
   // if (to.name === 'Tracking') {
   //   headerSearch.setChangeByLogin(false)
   // }
@@ -163,8 +162,8 @@ const handleLogin = () => {
           </div>
         </div>
         <template #reference>
-          <div class="avatar" v-if="userStore.username">
-            <span>{{ userStore.username?.slice(0, 1) }}</span>
+          <div class="header-avatar" v-if="userStore.username">
+            <span style="">{{ userStore.username?.slice(0, 1) }}</span>
           </div>
         </template>
       </el-popover>
@@ -193,16 +192,17 @@ const handleLogin = () => {
 </template>
 
 <style lang="scss" scoped>
-.avatar {
-  display: flex;
-  justify-content: center;
-  align-items: center;
+.header-avatar {
   width: 24px;
   height: 24px;
+  padding: 2px;
+  text-align: center;
   border-radius: 50%;
   background-color: var(--color-theme);
   cursor: pointer;
   & > span {
+    display: block;
+    height: 16px;
     color: #fff;
     font-size: 16px;
     font-weight: 700;
@@ -251,17 +251,18 @@ div.el-popover.el-popper.user-config-popover {
     gap: 8px;
     height: 70px;
     border-bottom: 1px solid #eeeeed;
-    .avatar {
+    & > .avatar {
       width: 48px;
       height: 48px;
+      padding-top: 7px;
       border-radius: 50%;
       text-align: center;
       background-color: var(--color-theme);
-      display: flex;
-      justify-content: center;
-      align-items: center;
       span {
+        display: block;
         color: #fff;
+        height: 32px;
+        line-height: 32px;
         font-size: 32px;
         font-weight: 700;
       }

+ 4 - 2
src/views/Login/src/components/ChangePasswordCard.vue

@@ -240,6 +240,8 @@ const checkPassword = () => {
     flex-direction: column;
     align-items: center;
     margin-bottom: 24px;
+    padding: 40px 40px 0;
+    background: url(../image/bg-login-card.png) no-repeat center center;
 
     .welcome {
       margin-bottom: 16px;
@@ -249,7 +251,7 @@ const checkPassword = () => {
   }
 
   :deep(.el-card__body) {
-    padding: 40px;
+    padding: 0;
     padding-bottom: 16px;
   }
 
@@ -264,7 +266,7 @@ const checkPassword = () => {
   display: flex;
   flex-direction: column;
   align-items: flex-start;
-
+  padding: 0 40px;
   .el-input {
     height: 40px;
     .confirm-icon {

BIN
src/views/Login/src/image/bg-login-card.png


+ 9 - 8
src/views/Login/src/loginView.vue

@@ -443,14 +443,15 @@ const errorTipsRef = ref()
     align-items: center;
     height: 94px;
     padding-top: 32px;
-    background: linear-gradient(
-      251deg,
-      #ffffff4d,
-      #fff4eb80 22.66%,
-      #f0f3ff80 44.57%,
-      #e0f7f999 80.46%,
-      #ffffff4d
-    );
+    // background: linear-gradient(
+    //   251deg,
+    //   #ffffff4d,
+    //   #fff4eb80 22.66%,
+    //   #f0f3ff80 44.57%,
+    //   #e0f7f999 80.46%,
+    //   #ffffff4d
+    // );
+    background: url(../src/image/bg-login-card.png) no-repeat center center;
     .welcome {
       margin-bottom: 16px;
       font-size: 24px;

+ 3 - 2
src/views/Tracking/src/TrackingView.vue

@@ -263,7 +263,6 @@ const clearMoreFiltersTags = () => {
 
 // 从 store 中获取数据并绑定到输入框
 const headerSearchdData = computed(() => headerSearch.searchValue)
-
 // 监听 sharedData 的变化并更新 inputValue
 headerSearchdData.value && (TrackingSearch.value = headerSearchdData.value)
 headerSearch.clearSearchData()
@@ -272,7 +271,9 @@ watch(
   () => headerSearchdData.value,
   (newData) => {
     if (newData) {
-      console.log(headerSearchdData.value)
+      // 更新表格数据
+      TrackingTable_ref.value.getSharedTableData()
+      // 更新筛选条件
       TrackingSearch.value = headerSearchdData.value
       headerSearch.clearSearchData()
     }

+ 5 - 1
src/views/Tracking/src/components/PublicTracking/src/PublicTrackingSearch.vue

@@ -65,7 +65,11 @@ const handleSearchNo = () => {
         placeholder="Search a reference number to see shipment details"
       >
         <template #append>
-          <span @click="handleSearchNo" class="font_family icon-icon_search_b"></span>
+          <span
+            @click="handleSearchNo"
+            style="padding: 0 12px; cursor: pointer"
+            class="font_family icon-icon_search_b"
+          ></span>
         </template>
       </el-input>
       <div class="empty">

+ 30 - 6
src/views/Tracking/src/components/PublicTracking/src/components/PublicTrackingDetail.vue

@@ -82,19 +82,31 @@ const formatTime = (time: string) => {
       </div>
       <div class="detail-info">
         <div class="item transport-way">
-          <div class="place">
+          <div class="origin">
             <div class="title">Origin</div>
             <div class="content">
-              <span>{{ allData.transportInfo?.origin }}</span>
+              <el-tooltip placement="top">
+                <template #content>{{ allData?.transportInfo?.origin || '--' }}</template>
+                <span class="info single-line-ellipsis">{{
+                  allData?.transportInfo?.origin || '--'
+                }}</span>
+              </el-tooltip>
               <div class="line_container">
                 <hr color="#000000" />
                 <div class="right-icon"></div>
               </div>
             </div>
           </div>
-          <div class="place">
+          <div class="destination">
             <div class="title">Destination</div>
-            <div class="content">{{ allData.transportInfo?.destination }}</div>
+            <div class="content">
+              <el-tooltip placement="top">
+                <template #content>{{ allData?.transportInfo?.destination || '--' }}</template>
+                <span class="info single-line-ellipsis">{{
+                  allData?.transportInfo?.destination || '--'
+                }}</span>
+              </el-tooltip>
+            </div>
           </div>
         </div>
         <div class="item">
@@ -180,7 +192,8 @@ const formatTime = (time: string) => {
       height: 96px;
       margin: 0 8px;
       & > .item {
-        flex: 1;
+        flex: 1 1 33%;
+        max-width: 40%;
         display: flex;
         flex-direction: column;
         justify-content: center;
@@ -204,8 +217,12 @@ const formatTime = (time: string) => {
         flex-direction: row;
         justify-content: flex-start;
         gap: 16px;
-        .place {
+        .origin {
           flex: 1;
+          width: calc(60% - 16px);
+        }
+        .destination {
+          max-width: 40%;
         }
         .title {
           margin-top: 11px;
@@ -221,6 +238,7 @@ const formatTime = (time: string) => {
           .line_container {
             flex: 1;
             position: relative;
+            min-width: 26px;
             margin-left: 16px;
           }
           .line_container hr {
@@ -264,4 +282,10 @@ const formatTime = (time: string) => {
     color: var(--color-neutral-1);
   }
 }
+.single-line-ellipsis {
+  display: inline-block; /* 或者根据需要使用 inline-block */
+  white-space: nowrap; /* 不换行 */
+  overflow: hidden; /* 隐藏超出部分 */
+  text-overflow: ellipsis; /* 超出部分显示省略号 */
+}
 </style>

+ 26 - 13
src/views/Tracking/src/components/TrackingDetail/src/TrackingDetail.vue

@@ -13,6 +13,7 @@ import MapView from './components/MapView.vue'
 import { cloneDeep } from 'lodash'
 import { transportationMode } from '@/components/TransportationMode'
 import { useRoute } from 'vue-router'
+import { useOverflow } from '@/hooks/useOverflow'
 
 const route = useRoute()
 
@@ -107,6 +108,10 @@ getData()
 const formatTime = (time: string) => {
   return time ? dayjs(time).format('MMM-DD-YYYY hh:mm A') : '--'
 }
+const originRef = ref()
+const destinationRef = ref()
+const { isOverflow: isOriginOverflow } = useOverflow(originRef, allData)
+const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allData)
 </script>
 
 <template>
@@ -142,13 +147,15 @@ const formatTime = (time: string) => {
           <div class="origin">
             <div class="title">Origin</div>
             <div class="content">
-              <el-tooltip placement="top">
+              <el-tooltip v-if="isOriginOverflow" placement="top">
                 <template #content>{{ allData?.transportInfo?.origin || '--' }}</template>
-                <span class="info single-line-ellipsis">{{
+                <span ref="originRef" class="info single-line-ellipsis">{{
                   allData?.transportInfo?.origin || '--'
                 }}</span>
               </el-tooltip>
-
+              <span v-else ref="originRef" class="info single-line-ellipsis">{{
+                allData?.transportInfo?.origin || '--'
+              }}</span>
               <div class="line_container">
                 <hr color="#000000" />
                 <div class="right-icon"></div>
@@ -158,12 +165,15 @@ const formatTime = (time: string) => {
           <div class="destination">
             <div class="title">Destination</div>
             <div class="content">
-              <el-tooltip placement="top">
+              <el-tooltip v-if="isDestinationOverflow" placement="top">
                 <template #content>{{ allData?.transportInfo?.destination || '--' }}</template>
-                <span class="info single-line-ellipsis">{{
+                <span ref="destinationRef" class="info single-line-ellipsis">{{
                   allData?.transportInfo?.destination || '--'
                 }}</span>
               </el-tooltip>
+              <span v-else ref="destinationRef" class="info single-line-ellipsis">{{
+                allData?.transportInfo?.destination || '--'
+              }}</span>
             </div>
           </div>
         </div>
@@ -268,7 +278,7 @@ const formatTime = (time: string) => {
         </template>
       </VueDraggable>
     </div>
-    <EmailDrawer ref="emailDrawerRef"></EmailDrawer>
+    <EmailDrawer @sendEmailSuccess="getData" ref="emailDrawerRef"></EmailDrawer>
     <AMSISFDrawer ref="AMSISFDrawerRef"></AMSISFDrawer>
   </div>
 </template>
@@ -324,7 +334,8 @@ const formatTime = (time: string) => {
       height: 96px;
       margin: 0 8px;
       & > .item {
-        flex: 1;
+        flex: 1 1 33%;
+        max-width: 40%;
         display: flex;
         flex-direction: column;
         justify-content: center;
@@ -348,15 +359,12 @@ const formatTime = (time: string) => {
         flex-direction: row;
         justify-content: flex-start;
         gap: 16px;
-        max-width: 500px;
         .origin {
-          width: 60%;
+          flex: 1;
+          width: calc(60% - 16px);
         }
         .destination {
-          width: 40%;
-          .info {
-            width: calc(100% - 16px);
-          }
+          max-width: 40%;
         }
         .title {
           margin-top: 11px;
@@ -447,3 +455,8 @@ const formatTime = (time: string) => {
   text-overflow: ellipsis; /* 超出部分显示省略号 */
 }
 </style>
+<style lang="scss">
+.is-show-tooltip {
+  // display: none;
+}
+</style>

+ 35 - 8
src/views/Tracking/src/components/TrackingDetail/src/components/EmailDrawer.vue

@@ -126,6 +126,10 @@ const handleFocusEditor = () => {
   editorRef.value.focus()
 }
 
+const emit = defineEmits<{
+  sendEmailSuccess: []
+}>()
+
 const sendEmail = () => {
   const html = editorRef.value.getHtml()
   const text = editorRef.value.getText()
@@ -141,6 +145,7 @@ const sendEmail = () => {
       if (res.code === 200) {
         ElMessage.success('Email sent successfully')
         emailRecords.value = res.data.emailRecords
+        emit('sendEmailSuccess')
       }
     })
     .catch((err: any) => {
@@ -148,13 +153,24 @@ const sendEmail = () => {
     })
 }
 
+const clearData = () => {
+  valueHtml.value = ''
+}
+
 defineExpose({
   openDrawer
 })
 </script>
 
 <template>
-  <el-drawer v-model="drawer" :modal="false" :size="1000" title="Communication" direction="rtl">
+  <el-drawer
+    v-model="drawer"
+    @close="clearData"
+    :modal="false"
+    :size="1000"
+    title="Communication"
+    direction="rtl"
+  >
     <div class="email-view">
       <div class="email-path">
         <span class="font_family icon-icon_email_b" style="font-size: 18px"></span>
@@ -202,7 +218,10 @@ defineExpose({
         />
       </div>
       <div style="border-bottom: 1px solid var(--color-border)">
-        <el-button class="el-button--dark" style="float: right; margin: 8px 0 14px 0; height: 40px"
+        <el-button
+          @click="sendEmail"
+          class="el-button--dark"
+          style="float: right; margin: 8px 0 14px 0; height: 40px"
           ><span class="font_family icon-icon_submit_b" style="margin-right: 4px"></span> Send
           Email</el-button
         >
@@ -211,7 +230,7 @@ defineExpose({
         <div class="record-item" v-for="(item, index) in emailRecords" :key="index">
           <div class="header">
             <div class="avatar">
-              <span>{{ item.name?.slice(0, 1) }}</span>
+              <div>{{ item.name?.slice(0, 1) }}</div>
             </div>
             <div class="name">{{ item.name }}</div>
             <div class="date">{{ dayjs(item.creatTime).format('MM-DD-YYYY HH:mm:ss') }}</div>
@@ -244,16 +263,23 @@ defineExpose({
 
 .email-path {
   display: flex;
-  align-items: center;
+  align-items: flex-start;
   margin-bottom: 12px;
   font-weight: 600;
 
   & > .label {
     margin-left: 8px;
+    padding-top: 2px;
     color: var(--color-neutral-1);
+    white-space: nowrap;
   }
 
   & > .content {
+    display: inline-block;
+    flex: 1;
+    padding-top: 2px;
+    line-height: 18px;
+    word-break: break-all;
     color: var(--color-theme);
   }
 }
@@ -275,14 +301,15 @@ defineExpose({
     padding-left: 0px;
 
     .avatar {
-      display: flex;
-      justify-content: center;
-      align-items: center;
       width: 24px;
       height: 24px;
+      padding-top: 5px;
+      text-align: center;
       border-radius: 50%;
       background-color: var(--color-theme);
-      span {
+      div {
+        height: 14px;
+        line-height: 14px;
         color: #fff;
         font-weight: 700;
       }

+ 3 - 32
src/views/Tracking/src/components/TrackingDetail/src/components/MapView.vue

@@ -1,5 +1,5 @@
 <template>
-  <div id="map" style="width: 100%; height: 520px" class="tracking-map"></div>
+  <div id="tracking-map" style="width: 100%; height: 520px" class="tracking-map"></div>
 </template>
 <script setup lang="ts">
 import L from 'leaflet'
@@ -44,7 +44,7 @@ const initMap = () => {
     return
   }
 
-  map = L.map('map').setView([51.505, -0.09], 3)
+  map = L.map('tracking-map').setView([51.505, -0.09], 3)
 
   // 添加 TileLayer
   L.tileLayer('https://map.kerryapex.com/osm_tiles/{z}/{x}/{y}.png', {
@@ -137,36 +137,7 @@ const getMarker = () => {
     })
     .then((res) => {
       if (res.code === 200) {
-        // const { data } = res
-        const data = [
-          {
-            lng: '117.70000000',
-            lat: '38.98333333',
-            label: 'Origin',
-            infor: 'XINGANG, CHINA',
-            sort: '1',
-            stime: '',
-            ptype: 'pol'
-          },
-          {
-            lng: '-76.61666667',
-            lat: '39.28333333',
-            label: 'Destination',
-            infor: 'BALTIMORE, MD',
-            sort: '2',
-            stime: '',
-            ptype: 'pod'
-          },
-          {
-            lng: '129.05000000',
-            lat: '35.13333333',
-            label: 'Transfer',
-            infor: 'BUSAN,KOREA',
-            sort: '3',
-            stime: '',
-            ptype: 'poe'
-          }
-        ]
+        const { data } = res
         data &&
           data.forEach((item) => {
             const iconColorList = {

+ 47 - 57
src/views/Tracking/src/components/TrackingDetail/src/components/RoutesView.vue

@@ -1,5 +1,7 @@
 <script setup lang="ts">
 import dayjs from 'dayjs'
+import { transportationMode } from '@/components/TransportationMode'
+
 const props = defineProps({
   data: Object
 })
@@ -20,7 +22,7 @@ const routes: any = ref([
   {
     serialNumber: 'Leg 2',
     mode: 'Sea',
-    origin: 'Valenciaenz',
+    origin: 'ValeShenzhenShweShenzhenShweShenzhenShweShenzhenShwenciaenz',
     destination: 'ShenzhenShweShenzhenShweShenzhenShweShenzhenShwe',
     etd: 'Jun-15-2024 12:00 AM',
     atd: 'Jun-17-2024 12:00 AM',
@@ -50,48 +52,23 @@ watch(
 const formatDate = (date: string) => {
   return date ? dayjs(date).format('MMM-DD-YYYY HH:mm A') : '--'
 }
-
-const basicDesWidth = ref('180px')
-const detailDesWidth = ref('220px')
-
-const getContainerWidth = () => {
-  let screenWidth = document.body.clientWidth
-  if (screenWidth < 1300) {
-    basicDesWidth.value = '180px'
-    detailDesWidth.value = '220px'
-  } else if (screenWidth < 1500) {
-    basicDesWidth.value = '220px'
-    detailDesWidth.value = '240px'
-  } else {
-    basicDesWidth.value = '240px'
-    detailDesWidth.value = '260px'
-  }
-}
-onMounted(() => {
-  getContainerWidth()
-  window.addEventListener('resize', getContainerWidth)
-})
-onBeforeUnmount(() => {
-  window.removeEventListener('resize', getContainerWidth)
-})
 </script>
 
 <template>
-  <div
-    class="routes-view"
-    :style="{
-      '--basic-destination-width': basicDesWidth,
-      '--detail-destination-width': detailDesWidth
-    }"
-  >
+  <div class="routes-view">
     <div class="title">Total number of legs: {{ routes.length }}</div>
     <div class="routes">
-      <div class="route-item" v-for="(item, index) in routes" :key="item.serialNumber">
+      <div
+        class="route-item"
+        @click="item.isCollapse = !item.isCollapse"
+        v-for="(item, index) in routes"
+        :key="item.serialNumber"
+      >
         <div class="basic-info">
           <div class="serial-number border-right">Leg {{ index + 1 }}</div>
           <div class="mode border-right">
-            <span class="font_family icon-icon_ocean_b"></span>
-            {{ item.mode }}
+            <span class="font_family" :class="[`icon-${transportationMode?.[item.mode]}`]"></span>
+            {{ item.mode_label }}
           </div>
           <div class="place border-right">
             <div class="origin">
@@ -112,7 +89,7 @@ onBeforeUnmount(() => {
               <div class="title">Destination</div>
               <el-tooltip placement="top">
                 <template #content>{{ item.destination || '--' }}</template>
-                <div class="content single-line-ellipsis">{{ item.destination || '--' }}</div>
+                <span class="content single-line-ellipsis">{{ item.destination || '--' }}</span>
               </el-tooltip>
             </div>
           </div>
@@ -124,7 +101,6 @@ onBeforeUnmount(() => {
             <div class="title">ETA</div>
             <div class="content">{{ formatDate(item.eta) }}</div>
             <span
-              @click="item.isCollapse = !item.isCollapse"
               :class="{ collapse: item.isCollapse }"
               class="font_family icon-icon_dropdown_b"
             ></span>
@@ -138,7 +114,9 @@ onBeforeUnmount(() => {
 
                 <el-tooltip placement="top">
                   <template #content>{{ item.origin || '--' }}</template>
-                  <span class="label single-line-ellipsis">{{ item.origin || '--' }}</span>
+                  <span class="label origin-label single-line-ellipsis">{{
+                    item.origin || '--'
+                  }}</span>
                 </el-tooltip>
                 <div class="line_container">
                   <hr color="#000000" />
@@ -215,7 +193,13 @@ onBeforeUnmount(() => {
 .basic-info {
   display: flex;
   height: 80px;
-
+  cursor: pointer;
+  &:hover {
+    background-color: #fef8f3;
+    .serial-number {
+      background-color: #f6f2ee;
+    }
+  }
   .serial-number {
     width: 80px;
     background: var(--color-header-bg);
@@ -237,10 +221,12 @@ onBeforeUnmount(() => {
       font-size: 40px;
     }
   }
+  .origin {
+    flex: 1;
+  }
 
   .destination {
-    flex: 1;
-    max-width: calc(var(--basic-destination-width) - 16px);
+    max-width: calc(40% - 16px);
     display: flex;
     flex-direction: column;
     justify-content: space-between;
@@ -248,10 +234,11 @@ onBeforeUnmount(() => {
     & > div.content {
       display: inline-block;
       width: 100%;
+      overflow: hidden;
     }
   }
   .place {
-    flex: 0 0 40%;
+    flex: 1;
     display: flex;
     align-items: center;
     padding: 0 16px;
@@ -261,7 +248,7 @@ onBeforeUnmount(() => {
       margin-top: 2px;
     }
     .origin {
-      width: calc(100% - var(--basic-destination-width));
+      width: 60%;
     }
 
     .content {
@@ -278,9 +265,7 @@ onBeforeUnmount(() => {
   }
 
   div.eta {
-    flex-basis: 80px;
     position: relative;
-
     & > .font_family {
       position: absolute;
       right: 20px;
@@ -331,6 +316,7 @@ onBeforeUnmount(() => {
   border-top: 1px solid var(--color-border);
   .line_container {
     flex: 1;
+    margin-left: 8px;
   }
   .line_container hr {
     border-color: #484c52;
@@ -339,40 +325,44 @@ onBeforeUnmount(() => {
 
   .line_container .right-icon {
     border-top: 1px solid #484c52;
-
     border-radius: 0 1px 1px 0;
-    top: -4px;
+    top: -2px;
     right: 0px;
     width: 10px;
     height: 12px;
   }
   .date-info {
+    flex: 1;
+    max-width: calc(100% - (100% - 165px) / 3);
     display: flex;
     justify-content: space-between;
     gap: 16px;
-    width: calc(100% - 248px);
-    padding: 12px 8px 12px;
+    padding: 12px 8px;
+    padding-right: 16px;
     background-color: var(--color-header-bg);
     border-radius: 6px;
 
     .origin {
-      flex: 1;
+      flex-grow: 1;
       display: flex;
       flex-direction: column;
       justify-content: space-between;
-
-      min-width: var(--detail-destination-width);
-      max-width: calc(100% - var(--detail-destination-width));
+      overflow: hidden;
+      .label {
+        margin-top: 1px;
+      }
     }
 
     .destination {
-      flex: 1;
-      min-width: calc(var(--detail-destination-width) - 16px);
+      flex-shrink: 0; /* 防止右边的子盒子缩小 */
+      flex-basis: auto; /* 根据内容决定初始宽度 */
+      max-width: 40%;
       display: flex;
       flex-direction: column;
       justify-content: space-between;
       .label {
         width: calc(100% - 40px);
+        margin-top: 1px;
       }
     }
 
@@ -422,11 +412,10 @@ onBeforeUnmount(() => {
   }
 
   .transport-info {
-    width: 248px;
+    width: calc((100% - 165px) / 3);
     padding: 8px 16px;
     background-color: var(--color-header-bg);
     border-radius: 6px;
-
     .item {
       .title {
         margin-bottom: 4px;
@@ -474,6 +463,7 @@ onBeforeUnmount(() => {
 }
 
 .single-line-ellipsis {
+  height: 18px;
   display: inline-block; /* 或者根据需要使用 inline-block */
   white-space: nowrap; /* 不换行 */
   overflow: hidden; /* 隐藏超出部分 */

+ 1 - 11
src/views/Tracking/src/components/TrackingTable/src/TrackingTable.vue

@@ -209,17 +209,6 @@ const getTableData = async (isInit: boolean, isPageChange?: boolean) => {
   })
 }
 
-// 当 sharedData 发生变化时,更新 inputValue
-watch(
-  () => headerSearch.isChangeByLogin,
-  (newData) => {
-    if (newData) {
-      getSharedTableData()
-      headerSearch.clearChangeByLogin()
-    }
-  }
-)
-
 // 查询列表数据
 const searchTableData = (data: any) => {
   tableLoading.value = true
@@ -448,6 +437,7 @@ const handleVGM = (row) => {
 }
 defineExpose({
   searchTableData,
+  getSharedTableData,
   pageInfo
 })
 </script>

+ 62 - 39
src/views/Tracking/src/components/TrackingTable/src/components/VGMView.vue

@@ -95,6 +95,16 @@ const handleColumns = (columns: any) => {
           edit: 'vInput'
         }
       }
+    } else if (item.edit_type === 'number') {
+      curColumn = {
+        ...curColumn,
+        editRender: {
+          name: 'vInputNumber'
+        },
+        slots: {
+          edit: 'vInputNumber'
+        }
+      }
     } else if (item.edit_type === 'dateTime') {
       curColumn = {
         ...curColumn,
@@ -246,22 +256,26 @@ const handleSave = () => {
     }
   })
 
-  const variableList = Object.keys(tableRowData[0])
-  const tableInfo = {}
-  variableList.forEach((item) => {
-    if (item === '_X_ROW_KEY') return
-    if (item === 'vgm_date' || item === 'vgm_time') {
+  let variableList = []
+  let tableInfo = {}
+  if (tableRowData.length !== 0) {
+    variableList = Object.keys(tableRowData?.[0])
+    variableList.forEach((item) => {
+      if (item === '_X_ROW_KEY') return
+      if (item === 'vgm_date' || item === 'vgm_time') {
+        Object.assign(tableInfo, {
+          [item]: tableRowData.map((row) =>
+            row[item] ? dayjs(row[item]).format('YYYY-MM-DD HH:mm:ss') : ''
+          )
+        })
+        return
+      }
       Object.assign(tableInfo, {
-        [item]: tableRowData.map((row) =>
-          row[item] ? dayjs(row[item]).format('YYYY-MM-DD HH:mm:ss') : ''
-        )
+        [item]: tableRowData.map((row) => row[item])
       })
-      return
-    }
-    Object.assign(tableInfo, {
-      [item]: tableRowData.map((row) => row[item])
     })
-  })
+  }
+
   $api
     .saveVGMData({
       serial_no: allData.value.serial_no,
@@ -271,7 +285,7 @@ const handleSave = () => {
     })
     .then((res) => {
       if (res.code === 200) {
-        // router.push({ name: 'Tracking' })
+        router.push({ name: 'Tracking' })
         ElMessage.success('Save success')
       } else if (res.code === 400) {
         ElMessage.error('No access')
@@ -282,6 +296,19 @@ const handleSave = () => {
 const formatTime = (time: string) => {
   return time ? dayjs(time).format('MMM/DD/YYYY') : '--'
 }
+const stopScroll = (evt) => {
+  evt = evt || window.event
+  if (evt.preventDefault) {
+    // Firefox
+    evt.preventDefault()
+    evt.stopPropagation()
+  } else {
+    // IE
+    evt.cancelBubble = true
+    evt.returnValue = false
+  }
+  return false
+}
 </script>
 
 <template>
@@ -372,13 +399,18 @@ const formatTime = (time: string) => {
         </div>
         <div class="table">
           <vxe-grid ref="tableRef" class="vgm-table" v-bind="tableData">
-            <template #vInput="{ row, column }">
+            <template #vInputNumber="{ row, column }">
               <el-input
                 v-model="row[column.field]"
                 placeholder="Please enter..."
-                clearable
+                type="number"
+                class="no-spinner"
+                @wheel.prevent="stopScroll($event)"
               ></el-input>
             </template>
+            <template #vInput="{ row, column }">
+              <el-input v-model="row[column.field]" placeholder="Please enter..."></el-input>
+            </template>
 
             <template #vUnitSelect="{ row, column }">
               <vxe-select v-model="row[column.field]" placeholder="Please select..." clearable>
@@ -398,21 +430,13 @@ const formatTime = (time: string) => {
               <el-date-picker
                 v-model="row[column.field]"
                 type="datetime"
+                class="vgm-date-picker"
                 style="width: 190px"
                 placeholder="Pick a Date"
                 format="MMM-DD-YYYY HH:mm:ss"
                 date-format="MMM-DD-YYYY"
                 time-format="HH:mm:ss"
               />
-              <!-- <a-date-picker
-                :showNow="false"
-                class="test-date-picker"
-                placement="topLeft"
-                v-model:value="row[column.field]"
-                format="MMM-DD-YYYY HH:mm:ss"
-                :getPopupContainer="(target) => target.parentElement"
-                :show-time="{ defaultValue: dayjs('00:00:00', 'HH:mm:ss') }"
-              /> -->
             </template>
           </vxe-grid>
         </div>
@@ -531,19 +555,18 @@ const formatTime = (time: string) => {
 .el-checkbox__input.is-checked + .el-checkbox__label {
   color: var(--color-neutral-1);
 }
-// .test-date-picker {
-//   .ant-picker-dropdown {
-//     // top: 40px !important;
-//   }
-//   .anticon svg {
-//     color: #202020;
-//   }
-// }
 
-// .vgm-table {
-//   .vxe-grid .vxe-grid--table-wrapper,
-//   div.vxe-table--body-wrapper {
-//     overflow: visible;
-//   }
-// }
+.no-spinner {
+  /* 隐藏计步器 */
+  input::-webkit-inner-spin-button,
+  input::-webkit-outer-spin-button {
+    -webkit-appearance: none;
+    margin: 0;
+  }
+
+  /* 针对 Firefox 浏览器 */
+  input[type='number'] {
+    -moz-appearance: textfield;
+  }
+}
 </style>