web-component-gallery 2.3.7 → 2.3.8
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/index.umd.js +1 -1
- package/dist/js.umd.js +1 -1
- package/lib/browse/index.jsx +75 -132
- package/lib/browse/style/index.less +9 -0
- package/lib/form-comp/ASelectCustom.vue +2 -0
- package/lib/form-comp/AUpload.vue +146 -85
- package/lib/form-comp/style/AUpload.less +14 -11
- package/package.json +1 -1
- package/utils/Axios.js +1 -1
- package/utils/File.js +146 -0
- package/utils/Filter.js +590 -133
- package/utils/Tree.js +13 -12
package/utils/Filter.js
CHANGED
|
@@ -1,65 +1,121 @@
|
|
|
1
|
-
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
4
|
-
* @param {
|
|
5
|
-
*
|
|
2
|
+
* 获取 n 天前的时间
|
|
3
|
+
* @param {number} n - 数量
|
|
4
|
+
* @param {string|Date} baseTime - 基准时间(可选)
|
|
5
|
+
* @param {string} cFormat - 格式化模板
|
|
6
|
+
* @returns {string} 格式化日期
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
-
export function getDay(day) {
|
|
9
|
-
return getNDaysBefore(day, null, "{y}-{m}-{d}")
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// 获取n天前的时间
|
|
13
8
|
export function getNDaysBefore(n, baseTime = null, cFormat) {
|
|
14
9
|
const base = baseTime ? new Date(baseTime) : new Date()
|
|
15
10
|
const targetTime = new Date(base.getTime() - n * 24 * 60 * 60 * 1000)
|
|
16
11
|
return formatDate(targetTime, cFormat)
|
|
17
12
|
}
|
|
18
13
|
|
|
19
|
-
|
|
14
|
+
/**
|
|
15
|
+
* 获取 n 小时前的时间
|
|
16
|
+
* @param {number} n - 小时数
|
|
17
|
+
* @param {string|Date} baseTime - 基准时间(可选)
|
|
18
|
+
* @param {string} cFormat - 格式化模板
|
|
19
|
+
* @returns {string} 格式化日期
|
|
20
|
+
*/
|
|
20
21
|
export function getNHoursBefore(n, baseTime = null, cFormat) {
|
|
21
22
|
const base = baseTime ? new Date(baseTime) : new Date()
|
|
22
23
|
const targetTime = new Date(base.getTime() - n * 60 * 60 * 1000)
|
|
23
24
|
return formatDate(targetTime, cFormat)
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
/**
|
|
28
|
+
* 获取 n 分钟前的时间
|
|
29
|
+
* @param {number} n - 分钟数
|
|
30
|
+
* @param {string|Date} baseTime - 基准时间(可选)
|
|
31
|
+
* @param {string} cFormat - 格式化模板
|
|
32
|
+
* @returns {string} 格式化日期
|
|
33
|
+
*/
|
|
27
34
|
export function getNMinutesBefore(n, baseTime = null, cFormat) {
|
|
28
35
|
const base = baseTime ? new Date(baseTime) : new Date()
|
|
29
36
|
const targetTime = new Date(base.getTime() - n * 60 * 1000)
|
|
30
37
|
return formatDate(targetTime, cFormat)
|
|
31
38
|
}
|
|
32
39
|
|
|
40
|
+
/**
|
|
41
|
+
* 获取 n 秒前的时间
|
|
42
|
+
* @param {number} n - 秒数
|
|
43
|
+
* @param {string|Date} baseTime - 基准时间(可选)
|
|
44
|
+
* @param {string} cFormat - 格式化模板
|
|
45
|
+
* @returns {string} 格式化日期
|
|
46
|
+
*/
|
|
47
|
+
export function getNSecondsBefore(n, baseTime = null, cFormat) {
|
|
48
|
+
const base = baseTime ? new Date(baseTime) : new Date()
|
|
49
|
+
const targetTime = new Date(base.getTime() - n * 1000)
|
|
50
|
+
return formatDate(targetTime, cFormat)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 获取 n 天后的日期
|
|
55
|
+
* @param {number} n - 天数
|
|
56
|
+
* @param {string|Date} baseTime - 基准时间(可选)
|
|
57
|
+
* @param {string} cFormat - 格式化模板
|
|
58
|
+
* @returns {string} 格式化日期
|
|
59
|
+
*/
|
|
60
|
+
export function getNDaysAfter(n, baseTime = null, cFormat) {
|
|
61
|
+
const base = baseTime ? new Date(baseTime) : new Date()
|
|
62
|
+
const targetTime = new Date(base.getTime() + n * 24 * 60 * 60 * 1000)
|
|
63
|
+
return formatDate(targetTime, cFormat)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 获取 n 小时后的时间
|
|
68
|
+
* @param {number} n - 小时数
|
|
69
|
+
* @param {string|Date} baseTime - 基准时间(可选)
|
|
70
|
+
* @param {string} cFormat - 格式化模板
|
|
71
|
+
* @returns {string} 格式化日期
|
|
72
|
+
*/
|
|
73
|
+
export function getNHoursAfter(n, baseTime = null, cFormat) {
|
|
74
|
+
const base = baseTime ? new Date(baseTime) : new Date()
|
|
75
|
+
const targetTime = new Date(base.getTime() + n * 60 * 60 * 1000)
|
|
76
|
+
return formatDate(targetTime, cFormat)
|
|
77
|
+
}
|
|
33
78
|
|
|
34
79
|
/**
|
|
35
|
-
*
|
|
36
|
-
* @param {
|
|
37
|
-
* @param {
|
|
38
|
-
* {y}年 {m}月 {d}日 {h}时 {i}分 {s}秒 {a}星期
|
|
80
|
+
* 格式化日期
|
|
81
|
+
* @param {string|number|Date} time - 时间
|
|
82
|
+
* @param {string} cFormat - 格式化模板
|
|
83
|
+
* {y}年 {m}月 {d}日 {h}时 {i}分 {s}秒 {a}星期 {q}季度
|
|
84
|
+
* @returns {string|null} 格式化后的日期字符串
|
|
39
85
|
*/
|
|
40
86
|
export function formatDate(time, cFormat) {
|
|
41
|
-
if (arguments.length === 0 || !time)
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
87
|
+
if (arguments.length === 0 || !time) return null
|
|
88
|
+
|
|
89
|
+
const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}"
|
|
90
|
+
let date
|
|
91
|
+
|
|
92
|
+
// 处理不同类型的输入
|
|
46
93
|
if (typeof time === "object") {
|
|
47
|
-
date = time
|
|
94
|
+
date = time
|
|
48
95
|
} else {
|
|
49
|
-
let
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
96
|
+
let timestamp = time
|
|
97
|
+
|
|
98
|
+
// 字符串处理
|
|
99
|
+
if (typeof timestamp === "string") {
|
|
100
|
+
timestamp = /^[0-9]+$/.test(timestamp)
|
|
101
|
+
? parseInt(timestamp)
|
|
102
|
+
: timestamp.replace(/-/g, "/")
|
|
57
103
|
}
|
|
58
|
-
|
|
59
|
-
|
|
104
|
+
|
|
105
|
+
// 10 位时间戳转毫秒
|
|
106
|
+
if (typeof timestamp === "number" && timestamp.toString().length === 10) {
|
|
107
|
+
timestamp *= 1000
|
|
60
108
|
}
|
|
61
|
-
|
|
109
|
+
|
|
110
|
+
date = new Date(timestamp)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 验证日期有效性
|
|
114
|
+
if (isNaN(date.getTime())) {
|
|
115
|
+
console.warn('无效的日期格式')
|
|
116
|
+
return null
|
|
62
117
|
}
|
|
118
|
+
|
|
63
119
|
const formatObj = {
|
|
64
120
|
y: date.getFullYear(),
|
|
65
121
|
m: date.getMonth() + 1,
|
|
@@ -68,172 +124,573 @@ export function formatDate(time, cFormat) {
|
|
|
68
124
|
i: date.getMinutes(),
|
|
69
125
|
s: date.getSeconds(),
|
|
70
126
|
a: date.getDay(),
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
127
|
+
q: Math.floor((date.getMonth() + 3) / 3), // 季度
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const timeStr = format.replace(/{([ymdhisaq])+}/g, (result, key) => {
|
|
131
|
+
const value = formatObj[key]
|
|
132
|
+
|
|
133
|
+
// 星期处理
|
|
75
134
|
if (key === "a") {
|
|
76
|
-
return ["日", "一", "二", "三", "四", "五", "六"][value]
|
|
135
|
+
return ["日", "一", "二", "三", "四", "五", "六"][value]
|
|
77
136
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
})
|
|
82
|
-
|
|
137
|
+
|
|
138
|
+
// 补零处理
|
|
139
|
+
return String(value).padStart(2, "0")
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
return timeStr
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 时间戳转格式化日期
|
|
147
|
+
* @param {number} timestamp - 时间戳(秒或毫秒)
|
|
148
|
+
* @param {string} format - 格式化模板
|
|
149
|
+
* @returns {string|null} 格式化日期
|
|
150
|
+
*/
|
|
151
|
+
export function formatTimestamp(timestamp, format) {
|
|
152
|
+
if (!timestamp) return null
|
|
153
|
+
|
|
154
|
+
// 10 位时间戳转毫秒
|
|
155
|
+
if (String(timestamp).length === 10) {
|
|
156
|
+
timestamp *= 1000
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return formatDate(new Date(timestamp), format)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 计算两个日期之间的差异
|
|
164
|
+
* @param {string|Date} date1 - 日期 1
|
|
165
|
+
* @param {string|Date} date2 - 日期 2
|
|
166
|
+
* @returns {Object} 差异对象 {days, hours, minutes, seconds, milliseconds}
|
|
167
|
+
*/
|
|
168
|
+
export function dateDiff(date1, date2) {
|
|
169
|
+
const d1 = new Date(date1)
|
|
170
|
+
const d2 = new Date(date2)
|
|
171
|
+
const diff = Math.abs(d2 - d1)
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
milliseconds: diff,
|
|
175
|
+
seconds: Math.floor(diff / 1000),
|
|
176
|
+
minutes: Math.floor(diff / (1000 * 60)),
|
|
177
|
+
hours: Math.floor(diff / (1000 * 60 * 60)),
|
|
178
|
+
days: Math.floor(diff / (1000 * 60 * 60 * 24)),
|
|
179
|
+
weeks: Math.floor(diff / (1000 * 60 * 60 * 24 * 7)),
|
|
180
|
+
months: Math.floor(diff / (1000 * 60 * 60 * 24 * 30)),
|
|
181
|
+
years: Math.floor(diff / (1000 * 60 * 60 * 24 * 365))
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* 判断是否为闰年
|
|
187
|
+
* @param {number} year - 年份
|
|
188
|
+
* @returns {boolean} 是否为闰年
|
|
189
|
+
*/
|
|
190
|
+
export function isLeapYear(year) {
|
|
191
|
+
return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 获取某月的天数
|
|
196
|
+
* @param {number} year - 年份
|
|
197
|
+
* @param {number} month - 月份(1-12)
|
|
198
|
+
* @returns {number} 天数
|
|
199
|
+
*/
|
|
200
|
+
export function getDaysInMonth(year, month) {
|
|
201
|
+
return new Date(year, month, 0).getDate()
|
|
83
202
|
}
|
|
84
203
|
|
|
85
204
|
/**
|
|
86
|
-
*
|
|
87
|
-
* sHex
|
|
88
|
-
* alpha
|
|
205
|
+
* 颜色十六进制转 RGB/RGBA
|
|
206
|
+
* @param {string} sHex - 十六进制色值
|
|
207
|
+
* @param {number} alpha - 透明度
|
|
208
|
+
* @returns {string} rgba(r,g,b,a) 格式字符串
|
|
89
209
|
*/
|
|
90
210
|
export function colorRgba(sHex, alpha) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
let sColor = sHex.toLowerCase();
|
|
211
|
+
const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
|
|
212
|
+
let sColor = sHex.toLowerCase()
|
|
213
|
+
|
|
95
214
|
if (sColor && reg.test(sColor)) {
|
|
215
|
+
// 简写形式转为完整形式 #fff -> #ffffff
|
|
96
216
|
if (sColor.length === 4) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
.concat(sColor.slice(i, i + 1));
|
|
101
|
-
}
|
|
102
|
-
sColor = sColorNew;
|
|
217
|
+
sColor = "#" + [1, 2, 3].map(i =>
|
|
218
|
+
sColor.slice(i, i + 1).repeat(2)
|
|
219
|
+
).join("")
|
|
103
220
|
}
|
|
104
|
-
|
|
105
|
-
|
|
221
|
+
|
|
222
|
+
// 提取 RGB 值
|
|
223
|
+
const rgbValues = []
|
|
106
224
|
for (let i = 1; i < 7; i += 2) {
|
|
107
|
-
|
|
225
|
+
rgbValues.push(parseInt(`0x${sColor.slice(i, i + 2)}`))
|
|
108
226
|
}
|
|
109
|
-
|
|
110
|
-
return
|
|
227
|
+
|
|
228
|
+
return alpha !== undefined
|
|
229
|
+
? `rgba(${rgbValues.join(",")},${alpha})`
|
|
230
|
+
: `rgb(${rgbValues.join(",")})`
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return sColor
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* RGB 转十六进制颜色
|
|
238
|
+
* @param {number} r - 红色值 (0-255)
|
|
239
|
+
* @param {number} g - 绿色值 (0-255)
|
|
240
|
+
* @param {number} b - 蓝色值 (0-255)
|
|
241
|
+
* @returns {string} 十六进制色值
|
|
242
|
+
*/
|
|
243
|
+
export function rgbToHex(r, g, b) {
|
|
244
|
+
const toHex = (c) => {
|
|
245
|
+
const hex = Math.max(0, Math.min(255, c)).toString(16)
|
|
246
|
+
return hex.length === 1 ? "0" + hex : hex
|
|
111
247
|
}
|
|
112
|
-
return
|
|
248
|
+
return "#" + toHex(r) + toHex(g) + toHex(b)
|
|
113
249
|
}
|
|
114
250
|
|
|
115
251
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*/
|
|
120
|
-
export function
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
for (let i = 0; i < tatal; i++) {
|
|
124
|
-
//parseInt接收string,所以需要转一趟
|
|
125
|
-
/**
|
|
126
|
-
* 换成生活中的场景,就是一百个苹果分给十个人,我们可以一个一个的取出,随机分给某个人,直到分完
|
|
127
|
-
* 在js里面,十个人即是一个长度为十的数组,每次数组随机一个位置加一,执行一百次
|
|
128
|
-
*/
|
|
129
|
-
var num = parseInt((Math.random() * segment).toString());
|
|
130
|
-
arrpercent[num]++;
|
|
252
|
+
* 生成随机颜色
|
|
253
|
+
* @param {boolean} full - 是否使用全色系(默认 false,使用柔和色系)
|
|
254
|
+
* @returns {string} 十六进制色值
|
|
255
|
+
*/
|
|
256
|
+
export function randomColor(full = false) {
|
|
257
|
+
if (full) {
|
|
258
|
+
return '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')
|
|
131
259
|
}
|
|
132
|
-
//console.log(arr.length)
|
|
133
260
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
261
|
+
// 生成柔和的彩色
|
|
262
|
+
const hue = Math.floor(Math.random() * 360)
|
|
263
|
+
const saturation = 70 + Math.floor(Math.random() * 20)
|
|
264
|
+
const lightness = 60 + Math.floor(Math.random() * 20)
|
|
265
|
+
|
|
266
|
+
return hslToHex(hue, saturation, lightness)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* HSL 转十六进制颜色
|
|
271
|
+
* @param {number} h - 色相 (0-360)
|
|
272
|
+
* @param {number} s - 饱和度 (0-100)
|
|
273
|
+
* @param {number} l - 亮度 (0-100)
|
|
274
|
+
* @returns {string} 十六进制色值
|
|
275
|
+
*/
|
|
276
|
+
export function hslToHex(h, s, l) {
|
|
277
|
+
s /= 100
|
|
278
|
+
l /= 100
|
|
279
|
+
|
|
280
|
+
const c = (1 - Math.abs(2 * l - 1)) * s
|
|
281
|
+
const x = c * (1 - Math.abs(((h / 60) % 2) - 1))
|
|
282
|
+
const m = l - c / 2
|
|
283
|
+
|
|
284
|
+
let r = 0, g = 0, b = 0
|
|
285
|
+
|
|
286
|
+
if (0 <= h && h < 60) { r = c; g = x; b = 0 }
|
|
287
|
+
else if (60 <= h && h < 120) { r = x; g = c; b = 0 }
|
|
288
|
+
else if (120 <= h && h < 180) { r = 0; g = c; b = x }
|
|
289
|
+
else if (180 <= h && h < 240) { r = 0; g = x; b = c }
|
|
290
|
+
else if (240 <= h && h < 300) { r = x; g = 0; b = c }
|
|
291
|
+
else if (300 <= h && h < 360) { r = c; g = 0; b = x }
|
|
292
|
+
|
|
293
|
+
return rgbToHex(
|
|
294
|
+
Math.round((r + m) * 255),
|
|
295
|
+
Math.round((g + m) * 255),
|
|
296
|
+
Math.round((b + m) * 255)
|
|
297
|
+
)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* 产生数据系列(分段随机数据)
|
|
302
|
+
* @param {number} segment - 分段数
|
|
303
|
+
* @param {number} total - 总百分比(通常 100)
|
|
304
|
+
* @param {number} baseValue - 基础值
|
|
305
|
+
* @returns {Array} [百分比数组,数值数组]
|
|
306
|
+
*/
|
|
307
|
+
export function produceDataSeriesEx(segment, total, baseValue) {
|
|
308
|
+
// 生成分段百分比
|
|
309
|
+
const percentArray = new Array(segment).fill(0)
|
|
310
|
+
for (let i = 0; i < total; i++) {
|
|
311
|
+
const randomIndex = Math.floor(Math.random() * segment)
|
|
312
|
+
percentArray[randomIndex]++
|
|
137
313
|
}
|
|
138
314
|
|
|
139
|
-
|
|
315
|
+
// 计算对应数值
|
|
316
|
+
const valueArray = percentArray.map(percent =>
|
|
317
|
+
Math.floor(percent / 100 * baseValue)
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
return [percentArray, valueArray]
|
|
140
321
|
}
|
|
141
322
|
|
|
142
323
|
/**
|
|
143
324
|
* 深拷贝
|
|
144
|
-
* obj
|
|
145
|
-
*
|
|
325
|
+
* @param {*} obj - 要拷贝的对象
|
|
326
|
+
* @returns {*} 深拷贝后的结果
|
|
146
327
|
*/
|
|
147
328
|
export function deepClone(obj) {
|
|
148
329
|
if (obj === null || typeof obj !== 'object') {
|
|
149
|
-
|
|
330
|
+
return obj
|
|
150
331
|
}
|
|
151
|
-
|
|
332
|
+
|
|
152
333
|
if (obj instanceof Date) {
|
|
153
|
-
|
|
334
|
+
return new Date(obj.getTime())
|
|
154
335
|
}
|
|
155
|
-
|
|
336
|
+
|
|
156
337
|
if (obj instanceof Array) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
338
|
+
return obj.reduce((arr, item) => {
|
|
339
|
+
arr.push(deepClone(item))
|
|
340
|
+
return arr
|
|
341
|
+
}, [])
|
|
161
342
|
}
|
|
162
|
-
|
|
343
|
+
|
|
163
344
|
if (obj instanceof Object) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
345
|
+
return Object.keys(obj).reduce((newObj, key) => {
|
|
346
|
+
newObj[key] = deepClone(obj[key])
|
|
347
|
+
return newObj
|
|
348
|
+
}, {})
|
|
168
349
|
}
|
|
169
350
|
}
|
|
170
351
|
|
|
171
352
|
/**
|
|
172
|
-
*
|
|
173
|
-
* data
|
|
174
|
-
*
|
|
353
|
+
* 数据类型转换工具函数
|
|
354
|
+
* @param {*} data - 原始数据
|
|
355
|
+
* @param {string|Object|null} format - 目标类型或转换配置对象
|
|
356
|
+
* - 字符串:'String'|'Number'|'Boolean'|'Array'|'Object'
|
|
357
|
+
* - 对象:转换映射配置 {key: type}
|
|
358
|
+
* - null/undefined:智能自动转换
|
|
359
|
+
* @param {Object} options - 配置选项
|
|
360
|
+
* @param {boolean} options.useDefault - 转换不成功是否返回默认值(默认 true)
|
|
361
|
+
* @param {*} options.defaultValue - 自定义默认值(可选)
|
|
362
|
+
* @returns {*} 转换后的数据
|
|
363
|
+
*
|
|
364
|
+
* @example
|
|
365
|
+
* // 智能转换(不传 format)
|
|
366
|
+
* transferData('123') // 123 (自动推断为 Number)
|
|
367
|
+
* transferData('true') // true (自动推断为 Boolean)
|
|
368
|
+
* transferData('[1,2]') // [1,2] (自动推断为 Array)
|
|
369
|
+
* transferData('hello') // 'hello' (保持 String)
|
|
370
|
+
*
|
|
371
|
+
* // 字符串模式:基本类型转换
|
|
372
|
+
* transferData('123', 'Number') // 123
|
|
373
|
+
* transferData(null, 'Array') // []
|
|
374
|
+
*
|
|
375
|
+
* // 对象模式:根据 key 批量转换
|
|
376
|
+
* transferData({a:'1', b:'2'}, {a: 'Number', b: 'Number'})
|
|
377
|
+
* // {a: 1, b: 2}
|
|
378
|
+
*
|
|
379
|
+
* // 配置选项
|
|
380
|
+
* transferData('abc', 'Number') // NaN
|
|
381
|
+
* transferData('abc', 'Number', { defaultValue: -1 }) // -1
|
|
175
382
|
*/
|
|
176
|
-
export function transferData(data, format =
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
383
|
+
export function transferData(data, format, options = {}) {
|
|
384
|
+
// 智能转换模式
|
|
385
|
+
if (!format) return autoTransferDataInternal(data, options)
|
|
386
|
+
|
|
387
|
+
const { defaultValue } = options
|
|
388
|
+
|
|
389
|
+
// 数组模式:支持两种形式
|
|
390
|
+
// 1. ['a', 'b', 'c'] - 转换为 Number
|
|
391
|
+
// 2. [['a', 'b'], 'Number'] - 指定类型
|
|
392
|
+
// 3. [{ fields: ['a', 'b'], type: 'Number' }] - 对象配置
|
|
393
|
+
if (Array.isArray(format)) return transferDataByFields(data, format, options)
|
|
394
|
+
|
|
395
|
+
// 对象映射模式
|
|
396
|
+
if (typeof format === 'object') return transferDataByMap(data, format, options)
|
|
397
|
+
|
|
398
|
+
// 默认值配置
|
|
399
|
+
const defaults = {
|
|
400
|
+
Number: 0,
|
|
401
|
+
Boolean: false,
|
|
402
|
+
String: '',
|
|
403
|
+
Array: [],
|
|
183
404
|
Object: {}
|
|
184
405
|
}
|
|
185
|
-
|
|
186
|
-
if (format === 'Array' || format === 'Object') {
|
|
187
406
|
|
|
188
|
-
|
|
407
|
+
const defaultVal = defaultValue ?? defaults[format]
|
|
408
|
+
|
|
409
|
+
// 空值处理
|
|
410
|
+
if (data == null) return defaultVal
|
|
411
|
+
|
|
412
|
+
// 复杂类型处理 (Array/Object)
|
|
413
|
+
if (format === 'Array' || format === 'Object') {
|
|
414
|
+
const isTargetType = (format === 'Array' && Array.isArray(data)) ||
|
|
415
|
+
(format === 'Object' && typeof data === 'object' && !Array.isArray(data))
|
|
416
|
+
|
|
417
|
+
if (isTargetType) return format === 'Array' ? [...data] : { ...data }
|
|
189
418
|
|
|
190
419
|
try {
|
|
191
|
-
|
|
192
|
-
} catch (
|
|
420
|
+
return JSON.parse(data)
|
|
421
|
+
} catch (e) {
|
|
422
|
+
console.error(`JSON 解析失败:${e.message}`)
|
|
423
|
+
return defaultVal
|
|
424
|
+
}
|
|
425
|
+
}
|
|
193
426
|
|
|
194
|
-
|
|
195
|
-
|
|
427
|
+
// 基础类型转换
|
|
428
|
+
try {
|
|
429
|
+
switch (format) {
|
|
430
|
+
case 'Number': {
|
|
431
|
+
const num = Number(data)
|
|
432
|
+
return isNaN(num) ? defaultVal : num
|
|
433
|
+
}
|
|
434
|
+
case 'Boolean': {
|
|
435
|
+
if (typeof data === 'boolean') return data
|
|
436
|
+
const lower = String(data).toLowerCase()
|
|
437
|
+
if (['true', '1', 'yes', 'ok'].includes(lower)) return true
|
|
438
|
+
if (['false', '0', 'no', 'cancel'].includes(lower)) return false
|
|
439
|
+
return Boolean(data)
|
|
440
|
+
}
|
|
441
|
+
case 'String': {
|
|
442
|
+
// 对象/数组转为 JSON 字符串
|
|
443
|
+
if (typeof data === 'object') {
|
|
444
|
+
try {
|
|
445
|
+
return JSON.stringify(data)
|
|
446
|
+
} catch (e) {
|
|
447
|
+
console.error(`对象转字符串失败:${e.message}`)
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return String(data)
|
|
451
|
+
}
|
|
452
|
+
default:
|
|
453
|
+
return data
|
|
196
454
|
}
|
|
455
|
+
} catch {
|
|
456
|
+
return defaultVal
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* 根据字段数组批量转换数据
|
|
462
|
+
* @param {*} data - 原始数据
|
|
463
|
+
* @param {Array} format - 格式配置
|
|
464
|
+
* - ['a', 'b', 'c'] - 默认转为 Number
|
|
465
|
+
* - [['a', 'b'], 'Number'] - 指定类型
|
|
466
|
+
* - [{ fields: ['a', 'b'], type: 'Number' }] - 对象配置
|
|
467
|
+
* @param {Object} options - 配置选项
|
|
468
|
+
* @returns {*} 转换后的数据
|
|
469
|
+
*/
|
|
470
|
+
function transferDataByFields(data, format, options) {
|
|
471
|
+
if (data == null || typeof data !== 'object') {
|
|
472
|
+
return data ?? options.defaultValue
|
|
473
|
+
}
|
|
197
474
|
|
|
198
|
-
|
|
475
|
+
let fields = []
|
|
476
|
+
let type = 'Number' // 默认转为 Number
|
|
477
|
+
|
|
478
|
+
// 解析数组配置
|
|
479
|
+
if (format.length === 0) return data
|
|
480
|
+
|
|
481
|
+
// 形式 1: ['a', 'b', 'c'] - 默认转 Number
|
|
482
|
+
if (typeof format[0] === 'string') {
|
|
483
|
+
fields = format
|
|
484
|
+
}
|
|
485
|
+
// 形式 2: [['a', 'b'], 'Number'] - [fields, type]
|
|
486
|
+
else if (Array.isArray(format[0])) {
|
|
487
|
+
fields = format[0]
|
|
488
|
+
if (format[1]) type = format[1]
|
|
199
489
|
}
|
|
200
|
-
|
|
201
|
-
|
|
490
|
+
// 形式 3: [{ fields: ['a', 'b'], type: 'Number' }] - 对象配置
|
|
491
|
+
else if (typeof format[0] === 'object') {
|
|
492
|
+
const config = format[0]
|
|
493
|
+
fields = config.fields || []
|
|
494
|
+
type = config.type || 'Number'
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// 如果是数组,递归处理每个元素
|
|
498
|
+
if (Array.isArray(data)) {
|
|
499
|
+
return data.map(item => transferDataByFields(item, format, options))
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// 对象处理:转换指定字段
|
|
503
|
+
const result = { ...data }
|
|
504
|
+
|
|
505
|
+
for (const field of fields) {
|
|
506
|
+
if (field in result) {
|
|
507
|
+
result[field] = transferData(result[field], type, options)
|
|
508
|
+
}
|
|
202
509
|
}
|
|
510
|
+
|
|
511
|
+
return result
|
|
203
512
|
}
|
|
204
513
|
|
|
514
|
+
/**
|
|
515
|
+
* 智能数据类型转换(内部函数)
|
|
516
|
+
* @param {*} data - 原始数据
|
|
517
|
+
* @param {Object} options - 配置选项
|
|
518
|
+
* @returns {*} 转换后的数据
|
|
519
|
+
*/
|
|
520
|
+
function autoTransferDataInternal(data, options) {
|
|
521
|
+
if (data == null || typeof data !== 'string') return data ?? options.defaultValue
|
|
522
|
+
|
|
523
|
+
const trimmed = data.trim()
|
|
524
|
+
if (!trimmed) return options.defaultValue
|
|
525
|
+
|
|
526
|
+
try {
|
|
527
|
+
if (/^true$/i.test(trimmed)) return true
|
|
528
|
+
if (/^false$/i.test(trimmed)) return false
|
|
529
|
+
|
|
530
|
+
if (/^[+-]?\d*\.?\d+(?:[eE][+-]?\d+)?$/.test(trimmed)) {
|
|
531
|
+
const num = Number(trimmed)
|
|
532
|
+
if (!isNaN(num)) return num
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (/^[\[{]/.test(trimmed)) {
|
|
536
|
+
return JSON.parse(trimmed)
|
|
537
|
+
}
|
|
538
|
+
} catch {}
|
|
539
|
+
|
|
540
|
+
return data
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* 根据映射对象批量转换数据
|
|
545
|
+
* @param {*} data - 原始数据(对象或数组)
|
|
546
|
+
* @param {Object} formatMap - 转换映射对象 {key: type}
|
|
547
|
+
* @param {Object} options - 配置选项
|
|
548
|
+
* @returns {*} 转换后的数据
|
|
549
|
+
*/
|
|
550
|
+
function transferDataByMap(data, formatMap, options) {
|
|
551
|
+
// 数据为空,返回空对象或原数据
|
|
552
|
+
if (data === null || data === undefined) {
|
|
553
|
+
return options.defaultValue ?? {}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// 数组处理:对每个元素应用转换映射
|
|
557
|
+
if (Array.isArray(data)) {
|
|
558
|
+
return data.map(item => {
|
|
559
|
+
if (typeof item !== 'object') return item
|
|
560
|
+
return transferDataByMap(item, formatMap, options)
|
|
561
|
+
})
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// 对象处理:根据 formatMap 的 key 进行转换
|
|
565
|
+
const result = {}
|
|
566
|
+
|
|
567
|
+
// 遍历映射表进行类型转换
|
|
568
|
+
for (const key in formatMap) {
|
|
569
|
+
if (Object.hasOwn(formatMap, key)) {
|
|
570
|
+
result[key] = transferData(data[key], formatMap[key], options)
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// 保留未在映射表中定义的其他属性
|
|
575
|
+
for (const key in data) {
|
|
576
|
+
if (Object.hasOwn(data, key) && !Object.hasOwn(result, key)) {
|
|
577
|
+
result[key] = data[key]
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
return result
|
|
582
|
+
}
|
|
205
583
|
|
|
206
584
|
/**
|
|
207
|
-
*
|
|
208
|
-
* str
|
|
209
|
-
* charToFind
|
|
210
|
-
* n
|
|
211
|
-
*
|
|
585
|
+
* 查找字符串中第 n 次出现的位置
|
|
586
|
+
* @param {string} str - 源字符串
|
|
587
|
+
* @param {string} charToFind - 查找字符
|
|
588
|
+
* @param {number} n - 第几次出现
|
|
589
|
+
* @returns {number} 位置索引,未找到返回 -1
|
|
212
590
|
*/
|
|
213
591
|
export function findNthOccurrence(str, charToFind, n) {
|
|
214
|
-
let count = 0
|
|
215
|
-
let index = str.indexOf(charToFind)
|
|
592
|
+
let count = 0
|
|
593
|
+
let index = str.indexOf(charToFind)
|
|
216
594
|
|
|
217
595
|
while (count < n && index !== -1) {
|
|
218
|
-
index = str.indexOf(charToFind, index + 1)
|
|
219
|
-
count
|
|
596
|
+
index = str.indexOf(charToFind, index + 1)
|
|
597
|
+
count++
|
|
220
598
|
}
|
|
221
599
|
|
|
222
|
-
return index
|
|
223
|
-
}
|
|
600
|
+
return index
|
|
601
|
+
}
|
|
224
602
|
|
|
225
603
|
/**
|
|
226
|
-
*
|
|
227
|
-
* @object
|
|
604
|
+
* 对象转 FormData
|
|
605
|
+
* @param {Object} object - 要转换的对象
|
|
606
|
+
* @returns {FormData} FormData 对象
|
|
228
607
|
*/
|
|
229
608
|
export function setFormData(object) {
|
|
230
|
-
|
|
231
609
|
const formData = new FormData()
|
|
232
610
|
|
|
233
611
|
for (const key in object) {
|
|
234
|
-
|
|
612
|
+
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
|
613
|
+
const value = object[key]
|
|
614
|
+
|
|
615
|
+
// 处理嵌套对象和数组
|
|
616
|
+
value instanceof Object || Array.isArray(value)
|
|
617
|
+
? formData.append(key, JSON.stringify(value))
|
|
618
|
+
: formData.append(key, value)
|
|
619
|
+
}
|
|
235
620
|
}
|
|
236
621
|
|
|
237
622
|
return formData
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* 防抖函数
|
|
627
|
+
* @param {Function} func - 要执行的函数
|
|
628
|
+
* @param {number} wait - 等待时间(毫秒)
|
|
629
|
+
* @returns {Function} 防抖后的函数
|
|
630
|
+
*/
|
|
631
|
+
export function debounce(func, wait = 300) {
|
|
632
|
+
let timeout
|
|
633
|
+
return function (...args) {
|
|
634
|
+
clearTimeout(timeout)
|
|
635
|
+
timeout = setTimeout(() => func.apply(this, args), wait)
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* 节流函数
|
|
641
|
+
* @param {Function} func - 要执行的函数
|
|
642
|
+
* @param {number} delay - 延迟时间(毫秒)
|
|
643
|
+
* @returns {Function} 节流后的函数
|
|
644
|
+
*/
|
|
645
|
+
export function throttle(func, delay = 300) {
|
|
646
|
+
let lastTime = 0
|
|
647
|
+
return function (...args) {
|
|
648
|
+
const now = Date.now()
|
|
649
|
+
if (now - lastTime >= delay) {
|
|
650
|
+
lastTime = now
|
|
651
|
+
func.apply(this, args)
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* 数组去重
|
|
658
|
+
* @param {Array} arr - 要去重的数组
|
|
659
|
+
* @param {string} key - 对象去重的键(可选)
|
|
660
|
+
* @returns {Array} 去重后的数组
|
|
661
|
+
*/
|
|
662
|
+
export function uniqueArray(arr, key) {
|
|
663
|
+
if (!Array.isArray(arr)) return []
|
|
664
|
+
|
|
665
|
+
if (key) {
|
|
666
|
+
const seen = new Set()
|
|
667
|
+
return arr.filter(item => {
|
|
668
|
+
const value = item[key]
|
|
669
|
+
if (seen.has(value)) return false
|
|
670
|
+
seen.add(value)
|
|
671
|
+
return true
|
|
672
|
+
})
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
return [...new Set(arr)]
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* 数组按指定字段排序
|
|
680
|
+
* @param {Array} arr - 要排序的数组
|
|
681
|
+
* @param {string} key - 排序字段
|
|
682
|
+
* @param {boolean} ascending - 是否升序(默认降序)
|
|
683
|
+
* @returns {Array} 排序后的数组
|
|
684
|
+
*/
|
|
685
|
+
export function sortByKey(arr, key, ascending = false) {
|
|
686
|
+
if (!Array.isArray(arr)) return []
|
|
687
|
+
|
|
688
|
+
return arr.sort((a, b) => {
|
|
689
|
+
const valA = a[key]
|
|
690
|
+
const valB = b[key]
|
|
238
691
|
|
|
239
|
-
|
|
692
|
+
if (valA < valB) return ascending ? -1 : 1
|
|
693
|
+
if (valA > valB) return ascending ? 1 : -1
|
|
694
|
+
return 0
|
|
695
|
+
})
|
|
696
|
+
}
|