소스 검색

merge dev

AmandaG 11 달 전
부모
커밋
baaa9f11ac
69개의 변경된 파일1700개의 추가작업 그리고 390개의 파일을 삭제
  1. 1 1
      src/assets/main.css
  2. 2 1
      src/auto-imports.d.ts
  3. 0 5
      src/components/AutoComplete/src/AutoComplete.vue
  4. 34 8
      src/components/ContainerStatus/src/ContainerStatus.vue
  5. BIN
      src/components/ContainerStatus/src/image/no-data.png
  6. BIN
      src/components/ContainerStatus/src/image/no_data.png
  7. BIN
      src/components/ContainerStatus/src/image/no_data_dark.png
  8. 20 18
      src/components/CustomizeColumns/src/CustomizeColumns.vue
  9. 20 8
      src/components/DateRange/src/DateRange.vue
  10. 14 4
      src/components/DateRange/src/components/CalendarDate.vue
  11. 4 3
      src/components/DateRange/src/components/QuickCalendarDate.vue
  12. 1 1
      src/components/FliterTags/src/FilterTags.vue
  13. 1 1
      src/components/IconDropDown/src/IconDropDown.vue
  14. 2 1
      src/components/MoreFilters/src/components/SelectValue.vue
  15. 13 3
      src/components/ScoringGrade/components/DialogColorful.vue
  16. 14 7
      src/components/ScoringGrade/components/DialogUe.vue
  17. BIN
      src/components/ScoringGrade/image/bubble_corner_colorful_darkmode.png
  18. BIN
      src/components/ScoringGrade/image/bubble_corner_darkmode.png
  19. 6 3
      src/components/ScoringGrade/src/ScoringGrade.vue
  20. 4 10
      src/components/SelectTable/src/SelectTable.vue
  21. 10 9
      src/components/ShipmentStatus/src/ShipmentStatus.vue
  22. 10 4
      src/components/TransportMode/src/TransportMode.vue
  23. 2 0
      src/components/VBox_Dashboard/src/VBox_Dashboard.vue
  24. 27 2
      src/components/VEmpty/src/VEmpty.vue
  25. BIN
      src/components/VEmpty/src/images/default_dark_image.png
  26. 4 1
      src/components/VSliderVerification/src/VSliderVerification.vue
  27. 1 1
      src/hooks/rowClickStyle.ts
  28. 34 0
      src/main.ts
  29. 38 0
      src/stores/modules/theme.ts
  30. 35 8
      src/styles/Antdui.scss
  31. 102 50
      src/styles/elementui.scss
  32. 4 1
      src/styles/index.scss
  33. 72 0
      src/styles/theme-g.scss
  34. 214 1
      src/styles/theme.scss
  35. 3 3
      src/styles/vxeTable.scss
  36. 12 5
      src/views/Booking/src/BookingView.vue
  37. 17 4
      src/views/Booking/src/components/BookingDetail/src/BookingDetail.vue
  38. 18 7
      src/views/Booking/src/components/BookingDetail/src/components/EmailView.vue
  39. 7 1
      src/views/Booking/src/components/BookingTable/src/BookingTable.vue
  40. 7 4
      src/views/Booking/src/components/BookingTable/src/components/DownloadDialog.vue
  41. 19 4
      src/views/Dashboard/src/DashboardView.vue
  42. 25 10
      src/views/Dashboard/src/components/DashFiters.vue
  43. 28 1
      src/views/Dashboard/src/components/PieChart.vue
  44. 12 13
      src/views/Dashboard/src/components/RecentStatus.vue
  45. 20 18
      src/views/Dashboard/src/components/ScoringSystem.vue
  46. 59 1
      src/views/Dashboard/src/components/TopMap.vue
  47. 153 4
      src/views/Layout/src/components/Header/HeaderView.vue
  48. 3 0
      src/views/Layout/src/components/Header/components/ChangePasswordDialog.vue
  49. BIN
      src/views/Layout/src/components/Header/images/dark.png
  50. BIN
      src/views/Layout/src/components/Header/images/light.png
  51. 1 0
      src/views/Layout/src/components/Menu/MenuView.vue
  52. 35 5
      src/views/Login/src/components/ChangePasswordCard.vue
  53. BIN
      src/views/Login/src/image/bg-dark.png
  54. BIN
      src/views/Login/src/image/bg-login-card-dark.png
  55. 33 6
      src/views/Login/src/loginView.vue
  56. 10 4
      src/views/OperationLog/src/OperationLog.vue
  57. 8 1
      src/views/OperationLog/src/components/BookingTable/src/BookingTable.vue
  58. 6 3
      src/views/OperationLog/src/components/BookingTable/src/components/DownloadDialog.vue
  59. 18 4
      src/views/Tracking/src/TrackingView.vue
  60. 30 5
      src/views/Tracking/src/components/PublicTracking/src/PublicTrackingSearch.vue
  61. 16 2
      src/views/Tracking/src/components/PublicTracking/src/components/PublicTrackingDetail.vue
  62. 18 3
      src/views/Tracking/src/components/TrackingDetail/src/TrackingDetail.vue
  63. 0 3
      src/views/Tracking/src/components/TrackingDetail/src/components/AttachmentView.vue
  64. 16 7
      src/views/Tracking/src/components/TrackingDetail/src/components/EmailDrawer.vue
  65. 409 106
      src/views/Tracking/src/components/TrackingDetail/src/components/MapView.vue
  66. 9 8
      src/views/Tracking/src/components/TrackingDetail/src/components/RoutesView.vue
  67. 4 2
      src/views/Tracking/src/components/TrackingDetail/src/components/TransportStep.vue
  68. 8 1
      src/views/Tracking/src/components/TrackingTable/src/TrackingTable.vue
  69. 7 4
      src/views/Tracking/src/components/TrackingTable/src/components/DownloadDialog.vue

+ 1 - 1
src/assets/main.css

@@ -13,7 +13,7 @@
   /* background-color: white; */
 }
 ::-webkit-scrollbar-thumb {
-  background-color: #dddee0;
+  background-color: var(--color-scrollbar-thumb);
   border-radius: 20px;
   box-shadow: inset 0 0 0 white;
 }

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

+ 0 - 5
src/components/AutoComplete/src/AutoComplete.vue

