web-component-gallery 2.3.13 → 2.3.15

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,16 +1,98 @@
1
1
  /**
2
- * 获取 n 天前的时间
2
+ * 格式化日期
3
+ * @param {string|number|Date} time - 时间
4
+ * @param {string} cFormat - 格式化模板
5
+ * {y}年 {m}月 {d}日 {h}时 {i}分 {s}秒 {a}星期 {q}季度
6
+ * @returns {string|null} 格式化后的日期字符串
7
+ */
8
+ export function formatDate(time, cFormat) {
9
+ if (arguments.length === 0 || !time) return null
10
+
11
+ const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}"
12
+ let date
13
+
14
+ if (typeof time === "object") {
15
+ date = time
16
+ } else {
17
+ let timestamp = time
18
+
19
+ if (typeof timestamp === "string") {
20
+ timestamp = /^[0-9]+$/.test(timestamp)
21
+ ? parseInt(timestamp)
22
+ : timestamp.replace(/-/g, "/")
23
+ }
24
+
25
+ if (typeof timestamp === "number" && timestamp.toString().length === 10) {
26
+ timestamp *= 1000
27
+ }
28
+
29
+ date = new Date(timestamp)
30
+ }
31
+
32
+ if (isNaN(date.getTime())) {
33
+ console.warn('无效的日期格式')
34
+ return null
35
+ }
36
+
37
+ const formatObj = {
38
+ y: date.getFullYear(),
39
+ m: date.getMonth() + 1,
40
+ d: date.getDate(),
41
+ h: date.getHours(),
42
+ i: date.getMinutes(),
43
+ s: date.getSeconds(),
44
+ a: date.getDay(),
45
+ q: Math.floor((date.getMonth() + 3) / 3),
46
+ }
47
+
48
+ const timeStr = format.replace(/{([ymdhisaq])+}/g, (result, key) => {
49
+ const value = formatObj[key]
50
+
51
+ if (key === "a") {
52
+ return ["日", "一", "二", "三", "四", "五", "六"][value]
53
+ }
54
+
55
+ return String(value).padStart(2, "0")
56
+ })
57
+
58
+ return timeStr
59
+ }
60
+
61
+ /**
62
+ * 获取相对时间(通用函数)
3
63
  * @param {number} n - 数量
64
+ * @param {string} unit - 单位:'days'|'hours'|'minutes'|'seconds'
65
+ * @param {boolean} isBefore - 是否之前
4
66
  * @param {string|Date} baseTime - 基准时间(可选)
5
67
  * @param {string} cFormat - 格式化模板
6
68
  * @returns {string} 格式化日期
7
69
  */
8
- export function getNDaysBefore(n, baseTime = null, cFormat) {
70
+ export function getRelativeTime(n, unit = 'days', isBefore = true, baseTime = null, cFormat) {
9
71
  const base = baseTime ? new Date(baseTime) : new Date()
10
- const targetTime = new Date(base.getTime() - n * 24 * 60 * 60 * 1000)
72
+ const multipliers = {
73
+ days: 24 * 60 * 60 * 1000,
74
+ hours: 60 * 60 * 1000,
75
+ minutes: 60 * 1000,
76
+ seconds: 1000
77
+ }
78
+
79
+ const diff = n * (multipliers[unit] || multipliers.days)
80
+ const targetTime = new Date(base.getTime() + (isBefore ? -diff : diff))
81
+
11
82
  return formatDate(targetTime, cFormat)
12
83
  }
13
84
 
85
+ /**
86
+ * 获取 n 天前的时间
87
+ * @param {number} n - 数量
88
+ * @param {string|Date} baseTime - 基准时间(可选)
89
+ * @param {string} cFormat - 格式化模板
90
+ * @returns {string} 格式化日期
91
+ */
92
+ export function getNDaysBefore(n, baseTime = null, cFormat) {
93
+ return getRelativeTime(n, 'days', true, baseTime, cFormat)
94
+ }
95
+
14
96
  /**
15
97
  * 获取 n 小时前的时间
16
98
  * @param {number} n - 小时数
@@ -19,9 +101,7 @@ export function getNDaysBefore(n, baseTime = null, cFormat) {
19
101
  * @returns {string} 格式化日期
20
102
  */
21
103
  export function getNHoursBefore(n, baseTime = null, cFormat) {
22
- const base = baseTime ? new Date(baseTime) : new Date()
23
- const targetTime = new Date(base.getTime() - n * 60 * 60 * 1000)
24
- return formatDate(targetTime, cFormat)
104
+ return getRelativeTime(n, 'hours', true, baseTime, cFormat)
25
105
  }
26
106
 
27
107
  /**
@@ -32,9 +112,7 @@ export function getNHoursBefore(n, baseTime = null, cFormat) {
32
112
  * @returns {string} 格式化日期
33
113
  */
34
114
  export function getNMinutesBefore(n, baseTime = null, cFormat) {
35
- const base = baseTime ? new Date(baseTime) : new Date()
36
- const targetTime = new Date(base.getTime() - n * 60 * 1000)
37
- return formatDate(targetTime, cFormat)
115
+ return getRelativeTime(n, 'minutes', true, baseTime, cFormat)
38
116
  }
39
117
 
40
118
  /**
@@ -45,9 +123,7 @@ export function getNMinutesBefore(n, baseTime = null, cFormat) {
45
123
  * @returns {string} 格式化日期
46
124
  */
47
125
  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)
