web-component-gallery 2.3.6 → 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/utils/Filter.js CHANGED
@@ -1,65 +1,121 @@
1
-
2
1
  /**
3
- *
4
- * @param {*} day 传入天数
5
- * 距离现在n天前的日期
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
- // 获取n小时前的时间
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
- // 获取n分钟前的时间
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 {*} time 传入时间
37
- * @param {*} cFormat 可不传。格式化结构 默认 年-月-日 时:分:秒
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
- return null;
43
- }
44
- const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}";
45
- let date;
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 times = time;
50
- times = new Date(time).getTime();
51
- if ((typeof times === "string")) {
52
- if ((/^[0-9]+$/.test(times))) {
53
- times = parseInt(times);
54
- } else {
55
- times = times.replace(new RegExp(/-/g), "/");
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
- if ((typeof times === "number") && (times.toString().length === 10)) {
59
- times *= 1000;
104
+
105
+ // 10 位时间戳转毫秒
106
+ if (typeof timestamp === "number" && timestamp.toString().length === 10) {
107
+ timestamp *= 1000
60
108
  }
61
- date = new Date(times);
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
- const timeStr = format.replace(/\{([ymdhisa])+\}/g, (result, key) => {
73
- const value = formatObj[key];
74
- // Note: getDay() returns 0 on Sunday
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
- if (!String.prototype.padStart) return padStart(2, value.toString());
79
- return value.toString()
80
- .padStart(2, "0"); // 返回替换的字符串,padStart用于头部补全
81
- });
82
- return timeStr;
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
- * JS颜色十六进制转换为rgb或rgba,返回的格式为 rgba(255,255,255,0.5)字符串
87
- * sHex为传入的十六进制的色值
88
- * alpha为rgba的透明度
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
- const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
93
- /* 16进制颜色转为RGB格式 */
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
- var sColorNew = "#";
98
- for (let i = 1; i < 4; i += 1) {
99
- sColorNew += sColor.slice(i, i + 1)
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
- const sColorChange = [];
221
+
222
+ // 提取 RGB
223
+ const rgbValues = []
106
224
  for (let i = 1; i < 7; i += 2) {
107
- sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`));
225
+ rgbValues.push(parseInt(`0x${sColor.slice(i, i + 2)}`))
108
226
  }
109
- // return sColorChange.join(',')
110
- return `rgba(${sColorChange.join(",")},${alpha})`;
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 sColor;
248
+ return "#" + toHex(r) + toHex(g) + toHex(b)
113
249
  }
114
250
 
115
251
  /**
116
- * segment: 分段 7段
117
- * tatalpercent: 百分比 100
118
- * basevalue: 基础值 200
119
- */
120
- export function produceDataSeriesEx(segment, tatal, basevalue) {
121
- //需要产生segment个随机数,且segment个随机数之和等于tatal
122
- let arrpercent = new Array(segment).fill(0);
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
- let arrvalue = new Array(segment).fill(0);
135
- for (let i = 0; i < segment; i++) {
136
- arrvalue[i] = parseInt(arrpercent[i] / 100 * basevalue);
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
- return [arrpercent, arrvalue];
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
- return obj
330
+ return obj
150
331
  }
151
-
332
+
152
333
  if (obj instanceof Date) {
153
- return new Date(obj.getTime())
334
+ return new Date(obj.getTime())
154
335
  }
155
-
336
+
156
337
  if (obj instanceof Array) {
157
- return obj.reduce((arr, item, i) => {
158
- arr[i] = deepClone(item)
159
- return arr
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
- return Object.keys(obj).reduce((newObj, key) => {
165
- newObj[key] = deepClone(obj[key])
166
- return newObj
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 = 'String') {
177
-
178
- const defaultData = {
179
- Number: 0,
180
- Boolean: false,
181
- String: '',
182
- Array: [],
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
- let parsed
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
- parsed = JSON.parse(data)
192
- } catch (error) { parsed = data }
420
+ return JSON.parse(data)
421
+ } catch (e) {
422
+ console.error(`JSON 解析失败:${e.message}`)
423
+ return defaultVal
424
+ }
425
+ }
193
426
 
194
- if (parsed && ( parsed instanceof Array || parsed instanceof Object )) {
195
- return parsed
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
- return defaultData[format]
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
- else {
201
- return data ?? defaultData[format]
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 === -1 ? -1 : index;
223
- }
600
+ return index
601
+ }
224
602
 
225
603
  /**
226
- * object转化为formData
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
- formData.append(key, object[key])
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
+ }