Explorar el Código

feat: 实现delivery 日历样式和功能

Jack Zhou hace 1 mes
padre
commit
dded38e3c2

+ 16 - 0
src/api/module/Delivery.ts

@@ -333,4 +333,20 @@ export const downloadBookingTableFile = (params: any, config: any) => {
     },
     config
   )
+}
+
+
+/**
+ * 获取delivery calendar view日历数据
+ */
+export const getDeliveryCalendarData = (params: any, config: any) => {
+  return HttpAxios.post(
+    `${baseUrl}`,
+    {
+      action: 'destination_delivery_booking',
+      operate: 'search_calendar',
+      ...params
+    },
+    config
+  )
 }

+ 0 - 8
src/router/index.ts

@@ -212,14 +212,6 @@ const router = createRouter({
           }
         },
         {
-          path: '/destination-delivery/modify-booking',
-          name: 'Modify Booking',
-          component: () => import('../views/DestinationDelivery/src/components/ModifyBooking'),
-          meta: {
-            breadName: 'Modify Booking',
-            activeMenu: '/destination-delivery'
-          }
-        }, {
           path: '/demo-video',
           name: 'Demo Video',
           component: () => import('../views/Video'),

+ 1 - 5
src/styles/Antdui.scss

@@ -43,11 +43,7 @@
 .ant-picker-dropdown .ant-picker-cell-in-view.ant-picker-cell-in-range {
   color: var(--color-theme);
 }
-.ant-picker-cell:hover:not(.ant-picker-cell-in-view).ant-picker-cell-inner,
-.ant-picker-cell:hover:not(.ant-picker-cell-selected):not(.ant-picker-cell-range-start)
-  :not(.ant-picker-cell-range-end):not(.ant-picker-cell-range-hover-start):not(
-    .ant-picker-cell-range-hover-end
-  ) {
+.ant-picker-cell:hover:not(.ant-picker-cell-in-view):not(.custom-delivery-calendar .ant-picker-cell) {
   background-color: var(--color-orange-6) !important;
   color: var(--color-theme);
 }

+ 50 - 0
src/styles/theme.scss

@@ -369,6 +369,31 @@
   --color-el-segmented-bg: #f1f5f9;
 
   --color-calendar-cell-bg: #fff;
+
+  --color-delivery-calendar-booking-sign-bg:rgba(130, 0, 218, 0.1);
+  --color-delivery-calendar-booking-sign-border: rgba(130, 0, 218, 0.3);
+  --color-delivery-calendar-booking-label-text: #646a73;
+  --color-calendar-booking-tag-bg: rgba(130, 0, 218, 0.1);
+   --color-calendar-booking-tag-text: #8200da;
+  --color-calendar-booking-tag-label-text: rgba(130, 0, 218, 0.5);
+  
+  --color-delivery-calendar-delivery-date-sign-bg:rgba(20, 71, 230, 0.1);
+  --color-delivery-calendar-delivery-date-sign-border: rgba(20, 71, 230, 0.3);
+  --color-delivery-calendar-delivery-date-label-text: #646a73;
+  --color-calendar-delivery-tag-bg: rgba(20, 71, 230, 0.1);
+  --color-calendar-delivery-tag-border: rgba(20, 71, 230, 0.3);
+  --color-calendar-delivery-tag-text: #1447e6;
+  --color-calendar-delivery-tag-label-text: rgba(20, 71, 230, 0.5);
+  
+  --color-delivery-calendar-ends-sign-bg:rgba(130, 0, 218, 0.1);
+  --color-delivery-calendar-ends-sign-border: rgba(193, 0, 8, 0.7);
+  --color-delivery-calendar-ends-label-text: #c10008;
+  --color-calendar-ending-tag-bg: rgba(193, 0, 8, 0.1);
+  --color-calendar-ending-tag-border: rgba(193, 0, 8, 0.7);
+  --color-calendar-ending-tag-text: #c10008;
+
+  --color-calendar-disabled-date-text: #b5b9bf;
+  --color-delivery-calendar-th-bg: #f6f8fa;
 }
 
 :root.dark {
@@ -608,5 +633,30 @@
   --color-el-segmented-bg: #374151;
 
   --color-calendar-cell-bg: #30353c;
+  
+  --color-delivery-calendar-booking-sign-bg:rgba(130, 0, 218, 0.2);
+  --color-delivery-calendar-booking-sign-border: rgba(153, 1, 255, 0.7);
+  --color-delivery-calendar-booking-label-text: rgba(240, 241, 243, 0.70);
+  --color-calendar-booking-tag-bg: rgba(153, 1, 255, 0.2);
+  --color-calendar-booking-tag-text: #fff;
+  --color-calendar-booking-tag-label-text: rgba(255,255,255,0.5);
+  
+  --color-delivery-calendar-delivery-date-sign-bg:rgba(31, 85, 255, 0.3);
+  --color-delivery-calendar-delivery-date-sign-border: rgba(31, 85, 255, 0.7);
+  --color-delivery-calendar-delivery-date-label-text: rgba(240, 241, 243, 0.70);
+  --color-calendar-delivery-tag-bg: rgba(31, 85, 255, 0.3);
+  --color-calendar-delivery-tag-border: rgba(31, 85, 255, 0.7);
+  --color-calendar-delivery-tag-text: #fff;
+  --color-calendar-delivery-tag-label-text: rgba(255,255,255,0.5);
+  
+  --color-delivery-calendar-ends-sign-bg:rgba(255, 18, 28, 0.2);
+  --color-delivery-calendar-ends-sign-border: rgba(255, 18, 28, 0.5);
+  --color-delivery-calendar-ends-label-text: rgba(255, 18, 28, 0.80);
+  --color-calendar-ending-tag-bg: rgba(255, 18, 28, 0.2);
+  --color-calendar-ending-tag-border: rgba(255, 18, 28, 0.5);
+  --color-calendar-ending-tag-text: #fff;
+
+  --color-calendar-disabled-date-text: rgba(240, 241, 243, 0.3);
+  --color-delivery-calendar-th-bg: #343a43;
 }
   

+ 11 - 5
src/views/DestinationDelivery/src/DestinationDelivery.vue

@@ -46,7 +46,7 @@ const directionOptions = [
       </div>
     </div>
     <div class="page-type">
-      <el-segmented v-model="pageType" :options="directionOptions" style="margin-bottom: 1rem">
+      <el-segmented v-model="pageType" :options="directionOptions">
         <template #default="scope">
           <div class="flex-center">
             <span
@@ -67,21 +67,27 @@ const directionOptions = [
 <style lang="scss" scoped>
 .destination-delivery {
   position: relative;
+  padding-bottom: 40px;
   background-color: var(--color-mode);
 }
 .header {
+  position: sticky;
+  top: 0;
+  z-index: 100;
   display: flex;
+  align-items: center;
+  justify-content: space-between;
   height: 68px;
+  padding: 0 24px;
   border-bottom: 1px solid var(--color-border);
   font-size: var(--font-size-6);
   font-weight: 700;
-  padding: 0 24px;
-  align-items: center;
-  justify-content: space-between;
+  background-color: var(--color-mode);
 }
 .page-type {
-  margin: 24px;
+  margin: 10px 24px;
   .el-segmented {
+    height: 40px;
     --el-segmented-item-selected-color: var(--color-neutral-1);
     --el-segmented-item-selected-bg-color: var(--color-el-segmented-checked-bg);
     --el-segmented-bg-color: var(--color-el-segmented-bg);

+ 191 - 0
src/views/DestinationDelivery/src/components/CalendarTagDetailDialog.vue

@@ -0,0 +1,191 @@
+<script setup lang="ts">
+import { autoWidth } from '@/utils/table'
+import { type VxeGridInstance, type VxeGridProps } from 'vxe-table'
+import { useRowClickStyle } from '@/hooks/rowClickStyle'
+import dayjs from 'dayjs'
+
+const dialogVisible = ref(false)
+
+const props = defineProps({
+  data: Object
+})
+const tableData = ref<VxeGridProps<any>>({
+  minHeight: 150,
+  maxHeight: 420,
+  border: true,
+  round: true,
+  columns: [],
+  data: [],
+  cellConfig: {
+    height: 40
+  },
+  headerCellConfig: {
+    height: 40
+  },
+  scrollY: { enabled: true, oSize: 20, gt: 30 },
+  emptyText: ' ',
+  showHeaderOverflow: true,
+  showOverflow: true,
+  headerRowStyle: {
+    backgroundColor: 'var(--color-table-header-bg)'
+  },
+  columnConfig: { resizable: true, useKey: true },
+  rowConfig: { isHover: true }
+})
+const tableRef = ref<VxeGridInstance | null>(null)
+// 实现行点击样式
+useRowClickStyle(tableRef)
+
+const columns = [
+  {
+    title: 'HBOL No.',
+    field: 'h_bol'
+  },
+  {
+    title: 'MBL No.',
+    field: 'm_bol'
+  },
+  {
+    title: 'Container No.',
+    field: 'ctnr'
+  },
+  {
+    title: 'Service Type',
+    field: 'service_type'
+  },
+  {
+    title: 'PO No.',
+    field: 'po_no'
+  },
+  {
+    title: 'Reference No.',
+    field: 'referebce_no'
+  },
+  {
+    title: 'Mode',
+    field: 'transport_mode'
+  },
+  {
+    title: 'Packages',
+    field: 'packages'
+  }
+]
+const handleColumns = (columns: any) => {
+  const newColumns = columns.map((item: any) => {
+    let curColumn: any = {
+      title: item.title,
+      field: item.field,
+      minWidth: 30
+    }
+
+    if (item.field === 'file') {
+      curColumn = {
+        ...curColumn,
+        slots: { default: 'file' }
+      }
+    }
+    return curColumn
+  })
+  return newColumns
+}
+
+tableData.value.columns = handleColumns(columns)
+const title = ref('')
+const pageData = ref()
+const tagType = ref()
+const openDialog = (type, date, data) => {
+  console.log(type, date, 'openDialog', data)
+  dialogVisible.value = true
+  pageData.value = data
+  tagType.value = type
+  if (type === 'ending') {
+    tableData.value.data = data['endingDetail']
+  } else if (type === 'delivery') {
+    title.value = `Recommended Delivery Shipments for ${dayjs(date).format('YYYY-MM-DD')}`
+    tableData.value.data = data['shipmentDetail']
+  }
+}
+
+defineExpose({
+  openDialog
+})
+</script>
+
+<template>
+  <div>
+    <el-dialog v-model="dialogVisible" width="1000px">
+      <template #header>
+        <div class="header-content">
+          <span class="title">{{ title }}</span>
+          <div class="ending-tag tag-style">
+            <span
+              class="font_family icon-icon_delay_b1"
+              style="margin-right: 3px; font-size: 13px"
+            ></span>
+            <span class="type">1 Free Storage Period Ends</span>
+          </div>
+        </div>
+      </template>
+      <span style="display: inline-block; color: var(--color-neutral-2)"
+        >Total:
+        {{ tagType === 'delivery' ? pageData.shipmentNumber : pageData.endingNumber }}
+        shipments</span
+      >
+      <span style="color: var(--color-neutral-2)"> | </span>
+      <span style="color: var(--color-neutral-2)"
+        >Total Cartons:
+        {{ tagType === 'delivery' ? pageData.shipmentCtns : pageData.endingCtns }} ctns</span
+      >
+      <vxe-grid style="margin-top: 8px" ref="tableRef" v-bind="tableData">
+        <template #empty>
+          <div class="empty">No data</div>
+        </template>
+      </vxe-grid>
+    </el-dialog>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.header-content {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  .title {
+    font-size: 18px;
+    font-weight: 700;
+  }
+}
+
+.ending-tag {
+  height: 24px;
+  width: auto;
+  border: 0.5px dashed var(--color-calendar-ending-tag-border);
+  background-color: var(--color-calendar-ending-tag-bg);
+  .font_family,
+  .type,
+  .ctns-tag {
+    color: var(--color-calendar-ending-tag-text) !important;
+  }
+  .ctns-tag {
+    background-color: var(--color-calendar-ending-tag-bg);
+  }
+}
+.tag-style {
+  display: flex;
+  align-items: center;
+  padding-left: 6px;
+  padding-right: 4px;
+  height: 24px;
+  border-radius: 3px;
+  overflow: hidden;
+
+  .font_family {
+    margin-right: 4px;
+  }
+  .type {
+    font-size: 10px;
+    font-weight: 700;
+    line-height: 16px;
+  }
+}
+</style>

+ 347 - 102
src/views/DestinationDelivery/src/components/CalendarView.vue

@@ -1,79 +1,232 @@
 <script setup lang="ts">
-import { ref } from 'vue'
+import { ref, computed } from 'vue'
 import type { Dayjs } from 'dayjs'
 import dayjs from 'dayjs'
+import CalendarTagDetailDialog from './CalendarTagDetailDialog.vue'
 
-const value = ref<Dayjs>(dayjs())
-
-// ✅ 修正:精确匹配年月日
-const getListData = (value: Dayjs) => {
-  let listData
-  switch (value.date()) {
-    case 8:
-      listData = [
-        { type: 'warning', content: 'This is warning event.' },
-        { type: 'success', content: 'This is usual event.' }
-      ]
-      break
-    case 10:
-      listData = [
-        { type: 'warning', content: 'This is warning event.' },
-        { type: 'success', content: 'This is usual event.' },
-        { type: 'error', content: 'This is error event.' }
-      ]
-      break
-    case 15:
-      listData = [
-        { type: 'warning', content: 'This is warning event' },
-        { type: 'success', content: 'This is very long usual event。。....' },
-        { type: 'error', content: 'This is error event 1.' },
-        { type: 'error', content: 'This is error event 2.' },
-        { type: 'error', content: 'This is error event 3.' },
-        { type: 'error', content: 'This is error event 4.' }
-      ]
-      break
-    default:
-  }
-  return listData || []
-}
-
-const getMonthData = (current: Date) => {
-  if (current.getFullYear() === 2026 && current.getMonth() === 8) {
-    return 1394
-  }
-  return null
+// 控制日历显示的月份(受控状态)
+const displayMonth = ref<Dayjs>(dayjs())
+
+// 年份选项
+const yearOptions = computed(() => {
+  const currentYear = new Date().getFullYear()
+  const startYear = 1100 // 你可以改成任意起始年,比如 1990
+  const years = []
+  for (let y = currentYear; y >= startYear; y--) {
+    years.push(y)
+  }
+  return years // [2026, 2025, ..., 2000]
+})
+
+const calendarData = ref({})
+
+const getDataByDate = (date: Dayjs, key: string) => {
+  return calendarData.value[date.format('YYYY-MM-DD')]?.[key] ?? 0
+}
+const getPageData = () => {
+  $api.getDeliveryCalendarData({ month: dayjs().format('MM/YYYY') }).then((res) => {
+    if (res.code === 200) {
+      calendarData.value = res.data
+    }
+  })
+}
+
+onMounted(() => {
+  getPageData()
+})
+
+// 👇 关键:监听 panelChange(月份/年份切换)
+const onPanelChange = (value: Dayjs) => {
+  // 同步更新 displayMonth,确保受控
+  displayMonth.value = value
+}
+
+// 可选:处理日期点击(比如查看详情)
+const onSelect = (date: Dayjs) => {
+  console.log('选中日期:', date.format('YYYY-MM-DD'))
+  // 你可以在这里打开详情弹窗等
+}
+
+// 年份切换
+const handleYearChange = (year: number, onChange: (date: Dayjs) => void) => {
+  const newDate = displayMonth.value.clone().year(year)
+  onChange(newDate)
+  displayMonth.value = newDate
+}
+
+// 月份切换
+const handleMonthChange = (month: number, onChange: (date: Dayjs) => void) => {
+  const newDate = displayMonth.value.clone().month(month - 1)
+  onChange(newDate)
+  displayMonth.value = newDate
+}
+
+const calendarTagDialog = ref()
+const handleTagClick = (type, date) => {
+  calendarTagDialog.value.openDialog(type, date, calendarData.value[date.format('YYYY-MM-DD')])
 }
 </script>
 
 <template>
   <div class="calendar-container">
-    <a-calendar v-model:value="value" fullscreen>
+    <!-- 👇 绑定 :value + 监听 @panelChange -->
+    <a-calendar :value="displayMonth" fullscreen @select="onSelect" @panelChange="onPanelChange">
+      <!-- 自定义头部:value 来自 displayMonth(已同步) -->
+      <template #headerRender="{ value, onChange }">
+        <div class="custom-header">
+          <div class="label-type destination-booking">
+            <div class="sign"></div>
+            <div class="label">Destination Booking</div>
+          </div>
+          <div class="label-type recommended-delivery-date">
+            <div class="sign"></div>
+            <div class="label">Recommended Delivery Date</div>
+          </div>
+          <div class="label-type free-storage-period-ends">
+            <div class="sign"></div>
+            <div class="label">Free Storage Period Ends</div>
+          </div>
+          <div class="grid-lines"></div>
+          <a-select
+            :value="value.year()"
+            style="width: 180px; margin-right: 8px"
+            @change="(year) => handleYearChange(year, onChange)"
+          >
+            <a-select-option v-for="y in yearOptions" :key="y" :value="y">
+              {{ y }}年
+            </a-select-option>
+          </a-select>
+
+          <a-select
+            :value="value.month() + 1"
+            style="width: 80px"
+            @change="(month) => handleMonthChange(month, onChange)"
+          >
+            <a-select-option v-for="m in 12" :key="m" :value="m">
+              {{
+                [
+                  'Jan',
+                  'Feb',
+                  'Mar',
+                  'Apr',
+                  'May',
+                  'Jun',
+                  'Jul',
+                  'Aug',
+                  'Sep',
+                  'Oct',
+                  'Nov',
+                  'Dec'
+                ][m - 1]
+              }}
+            </a-select-option>
+          </a-select>
+        </div>
+      </template>
+
       <template #dateCellRender="{ current }">
         <ul class="events">
-          <li v-for="(item, index) in getListData(current)" :key="index">
-            <!-- 使用原生 span 替代 a-badge(更易控制暗黑样式) -->
-            <span class="event-badge" :class="`event- $ {item.type}`"></span>
-            <span class="event-text">{{ item.content }}</span>
-          </li>
+          <!-- 如果不为当前月份的日期,则不显示标签 -->
+          <div
+            class="tags-details"
+            v-if="
+              calendarData?.[dayjs(current).format('YYYY-MM-DD')] &&
+              dayjs(current).isSame(dayjs(displayMonth), 'month')
+            "
+          >
+            <div class="ending-tag tag-style" @click="handleTagClick('ending', current)">
+              <span
+                class="font_family icon-icon_delay_b1"
+                style="margin-right: 3px; font-size: 13px"
+              ></span>
+              <span class="type">{{ getDataByDate(current, 'endingNumber') }} Ending</span>
+              <span class="ctns-tag">{{ getDataByDate(current, 'endingCtns') }} ctns</span>
+            </div>
+            <div class="delivery-tag" @click="handleTagClick('delivery', current)">
+              <div class="label">Recommended Delivery</div>
+              <div class="tag-style">
+                <span class="font_family icon-icon_road__booking_b" style="font-size: 12px"></span>
+                <span class="type">{{ getDataByDate(current, 'shipmentNumber') }} Shipments</span>
+                <span class="ctns-tag">{{ getDataByDate(current, 'shipmentCtns') }} ctns</span>
+              </div>
+            </div>
+            <div class="booking-tag">
+              <div class="label">Destination Booking</div>
+              <div class="tag-style">
+                <span class="font_family icon-icon_booking_order_b" style="font-size: 12px"></span>
+                <span class="type">{{ getDataByDate(current, 'bookingNumber') }} Bookings</span>
+                <span class="ctns-tag">{{ getDataByDate(current, 'bookingCtns') }} ctns</span>
+              </div>
+            </div>
+          </div>
         </ul>
       </template>
-
-      <template #monthCellRender="{ current }">
-        <div v-if="getMonthData(current)" class="notes-month">
-          <section>{{ getMonthData(current) }}</section>
-          <span>Backlog number</span>
-        </div>
-      </template>
     </a-calendar>
+    <CalendarTagDetailDialog ref="calendarTagDialog"></CalendarTagDetailDialog>
   </div>
 </template>
 
-<style scoped>
+<style scoped lang="scss">
+/* ... 你的深色样式保持不变 ... */
 .calendar-container {
+  margin-top: -46px;
   padding: 0 24px;
 }
 
-/* ===== 深色主题覆盖 ===== */
+.custom-header {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  padding: 2px 0;
+  .label-type {
+    display: flex;
+    align-items: center;
+    margin-right: 24px;
+
+    .sign {
+      width: 10px;
+      height: 10px;
+      margin-right: 4px;
+      border-radius: 3px;
+    }
+  }
+  .destination-booking {
+    .sign {
+      background-color: var(--color-delivery-calendar-booking-sign-bg);
+      border: 1px dashed var(--color-delivery-calendar-booking-sign-border);
+    }
+    .label {
+      color: var(--color-delivery-calendar-booking-label-text);
+    }
+  }
+  .recommended-delivery-date {
+    .sign {
+      background-color: var(--color-delivery-calendar-delivery-date-sign-bg);
+      border: 1px dashed var(--color-delivery-calendar-delivery-date-sign-border);
+    }
+    .label {
+      color: var(--color-delivery-calendar-delivery-date-label-text);
+    }
+  }
+  .free-storage-period-ends {
+    margin-right: 8px;
+    .sign {
+      background-color: var(--color-delivery-calendar-ends-sign-bg);
+      border: 1px dashed var(--color-delivery-calendar-ends-sign-border);
+    }
+    .label {
+      color: var(--color-delivery-calendar-ends-label-text);
+    }
+  }
+  .grid-lines {
+    height: 18px;
+    width: 2px;
+    margin-right: 8px;
+    background-color: var(--color-border);
+  }
+}
+
+/* ===== 深色主题覆盖(保持原样)===== */
 :deep(.ant-picker-calendar) {
   background-color: var(--color-mode);
   color: #e0e0e0;
@@ -82,47 +235,49 @@ const getMonthData = (current: Date) => {
 
 :deep(.ant-picker-calendar-header) {
   background-color: var(--color-mode);
-  /* border-bottom: 1px solid #333; */
 }
 
 :deep(.ant-picker-calendar-header .ant-picker-year-select),
 :deep(.ant-picker-calendar-header .ant-picker-month-select) {
-  /* background-color: #2d2d2d; */
   border: 1px solid #444;
   color: #e0e0e0;
 }
 
 :deep(.ant-picker-calendar-body) {
-  background-color: #1a1a1a;
+  // background-color: #1a1a1a;
 }
+
 :deep(.ant-picker-cell) {
   background-color: var(--color-calendar-cell-bg) !important;
   border: 1px solid var(--color-border) !important;
 }
 
-/* 修复日期格子布局 —— 关键! */
 :deep(.ant-picker-calendar-date) {
-  height: 100px !important;
+  height: 143px !important;
   display: block !important;
-  border-top: 0px !important;
+  border-top: 0 !important;
   margin: 0 !important;
   overflow: hidden;
   transition: none !important;
 }
-.ant-picker-calendar .ant-picker-content td.ant-picker-cell:not(.ant-picker-cell-in-view),
-.ant-picker-dropdown .ant-picker-content td.ant-picker-cell:not(.ant-picker-cell-in-view) {
-  background-color: red !important;
+
+:deep(.ant-picker-content) {
+  border-radius: 6px;
+  overflow: hidden;
 }
-:deep(.ant-picker-calendar-date:hover) {
-  background-color: #2a2a2a !important;
+:deep(.ant-picker-content thead) {
+  border-radius: 6px;
+  overflow: hidden;
+  border: 1px solid var(--color-border) !important;
 }
 :deep(.ant-picker-content th) {
   height: 24px !important;
   padding: 0 !important;
   text-align: center;
-  background-color: var(--color-calendar-cell-bg) !important;
+  color: var(--color-calendar-disabled-date-text) !important;
+  background-color: var(--color-delivery-calendar-th-bg) !important;
 }
-/* 日期数字 */
+
 :deep(.ant-picker-calendar-date-value) {
   display: block;
   font-size: 14px;
@@ -132,30 +287,57 @@ const getMonthData = (current: Date) => {
   text-align: left;
 }
 
-/* 选中状态 */
-:deep(.ant-picker-calendar-date-selected) {
-  background-color: #0066ff !important;
-  border-color: #0066ff !important;
-  color: white !important;
+:deep(.ant-picker-cell .ant-picker-calendar-date-value) {
+  color: var(--color-n--color-neutral-1) !important;
+}
+
+/* 彻底清除选中状态 */
+:deep(.ant-picker-calendar-date-selected),
+:deep(.ant-picker-cell-selected .ant-picker-calendar-date) {
+  background: transparent !important;
+  color: #e0e0e0 !important;
+  box-shadow: none !important;
+}
+
+// 不是当月日期时的样式
+:deep(
+  td.ant-picker-cell:not(.ant-picker-cell-in-view):not(.custom-delivery-calendar .ant-picker-cell)
+) {
+  background-color: rgba(0, 0, 0, 0) !important;
+  .ant-picker-calendar-date-value {
+    color: var(--color-calendar-disabled-date-text) !important;
+  }
+}
+
+:deep(
+  td.ant-picker-cell:hover:not(.ant-picker-cell-in-view):not(
+      .custom-delivery-calendar .ant-picker-cell
+    )
+) {
+  background-color: rgba(249, 250, 252, 0.1) !important;
+}
+:deep(.ant-picker-cell:hover) {
+  background-color: rgba(249, 250, 252, 0.1) !important;
+  .ant-picker-calendar-date-value {
+    color: var(--color-neutral-1) !important;
+  }
 }
 
-/* 今天 */
-:deep(.ant-picker-calendar-date-today) {
-  background-color: #2a2a2a !important;
-  border-color: #555 !important;
+/* 同时清除 hover 时的干扰 */
+:deep(.ant-picker-cell-selected:hover .ant-picker-calendar-date) {
+  background: transparent !important;
 }
 
-/* 事件列表 */
 .events {
   list-style: none;
   margin: 0;
   padding: 0;
-  max-height: 70px;
+  height: 110px;
   overflow-y: auto;
   font-size: 12px;
 }
 
-.events li {
+.events .tags-details {
   display: flex;
   align-items: center;
   gap: 4px;
@@ -164,37 +346,100 @@ const getMonthData = (current: Date) => {
   text-align: left;
 }
 
-.event-badge {
-  display: inline-block;
-  width: 8px;
-  height: 8px;
-  border-radius: 50%;
+.tags-details {
+  display: flex;
+  flex-direction: column;
 }
+.tag-style {
+  display: flex;
+  align-items: center;
+  padding-left: 6px;
+  height: 15px;
+  border-radius: 3px;
+  overflow: hidden;
 
-.event-warning {
-  background-color: #faad14;
+  .font_family {
+    margin-right: 4px;
+  }
+  .type {
+    font-size: 10px;
+    font-weight: 700;
+    line-height: 16px;
+  }
+  .ctns-tag {
+    height: 12px;
+    margin-left: 6px;
+    padding: 0 3px;
+    padding-top: 0.5px;
+    font-size: 8px;
+    border-radius: 3px;
+    background-color: #f3cfd0;
+  }
 }
-.event-success {
-  background-color: #52c41a;
+.delivery-tag,
+.booking-tag {
+  height: 36px;
+  width: 100%;
+  padding-top: 4px;
+  border-radius: 3px;
+  .label {
+    height: 12px;
+    padding-left: 6px;
+    font-size: 8px;
+    line-height: 12px;
+  }
+  .ctns-tag {
+    padding-top: 1px;
+  }
 }
-.event-error {
-  background-color: #ff4d4f;
+.delivery-tag {
+  border: 0.5px dashed var(--color-calendar-delivery-tag-border);
+  background-color: var(--color-calendar-delivery-tag-bg);
+  .label {
+    color: var(--color-calendar-delivery-tag-label-text);
+  }
+  .font_family,
+  .type,
+  .ctns-tag {
+    color: var(--color-calendar-delivery-tag-text) !important;
+  }
+  .ctns-tag {
+    background-color: var(--color-calendar-delivery-tag-bg);
+  }
 }
-
-/* 月份备注 */
-:deep(.notes-month) {
-  text-align: center;
-  color: #e0e0e0;
+.booking-tag {
+  background-color: var(--color-calendar-booking-tag-bg);
+  .label {
+    color: var(--color-calendar-booking-tag-label-text);
+  }
+  .font_family,
+  .type,
+  .ctns-tag {
+    color: var(--color-calendar-booking-tag-text) !important;
+  }
+  .ctns-tag {
+    background-color: var(--color-calendar-booking-tag-bg);
+  }
 }
-:deep(.notes-month section) {
-  font-size: 28px;
-  line-height: 28px;
+.ending-tag {
+  height: 24px;
+  width: 100%;
+  border: 0.5px dashed var(--color-calendar-ending-tag-border);
+  background-color: var(--color-calendar-ending-tag-bg);
+  .font_family,
+  .type,
+  .ctns-tag {
+    color: var(--color-calendar-ending-tag-text) !important;
+  }
+  .ctns-tag {
+    background-color: var(--color-calendar-ending-tag-bg);
+  }
 }
-:deep(.notes-month span) {
-  font-size: 14px;
-  color: #aaa;
+:deep(.ant-picker-calendar-date-content) {
+  height: 110px !important;
 }
 </style>
+
 <style lang="scss">
 div:where(.css-dev-only-do-not-override-1p3hq3p).ant-picker-calendar.ant-picker-calendar-full
   .ant-picker-panel {

+ 0 - 1
src/views/DestinationDelivery/src/components/ModifyBooking/index.ts

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

+ 0 - 275
src/views/DestinationDelivery/src/components/ModifyBooking/src/ModifyBooking.vue

@@ -1,275 +0,0 @@
-<script lang="ts" setup>
-import SelectShipmentsTable from './components/SelectShipmentsTable.vue'
-import { useRouter } from 'vue-router'
-
-const router = useRouter()
-
-const selectVModel = ref('')
-const optionOptions = ref([
-  { key: '1', value: 'option1', label: 'Option 1' },
-  { key: '2', value: 'option2', label: 'Option 2' },
-  { key: '3', value: 'option3', label: 'Option 3' }
-])
-
-const inputVModel = ref('')
-const radioVModel = ref(1)
-const deliveryDate = ref('')
-
-const handleCancel = () => {
-  // Logic to handle cancel action
-  router.push({ name: 'Destination Delivery' })
-}
-</script>
-<template>
-  <div class="modify-booking">
-    <div class="header">
-      <span>Modify Booking</span>
-      <div class="operator">
-        <el-button @click="handleCancel" style="height: 40px; width: 115px" type="default">
-          <span style="margin-right: 4px" class="font_family icon-icon_return_b"></span>
-          <span style="font-weight: 400">Cancel</span></el-button
-        >
-        <el-button style="height: 40px; width: 120px" class="el-button--main el-button--pain-theme">
-          <span
-            style="
-              display: inline-block;
-              margin-top: -4px;
-              margin-right: 4px;
-              transform: rotate(-60deg);
-            "
-            class="font_family icon-icon_submit_b"
-          ></span>
-          <span style="font-weight: 400">Submit</span>
-        </el-button>
-      </div>
-    </div>
-    <div class="content">
-      <div class="booking-info">
-        <div class="booking-no">
-          <span class="no">Booking No.B83131200164</span>
-          <v-tag class="tag" type="Pending Approval">Pending Approval</v-tag>
-        </div>
-      </div>
-      <el-divider style="margin: 8px 0" />
-      <SelectShipmentsTable></SelectShipmentsTable>
-      <el-divider style="margin: 8px 0 20px" />
-      <div class="delivery-information">
-        <div class="label">Delivery Information</div>
-        <div class="delivery-info-content">
-          <div class="delivery-address-header">
-            <div class="label"><span class="require-icon">*</span>Delivery Address</div>
-            <div class="operator">
-              <el-button class="el-button--text" style="height: 32px">
-                <span class="font_family icon-icon_add_b" style="margin-right: 4px"></span>
-                <span>Add New Address</span>
-              </el-button>
-              <el-button class="el-button--text" style="height: 32px">
-                <span
-                  class="font_family icon-icon_configurations_b"
-                  style="margin-right: 4px"
-                ></span>
-                <span>Manage Address</span>
-              </el-button>
-            </div>
-          </div>
-          <div class="delivery-address-content">
-            <el-radio-group v-model="radioVModel">
-              <el-radio :value="1" label="string">
-                <div class="delivery-address-label">Main Distribution Center</div>
-                <div class="delivery-address-info">
-                  <p>160#BEIJING ROAD, JINGAN District,</p>
-                  <p>Shenzhen, China</p>
-                  <p class="time">Contact: John Doe (+65 9123 4567)</p>
-                </div>
-              </el-radio>
-            </el-radio-group>
-          </div>
-          <div class="filetr-item mode-type">
-            <div class="label"><span class="require-icon">*</span>Mode Type</div>
-            <el-select v-model="selectVModel" clearable placeholder="Please Select Type">
-              <el-option
-                v-for="item in optionOptions"
-                :key="item.key"
-                :value="item.value"
-                :label="item.label"
-              ></el-option>
-            </el-select>
-          </div>
-          <div class="filetr-item mode-type">
-            <div class="label"><span class="require-icon">*</span>Preferred Delivery Date</div>
-            <el-date-picker v-model="deliveryDate" type="date" placeholder="Pick a day" />
-          </div>
-          <div class="special-requirements">
-            <div class="label">Special Requirements</div>
-            <div class="tag-list">
-              <div class="tag-item">Tail Lift Required</div>
-              <div class="tag-item">Side Loading</div>
-              <div class="tag-item">Forklift Required</div>
-              <div class="tag-item">Special Equipment</div>
-            </div>
-            <el-input
-              type="textarea"
-              class="input-textarea"
-              v-model="inputVModel"
-              placeholder="Enter any additional requirements or notes..."
-            ></el-input>
-          </div>
-          <div class="modification-reason">
-            <div class="label" style="margin-bottom: 4px">
-              <span class="require-icon">*</span>Modification Reason
-            </div>
-            <el-input class="input-textarea" type="textarea" v-model="inputVModel"></el-input>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<style lang="scss" scoped>
-.modify-booking {
-  position: relative;
-  background-color: var(--color-mode);
-}
-.header {
-  display: flex;
-  height: 68px;
-  border-bottom: 1px solid var(--color-border);
-  font-size: var(--font-size-6);
-  font-weight: 700;
-  padding: 0 24px;
-  align-items: center;
-  justify-content: space-between;
-}
-
-.content {
-  padding: 16px 24px 48px;
-}
-
-.booking-info {
-  display: flex;
-  align-items: center;
-  height: 48px;
-  padding: 0 16px;
-  border-radius: 12px;
-  background-image: var(--color-booking-info-linear-bg);
-
-  .booking-no {
-    display: flex;
-    align-items: center;
-    .no {
-      margin-top: 2px;
-      font-size: 18px;
-      font-weight: 700;
-      line-height: 21px;
-    }
-    .tag {
-      margin-left: 8px;
-    }
-  }
-  .created-time {
-    margin-top: 8px;
-    font-size: 12px;
-    color: var(--color-neutral-2);
-  }
-}
-
-.delivery-information {
-  & > .label {
-    font-size: 18px;
-    font-weight: 700;
-    margin-bottom: 16px;
-  }
-  .delivery-info-content {
-    padding: 16px;
-    border: 1px solid var(--color-border);
-    border-radius: 12px;
-    .label {
-      font-weight: 700;
-      line-height: 22px;
-    }
-    .delivery-address-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      margin-bottom: 4px;
-      & > .operator {
-        display: flex;
-        align-items: center;
-        & > .el-button--text {
-          height: 32px;
-          font-size: 14px;
-          font-weight: 400;
-          span {
-            color: var(--color-theme);
-          }
-        }
-      }
-    }
-    .delivery-address-content {
-      height: 122px;
-      margin-bottom: 16px;
-      padding: 10px 12px 8px 8px;
-      border-radius: 12px;
-      background-color: var(--color-share-link-bg);
-      :deep(.el-radio__label) {
-        display: flex;
-        flex-direction: column;
-        height: 100%;
-        justify-content: space-between;
-      }
-      .delivery-address-label {
-        margin-top: 9px;
-        margin-bottom: 2px;
-        font-weight: 700;
-      }
-      .delivery-address-info {
-        margin-top: 8px;
-        p {
-          line-height: 21px;
-          color: var(--color-neutral-2);
-        }
-        & > .time {
-          margin-top: 6px;
-          font-size: 12px;
-        }
-      }
-    }
-    .filetr-item {
-      display: inline-flex;
-      flex-direction: column;
-      width: 240px;
-      margin-right: 16px;
-      & > .label {
-        margin-bottom: 4px;
-      }
-    }
-    .special-requirements {
-      margin: 16px 0;
-    }
-    .input-textarea {
-      :deep(.el-textarea__inner) {
-        height: 80px;
-        resize: none;
-        line-height: 22px;
-      }
-    }
-    .tag-list {
-      margin-top: 8px;
-      margin-bottom: 8px;
-      .tag-item {
-        display: inline-block;
-        height: 32px;
-        padding: 10px 16px;
-        margin-right: 8px;
-        background-color: var(--color-download-file-filter-tag-bg);
-        border-radius: 15px;
-        font-size: 12px;
-      }
-    }
-  }
-  .require-icon {
-    color: red;
-  }
-}
-</style>

+ 0 - 152
src/views/DestinationDelivery/src/components/ModifyBooking/src/components/SelectShipmentsTable.vue

@@ -1,152 +0,0 @@
-<script setup lang="ts">
-import { type VxeGridInstance, type VxeGridProps } from 'vxe-table'
-// import { autoWidth } from '@/utils/table'
-import { useRowClickStyle } from '@/hooks/rowClickStyle'
-import { formatTimezone, formatNumber } from '@/utils/tools'
-
-const props = defineProps({
-  data: Object
-})
-const tableRef = ref<VxeGridInstance | null>(null)
-const tableData = ref<VxeGridProps<any>>({
-  minHeight: 70,
-  border: true,
-  round: true,
-  columns: [],
-  data: [],
-  scrollY: { enabled: true, oSize: 20, gt: 30 },
-  emptyText: ' ',
-  showHeaderOverflow: true,
-  showOverflow: true,
-  headerRowStyle: {
-    backgroundColor: 'var(--color-table-header-bg)'
-  },
-  columnConfig: { resizable: true, useKey: true },
-  rowConfig: { isHover: true }
-})
-
-const handleColumns = (columns: any) => {
-  const newColumns = columns.map((item: any) => {
-    let curColumn: any = {
-      title: item.title,
-      field: item.field,
-      minWidth: 30
-    }
-
-    // 格式化
-    if (item.formatter === 'date' || item.formatter === 'dateTime') {
-      curColumn = {
-        ...curColumn,
-        formatter: ({ cellValue }: any) => formatTimezone(cellValue)
-      }
-    } else if (item.formatter === 'number') {
-      curColumn = {
-        ...curColumn,
-        formatter: ({ cellValue }: any) => formatNumber(Number(cellValue), item?.digits)
-      }
-    }
-    return curColumn
-  })
-  return newColumns
-}
-watch(
-  () => props.data,
-  (newVal) => {
-    const containers = newVal?.containers
-    if (containers && containers.container_column) {
-      tableData.value.columns = handleColumns(containers.container_column)
-      tableData.value.data = containers.container_data
-      // nextTick(() => {
-      //   tableRef.value && autoWidth(tableData.value, tableRef.value)
-      // })
-    }
-  },
-  {
-    immediate: true,
-    deep: true
-  }
-)
-
-const tableLoadingColumn = ref(false)
-const tableLoadingTableData = ref(false)
-
-const tableOriginColumnsField = ref()
-// 获取表格列
-const getTableColumns = async () => {
-  tableLoadingColumn.value = true
-  await $api.getOperationTableColumns().then((res: any) => {
-    if (res.code === 200) {
-      tableData.value.columns = [
-        { type: 'checkbox', width: 50, fixed: 'left' },
-        ...handleColumns(res.data.OperationTableColumns),
-        {}
-      ]
-
-      tableOriginColumnsField.value = res.data.OperationTableColumns
-
-      tableLoadingColumn.value = false
-    }
-  })
-}
-let searchdata: any = {}
-// 获得表格数据后赋值
-const assignTableData = (data: any) => {
-  tableData.value.data = data.searchData || []
-}
-
-// 获取表格数据
-const getTableData = async () => {
-  const rc = -1
-  tableLoadingTableData.value = true
-  await $api
-    .SearchOperationLog({
-      cp: 1,
-      ps: 6,
-      rc,
-      ...searchdata
-    })
-    .then((res: any) => {
-      if (res.code === 200) {
-        assignTableData(res.data)
-      }
-    })
-    .finally(() => {
-      tableLoadingTableData.value = false
-    })
-}
-
-onMounted(() => {
-  Promise.all([getTableColumns(), getTableData()]).finally(() => {})
-})
-// 实现行点击样式
-useRowClickStyle(tableRef)
-</script>
-
-<template>
-  <div class="shipment-table">
-    <div class="label">*Select Shipments</div>
-    <vxe-grid
-      ref="tableRef"
-      v-vloading="tableLoadingTableData || tableLoadingColumn"
-      v-bind="tableData"
-      height="240"
-    >
-      <template #empty v-if="!tableLoadingTableData && tableData.data.length === 0">
-        <div class="empty">No data</div>
-      </template>
-    </vxe-grid>
-  </div>
-</template>
-
-<style lang="scss" scoped>
-.shipment-table {
-  padding: 16px;
-  border: 1px solid var(--color-border);
-  border-radius: 12px;
-  .label {
-    margin-bottom: 16px;
-    font-size: 18px;
-    font-weight: 700;
-  }
-}
-</style>