util-helpers 4.15.2 → 4.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.
Files changed (74) hide show
  1. package/README.md +6 -5
  2. package/dist/util-helpers.js +887 -479
  3. package/dist/util-helpers.js.map +1 -1
  4. package/dist/util-helpers.min.js +1 -1
  5. package/dist/util-helpers.min.js.map +1 -1
  6. package/esm/ajax.js +149 -0
  7. package/esm/blobToDataURL.js +8 -12
  8. package/esm/dataURLToBlob.js +6 -5
  9. package/esm/download.js +156 -0
  10. package/esm/fileReader.js +67 -0
  11. package/esm/filterTree.js +1 -1
  12. package/esm/findTreeNode.js +1 -1
  13. package/esm/findTreeNodes.js +1 -1
  14. package/esm/findTreeSelect.js +1 -1
  15. package/esm/index.js +15 -5
  16. package/esm/interface.doc.js +124 -0
  17. package/esm/{transformFieldNames.type.js → interface.type.js} +2 -4
  18. package/esm/listToTree.js +1 -1
  19. package/esm/numberToChinese.js +3 -2
  20. package/esm/parseIdCard.js +1 -1
  21. package/esm/replaceChar.js +11 -7
  22. package/esm/safeDate.js +26 -9
  23. package/esm/transformFieldNames.js +2 -3
  24. package/esm/treeToList.js +1 -1
  25. package/esm/utils/config.js +1 -1
  26. package/esm/utils/type/index.js +3 -1
  27. package/esm/utils/type/isArrayBuffer.js +25 -0
  28. package/esm/utils/type/isBlob.js +27 -0
  29. package/lib/ajax.js +156 -0
  30. package/lib/blobToDataURL.js +8 -12
  31. package/lib/dataURLToBlob.js +6 -5
  32. package/lib/download.js +161 -0
  33. package/lib/fileReader.js +74 -0
  34. package/lib/filterTree.js +1 -1
  35. package/lib/findTreeNode.js +1 -1
  36. package/lib/findTreeNodes.js +1 -1
  37. package/lib/findTreeSelect.js +1 -1
  38. package/lib/index.js +26 -5
  39. package/lib/interface.doc.js +126 -0
  40. package/lib/listToTree.js +1 -1
  41. package/lib/numberToChinese.js +3 -2
  42. package/lib/parseIdCard.js +1 -1
  43. package/lib/replaceChar.js +11 -7
  44. package/lib/safeDate.js +27 -10
  45. package/lib/transformFieldNames.js +1 -1
  46. package/lib/treeToList.js +1 -1
  47. package/lib/utils/config.js +1 -1
  48. package/lib/utils/type/index.js +14 -0
  49. package/lib/utils/type/isArrayBuffer.js +32 -0
  50. package/lib/utils/type/isBlob.js +34 -0
  51. package/package.json +2 -2
  52. package/types/ajax.d.ts +121 -0
  53. package/types/blobToDataURL.d.ts +5 -1
  54. package/types/download.d.ts +77 -0
  55. package/types/fileReader.d.ts +3 -0
  56. package/types/filterTree.d.ts +1 -1
  57. package/types/findTreeNode.d.ts +1 -1
  58. package/types/findTreeNodes.d.ts +1 -1
  59. package/types/findTreeSelect.d.ts +1 -1
  60. package/types/index.d.ts +8 -5
  61. package/types/{transformFieldNames.type.d.ts → interface.type.d.ts} +1 -1
  62. package/types/listToTree.d.ts +1 -1
  63. package/types/numberToChinese.d.ts +3 -2
  64. package/types/parseIdCard.d.ts +2 -2
  65. package/types/replaceChar.d.ts +11 -7
  66. package/types/safeDate.d.ts +3 -23
  67. package/types/transformFieldNames.d.ts +2 -2
  68. package/types/treeToList.d.ts +1 -1
  69. package/types/utils/type/index.d.ts +21 -19
  70. package/types/utils/type/isArrayBuffer.d.ts +21 -0
  71. package/types/utils/type/isBlob.d.ts +23 -0
  72. package/esm/transformFieldNames.doc.js +0 -35
  73. package/lib/transformFieldNames.doc.js +0 -42
  74. /package/lib/{transformFieldNames.type.js → interface.type.js} +0 -0
@@ -537,7 +537,7 @@
537
537
  }
538
538
 
539
539
  // eslint-disable-next-line no-undef
540
- var version = "4.15.2";
540
+ var version = "4.16.0";
541
541
 
542
542
  /**
543
543
  * 打印警告信息
@@ -1542,6 +1542,31 @@
1542
1542
  // 最小安全数字
1543
1543
  var MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;
1544
1544
 
1545
+ /**
1546
+ * 检查值是否为Blob对象<br/><br/>
1547
+ *
1548
+ * <em style="font-weight: bold;">注意:该方法仅适用于浏览器端。</em>
1549
+ *
1550
+ * @static
1551
+ * @alias module:Type.isBlob
1552
+ * @since 4.16.0
1553
+ * @param {*} value 检查值
1554
+ * @returns {boolean} 是否为Blob对象
1555
+ * @example
1556
+ *
1557
+ * isBlob(new Blob(['a']))
1558
+ * // => true
1559
+ *
1560
+ * isBlob({})
1561
+ * // => false
1562
+ *
1563
+ * isBlob('2012')
1564
+ * // => false
1565
+ */
1566
+ function isBlob(value) {
1567
+ return isType(value, 'Blob');
1568
+ }
1569
+
1545
1570
  /**
1546
1571
  * 检查值是否为Object
1547
1572
  *
@@ -2025,20 +2050,24 @@
2025
2050
  * @returns {string} 处理后的字符
2026
2051
  * @example
2027
2052
  *
2028
- * // 手机号
2053
+ * // 手机号 前3后4
2029
2054
  * replaceChar('13000000000'); // 130****0000
2030
2055
  *
2031
- * // 身份证
2032
- * replaceChar('130701199310302288'); // 130***********2288
2056
+ * // 身份证 前6后4
2057
+ * replaceChar('130701199310302288', { start: 6, end: -4 }); // 130701********2288
2033
2058
  *
2034
- * // 邮箱
2059
+ * // 邮箱 @前两位
2035
2060
  * const email = '12345@qq.com'
2061
+ * const emailAtIndex = email.indexOf('@');
2062
+ * replaceChar(email, { start: emailAtIndex - 2, end: emailAtIndex }); // 123**@qq.com
2063
+ * // 邮箱 前2和@后面内容,固定替换字符4位
2036
2064
  * replaceChar(email, {start: 2, end: email.indexOf('@'), repeat: 4}); // 12****@qq.com
2037
2065
  *
2038
- * // 银行卡号
2066
+ * // 银行卡号 只展示后4位,固定替换字符4位
2039
2067
  * replaceChar('6228480402564890018', {start: 0, end: -4, repeat: 4}); // ****0018
2040
- *
2041
- * // 带格式的银行卡号,忽略空字符串
2068
+ * // 银行卡号 前6后4
2069
+ * replaceChar('6228480402564890018', { start: 6, end: -4 }); // 622848*********0018
2070
+ * // 银行卡号 前4后3 忽略格式的空格
2042
2071
  * replaceChar('6228 4804 0256 4890 018', {start: 4, end: -4, exclude: ' '}); // 6228 **** **** **** 018
2043
2072
  *
2044
2073
  * // 用户名
@@ -2211,8 +2240,9 @@
2211
2240
  }
2212
2241
 
2213
2242
  /**
2214
- * 数字转中文数字
2215
- * 不在安全数字 -9007199254740991~9007199254740991 内,处理会有异常
2243
+ * 数字转中文数字<br/><br/>
2244
+ *
2245
+ * 如果数字不在安全数字 -9007199254740991~9007199254740991 范围内,处理会有异常。
2216
2246
  *
2217
2247
  * @static
2218
2248
  * @alias module:Processor.numberToChinese
@@ -2419,7 +2449,7 @@
2419
2449
  * @since 4.0.0
2420
2450
  * @see 参考 {@link https://baike.baidu.com/item/居民身份证号码|居民身份证号码}
2421
2451
  * @param {string} id 身份证号码,支持15位
2422
- * @returns {null|IdCardInfo} null 或 省份、生日、性别,省/市/区/年/月/日/性别编码
2452
+ * @returns {IdCardInfo | null} 省份、生日、性别,省/市/区/年/月/日/性别编码。如果解析失败将返回 null
2423
2453
  * @example
2424
2454
  *
2425
2455
  * parseIdCard('123456789123456'); // null
@@ -2481,37 +2511,63 @@
2481
2511
  };
2482
2512
  }
2483
2513
 
2484
- // file、blob文件如何预览图片?
2485
- // 方法1:将file或者blob类型文件转成base64数据,再作为src赋值给img标签
2486
- // 方法2:使用 window.URL.createObjectURL(blob) 为blob、file 创建一个指向该参数对象的URL
2514
+ var FileReaderMethodMap = {
2515
+ arrayBuffer: 'readAsArrayBuffer',
2516
+ binaryString: 'readAsBinaryString',
2517
+ dataURL: 'readAsDataURL',
2518
+ text: 'readAsText'
2519
+ };
2520
+
2521
+ /**
2522
+ * @overload
2523
+ * @param {Blob} blob
2524
+ * @param {'arrayBuffer'} type
2525
+ * @returns {Promise<ArrayBuffer>}
2526
+ */
2527
+
2528
+ /**
2529
+ * @overload
2530
+ * @param {Blob} blob
2531
+ * @param {'binaryString'|'binaryString'|'dataURL'|'text'} [type='dataURL']
2532
+ * @returns {Promise<string>}
2533
+ */
2487
2534
 
