zhouyuhao 1 год назад
Родитель
Сommit
3645edd4fb

+ 3 - 0
index.html

@@ -4,6 +4,9 @@
     <meta charset="UTF-8" />
     <link rel="icon" href="/favicon.ico" />
     <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>
   </head>
   <body>

+ 1 - 0
package.json

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

+ 6 - 5
src/router/index.ts

@@ -94,6 +94,11 @@ const router = createRouter({
 
 // * 路由拦截 beforeEach
 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']
   // 判断是否登录
@@ -105,13 +110,9 @@ router.beforeEach(async (to, from, next) => {
       next(false)
       return
     } else {
-      next('/public-tracking')
+      next('/Login')
     }
   }
-  if (to.path === '/Login') {
-    const userStore = useUserStore()
-    userStore.clearUsername()
-  }
   next()
 })
 

+ 20 - 0
src/styles/elementui.scss

@@ -361,6 +361,26 @@ div .el-checkbox__input.is-checked .el-checkbox__inner {
   background-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:before {
   height: 0;

+ 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 hasLowercase = ref(false)
@@ -111,16 +103,12 @@ const hasNumber = ref(false)
 const isValidLength = ref(false)
 const checkPassword = () => {
   const pwd = loginForm.value.newPassword
-
   // 检测是否包含大写字母
   hasUppercase.value = /[A-Z]/.test(pwd)
-
   // 检测是否包含小写字母
   hasLowercase.value = /[a-z]/.test(pwd)
-
   // 检测是否包含数字
   hasNumber.value = /[0-9]/.test(pwd)
-
   // 检测长度是否符合要求
   isValidLength.value = pwd.length >= 12 && pwd.length <= 20
 }
@@ -224,10 +212,6 @@ const checkPassword = () => {
         <el-button @click="handleChangePwd" class="el-button--dark login-btn"
           >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>
       <template #footer>
         <div class="license">
@@ -392,25 +376,6 @@ const checkPassword = () => {
     color: var(--color-danger);
     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 {

+ 73 - 1
src/views/Login/src/loginView.vue

@@ -3,6 +3,7 @@ import { useRouter, useRoute } from 'vue-router'
 import ErrorTips from './components/ErrorTips.vue'
 import { useUserStore } from '@/stores/modules/user'
 import ScoringSystem from '@/views/Dashboard/src/components/ScoringSystem.vue'
+import CryptoJS from 'crypto-js'
 
 const router = useRouter()
 const route = useRoute()
@@ -41,6 +42,7 @@ const verificationCode = ref()
 const loading = ref(false)
 // 获取验证码
 const getCode = () => {
+  if (loading.value) return
   loading.value = true
   $api
     .getVerifcationCode()
@@ -91,6 +93,11 @@ const handleLogin = () => {
     .then((res: any) => {
       if (res.code === 200) {
         const { data } = res
+        if (isRememerPwd.value) {
+          saveCredentials()
+        } else {
+          clearCredentials()
+        }
         if (data.msg === 'today') {
           ElMessageBox.alert('Your password will expire today, please reset', 'Prompt', {
             confirmButtonText: 'OK',
@@ -156,6 +163,44 @@ const handleDeleteEmailTips = (type?: any) => {
 }
 
 const errorTipsRef = ref()
+
+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('username', loginForm.value.username)
+  localStorage.setItem('password', encryptedPassword)
+}
+
+// 读取存储的账号和解密后的密码
+const getCredentials = () => {
+  const username = localStorage.getItem('username')
+  const encryptedPassword = localStorage.getItem('password')
+  if (username && encryptedPassword) {
+    const password = decryptPassword(encryptedPassword) // 解密密码
+    loginForm.value.username = username
+    loginForm.value.password = password
+  }
+}
+
+// 删除存储的账号和密码
+const clearCredentials = () => {
+  localStorage.removeItem('username')
+  localStorage.removeItem('password')
+}
 </script>
 
 <template>
@@ -219,10 +264,12 @@ const errorTipsRef = ref()
           v-model="loginForm.code"
           placeholder="Verification Code"
           @focus="handleDeleteEmailTips('code')"
+          @keyup.enter="handleLogin"
         >
           <template #append>
             <img
               v-vloading="loading"
+              @click="getCode"
               class="verification-code-img"
               :src="verificationCode"
               alt=""
@@ -230,6 +277,12 @@ const errorTipsRef = ref()
           </template>
         </el-input>
         <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>
       </div>
       <template #footer>
@@ -286,8 +339,15 @@ const errorTipsRef = ref()
           v-model="loginForm.code"
           placeholder="Verification Code"
           @focus="handleDeleteEmailTips('code')"
+          @keyup.enter="handleSendPassword"
           ><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>
         <div class="error" v-if="loginError.code">Incorrect verification code.</div>
         <el-button @click="handleSendPassword" class="el-button--dark login-btn"
@@ -459,6 +519,10 @@ const errorTipsRef = ref()
     color: var(--color-danger);
     line-height: 14px;
   }
+  .remember-password {
+    height: 24px;
+    margin-top: 16px;
+  }
 
   .back-text {
     width: 100%;
@@ -495,3 +559,11 @@ const errorTipsRef = ref()
   }
 }
 </style>
+<style lang="scss">
+.login {
+  .el-checkbox__label {
+    font-weight: 600;
+    color: var(--color-neutral-2);
+  }
+}
+</style>

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

@@ -78,40 +78,9 @@ const handleEmailDrawer = () => {
   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 isShowAMSISF = ref(false)
 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()
@@ -132,7 +101,6 @@ const getData = () => {
     })
     .finally(() => {
       loading.value = false
-      getAmsIsfData()
     })
 }
 getData()

+ 30 - 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 canViewISFLog = ref(false)
+const loading = ref(false)
 const handleColumns = (columns: any) => {
   const newColumns = columns.map((item: any) => {
     let curColumn: any = {
@@ -27,14 +28,31 @@ const handleColumns = (columns: any) => {
   })
   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) => {
+  console.log(pageData)
+  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 = () => {
   if (canViewAMSLog.value && canViewISFLog.value) {
@@ -114,6 +132,8 @@ const clearData = () => {
   AMSTableData.value.columns = []
   ISFTableData.value.data = []
   ISFTableData.value.columns = []
+  canViewAMSLog.value = false
+  canViewISFLog.value = false
 }
 
 defineExpose({
@@ -130,7 +150,7 @@ defineExpose({
     :title="drawerTitle()"
     direction="rtl"
   >
-    <div class="ams-isf">
+    <div class="ams-isf" v-vloading="loading">
       <div class="label" v-if="canViewAMSLog" style="margin-top: 8px">
         <span>AMS-M1 Log</span>
         <el-button class="el-button--icon" @click="exportAMSTable">
@@ -165,6 +185,7 @@ defineExpose({
 
 <style lang="scss" scoped>
 .ams-isf {
+  height: 500px;
   .label {
     display: flex;
     justify-content: space-between;

+ 2 - 6
src/views/Tracking/src/components/TrackingDetail/src/components/MapView.vue

@@ -10,7 +10,7 @@ import { onMounted, ref, watch } from 'vue'
 
 const props = defineProps<{
   serial_no: string
-  uncoded: string
+  uncode: string
 }>()
 
 const markerPositions = ref([])
@@ -38,10 +38,6 @@ const transferIcon = L.icon({
 
 let map: L.Map | null = null
 
-// 定义响应式的重置缩放中心和级别
-const resetZoomCenter: any = ref([51.505, -0.09]) // 默认中心
-const resetZoomLevel = ref(5) // 默认缩放级别
-
 // 初始化地图(不添加标记)
 const initMap = () => {
   if (map) {
@@ -139,7 +135,7 @@ const getMarker = () => {
   $api
     .getTrackingDetailMapData({
       serial_no: props.serial_no,
-      uncoded: props.uncoded
+      uncode: props.uncode
     })
     .then((res) => {
       if (res.code === 200) {

+ 33 - 25
src/views/Tracking/src/components/TrackingTable/src/TrackingTable.vue

@@ -98,18 +98,18 @@ const getSharedTableData = () => {
     pageInfo.value.total = Number(trackingData.rc)
     TransportListItem.value = trackingData.TransportList
     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(() => {
       allTable.value.columns = handleColumns(trackingData.allColums, 'all')
@@ -140,13 +140,16 @@ const getTableData = async (isInit: boolean, isPageChange?: boolean) => {
     pageInfo.value.total = Number(data.rc)
     TransportListItem.value = data.TransportList
     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' }
+        })
+      }
     }
 
     // 拥有所有字段的表格
@@ -175,13 +178,18 @@ const getTableData = async (isInit: boolean, isPageChange?: boolean) => {
           pageInfo.value.total = Number(res.data.rc)
           TransportListItem.value = res.data.TransportList
           TagsList.value = res.data.tagsList
-          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' }
+              })
+            }
           }
 
           // 拥有所有字段的表格
@@ -372,7 +380,7 @@ const handleLinkClick = (row: any, column: any) => {
   } else if (column.title === 'HBL No.') {
     router.push({
       path: '/tracking/detail',
-      query: { a: row.__serial_no, _schemas: row._schemas, serial_no: row.serial_no }
+      query: { a: row.__serial_no, _schemas: row._schemas }
     })
   }
 }

+ 1 - 1
vite.config.ts

@@ -9,7 +9,7 @@ import IconsResolver from 'unplugin-icons/resolver'
 
 // https://vitejs.dev/config/
 export default defineConfig({
-  base: `/${process.env.VITE_BASE_URL}/`,
+  base: `/new/`,
   resolve: {
     alias: {
       '@': fileURLToPath(new URL('./src', import.meta.url))