AmandaG 7 сар өмнө
parent
commit
c29d60098d
27 өөрчлөгдсөн 618 нэмэгдсэн , 263 устгасан
  1. 2 0
      package.json
  2. 1 2
      src/auto-imports.d.ts
  3. 67 43
      src/components/AIRobot/src/AIRobot.vue
  4. 0 1
      src/components/AddRules/src/components/NotiMethods.vue
  5. 0 1
      src/components/CreateAddRules/src/CreateAddRules.vue
  6. 0 1
      src/components/CreateAddRules/src/components/ShipmentRange.vue
  7. 1 2
      src/components/NotificationMessageCard/src/NotificationMessageCard.vue
  8. 0 1
      src/components/NotificationMessageCard/src/components/EventCard.vue
  9. 4 2
      src/components/SelectTableSelect/src/SelectTableSelect.vue
  10. 0 0
      src/styles/icons/iconfont.js
  11. BIN
      src/styles/icons/iconfont.ttf
  12. BIN
      src/styles/icons/iconfont.woff
  13. BIN
      src/styles/icons/iconfont.woff2
  14. 65 7
      src/styles/reset.scss
  15. 18 5
      src/styles/theme.scss
  16. 292 100
      src/views/AIRobotChat/src/AIRobotChat.vue
  17. 97 81
      src/views/AIRobotChat/src/components/AIQuestions.vue
  18. 46 0
      src/views/AIRobotChat/src/components/LoadingDots.vue
  19. 0 1
      src/views/Layout/src/LayoutView.vue
  20. 0 3
      src/views/Layout/src/components/Header/components/NotificationDrawer.vue
  21. 6 0
      src/views/Layout/src/components/Header/components/TrainingCard.vue
  22. 2 2
      src/views/Login/src/components/ChangePasswordCard.vue
  23. 3 3
      src/views/Login/src/loginView.vue
  24. 7 2
      src/views/SystemMessage/src/SystemMessage.vue
  25. 1 0
      src/views/Tracking/src/TrackingView.vue
  26. 5 5
      src/views/Tracking/src/components/TrackingDetail/src/TrackingDetail.vue
  27. 1 1
      vite.config.ts

+ 2 - 0
package.json

@@ -31,8 +31,10 @@
     "element-plus": "^2.8.1",
     "exceljs": "^4.4.0",
     "highlight.js": "^11.11.1",
+    "github-markdown-css": "^5.8.1",
     "leaflet": "^1.9.4",
     "lodash": "^4.17.21",
+    "markdown-it": "^14.1.0",
     "mitt": "^3.0.1",
     "moment": "^2.30.1",
     "moment-timezone": "^0.5.46",

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

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

+ 67 - 43
src/components/AIRobot/src/AIRobot.vue

@@ -42,22 +42,28 @@ const DeQuestions = ref([
     isLong: false
   },
   {
-    label: 'List shipments with ETA changes in the last 30 days11111111111111111111111111111111111.',
-    value: 'List shipments with ETA changes in the last 30 days11111111111111111111111111111111111.',
+    label:
+      'List shipments with ETA changes in the last 30 days11111111111111111111111111111111111.',
+    value:
+      'List shipments with ETA changes in the last 30 days11111111111111111111111111111111111.',
     isLong: true
   },
   {
-    label: 'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111122.',
-    value: 'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111122.',
+    label:
+      'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111122.',
+    value:
+      'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111122.',
     isLong: true
   },
   {
-    label: 'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111133.',
-    value: 'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111133.',
+    label:
+      'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111133.',
+    value:
+      'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111133.',
     isLong: true
-  },
+  }
 ])