@@ -233,9 +233,4 @@ const handleCurrentChange = (val: number) => {
 :deep(.el-popper) {
   border-radius: 12px !important;
 }
-:deep(.el-pagination) {
-  .is-active {
-    color: #b57b32 !important;
-  }
-}
 </style>

+ 34 - 8
src/components/ContainerStatus/src/ContainerStatus.vue

@@ -1,6 +1,31 @@
 <script setup lang="ts">
-import emptyImage from './image/no-data.png'
+import emptyImage from './image/no_data.png'
 import { formatTimezone } from '@/utils/tools'
+import { useThemeStore } from '@/stores/modules/theme'
+import lightPng from './image/no_data.png'
+import darkPng from './image/no_data_dark.png'
+
+const emptyImg = ref(lightPng)
+
+const themeStore = useThemeStore()
+// 判断当前系统主题模式
+onMounted(() => {
+  watch(
+    () => themeStore.theme,
+    (newVal) => {
+      console.log(newVal, 'value')
+      if (newVal === 'dark') {
+        emptyImg.value = darkPng
+      } else {
+        emptyImg.value = lightPng
+      }
+    },
+    {
+      immediate: true,
+      deep: true
+    }
+  )
+})
 
 const props = defineProps({
   data: Object
@@ -58,7 +83,12 @@ watch(
       </el-collapse-item>
     </el-collapse>
     <div v-else class="empty-content" style="">
-      <el-image :src="emptyImage" alt="empty"></el-image>
+      <img
+        :src="emptyImg"
+        :class="{ 'is-dark': themeStore.theme === 'dark' }"
+        fit="contain"
+        alt="empty"
+      />
       <div class="empty-text" style="">No data</div>
     </div>
     <div class="footer">
@@ -84,12 +114,8 @@ watch(
     flex-direction: column;
     align-items: center;
     height: 394px;
-    .el-image {
-      width: 200px;
-      height: 200px;
-      margin-top: 20px;
-      object-fit: cover;
-    }
+    padding-top: 125px;
+
     .empty-text {
       margin-top: 8px;
       color: #b5b9bf;

BIN
src/components/ContainerStatus/src/image/no-data.png


BIN
src/components/ContainerStatus/src/image/no_data.png


BIN
src/components/ContainerStatus/src/image/no_data_dark.png


+ 20 - 18
src/components/CustomizeColumns/src/CustomizeColumns.vue

@@ -349,11 +349,7 @@ defineExpose({
           placeholder="Search columns you preffered"
         >
           <template #prefix>
-            <span class="iconfont_icon">
-              <svg class="iconfont" aria-hidden="true">
-                <use xlink:href="#icon-icon_search_b"></use>
-              </svg>
-            </span>
+            <span class="font_family icon-icon_search_b"></span>
           </template>
           <el-option
             v-for="item in searchOptions"
@@ -384,6 +380,7 @@ defineExpose({
               <VueDraggable
                 v-model="groupItem.children"
                 class="column-list"
+                :sort="false"
                 ghost-class="ghost-column"
                 :forceFallback="true"
                 fallbackClass="fallback-class"
@@ -577,9 +574,10 @@ defineExpose({
       padding-left: 12px;
       border: 1px solid var(--color-border);
       border-radius: 6px;
+      background-color: var(--color-customize-column-item-bg);
 
       &:hover {
-        background-color: #fff1e5;
+        background-color: var(--color-customize-column-item-hover-bg);
         box-shadow: 4px 4px 32px 0px rgba(0, 0, 0, 0.1);
       }
 
@@ -589,7 +587,7 @@ defineExpose({
 
       span.draggable-icon {
         margin-right: 12px;
-        color: var(--color-neutral-3);
+        color: var(--color-customize-column-item-drag-icon);
       }
 
       .font_family {
@@ -607,13 +605,18 @@ defineExpose({
   }
 
   .ghost-column {
-    opacity: 0;
     cursor: move !important;
+    span {
+      opacity: 0;
+    }
+    border: 1px dashed var(--color-customize-column-item-drag-border) !important;
+    background-color: var(--color-customize-column-item-drag-bg) !important;
+    box-shadow: none !important;
   }
 
   .fallback-class {
     opacity: 1 !important;
-    background-color: #fff1e5 !important;
+    background-color: var(--color-customize-column-item-hover-bg) !important;
     cursor: move !important;
   }
 }
@@ -629,7 +632,7 @@ defineExpose({
     .el-tabs {
       .el-tabs__header {
         margin-bottom: 0px;
-        border-bottom: 1px solid #ebeef5;
+        border-bottom: 1px solid var(--color-customize-column-tabs-header-border);
       }
 
       .el-tabs__item {
@@ -654,9 +657,9 @@ defineExpose({
 }
 
 .right-select-columns {
-  background-color: #fffbf7;
+  background-color: var(--color-customize-column-right-section-bg);
   padding-top: 0;
-  border: 1px dashed var(--color-border);
+  border: 1px dashed var(--color-customize-column-right-section-border);
   border-radius: 12px;
 
   & > .title {
@@ -671,10 +674,6 @@ defineExpose({
     padding: 8px;
     padding-bottom: 0px;
   }
-
-  .column-item {
-    background-color: #fff;
-  }
 }
 </style>
 <style lang="scss">
@@ -700,13 +699,16 @@ defineExpose({
 
   .el-tabs__nav-prev {
     border-right: 1px solid var(--color-border);
-    box-shadow: 1px 0px 10px rgba(0, 0, 0, 0.2);
+    box-shadow: 2px 0px 12px rgba(0, 0, 0, 0.3);
+    // .el-icon {
+    //   color: white;
+    // }
     /* 左侧阴影 */
   }
 
   .el-tabs__nav-next {
     border-left: 1px solid var(--color-border);
-    box-shadow: -1px 0px 10px rgba(0, 0, 0, 0.2);
+    box-shadow: -2px 0px 12px rgba(0, 0, 0, 0.2);
     /* 左侧阴影 */
   }
 

+ 20 - 8
src/components/DateRange/src/DateRange.vue

@@ -293,18 +293,18 @@ const clearDaterangeObj = () => {
 </script>
 <template>
   <div class="select">
-    <el-popover trigger="click" :width="400" :visible="Date_visible">
+    <el-popover trigger="click" :width="400" :visible="Date_visible" popper-class="DaterangeClass">
       <template #reference>
         <div class="Date_Range" @blur="Date_visible = false" @click="Date_visible = !Date_visible">
           <div class="select_title">Date Range</div>
           <span class="iconfont_icon">
-            <svg class="iconfont" aria-hidden="true">
+            <svg class="iconfont icon_dark" aria-hidden="true">
               <use xlink:href="#icon-icon_dropdown_b"></use>
             </svg>
           </span>
         </div>
       </template>
-      <div>
+      <div class="date_header">
         <div class="title">Date Range</div>
         <div class="ETD">
           <CalendarDate
@@ -323,7 +323,7 @@ const clearDaterangeObj = () => {
         <div class="AddType" v-for="(item, index) in AddDateType" :key="item">
           <div>
             <div class="ETD_title Date_Title">
-              <div>Date Type</div>
+              <div class="Date_type">Date Type</div>
               <span class="iconfont_icon" @click="deleteType(index)">
                 <svg class="iconfont icon_delete" aria-hidden="true">
                   <use xlink:href="#icon-icon_delete_b"></use>
@@ -350,6 +350,7 @@ const clearDaterangeObj = () => {
               CalendarWidth="352px"
               :Date="DateCreation"
               @DateRangeChange="DateRangeChange"
+              :isType="true"
             ></CalendarDate>
           </div>
         </div>
@@ -379,7 +380,7 @@ const clearDaterangeObj = () => {
   cursor: pointer;
   display: flex;
   align-items: center;
-  border: 1px solid var(--color-border);
+  border: 1px solid var(--color-select-border);
   border-radius: var(--border-radius-6);
 }
 .Date_Range {
@@ -405,11 +406,12 @@ const clearDaterangeObj = () => {
 .title {
   font-weight: 700;
   font-size: var(--font-size-5);
-  background-color: #f6f8fa;
+  background-color: var(--color-header-bg);
   height: 48px;
   display: flex;
   align-items: center;
   padding-left: 16px;
+  border-radius: 12px 12px 0 0;
 }
 .ETD {
   margin: 8px 16px;
@@ -448,7 +450,7 @@ const clearDaterangeObj = () => {
   height: 40px;
 }
 .AddType {
-  background-color: var(--color-neutral-4);
+  background-color: var(--color-header-bg);
   margin: 0 16px 8px 16px;
   padding: 8px;
   border-radius: var(--border-radius-6);
@@ -458,7 +460,7 @@ const clearDaterangeObj = () => {
   justify-content: flex-end;
   align-items: center;
   height: 48px;
-  border-top: 1px solid var(--color-border);
+  border-top: 1px solid var(--border-color-2);
   margin-top: 5px;
   font-weight: 400;
   font-size: var(--font-size-3);
@@ -494,4 +496,14 @@ const clearDaterangeObj = () => {
   padding: 0 4px;
   height: 24px;
 }
+.icon_dark {
+  fill: var(--color-neutral-1);
+}
+.date_header {
+  background-color: var(--management-bg-color);
+  border-radius: 12px;
+}
+.Date_type {
+  color: var(--color-neutral-2);
+}
 </style>

+ 14 - 4
src/components/DateRange/src/components/CalendarDate.vue

@@ -15,6 +15,10 @@ const props = defineProps({
   },
   Date: {
     type: Array
+  },
+  isType: {
+    type: Boolean,
+    default: false
   }
 })
 const ETDDate = ref(props.Date)
@@ -104,7 +108,10 @@ const isTwoDate = (date: any) => {
     <a-range-picker
       separator="To"
       :showToday="false"
-      :style="{ width: props.CalendarWidth }"
+      :style="{
+        width: props.CalendarWidth,
+        backgroundColor: props.isType ? 'var(--more-type-bg-color)' : 'var(--management-bg-color)'
+      }"
       :open="open"
       :disabled="Disabled"
       @change="changeRangeData"
@@ -117,7 +124,7 @@ const isTwoDate = (date: any) => {
     >
       <template #suffixIcon>
         <span class="iconfont_icon">
-          <svg class="iconfont" aria-hidden="true">
+          <svg class="iconfont icon_suffix" aria-hidden="true">
             <use xlink:href="#icon-icon_date_b"></use>
           </svg>
         </span>
@@ -148,13 +155,13 @@ const isTwoDate = (date: any) => {
 .footer_left {
   display: flex;
   flex: 50%;
-  padding: 0 4px 0 0;
+  padding: 0 0 0 5px;
   height: 48px;
   display: flex;
   align-items: center;
 }
 .footer_right {
-  border-left: 1px solid var(--color-border);
+  border-left: 1px solid var(--border-color-2);
   padding-left: 8px;
 }
 .el-button--noborder {
@@ -172,4 +179,7 @@ const isTwoDate = (date: any) => {
   width: 14px;
   height: 14px;
 }
+.icon_suffix {
+  fill: var(--color-neutral-1);
+}
 </style>

+ 4 - 3
src/components/DateRange/src/components/QuickCalendarDate.vue

@@ -129,7 +129,7 @@ const placeholder = computed(() => {
     >
       <template #suffixIcon>
         <span class="iconfont_icon">
-          <svg class="iconfont" aria-hidden="true">
+          <svg class="iconfont icon_dark" aria-hidden="true">
             <use xlink:href="#icon-icon_date_b"></use>
           </svg>
         </span>
@@ -160,13 +160,14 @@ const placeholder = computed(() => {
 .footer_left {
   display: flex;
   flex: 50%;
-  padding: 0 4px 0 0;
+  padding: 0 0 0 5px;
   height: 48px;
   display: flex;
   align-items: center;
+  border-left: 1px solid var(--border-color-2);
 }
 .footer_right {
-  border-left: 1px solid var(--color-border);
+  border-left: 1px solid var(--border-color-2);
   padding-left: 8px;
 }
 .el-button--noborder {

+ 1 - 1
src/components/FliterTags/src/FilterTags.vue

@@ -132,7 +132,7 @@ const checkedBox = (i: any, name: any, checked: any) => {
 }
 .v-tag__all {
   font-weight: 400;
-  background-color: #feecf3;
+  background-color: var(--color-tag-all-bg-color);
   color: #e26394;
 }
 .v-tag__created {

+ 1 - 1
src/components/IconDropDown/src/IconDropDown.vue

@@ -13,6 +13,6 @@
 .iconfont_select {
   width: 17px;
   height: 17px;
-  fill: var(--color-btn-default-dark-bg);
+  fill: var(--color-neutral-1);
 }
 </style>

+ 2 - 1
src/components/MoreFilters/src/components/SelectValue.vue

@@ -205,6 +205,7 @@ const clickSeeAll = () => {
   background-color: white;
   border: 1px solid var(--color-border);
   border-radius: var(--border-radius-6);
+  background-color: var(--tips-bg-color);
 }
 .select:hover {
   border: 1px solid var(--color-theme);
@@ -333,7 +334,7 @@ const clickSeeAll = () => {
   overflow: scroll;
 }
 .isDisabled {
-  background-color: #f5f7fa;
+  background-color: var(--input-disabled-bg-color);
   color: #a8abb2;
   cursor: not-allowed;
   box-shadow: none !important;

+ 13 - 3
src/components/ScoringGrade/components/DialogColorful.vue

@@ -1,5 +1,8 @@
 <script setup lang="ts">
 import { ref } from 'vue'
+import { useThemeStore } from '@/stores/modules/theme'
+import BubbleLight from '../image/bubble_corner_colorful.png'
+import BubbleDark from '../image/bubble_corner_colorful_darkmode.png'
 const props = defineProps({
   colorfulSrc: String,
   isshowexpression: Boolean,
@@ -10,6 +13,7 @@ const emits = defineEmits(['submitDetails'])
 const submitDetails = (val: any) => {
   emits('submitDetails', val)
 }
+const themeStore = useThemeStore()
 </script>
 <template>
   <div class="colorfulflex">
@@ -18,7 +22,7 @@ const submitDetails = (val: any) => {
         <img :src="props.colorfulSrc" />
       </div>
       <div class="vector">
-        <img class="vector_img" src="../image/bubble_corner_colorful.png" />
+        <img class="vector_img" :src="themeStore.theme == 'light' ? BubbleLight : BubbleDark" />
       </div>
     </div>
     <div v-if="props.isshowDetails" class="dialogcolorful submit">
@@ -38,7 +42,7 @@ const submitDetails = (val: any) => {
         </div>
       </div>
       <div class="vector vector_submit">
-        <img class="vector_img" src="../image/bubble_corner_colorful.png" />
+        <img class="vector_img" :src="themeStore.theme == 'light' ? BubbleLight : BubbleDark" />
       </div>
     </div>
   </div>
@@ -62,7 +66,7 @@ const submitDetails = (val: any) => {
   color: var(--tag-info-text-color);
   font-size: var(--font-size-4);
   border-radius: var(--border-radius-12) var(--border-radius-12) 0 var(--border-radius-12);
-  background: linear-gradient(251deg, rgba(242, 244, 247) 0%, rgba(255, 237, 230) 100%);
+  background: var(--scoring-colurful-color);
   padding: 8px;
   width: 56px;
   height: 56px;
@@ -91,6 +95,7 @@ const submitDetails = (val: any) => {
   .el-textarea__inner {
     resize: none; // 去除右下角图标
     padding: 5px 7px 5px 10px;
+    box-shadow: 0 0 0 1px var(--color-select-border) inset;
   }
 }
 .submit_button {
@@ -108,4 +113,9 @@ const submitDetails = (val: any) => {
   font-weight: 400;
   font-size: var(--font-size-3);
 }
+.inputdetails {
+  background-color: var(--management-bg-color);
+  border-radius: 6px;
+  border-color: var(--color-select-border);
+}
 </style>

+ 14 - 7
src/components/ScoringGrade/components/DialogUe.vue

@@ -1,5 +1,8 @@
 <script setup lang="ts">
 import { ref } from 'vue'
+import { useThemeStore } from '@/stores/modules/theme'
+import BubbleLight from '../image/bubble_corner.png'
+import BubbleDark from '../image/bubble_corner_darkmode.png'
 
 const props = defineProps({
   content: String,
@@ -77,6 +80,7 @@ const changeSmileRadio = (title: any, value: any) => {
   SmileObj[title] = value
   emits('changeSmileRadio', SmileObj)
 }
+const themeStore = useThemeStore()
 </script>
 <template>
   <div style="margin-bottom: 8px">
@@ -130,7 +134,9 @@ const changeSmileRadio = (title: any, value: any) => {
         </div>
       </div>
     </div>
-    <div class="vector"><img class="vector_img" src="../image/bubble_corner.png" /></div>
+    <div class="vector">
+      <img class="vector_img" :src="themeStore.theme == 'light' ? BubbleLight : BubbleDark" />
+    </div>
   </div>
 </template>
 <style lang="scss" scoped>
@@ -142,7 +148,7 @@ const changeSmileRadio = (title: any, value: any) => {
   color: var(--tag-info-text-color);
   font-size: var(--font-size-4);
   border-radius: var(--border-radius-12) var(--border-radius-12) var(--border-radius-12) 0;
-  background-color: #f2f4f7;
+  background-color: var(--scoring-bg-color);
   padding: 8px;
 }
 .vector {
@@ -154,6 +160,7 @@ const changeSmileRadio = (title: any, value: any) => {
 :deep(.el-checkbox-button__inner) {
   color: var(--tag-info-text-color);
   font-size: var(--font-size-3);
+  background-color: var(--management-bg-color);
   font-weight: 400;
   padding: 0;
   width: 180px;
@@ -161,7 +168,7 @@ const changeSmileRadio = (title: any, value: any) => {
   display: flex;
   align-items: center;
   justify-content: center;
-  border: 1px solid var(--color-border);
+  border: 1px solid var(--color-select-border);
   border-radius: var(--border-radius-6);
   margin-bottom: 8px;
 }
@@ -174,7 +181,7 @@ const changeSmileRadio = (title: any, value: any) => {
   border-color: transparent;
 }
 :deep(.el-checkbox-button:first-child .el-checkbox-button__inner) {
-  border-left: 1px solid var(--color-border);
+  border-left: 1px solid var(--color-select-border);
   border-top-left-radius: var(--border-radius-6);
   border-bottom-left-radius: var(--border-radius-6);
 }
@@ -219,9 +226,9 @@ const changeSmileRadio = (title: any, value: any) => {
 }
 .content_left {
   height: 41px;
-  background-color: #fff;
+  background-color: var(--management-bg-color);
   font-weight: 400;
-  border: 1px solid var(--color-border);
+  border: 1px solid var(--color-select-border);
   font-size: var(--font-size-3);
   border-radius: 6px 0 0 6px;
   display: flex;
@@ -234,7 +241,7 @@ const changeSmileRadio = (title: any, value: any) => {
   justify-content: center;
 }
 .content_right {
-  background-color: #e0e2e6;
+  background-color: var(--scoring-smile-radio-color);
   border-radius: 0 6px 6px 0;
 }
 .el-radio {

BIN
src/components/ScoringGrade/image/bubble_corner_colorful_darkmode.png


BIN
src/components/ScoringGrade/image/bubble_corner_darkmode.png


+ 6 - 3
src/components/ScoringGrade/src/ScoringGrade.vue

@@ -391,7 +391,7 @@ const SubmitText = ref()
   width: 64px;
   height: 64px;
   border-radius: 12px 0 0 12px;
-  background-color: #fff;
+  background-color: var(--management-bg-color);
   position: absolute;
   box-shadow: -2px 2px 12px rgba(0, 0, 0, 15%);
   z-index: 2013;
@@ -402,7 +402,7 @@ const SubmitText = ref()
   justify-content: center;
 }
 .el-avatar {
-  background-color: #fff;
+  background-color: var(--management-bg-color);
   cursor: pointer;
 }
 .score_flex {
@@ -412,7 +412,7 @@ const SubmitText = ref()
   position: absolute;
   right: 64px;
   top: -30px;
-  background-color: white;
+  background-color: var(--management-bg-color);
   border-radius: 12px 0 0 12px;
 }
 .score {
@@ -428,6 +428,9 @@ const SubmitText = ref()
   z-index: 2013 !important;
   border: none;
 }
+:deep(.scoreDialog) {
+  background-color: var(--management-bg-color);
+}
 .el-dialog.scoreDialog {
   position: absolute;
   margin-bottom: 0;

+ 4 - 10
src/components/SelectTable/src/SelectTable.vue

@@ -297,7 +297,7 @@ const onInput = () => {
 
 :deep(.el-table__row:not(.current-row):hover) {
   td {
-    background-color: #fff1e6 !important;
+    background-color: var(--color-btn-default-bg-hover) !important;
   }
 }
 
@@ -313,7 +313,7 @@ const onInput = () => {
   height: 40px;
   justify-content: space-between;
   padding: 0 12px 0 8px;
-
+  background-color: var(--color-mode);
   > span {
     font-size: 13px;
   }
@@ -323,12 +323,6 @@ const onInput = () => {
   border-radius: 12px !important;
 }
 
-:deep(.el-pagination) {
-  .is-active {
-    color: #b57b32 !important;
-  }
-}
-
 :deep(.el-table--fit) {
   border-top-left-radius: 12px;
   border-top-right-radius: 12px;
@@ -339,8 +333,8 @@ const onInput = () => {
 }
 
 .is-disabled {
-  background-color: #f5f7fa;
-  color: #a8abb2;
+  background-color: var(--input-disabled-bg-color);
+  color: var(--input-disabled-text-color);
   cursor: not-allowed;
   box-shadow: none !important;
 }

+ 10 - 9
src/components/ShipmentStatus/src/ShipmentStatus.vue

@@ -111,7 +111,7 @@ const { isOverflow: isPathOverflow } = useOverflow(pathRef, props)
       font-weight: 700;
       text-align: center;
       line-height: 16px;
-      color: #fff;
+      color: var(--color-mode);
     }
     .right-info {
       flex: 1;
@@ -143,7 +143,7 @@ const { isOverflow: isPathOverflow } = useOverflow(pathRef, props)
         .label {
           // width: 96px;
           background-color: var(--color-neutral-1);
-          color: #fff;
+          color: var(--color-mode);
           font-weight: 500;
           font-size: 12px;
           border-radius: 3px 0 0 3px;
@@ -151,7 +151,7 @@ const { isOverflow: isPathOverflow } = useOverflow(pathRef, props)
         .detail-path {
           flex: 1;
           width: 252px;
-          background-color: #fff;
+          background-color: transparent;
           font-weight: 700;
           color: var(--color-neutral-1);
           border: 1px solid #bfc1c3;
@@ -190,21 +190,22 @@ const { isOverflow: isPathOverflow } = useOverflow(pathRef, props)
   &.last {
     & > .data {
       .left-step-icon {
-        background-color: #ccd1db;
+        background-color: var(--color-shipment-status-label-bg);
       }
       .right-info {
         .step-dot {
-          background-color: #ccd1db;
+          background-color: var(--color-shipment-status-label-bg);
         }
         .path {
           .label {
-            background-color: #ccd1db;
+            background-color: var(--color-shipment-status-label-bg);
 
-            font-weight: 600;
-            color: var(--color-neutral-1);
+            font-weight: 500;
+            color: var(--color-shipment-status-label-font-color);
           }
           .detail-path {
-            border-color: #ccd1db;
+            color: var(--color-shipment-status-detail-path-font-color);
+            border-color: var(--color-shipment-status-label-bg);
           }
         }
       }

+ 10 - 4
src/components/TransportMode/src/TransportMode.vue

@@ -180,7 +180,7 @@ const defaultTransport = () => {
       <div class="el-dropdown-link">
         <div class="select_title">Transport Mode</div>
         <span class="iconfont_icon">
-          <svg class="iconfont" aria-hidden="true">
+          <svg class="iconfont icon_dark" aria-hidden="true">
             <use xlink:href="#icon-icon_dropdown_b"></use>
           </svg>
         </span>
@@ -244,6 +244,7 @@ const defaultTransport = () => {
 .iconfont_select {
   width: 17px;
   height: 17px;
+  fill: var(--color-neutral-1);
 }
 .select {
   width: 186px;
@@ -251,7 +252,7 @@ const defaultTransport = () => {
   cursor: pointer;
   display: flex;
   align-items: center;
-  border: 1px solid var(--color-border);
+  border: 1px solid var(--color-select-border);
   border-radius: var(--border-radius-6);
 }
 .select:hover {
@@ -307,7 +308,7 @@ const defaultTransport = () => {
   justify-content: flex-end;
   align-items: center;
   height: 48px;
-  border-top: 1px solid var(--color-border);
+  border-top: 1px solid var(--border-color-2);
   margin-top: 5px;
   font-weight: 400;
   font-size: var(--font-size-3);
@@ -339,8 +340,13 @@ const defaultTransport = () => {
   border-radius: var(--border-radius-6);
   border-color: var(--border-hover-color);
 }
+:deep(.el-dropdown-menu) {
+  background-color: var(--management-bg-color);
+}
 .dropdownwidth {
   width: 248px;
+  background-color: var(--management-bg-color);
+  border-color: var(--management-bg-color);
 }
 @media only screen and (min-width: 1280px) {
   .el-dropdown-link,
@@ -362,6 +368,6 @@ const defaultTransport = () => {
 }
 .el-divider--horizontal {
   margin: 8px 0;
-  border-top-color: var(--color-border);
+  border-top-color: var(--border-color-2);
 }
 </style>

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

@@ -75,6 +75,7 @@ const vBoxPopoverRef = ref()
   margin-right: 0;
 }
 .cancel {
+  fill: var(--color-neutral-1);
   position: absolute;
   right: 12px;
   top: 12px;
@@ -94,6 +95,7 @@ const vBoxPopoverRef = ref()
     padding: 0 16px 0 48px;
     height: 48px;
     line-height: 48px;
+    fill: var(--color-neutral-1);
     font-size: 18px;
     border-bottom: 1px solid var(--color-border);
     font-weight: 700;

+ 27 - 2
src/components/VEmpty/src/VEmpty.vue

@@ -1,9 +1,34 @@
-<script setup lang="ts"></script>
+<script setup lang="ts">
+import lightPng from './images/default_image.png'
+import darkPng from './images/default_dark_image.png'
+import { useThemeStore } from '@/stores/modules/theme'
+
+const emptyImg = ref(lightPng)
+
+const themeStore = useThemeStore()
+// 判断当前系统主题模式
+onMounted(() => {
+  watch(
+    () => themeStore.theme,
+    (newVal) => {
+      if (newVal === 'dark') {
+        emptyImg.value = darkPng
+      } else {
+        emptyImg.value = lightPng
+      }
+    },
+    {
+      immediate: true,
+      deep: true
+    }
+  )
+})
+</script>
 
 <template>
   <div class="v-empty">
     <div class="empty-img">
-      <img src="./images/default_image.png" alt="" />
+      <img :src="emptyImg" alt="" />
     </div>
     <p class="title">
       <slot name="title">No Results Found</slot>

BIN
src/components/VEmpty/src/images/default_dark_image.png


+ 4 - 1
src/components/VSliderVerification/src/VSliderVerification.vue

@@ -47,7 +47,7 @@ const addTipsNode = () => {
 
 const styleMap = {
   start: {
-    thumbColor: 'var(--color-neutral-1)',
+    thumbColor: 'var(--color-slider-thumb-start)',
     thumbIcon: 'icon-icon_drag__line_b',
     trackBackground: 'var(--color-success)'
   },
@@ -163,6 +163,9 @@ defineExpose({
   width: 400px;
   height: 373px;
   padding: 40px;
+  background-color: var(--color-slider-bg);
+  border-radius: 16px;
+  box-shadow: -2px 2px 12px 0 rgba(0, 0, 0, 0.5);
   .tips {
     margin-bottom: 16px;
     text-align: center;

+ 1 - 1
src/hooks/rowClickStyle.ts

@@ -1,6 +1,6 @@
 import { onMounted, onBeforeUnmount } from 'vue'
 
-export function useRowClickStyle(tableRef: any, rowClass: string = 'row--clicked') {
+export function useRowClickStyle(tableRef: any, rowClass: string = 'vxe-table-row-clicked-style') {
   const handleMouseDown = (event: any) => {
     const trElement = event.target.closest('tr')
     if (trElement && trElement.hasAttribute('rowid')) {

+ 34 - 0
src/main.ts

@@ -22,6 +22,40 @@ import router from './router'
 
 const app = createApp(App)
 
+// 动态加载暗黑主题
+async function loadDarkTheme() {
+  await import('element-plus/theme-chalk/dark/css-vars.css') // 动态导入暗黑主题
+}
+// 动态移除暗黑主题
+function unloadDarkTheme() {
+  const darkThemeStylesheet = document.getElementById('dark-theme-style')
+  if (darkThemeStylesheet) {
+    darkThemeStylesheet.remove()
+  }
+}
+// 根据用户偏好或系统设置决定是否加载暗黑主题 (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) ||
+if (localStorage.getItem('theme') === 'dark') {
+  loadDarkTheme()
+  document.documentElement.classList.add('dark')
+}
+// 根据用户偏好或系统设置决定是否添加暗黑模式类名
+// if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+//   document.documentElement.classList.add('dark')
+// }
+// 提供一个全局方法来切换主题
+app.config.globalProperties.$toggleDarkMode = () => {
+  const html = document.documentElement
+  if (html.classList.contains('dark')) {
+    unloadDarkTheme()
+    html.classList.remove('dark')
+    localStorage.setItem('theme', 'light')
+  } else {
+    loadDarkTheme()
+    html.classList.add('dark')
+    localStorage.setItem('theme', 'dark')
+  }
+}
+
 for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
   app.component(key, component)
 }

+ 38 - 0
src/stores/modules/theme.ts

@@ -0,0 +1,38 @@
+import { defineStore } from 'pinia'
+
+interface ThemeState {
+  theme: string
+}
+export const useThemeStore = defineStore('theme', {
+  state: (): ThemeState => ({
+    theme: localStorage.getItem('theme') || 'light'
+  }),
+  actions: {
+    toggleTheme(theme: string) {
+      const html = document.documentElement
+      if (html.classList.contains('dark') && theme === 'light') {
+        unloadDarkTheme()
+        html.classList.remove('dark')
+        localStorage.setItem('theme', 'light')
+        this.theme = 'light'
+      } else if (!html.classList.contains('dark') && theme === 'dark') {
+        loadDarkTheme()
+        html.classList.add('dark')
+        localStorage.setItem('theme', 'dark')
+        this.theme = 'dark'
+      }
+    }
+  }
+})
+
+// 动态加载暗黑主题
+async function loadDarkTheme() {
+  await import('element-plus/theme-chalk/dark/css-vars.css') // 动态导入暗黑主题
+}
+// 动态移除暗黑主题
+function unloadDarkTheme() {
+  const darkThemeStylesheet = document.getElementById('dark-theme-style')
+  if (darkThemeStylesheet) {
+    darkThemeStylesheet.remove()
+  }
+}

+ 35 - 8
src/styles/Antdui.scss

@@ -1,6 +1,11 @@
+.ant-picker {
+  background-color: var(--management-bg-color);
+  color: var(--color-neutral-1);
+}
 .ant-picker-range {
-  height: 32px;
-  border: 1px solid var(--color-border-1);
+  height: 40px;
+  background-color: var(--management-bg-color);
+  border: 1px solid var(--color-select-border);
 }
 .ant-picker:hover, .ant-picker-focused {
   border-color: var(--color-theme);
@@ -55,11 +60,12 @@
   .ant-picker-dropdown .ant-picker-header-view button:hover {
     color: var(--color-theme);
   }
-  .ant-picker-dropdown .ant-picker-panel-container .ant-picker-panels .ant-picker-panel {
-    border-left: 1px solid var(--color-border);
+  .ant-picker-dropdown .ant-picker-panel-container {
+    background-color: var(--management-bg-color);
+    border: 1px solid var(--border-color-2);
   }
   .ant-picker-footer {
-    border-top: 1px solid var(--color-border);
+    border-top: 1px solid var(--border-color-2);
   }
   .ant-picker-dropdown .ant-picker-panel {
     border: none;
@@ -68,9 +74,30 @@
     background: var(--color-orange-6);
   }
  .ant-picker-dropdown .ant-picker-date-panel .ant-picker-content th {
-  color: var(--color-neutral-3);
+  color: var(--color-neutral-2);
  }
 .ant-picker-dropdown .ant-picker-decade-panel,.ant-picker-dropdown .ant-picker-year-panel,.ant-picker-dropdown .ant-picker-quarter-panel,.ant-picker-dropdown .ant-picker-month-panel,.ant-picker-dropdown .ant-picker-week-panel,.ant-picker-dropdown .ant-picker-date-panel,.ant-picker-dropdown .ant-picker-time-panel {
-  
-  border-left: 1px solid var(--color-border);
+  border-left: 1px solid var(--border-color-2);
+}
+.ant-picker .ant-picker-input >input, .ant-picker .ant-picker-input >input::placeholder {
+  color: var(--color-neutral-1);
+}
+.ant-picker-dropdown .ant-picker-cell .ant-picker-cell-inner {
+  color: var(--color-neutral-1);
+}
+.ant-picker-dropdown .ant-picker-header {
+  border-bottom: 1px solid var(--border-color-2);
+}
+.ant-picker .ant-picker-clear {
+  background-color: var(--management-bg-color);
+  color: var(--color-neutral-1);
+}
+.ant-picker .ant-picker-clear:hover {
+  color: var(--color-neutral-1);
+}
+.ant-picker.ant-picker-disabled {
+  border-color: var(--border-color-2);
+}
+.ant-picker-dropdown.ant-picker-dropdown-placement-bottomLeft .ant-picker-range-arrow {
+  display: none;
 }

+ 102 - 50
src/styles/elementui.scss

@@ -1,7 +1,7 @@
 // button
 .el-button.el-button--noborder {
   border: none;
-  background-color: var(--color-white);
+  background-color: var(--management-bg-color);
   span {
     color: var(--color-theme);
   }
@@ -20,19 +20,22 @@ button.el-button.el-button--text {
   padding: 4px 8px;
   border: none;
   background-color: transparent;
-  span {
-    color: var(--color-theme);
-  }
+
   &:hover {
     background-color: var(--color-btn-default-bg-hover);
-    color: var(--color-theme);
+  }
+  &:active {
+    span {
+      color: var(--color-theme);
+    }
   }
 }
 
 .el-button.el-button--default {
-  background-color: var(--color-white);
+  background-color: var(--color-btn-default-bg-color);
   color: var(--color-neutral-1);
-  border: 1px solid var(--color-border);
+  fill: var(--color-neutral-1);
+  border: 1px solid var(--color-select-border);
   margin-left: 8px !important;
   &:hover {
     border: 1px solid var(--color-btn-default-bg-hover);
@@ -44,12 +47,13 @@ button.el-button.el-button--text {
   }
 }
 
-.el-button.el-button--main.is-plain {
+.el-button--main.is-plain {
   background-color: var(--color-white);
   border: 1px solid var(--color-border);
   span {
     color: var(--color-theme);
   }
+  fill: var(--color-theme);
   &:hover {
     border: 1px solid var(--color-btn-main-plain-bg-hover);
     background-color: var(--color-btn-main-plain-bg-hover);
@@ -58,12 +62,13 @@ button.el-button.el-button--text {
   }
 }
 
-.el-button.el-button--main {
+button.el-button--main {
   border: none;
   background-color: var(--color-theme);
   span {
     color: var(--color-white);
   }
+  fill: var(--color-white);
   &:hover {
     background-color: var(--color-btn-main-bg-hover);
     color: var(--color-white);
@@ -71,12 +76,30 @@ button.el-button.el-button--text {
   }
 }
 
+button.el-button.el-button--pain-theme {
+  border: 1px solid var(--color-el-btn-pain-theme-border);
+  background-color: var(--color-el-btn-pain-theme-bg);
+
+  fill: var(--color-el-btn-pain-theme-text);
+  color: var(--color-el-btn-pain-theme-text);
+  span {
+    color: var(--color-el-btn-pain-theme-text);
+  }
+  &:hover {
+    border-color: var(--color-el-btn-pain-theme-border);
+    background-color: var(--color-el-btn-pain-theme-bg-hover);
+    color: var(--color-white);
+    fill: var(--color-white);
+  }
+}
+
 .el-button.el-button--success {
   border: none;
   background-color: var(--color-success);
   span {
     color: var(--color-white);
   }
+  fill: var(--color-white);
   &:hover {
     background-color: var(--color-btn-success-bg-hover);
     color: var(--color-white);
@@ -90,6 +113,7 @@ button.el-button.el-button--text {
   span {
     color: var(--color-white);
   }
+  fill: var(--color-white);
   &:hover {
     background-color: var(--color-btn-warning-bg-hover);
     color: var(--color-white);
@@ -103,6 +127,7 @@ button.el-button.el-button--text {
   span {
     color: var(--color-white);
   }
+  fill: var(--color-white);
   &:hover {
     background-color: var(--color-btn-danger-bg-hover);
     color: var(--color-white);
@@ -113,7 +138,8 @@ button.el-button.el-button--text {
 .el-button.el-button--grey {
   border: none;
   background-color: var(--color-grey);
-  color: var(--color-accent-1);
+  color: var(--color-neutral-1);
+  fill: var(--color-neutral-1);
   &:hover {
     background-color: var(--color-btn-default-bg-hover);
     fill: var(--color-theme);
@@ -126,8 +152,9 @@ button.el-button.el-button--text {
 .el-button.el-button--blue {
   border: none;
   padding: 0 4px;
-  background-color: #f6f6fe;
-  color: var(--color-accent-1);
+  background-color: var(--color-btn-blue-bg);
+  color: var(--color-neutral-1);
+  fill: var(--color-neutral-1);
   &:hover {
     background-color: var(--color-btn-default-bg-hover);
     fill: var(--color-theme);
@@ -142,9 +169,9 @@ button.el-button.el-button--icon {
   height: auto;
   padding: 4px;
   border: none;
-  background-color: #f6f6fe;
+  background-color: var(--color-btn-icon-bg);
   &:hover {
-    background-color: #f6f6fe;
+    background-color: var(--color-btn-icon-bg);
   }
 }
 // 初始为黑色
@@ -155,9 +182,10 @@ button.el-button.el-button--icon {
   span {
     color: var(--color-white);
   }
+  fill: var(--color-white);
   &:hover {
-    background-color: var(--color-btn-default-dark-bg);
-    fill: var(--color-btn-default-dark-hover);
+    background-color: var(--color-btn-default-dark-hover-bg);
+    fill: var(--color-btn-default-dark-hover-bg);
     span {
       color: var(--color-btn-default-dark-hover) !important;
     }
@@ -203,6 +231,7 @@ div.el-dialog {
   padding: 0 0 8px;
   border-radius: 12px;
   overflow: hidden;
+  background-color: var(--color-dialog-body-bg);
 }
 header.el-dialog__header {
   padding: 12px 16px;
@@ -276,7 +305,7 @@ div.el-message-box {
   .el-message-box__header {
     height: 56px;
     padding: 16px;
-    background-color: var(--color-table-header-bg);
+    background-color: var(--color-message-box-header-bg);
     & > span {
       font-weight: 700;
       font-size: var(--font-size-4);
@@ -320,6 +349,7 @@ div.el-drawer {
   }
   .el-drawer__body {
     padding: 16px;
+    background-color: var(--color-table-header-bg);
   }
   .el-drawer__close-btn:focus i,
   .el-drawer__close-btn:hover i {
@@ -331,8 +361,8 @@ div .el-input__inner {
   color: var(--color-neutral-1);
   font-size: var(--font-size-3);
 }
-input.el-input__inner::placeholder {
-  color: var(--color-neutral-3);
+.el-input__inner::placeholder {
+  color: #6c6f75;
   font-size: var(--font-size-3);
 }
 div .el-select__placeholder.is-transparent {
@@ -343,11 +373,11 @@ div .el-select__placeholder.is-transparent {
 }
 div.el-input__wrapper {
   box-shadow: 0 0 0 1px var(--color-border) inset;
-  padding-left: 8px;
+  padding: 0 8px;
 }
 div.el-input div.el-input__wrapper.is-focus {
   box-shadow: 0 0 0 1px var(--color-theme) inset;
-  background-color: #ffffff !important;
+  background-color: var(--color-mode) !important;
 }
 div.el-input__wrapper:hover {
   box-shadow: 0 0 0 1px var(--color-theme) inset;
@@ -373,7 +403,14 @@ div .el-dropdown__popper .el-dropdown__list {
   user-select: none;
 }
 div .el-checkbox__inner:hover {
-  border-color: var(--color-border);
+  border-color: var(--color-select-border);
+}
+div .el-checkbox__inner {
+  border-color: var(--color-select-border);
+  background-color: #fff;
+}
+div .el-checkbox__input.is-checked .el-checkbox__inner:after {
+  border-color: var(--color-mode);
 }
 div .el-checkbox__input.is-checked .el-checkbox__inner {
   background-color: var(--color-theme);
@@ -401,14 +438,19 @@ div .el-checkbox.el-checkbox--large span.el-checkbox__inner::after {
 }
 div .el-popper__arrow,
 div .el-popper__arrow:before {
-  height: 0;
-  width: 0;
+  // height: 0;
+  // width: 0;
+}
+.el-popper.is-dark,
+div.el-popper.is-dark > .el-popper__arrow:before {
+  background-color: var(--color-el-popper-bg);
+  border: var(--color-el-popper-bg);
 }
 div .el-popper[data-popper-placement^='bottom'] > .el-popper__arrow {
   top: 0;
 }
 div .el-dropdown-menu__item {
-  border: 1px solid var(--color-border);
+  border: 1px solid var(--color-select-border);
   border-radius: var(--border-radius-6);
 }
 div .el-dropdown__popper.el-popper,
@@ -429,10 +471,12 @@ div .el-popper[data-popper-placement^='bottom'] .el-popper__arrow:before {
 div .el-popover.el-popper {
   padding: 0;
 }
-.el-popper.is-dark {
+div.el-popper.is-dark {
   span {
     color: #fff;
   }
+  background-color: var(--color-el-popper-bg);
+  border-color: var(--color-el-popper-bg);
 }
 div .el-collapse-item__arrow,
 .el-tabs__nav {
@@ -450,7 +494,7 @@ div .el-collapse-item__content {
   }
 }
 div .el-select__wrapper {
-  box-shadow: 0 0 0 1px var(--color-border);
+  box-shadow: 0 0 0 1px var(--color-select-border);
 }
 div .el-select__wrapper.is-focused {
   box-shadow: 0 0 0 1px var(--color-theme);
@@ -594,34 +638,24 @@ div .el-select-dropdown.is-multiple .el-select-dropdown__item.is-selected:after
 div .el-select__wrapper.is-disabled,
 .el-select__wrapper.is-disabled:hover {
   box-shadow: none !important;
+  background-color: var(--input-disabled-bg-color);
+  color: var(--input-disabled-text-color);
 }
 div .scoreDialog header.el-dialog__header {
-  background: linear-gradient(
-    251deg,
-    rgba(255, 255, 255),
-    rgba(255, 244, 235) 22.66%,
-    rgba(240, 243, 255) 44.57%,
-    rgba(224, 247, 249) 80.46%,
-    rgba(255, 255, 255)
-  );
+  background: var(--dashboard-scoring-bg-color);
   position: fixed;
   width: 640px;
   height: 48px;
   border-radius: 6px 6px 0 0;
 }
+div .el-dialog.scoreDialog {
+  background-color: var(--management-bg-color);
+}
 div .scoreDialog .el-dialog__body {
   margin-top: 40px;
 }
 div .scoreDialog2 header.el-dialog__header {
-  background: linear-gradient(
-    251deg,
-    rgba(255, 255, 255),
-    rgba(255, 244, 235) 22.66%,
-    rgba(240, 243, 255) 44.57%,
-    rgba(224, 247, 249) 80.46%,
-    rgba(255, 255, 255)
-  );
-  position: fixed;
+  background: var(--dashboard-scoring-bg-color);
   width: 640px;
   border-radius: 6px 6px 0 0;
   height: 48px;
@@ -704,14 +738,32 @@ div .el-loading-spinner .path {
 }
 div .ShowAlerIcon {
   width: 342px;
-}
-div .dash_popver {
-  border-radius: 12px !important;
+  background-color: var(--tips-bg-color) !important;
+  border-color: var(--tips-bg-color) !important;
 }
 div .el-month-table td .el-date-table-cell__text {
   color: var(--color-neutral-1);
 }
 div .el-month-table td.today .el-date-table-cell__text {
-  color: var(--color-neutral-1) ; 
-  font-weight: 400 ;
-}
+  color: var(--color-neutral-1);
+  font-weight: 400;
+}
+div .el-select-dropdown {
+  background-color: var(--management-bg-color);
+  border-color: var(--color-header-bg);
+}
+div label.smile_radio .el-radio__inner {
+  background-color: var(--management-bg-color);
+}
+div .el-radio__inner:hover {
+  border-color: var(--color-theme);
+}
+div .dash_popver {
+  background-color: var(--management-bg-color) !important;
+  border-radius: 12px !important;
+}
+div .DaterangeClass {
+  background-color: var(--management-bg-color) !important;
+  border-color: var(--management-bg-color) !important;
+  border-radius: 12px !important;
+}

+ 4 - 1
src/styles/index.scss

@@ -9,7 +9,7 @@
   font-size: var(--font-size-3);
   color: var(--color-neutral-1);
   // user-select: none;
-  background-color: white;
+  background-color: var(--color-mode);
 }
 @font-face {
   font-family: 'Lato-Light'; /* 为字体定义一个名称 */
@@ -47,3 +47,6 @@
   border-radius: var(--border-radius-6);
   background: var(--border-hover-color);
 }
+.icon_dark {
+  fill: var(--color-neutral-1);
+}

+ 72 - 0
src/styles/theme-g.scss

@@ -0,0 +1,72 @@
+:root.dark {
+  // 菜单栏
+  --color-mune-active-bg: rgba(255, 117, 0, 0.2);
+  // 横幅
+  --dashboard-scoring-bg-color: linear-gradient(
+    270deg,
+    rgba(255, 182, 121,0.1) 0.9%,
+    rgba(118, 145, 255,0.1) 49.92%,
+    rgba(96, 242, 255,0.1) 98.78%
+  );
+  --scoring-colurful-color: linear-gradient(251deg, rgba(113, 103, 99) 0%,rgba(92, 106, 125) 100%);
+
+  // button 
+  --color-btn-default-bg-color: transparent;
+  --color-btn-default-bg-hover:rgba(255, 117, 0, 0.2);
+  --color-btn-default-dark-bg: #ED6D00;
+  --color-btn-default-dark-hover: #fff;
+  --color-grey: #3C414A;
+
+  --management-bg-color: #3e454f;
+  --more-type-bg-color: #343A43;
+
+  // filterstag
+  --color-tag-checked-all: rgba(255, 117, 0, 0.2);
+  --color-tag-all-bg: rgba(255, 117, 0, 0.2);
+  --color-tag-all-bg-color:rgba(226,99,148,0.2);
+  --color-tag-created-bg: rgba(1, 103, 251, 0.2);
+  --color-tag-confirmed-bg: rgba(179, 232, 93, 0.15);
+  --color-tag-cancelled-bg: rgba(240, 241, 243, 0.2);
+  --color-tag-cancelled: rgba(240,241,243,0.7)
+  --color-tag-departure-bg: rgba(64, 166, 229, 0.2);
+  --color-tag-cargo-received-bg: rgba(111, 124, 241, 0.2);
+  --color-tag-cargo-received: #6f7cf1;
+  --color-tag-arrived-bg: rgba(1, 183, 161, 0.2);
+  --color-tag-completed-bg: rgba(91, 180, 98, 0.2);
+
+  --color-select-border: #656f7d;
+  --border-color-2: #4C515A;
+  --border-hover-color: rgba(255, 117, 0, 0.2);
+
+
+  --el-color-info: #fff;
+  --el-border-color-light: #3e454f;
+  --el-checkbox-bg-color: #656f7d;
+
+  // 日历
+  --color-orange-6: #614d3f;
+  --color-range-text: #ED6D00;
+
+  // more filters
+  --color-table-header-bg: #343A43;
+  --icon-color-black: #fff;
+  --more-filters-background-color: #2A2E34;
+  --addparties-background-color: #343A43;
+  --color-border-top: #3F434A;
+
+  // tag
+  --tag-bg-color: rgba(239, 239, 240, 0.1);
+  --tag-info-text-color: #fff;
+  --tips-bg-color: rgba(26, 28, 32, 1);
+  --tag-info-bg-color: rgba(239, 239, 240, 0.1);
+
+  // 评分
+  --scoring-bg-color: #525b69;
+  --scoring-smile-radio-color: #626871;
+
+  // 输入框禁用的颜色
+  --input-disabled-bg-color: rgba(244,244,244,0.2);
+  --input-disabled-text-color: #66696f;
+  --color-recent-name: rgba(240,241,243,0.1);
+  --color-disabled-bg: #2b2b2c;
+}

+ 214 - 1
src/styles/theme.scss

@@ -1,7 +1,10 @@
+@import url(./theme-g.scss);
 :root {
   // color palettes
   --color-theme: #ed6d00;
 
+  --color-mode: #fff;
+
   --color-neutral-1: #2b2f36;
   --color-neutral-2: #646a73;
   --color-neutral-3: #b5b9bf;
@@ -63,6 +66,7 @@
   --color-tag-created-bg: #e5f0fb;
   --color-tag-booked-bg: #f3e6fa;
   --color-tag-all-bg: #ffe5cf;
+  --color-tag-all-bg-color:#feecf3;
   --color-tag-cargo-received-bg: #eaecff;
   --color-tag-departure-bg: #d9edfa;
   --color-tag-arrived-bg: #e7faf8;
@@ -70,6 +74,8 @@
   --color-tag-Departed-bg: #d9edfa;
 
   --color-border: #eaebed;
+  --color-select-border: #eaebed;
+  --border-color-2: #eaebed;
   --color-border-1: #e8eaee;
   --color-border-2: #eaebed;
 
@@ -78,15 +84,17 @@
   --color-table-header-bg: #f8f9fd;
 
   --color-dialog-header-bg: #f6f8fa;
+  --color-dialog-body-bg: #ffffff;
 
   // 按钮
   // default
   --color-btn-default-bg-hover: #fff1e6;
+  --color-btn-default-bg-color: #fff;
   // dark
   --color-btn-default-dark-bg: #2b2f36;
   --color-btn-default-dark-hover: #ff7500;
   // main-plain
-  --color-btn-main-plain-bg-hover: #fff1e6;
+  --color-btn-main-plain-bg-hover: hsl(26, 100%, 95%);
   // main
   --color-btn-main-bg-hover: #d56200;
   // success
@@ -106,6 +114,9 @@
 
   --color-header-bg: #f6f8fa;
 
+  --management-bg-color: #fff;
+  --more-type-bg-color: #fff;
+
   // 字体
   --font-size-1: 10px;
   --font-size-2: 12px;
@@ -133,4 +144,206 @@
   --tag-info-text-color: #2b2f36;
 
   --dashboard-text-color: #646a73;
+
+  --el-input-focus: #fff;
+
+  // 发送邮件部分
+
+  --color-avatar: #fff;
+  --color-email-bg: #f6f8fa;
+  --color-detail-email-record-bg: #eceef1;
+  --color-email-border: #eaebed;
+  --w-e-textarea-bg-color: #ffffff;
+  --color-divider: #eaebed;
+  // 横幅
+  --dashboard-scoring-bg-color: linear-gradient(
+    251deg,
+    rgba(255, 255, 255, 0.3),
+    rgba(255, 244, 235, 0.5) 22.66%,
+    rgba(240, 243, 255, 0.5) 44.57%,
+    rgba(224, 247, 249, 0.6) 80.46%,
+    rgba(255, 255, 255, 0.3)
+  );
+
+  --color-range-text: #2b2f36;
+  --tag-bg-color: rgba(239, 239, 240);
+  --tips-bg-color: rgba(26, 28, 32, 1);
+  --scoring-bg-color: #f2f4f7;
+
+  --scoring-colurful-color: linear-gradient(
+    251deg,
+    rgba(242, 244, 247) 0%,
+    rgba(255, 237, 230) 100%
+  );
+  --scoring-smile-radio-color: #e0e2e6;
+
+  --color-el-popper-bg: #303133;
+  // 滚动条
+  --color-scrollbar-thumb: #d9dddf;
+
+  --color-message-box-header-bg: #f6f8fa;
+  --color-table-header-bg: #f8f9fd;
+  --color-table-click-row-bg: #ffe3cc;
+
+  --color-download-file-filter-tag-bg: #eceef0;
+  --color-download-file-selected-column-tag-bg: #eceef0;
+
+  --color-tracking-routes-item-bg: #fef8f3;
+  --color-tracking-routes-item-leg-bg: #f6f2ee;
+
+  --color-customize-column-right-section-bg: #fffbf7;
+  --color-customize-column-right-section-border: #eaebed;
+  --color-customize-column-item-bg: #fff;
+  --color-customize-column-item-hover-bg: #fff1e5;
+  --color-customize-column-item-drag-icon: var(--color-neutral-3);
+  --color-customize-column-item-drag-border: var(--color-customize-column-right-section-bg);
+  --color-customize-column-item-drag-bg: var(--color-customize-column-right-section-bg);
+  --color-customize-column-tabs-header-border: #ebeef5;
+
+  --color-shipment-status-label-bg: #ccd1db;
+  --color-shipment-status-shadow: rgba(0, 0, 0, 0.1);
+
+  --color-slider-bg: #fff;
+  --color-slider-thumb-start: #2b2f36;
+
+  --color-public-tracking-bg-mask: rgba(255, 255, 255, 0.85);
+  --color-public-tracking-search-input-btn: #000;
+  --color-public-tracking-search-input-border: #2b2f36;
+
+  --color-v-box-content-drag-bg: #fff;
+
+  --color-toggle-btn-module-bg: #f0f1f3;
+  --color-toggle-btn-module-active-bg: #fff;
+
+  --color-user-config-title-bottom-border: #eeeeed;
+  // 输入框禁用的颜色
+  --input-disabled-bg-color: #f5f7fa;
+  --input-disabled-text-color: #a8abb2;
+
+  --el-disabled-bg-color: #f4f4f4;
+
+  --color-btn-icon-bg: #f6f6fe;
+
+  --color-btn-blue-bg: #f6f6fe;
+
+  --color-btn-default-dark-hover-bg: #2b2f36;
+
+  --color-recent-name: rgba(43, 47, 54, 0.05);
+  --color-disabled-bg: #eaebed;
+}
+
+:root.dark {
+  --color-mode: #2b2f36;
+
+  // 文字颜色
+  --color-neutral-1: #f0f1f3;
+  --color-neutral-2: rgba(240, 241, 243, 0.7);
+  --color-neutral-3: rgba(240, 241, 243, 0.3);
+  --color-border: #3f434a;
+  --color-header-bg: #30353c;
+
+  --border-hover-color: #654f3f;
+
+  --color-download-file-filter-tag-bg: #3f4249;
+  --color-download-file-selected-column-tag-bg: #474e57;
+
+  --color-customize-column-right-section-bg: #453b36;
+  --color-customize-column-right-section-border: var(--color-theme);
+  --color-customize-column-item-bg: #3a4149;
+  --color-customize-column-item-hover-bg: #585b60;
+  --color-customize-column-item-drag-icon: var(--color-neutral-1);
+  --color-customize-column-item-drag-border: var(--color-theme);
+  --color-customize-column-item-drag-bg: #7d4c26;
+  --color-customize-column-tabs-header-border: #3f434a;
+
+  --color-shipment-status-shadow: rgba(0, 0, 0, 0.5);
+  --color-shipment-status-label-bg: #656f7d;
+  --color-shipment-status-detail-path-font-color: #b5b7ba;
+  --color-shipment-status-label-font-color: #c6cad0;
+
+  --color-slider-bg: #3f434a;
+  --color-slider-thumb-start: #646a73;
+
+  --color-public-tracking-bg-mask: rgba(43, 47, 54, 0.75);
+  --color-public-tracking-search-input-btn: #ed6d00;
+  --color-public-tracking-search-input-border: #656f7d;
+
+  --color-toggle-btn-module-bg: #434b53;
+  --color-toggle-btn-module-active-bg: #656f7d;
+
+  --color-user-config-title-bottom-border: #3f434a;
+
+  --color-btn-blue-bg: rgba(255, 255, 255, 0);
+
+  --color-el-btn-pain-theme-border: #ed6d00;
+  --color-el-btn-pain-theme-text: #ed6d00;
+  --color-el-btn-pain-theme-bg: rgba(237, 109, 0, 0.1);
+  --color-el-btn-pain-theme-bg-hover: rgba(237, 109, 0, 0.3);
+
+  --color-btn-default-dark-hover-bg: #d56200;
+
+  --color-btn-icon-bg: #3f434a;
+  // 滚动条
+  --color-scrollbar-thumb: #656f7d;
+
+  // 菜单选中背景
+  --color-mune-active-bg: #553d2b;
+
+  --color-tracking-routes-item-bg: #403631;
+  --color-tracking-routes-item-leg-bg: #524843;
+
+  --color-v-box-content-drag-bg: #2b2f36;
+
+  --color-input-disabled-border: #656f7d;
+  // 邮件
+  --w-e-toolbar-bg-color: var(--color-email-bg);
+  --w-e-textarea-bg-color: var(--color-email-bg);
+  --w-e-toolbar-border-color: #656f7d;
+  --w-e-toolbar-color: var(--color-neutral-1);
+  --w-e-toolbar-active-bg-color: #553d2b;
+  button.w-e-menu-tooltip-v5::before {
+    color: var(--color-neutral-1);
+  }
+  div.w-e-bar-item button:hover {
+    color: var(--color-neutral-1);
+  }
+  --color-email-border: #656f7d;
+  --color-email-bg: #3c414a;
+  --color-detail-email-record-bg: #343a43;
+  --color-divider: #4c515a;
+  --color-avatar: var(--color-mode);
+  --color-header-bg: #343a43;
+
+  // ElementUI
+  --color-message-box-header-bg: #3e454f;
+  // 整体背景颜色
+  --el-bg-color: #30353c;
+  // 按钮边框颜色
+  --color-accent-13: #656f7d;
+  --el-border: #656f7d;
+  .el-input {
+    --el-input-border: #656f7d;
+  }
+  --color-table-header-bg: #34383f;
+  --el-input-focus: #2b2f36;
+  --color-dialog-header-bg: #3e454f;
+  --color-dialog-body-bg: #30353c;
+  div.el-card {
+    --el-card-bg-color: #30353c;
+  }
+  --color-el-popper-bg: #1a1c20;
+  // --el-bg-color: var(--color-neutral-1);
+  --el-bg-color-overlay: #30353c;
+  div.el-popper.is-dark {
+    --el-bg-color: var(--color-neutral-1);
+  }
+  --el-disabled-bg-color: rgba(244, 244, 244, 0.2);
+
+  // vxe-table
+  --vxe-ui-layout-background-color: #2b2f36;
+  --vxe-ui-table-border-color: #3f434a;
+  --vxe-ui-table-column-icon-border-color: #6a6d73;
+  --color-table-header-bg: #30353c;
+
+  --color-table-click-row-bg: #8b582f;
 }

+ 3 - 3
src/styles/vxeTable.scss

@@ -60,14 +60,14 @@ div.vxe-table .vxe-sort--desc-btn.sort--active {
 }
 
 // 表格点击样式
-.row--clicked {
-  background-color: #ffe3cc !important;
+.vxe-table-row-clicked-style {
+  background-color: var(--color-table-click-row-bg) !important;
 }
 div.vxe-table--render-default tr.vxe-body--row.row--hover,
 .vxe-table--render-default tr.vxe-body--row.row--stripe.row--hover {
   background-color: var(--border-hover-color);
 }
-div.vxe-table--render-default tr.vxe-body--row.row--clicked {
+div.vxe-table--render-default tr.vxe-body--row.vxe-table-row-clicked-style {
   background-color: var(--border-hover-color);
 }
 

+ 12 - 5
src/views/Booking/src/BookingView.vue

@@ -397,13 +397,13 @@ const SearchInput = () => {
     <div class="heaer_top">
       <div class="search">
         <el-input
-          placeholder="Enter Booking/HBL/PO/Carrier Booking No. "
+          placeholder="Enter Booking/HBL/PO/Container/Carrier Booking No. "
           v-model="BookingSearch"
-          @keyup.enter="SearchInput"
+          class="log_input"
         >
           <template #prefix>
             <span class="iconfont_icon">
-              <svg class="iconfont" aria-hidden="true">
+              <svg class="iconfont icon_search" aria-hidden="true">
                 <use xlink:href="#icon-icon_search_b"></use>
               </svg>
             </span>
@@ -418,7 +418,7 @@ const SearchInput = () => {
               placement="bottom"
             >
               <span class="iconfont_icon iconfont_icon_tip">
-                <svg class="iconfont" aria-hidden="true">
+                <svg class="iconfont icon_search" aria-hidden="true">
                   <use xlink:href="#icon-icon_info_b"></use>
                 </svg>
               </span>
@@ -513,12 +513,12 @@ const SearchInput = () => {
   flex-wrap: wrap;
 }
 .tag {
-  border-color: #efeff0;
   border-radius: var(--border-radius-22);
   margin: 0 8px 8px 0;
   color: var(--color-neutral-1);
   font-weight: 600;
   font-size: var(--font-size-2);
+  background-color: var(--tag-bg-color) !important;
 }
 .iconfont_icon_tip {
   margin-left: 8px;
@@ -527,6 +527,9 @@ const SearchInput = () => {
   display: flex;
   align-items: center;
 }
+.icon_search {
+  fill: var(--color-neutral-1);
+}
 @media only screen and (min-width: 1280px) {
   .search {
     width: 480px;
@@ -537,4 +540,8 @@ const SearchInput = () => {
     width: 740px;
   }
 }
+:deep(.log_input .el-input__wrapper) {
+  box-shadow: 0 0 0 1px var(--color-select-border) inset;
+  border-radius: 6px;
+}
 </style>

+ 17 - 4
src/views/Booking/src/components/BookingDetail/src/BookingDetail.vue

@@ -8,9 +8,12 @@ import { transportationMode } from '@/components/TransportationMode'
 import { useRoute } from 'vue-router'
 import { useOverflow } from '@/hooks/useOverflow'
 import { formatTimezone } from '@/utils/tools'
+import { useThemeStore } from '@/stores/modules/theme'
 
 const route = useRoute()
 
+const themeStore = useThemeStore()
+
 // 可拖拽模块的列表
 const boxList = ref([
   { id: 1, name: 'Basic Information' },
@@ -94,7 +97,7 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
 
 <template>
   <div class="booking-detail" v-vloading="loading">
-    <div class="header">
+    <div class="header" :class="{ 'is-dark': themeStore.theme === 'dark' }">
       <div class="detail-status">
         <span
           class="font_family"
@@ -243,6 +246,16 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
       rgba(224, 247, 249, 0.6) 80.46%,
       rgba(255, 255, 255, 0.3)
     );
+    &.is-dark {
+      background: linear-gradient(
+        270deg,
+        rgba(43, 47, 54, 0.1) 1.88%,
+        rgba(255, 182, 121, 0.1) 15.6%,
+        rgba(118, 145, 255, 0.1) 49.92%,
+        rgba(96, 242, 255, 0.1) 81.78%,
+        rgba(43, 47, 54, 0.1) 97.95%
+      );
+    }
 
     .detail-status {
       position: relative;
@@ -317,6 +330,7 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
           .line_container hr {
             width: 100%;
             border-radius: 0 2px 6px 0;
+            border-color: var(--color-neutral-1);
           }
           .line_container .right-icon {
             position: absolute;
@@ -324,7 +338,7 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
             right: 0px;
             width: 10px;
             height: 11px;
-            border-top: 2px solid #000000;
+            border-top: 2px solid var(--color-neutral-1);
             transform: rotate(30deg);
             border-radius: 0 1px 0 0;
           }
@@ -339,9 +353,8 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
 }
 .fallback-class {
   opacity: 1 !important;
-  // background-color: #fff1e5 !important;
   cursor: move !important;
-  background-color: #fff;
+  background-color: var(--color-v-box-content-drag-bg);
   box-shadow: 4px 4px 32px 0px rgba(0, 0, 0, 0.2);
   border-radius: 12px;
 }

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

@@ -204,7 +204,7 @@ const sendEmail = () => {
         @click="handleFocusEditor"
       />
     </div>
-    <div style="border-bottom: 1px solid var(--color-border)">
+    <div style="border-bottom: 1px solid var(--color-divider)">
       <el-button
         @click="sendEmail"
         class="el-button--dark"
@@ -238,7 +238,7 @@ const sendEmail = () => {
   padding: 16px;
   border-radius: 12px;
   border-bottom: 1px solid var(--color-border);
-  background: var(--color-header-bg);
+  background: var(--color-email-bg);
 
   .show-records {
     max-height: 370px;
@@ -248,7 +248,7 @@ const sendEmail = () => {
 
 :deep(.w-e-text-container) {
   min-height: 170px;
-
+  border-radius: 0 0 6px 6px;
   p {
     margin: 0px;
   }
@@ -268,17 +268,28 @@ const sendEmail = () => {
   }
 
   & > .content {
+    display: inline-block;
+    flex: 1;
     padding-top: 2px;
     line-height: 18px;
     color: var(--color-theme);
     word-break: break-all;
   }
 }
+.separated-by {
+  :deep(.el-input__wrapper) {
+    box-shadow: 0 0 0 1px var(--color-email-border) inset;
+  }
+}
 
 .text-editor {
   margin-top: 16px;
   border-radius: 6px;
-  border: 1px solid var(--color-border);
+  border: 1px solid var(--color-email-border);
+  // overflow: hidden;
+  :deep(div.w-e-toolbar) {
+    border-radius: 6px 6px 0 0;
+  }
 }
 
 .record-item {
@@ -300,7 +311,7 @@ const sendEmail = () => {
       div {
         height: 14px;
         line-height: 14px;
-        color: #fff;
+        color: var(--color-avatar);
         font-weight: 700;
       }
     }
@@ -324,14 +335,14 @@ const sendEmail = () => {
 
   & > .content {
     padding: 16px 6px;
-    background-color: #eceef1;
+    background-color: var(--color-detail-email-record-bg);
     border-radius: 6px;
   }
 }
 
 :deep(.text-editor) {
   & > div:first-of-type {
-    border-bottom: 1px solid var(--color-border) !important;
+    border-bottom: 1px solid var(--color-email-border) !important;
   }
 }
 </style>

+ 7 - 1
src/views/Booking/src/components/BookingTable/src/BookingTable.vue

@@ -7,7 +7,9 @@ import dayjs from 'dayjs'
 import { ref, onMounted } from 'vue'
 import { useRouter } from 'vue-router'
 import { transportationMode } from '@/components/TransportationMode'
+import { useThemeStore } from '@/stores/modules/theme'
 
+const themeStore = useThemeStore()
 const router = useRouter()
 const props = defineProps({
   height: {
@@ -430,7 +432,11 @@ defineExpose({
     <div class="table-tools">
       <div class="left-total-records">{{ selectedNumber }} Selected</div>
       <div class="right-tools-btn">
-        <el-button class="el-button--main" @click="handleDownload">
+        <el-button
+          :class="{ 'el-button--pain-theme': themeStore.theme === 'dark' }"
+          class="el-button--main"
+          @click="handleDownload"
+        >
           <span style="margin-right: 8px" class="font_family icon-icon_download_b"></span>
           Download
         </el-button>

+ 7 - 4
src/views/Booking/src/components/BookingTable/src/components/DownloadDialog.vue

@@ -34,7 +34,7 @@ defineExpose({
 
 <template>
   <div>
-    <el-dialog @close="clearData" v-model="dialogVisible" title="Download File" width="480">
+    <el-dialog @close="clearData" v-model="dialogVisible" title="Download File" width="540">
       <div class="download-dialog">
         <div class="select-data">
           <div style="display: inline-block">
@@ -95,12 +95,14 @@ defineExpose({
   display: flex;
   flex-wrap: wrap;
   gap: 8px;
+  max-height: 120px;
   margin-top: 8px;
+  overflow: auto;
 
   .filter-item {
     height: 22px;
     padding: 0px 8px;
-    background-color: #eceef0;
+    background-color: var(--color-download-file-filter-tag-bg);
     border-radius: 12px;
     line-height: 22px;
     font-size: 12px;
@@ -144,11 +146,12 @@ defineExpose({
     }
 
     .select-columns {
+      max-height: 350px;
       padding: 8px;
       margin-top: 8px;
       background-color: var(--color-header-bg);
       border-radius: 6px;
-      overflow: hidden;
+      overflow: auto;
 
       &.show {
         max-height: 500px;
@@ -168,7 +171,7 @@ defineExpose({
         .column-item {
           height: 22px;
           padding: 0px 8px;
-          background-color: #eceef0;
+          background-color: var(--color-download-file-selected-column-tag-bg);
           line-height: 22px;
           border-radius: 12px;
           font-size: 12px;

+ 19 - 4
src/views/Dashboard/src/DashboardView.vue

@@ -781,7 +781,7 @@ const ClickParams = (val: any) => {
     <div class="Title">
       <div>Dashboard</div>
       <div>
-        <el-popover trigger="click" width="400">
+        <el-popover trigger="click" width="400" popper-style="border-radius: 12px">
           <template #reference>
             <el-button class="el-button--default">
               <span class="iconfont_icon">
@@ -817,7 +817,12 @@ const ClickParams = (val: any) => {
         </el-popover>
         <el-popover
           :visible="SaveVisible"
-          :popper-style="{ display: 'flex', flexDirection: 'column', alignItems: 'center' }"
+          :popper-style="{
+            display: 'flex',
+            flexDirection: 'column',
+            alignItems: 'center',
+            backgroundColor: 'var(--management-bg-color)'
+          }"
         >
           <template #reference>
             <el-button
@@ -1207,6 +1212,7 @@ const ClickParams = (val: any) => {
 <style lang="scss" scoped>
 .Title {
   display: flex;
+  background-color: var(--color-mode);
   height: 68px;
   font-size: var(--font-size-6);
   font-weight: 700;
@@ -1220,6 +1226,8 @@ const ClickParams = (val: any) => {
 .Management {
   max-height: 640px;
   overflow-y: hidden;
+  border-radius: 12px;
+  background-color: var(--management-bg-color);
 }
 .Management:hover {
   overflow-y: scroll;
@@ -1260,6 +1268,9 @@ const ClickParams = (val: any) => {
   display: flex;
   justify-content: center;
 }
+.iconfont_tips {
+  fill: var(--color-neutral-2);
+}
 .tips_text {
   width: 278.43px;
   text-align: center;
@@ -1281,11 +1292,14 @@ const ClickParams = (val: any) => {
 }
 .iconfont_icon_save {
   margin-right: 16px;
+  fill: var(--color-neutral-1);
 }
 .Save_filters:hover {
   border-color: var(--color-btn-default-bg-hover);
   background-color: var(--color-btn-default-bg-hover);
-  fill: var(--color-theme);
+  .iconfont_icon_save {
+    fill: var(--color-theme);
+  }
   div {
     color: var(--color-theme);
   }
@@ -1334,6 +1348,7 @@ const ClickParams = (val: any) => {
 }
 .echarts {
   padding: 0 22px;
+  background-color: var(--color-mode);
 }
 .kpi {
   width: 50%;
@@ -1387,7 +1402,7 @@ const ClickParams = (val: any) => {
 .dashboard {
   z-index: 2014;
   position: relative;
-  background-color: white;
+  background-color: var(--color-mode);
   padding-bottom: 40px;
 }
 :deep(.el-tabs__header) {

+ 25 - 10
src/views/Dashboard/src/components/DashFiters.vue

@@ -182,7 +182,7 @@ const DateRangeSearch = () => {
           </span>
           Filters
           <span class="iconfont_icon">
-            <svg class="iconfont" aria-hidden="true">
+            <svg class="iconfont icon_dark" aria-hidden="true">
               <use xlink:href="#icon-icon_dropdown_b"></use>
             </svg>
           </span>
@@ -227,7 +227,10 @@ const DateRangeSearch = () => {
         <div class="filter_filter" style="margin-left: 4px">
           <div v-if="props.isContainer">
             <el-date-picker
-              :style="{ width: props.isRevenue ? '110px' : '120px', height: '40px' }"
+              :style="{
+                width: props.isRevenue ? '110px' : '120px',
+                height: '40px'
+              }"
               v-model="startDate"
               format="MMM-YYYY"
               type="month"
@@ -283,7 +286,7 @@ const DateRangeSearch = () => {
   display: flex;
   align-items: center;
   justify-content: center;
-  border: 1px solid var(--color-border);
+  border: 1px solid var(--color-select-border);
   margin-bottom: 8px;
 }
 :deep(.el-checkbox-button__inner:hover) {
@@ -292,10 +295,10 @@ const DateRangeSearch = () => {
   border-color: var(--color-btn-default-bg-hover);
 }
 :deep(.el-checkbox-button.is-focus .el-checkbox-button__inner) {
-  border-color: var(--color-border);
+  border-color: var(--color-select-border);
 }
 :deep(.el-checkbox-button:first-child .el-checkbox-button__inner) {
-  border-left: 1px solid var(--color-border);
+  border-left: 1px solid var(--color-select-border);
   border-top-left-radius: var(--border-radius-6);
   border-bottom-left-radius: var(--border-radius-6);
 }
@@ -314,14 +317,20 @@ const DateRangeSearch = () => {
   border-left-color: var(--color-theme);
 }
 :deep(.el-checkbox-button.is-disabled.is-checked .el-checkbox-button__inner) {
-  background-color: #eaebed;
-  border-color: var(--color-border);
-  color: #2b2f36;
+  background-color: var(--color-disabled-bg);
+  border-color: var(--color-select-border);
+  color: var(--color-neutral-1);
   font-weight: 700;
 }
 // :deep(.el-checkbox-button.is-focus .el-checkbox-button__inner) {
-//   border-color: var(--color-border);
+//   border-color: var(--color-select-border);
 // }
+:deep(.el-radio-button__original-radio:disabled + .el-radio-button__inner) {
+  border-color: var(--color-select-border);
+}
+:deep(.el-checkbox-button.is-disabled .el-checkbox-button__inner) {
+  border-color: var(--color-select-border);
+}
 .Dash_title {
   height: 48px;
   font-size: 16px;
@@ -345,7 +354,7 @@ const DateRangeSearch = () => {
   justify-content: flex-end;
   align-items: center;
   height: 48px;
-  border-top: 1px solid var(--color-border);
+  border-top: 1px solid var(--color-select-border);
   margin-top: 5px;
   font-weight: 400;
   font-size: var(--font-size-3);
@@ -378,15 +387,21 @@ const DateRangeSearch = () => {
   height: 40px;
   display: flex;
   align-items: center;
+  border: 1px solid var(--color-select-border);
 }
 :deep(.el-radio-button:first-child .el-radio-button__inner) {
   height: 40px;
   display: flex;
+  border: 1px solid var(--color-select-border);
   align-items: center;
 }
 :deep(.el-radio-button__inner) {
   display: flex;
   align-items: center;
   height: 40px;
+  border: 1px solid var(--color-select-border);
+}
+:deep(.el-input__wrapper) {
+  box-shadow: 0 0 0 1px var(--color-select-border) inset;
 }
 </style>

+ 28 - 1
src/views/Dashboard/src/components/PieChart.vue

@@ -1,11 +1,13 @@
 <!-- 饼状图 -->
  <script lang="ts" setup>
 import * as echarts from 'echarts'
+import { useThemeStore } from '@/stores/modules/theme'
 import { onMounted, ref, reactive, watch, computed } from 'vue'
 const props = defineProps({
   PieData: Object
 })
 const pie_data = ref(props.PieData)
+const themeStore = useThemeStore()
 watch(
   () => props.PieData,
   (current) => {
@@ -116,7 +118,10 @@ const initOption: any = reactive({
       alignTo: 'labelLine',
       rich: {
         name: {
-          fontFamily: 'Lato-Light'
+          fontFamily: 'Lato-Light',
+          color: '#646A73',
+          fontSize: '12px',
+          fontWeight: '700'
         },
         time: {
           fontSize: '10px',
@@ -164,6 +169,28 @@ const initOption: any = reactive({
 onMounted(() => {
   initChart()
   clickParams()
+  watch(
+    () => themeStore.theme,
+    (newVal) => {
+      if (newVal === 'dark') {
+        initOption.title.textStyle.color = '#f0f1f3'
+        initOption.series.label.rich.time.color = 'rgba(240,241,243,0.7)'
+        initOption.series.label.rich.name.color = 'rgba(240,241,243,0.7)'
+        initOption.legend.textStyle.color = 'rgba(240,241,243,0.7)'
+        initChart()
+      } else {
+        initOption.title.textStyle.color = '#2B2F36'
+        initOption.series.label.rich.time.color = '#999'
+        initOption.series.label.rich.name.color = '#646A73'
+        initOption.legend.textStyle.color = '#646A73'
+        initChart()
+      }
+    },
+    {
+      immediate: true,
+      deep: true
+    }
+  )
 })
 const emits = defineEmits(['ClickParams'])
 const paramsdata = ref()

+ 12 - 13
src/views/Dashboard/src/components/RecentStatus.vue

@@ -1,6 +1,5 @@
 <script lang="ts" setup>
 import { useRouter } from 'vue-router'
-import dayjs from 'dayjs'
 import { formatTimezoneByUTCorGMT } from '@/utils/tools'
 
 const router = useRouter()
@@ -42,7 +41,7 @@ const RouteToDetail = (val: any) => {
       <div class="recent-header-left">
         <div>
           <span class="iconfont_icon">
-            <svg class="iconfont iconfont_route" aria-hidden="true">
+            <svg class="iconfont iconfont_route icon_dark" aria-hidden="true">
               <use xlink:href="#icon-icon_ocean_b"></use>
             </svg>
           </span>
@@ -89,7 +88,7 @@ const RouteToDetail = (val: any) => {
         <div class="startStation">
           <div class="startStation_title">
             <span class="iconfont_icon">
-              <svg class="iconfont" aria-hidden="true">
+              <svg class="iconfont icon_dark" aria-hidden="true">
                 <use xlink:href="#icon-icon_location_fill_b"></use>
               </svg>
             </span>
@@ -100,7 +99,7 @@ const RouteToDetail = (val: any) => {
         <div class="StationIcon">
           <div>
             <span class="iconfont_icon">
-              <svg class="iconfont" aria-hidden="true">
+              <svg class="iconfont icon_dark" aria-hidden="true">
                 <use xlink:href="#icon-icon_path_b"></use>
               </svg>
             </span>
@@ -110,7 +109,7 @@ const RouteToDetail = (val: any) => {
         <div class="startStation">
           <div class="startStation_title">
             <span class="iconfont_icon">
-              <svg class="iconfont" aria-hidden="true">
+              <svg class="iconfont icon_dark" aria-hidden="true">
                 <use xlink:href="#icon-icon_location_fill_b"></use>
               </svg>
             </span>
@@ -134,13 +133,13 @@ const RouteToDetail = (val: any) => {
 <style lang="scss" scoped>
 .recent_route {
   border-radius: var(--border-radius-12);
-  border: 1px solid var(--color-border-2);
+  border: 1px solid var(--color-border);
   margin: 8px;
 }
 .recent_header {
   background-color: var(--color-header-bg);
   border-radius: var(--border-radius-12) var(--border-radius-12) 0 0;
-  border-bottom: 1px solid var(--color-border-2);
+  border-bottom: 1px solid var(--color-border);
   display: flex;
   padding: 12px 16px;
   justify-content: space-between;
@@ -171,9 +170,9 @@ const RouteToDetail = (val: any) => {
   color: var(--color-theme);
 }
 .recent-name {
-  border: 1px solid var(--color-border-2);
+  border: 1px solid var(--color-border);
   border-radius: 3px;
-  background-color: rgba(43, 47, 54, 0.05);
+  background-color: var(--color-recent-name);
   padding: 4px;
   margin-right: 8px;
 }
@@ -207,7 +206,7 @@ const RouteToDetail = (val: any) => {
   }
 }
 .recent-content-left {
-  border-right: 1px solid var(--color-border-2);
+  border-right: 1px solid var(--color-border);
   padding-left: 16px;
   width: 37%;
   height: 76px;
@@ -218,14 +217,14 @@ const RouteToDetail = (val: any) => {
   line-height: 21px;
 }
 .recent-content-middle {
-  border-right: 1px solid var(--color-border-2);
+  border-right: 1px solid var(--color-border);
   padding-left: 8px;
   width: 37%;
   height: 76px;
   display: flex;
 }
 .left_title {
-  color: var(--dashboard-text-color);
+  color: var(--color-neutral-2);
 }
 .startStation {
   display: flex;
@@ -239,7 +238,7 @@ const RouteToDetail = (val: any) => {
 }
 .startStation_time {
   font-size: var(--font-size-2);
-  color: var(--dashboard-text-color);
+  color: var(--color-neutral-2);
 }
 .recent-content-right {
   width: 24%;

+ 20 - 18
src/views/Dashboard/src/components/ScoringSystem.vue

@@ -175,7 +175,7 @@ const InnerTitle = ref()
 const InnerTileQues = ref()
 const checkexpression = ref()
 const OpenScoring = (item: any) => {
-  dialogVisible.value = false
+  // dialogVisible.value = false
   innerVisible.value = true
   InnerTitle.value = item.itemtext
   InnerTileQues.value = item.proposal
@@ -328,6 +328,7 @@ const submitDetails = (val: any) => {
         class="scoreDialog2"
         :destroy-on-close="true"
         @close="closeDialog"
+        :close-on-click-modal="false"
       >
         <div class="dialog" v-if="isshowDetails">
           <div class="das_in_title">
@@ -403,7 +404,7 @@ const submitDetails = (val: any) => {
           <div class="buttom">
             <div class="previous" @click="previous">
               <span class="iconfont_icon">
-                <svg class="iconfont" aria-hidden="true">
+                <svg class="iconfont icon_dark" aria-hidden="true">
                   <use xlink:href="#icon-icon_back_b"></use>
                 </svg>
               </span>
@@ -437,9 +438,9 @@ const submitDetails = (val: any) => {
         </el-result>
       </el-dialog>
     </div>
-    <div @click="isShowScoring = false" style="cursor: pointer">
+    <div @click="isShowScoring = false" style="cursor: pointer; fill: var(--color-neutral-1)">
       <span class="iconfont_icon">
-        <svg class="iconfont" aria-hidden="true">
+        <svg class="iconfont icon_dark" aria-hidden="true">
           <use xlink:href="#icon-icon_reject_b"></use>
         </svg>
       </span>
@@ -453,14 +454,7 @@ const submitDetails = (val: any) => {
   justify-content: space-between;
   padding-right: 24px;
   align-items: center;
-  background: linear-gradient(
-    251deg,
-    rgba(255, 255, 255, 0.3),
-    rgba(255, 244, 235, 0.5) 22.66%,
-    rgba(240, 243, 255, 0.5) 44.57%,
-    rgba(224, 247, 249, 0.6) 80.46%,
-    rgba(255, 255, 255, 0.3)
-  );
+  background: var(--dashboard-scoring-bg-color);
   height: 48px;
 }
 .scoring_img {
@@ -570,14 +564,15 @@ const submitDetails = (val: any) => {
 :deep(.el-checkbox-button__inner) {
   color: var(--tag-info-text-color);
   font-size: var(--font-size-3);
+  background-color: var(--management-bg-color);
   font-weight: 400;
   padding: 0;
-  width: 180px !important;
+  width: 180px;
   height: 40px;
   display: flex;
   align-items: center;
   justify-content: center;
-  border: 1px solid var(--color-border);
+  border: 1px solid var(--color-select-border);
   border-radius: var(--border-radius-6);
   margin-bottom: 8px;
 }
@@ -590,7 +585,7 @@ const submitDetails = (val: any) => {
   border-color: transparent;
 }
 :deep(.el-checkbox-button:first-child .el-checkbox-button__inner) {
-  border-left: 1px solid var(--color-border);
+  border-left: 1px solid var(--color-select-border);
   border-top-left-radius: var(--border-radius-6);
   border-bottom-left-radius: var(--border-radius-6);
 }
@@ -609,13 +604,20 @@ const submitDetails = (val: any) => {
   background-color: var(--color-theme);
   border-color: var(--color-theme);
 }
+:deep(.scoreDialog2) {
+  background-color: var(--management-bg-color);
+}
 .inputdetails {
   margin-top: 8px;
+  background-color: var(--management-bg-color);
+  border-radius: 6px;
+  border-color: var(--color-select-border);
 }
 :deep(.el-textarea) {
   .el-textarea__inner {
     resize: none; // 去除右下角图标
     padding: 5px 7px 5px 10px;
+    box-shadow: 0 0 0 1px var(--color-select-border) inset;
   }
 }
 .smile_flex {
@@ -644,9 +646,9 @@ const submitDetails = (val: any) => {
 }
 .content_left {
   height: 41px;
-  background-color: #fff;
+  background-color: var(--management-bg-color);
   font-weight: 400;
-  border: 1px solid var(--color-border);
+  border: 1px solid var(--color-select-border);
   font-size: var(--font-size-3);
   border-radius: 6px 0 0 6px;
   display: flex;
@@ -659,7 +661,7 @@ const submitDetails = (val: any) => {
   justify-content: center;
 }
 .content_right {
-  background-color: #e0e2e6;
+  background-color: var(--scoring-smile-radio-color);
   border-radius: 0 6px 6px 0;
 }
 .el-radio {

+ 59 - 1
src/views/Dashboard/src/components/TopMap.vue

@@ -2,6 +2,9 @@
 import { onMounted, ref, watch } from 'vue'
 import OriginIcon from '../image/hhh_2.png'
 import L from 'leaflet'
+import { useThemeStore } from '@/stores/modules/theme'
+
+const themeStore = useThemeStore()
 const MapDataList = ref([])
 const mapobj = ref()
 const originIcon = L.icon({
@@ -131,7 +134,11 @@ defineExpose({
 })
 </script>
 <template>
-  <div id="map" style="width: 100%; height: 272px"></div>
+  <div
+    id="map"
+    style="width: 100%; height: 272px"
+    :class="{ 'dark-mode': themeStore.theme === 'dark' }"
+  ></div>
 </template>
 
 <style lang="scss">
@@ -180,6 +187,57 @@ defineExpose({
     }
   }
 }
+.dark-mode {
+  div.leaflet-control-zoom.leaflet-bar.leaflet-control {
+    border: 0;
+    border-radius: 4px;
+    box-shadow: none;
+    a {
+      background-color: #3c414a;
+      border-bottom: none;
+      span {
+        color: var(--color-neutral-1);
+      }
+      &:first-child {
+        span {
+          display: inline-block;
+          width: 24px;
+          border-bottom: 2px solid #575c64;
+        }
+      }
+    }
+  }
+  .reset-zoom-control {
+    border: none;
+    background-color: #3c414a;
+  }
+  a.leaflet-bar-part {
+    background-color: #3c414a;
+    border-radius: 4px;
+    box-shadow: none;
+    overflow: hidden;
+    div {
+      border-color: var(--color-neutral-1) !important;
+      div {
+        background-color: var(--color-neutral-1) !important;
+      }
+    }
+  }
+}
+/* 示例:将所有地图图片的颜色反转 */
+.dark-mode img:not(.leaflet-marker-icon) {
+  filter: invert(1) hue-rotate(170deg);
+}
+// 防止暗黑模式下地图超出容器
+#map {
+  overflow: hidden;
+}
+// 修改暗黑模式下的背景色
+.leaflet-container.dark-mode,
+.leaflet-map-pane.dark-mode,
+.leaflet-tile-container.dark-mode {
+  background-color: #2b2f36;
+}
 /* 自定义重置缩放按钮控件样式 */
 .reset-zoom-control {
   margin-top: 10px; /* 增加上边距,使按钮与默认缩放按钮之间有间距 */

+ 153 - 4
src/views/Layout/src/components/Header/HeaderView.vue

@@ -7,12 +7,20 @@ import { useUserStore } from '@/stores/modules/user'
 import { useHeaderSearch } from '@/stores/modules/headerSearch'
 import { onBeforeRouteUpdate } from 'vue-router'
 import { useLoadingState } from '@/stores/modules/loadingState'
+import { useThemeStore } from '@/stores/modules/theme'
 
+const themeStore = useThemeStore()
 const userStore = useUserStore()
 const route = useRoute()
 const router = useRouter()
 const headerSearch = useHeaderSearch()
 
+const themePopoverRef = ref()
+// 切换系统主题颜色
+const toggleThemeMode = (theme: string) => {
+  themeStore.toggleTheme(theme)
+}
+
 const searchValue = ref('')
 // 用于判断是否在搜索后跳转页面,跳转后清空搜索框的值
 const isJumpPageBySearch = ref(false)
@@ -155,12 +163,67 @@ const handleLogin = () => {
       <!-- <span class="font_family icon-icon_notice_b" style="font-size: 18px"></span>
       <span class="font_family icon-icon_language_b" style="font-size: 16px"></span> -->
 
+      <el-popover
+        placement="bottom-end"
+        :width="400"
+        trigger="click"
+        ref="themePopoverRef"
+        popper-class="toggle-theme-popover"
+      >
+        <div>
+          <div class="header">
+            <span class="title">Themes</span>
+            <el-button @click="themePopoverRef.hide()" class="close-icon el-button--text">
+              <div class="font_family icon-icon_reject_b"></div>
+            </el-button>
+          </div>
+          <div class="tips">
+            Customize your workspace by changing the appearance and theme color
+          </div>
+          <div class="picture-module">
+            <div class="item" :class="{ active: themeStore.theme === 'light' }">
+              <img src="./images/light.png" alt="" />
+              <div v-if="themeStore.theme === 'light'" class="selected-icon">
+                <span class="font_family icon-icon_confirm_b"></span>
+              </div>
+            </div>
+            <div class="item" :class="{ active: themeStore.theme === 'dark' }">
+              <img src="./images/dark.png" alt="" />
+              <div v-if="themeStore.theme === 'dark'" class="selected-icon">
+                <span class="font_family icon-icon_confirm_b"></span>
+              </div>
+            </div>
+          </div>
+          <div class="btn-module">
+            <div
+              class="btn-item"
+              @click="toggleThemeMode('light')"
+              :class="{ active: themeStore.theme === 'light' }"
+            >
+              <span class="font_family icon-icon_light_b"></span>
+              Light
+            </div>
+            <div
+              class="btn-item"
+              @click="toggleThemeMode('dark')"
+              :class="{ active: themeStore.theme === 'dark' }"
+            >
+              <span class="font_family icon-icon_dark_b"></span>Dark
+            </div>
+          </div>
+        </div>
+        <template #reference>
+          <el-button style="height: 40px; width: 40px" class="el-button--text">
+            <span class="font_family icon-icon_themes_b" style="font-size: 16px"></span
+          ></el-button>
+        </template>
+      </el-popover>
+
       <el-popover
         placement="bottom-end"
         :width="256"
         trigger="click"
         popper-class="user-config-popover"
-        content="this is content, this is content, this is content"
       >
         <div class="title">
           <div class="avatar">
@@ -189,9 +252,10 @@ const handleLogin = () => {
         </template>
       </el-popover>
       <el-button
+        :class="{ 'el-button--pain-theme': themeStore.theme === 'dark' }"
         v-if="!userStore.username || (userStore.username && userStore.isFirstLogin === true)"
         class="el-button--main"
-        style="padding: 8px 10px"
+        style="padding: 8px 10px; margin-right: 10px; margin-left: 0"
         plain
         @click="handleDownload"
       >
@@ -238,7 +302,7 @@ const handleLogin = () => {
   display: flex;
   align-items: center;
   justify-content: center;
-  gap: 24px;
+  gap: 8px;
   height: 100%;
 
   .el-input {
@@ -262,6 +326,91 @@ const handleLogin = () => {
 }
 </style>
 <style lang="scss">
+div.el-popover.el-popper.toggle-theme-popover {
+  width: 400px;
+  height: 278px;
+  padding: 16px;
+  .header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 8px;
+    .title {
+      font-size: 18px;
+      font-weight: 700;
+    }
+    .close-icon {
+      width: 24px;
+      cursor: pointer;
+    }
+  }
+  .tips {
+    color: var(--color-neutral-2);
+  }
+  .picture-module {
+    display: flex;
+    justify-content: center;
+    gap: 6px;
+    margin-top: 16px;
+    .item {
+      position: relative;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      width: 174px;
+      height: 108px;
+      padding: 8px;
+      img {
+        width: 154px;
+        height: 90px;
+      }
+      &.active {
+        border: 2px solid var(--color-theme);
+        border-radius: 6px;
+      }
+      .selected-icon {
+        position: absolute;
+        bottom: 8px;
+        left: 50%;
+        transform: translateX(-50%);
+        height: 16px;
+        span {
+          height: 16px;
+          width: 16px;
+          background-color: var(--color-theme);
+          color: #fff;
+          border-radius: 50%;
+        }
+      }
+    }
+  }
+  .btn-module {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 368px;
+    height: 40px;
+    margin-top: 10px;
+    padding: 0 8px;
+    background-color: var(--color-toggle-btn-module-bg);
+    border-radius: 6px;
+    .btn-item {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      gap: 4px;
+      width: 180px;
+      height: 32px;
+      border-radius: 6px;
+      color: var(--color-neutral-2);
+      cursor: pointer;
+      &.active {
+        background-color: var(--color-toggle-btn-module-active-bg);
+        color: var(--color-neutral-1);
+      }
+    }
+  }
+}
 div.el-popover.el-popper.user-config-popover {
   padding: 8px;
   width: 240px;
@@ -271,7 +420,7 @@ div.el-popover.el-popper.user-config-popover {
     align-items: center;
     gap: 8px;
     height: 70px;
-    border-bottom: 1px solid #eeeeed;
+    border-bottom: 1px solid var(--color-user-config-title-bottom-border);
     & > .avatar {
       width: 48px;
       height: 48px;

+ 3 - 0
src/views/Layout/src/components/Header/components/ChangePasswordDialog.vue

@@ -210,7 +210,10 @@ defineExpose({
   .form-item {
     margin-bottom: 16px;
     .label {
+      display: inline-block;
+      margin-bottom: 4px;
       font-size: 12px;
+      color: var(--color-neutral-2);
     }
     .error {
       font-size: 12px;

BIN
src/views/Layout/src/components/Header/images/dark.png


BIN
src/views/Layout/src/components/Header/images/light.png


+ 1 - 0
src/views/Layout/src/components/Menu/MenuView.vue

@@ -221,6 +221,7 @@ const jumpLink = (link: string) => {
   margin: 0 12px 2px;
   padding-left: 8px !important;
   border-radius: 6px;
+  color: var(--color-neutral-1);
   &:hover {
     background-color: var(--color-mune-active-bg);
   }

+ 35 - 5
src/views/Login/src/components/ChangePasswordCard.vue

@@ -1,9 +1,31 @@
 <script setup lang="ts">
+import { useThemeStore } from '@/stores/modules/theme'
 import { useRouter, useRoute } from 'vue-router'
 import { useUserStore } from '@/stores/modules/user'
 
 const userStore = useUserStore()
 const router = useRouter()
+
+const themeStore = useThemeStore()
+const changePasswordRef = ref()
+// 判断当前系统主题模式
+onMounted(() => {
+  watch(
+    () => themeStore.theme,
+    (newVal) => {
+      if (newVal === 'dark') {
+        changePasswordRef.value.classList.add('dark-bg')
+      } else {
+        changePasswordRef.value.classList.remove('dark-bg')
+      }
+    },
+    {
+      immediate: true,
+      deep: true
+    }
+  )
+})
+
 const route = useRoute()
 
 const tips = ref('Please change your password for security.')
@@ -125,9 +147,9 @@ onUnmounted(() => {
 </script>
 
 <template>
-  <div class="login">
+  <div class="login" ref="changePasswordRef">
     <el-card class="login-card">
-      <div class="title">
+      <div class="title" :class="{ 'is-dark': themeStore.theme === 'dark' }">
         <span class="welcome">Change Password</span>
         <span class="tips">{{ tips }}</span>
       </div>
@@ -242,20 +264,27 @@ onUnmounted(() => {
   width: 100%;
   background: url(../image/bg.png) no-repeat center center;
   background-size: cover;
+  &.dark-bg {
+    background: url(../image/bg-dark.png) no-repeat center center;
+    background-size: cover;
+  }
 }
 
 .login-card {
   width: 400px;
-
+  border-radius: 12px;
   .title {
     display: flex;
     flex-direction: column;
     align-items: center;
     margin-bottom: 24px;
     padding: 40px 40px 0;
-    background: url(../image/bg-login-card.png) no-repeat center center;
+    background: url(../image/bg-login-card.png) no-repeat;
     background-position: top left; /* 从左上角开始显示 */
     background-size: 400px 100px; /* 保持背景图像的原始尺寸 */
+    &.is-dark {
+      background: url(../image/bg-login-card-dark.png) no-repeat;
+    }
     .welcome {
       margin-bottom: 16px;
       font-size: 24px;
@@ -307,7 +336,7 @@ onUnmounted(() => {
     }
     &.is-disabled {
       :deep(.el-input__wrapper) {
-        background-color: #f4f4f4;
+        // background-color: #f4f4f4;
       }
       :deep(.el-input__inner) {
         -webkit-text-fill-color: var(--color-neutral-1);
@@ -362,6 +391,7 @@ onUnmounted(() => {
   .el-input.user-name {
     :deep(.el-input__wrapper) {
       padding-right: 6px;
+      box-shadow: 0 0 0 1px var(--color-input-disabled-border) inset;
     }
   }
 

BIN
src/views/Login/src/image/bg-dark.png


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


+ 33 - 6
src/views/Login/src/loginView.vue

@@ -3,12 +3,33 @@ import { useRouter, useRoute } from 'vue-router'
 import ErrorTips from './components/ErrorTips.vue'
 import FirstLoginTips from './components/FirstLoginTips.vue'
 import { useUserStore } from '@/stores/modules/user'
+import { useThemeStore } from '@/stores/modules/theme'
 import ScoringSystem from '@/views/Dashboard/src/components/ScoringSystem.vue'
 import CryptoJS from 'crypto-js'
 import dayjs from 'dayjs'
 
 const router = useRouter()
 const route = useRoute()
+const themeStore = useThemeStore()
+
+const loginRef = ref()
+// 判断当前系统主题模式
+onMounted(() => {
+  watch(
+    () => themeStore.theme,
+    (newVal) => {
+      if (newVal === 'dark') {
+        loginRef.value.classList.add('dark-bg')
+      } else {
+        loginRef.value.classList.remove('dark-bg')
+      }
+    },
+    {
+      immediate: true,
+      deep: true
+    }
+  )
+})
 
 // 手动获取url中的参数,直接获取route.query的参数时如果有+号会被转义成空格
 const getQueryParams = (url: string) => {
@@ -322,10 +343,10 @@ const firstLoginTipsRef = ref()
 </script>
 
 <template>
-  <div class="login">
+  <div class="login" ref="loginRef">
     <ScoringSystem class="scoring-system"></ScoringSystem>
     <el-card class="login-card" v-if="status === 'login'">
-      <div class="card-title">
+      <div class="card-title" :class="{ 'is-dark': themeStore.theme === 'dark' }">
         <span class="welcome">Welcome to KLN Portal</span>
         <span class="tips">Login to your account</span>
       </div>
@@ -394,7 +415,7 @@ const firstLoginTipsRef = ref()
       </template>
     </el-card>
     <el-card class="login-card" v-else-if="status === 'reset'">
-      <div class="card-title">
+      <div class="card-title" :class="{ 'is-dark': themeStore.theme === 'dark' }">
         <span class="welcome">Password Retrieval</span>
         <span class="tips">We'll send your password to your email address.</span>
       </div>
@@ -468,11 +489,15 @@ const firstLoginTipsRef = ref()
   width: 100%;
   background: url(../src/image/bg.png) no-repeat center center;
   background-size: cover;
+  &.dark-bg {
+    background: url(../src/image/bg-dark.png) no-repeat center center;
+    background-size: cover;
+  }
   .scoring-system {
     position: absolute;
     top: 0;
     width: 100%;
-    background: linear-gradient(251deg, #fff4eb 22.66%, #f0f3ff 44.57%, #e0f7f9 70.46%);
+    background: var(--dashboard-scoring-bg-color);
   }
 }
 
@@ -485,10 +510,12 @@ const firstLoginTipsRef = ref()
     align-items: center;
     height: 94px;
     padding-top: 32px;
-    background: url(../src/image/bg-login-card.png) no-repeat center center;
+    background: url(../src/image/bg-login-card.png) no-repeat;
     background-position: top left; /* 从左上角开始显示 */
     background-size: 400px 100px; /* 保持背景图像的原始尺寸 */
-
+    &.is-dark {
+      background: url(../src/image/bg-login-card-dark.png) no-repeat;
+    }
     .welcome {
       margin-bottom: 16px;
       font-size: 24px;

+ 10 - 4
src/views/OperationLog/src/OperationLog.vue

@@ -174,10 +174,10 @@ const DateChange = (date: any) => {
     <div class="display">
       <div class="heaer_top">
         <div class="search tips_filter">
-          <el-input placeholder="Search user name" v-model="OperationSearch">
+          <el-input placeholder="Search user name" v-model="OperationSearch" class="log_input">
             <template #prefix>
               <span class="iconfont_icon">
-                <svg class="iconfont" aria-hidden="true">
+                <svg class="iconfont icon_dark" aria-hidden="true">
                   <use xlink:href="#icon-icon_search_b"></use>
                 </svg>
               </span>
@@ -272,16 +272,22 @@ const DateChange = (date: any) => {
 :deep(.ETD_title) {
   margin-bottom: 0;
 }
-:deep(:where(.css-dev-only-do-not-override-19iuou).ant-picker-range) {
+:deep(.ant-picker-range) {
   width: 250px !important;
   height: 32px;
+  background-color: var(--color-mode) !important;
 }
 .tips_filter {
   margin-right: 8px;
+  height: 32px;
 }
 .dashboard {
   z-index: 2014;
   position: relative;
-  background-color: white;
+  background-color: var(--color-mode);
+}
+:deep(.log_input .el-input__wrapper) {
+  box-shadow: 0 0 0 1px var(--color-select-border) inset;
+  border-radius: 6px;
 }
 </style>

+ 8 - 1
src/views/OperationLog/src/components/BookingTable/src/BookingTable.vue

@@ -5,6 +5,9 @@ import DownloadDialog from './components/DownloadDialog.vue'
 import { autoWidth } from '@/utils/table'
 import { useRowClickStyle } from '@/hooks/rowClickStyle'
 import dayjs from 'dayjs'
+import { useThemeStore } from '@/stores/modules/theme'
+
+const themeStore = useThemeStore()
 
 const props = defineProps({
   height: {
@@ -353,7 +356,11 @@ defineExpose({
     <div class="table-tools">
       <div class="left-total-records">{{ selectedNumber }} Selected</div>
       <div class="right-tools-btn">
-        <el-button class="el-button--main" @click="handleDownload">
+        <el-button
+          :class="{ 'el-button--pain-theme': themeStore.theme === 'dark' }"
+          class="el-button--main"
+          @click="handleDownload"
+        >
           <span style="margin-right: 8px" class="font_family icon-icon_download_b"></span>
           Download
         </el-button>

+ 6 - 3
src/views/OperationLog/src/components/BookingTable/src/components/DownloadDialog.vue

@@ -32,7 +32,7 @@ defineExpose({
 
 <template>
   <div>
-    <el-dialog @close="clearData" v-model="dialogVisible" title="Download File" width="480">
+    <el-dialog @close="clearData" v-model="dialogVisible" title="Download File" width="540">
       <div class="download-dialog">
         <div class="select-data">
           <div style="display: inline-block">
@@ -90,12 +90,14 @@ defineExpose({
   display: flex;
   flex-wrap: wrap;
   gap: 8px;
+  max-height: 120px;
   margin-top: 8px;
+  overflow: auto;
 
   .filter-item {
     height: 22px;
     padding: 0px 8px;
-    background-color: #eceef0;
+    background-color: var(--color-download-file-filter-tag-bg);
     border-radius: 12px;
     line-height: 22px;
     font-size: 12px;
@@ -139,6 +141,7 @@ defineExpose({
     }
 
     .select-columns {
+      max-height: 350px;
       padding: 8px;
       margin-top: 8px;
       background-color: var(--color-header-bg);
@@ -163,7 +166,7 @@ defineExpose({
         .column-item {
           height: 22px;
           padding: 0px 8px;
-          background-color: #eceef0;
+          background-color: var(--color-download-file-selected-column-tag-bg);
           line-height: 22px;
           border-radius: 12px;
           font-size: 12px;

+ 18 - 4
src/views/Tracking/src/TrackingView.vue

@@ -645,11 +645,11 @@ const SearchInput = () => {
         <el-input
           placeholder="Enter Booking/HBL/PO/Container/Carrier Booking No. "
           v-model="TrackingSearch"
-          @keyup.enter="SearchInput"
+          class="log_input"
         >
           <template #prefix>
             <span class="iconfont_icon">
-              <svg class="iconfont" aria-hidden="true">
+              <svg class="iconfont icon_search" aria-hidden="true">
                 <use xlink:href="#icon-icon_search_b"></use>
               </svg>
             </span>
@@ -664,7 +664,7 @@ const SearchInput = () => {
               placement="bottom"
             >
               <span class="iconfont_icon iconfont_icon_tip">
-                <svg class="iconfont" aria-hidden="true">
+                <svg class="iconfont icon_search" aria-hidden="true">
                   <use xlink:href="#icon-icon_info_b"></use>
                 </svg>
               </span>
@@ -760,12 +760,22 @@ const SearchInput = () => {
   flex-wrap: wrap;
 }
 .tag {
-  border-color: #efeff0;
   border-radius: var(--border-radius-22);
   margin: 0 8px 8px 0;
   color: var(--color-neutral-1);
   font-weight: 600;
   font-size: var(--font-size-2);
+  background-color: var(--tag-bg-color) !important;
+}
+.iconfont_icon_tip {
+  margin-left: 8px;
+  width: 16px;
+  height: 16px;
+  display: flex;
+  align-items: center;
+}
+.icon_search {
+  fill: var(--color-neutral-1);
 }
 @media only screen and (min-width: 1280px) {
   .search {
@@ -777,4 +787,8 @@ const SearchInput = () => {
     width: 740px;
   }
 }
+:deep(.log_input .el-input__wrapper) {
+  box-shadow: 0 0 0 1px var(--color-select-border) inset;
+  border-radius: 6px;
+}
 </style>

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

@@ -4,6 +4,27 @@ import { useHeaderSearch } from '@/stores/modules/headerSearch'
 import SlideVerify from './components/SlideVerify.vue'
 import CryptoJS from 'crypto-js'
 import dayjs from 'dayjs'
+import { useThemeStore } from '@/stores/modules/theme'
+
+const themeStore = useThemeStore()
+const publicTrackingRef = ref()
+// 判断当前系统主题模式
+onMounted(() => {
+  watch(
+    () => themeStore.theme,
+    (newVal) => {
+      if (newVal === 'dark') {
+        publicTrackingRef.value.classList.add('dark-bg')
+      } else {
+        publicTrackingRef.value.classList.remove('dark-bg')
+      }
+    },
+    {
+      immediate: true,
+      deep: true
+    }
+  )
+})
 
 const router = useRouter()
 
@@ -91,7 +112,7 @@ const encryptPassword = (password) => {
 </script>
 
 <template>
-  <div class="public-tracking-search" v-vloading="loading">
+  <div class="public-tracking-search" ref="publicTrackingRef" v-vloading="loading">
     <div class="search-info">
       <div class="title">Tracking</div>
       <el-input
@@ -155,6 +176,10 @@ const encryptPassword = (password) => {
   background-size: cover;
   z-index: 1;
   height: 100%;
+  &.dark-bg {
+    background: url(../../../../../Login/src/image/bg-dark.png) no-repeat center center;
+    background-size: cover;
+  }
 }
 
 .public-tracking-search::before {
@@ -164,7 +189,7 @@ const encryptPassword = (password) => {
   left: 0;
   right: 0;
   bottom: 0;
-  background-color: rgba(255, 255, 255, 0.85); /* 半透明白色背景层 */
+  background-color: var(--color-public-tracking-bg-mask); /* 半透明白色背景层 */
   z-index: -1; /* 将伪元素放置在背景图片的下方 */
 }
 
@@ -187,8 +212,8 @@ const encryptPassword = (password) => {
     }
     :deep(.el-input-group__append) {
       padding: 0;
-      background-color: black;
-      border: 1px solid black;
+      background-color: var(--color-public-tracking-search-input-btn);
+      border: 1px solid var(--color-public-tracking-search-input-btn);
       border-radius: 0 6px 6px 0;
       box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
       span {
@@ -217,7 +242,7 @@ const encryptPassword = (password) => {
 }
 .public-tracking-search-input {
   :deep(.el-input__wrapper) {
-    box-shadow: 0 0 0 1px #2b2f36 inset;
+    box-shadow: 0 0 0 1px var(--color-public-tracking-search-input-border) inset;
   }
 }
 </style>

+ 16 - 2
src/views/Tracking/src/components/PublicTracking/src/components/PublicTrackingDetail.vue

@@ -4,10 +4,13 @@ import MilestonesTable from './MilestonesTable.vue'
 import { transportationMode } from '@/components/TransportationMode'
 import { useRoute } from 'vue-router'
 import { useOverflow } from '@/hooks/useOverflow'
+import { useThemeStore } from '@/stores/modules/theme'
 import { formatTimezone } from '@/utils/tools'
 
 const route = useRoute()
 
+const themeStore = useThemeStore()
+
 const allData: any = ref({
   transportInfo: {
     'Tracking No.': '',
@@ -72,7 +75,7 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
 
 <template>
   <div class="tracking-detail">
-    <div class="header">
+    <div class="header" :class="{ 'is-dark': themeStore.theme === 'dark' }">
       <div class="detail-status">
         <span
           class="font_family"
@@ -191,6 +194,16 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
       rgba(224, 247, 249, 0.6) 80.46%,
       rgba(255, 255, 255, 0.3)
     );
+    &.is-dark {
+      background: linear-gradient(
+        270deg,
+        rgba(43, 47, 54, 0.1) 1.88%,
+        rgba(255, 182, 121, 0.1) 15.6%,
+        rgba(118, 145, 255, 0.1) 49.92%,
+        rgba(96, 242, 255, 0.1) 81.78%,
+        rgba(43, 47, 54, 0.1) 97.95%
+      );
+    }
 
     .detail-status {
       position: relative;
@@ -265,6 +278,7 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
           .line_container hr {
             width: 100%;
             border-radius: 0 2px 6px 0;
+            border-color: var(--color-neutral-1);
           }
           .line_container .right-icon {
             position: absolute;
@@ -272,7 +286,7 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
             right: 0px;
             width: 10px;
             height: 11px;
-            border-top: 2px solid #000000;
+            border-top: 2px solid var(--color-neutral-1);
             transform: rotate(30deg);
             border-radius: 0 1px 0 0;
           }

+ 18 - 3
src/views/Tracking/src/components/TrackingDetail/src/TrackingDetail.vue

@@ -14,9 +14,12 @@ import { transportationMode } from '@/components/TransportationMode'
 import { useRoute } from 'vue-router'
 import { useOverflow } from '@/hooks/useOverflow'
 import { formatTimezone } from '@/utils/tools'
+import { useThemeStore } from '@/stores/modules/theme'
 
 const route = useRoute()
 
+const themeStore = useThemeStore()
+
 // 可拖拽模块的列表
 const boxList = ref([
   { id: 1, name: 'Basic Information' },
@@ -113,7 +116,7 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
 
 <template>
   <div class="tracking-detail" v-vloading="loading">
-    <div class="header">
+    <div class="header" :class="{ 'is-dark': themeStore.theme === 'dark' }">
       <div class="detail-status">
         <span
           class="font_family"
@@ -308,6 +311,16 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
       rgba(224, 247, 249, 0.6) 80.46%,
       rgba(255, 255, 255, 0.3)
     );
+    &.is-dark {
+      background: linear-gradient(
+        270deg,
+        rgba(43, 47, 54, 0.1) 1.88%,
+        rgba(255, 182, 121, 0.1) 15.6%,
+        rgba(118, 145, 255, 0.1) 49.92%,
+        rgba(96, 242, 255, 0.1) 81.78%,
+        rgba(43, 47, 54, 0.1) 97.95%
+      );
+    }
 
     .detail-status {
       position: relative;
@@ -395,6 +408,7 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
           .line_container hr {
             width: 100%;
             border-radius: 0 2px 6px 0;
+            border-color: var(--color-neutral-1);
           }
           .line_container .right-icon {
             position: absolute;
@@ -402,7 +416,7 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
             right: 0px;
             width: 10px;
             height: 11px;
-            border-top: 2px solid #000000;
+            border-top: 2px solid var(--color-neutral-1);
             transform: rotate(30deg);
             border-radius: 0 1px 0 0;
           }
@@ -418,6 +432,7 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
       top: 8px;
       right: 16px;
       z-index: 1000;
+      overflow: hidden;
     }
   }
 }
@@ -428,7 +443,7 @@ const { isOverflow: isDestinationOverflow } = useOverflow(destinationRef, allDat
 .fallback-class {
   opacity: 1 !important;
   cursor: move !important;
-  background-color: #fff;
+  background-color: var(--color-v-box-content-drag-bg);
   box-shadow: 4px 4px 32px 0px rgba(0, 0, 0, 0.2);
   border-radius: 12px;
 }

+ 0 - 3
src/views/Tracking/src/components/TrackingDetail/src/components/AttachmentView.vue

@@ -59,9 +59,6 @@ watch(
         }
       ]
       tableData.value.data = attachment.document_data
-      // nextTick(() => {
-      //   tableRef.value && autoWidth(tableData.value, tableRef.value)
-      // })
     }
   },
   {

+ 16 - 7
src/views/Tracking/src/components/TrackingDetail/src/components/EmailDrawer.vue

@@ -207,7 +207,7 @@ const sendEmail = () => {
         @click="handleFocusEditor"
       />
     </div>
-    <div style="border-bottom: 1px solid var(--color-border)">
+    <div style="border-bottom: 1px solid var(--color-divider)">
       <el-button
         @click="sendEmail"
         class="el-button--dark"
@@ -241,7 +241,7 @@ const sendEmail = () => {
   padding: 16px;
   border-radius: 12px;
   border-bottom: 1px solid var(--color-border);
-  background: var(--color-header-bg);
+  background: var(--color-email-bg);
 
   .show-records {
     max-height: 370px;
@@ -251,6 +251,7 @@ const sendEmail = () => {
 
 :deep(.w-e-text-container) {
   min-height: 170px;
+  border-radius: 0 0 6px 6px;
   p {
     margin: 0px;
   }
@@ -278,12 +279,20 @@ const sendEmail = () => {
     color: var(--color-theme);
   }
 }
+.separated-by {
+  :deep(.el-input__wrapper) {
+    box-shadow: 0 0 0 1px var(--color-email-border) inset;
+  }
+}
 
 .text-editor {
   margin-top: 16px;
   border-radius: 6px;
-  border: 1px solid var(--color-border);
-  overflow: hidden;
+  border: 1px solid var(--color-email-border);
+  // overflow: hidden;
+  :deep(div.w-e-toolbar) {
+    border-radius: 6px 6px 0 0;
+  }
 }
 
 .record-item {
@@ -305,7 +314,7 @@ const sendEmail = () => {
       div {
         height: 14px;
         line-height: 14px;
-        color: #fff;
+        color: var(--color-avatar);
         font-weight: 700;
       }
     }
@@ -329,14 +338,14 @@ const sendEmail = () => {
 
   & > .content {
     padding: 16px 6px;
-    background-color: #eceef1;
+    background-color: var(--color-detail-email-record-bg);
     border-radius: 6px;
   }
 }
 
 :deep(.text-editor) {
   & > div:first-of-type {
-    border-bottom: 1px solid var(--color-border) !important;
+    border-bottom: 1px solid var(--color-email-border) !important;
   }
 }
 </style>

+ 409 - 106
src/views/Tracking/src/components/TrackingDetail/src/components/MapView.vue

@@ -1,5 +1,11 @@
 <template>
-  <div id="tracking-map" style="width: 100%; height: 520px" class="tracking-map"></div>
+  <div
+    id="tracking-map"
+    ref="mapContainer"
+    style="width: 100%; height: 520px"
+    class="tracking-map"
+    :class="{ 'dark-mode': themeStore.theme === 'dark' }"
+  ></div>
 </template>
 <script setup lang="ts">
 import L from 'leaflet'
@@ -8,6 +14,10 @@ import OriginIcon from '../images/originIcon.png'
 import TransferIcon from '../images/transferIcon.png'
 import { onMounted, ref, watch } from 'vue'
 import * as turf from '@turf/turf'
+import { mapData } from './mapData'
+import { useThemeStore } from '@/stores/modules/theme'
+
+const themeStore = useThemeStore()
 
 const props = defineProps<{
   serial_no?: string
@@ -45,7 +55,7 @@ const initMap = () => {
     return
   }
 
-  map = L.map('tracking-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', {
@@ -54,8 +64,6 @@ const initMap = () => {
   }).addTo(map)
 }
 
-const track_base_line = ref([])
-const track_first_pt = null
 // 修正经度
 const fixLng = (lng: number) => {
   while (lng > 180) lng = lng - 360
@@ -121,74 +129,84 @@ const getBBox = () => {
   if (bbox3.length > 0) ll.push(bbox3)
   return ll
 }
-const draw_marker = () => {
-  track_base_line.value.forEach((l) => {
-    addMapLine(l, true, false, { color: '#ff7500', weight: 2 })
+let track_added_marker = []
+
+const clear_marker = () => {
+  track_added_marker.forEach((v) => {
+    map!.removeLayer(v)
   })
+
+  track_added_marker = []
 }
-const addMapLine = (l, IsDash, HasArrow, opts) => {
+const draw_marker = (dottedLine = [], solidLine = []) => {
+  clear_marker()
+  dottedLine.forEach((l) => {
+    addMapLine(l, true, { color: '#ff7500', weight: 2 })
+  })
+  solidLine.forEach((l) => {
+    addMapLine(l, false, { color: '#ff7500', weight: 2 })
+  })
+}
+const addMapLine = (l, IsDash, opts) => {
   let mpts = l.pts
   if (mpts == null || mpts.length == 0) return
 
   let bnd = map.getBounds()
   let ww = bnd.getEast() - bnd.getWest()
   let cc = Math.ceil(ww / 360)
-  // let cent_pt = map.getCenter()
-  // let count = Math.ceil(cent_pt.lng / 360)
-
-  // let boxlist = getBBox()
-
-  // let ll = []
-
-  // for (let ii = 0; ii < mpts.length; ii++) {
-  //   ll[ii] = [mpts[ii][1], mpts[ii][0]]
-  // }
-  // let pline = turf.lineString(ll, { name: '' })
-  // let level = map.getZoom()
-  // let options = {
-  //   tolerance:
-  //     Math.round(
-  //       ((level < 8 ? 0.0005 : level < 12 ? 0.00005 : 0) / (level == 0 ? 1 : level)) * 1000000
-  //     ) / 1000000,
-  //   highQuality: false
-  // }
-  // let simplified = turf.simplify(pline, options)
-
-  // let lines_list = []
-  // let clipped: any = simplified
-  // boxlist.forEach((bbox) => {
-  //   let bb = bbox
-  //   clipped = turf.bboxClip(simplified, bb)
-  //   if (clipped != null) {
-  //     if (clipped.geometry.type === 'LineString') {
-  //       let line_pts = clipped.geometry.coordinates
-  //       let pta = []
-  //       let jj = 0
-  //       for (let ii = 0; ii < line_pts.length; ii++) {
-  //         pta[jj++] = [line_pts[ii][1], line_pts[ii][0]]
-  //       }
-  //       lines_list.push(pta)
-  //     } else if (clipped.geometry.type === 'MultiLineString') {
-  //       clipped.geometry.coordinates.forEach((_pts) => {
-  //         let line_pts = _pts
-  //         let pta = []
-  //         let jj = 0
-  //         for (let ii = 0; ii < line_pts.length; ii++) {
-  //           pta[jj++] = [line_pts[ii][1], line_pts[ii][0]]
-  //         }
-  //         lines_list.push(pta)
-  //       })
-  //     }
-  //   }
-  // })
+
+  let boxlist = getBBox()
+
+  let ll = []
+
+  for (let ii = 0; ii < mpts.length; ii++) {
+    ll[ii] = [mpts[ii][1], mpts[ii][0]]
+  }
+  let pline = turf.lineString(ll, { name: '' })
+  let level = map.getZoom()
+  let options = {
+    tolerance:
+      Math.round(
+        ((level < 8 ? 0.0005 : level < 12 ? 0.00005 : 0) / (level == 0 ? 1 : level)) * 1000000
+      ) / 1000000,
+    highQuality: false
+  }
+  let simplified = turf.simplify(pline, options)
+
+  let lines_list = []
+  let clipped: any = simplified
+  boxlist.forEach((bbox) => {
+    let bb = bbox
+    clipped = turf.bboxClip(simplified, bb)
+    if (clipped != null) {
+      if (clipped.geometry.type === 'LineString') {
+        let line_pts = clipped.geometry.coordinates
+        let pta = []
+        let jj = 0
+        for (let ii = 0; ii < line_pts.length; ii++) {
+          pta[jj++] = [line_pts[ii][1], line_pts[ii][0]]
+        }
+        lines_list.push(pta)
+      } else if (clipped.geometry.type === 'MultiLineString') {
+        clipped.geometry.coordinates.forEach((_pts) => {
+          let line_pts = _pts
+          let pta = []
+          let jj = 0
+          for (let ii = 0; ii < line_pts.length; ii++) {
+            pta[jj++] = [line_pts[ii][1], line_pts[ii][0]]
+          }
+          lines_list.push(pta)
+        })
+      }
+    }
+  })
 
   let cc1 = Math.floor(bnd.getWest() / 360)
   let cc2 = Math.ceil(bnd.getEast() / 360)
   cc = cc2 - cc1 + 1
 
   let kk = cc1
-  // let llIndex = 0
-  let lines_list = [mpts]
+  // let lines_list = [mpts]
   while (kk >= cc1 && kk <= cc2 && cc > 0) {
     lines_list.forEach((a) => {
       let ii = 0
@@ -197,16 +215,15 @@ const addMapLine = (l, IsDash, HasArrow, opts) => {
       for (ii = 0; ii < a.length; ii++) pts[jj++] = [a[ii][0], a[ii][1] + kk * 360]
 
       if (jj > 0) {
-        if (IsDash)
+        if (IsDash) {
           showTrackLine(
             pts,
             jj,
-            Object.assign({}, { color: '#ff7500', dashArray: '10', weight: 2 }, opts),
-            HasArrow
+            Object.assign({}, { color: '#ff7500', dashArray: '10', weight: 2 }, opts)
           )
-        else
-          showTrackLine(pts, jj, Object.assign({}, { color: '#ff7500', weight: 1 }, opts), HasArrow)
-        // llIndex++
+        } else {
+          showTrackLine(pts, jj, Object.assign({}, { color: '#ff7500', weight: 1 }, opts))
+        }
       }
     })
 
@@ -215,34 +232,9 @@ const addMapLine = (l, IsDash, HasArrow, opts) => {
   }
 }
 
-const showTrackLine = (pts, jj, opts, HasArrow) => {
+const showTrackLine = (pts, jj, opts) => {
   let arrow = L.polyline(pts, Object.assign({}, { color: '#ff7500', weight: 2 }, opts)).addTo(map)
-
-  // if (HasArrow) {
-  //   let arrowHead = L.polylineDecorator(arrow, {
-  //     patterns: [
-  //       {
-  //         offset: 0,
-  //         repeat: 25,
-  //         symbol: L.Symbol.arrowHead({
-  //           pixelSize: 10,
-  //           pathOptions: Object.assign({}, { color: '#ff7500', fillOpacity: 0.5, weight: 0.8 }, opts)
-  //         })
-  //       }
-  //     ]
-  //   }).addTo(map)
-  // }
-}
-
-const test = () => {
-  track_base_line.value = mapData
-  draw_marker()
-  // map.on('moveend', function (e) {
-  //   draw_marker()
-  // })
-  // map.on('zoomend', function (e) {
-  //   draw_marker()
-  // })
+  track_added_marker.push(arrow)
 }
 
 const addResetZoomButton = (center: L.LatLng, zoom: number) => {
@@ -280,10 +272,14 @@ let initialCenter: L.LatLng | null = null
 let initialZoomLevel: number | null = null
 let isFirstRender = true // 标记是否为首次渲染
 
+let allMarkers = []
+let visibleMarkers = new Set()
+
 // 添加标记后更新中心和缩放级别
 const addMarkersToMap = () => {
+  // debugger
   if (!map) return // 确保地图已经初始化
-  const latLngBounds: any = [] // 用来存储所有标记的坐标
+
   markerPositions.value.forEach((position) => {
     const marker = L.marker([position.lat, position.lng], { icon: position.icon }).addTo(map)
 
@@ -303,11 +299,14 @@ const addMarkersToMap = () => {
         closeOnClick: false
       })
       .openPopup()
-    latLngBounds.push([position.lat, position.lng])
+    allMarkers[`${position.lat},${position.lng}`] = marker
   })
 
-  if (latLngBounds.length > 0) {
-    const bounds = L.latLngBounds(latLngBounds)
+  updateVisibleMarkers()
+
+  if (viewData.value.length > 0) {
+    // 根据标记的位置设置中心点以及缩放级别
+    const bounds = L.latLngBounds(viewData.value)
     map!.fitBounds(bounds, { paddingTopLeft: [20, 70], paddingBottomRight: [400, 0] })
     setTimeout(() => {
       if (isFirstRender) {
@@ -320,6 +319,153 @@ const addMarkersToMap = () => {
   }
 }
 
+// 新增轮船当前位置标记
+const addShipMarker = (x: number) => {
+  const solidLine = allMapData.value.solidLine
+  // 如果轮船还未出发,则显示起点轮船标记
+  if (solidLine.length === 0) {
+    // 创建轮船图标
+    const arrowIcon = L.divIcon({
+      html: `
+        <div class="container">
+          <div class="circle"></div>
+          <span style="padding: 0; color:white; border:1px solid white" class="font_family icon-icon_ocean_b"></span>
+        </div>
+        `,
+      className: 'arrow-icon',
+      iconSize: [50, 50],
+      iconAnchor: [25, 25], // 箭头的中心点
+      popupAnchor: [0, -25] // 弹出框的锚点
+    })
+
+    let curMarkerLocation = markerPositions.value.find((item) => item.label === 'Origin')
+    const arrowMarker = L.marker([curMarkerLocation.lat, curMarkerLocation.lng + x * 360], {
+      icon: arrowIcon
+    }).addTo(map)
+    track_added_marker.push(arrowMarker)
+  } else if (solidLine.length > 0) {
+    // 如果轮船已经出发,则显示轮船当前位置标记
+    // 如果线段至少有两个点,才添加箭头
+    // 获取线段的最后一个点和倒数第二个点
+    const lastPoint = solidLine[solidLine.length - 1]
+    const secondLastPoint = solidLine[solidLine.length - 2]
+    console.log(lastPoint, secondLastPoint, 'lastPoint, secondLastPoint')
+    // 计算线段末端的角度(以弧度为单位)
+    const angle =
+      (Math.atan2(
+        Number(lastPoint.lon) - Number(secondLastPoint.lon), // Δlon (x)
+        Number(lastPoint.lat) - Number(secondLastPoint.lat) // Δlat (y)
+      ) *
+        (180 / Math.PI) +
+        360) %
+      360
+    // 创建自定义箭头图标
+    const arrowIcon = L.divIcon({
+      html: `
+      <div style="transform: rotate(${angle}deg);" class="container">
+        <div class="circle"></div>
+        <span style="color:white;border:1px solid white" class="font_family icon-icon_arrow_b"></span>
+      </div>
+      `,
+      className: 'arrow-icon',
+      iconSize: [50, 50],
+      iconAnchor: [25, 25], // 箭头的中心点
+      popupAnchor: [0, -25] // 弹出框的锚点
+    })
+    // 创建箭头标记,并根据计算出的角度旋转箭头
+    const arrowMarker = L.marker([Number(lastPoint.lat), Number(lastPoint.lon) + x * 360], {
+      icon: arrowIcon
+    }).addTo(map)
+    // 将箭头标记也存储在 track_added_marker 数组中,以便后续管理
+    track_added_marker.push(arrowMarker)
+  }
+}
+
+// 更新可见标记
+const updateVisibleMarkers = () => {
+  const newVisibleMarkers = new Set()
+
+  let bnd = map.getBounds()
+  let ww = bnd.getEast() - bnd.getWest()
+
+  let cc = Math.ceil(ww / 360)
+
+  let cc1 = Math.floor(bnd.getWest() / 360)
+  let cc2 = Math.ceil(bnd.getEast() / 360)
+  cc = cc2 - cc1 + 1
+
+  let x = cc1
+
+  // 移除不再可见的标记
+  visibleMarkers.forEach((marker: any) => {
+    if (!newVisibleMarkers.has(marker)) {
+      map.removeLayer(marker)
+      delete allMarkers[`${marker.getLatLng().lat},${marker._lng},${marker._x}`]
+    }
+  })
+
+  // 计算当前视图中的标记,包括多地球的情况
+  while (x >= cc1 && x <= cc2 && cc > 0) {
+    Object.values(allMarkers).forEach((marker) => {
+      const latLng = marker.getLatLng()
+      const key = `${latLng.lat},${latLng.lng},${x}`
+      if (!allMarkers[key]) {
+        const newMarker: any = L.marker([latLng.lat, latLng.lng + x * 360], {
+          icon: marker.options.icon
+        })
+          .bindPopup(marker.getPopup().getContent(), marker.getPopup().options)
+          .openPopup()
+        newMarker._x = x
+        // 使用原始的经度作为标记的唯一标识
+        newMarker._lng = latLng.lng
+        allMarkers[key] = newMarker
+        map.addLayer(newMarker)
+      }
+      newVisibleMarkers.add(allMarkers[key])
+    })
+
+    addShipMarker(x)
+
+    x++
+    cc--
+  }
+
+  // 更新可见标记集合
+  visibleMarkers = newVisibleMarkers
+}
+
+// 处理得到的数据
+const handleData = (data) => {
+  let key = 0
+  let curLine = []
+  let resultLine = []
+  data.forEach((item, index) => {
+    if (item.sn === '1' && key === 0) {
+      key++
+      curLine.push([Number(item.lat), Number(item.lon)])
+    } else if (item.sn === '1' && key !== 0) {
+      resultLine.push({
+        name: key,
+        pts: curLine
+      })
+      curLine = [[Number(item.lat), Number(item.lon)]]
+      key++
+    }
+    if (item.sn !== '1') {
+      curLine.push([Number(item.lat), Number(item.lon)])
+    }
+    if (index === data.length - 1 && item.sn !== '1') {
+      resultLine.push({
+        name: key,
+        pts: curLine
+      })
+    }
+  })
+  return resultLine
+}
+
+const allMapData = ref()
+const viewData = ref([])
 // 请求接口并处理标记
 const getMarker = () => {
   $api
@@ -329,9 +475,10 @@ const getMarker = () => {
     })
     .then((res) => {
       if (res.code === 200) {
+        allMapData.value = res.data
         const { data } = res
-        data &&
-          data.forEach((item) => {
+        data?.point &&
+          data?.point.forEach((item) => {
             const iconColorList = {
               Destination: { color: '#24ca5a', icon: destinationIcon },
               Origin: { color: '#ED6D00', icon: originIcon },
@@ -339,15 +486,31 @@ const getMarker = () => {
             }
             markerPositions.value.push({
               lat: item.lat,
-              lng: item.lng,
+              lng: (Number(item.lng) + 360) % 360,
               city: item.infor,
               label: item.label,
               icon: iconColorList[item.label].icon,
               iconColor: iconColorList[item.label].color
             })
           })
+        viewData.value = (data?.rangePoint.length > 0 ? data?.rangePoint : data?.point)?.map(
+          (item) => {
+            return [Number(item.lat), (Number(item.lon || item.lng) + 360) % 360]
+          }
+        )
         // 请求成功后添加标记,并动态添加重置按钮
         addMarkersToMap()
+        if (data?.dottedLine) {
+          draw_marker(handleData(data.dottedLine), handleData(data.solidLine))
+          map.on('moveend', function () {
+            draw_marker(handleData(data.dottedLine), handleData(data.solidLine))
+            updateVisibleMarkers()
+          })
+          map.on('zoomend', function () {
+            draw_marker(handleData(data.dottedLine), handleData(data.solidLine))
+            updateVisibleMarkers()
+          })
+        }
       }
     })
 }
@@ -367,6 +530,10 @@ watch(
 onMounted(() => {
   initMap() // 初始化地图,不加标记
 })
+
+onUnmounted(() => {
+  map?.remove()
+})
 </script>
 
 <style lang="scss">
@@ -387,12 +554,13 @@ onMounted(() => {
           margin-left: -2px;
           font-size: 12px;
           font-weight: 700;
+          color: #2b2f36;
         }
       }
       .label {
         margin-bottom: 4px;
         font-size: 12px;
-        color: let(--color-neutral-2);
+        color: #646a73;
       }
     }
   }
@@ -401,19 +569,91 @@ onMounted(() => {
   .leaflet-popup-tip {
     display: none;
   }
-  .transport-map {
-    .leaflet-touch {
-      .leaflet-bar {
-        border: 0;
-        border-radius: 4px;
-        overflow: hidden;
+
+  .leaflet-control-zoom {
+    span {
+      color: #2b2f36;
+    }
+  }
+}
+.leaflet-control {
+  a.leaflet-control-zoom-in,
+  a.leaflet-control-zoom-out,
+  a.leaflet-bar-part {
+    width: 26px;
+    height: 26px;
+    font-size: 18px;
+  }
+}
+.dark-mode {
+  div.leaflet-control-zoom.leaflet-bar.leaflet-control {
+    border: 0;
+    border-radius: 4px;
+    box-shadow: none;
+    a {
+      background-color: #3c414a;
+      border-bottom: none;
+      span {
+        color: var(--color-neutral-1);
+      }
+      &:first-child {
+        span {
+          display: inline-block;
+          width: 24px;
+          border-bottom: 2px solid #575c64;
+        }
       }
     }
   }
+  .reset-zoom-control {
+    border: none;
+    background-color: #3c414a;
+  }
+  a.leaflet-bar-part {
+    background-color: #3c414a;
+    border-radius: 4px;
+    box-shadow: none;
+    overflow: hidden;
+    div {
+      border-color: var(--color-neutral-1) !important;
+      div {
+        background-color: var(--color-neutral-1) !important;
+      }
+    }
+  }
+}
+
+/* 示例:将所有地图图片的颜色反转 */
+.dark-mode img:not(.leaflet-marker-icon) {
+  filter: invert(1) hue-rotate(170deg);
+}
+// 防止暗黑模式下地图超出容器
+.tracking-map {
+  overflow: hidden;
+}
+// 修改暗黑模式下的背景色
+.leaflet-container.dark-mode,
+.leaflet-map-pane.dark-mode,
+.leaflet-tile-container.dark-mode {
+  background-color: #2b2f36;
+}
+// 处理版权信息在切换模式后样式错误bug
+.leaflet-right .leaflet-control-attribution {
+  background: rgba(255, 255, 255, 0.8);
+  margin: 0 4px 4px 0;
+  color: #2b2f36;
+  span {
+    font-size: 12px;
+    color: #2b2f36;
+  }
+  a {
+    color: #0078a8;
+    font-size: 12px;
+  }
 }
 /* 自定义重置缩放按钮控件样式 */
 .reset-zoom-control {
-  margin-top: 10px; /* 增加上边距,使按钮与默认缩放按钮之间有间距 */
+  margin-top: 10px;
   border-radius: 4px;
   background-color: white;
   border: 1px solid #ccc;
@@ -427,3 +667,66 @@ onMounted(() => {
   padding: 6px;
 }
 </style>
+
+<style lang="scss">
+.tracking-map {
+  .container {
+    position: relative;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    height: 50px;
+    width: 50px;
+    /* background-color: #d9dddf; */
+    .font_family {
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-12px, -12px);
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      width: 24px;
+      height: 24px;
+      padding-bottom: 2px;
+      padding-left: 1px;
+      color: white;
+      background-color: rgba(255, 117, 0, 1);
+      border-radius: 50%;
+      font-size: 14px;
+      border: 1px solid white;
+    }
+  }
+  .circle {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 24px;
+    height: 24px;
+    background-color: rgba(255, 117, 0, 1);
+    border-radius: 50%;
+    position: relative;
+    animation: expandAndFade 1.3s linear infinite;
+    overflow: hidden; /* 确保子元素不会溢出 */
+
+    opacity: 0.9;
+  }
+
+  @keyframes expandAndFade {
+    0% {
+      transform: scale(1);
+      opacity: 0.9;
+    }
+
+    50% {
+      transform: scale(1.5);
+      opacity: 0.7;
+    }
+
+    100% {
+      transform: scale(2);
+      opacity: 0.2;
+    }
+  }
+}
+</style>

+ 9 - 8
src/views/Tracking/src/components/TrackingDetail/src/components/RoutesView.vue

@@ -233,9 +233,9 @@ const { isOverflow: isDetailDestinationOverflow } = useOverflow(detailDestinatio
   height: 80px;
   cursor: pointer;
   &:hover {
-    background-color: #fef8f3;
+    background-color: var(--color-tracking-routes-item-bg);
     .serial-number {
-      background-color: #f6f2ee;
+      background-color: var(--color-tracking-routes-item-leg-bg);
     }
   }
   .serial-number {
@@ -357,16 +357,16 @@ const { isOverflow: isDetailDestinationOverflow } = useOverflow(detailDestinatio
     margin-left: 8px;
   }
   .line_container hr {
-    border-color: #484c52;
+    border-color: var(--color-neutral-1);
     border-top: none;
   }
 
   .line_container .right-icon {
-    border-top: 1px solid #484c52;
-    border-radius: 0 1px 1px 0;
-    top: -2px;
+    border-top: 2px solid var(--color-neutral-1);
+    border-radius: 0 2px 2px 0px;
+    top: -4px;
     right: 0px;
-    width: 10px;
+    width: 12px;
     height: 12px;
   }
   .date-info {
@@ -487,6 +487,7 @@ const { isOverflow: isDetailDestinationOverflow } = useOverflow(detailDestinatio
   width: 100%;
   min-width: 16px;
   border-radius: 0 2px 6px 0;
+  border-color: var(--color-neutral-1);
 }
 
 .line_container .right-icon {
@@ -495,7 +496,7 @@ const { isOverflow: isDetailDestinationOverflow } = useOverflow(detailDestinatio
   right: 0px;
   width: 10px;
   height: 11px;
-  border-top: 2px solid #000000;
+  border-top: 2px solid var(--color-neutral-1);
   transform: rotate(30deg);
   border-radius: 0 1px 0 0;
 }

+ 4 - 2
src/views/Tracking/src/components/TrackingDetail/src/components/TransportStep.vue

@@ -43,9 +43,10 @@ const handleTabClick = (name: string) => {
 .transport-step {
   width: 400px;
   height: 484px;
-  background-color: #fff;
-  border: 1px solid #eaebed;
+  background-color: var(--color-header-bg);
   border-radius: 12px;
+  border: 1px solid var(--color-border);
+  box-shadow: -2px 2px 12px 0px var(--color-shipment-status-shadow);
   .header {
     display: flex;
     height: 48px;
@@ -67,6 +68,7 @@ const handleTabClick = (name: string) => {
   }
   .content {
     height: calc(100% - 48px);
+    background-color: var(--color-mode);
   }
 }
 </style>

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

@@ -7,6 +7,9 @@ import { useRouter } from 'vue-router'
 import { ref, onMounted } from 'vue'
 import { transportationMode } from '@/components/TransportationMode'
 import { useLoadingState } from '@/stores/modules/loadingState'
+import { useThemeStore } from '@/stores/modules/theme'
+
+const themeStore = useThemeStore()
 
 const router = useRouter()
 const props = defineProps({
@@ -520,7 +523,11 @@ defineExpose({
     <div class="table-tools">
       <div class="left-total-records">{{ selectedNumber }} Selected</div>
       <div class="right-tools-btn">
-        <el-button class="el-button--main" @click="handleDownload">
+        <el-button
+          class="el-button--main"
+          :class="{ 'el-button--pain-theme': themeStore.theme === 'dark' }"
+          @click="handleDownload"
+        >
           <span style="margin-right: 8px" class="font_family icon-icon_download_b"></span>
           Download
         </el-button>

+ 7 - 4
src/views/Tracking/src/components/TrackingTable/src/components/DownloadDialog.vue

@@ -34,7 +34,7 @@ defineExpose({
 
 <template>
   <div>
-    <el-dialog @close="clearData" v-model="dialogVisible" title="Download File" width="480">
+    <el-dialog @close="clearData" v-model="dialogVisible" title="Download File" width="540">
       <div class="download-dialog">
         <div class="select-data">
           <div style="display: inline-block">
@@ -95,12 +95,14 @@ defineExpose({
   display: flex;
   flex-wrap: wrap;
   gap: 8px;
+  max-height: 120px;
   margin-top: 8px;
+  overflow: auto;
 
   .filter-item {
     height: 22px;
     padding: 0px 8px;
-    background-color: #eceef0;
+    background-color: var(--color-download-file-filter-tag-bg);
     border-radius: 12px;
     line-height: 22px;
     font-size: 12px;
@@ -144,11 +146,12 @@ defineExpose({
     }
 
     .select-columns {
+      max-height: 350px;
       padding: 8px;
       margin-top: 8px;
       background-color: var(--color-header-bg);
       border-radius: 6px;
-      overflow: hidden;
+      overflow: auto;
 
       &.show {
         max-height: 500px;
@@ -168,7 +171,7 @@ defineExpose({
         .column-item {
           height: 22px;
           padding: 0px 8px;
-          background-color: #eceef0;
+          background-color: var(--color-download-file-selected-column-tag-bg);
           line-height: 22px;
           border-radius: 12px;
           font-size: 12px;