Quellcode durchsuchen

feat(订单实时): 静默请求开关 + 列表 API 透传 + 登出停流;删零引用 websocket.ts

alphaH vor 1 Woche
Ursprung
Commit
d23d41d4fd

+ 27 - 20
frontend/src/api/module_payment/collection.ts

@@ -24,19 +24,23 @@ import request from "@/utils/request";
  */
 
 // ==================== 订单 ====================
-export function getLsyOrderPage(params: {
-  pageNo: number;
-  pageSize: number;
-  status?: string;
-  payScene?: string;
-  keyword?: string;
-  /**
-   * ★ 只有超管会传(2026-09-30)。后端 `LeshouyingOrderController#applyTenantFilter`
-   * 对非超管传它一律 403 —— 不是「忽略」,理由见那边的 javadoc。
-   */
-  tenantId?: number;
-}) {
-  return request({ url: "/payment/collection/order/page", method: "get", params });
+export function getLsyOrderPage(
+  params: {
+    pageNo: number;
+    pageSize: number;
+    status?: string;
+    payScene?: string;
+    keyword?: string;
+    /**
+     * ★ 只有超管会传(2026-09-30)。后端 `LeshouyingOrderController#applyTenantFilter`
+     * 对非超管传它一律 403 —— 不是「忽略」,理由见那边的 javadoc。
+     */
+    tenantId?: number;
+  },
+  /** true = 后台静默刷新:失败不弹 toast(见 request.ts 的 silent 声明) */
+  silent = false
+) {
+  return request({ url: "/payment/collection/order/page", method: "get", params, silent });
 }
 
 export function getLsyOrderDetail(outTradeNo: string) {
@@ -88,13 +92,16 @@ export function refundLsyOrder(outTradeNo: string, refundFee?: number) {
 }
 
 // ==================== 退款 ====================
-export function getLsyRefundPage(params: {
-  pageNo: number;
-  pageSize: number;
-  status?: string;
-  keyword?: string;
-}) {
-  return request({ url: "/payment/collection/refund/page", method: "get", params });
+export function getLsyRefundPage(
+  params: {
+    pageNo: number;
+    pageSize: number;
+    status?: string;
+    keyword?: string;
+  },
+  silent = false
+) {
+  return request({ url: "/payment/collection/refund/page", method: "get", params, silent });
 }
 
 export function getLsyRefundDetail(outRefundNo: string) {

+ 6 - 4
frontend/src/api/module_payment/har.ts

@@ -303,20 +303,22 @@ const HarAPI = {
 
   // ---------- 订单 ----------
 
-  /** 订单列表(分页) */
-  orderList(params: HarOrderQueryParams) {
+  /** 订单列表(分页);silent = 后台静默刷新 */
+  orderList(params: HarOrderQueryParams, silent = false) {
     return request<ApiResponse<HarPageResult<HarOrderVO[]>>>({
       url: `${API_PATH}/order`,
       method: "get",
       params,
+      silent,
     });
   },
 
-  /** 订单详情 */
-  orderDetail(id: string) {
+  /** 订单详情;silent = 后台静默刷新(详情弹窗实时联动用) */
+  orderDetail(id: string, silent = false) {
     return request<ApiResponse<HarOrderVO>>({
       url: `${API_PATH}/order/${id}`,
       method: "get",
+      silent,
     });
   },
 

+ 3 - 0
frontend/src/store/modules/user.store.ts

@@ -5,6 +5,7 @@ import UserAPI, { type UserInfo } from "@/api/module_system/user";
 import { type TenantInfo } from "@/api/module_system/tenant";
 import type { MenuTable } from "@/api/module_system/menu";
 import { Auth } from "@/utils/auth";
+import { stopOrderStream } from "@/utils/orderStreamInstance";
 import { ResultEnum } from "@/enums";
 
 export { type TenantInfo } from "@/api/module_system/tenant";
@@ -164,6 +165,8 @@ export const useUserStore = defineStore("user", {
     resetAllState() {
       // 重置用户状态
       Auth.clearAuth();
+      // 停掉订单实时长连接:token 已经清了,继续挂着只会被 403 挡回、无限重连
+      stopOrderStream();
       // 重置用户信息
       this.clearUserInfo();
       // 重置路由

+ 27 - 6
frontend/src/utils/request.ts

@@ -9,6 +9,13 @@ import { ResultEnum } from "@/enums/api/result.enum";
 import { Auth } from "@/utils/auth";
 import { redirectToLogin } from "@/utils/authRedirect";
 
+declare module "axios" {
+  export interface AxiosRequestConfig {
+    /** 静默请求:失败不弹 toast(后台自动刷新用)。401 / TOKEN_EXPIRED 的跳登录行为不变 */
+    silent?: boolean;
+  }
+}
+
 /**
  * 创建 HTTP 请求实例
  */
@@ -61,12 +68,15 @@ httpRequest.interceptors.response.use(
 
     // 检查请求是否失败
     if (data.code !== ResultEnum.SUCCESS) {
-      ElMessage.error(data.msg);
+      if (!response.config.silent) {
+        ElMessage.error(data.msg);
+      }
       return Promise.reject(response);
     }
 
     // 如果请求不是 GET 请求,且不是登录或退出登录接口,请求成功时显示成功提示
     if (
+      !response.config.silent &&
       response.config.method?.toUpperCase() !== "GET" &&
       !response.config.url?.includes("login") &&
       !response.config.url?.includes("logout")
@@ -77,6 +87,7 @@ httpRequest.interceptors.response.use(
     return response;
   },
   async (error: AxiosError<ApiResponse>) => {
+    const silent = error.config?.silent === true;
     // 处理网络错误(连接拒绝、超时等)
     if (!error.response) {
       let errorMessage = "网络连接异常";
@@ -91,7 +102,9 @@ httpRequest.interceptors.response.use(
       }
 
       console.error("网络请求失败:", error);
-      ElMessage.error(errorMessage);
+      if (!silent) {
+        ElMessage.error(errorMessage);
+      }
       return Promise.reject(new Error(errorMessage));
     }
 
@@ -139,16 +152,24 @@ httpRequest.interceptors.response.use(
       await redirectToLogin("登录已过期,请重新登录");
       return Promise.reject(new Error(data.msg));
     } else if (data?.code === ResultEnum.ERROR) {
-      ElMessage.error(data.msg || "请求错误");
+      if (!silent) {
+        ElMessage.error(data.msg || "请求错误");
+      }
       return Promise.reject(new Error(data.msg || "请求错误"));
     } else if (data?.code === ResultEnum.UNAUTHORIZED) {
-      ElMessage.error(data.msg || "暂无权限");
+      if (!silent) {
+        ElMessage.error(data.msg || "暂无权限");
+      }
       return Promise.reject(new Error(data.msg || "请求错误"));
     } else if (data?.code === ResultEnum.EXCEPTION) {
-      ElMessage.error(data.msg || "服务异常");
+      if (!silent) {
+        ElMessage.error(data.msg || "服务异常");
+      }
       return Promise.reject(new Error(data.msg || "服务异常"));
     } else {
-      ElMessage.error("请求处理失败,请稍后重试");
+      if (!silent) {
+        ElMessage.error("请求处理失败,请稍后重试");
+      }
       return Promise.reject(new Error("请求处理失败"));
     }
   }

+ 0 - 109
frontend/src/utils/websocket.ts

@@ -1,109 +0,0 @@
-/**
- * WebSocket 服务管理
- *
- * @description
- * 统一管理应用中的所有 WebSocket 连接
- * - 字典同步 WebSocket
- * - 在线用户计数 WebSocket
- * - 其他业务 WebSocket
- *
- * @author fastapiadmin
- */
-
-import { Auth } from "@/utils/auth";
-
-/**
- * WebSocket 服务实例约定接口
- */
-type WebSocketService = {
-  disconnect?: () => void;
-  closeWebSocket?: () => void;
-  cleanup?: () => void;
-  [key: string]: any;
-};
-
-/**
- * 全局 WebSocket 实例管理
- */
-const websocketInstances = new Map<string, WebSocketService>();
-
-/**
- * 防止重复初始化的状态标记
- */
-let isInitialized = false;
-
-/**
- * 注册 WebSocket 实例
- */
-export function registerWebSocketInstance(key: string, instance: WebSocketService) {
-  websocketInstances.set(key, instance);
-}
-
-/**
- * 获取 WebSocket 实例
- */
-export function getWebSocketInstance(key: string) {
-  return websocketInstances.get(key);
-}
-
-/**
- * 初始化 WebSocket 服务
- */
-export function setupWebSocket() {
-  if (isInitialized) {
-    console.warn("[WebSocket] 已初始化,跳过重复初始化");
-    return;
-  }
-
-  if (!Auth.getAccessToken()) {
-    console.warn("[WebSocket] 未登录,跳过 WebSocket 初始化");
-    return;
-  }
-
-  try {
-    isInitialized = true;
-    console.log("[WebSocket] 初始化成功");
-  } catch (error) {
-    console.error("[WebSocket] 初始化失败:", error);
-  }
-}
-
-/**
- * 清理所有 WebSocket 连接
- */
-export function cleanupWebSocket() {
-  console.log("[WebSocket] 开始清理连接...");
-
-  websocketInstances.forEach((instance, key) => {
-    try {
-      if (instance.disconnect) {
-        instance.disconnect();
-      } else if (instance.closeWebSocket) {
-        instance.closeWebSocket();
-      } else if (instance.cleanup) {
-        instance.cleanup();
-      }
-      console.log(`[WebSocket] ${key} 已断开`);
-    } catch (error) {
-      console.error(`[WebSocket] ${key} 清理失败:`, error);
-    }
-  });
-
-  websocketInstances.clear();
-  isInitialized = false;
-  console.log("[WebSocket] 清理完成");
-}
-
-/**
- * 重新初始化 WebSocket
- */
-export function reinitializeWebSocket() {
-  cleanupWebSocket();
-  setupWebSocket();
-}
-
-if (typeof window !== "undefined") {
-  window.addEventListener("beforeunload", () => {
-    cleanupWebSocket();
-  });
-}