2488
2535
  /**
2489
- * Blob 或 File 对象转成 data:URL 格式的 Base64 字符串。
2536
+ * 读取 Blob 或 File 对象<br/><br/>
2537
+ *
2538
+ * <em style="font-weight: bold;">注意:该方法仅适用于浏览器端。</em>
2490
2539
  *
2491
2540
  * @static
2492
- * @alias module:Processor.blobToDataURL
2493
- * @see 参考 {@link https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader/readAsDataURL|FileReader.readAsDataURL()}
2494
- * @since 4.1.0
2541
+ * @alias module:Processor.fileReader
2542
+ * @see 参考 {@link https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader|FileReader}
2543
+ * @since 4.16.0
2495
2544
  * @param {Blob} blob Blob 或 File 对象
2496
- * @returns {Promise<string>} data:URL 格式的 Base64 字符串。
2545
+ * @param {'arrayBuffer'|'binaryString'|'dataURL'|'text'} [type='dataURL'] Blob File 对象
2546
+ * @returns {Promise<string|ArrayBuffer>} 文件的内容
2497
2547
  * @example
2498
2548
  * const aFileParts = ['<a id="a"><b id="b">hey!</b></a>']; // 一个包含DOMString的数组
2499
2549
  * const htmlBlob = new Blob(aFileParts, { type: 'text/html' }); // 得到 blob
2500
2550
  *
2501
- * blobToDataURL(htmlBlob).then(data=>{
2551
+ * fileReader(htmlBlob).then(data=>{
2502
2552
  * console.log(data); // data:text/html;base64,PGEgaWQ9ImEiPjxiIGlkPSJiIj5oZXkhPC9iPjwvYT4=
2503
2553
  * });
2504
2554
  *
2505
2555
  * const textBlob = new Blob(aFileParts, { type: 'text/plain' });
2506
2556
  *
2507
- * blobToDataURL(textBlob).then(data=>{
2508
- * console.log(data); // data:text/plain;base64,PGEgaWQ9ImEiPjxiIGlkPSJiIj5oZXkhPC9iPjwvYT4=
2557
+ * fileReader(textBlob, 'text').then(data=>{
2558
+ * console.log(data); // <a id="a"><b id="b">hey!</b></a>
2509
2559
  * });
2510
2560
  */
2511
- function blobToDataURL(blob) {
2561
+ function fileReader(blob) {
2562
+ var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'dataURL';
2563
+ var method = FileReaderMethodMap[type];
2564
+ if (!method) {
2565
+ method = FileReaderMethodMap.dataURL;
2566
+ }
2512
2567
  return new Promise(function (resolve, reject) {
2513
2568
  var reader = new FileReader();
2514
- reader.readAsDataURL(blob);
2569
+ // @ts-ignore
2570
+ reader[method](blob);
2515
2571
  // @ts-ignore
2516
2572
  reader.onload = function () {
2517
2573
  return resolve(reader.result);
@@ -2522,6 +2578,39 @@
2522
2578
  });
2523
2579
  }
2524
2580
 
2581
+ // file、blob文件如何预览图片?
2582
+
2583
+ /**
2584
+ * 将 Blob 或 File 对象转成 data:URL 格式的 Base64 字符串<br/><br/>
2585
+ *
2586
+ * <em style="font-weight: bold;">注意:该方法仅适用于浏览器端。</em>
2587
+ *
2588
+ * @static
2589
+ * @alias module:Processor.blobToDataURL
2590
+ * @see 参考 {@link https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader/readAsDataURL|FileReader.readAsDataURL()}
2591
+ * @since 4.1.0
2592
+ * @ignore
2593
+ * @deprecated 请使用 `fileReader` 方法
2594
+ * @param {Blob} blob Blob 或 File 对象
2595
+ * @returns {Promise<string>} data:URL 格式的 Base64 字符串。
2596
+ * @example
2597
+ * const aFileParts = ['<a id="a"><b id="b">hey!</b></a>']; // 一个包含DOMString的数组
2598
+ * const htmlBlob = new Blob(aFileParts, { type: 'text/html' }); // 得到 blob
2599
+ *
2600
+ * blobToDataURL(htmlBlob).then(data=>{
2601
+ * console.log(data); // data:text/html;base64,PGEgaWQ9ImEiPjxiIGlkPSJiIj5oZXkhPC9iPjwvYT4=
2602
+ * });
2603
+ *
2604
+ * const textBlob = new Blob(aFileParts, { type: 'text/plain' });
2605
+ *
2606
+ * blobToDataURL(textBlob).then(data=>{
2607
+ * console.log(data); // data:text/plain;base64,PGEgaWQ9ImEiPjxiIGlkPSJiIj5oZXkhPC9iPjwvYT4=
2608
+ * });
2609
+ */
2610
+ function blobToDataURL(blob) {
2611
+ return fileReader(blob);
2612
+ }
2613
+
2525
2614
  /**
2526
2615
  * 将 DataURL 转为 Blob 对象
2527
2616
  *
@@ -2536,17 +2625,18 @@
2536
2625
  * dataURLToBlob(dataurl); // Blob {size: 32, type: 'text/html'}
2537
2626
  */
2538
2627
  function dataURLToBlob(dataurl) {
2539
- var arr = dataurl.split(',');
2540
- // @ts-ignore
2541
- var mime = arr[0].match(/:(.*?);/)[1];
2542
- var bstr = atob(arr[1]);
2628
+ var parts = dataurl.split(',');
2629
+ var meta = parts[0].substring(5).split(';');
2630
+ var type = meta[0];
2631
+ var decoder = meta.indexOf('base64') !== -1 ? atob : decodeURIComponent;
2632
+ var bstr = decoder(parts[1]);
2543
2633
  var n = bstr.length;
2544
2634
  var u8arr = new Uint8Array(n);
2545
2635
  while (n--) {
2546
2636
  u8arr[n] = bstr.charCodeAt(n);
2547
2637
  }
2548
2638
  return new Blob([u8arr], {
2549
- type: mime
2639
+ type: type
2550
2640
  });
2551
2641
  }
2552
2642
 
@@ -2580,11 +2670,34 @@
2580
2670
  return "data:".concat(mimetype).concat(base64 ? ';base64' : '', ",").concat(data);
2581
2671
  }
2582
2672
 
2583
- // TODO: 函数重载,类型参照 Date
2673
+ /**
2674
+ * @overload
2675
+ * @return {Date}
2676
+ */
2677
+
2678
+ /**
2679
+ * @overload
2680
+ * @param {number | string | Date} value Unix时间戳、时间戳字符串 dateString 、Date 日期对象
2681
+ * @return {Date}
2682
+ */
2683
+
2684
+ /**
2685
+ * @overload
2686
+ * @param {number} year 表示年份的整数值。0 到 99 会被映射至 1900 年至 1999 年,其他值代表实际年份。
2687
+ * @param {number} monthIndex 表示月份的整数值,从 0(1 月)到 11(12 月)。
2688
+ * @param {number} [date] 表示一个月中的第几天的整数值,从 1 开始。默认值为 1。
2689
+ * @param {number} [hours] 表示一天中的小时数的整数值 (24 小时制)。默认值为 0(午夜)。
2690
+ * @param {number} [minutes] 表示一个完整时间(如 01:10:00)中的分钟部分的整数值。默认值为 0。
2691
+ * @param {number} [seconds] 表示一个完整时间(如 01:10:00)中的秒部分的整数值。默认值为 0。
2692
+ * @param {number} [ms] 表示一个完整时间的毫秒部分的整数值。默认值为 0。
2693
+ * @return {Date}
2694
+ */
2584
2695
 
2585
2696
  /**
2586
- * 创建一个 Date 实例日期对象,同 new Date() 。<br/>
2587
- * 规避了苹果设备浏览器不支持部分格式(YYYY-MM-DD HH-mm 或 YYYY.MM.DD)。
2697
+ * 创建一个 Date 实例日期对象,同 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date#%E5%8F%82%E6%95%B0">new Date()</a> <br/><br/>
2698
+ *
2699
+ * 规避了苹果设备浏览器不支持部分格式(例如,YYYY-MM-DD HH-mm 或 YYYY.MM.DD)。<br/>
2700
+ * 如果参数为 undefined 正常返回 Date 。
2588
2701
  *
2589
2702
  * @static
2590
2703
  * @alias module:Processor.safeDate
@@ -2601,8 +2714,6 @@
2601
2714
  * safeDate('2022.1.1 11:11'); // Sat Jan 01 2022 11:11:00 GMT+0800 (中国标准时间)
2602
2715
  * safeDate(99, 1); // Mon Feb 01 1999 00:00:00 GMT+0800 (中国标准时间)
2603
2716
  * safeDate(1646711233171); // Tue Mar 08 2022 11:47:13 GMT+0800 (中国标准时间)
2604
- *
2605
- *
2606
2717
  */
2607
2718
  function safeDate(value) {
2608
2719
  var safeValue = typeof value === 'string' ? value.replace(/[\\.-]/g, '/') : value;
@@ -2613,9 +2724,7 @@
2613
2724
  // @ts-ignore
2614
2725
  return _construct(Date, [safeValue].concat(args));
2615
2726
  }
2616
-
2617
- // @ts-ignore
2618
- return isNil(safeValue) ? new Date() : new Date(safeValue);
2727
+ return typeof safeValue === 'undefined' ? new Date() : new Date(safeValue);
2619
2728
  }
2620
2729
 
2621
2730
  /**
@@ -2698,352 +2807,110 @@
2698
2807
  }
2699
2808
 
2700
2809
  /**
2701
- * 转换字段名,返回一个转换字段后的值,不改变原值。
2702
- *
2810
+ * 精确乘法,支持多个数相乘,乘数默认为 1 。
2811
+ *
2703
2812
  * @static
2704
- * @alias module:Processor.transformFieldNames
2705
- * @since 4.14.0
2706
- * @template {*} D
2707
- * @template {Record<string, keyof D>} F
2708
- * @template {string} C
2709
- * @param {D[]} data 对象数组。如果是树结构数据,需要指定第三个参数 childrenField
2710
- * @param {F} fieldNames 字段名映射
2711
- * @param {C} [childrenField] 子级数据字段名
2712
- * @param {'spread'|'self'} [nodeAssign='spread'] 节点赋值方式。spread表示使用展开运算符创建新值,self表示使用自身对象。
2713
- * @returns {import('./transformFieldNames.type.js').TransformFieldNames<D, F, C>}
2813
+ * @alias module:Math.times
2814
+ * @since 3.1.0
2815
+ * @param {...number|string} nums 相乘的数
2816
+ * @returns {number} 乘积
2714
2817
  * @example
2818
+ *
2819
+ * times(3, 0.6); // 1.8
2820
+ * times(3, 0.6, 2); // 3.6
2821
+ * times(3, 0.6, 2, 10); // 36
2715
2822
  *
2716
- * const options = [{code: '1', name: 'one'},{code:'2', name:'two'}];
2717
- * const newOptions = transformFieldNames(options, {label: 'name', value: 'code'});
2718
- * // [{value: '1', label: 'one'},{value:'2', label:'two'}]
2719
- *
2720
- * // 嵌套数据,指定子级字段名 children
2721
- * const options2 = [{code: '1', name: 'one'},{code:'2', name:'two', children: [{code:'2-1', name:'two-one', children: [{code: '2-1-1', name:'two-one-one'}]}]}];
2722
- * const newOptions2 = transformFieldNames(options2, {label: 'name', value: 'code'}, 'children');
2723
- * // [{value: '1', label: 'one'},{value:'2', label:'two', children: [{value: '2-1', label:'two-one', children: [{value: '2-1-1', label:'two-one-one'}]}]}]
2724
- *
2725
- * const options3 = [{code: '1', name: 'one'},{code:'2', name:'two', childs: [{code:'2-1', name:'two-one'}]}];
2726
- * const newOptions3 = transformFieldNames(options3, {label: 'name', value: 'code'}, 'childs');
2727
- * // [{value: '1', label: 'one'},{value:'2', label:'two', childs: [{value: '2-1', label:'two-one'}]}]
2728
- *
2729
- * // 嵌套数据,并替换子集字段名
2730
- * const newOptions4 = transformFieldNames(options3, {label: 'name', value: 'code', children: 'childs'}, 'childs');
2731
- * // [{value: '1', label: 'one'},{value:'2', label:'two', children: [{value: '2-1', label:'two-one'}]}]
2732
2823
  */
