Просмотр исходного кода

Merge branch 'dev_zyh' of United_Software/k_online_ui into dev

Jack Zhou 1 год назад
Родитель
Сommit
c70520245a

+ 3 - 0
index.html

@@ -4,6 +4,9 @@
     <meta charset="UTF-8" />
     <meta charset="UTF-8" />
     <link rel="icon" href="/favicon.ico" />
     <link rel="icon" href="/favicon.ico" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
+    <meta http-equiv="Pragma" content="no-cache" />
+    <meta http-equiv="Expires" content="0" />
     <title>online</title>
     <title>online</title>
   </head>
   </head>
   <body>
   <body>

+ 1 - 0
package.json

@@ -22,6 +22,7 @@
     "@wangeditor/editor-for-vue": "^5.1.12",
     "@wangeditor/editor-for-vue": "^5.1.12",
     "ant-design-vue": "^4.2.3",
     "ant-design-vue": "^4.2.3",
     "axios": "^1.7.5",
     "axios": "^1.7.5",
+    "crypto-js": "^4.2.0",
     "dayjs": "^1.11.13",
     "dayjs": "^1.11.13",
     "echarts": "^5.5.1",
     "echarts": "^5.5.1",
     "element-plus": "^2.8.1",
     "element-plus": "^2.8.1",

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

@@ -3,6 +3,7 @@
 // @ts-nocheck
 // @ts-nocheck
 // noinspection JSUnusedGlobalSymbols
 // noinspection JSUnusedGlobalSymbols
 // Generated by unplugin-auto-import
 // Generated by unplugin-auto-import
