util-helpers 4.10.1 → 4.11.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.
@@ -500,7 +500,7 @@
500
500
  * @since 1.1.0
501
501
  * @param {*} value 要检测的值
502
502
  * @param {Object} [options] 配置项
503
- * @param {boolean} [options.loose=false] 宽松模式。如果为true,不校验校验位。
503
+ * @param {boolean} [options.checkCode=true] 是否校验最后一位校验码,如果为false,不校验校验位。
504
504
  * @returns {boolean} 值是否为统一社会信用代码
505
505
  * @example
506
506
  *
@@ -510,18 +510,25 @@
510
510
  * isSocialCreditCode('91350100M000100Y4A');
511
511
  * // => false
512
512
  *
513
- * // 宽松模式,不校验校验位。所以也可以通过
514
- * isSocialCreditCode('91350100M000100Y4A', {loose: true});
513
+ * // 不校验校验位
514
+ * isSocialCreditCode('91350100M000100Y4A', { checkCode: false });
515
515
  * // => true
516
516
  *
517
+ * isSocialCreditCode('91350100M000100Y', { checkCode: false });
518
+ * // => false
519
+ *
517
520
  */
518
- function isSocialCreditCode(value, { loose = false } = {}) {
521
+ function isSocialCreditCode(value, options = {}) {
519
522
  const valueStr = normalizeString(value);
523
+ // @ts-ignore
524
+ // TODO 下个版本废弃 loose
525
+ const { loose = false, checkCode: cc = true } = options;
526
+ const needCheckCode = !loose && cc;
520
527
 
521
528
  const passBaseRule = baseReg$1.test(valueStr);
522
529
 
523
530
  // 宽松模式 或 基础规则不通过直接返回
524
- if (loose || !passBaseRule) {
531
+ if (!needCheckCode || !passBaseRule) {
525
532
  return passBaseRule;
526
533
  }
527
534
 
@@ -551,6 +558,17 @@
551
558
  config.disableWarning = !!bool;
552
559
  }
553
560
 
561
+ /**
562
+ * 打印警告信息
563
+ *
564
+ * @param {any[]} args 打印的信息
565
+ */
566
+ function devWarn(...args) {
567
+ if (!config.disableWarning) {
568
+ console.warn(...args);
569
+ }
570
+ }
571
+
554
572
  const regNumber = /[\d]/;
555
573
  const regLowerCaseLetter = /[a-z]/;
556
574
  const regUpperCaseLetter = /[A-Z]/;
@@ -605,15 +623,20 @@
605
623
  *
606
624
  * @private
607
625
  * @param {string} val 检测的值
608
- * @param {string} [chars] 特殊字符
626
+ * @param {string} chars 特殊字符
609
627
  * @returns {boolean} 是否包含特殊字符
610
628
  */
611
- function hasSpecialCharacter(val, chars = '') {
612
- if (!chars) {
629
+ function hasSpecialCharacter(val, chars) {
630
+ if (!chars || !val) {
613
631
  return false;
614
632
  }
615
633
 
616
634
  const specialChars = val.replace(regAllNumberAndLetter, '');
635
+
636
+ if (!specialChars) {
637
+ return false;
638
+ }
639
+
617
640
  const regChars = hasHex(chars) ? new RegExp(`[${chars}]`) : null;
618
641
 
619
642
  if (regChars) {
@@ -635,13 +658,19 @@
635
658
  *
636
659
  * @private
637
660
  * @param {string} val 检测的值
638
- * @param {string} chars 非法字符
661
+ * @param {string} chars 特殊字符
639
662
  * @returns {boolean} 是否包含非法字符
640
663
  */
641
- function hasUnallowableCharacter(val, chars = '') {
664
+ function hasUnallowableCharacter(val, chars) {
665
+ if (!val) {
666
+ return false;
667
+ }
668
+
642
669
  const specialChars = val.replace(regAllNumberAndLetter, '');
643
670
 
644
- if (!chars && specialChars) {
671
+ if (!specialChars) {
672
+ return false;
673
+ } else if (!chars) {
645
674
  return true;
646
675
  }
647
676
 
@@ -704,7 +733,7 @@
704
733
  * }
705
734
  * }
706
735
  *
707
- * validatePassword('a12345678', {level: 3});
736
+ * validatePassword('a12345678', { level: 3 });
708
737
  * // =>
709
738
  * {
710
739
  * validated: false,
@@ -718,7 +747,7 @@
718
747
  * }
719
748
  * }
720
749
  *
721
- * validatePassword('_Aa一二三45678', {level: 3, ignoreCase: true});
750
+ * validatePassword('_Aa一二三45678', { level: 3, ignoreCase: true });
722
751
  * // =>
723
752
  * {
724
753
  * validated: false,
@@ -733,7 +762,7 @@
733
762
  * }
734
763
  *
735
764
  * // 自定义特殊字符
736
- * validatePassword('_Aa一二三45678', {level: 3, ignoreCase: true, special: '_一二三'});
765
+ * validatePassword('_Aa一二三45678', { level: 3, ignoreCase: true, special: '_一二三' });
737
766
  * // =>
738
767
  * {
739
768
  * validated: true,
@@ -751,9 +780,7 @@
751
780
  let valStr = value;
752
781
 
753
782
  if (typeof value !== 'string') {
754
- if (!config.disableWarning) {
755
- console.warn(`[validatePassword] value must be a string.`);
756
- }
783
+ devWarn(`[validatePassword] value must be a string.`);
757
784
  valStr = '';
758
785
  }
759
786
 
@@ -767,15 +794,15 @@
767
794
  const containesUpperCaseLetter = hasUpperCaseLetter(valStr);
768
795
  // 包含特殊字符
769
796
  const containesSpecialCharacter = hasSpecialCharacter(valStr, special);
770
- // 包含非法字符
797
+ // 包含非法字符,即含有非数字字母特殊字符以外的其他字符
771
798
  const containesUnallowableCharacter = hasUnallowableCharacter(valStr, special);
772
799
 
773
800
  if (containesNumber) {
774
801
  currentLevel += 1;
775
802
  }
776
803
 
804
+ // 不区分大小写
777
805
  if (ignoreCase) {
778
- // 不区分大小写
779
806
  if (containesLowerCaseLetter || containesUpperCaseLetter) {
780
807
  currentLevel += 1;
781
808
  }
@@ -906,18 +933,16 @@
906
933
  chineseExtendF: '[\u{2CEB0}-\u{2EBE0}]'
907
934
  };
908
935
 
909
- let looseChineseRegExp = chineseDictionary.chineseBasic + '+';
936
+ const looseChineseRegExp = chineseDictionary.chineseBasic + '+';
937
+ const chineseRegExp = '^' + chineseDictionary.chineseBasic + '+$';
910
938
 
911
- let chineseRegExp = '^' + chineseDictionary.chineseBasic + '+$';
939
+ const chineseWithExtend = '(?:' + chineseDictionary.chineseBasic + '|' + chineseDictionary.chineseExtend + '|' + chineseDictionary.chineseExtendA + '|' + chineseDictionary.chineseExtendB + '|' + chineseDictionary.chineseExtendC + '|' + chineseDictionary.chineseExtendD + '|' + chineseDictionary.chineseExtendE + '|' + chineseDictionary.chineseExtendF + ')';
940
+ const looseChineseExtendRegExp = chineseWithExtend + '+';
941
+ const chineseExtendRegExp = '^' + chineseWithExtend + '+$';
912
942
 
913
943
  // eslint-disable-next-line no-prototype-builtins
914
944
  const supportRegExpUnicode = RegExp.prototype.hasOwnProperty('unicode');
915
945
 
916
- if (supportRegExpUnicode) {
917
- looseChineseRegExp = '(?:' + chineseDictionary.chineseBasic + '|' + chineseDictionary.chineseExtend + '|' + chineseDictionary.chineseExtendA + '|' + chineseDictionary.chineseExtendB + '|' + chineseDictionary.chineseExtendC + '|' + chineseDictionary.chineseExtendD + '|' + chineseDictionary.chineseExtendE + '|' + chineseDictionary.chineseExtendF + ')+';
918
- chineseRegExp = '^(?:' + chineseDictionary.chineseBasic + '|' + chineseDictionary.chineseExtend + '|' + chineseDictionary.chineseExtendA + '|' + chineseDictionary.chineseExtendB + '|' + chineseDictionary.chineseExtendC + '|' + chineseDictionary.chineseExtendD + '|' + chineseDictionary.chineseExtendE + '|' + chineseDictionary.chineseExtendF + ')+$';
919
- }
920
-
921
946
  /**
922
947
  * 检测值是否为中文
923
948
  *
@@ -928,6 +953,7 @@
928
953
  * @param {*} value 要检测的值
929
954
  * @param {Object} [options] 配置项
930
955
  * @param {boolean} [options.loose=false] 宽松模式。如果为true,只要包含中文即为true
956
+ * @param {boolean} [options.useExtend=false] 使用统一表意文字扩展A-F。注意:如果不支持 `RegExp.prototype.unicode`,扩展字符集将自动不生效,如IE浏览器。
931
957
  * @returns {boolean} 值是否为中文
932
958
  * @example
933
959
  *
@@ -938,16 +964,30 @@
938
964
  * // => false
939
965
  *
940
966
  * // 宽松模式,只要包含中文即为true
941
- * isChinese('林A', {loose: true});
967
+ * isChinese('林A', { loose: true });
942
968
  * // => true
943
969
  *
944
- * isChinese('A林A', {loose: true});
970
+ * isChinese('A林A', { loose: true });
945
971
  * // => true
946
972
  *
973
+ * isChinese('𠮷');
974
+ * // => false
975
+ *
976
+ * // 使用中文扩展字符集,需要浏览器支持 RegExp.prototype.unicode 才生效。
977
+ * isChinese('𠮷', { useExtend: true });
978
+ * // => true
979
+ * isChinese('𠮷aa', { useExtend: true, loose: true });
980
+ * // => true
947
981
  */
948
- function isChinese(value, { loose = false } = {}) {
982
+ function isChinese(value, { loose = false, useExtend = false } = {}) {
949
983
  const valueStr = normalizeString(value);
950
- const reg = new RegExp(loose ? looseChineseRegExp : chineseRegExp, supportRegExpUnicode ? 'u' : undefined);
984
+ const basicRegExp = loose ? looseChineseRegExp : chineseRegExp;
985
+ const extendRegExp = loose ? looseChineseExtendRegExp : chineseExtendRegExp;
986
+
987
+ const hasExtend = useExtend && supportRegExpUnicode;
988
+ const resultRegExp = hasExtend ? extendRegExp : basicRegExp;
989
+ const flag = hasExtend ? 'u' : undefined;
990
+ const reg = new RegExp(resultRegExp, flag);
951
991
  return reg.test(valueStr);
952
992
  }
953
993
 
@@ -1103,8 +1143,8 @@
1103
1143
  }
1104
1144
 
1105
1145
  // 反模10计算
1106
- if (pj === 10 || pj === 1) {
1107
- retNum = 1;
1146
+ if (pj === 1) {
1147
+ retNum = 0;
1108
1148
  } else {
1109
1149
  retNum = 11 - pj;
1110
1150
  }
@@ -1121,32 +1161,33 @@
1121
1161
  * @since 3.5.0
1122
1162
  * @param {*} value 要检测的值
1123
1163
  * @param {Object} [options] 配置项
1124
- * @param {boolean} [options.loose=false] 宽松模式。如果为true,不校验校验位。
1164
+ * @param {boolean} [options.checkCode=true] 是否校验最后一位校验码,如果为false,不校验校验位。
1125
1165
  * @returns {boolean} 值是否为营业执照号
1126
1166
  * @example
1127
1167
  *
1128
1168
  * isBusinessLicense('310115600985533');
1129
1169
  * // => true
1130
1170
  *
1131
- * isBusinessLicense('3101156009');
1132
- * // => false
1133
- *
1134
- * isBusinessLicense('3101156009', { loose: true });
1135
- * // => false
1136
- *
1137
1171
  * isBusinessLicense('310115600985535');
1138
1172
  * // => false
1139
1173
  *
1140
- * isBusinessLicense('310115600985535', { loose: true });
1174
+ * isBusinessLicense('310115600985535', { checkCode: false });
1141
1175
  * // => true
1176
+ *
1177
+ * isBusinessLicense('31011560098', { checkCode: false });
1178
+ * // => false
1142
1179
  */
1143
- function isBusinessLicense(value, { loose = false } = {}) {
1180
+ function isBusinessLicense(value, options = {}) {
1144
1181
  const valueStr = normalizeString(value);
1182
+ // @ts-ignore
1183
+ // TODO 下个版本废弃 loose
1184
+ const { loose = false, checkCode: cc = true } = options;
1185
+ const needCheckCode = !loose && cc;
1145
1186
 
1146
1187
  const passBaseRule = baseReg.test(valueStr);
1147
1188
 
1148
1189
  // 宽松模式 或 基础规则不通过直接返回
1149
- if (loose || !passBaseRule) {
1190
+ if (!needCheckCode || !passBaseRule) {
1150
1191
  return passBaseRule;
1151
1192
  }
1152
1193
 
@@ -1213,8 +1254,11 @@
1213
1254
  return regHMCard.test(valueStr);
1214
1255
  }
1215
1256
 
1216
- // 台湾居民来往大陆通行证正则,支持一次性短期台胞证
1217
- const regTWCard = /^(\d{8}|[\da-z]{10})$/i;
1257
+ // 台湾居民来往大陆通行证正则
1258
+ const regTWCard = /^\d{8}$/i;
1259
+
1260
+ // 一次性短期台胞证
1261
+ const singleRegTWCard = /^[\da-z]{10,12}$/i;
1218
1262
 
1219
1263
  /**
1220
1264
  * 检测值是否为台湾居民来往大陆通行证,俗称台胞证。
@@ -1224,17 +1268,23 @@
1224
1268
  * @since 4.0.0
1225
1269
  * @see 参考 {@link https://zh.wikipedia.org/wiki/台湾居民来往大陆通行证|台湾居民来往大陆通行证}
1226
1270
  * @param {*} value 要检测的值
1271
+ * @param {Object} [options] 配置项
1272
+ * @param {boolean} [options.loose=false] 宽松模式。如果为true,表示支持一次性短期通行证
1227
1273
  * @returns {boolean} 是否为台湾居民来往大陆通行证
1228
1274
  * @example
1229
1275
  * isTWCard('12345678') // true
1230
1276
  * isTWCard('07257456') // true
1231
1277
  *
1232
1278
  * // 一次性短期
1233
- * isTWCard('F290299977') // true
1279
+ * isTWCard('F290299977') // false
1280
+ * isTWCard('F290299977', { loose: true }) // true
1234
1281
  */
1235
- function isTWCard(value) {
1282
+ function isTWCard(value, { loose = false } = {}) {
1236
1283
  const valueStr = normalizeString(value);
1237
- return regTWCard.test(valueStr);
1284
+ if (regTWCard.test(valueStr)) {
1285
+ return true;
1286
+ }
1287
+ return loose ? singleRegTWCard.test(valueStr) : false;
1238
1288
  }
1239
1289
 
1240
1290
  const reg$1 = /^[A-Z]{6}[A-Z\d]{2}(?:[A-Z\d]{3})?$/;
@@ -1320,8 +1370,9 @@
1320
1370
  * @returns {number}
1321
1371
  */
1322
1372
  function float2Fixed(num) {
1323
- if (!isScientificNumber(num.toString())) {
1324
- return Number(num.toString().replace('.', ''));
1373
+ const strNum = String(num);
1374
+ if (!isScientificNumber(strNum)) {
1375
+ return Number(strNum.replace('.', ''));
1325
1376
  }
1326
1377
  const dLen = digitLength(num);
1327
1378
  return dLen > 0 ? strip(+num * Math.pow(10, dLen)) : +num;
@@ -1334,9 +1385,7 @@
1334
1385
  */
1335
1386
  function checkBoundary(num) {
1336
1387
  if (+num > MAX_SAFE_INTEGER || +num < MIN_SAFE_INTEGER) {
1337
- if (!config.disableWarning) {
1338
- console.warn(`${num} is beyond boundary when transfer to integer, the results may not be accurate`);
1339
- }
1388
+ devWarn(`${num} is beyond boundary when transfer to integer, the results may not be accurate`);
1340
1389
  }
1341
1390
  }
1342
1391
 
@@ -1368,37 +1417,63 @@
1368
1417
  * 2.小数点前边是0,小数点后十分位(包含十分位)之后连续零的个数大于等于6个
1369
1418
  *
1370
1419
  * @param {string | number} num 科学计数法数字
1371
- * @returns {string} 转换后的数字字符串
1420
+ * @returns {string | number} 转换后的数字字符串
1372
1421
  */
1373
1422
  function scientificToNumber(num) {
1374
- if (isScientificNumber(num.toString())) {
1375
- const zero = '0';
1376
- const parts = String(num).toLowerCase().split('e');
1377
- const e = parts.pop(); // 存储指数
1378
- // @ts-ignore
1379
- const l = Math.abs(e); // 取绝对值,l-1就是0的个数
1380
- // @ts-ignore
1381
- const sign = e / l; //判断正负
1382
- const coeff_array = parts[0].split('.'); // 将系数按照小数点拆分
1423
+ const strNum = String(num);
1383
1424
 
1384
- //如果是小数
1385
- if (sign === -1) {
1386
- //拼接字符串,如果是小数,拼接0和小数点
1387
- num = zero + '.' + new Array(l).join(zero) + coeff_array.join('');
1388
- } else {
1389
- const dec = coeff_array[1];
1425
+ if (!isScientificNumber(strNum)) {
1426
+ return num;
1427
+ }
1390
1428
 
1391
- //如果是整数,将整数除第一位之外的非零数字计入位数,相应的减少0的个数
1392
- if (l - dec.length < 0) {
1393
- num = trimLeftZero(coeff_array[0] + dec.substring(0, l)) + '.' + dec.substring(l);
1394
- } else {
1395
- //拼接字符串,如果是整数,不需要拼接小数点
1396
- num = coeff_array.join('') + new Array(l - dec.length + 1).join(zero);
1429
+ /** @type string */
1430
+ let ret;
1431
+
1432
+ const zero = '0';
1433
+ const parts = strNum.toLowerCase().split('e');
1434
+ const e = parts.pop(); // 存储指数
1435
+ // @ts-ignore
1436
+ const l = Math.abs(e); // 取绝对值,l-1就是0的个数
1437
+ // @ts-ignore
1438
+ const sign = e / l; //判断正负
1439
+ const coeff_array = parts[0].split('.'); // 将系数按照小数点拆分
1440
+
1441
+ // 如果是小数
1442
+ if (sign === -1) {
1443
+ // 整数部分
1444
+ const intVal = trimLeftZero(coeff_array[0]);
1445
+
1446
+ // 整数部分大于科学计数后面部分
1447
+ // 如: 10e-1, 10.2e-1
1448
+ if (intVal.length > l) {
1449
+ const thanLen = intVal.length - l;
1450
+ const dec = coeff_array[1] || '';
1451
+
1452
+ ret = intVal.slice(0, thanLen);
1453
+
1454
+ // 处理 10e-1, 100e-1
1455
+ if (intVal.slice(thanLen) !== '0' || dec) {
1456
+ ret += '.' + intVal.slice(thanLen) + dec;
1397
1457
  }
1458
+ } else {
1459
+ // 整数部分小于等于科学计数后面部分
1460
+ // 如: 1e-1, 0.2e-1, 1.2e-2, 1.2e-1
1461
+ ret = zero + '.' + new Array(l - intVal.length + 1).join(zero) + coeff_array.join('');
1462
+ }
1463
+ } else {
1464
+ // 小数部分
1465
+ const dec = coeff_array[1] || '';
1466
+
1467
+ // 如果是整数,将整数除第一位之外的非零数字计入位数,相应的减少0的个数
1468
+ if (l - dec.length < 0) {
1469
+ ret = trimLeftZero(coeff_array[0] + dec.substring(0, l)) + '.' + dec.substring(l);
1470
+ } else {
1471
+ // 拼接字符串,如果是整数,不需要拼接小数点
1472
+ ret = coeff_array.join('') + new Array(l - dec.length + 1).join(zero);
1398
1473
  }
1399
1474
  }
1400
- // @ts-ignore
1401
- return num;
1475
+
1476
+ return trimLeftZero(ret);
1402
1477
  }
1403
1478
 
1404
1479
  /**
@@ -1432,9 +1507,7 @@
1432
1507
  */
1433
1508
  function checkNumber(num) {
1434
1509
  if (!(reg.test(num) || isScientificNumber(num)) || _isNaN(num) || (typeof num !== 'number' && typeof num !== 'string') || num === '') {
1435
- if (!config.disableWarning) {
1436
- console.warn(`${num} invalid parameter.`);
1437
- }
1510
+ devWarn(`${num} invalid parameter.`);
1438
1511
 
1439
1512
  return false;
1440
1513
  }
@@ -1558,9 +1631,9 @@
1558
1631
  decimal = typeof decimal === 'string' ? decimal : '.';
1559
1632
 
1560
1633
  // 转换数字字符串,支持科学记数法
1561
- const numStr = scientificToNumber(num) + '';
1634
+ const strNum = scientificToNumber(num) + '';
1562
1635
  // 整数和小数部分
1563
- const [intStr, decStr] = numStr.split('.');
1636
+ const [intStr, decStr] = strNum.split('.');
1564
1637
 
1565
1638
  return symbol + formatInt(intStr, thousand) + formatDec(decStr, precision, decimal);
1566
1639
  };
@@ -1651,12 +1724,13 @@
1651
1724
  * // => 林**
1652
1725
  *
1653
1726
  */
1654
- function replaceChar(str = '', { start = 3, end = -4, char = '*', repeat, exclude } = {}) {
1655
- const strLen = str.length;
1727
+ function replaceChar(str, { start = 3, end = -4, char = '*', repeat, exclude } = {}) {
1728
+ const realStr = normalizeString(str);
1729
+ const strLen = realStr.length;
1656
1730
 
1657
1731
  // 开始位置超过str长度
1658
1732
  if (Math.abs(start) >= strLen) {
1659
- return str;
1733
+ return realStr;
1660
1734
  }
1661
1735
 
1662
1736
  start = start >= 0 ? start : strLen + start;
@@ -1664,10 +1738,10 @@
1664
1738
 
1665
1739
  // 开始位置大于结束位置
1666
1740
  if (start >= end) {
1667
- return str;
1741
+ return realStr;
1668
1742
  }
1669
1743
 
1670
- let middleStr = str.substring(start, end);
1744
+ let middleStr = realStr.substring(start, end);
1671
1745
 
1672
1746
  if (exclude) {
1673
1747
  const reg = new RegExp(`[^${exclude}]`, 'g');
@@ -1677,7 +1751,7 @@
1677
1751
  middleStr = char.repeat(repeat);
1678
1752
  }
1679
1753
 
1680
- return str.substring(0, start) + middleStr + str.substring(end);
1754
+ return realStr.substring(0, start) + middleStr + realStr.substring(end);
1681
1755
  }
1682
1756
 
1683
1757
  // 简体
@@ -1716,10 +1790,10 @@
1716
1790
  * @returns {string} 转化的数字
1717
1791
  */
1718
1792
  function sectionToChinese(section) {
1719
- let str = '',
1720
- chnstr = '',
1721
- zero = false, //zero为是否进行补零, 第一次进行取余由于为个位数,默认不补零
1722
- unitPos = 0;
1793
+ let str = '';
1794
+ let chnstr = '';
1795
+ let zero = false; //zero为是否进行补零, 第一次进行取余由于为个位数,默认不补零
1796
+ let unitPos = 0;
1723
1797
 
1724
1798
  while (section > 0) {
1725
1799
  // 对数字取余10,得到的数即为个位数
@@ -1753,18 +1827,18 @@
1753
1827
  * @returns {string} 中文数字
1754
1828
  */
1755
1829
  function convertInteger(num) {
1756
- num = Math.floor(num);
1830
+ let numInt = Math.floor(num);
1757
1831
 
1758
1832
  let unitPos = 0;
1759
- let strIns = '',
1760
- chnStr = '';
1833
+ let strIns = '';
1834
+ let chnStr = '';
1761
1835
  let needZero = false;
1762
1836
 
1763
- if (num === 0) {
1837
+ if (numInt === 0) {
1764
1838
  return numberChar[0];
1765
1839
  }
1766
- while (num > 0) {
1767
- var section = num % 10000;
1840
+ while (numInt > 0) {
1841
+ var section = numInt % 10000;
1768
1842
  if (needZero) {
1769
1843
  chnStr = numberChar[0] + chnStr;
1770
1844
  }
@@ -1772,7 +1846,7 @@
1772
1846
  strIns += section !== 0 ? unitSection[unitPos] : unitSection[0];
1773
1847
  chnStr = strIns + chnStr;
1774
1848
  needZero = section < 1000 && section > 0;
1775
- num = Math.floor(num / 10000);
1849
+ numInt = Math.floor(numInt / 10000);
1776
1850
  unitPos++;
1777
1851
  }
1778
1852
  return chnStr;
@@ -1785,13 +1859,13 @@
1785
1859
  * @param {number} num 要转换的数字
1786
1860
  */
1787
1861
  function convertDecimal(num) {
1788
- const numStr = num + '';
1789
- const index = numStr.indexOf('.');
1862
+ const strNum = num + '';
1863
+ const index = strNum.indexOf('.');
1790
1864
 
1791
1865
  let ret = '';
1792
1866
 
1793
1867
  if (index > -1) {
1794
- let decimalStr = numStr.slice(index + 1);
1868
+ let decimalStr = strNum.slice(index + 1);
1795
1869
  ret = mapNumberChar(parseInt(decimalStr));
1796
1870
  }
1797
1871
 
@@ -1806,11 +1880,11 @@
1806
1880
  * @returns {string} 返回中文数字的映射
1807
1881
  */
1808
1882
  function mapNumberChar(num) {
1809
- const numStr = num + '';
1883
+ const strNum = num + '';
1810
1884
  let ret = '';
1811
1885
 
1812
- for (let i = 0, len = numStr.length; i < len; i++) {
1813
- ret += numberChar[parseInt(numStr[i])];
1886
+ for (let i = 0, len = strNum.length; i < len; i++) {
1887
+ ret += numberChar[parseInt(strNum[i])];
1814
1888
  }
1815
1889
 
1816
1890
  return ret;
@@ -1861,25 +1935,10 @@
1861
1935
  * // => 一九九〇
1862
1936
  *
1863
1937
  */
1864
- function numberToChinese(
1865
- num,
1866
- {
1867
- big5 = false,
1868
- unit = true,
1869
- decimal = '点',
1870
- zero = '',
1871
- negative = '负',
1872
- unitConfig = {
1873
- w: '万', // '萬'
1874
- y: '亿' // '億'
1875
- }
1876
- } = {}
1877
- ) {
1938
+ function numberToChinese(num, { big5 = false, unit = true, decimal = '点', zero = '', negative = '负', unitConfig = {} } = {}) {
1878
1939
  // 非数字 或 NaN 不处理
1879
1940
  if (typeof num !== 'number' || isNaN(num)) {
1880
- if (!config.disableWarning) {
1881
- console.warn(`参数错误 ${num},请传入数字`);
1882
- }
1941
+ devWarn(`参数错误 ${num},请传入数字`);
1883
1942
 
1884
1943
  return '';
1885
1944
  }
@@ -1897,9 +1956,10 @@
1897
1956
  }
1898
1957
 
1899
1958
  // 设置节点计数单位,万、亿、万亿
1900
- const defaultUnitWan = '万';
1901
- const defaultUnitYi = '亿';
1902
- unitSection = ['', unitConfig.w || defaultUnitWan, unitConfig.y || defaultUnitYi, unitConfig.w && unitConfig.y ? unitConfig.w + unitConfig.y : defaultUnitWan + defaultUnitYi];
1959
+ const unitWan = unitConfig?.w || '万';
1960
+ const unitYi = unitConfig?.y || '亿';
1961
+ const unitWanYi = unitWan + unitYi;
1962
+ unitSection = ['', unitWan, unitYi, unitWanYi];
1903
1963
 
1904
1964
  // 设置0
1905
1965
  if (zero) {
@@ -1911,16 +1971,17 @@
1911
1971
 
1912
1972
  // 整数和小数
1913
1973
  let chnInteger, chnDecimal;
1974
+ const numAbs = Math.abs(num);
1914
1975
 
1915
1976
  // 处理整数
1916
1977
  if (unit) {
1917
- chnInteger = convertInteger(num);
1978
+ chnInteger = convertInteger(numAbs);
1918
1979
  } else {
1919
- chnInteger = mapNumberChar(Math.floor(num));
1980
+ chnInteger = mapNumberChar(Math.floor(numAbs));
1920
1981
  }
1921
1982
 
1922
1983
  // 处理小数
1923
- chnDecimal = convertDecimal(num);
1984
+ chnDecimal = convertDecimal(numAbs);
1924
1985
 
1925
1986
  return chnDecimal ? `${preStr}${chnInteger}${decimal}${chnDecimal}` : `${preStr}${chnInteger}`;
1926
1987
  }
@@ -1948,13 +2009,15 @@
1948
2009
  * // => 1 GB
1949
2010
  */
1950
2011
  function bytesToSize(bytes) {
1951
- if (bytes === 0) return '0 B';
2012
+ const numBytes = typeof bytes !== 'number' ? Number(bytes) : bytes;
2013
+ if (numBytes === 0 || isNaN(numBytes)) return '0 B';
2014
+
1952
2015
  const k = 1024;
1953
2016
  // 存储单位
1954
2017
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
1955
- const i = Math.floor(Math.log(bytes) / Math.log(k));
2018
+ const i = Math.floor(Math.log(numBytes) / Math.log(k));
1956
2019
 
1957
- return sizes[i] ? `${Number((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}` : bytes + '';
2020
+ return sizes[i] ? `${Number((numBytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}` : numBytes + '';
1958
2021
  }
1959
2022
 
1960
2023
  const regIdCard = /^(?<province>\d{2})(?<city>\d{2})(?<area>\d{2})(?<year>(?:\d{2})?\d{2})(?<month>\d{2})(?<day>\d{2})\d{2}(?<gender>\d)(?:\d|X)?$/i;
@@ -2095,31 +2158,17 @@
2095
2158
  * @type {{ province: string, city: string, area: string, year: string, month: string, day: string, gender: string }}
2096
2159
  *
2097
2160
  */
2098
- let origin = {
2099
- province: '',
2100
- city: '',
2101
- area: '',
2102
- year: '',
2103
- month: '',
2104
- day: '',
2105
- gender: ''
2161
+ // @ts-ignore
2162
+ const origin = info?.groups || {
2163
+ province: info[1],
2164
+ city: info[2],
2165
+ area: info[3],
2166
+ year: info[4],
2167
+ month: info[5],
2168
+ day: info[6],
2169
+ gender: info[7]
2106
2170
  };
2107
2171
 
2108
- if (info.groups) {
2109
- // @ts-ignore
2110
- origin = info.groups;
2111
- } else {
2112
- origin = {
2113
- province: info[1],
2114
- city: info[2],
2115
- area: info[3],
2116
- year: info[4],
2117
- month: info[5],
2118
- day: info[6],
2119
- gender: info[7]
2120
- };
2121
- }
2122
-
2123
2172
  const province = Provinces.find((item) => item[0] === origin.province);
2124
2173
 
2125
2174
  if (!province) {
@@ -2538,6 +2587,12 @@
2538
2587
  * // => 4100
2539
2588
  */
2540
2589
  function round(num, precision = 0) {
2590
+ // 兼容处理,如果参数为非数字或字符串时,直接返回
2591
+ if ((!isNumber(num) || _isNaN(num)) && !isString(num)) {
2592
+ // @ts-ignore
2593
+ return num;
2594
+ }
2595
+
2541
2596
  const base = Math.pow(10, precision);
2542
2597
  return divide(Math.round(times(num, base)), base);
2543
2598
  }