126
+ return getRelativeTime(n, 'seconds', true, baseTime, cFormat)
51
127
  }
52
128
 
53
129
  /**
@@ -58,9 +134,7 @@ export function getNSecondsBefore(n, baseTime = null, cFormat) {
58
134
  * @returns {string} 格式化日期
59
135
  */
60
136
  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)
137
+ return getRelativeTime(n, 'days', false, baseTime, cFormat)
64
138
  }
65
139
 
66
140
  /**
@@ -71,75 +145,7 @@ export function getNDaysAfter(n, baseTime = null, cFormat) {
71
145
  * @returns {string} 格式化日期
72
146
  */
73
147
  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
- }
78
-
79
- /**
80
- * 格式化日期
81
- * @param {string|number|Date} time - 时间
82
- * @param {string} cFormat - 格式化模板
83
- * {y}年 {m}月 {d}日 {h}时 {i}分 {s}秒 {a}星期 {q}季度
84
- * @returns {string|null} 格式化后的日期字符串
85
- */
86
- export function formatDate(time, cFormat) {
87
- if (arguments.length === 0 || !time) return null
88
-
89
- const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}"
90
- let date
91
-
92
- // 处理不同类型的输入
93
- if (typeof time === "object") {
94
- date = time
95
- } else {
96
- let timestamp = time
97
-
98
- // 字符串处理
99
- if (typeof timestamp === "string") {
100
- timestamp = /^[0-9]+$/.test(timestamp)
101
- ? parseInt(timestamp)
102
- : timestamp.replace(/-/g, "/")
103
- }
104
-
105
- // 10 位时间戳转毫秒
106
- if (typeof timestamp === "number" && timestamp.toString().length === 10) {
107
- timestamp *= 1000
108
- }
109
-
110
- date = new Date(timestamp)
111
- }
112
-
113
- // 验证日期有效性
114
- if (isNaN(date.getTime())) {
115
- console.warn('无效的日期格式')
116
- return null
117
- }
118
-
119
- const formatObj = {
120
- y: date.getFullYear(),
121
- m: date.getMonth() + 1,
122
- d: date.getDate(),
123
- h: date.getHours(),
124
- i: date.getMinutes(),
125
- s: date.getSeconds(),
126
- a: date.getDay(),
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
- // 星期处理
134
- if (key === "a") {
135
- return ["日", "一", "二", "三", "四", "五", "六"][value]
136
- }
137
-
138
- // 补零处理
139
- return String(value).padStart(2, "0")
140
- })
141
-
142
- return timeStr
148
+ return getRelativeTime(n, 'hours', false, baseTime, cFormat)
143
149
  }
144
150
 