+// biome-ignore lint: disable
 export {}
 export {}
 declare global {
 declare global {
   const $api: typeof import('@/api/index')['default']
   const $api: typeof import('@/api/index')['default']
@@ -68,6 +69,6 @@ declare global {
 // for type re-export
 // for type re-export
 declare global {
 declare global {
   // @ts-ignore
   // @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')
   import('vue')
 }
 }

+ 10 - 6
src/router/index.ts

@@ -94,6 +94,11 @@ const router = createRouter({
 
 
 // * 路由拦截 beforeEach
 // * 路由拦截 beforeEach
 router.beforeEach(async (to, from, next) => {
 router.beforeEach(async (to, from, next) => {
+  // 如果手动跳转登录页,清除登录信息
+  if (to.path === '/login') {
+    const userStore = useUserStore()
+    userStore.clearUsername()
+  }
   // 未登录白名单
   // 未登录白名单
   const whiteList = ['/login', '/public-tracking', '/public-tracking/detail', '/reset-password']
   const whiteList = ['/login', '/public-tracking', '/public-tracking/detail', '/reset-password']
   // 判断是否登录
   // 判断是否登录
@@ -101,17 +106,16 @@ router.beforeEach(async (to, from, next) => {
     const userStore = useUserStore()
     const userStore = useUserStore()
     userStore.clearUsername()
     userStore.clearUsername()
     if (whiteList.includes(from.path)) {
     if (whiteList.includes(from.path)) {
-      ElMessage.warning('Please log in to use this feature.')
+      ElMessage.warning({
+        message: 'Please log in to use this feature.',
+        grouping: true
+      })
       next(false)
       next(false)
       return
       return
     } else {
     } else {
-      next('/public-tracking')
+      next('/login')
     }
     }
   }
   }
-  if (to.path === '/Login') {
-    const userStore = useUserStore()
-    userStore.clearUsername()
-  }
   next()
   next()
 })
 })
 
 

+ 23 - 0
src/styles/elementui.scss

@@ -236,6 +236,9 @@ div.el-message {
   display: flex;
   display: flex;
   justify-content: center;
   justify-content: center;
   width: 800px;
   width: 800px;
+  .el-badge.el-message__badge {
+    display: none;
+  }
 }
 }
 div.el-message--error {
 div.el-message--error {
   --el-message-bg-color: #faebec;
   --el-message-bg-color: #faebec;
@@ -361,6 +364,26 @@ div .el-checkbox__input.is-checked .el-checkbox__inner {
   background-color: var(--color-theme);
   background-color: var(--color-theme);
   border-color: var(--color-theme);
   border-color: var(--color-theme);
 }
 }
+div .el-checkbox.el-checkbox--large .el-checkbox__inner {
+  height: 16px;
+  width: 16px;
+  font-size: 16px;
+  border-radius: 3px;
+}
+div .el-checkbox--large .el-checkbox__label {
+  margin-top: 1px;
+  padding-left: 4px;
+}
+span.el-checkbox__input.is-checked + .el-checkbox__label {
+  color: var(--color-neutral-2);
+}
+/* 修改选中时打勾图标的大小 */
+span.el-checkbox__inner::after {
+  left: 4px; /* 调整左边距 */
+  top: 0px; /* 调整上边距 */
+  width: 5px; /* 打勾图标宽度 */
+  height: 10px; /* 打勾图标高度 */
+}
 div .el-popper__arrow,
 div .el-popper__arrow,
 div .el-popper__arrow:before {
 div .el-popper__arrow:before {
   height: 0;
   height: 0;

+ 4 - 1
src/utils/axios.ts

@@ -60,7 +60,10 @@ class HttpAxios {
         const userStore = useUserStore()
         const userStore = useUserStore()
         userStore.clearUsername()
         userStore.clearUsername()
         router.push('/login')
         router.push('/login')
-        ElMessage.warning('Please log in to use this feature.')
+        ElMessage.warning({
+          message: 'Please log in to use this feature.',
+          grouping: true
+        })
       } else if (response.data.code !== 200 && response.data.code !== 400) {
       } else if (response.data.code !== 200 && response.data.code !== 400) {
         ElMessageBox.alert(
         ElMessageBox.alert(
           response.data?.data?.msg || 'The request failed. Please try again later',
           response.data?.data?.msg || 'The request failed. Please try again later',

+ 0 - 1
src/views/Booking/src/BookingView.vue

@@ -9,7 +9,6 @@ import { ref, reactive, onMounted } from 'vue'
 import { useCalculatingHeight } from '@/hooks/calculatingHeight'
 import { useCalculatingHeight } from '@/hooks/calculatingHeight'
 
 
 const filterRef: Ref<HTMLElement | null> = ref(null)
 const filterRef: Ref<HTMLElement | null> = ref(null)
-// const containerHeight: any = ref(0)
 
 
 const containerHeight = useCalculatingHeight(document.documentElement, 246, [filterRef])
 const containerHeight = useCalculatingHeight(document.documentElement, 246, [filterRef])
 
 

+ 30 - 22
src/views/Booking/src/components/BookingTable/src/BookingTable.vue

@@ -42,7 +42,10 @@ const handleColumns = (columns: any, status?: string) => {
     } else if (item.type === 'mode' && status !== 'all') {
     } else if (item.type === 'mode' && status !== 'all') {
       curColumn = {
       curColumn = {
         ...curColumn,
         ...curColumn,
-        slots: { default: 'mode' }
+        slots: { default: 'mode' },
+        formatter: ({ cellValue }: any) => {
+          return cellValue
+        }
       }
       }
     }
     }
     // 格式化
     // 格式化
@@ -103,12 +106,13 @@ const getTableData = async (isInit: boolean, isPageChange?: boolean) => {
     })
     })
     .then((res: any) => {
     .then((res: any) => {
       if (res.code === 200) {
       if (res.code === 200) {
-        bookingTable.value.data = res.data.searchData
+        bookingTable.value.data = res.data.searchData || []
         pageInfo.value.total = Number(res.data.rc)
         pageInfo.value.total = Number(res.data.rc)
         // 拥有所有字段的表格
         // 拥有所有字段的表格
         setTimeout(() => {
         setTimeout(() => {
           allTable.value.columns = handleColumns(res.data.allColums, 'all')
           allTable.value.columns = handleColumns(res.data.allColums, 'all')
-          allTable.value.data = res.data.searchData
+          allTable.value.data = res.data.searchData || []
+          // 为了让导出的表格列宽度自适应
           nextTick(() => {
           nextTick(() => {
             allTableRef.value && autoWidth(allTable.value, allTableRef.value)
             allTableRef.value && autoWidth(allTable.value, allTableRef.value)
           })
           })
@@ -140,9 +144,18 @@ const searchTableData = (data: any) => {
             query: { a: res.data.searchData.__serial_no, _schemas: res.data.searchData.__schemas }
             query: { a: res.data.searchData.__serial_no, _schemas: res.data.searchData.__schemas }
           })
           })
         } else {
         } else {
-          bookingTable.value.data = res.data.searchData
+          bookingTable.value.data = res.data.searchData || []
           pageInfo.value.total = Number(res.data.rc)
           pageInfo.value.total = Number(res.data.rc)
           tableLoading.value = false
           tableLoading.value = false
+          // 拥有所有字段的表格
+          setTimeout(() => {
+            allTable.value.columns = handleColumns(res.data.allColums, 'all')
+            allTable.value.data = res.data.searchData || []
+            // 为了让导出的表格列宽度自适应
+            nextTick(() => {
+              allTableRef.value && autoWidth(allTable.value, allTableRef.value)
+            })
+          }, 1000)
         }
         }
       }
       }
     })
     })
@@ -255,25 +268,22 @@ const handleDownload = () => {
   downloadDialogRef.value.openDialog(props.tagsData, curSelectedColumns)
   downloadDialogRef.value.openDialog(props.tagsData, curSelectedColumns)
 }
 }
 
 
-// 导出表格
+// 导出表格 status: 1 导出当前表格 2 导出所有字段表格
 const exportTable = (status: number) => {
 const exportTable = (status: number) => {
+  const exportConfig: any = {
+    type: 'xlsx',
+    message: false,
+    filename: `Booking List_${dayjs().format('YYYYMMDDHH[h]mm[m]ss[s]')}`
+  }
   if (status === 1) {
   if (status === 1) {
-    tableRef.value?.exportData({
-      type: 'xlsx',
-      message: false,
-      filename: `Booking List_${dayjs().format('YYYYMMDDHH[h]mm[m]ss[s]')}`,
-      columnFilterMethod: ({ column }: any) => {
-        // 排除复选框列
-        return column.field
-      }
-    })
-  } else {
-    allTableRef.value?.exportData({
-      type: 'xlsx',
-      message: false,
-      filename: `Booking List_${dayjs().format('YYYYMMDDHH[h]mm[m]ss[s]')}`
-    })
+    exportConfig.columnFilterMethod = ({ column }: any) => {
+      const index = bookingTable.value.columns.findIndex((item: any) => item.field === column.field)
+      // 排除复选框列
+      return column.field && index !== -1
+    }
+    exportConfig.columns = bookingTable.value.columns
   }
   }
+  allTableRef.value?.exportData(exportConfig)
 }
 }
 
 
 const tableLoading = ref(false)
 const tableLoading = ref(false)
@@ -465,8 +475,6 @@ defineExpose({
     position: absolute;
     position: absolute;
     top: -100000px;
     top: -100000px;
     width: 20px;
     width: 20px;
-    opacity: 0;
-    visibility: hidden;
   }
   }
 }
 }
 </style>
 </style>

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

@@ -13,6 +13,9 @@ const headerSearch = useHeaderSearch()
 
 
 const searchValue = ref('')
 const searchValue = ref('')
 const handleSearch = () => {
 const handleSearch = () => {
+  if (!searchValue.value) {
+    return
+  }
   // 先判断是否登录
   // 先判断是否登录
   // 未登录
   // 未登录
   if (!localStorage.getItem('username')) {
   if (!localStorage.getItem('username')) {

+ 4 - 13
src/views/Layout/src/components/Menu/MenuView.vue

@@ -96,18 +96,6 @@ onUnmounted(() => {
 const activeMenu = ref()
 const activeMenu = ref()
 activeMenu.value = (route.meta?.activeMenu as string) || route.path
 activeMenu.value = (route.meta?.activeMenu as string) || route.path
 
 
-const getAllMenuPaths = (menuList: any) => {
-  let paths: any = []
-  menuList.forEach((item: any) => {
-    paths.push(item.path) // 添加主菜单路径
-    if (item.children && item.children.length > 0) {
-      // 递归添加子菜单路径
-      paths = paths.concat(getAllMenuPaths(item.children))
-    }
-  })
-  return paths
-}
-
 // 未登录白名单
 // 未登录白名单
 const whiteList = ['/login', '/public-tracking', '/public-tracking/detail', '/reset-password']
 const whiteList = ['/login', '/public-tracking', '/public-tracking/detail', '/reset-password']
 
 
@@ -115,7 +103,10 @@ const whiteList = ['/login', '/public-tracking', '/public-tracking/detail', '/re
 const isAllowJump = (path: any) => {
 const isAllowJump = (path: any) => {
   // 判断是否登录
   // 判断是否登录
   if (!whiteList.includes(path) && !localStorage.getItem('username')) {
   if (!whiteList.includes(path) && !localStorage.getItem('username')) {
-    ElMessage.warning('Please log in to use this feature.')
+    ElMessage.warning({
+      message: 'Please log in to use this feature.',
+      grouping: true
+    })
     activeMenu.value = route.path // 保持选中状态不变
     activeMenu.value = route.path // 保持选中状态不变
     return false
     return false
   }
   }

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

@@ -96,14 +96,6 @@ const handleForgot = () => {
     }
     }
   })
   })
 }
 }
-const handleBackLogin = () => {
-  router.push({
-    name: 'Login',
-    query: {
-      status: 'login'
-    }
-  })
-}
 
 
 const hasUppercase = ref(false)
 const hasUppercase = ref(false)
 const hasLowercase = ref(false)
 const hasLowercase = ref(false)
@@ -111,16 +103,12 @@ const hasNumber = ref(false)
 const isValidLength = ref(false)
 const isValidLength = ref(false)
 const checkPassword = () => {
 const checkPassword = () => {
   const pwd = loginForm.value.newPassword
   const pwd = loginForm.value.newPassword
-
   // 检测是否包含大写字母
   // 检测是否包含大写字母
   hasUppercase.value = /[A-Z]/.test(pwd)
   hasUppercase.value = /[A-Z]/.test(pwd)
-
   // 检测是否包含小写字母
   // 检测是否包含小写字母
   hasLowercase.value = /[a-z]/.test(pwd)
   hasLowercase.value = /[a-z]/.test(pwd)
-
   // 检测是否包含数字
   // 检测是否包含数字
   hasNumber.value = /[0-9]/.test(pwd)
   hasNumber.value = /[0-9]/.test(pwd)
-
   // 检测长度是否符合要求
   // 检测长度是否符合要求
   isValidLength.value = pwd.length >= 12 && pwd.length <= 20
   isValidLength.value = pwd.length >= 12 && pwd.length <= 20
 }
 }
@@ -224,10 +212,6 @@ const checkPassword = () => {
         <el-button @click="handleChangePwd" class="el-button--dark login-btn"
         <el-button @click="handleChangePwd" class="el-button--dark login-btn"
           >Change Password</el-button
           >Change Password</el-button
         >
         >
-        <div @click="handleBackLogin" class="back-text">
-          <span class="font_family icon-icon_back_b"></span>
-          <span class="text"> Back to login</span>
-        </div>
       </div>
       </div>
       <template #footer>
       <template #footer>
         <div class="license">
         <div class="license">
@@ -392,25 +376,6 @@ const checkPassword = () => {
     color: var(--color-danger);
     color: var(--color-danger);
     line-height: 14px;
     line-height: 14px;
   }
   }
-
-  .back-text {
-    width: 100%;
-    height: 20px;
-    margin-top: 24px;
-    margin-bottom: 8px;
-    text-align: center;
-    cursor: pointer;
-
-    span {
-      color: var(--color-theme);
-    }
-
-    .text {
-      display: inline-block;
-      transform: translateY(-2px);
-      font-size: 12px;
-    }
-  }
 }
 }
 
 
 .license {
 .license {

+ 98 - 4
src/views/Login/src/loginView.vue

@@ -3,9 +3,11 @@ import { useRouter, useRoute } from 'vue-router'
 import ErrorTips from './components/ErrorTips.vue'
 import ErrorTips from './components/ErrorTips.vue'
 import { useUserStore } from '@/stores/modules/user'
 import { useUserStore } from '@/stores/modules/user'
 import ScoringSystem from '@/views/Dashboard/src/components/ScoringSystem.vue'
 import ScoringSystem from '@/views/Dashboard/src/components/ScoringSystem.vue'
+import CryptoJS from 'crypto-js'
 
 
 const router = useRouter()
 const router = useRouter()
 const route = useRoute()
 const route = useRoute()
+
 const loginForm = ref({
 const loginForm = ref({
   username: '',
   username: '',
   password: '',
   password: '',
@@ -13,6 +15,45 @@ const loginForm = ref({
   code: ''
   code: ''
 })
 })
 
 
+const isRememerPwd = ref(false)
+const secretKey = 'fT5!R1k$7Mv@4Q9X'
+// AES 加密函数
+const encryptPassword = (password) => {
+  return CryptoJS.AES.encrypt(password, secretKey).toString()
+}
+
+// AES 解密函数
+const decryptPassword = (encryptedPassword) => {
+  const bytes = CryptoJS.AES.decrypt(encryptedPassword, secretKey)
+  return bytes.toString(CryptoJS.enc.Utf8)
+}
+
+// 存储账号和加密后的密码
+const saveCredentials = () => {
+  clearCredentials()
+  const encryptedPassword = encryptPassword(loginForm.value.password) // 加密密码
+  localStorage.setItem('account', loginForm.value.username)
+  localStorage.setItem('password', encryptedPassword)
+}
+
+// 读取存储的账号和解密后的密码
+const getCredentials = () => {
+  const username = localStorage.getItem('account')
+  const encryptedPassword = localStorage.getItem('password')
+  if (username && encryptedPassword) {
+    const password = decryptPassword(encryptedPassword) // 解密密码
+    loginForm.value.username = username
+    loginForm.value.password = password
+    isRememerPwd.value = true
+  }
+}
+
+// 删除存储的账号和密码
+const clearCredentials = () => {
+  localStorage.removeItem('account')
+  localStorage.removeItem('password')
+}
+getCredentials()
 const status = ref(route.query.status || 'login')
 const status = ref(route.query.status || 'login')
 watch(status, () => {
 watch(status, () => {
   loginForm.value = {
   loginForm.value = {
@@ -41,6 +82,7 @@ const verificationCode = ref()
 const loading = ref(false)
 const loading = ref(false)
 // 获取验证码
 // 获取验证码
 const getCode = () => {
 const getCode = () => {
+  if (loading.value) return
   loading.value = true
   loading.value = true
   $api
   $api
     .getVerifcationCode()
     .getVerifcationCode()
@@ -91,6 +133,11 @@ const handleLogin = () => {
     .then((res: any) => {
     .then((res: any) => {
       if (res.code === 200) {
       if (res.code === 200) {
         const { data } = res
         const { data } = res
+        if (isRememerPwd.value) {
+          saveCredentials()
+        } else {
+          clearCredentials()
+        }
         if (data.msg === 'today') {
         if (data.msg === 'today') {
           ElMessageBox.alert('Your password will expire today, please reset', 'Prompt', {
           ElMessageBox.alert('Your password will expire today, please reset', 'Prompt', {
             confirmButtonText: 'OK',
             confirmButtonText: 'OK',
@@ -111,14 +158,34 @@ const handleLogin = () => {
         userStore.setUsername(res.data.uname || '')
         userStore.setUsername(res.data.uname || '')
         router.push('/')
         router.push('/')
       } else if (res.code === 400) {
       } else if (res.code === 400) {
+        const { data } = res
         // 验证码错误
         // 验证码错误
-        if (res.data.msg === 'password_error') {
+        if (data.msg === 'password_error') {
           loginError.value.password = true
           loginError.value.password = true
-        } else if (res.data.msg === 'verifcation_error') {
+        } else if (data.msg === 'verifcation_error') {
           loginError.value.code = true
           loginError.value.code = true
-        } else if (res.data.msg === 'error_times') {
+        } else if (data.msg === 'error_times') {
           errorTipsRef.value.openDialog()
           errorTipsRef.value.openDialog()
         }
         }
+      } else if (res.code === 500) {
+        const { data } = res
+        if (data.msg === 'passwordExpires') {
+          ElMessageBox.alert('Password expired, please change your password', 'Prompt', {
+            confirmButtonText: 'OK',
+            type: 'warning',
+            confirmButtonClass: 'el-button--dark'
+          })
+          userStore.setUsername(res.data.uname || '')
+          router.push({
+            name: 'Reset Password'
+          })
+        } else {
+          ElMessageBox.alert(data.desc, {
+            confirmButtonText: 'OK',
+            type: 'warning',
+            confirmButtonClass: 'el-button--dark'
+          })
+        }
       }
       }
     })
     })
     .finally(() => {
     .finally(() => {
@@ -219,10 +286,12 @@ const errorTipsRef = ref()
           v-model="loginForm.code"
           v-model="loginForm.code"
           placeholder="Verification Code"
           placeholder="Verification Code"
           @focus="handleDeleteEmailTips('code')"
           @focus="handleDeleteEmailTips('code')"
+          @keyup.enter="handleLogin"
         >
         >
           <template #append>
           <template #append>
             <img
             <img
               v-vloading="loading"
               v-vloading="loading"
+              @click="getCode"
               class="verification-code-img"
               class="verification-code-img"
               :src="verificationCode"
               :src="verificationCode"
               alt=""
               alt=""
@@ -230,6 +299,12 @@ const errorTipsRef = ref()
           </template>
           </template>
         </el-input>
         </el-input>
         <div class="error" v-if="loginError.code">Incorrect verification code.</div>
         <div class="error" v-if="loginError.code">Incorrect verification code.</div>
+        <el-checkbox
+          class="remember-password"
+          v-model="isRememerPwd"
+          label="Remember Password"
+          size="large"
+        />
         <el-button @click="handleLogin" class="el-button--dark login-btn">Login</el-button>
         <el-button @click="handleLogin" class="el-button--dark login-btn">Login</el-button>
       </div>
       </div>
       <template #footer>
       <template #footer>
@@ -286,8 +361,15 @@ const errorTipsRef = ref()
           v-model="loginForm.code"
           v-model="loginForm.code"
           placeholder="Verification Code"
           placeholder="Verification Code"
           @focus="handleDeleteEmailTips('code')"
           @focus="handleDeleteEmailTips('code')"
+          @keyup.enter="handleSendPassword"
           ><template #append>
           ><template #append>
-            <img class="verification-code-img" :src="verificationCode" alt="" /> </template
+            <img
+              v-vloading="loading"
+              class="verification-code-img"
+              :src="verificationCode"
+              @click="getCode"
+              alt=""
+            /> </template
         ></el-input>
         ></el-input>
         <div class="error" v-if="loginError.code">Incorrect verification code.</div>
         <div class="error" v-if="loginError.code">Incorrect verification code.</div>
         <el-button @click="handleSendPassword" class="el-button--dark login-btn"
         <el-button @click="handleSendPassword" class="el-button--dark login-btn"
@@ -459,6 +541,10 @@ const errorTipsRef = ref()
     color: var(--color-danger);
     color: var(--color-danger);
     line-height: 14px;
     line-height: 14px;
   }
   }
+  .remember-password {
+    height: 24px;
+    margin-top: 16px;
+  }
 
 
   .back-text {
   .back-text {
     width: 100%;
     width: 100%;
@@ -495,3 +581,11 @@ const errorTipsRef = ref()
   }
   }
 }
 }
 </style>
 </style>
+<style lang="scss">
+.login {
+  .el-checkbox__label {
+    font-weight: 600;
+    color: var(--color-neutral-2);
+  }
+}
+</style>

+ 3 - 0
src/views/Tracking/src/components/PublicTracking/src/PublicTrackingSearch.vue

@@ -30,6 +30,9 @@ watch(
 
 
 const loading = ref(false)
 const loading = ref(false)
 const handleSearchNo = () => {
 const handleSearchNo = () => {
+  if (!inputVModel.value) {
+    return
+  }
   loading.value = true
   loading.value = true
   $api
   $api
     .getPublicTrackingDetail({ reference_number: inputVModel.value })
     .getPublicTrackingDetail({ reference_number: inputVModel.value })

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

@@ -78,40 +78,9 @@ const handleEmailDrawer = () => {
   emailDrawerRef.value.openDrawer(allData.value)
   emailDrawerRef.value.openDrawer(allData.value)
 }
 }
 
 
-const amsIsfData = ref()
-const getAmsIsfData = () => {
-  $api
-    .getTrackingAmsIsf({
-      ams_ss: allData.value.ams_ss,
-      isf_ss: allData.value.isf_ss,
-      _schemas: allData.value._schemas
-    })
-    .then((res: any) => {
-      if (res.code === 200) {
-        // 获取数据
-        amsIsfData.value = res.data
-        isShowAMSISF.value = true
-      }
-    })
-}
-
 const AMSISFDrawerRef = ref()
 const AMSISFDrawerRef = ref()
-const isShowAMSISF = ref(false)
 const handleAMSISF = () => {
 const handleAMSISF = () => {
-  if (isShowAMSISF.value) {
-    AMSISFDrawerRef.value?.openDrawer(amsIsfData.value)
-  } else {
-    // 如果 isShowAMSISF 从 false 变为 true,自动打开抽屉
-    watch(
-      isShowAMSISF,
-      (newValue) => {
-        if (newValue) {
-          AMSISFDrawerRef.value?.openDrawer(amsIsfData.value)
-        }
-      },
-      { immediate: true }
-    )
-  }
+  AMSISFDrawerRef.value?.openDrawer(allData.value)
 }
 }
 
 
 const allData = ref()
 const allData = ref()
@@ -132,7 +101,6 @@ const getData = () => {
     })
     })
     .finally(() => {
     .finally(() => {
       loading.value = false
       loading.value = false
-      getAmsIsfData()
     })
     })
 }
 }
 getData()
 getData()

+ 29 - 9
src/views/Tracking/src/components/TrackingDetail/src/components/AMS&ISF.vue

@@ -10,6 +10,7 @@ const openDrawer = (data: any) => {
 
 
 const canViewAMSLog = ref(false)
 const canViewAMSLog = ref(false)
 const canViewISFLog = ref(false)
 const canViewISFLog = ref(false)
+const loading = ref(false)
 const handleColumns = (columns: any) => {
 const handleColumns = (columns: any) => {
   const newColumns = columns.map((item: any) => {
   const newColumns = columns.map((item: any) => {
     let curColumn: any = {
     let curColumn: any = {
@@ -27,14 +28,30 @@ const handleColumns = (columns: any) => {
   })
   })
   return newColumns
   return newColumns
 }
 }
-const getData = (data: any) => {
-  const { amsLog, isfLog } = data
-  canViewAMSLog.value = data.canViewAMSLog
-  canViewISFLog.value = data.canViewISFLog
-  AMSTableData.value.columns = handleColumns(amsLog.amsLog_column)
-  AMSTableData.value.data = amsLog.data
-  ISFTableData.value.columns = handleColumns(isfLog.isfLog_column)
-  ISFTableData.value.data = data.isf
+const getData = (pageData: any) => {
+  loading.value = true
+  $api
+    .getTrackingAmsIsf({
+      ams_ss: pageData.ams_ss,
+      isf_ss: pageData.isf_ss,
+      _schemas: pageData._schemas
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        // 获取数据
+        const data = res.data
+        const { amsLog, isfLog } = res.data
+        canViewAMSLog.value = data.canViewAMSLog
+        canViewISFLog.value = data.canViewISFLog
+        AMSTableData.value.columns = handleColumns(amsLog.amsLog_column)
+        AMSTableData.value.data = amsLog.data
+        ISFTableData.value.columns = handleColumns(isfLog.isfLog_column)
+        ISFTableData.value.data = data.isf
+      }
+    })
+    .finally(() => {
+      loading.value = false
+    })
 }
 }
 const drawerTitle = () => {
 const drawerTitle = () => {
   if (canViewAMSLog.value && canViewISFLog.value) {
   if (canViewAMSLog.value && canViewISFLog.value) {
@@ -114,6 +131,8 @@ const clearData = () => {
   AMSTableData.value.columns = []
   AMSTableData.value.columns = []
   ISFTableData.value.data = []
   ISFTableData.value.data = []
   ISFTableData.value.columns = []
   ISFTableData.value.columns = []
+  canViewAMSLog.value = false
+  canViewISFLog.value = false
 }
 }
 
 
 defineExpose({
 defineExpose({
@@ -130,7 +149,7 @@ defineExpose({
     :title="drawerTitle()"
     :title="drawerTitle()"
     direction="rtl"
     direction="rtl"
   >
   >
-    <div class="ams-isf">
+    <div class="ams-isf" v-vloading="loading">
       <div class="label" v-if="canViewAMSLog" style="margin-top: 8px">
       <div class="label" v-if="canViewAMSLog" style="margin-top: 8px">
         <span>AMS-M1 Log</span>
         <span>AMS-M1 Log</span>
         <el-button class="el-button--icon" @click="exportAMSTable">
         <el-button class="el-button--icon" @click="exportAMSTable">
@@ -165,6 +184,7 @@ defineExpose({
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
 .ams-isf {
 .ams-isf {
+  height: 500px;
   .label {
   .label {
     display: flex;
     display: flex;
     justify-content: space-between;
     justify-content: space-between;

+ 17 - 20
src/views/Tracking/src/components/TrackingDetail/src/components/MapView.vue

@@ -10,7 +10,7 @@ import { onMounted, ref, watch } from 'vue'
 
 
 const props = defineProps<{
 const props = defineProps<{
   serial_no: string
   serial_no: string
-  uncoded: string
+  uncode: string
 }>()
 }>()
 
 
 const markerPositions = ref([])
 const markerPositions = ref([])
@@ -38,10 +38,6 @@ const transferIcon = L.icon({
 
 
 let map: L.Map | null = null
 let map: L.Map | null = null
 
 
-// 定义响应式的重置缩放中心和级别
-const resetZoomCenter: any = ref([51.505, -0.09]) // 默认中心
-const resetZoomLevel = ref(5) // 默认缩放级别
-
 // 初始化地图(不添加标记)
 // 初始化地图(不添加标记)
 const initMap = () => {
 const initMap = () => {
   if (map) {
   if (map) {
@@ -139,26 +135,27 @@ const getMarker = () => {
   $api
   $api
     .getTrackingDetailMapData({
     .getTrackingDetailMapData({
       serial_no: props.serial_no,
       serial_no: props.serial_no,
-      uncoded: props.uncoded
+      uncode: props.uncode
     })
     })
     .then((res) => {
     .then((res) => {
       if (res.code === 200) {
       if (res.code === 200) {
         const { data } = res
         const { data } = res
-        data.forEach((item) => {
-          const iconColorList = {
-            Destination: { color: '#24ca5a', icon: destinationIcon },
-            Origin: { color: '#ED6D00', icon: originIcon },
-            Transfer: { color: '#ed0000', icon: transferIcon }
-          }
-          markerPositions.value.push({
-            lat: item.lat,
-            lng: item.lng,
-            city: item.infor,
-            label: item.label,
-            icon: iconColorList[item.label].icon,
-            iconColor: iconColorList[item.label].color
+        data &&
+          data.forEach((item) => {
+            const iconColorList = {
+              Destination: { color: '#24ca5a', icon: destinationIcon },
+              Origin: { color: '#ED6D00', icon: originIcon },
+              Transfer: { color: '#ed0000', icon: transferIcon }
+            }
+            markerPositions.value.push({
+              lat: item.lat,
+              lng: item.lng,
+              city: item.infor,
+              label: item.label,
+              icon: iconColorList[item.label].icon,
+              iconColor: iconColorList[item.label].color
+            })
           })
           })
-        })
         // 请求成功后添加标记,并动态添加重置按钮
         // 请求成功后添加标记,并动态添加重置按钮
         addMarkersToMap()
         addMarkersToMap()
       }
       }

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

@@ -3,7 +3,7 @@ const props = defineProps({
   data: Object
   data: Object
 })
 })
 
 
-const activeName = ref('containerStatus')
+const activeName = ref('shipmentStatus')
 
 
 const handleTabClick = (name: string) => {
 const handleTabClick = (name: string) => {
   activeName.value = name
   activeName.value = name

+ 53 - 48
src/views/Tracking/src/components/TrackingTable/src/TrackingTable.vue

@@ -94,27 +94,27 @@ let filterdataobj: any = {}
 const getSharedTableData = () => {
 const getSharedTableData = () => {
   const trackingData = JSON.parse(localStorage.getItem('TrackingData'))
   const trackingData = JSON.parse(localStorage.getItem('TrackingData'))
   if (trackingData) {
   if (trackingData) {
-    trackingTable.value.data = trackingData.searchData
+    trackingTable.value.data = trackingData.searchData || []
     pageInfo.value.total = Number(trackingData.rc)
     pageInfo.value.total = Number(trackingData.rc)
     TransportListItem.value = trackingData.TransportList
     TransportListItem.value = trackingData.TransportList
     TagsList.value = trackingData.tagsList
     TagsList.value = trackingData.tagsList
-    console.log(trackingData.canEdiVgm)
-    if (trackingData.canEdiVgm) {
-      console.log('canEdiVgm')
-      trackingTable.value.columns.push({
-        title: 'Action',
-        fixed: 'right',
-        width: 80,
-        slots: { default: 'action' }
-      })
+    if (trackingData.canEdiVgm && trackingTable.value.columns.length > 0) {
+      const index = trackingTable.value.columns.findIndex((item: any) => item.title === 'Action')
+      if (index === -1) {
+        trackingTable.value.columns.push({
+          title: 'Action',
+          fixed: 'right',
+          width: 80,
+          slots: { default: 'action' }
+        })
+      }
     }
     }
 
 
-    console.log(trackingTable.value.columns)
     // 拥有所有字段的表格
     // 拥有所有字段的表格
     setTimeout(() => {
     setTimeout(() => {
       allTable.value.columns = handleColumns(trackingData.allColums, 'all')
       allTable.value.columns = handleColumns(trackingData.allColums, 'all')
 
 
-      allTable.value.data = trackingData.searchData
+      allTable.value.data = trackingData.searchData || []
       nextTick(() => {
       nextTick(() => {
         allTableRef.value && autoWidth(allTable.value, allTableRef.value)
         allTableRef.value && autoWidth(allTable.value, allTableRef.value)
       })
       })
@@ -136,17 +136,20 @@ const getTableData = async (isInit: boolean, isPageChange?: boolean) => {
     sessionStorage.getItem('clickParams') != ''
     sessionStorage.getItem('clickParams') != ''
   ) {
   ) {
     const data = JSON.parse(sessionStorage.getItem('clickParams') as string) || {}
     const data = JSON.parse(sessionStorage.getItem('clickParams') as string) || {}
-    trackingTable.value.data = data.searchData
+    trackingTable.value.data = data.searchData || []
     pageInfo.value.total = Number(data.rc)
     pageInfo.value.total = Number(data.rc)
     TransportListItem.value = data.TransportList
     TransportListItem.value = data.TransportList
     TagsList.value = data.tagsList
     TagsList.value = data.tagsList
-    if (data.canEdiVgm) {
-      trackingTable.value.columns.push({
-        title: 'Action',
-        fixed: 'right',
-        width: 80,
-        slots: { default: 'action' }
-      })
+    if (data.canEdiVgm && trackingTable.value.columns.length > 0) {
+      const index = trackingTable.value.columns.findIndex((item: any) => item.title === 'Action')
+      if (index === -1) {
+        trackingTable.value.columns.push({
+          title: 'Action',
+          fixed: 'right',
+          width: 80,
+          slots: { default: 'action' }
+        })
+      }
     }
     }
 
 
     // 拥有所有字段的表格
     // 拥有所有字段的表格
@@ -171,21 +174,26 @@ const getTableData = async (isInit: boolean, isPageChange?: boolean) => {
       })
       })
       .then((res: any) => {
       .then((res: any) => {
         if (res.code === 200) {
         if (res.code === 200) {
-          trackingTable.value.data = res.data.searchData
+          trackingTable.value.data = res.data.searchData || []
           pageInfo.value.total = Number(res.data.rc)
           pageInfo.value.total = Number(res.data.rc)
-          if (res.data.canEdiVgm) {
-            trackingTable.value.columns.push({
-              title: 'Action',
-              fixed: 'right',
-              width: 80,
-              slots: { default: 'action' }
-            })
+          if (res.data.canEdiVgm && trackingTable.value.columns.length > 0) {
+            const index = trackingTable.value.columns.findIndex(
+              (item: any) => item.title === 'Action'
+            )
+            if (index === -1) {
+              trackingTable.value.columns.push({
+                title: 'Action',
+                fixed: 'right',
+                width: 80,
+                slots: { default: 'action' }
+              })
+            }
           }
           }
 
 
           // 拥有所有字段的表格
           // 拥有所有字段的表格
           setTimeout(() => {
           setTimeout(() => {
             allTable.value.columns = handleColumns(res.data.allColums, 'all')
             allTable.value.columns = handleColumns(res.data.allColums, 'all')
-            allTable.value.data = res.data.searchData
+            allTable.value.data = res.data.searchData || []
             nextTick(() => {
             nextTick(() => {
               allTableRef.value && autoWidth(allTable.value, allTableRef.value)
               allTableRef.value && autoWidth(allTable.value, allTableRef.value)
             })
             })
@@ -233,7 +241,7 @@ const searchTableData = (data: any) => {
             }
             }
           })
           })
         } else {
         } else {
-          trackingTable.value.data = res.data.searchData
+          trackingTable.value.data = res.data.searchData || []
           pageInfo.value.total = Number(res.data.rc)
           pageInfo.value.total = Number(res.data.rc)
           tableLoading.value = false
           tableLoading.value = false
         }
         }
@@ -307,23 +315,22 @@ const handleDownload = () => {
 
 
 // 导出表格
 // 导出表格
 const exportTable = (status: number) => {
 const exportTable = (status: number) => {
+  const exportConfig: any = {
+    type: 'xlsx',
+    message: false,
+    filename: `Tracking List_${dayjs().format('YYYYMMDDHH[h]mm[m]ss[s]')}`
+  }
   if (status === 1) {
   if (status === 1) {
-    tableRef.value?.exportData({
-      type: 'xlsx',
-      message: false,
-      filename: `Tracking List_${dayjs().format('YYYYMMDDHH[h]mm[m]ss[s]')}`,
-      columnFilterMethod: ({ column }: any) => {
-        // 排除复选框列
-        return column.field
-      }
-    })
-  } else {
-    allTableRef.value?.exportData({
-      type: 'xlsx',
-      message: false,
-      filename: `Tracking List_${dayjs().format('YYYYMMDDHH[h]mm[m]ss[s]')}`
-    })
+    exportConfig.columnFilterMethod = ({ column }: any) => {
+      const index = trackingTable.value.columns.findIndex(
+        (item: any) => item.field === column.field
+      )
+      // 排除复选框列
+      return column.field && index !== -1
+    }
+    exportConfig.columns = trackingTable.value.columns
   }
   }
+  allTableRef.value?.exportData(exportConfig)
 }
 }
 
 
 const tableLoading = ref(false)
 const tableLoading = ref(false)
@@ -370,7 +377,7 @@ const handleLinkClick = (row: any, column: any) => {
   } else if (column.title === 'HBL No.') {
   } else if (column.title === 'HBL No.') {
     router.push({
     router.push({
       path: '/tracking/detail',
       path: '/tracking/detail',
-      query: { a: row.__serial_no, _schemas: row._schemas, serial_no: row.serial_no }
+      query: { a: row.__serial_no, _schemas: row._schemas }
     })
     })
   }
   }
 }
 }
@@ -529,8 +536,6 @@ defineExpose({
     position: absolute;
     position: absolute;
     top: -100000px;
     top: -100000px;
     width: 20px;
     width: 20px;
-    opacity: 0;
-    visibility: hidden;
   }
   }
 }
 }
 </style>
 </style>