@base-web-kits/base-tools-web 1.1.11 → 1.1.18-alpha.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.
- package/dist/async/index.d.ts +26 -0
- package/dist/async/index.d.ts.map +1 -0
- package/dist/base-tools-web.umd.global.js +133 -19
- package/dist/base-tools-web.umd.global.js.map +1 -1
- package/dist/config/index.d.ts +3 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/index.cjs +137 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +134 -5
- package/dist/index.js.map +1 -1
- package/dist/network/{load.d.ts → download.d.ts} +1 -1
- package/dist/network/download.d.ts.map +1 -0
- package/dist/network/index.d.ts +2 -1
- package/dist/network/index.d.ts.map +1 -1
- package/dist/network/request.d.ts +11 -3
- package/dist/network/request.d.ts.map +1 -1
- package/dist/network/uploadFile.d.ts +57 -0
- package/dist/network/uploadFile.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/web/async/index.ts +82 -0
- package/src/web/config/index.ts +1 -1
- package/src/web/network/index.ts +2 -1
- package/src/web/network/request.ts +33 -12
- package/src/web/network/uploadFile.ts +152 -0
- package/dist/network/load.d.ts.map +0 -1
- /package/src/web/network/{load.ts → download.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/web/network/download.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,SAAK,iBAyC/D;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,aAAa,CAAC,IAAI,CAAC;;;GAc5D;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,CAAC,EAAE,MAAM,UAkB1D;AAED;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAC1B,GAAG,EAAE,MAAM,EACX,KAAK,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,OAAO,GAAG,OAAO,GAAG,aAAa,CAAC,iBAuBnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,WAOhC;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,GAAG,OAAO,CAAC,iBAuBvD;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,WAOlC;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,6BAOvC"}
|
package/dist/network/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web/network/index.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web/network/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
|
|
@@ -39,8 +39,8 @@ export type RequestConfigBase<D extends RequestData = RequestData> = {
|
|
|
39
39
|
successCode: (number | string)[];
|
|
40
40
|
/** 登录过期状态码 */
|
|
41
41
|
reloginCode: (number | string)[];
|
|
42
|
-
/**
|
|
43
|
-
showLoading?: boolean;
|
|
42
|
+
/** 是否显示进度条: 支持字符串,自定义文本 (默认true) */
|
|
43
|
+
showLoading?: boolean | string;
|
|
44
44
|
/** 是否提示接口异常 (默认true) */
|
|
45
45
|
toastError?: boolean;
|
|
46
46
|
/** 是否输出日志 (默认true) */
|
|
@@ -82,7 +82,7 @@ export type ChunkCallback = (response: {
|
|
|
82
82
|
* // 在入口文件完成配置 (确保请求失败有toast提示,登录过期能够触发重新登录,log有日志输出)
|
|
83
83
|
* setBaseToolsConfig({
|
|
84
84
|
* toast: ({ msg, status }) => (status === 'fail' ? message.error(msg) : message.success(msg)),
|
|
85
|
-
* showLoading: () => message.loading('加载中...'),
|
|
85
|
+
* showLoading: ({ title }) => message.loading(title || '加载中...'),
|
|
86
86
|
* hideLoading: () => message.destroy(),
|
|
87
87
|
* toLogin: () => reLogin(),
|
|
88
88
|
* log(level, data) {
|
|
@@ -148,4 +148,12 @@ export type ChunkCallback = (response: {
|
|
|
148
148
|
export declare function request<T, D extends RequestData = RequestData>(config: RequestConfigBase<D>): Promise<T> & {
|
|
149
149
|
task?: RequestTask;
|
|
150
150
|
};
|
|
151
|
+
/**
|
|
152
|
+
* 参数过滤undefined, 避免接口处理异常 (不可过滤 null 、 "" 、 false 、 0 这些有效值)
|
|
153
|
+
*/
|
|
154
|
+
export declare function filterRequestData(data: Record<string, any>): Record<string, any>;
|
|
155
|
+
/**
|
|
156
|
+
* 请求头过滤空值 (undefined, null, ""), 不过滤0和false
|
|
157
|
+
*/
|
|
158
|
+
export declare function filterRequestHeader(header: RequestConfigBase['header']): Record<string, string>;
|
|
151
159
|
//# sourceMappingURL=request.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/web/network/request.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/web/network/request.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { WebApiConfig } from '../async';
|
|
2
|
+
/**
|
|
3
|
+
* 上传文件的选项
|
|
4
|
+
*/
|
|
5
|
+
export type UploadFileOption = {
|
|
6
|
+
/** 上传接口地址 */
|
|
7
|
+
url: string;
|
|
8
|
+
/** 要上传的文件对象 */
|
|
9
|
+
file: File;
|
|
10
|
+
/** 文件对应的 key, 默认'file' (服务端通过这个 key 获取文件的二进制内容) */
|
|
11
|
+
name?: string;
|
|
12
|
+
/** 请求头 */
|
|
13
|
+
header?: Record<string, string | number>;
|
|
14
|
+
/** 额外的formData参数 */
|
|
15
|
+
formData?: Record<string, string | number>;
|
|
16
|
+
/** 超时时间,单位 ms,默认 0(不超时) */
|
|
17
|
+
timeout?: number;
|
|
18
|
+
};
|
|
19
|
+
export type OnUploadProgressUpdate = (res: UploadProgressEvent) => void;
|
|
20
|
+
export type UploadProgressEvent = {
|
|
21
|
+
/** 上传进度百分比: 0-100 */
|
|
22
|
+
progress: number;
|
|
23
|
+
/** 已上传字节数 */
|
|
24
|
+
loaded: number;
|
|
25
|
+
/** 总字节数 */
|
|
26
|
+
total: number;
|
|
27
|
+
};
|
|
28
|
+
export type UploadTask = {
|
|
29
|
+
/** 上传进度 */
|
|
30
|
+
onProgressUpdate: (callback: OnUploadProgressUpdate) => void;
|
|
31
|
+
/** 取消上传 */
|
|
32
|
+
abort: () => void;
|
|
33
|
+
};
|
|
34
|
+
export type UploadConfig = {
|
|
35
|
+
/** 获取task对象 */
|
|
36
|
+
onTaskReady?: (task: UploadTask) => void;
|
|
37
|
+
};
|
|
38
|
+
export type UploadFail = {
|
|
39
|
+
message: string;
|
|
40
|
+
status: number;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* 上传文件
|
|
44
|
+
* @param option 上传文件的选项
|
|
45
|
+
* @param config 配置项
|
|
46
|
+
* @example
|
|
47
|
+
* // 上传
|
|
48
|
+
* await uploadFile({ url: 'https://xx', file: file});
|
|
49
|
+
*
|
|
50
|
+
* // 监听上传进度
|
|
51
|
+
* await uploadFile({ url: 'https://xx', file: file}, {
|
|
52
|
+
* onTaskReady: (task) =>
|
|
53
|
+
* task.onProgressUpdate((res) => console.log('上传进度:', res.progress)),
|
|
54
|
+
* });
|
|
55
|
+
*/
|
|
56
|
+
export declare function uploadFile<T = any>(option: UploadFileOption, config?: UploadConfig & WebApiConfig<T, UploadFail>): Promise<T>;
|
|
57
|
+
//# sourceMappingURL=uploadFile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploadFile.d.ts","sourceRoot":"","sources":["../../src/web/network/uploadFile.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa;IACb,GAAG,EAAE,MAAM,CAAC;IAEZ,eAAe;IACf,IAAI,EAAE,IAAI,CAAC;IAEX,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,UAAU;IACV,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IAEzC,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IAE3C,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,CAAC,GAAG,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAExE,MAAM,MAAM,mBAAmB,GAAG;IAChC,qBAAqB;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW;IACX,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,WAAW;IACX,gBAAgB,EAAE,CAAC,QAAQ,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAC7D,WAAW;IACX,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,eAAe;IACf,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AA6EF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,GAAG,EAChC,MAAM,EAAE,gBAAgB,EACxB,MAAM,CAAC,EAAE,YAAY,GAAG,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,cAMpD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@base-web-kits/base-tools-web",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.18-alpha.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.
|
|
28
|
+
"@base-web-kits/base-tools-ts": "^1.1.11"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"axios": ">=0.18.0"
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { getBaseToolsConfig } from '../index';
|
|
2
|
+
|
|
3
|
+
type WebApi<Option, Res, Config = unknown> = (option: Option, config?: Config) => Promise<Res>;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* web api 的调用配置
|
|
7
|
+
*/
|
|
8
|
+
export type WebApiConfig<Res, Err> = {
|
|
9
|
+
/** 是否显示加载提示, 默认 false. (支持字符串,自定义文本) */
|
|
10
|
+
showLoading?: boolean | string;
|
|
11
|
+
|
|
12
|
+
/** 操作成功的toast提示, 默认不显示 */
|
|
13
|
+
toastSuccess?: ((res: Res) => false | string) | false | string;
|
|
14
|
+
|
|
15
|
+
/** 是否显示操作失败的详细错误信息, 默认 true. (支持字符串,自定义文本; 支持根据errMsg判断是否显示, 例如: (e) => !e.errMsg.includes('cancel') */
|
|
16
|
+
toastError?: ((e: Err) => boolean | string) | boolean | string;
|
|
17
|
+
|
|
18
|
+
/** 是否显示日志, 默认 true */
|
|
19
|
+
showLog?: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 拓展 web api, 使其支持loading,toast,log,任务对象等能力
|
|
24
|
+
* @param webApi web api
|
|
25
|
+
* @param apiName web api 名称 (可选, 用于日志输出, 默认'promisifyWebApi')
|
|
26
|
+
* @return 注入拓展能力的promise (默认提示异常和输出日志,不显示进度条和操作成功)
|
|
27
|
+
* @example
|
|
28
|
+
* const promise = promisifyWebApi(downloadFile, 'downloadFile');
|
|
29
|
+
* await promise({ url: 'xx' }, {showLoading: '下载中', toastSuccess: '下载成功'});
|
|
30
|
+
*/
|
|
31
|
+
export function promisifyWebApi<Option, Res, Err, Config = unknown>(
|
|
32
|
+
webApi: WebApi<Option, Res, Config>,
|
|
33
|
+
apiName?: string,
|
|
34
|
+
) {
|
|
35
|
+
return (option: Option, config?: WebApiConfig<Res, Err> & Config) => {
|
|
36
|
+
const finalConfig = config || ({} as WebApiConfig<Res, Err> & Config);
|
|
37
|
+
const {
|
|
38
|
+
showLoading = false,
|
|
39
|
+
toastSuccess = false,
|
|
40
|
+
toastError = true,
|
|
41
|
+
showLog = true,
|
|
42
|
+
} = finalConfig;
|
|
43
|
+
const {
|
|
44
|
+
log,
|
|
45
|
+
toast,
|
|
46
|
+
showLoading: showLoadingFn,
|
|
47
|
+
hideLoading: hideLoadingFn,
|
|
48
|
+
} = getBaseToolsConfig();
|
|
49
|
+
const fname = apiName || 'promisifyWebApi'; // webApi.name经过打包后取不到原函数名,不如默认'promisifyWebApi'
|
|
50
|
+
|
|
51
|
+
if (showLoading) {
|
|
52
|
+
const title = typeof showLoading === 'string' ? showLoading : '';
|
|
53
|
+
showLoadingFn?.({ title });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return new Promise<Res>((resolve, reject) => {
|
|
57
|
+
webApi(option, finalConfig)
|
|
58
|
+
.then((res) => {
|
|
59
|
+
if (showLoading) hideLoadingFn?.();
|
|
60
|
+
if (showLog) log?.('info', { name: fname, status: 'success', option, res });
|
|
61
|
+
resolve(res);
|
|
62
|
+
|
|
63
|
+
const msg = typeof toastSuccess === 'function' ? toastSuccess(res) : toastSuccess;
|
|
64
|
+
if (msg) toast?.({ msg, status: 'success' });
|
|
65
|
+
})
|
|
66
|
+
.catch((e) => {
|
|
67
|
+
if (showLoading) hideLoadingFn?.();
|
|
68
|
+
if (showLog) log?.('error', { name: fname, status: 'fail', option, e });
|
|
69
|
+
|
|
70
|
+
const msg = typeof toastError === 'function' ? toastError(e) : toastError;
|
|
71
|
+
if (msg) {
|
|
72
|
+
toast?.({
|
|
73
|
+
msg: typeof msg === 'string' ? msg : `${fname} fail: ${JSON.stringify(e)}`,
|
|
74
|
+
status: 'fail',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
reject(e);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
}
|
package/src/web/config/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ export type AppConfig = {
|
|
|
2
2
|
/** 全局 Toast 提示 */
|
|
3
3
|
toast?: (option: { msg: string; status: 'success' | 'fail' }) => void;
|
|
4
4
|
/** 显示全局 Loading */
|
|
5
|
-
showLoading?: () => void;
|
|
5
|
+
showLoading?: (option?: { title?: string }) => void;
|
|
6
6
|
/** 隐藏全局 Loading */
|
|
7
7
|
hideLoading?: () => void;
|
|
8
8
|
/** 跳转登录页的方法 */
|
package/src/web/network/index.ts
CHANGED
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
cloneDeep,
|
|
4
4
|
getObjectValue,
|
|
5
5
|
isPlainObject,
|
|
6
|
-
pickBy,
|
|
7
6
|
toDayjs,
|
|
8
7
|
} from '@base-web-kits/base-tools-ts';
|
|
9
8
|
import { getBaseToolsConfig } from '../config';
|
|
@@ -80,8 +79,8 @@ export type RequestConfigBase<D extends RequestData = RequestData> = {
|
|
|
80
79
|
/** 登录过期状态码 */
|
|
81
80
|
reloginCode: (number | string)[];
|
|
82
81
|
|
|
83
|
-
/**
|
|
84
|
-
showLoading?: boolean;
|
|
82
|
+
/** 是否显示进度条: 支持字符串,自定义文本 (默认true) */
|
|
83
|
+
showLoading?: boolean | string;
|
|
85
84
|
|
|
86
85
|
/** 是否提示接口异常 (默认true) */
|
|
87
86
|
toastError?: boolean;
|
|
@@ -136,7 +135,7 @@ const requestCache = new Map<string, { res: unknown; expire: number }>();
|
|
|
136
135
|
* // 在入口文件完成配置 (确保请求失败有toast提示,登录过期能够触发重新登录,log有日志输出)
|
|
137
136
|
* setBaseToolsConfig({
|
|
138
137
|
* toast: ({ msg, status }) => (status === 'fail' ? message.error(msg) : message.success(msg)),
|
|
139
|
-
* showLoading: () => message.loading('加载中...'),
|
|
138
|
+
* showLoading: ({ title }) => message.loading(title || '加载中...'),
|
|
140
139
|
* hideLoading: () => message.destroy(),
|
|
141
140
|
* toLogin: () => reLogin(),
|
|
142
141
|
* log(level, data) {
|
|
@@ -244,14 +243,11 @@ export function request<T, D extends RequestData = RequestData>(config: RequestC
|
|
|
244
243
|
const isArrayData = !isObjectData && Array.isArray(data);
|
|
245
244
|
|
|
246
245
|
// 2.1 参数处理
|
|
247
|
-
//
|
|
248
|
-
const fillData = isObjectData ?
|
|
246
|
+
// 参数过滤 undefined
|
|
247
|
+
const fillData = isObjectData ? filterRequestData(data) : data;
|
|
249
248
|
|
|
250
|
-
//
|
|
251
|
-
const
|
|
252
|
-
const fillHeader = (
|
|
253
|
-
header ? pickBy(header, (val) => !emptyValue.includes(val)) : {}
|
|
254
|
-
) as Record<string, string>;
|
|
249
|
+
// 请求头过滤空值 (undefined, null, "")
|
|
250
|
+
const fillHeader = filterRequestHeader(header);
|
|
255
251
|
|
|
256
252
|
// 获取 Content-Type (忽略大小写)
|
|
257
253
|
const contentTypeKey = Object.keys(fillHeader).find(
|
|
@@ -310,7 +306,8 @@ export function request<T, D extends RequestData = RequestData>(config: RequestC
|
|
|
310
306
|
|
|
311
307
|
// 2.5 UI 反馈
|
|
312
308
|
const appConfig = getBaseToolsConfig();
|
|
313
|
-
if (showLoading)
|
|
309
|
+
if (showLoading)
|
|
310
|
+
appConfig.showLoading?.(typeof showLoading === 'string' ? { title: showLoading } : {});
|
|
314
311
|
|
|
315
312
|
// 2.6 设置超时
|
|
316
313
|
let isTimeout = false;
|
|
@@ -406,6 +403,30 @@ export function request<T, D extends RequestData = RequestData>(config: RequestC
|
|
|
406
403
|
return promise;
|
|
407
404
|
}
|
|
408
405
|
|
|
406
|
+
/**
|
|
407
|
+
* 参数过滤undefined, 避免接口处理异常 (不可过滤 null 、 "" 、 false 、 0 这些有效值)
|
|
408
|
+
*/
|
|
409
|
+
export function filterRequestData(data: Record<string, any>) {
|
|
410
|
+
const res: Record<string, any> = {};
|
|
411
|
+
Object.entries(data).forEach(([k, v]) => {
|
|
412
|
+
if (v !== undefined) res[k] = v;
|
|
413
|
+
});
|
|
414
|
+
return res;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* 请求头过滤空值 (undefined, null, ""), 不过滤0和false
|
|
419
|
+
*/
|
|
420
|
+
export function filterRequestHeader(header: RequestConfigBase['header']) {
|
|
421
|
+
const newHeader: Record<string, string> = {};
|
|
422
|
+
if (header) {
|
|
423
|
+
Object.entries(header).forEach(([k, v]) => {
|
|
424
|
+
if (v !== undefined && v !== null && v !== '') newHeader[k] = String(v);
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
return newHeader;
|
|
428
|
+
}
|
|
429
|
+
|
|
409
430
|
/**
|
|
410
431
|
* 日志输出
|
|
411
432
|
*/
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { promisifyWebApi } from '../async';
|
|
2
|
+
import type { WebApiConfig } from '../async';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 上传文件的选项
|
|
6
|
+
*/
|
|
7
|
+
export type UploadFileOption = {
|
|
8
|
+
/** 上传接口地址 */
|
|
9
|
+
url: string;
|
|
10
|
+
|
|
11
|
+
/** 要上传的文件对象 */
|
|
12
|
+
file: File;
|
|
13
|
+
|
|
14
|
+
/** 文件对应的 key, 默认'file' (服务端通过这个 key 获取文件的二进制内容) */
|
|
15
|
+
name?: string;
|
|
16
|
+
|
|
17
|
+
/** 请求头 */
|
|
18
|
+
header?: Record<string, string | number>;
|
|
19
|
+
|
|
20
|
+
/** 额外的formData参数 */
|
|
21
|
+
formData?: Record<string, string | number>;
|
|
22
|
+
|
|
23
|
+
/** 超时时间,单位 ms,默认 0(不超时) */
|
|
24
|
+
timeout?: number;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type OnUploadProgressUpdate = (res: UploadProgressEvent) => void;
|
|
28
|
+
|
|
29
|
+
export type UploadProgressEvent = {
|
|
30
|
+
/** 上传进度百分比: 0-100 */
|
|
31
|
+
progress: number;
|
|
32
|
+
/** 已上传字节数 */
|
|
33
|
+
loaded: number;
|
|
34
|
+
/** 总字节数 */
|
|
35
|
+
total: number;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type UploadTask = {
|
|
39
|
+
/** 上传进度 */
|
|
40
|
+
onProgressUpdate: (callback: OnUploadProgressUpdate) => void;
|
|
41
|
+
/** 取消上传 */
|
|
42
|
+
abort: () => void;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type UploadConfig = {
|
|
46
|
+
/** 获取task对象 */
|
|
47
|
+
onTaskReady?: (task: UploadTask) => void;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type UploadFail = {
|
|
51
|
+
message: string;
|
|
52
|
+
status: number;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
function upload<T>(option: UploadFileOption, config?: UploadConfig) {
|
|
56
|
+
return new Promise<T>((resolve, reject) => {
|
|
57
|
+
const xhr = new XMLHttpRequest();
|
|
58
|
+
const { url, file, name = 'file', header, formData, timeout = 0 } = option;
|
|
59
|
+
|
|
60
|
+
const fail = (error: UploadFail) => reject(error);
|
|
61
|
+
|
|
62
|
+
const success = (responseText: string) => {
|
|
63
|
+
try {
|
|
64
|
+
resolve(JSON.parse(responseText) as T);
|
|
65
|
+
} catch (e) {
|
|
66
|
+
resolve(responseText as T);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// 构造任务对象
|
|
71
|
+
let onProgressUpdate: OnUploadProgressUpdate;
|
|
72
|
+
const task: UploadTask = {
|
|
73
|
+
onProgressUpdate: (callback) => {
|
|
74
|
+
onProgressUpdate = callback;
|
|
75
|
+
},
|
|
76
|
+
abort: () => xhr.abort(),
|
|
77
|
+
};
|
|
78
|
+
config?.onTaskReady?.(task);
|
|
79
|
+
|
|
80
|
+
// 监听进度
|
|
81
|
+
xhr.upload.onprogress = (e) => {
|
|
82
|
+
if (!e.lengthComputable) return;
|
|
83
|
+
const ev: UploadProgressEvent = {
|
|
84
|
+
progress: Math.round((e.loaded / e.total) * 100),
|
|
85
|
+
loaded: e.loaded,
|
|
86
|
+
total: e.total,
|
|
87
|
+
};
|
|
88
|
+
onProgressUpdate?.(ev);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// 监听事件
|
|
92
|
+
xhr.onload = () => {
|
|
93
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
94
|
+
success(xhr.responseText);
|
|
95
|
+
} else {
|
|
96
|
+
fail({ message: `上传失败`, status: xhr.status });
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
xhr.onerror = () => fail({ message: '网络错误', status: 0 });
|
|
100
|
+
xhr.ontimeout = () => fail({ message: '上传超时', status: -1 });
|
|
101
|
+
xhr.onabort = () => fail({ message: '用户取消', status: -2 });
|
|
102
|
+
|
|
103
|
+
// 设置请求方法和 URL
|
|
104
|
+
xhr.open('POST', url);
|
|
105
|
+
|
|
106
|
+
// 设置请求头
|
|
107
|
+
if (header) {
|
|
108
|
+
Object.entries(header).forEach(([k, v]) => {
|
|
109
|
+
if (v !== undefined && v !== null && v !== '') xhr.setRequestHeader(k, String(v));
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 设置超时时间
|
|
114
|
+
xhr.timeout = timeout;
|
|
115
|
+
|
|
116
|
+
// 组装 FormData
|
|
117
|
+
const data = new FormData();
|
|
118
|
+
data.append(name, file);
|
|
119
|
+
if (formData) {
|
|
120
|
+
Object.entries(formData).forEach(([k, v]) => {
|
|
121
|
+
if (v !== undefined) data.append(k, String(v));
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 发送请求
|
|
126
|
+
xhr.send(data);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 上传文件
|
|
132
|
+
* @param option 上传文件的选项
|
|
133
|
+
* @param config 配置项
|
|
134
|
+
* @example
|
|
135
|
+
* // 上传
|
|
136
|
+
* await uploadFile({ url: 'https://xx', file: file});
|
|
137
|
+
*
|
|
138
|
+
* // 监听上传进度
|
|
139
|
+
* await uploadFile({ url: 'https://xx', file: file}, {
|
|
140
|
+
* onTaskReady: (task) =>
|
|
141
|
+
* task.onProgressUpdate((res) => console.log('上传进度:', res.progress)),
|
|
142
|
+
* });
|
|
143
|
+
*/
|
|
144
|
+
export function uploadFile<T = any>(
|
|
145
|
+
option: UploadFileOption,
|
|
146
|
+
config?: UploadConfig & WebApiConfig<T, UploadFail>,
|
|
147
|
+
) {
|
|
148
|
+
return promisifyWebApi<UploadFileOption, T, UploadFail, UploadConfig>(upload, 'uploadFile')(
|
|
149
|
+
option,
|
|
150
|
+
config,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/web/network/load.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,SAAK,iBAyC/D;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,aAAa,CAAC,IAAI,CAAC;;;GAc5D;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,CAAC,EAAE,MAAM,UAkB1D;AAED;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAC1B,GAAG,EAAE,MAAM,EACX,KAAK,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,OAAO,GAAG,OAAO,GAAG,aAAa,CAAC,iBAuBnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,WAOhC;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,GAAG,OAAO,CAAC,iBAuBvD;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,WAOlC;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,6BAOvC"}
|
|
File without changes
|