@base-web-kits/base-tools-web 1.2.0-alpha.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,22 +39,24 @@ export type RequestConfigBase<D extends RequestData = RequestData> = {
39
39
  successCode: (number | string)[];
40
40
  /** 登录过期状态码 */
41
41
  reloginCode: (number | string)[];
42
- /** 是否显示进度条: 支持字符串,自定义文本 (默认true) */
43
- showLoading?: boolean | string;
42
+ /** 是否开启流式传输 (如 SSE) */
43
+ enableChunked?: boolean;
44
+ /** 响应类型 (默认 json, enableChunked为true时忽略) */
45
+ responseType?: 'text' | 'arraybuffer' | 'json';
46
+ /** 响应数据的缓存时间, 单位毫秒。仅在成功时缓存;仅缓存在内存,应用退出,缓存消失。(默认0,不开启缓存) */
47
+ cacheTime?: number;
44
48
  /** 是否提示接口异常 (默认true) */
45
49
  toastError?: boolean;
50
+ /** 是否显示进度条: 支持字符串,自定义文本 (默认true) */
51
+ showLoading?: boolean | string;
46
52
  /** 是否输出日志 (默认true) */
47
- isLog?: boolean;
53
+ showLog?: boolean;
48
54
  /** 成功和失败时,额外输出的日志数据 (可覆盖内部log参数,如'name') */
49
55
  logExtra?: Record<string, unknown>;
50
- /** 响应数据的缓存时间, 单位毫秒。仅在成功时缓存;仅缓存在内存,应用退出,缓存消失。(默认0,不开启缓存) */
51
- cacheTime?: number;
52
- /** 是否开启流式传输 (如 SSE) */
53
- enableChunked?: boolean;
54
- /** 响应类型 (默认 json, enableChunked为true时忽略) */
55
- responseType?: 'text' | 'arraybuffer' | 'json';
56
56
  /** 响应拦截 */
57
- responseInterceptor?: (data: ResponseData) => ResponseData;
57
+ resMap?: (data: ResponseData) => ResponseData;
58
+ /** 获取task对象, 用于取消请求或监听流式数据 */
59
+ onTaskReady?: (task: RequestTask) => void;
58
60
  };
59
61
  /**
60
62
  * 请求任务对象 (用于取消请求或监听流式数据)
@@ -77,7 +79,6 @@ export type ChunkCallback = (response: {
77
79
  * 基础请求 (返回 Promise 和 Task 对象)
78
80
  * 基于 fetch API 封装,支持流式请求
79
81
  * @param config 请求配置
80
- * @returns Promise<T> & { task?: RequestTask }
81
82
  * @example
82
83
  * // 在入口文件完成配置 (确保请求失败有toast提示,登录过期能够触发重新登录,log有日志输出)
83
84
  * setBaseToolsConfig({
@@ -100,7 +101,7 @@ export type ChunkCallback = (response: {
100
101
  * export function requestApi<T>(config: RequestConfig) {
101
102
  * return request<T>({
102
103
  * header: { token: 'xx', version: 'xx', tid: 'xx' }, // 会自动过滤空值
103
- * // responseInterceptor: (res) => res, // 响应拦截,可预处理响应数据,如解密 (可选)
104
+ * // resMap: (res) => res, // 响应拦截,可预处理响应数据,如解密 (可选)
104
105
  * resKey: 'data',
105
106
  * msgKey: 'message',
106
107
  * codeKey: 'status',
@@ -122,32 +123,36 @@ export type ChunkCallback = (response: {
122
123
  * return requestApi<GoodItem[]>({ url: '/goods/list', resKey: 'data.list', ...config });
123
124
  * }
124
125
  *
125
- * const goodList = await apiGoodList({ data: { page:1, size:10 }, showLoading: false });
126
+ * const goodList = await apiGoodList({ data: { page:1, size:10 } });
126
127
  *
127
128
  * // 3. 基于上面 requestApi 的流式接口
128
- * export function apiChatStream(data: { question: string }) {
129
- * return requestApi<T>({
129
+ * export function apiChatStream(config: RequestConfig) {
130
+ * return requestApi({
131
+ * ...config,
130
132
  * url: '/sse/chatStream',
131
- * data,
132
133
  * resKey: false,
133
134
  * showLoading: false,
134
- * responseType: 'arraybuffer',
135
- * enableChunked: true,
135
+ * responseType: 'arraybuffer', // 流式响应类型
136
+ * enableChunked: true, // 开启分块传输
136
137
  * });
137
138
  * }
138
139
  *
139
- * const { task } = apiChatStream({question: '你好'}); // 发起流式请求
140
+ * // 流式监听
141
+ * const onTaskReady = (task: RequestTask) => {
142
+ * task.onChunkReceived((res) => {
143
+ * console.log('ArrayBuffer', res.data);
144
+ * });
145
+ * }
140
146
  *
141
- * task.onChunkReceived((res) => {
142
- * console.log('ArrayBuffer', res.data); // 接收流式数据
143
- * });
147
+ * // 流式发起
148
+ * const data: ChatData = { content: '你好', conversationId: 123 };
149
+ * await apiChatStream({ data, onTaskReady });
144
150
  *
145
- * task.offChunkReceived(); // 取消监听,中断流式接收 (调用时机:流式结束,组件销毁,页面关闭)
146
- * task.abort(); // 取消请求 (若流式传输中,会中断流并抛出异常)
151
+ * // 流式取消 (在组件销毁或页面关闭时调用)
152
+ * task?.offChunkReceived(); // 取消监听,中断流式接收
153
+ * task?.abort(); // 取消请求 (若流式已生成,此时abort无效,因为请求已成功)
147
154
  */
148
- export declare function request<T, D extends RequestData = RequestData>(config: RequestConfigBase<D>): Promise<T> & {
149
- task?: RequestTask;
150
- };
155
+ export declare function request<T, D extends RequestData = RequestData>(config: RequestConfigBase<D>): Promise<T>;
151
156
  /**
152
157
  * 参数过滤undefined, 避免接口处理异常 (不可过滤 null 、 "" 、 false 、 0 这些有效值)
153
158
  */
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/web/network/request.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/web/network/request.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base-web-kits/base-tools-web",
3
- "version": "1.2.0-alpha.0",
3
+ "version": "1.2.0",
4
4
  "sideEffects": false,
5
5
  "description": "Independent Web utilities package built from src/web.",
6
6
  "keywords": [
@@ -25,7 +25,7 @@
25
25
  "src"
26
26
  ],
27
27
  "dependencies": {
28
- "@base-web-kits/base-tools-ts": "^1.1.11"
28
+ "@base-web-kits/base-tools-ts": "^1.2.0"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "axios": ">=0.18.0"
@@ -23,8 +23,8 @@ export type WebApiConfig<Res = any, Err = any> = {
23
23
  /** 是否显示日志, 默认 true */
24
24
  showLog?: boolean;
25
25
 
26
- /** 处理成功res, 如解密操作 (返回值在成功日志中输出'resFilter'字段) */
27
- resFilter?: (res: Res) => Res;
26
+ /** 成功响应数据的处理, 如解密操作 (返回值在成功日志中输出'resMap'字段) */
27
+ resMap?: (res: any) => Res;
28
28
 
29
29
  /** 成功和失败时,额外输出的日志数据 (可覆盖内部log参数,如'name') */
30
30
  logExtra?: Record<string, unknown>;
@@ -50,7 +50,7 @@ export function enhanceWebApi<Option = any, Res = any, Err = any, Config = any>(
50
50
  toastSuccess = false,
51
51
  toastError = true,
52
52
  showLog = true,
53
- resFilter,
53
+ resMap,
54
54
  logExtra,
55
55
  } = finalConfig;
56
56
 
@@ -72,14 +72,14 @@ export function enhanceWebApi<Option = any, Res = any, Err = any, Config = any>(
72
72
  .then((res) => {
73
73
  if (showLoading) hideLoadingFn?.();
74
74
 
75
- const finalRes = resFilter ? resFilter(res) : res;
75
+ const finalRes = resMap ? resMap(res) : res;
76
76
 
77
77
  if (showLog) {
78
78
  const logData: AppLogInfo = { name: fname, status: 'success', option, ...logExtra };
79
79
 
80
- if (resFilter) {
80
+ if (resMap) {
81
81
  logData.res = res; // 输出原始数据
82
- logData.resFilter = cloneDeep(finalRes); // 深拷贝处理后数据,避免外部修改对象,造成输出不一致
82
+ logData.resMap = cloneDeep(finalRes); // 深拷贝处理后数据,避免外部修改对象,造成输出不一致
83
83
  } else {
84
84
  logData.res = cloneDeep(res); // 深拷贝原始数据,避免外部修改对象,造成输出不一致
85
85
  }
@@ -83,29 +83,32 @@ export type RequestConfigBase<D extends RequestData = RequestData> = {
83
83
  /** 登录过期状态码 */
84
84
  reloginCode: (number | string)[];
85
85
 
86
- /** 是否显示进度条: 支持字符串,自定义文本 (默认true) */
87
- showLoading?: boolean | string;
86
+ /** 是否开启流式传输 (如 SSE) */
87
+ enableChunked?: boolean;
88
+
89
+ /** 响应类型 (默认 json, enableChunked为true时忽略) */
90
+ responseType?: 'text' | 'arraybuffer' | 'json';
91
+
92
+ /** 响应数据的缓存时间, 单位毫秒。仅在成功时缓存;仅缓存在内存,应用退出,缓存消失。(默认0,不开启缓存) */
93
+ cacheTime?: number;
88
94
 
89
95
  /** 是否提示接口异常 (默认true) */
90
96
  toastError?: boolean;
91
97
 
98
+ /** 是否显示进度条: 支持字符串,自定义文本 (默认true) */
99
+ showLoading?: boolean | string;
100
+
92
101
  /** 是否输出日志 (默认true) */
93
- isLog?: boolean;
102
+ showLog?: boolean;
94
103
 
95
104
  /** 成功和失败时,额外输出的日志数据 (可覆盖内部log参数,如'name') */
96
105
  logExtra?: Record<string, unknown>;
97
106
 
98
- /** 响应数据的缓存时间, 单位毫秒。仅在成功时缓存;仅缓存在内存,应用退出,缓存消失。(默认0,不开启缓存) */
99
- cacheTime?: number;
100
-
101
- /** 是否开启流式传输 (如 SSE) */
102
- enableChunked?: boolean;
103
-
104
- /** 响应类型 (默认 json, enableChunked为true时忽略) */
105
- responseType?: 'text' | 'arraybuffer' | 'json';
106
-
107
107
  /** 响应拦截 */
108
- responseInterceptor?: (data: ResponseData) => ResponseData;
108
+ resMap?: (data: ResponseData) => ResponseData;
109
+
110
+ /** 获取task对象, 用于取消请求或监听流式数据 */
111
+ onTaskReady?: (task: RequestTask) => void;
109
112
  };
110
113
 
111
114
  /**
@@ -134,7 +137,6 @@ const requestCache = new Map<string, { res: unknown; expire: number }>();
134
137
  * 基础请求 (返回 Promise 和 Task 对象)
135
138
  * 基于 fetch API 封装,支持流式请求
136
139
  * @param config 请求配置
137
- * @returns Promise<T> & { task?: RequestTask }
138
140
  * @example
139
141
  * // 在入口文件完成配置 (确保请求失败有toast提示,登录过期能够触发重新登录,log有日志输出)
140
142
  * setBaseToolsConfig({
@@ -157,7 +159,7 @@ const requestCache = new Map<string, { res: unknown; expire: number }>();
157
159
  * export function requestApi<T>(config: RequestConfig) {
158
160
  * return request<T>({
159
161
  * header: { token: 'xx', version: 'xx', tid: 'xx' }, // 会自动过滤空值
160
- * // responseInterceptor: (res) => res, // 响应拦截,可预处理响应数据,如解密 (可选)
162
+ * // resMap: (res) => res, // 响应拦截,可预处理响应数据,如解密 (可选)
161
163
  * resKey: 'data',
162
164
  * msgKey: 'message',
163
165
  * codeKey: 'status',
@@ -179,30 +181,57 @@ const requestCache = new Map<string, { res: unknown; expire: number }>();
179
181
  * return requestApi<GoodItem[]>({ url: '/goods/list', resKey: 'data.list', ...config });
180
182
  * }
181
183
  *
182
- * const goodList = await apiGoodList({ data: { page:1, size:10 }, showLoading: false });
184
+ * const goodList = await apiGoodList({ data: { page:1, size:10 } });
183
185
  *
184
186
  * // 3. 基于上面 requestApi 的流式接口
185
- * export function apiChatStream(data: { question: string }) {
186
- * return requestApi<T>({
187
+ * export function apiChatStream(config: RequestConfig) {
188
+ * return requestApi({
189
+ * ...config,
187
190
  * url: '/sse/chatStream',
188
- * data,
189
191
  * resKey: false,
190
192
  * showLoading: false,
191
- * responseType: 'arraybuffer',
192
- * enableChunked: true,
193
+ * responseType: 'arraybuffer', // 流式响应类型
194
+ * enableChunked: true, // 开启分块传输
193
195
  * });
194
196
  * }
195
197
  *
196
- * const { task } = apiChatStream({question: '你好'}); // 发起流式请求
198
+ * // 流式监听
199
+ * const onTaskReady = (task: RequestTask) => {
200
+ * task.onChunkReceived((res) => {
201
+ * console.log('ArrayBuffer', res.data);
202
+ * });
203
+ * }
197
204
  *
198
- * task.onChunkReceived((res) => {
199
- * console.log('ArrayBuffer', res.data); // 接收流式数据
200
- * });
205
+ * // 流式发起
206
+ * const data: ChatData = { content: '你好', conversationId: 123 };
207
+ * await apiChatStream({ data, onTaskReady });
201
208
  *
202
- * task.offChunkReceived(); // 取消监听,中断流式接收 (调用时机:流式结束,组件销毁,页面关闭)
203
- * task.abort(); // 取消请求 (若流式传输中,会中断流并抛出异常)
209
+ * // 流式取消 (在组件销毁或页面关闭时调用)
210
+ * task?.offChunkReceived(); // 取消监听,中断流式接收
211
+ * task?.abort(); // 取消请求 (若流式已生成,此时abort无效,因为请求已成功)
204
212
  */
205
213
  export function request<T, D extends RequestData = RequestData>(config: RequestConfigBase<D>) {
214
+ const {
215
+ url,
216
+ data,
217
+ header,
218
+ method = 'GET',
219
+ resKey,
220
+ msgKey,
221
+ codeKey,
222
+ successKey,
223
+ successCode,
224
+ reloginCode,
225
+ showLoading = true,
226
+ toastError = true,
227
+ enableChunked = false,
228
+ cacheTime,
229
+ resMap,
230
+ responseType = 'json',
231
+ timeout = 60000,
232
+ onTaskReady,
233
+ } = config;
234
+
206
235
  // 1. 初始化控制对象
207
236
  const controller = new AbortController();
208
237
  const signal = controller.signal;
@@ -218,30 +247,11 @@ export function request<T, D extends RequestData = RequestData>(config: RequestC
218
247
  chunkCallback = null;
219
248
  },
220
249
  };
250
+ onTaskReady?.(task);
221
251
 
222
252
  // 2. 创建 Promise
223
- const promise = new Promise<T>((resolve, reject) => {
253
+ return new Promise<T>((resolve, reject) => {
224
254
  const execute = async () => {
225
- const {
226
- url,
227
- data,
228
- header,
229
- method = 'GET',
230
- resKey,
231
- msgKey,
232
- codeKey,
233
- successKey,
234
- successCode,
235
- reloginCode,
236
- showLoading = true,
237
- toastError = true,
238
- enableChunked = false,
239
- cacheTime,
240
- responseInterceptor,
241
- responseType = 'json',
242
- timeout = 60000,
243
- } = config;
244
-
245
255
  const isGet = method === 'GET';
246
256
  const isObjectData = isPlainObject(data);
247
257
  const isArrayData = !isObjectData && Array.isArray(data);
@@ -353,7 +363,7 @@ export function request<T, D extends RequestData = RequestData>(config: RequestC
353
363
  if (showLoading) appConfig.hideLoading?.();
354
364
 
355
365
  // 响应拦截
356
- const res = responseInterceptor ? responseInterceptor(resData) : resData;
366
+ const res = resMap ? resMap(resData) : resData;
357
367
 
358
368
  // 2.10 业务状态码解析
359
369
  const code = getObjectValue(res, codeKey);
@@ -399,12 +409,7 @@ export function request<T, D extends RequestData = RequestData>(config: RequestC
399
409
  };
400
410
 
401
411
  execute();
402
- }) as Promise<T> & { task?: RequestTask };
403
-
404
- // 3. 挂载 Task
405
- promise.task = task;
406
-
407
- return promise;
412
+ });
408
413
  }
409
414
 
410
415
  /**
@@ -443,9 +448,9 @@ function logRequestInfo(options: {
443
448
  e?: unknown;
444
449
  }) {
445
450
  const { log } = getBaseToolsConfig();
446
- const { isLog = true } = options.config;
451
+ const { showLog = true } = options.config;
447
452
 
448
- if (!log || !isLog) return;
453
+ if (!log || !showLog) return;
449
454
 
450
455
  const { config, res, fromCache = false, startTime, status, e } = options;
451
456
  const { url, data, header, method, logExtra } = config;