Przeglądaj źródła

用户端小程序首页优化

skyline 1 miesiąc temu
rodzic
commit
2130052f7a

+ 79 - 8
haha-mp/src/App.vue

@@ -1,5 +1,7 @@
 <script setup lang="ts">
 import { onLaunch, onShow, onHide } from "@dcloudio/uni-app";
+import { API_CONFIG } from './utils/config';
+import { handleUnauthorized, clearAuth } from './utils/auth';
 
 /**
  * 应用启动
@@ -39,11 +41,62 @@ const LOGIN_WHITE_LIST = [
   'pages/products/products',
 ];
 
+/**
+ * 验证token是否有效
+ * 调用后端用户信息接口校验token,返回true/false
+ */
+const verifyToken = (): Promise<boolean> => {
+  return new Promise((resolve) => {
+    const token = uni.getStorageSync('accessToken');
+    if (!token) {
+      resolve(false);
+      return;
+    }
+
+    const url = `${API_CONFIG.baseUrl}/login/user-info`;
+    uni.request({
+      url,
+      method: 'POST',
+      header: {
+        'Content-Type': 'application/json',
+        'accessToken': token
+      },
+      timeout: 10000,
+      success: (res: any) => {
+        if (res.statusCode === 200) {
+          const data = res.data;
+          if (data && (data.code === 200 || data.code === 0)) {
+            // token有效
+            resolve(true);
+          } else if (data && data.code === 401) {
+            // token无效或已过期
+            console.log('[App] token无效:', data.message);
+            resolve(false);
+          } else {
+            // 其他业务错误,保守起见仍视为token有效
+            console.warn('[App] 验证token返回异常状态:', data?.code, data?.message);
+            resolve(true);
+          }
+        } else {
+          // 网络或服务异常,不阻断用户使用,保守视为token有效
+          console.warn('[App] 验证token网络异常, statusCode:', res.statusCode);
+          resolve(true);
+        }
+      },
+      fail: (err: any) => {
+        // 网络请求失败,保守视为token有效,不阻断用户使用
+        console.warn('[App] 验证token请求失败:', err.errMsg);
+        resolve(true);
+      }
+    });
+  });
+};
+
 /**
  * 检查登录状态
- * 如果未登录且当前不在白名单页面,则跳转到登录页
+ * 如果未登录或token无效且当前不在白名单页面,则跳转到登录页
  */
-const checkLoginStatus = (launchOptions?: any) => {
+const checkLoginStatus = async (launchOptions?: any) => {
   const token = uni.getStorageSync('accessToken');
 
   // 优先从启动参数获取目标页面路径(onLaunch时getCurrentPages为空)
@@ -56,13 +109,31 @@ const checkLoginStatus = (launchOptions?: any) => {
 
   console.log('[App] 检查登录状态 - token:', token ? '已存在' : '不存在', ', 目标页面:', currentPath);
 
-  // 如果没有token且不在白名单页面,跳转到登录页
   const isWhiteListed = LOGIN_WHITE_LIST.some(path => currentPath.indexOf(path) !== -1);
-  if (!token && !isWhiteListed) {
-    console.log('[App] 未登录,跳转到登录页');
-    uni.reLaunch({
-      url: '/pages/login/login'
-    });
+
+  // 没有token
+  if (!token) {
+    if (!isWhiteListed) {
+      console.log('[App] 未登录,跳转到登录页');
+      uni.reLaunch({ url: '/pages/login/login' });
+    }
+    return;
+  }
+
+  // 有token,向后端验证是否有效
+  console.log('[App] token存在,验证token有效性...');
+  const isValid = await verifyToken();
+
+  if (!isValid && !isWhiteListed) {
+    // token无效且不在白名单 -> 触发全局未授权处理
+    console.log('[App] token无效,触发全局未授权处理');
+    handleUnauthorized();
+  } else if (!isValid && isWhiteListed) {
+    // 白名单页面只清除数据不跳转(不触发全局未授权处理的重定向)
+    console.log('[App] token无效,清除登录数据(当前在白名单页面)');
+    clearAuth();
+  } else {
+    console.log('[App] token有效');
   }
 };
 </script>

+ 8 - 1
haha-mp/src/static/icons/coupon.svg

@@ -1 +1,8 @@
-<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19 3H5C3.9 3 3 3.9 3 5V19C3 20.1 3.9 21 5 21H19C20.1 21 21 20.1 21 19V5C21 3.9 20.1 3 19 3ZM19 19H5V5H19V19ZM8 14H16V16H8V14ZM8 10H16V12H8V10Z" fill="#FFD700"/></svg>
+<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <rect x="8" y="12" width="34" height="26" rx="3" fill="#FFD700"/>
+  <circle cx="8" cy="25" r="5" fill="#FAFAFA"/>
+  <circle cx="42" cy="25" r="5" fill="#FAFAFA"/>
+  <line x1="20" y1="14" x2="20" y2="36" stroke="white" stroke-width="1.5" stroke-dasharray="3,2.5" stroke-linecap="round"/>
+  <path d="M28 17C30 17 32 19 32 21C32 25 28 28 28 28C28 28 24 25 24 21C24 19 26 17 28 17Z" fill="white" fill-opacity="0.85"/>
+  <line x1="32" y1="18" x2="24" y2="26" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
+</svg>

+ 13 - 0
haha-mp/src/utils/auth.ts

@@ -96,6 +96,19 @@ export const checkAuth = (redirectUrl?: string): boolean => {
   return true;
 };
 
+/**
+ * 全局401未授权处理
+ * 清除所有登录信息并跳转到登录页
+ * 任何接口遇到401时都应调用此函数
+ */
+export const handleUnauthorized = (): void => {
+  console.log('[Auth] token无效或已过期,清除登录信息并跳转登录页');
+  clearAuth();
+  uni.reLaunch({
+    url: '/pages/login/login'
+  });
+};
+
 /**
  * 退出登录
  */

+ 6 - 16
haha-mp/src/utils/request.ts

@@ -4,7 +4,7 @@
  */
 
 import { API_CONFIG } from './config';
-import { getToken, removeToken } from './auth';
+import { getToken, handleUnauthorized } from './auth';
 
 /**
  * 请求配置接口
@@ -45,10 +45,9 @@ export const request = <T = any>(config: RequestConfig): Promise<T> => {
       const token = getToken();
       if (token) {
         header['accessToken'] = token;
-
-      if (API_CONFIG.enableLog) {
-        console.log('[请求拦截] 添加token到请求头:', token.substring(0, 8) + '...');
-      }
+        if (API_CONFIG.enableLog) {
+          console.log('[请求拦截] 添加token到请求头:', token.substring(0, 8) + '...');
+        }
       } else {
         if (API_CONFIG.enableLog) {
           console.warn('[请求拦截] 未找到token,请求将不携带token');
@@ -100,17 +99,8 @@ export const request = <T = any>(config: RequestConfig): Promise<T> => {
           }
           resolve(responseData.data as T);
         } else if (responseData.code === 401) {
-          // 未登录或token过期
-          uni.showToast({
-            title: '请先登录',
-            icon: 'none'
-          });
-          // 清除token
-          removeToken();
-          // 跳转到登录页
-          setTimeout(() => {
-            uni.reLaunch({ url: '/pages/login/login' });
-          }, 1500);
+          // 未登录或token过期 -> 全局未授权处理(清除登录信息并跳转登录页)
+          handleUnauthorized();
           reject(new Error(responseData.message || '未登录'));
         } else {
           // 业务错误