-const itemGroups = ref([]);
+const itemGroups = ref([])
 
 // 鼠标hover AIRobot图标
 const AvatarMouseEnter = () => {
@@ -94,29 +100,29 @@ const HideAIRobotTopTwo = () => {
 
 // 随机显示方法
 const prepareGroups = () => {
-  const groups = [];
-  let currentGroup = [];
-  let currentHeight = 0;
+  const groups = []
+  let currentGroup = []
+  let currentHeight = 0
+
+  DeQuestions.value.forEach((item) => {
+    const itemHeight = item.isLong ? 2 : 1
 
-  DeQuestions.value.forEach(item => {
-    const itemHeight = item.isLong ? 2 : 1;
-    
     if (currentHeight + itemHeight > 4) {
-      groups.push(currentGroup);
-      currentGroup = [];
-      currentHeight = 0;
+      groups.push(currentGroup)
+      currentGroup = []
+      currentHeight = 0
     }
-    
-    currentGroup.push(item);
-    currentHeight += itemHeight;
-  });
+
+    currentGroup.push(item)
+    currentHeight += itemHeight
+  })
 
   // 添加最后一组
   if (currentGroup.length > 0) {
-    groups.push(currentGroup);
+    groups.push(currentGroup)
   }
 
-  itemGroups.value = groups;
+  itemGroups.value = groups
 }
 const isShowLogin = () => {
   const LoginDays = 0
@@ -147,12 +153,12 @@ const handelClick = (item: any) => {
 
 onMounted(() => {
   prepareGroups()
-  emitter.on('login-success', isShowLogin);
-});
+  emitter.on('login-success', isShowLogin)
+})
 
 onUnmounted(() => {
-  emitter.off('login-success', isShowLogin);
-});
+  emitter.off('login-success', isShowLogin)
+})
 
 defineExpose({
   isShowLogin
@@ -174,30 +180,29 @@ defineExpose({
       <div class="AIAvator">
         <img width="40px" src="../image/icon_ai_robot36_b@2x.png" />
       </div>
-      <div class="dialogue_title">
-        Hi! I'm your Freight Assistant, always on call
-      </div>
+      <div class="dialogue_title">Hi! I'm your Freight Assistant, always on call</div>
     </div>
     <div class="flex_end">
-      <div class="dialogue_content ">
+      <div class="dialogue_content">
         <div class="dialogue_content_title">
           <div class="dialogue_title_left">
             <img src="../image/icon_faq_b@2x.png" width="24px" />
             Frequently Asked Questions
           </div>
         </div>
-        <el-carousel class="carousel" :autoplay="false" height="190px" style="width: 452px;" >
-          <el-carousel-item 
-            v-for="(group, index) in itemGroups "
-            :key="index"
-          >
+        <el-carousel class="carousel" :autoplay="false" height="190px" style="width: 452px">
+          <el-carousel-item v-for="(group, index) in itemGroups" :key="index">
             <div class="dialogue_container">
-              <div 
+              <div
                 class="dialogue_content_item"
                 v-for="item in group"
                 :key="item.label"
+<<<<<<< HEAD
                 @click="handelClick(item.label)"
                 :class="{ 'long_item': item.isLong }"
+=======
+                :class="{ long_item: item.isLong }"
+>>>>>>> dev
               >
                 {{ item.label }}
               </div>
@@ -210,26 +215,45 @@ defineExpose({
   <div class="AIRobot-top" v-if="isShowAIRobotTop">
     <div class="flex_end" @click="HideAIRobotTopTwo">
       <div class="icon flex_center">
+<<<<<<< HEAD
         <span class="iconfont_icon icon_dark AI_icon">
             <svg class="iconfont" aria-hidden="true">
               <use xlink:href="#icon-icon_reject_b"></use>
             </svg>
           </span>
+=======
+        <span class="iconfont_icon icon_dark">
+          <svg class="iconfont" aria-hidden="true">
+            <use xlink:href="#icon-icon_reject_b"></use>
+          </svg>
+        </span>
+>>>>>>> dev
       </div>
     </div>
-    <div class="dialogue_title">
-      Hi! I'm your Freight Assistant, always on call
-    </div>
+    <div class="dialogue_title">Hi! I'm your Freight Assistant, always on call</div>
   </div>
   <!-- 悬浮icon -->
+<<<<<<< HEAD
   <div class="AIRobot flex_center" v-if="AIIconVisible">
     <el-popover
       :visible="visible"
       placement="top-end"
       width="auto"
     >
+=======
+  <div class="AIRobot flex_center">
+    <el-popover :visible="visible" placement="top-end" width="auto">
+>>>>>>> dev
       <template #reference>
-        <el-avatar @click="AvatarClick" @mouseenter="AvatarMouseEnter" @mouseleave="AvatarMouseLeave" :size="46" shape="square" class="avatar_bg" :src="clickSrc" />
+        <el-avatar
+          @click="AvatarClick"
+          @mouseenter="AvatarMouseEnter"
+          @mouseleave="AvatarMouseLeave"
+          :size="46"
+          shape="square"
+          class="avatar_bg"
+          :src="clickSrc"
+        />
       </template>
       <!-- hover时显示的对话框 -->
       <div v-if="AIRobotHoverVisible" class="AIRobot_dialog">Continue the conversation</div>
@@ -354,10 +378,10 @@ defineExpose({
   background-color: var(--color-arrow-hoverL);
   color: var(--color-theme);
 }
-.itemLable { 
+.itemLable {
   width: 100%;
 }
 .long_item {
   height: 64px;
 }
-</style>
+</style>

+ 0 - 1
src/components/AddRules/src/components/NotiMethods.vue

@@ -45,7 +45,6 @@ const MethodsInit = () => {
 
 // 选中Method
 const changeMethod = (val: any) => {
-  console.log(val)
   if (val.indexOf('By Email') != -1) {
     savesubscribeobj.method_by_email = true
   } else {

+ 0 - 1
src/components/CreateAddRules/src/CreateAddRules.vue

@@ -160,7 +160,6 @@ const Initdata = () => {
             ShipmentRangeCon.value = res.data.Container_Status_Update
             createObj.Transportstr = res.data.Container_Status_Update.shipment_details.split(';\r\n')[0]
             createObj.Timestr = res.data.Container_Status_Update.shipment_details.split(';\r\n')[1]
-            console.log(res.data.Container_Status_Update.shipment_details.split(';\r\n')[1])
             createListContainer.value.push(createObj.Transportstr)
             createListContainer.value.push(createObj.Timestr)
           } else if (editTablerules_type == 'Departure/Arrival_Delay') {

+ 0 - 1
src/components/CreateAddRules/src/components/ShipmentRange.vue

@@ -40,7 +40,6 @@ watch(
 )
 
 const ShipmentRangeInit = () => {
-  console.log(ShipmentRange_data.value)
   if (ShipmentRange_data.value?.shipment_transport_mode != undefined) {
     TransportCheckedList.value = ShipmentRange_data.value?.shipment_transport_mode.split(';')
     CheckChange(ShipmentRange_data.value?.shipment_transport_mode)

+ 1 - 2
src/components/NotificationMessageCard/src/NotificationMessageCard.vue

@@ -191,7 +191,6 @@ const parentHeight = computed(() => {
   return (window.innerHeight || document.documentElement.clientHeight) - props.topOffset
 })
 const scrollParentBoxStyle = computed(() => {
-  console.log(props.topOffset, 'value')
   return props.topOffset ? { height: `${parentHeight.value}px` } : {}
 })
 </script>
@@ -240,7 +239,7 @@ const scrollParentBoxStyle = computed(() => {
   width: 100%;
   overflow-y: auto;
   .scroll-padding {
-    padding: 10px 140px 0px 16px;
+    padding: 0px 140px 0px 16px;
   }
 }
 </style>

+ 0 - 1
src/components/NotificationMessageCard/src/components/EventCard.vue

@@ -185,7 +185,6 @@ const jumpTracking = (data: EventCardPropsData) => {
 
 <style lang="scss" scoped>
 .notification-card {
-  // max-width: 640px;
   margin-bottom: 16px;
   &.is-read {
     & > .header {

+ 4 - 2
src/components/SelectTableSelect/src/SelectTableSelect.vue

@@ -75,14 +75,16 @@ const changeSelect = (val: any) => {
 const emit = defineEmits(['changeAutoSelectAddType', 'delSelect', 'changeAutoSelect'])
 const errorBoolean = ref(false)
 let AutoSelectObj: any = {}
+let AutoSelectObj2: any = {}
 const changeAutoSelect = (val: any, value: any) => {
   if (value.length) {
     errorBoolean.value = true
   } else {
     errorBoolean.value = false
   }
-  AutoSelectObj[val] = value
-  emit('changeAutoSelect', AutoSelectObj, errorBoolean.value)
+  AutoSelectObj[val] = value.join()
+  AutoSelectObj2[val] = value
+  emit('changeAutoSelect', AutoSelectObj, AutoSelectObj2,errorBoolean.value)
 }
 const typeSelectFocus = (index: any, e: any) => {
   typeSelectIndex.value = index

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
src/styles/icons/iconfont.js


BIN
src/styles/icons/iconfont.ttf


BIN
src/styles/icons/iconfont.woff


BIN
src/styles/icons/iconfont.woff2


+ 65 - 7
src/styles/reset.scss

@@ -8,12 +8,6 @@ span,
 applet,
 object,
 iframe,
-h1,
-h2,
-h3,
-h4,
-h5,
-h6,
 p,
 blockquote,
 pre,
@@ -26,7 +20,6 @@ cite,
 code,
 del,
 dfn,
-em,
 img,
 ins,
 kbd,
@@ -141,3 +134,68 @@ div {
     margin: 0;
   }
 }
+
+.markdown-body {
+  line-height: 1.6;
+  font-size: 16px;
+  color: #333;
+}
+
+.markdown-body h1,
+.markdown-body h2,
+.markdown-body h3,
+.markdown-body h4,
+.markdown-body h5,
+.markdown-body h6 {
+  margin: 1em 0 0.5em;
+  font-weight: bold;
+}
+
+.markdown-body p {
+  margin: 1em 0;
+}
+
+.markdown-body ul,
+.markdown-body ol {
+  margin-left: 1.5em;
+  padding-left: 1em;
+}
+
+.markdown-body ul {
+  list-style-type: disc;
+}
+
+.markdown-body ol {
+  list-style-type: decimal;
+}
+
+.markdown-body li {
+  margin: 0.5em 0;
+}
+
+.markdown-body blockquote {
+  padding-left: 1em;
+  border-left: 4px solid #ddd;
+  color: #555;
+  margin: 1em 0;
+}
+
+.markdown-body a {
+  color: #0366d6;
+  text-decoration: underline;
+}
+
+.markdown-body code {
+  background: #f5f5f5;
+  padding: 0.2em 0.4em;
+  border-radius: 4px;
+  font-family: monospace;
+  font-size: 0.9em;
+}
+
+.markdown-body pre code {
+  display: block;
+  padding: 1em;
+  background: #f6f8fa;
+  overflow-x: auto;
+}

+ 18 - 5
src/styles/theme.scss

@@ -285,11 +285,19 @@
   --color-dialogue-bg: #fff;
   --color-dialogue_container-border: #fff;
   --color-carousel-card-bg: #fff;
-  --color-dialogue-icon-bg: radial-gradient(50% 43% at 50% 54.79%, #D5B4F3 0%, #FFF9FC 100%);
-  --color-dialogue-text-bg: linear-gradient(92deg, #EAECFF 1.33%, #F1E3FB 99.63%);
-  --color-dialogue_title: linear-gradient(90deg, #A71549 1.77%, #06256E 46.77%);
-  --color-dialogue_container-bg:rgba(255, 255, 255, 0.50);
-  --color-dialogue_content-bg:linear-gradient(117deg, var(--1-gradient-ai-robot-0, #B5FEF3) 4.31%, var(--1-gradient-ai-robot-15, #F9EEEC) 14.24%, var(--1-gradient-ai-robot-38, #FBD3EE) 29.71%, var(--1-gradient-ai-robot-59, #DDD5F7) 43.72%, var(--1-gradient-ai-robot-83, #C8F4F3) 59.35%, var(--1-gradient-ai-robot-100, #CADFF8) 70.56%);
+  --color-dialogue-icon-bg: radial-gradient(50% 43% at 50% 54.79%, #d5b4f3 0%, #fff9fc 100%);
+  --color-dialogue-text-bg: linear-gradient(92deg, #eaecff 1.33%, #f1e3fb 99.63%);
+  --color-dialogue_title: linear-gradient(90deg, #a71549 1.77%, #06256e 46.77%);
+  --color-dialogue_container-bg: rgba(255, 255, 255, 0.5);
+  --color-dialogue_content-bg: linear-gradient(
+    117deg,
+    var(--1-gradient-ai-robot-0, #b5fef3) 4.31%,
+    var(--1-gradient-ai-robot-15, #f9eeec) 14.24%,
+    var(--1-gradient-ai-robot-38, #fbd3ee) 29.71%,
+    var(--1-gradient-ai-robot-59, #ddd5f7) 43.72%,
+    var(--1-gradient-ai-robot-83, #c8f4f3) 59.35%,
+    var(--1-gradient-ai-robot-100, #cadff8) 70.56%
+  );
   --color-ai-chat-header-bg-gradient-begin: #eaecff;
   --color-ai-chat-header-bg-gradient-end: #fefdff;
   --color-ai-user-bubble-bg-gradient-begin: #ffede6;
@@ -301,6 +309,8 @@
   --color-output-type-bg: #4361ED;
   --color-output-type-string-bg: #6C757E;
   --color-output-select-text: #F9A725;
+  --color-loading-text: #b5b9bf;
+  --color-warning-tips-bg: #fff4d1;
 }
 
 :root.dark {
@@ -482,4 +492,7 @@
   --color-ai-user-bubble-bg-gradient-end: #5c6a7d;
   --input-border: #656f7d;
   --color-pause-btn-bg: #453b36;
+  --color-loading-text: #818892;
+  --color-warning-tips-bg: #85681b;
+  --color-warning-tips-text: #edb82f;
 }

+ 292 - 100
src/views/AIRobotChat/src/AIRobotChat.vue

@@ -1,11 +1,25 @@
 <script setup lang="ts">
 import AutoResizeTextarea from './components/AutoResizeTextarea.vue'
+import LoadingDots from './components/LoadingDots.vue'
 import AIQuestions from './components/AIQuestions.vue'
 import userBubbleLight from './image/userBubbleLight.png'
 import userBubbleDark from './image/userBubbleDark.png'
 import robotBubbleLight from './image/robotBubbleLight.png'
 import robotBubbleDark from './image/robotBubbleDark.png'
 import { useThemeStore } from '@/stores/modules/theme'
+import MarkdownIt from 'markdown-it'
+import 'github-markdown-css/github-markdown.css'
+
+const md = new MarkdownIt({
+  html: true,
+  linkify: true,
+  typographer: true,
+  breaks: true
+})
+
+const renderedMessage = (content) => {
+  return md.render(content)
+}
 
 const themeStore = useThemeStore()
 const modalSize = ref('large')
@@ -20,16 +34,25 @@ const robotBubbleImg = computed(() => {
   return themeStore.theme === 'light' ? robotBubbleLight : robotBubbleDark
 })
 
+// 是否显示footer的顶部阴影
+const isShowFooterShadow = ref(false)
+// 是否显示header的底部阴影
+const isShowHeaderShadow = ref(false)
+
+const loadingAnswer = ref(false) // 是否正在加载答案
 interface MessageItem {
   type: 'robot' | 'user'
   content: string
   feedback?: 'good' | 'noGood' | '' // 反馈结果
   isShowFeedback?: boolean // 是否展示反馈样式
   isAnswer?: boolean // 是否为用户问题的答案,是则才能展示反馈组件
+  isError?: boolean // 是否为错误消息
+  isCancel?: boolean // 是否为取消消息
 }
 const messages = ref<MessageItem[]>([
   {
     type: 'robot',
+    isShowFeedback: false,
     content: 'You can click on Frequently Asked Questions above or type your own question'
   },
   {
@@ -48,6 +71,19 @@ const messages = ref<MessageItem[]>([
     content: 'Of course! Please provide me with the details of your shipment.'
   }
 ])
+messages.value = JSON.parse(sessionStorage.getItem('AIChat')) || messages.value
+onMounted(() => {
+  scrollToBottom()
+})
+
+watch(
+  () => messages.value,
+  (newVal) => {
+    // 将消息存储到 sessionStorage 中
+    sessionStorage.setItem('AIChat', JSON.stringify(newVal))
+  },
+  { immediate: true, deep: true }
+)
 
 // 用户问题请求时间
 const queryTime = ref(-1)
@@ -62,59 +98,128 @@ const progressStatus = {
   cancel: 'You have stopped this answer'
 }
 
+const isShowTips = ref(false) // 是否展示提示信息
+
 const progressInterval = ref()
-const handleSend = () => {
-  if (!userQuestion.value) return
+const handleSend = (question, isPresetQuestion = true) => {
+  if (!question) return
+
+  if (loadingAnswer.value) {
+    isShowTips.value = true
+    setTimeout(() => {
+      isShowTips.value = false
+    }, 2000)
+    return
+  }
+  loadingAnswer.value = true
 
   messages.value.push({
     type: 'user',
-    content: userQuestion.value
+    content: question
   })
-  userQuestion.value = ''
+  !isPresetQuestion ? (userQuestion.value = '') : ''
   queryTime.value = 0
   messages.value.push({
     type: 'robot',
     content: progressStatus[0]
   })
+  autoScroll.value = true
+  scrollToBottom()
+
   progressInterval.value = setInterval(() => {
     queryTime.value++
+    // 定义时间点与对应状态的映射
+    const timeToStatusMap = {
+      15: 15,
+      30: 30,
+      60: 60
+    }
+    // 获取最后一个消息对象
+    const lastMessage = messages.value[messages.value.length - 1]
+    if (queryTime.value === 120) {
+      clearInterval(progressInterval.value)
+      lastMessage.content = progressStatus[120]
+      lastMessage.isError = true
+      queryTime.value = -1
+      loadingAnswer.value = false
+      return
+    }
+    if (timeToStatusMap[queryTime.value] !== undefined) {
+      lastMessage.content = progressStatus[queryTime.value]
+    }
   }, 1000)
 }
+const showScrollButton = ref(false) // 控制按钮显示
+const messagesRef = ref()
+const autoScroll = ref(true)
 
-// 根据时间更新消息内容
-const updateMessageContent = (time) => {
-  const lastMessageIndex = messages.value.length - 1
+function handleScroll() {
+  const el = messagesRef.value
+  const threshold = 50 // 到底部的距离阈值
+  const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < threshold
+  autoScroll.value = atBottom
 
-  // 确保消息数组不为空
-  if (lastMessageIndex >= 0) {
-    messages.value[lastMessageIndex].content = progressStatus[time]
-    if (time === 120) {
-      clearInterval(progressInterval.value)
-      queryTime.value = -3
-    }
-  }
+  showScrollButton.value = el.scrollHeight > el.clientHeight && !autoScroll.value
+
+  isShowFooterShadow.value =
+    messagesRef.value?.scrollTop <
+    messagesRef.value?.scrollHeight - messagesRef.value?.clientHeight - 1
+
+  isShowHeaderShadow.value = !!messagesRef.value?.scrollTop
 }
-watch(
-  () => queryTime.value,
-  (newVal) => {
-    // 定义时间点与对应状态的映射
-    const timeToStatusMap = {
-      15: 15,
-      30: 30,
-      60: 60,
-      120: 120
+function scrollToBottom() {
+  nextTick(() => {
+    if (messagesRef.value) {
+      messagesRef.value.scrollTop = messagesRef.value.scrollHeight
     }
+  })
+}
+
+const simulateStreamingMarkdown = () => {
+  loadingAnswer.value = true
+  const chunks = [
+    '# 欢迎使用 Markdown\n\n',
+    '这是一个用于测试的 **Markdown** 文本。\n\n',
+    '你可以使用 *斜体* 来强调重点。\n\n',
+    '也可以使用 [链接](https://example.com) 引导用户跳转。\n\n',
+    '- 支持无序列表\n',
+    '- 非常适合逐行流式显示\n\n',
+    '这是一段测试!\n'
+  ]
+
+  messages.value.push({
+    type: 'robot',
+    content: '',
+    isAnswer: true,
+    feedback: '',
+    isShowFeedback: false
+  })
+
+  let index = 0
 
-    // 如果当前时间点在映射中,更新消息内容
-    if (timeToStatusMap[newVal] !== undefined) {
-      updateMessageContent(timeToStatusMap[newVal])
+  autoScroll.value = true
+  scrollToBottom()
+
+  const interval = setInterval(() => {
+    index === chunks.length - 1 ? (loadingAnswer.value = false) : ''
+    if (index < chunks.length) {
+      messages.value[messages.value.length - 1].content += chunks[index]
+      index++
+
+      if (autoScroll.value) {
+        scrollToBottom()
+      }
+    } else {
+      clearInterval(interval)
     }
-  }
-)
+  }, 200) // 每500ms追加一段
+}
+
 // 暂停回答
 const handlePause = () => {
   clearInterval(progressInterval.value)
-  queryTime.value = -2
+  queryTime.value = -1
+  messages.value[messages.value.length - 1].isCancel = true
   messages.value[messages.value.length - 1].content = progressStatus.cancel
 }
 
@@ -155,7 +260,7 @@ defineExpose({
 
 <template>
   <div class="ai-robot" :style="{ width: modalSize === 'large' ? '1000px' : '484px' }">
-    <div class="top-section">
+    <div class="top-section" :class="[isShowHeaderShadow ? 'box-shadow' : '']">
       <div class="header">
         <span class="welcome">Hi! I'm your Freight Assistant</span>
         <div class="option-icon">
@@ -172,14 +277,20 @@ defineExpose({
           <span @click="handleClose" class="font_family icon-icon_collapsed__to_widget_b"></span>
         </div>
       </div>
-      <AIQuestions :modalSize="modalSize" @handelClickAIQuestion="handelClickAIQuestion"></AIQuestions>
+      <AIQuestions :modalSize="modalSize" @question="handleSend"></AIQuestions>
+      <div class="warning-tips" v-if="isShowTips">
+        <div class="warning-bg">
+          <span class="warning-icon font_family icon-icon_warning_fill_b"></span>
+        </div>
+        <span>Answer in progress, please wait.</span>
+      </div>
     </div>
-    <div class="chat-messages" ref="messagesRef" :style="{ marginTop: modalSize === 'large' ? '81px' : '151px' }">
+    <div class="chat-messages" ref="messagesRef" @scroll="handleScroll">
       <div
         class="message-item"
         :class="[
           msg.type === 'user' ? 'user-bubble' : 'robot-bubble',
-          ((queryTime > -1 && queryTime < 120) || queryTime === -2) && index === messages.length - 1
+          (queryTime > -1 && queryTime < 120 && index === messages.length - 1) || msg.isCancel
             ? 'query-style'
             : ''
         ]"
@@ -188,12 +299,10 @@ defineExpose({
         @mouseenter="msg.isShowFeedback = true"
         @mouseleave="msg.isShowFeedback = false"
       >
-        <!-- 请求失败后的提示icon -->
-        <span
-          v-if="queryTime === -3 && index === messages.length - 1"
-          class="font_family icon-icon_warning_fill_b"
-          style="margin-top: 1px; color: #c9353f"
-        ></span>
+        <!-- 请求失败后的提示icon   -->
+        <div class="pause-bg" v-if="msg.isError">
+          <span class="pause-icon font_family icon-icon_warning_fill_b"></span>
+        </div>
         <!-- loading icon -->
         <img
           class="loading-img"
@@ -201,7 +310,15 @@ defineExpose({
           src="./image/icon_loading.png"
           alt=""
         />
-        {{ msg.content }}
+        <span v-if="!msg.isAnswer">{{ msg.content }}</span>
+        <div v-else>
+          <div v-html="renderedMessage(msg.content)" class="markdown-body"></div>
+          <LoadingDots
+            v-if="index === messages.length - 1 && msg.isAnswer && loadingAnswer"
+          ></LoadingDots>
+          <div></div>
+        </div>
+        <!-- 评价  -->
         <div class="review" v-if="msg.isShowFeedback && msg.isAnswer">
           <el-button
             v-if="msg.feedback !== 'good'"
@@ -236,27 +353,38 @@ defineExpose({
         <!-- 暂停回答 icon -->
         <div
           class="pause-btn"
-          v-if="index === messages.length - 1 && queryTime > 30 && queryTime < 120"
+          v-if="index === messages.length - 1 && queryTime > 29 && queryTime < 120"
           @click="handlePause"
         >
           <div class="dot"></div>
         </div>
       </div>
+      <!-- 滚动到底部icon -->
+      <div v-if="showScrollButton" class="scroll-to-bottom-btn" @click="scrollToBottom">
+        <span class="font_family icon-icon_movedown_b"></span>
+      </div>
     </div>
 
-    <div class="footer-input" :class="[isFooterInputFocus ? 'focus-style' : '']">
-      <AutoResizeTextarea
-        v-model="userQuestion"
-        :placeholder="'Type your question here...'"
-        @focus="isFooterInputFocus = true"
-        @blur="isFooterInputFocus = false"
-      />
-      <div
-        class="input-icon"
-        :class="[userQuestion ? 'input-style' : 'disable']"
-        @click="handleSend"
-      >
-        <span class="font_family icon-icon_send_b"></span>
+    <div
+      class="footer"
+      :class="[isFooterInputFocus ? 'focus-style' : '', isShowFooterShadow ? 'box-shadow' : '']"
+    >
+      <div class="footer-input">
+        <AutoResizeTextarea
+          style="flex: 1"
+          v-model="userQuestion"
+          :placeholder="'Type your question here...'"
+          @focus="isFooterInputFocus = true"
+          @blur="isFooterInputFocus = false"
+        />
+        <el-button @click="simulateStreamingMarkdown">测试</el-button>
+        <div
+          class="input-icon"
+          :class="[!userQuestion || queryTime !== -1 ? 'disable' : '']"
+          @click="handleSend(userQuestion, false)"
+        >
+          <span class="font_family icon-icon_send_b"></span>
+        </div>
       </div>
     </div>
   </div>
@@ -277,18 +405,23 @@ defineExpose({
   background-color: var(--color-dialog-body-bg);
   overflow: hidden;
   .top-section {
-    height: 150px;
+    position: relative;
+    padding-bottom: 16px;
     background: linear-gradient(
       to bottom,
       var(--color-ai-chat-header-bg-gradient-begin) 10%,
       var(--color-ai-chat-header-bg-gradient-begin) 10%,
       var(--color-ai-chat-header-bg-gradient-end) 100%
     );
+    &.box-shadow {
+      box-shadow: -2px 0px 12px rgba(0, 0, 0, 0.1);
+    }
     .header {
       display: flex;
       justify-content: space-between;
       align-items: center;
       height: 64px;
+      margin-bottom: 6px;
       padding: 0 16px;
       .welcome {
         font-size: 18px;
@@ -307,13 +440,45 @@ defineExpose({
         }
       }
     }
+    .warning-tips {
+      position: absolute;
+      top: 60px;
+      left: 17px;
+      width: calc(100% - 32px);
+      height: 40px;
+      padding-top: 14px;
+      background-color: var(--color-warning-tips-bg);
+      border-radius: 6px;
+      text-align: center;
+      .warning-bg {
+        position: relative;
+        display: inline-flex;
+        align-items: center;
+        justify-content: center;
+        height: 12px;
+        width: 12px;
+        margin-right: 6px;
+        border-radius: 50%;
+        background-color: #fff;
+      }
+      .warning-icon {
+        position: absolute;
+        top: -3px;
+        border-radius: 50%;
+        border: none;
+      }
+      span {
+        color: #edb82f;
+      }
+    }
   }
+
   .chat-messages {
     flex: 1;
     display: flex;
     flex-direction: column;
     gap: 16px;
-    padding: 0 16px;
+    padding: 0 16px 18px;
     overflow: auto;
     .message-item {
       position: relative;
@@ -333,20 +498,30 @@ defineExpose({
         height: 30px;
         margin-top: 10px;
         padding-left: 30px;
-        padding-top: 10px;
+        padding-top: 5px;
 
         button.el-button + .el-button {
           margin-left: 0px;
         }
       }
-      .review-input-card {
-        margin-top: 6px;
-        padding: 8px;
-        text-align: right;
-        box-shadow: 1px 1px 12px 0px rgba(0, 0, 0, 0.05);
-        border-radius: 6px;
+      .pause-bg {
+        position: relative;
+        display: inline-flex;
+        align-items: center;
+        justify-content: center;
+        height: 12px;
+        width: 12px;
+        margin-right: 6px;
+        border-radius: 50%;
+        background-color: #fff;
+      }
+      .pause-icon {
+        position: absolute;
+        top: -2px;
+        color: #c9353f;
+        border-radius: 50%;
+        border: none;
       }
-
       .el-button--text {
         height: 16px;
         width: 16px;
@@ -365,10 +540,12 @@ defineExpose({
         width: 16px;
         height: 16px;
         margin-top: -1px;
-        margin-right: 2px;
+        margin-right: 4px;
         animation: loading-rotate 2s linear infinite;
       }
-
+      .markdown-body {
+        background: transparent;
+      }
       .pause-btn {
         position: absolute;
         right: -22px;
@@ -389,7 +566,9 @@ defineExpose({
       }
     }
     .query-style {
-      color: #b5b9bf;
+      span {
+        color: #b5b9bf;
+      }
     }
     .robot-bubble {
       background: var(--scoring-bg-color);
@@ -413,6 +592,50 @@ defineExpose({
         bottom: -7px;
       }
     }
+    .scroll-to-bottom-btn {
+      position: absolute;
+      right: 50%;
+      transform: translateX(50%);
+      bottom: 58px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      height: 32px;
+      width: 32px;
+      border-radius: 50%;
+      background-color: #f5f4f4;
+      box-shadow: 2px 2px 12px 0px rgba(0, 0, 0, 0.1);
+      span {
+        color: #2b2f36;
+      }
+      cursor: pointer;
+      &:hover {
+        background-color: var(--color-theme);
+        span {
+          color: #fff;
+        }
+      }
+    }
+  }
+  .footer {
+    padding: 12px 16px;
+    &.box-shadow {
+      box-shadow: 0px 2px 12px rgba(0, 0, 0, 0.1);
+    }
+    &.focus-style {
+      .footer-input {
+        border: 1px solid var(--color-theme);
+      }
+      .input-icon {
+        background-color: var(--color-theme);
+        span {
+          color: #fff;
+        }
+        &:hover {
+          background-color: #d56200;
+        }
+      }
+    }
   }
   .footer-input {
     display: flex;
@@ -420,10 +643,10 @@ defineExpose({
     gap: 12px;
     padding: 4px 12px;
     padding-right: 4px;
-    margin: 12px 16px;
     border: 1px solid var(--input-border);
     border-radius: 20px;
     box-sizing: border-box;
+
     .input-icon {
       display: flex;
       justify-content: center;
@@ -437,39 +660,8 @@ defineExpose({
         cursor: not-allowed;
       }
     }
-    .input-style {
-      background-color: var(--color-theme);
-      span {
-        color: #fff;
-      }
-      &:hover {
-        background-color: #d56200;
-      }
-    }
-    &.focus-style {
-      border: 1px solid var(--color-theme);
-    }
   }
 
-  // .input-area {
-  //   width: 100%;
-  //   font-size: 14px;
-  //   line-height: 21px;
-  //   padding: 4px;
-  //   resize: none;
-  //   overflow-y: hidden; // 默认不显示滚动条
-  //   height: 40px; // 初始高度(1 行)
-  //   max-height: 100px; // 最多 4 行
-  //   box-sizing: border-box;
-  //   border: none;
-  //   outline-color: #fff;
-  //   border-radius: 8px;
-  //   transition: height 0.1s ease;
-  //   &::placeholder {
-  //     color: #b5b9bf;
-  //     opacity: 1;
-  //   }
-  // }
   @keyframes loading-rotate {
     0% {
       transform: rotate(0deg);

+ 97 - 81
src/views/AIRobotChat/src/components/AIQuestions.vue

@@ -37,134 +37,150 @@ const DeQuestions = ref([
     isLong: false
   },
   {
-    label: 'List shipments with ETA changes in the last 30 days11111111111111111111111111111111111.',
-    value: 'List shipments with ETA changes in the last 30 days11111111111111111111111111111111111.',
+    label:
+      'List shipments with ETA changes in the last 30 days11111111111111111111111111111111111.',
+    value:
+      'List shipments with ETA changes in the last 30 days11111111111111111111111111111111111.',
     isLong: true
   },
   {
-    label: 'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111122.',
-    value: 'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111122.',
+    label:
+      'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111122.',
+    value:
+      'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111122.',
     isLong: true
   },
   {
-    label: 'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111133.',
-    value: 'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111133.',
+    label:
+      'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111133.',
+    value:
+      'List shipments with ETA changes in the last 30 days1111111111111111111111111111111111133.',
     isLong: true
-  },
+  }
 ])
-const itemGroups = ref([]);
-const pages = ref([]);
+const itemGroups = ref([])
+const pages = ref([])
 // 随机显示方法
 const prepareGroups = () => {
-  const groups = [];
-  let currentGroup = [];
-  let currentHeight = 0;
+  const groups = []
+  let currentGroup = []
+  let currentHeight = 0
+
+  DeQuestions.value.forEach((item) => {
+    const itemHeight = item.isLong ? 2 : 1
 
-  DeQuestions.value.forEach(item => {
-    const itemHeight = item.isLong ? 2 : 1;
-    
     if (currentHeight + itemHeight > 4) {
-      groups.push(currentGroup);
-      currentGroup = [];
-      currentHeight = 0;
+      groups.push(currentGroup)
+      currentGroup = []
+      currentHeight = 0
     }
-    
-    currentGroup.push(item);
-    currentHeight += itemHeight;
-  });
+
+    currentGroup.push(item)
+    currentHeight += itemHeight
+  })
 
   // 添加最后一组
   if (currentGroup.length > 0) {
-    groups.push(currentGroup);
+    groups.push(currentGroup)
   }
 
-  itemGroups.value = groups;
+  itemGroups.value = groups
 }
 // 智能分页算法
 const generatePages = () => {
-  const result = [];
-  let currentPage = { row1: [], row2: [] };
-  let cursor = 0;
-  
-  while(cursor < DeQuestions.value.length) {
+  const result = []
+  let currentPage = { row1: [], row2: [] }
+  let cursor = 0
+
+  while (cursor < DeQuestions.value.length) {
     // 处理第一排
-    const currentItem = DeQuestions.value[cursor];
+    const currentItem = DeQuestions.value[cursor]
     // 第一排逻辑
-    if(currentItem.isLong) {
+    if (currentItem.isLong) {
       // 长文本独占第一排
-      currentPage.row1.push(currentItem);
-      cursor++;
+      currentPage.row1.push(currentItem)
+      cursor++
     } else {
       // 尝试取两个短文本
-      const nextItem = DeQuestions.value[cursor + 1];
-      if(nextItem && !nextItem.isLong) {
-        currentPage.row1.push(currentItem, nextItem);
-        cursor += 2;
+      const nextItem = DeQuestions.value[cursor + 1]
+      if (nextItem && !nextItem.isLong) {
+        currentPage.row1.push(currentItem, nextItem)
+        cursor += 2
       } else {
-        currentPage.row1.push(currentItem);
-        cursor++;
+        currentPage.row1.push(currentItem)
+        cursor++
       }
     }
 
     // 处理第二排
-    const remaining = DeQuestions.value.slice(cursor);
-    if(remaining.length > 0) {
-      const secondItem = remaining[0];
-      
-      if(secondItem.isLong) {
-        currentPage.row2.push(secondItem);
-        cursor++;
+    const remaining = DeQuestions.value.slice(cursor)
+    if (remaining.length > 0) {
+      const secondItem = remaining[0]
+
+      if (secondItem.isLong) {
+        currentPage.row2.push(secondItem)
+        cursor++
       } else {
-        const nextSecondItem = remaining[1];
-        if(nextSecondItem && !nextSecondItem.isLong) {
-          currentPage.row2.push(secondItem, nextSecondItem);
-          cursor += 2;
+        const nextSecondItem = remaining[1]
+        if (nextSecondItem && !nextSecondItem.isLong) {
+          currentPage.row2.push(secondItem, nextSecondItem)
+          cursor += 2
         } else {
-          currentPage.row2.push(secondItem);
-          cursor++;
+          currentPage.row2.push(secondItem)
+          cursor++
         }
       }
     }
 
     // 保存当前页
-    result.push(currentPage);
-    
+    result.push(currentPage)
+
     // 重置页面
-    currentPage = { row1: [], row2: [] };
+    currentPage = { row1: [], row2: [] }
   }
-  pages.value = result.filter(p => p.row1.length > 0);
-}
-
-// 点击问题
-const emits = defineEmits(['handelClickAIQuestion'])
-const handelClick = (item: any) => {
-  emits('handelClickAIQuestion',item)
+  pages.value = result.filter((p) => p.row1.length > 0)
+  console.log(pages.value)
 }
 onMounted(() => {
   prepareGroups()
   generatePages()
-});
+})
+
+const emit = defineEmits<{ question: [string] }>()
+const clickQuestion = (question) => {
+  emit('question', question)
+}
 </script>
 <template>
   <div class="flex_center">
-    <div class="dialogue_content ">
+    <div class="dialogue_content">
       <div class="dialogue_content_title">
         <div class="dialogue_title_left">
-          <img class="dialogue_title_left_img" src="../image/icon_ai_robot48_b@2x.png" width="48px" />
+          <img
+            class="dialogue_title_left_img"
+            src="../image/icon_ai_robot48_b@2x.png"
+            width="48px"
+          />
           <div class="dialogue_title_left_text">Frequently Asked Questions</div>
         </div>
       </div>
-      <el-carousel v-if="props.modalSize === 'large'"  class="carousel large_carousel" :autoplay="false" height="115px" >
-        <el-carousel-item 
-          v-for="(page, index) in pages "
-          :key="index"
-        >
+      <el-carousel
+        v-if="props.modalSize === 'large'"
+        class="carousel large_carousel"
+        :autoplay="false"
+        height="115px"
+      >
+        <el-carousel-item v-for="(page, index) in pages" :key="index">
           <div class="dialogue_container dialogue_container_large">
             <div class="double-row-layout">
               <!-- 第一排 -->
               <div class="row first-row">
                 <template v-for="item in page.row1" :key="item.id">
-                  <div @click="handelClick(item.label)" class="dialogue_content_item" :class="{ 'long-item': item.isLong }">
+                  <div
+                    @click="clickQuestion(item.label)"
+                    class="dialogue_content_item"
+                    :class="{ 'long-item': item.isLong }"
+                  >
                     {{ item.label }}
                   </div>
                 </template>
@@ -172,7 +188,11 @@ onMounted(() => {
               <!-- 第二排 -->
               <div class="row second-row">
                 <template v-for="item in page.row2" :key="item.id">
-                  <div @click="handelClick(item.label)"  class="dialogue_content_item" :class="{ 'long-item': item.isLong }">
+                  <div
+                    @click="clickQuestion(item.label)"
+                    class="dialogue_content_item"
+                    :class="{ 'long-item': item.isLong }"
+                  >
                     {{ item.label }}
                   </div>
                 </template>
@@ -181,17 +201,14 @@ onMounted(() => {
           </div>
         </el-carousel-item>
       </el-carousel>
-      <el-carousel v-else  class="carousel small_carousel" :autoplay="false" height="190px" >
-        <el-carousel-item 
-          v-for="(group, index) in itemGroups "
-          :key="index"
-        >
+      <el-carousel v-else class="carousel small_carousel" :autoplay="false" height="190px">
+        <el-carousel-item v-for="(group, index) in itemGroups" :key="index">
           <div class="dialogue_container">
-            <div 
+            <div
               class="dialogue_content_item"
               v-for="item in group"
               :key="item.label"
-              @click="handelClick(item.label)"
+              @click="clickQuestion(item.label)"
               :class="{ 'long_item': item.isLong }"
             >
               {{ item.label }}
@@ -212,7 +229,7 @@ onMounted(() => {
 }
 .dialogue_title_left_img {
   position: absolute;
-  top: -22px;
+  top: -20px;
 }
 .dialogue_title_left_text {
   background: var(--color-dialogue_title);
@@ -271,4 +288,3 @@ onMounted(() => {
   padding-bottom: 0 !important;
 }
 </style>
-

+ 46 - 0
src/views/AIRobotChat/src/components/LoadingDots.vue

@@ -0,0 +1,46 @@
+<template>
+  <div class="loading-dots">
+    <span class="dot"></span>
+    <span class="dot"></span>
+    <span class="dot"></span>
+  </div>
+</template>
+
+<style scoped>
+.loading-dots {
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  gap: 6px;
+  height: 24px;
+}
+
+.dot {
+  width: 4px;
+  height: 4px;
+  border-radius: 50%;
+  background-color: var(--color-theme);
+  animation: bounce 1.4s infinite ease-in-out both;
+}
+
+.dot:nth-child(1) {
+  animation-delay: 0s;
+}
+.dot:nth-child(2) {
+  animation-delay: 0.2s;
+}
+.dot:nth-child(3) {
+  animation-delay: 0.4s;
+}
+
+@keyframes bounce {
+  0%,
+  80%,
+  100% {
+    transform: translateY(0);
+  }
+  40% {
+    transform: translateY(-4px);
+  }
+}
+</style>

+ 0 - 1
src/views/Layout/src/LayoutView.vue

@@ -54,7 +54,6 @@ const handelClickAIDefault = async  (item :any) => {
 
     <!-- 右侧整体布局 -->
     <el-container style="min-width: 900px">
-      <el-button @click="onClick">测试</el-button>
       <!-- 顶部Header -->
       <el-header class="layout-header">
         <Header></Header>

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

@@ -149,7 +149,6 @@ div.layout-toolbar {
     background-color: var(--color-dialog-body-bg);
   }
   .password-notifications {
-    margin-bottom: 16px;
     .header {
       display: flex;
       align-items: center;
@@ -187,8 +186,6 @@ div.layout-toolbar {
     }
   }
   .feature-update {
-    margin-bottom: 16px;
-
     .header {
       display: flex;
       align-items: center;

+ 6 - 0
src/views/Layout/src/components/Header/components/TrainingCard.vue

@@ -164,5 +164,11 @@ const closeMessage = () => {
   :deep(.notification-card) {
     margin-bottom: 0px;
   }
+  :deep(.feature-update) {
+    margin-bottom: 0px;
+  }
+  :deep(.password-notifications) {
+    margin-bottom: 0px;
+  }
 }
 </style>

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

@@ -229,7 +229,7 @@ const checkPassword = () => {
       </div>
       <template #footer>
         <div class="license">
-          <span>© KERRY LOGISTICS NETWORK LIMITED. ALL RIGHTS RESERVED.</span>
+          <span>© KLN LOGISTICS GROUP LIMITED. ALL RIGHTS RESERVED.</span>
         </div>
       </template>
     </el-card>
@@ -253,7 +253,7 @@ const checkPassword = () => {
 }
 
 .login-card {
-  width: 410px;
+  width: 400px;
   border-radius: 12px;
   .title {
     display: flex;

+ 3 - 3
src/views/Login/src/loginView.vue

@@ -394,7 +394,7 @@ const firstLoginTipsRef = ref()
       </div>
       <template #footer>
         <div class="license">
-          <span>© KERRY LOGISTICS NETWORK LIMITED. ALL RIGHTS RESERVED.</span>
+          <span>© KLN LOGISTICS GROUP LIMITED. ALL RIGHTS RESERVED.</span>
         </div>
       </template>
     </el-card>
@@ -449,7 +449,7 @@ const firstLoginTipsRef = ref()
       </div>
       <template #footer>
         <div class="license">
-          <span>© KERRY LOGISTICS NETWORK LIMITED. ALL RIGHTS RESERVED.</span>
+          <span>© KLN LOGISTICS GROUP LIMITED. ALL RIGHTS RESERVED.</span>
         </div>
       </template>
     </el-card>
@@ -487,7 +487,7 @@ const firstLoginTipsRef = ref()
 }
 
 .login-card {
-  width: 410px;
+  width: 400px;
 
   .card-title {
     display: flex;

+ 7 - 2
src/views/SystemMessage/src/SystemMessage.vue

@@ -192,7 +192,7 @@ onMounted(() => {
                 <span>{{ handleCount(unreadNotificationList.length) }}</span>
               </div>
             </template>
-            <div style="padding: 10px 140px 0px 16px" v-if="activeTabName === 'Unread'">
+            <div style="padding-bottom: 20px" v-if="activeTabName === 'Unread'">
               <NotificationMessageCard
                 v-if="activeTabName === 'Unread'"
                 :data="unreadNotificationList"
@@ -203,7 +203,7 @@ onMounted(() => {
           </el-tab-pane>
           <el-tab-pane label="Read" name="Read">
             <template #label><span style="margin-right: 4px">Read</span> </template>
-            <div style="padding: 10px 140px 0px 16px" v-if="activeTabName === 'Read'">
+            <div style="padding-bottom: 20px" v-if="activeTabName === 'Read'">
               <NotificationMessageCard
                 v-if="activeTabName === 'Read'"
                 :updateReadCardsOnChange="false"
@@ -322,5 +322,10 @@ onMounted(() => {
       height: 100%;
     }
   }
+  :deep {
+    .scroller {
+      padding-top: 10px;
+    }
+  }
 }
 </style>

+ 1 - 0
src/views/Tracking/src/TrackingView.vue

@@ -259,6 +259,7 @@ const DateRangeSearch = (val: any, value: any) => {
 }
 //MoreFiltersSearch
 const MoreFiltersSearch = (val: any, value: any) => {
+  console.log(val,value)
   filterData.morefiltersData = []
   if (Object.keys(value).length == 0) {
     delete searchTableQeuryTracking.shipper

+ 5 - 5
src/views/Tracking/src/components/TrackingDetail/src/TrackingDetail.vue

@@ -146,11 +146,11 @@ const SubscribeShipments = () => {
 <template>
   <div class="tracking-detail" v-vloading="loading">
     <!-- 分享链接 -->
-    <div class="share-link" @click="openShareDialog">
-      <el-tooltip content="Share" :offset="4">
+    <el-tooltip content="Share" :offset="4" placement="top">
+      <div class="share-link" @click="openShareDialog">
         <span class="font_family icon-icon_share_b share-icon"></span>
-      </el-tooltip>
-    </div>
+      </div>
+    </el-tooltip>
     <div class="header" :class="{ 'is-dark': themeStore.theme === 'dark' }">
       <div class="detail-status">
         <span
@@ -497,7 +497,7 @@ const SubscribeShipments = () => {
   }
   .share-link {
     position: fixed;
-    bottom: 152px;
+    bottom: 248px;
     right: 20px;
     display: flex;
     align-items: center;

+ 1 - 1
vite.config.ts

@@ -8,7 +8,7 @@ import Icons from 'unplugin-icons/vite'
 import IconsResolver from 'unplugin-icons/resolver'
 
 // https://vitejs.dev/config/
-export default defineConfig((mode) => {
+export default defineConfig(({ mode }) => {
   const env = loadEnv(mode, process.cwd())
   return {
     base: env.VITE_BASE_URL || '/',

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно