Browse Source

🎈 perf: 对页面进行了美化,增加移动端拦截

Pchen. 10 months ago
parent
commit
72971c8136

+ 1 - 1
.env

@@ -1,3 +1,3 @@
 NODE_ENV=production
 VITE_APP_API_BASE_URL=https://lepao-api.xxoo365.top
-VITE_RSA_PUBLIC_KEY=-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzgYFc5Q0ejm8xjFlJ7LI\\nAd2Fx/SjS49d9zl2dyZ73C0fKSqnsZIAFdDJVeezmJzOXNXWhaVGhqp3GBQeop0J\\nR1zFwmK5zoQxISL79YQwJlhJ7ZzYa/LMpkFd4CTT8S50Las7QiqKjDMAB1KdJZNr\\n4NGr3TYUx1UiO9TMoXWyAtVQASvkyEIQHopxOehwFn4daTO//1yMtr6vhrQ8zrQ3\\nqPm5abfcIQ3puX5IwS+zDfJB9FoksJZktV4r6+36SQ7Xjv01AB2o+m2z6j73nZ45\\n/yLLy6fGLneMjSiLG08MQaBR5uu3HM4g2Jgjp8yMtFH5NG9g+5utaL3swrFB8qwU\\ntQIDAQAB\\n-----END PUBLIC KEY-----
+VITE_RSA_PUBLIC_KEY=LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF6Z1lGYzVRMGVqbTh4akZsSjdMSQpBZDJGeC9TalM0OWQ5emwyZHlaNzNDMGZLU3Fuc1pJQUZkREpWZWV6bUp6T1hOWFdoYVZHaHFwM0dCUWVvcDBKClIxekZ3bUs1em9ReElTTDc5WVF3SmxoSjdaellhL0xNcGtGZDRDVFQ4UzUwTGFzN1FpcUtqRE1BQjFLZEpaTnIKNE5HcjNUWVV4MVVpTzlUTW9YV3lBdFZRQVN2a3lFSVFIb3B4T2Vod0ZuNGRhVE8vLzF5TXRyNnZoclE4enJRMwpxUG01YWJmY0lRM3B1WDVJd1MrekRmSkI5Rm9rc0paa3RWNHI2KzM2U1E3WGp2MDFBQjJvK20yejZqNzNuWjQ1Ci95TEx5NmZHTG5lTWpTaUxHMDhNUWFCUjV1dTNITTRnMkpnanA4eU10Rkg1Tkc5Zys1dXRhTDNzd3JGQjhxd1UKdFFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==

+ 1 - 1
.env.preview

@@ -1,3 +1,3 @@
 NODE_ENV=production
 VITE_APP_API_BASE_URL=/api
-VITE_RSA_PUBLIC_KEY=-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzgYFc5Q0ejm8xjFlJ7LI\\nAd2Fx/SjS49d9zl2dyZ73C0fKSqnsZIAFdDJVeezmJzOXNXWhaVGhqp3GBQeop0J\\nR1zFwmK5zoQxISL79YQwJlhJ7ZzYa/LMpkFd4CTT8S50Las7QiqKjDMAB1KdJZNr\\n4NGr3TYUx1UiO9TMoXWyAtVQASvkyEIQHopxOehwFn4daTO//1yMtr6vhrQ8zrQ3\\nqPm5abfcIQ3puX5IwS+zDfJB9FoksJZktV4r6+36SQ7Xjv01AB2o+m2z6j73nZ45\\n/yLLy6fGLneMjSiLG08MQaBR5uu3HM4g2Jgjp8yMtFH5NG9g+5utaL3swrFB8qwU\\ntQIDAQAB\\n-----END PUBLIC KEY-----
+VITE_RSA_PUBLIC_KEY=LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF6Z1lGYzVRMGVqbTh4akZsSjdMSQpBZDJGeC9TalM0OWQ5emwyZHlaNzNDMGZLU3Fuc1pJQUZkREpWZWV6bUp6T1hOWFdoYVZHaHFwM0dCUWVvcDBKClIxekZ3bUs1em9ReElTTDc5WVF3SmxoSjdaellhL0xNcGtGZDRDVFQ4UzUwTGFzN1FpcUtqRE1BQjFLZEpaTnIKNE5HcjNUWVV4MVVpTzlUTW9YV3lBdFZRQVN2a3lFSVFIb3B4T2Vod0ZuNGRhVE8vLzF5TXRyNnZoclE4enJRMwpxUG01YWJmY0lRM3B1WDVJd1MrekRmSkI5Rm9rc0paa3RWNHI2KzM2U1E3WGp2MDFBQjJvK20yejZqNzNuWjQ1Ci95TEx5NmZHTG5lTWpTaUxHMDhNUWFCUjV1dTNITTRnMkpnanA4eU10Rkg1Tkc5Zys1dXRhTDNzd3JGQjhxd1UKdFFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==