145
151
  /**
@@ -151,7 +157,6 @@ export function formatDate(time, cFormat) {
151
157
  export function formatTimestamp(timestamp, format) {
152
158
  if (!timestamp) return null
153
159
 
154
- // 10 位时间戳转毫秒
155
160
  if (String(timestamp).length === 10) {
156
161
  timestamp *= 1000
157
162
  }
@@ -163,7 +168,7 @@ export function formatTimestamp(timestamp, format) {
163
168
  * 计算两个日期之间的差异
164
169
  * @param {string|Date} date1 - 日期 1
165
170
  * @param {string|Date} date2 - 日期 2
166
- * @returns {Object} 差异对象 {days, hours, minutes, seconds, milliseconds}
171
+ * @returns {Object} 差异对象
167
172
  */
168
173
  export function dateDiff(date1, date2) {
169
174
  const d1 = new Date(date1)
@@ -204,28 +209,27 @@ export function getDaysInMonth(year, month) {
204
209
  /**
205
210
  * 颜色十六进制转 RGB/RGBA
206
211
  * @param {string} sHex - 十六进制色值
207
- * @param {number} alpha - 透明度
208
- * @returns {string} rgba(r,g,b,a) 格式字符串
212
+ * @param {number} [alpha] - 透明度(0-1)
213
+ * @returns {string} rgba(r,g,b,a) 或 rgb(r,g,b) 格式字符串
209
214
  */
210
215
  export function colorRgba(sHex, alpha) {
211
216
  const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
212
217
  let sColor = sHex.toLowerCase()
213
218
 
214
219
  if (sColor && reg.test(sColor)) {
215
- // 简写形式转为完整形式 #fff -> #ffffff
216
220
  if (sColor.length === 4) {
217
221
  sColor = "#" + [1, 2, 3].map(i =>
218
222
  sColor.slice(i, i + 1).repeat(2)
219
223
  ).join("")
220
224
  }
221
225
 
222
- // 提取 RGB 值
223
226
  const rgbValues = []
224
227
  for (let i = 1; i < 7; i += 2) {
225
228
  rgbValues.push(parseInt(`0x${sColor.slice(i, i + 2)}`))
226
229
  }
227
230
 
228
- return alpha !== undefined
231
+ // 修复:使用 alpha == null 检查(同时排除 undefined 和 null)
232
+ return (alpha != null)
229
233
  ? `rgba(${rgbValues.join(",")},${alpha})`
230
234
  : `rgb(${rgbValues.join(",")})`
231
235
  }
@@ -258,7 +262,6 @@ export function randomColor(full = false) {
258
262
  return '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')
259
263
  }
260
264
 
261
- // 生成柔和的彩色
262
265
  const hue = Math.floor(Math.random() * 360)
263
266
  const saturation = 70 + Math.floor(Math.random() * 20)
264
267
  const lightness = 60 + Math.floor(Math.random() * 20)
@@ -305,14 +308,12 @@ export function hslToHex(h, s, l) {
305
308
  * @returns {Array} [百分比数组,数值数组]
306
309
  */
307
310
  export function produceDataSeriesEx(segment, total, baseValue) {
308
- // 生成分段百分比
309
311
  const percentArray = new Array(segment).fill(0)
310
312
  for (let i = 0; i < total; i++) {
311
313
  const randomIndex = Math.floor(Math.random() * segment)
312
314
  percentArray[randomIndex]++
313
315
  }
314
316
 
315
- // 计算对应数值
316
317
  const valueArray = percentArray.map(percent =>
317
318
  Math.floor(percent / 100 * baseValue)
318
319
  )
@@ -321,7 +322,7 @@ export function produceDataSeriesEx(segment, total, baseValue) {
321
322
  }
322
323
 
323
324
  /**
324
- * 深拷贝
325
+ * 深拷贝(增强版)
325
326
  * @param {*} obj - 要拷贝的对象
326
327
  * @returns {*} 深拷贝后的结果
327
328
  */
@@ -334,6 +335,10 @@ export function deepClone(obj) {
334
335
  return new Date(obj.getTime())
335
336
  }
336
337
 
338
+ if (obj instanceof RegExp) {
339
+ return new RegExp(obj.source, obj.flags)
340
+ }
341
+
337
342
  if (obj instanceof Array) {
338
343
  return obj.reduce((arr, item) => {
339
344
  arr.push(deepClone(item))
@@ -347,55 +352,43 @@ export function deepClone(obj) {
347
352
  return newObj
348
353
  }, {})
349
354
  }
355
+
356
+ return obj
350
357
  }
351
358
 
352
359
  /**
353
360
  * 数据类型转换工具函数
354
361
  * @param {*} data - 原始数据
355
- * @param {string|Object|null} format - 目标类型或转换配置对象
362
+ * @param {string|Object|null} format - 目标类型或转换配置
356
363
  * - 字符串:'String'|'Number'|'Boolean'|'Array'|'Object'
357
- * - 对象:转换映射配置 {key: type}
358
- * - null/undefined:智能自动转换
364
+ * - 对象:映射配置 {key: type}
365
+ * - 数组:字段配置 [{ fields: ['a'], type: 'Number' }]
366
+ * - null:智能转换
359
367
  * @param {Object} options - 配置选项
360
- * @param {boolean} options.useDefault - 转换不成功是否返回默认值(默认 true)
361
- * @param {*} options.defaultValue - 自定义默认值(可选)
368
+ * @param {*} options.defaultValue - 自定义默认值
362
369
  * @returns {*} 转换后的数据
363
370
  *
364
371
  * @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
372
+ * transferData('123') // 智能转换:123
373
+ * transferData('123', 'Number') // Number:123
374
+ * transferData('true', 'Boolean') // Boolean:true
375
+ * transferData(123, 'String') // String:'123'
376
+ * transferData('[1,2]', 'Array') // Array:[1,2]
377
+ * transferData('{"a":1}', 'Object') // Object:{a:1}
378
+ * transferData({a:'1'}, ['a']) // 批量转 Number:{a:1}
379
+ * transferData({a:'1'}, [['a'],'Number']) // 指定类型:{a:1}
380
+ * transferData({a:'1'}, [{fields:['a'],type:'Number'}]) // 对象配置:{a:1}
381
+ * transferData({a:null}, ['a'], {defaultValue:0}) // 带默认值:{a:0}
382
+ * transferData([{a:'1'},{a:'2'}], ['a']) // 数组递归:[{a:1},{a:2}]
383
+ * transferData({a:'1',b:'2'}, {a:'Number'}) // 对象映射:{a:1,b:'2'}
382
384
  */
383
385
  export function transferData(data, format, options = {}) {
384
- // 智能转换模式
385
386
  if (!format) return autoTransferDataInternal(data, options)
386
387
 
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
388
  if (Array.isArray(format)) return transferDataByFields(data, format, options)
394
389
 
395
- // 对象映射模式
396
390
  if (typeof format === 'object') return transferDataByMap(data, format, options)
397
391
 
398
- // 默认值配置
399
392
  const defaults = {
400
393
  Number: 0,
401
394
  Boolean: false,
@@ -404,12 +397,10 @@ export function transferData(data, format, options = {}) {
404
397
  Object: {}
405
398
  }
406
399
 
407
- const defaultVal = defaultValue ?? defaults[format]
400
+ const defaultVal = options.defaultValue ?? defaults[format]
408
401
 
409
- // 空值处理
410
402
  if (data == null) return defaultVal
411
403
 
412
- // 复杂类型处理 (Array/Object)
413
404
  if (format === 'Array' || format === 'Object') {
414
405
  const isTargetType = (format === 'Array' && Array.isArray(data)) ||
415
406
  (format === 'Object' && typeof data === 'object' && !Array.isArray(data))
@@ -424,7 +415,6 @@ export function transferData(data, format, options = {}) {
424
415
  }
425
416
  }
426
417
 
427
- // 基础类型转换
428
418
  try {
429
419
  switch (format) {
430
420
  case 'Number': {
@@ -439,7 +429,6 @@ export function transferData(data, format, options = {}) {
439
429
  return Boolean(data)
440
430
  }
441
431
  case 'String': {
442
- // 对象/数组转为 JSON 字符串
443
432
  if (typeof data === 'object') {
444
433
  try {
445
434
  return JSON.stringify(data)
@@ -461,61 +450,74 @@ export function transferData(data, format, options = {}) {
461
450
  * 根据字段数组批量转换数据
462
451
  * @param {*} data - 原始数据
463
452
  * @param {Array} format - 格式配置
464
- * - ['a', 'b', 'c'] - 默认转为 Number
465
- * - [['a', 'b'], 'Number'] - 指定类型
466
- * - [{ fields: ['a', 'b'], type: 'Number' }] - 单个对象配置
467
- * - [{ fields: ['a', 'b'], type: 'Number', defaultValue: 0 }, { fields: ['c'], type: 'String' }] - 多个对象配置
468
453
  * @param {Object} options - 配置选项
469
454
  * @returns {*} 转换后的数据
470
455
  */
471
456
  function transferDataByFields(data, format, options) {
457
+ // 边界情况处理
472
458
  if (data == null || typeof data !== 'object') {
473
459
  return data ?? options.defaultValue
474
460
  }
475
461
 
476
- // 解析数组配置
477
- if (format.length === 0) return data
462
+ // 空配置直接返回
463
+ if (!format || format.length === 0) return data
478
464
 
479
- let fields = []
480
- let type = 'Number' // 默认转为 Number
465
+ // 数组处理:递归处理每个元素(提前到最前面)
466
+ if (Array.isArray(data)) {
467
+ return data.map(item => transferDataByFields(item, format, options))
468
+ }
481
469
 
482
- // 对象处理:转换指定字段
483
470
  const result = { ...data }
484
-
485
- // 形式 1: ['a', 'b', 'c'] - 默认转 Number
486
- if (typeof format[0] === 'string') {
487
- fields = format
488
- }
489
- // 形式 2: [['a', 'b'], 'Number'] - [fields, type]
490
- else if (Array.isArray(format[0])) {
491
- fields = format[0]
492
- if (format[1]) type = format[1]
493
- }
494
- // 形式 3: [{ fields: ['a', 'b'], type: 'Number' }] - 对象配置
495
- else if (typeof format[0] === 'object') {
471
+ const configType = typeof format[0]
472
+
473
+ if (configType === 'string' || Array.isArray(format[0])) {
474
+ // 形式 1 和形式 2:统一解析
475
+ const { fields, type } = parseFormatConfig(format)
476
+
477
+ for (const field of fields) {
478
+ if (field in result) {
479
+ result[field] = transferData(result[field], type, options)
480
+ }
481
+ }
482
+ } else if (configType === 'object') {
483
+ // 形式 3:对象配置数组
496
484
  format.forEach(config => {
497
- // 转换指定字段
498
- for (const field of config.fields) {
485
+ const fields = config.fields || []
486
+ const type = config.type || 'Number'
487
+
488
+ for (const field of fields) {
499
489
  if (field in result) {
500
- const fieldDefaultValue = config.defaultValue || options.defaultValue
501
- result[field] = transferData(result[field], config.type, fieldDefaultValue)
490
+ const fieldOptions = config.defaultValue !== undefined
491
+ ? { ...options, defaultValue: config.defaultValue }
492
+ : options
493
+
494
+ result[field] = transferData(result[field], type, fieldOptions)
502
495
  }
503
496
  }
504
497
  })
505
498
  }
506
499
 
507
- // 如果是数组,递归处理每个元素
508
- if (Array.isArray(data)) {
509
- return data.map(item => transferDataByFields(item, format, options))
500
+ return result
501
+ }
502
+
503
+ /**
504
+ * 解析传统格式配置
505
+ * @param {Array} format - 格式配置
506
+ * @returns {{fields: Array, type: string}} 解析后的配置
507
+ */
508
+ function parseFormatConfig(format) {
509
+ if (typeof format[0] === 'string') {
510
+ return { fields: format, type: 'Number' }
510
511
  }
511
512
 
512
- for (const field of fields) {
513
- if (field in result) {
514
- result[field] = transferData(result[field], type, options)
513
+ if (Array.isArray(format[0])) {
514
+ return {
515
+ fields: format[0] || [],
516
+ type: format[1] || 'Number'
515
517
  }
516
518
  }
517
-
518
- return result
519
+
520
+ return { fields: [], type: 'Number' }
519
521
  }
520
522
 
521
523
  /**
@@ -549,18 +551,16 @@ function autoTransferDataInternal(data, options) {
549
551
 
550
552
  /**
551
553
  * 根据映射对象批量转换数据
552
- * @param {*} data - 原始数据(对象或数组)
553
- * @param {Object} formatMap - 转换映射对象 {key: type}
554
+ * @param {*} data - 原始数据
555
+ * @param {Object} formatMap - 转换映射对象
554
556
  * @param {Object} options - 配置选项
555
557
  * @returns {*} 转换后的数据
556
558
  */
557
559
  function transferDataByMap(data, formatMap, options) {
558
- // 数据为空,返回空对象或原数据
559
560
  if (data === null || data === undefined) {
560
561
  return options.defaultValue ?? {}
561
562
  }
562
563
 
563
- // 数组处理:对每个元素应用转换映射
564
564
  if (Array.isArray(data)) {
565
565
  return data.map(item => {
566
566
  if (typeof item !== 'object') return item
@@ -568,17 +568,14 @@ function transferDataByMap(data, formatMap, options) {
568
568
  })
569
569
  }
570
570
 
571
- // 对象处理:根据 formatMap 的 key 进行转换
572
571
  const result = {}
573
572
 
574
- // 遍历映射表进行类型转换
575
573
  for (const key in formatMap) {
576
574
  if (Object.hasOwn(formatMap, key)) {
577
575
  result[key] = transferData(data[key], formatMap[key], options)
578
576
  }
579
577
  }
580
578
 
581
- // 保留未在映射表中定义的其他属性
582
579
  for (const key in data) {
583
580
  if (Object.hasOwn(data, key) && !Object.hasOwn(result, key)) {
584
581
  result[key] = data[key]
@@ -592,18 +589,21 @@ function transferDataByMap(data, formatMap, options) {
592
589
  * 查找字符串中第 n 次出现的位置
593
590
  * @param {string} str - 源字符串
594
591
  * @param {string} charToFind - 查找字符
595
- * @param {number} n - 第几次出现
592
+ * @param {number} n - 第几次出现(从 1 开始)
596
593
  * @returns {number} 位置索引,未找到返回 -1
597
594
  */
598
595
  export function findNthOccurrence(str, charToFind, n) {
596
+ if (n < 1) return -1
597
+
598
+ let index = -1
599
599
  let count = 0
600
- let index = str.indexOf(charToFind)
601
-
602
- while (count < n && index !== -1) {
603
- index = str.indexOf(charToFind, index + 1)
604
- count++
600
+
601
+ while (count < n) {
602
+ index = str.indexOf(charToFind, index + 1)
603
+ if (index === -1) return -1
604
+ count++
605
605
  }
606
-
606
+
607
607
  return index
608
608
  }
609
609
 
@@ -619,7 +619,6 @@ export function setFormData(object) {
619
619
  if (Object.prototype.hasOwnProperty.call(object, key)) {
620
620
  const value = object[key]
621
621
 
622
- // 处理嵌套对象和数组
623
622
  value instanceof Object || Array.isArray(value)
624
623
  ? formData.append(key, JSON.stringify(value))
625
624
  : formData.append(key, value)
@@ -663,7 +662,7 @@ export function throttle(func, delay = 300) {
663
662
  /**
664
663
  * 数组去重
665
664
  * @param {Array} arr - 要去重的数组
666
- * @param {string} key - 对象去重的键(可选)
665
+ * @param {string} [key] - 对象去重的键(可选)
667
666
  * @returns {Array} 去重后的数组
668
667
  */
669
668
  export function uniqueArray(arr, key) {