Procházet zdrojové kódy

feat: 新增请求中止控制

喵你个旺呀 před 1 rokem
rodič
revize
1f720be20d

+ 5 - 5
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/api.ts.vm

@@ -20,10 +20,6 @@ export const use@(Model.ClassName)Api = () => {
 		delete: baseApi.delete,
 		// 批量删除@(Model.BusName)
 		batchDelete: baseApi.batchDelete,
-		@foreach (var column in Model.UploadFieldList){
-		@:// 上传@(column.ColumnComment)
-		@:upload@(column.PropertyName): (params: any) => baseApi.uploadFile(params, baseApi.baseUrl + 'upload@(column.PropertyName)'),
-		}
 		@if (Model.ImportFieldList.Count > 0) {
 		@:// 导出@(Model.BusName)数据
 		@:exportData: baseApi.exportData,
@@ -34,7 +30,11 @@ export const use@(Model.ClassName)Api = () => {
 		}
 		@if (Model.DropdownFieldList.Count > 0) {
 		@:// 获取下拉列表数据
-		@:getDropdownData: (fromPage: Boolean = false) => baseApi.dropdownData({ fromPage }),
+		@:getDropdownData: (fromPage: Boolean = false, cancel: boolean = false) => baseApi.dropdownData({ fromPage }, cancel),
+		}
+		@foreach (var column in Model.UploadFieldList) {
+		@:// 上传@(column.ColumnComment)
+		@:upload@(column.PropertyName): (params: any, cancel: boolean = false) => baseApi.uploadFile(params, 'upload@(column.PropertyName)', cancel),
 		}
 	}
 }

+ 104 - 58
Web/src/api/base/index.ts

@@ -1,65 +1,88 @@
-import {uploadFile} from '/@/api/system/uploadFile';
-import request from '/@/utils/request';
+import { service, cancelRequest } from '/@/utils/request';
+import { AxiosRequestConfig } from "axios";
 
 // 接口基类
 export const useBaseApi = (module: string) => {
     const baseUrl = `/api/${module}/`;
+    const request = <T>(config: AxiosRequestConfig<T>, cancel: boolean = false) => {
+        if (cancel) return cancelRequest(config.url || "");
+        return service(config);
+    }
     return {
-        request,
-        uploadFile,
         baseUrl: baseUrl,
-        page: (data: any) => request({
-            url: baseUrl + "page",
-            method: 'post',
-            data,
-        }),
-        detail: (id: any) => request({
-            url: baseUrl + "detail",
-            method: 'get',
-            data: { id },
-        }),
-        dropdownData: (data: any) => request({
-            url: baseUrl + "dropdownData",
-            method: 'post',
-            data,
-        }),
-        add: (data: any) => request({
-            url: baseUrl + 'add',
-            method: 'post',
-            data
-        }),
-        update: (data: any) => request({
-            url: baseUrl + 'update',
-            method: 'post',
-            data
-        }),
-        setStatus: (data: any) => request({
-            url: baseUrl + 'setStatus',
-            method: 'post',
-            data
-        }),
-        delete: (data: any) => request({
-            url: baseUrl + 'delete',
-            method: 'post',
-            data
-        }),
-        batchDelete: (data: any) => request({
-            url: baseUrl + 'batchDelete',
-            method: 'post',
-            data
-        }),
-        exportData: (data: any) => request({
-            responseType: 'arraybuffer',
-            url: baseUrl + 'export',
-            method: 'post',
-            data
-        }),
-        downloadTemplate: () => request({
-            responseType: 'arraybuffer',
-            url: baseUrl + 'import',
-            method: 'get',
-        }),
-        importData: (file: any) => {
+        request: request,
+        page: function (data: any, cancel: boolean = false) {
+            return request({
+                url: baseUrl + "page",
+                method: 'post',
+                data,
+            }, cancel);
+        },
+        detail: function (id: any, cancel: boolean = false) {
+            return request({
+                url: baseUrl + "detail",
+                method: 'get',
+                data: { id },
+            }, cancel);
+        },
+        dropdownData: function (data: any, cancel: boolean = false) {
+            return request({
+                url: baseUrl + "dropdownData",
+                method: 'post',
+                data,
+            }, cancel);
+        },
+        add: function (data: any, cancel: boolean = false) {
+            return request({
+                url: baseUrl + 'add',
+                method: 'post',
+                data
+            }, cancel);
+        },
+        update: function (data: any, cancel: boolean = false) {
+            return request({
+                url: baseUrl + 'update',
+                method: 'post',
+                data
+            }, cancel);
+        },
+        setStatus: function (data: any, cancel: boolean = false) {
+            return request({
+                url: baseUrl + 'setStatus',
+                method: 'post',
+                data
+            }, cancel);
+        },
+        delete: function (data: any, cancel: boolean = false) {
+            return request({
+                url: baseUrl + 'delete',
+                method: 'post',
+                data
+            }, cancel);
+        },
+        batchDelete: function (data: any, cancel: boolean = false) {
+            return request({
+                url: baseUrl + 'batchDelete',
+                method: 'post',
+                data
+            }, cancel);
+        },
+        exportData: function (data: any, cancel: boolean = false) {
+            return request({
+                responseType: 'arraybuffer',
+                url: baseUrl + 'export',
+                method: 'post',
+                data
+            }, cancel);
+        },
+        downloadTemplate: function (cancel: boolean = false) {
+            return request({
+                responseType: 'arraybuffer',
+                url: baseUrl + 'import',
+                method: 'get',
+            }, cancel);
+        },
+        importData: function (file: any, cancel: boolean = false) {
             const formData = new FormData();
 	        formData.append('file', file);
             return request({
@@ -68,8 +91,31 @@ export const useBaseApi = (module: string) => {
                 url: baseUrl + 'import',
                 method: 'post',
                 data: formData,
-            });
+            }, cancel);
         },
-        
+        uploadFile: function (params: any, action: string, cancel: boolean = false) {
+            const formData = new FormData();
+            formData.append('file', params.file);
+            // 自定义参数
+            if (params.data) {
+                Object.keys(params.data).forEach((key) => {
+                    const value = params.data![key];
+                    if (Array.isArray(value)) {
+                        value.forEach((item) => formData.append(`${key}[]`, item));
+                        return;
+                    }
+                    formData.append(key, params.data![key]);
+                });
+            }
+            return request({
+                url: baseUrl + action,
+                method: 'POST',
+                data: formData,
+                headers: {
+                    ContentType: 'multipart/form-data;charset=UTF-8',
+                    ignoreCancelToken: true,
+                },
+            }, cancel);
+        }
     }
 }

