@yh-kit/utils 1.15.1 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- const w = {
1
+ const m = {
2
2
  /**
3
3
  * 统计数组中某元素出现的次数:对于大型数组,手动循环的性能略优于 filter 和 reduce。
4
4
  * @param arr 数组
@@ -25,7 +25,7 @@ const w = {
25
25
  while (t !== -1);
26
26
  return r;
27
27
  }
28
- }, b = {
28
+ }, A = {
29
29
  // toEnumObj: handleArrTansferEnumObj,
30
30
  /**
31
31
  * 数组转枚举对象
@@ -41,7 +41,7 @@ const w = {
41
41
  t[r[n]] = o;
42
42
  }), t;
43
43
  }
44
- }, A = {
44
+ }, b = {
45
45
  /**
46
46
  * 判断某元素是否在存在于数组中(indexOf方法)
47
47
  * @param arr 数组
@@ -109,58 +109,194 @@ const w = {
109
109
  }
110
110
  }, M = {
111
111
  /**
112
- * 数组排序-默认升序
112
+ * 数组随机打乱-Fisher-Yates算法
113
113
  * @param arr 数组
114
- * @param order 排序方式:asc 升序;desc 降序
115
- * @returns 排序后的数组
114
+ * @returns 随机打乱后的数组
115
+ *
116
+ * 注意,这个算法会改变原数组。如果不想改变原数组,可以先复制一份再进行操作。
117
+ * 时间复杂度:O(n)
118
+ * 空间复杂度:O(1)
116
119
  */
117
- sort(e, n = "asc") {
118
- return e ? e.sort((t, r) => n === "asc" ? t > r ? 1 : -1 : t < r ? 1 : -1) : [];
120
+ shuffle(e) {
121
+ if (!e)
122
+ return [];
123
+ const n = [...e];
124
+ for (let t = n.length - 1; t > 0; t--) {
125
+ const r = Math.floor(Math.random() * (t + 1));
126
+ [n[t], n[r]] = [n[r], n[t]];
127
+ }
128
+ return n;
119
129
  },
120
130
  /**
121
- * 数组乱序(洗牌算法)
122
- * 1. 从数组的最后一个元素开始,将其与随机位置的元素交换位置。
123
- * 2. 然后,从倒数第二个元素开始,将其与随机位置的元素交换位置。
124
- * 3. 以此类推,直到第一个元素。
125
- * 4. 这样,数组中的元素就会被随机打乱顺序。
126
- * 5. 注意,这个算法会改变原数组。如果不想改变原数组,可以先复制一份再进行操作。
127
- * 6. 时间复杂度:O(n)
131
+ * 数组随机抽样-Fisher-Yates算法前k次迭代,再取前k个元素
128
132
  * @param arr 数组
129
- * @returns
133
+ * @param k 抽样次数
134
+ * @returns 抽样后的数组
130
135
  */
131
- shuffle(e) {
136
+ sample(e, n) {
132
137
  if (!e)
133
138
  return [];
134
- for (let n = e.length - 1; n > 0; n--) {
135
- const t = Math.floor(Math.random() * (n + 1));
136
- [e[n], e[t]] = [e[t], e[n]];
139
+ if (n <= 0 || n > e.length)
140
+ throw new Error("抽样次数必须在1次到数组长度之间");
141
+ const t = [...e];
142
+ for (let r = 0; r < n; r++) {
143
+ const o = Math.floor(Math.random() * (e.length - r));
144
+ [t[r], t[o]] = [t[o], t[r]];
137
145
  }
138
- return e;
146
+ return t.slice(0, n);
147
+ }
148
+ }, E = {
149
+ /**
150
+ * 数组排序-默认升序
151
+ * @param arr 数组
152
+ * @param order 排序方式:asc 升序;desc 降序
153
+ * @returns 排序后的数组
154
+ */
155
+ sort(e, n = "asc") {
156
+ return e ? e.sort((t, r) => n === "asc" ? t > r ? 1 : -1 : t < r ? 1 : -1) : [];
139
157
  }
140
158
  }, x = {
141
159
  /**
142
- * 数组去重
160
+ * 数组去重:针对简单类型数据s
161
+ * 性能 O(n)
143
162
  * @param arr 数组
144
163
  * @returns 去重后的数组
145
164
  */
146
165
  uniqueBySet(e) {
147
- return e ? Array.from(new Set(e)) : [];
166
+ if (!e)
167
+ throw new Error("数组不能为空");
168
+ const n = e;
169
+ return Array.from(new Set(n));
170
+ },
171
+ /**
172
+ * 双重循环之 filter + indexOf 数组去重:
173
+ * 此方法不能去重 NaN 值,也不能去重对象类型数据。
174
+ * 性能 O(n²),每次 indexOf 都是 O(n) 操作
175
+ * @param arr 数组
176
+ * @returns 去重后的数组
177
+ */
178
+ uniqueByFilter(e) {
179
+ if (!e)
180
+ throw new Error("数组不能为空");
181
+ return e.filter((t, r, o) => r === o.indexOf(t));
182
+ },
183
+ /**
184
+ * 双重循环之 reduce + includes 数组去重:
185
+ * 适用于基本类型数据(string、number、boolean),能去重 NaN 值,但不能去重对象类型数据。
186
+ * 性能 O(n²),每次 includes 都是 O(n) 操作
187
+ * @param arr 数组
188
+ * @returns 去重后的数组
189
+ */
190
+ uniqueByReduce(e) {
191
+ if (!e)
192
+ throw new Error("数组不能为空");
193
+ return e.reduce((t, r) => (t.includes(r) || t.push(r), t), []);
194
+ },
195
+ /**
196
+ * 双重循环之 forEach + includes 数组去重:
197
+ * 适用于基本类型数据(string、number、boolean),能去重 NaN 值,但不能去重对象类型数据。
198
+ * 性能 O(n²),每次 includes 都是 O(n) 操作
199
+ * @param arr 数组
200
+ * @returns 去重后的数组
201
+ */
202
+ uniqueByIncludes(e) {
203
+ if (!e)
204
+ throw new Error("数组不能为空");
205
+ const n = e, t = [];
206
+ return n.forEach((r) => {
207
+ t.includes(r) || t.push(r);
208
+ }), t;
209
+ },
210
+ /**
211
+ * 双重循环之 for + includes 数组去重:
212
+ * 适用于基本类型数据(string、number、boolean),能去重 NaN 值,但不能去重对象类型数据。
213
+ * 性能 O(n²),每次 includes 都是 O(n) 操作
214
+ * @param arr 数组
215
+ * @returns 去重后的数组
216
+ */
217
+ uniqueByFor(e) {
218
+ if (!e)
219
+ throw new Error("数组不能为空");
220
+ const n = e, t = [];
221
+ for (let r = 0; r < n.length; r++)
222
+ t.includes(n[r]) || t.push(n[r]);
223
+ return t;
224
+ },
225
+ /**
226
+ * Map + 根据指定键去重
227
+ * 适用类型 对象数组(通过指定键进行去重)
228
+ * 键值类型 支持 string、number、boolean、Symbol
229
+ * NaN 处理 ✅ 支持(Map 支持 NaN 作为键)
230
+ * 性能 O(n),Map 的 has 和 set 操作都是 O(1)
231
+ * @param arr 数组
232
+ * @param key 对象的键名
233
+ * @returns 去重后的数组
234
+ */
235
+ uniqueByKey(e, n) {
236
+ if (!e || !n)
237
+ throw new Error("数组不能为空或键名不能为空");
238
+ const t = e, r = /* @__PURE__ */ new Map();
239
+ return t.filter((o) => r.has(o[n]) ? !1 : (r.set(o[n], !0), !0));
240
+ },
241
+ /**
242
+ * 通用数组去重函数 - 根据选项自动选择去重策略
243
+ *
244
+ * @template T - 数组元素类型
245
+ * @param {T[]} _arr - 待去重的数组
246
+ * @param {TUniqueOptions<T>} [options={}] - 去重选项
247
+ * @param {(keyof T)[]} [options.keys] - 按指定键组合去重(适用于对象数组)
248
+ * @param {(a: T, b: T) => boolean} [options.compareFn] - 自定义比较函数
249
+ * @returns {T[]} 去重后的数组
250
+ *
251
+ * @example
252
+ * // 基本类型数组(默认使用 Set 去重)
253
+ * unique([1, 2, 2, 3, 1]); // [1, 2, 3]
254
+ *
255
+ * @example
256
+ * // 对象数组按多个键去重
257
+ * const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 1, name: 'Alice' }];
258
+ * unique(users, { keys: ['id', 'name'] }); // [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
259
+ *
260
+ * @example
261
+ * // 使用自定义比较函数
262
+ * unique(arr, { compareFn: (a, b) => a.x === b.x && a.y === b.y });
263
+ *
264
+ * @throws {Error} 当输入数组为空时抛出错误
265
+ */
266
+ unique(e, n = {}) {
267
+ const { keys: t, compareFn: r } = n;
268
+ if (!e)
269
+ throw new Error("数组不能为空");
270
+ const o = e;
271
+ if (!t && !r)
272
+ return this.uniqueBySet(o);
273
+ if (t) {
274
+ const s = /* @__PURE__ */ new Map();
275
+ return o.filter((c) => {
276
+ const l = t.map((i) => c[i]).join("|");
277
+ return s.has(l) ? !1 : (s.set(l, !0), !0);
278
+ });
279
+ }
280
+ if (r)
281
+ return o.filter((s, c, l) => c === l.findIndex((i) => r(s, i)));
148
282
  }
149
- }, E = {
283
+ }, B = {
150
284
  // 数组转对象
151
- ...b,
285
+ ...A,
152
286
  // 数组去重
153
287
  ...x,
154
288
  // 判断元素是否存在
155
- ...A,
289
+ ...b,
156
290
  // 数组排序
157
- ...M,
291
+ ...E,
158
292
  // 获取极值
159
293
  ...S,
160
294
  // 统计出现次数
161
- ...w
295
+ ...m,
296
+ // 数组随机打乱-Fisher-Yates算法
297
+ ...M
162
298
  };
163
- class I {
299
+ class k {
164
300
  /** Base64 编码表 */
165
301
  static BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
166
302
  /**
@@ -458,7 +594,7 @@ const C = {
458
594
  isMobile() {
459
595
  return /Mobi|Android|iPhone/i.test(navigator.userAgent);
460
596
  }
461
- }, k = {
597
+ }, H = {
462
598
  /**
463
599
  * 获取变量的类型
464
600
  * @param val 任意变量
@@ -467,7 +603,7 @@ const C = {
467
603
  getType(e) {
468
604
  return Object.prototype.toString.call(e).replace(/\[object\s(\w+)\]/, "$1");
469
605
  }
470
- }, H = {
606
+ }, $ = {
471
607
  /**
472
608
  * 通过传入的name获取cookie的值
473
609
  * @param name cookie的name
@@ -497,7 +633,7 @@ const C = {
497
633
  deleteCookie(e) {
498
634
  this.setCookie(e, "", -1);
499
635
  }
500
- }, $ = {
636
+ }, j = {
501
637
  /**
502
638
  * 获取当前时间字符串
503
639
  * @param locales 区域设置。如:'zh-CN','en-US',"chinese"。默认'zh-CN'。
@@ -570,10 +706,10 @@ const C = {
570
706
  else {
571
707
  const g = /* @__PURE__ */ new Date();
572
708
  g.setDate(g.getDate() - 1);
573
- const m = /* @__PURE__ */ new Date();
574
- if (m.setDate(m.getDate() - 2), i === g.getMonth() + 1 && h === g.getDate())
709
+ const w = /* @__PURE__ */ new Date();
710
+ if (w.setDate(w.getDate() - 2), i === g.getMonth() + 1 && h === g.getDate())
575
711
  a = "昨天" + u;
576
- else if (i === m.getMonth() + 1 && h === m.getDate())
712
+ else if (i === w.getMonth() + 1 && h === w.getDate())
577
713
  a = "前天" + u;
578
714
  else if (f / 36e5 <= 7 * 24) {
579
715
  const y = new Array(7);
@@ -612,7 +748,7 @@ const C = {
612
748
  new RegExp("(" + r + ")").test(n) && (n = n.replace(RegExp.$1, RegExp.$1.length === 1 ? t[r] : ("00" + t[r]).substr(("" + t[r]).length)));
613
749
  return n;
614
750
  }
615
- }, j = {
751
+ }, F = {
616
752
  /**
617
753
  * 获取元素相对于文档顶部的偏移量(距离)
618
754
  * 处理了SVG元素的特殊情况。
@@ -734,7 +870,7 @@ const C = {
734
870
  });
735
871
  });
736
872
  }
737
- }, F = {
873
+ }, q = {
738
874
  /**
739
875
  * 将选中的字母数组从A-Z排序:用于试题选择答案的排序实例
740
876
  * @param arr 字母数组
@@ -930,15 +1066,15 @@ const Y = {
930
1066
  }
931
1067
  return `${e.slice(0, c)}${"*".repeat(e.length - c)}`;
932
1068
  }
933
- }, B = (e) => e > 25 || e < 0 ? "" : "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[e], D = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1069
+ }, D = (e) => e > 25 || e < 0 ? "" : "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[e], R = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
934
1070
  __proto__: null,
935
- toLetter: B
936
- }, Symbol.toStringTag, { value: "Module" })), R = (e) => e.toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","), U = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1071
+ toLetter: D
1072
+ }, Symbol.toStringTag, { value: "Module" })), U = (e) => e.toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","), v = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
937
1073
  __proto__: null,
938
- toMoney: R
1074
+ toMoney: U
939
1075
  }, Symbol.toStringTag, { value: "Module" })), z = {
940
- ...D,
941
- ...U,
1076
+ ...R,
1077
+ ...v,
942
1078
  /**
943
1079
  * 判断是否为数字
944
1080
  * @param val 待判断的值
@@ -947,7 +1083,7 @@ const Y = {
947
1083
  isNumber(e) {
948
1084
  return typeof e == "number" && !isNaN(e);
949
1085
  }
950
- }, q = {
1086
+ }, Z = {
951
1087
  /**
952
1088
  * 判断对象是否为空
953
1089
  * @param obj 对象
@@ -978,7 +1114,7 @@ const Y = {
978
1114
  r instanceof Object ? (n[t] = {}, this.deepCopy(r, n[t])) : r instanceof Array ? (n[t] = [], this.deepCopy(r, n[t])) : n[t] = e[t];
979
1115
  }
980
1116
  }
981
- }, Z = {
1117
+ }, J = {
982
1118
  /**
983
1119
  * 脱敏
984
1120
  * @param phone 电话号码/手机号码
@@ -987,7 +1123,7 @@ const Y = {
987
1123
  desensitize(e) {
988
1124
  return e ? e.replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2") || e.slice(0, 3) + "****" + e.slice(7) : "";
989
1125
  }
990
- }, J = {
1126
+ }, X = {
991
1127
  /**
992
1128
  * 生成随机颜色
993
1129
  * @returns 随机颜色值
@@ -1011,7 +1147,7 @@ const Y = {
1011
1147
  uniqueId() {
1012
1148
  return Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
1013
1149
  }
1014
- }, X = {
1150
+ }, G = {
1015
1151
  /**
1016
1152
  * 验证手机号
1017
1153
  */
@@ -1048,7 +1184,7 @@ const Y = {
1048
1184
  * 验证0.01~0.99正则:最多两位小数。0.1、0.10、0.9、0.90
1049
1185
  */
1050
1186
  decimal: /^0\.(0[1-9]|[1-9][0-9]*)$/
1051
- }, G = {
1187
+ }, K = {
1052
1188
  /**
1053
1189
  * 通过key值获取 localStorage 中存储的某个值
1054
1190
  * @param key 获取的key
@@ -1178,19 +1314,19 @@ const Y = {
1178
1314
  throw new Error("开始位置小于0或结束位置超出字符串长度或开始位置大于结束位置");
1179
1315
  return e.slice(0, n) + "*".repeat(t - n + 1) + e.slice(t);
1180
1316
  }
1181
- }, v = (e) => {
1317
+ }, O = (e) => {
1182
1318
  const t = new RegExp("[?&]" + e + "=([^&#]*)", "gi").exec(window.location.href);
1183
1319
  return t ? decodeURIComponent(t[1]) : null;
1184
1320
  };
1185
1321
  function L(e) {
1186
1322
  return new URLSearchParams(window.location.search).get(e);
1187
1323
  }
1188
- const O = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1324
+ const T = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1189
1325
  __proto__: null,
1190
- getQueryInfoByName: v,
1326
+ getQueryInfoByName: O,
1191
1327
  getQueryParam: L
1192
- }, Symbol.toStringTag, { value: "Module" })), K = {
1193
- ...O,
1328
+ }, Symbol.toStringTag, { value: "Module" })), ee = {
1329
+ ...T,
1194
1330
  /**
1195
1331
  * 获取当前域名
1196
1332
  * @returns 当前url链接的host信息
@@ -1205,7 +1341,7 @@ const O = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1205
1341
  getPath() {
1206
1342
  return window.location.pathname;
1207
1343
  }
1208
- }, ee = {
1344
+ }, te = {
1209
1345
  /**
1210
1346
  * 处理瀑布流数据,使其竖向瀑布流布局呈现横向瀑布流的展现形式。适用于 column-gap: 20rpx; column-count: 2; 布局的瀑布流
1211
1347
  * @param list 瀑布流数据-数组
@@ -1236,33 +1372,33 @@ const O = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1236
1372
  if (i < s)
1237
1373
  a.style.left = (o + c) * i + "px", l[i] = a.offsetHeight;
1238
1374
  else {
1239
- const { index: u, value: d } = E.getMinValueAndIndex(l);
1375
+ const { index: u, value: d } = B.getMinValueAndIndex(l);
1240
1376
  a.style.left = (o + c) * u + "px", a.style.top = d + t + "px", l[u] = a.offsetHeight + t + d;
1241
1377
  }
1242
1378
  }
1243
1379
  }
1244
1380
  };
1245
1381
  export {
1246
- I as Base64Utils,
1382
+ k as Base64Utils,
1247
1383
  W as MoneyFormatter,
1248
- E as arrayUtils,
1384
+ B as arrayUtils,
1249
1385
  C as booleanUtils,
1250
- k as commonUtils,
1251
- H as cookieUtils,
1252
- $ as dateUtils,
1253
- j as documentUtils,
1386
+ H as commonUtils,
1387
+ $ as cookieUtils,
1388
+ j as dateUtils,
1389
+ F as documentUtils,
1254
1390
  N as downloadUtils,
1255
1391
  P as echartsUtils,
1256
- F as letterUtils,
1392
+ q as letterUtils,
1257
1393
  V as mapUtils,
1258
1394
  Y as nameUtils,
1259
1395
  z as numberUtils,
1260
- q as objectUtils,
1261
- Z as phoneUtils,
1262
- J as randomUtils,
1263
- X as regexpUtils,
1264
- G as storageUtils,
1396
+ Z as objectUtils,
1397
+ J as phoneUtils,
1398
+ X as randomUtils,
1399
+ G as regexpUtils,
1400
+ K as storageUtils,
1265
1401
  Q as stringUtils,
1266
- K as urlUtils,
1267
- ee as waterfallUtils
1402
+ ee as urlUtils,
1403
+ te as waterfallUtils
1268
1404
  };
@@ -1 +1 @@
1
- (function(h,w){typeof exports=="object"&&typeof module<"u"?w(exports):typeof define=="function"&&define.amd?define(["exports"],w):(h=typeof globalThis<"u"?globalThis:h||self,w(h.yhkitUtils={}))})(this,function(h){"use strict";const A={...{toEnumObj(e,n="value"){if(!e||!e.length)return{};const t={};return e.forEach(r=>{const o=Object.assign({label:r.label,text:r.label},r);t[r[n]]=o}),t}},...{uniqueBySet(e){return e?Array.from(new Set(e)):[]}},...{isExistByIndexOf(e,n){return!e||!n?!1:e.indexOf(n)!==-1},isExistByIncludes(e,n){return!e||!n?!1:e.includes(n)}},...{sort(e,n="asc"){return e?e.sort((t,r)=>n==="asc"?t>r?1:-1:t<r?1:-1):[]},shuffle(e){if(!e)return[];for(let n=e.length-1;n>0;n--){const t=Math.floor(Math.random()*(n+1));[e[n],e[t]]=[e[t],e[n]]}return e}},...{getMaxValue(e){return e?Math.max(...e):0},getMinValue(e){return e?Math.min(...e):0},getMinValueAndIndex(e){if(e.length===0)return{value:0,index:0};const n={value:e[0],index:0};for(let t=1,r=e.length;t<r;t++){const o=e[t];n.value>o&&(n.value=o,n.index=t)}return n},getMaxValueAndIndex(e){return e.length===0?{value:0,index:0}:e.reduce((n,t,r)=>t<n.value?{value:t,index:r}:n,{value:e[0],index:0})}},...{countOfAppear(e,n){let t=0;for(const r of e)r===n&&t++;return t},indexsOfAppear(e,n){let t=-1;const r=[];do t=e.indexOf(n,t+1),t!==-1&&r.push(t);while(t!==-1);return r}}};class M{static BASE64_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";static toBlob(n,t="",r=512){const s=(n.split(",")[1]||n).replace(/-/g,"+").replace(/_/g,"/"),c="=".repeat((4-s.length%4)%4),l=s+c;try{const i=atob(l),d=[];for(let a=0;a<i.length;a+=r){const u=i.slice(a,a+r),f=new Array(u.length);for(let g=0;g<u.length;g++)f[g]=u.charCodeAt(g);const p=new Uint8Array(f);d.push(p)}return new Blob(d,{type:t})}catch(i){return console.error("Failed to convert base64 to blob:",i),null}}static toFile(n,t="file.txt",r="text/plain"){const s=n.replace(/^data:.+;base64,/,"").replace(/-/g,"+").replace(/_/g,"/"),c="=".repeat((4-s.length%4)%4),l=s+c,i=atob(l),d=[];for(let u=0;u<i.length;u+=512){const f=i.slice(u,u+512),p=new Array(f.length);for(let g=0;g<f.length;g++)p[g]=f.charCodeAt(g);d.push(new Uint8Array(p))}const a=new Blob(d,{type:r});return new File([a],t,{type:r})}static encode(n){if(!n)return"";const t=this._stringToUtf8Bytes(n);return this._bytesToBase64(t)}static decode(n){if(!n)return"";n=n.replace(/\s/g,"");const t=this._base64ToBytes(n);return this._utf8BytesToString(t)}static _stringToUtf8Bytes(n){const t=[];for(let r=0;r<n.length;r++){let o=n.charCodeAt(r);if(o<128)t.push(o);else if(o<2048)t.push(192|o>>6),t.push(128|o&63);else if(o<55296||o>=57344)t.push(224|o>>12),t.push(128|o>>6&63),t.push(128|o&63);else{r++;const s=o,c=n.charCodeAt(r);if(isNaN(c))throw new Error("代理对不完整");o=65536+((s&1023)<<10)+(c&1023),t.push(240|o>>18),t.push(128|o>>12&63),t.push(128|o>>6&63),t.push(128|o&63)}}return t}static _utf8BytesToString(n){let t="",r=0;for(;r<n.length;){const o=n[r++];if(o<128)t+=String.fromCharCode(o);else if(o>=192&&o<224){const s=n[r++]&63;t+=String.fromCharCode((o&31)<<6|s)}else if(o>=224&&o<240){const s=n[r++]&63,c=n[r++]&63;t+=String.fromCharCode((o&15)<<12|s<<6|c)}else if(o>=240&&o<248){const s=n[r++]&63,c=n[r++]&63,l=n[r++]&63,i=(o&7)<<18|s<<12|c<<6|l,d=Math.floor((i-65536)/1024)+55296,a=(i-65536)%1024+56320;t+=String.fromCharCode(d,a)}else t+="�"}return t}static _bytesToBase64(n){let t="",r=0;for(;r<n.length;){const o=n[r++],s=r<n.length,c=s?n[r++]:0,l=r<n.length,i=l?n[r++]:0,d=o>>2,a=(o&3)<<4|c>>4,u=(c&15)<<2|i>>6,f=i&63;s?l?t+=this.BASE64_CHARS.charAt(d)+this.BASE64_CHARS.charAt(a)+this.BASE64_CHARS.charAt(u)+this.BASE64_CHARS.charAt(f):t+=this.BASE64_CHARS.charAt(d)+this.BASE64_CHARS.charAt(a)+this.BASE64_CHARS.charAt(u)+"=":t+=this.BASE64_CHARS.charAt(d)+this.BASE64_CHARS.charAt(a)+"=="}return t}static _base64ToBytes(n){const t=n.length;let r=0;t>=2&&(n[t-1]==="="&&r++,n[t-2]==="="&&r++);const o=Math.floor(t*3/4)-r,s=new Array(o),c=new Array(256).fill(-1);for(let d=0;d<this.BASE64_CHARS.length;d++)c[this.BASE64_CHARS.charCodeAt(d)]=d;let l=0,i=0;for(;i<t;){const d=c[n.charCodeAt(i++)],a=c[n.charCodeAt(i++)],u=i<t?c[n.charCodeAt(i++)]:-1,f=i<t?c[n.charCodeAt(i++)]:-1;if(d===-1||a===-1)throw new Error("无效的 Base64 字符");const p=d<<2|a>>4;if(s[l++]=p,u!==-1){const g=(a&15)<<4|u>>2;if(s[l++]=g,f!==-1){const y=(u&3)<<6|f;s[l++]=y}}}return s}}const S={isEmptyString(e){return typeof e=="string"&&e.trim()===""},isNumber(e){return typeof e=="number"&&!isNaN(e)},isObject(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)},isEmptyObject(e){return e?Object.keys(e).length===0&&e.constructor===Object:!0},isBoolean(e){return typeof e=="boolean"},isArray(e){return Array.isArray(e)},isFunction(e){return typeof e=="function"},isPromise(e){return!!e&&(typeof e=="object"||typeof e=="function")&&typeof e.then=="function"},isElement(e){return e instanceof Element},isPhone(e){return/^1[3-9]\d{9}$/.test(e)},isEmail(e){return/^[\w.-]+@[\w.-]+\.\w+$/.test(e)},isJSON(e){try{return JSON.parse(e),!0}catch{return!1}},isImageLoaded(e){return e.complete&&e.naturalWidth!==0},isInViewport(e){const n=e.getBoundingClientRect();return n.top>=0&&n.left>=0&&n.bottom<=window.innerHeight&&n.right<=window.innerWidth},isLeapYear(e){return e%4===0&&e%100!==0||e%400===0},isMobile(){return/Mobi|Android|iPhone/i.test(navigator.userAgent)}},U={getType(e){return Object.prototype.toString.call(e).replace(/\[object\s(\w+)\]/,"$1")}},E={getCookie(e){if(!e)return;const n=document.cookie.match(new RegExp("(^| )"+e+"=([^;]+)"));return n?decodeURIComponent(n[2]):null},setCookie(e,n,t=7){const r=new Date;r.setTime(r.getTime()+t*24*60*60*1e3),document.cookie=`${e}=${encodeURIComponent(n)};expires=${r.toUTCString()};path=/`},deleteCookie(e){this.setCookie(e,"",-1)}},B={getTimeString(e,n=!1){return n?new Date().toLocaleString(e,{hour12:!0}):new Date().toLocaleString("chinese",{hour12:!1})},diffDays(e,n){const t=new Date(e).getTime(),r=new Date(n).getTime();return t>r?Math.abs(Math.floor((t-r)/(24*3600*1e3))):Math.abs(Math.floor((r-t)/(24*3600*1e3)))},uniqueId(){return Date.now().toString(36)+Math.random().toString(36).substr(2,5)},getWhichDays(e,n,t){let r=t;for(let o=1;o<n;o++)switch(o){case 1:case 3:case 5:case 7:case 8:case 10:case 12:r+=31;break;case 2:S.isLeapYear(e)?r+=29:r+=28;break;default:r+=30;break}return r},getTimeStringAutoShort2(e,n){const t=new Date,r=new Date(e),o=t.getFullYear(),s=t.getMonth()+1,c=t.getDate(),l=r.getFullYear(),i=r.getMonth()+1,d=r.getDate();let a="";const u=n?" "+this.formatDate(r,"hh:mm"):"";if(o===l){const g=t.getTime()-e;if(s===i&&c===d)g<60*1e3?a="刚刚":a=this.formatDate(r,"hh:mm");else{const y=new Date;y.setDate(y.getDate()-1);const b=new Date;if(b.setDate(b.getDate()-2),i===y.getMonth()+1&&d===y.getDate())a="昨天"+u;else if(i===b.getMonth()+1&&d===b.getDate())a="前天"+u;else if(g/36e5<=7*24){const m=new Array(7);m[0]="星期日",m[1]="星期一",m[2]="星期二",m[3]="星期三",m[4]="星期四",m[5]="星期五",m[6]="星期六",a=m[r.getDay()]+u}else a=this.formatDate(r,"yyyy/M/d")+u}}else a=this.formatDate(r,"yyyy/M/d")+u;return a},formatDate(e,n){const t={"M+":e.getMonth()+1,"d+":e.getDate(),"h+":e.getHours(),"m+":e.getMinutes(),"s+":e.getSeconds(),"q+":Math.floor((e.getMonth()+3)/3),S:e.getMilliseconds()};/(y+)/.test(n)&&(n=n.replace(RegExp.$1,(e.getFullYear()+"").substr(4-RegExp.$1.length)));for(const r in t)new RegExp("("+r+")").test(n)&&(n=n.replace(RegExp.$1,RegExp.$1.length===1?t[r]:("00"+t[r]).substr((""+t[r]).length)));return n}},C={getOffsetTop(e){if(!e)throw new Error("Element is not provided");if(e instanceof SVGElement){const t=e.getBoundingClientRect(),r=window.pageYOffset||document.documentElement.scrollTop;return t.top+r}let n=0;for(;e;)n+=e.offsetTop,e=e.offsetParent;return n},getScrollValue(){const e={scrollLeft:0,scrollTop:0};return e.scrollLeft=document.body.scrollLeft||document.documentElement.scrollLeft,e.scrollTop=document.body.scrollTop||document.documentElement.scrollTop,e},getPageValue(e){e=e||window.event;const n=e.pageX||e.clientX+this.getScrollValue().scrollLeft,t=e.pageY||e.clientY+this.getScrollValue().scrollTop;return{pageX:n,pageY:t}},addEventListener(e,n,t){e.addEventListener?e.addEventListener(n,t):e.attachEvent?e.attachEvent("on"+n,t):e["on"+n]=t},getViewportWidth(){return window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth},getViewportHeight(){return window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight}},x={saveAsBlob(e,n){const t=document.createElement("a"),r=window.URL.createObjectURL(e);t.href=r,t.download=n,document.body.appendChild(t),t.click(),URL.revokeObjectURL(r),document.body.removeChild(t)},saveAsUrl(e,n){const t=document.createElement("a");t.href=e,t.download=n,document.body.appendChild(t),t.click(),URL.revokeObjectURL(e),document.body.removeChild(t)}},D={animate(e,n){let t=-1;const r=e.series[0].data.length;let o;o=setInterval(()=>{n.dispatchAction({type:"downplay",seriesIndex:0,dataIndex:t}),t=(t+1)%r,n.dispatchAction({type:"highlight",seriesIndex:0,dataIndex:t}),n.dispatchAction({type:"showTip",seriesIndex:0,dataIndex:t}),t>r&&(t=0)},2e3),n.on("mouseover",()=>{clearInterval(o),n.dispatchAction({type:"downplay",seriesIndex:0,dataIndex:t})})}},R={sortFromA2Z(e){return e?.length?e.sort((t,r)=>{const o=t.toUpperCase(),s=r.toUpperCase();return o<s?-1:o>s?1:0}):void 0}},v={degrees2Radians(e){return e*Math.PI/180},getDistance(e,n,t,r){const o=this.degrees2Radians(e),s=this.degrees2Radians(t),c=o-s,l=this.degrees2Radians(n)-this.degrees2Radians(r);let i=2*Math.asin(Math.sqrt(Math.pow(Math.sin(c/2),2)+Math.cos(o)*Math.cos(s)*Math.pow(Math.sin(l/2),2)));return i=i*6378.137,i=Math.round(i*1e4)/1e4,i=+i.toFixed(2),console.log("经纬度计算的距离为:"+i),i},calculateDistanceByHaversine(e,n,t="km"){const r=this,o=e.longitude??e.lng,s=e.latitude??e.lat,c=n.longitude??n.lng,l=n.latitude??n.lat;if(o===void 0||s===void 0||c===void 0||l===void 0)throw new Error("无效的坐标格式,缺少经纬度信息");const i=6371,d=r.degrees2Radians(s),a=r.degrees2Radians(l),u=r.degrees2Radians(l-s),f=r.degrees2Radians(c-o),p=Math.sin(u/2)*Math.sin(u/2)+Math.cos(d)*Math.cos(a)*Math.sin(f/2)*Math.sin(f/2),g=2*Math.atan2(Math.sqrt(p),Math.sqrt(1-p)),y=i*g;switch(t){case"m":return y*1e3;case"mi":return y*.621371;case"nmi":return y*.539957;default:return y}},calculateDistancesByHaversine(e,n="km",t=!1){if(e.length<2)return{segments:[],total:0};const r=[];let o=0;for(let s=0;s<e.length-1;s++){const c=this.calculateDistanceByHaversine(e[s],e[s+1],n);r.push(c),o+=c}if(t&&e.length>2){const s=this.calculateDistanceByHaversine(e[e.length-1],e[0],n);r.push(s),o+=s}return{segments:r,total:o}}};class T{static toStandardFormat(n){try{const t=typeof n=="string"?parseFloat(n):n;if(isNaN(t))throw new Error("输入不是有效的数字");if(!isFinite(t))throw new Error("输入是无穷大");return t.toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")}catch(t){return console.error("格式化失败:",t),"格式错误"}}static toChineseFormat(n){try{const t=typeof n=="string"?parseFloat(n):n;if(isNaN(t))throw new Error("输入不是有效的数字");if(t>9999999999999e-2||t<-9999999999999e-2)throw new Error("输入数字超出范围");const r=t<0,o=Math.abs(t),s=Math.floor(o),c=Math.round((o-s)*100),l=["零","壹","贰","叁","肆","伍","陆","柒","捌","玖"],i=["","拾","佰","仟","万","拾","佰","仟","亿","拾","佰","仟"],d=["角","分"];let a="",u=s;if(u===0)a=l[0];else{let g=0;for(;u>0;){const y=u%10;y!==0?a=l[y]+i[g]+a:a.charAt(0)!==l[0]&&(a=l[y]+a),u=Math.floor(u/10),g++}a=a.replace(/零+/g,"零"),a=a.replace(/零+$/,"")}let f="";if(c>0){const g=Math.floor(c/10),y=c%10;g>0&&(f+=l[g]+d[0]),y>0&&(f+=l[y]+d[1])}else f="整";let p=(r?"负":"")+a+"圆"+f;return p==="零圆整"&&(p="零圆"),p}catch(t){return console.error("转换失败:",t),"格式错误"}}}const L={desensitizeChineseName(e,n={}){const{keepLength:t=1,keepLast:r=!1}=n;if(!e||e.length===0||e.trim().length===0)throw new Error("姓名不能为空");if(typeof e!="string")throw new Error("姓名必须是字符串");if(e.length<=1)return e;const o=["欧阳","司马","上官","东方","独孤","南宫","闻人","夏侯","诸葛","尉迟","公孙","长孙","宇文","司徒","慕容"];n.compoundSurname&&n.compoundSurname.trim().length>0&&!o.includes(n.compoundSurname)&&o.push(n.compoundSurname);let s="";o.some(l=>e.startsWith(l))?s=o.find(l=>e.startsWith(l))||"":s=e[0]||"";const c=Math.max(t,s.length);if(c>=e.length)return e;if(r&&e.length>2){const l=e.slice(0,c),i=e.slice(-1),d=e.length-c-1;return`${l}${"*".repeat(d)}${i}`}return`${e.slice(0,c)}${"*".repeat(e.length-c)}`}},O={...Object.freeze(Object.defineProperty({__proto__:null,toLetter:e=>e>25||e<0?"":"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[e]},Symbol.toStringTag,{value:"Module"})),...Object.freeze(Object.defineProperty({__proto__:null,toMoney:e=>e.toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")},Symbol.toStringTag,{value:"Module"})),isNumber(e){return typeof e=="number"&&!isNaN(e)}},_={isEmptyObject(e){return!e||JSON.stringify(e)==="{}"?!0:Object.keys(e).length===0&&e.constructor===Object},copy(e,n){for(const t in e)n[t]=e[t]},deepCopy(e,n){for(const t in e){const r=e[t];r instanceof Object?(n[t]={},this.deepCopy(r,n[t])):r instanceof Array?(n[t]=[],this.deepCopy(r,n[t])):n[t]=e[t]}}},I={desensitize(e){return e?e.replace(/^(\d{3})\d{4}(\d{4})$/,"$1****$2")||e.slice(0,3)+"****"+e.slice(7):""}},k={color:function(){return`#${Math.random().toString(16).slice(2,8)}`},int(e,n){return Math.floor(Math.random()*(n-e+1))+e},uniqueId(){return Date.now().toString(36)+Math.random().toString(36).substr(2,5)}},j={mobile:/^1[3-9]\d{9}$/,email:/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,chinese:/^[\u4e00-\u9fa5]+$/,english:/^[a-zA-Z]+$/,chineseStart:/^[\u4e00-\u9fa5]+\w*$/,integer:/^\d+$/,integerAndzero:/^(0|[1-9]+[0-9]*)$/,strongPassword:/^(?!.*[\s\p{C}])(?:(?=.*[A-Z])(?=.*[a-z])(?=.*[\d\W])|(?=.*\d)(?=.*[^\w\s])).{8,}$/u,decimal:/^0\.(0[1-9]|[1-9][0-9]*)$/},H={getLocal(e){return localStorage.getItem(e)},setLocal(e,n){localStorage.setItem(e,n)},removeLocal(e){localStorage.removeItem(e)},getSession(e){return sessionStorage.getItem(e)},setSession(e,n){sessionStorage.setItem(e,n)},removeSession(e){sessionStorage.removeItem(e)}},$={isExist(e,n){if(!e||!n)return!1;const t=e.split(",");return console.log("判断某元素是否在字符串中",t.indexOf(n)===-1),t.indexOf(n)!==-1},includes(e,n){return!e||!n?!1:e.includes(n)},isJSON(e){try{return JSON.parse(e),!0}catch{return!1}},indexsOfAppear(e,n){let t=-1;const r=[];do t=e.indexOf(n,t+1),t!==-1&&r.push(t);while(t!==-1);return r},getMaxTimesAndVal(e){const n=[0,""],t={};for(let s=0;s<e.length;s++){const c=e.charAt(s);t[c]?t[c]++:t[c]=1}let r=1;for(const s in t)r<t[s]&&(r=t[s]);const o=[];for(const s in t)r==t[s]&&o.push(s);return n[0]=r,n[1]=o.join(),n},mask(e,n,t){if(!e)throw new Error("字符串为空");if(typeof n!="number"||typeof t!="number")throw new Error("开始位置或结束位置为空");if(n<0||t>e.length||n>t)throw new Error("开始位置小于0或结束位置超出字符串长度或开始位置大于结束位置");return e.slice(0,n)+"*".repeat(t-n+1)+e.slice(t)}},N=e=>{const t=new RegExp("[?&]"+e+"=([^&#]*)","gi").exec(window.location.href);return t?decodeURIComponent(t[1]):null};function P(e){return new URLSearchParams(window.location.search).get(e)}const F={...Object.freeze(Object.defineProperty({__proto__:null,getQueryInfoByName:N,getQueryParam:P},Symbol.toStringTag,{value:"Module"})),getHost(){return window.location.host},getPath(){return window.location.pathname}},V={toList(e,n=2){console.log(e,n);const t={};for(let o=0;o<n;o++)t[o]=[];e.forEach((o,s)=>t[s%n].push(o));const r=[];for(const o in t)r.push(...t[o]);return r},jsLayout(e,n,t){const r=e.offsetWidth,o=n[0].offsetWidth,s=parseInt((r/o).toString()),c=(r-o*s)/(s-1),l=[];for(let i=0,d=n.length;i<d;i++){const a=n[i];if(i<s)a.style.left=(o+c)*i+"px",l[i]=a.offsetHeight;else{const{index:u,value:f}=A.getMinValueAndIndex(l);a.style.left=(o+c)*u+"px",a.style.top=f+t+"px",l[u]=a.offsetHeight+t+f}}}};h.Base64Utils=M,h.MoneyFormatter=T,h.arrayUtils=A,h.booleanUtils=S,h.commonUtils=U,h.cookieUtils=E,h.dateUtils=B,h.documentUtils=C,h.downloadUtils=x,h.echartsUtils=D,h.letterUtils=R,h.mapUtils=v,h.nameUtils=L,h.numberUtils=O,h.objectUtils=_,h.phoneUtils=I,h.randomUtils=k,h.regexpUtils=j,h.storageUtils=H,h.stringUtils=$,h.urlUtils=F,h.waterfallUtils=V,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})});
1
+ (function(d,w){typeof exports=="object"&&typeof module<"u"?w(exports):typeof define=="function"&&define.amd?define(["exports"],w):(d=typeof globalThis<"u"?globalThis:d||self,w(d.yhkitUtils={}))})(this,function(d){"use strict";const A={...{toEnumObj(e,n="value"){if(!e||!e.length)return{};const t={};return e.forEach(r=>{const o=Object.assign({label:r.label,text:r.label},r);t[r[n]]=o}),t}},...{uniqueBySet(e){if(!e)throw new Error("数组不能为空");const n=e;return Array.from(new Set(n))},uniqueByFilter(e){if(!e)throw new Error("数组不能为空");return e.filter((t,r,o)=>r===o.indexOf(t))},uniqueByReduce(e){if(!e)throw new Error("数组不能为空");return e.reduce((t,r)=>(t.includes(r)||t.push(r),t),[])},uniqueByIncludes(e){if(!e)throw new Error("数组不能为空");const n=e,t=[];return n.forEach(r=>{t.includes(r)||t.push(r)}),t},uniqueByFor(e){if(!e)throw new Error("数组不能为空");const n=e,t=[];for(let r=0;r<n.length;r++)t.includes(n[r])||t.push(n[r]);return t},uniqueByKey(e,n){if(!e||!n)throw new Error("数组不能为空或键名不能为空");const t=e,r=new Map;return t.filter(o=>r.has(o[n])?!1:(r.set(o[n],!0),!0))},unique(e,n={}){const{keys:t,compareFn:r}=n;if(!e)throw new Error("数组不能为空");const o=e;if(!t&&!r)return this.uniqueBySet(o);if(t){const s=new Map;return o.filter(c=>{const l=t.map(i=>c[i]).join("|");return s.has(l)?!1:(s.set(l,!0),!0)})}if(r)return o.filter((s,c,l)=>c===l.findIndex(i=>r(s,i)))}},...{isExistByIndexOf(e,n){return!e||!n?!1:e.indexOf(n)!==-1},isExistByIncludes(e,n){return!e||!n?!1:e.includes(n)}},...{sort(e,n="asc"){return e?e.sort((t,r)=>n==="asc"?t>r?1:-1:t<r?1:-1):[]}},...{getMaxValue(e){return e?Math.max(...e):0},getMinValue(e){return e?Math.min(...e):0},getMinValueAndIndex(e){if(e.length===0)return{value:0,index:0};const n={value:e[0],index:0};for(let t=1,r=e.length;t<r;t++){const o=e[t];n.value>o&&(n.value=o,n.index=t)}return n},getMaxValueAndIndex(e){return e.length===0?{value:0,index:0}:e.reduce((n,t,r)=>t<n.value?{value:t,index:r}:n,{value:e[0],index:0})}},...{countOfAppear(e,n){let t=0;for(const r of e)r===n&&t++;return t},indexsOfAppear(e,n){let t=-1;const r=[];do t=e.indexOf(n,t+1),t!==-1&&r.push(t);while(t!==-1);return r}},...{shuffle(e){if(!e)return[];const n=[...e];for(let t=n.length-1;t>0;t--){const r=Math.floor(Math.random()*(t+1));[n[t],n[r]]=[n[r],n[t]]}return n},sample(e,n){if(!e)return[];if(n<=0||n>e.length)throw new Error("抽样次数必须在1次到数组长度之间");const t=[...e];for(let r=0;r<n;r++){const o=Math.floor(Math.random()*(e.length-r));[t[r],t[o]]=[t[o],t[r]]}return t.slice(0,n)}}};class M{static BASE64_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";static toBlob(n,t="",r=512){const s=(n.split(",")[1]||n).replace(/-/g,"+").replace(/_/g,"/"),c="=".repeat((4-s.length%4)%4),l=s+c;try{const i=atob(l),h=[];for(let a=0;a<i.length;a+=r){const u=i.slice(a,a+r),f=new Array(u.length);for(let g=0;g<u.length;g++)f[g]=u.charCodeAt(g);const y=new Uint8Array(f);h.push(y)}return new Blob(h,{type:t})}catch(i){return console.error("Failed to convert base64 to blob:",i),null}}static toFile(n,t="file.txt",r="text/plain"){const s=n.replace(/^data:.+;base64,/,"").replace(/-/g,"+").replace(/_/g,"/"),c="=".repeat((4-s.length%4)%4),l=s+c,i=atob(l),h=[];for(let u=0;u<i.length;u+=512){const f=i.slice(u,u+512),y=new Array(f.length);for(let g=0;g<f.length;g++)y[g]=f.charCodeAt(g);h.push(new Uint8Array(y))}const a=new Blob(h,{type:r});return new File([a],t,{type:r})}static encode(n){if(!n)return"";const t=this._stringToUtf8Bytes(n);return this._bytesToBase64(t)}static decode(n){if(!n)return"";n=n.replace(/\s/g,"");const t=this._base64ToBytes(n);return this._utf8BytesToString(t)}static _stringToUtf8Bytes(n){const t=[];for(let r=0;r<n.length;r++){let o=n.charCodeAt(r);if(o<128)t.push(o);else if(o<2048)t.push(192|o>>6),t.push(128|o&63);else if(o<55296||o>=57344)t.push(224|o>>12),t.push(128|o>>6&63),t.push(128|o&63);else{r++;const s=o,c=n.charCodeAt(r);if(isNaN(c))throw new Error("代理对不完整");o=65536+((s&1023)<<10)+(c&1023),t.push(240|o>>18),t.push(128|o>>12&63),t.push(128|o>>6&63),t.push(128|o&63)}}return t}static _utf8BytesToString(n){let t="",r=0;for(;r<n.length;){const o=n[r++];if(o<128)t+=String.fromCharCode(o);else if(o>=192&&o<224){const s=n[r++]&63;t+=String.fromCharCode((o&31)<<6|s)}else if(o>=224&&o<240){const s=n[r++]&63,c=n[r++]&63;t+=String.fromCharCode((o&15)<<12|s<<6|c)}else if(o>=240&&o<248){const s=n[r++]&63,c=n[r++]&63,l=n[r++]&63,i=(o&7)<<18|s<<12|c<<6|l,h=Math.floor((i-65536)/1024)+55296,a=(i-65536)%1024+56320;t+=String.fromCharCode(h,a)}else t+="�"}return t}static _bytesToBase64(n){let t="",r=0;for(;r<n.length;){const o=n[r++],s=r<n.length,c=s?n[r++]:0,l=r<n.length,i=l?n[r++]:0,h=o>>2,a=(o&3)<<4|c>>4,u=(c&15)<<2|i>>6,f=i&63;s?l?t+=this.BASE64_CHARS.charAt(h)+this.BASE64_CHARS.charAt(a)+this.BASE64_CHARS.charAt(u)+this.BASE64_CHARS.charAt(f):t+=this.BASE64_CHARS.charAt(h)+this.BASE64_CHARS.charAt(a)+this.BASE64_CHARS.charAt(u)+"=":t+=this.BASE64_CHARS.charAt(h)+this.BASE64_CHARS.charAt(a)+"=="}return t}static _base64ToBytes(n){const t=n.length;let r=0;t>=2&&(n[t-1]==="="&&r++,n[t-2]==="="&&r++);const o=Math.floor(t*3/4)-r,s=new Array(o),c=new Array(256).fill(-1);for(let h=0;h<this.BASE64_CHARS.length;h++)c[this.BASE64_CHARS.charCodeAt(h)]=h;let l=0,i=0;for(;i<t;){const h=c[n.charCodeAt(i++)],a=c[n.charCodeAt(i++)],u=i<t?c[n.charCodeAt(i++)]:-1,f=i<t?c[n.charCodeAt(i++)]:-1;if(h===-1||a===-1)throw new Error("无效的 Base64 字符");const y=h<<2|a>>4;if(s[l++]=y,u!==-1){const g=(a&15)<<4|u>>2;if(s[l++]=g,f!==-1){const p=(u&3)<<6|f;s[l++]=p}}}return s}}const S={isEmptyString(e){return typeof e=="string"&&e.trim()===""},isNumber(e){return typeof e=="number"&&!isNaN(e)},isObject(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)},isEmptyObject(e){return e?Object.keys(e).length===0&&e.constructor===Object:!0},isBoolean(e){return typeof e=="boolean"},isArray(e){return Array.isArray(e)},isFunction(e){return typeof e=="function"},isPromise(e){return!!e&&(typeof e=="object"||typeof e=="function")&&typeof e.then=="function"},isElement(e){return e instanceof Element},isPhone(e){return/^1[3-9]\d{9}$/.test(e)},isEmail(e){return/^[\w.-]+@[\w.-]+\.\w+$/.test(e)},isJSON(e){try{return JSON.parse(e),!0}catch{return!1}},isImageLoaded(e){return e.complete&&e.naturalWidth!==0},isInViewport(e){const n=e.getBoundingClientRect();return n.top>=0&&n.left>=0&&n.bottom<=window.innerHeight&&n.right<=window.innerWidth},isLeapYear(e){return e%4===0&&e%100!==0||e%400===0},isMobile(){return/Mobi|Android|iPhone/i.test(navigator.userAgent)}},E={getType(e){return Object.prototype.toString.call(e).replace(/\[object\s(\w+)\]/,"$1")}},U={getCookie(e){if(!e)return;const n=document.cookie.match(new RegExp("(^| )"+e+"=([^;]+)"));return n?decodeURIComponent(n[2]):null},setCookie(e,n,t=7){const r=new Date;r.setTime(r.getTime()+t*24*60*60*1e3),document.cookie=`${e}=${encodeURIComponent(n)};expires=${r.toUTCString()};path=/`},deleteCookie(e){this.setCookie(e,"",-1)}},B={getTimeString(e,n=!1){return n?new Date().toLocaleString(e,{hour12:!0}):new Date().toLocaleString("chinese",{hour12:!1})},diffDays(e,n){const t=new Date(e).getTime(),r=new Date(n).getTime();return t>r?Math.abs(Math.floor((t-r)/(24*3600*1e3))):Math.abs(Math.floor((r-t)/(24*3600*1e3)))},uniqueId(){return Date.now().toString(36)+Math.random().toString(36).substr(2,5)},getWhichDays(e,n,t){let r=t;for(let o=1;o<n;o++)switch(o){case 1:case 3:case 5:case 7:case 8:case 10:case 12:r+=31;break;case 2:S.isLeapYear(e)?r+=29:r+=28;break;default:r+=30;break}return r},getTimeStringAutoShort2(e,n){const t=new Date,r=new Date(e),o=t.getFullYear(),s=t.getMonth()+1,c=t.getDate(),l=r.getFullYear(),i=r.getMonth()+1,h=r.getDate();let a="";const u=n?" "+this.formatDate(r,"hh:mm"):"";if(o===l){const g=t.getTime()-e;if(s===i&&c===h)g<60*1e3?a="刚刚":a=this.formatDate(r,"hh:mm");else{const p=new Date;p.setDate(p.getDate()-1);const b=new Date;if(b.setDate(b.getDate()-2),i===p.getMonth()+1&&h===p.getDate())a="昨天"+u;else if(i===b.getMonth()+1&&h===b.getDate())a="前天"+u;else if(g/36e5<=7*24){const m=new Array(7);m[0]="星期日",m[1]="星期一",m[2]="星期二",m[3]="星期三",m[4]="星期四",m[5]="星期五",m[6]="星期六",a=m[r.getDay()]+u}else a=this.formatDate(r,"yyyy/M/d")+u}}else a=this.formatDate(r,"yyyy/M/d")+u;return a},formatDate(e,n){const t={"M+":e.getMonth()+1,"d+":e.getDate(),"h+":e.getHours(),"m+":e.getMinutes(),"s+":e.getSeconds(),"q+":Math.floor((e.getMonth()+3)/3),S:e.getMilliseconds()};/(y+)/.test(n)&&(n=n.replace(RegExp.$1,(e.getFullYear()+"").substr(4-RegExp.$1.length)));for(const r in t)new RegExp("("+r+")").test(n)&&(n=n.replace(RegExp.$1,RegExp.$1.length===1?t[r]:("00"+t[r]).substr((""+t[r]).length)));return n}},C={getOffsetTop(e){if(!e)throw new Error("Element is not provided");if(e instanceof SVGElement){const t=e.getBoundingClientRect(),r=window.pageYOffset||document.documentElement.scrollTop;return t.top+r}let n=0;for(;e;)n+=e.offsetTop,e=e.offsetParent;return n},getScrollValue(){const e={scrollLeft:0,scrollTop:0};return e.scrollLeft=document.body.scrollLeft||document.documentElement.scrollLeft,e.scrollTop=document.body.scrollTop||document.documentElement.scrollTop,e},getPageValue(e){e=e||window.event;const n=e.pageX||e.clientX+this.getScrollValue().scrollLeft,t=e.pageY||e.clientY+this.getScrollValue().scrollTop;return{pageX:n,pageY:t}},addEventListener(e,n,t){e.addEventListener?e.addEventListener(n,t):e.attachEvent?e.attachEvent("on"+n,t):e["on"+n]=t},getViewportWidth(){return window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth},getViewportHeight(){return window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight}},x={saveAsBlob(e,n){const t=document.createElement("a"),r=window.URL.createObjectURL(e);t.href=r,t.download=n,document.body.appendChild(t),t.click(),URL.revokeObjectURL(r),document.body.removeChild(t)},saveAsUrl(e,n){const t=document.createElement("a");t.href=e,t.download=n,document.body.appendChild(t),t.click(),URL.revokeObjectURL(e),document.body.removeChild(t)}},D={animate(e,n){let t=-1;const r=e.series[0].data.length;let o;o=setInterval(()=>{n.dispatchAction({type:"downplay",seriesIndex:0,dataIndex:t}),t=(t+1)%r,n.dispatchAction({type:"highlight",seriesIndex:0,dataIndex:t}),n.dispatchAction({type:"showTip",seriesIndex:0,dataIndex:t}),t>r&&(t=0)},2e3),n.on("mouseover",()=>{clearInterval(o),n.dispatchAction({type:"downplay",seriesIndex:0,dataIndex:t})})}},R={sortFromA2Z(e){return e?.length?e.sort((t,r)=>{const o=t.toUpperCase(),s=r.toUpperCase();return o<s?-1:o>s?1:0}):void 0}},v={degrees2Radians(e){return e*Math.PI/180},getDistance(e,n,t,r){const o=this.degrees2Radians(e),s=this.degrees2Radians(t),c=o-s,l=this.degrees2Radians(n)-this.degrees2Radians(r);let i=2*Math.asin(Math.sqrt(Math.pow(Math.sin(c/2),2)+Math.cos(o)*Math.cos(s)*Math.pow(Math.sin(l/2),2)));return i=i*6378.137,i=Math.round(i*1e4)/1e4,i=+i.toFixed(2),console.log("经纬度计算的距离为:"+i),i},calculateDistanceByHaversine(e,n,t="km"){const r=this,o=e.longitude??e.lng,s=e.latitude??e.lat,c=n.longitude??n.lng,l=n.latitude??n.lat;if(o===void 0||s===void 0||c===void 0||l===void 0)throw new Error("无效的坐标格式,缺少经纬度信息");const i=6371,h=r.degrees2Radians(s),a=r.degrees2Radians(l),u=r.degrees2Radians(l-s),f=r.degrees2Radians(c-o),y=Math.sin(u/2)*Math.sin(u/2)+Math.cos(h)*Math.cos(a)*Math.sin(f/2)*Math.sin(f/2),g=2*Math.atan2(Math.sqrt(y),Math.sqrt(1-y)),p=i*g;switch(t){case"m":return p*1e3;case"mi":return p*.621371;case"nmi":return p*.539957;default:return p}},calculateDistancesByHaversine(e,n="km",t=!1){if(e.length<2)return{segments:[],total:0};const r=[];let o=0;for(let s=0;s<e.length-1;s++){const c=this.calculateDistanceByHaversine(e[s],e[s+1],n);r.push(c),o+=c}if(t&&e.length>2){const s=this.calculateDistanceByHaversine(e[e.length-1],e[0],n);r.push(s),o+=s}return{segments:r,total:o}}};class T{static toStandardFormat(n){try{const t=typeof n=="string"?parseFloat(n):n;if(isNaN(t))throw new Error("输入不是有效的数字");if(!isFinite(t))throw new Error("输入是无穷大");return t.toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")}catch(t){return console.error("格式化失败:",t),"格式错误"}}static toChineseFormat(n){try{const t=typeof n=="string"?parseFloat(n):n;if(isNaN(t))throw new Error("输入不是有效的数字");if(t>9999999999999e-2||t<-9999999999999e-2)throw new Error("输入数字超出范围");const r=t<0,o=Math.abs(t),s=Math.floor(o),c=Math.round((o-s)*100),l=["零","壹","贰","叁","肆","伍","陆","柒","捌","玖"],i=["","拾","佰","仟","万","拾","佰","仟","亿","拾","佰","仟"],h=["角","分"];let a="",u=s;if(u===0)a=l[0];else{let g=0;for(;u>0;){const p=u%10;p!==0?a=l[p]+i[g]+a:a.charAt(0)!==l[0]&&(a=l[p]+a),u=Math.floor(u/10),g++}a=a.replace(/零+/g,"零"),a=a.replace(/零+$/,"")}let f="";if(c>0){const g=Math.floor(c/10),p=c%10;g>0&&(f+=l[g]+h[0]),p>0&&(f+=l[p]+h[1])}else f="整";let y=(r?"负":"")+a+"圆"+f;return y==="零圆整"&&(y="零圆"),y}catch(t){return console.error("转换失败:",t),"格式错误"}}}const O={desensitizeChineseName(e,n={}){const{keepLength:t=1,keepLast:r=!1}=n;if(!e||e.length===0||e.trim().length===0)throw new Error("姓名不能为空");if(typeof e!="string")throw new Error("姓名必须是字符串");if(e.length<=1)return e;const o=["欧阳","司马","上官","东方","独孤","南宫","闻人","夏侯","诸葛","尉迟","公孙","长孙","宇文","司徒","慕容"];n.compoundSurname&&n.compoundSurname.trim().length>0&&!o.includes(n.compoundSurname)&&o.push(n.compoundSurname);let s="";o.some(l=>e.startsWith(l))?s=o.find(l=>e.startsWith(l))||"":s=e[0]||"";const c=Math.max(t,s.length);if(c>=e.length)return e;if(r&&e.length>2){const l=e.slice(0,c),i=e.slice(-1),h=e.length-c-1;return`${l}${"*".repeat(h)}${i}`}return`${e.slice(0,c)}${"*".repeat(e.length-c)}`}},L={...Object.freeze(Object.defineProperty({__proto__:null,toLetter:e=>e>25||e<0?"":"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[e]},Symbol.toStringTag,{value:"Module"})),...Object.freeze(Object.defineProperty({__proto__:null,toMoney:e=>e.toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")},Symbol.toStringTag,{value:"Module"})),isNumber(e){return typeof e=="number"&&!isNaN(e)}},I={isEmptyObject(e){return!e||JSON.stringify(e)==="{}"?!0:Object.keys(e).length===0&&e.constructor===Object},copy(e,n){for(const t in e)n[t]=e[t]},deepCopy(e,n){for(const t in e){const r=e[t];r instanceof Object?(n[t]={},this.deepCopy(r,n[t])):r instanceof Array?(n[t]=[],this.deepCopy(r,n[t])):n[t]=e[t]}}},j={desensitize(e){return e?e.replace(/^(\d{3})\d{4}(\d{4})$/,"$1****$2")||e.slice(0,3)+"****"+e.slice(7):""}},k={color:function(){return`#${Math.random().toString(16).slice(2,8)}`},int(e,n){return Math.floor(Math.random()*(n-e+1))+e},uniqueId(){return Date.now().toString(36)+Math.random().toString(36).substr(2,5)}},_={mobile:/^1[3-9]\d{9}$/,email:/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,chinese:/^[\u4e00-\u9fa5]+$/,english:/^[a-zA-Z]+$/,chineseStart:/^[\u4e00-\u9fa5]+\w*$/,integer:/^\d+$/,integerAndzero:/^(0|[1-9]+[0-9]*)$/,strongPassword:/^(?!.*[\s\p{C}])(?:(?=.*[A-Z])(?=.*[a-z])(?=.*[\d\W])|(?=.*\d)(?=.*[^\w\s])).{8,}$/u,decimal:/^0\.(0[1-9]|[1-9][0-9]*)$/},H={getLocal(e){return localStorage.getItem(e)},setLocal(e,n){localStorage.setItem(e,n)},removeLocal(e){localStorage.removeItem(e)},getSession(e){return sessionStorage.getItem(e)},setSession(e,n){sessionStorage.setItem(e,n)},removeSession(e){sessionStorage.removeItem(e)}},$={isExist(e,n){if(!e||!n)return!1;const t=e.split(",");return console.log("判断某元素是否在字符串中",t.indexOf(n)===-1),t.indexOf(n)!==-1},includes(e,n){return!e||!n?!1:e.includes(n)},isJSON(e){try{return JSON.parse(e),!0}catch{return!1}},indexsOfAppear(e,n){let t=-1;const r=[];do t=e.indexOf(n,t+1),t!==-1&&r.push(t);while(t!==-1);return r},getMaxTimesAndVal(e){const n=[0,""],t={};for(let s=0;s<e.length;s++){const c=e.charAt(s);t[c]?t[c]++:t[c]=1}let r=1;for(const s in t)r<t[s]&&(r=t[s]);const o=[];for(const s in t)r==t[s]&&o.push(s);return n[0]=r,n[1]=o.join(),n},mask(e,n,t){if(!e)throw new Error("字符串为空");if(typeof n!="number"||typeof t!="number")throw new Error("开始位置或结束位置为空");if(n<0||t>e.length||n>t)throw new Error("开始位置小于0或结束位置超出字符串长度或开始位置大于结束位置");return e.slice(0,n)+"*".repeat(t-n+1)+e.slice(t)}},F=e=>{const t=new RegExp("[?&]"+e+"=([^&#]*)","gi").exec(window.location.href);return t?decodeURIComponent(t[1]):null};function N(e){return new URLSearchParams(window.location.search).get(e)}const q={...Object.freeze(Object.defineProperty({__proto__:null,getQueryInfoByName:F,getQueryParam:N},Symbol.toStringTag,{value:"Module"})),getHost(){return window.location.host},getPath(){return window.location.pathname}},P={toList(e,n=2){console.log(e,n);const t={};for(let o=0;o<n;o++)t[o]=[];e.forEach((o,s)=>t[s%n].push(o));const r=[];for(const o in t)r.push(...t[o]);return r},jsLayout(e,n,t){const r=e.offsetWidth,o=n[0].offsetWidth,s=parseInt((r/o).toString()),c=(r-o*s)/(s-1),l=[];for(let i=0,h=n.length;i<h;i++){const a=n[i];if(i<s)a.style.left=(o+c)*i+"px",l[i]=a.offsetHeight;else{const{index:u,value:f}=A.getMinValueAndIndex(l);a.style.left=(o+c)*u+"px",a.style.top=f+t+"px",l[u]=a.offsetHeight+t+f}}}};d.Base64Utils=M,d.MoneyFormatter=T,d.arrayUtils=A,d.booleanUtils=S,d.commonUtils=E,d.cookieUtils=U,d.dateUtils=B,d.documentUtils=C,d.downloadUtils=x,d.echartsUtils=D,d.letterUtils=R,d.mapUtils=v,d.nameUtils=O,d.numberUtils=L,d.objectUtils=I,d.phoneUtils=j,d.randomUtils=k,d.regexpUtils=_,d.storageUtils=H,d.stringUtils=$,d.urlUtils=q,d.waterfallUtils=P,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yh-kit/utils",
3
3
  "private": false,
4
- "version": "1.15.1",
4
+ "version": "1.16.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
@@ -0,0 +1,20 @@
1
+ declare const _default: {
2
+ /**
3
+ * 数组随机打乱-Fisher-Yates算法
4
+ * @param arr 数组
5
+ * @returns 随机打乱后的数组
6
+ *
7
+ * 注意,这个算法会改变原数组。如果不想改变原数组,可以先复制一份再进行操作。
8
+ * 时间复杂度:O(n)
9
+ * 空间复杂度:O(1)
10
+ */
11
+ shuffle<T>(arr: T[]): T[];
12
+ /**
13
+ * 数组随机抽样-Fisher-Yates算法前k次迭代,再取前k个元素
14
+ * @param arr 数组
15
+ * @param k 抽样次数
16
+ * @returns 抽样后的数组
17
+ */
18
+ sample<T>(arr: T[], k: number): T[];
19
+ };
20
+ export default _default;
@@ -3,6 +3,8 @@
3
3
  * @namespace arrayUtils
4
4
  */
5
5
  export declare const arrayUtils: {
6
+ readonly shuffle: <T>(arr: T[]) => T[];
7
+ readonly sample: <T>(arr: T[], k: number) => T[];
6
8
  readonly countOfAppear: <T>(arr: T[], target: T) => number;
7
9
  readonly indexsOfAppear: <T>(array: T[], element: T) => number[];
8
10
  readonly getMaxValue: (arr: number[]) => number;
@@ -16,9 +18,14 @@ export declare const arrayUtils: {
16
18
  index: number;
17
19
  };
18
20
  readonly sort: <T>(arr: T[], order?: "asc" | "desc") => T[];
19
- readonly shuffle: <T>(arr: T[]) => T[];
20
21
  readonly isExistByIndexOf: <T>(arr: T[], element: T) => boolean;
21
22
  readonly isExistByIncludes: <T>(arr: T[], element: T) => boolean;
22
- readonly uniqueBySet: <T>(arr: T[]) => T[];
23
+ readonly uniqueBySet: <T>(_arr: T[]) => T[];
24
+ readonly uniqueByFilter: <T>(_arr: T[]) => T[];
25
+ readonly uniqueByReduce: <T>(_arr: T[]) => T[];
26
+ readonly uniqueByIncludes: <T>(_arr: T[]) => T[];
27
+ readonly uniqueByFor: <T>(_arr: T[]) => T[];
28
+ readonly uniqueByKey: <T>(_arr: T[], key: keyof T) => T[];
29
+ readonly unique: <T>(_arr: T[], options?: import("./unique").TUniqueOptions<T>) => T[] | undefined;
23
30
  readonly toEnumObj: (arr: import("@yh-kit/types").IOptionItem[], valueKey?: string) => import("@yh-kit/types").TValueEnum;
24
31
  };
@@ -6,17 +6,5 @@ declare const _default: {
6
6
  * @returns 排序后的数组
7
7
  */
8
8
  sort<T>(arr: T[], order?: "asc" | "desc"): T[];
9
- /**
10
- * 数组乱序(洗牌算法)
11
- * 1. 从数组的最后一个元素开始,将其与随机位置的元素交换位置。
12
- * 2. 然后,从倒数第二个元素开始,将其与随机位置的元素交换位置。
13
- * 3. 以此类推,直到第一个元素。
14
- * 4. 这样,数组中的元素就会被随机打乱顺序。
15
- * 5. 注意,这个算法会改变原数组。如果不想改变原数组,可以先复制一份再进行操作。
16
- * 6. 时间复杂度:O(n)
17
- * @param arr 数组
18
- * @returns
19
- */
20
- shuffle<T>(arr: T[]): T[];
21
9
  };
22
10
  export default _default;
@@ -1,9 +1,89 @@
1
+ /**
2
+ * 数组去重选项
3
+ * @template T 数组元素类型
4
+ * @param keys - 要去重的属性键名数组
5
+ * @param compareFn - 自定义比较函数,用于判断两个元素是否相等
6
+ */
7
+ export interface TUniqueOptions<T> {
8
+ keys?: (keyof T)[];
9
+ compareFn?: (a: T, b: T) => boolean;
10
+ }
1
11
  declare const _default: {
2
12
  /**
3
- * 数组去重
13
+ * 数组去重:针对简单类型数据s
14
+ * 性能 O(n)
4
15
  * @param arr 数组
5
16
  * @returns 去重后的数组
6
17
  */
7
- uniqueBySet<T>(arr: T[]): T[];
18
+ uniqueBySet<T>(_arr: T[]): T[];
19
+ /**
20
+ * 双重循环之 filter + indexOf 数组去重:
21
+ * 此方法不能去重 NaN 值,也不能去重对象类型数据。
22
+ * 性能 O(n²),每次 indexOf 都是 O(n) 操作
23
+ * @param arr 数组
24
+ * @returns 去重后的数组
25
+ */
26
+ uniqueByFilter<T>(_arr: T[]): T[];
27
+ /**
28
+ * 双重循环之 reduce + includes 数组去重:
29
+ * 适用于基本类型数据(string、number、boolean),能去重 NaN 值,但不能去重对象类型数据。
30
+ * 性能 O(n²),每次 includes 都是 O(n) 操作
31
+ * @param arr 数组
32
+ * @returns 去重后的数组
33
+ */
34
+ uniqueByReduce<T>(_arr: T[]): T[];
35
+ /**
36
+ * 双重循环之 forEach + includes 数组去重:
37
+ * 适用于基本类型数据(string、number、boolean),能去重 NaN 值,但不能去重对象类型数据。
38
+ * 性能 O(n²),每次 includes 都是 O(n) 操作
39
+ * @param arr 数组
40
+ * @returns 去重后的数组
41
+ */
42
+ uniqueByIncludes<T>(_arr: T[]): T[];
43
+ /**
44
+ * 双重循环之 for + includes 数组去重:
45
+ * 适用于基本类型数据(string、number、boolean),能去重 NaN 值,但不能去重对象类型数据。
46
+ * 性能 O(n²),每次 includes 都是 O(n) 操作
47
+ * @param arr 数组
48
+ * @returns 去重后的数组
49
+ */
50
+ uniqueByFor<T>(_arr: T[]): T[];
51
+ /**
52
+ * Map + 根据指定键去重
53
+ * 适用类型 对象数组(通过指定键进行去重)
54
+ * 键值类型 支持 string、number、boolean、Symbol
55
+ * NaN 处理 ✅ 支持(Map 支持 NaN 作为键)
56
+ * 性能 O(n),Map 的 has 和 set 操作都是 O(1)
57
+ * @param arr 数组
58
+ * @param key 对象的键名
59
+ * @returns 去重后的数组
60
+ */
61
+ uniqueByKey<T>(_arr: T[], key: keyof T): T[];
62
+ /**
63
+ * 通用数组去重函数 - 根据选项自动选择去重策略
64
+ *
65
+ * @template T - 数组元素类型
66
+ * @param {T[]} _arr - 待去重的数组
67
+ * @param {TUniqueOptions<T>} [options={}] - 去重选项
68
+ * @param {(keyof T)[]} [options.keys] - 按指定键组合去重(适用于对象数组)
69
+ * @param {(a: T, b: T) => boolean} [options.compareFn] - 自定义比较函数
70
+ * @returns {T[]} 去重后的数组
71
+ *
72
+ * @example
73
+ * // 基本类型数组(默认使用 Set 去重)
74
+ * unique([1, 2, 2, 3, 1]); // [1, 2, 3]
75
+ *
76
+ * @example
77
+ * // 对象数组按多个键去重
78
+ * const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 1, name: 'Alice' }];
79
+ * unique(users, { keys: ['id', 'name'] }); // [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
80
+ *
81
+ * @example
82
+ * // 使用自定义比较函数
83
+ * unique(arr, { compareFn: (a, b) => a.x === b.x && a.y === b.y });
84
+ *
85
+ * @throws {Error} 当输入数组为空时抛出错误
86
+ */
87
+ unique<T>(_arr: T[], options?: TUniqueOptions<T>): T[] | undefined;
8
88
  };
9
89
  export default _default;