2733
- function transformFieldNames(data, fieldNames, childrenField) {
2734
- var nodeAssign = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'spread';
2735
- if (!Array.isArray(data)) {
2736
- return data;
2737
- }
2738
- if (data.length <= 0) {
2739
- // @ts-ignore
2740
- return [];
2824
+ function times() {
2825
+ for (var _len = arguments.length, nums = new Array(_len), _key = 0; _key < _len; _key++) {
2826
+ nums[_key] = arguments[_key];
2741
2827
  }
2742
-
2743
- /**
2744
- * 递归处理字段名
2745
- *
2746
- * @param {Array.<object>} arr 列表数据
2747
- * @returns {*}
2748
- */
2749
- function recusion(arr) {
2750
- return arr.map(function (item) {
2751
- if (!isObject(item)) {
2752
- return item;
2753
- }
2754
- var newItem = nodeAssign === 'spread' ? _objectSpread2({}, item) : item;
2755
- /** @type {Array.<string>} */
2756
- var delKeys = [];
2757
-
2758
- // 树形数据子节点
2759
- // @ts-ignore
2760
- if (childrenField && Array.isArray(newItem[childrenField]) && newItem[childrenField].length > 0) {
2761
- // @ts-ignore
2762
- newItem[childrenField] = recusion(newItem[childrenField].slice());
2763
- }
2764
-
2765
- // 替换字段名
2766
- Object.keys(fieldNames).forEach(function (newKey) {
2767
- var oldKey = fieldNames[newKey];
2768
- if (oldKey in newItem) {
2769
- // @ts-ignore
2770
- newItem[newKey] = newItem[oldKey];
2771
- // @ts-ignore
2772
- delKeys.push(oldKey);
2773
- }
2774
- });
2775
-
2776
- // 删除旧字段
2777
- if (delKeys.length > 0) {
2778
- delKeys.forEach(function (delKey) {
2779
- // @ts-ignore
2780
- delete newItem[delKey];
2781
- });
2782
- }
2783
- return newItem;
2784
- });
2828
+ var num1 = nums[0],
2829
+ _nums$ = nums[1],
2830
+ num2 = _nums$ === void 0 ? 1 : _nums$,
2831
+ rest = nums.slice(2);
2832
+ if (rest.length > 0) {
2833
+ return times.apply(void 0, [times(num1, num2)].concat(_toConsumableArray(rest)));
2785
2834
  }
2835
+ num1 = transformEffectiveNumber(num1);
2836
+ num2 = transformEffectiveNumber(num2);
2786
2837
 
2838
+ // 兼容处理,如果参数包含无效数值时,返回 NaN
2787
2839
  // @ts-ignore
2788
- return recusion(data.slice());
2840
+ if (isNaN(num1) || isNaN(num2)) {
2841
+ return Number.NaN;
2842
+ }
2843
+ var num1Changed = float2Fixed(num1);
2844
+ var num2Changed = float2Fixed(num2);
2845
+ var baseNum = digitLength(num1) + digitLength(num2);
2846
+ var leftValue = num1Changed * num2Changed;
2847
+ checkBoundary(leftValue);
2848
+ return leftValue / Math.pow(10, baseNum);
2789
2849
  }
2790
2850
 
2791
2851
  /**
2792
- * 递归处理空子级
2852
+ * 精确加法,支持多个数相加,加数默认为 0 。
2853
+ *
2854
+ * @static
2855
+ * @alias module:Math.plus
2856
+ * @since 3.1.0
2857
+ * @param {...number|string} nums 相加的数
2858
+ * @returns {number} 总和
2859
+ * @example
2860
+ *
2861
+ * plus(0.1, 0.2); // 0.3
2862
+ * plus(0.1, 0.2, 0.3); // 0.6
2863
+ * plus(0.1, 0.2, 0.3, 0.4); // 1
2793
2864
  *
2794
- * @private
2795
- * @template {Record<string,any>} [T=Record<string,any>]
2796
- * @param {T[]} arr 列表数据
2797
- * @param {object} [options] 配置项
2798
- * @param {string} [options.childrenField='children'] 子级字段名称
2799
- * @param {'none'|'null'} [options.emptyChildrenValue='none'] 子级为空时的值,none表示删除该子级,null表示为null,array表示为[]。
2800
2865
  */
2801
- function processEmptyChildren(arr, options) {
2802
- var _ref = options || {},
2803
- _ref$childrenField = _ref.childrenField,
2804
- childrenField = _ref$childrenField === void 0 ? 'children' : _ref$childrenField,
2805
- _ref$emptyChildrenVal = _ref.emptyChildrenValue,
2806
- emptyChildrenValue = _ref$emptyChildrenVal === void 0 ? 'none' : _ref$emptyChildrenVal;
2807
- arr.forEach(function (item) {
2808
- // if (isObject(item) && Array.isArray(item[childrenField])) {
2809
- if (item[childrenField].length <= 0) {
2810
- if (emptyChildrenValue === 'null') {
2811
- // @ts-ignore
2812
- item[childrenField] = null;
2813
- // } else if (emptyChildrenValue === 'none') { // emptyChildrenValue='array' 不会执行该内部方法
2814
- } else {
2815
- delete item[childrenField];
2816
- }
2817
- } else {
2818
- processEmptyChildren(item[childrenField], options);
2819
- }
2820
- // }
2821
- });
2866
+ function plus() {
2867
+ for (var _len = arguments.length, nums = new Array(_len), _key = 0; _key < _len; _key++) {
2868
+ nums[_key] = arguments[_key];
2869
+ }
2870
+ var num1 = nums[0],
2871
+ _nums$ = nums[1],
2872
+ num2 = _nums$ === void 0 ? 0 : _nums$,
2873
+ rest = nums.slice(2);
2874
+ if (rest.length > 0) {
2875
+ return plus.apply(void 0, [plus(num1, num2)].concat(_toConsumableArray(rest)));
2876
+ }
2877
+ num1 = transformEffectiveNumber(num1);
2878
+ num2 = transformEffectiveNumber(num2);
2879
+
2880
+ // 兼容处理,如果参数包含无效数值时,返回 NaN
2881
+ // @ts-ignore
2882
+ if (isNaN(num1) || isNaN(num2)) {
2883
+ return Number.NaN;
2884
+ }
2885
+ var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
2886
+ return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
2822
2887
  }
2823
2888
 
2824
2889
  /**
2825
- * 列表数据转树结构
2826
- *
2890
+ * 精确减法,支持多个数相减,减数默认为 0 。
2891
+ *
2827
2892
  * @static
2828
- * @alias module:Processor.listToTree
2829
- * @since 4.14.0
2830
- * @template {Record<string,any>} [T=Record<string,any>]
2831
- * @template {*} [R=T&Record<string,any>]
2832
- * @param {T[]} list 列表数据
2833
- * @param {object} [options] 配置项
2834
- * @param {string} [options.keyField='id'] 当前数据的键值字段名称
2835
- * @param {string} [options.parentField='pid'] 当前数据的父级字段名称
2836
- * @param {string} [options.childrenField='children'] 子级字段名称
2837
- * @param {'none'|'null'|'array'} [options.emptyChildrenValue='none'] 子级为空时的值,none表示删除该子级,null表示为null,array表示为[]。
2838
- * @param {'spread'|'self'} [options.nodeAssign='spread'] 节点赋值方式。spread表示使用展开运算符创建新值,self表示使用自身对象。
2839
- * @returns {R[]} 树结构
2840
- * @example
2841
- *
2842
- * const menus = [
2843
- * { id: '1', name: '首页', code: 'trade', pid: null },
2844
- * { id: '2', name: '交易管理', code: 'trade', pid: null },
2845
- * { id: '3', name: '交易查询', code: 'trade-1', pid: '2' },
2846
- * { id: '4', name: '交易查询-查询操作', code: 'trade-1-1', pid: '3' },
2847
- * { id: '5', name: '权限管理', code: 'authorization', pid: null },
2848
- * { id: '6', name: '角色管理', code: 'authorization-1', pid: '5' },
2849
- * { id: '7', name: '用户管理', code: 'authorization-2', pid: '5' }
2850
- * ];
2851
- * listToTree(menus);
2852
- * // [{"id":"1","name":"首页","code":"trade","pid":null},{"id":"2","name":"交易管理","code":"trade","pid":null,"children":[{"id":"3","name":"交易查询","code":"trade-1","pid":"2","children":[{"id":"4","name":"交易查询-查询操作","code":"trade-1-1","pid":"3"}]}]},{"id":"5","name":"权限管理","code":"authorization","pid":null,"children":[{"id":"6","name":"角色管理","code":"authorization-1","pid":"5"},{"id":"7","name":"用户管理","code":"authorization-2","pid":"5"}]}]
2853
- *
2854
- * // 自定义子级字段名
2855
- * listToTree(basicMenus, { childrenField: 'childs' });
2856
- * // [{"id":"1","name":"首页","code":"trade","pid":null},{"id":"2","name":"交易管理","code":"trade","pid":null,"childs":[{"id":"3","name":"交易查询","code":"trade-1","pid":"2","childs":[{"id":"4","name":"交易查询-查询操作","code":"trade-1-1","pid":"3"}]}]},{"id":"5","name":"权限管理","code":"authorization","pid":null,"childs":[{"id":"6","name":"角色管理","code":"authorization-1","pid":"5"},{"id":"7","name":"用户管理","code":"authorization-2","pid":"5"}]}]
2857
- *
2858
- */
2859
- function listToTree(list, options) {
2860
- var _ref2 = options || {},
2861
- _ref2$keyField = _ref2.keyField,
2862
- keyField = _ref2$keyField === void 0 ? 'id' : _ref2$keyField,
2863
- _ref2$parentField = _ref2.parentField,
2864
- parentField = _ref2$parentField === void 0 ? 'pid' : _ref2$parentField,
2865
- _ref2$childrenField = _ref2.childrenField,
2866
- childrenField = _ref2$childrenField === void 0 ? 'children' : _ref2$childrenField,
2867
- _ref2$emptyChildrenVa = _ref2.emptyChildrenValue,
2868
- emptyChildrenValue = _ref2$emptyChildrenVa === void 0 ? 'none' : _ref2$emptyChildrenVa,
2869
- _ref2$nodeAssign = _ref2.nodeAssign,
2870
- nodeAssign = _ref2$nodeAssign === void 0 ? 'spread' : _ref2$nodeAssign;
2871
-
2872
- /** @type {R[]} */
2873
- var tree = [];
2874
-
2875
- /** @type {Object.<string, T[]>} */
2876
- var record = {};
2877
- if (!Array.isArray(list)) {
2878
- return tree;
2879
- }
2880
- list.forEach(function (item) {
2881
- if (isObject(item)) {
2882
- var newItem = nodeAssign === 'spread' ? _objectSpread2({}, item) : item;
2883
-
2884
- /** @type {string} */
2885
- var id = newItem[keyField];
2886
-
2887
- /** @type {string} */
2888
- var pid = newItem[parentField];
2889
- if (record[id]) {
2890
- // @ts-ignore
2891
- newItem[childrenField] = record[id];
2892
- } else {
2893
- // @ts-ignore
2894
- newItem[childrenField] = record[id] = [];
2895
- }
2896
- if (pid) {
2897
- if (!record[pid]) {
2898
- record[pid] = [newItem];
2899
- } else {
2900
- record[pid].push(newItem);
2901
- }
2902
- } else {
2903
- // @ts-ignore
2904
- tree.push(newItem);
2905
- }
2906
- }
2907
- });
2908
- if (emptyChildrenValue !== 'array') {
2909
- // @ts-ignore
2910
- processEmptyChildren(tree, options);
2911
- }
2912
- return tree;
2913
- }
2914
-
2915
- /**
2916
- * 树结构转列表数据
2917
- *
2918
- * @static
2919
- * @alias module:Processor.treeToList
2920
- * @since 4.14.0
2921
- * @template {Record<string,any>} T
2922
- * @template {keyof T} K
2923
- * @template {Omit<T, K>} R
2924
- * @param {T[]} tree 列表数据
2925
- * @param {K} childrenField 子级字段名称
2926
- * @returns {R[]} 列表数据
2927
- * @example
2928
- * const menus = [{ "id": "1", "name": "首页", "code": "trade", "pid": null }, { "id": "2", "name": "交易管理", "code": "trade", "pid": null, "children": [{ "id": "3", "name": "交易查询", "code": "trade-1", "pid": "2", "children": [{ "id": "4", "name": "交易查询-查询操作", "code": "trade-1-1", "pid": "3" }] }] }, { "id": "5", "name": "权限管理", "code": "authorization", "pid": null, "children": [{ "id": "6", "name": "角色管理", "code": "authorization-1", "pid": "5" }, { "id": "7", "name": "用户管理", "code": "authorization-2", "pid": "5" }] }];
2929
- *
2930
- * treeToList(menus, 'children'));
2931
- * // [{"id":"1","name":"首页","code":"trade","pid":null},{"id":"2","name":"交易管理","code":"trade","pid":null},{"id":"3","name":"交易查询","code":"trade-1","pid":"2"},{"id":"4","name":"交易查询-查询操作","code":"trade-1-1","pid":"3"},{"id":"5","name":"权限管理","code":"authorization","pid":null},{"id":"6","name":"角色管理","code":"authorization-1","pid":"5"},{"id":"7","name":"用户管理","code":"authorization-2","pid":"5"}]
2932
- */
2933
- function treeToList(tree, childrenField) {
2934
- /** @type {R[]} */
2935
- var list = [];
2936
- if (!Array.isArray(tree)) {
2937
- return list;
2938
- }
2939
-
2940
- /**
2941
- * 递归遍历
2942
- * @param {T[]} arr 列表数据
2943
- */
2944
- function recusion(arr) {
2945
- arr.forEach(function (item) {
2946
- if (isObject(item)) {
2947
- var newItem = _objectSpread2({}, item);
2948
- // @ts-ignore
2949
- list.push(newItem);
2950
- if (newItem[childrenField]) {
2951
- if (Array.isArray(newItem[childrenField]) && newItem[childrenField].length > 0) {
2952
- recusion(newItem[childrenField]);
2953
- }
2954
- delete newItem[childrenField];
2955
- }
2956
- } else {
2957
- // @ts-ignore
2958
- list.push(item);
2959
- }
2960
- });
2961
- }
2962
- recusion(tree);
2963
- return list;
2964
- }
2965
-
2966
- /**
2967
- * 过滤/筛选树节点。<br/><br/>如果某节点被过滤掉,它的子节点也一并抛弃
2968
- *
2969
- * @static
2970
- * @alias module:Processor.filterTree
2971
- * @since 4.15.0
2972
- * @template {any} T
2973
- * @template {(item: T) => boolean} F
2974
- * @param {T[]} tree 树结构数据
2975
- * @param {F} predicate 遍历每一项执行的函数,参数是当前遍历到的节点数据,如果返回 Truthy ,结果将包含该节点
2976
- * @param {string} [childrenField='children'] 子级字段名
2977
- * @param {'spread'|'self'} [nodeAssign='spread'] 节点赋值方式。spread表示使用展开运算符创建新值,self表示使用自身对象。
2978
- * @returns {T[]}
2979
- * @example
2980
- * const menus = [{ "id": "1", "name": "首页", "code": "trade", "pid": null }, { "id": "2", "name": "交易管理", "code": "trade", "pid": null, "children": [{ "id": "3", "name": "交易查询", "code": "trade-1", "pid": "2", "children": [{ "id": "4", "name": "交易查询-查询操作", "code": "trade-1-1", "pid": "3" }] }] }, { "id": "5", "name": "权限管理", "code": "authorization", "pid": null, "children": [{ "id": "6", "name": "角色管理", "code": "authorization-1", "pid": "5" }, { "id": "7", "name": "用户管理", "code": "authorization-2", "pid": "5" }] }];
2981
- *
2982
- * filterTree(menus, item=>item.name.indexOf('管理') > -1);
2983
- * // [{"id":"2","name":"交易管理","code":"trade","pid":null,"children":[]},{"id":"5","name":"权限管理","code":"authorization","pid":null,"children":[{"id":"6","name":"角色管理","code":"authorization-1","pid":"5"},{"id":"7","name":"用户管理","code":"authorization-2","pid":"5"}]}]
2984
- *
2985
- * // 如果某节点被过滤掉,它的子节点也一并抛弃
2986
- * filterTree(menus, item=>item.id === '7');
2987
- * // []
2988
- *
2989
- * filterTree(menus, item=>item.id === 'not found');
2990
- * // []
2991
- */
2992
- function filterTree(tree, predicate) {
2993
- var childrenField = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'children';
2994
- var nodeAssign = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'spread';
2995
- /** @type {T[]} */
2996
- var result = [];
2997
- if (!Array.isArray(tree)) {
2998
- return result;
2999
- }
3000
- tree.forEach(function (item) {
3001
- var newItem = item;
3002
- if (isObject(item)) {
3003
- // @ts-ignore
3004
- newItem = nodeAssign === 'spread' ? _objectSpread2({}, item) : item;
3005
- }
3006
- if (predicate(newItem)) {
3007
- if (isObject(newItem)) {
3008
- /** @type {T[]|undefined} */
3009
- // @ts-ignore
3010
- var childs = newItem[childrenField];
3011
- if (Array.isArray(childs) && childs.length > 0) {
3012
- // @ts-ignore
3013
- newItem[childrenField] = filterTree(childs, predicate, childrenField, nodeAssign);
3014
- }
3015
- }
3016
- result.push(newItem);
3017
- }
3018
- });
3019
- return result;
3020
- }
3021
-
3022
- /**
3023
- * 精确乘法,支持多个数相乘,乘数默认为 1 。
3024
- *
3025
- * @static
3026
- * @alias module:Math.times
2893
+ * @alias module:Math.minus
3027
2894
  * @since 3.1.0
3028
- * @param {...number|string} nums 相乘的数
3029
- * @returns {number} 乘积
2895
+ * @param {...number|string} nums 相减的数
2896
+ * @returns {number}
3030
2897
  * @example
3031
2898
  *
3032
- * times(3, 0.6); // 1.8
3033
- * times(3, 0.6, 2); // 3.6
3034
- * times(3, 0.6, 2, 10); // 36
2899
+ * minus(1, 0.9); // 0.1
2900
+ * minus(1, 0.9, 0.02); // 0.08
2901
+ * minus(1, 0.9, 0.02, 0.08); // 0
3035
2902
  *
3036
2903
  */
3037
- function times() {
2904
+ function minus() {
3038
2905
  for (var _len = arguments.length, nums = new Array(_len), _key = 0; _key < _len; _key++) {
3039
2906
  nums[_key] = arguments[_key];
3040
2907
  }
3041
2908
  var num1 = nums[0],
3042
2909
  _nums$ = nums[1],
3043
- num2 = _nums$ === void 0 ? 1 : _nums$,
2910
+ num2 = _nums$ === void 0 ? 0 : _nums$,
3044
2911
  rest = nums.slice(2);
3045
2912
  if (rest.length > 0) {
3046
- return times.apply(void 0, [times(num1, num2)].concat(_toConsumableArray(rest)));
2913
+ return minus.apply(void 0, [minus(num1, num2)].concat(_toConsumableArray(rest)));
3047
2914
  }
3048
2915
  num1 = transformEffectiveNumber(num1);
3049
2916
  num2 = transformEffectiveNumber(num2);
@@ -3053,39 +2920,40 @@
3053
2920
  if (isNaN(num1) || isNaN(num2)) {
3054
2921
  return Number.NaN;
3055
2922
  }
3056
- var num1Changed = float2Fixed(num1);
3057
- var num2Changed = float2Fixed(num2);
3058
- var baseNum = digitLength(num1) + digitLength(num2);
3059
- var leftValue = num1Changed * num2Changed;
3060
- checkBoundary(leftValue);
3061
- return leftValue / Math.pow(10, baseNum);
2923
+ var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
2924
+ return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
3062
2925
  }
3063
2926
 
3064
2927
  /**
3065
- * 精确加法,支持多个数相加,加数默认为 0
2928
+ * 精确除法,支持多个数相除,除数默认为 1
3066
2929
  *
3067
2930
  * @static
3068
- * @alias module:Math.plus
2931
+ * @alias module:Math.divide
3069
2932
  * @since 3.1.0
3070
- * @param {...number|string} nums 相加的数
3071
- * @returns {number} 总和
2933
+ * @param {...number|string} nums 被除数和除数
2934
+ * @returns {number} 商数
3072
2935
  * @example
3073
2936
  *
3074
- * plus(0.1, 0.2); // 0.3
3075
- * plus(0.1, 0.2, 0.3); // 0.6
3076
- * plus(0.1, 0.2, 0.3, 0.4); // 1
2937
+ * divide(1.21); // 1.21 除数默认为 1 ,即 1.21/1 = 1.21
2938
+ * divide(1.21, 1.1); // 1.1
2939
+ * divide(1000, 10, 10); // 10
2940
+ * divide(1000, 10, 10, 10); // 1
2941
+ *
2942
+ * divide(); // NaN 如果没有传入参数,被除数默认为 undefined 。 Number(undefined) 转换为 NaN ,NaN/1 = NaN
2943
+ * divide(null); // 0 Number(null) 转换为 0 , 0/1 = 0
2944
+ * divide('1.5 ', 0.5); // 3 Number('1.5 ') 转换为 1.5 ,1.5/0.5 = 3
3077
2945
  *
3078
2946
  */
3079
- function plus() {
2947
+ function divide() {
3080
2948
  for (var _len = arguments.length, nums = new Array(_len), _key = 0; _key < _len; _key++) {
3081
2949
  nums[_key] = arguments[_key];
3082
2950
  }
3083
2951
  var num1 = nums[0],
3084
2952
  _nums$ = nums[1],
3085
- num2 = _nums$ === void 0 ? 0 : _nums$,
2953
+ num2 = _nums$ === void 0 ? 1 : _nums$,
3086
2954
  rest = nums.slice(2);
3087
2955
  if (rest.length > 0) {
3088
- return plus.apply(void 0, [plus(num1, num2)].concat(_toConsumableArray(rest)));
2956
+ return divide.apply(void 0, [divide(num1, num2)].concat(_toConsumableArray(rest)));
3089
2957
  }
3090
2958
  num1 = transformEffectiveNumber(num1);
3091
2959
  num2 = transformEffectiveNumber(num2);
@@ -3095,100 +2963,19 @@
3095
2963
  if (isNaN(num1) || isNaN(num2)) {
3096
2964
  return Number.NaN;
3097
2965
  }
3098
- var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
3099
- return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
2966
+ var num1Changed = float2Fixed(num1);
2967
+ var num2Changed = float2Fixed(num2);
2968
+ checkBoundary(num1Changed);
2969
+ checkBoundary(num2Changed);
2970
+ // fix: 类似 10 ** -4 为 0.00009999999999999999,strip 修正
2971
+ return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) - digitLength(num1))));
3100
2972
  }
3101
2973
 
3102
2974
  /**
3103
- * 精确减法,支持多个数相减,减数默认为 0 。
2975
+ * 四舍五入,支持设置精度
3104
2976
  *
3105
2977
  * @static
3106
- * @alias module:Math.minus
3107
- * @since 3.1.0
3108
- * @param {...number|string} nums 相减的数
3109
- * @returns {number} 差
3110
- * @example
3111
- *
3112
- * minus(1, 0.9); // 0.1
3113
- * minus(1, 0.9, 0.02); // 0.08
3114
- * minus(1, 0.9, 0.02, 0.08); // 0
3115
- *
3116
- */
3117
- function minus() {
3118
- for (var _len = arguments.length, nums = new Array(_len), _key = 0; _key < _len; _key++) {
3119
- nums[_key] = arguments[_key];
3120
- }
3121
- var num1 = nums[0],
3122
- _nums$ = nums[1],
3123
- num2 = _nums$ === void 0 ? 0 : _nums$,
3124
- rest = nums.slice(2);
3125
- if (rest.length > 0) {
3126
- return minus.apply(void 0, [minus(num1, num2)].concat(_toConsumableArray(rest)));
3127
- }
3128
- num1 = transformEffectiveNumber(num1);
3129
- num2 = transformEffectiveNumber(num2);
3130
-
3131
- // 兼容处理,如果参数包含无效数值时,返回 NaN
3132
- // @ts-ignore
3133
- if (isNaN(num1) || isNaN(num2)) {
3134
- return Number.NaN;
3135
- }
3136
- var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
3137
- return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
3138
- }
3139
-
3140
- /**
3141
- * 精确除法,支持多个数相除,除数默认为 1 。
3142
- *
3143
- * @static
3144
- * @alias module:Math.divide
3145
- * @since 3.1.0
3146
- * @param {...number|string} nums 被除数和除数
3147
- * @returns {number} 商数
3148
- * @example
3149
- *
3150
- * divide(1.21); // 1.21 除数默认为 1 ,即 1.21/1 = 1.21
3151
- * divide(1.21, 1.1); // 1.1
3152
- * divide(1000, 10, 10); // 10
3153
- * divide(1000, 10, 10, 10); // 1
3154
- *
3155
- * divide(); // NaN 如果没有传入参数,被除数默认为 undefined 。 Number(undefined) 转换为 NaN ,NaN/1 = NaN
3156
- * divide(null); // 0 Number(null) 转换为 0 , 0/1 = 0
3157
- * divide('1.5 ', 0.5); // 3 Number('1.5 ') 转换为 1.5 ,1.5/0.5 = 3
3158
- *
3159
- */
3160
- function divide() {
3161
- for (var _len = arguments.length, nums = new Array(_len), _key = 0; _key < _len; _key++) {
3162
- nums[_key] = arguments[_key];
3163
- }
3164
- var num1 = nums[0],
3165
- _nums$ = nums[1],
3166
- num2 = _nums$ === void 0 ? 1 : _nums$,
3167
- rest = nums.slice(2);
3168
- if (rest.length > 0) {
3169
- return divide.apply(void 0, [divide(num1, num2)].concat(_toConsumableArray(rest)));
3170
- }
3171
- num1 = transformEffectiveNumber(num1);
3172
- num2 = transformEffectiveNumber(num2);
3173
-
3174
- // 兼容处理,如果参数包含无效数值时,返回 NaN
3175
- // @ts-ignore
3176
- if (isNaN(num1) || isNaN(num2)) {
3177
- return Number.NaN;
3178
- }
3179
- var num1Changed = float2Fixed(num1);
3180
- var num2Changed = float2Fixed(num2);
3181
- checkBoundary(num1Changed);
3182
- checkBoundary(num2Changed);
3183
- // fix: 类似 10 ** -4 为 0.00009999999999999999,strip 修正
3184
- return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) - digitLength(num1))));
3185
- }
3186
-
3187
- /**
3188
- * 四舍五入,支持设置精度
3189
- *
3190
- * @static
3191
- * @alias module:Math.round
2978
+ * @alias module:Math.round
3192
2979
  * @since 3.1.0
3193
2980
  * @param {number|string} num 要四舍五入的数字
3194
2981
  * @param {number} [precision=0] 四舍五入的精度
@@ -3214,29 +3001,150 @@
3214
3001
  }
3215
3002
 
3216
3003
  /**
3217
- * 等待时间返回 Promise 。常用于异步方法中延时。
3218
- *
3004
+ * @typedef {XMLHttpRequest['onloadstart']} XMLHttpRequestEvent XMLHttpRequest 事件对象
3005
+ */
3006
+
3007
+ /**
3008
+ * @see {@link https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest|XMLHttpRequest}
3009
+ * @typedef {Object} AjaxOptions ajax配置项
3010
+ * @property {string} [method="get"] 创建请求时使用的方法
3011
+ * @property {Document | XMLHttpRequestBodyInit | null} [data=null] 请求体被发送的数据
3012
+ * @property {Object.<string, string>} [headers] 自定义请求头
3013
+ * @property {XMLHttpRequestResponseType} [responseType] 响应类型
3014
+ * @property {number} [timeout] 请求超时的毫秒数
3015
+ * @property {boolean} [withCredentials=false] 跨域请求时是否需要使用凭证
3016
+ * @property {boolean} [async=true] 是否异步执行操作
3017
+ * @property {string|null} [user=null] 用户名,用于认证用途
3018
+ * @property {string|null} [password=null] 密码,用于认证用途
3019
+ * @property {XMLHttpRequestEvent} [onLoadStart] 接收到响应数据时触发
3020
+ * @property {XMLHttpRequestEvent} [onProgress] 请求接收到更多数据时,周期性地触发
3021
+ * @property {XMLHttpRequestEvent} [onAbort] 当 request 被停止时触发,例如当程序调用 XMLHttpRequest.abort() 时
3022
+ * @property {XMLHttpRequestEvent} [onTimeout] 在预设时间内没有接收到响应时触发
3023
+ * @property {XMLHttpRequestEvent} [onError] 当 request 遭遇错误时触发
3024
+ * @property {XMLHttpRequestEvent} [onLoad] 请求成功完成时触发
3025
+ * @property {XMLHttpRequestEvent} [onLoadEnd] 请求结束时触发,无论请求成功 (load) 还是失败 (abort 或 error)
3026
+ */
3027
+
3028
+ /**
3029
+ * 请求<br/><br/>
3030
+ *
3031
+ * <em style="font-weight: bold;">注意:该方法仅适用于浏览器端。</em>
3032
+ *
3219
3033
  * @static
3220
- * @alias module:Other.waitTime
3221
- * @since 4.2.0
3222
- * @param {number} [time=1000] 延时时间,单位毫秒
3223
- * @returns {Promise<void>}
3034
+ * @alias module:Other.ajax
3035
+ * @since 4.16.0
3036
+ * @see {@link https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest|XMLHttpRequest}
3037
+ * @param {string} url 地址
3038
+ * @param {AjaxOptions} [options] 配置项
3039
+ * @returns {Promise<ProgressEvent<EventTarget>>}
3224
3040
  * @example
3225
- *
3226
- * const test = async ()=>{
3227
- * await waitTime();
3228
- * // do something
3229
- * }
3230
- *
3231
- * waitTime(500).then(()=>{
3041
+ * ajax('/somefile').then(res=>{
3232
3042
  * // do something
3233
3043
  * });
3234
3044
  *
3045
+ * ajax('/api', { method: 'post' }).then(res=>{
3046
+ * // do something
3047
+ * });
3235
3048
  */
