@lambo-design/shared 1.0.0-beta.306 → 1.0.0-beta.307
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/package.json +1 -1
- package/utils/ajax/abort-controller.js +68 -0
- package/utils/ajax/cancel-token.js +69 -0
- package/utils/ajax/interceptors.js +10 -3
- package/utils/ajax/throttle.js +46 -0
- package/utils/storage.js +198 -198
- package/utils/type.js +102 -102
- package/utils/repeatSubmit.js +0 -35
package/package.json
CHANGED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// 用于存储每个请求的标识和取消函数
|
|
2
|
+
const pendingMap = new Map();
|
|
3
|
+
|
|
4
|
+
const getPendingUrl = (config) => {
|
|
5
|
+
const { url, method, data, headers } = config;
|
|
6
|
+
|
|
7
|
+
// 生成请求唯一标识
|
|
8
|
+
return headers['is-cancel-token']
|
|
9
|
+
? headers['is-cancel-token']
|
|
10
|
+
: [url, method].join('&');
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 添加请求
|
|
15
|
+
* @param config 请求配置
|
|
16
|
+
*/
|
|
17
|
+
function addPending(config) {
|
|
18
|
+
removePending(config);
|
|
19
|
+
const url = getPendingUrl(config);
|
|
20
|
+
const controller = new AbortController();
|
|
21
|
+
config.signal = config.signal || controller.signal;
|
|
22
|
+
if (!pendingMap.has(url)) {
|
|
23
|
+
// 如果当前请求不在等待中,将其添加到等待中
|
|
24
|
+
pendingMap.set(url, controller);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 移除请求
|
|
30
|
+
* @param config 请求配置
|
|
31
|
+
*/
|
|
32
|
+
function removePending(config) {
|
|
33
|
+
const url = getPendingUrl(config);
|
|
34
|
+
if (pendingMap.has(url)) {
|
|
35
|
+
// 如果当前请求在等待中,取消它并将其从等待中移除
|
|
36
|
+
const abortController = pendingMap.get(url);
|
|
37
|
+
if (abortController) {
|
|
38
|
+
abortController.abort(url);
|
|
39
|
+
}
|
|
40
|
+
pendingMap.delete(url);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 重置
|
|
46
|
+
*/
|
|
47
|
+
function reset() {
|
|
48
|
+
pendingMap.clear();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 清除所有等待中的请求
|
|
53
|
+
*/
|
|
54
|
+
function removeAllPending() {
|
|
55
|
+
pendingMap.forEach((abortController) => {
|
|
56
|
+
if (abortController) {
|
|
57
|
+
abortController.abort();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
reset();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
export default {
|
|
65
|
+
addPending,
|
|
66
|
+
removePending,
|
|
67
|
+
removeAllPending
|
|
68
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// axios 0.22.0 版本以后推荐使用abort-controller
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
|
|
4
|
+
// 存储所有请求的取消函数
|
|
5
|
+
const cancelTokenMap = {};
|
|
6
|
+
|
|
7
|
+
const getPendingUrl = (config) => {
|
|
8
|
+
const { url, method, data, headers } = config;
|
|
9
|
+
|
|
10
|
+
// 生成请求唯一标识
|
|
11
|
+
return headers['is-cancel-token']
|
|
12
|
+
? headers['is-cancel-token']
|
|
13
|
+
: [url, method, JSON.stringify(data), JSON.stringify(headers)].join('&');
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* 生成请求唯一标识并注册取消函数
|
|
17
|
+
* @param {Object} config - 请求配置
|
|
18
|
+
* @returns {Object} 增强后的请求配置
|
|
19
|
+
*/
|
|
20
|
+
function addPending(config) {
|
|
21
|
+
|
|
22
|
+
// 生成请求唯一标识
|
|
23
|
+
const requestId = getPendingUrl(config);
|
|
24
|
+
|
|
25
|
+
// 获取已存在的取消函数
|
|
26
|
+
const existingCancel = cancelTokenMap[requestId];
|
|
27
|
+
|
|
28
|
+
// 注册取消令牌
|
|
29
|
+
config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => {
|
|
30
|
+
if (!existingCancel) {
|
|
31
|
+
cancelTokenMap[requestId] = cancel;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return config;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 取消指定请求
|
|
40
|
+
* @param {Object} config - 要取消的请求配置
|
|
41
|
+
*/
|
|
42
|
+
function removePending(config) {
|
|
43
|
+
const { url, method, data, headers } = config;
|
|
44
|
+
|
|
45
|
+
const requestId = getPendingUrl(config);
|
|
46
|
+
|
|
47
|
+
const cancelFn = cancelTokenMap[requestId];
|
|
48
|
+
|
|
49
|
+
if (cancelFn && typeof cancelFn === 'function') {
|
|
50
|
+
cancelFn(); // 执行取消
|
|
51
|
+
delete cancelTokenMap[requestId]; // 清理
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 取消所有未完成的请求
|
|
57
|
+
*/
|
|
58
|
+
function removeAllPending() {
|
|
59
|
+
Object.keys(cancelTokenMap).forEach(key => {
|
|
60
|
+
const cancelFn = cancelTokenMap[key];
|
|
61
|
+
cancelFn();
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default {
|
|
66
|
+
addPending,
|
|
67
|
+
removePending,
|
|
68
|
+
removeAllPending
|
|
69
|
+
}
|
|
@@ -3,7 +3,8 @@ import cacheRules from "./cacheconf";
|
|
|
3
3
|
import {getLocalStorage, getToken, getUrlParams} from '../platform'
|
|
4
4
|
import Bus from '../bus';
|
|
5
5
|
import headers from './headers';
|
|
6
|
-
import {
|
|
6
|
+
import {throttle} from "./throttle";
|
|
7
|
+
import abortController from "./abort-controller"
|
|
7
8
|
let timer1, timer2;
|
|
8
9
|
let hasDialog = false;
|
|
9
10
|
|
|
@@ -61,9 +62,14 @@ function requestInterceptors(config) {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
// 添加防止重复提交
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
if(process.env.IF_OPEN_NO_REPEAT_SUBMIT && process.env.IF_OPEN_NO_REPEAT_SUBMIT === "true"){
|
|
66
|
+
// throttle(config);
|
|
67
|
+
const ignoreCancelToken = config.ignoreCancelToken ?? true;
|
|
68
|
+
if(!ignoreCancelToken){
|
|
69
|
+
abortController.addPending(config);
|
|
66
70
|
}
|
|
71
|
+
}
|
|
72
|
+
|
|
67
73
|
|
|
68
74
|
return config;
|
|
69
75
|
}
|
|
@@ -74,6 +80,7 @@ function requestError(error) {
|
|
|
74
80
|
}
|
|
75
81
|
|
|
76
82
|
function responseInterceptors(response) {
|
|
83
|
+
response && abortController.removePending(response.config)
|
|
77
84
|
const data = response.data;
|
|
78
85
|
if (data instanceof Object) {
|
|
79
86
|
const code = data["code"];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const requestObjMap = {};
|
|
2
|
+
|
|
3
|
+
const getPendingUrl = (config) => {
|
|
4
|
+
const { url, method, data, headers } = config;
|
|
5
|
+
// 生成请求唯一标识
|
|
6
|
+
return [url, method].join('&');
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* 防止重复提交
|
|
10
|
+
* 防抖(debounce)和节流(throttle)
|
|
11
|
+
*/
|
|
12
|
+
export function throttle(config) {
|
|
13
|
+
if (config) {
|
|
14
|
+
// 是否需要防止数据重复提交
|
|
15
|
+
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false ;
|
|
16
|
+
|
|
17
|
+
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
|
|
18
|
+
const requestObj = {
|
|
19
|
+
url: config.url,
|
|
20
|
+
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
|
|
21
|
+
time: new Date().getTime()
|
|
22
|
+
}
|
|
23
|
+
const requestId = getPendingUrl(config);
|
|
24
|
+
|
|
25
|
+
const lastRequestObj = requestObjMap[requestId];
|
|
26
|
+
|
|
27
|
+
if (lastRequestObj === undefined || lastRequestObj === null || lastRequestObj === '') {
|
|
28
|
+
requestObjMap[requestId] = requestObj;
|
|
29
|
+
} else {
|
|
30
|
+
const lastUrl = lastRequestObj.url;
|
|
31
|
+
const lastData = lastRequestObj.data;
|
|
32
|
+
const lastTime = lastRequestObj.time;
|
|
33
|
+
// 间隔时间(ms),小于此时间视为重复提交
|
|
34
|
+
const interval = 1000;
|
|
35
|
+
if (lastUrl === requestObj.url && lastData === requestObj.data
|
|
36
|
+
&& requestObj.time - lastTime < interval) {
|
|
37
|
+
const message = '数据正在处理,请勿重复提交';
|
|
38
|
+
console.warn(`[${his_url}]: ` + message);
|
|
39
|
+
return Promise.reject(new Error(message));
|
|
40
|
+
} else {
|
|
41
|
+
requestObjMap[requestId] = requestObj;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
package/utils/storage.js
CHANGED
|
@@ -1,198 +1,198 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2019 WeBank
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
/* \
|
|
19
|
-
|*|
|
|
20
|
-
|*| :: cookies.js ::
|
|
21
|
-
|*|
|
|
22
|
-
|*| A complete cookies reader/writer framework with full unicode support.
|
|
23
|
-
|*|
|
|
24
|
-
|*| https://developer.mozilla.org/en-US/docs/DOM/document.cookie
|
|
25
|
-
|*|
|
|
26
|
-
|*| This framework is released under the GNU Public License, version 3 or later.
|
|
27
|
-
|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html
|
|
28
|
-
|*|
|
|
29
|
-
|*| Syntaxes:
|
|
30
|
-
|*|
|
|
31
|
-
|*| * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])
|
|
32
|
-
|*| * docCookies.getItem(name)
|
|
33
|
-
|*| * docCookies.removeItem(name[, path], domain)
|
|
34
|
-
|*| * docCookies.hasItem(name)
|
|
35
|
-
|*| * docCookies.keys()
|
|
36
|
-
|*|
|
|
37
|
-
\ */
|
|
38
|
-
|
|
39
|
-
let docCookies = {
|
|
40
|
-
getItem: function(sKey) {
|
|
41
|
-
return decodeURIComponent(document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1')) || null;
|
|
42
|
-
},
|
|
43
|
-
setItem: function(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
|
|
44
|
-
if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) {
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
let sExpires = '';
|
|
48
|
-
if (vEnd) {
|
|
49
|
-
switch (vEnd.constructor) {
|
|
50
|
-
case Number:
|
|
51
|
-
sExpires = vEnd === Infinity ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' : '; max-age=' + vEnd;
|
|
52
|
-
break;
|
|
53
|
-
case String:
|
|
54
|
-
sExpires = '; expires=' + vEnd;
|
|
55
|
-
break;
|
|
56
|
-
case Date:
|
|
57
|
-
sExpires = '; expires=' + vEnd.toUTCString();
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
document.cookie = encodeURIComponent(sKey) + '=' + encodeURIComponent(sValue) + sExpires + (sDomain ? '; domain=' + sDomain : '') + (sPath ? '; path=' + sPath : '') + (bSecure ? '; secure' : '');
|
|
62
|
-
return true;
|
|
63
|
-
},
|
|
64
|
-
removeItem: function(sKey, sPath, sDomain) {
|
|
65
|
-
if (!sKey || !this.hasItem(sKey)) {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
document.cookie = encodeURIComponent(sKey) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' + (sDomain ? '; domain=' + sDomain : '') + (sPath ? '; path=' + sPath : '');
|
|
69
|
-
return true;
|
|
70
|
-
},
|
|
71
|
-
hasItem: function(sKey) {
|
|
72
|
-
return (new RegExp('(?:^|;\\s*)' + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=')).test(document.cookie);
|
|
73
|
-
},
|
|
74
|
-
keys: /* optional method: you can safely remove it! */ function() {
|
|
75
|
-
let aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, '').split(/\s*(?:\=[^;]*)?;\s*/);
|
|
76
|
-
for (let nIdx = 0; nIdx < aKeys.length; nIdx++) {
|
|
77
|
-
aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
|
|
78
|
-
}
|
|
79
|
-
return aKeys;
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* 操作cookie、sessionStorage、localStorage、缓存
|
|
85
|
-
*/
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
SESSION = 'session';
|
|
89
|
-
|
|
90
|
-
const LOCAL = 'local';
|
|
91
|
-
|
|
92
|
-
const COOKIE = 'cookie';
|
|
93
|
-
|
|
94
|
-
export default {
|
|
95
|
-
set: function(key, value, category = SESSION, expired) {
|
|
96
|
-
let { storage, isWebStorage = true } = this._map(category);
|
|
97
|
-
|
|
98
|
-
if (isWebStorage) {
|
|
99
|
-
storageManager.set(key, value, storage);
|
|
100
|
-
} else {
|
|
101
|
-
cookieManager.set(key, value, expired);
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
get: function(key, category = SESSION) {
|
|
105
|
-
let { storage, isWebStorage = true } = this._map(category);
|
|
106
|
-
|
|
107
|
-
if (isWebStorage) {
|
|
108
|
-
return storageManager.get(key, storage);
|
|
109
|
-
} else {
|
|
110
|
-
return cookieManager.get(key);
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
clear: function(category = SESSION) {
|
|
114
|
-
let { storage, isWebStorage = true } = this._map(category);
|
|
115
|
-
|
|
116
|
-
if (isWebStorage) {
|
|
117
|
-
storageManager.clear(storage);
|
|
118
|
-
} else {
|
|
119
|
-
cookieManager.clear();
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
remove: function(key, category = SESSION) {
|
|
123
|
-
let { storage, isWebStorage = true } = this._map(category);
|
|
124
|
-
|
|
125
|
-
if (isWebStorage) {
|
|
126
|
-
storageManager.remove(key, storage);
|
|
127
|
-
} else {
|
|
128
|
-
cookieManager.remove(key);
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
_map: function(category) {
|
|
132
|
-
let isWebStorage = true; let storage;
|
|
133
|
-
|
|
134
|
-
switch (true) {
|
|
135
|
-
case category === SESSION:
|
|
136
|
-
storage = 'sessionStorage';
|
|
137
|
-
break;
|
|
138
|
-
case category === LOCAL:
|
|
139
|
-
storage = 'localStorage';
|
|
140
|
-
break;
|
|
141
|
-
case category === COOKIE:
|
|
142
|
-
storage = 'cookie';
|
|
143
|
-
isWebStorage = false;
|
|
144
|
-
break;
|
|
145
|
-
default:
|
|
146
|
-
storage = 'sessionStorage';
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return { isWebStorage, storage };
|
|
150
|
-
},
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
let isProd = process.env.NODE_ENV === 'production';
|
|
154
|
-
|
|
155
|
-
export const storageManager = {
|
|
156
|
-
set: function(key, value, storage) {
|
|
157
|
-
try {
|
|
158
|
-
window[storage].setItem(key, JSON.stringify(value));
|
|
159
|
-
} catch (e) {
|
|
160
|
-
!isProd && console.error(e);
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
get: function(key, storage) {
|
|
164
|
-
try {
|
|
165
|
-
if (window[storage].getItem(key)) {
|
|
166
|
-
return JSON.parse(window[storage].getItem(key));
|
|
167
|
-
} else {
|
|
168
|
-
return window[storage].getItem(key);
|
|
169
|
-
}
|
|
170
|
-
} catch (e) {
|
|
171
|
-
!isProd && console.error(e, key);
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
clear: function(storage) {
|
|
175
|
-
window[storage].clear();
|
|
176
|
-
},
|
|
177
|
-
remove: function(key, storage) {
|
|
178
|
-
window[storage].removeItem(key);
|
|
179
|
-
},
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
export const cookieManager = {
|
|
183
|
-
set: function(key, value, expired) {
|
|
184
|
-
if (expired) docCookies.setItem(key, value, expired);
|
|
185
|
-
else docCookies.setItem(key, value);
|
|
186
|
-
},
|
|
187
|
-
get: function(key) {
|
|
188
|
-
return docCookies.getItem(key);
|
|
189
|
-
},
|
|
190
|
-
clear: function() {
|
|
191
|
-
docCookies.keys().forEach((key) => {
|
|
192
|
-
docCookies.removeItem(key);
|
|
193
|
-
});
|
|
194
|
-
},
|
|
195
|
-
remove: function(key) {
|
|
196
|
-
docCookies.removeItem(key);
|
|
197
|
-
},
|
|
198
|
-
};
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2019 WeBank
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/* \
|
|
19
|
+
|*|
|
|
20
|
+
|*| :: cookies.js ::
|
|
21
|
+
|*|
|
|
22
|
+
|*| A complete cookies reader/writer framework with full unicode support.
|
|
23
|
+
|*|
|
|
24
|
+
|*| https://developer.mozilla.org/en-US/docs/DOM/document.cookie
|
|
25
|
+
|*|
|
|
26
|
+
|*| This framework is released under the GNU Public License, version 3 or later.
|
|
27
|
+
|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html
|
|
28
|
+
|*|
|
|
29
|
+
|*| Syntaxes:
|
|
30
|
+
|*|
|
|
31
|
+
|*| * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])
|
|
32
|
+
|*| * docCookies.getItem(name)
|
|
33
|
+
|*| * docCookies.removeItem(name[, path], domain)
|
|
34
|
+
|*| * docCookies.hasItem(name)
|
|
35
|
+
|*| * docCookies.keys()
|
|
36
|
+
|*|
|
|
37
|
+
\ */
|
|
38
|
+
|
|
39
|
+
let docCookies = {
|
|
40
|
+
getItem: function(sKey) {
|
|
41
|
+
return decodeURIComponent(document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1')) || null;
|
|
42
|
+
},
|
|
43
|
+
setItem: function(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
|
|
44
|
+
if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
let sExpires = '';
|
|
48
|
+
if (vEnd) {
|
|
49
|
+
switch (vEnd.constructor) {
|
|
50
|
+
case Number:
|
|
51
|
+
sExpires = vEnd === Infinity ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' : '; max-age=' + vEnd;
|
|
52
|
+
break;
|
|
53
|
+
case String:
|
|
54
|
+
sExpires = '; expires=' + vEnd;
|
|
55
|
+
break;
|
|
56
|
+
case Date:
|
|
57
|
+
sExpires = '; expires=' + vEnd.toUTCString();
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
document.cookie = encodeURIComponent(sKey) + '=' + encodeURIComponent(sValue) + sExpires + (sDomain ? '; domain=' + sDomain : '') + (sPath ? '; path=' + sPath : '') + (bSecure ? '; secure' : '');
|
|
62
|
+
return true;
|
|
63
|
+
},
|
|
64
|
+
removeItem: function(sKey, sPath, sDomain) {
|
|
65
|
+
if (!sKey || !this.hasItem(sKey)) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
document.cookie = encodeURIComponent(sKey) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' + (sDomain ? '; domain=' + sDomain : '') + (sPath ? '; path=' + sPath : '');
|
|
69
|
+
return true;
|
|
70
|
+
},
|
|
71
|
+
hasItem: function(sKey) {
|
|
72
|
+
return (new RegExp('(?:^|;\\s*)' + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=')).test(document.cookie);
|
|
73
|
+
},
|
|
74
|
+
keys: /* optional method: you can safely remove it! */ function() {
|
|
75
|
+
let aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, '').split(/\s*(?:\=[^;]*)?;\s*/);
|
|
76
|
+
for (let nIdx = 0; nIdx < aKeys.length; nIdx++) {
|
|
77
|
+
aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
|
|
78
|
+
}
|
|
79
|
+
return aKeys;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 操作cookie、sessionStorage、localStorage、缓存
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
const
|
|
88
|
+
SESSION = 'session';
|
|
89
|
+
|
|
90
|
+
const LOCAL = 'local';
|
|
91
|
+
|
|
92
|
+
const COOKIE = 'cookie';
|
|
93
|
+
|
|
94
|
+
export default {
|
|
95
|
+
set: function(key, value, category = SESSION, expired) {
|
|
96
|
+
let { storage, isWebStorage = true } = this._map(category);
|
|
97
|
+
|
|
98
|
+
if (isWebStorage) {
|
|
99
|
+
storageManager.set(key, value, storage);
|
|
100
|
+
} else {
|
|
101
|
+
cookieManager.set(key, value, expired);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
get: function(key, category = SESSION) {
|
|
105
|
+
let { storage, isWebStorage = true } = this._map(category);
|
|
106
|
+
|
|
107
|
+
if (isWebStorage) {
|
|
108
|
+
return storageManager.get(key, storage);
|
|
109
|
+
} else {
|
|
110
|
+
return cookieManager.get(key);
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
clear: function(category = SESSION) {
|
|
114
|
+
let { storage, isWebStorage = true } = this._map(category);
|
|
115
|
+
|
|
116
|
+
if (isWebStorage) {
|
|
117
|
+
storageManager.clear(storage);
|
|
118
|
+
} else {
|
|
119
|
+
cookieManager.clear();
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
remove: function(key, category = SESSION) {
|
|
123
|
+
let { storage, isWebStorage = true } = this._map(category);
|
|
124
|
+
|
|
125
|
+
if (isWebStorage) {
|
|
126
|
+
storageManager.remove(key, storage);
|
|
127
|
+
} else {
|
|
128
|
+
cookieManager.remove(key);
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
_map: function(category) {
|
|
132
|
+
let isWebStorage = true; let storage;
|
|
133
|
+
|
|
134
|
+
switch (true) {
|
|
135
|
+
case category === SESSION:
|
|
136
|
+
storage = 'sessionStorage';
|
|
137
|
+
break;
|
|
138
|
+
case category === LOCAL:
|
|
139
|
+
storage = 'localStorage';
|
|
140
|
+
break;
|
|
141
|
+
case category === COOKIE:
|
|
142
|
+
storage = 'cookie';
|
|
143
|
+
isWebStorage = false;
|
|
144
|
+
break;
|
|
145
|
+
default:
|
|
146
|
+
storage = 'sessionStorage';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return { isWebStorage, storage };
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
let isProd = process.env.NODE_ENV === 'production';
|
|
154
|
+
|
|
155
|
+
export const storageManager = {
|
|
156
|
+
set: function(key, value, storage) {
|
|
157
|
+
try {
|
|
158
|
+
window[storage].setItem(key, JSON.stringify(value));
|
|
159
|
+
} catch (e) {
|
|
160
|
+
!isProd && console.error(e);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
get: function(key, storage) {
|
|
164
|
+
try {
|
|
165
|
+
if (window[storage].getItem(key)) {
|
|
166
|
+
return JSON.parse(window[storage].getItem(key));
|
|
167
|
+
} else {
|
|
168
|
+
return window[storage].getItem(key);
|
|
169
|
+
}
|
|
170
|
+
} catch (e) {
|
|
171
|
+
!isProd && console.error(e, key);
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
clear: function(storage) {
|
|
175
|
+
window[storage].clear();
|
|
176
|
+
},
|
|
177
|
+
remove: function(key, storage) {
|
|
178
|
+
window[storage].removeItem(key);
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export const cookieManager = {
|
|
183
|
+
set: function(key, value, expired) {
|
|
184
|
+
if (expired) docCookies.setItem(key, value, expired);
|
|
185
|
+
else docCookies.setItem(key, value);
|
|
186
|
+
},
|
|
187
|
+
get: function(key) {
|
|
188
|
+
return docCookies.getItem(key);
|
|
189
|
+
},
|
|
190
|
+
clear: function() {
|
|
191
|
+
docCookies.keys().forEach((key) => {
|
|
192
|
+
docCookies.removeItem(key);
|
|
193
|
+
});
|
|
194
|
+
},
|
|
195
|
+
remove: function(key) {
|
|
196
|
+
docCookies.removeItem(key);
|
|
197
|
+
},
|
|
198
|
+
};
|
package/utils/type.js
CHANGED
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2019 WeBank
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const objectToString = Object.prototype.toString;
|
|
19
|
-
const OBJECT_STRING = '[object Object]';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 是否是普通对象
|
|
23
|
-
* @param {any} obj
|
|
24
|
-
* @return {Boolean}
|
|
25
|
-
*/
|
|
26
|
-
export function isPlainObject(obj) {
|
|
27
|
-
return objectToString.call(obj) === OBJECT_STRING;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* 是否是数字
|
|
32
|
-
* @param {any} value
|
|
33
|
-
* @return {Boolean}
|
|
34
|
-
*/
|
|
35
|
-
export function isNumber(value) {
|
|
36
|
-
return typeof value === 'number';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* 是否是日期
|
|
41
|
-
* @param {any} value
|
|
42
|
-
* @return {Boolean}
|
|
43
|
-
*/
|
|
44
|
-
export function isDate(value) {
|
|
45
|
-
return objectToString.call(value) === '[object Date]';
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* 是否是函数
|
|
50
|
-
* @param {any} value
|
|
51
|
-
* @return {Boolean}
|
|
52
|
-
*/
|
|
53
|
-
export function isFunction(value) {
|
|
54
|
-
return typeof value === 'function';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* 是否是函数
|
|
59
|
-
* @param {any} value
|
|
60
|
-
* @return {Boolean}
|
|
61
|
-
*/
|
|
62
|
-
export function isObject(value) {
|
|
63
|
-
let type = typeof value;
|
|
64
|
-
return !!value && (type == 'object' || type == 'function');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 是否是数组
|
|
69
|
-
* @param {any} value
|
|
70
|
-
* @return {Boolean}
|
|
71
|
-
*/
|
|
72
|
-
export function isArray(value) {
|
|
73
|
-
return Array.isArray(value);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* 是否像对象
|
|
78
|
-
* @param {any} value
|
|
79
|
-
* @return {Boolean}
|
|
80
|
-
*/
|
|
81
|
-
export function isObjectLike(value) {
|
|
82
|
-
return !!value && typeof value == 'object';
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* 是否是字符串
|
|
87
|
-
* @param {any} value
|
|
88
|
-
* @return {Boolean}
|
|
89
|
-
*/
|
|
90
|
-
export function isString(value) {
|
|
91
|
-
return typeof value == 'string' ||
|
|
92
|
-
(!isArray(value) && isObjectLike(value) && objectToString.call(value) == '[object String]');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* 是否是空的
|
|
97
|
-
* @param {any} value
|
|
98
|
-
* @return {Boolean}
|
|
99
|
-
*/
|
|
100
|
-
export function isNull(value) {
|
|
101
|
-
return value === undefined || value === null || value === '';
|
|
102
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2019 WeBank
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const objectToString = Object.prototype.toString;
|
|
19
|
+
const OBJECT_STRING = '[object Object]';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 是否是普通对象
|
|
23
|
+
* @param {any} obj
|
|
24
|
+
* @return {Boolean}
|
|
25
|
+
*/
|
|
26
|
+
export function isPlainObject(obj) {
|
|
27
|
+
return objectToString.call(obj) === OBJECT_STRING;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 是否是数字
|
|
32
|
+
* @param {any} value
|
|
33
|
+
* @return {Boolean}
|
|
34
|
+
*/
|
|
35
|
+
export function isNumber(value) {
|
|
36
|
+
return typeof value === 'number';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 是否是日期
|
|
41
|
+
* @param {any} value
|
|
42
|
+
* @return {Boolean}
|
|
43
|
+
*/
|
|
44
|
+
export function isDate(value) {
|
|
45
|
+
return objectToString.call(value) === '[object Date]';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 是否是函数
|
|
50
|
+
* @param {any} value
|
|
51
|
+
* @return {Boolean}
|
|
52
|
+
*/
|
|
53
|
+
export function isFunction(value) {
|
|
54
|
+
return typeof value === 'function';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 是否是函数
|
|
59
|
+
* @param {any} value
|
|
60
|
+
* @return {Boolean}
|
|
61
|
+
*/
|
|
62
|
+
export function isObject(value) {
|
|
63
|
+
let type = typeof value;
|
|
64
|
+
return !!value && (type == 'object' || type == 'function');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 是否是数组
|
|
69
|
+
* @param {any} value
|
|
70
|
+
* @return {Boolean}
|
|
71
|
+
*/
|
|
72
|
+
export function isArray(value) {
|
|
73
|
+
return Array.isArray(value);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 是否像对象
|
|
78
|
+
* @param {any} value
|
|
79
|
+
* @return {Boolean}
|
|
80
|
+
*/
|
|
81
|
+
export function isObjectLike(value) {
|
|
82
|
+
return !!value && typeof value == 'object';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 是否是字符串
|
|
87
|
+
* @param {any} value
|
|
88
|
+
* @return {Boolean}
|
|
89
|
+
*/
|
|
90
|
+
export function isString(value) {
|
|
91
|
+
return typeof value == 'string' ||
|
|
92
|
+
(!isArray(value) && isObjectLike(value) && objectToString.call(value) == '[object String]');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 是否是空的
|
|
97
|
+
* @param {any} value
|
|
98
|
+
* @return {Boolean}
|
|
99
|
+
*/
|
|
100
|
+
export function isNull(value) {
|
|
101
|
+
return value === undefined || value === null || value === '';
|
|
102
|
+
}
|
package/utils/repeatSubmit.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import {setSessionStorage, getSessionStorage} from './platform';
|
|
2
|
-
/**
|
|
3
|
-
* 防止重复提交
|
|
4
|
-
*/
|
|
5
|
-
export function noRepeatSubmit(config) {
|
|
6
|
-
if (config) {
|
|
7
|
-
// 是否需要防止数据重复提交
|
|
8
|
-
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false ;
|
|
9
|
-
|
|
10
|
-
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
|
|
11
|
-
const requestObj = {
|
|
12
|
-
url: config.url,
|
|
13
|
-
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
|
|
14
|
-
time: new Date().getTime()
|
|
15
|
-
}
|
|
16
|
-
const nlamboSessionObj =getSessionStorage('nlamboSessionObj') ;
|
|
17
|
-
if (nlamboSessionObj === undefined || nlamboSessionObj === null || nlamboSessionObj === '') {
|
|
18
|
-
setSessionStorage('nlamboSessionObj', requestObj) ;
|
|
19
|
-
} else {
|
|
20
|
-
const his_url = nlamboSessionObj.url; // 请求地址
|
|
21
|
-
const his_data = nlamboSessionObj.data; // 请求数据
|
|
22
|
-
const his_time = nlamboSessionObj.time; // 请求时间
|
|
23
|
-
const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
|
|
24
|
-
if (his_data === requestObj.data && requestObj.time - his_time < interval && his_url === requestObj.url) {
|
|
25
|
-
const message = '数据正在处理,请勿重复提交';
|
|
26
|
-
console.warn(`[${his_url}]: ` + message) ;
|
|
27
|
-
return Promise.reject(new Error(message)) ;
|
|
28
|
-
} else {
|
|
29
|
-
setSessionStorage('nlamboSessionObj', requestObj) ;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
}
|