+ 3 - 1
package.json

@@ -4,7 +4,7 @@
   "version": "1.0.0",
   "type": "module",
   "author": "thc <2580797295@qq.com>",
-  "description": "GitNexus 一款Git可视化分析管理工具",
+  "description": "",
   "homepage": "https://www.gitnexus.cn",
   "repository": {
     "type": "git",
@@ -26,11 +26,13 @@
     "highlight.js": "^11.11.1",
     "html2pdf.js": "^0.10.3",
     "jsencrypt": "^3.3.2",
+    "lru-cache": "^11.1.0",
     "markdown-it": "^14.1.0",
     "mitt": "^3.0.1",
     "pinia": "^3.0.1",
     "store": "^2.0.12",
     "three": "^0.175.0",
+    "uuid": "^11.1.0",
     "vue": "^3.5.13",
     "vue-echarts": "^7.0.3",
     "vue-router": "^4.5.0"

BIN
public/background.webm


+ 60 - 0
src/App.vue

@@ -1,5 +1,65 @@
 <template>
   <div id="app">
+    <div class="mobile" v-if="mobile">
+      <a-result status="warning" title="使用电脑访问页面" class="mid">
+        <template #subtitle>
+          该网页专为电脑用户打造,使用电脑访问页面可获得最佳体验。您也可继续使用移动设备访问
+        </template>
+
+        <template #extra>
+          <a-space>
+            <a-button type='primary' @click="mobileGoOn">继续访问</a-button>
+          </a-space>
+        </template>
+      </a-result>
+    </div>
     <router-view></router-view>
   </div>
 </template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import storage from 'store'
+
+const mobile = ref(false)
+
+function checkMobile() {
+  const isMobileWidth = window.innerWidth <= 768
+  const ua = navigator.userAgent.toLowerCase()
+  const isMobileUA = /android|iphone|ipad|ipod|windows phone/i.test(ua)
+
+  if (isMobileWidth || isMobileUA) {
+    const mobileShow = storage.get('mobileShow')
+    if (!mobileShow)
+      mobile.value = true
+  }
+}
+
+function mobileGoOn() {
+  mobile.value = false
+  storage.set('mobileShow', true)
+}
+
+onMounted(() => {
+  checkMobile()
+})
+
+</script>
+
+<style scoped>
+.mobile {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 999;
+  width: 100%;
+  height: 100%;
+  background-color: white;
+}
+
+.mid {
+  position: absolute;
+  top: 50%;
+  transform: translateY(-50%);
+}
+</style>

+ 1 - 1
src/components/AIChat/index.vue

@@ -90,7 +90,7 @@ const getAIChatMessages = async () => {
         messagesLoading.value = true
         const res = await GetAIChatMessages()
         if (!res || res.code !== 0)
-            return Message.error(`获取历史对话消息失败!${res?.msg || ''}`)
+            return Message.error(`获取历史对话消息失败!${res.msg || ''}`)
         messages.value = res.data
         messages.value.push({
             type: 'system', time: new Date().getTime(), content: '你好!我是你的专属AI智能助手“小吉”,你可以问我任何问题哦~~\n试着问问:\n- 我拥有哪些Git仓库?\n- 仓库GitNexus最近一次提交的信息是什么?\n- 请对比electron仓库的最后两次提交。'

+ 0 - 3
src/components/Map/MapContainer.vue

@@ -66,17 +66,14 @@ onMounted(() => {
       }
 
       // 添加打卡点
-      console.log(props.point_list)
       if (props.point_list?.length > 0) {
         props.point_list.forEach((point, index) => {
-          console.log(point)
           const marker = new AMap.Marker({
             position: [point.longtitude, point.latitude],
             offset: new AMap.Pixel(-24, -48),
             icon: "/mark/daka.png",
             title: `打卡点${index + 1}`
           })
-          console.log('添加点')
           map.add(marker)
         })
       }

+ 1 - 1
src/pages/Login/components/login.vue

@@ -74,7 +74,7 @@ const getCaptcha = async () => {
     try {
         const res = await getImageCaptcha()
         if (!res || res.code != 0)
-            return requestFailed('获取图片验证码失败!' + res?.msg || '')
+            return requestFailed('获取图片验证码失败!' + res.msg || '')
         ImageCaptcha.value = res.data.img
         CaptchaId.value = res.data.id
     } catch (error) {

+ 4 - 4
src/pages/Login/components/register.vue

@@ -135,13 +135,13 @@ const SendEmail = async () => {
             if (res.code === -10501) {
                 return Notification.error({
                     title: '验证码输入错误',
-                    content: res?.msg || '请求出现错误,请稍后再试'
+                    content: res.msg || '请求出现错误,请稍后再试'
                 })
             }
 
             return Notification.error({
                 title: '获取验证码失败',
-                content: res?.msg || '请求出现错误,请稍后再试'
+                content: res.msg || '请求出现错误,请稍后再试'
             })
         }
     } catch (error) {
@@ -153,7 +153,7 @@ const getCaptcha = async () => {
     try {
         const res = await getImageCaptcha()
         if (!res || res.code != 0)
-            return requestFailed('获取图片验证码失败!' + res?.msg || '')
+            return requestFailed('获取图片验证码失败!' + res.msg || '')
         ImageCaptcha.value = res.data.img
         CaptchaId.value = res.data.id
     } catch (error) {
@@ -174,7 +174,7 @@ const handleSubmit = async ({ values, errors }) => {
         data.password = btoa(data.password)
         const res = await register(data)
         if(!res || res.code !== 0)
-            return requestFailed(res?.msg)
+            return requestFailed(res.msg)
         Message.success('注册成功!请登录')
         emit('changeMode', 'login')
     } catch (error) {

+ 1 - 1
src/pages/Login/uniLogin/uniLogin.vue

@@ -55,7 +55,7 @@ const GetLoginUrl = async (type) => {
         changeLoading(true)
         const res = await getLoginUrl({ type })
         if (!res || res.code != 0)
-            return requestFailed('获取登录链接失败!' + res?.msg || '')
+            return requestFailed('获取登录链接失败!' + res.msg || '')
         window.location.href = res.data
     } catch (error) {
         requestFailed('获取登录链接失败!')

+ 1 - 1
src/pages/Main/Main.vue

@@ -2,7 +2,7 @@
     <div id="section1" class="section root">
         <div class="videocontainer">
             <video class="fullscreenvideo" playsinline="" autoplay="" muted="" loop=""
-                src="https://www.gitnexus.cn/assets/background-CL3lUlc-.webm" type="video/mp4" />
+                src="/background.webm" type="video/mp4" />
             <div class="overlay" />
         </div>
         <Header color="white" />

+ 1 - 1
src/pages/Main/components/section2.vue

@@ -25,7 +25,7 @@ const cards = [
     {
         title: '全自动乐跑体验',
         icon: new URL('@/assets/img/homePage/icons/visualization.svg', import.meta.url).href,
-        dec: '自动记录跑步数据,无需手动操作,轻松完成校园任务',
+        dec: '自动上传跑步数据,无需手动操作,轻松完成乐跑任务',
         img: new URL('https://cloud.vite.net.cn/view.php/6cf4d3d8f5d9e6b41c525541c8949329.png').href,
         reverse: false
     },

+ 1 - 1
src/pages/User/info/components/my-project.vue

@@ -47,7 +47,7 @@ const GetRepo = async () => {
     if (!res || res.code !== 0)
       return Notification.error({
         title: '获取仓库列表失败!',
-        content: res?.msg || '请稍后再试'
+        content: res.msg || '请稍后再试'
       })
     repos.value = res.data
   } catch (error) {

+ 5 - 5
src/pages/User/setting/components/basic-information.vue

@@ -106,7 +106,7 @@ const getCaptcha = async () => {
     try {
         const res = await getImageCaptcha()
         if (!res || res.code != 0)
-            return Message.error('获取图片验证码失败!' + res?.msg || '')
+            return Message.error('获取图片验证码失败!' + res.msg || '')
         ImageCaptcha.value = res.data.img
         CaptchaId.value = res.data.id
     } catch (error) {
@@ -123,7 +123,7 @@ const changeName = async () => {
     if (v || user.value.username === usernameForm.username) return
 
     const res = await ChangeUsername({ username: usernameForm.username })
-    if (!res || res.code !== 0) throw new Error(res?.msg || '更新失败!请稍后再试')
+    if (!res || res.code !== 0) throw new Error(res.msg || '更新失败!请稍后再试')
 
     user.value = await userStore.getInfoFromServer()
     Message.success('更新用户名成功!')
@@ -168,13 +168,13 @@ const SendEmail = async () => {
             if (res.code === -10501) {
                 return Notification.error({
                     title: '验证码输入错误',
-                    content: res?.msg || '请求出现错误,请稍后再试'
+                    content: res.msg || '请求出现错误,请稍后再试'
                 })
             }
 
             return Notification.error({
                 title: '获取验证码失败',
-                content: res?.msg || '请求出现错误,请稍后再试'
+                content: res.msg || '请求出现错误,请稍后再试'
             })
         }
     } catch (error) {
@@ -189,7 +189,7 @@ const changeEmail = async () => {
     if (v || user.value.email === emailForm.email) return
 
     const res = await BindEmail({ email: emailForm.email, code:  emailForm.code})
-    if (!res || res.code !== 0) throw new Error(res?.msg || '更新失败!请稍后再试')
+    if (!res || res.code !== 0) throw new Error(res.msg || '更新失败!请稍后再试')
 
     user.value = await userStore.getInfoFromServer()
     Message.success('更新邮箱成功!')

+ 1 - 1
src/pages/User/setting/components/security-settings.vue

@@ -71,7 +71,7 @@ const changePassword = async () => {
       password = btoa(password)
 
     const res = await ChangePassword({oldpassword, password })
-    if (!res || res.code !== 0) throw new Error(res?.msg || '更新密码失败!请稍后再试')
+    if (!res || res.code !== 0) throw new Error(res.msg || '更新密码失败!请稍后再试')
 
     Message.success('更新密码成功!请重新登录')
     userStore.logout()

+ 1 - 1
src/pages/User/setting/components/user-panel.vue

@@ -112,7 +112,7 @@ const customRequest = async ({ onSuccess, onError, fileItem }) => {
       onError(new Error('上传失败'), res)
       return Notification.error({
         title: '头像上传失败',
-        content: res?.msg || '请求出现错误,请稍后再试'
+        content: res.msg || '请求出现错误,请稍后再试'
       })
     }
 

+ 1 - 1
src/pages/lepao/accountList/components/userCard.vue

@@ -30,7 +30,7 @@ const GetCount = async () => {
     if (!res || res.code !== 0)
       return Notification.error({
         title: '获取用户数据失败!',
-        content: res?.msg || '请稍后再试'
+        content: res.msg || '请稍后再试'
       })
     userCount.value = res.data
   } catch (error) {

+ 5 - 5
src/pages/lepao/accountList/index.vue

@@ -245,7 +245,7 @@ const GetCount = async () => {
     if (!res || res.code !== 0)
       return Notification.error({
         title: '获取用户数据失败!',
-        content: res?.msg || '请稍后再试'
+        content: res.msg || '请稍后再试'
       })
     userCount.value = res.data
   } catch (error) {
@@ -314,7 +314,7 @@ const handleBeforeOk = async (done) => {
     if (!res || res.code !== 0) {
       Notification.error({
         title: '保存乐跑账号失败!',
-        content: res?.msg || '请稍后再试'
+        content: res.msg || '请稍后再试'
       })
       return false
     }
@@ -344,7 +344,7 @@ const getAccounts = async () => {
     if (!res || res.code !== 0)
       return Notification.error({
         title: '获取账号列表失败!',
-        content: res?.msg || '请稍后再试'
+        content: res.msg || '请稍后再试'
       })
     data.value = res.data
   } catch (error) {
@@ -368,7 +368,7 @@ const SingleRun = async (item) => {
       if (!res || res.code !== 0)
         return Notification.error({
           title: '提交乐跑任务失败',
-          content: res?.msg || '请稍后再试'
+          content: res.msg || '请稍后再试'
         })
       Message.success('提交乐跑任务成功!')
     }
@@ -386,7 +386,7 @@ const DeleteAccount = async (item) => {
       if (!res || res.code !== 0)
         return Notification.error({
           title: '删除失败',
-          content: res?.msg || '请稍后再试'
+          content: res.msg || '请稍后再试'
         })
       Message.success('删除成功!')
       getAccounts()

+ 1 - 1
src/pages/lepao/lepaoRecords/index.vue

@@ -179,7 +179,7 @@ const getRecords = async () => {
     if (!res || res.code !== 0)
       return Notification.error({
         title: '获取乐跑记录失败!',
-        content: res?.msg || '请稍后再试'
+        content: res.msg || '请稍后再试'
       })
     data.value = res.data
     pagination.total = res.pagination.total

+ 1 - 1
src/pages/lepao/lepaoRecords/recordDetail.vue

@@ -30,7 +30,7 @@ const getRecordDetail = async (id) => {
         if (!res || res.code !== 0)
             return Notification.error({
                 title: '获取路径数据失败!',
-                content: res?.msg || '请稍后再试'
+                content: res.msg || '请稍后再试'
             })
 
         data.value = res.data

+ 2 - 2
src/pages/path/pathDetail.vue

@@ -52,7 +52,7 @@ const changePathState = async (state) => {
         if (!res || res.code !== 0)
             return Notification.error({
                 title: '改变路径状态失败!',
-                content: res?.msg || '请稍后再试'
+                content: res.msg || '请稍后再试'
             })
         Notification.success({
             title: '改变成功!',
@@ -77,7 +77,7 @@ const getPathDetail = async (id) => {
         if (!res || res.code !== 0)
             return Notification.error({
                 title: '获取路径数据失败!',
-                content: res?.msg || '请稍后再试'
+                content: res.msg || '请稍后再试'
             })
 
         data.value = res.data

+ 1 - 1
src/pages/path/pathList.vue

@@ -158,7 +158,7 @@ const getPathList = async () => {
         if (!res || res.code !== 0)
             return Notification.error({
                 title: '获取路径数据失败!',
-                content: res?.msg || '请稍后再试'
+                content: res.msg || '请稍后再试'
             })
 
         data.value = res.data

+ 2 - 2
src/pages/store/goodsDetail/index.vue

@@ -82,7 +82,7 @@ const handleBeforeOk = async (done) => {
         if (!res || res.code !== 0) {
             Notification.error({
                 title: '创建订单失败!',
-                content: res?.msg || '请稍后再试'
+                content: res.msg || '请稍后再试'
             })
             return false
         }
@@ -108,7 +108,7 @@ const getGoodsDetail = async () => {
         if (!res || res.code !== 0)
             return Notification.error({
                 title: '获取商品列表失败!',
-                content: res?.msg || '请稍后再试'
+                content: res.msg || '请稍后再试'
             })
         data.value = res.data
         content.value = decodeURI(atob(res.data.content || ''))

+ 2 - 2
src/pages/store/goodsList/index.vue

@@ -49,7 +49,7 @@ const getGoods = async () => {
         if (!res || res.code !== 0)
             return Notification.error({
                 title: '获取商品列表失败!',
-                content: res?.msg || '请稍后再试'
+                content: res.msg || '请稍后再试'
             })
         data.value = res.data
     } catch (error) {
@@ -69,7 +69,7 @@ const GetCount = async () => {
         if (!res || res.code !== 0)
             return Notification.error({
                 title: '获取用户数据失败!',
-                content: res?.msg || '请稍后再试'
+                content: res.msg || '请稍后再试'
             })
         userCount.value = res.data
     } catch (error) {

+ 1 - 1
src/pages/store/orders/orderDetail/index.vue

@@ -72,7 +72,7 @@ const getOrderDeatil = async () => {
     if (!res || res.code !== 0)
       return Notification.error({
         title: '获取订单详情失败!',
-        content: res?.msg || '请稍后再试'
+        content: res.msg || '请稍后再试'
       })
     data.value = res.data
     content.value = decodeURI(atob(res.data.content || ''))

+ 1 - 1
src/pages/store/orders/orderList/index.vue

@@ -103,7 +103,7 @@ const GetMyOrder = async () => {
     if (!res || res.code !== 0)
       return Notification.error({
         title: '获取订单列表失败!',
-        content: res?.msg || '请稍后再试'
+        content: res.msg || '请稍后再试'
       })
     data.value = res.data
   } catch (error) {

+ 4 - 4
src/store/modules/user.js

@@ -21,7 +21,7 @@ export const useUserStore = defineStore('user', {
     async login(userInfo) {
       try {
         const res = await login(userInfo)
-        if (!res || res.code !== 0) throw new Error(res?.msg || '登录失败!请稍后再试')
+        if (!res || res.code !== 0) throw new Error(res.msg || '登录失败!请稍后再试')
         storage.set('user', res.data, new Date().getTime() + 7 * 24 * 60 * 60 * 1000)
         this.setUser(res.data)
         return res.data
@@ -33,7 +33,7 @@ export const useUserStore = defineStore('user', {
     async uniLogin(type, code) {
       try {
         const res = await uniLogin({type, code})
-        if (!res || res.code !== 0) throw new Error(res?.msg || '登录失败!请稍后再试')
+        if (!res || res.code !== 0) throw new Error(res.msg || '登录失败!请稍后再试')
         storage.set('user', res.data, new Date().getTime() + 7 * 24 * 60 * 60 * 1000)
         this.setUser(res.data)
         return res.data
@@ -46,7 +46,7 @@ export const useUserStore = defineStore('user', {
     async changeName(username) {
       try {
         const res = await ChangeUsername({ username })
-        if (!res || res.code !== 0) throw new Error(res?.msg || '更新失败!请稍后再试')
+        if (!res || res.code !== 0) throw new Error(res.msg || '更新失败!请稍后再试')
         this.username = username
         storage.set('user', this.$state, new Date().getTime() + 7 * 24 * 60 * 60 * 1000)
       } catch (error) {
@@ -67,7 +67,7 @@ export const useUserStore = defineStore('user', {
     async getInfoFromServer() {
       try {
         const res = await GetUserInfo()
-        if (!res || res.code !== 0) throw new Error(res?.msg || '获取用户信息失败!请稍后再试')
+        if (!res || res.code !== 0) throw new Error(res.msg || '获取用户信息失败!请稍后再试')
         storage.set('user', res.data, new Date().getTime() + 7 * 24 * 60 * 60 * 1000)
         this.setUser(res.data)
         return res.data

+ 9 - 1
src/utils/encrypt.js

@@ -1,7 +1,7 @@
 import CryptoJS from 'crypto-js'
 import JSEncrypt from 'jsencrypt'
 
-const publicKey = import.meta.env.VITE_RSA_PUBLIC_KEY.replace(/\\n/g, '\n')
+const publicKey = atob(import.meta.env.VITE_RSA_PUBLIC_KEY)
 
 // 生成随机 AES 密钥
 export function generateAesKey(length = 16) {
@@ -21,6 +21,14 @@ export function aesEncrypt(data, key) {
   }).toString()
 }
 
+export function aesDecrypt(encryptedData, aesKey) {
+  const bytes = CryptoJS.AES.decrypt(encryptedData, CryptoJS.enc.Utf8.parse(aesKey), {
+    mode: CryptoJS.mode.ECB,
+    padding: CryptoJS.pad.Pkcs7
+  })
+  return JSON.parse(bytes.toString(CryptoJS.enc.Utf8))
+}
+
 // RSA 加密 AES 密钥
 export function rsaEncryptKey(aesKey) {
   const encryptor = new JSEncrypt()

+ 45 - 20
src/utils/request.js

@@ -3,20 +3,24 @@ import { useUserStore } from '@/store'
 import storage from 'store'
 import { Notification } from '@arco-design/web-vue';
 import { VueAxios } from './axios'
-import { generateAesKey, aesEncrypt, rsaEncryptKey } from './encrypt'
+import { v4 as uuidv4 } from 'uuid'
+import { LRUCache } from 'lru-cache'
+import { generateAesKey, aesEncrypt, aesDecrypt, rsaEncryptKey } from './encrypt'
 
-// 创建 axios 实例
 const request = axios.create({
-  // API 请求的默认前缀
   baseURL: import.meta.env.VITE_APP_API_BASE_URL,
-  timeout: 30000 // 请求超时时间
+  timeout: 10000
+})
+
+const aesKeyCache = new LRUCache({
+  max: 200,
+  ttl: 1000 * 60 * 5
 })
 
-// 异常拦截处理器
 const errorHandler = (error) => {
   const userStore = useUserStore()
   const user = storage.get('user')
-  console.log(error)
+  console.log(error.stack)
 
   if (error.response) {
     if (error.response.status === 401) {
@@ -34,7 +38,7 @@ const errorHandler = (error) => {
   } else {
     console.error('无法连接到服务器,请检查网络')
 
-    
+
     Notification.error({
       title: '服务器维护中',
       content: '服务器停机维护中,请耐心等待'
@@ -43,29 +47,50 @@ const errorHandler = (error) => {
 }
 
 request.interceptors.request.use(config => {
-  const userStore = useUserStore()  // 使用 Pinia store
+  const userStore = useUserStore()
 
   const user = userStore.$state
-  if (user && config.headers['Content-Type'] !== 'multipart/form-data') {
-    if (config.method === 'get') {
+  if (config.headers['Content-Type'] !== 'multipart/form-data') {
+
+    const data = {
+      ...(config.method === 'get' ? config.params : config.data),
+      time: Date.now(),
+      uuid: user?.uuid,
+      session: user?.session
+    }
+
+    const aesKey = generateAesKey()
+    const encryptedData = aesEncrypt(data, aesKey)
+    const encryptedKey = rsaEncryptKey(aesKey)
+
+    const requestId = uuidv4()
+    config.headers['X-Request-ID'] = requestId
+    aesKeyCache.set(requestId, aesKey)
+
+    if (config.method === 'get')
       config.params = {
-        ...config.params,
-        uuid: user.uuid,
-        session: user.session
+        encryptedData,
+        encryptedKey
       }
-    } else {
+    else
       config.data = {
-        ...config.data,
-        uuid: user.uuid,
-        session: user.session
+        encryptedData,
+        encryptedKey
       }
-    }
   }
+
   return config
 }, errorHandler)
 
-// response interceptor
-request.interceptors.response.use((response) => {
+request.interceptors.response.use(async (response) => {
+  if (response.data.encryptedData) {
+    const requestId = response.config.headers['X-Request-ID']
+    const aesKey = aesKeyCache.get(requestId)
+
+    response.data.data = aesDecrypt(response.data.encryptedData, aesKey)
+    aesKeyCache.delete(requestId)
+  }
+
   return response.data
 }, errorHandler)