3236
- function waitTime() {
3237
- var time = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1000;
3238
- return new Promise(function (resolve) {
3239
- setTimeout(resolve, time);
3049
+ function ajax(url, options) {
3050
+ var _ref = options || {},
3051
+ _ref$method = _ref.method,
3052
+ method = _ref$method === void 0 ? 'get' : _ref$method,
3053
+ _ref$data = _ref.data,
3054
+ data = _ref$data === void 0 ? null : _ref$data,
3055
+ timeout = _ref.timeout,
3056
+ headers = _ref.headers,
3057
+ _ref$withCredentials = _ref.withCredentials,
3058
+ withCredentials = _ref$withCredentials === void 0 ? false : _ref$withCredentials,
3059
+ _ref$async = _ref.async,
3060
+ async = _ref$async === void 0 ? true : _ref$async,
3061
+ _ref$user = _ref.user,
3062
+ user = _ref$user === void 0 ? null : _ref$user,
3063
+ _ref$password = _ref.password,
3064
+ password = _ref$password === void 0 ? null : _ref$password,
3065
+ responseType = _ref.responseType,
3066
+ onAbort = _ref.onAbort,
3067
+ onError = _ref.onError,
3068
+ onLoad = _ref.onLoad,
3069
+ onLoadEnd = _ref.onLoadEnd,
3070
+ onLoadStart = _ref.onLoadStart,
3071
+ onProgress = _ref.onProgress,
3072
+ onTimeout = _ref.onTimeout;
3073
+ return new Promise(function (resolve, reject) {
3074
+ var xhr = new XMLHttpRequest();
3075
+ xhr.open(method.toLowerCase(), url, async, user, password);
3076
+
3077
+ // 设置请求超时
3078
+ if (typeof timeout === 'number' && timeout > 0) {
3079
+ xhr.timeout = timeout;
3080
+ }
3081
+
3082
+ // 跨域请求时是否需要使用凭证
3083
+ xhr.withCredentials = withCredentials;
3084
+
3085
+ // 设置响应类型
3086
+ if (responseType) {
3087
+ xhr.responseType = responseType;
3088
+ }
3089
+
3090
+ // 设置请求头
3091
+ if (_typeof(headers) === 'object') {
3092
+ Object.keys(headers).map(function (item) {
3093
+ xhr.setRequestHeader(item, headers[item]);
3094
+ });
3095
+ }
3096
+
3097
+ /**
3098
+ * 请求成功异步调用
3099
+ * @param {XMLHttpRequestEvent} [cb] 回调方法
3100
+ */
3101
+ var wrapSuccess = function wrapSuccess(cb) {
3102
+ /**
3103
+ * 内部方法
3104
+ * @param {ProgressEvent<EventTarget>} e 事件对象
3105
+ */
3106
+ return function (e) {
3107
+ resolve(e);
3108
+ cb === null || cb === void 0 ? void 0 : cb.call(xhr, e);
3109
+ };
3110
+ };
3111
+
3112
+ /**
3113
+ * 请求失败(中断/超时/失败)处理
3114
+ * @param {XMLHttpRequestEvent} [cb] 回调方法
3115
+ */
3116
+ var wrapError = function wrapError(cb) {
3117
+ /**
3118
+ * 内部方法
3119
+ * @param {ProgressEvent<EventTarget>} e 事件对象
3120
+ */
3121
+ return function (e) {
3122
+ reject(e);
3123
+ cb === null || cb === void 0 ? void 0 : cb.call(xhr, e);
3124
+ };
3125
+ };
3126
+
3127
+ // 事件处理
3128
+ /**@type {Object.<keyof XMLHttpRequestEventTargetEventMap, XMLHttpRequestEvent | undefined>} */
3129
+ var events = {
3130
+ loadstart: onLoadStart,
3131
+ progress: onProgress,
3132
+ abort: wrapError(onAbort),
3133
+ timeout: wrapError(onTimeout),
3134
+ error: wrapError(onError),
3135
+ load: wrapSuccess(onLoad),
3136
+ loadend: onLoadEnd
3137
+ };
3138
+ /**@type {(keyof XMLHttpRequestEventTargetEventMap)[]} */
3139
+ // @ts-ignore
3140
+ var eventNames = Object.keys(events);
3141
+ eventNames.map(function (item) {
3142
+ var func = events[item];
3143
+ if (func) {
3144
+ xhr.addEventListener(item, func);
3145
+ }
3146
+ });
3147
+ xhr.send(data);
3240
3148
  });
3241
3149
  }
3242
3150
 
@@ -3293,6 +3201,154 @@
3293
3201
  return pos;
3294
3202
  }
3295
3203
 
3204
+ /**
3205
+ * 下载文件
3206
+ *
3207
+ * @param {string} blobUrl blob 地址
3208
+ * @param {string} [fileName] 文件名称
3209
+ */
3210
+ function saver(blobUrl, fileName) {
3211
+ var anchor = document.createElement('a');
3212
+ // anchor.href = decodeURIComponent(blobUrl);
3213
+ anchor.href = blobUrl;
3214
+ anchor.style.display = 'none';
3215
+ anchor.setAttribute('download', fileName || '');
3216
+
3217
+ /**
3218
+ * 处理点击事件,防止事件冒泡到 body/html 的点击事件。
3219
+ *
3220
+ * @param {MouseEvent} e 鼠标事件对象
3221
+ */
3222
+ function handleClick(e) {
3223
+ e.stopPropagation();
3224
+ anchor.removeEventListener('click', handleClick);
3225
+ }
3226
+ anchor.addEventListener('click', handleClick);
3227
+ document.body.appendChild(anchor);
3228
+ anchor.click();
3229
+ document.body.removeChild(anchor);
3230
+ }
3231
+
3232
+ /**
3233
+ * @typedef {import('./ajax.js').AjaxOptions} AjaxOptions ajax 配置项
3234
+ */
3235
+
3236
+ /**
3237
+ * @callback TransformRequest
3238
+ * @param {AjaxOptions} options ajax 配置项
3239
+ * @returns {AjaxOptions}
3240
+ */
3241
+
3242
+ /**
3243
+ * @callback TransformResponse
3244
+ * @param {Blob} res 响应的Blob对象。如果你通过 transformRequest 修改了 responseType ,该参数将是该类型响应值。
3245
+ * @returns {Blob}
3246
+ */
3247
+
3248
+ /**
3249
+ * @typedef {Object} DownloadOptions 下载配置项
3250
+ * @property {string} [options.fileName] 文件名称
3251
+ * @property {string} [options.type] MIME 类型
3252
+ * @property {'url'|'text'} [options.dataType] 手动设置数据类型,默认会根据传入的数据判断类型,主要是为了区分 url 和 text 。<br/>如果你要下载的文本是 url ,请设置 'text' ;如果你要下载的 url 是绝对/相对路径,请设置 'url' 。
3253
+ * @property {TransformRequest} [options.transformRequest] 请求前触发,XHR 对象或配置调整
3254
+ * @property {TransformResponse} [options.transformResponse] 请求成功后触发,在传递给 then/catch 前,允许修改响应数据
3255
+ */
3256
+
3257
+ /**
3258
+ * 下载<br/><br/>
3259
+ *
3260
+ * <em style="font-weight: bold;">注意:该方法仅适用于浏览器端,兼容 IE10+ 和现代浏览器。</em>
3261
+ *
3262
+ * @static
3263
+ * @alias module:Other.download
3264
+ * @since 4.16.0
3265
+ * @see {@link https://zh.wikipedia.org/wiki/多用途互聯網郵件擴展|多用途互联网邮件扩展}
3266
+ * @param {string|Blob|ArrayBuffer|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array|BigInt64Array|BigUint64Array} data 字符串、blob数据或url地址
3267
+ * @param {string|DownloadOptions} [options] 文件名称 或 配置项
3268
+ * @returns {Promise<void>}
3269
+ * @example
3270
+ * // 文本
3271
+ * download('hello world', 'text.txt');
3272
+ *
3273
+ * // 远程文件
3274
+ * download('/xxx.jpg', { dataType: 'url' });
3275
+ *
3276
+ * // blob文件
3277
+ * download(new Blob(['hello world']), 'text.txt');
3278
+ *
3279
+ */
3280
+ function download(data, options) {
3281
+ var config = _typeof(options) === 'object' ? options : {};
3282
+ if (typeof options === 'string') {
3283
+ config.fileName = options;
3284
+ }
3285
+ var fileName = config.fileName,
3286
+ type = config.type,
3287
+ dataType = config.dataType,
3288
+ transformRequest = config.transformRequest,
3289
+ transformResponse = config.transformResponse;
3290
+
3291
+ /** @type {Blob|undefined} */
3292
+ var payload;
3293
+
3294
+ // dataURLs、blob url、url、string
3295
+ if (typeof data === 'string') {
3296
+ if (!dataType && /^blob:.*?\/.*/.test(data)) {
3297
+ // blob url
3298
+ saver(data, fileName);
3299
+ return Promise.resolve();
3300
+ } else if (!dataType && /^data:([\w+-]+\/[\w+.-]+)?[,;]/.test(data)) {
3301
+ // dataURLs
3302
+ payload = dataURLToBlob(data);
3303
+ } else if (dataType === 'url' || !dataType && isUrl(data)) {
3304
+ // url
3305
+ /** @type {AjaxOptions} */
3306
+ var defaultAjaxOptions = {
3307
+ responseType: 'blob'
3308
+ };
3309
+ // 请求前配置调整
3310
+ var ajaxOptions = typeof transformRequest === 'function' ? transformRequest(defaultAjaxOptions) : defaultAjaxOptions;
3311
+ return ajax(data, ajaxOptions).then(function (e) {
3312
+ /** @type {Blob} */
3313
+ // @ts-ignore
3314
+ // 响应结果调整
3315
+ var res = typeof transformResponse === 'function' ? transformResponse(e.target.response) : e.target.response;
3316
+ var currentFileName = fileName || data.split("?")[0].split("#")[0].split("/").pop();
3317
+ return download(res, {
3318
+ fileName: currentFileName,
3319
+ type: type || (isBlob(res) ? res.type : undefined)
3320
+ });
3321
+ });
3322
+ } else {
3323
+ // string
3324
+ payload = new Blob([data], {
3325
+ type: type || 'text/plain'
3326
+ });
3327
+ }
3328
+ } else if (isBlob(data)) {
3329
+ // @ts-ignore
3330
+ payload = data;
3331
+ }
3332
+
3333
+ // html、TypedArray
3334
+ if (!(payload instanceof Blob)) {
3335
+ payload = new Blob([data], {
3336
+ type: type
3337
+ });
3338
+ }
3339
+
3340
+ // @ts-ignore
3341
+ if (navigator.msSaveBlob) {
3342
+ // @ts-ignore
3343
+ navigator.msSaveBlob(payload, fileName || 'download');
3344
+ } else {
3345
+ var url = URL.createObjectURL(payload);
3346
+ saver(url, fileName);
3347
+ URL.revokeObjectURL(url);
3348
+ }
3349
+ return Promise.resolve();
3350
+ }
3351
+
3296
3352
  var numberChars = '0123456789';
3297
3353
  var letterChars = 'abcdefghijklmnopqrstuvwxyz';
3298
3354
  var defaultChars = numberChars + letterChars + letterChars.toUpperCase();
@@ -3371,11 +3427,360 @@
3371
3427
  return len;
3372
3428
  }
3373
3429
 
3430
+ /**
3431
+ * 等待时间返回 Promise 。常用于异步方法中延时。
3432
+ *
3433
+ * @static
3434
+ * @alias module:Other.waitTime
3435
+ * @since 4.2.0
3436
+ * @param {number} [time=1000] 延时时间,单位毫秒
3437
+ * @returns {Promise<void>}
3438
+ * @example
3439
+ *
3440
+ * const test = async ()=>{
3441
+ * await waitTime();
3442
+ * // do something
3443
+ * }
3444
+ *
3445
+ * waitTime(500).then(()=>{
3446
+ * // do something
3447
+ * });
3448
+ *
3449
+ */
3450
+ function waitTime() {
3451
+ var time = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1000;
3452
+ return new Promise(function (resolve) {
3453
+ setTimeout(resolve, time);
3454
+ });
3455
+ }
3456
+
3457
+ /**
3458
+ * 转换字段名,返回一个转换字段后的值,不改变原值。
3459
+ *
3460
+ * @static
3461
+ * @alias module:Processor.transformFieldNames
3462
+ * @since 4.14.0
3463
+ * @template {*} D
3464
+ * @template {Record<string, keyof D>} F
3465
+ * @template {string} C
3466
+ * @param {D[]} data 对象数组。如果是树结构数据,需要指定第三个参数 childrenField
3467
+ * @param {F} fieldNames 字段名映射
3468
+ * @param {C} [childrenField] 子级数据字段名
3469
+ * @param {'spread'|'self'} [nodeAssign='spread'] 节点赋值方式。spread表示使用展开运算符创建新值,self表示使用自身对象。
3470
+ * @returns {import('./interface.type.js').TransformFieldNames<D, F, C>}
3471
+ * @example
3472
+ *
3473
+ * const options = [{code: '1', name: 'one'},{code:'2', name:'two'}];
3474
+ * const newOptions = transformFieldNames(options, {label: 'name', value: 'code'});
3475
+ * // [{value: '1', label: 'one'},{value:'2', label:'two'}]
3476
+ *
3477
+ * // 嵌套数据,指定子级字段名 children
3478
+ * const options2 = [{code: '1', name: 'one'},{code:'2', name:'two', children: [{code:'2-1', name:'two-one', children: [{code: '2-1-1', name:'two-one-one'}]}]}];
3479
+ * const newOptions2 = transformFieldNames(options2, {label: 'name', value: 'code'}, 'children');
3480
+ * // [{value: '1', label: 'one'},{value:'2', label:'two', children: [{value: '2-1', label:'two-one', children: [{value: '2-1-1', label:'two-one-one'}]}]}]
3481
+ *
3482
+ * const options3 = [{code: '1', name: 'one'},{code:'2', name:'two', childs: [{code:'2-1', name:'two-one'}]}];
3483
+ * const newOptions3 = transformFieldNames(options3, {label: 'name', value: 'code'}, 'childs');
3484
+ * // [{value: '1', label: 'one'},{value:'2', label:'two', childs: [{value: '2-1', label:'two-one'}]}]
3485
+ *
3486
+ * // 嵌套数据,并替换子集字段名
3487
+ * const newOptions4 = transformFieldNames(options3, {label: 'name', value: 'code', children: 'childs'}, 'childs');
3488
+ * // [{value: '1', label: 'one'},{value:'2', label:'two', children: [{value: '2-1', label:'two-one'}]}]
3489
+ */
3490
+ function transformFieldNames(data, fieldNames, childrenField) {
3491
+ var nodeAssign = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'spread';
3492
+ if (!Array.isArray(data)) {
3493
+ return data;
3494
+ }
3495
+ if (data.length <= 0) {
3496
+ // @ts-ignore
3497
+ return [];
3498
+ }
3499
+
3500
+ /**
3501
+ * 递归处理字段名
3502
+ *
3503
+ * @param {Array.<object>} arr 列表数据
3504
+ * @returns {*}
3505
+ */
3506
+ function recusion(arr) {
3507
+ return arr.map(function (item) {
3508
+ if (!isObject(item)) {
3509
+ return item;
3510
+ }
3511
+ var newItem = nodeAssign === 'spread' ? _objectSpread2({}, item) : item;
3512
+ /** @type {Array.<string>} */
3513
+ var delKeys = [];
3514
+
3515
+ // 树形数据子节点
3516
+ // @ts-ignore
3517
+ if (childrenField && Array.isArray(newItem[childrenField]) && newItem[childrenField].length > 0) {
3518
+ // @ts-ignore
3519
+ newItem[childrenField] = recusion(newItem[childrenField].slice());
3520
+ }
3521
+
3522
+ // 替换字段名
3523
+ Object.keys(fieldNames).forEach(function (newKey) {
3524
+ var oldKey = fieldNames[newKey];
3525
+ if (oldKey in newItem) {
3526
+ // @ts-ignore
3527
+ newItem[newKey] = newItem[oldKey];
3528
+ // @ts-ignore
3529
+ delKeys.push(oldKey);
3530
+ }
3531
+ });
3532
+
3533
+ // 删除旧字段
3534
+ if (delKeys.length > 0) {
3535
+ delKeys.forEach(function (delKey) {
3536
+ // @ts-ignore
3537
+ delete newItem[delKey];
3538
+ });
3539
+ }
3540
+ return newItem;
3541
+ });
3542
+ }
3543
+
3544
+ // @ts-ignore
3545
+ return recusion(data.slice());
3546
+ }
3547
+
3548
+ /**
3549
+ * 递归处理空子级
3550
+ *
3551
+ * @private
3552
+ * @template {Record<string,any>} [T=Record<string,any>]
3553
+ * @param {T[]} arr 列表数据
3554
+ * @param {object} [options] 配置项
3555
+ * @param {string} [options.childrenField='children'] 子级字段名称
3556
+ * @param {'none'|'null'} [options.emptyChildrenValue='none'] 子级为空时的值,none表示删除该子级,null表示为null,array表示为[]。
3557
+ */
3558
+ function processEmptyChildren(arr, options) {
3559
+ var _ref = options || {},
3560
+ _ref$childrenField = _ref.childrenField,
3561
+ childrenField = _ref$childrenField === void 0 ? 'children' : _ref$childrenField,
3562
+ _ref$emptyChildrenVal = _ref.emptyChildrenValue,
3563
+ emptyChildrenValue = _ref$emptyChildrenVal === void 0 ? 'none' : _ref$emptyChildrenVal;
3564
+ arr.forEach(function (item) {
3565
+ // if (isObject(item) && Array.isArray(item[childrenField])) {
3566
+ if (item[childrenField].length <= 0) {
3567
+ if (emptyChildrenValue === 'null') {
3568
+ // @ts-ignore
3569
+ item[childrenField] = null;
3570
+ // } else if (emptyChildrenValue === 'none') { // emptyChildrenValue='array' 不会执行该内部方法
3571
+ } else {
3572
+ delete item[childrenField];
3573
+ }
3574
+ } else {
3575
+ processEmptyChildren(item[childrenField], options);
3576
+ }
3577
+ // }
3578
+ });
3579
+ }
3580
+
3581
+ /**
3582
+ * 列表数据转树结构
3583
+ *
3584
+ * @static
3585
+ * @alias module:Tree.listToTree
3586
+ * @since 4.14.0
3587
+ * @template {Record<string,any>} [T=Record<string,any>]
3588
+ * @template {*} [R=T&Record<string,any>]
3589
+ * @param {T[]} list 列表数据
3590
+ * @param {object} [options] 配置项
3591
+ * @param {string} [options.keyField='id'] 当前数据的键值字段名称
3592
+ * @param {string} [options.parentField='pid'] 当前数据的父级字段名称
3593
+ * @param {string} [options.childrenField='children'] 子级字段名称
3594
+ * @param {'none'|'null'|'array'} [options.emptyChildrenValue='none'] 子级为空时的值,none表示删除该子级,null表示为null,array表示为[]。
3595
+ * @param {'spread'|'self'} [options.nodeAssign='spread'] 节点赋值方式。spread表示使用展开运算符创建新值,self表示使用自身对象。
3596
+ * @returns {R[]} 树结构
3597
+ * @example
3598
+ *
3599
+ * const menus = [
3600
+ * { id: '1', name: '首页', code: 'trade', pid: null },
3601
+ * { id: '2', name: '交易管理', code: 'trade', pid: null },
3602
+ * { id: '3', name: '交易查询', code: 'trade-1', pid: '2' },
3603
+ * { id: '4', name: '交易查询-查询操作', code: 'trade-1-1', pid: '3' },
3604
+ * { id: '5', name: '权限管理', code: 'authorization', pid: null },
3605
+ * { id: '6', name: '角色管理', code: 'authorization-1', pid: '5' },
3606
+ * { id: '7', name: '用户管理', code: 'authorization-2', pid: '5' }
3607
+ * ];
3608
+ * listToTree(menus);
3609
+ * // [{"id":"1","name":"首页","code":"trade","pid":null},{"id":"2","name":"交易管理","code":"trade","pid":null,"children":[{"id":"3","name":"交易查询","code":"trade-1","pid":"2","children":[{"id":"4","name":"交易查询-查询操作","code":"trade-1-1","pid":"3"}]}]},{"id":"5","name":"权限管理","code":"authorization","pid":null,"children":[{"id":"6","name":"角色管理","code":"authorization-1","pid":"5"},{"id":"7","name":"用户管理","code":"authorization-2","pid":"5"}]}]
3610
+ *
3611
+ * // 自定义子级字段名
3612
+ * listToTree(basicMenus, { childrenField: 'childs' });
3613
+ * // [{"id":"1","name":"首页","code":"trade","pid":null},{"id":"2","name":"交易管理","code":"trade","pid":null,"childs":[{"id":"3","name":"交易查询","code":"trade-1","pid":"2","childs":[{"id":"4","name":"交易查询-查询操作","code":"trade-1-1","pid":"3"}]}]},{"id":"5","name":"权限管理","code":"authorization","pid":null,"childs":[{"id":"6","name":"角色管理","code":"authorization-1","pid":"5"},{"id":"7","name":"用户管理","code":"authorization-2","pid":"5"}]}]
3614
+ *
3615
+ */
3616
+ function listToTree(list, options) {
3617
+ var _ref2 = options || {},
3618
+ _ref2$keyField = _ref2.keyField,
3619
+ keyField = _ref2$keyField === void 0 ? 'id' : _ref2$keyField,
3620
+ _ref2$parentField = _ref2.parentField,
3621
+ parentField = _ref2$parentField === void 0 ? 'pid' : _ref2$parentField,
3622
+ _ref2$childrenField = _ref2.childrenField,
3623
+ childrenField = _ref2$childrenField === void 0 ? 'children' : _ref2$childrenField,
3624
+ _ref2$emptyChildrenVa = _ref2.emptyChildrenValue,
3625
+ emptyChildrenValue = _ref2$emptyChildrenVa === void 0 ? 'none' : _ref2$emptyChildrenVa,
3626
+ _ref2$nodeAssign = _ref2.nodeAssign,
3627
+ nodeAssign = _ref2$nodeAssign === void 0 ? 'spread' : _ref2$nodeAssign;
3628
+
3629
+ /** @type {R[]} */
3630
+ var tree = [];
3631
+
3632
+ /** @type {Object.<string, T[]>} */
3633
+ var record = {};
3634
+ if (!Array.isArray(list)) {
3635
+ return tree;
3636
+ }
3637
+ list.forEach(function (item) {
3638
+ if (isObject(item)) {
3639
+ var newItem = nodeAssign === 'spread' ? _objectSpread2({}, item) : item;
3640
+
3641
+ /** @type {string} */
3642
+ var id = newItem[keyField];
3643
+
3644
+ /** @type {string} */
3645
+ var pid = newItem[parentField];
3646
+ if (record[id]) {
3647
+ // @ts-ignore
3648
+ newItem[childrenField] = record[id];
3649
+ } else {
3650
+ // @ts-ignore
3651
+ newItem[childrenField] = record[id] = [];
3652
+ }
3653
+ if (pid) {
3654
+ if (!record[pid]) {
3655
+ record[pid] = [newItem];
3656
+ } else {
3657
+ record[pid].push(newItem);
3658
+ }
3659
+ } else {
3660
+ // @ts-ignore
3661
+ tree.push(newItem);
3662
+ }
3663
+ }
3664
+ });
3665
+ if (emptyChildrenValue !== 'array') {
3666
+ // @ts-ignore
3667
+ processEmptyChildren(tree, options);
3668
+ }
3669
+ return tree;
3670
+ }
3671
+
3672
+ /**
3673
+ * 树结构转列表数据
3674
+ *
3675
+ * @static
3676
+ * @alias module:Tree.treeToList
3677
+ * @since 4.14.0
3678
+ * @template {Record<string,any>} T
3679
+ * @template {keyof T} K
3680
+ * @template {Omit<T, K>} R
3681
+ * @param {T[]} tree 列表数据
3682
+ * @param {K} childrenField 子级字段名称
3683
+ * @returns {R[]} 列表数据
3684
+ * @example
3685
+ * const menus = [{ "id": "1", "name": "首页", "code": "trade", "pid": null }, { "id": "2", "name": "交易管理", "code": "trade", "pid": null, "children": [{ "id": "3", "name": "交易查询", "code": "trade-1", "pid": "2", "children": [{ "id": "4", "name": "交易查询-查询操作", "code": "trade-1-1", "pid": "3" }] }] }, { "id": "5", "name": "权限管理", "code": "authorization", "pid": null, "children": [{ "id": "6", "name": "角色管理", "code": "authorization-1", "pid": "5" }, { "id": "7", "name": "用户管理", "code": "authorization-2", "pid": "5" }] }];
3686
+ *
3687
+ * treeToList(menus, 'children'));
3688
+ * // [{"id":"1","name":"首页","code":"trade","pid":null},{"id":"2","name":"交易管理","code":"trade","pid":null},{"id":"3","name":"交易查询","code":"trade-1","pid":"2"},{"id":"4","name":"交易查询-查询操作","code":"trade-1-1","pid":"3"},{"id":"5","name":"权限管理","code":"authorization","pid":null},{"id":"6","name":"角色管理","code":"authorization-1","pid":"5"},{"id":"7","name":"用户管理","code":"authorization-2","pid":"5"}]
3689
+ */
3690
+ function treeToList(tree, childrenField) {
3691
+ /** @type {R[]} */
3692
+ var list = [];
3693
+ if (!Array.isArray(tree)) {
3694
+ return list;
3695
+ }
3696
+
3697
+ /**
3698
+ * 递归遍历
3699
+ * @param {T[]} arr 列表数据
3700
+ */
3701
+ function recusion(arr) {
3702
+ arr.forEach(function (item) {
3703
+ if (isObject(item)) {
3704
+ var newItem = _objectSpread2({}, item);
3705
+ // @ts-ignore
3706
+ list.push(newItem);
3707
+ if (newItem[childrenField]) {
3708
+ if (Array.isArray(newItem[childrenField]) && newItem[childrenField].length > 0) {
3709
+ recusion(newItem[childrenField]);
3710
+ }
3711
+ delete newItem[childrenField];
3712
+ }
3713
+ } else {
3714
+ // @ts-ignore
3715
+ list.push(item);
3716
+ }
3717
+ });
3718
+ }
3719
+ recusion(tree);
3720
+ return list;
3721
+ }
3722
+
3723
+ /**
3724
+ * 过滤/筛选树节点。<br/><br/>如果某节点被过滤掉,它的子节点也一并抛弃
3725
+ *
3726
+ * @static
3727
+ * @alias module:Tree.filterTree
3728
+ * @since 4.15.0
3729
+ * @template {any} T
3730
+ * @template {(item: T) => boolean} F
3731
+ * @param {T[]} tree 树结构数据
3732
+ * @param {F} predicate 遍历每一项执行的函数,参数是当前遍历到的节点数据,如果返回 Truthy ,结果将包含该节点
3733
+ * @param {string} [childrenField='children'] 子级字段名
3734
+ * @param {'spread'|'self'} [nodeAssign='spread'] 节点赋值方式。spread表示使用展开运算符创建新值,self表示使用自身对象。
3735
+ * @returns {T[]}
3736
+ * @example
3737
+ * const menus = [{ "id": "1", "name": "首页", "code": "trade", "pid": null }, { "id": "2", "name": "交易管理", "code": "trade", "pid": null, "children": [{ "id": "3", "name": "交易查询", "code": "trade-1", "pid": "2", "children": [{ "id": "4", "name": "交易查询-查询操作", "code": "trade-1-1", "pid": "3" }] }] }, { "id": "5", "name": "权限管理", "code": "authorization", "pid": null, "children": [{ "id": "6", "name": "角色管理", "code": "authorization-1", "pid": "5" }, { "id": "7", "name": "用户管理", "code": "authorization-2", "pid": "5" }] }];
3738
+ *
3739
+ * filterTree(menus, item=>item.name.indexOf('管理') > -1);
3740
+ * // [{"id":"2","name":"交易管理","code":"trade","pid":null,"children":[]},{"id":"5","name":"权限管理","code":"authorization","pid":null,"children":[{"id":"6","name":"角色管理","code":"authorization-1","pid":"5"},{"id":"7","name":"用户管理","code":"authorization-2","pid":"5"}]}]
3741
+ *
3742
+ * // 如果某节点被过滤掉,它的子节点也一并抛弃
3743
+ * filterTree(menus, item=>item.id === '7');
3744
+ * // []
3745
+ *
3746
+ * filterTree(menus, item=>item.id === 'not found');
3747
+ * // []
3748
+ */
3749
+ function filterTree(tree, predicate) {
3750
+ var childrenField = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'children';
3751
+ var nodeAssign = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'spread';
3752
+ /** @type {T[]} */
3753
+ var result = [];
3754
+ if (!Array.isArray(tree)) {
3755
+ return result;
3756
+ }
3757
+ tree.forEach(function (item) {
3758
+ var newItem = item;
3759
+ if (isObject(item)) {
3760
+ // @ts-ignore
3761
+ newItem = nodeAssign === 'spread' ? _objectSpread2({}, item) : item;
3762
+ }
3763
+ if (predicate(newItem)) {
3764
+ if (isObject(newItem)) {
3765
+ /** @type {T[]|undefined} */
3766
+ // @ts-ignore
3767
+ var childs = newItem[childrenField];
3768
+ if (Array.isArray(childs) && childs.length > 0) {
3769
+ // @ts-ignore
3770
+ newItem[childrenField] = filterTree(childs, predicate, childrenField, nodeAssign);
3771
+ }
3772
+ }
3773
+ result.push(newItem);
3774
+ }
3775
+ });
3776
+ return result;
3777
+ }
3778
+
3374
3779
  /**
3375
3780
  * 查找树结构数据节点
3376
3781
  *
3377
3782
  * @static
3378
- * @alias module:Other.findTreeNode
3783
+ * @alias module:Tree.findTreeNode
3379
3784
  * @since 4.14.0
3380
3785
  * @template {any} T
3381
3786
  * @template {(item: T) => boolean} F
@@ -3443,7 +3848,7 @@
3443
3848
  * 查找树结构数据多个节点
3444
3849
  *
3445
3850
  * @static
3446
- * @alias module:Other.findTreeNodes
3851
+ * @alias module:Tree.findTreeNodes
3447
3852
  * @since 4.15.0
3448
3853
  * @template {any} T
3449
3854
  * @template {(item: T) => boolean} F
@@ -3557,7 +3962,7 @@
3557
3962
  * 查找包含当前节点的所有父级节点
3558
3963
  *
3559
3964
  * @static
3560
- * @alias module:Other.findTreeSelect
3965
+ * @alias module:Tree.findTreeSelect
3561
3966
  * @since 4.14.0
3562
3967
  * @template {any} T
3563
3968
  * @template {(item: T) => boolean} F
@@ -3582,11 +3987,14 @@
3582
3987
  return internalFindTreeSelect(tree, predicate, childrenField);
3583
3988
  }
3584
3989
 
3990
+ exports.ajax = ajax;
3585
3991
  exports.blobToDataURL = blobToDataURL;
3586
3992
  exports.bytesToSize = bytesToSize;
3587
3993
  exports.calculateCursorPosition = calculateCursorPosition;
3588
3994
  exports.dataURLToBlob = dataURLToBlob;
3589
3995
  exports.divide = divide;
3996
+ exports.download = download;
3997
+ exports.fileReader = fileReader;
3590
3998
  exports.filterTree = filterTree;
3591
3999
  exports.findTreeNode = findTreeNode;
3592
4000
  exports.findTreeNodes = findTreeNodes;