+ 0 - 26
Web/src/api/system/uploadFile.ts

@@ -1,26 +0,0 @@
-import request from "/@/utils/request";
-
-export const uploadFile = (params: any, url: string) => { 
-	const formData = new FormData();
-	formData.append('file', params.file);
-	// 自定义参数
-	if (params.data) {
-		Object.keys(params.data).forEach((key) => {
-			const value = params.data![key];
-			if (Array.isArray(value)) {
-				value.forEach((item) => formData.append(`${key}[]`, item));
-				return;
-			}
-			formData.append(key, params.data![key]);
-		});
-	}
-	return request({
-		url: url,
-		method: 'POST',
-		data: formData,
-		headers: {
-			'Content-type': 'multipart/form-data;charset=UTF-8',
-			ignoreCancelToken: true,
-		},
-	});
-};

+ 7 - 0
Web/src/utils/commonFunction.ts

@@ -75,6 +75,12 @@ export default function () {
 	const getEnumDesc = (key: any, lstEnum: any) => {
 		return lstEnum.find((x: any) => x.value == key)?.describe;
 	};
+	// 追加query参数到url
+	const appendQueryParams = (url: string, params: { [key : string]: any }) => {
+		if (!params || Object.keys(params).length == 0) return url;
+		const queryString = Object.keys(params).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`).join('&');
+		return `${url}${url.includes('?') ? '&' : '?'}${queryString}`;
+	};
 	return {
 		percentFormat,
 		dateFormatYMD,
@@ -87,5 +93,6 @@ export default function () {
 		removeHtmlSub,
 		removeHtml,
 		getEnumDesc,
+		appendQueryParams
 	};
 }

+ 31 - 0
Web/src/utils/request.ts

@@ -2,6 +2,9 @@ import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
 import { ElMessage } from 'element-plus';
 import { Local, Session } from '/@/utils/storage';
 
+// 定义请求中止控制器映射表
+const abortControllerMap: Map<string, AbortController> = new Map();
+
 // 配置新建一个 axios 实例
 export const service = axios.create({
 	baseURL: window.__env__.VITE_API_URL as any,
@@ -41,6 +44,12 @@ service.interceptors.request.use(
 		// 	(<any>config.headers).common['Authorization'] = `${Session.get('token')}`;
 		// }
 
+		// 记录中止控制信息
+		const controller = new AbortController();
+		config.signal = controller.signal;
+		const url = config.url || '';
+		abortControllerMap.set(url, controller);
+
 		// 获取本地的 token
 		const accessToken = Local.get(accessTokenKey);
 		if (accessToken) {
@@ -81,6 +90,11 @@ service.interceptors.request.use(
 // 添加响应拦截器
 service.interceptors.response.use(
 	(res) => {
+
+		// 请求结束后清除中止控制项
+		const url = res.config.url || '';
+		abortControllerMap.delete(url);
+
 		// 获取状态码和返回数据
 		var status = res.status;
 		var serve = res.data;
@@ -159,6 +173,23 @@ service.interceptors.response.use(
 	}
 );
 
+// 取消指定请求
+export const cancelRequest = (url: string | string[]) => {
+	const urlList = Array.isArray(url) ? url : [url];
+	for (const _url of urlList) {
+		abortControllerMap.get(_url)?.abort();
+		abortControllerMap.delete(_url);
+	}
+}
+
+// 取消全部请求
+export const cancelAllRequest = () => {
+	for (const [_, controller] of abortControllerMap) {
+		controller.abort();
+	}
+	abortControllerMap.clear();
+}
+
 /**
  *  参数处理
  * @param {*} params  参数