@zamlia/mini-ui 0.0.12 → 0.0.13
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/es/index.d.ts +1 -0
- package/es/index.d.ts.map +1 -1
- package/es/index.js +762 -33
- package/es/index.js.map +1 -1
- package/es/types/components.d.ts +13 -0
- package/es/types/components.d.ts.map +1 -0
- package/es/types/index.d.ts +8 -0
- package/es/types/index.d.ts.map +1 -0
- package/es/types/utils.d.ts +70 -0
- package/es/types/utils.d.ts.map +1 -0
- package/es/utils/cache.d.ts +6 -0
- package/es/utils/cache.d.ts.map +1 -0
- package/es/utils/index.d.ts +73 -33
- package/es/utils/index.d.ts.map +1 -1
- package/es/utils/lib/format.utils.d.ts +29 -0
- package/es/utils/lib/format.utils.d.ts.map +1 -0
- package/es/utils/lib/is.utils.d.ts +128 -0
- package/es/utils/lib/is.utils.d.ts.map +1 -0
- package/es/utils/lib/mini.utils.d.ts +78 -0
- package/es/utils/lib/mini.utils.d.ts.map +1 -0
- package/es/utils/lib/object.utils.d.ts +40 -0
- package/es/utils/lib/object.utils.d.ts.map +1 -0
- package/es/utils/lib/pay.utils.d.ts +25 -0
- package/es/utils/lib/pay.utils.d.ts.map +1 -0
- package/es/utils/lib/string.utils.d.ts +36 -0
- package/es/utils/lib/string.utils.d.ts.map +1 -0
- package/lib/index.d.ts +155 -34
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +762 -33
- package/lib/index.js.map +1 -1
- package/lib/types/components.d.ts +13 -0
- package/lib/types/components.d.ts.map +1 -0
- package/lib/types/index.d.ts +8 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/utils.d.ts +70 -0
- package/lib/types/utils.d.ts.map +1 -0
- package/lib/utils/cache.d.ts +6 -0
- package/lib/utils/cache.d.ts.map +1 -0
- package/lib/utils/index.d.ts +73 -33
- package/lib/utils/index.d.ts.map +1 -1
- package/lib/utils/lib/format.utils.d.ts +29 -0
- package/lib/utils/lib/format.utils.d.ts.map +1 -0
- package/lib/utils/lib/is.utils.d.ts +128 -0
- package/lib/utils/lib/is.utils.d.ts.map +1 -0
- package/lib/utils/lib/mini.utils.d.ts +78 -0
- package/lib/utils/lib/mini.utils.d.ts.map +1 -0
- package/lib/utils/lib/object.utils.d.ts +40 -0
- package/lib/utils/lib/object.utils.d.ts.map +1 -0
- package/lib/utils/lib/pay.utils.d.ts +25 -0
- package/lib/utils/lib/pay.utils.d.ts.map +1 -0
- package/lib/utils/lib/string.utils.d.ts +36 -0
- package/lib/utils/lib/string.utils.d.ts.map +1 -0
- package/package.json +2 -2
package/es/index.js
CHANGED
|
@@ -225,15 +225,153 @@ const NavBar = (props) => {
|
|
|
225
225
|
React.createElement(Text, null, title)));
|
|
226
226
|
};
|
|
227
227
|
|
|
228
|
-
|
|
229
|
-
* 工具函数
|
|
230
|
-
*/
|
|
231
|
-
const Utils = {
|
|
228
|
+
var IsUtils = {
|
|
232
229
|
/**
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
230
|
+
* 是否是阿里
|
|
231
|
+
* @returns {boolean}
|
|
232
|
+
*/
|
|
233
|
+
isAlipay: () => {
|
|
234
|
+
return Utils.env() === 'alipay';
|
|
235
|
+
},
|
|
236
|
+
/**
|
|
237
|
+
* 是否是微信
|
|
238
|
+
* @returns {boolean}
|
|
239
|
+
*/
|
|
240
|
+
isWeapp: () => {
|
|
241
|
+
return Utils.env() === 'weapp';
|
|
242
|
+
},
|
|
243
|
+
/**
|
|
244
|
+
* 纯数字
|
|
245
|
+
* @param {*} str
|
|
246
|
+
* @returns {boolean}
|
|
236
247
|
*/
|
|
248
|
+
isNumberStr(str) {
|
|
249
|
+
return /^\d+$/.test(str);
|
|
250
|
+
},
|
|
251
|
+
isText: (value) => {
|
|
252
|
+
if (!value) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
if (value.trim().length === 0) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
return true;
|
|
259
|
+
},
|
|
260
|
+
/**
|
|
261
|
+
* 验证是否是【16进制颜色】
|
|
262
|
+
* @public
|
|
263
|
+
* @param {string} text 验证字符串
|
|
264
|
+
* @returns {boolean}
|
|
265
|
+
* @example `
|
|
266
|
+
* 例如:isHexColor('#FF0000'); // true
|
|
267
|
+
* 例如:isHexColor('#f00'); // true
|
|
268
|
+
* 例如:isHexColor('#12345G'); // false
|
|
269
|
+
* `
|
|
270
|
+
*/
|
|
271
|
+
isHexColor(text) {
|
|
272
|
+
const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
|
|
273
|
+
return hexColorRegex.test(text);
|
|
274
|
+
},
|
|
275
|
+
/**
|
|
276
|
+
* 验证是否是【rgb或者rgba颜色】
|
|
277
|
+
* @public
|
|
278
|
+
* @param {string} text 验证字符串
|
|
279
|
+
* @returns {boolean}
|
|
280
|
+
* @example `
|
|
281
|
+
* 匹配 rgb() 格式,例如:isRgbOrRgbaColor(rgb(255, 0, 0)); // true
|
|
282
|
+
* 匹配 rgba() 格式,例如:isRgbOrRgbaColor(rgba(255, 0, 0, 0.5)); // true
|
|
283
|
+
* `
|
|
284
|
+
*/
|
|
285
|
+
isRgbOrRgbaColor(text) {
|
|
286
|
+
const rgbRegex = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/;
|
|
287
|
+
const rgbaRegex = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|0?\.\d+|1(\.0)?)\s*\)$/;
|
|
288
|
+
return rgbRegex.test(text) || rgbaRegex.test(text);
|
|
289
|
+
},
|
|
290
|
+
/**
|
|
291
|
+
* 验证是否是【手机号码 简版】
|
|
292
|
+
* @public
|
|
293
|
+
* @param {string} text 验证字符串
|
|
294
|
+
* @returns {boolean}
|
|
295
|
+
*/
|
|
296
|
+
isMobile(text) {
|
|
297
|
+
const mobileRegex = /^1[0-9]{10}$/;
|
|
298
|
+
return mobileRegex.test(text);
|
|
299
|
+
},
|
|
300
|
+
/**
|
|
301
|
+
* 验证是否是【电话号码】
|
|
302
|
+
* @public
|
|
303
|
+
* @param {string} text 验证字符串
|
|
304
|
+
* @returns {boolean}
|
|
305
|
+
*/
|
|
306
|
+
isPhone(text) {
|
|
307
|
+
const phoneRegex = /^(13[0-9]|14[01456879]|15[0-3,5-9]|16[2567]|17[0-8]|18[0-9]|19[0-3,5-9])\d{8}$/;
|
|
308
|
+
return phoneRegex.test(text);
|
|
309
|
+
},
|
|
310
|
+
/**
|
|
311
|
+
* 验证是否是【邮箱】
|
|
312
|
+
* @public
|
|
313
|
+
* @param {string} text 验证字符串
|
|
314
|
+
* @returns {boolean}
|
|
315
|
+
*/
|
|
316
|
+
isEmail(text) {
|
|
317
|
+
const emailRegex = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/;
|
|
318
|
+
return emailRegex.test(text);
|
|
319
|
+
},
|
|
320
|
+
/**
|
|
321
|
+
* 验证是否是【URL地址】
|
|
322
|
+
* @public
|
|
323
|
+
* @param {string} text 验证字符串
|
|
324
|
+
* @returns {boolean}
|
|
325
|
+
*/
|
|
326
|
+
isURL(text) {
|
|
327
|
+
const urlRegex = /^http[s]?:\/\/.*/;
|
|
328
|
+
return urlRegex.test(text);
|
|
329
|
+
},
|
|
330
|
+
/**
|
|
331
|
+
* 验证是否是【身份证】
|
|
332
|
+
* @public
|
|
333
|
+
* @param {string} text 验证字符串
|
|
334
|
+
* @returns {boolean}
|
|
335
|
+
*/
|
|
336
|
+
isIdCard(text) {
|
|
337
|
+
const idcardRegex = /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/;
|
|
338
|
+
return idcardRegex.test(text);
|
|
339
|
+
},
|
|
340
|
+
/**
|
|
341
|
+
* 验证是否是【金钱】
|
|
342
|
+
* @public
|
|
343
|
+
* @param {string} text 验证字符串
|
|
344
|
+
* @returns {boolean}
|
|
345
|
+
*/
|
|
346
|
+
isMoney(text) {
|
|
347
|
+
const moneyRegex = /([1-9]([0-9]+)?(.[0-9]{1,2})?$)|((0){1}$)|(^[0-9].0-9?$)/;
|
|
348
|
+
return moneyRegex.test(text);
|
|
349
|
+
},
|
|
350
|
+
/**
|
|
351
|
+
* 验证是否是【姓名】
|
|
352
|
+
* @public
|
|
353
|
+
* @param {string} text 验证字符串
|
|
354
|
+
* @returns {boolean}
|
|
355
|
+
*/
|
|
356
|
+
isName(text) {
|
|
357
|
+
const nameRegex = /^[\u4e00-\u9fa5]{1,20}(·[\u4e00-\u9fa5]{1,20}){0,20}([,,][\u4e00-\u9fa5]{1,20}(·[\u4e00-\u9fa5]{1,20}){0,20})*$/;
|
|
358
|
+
return nameRegex.test(text);
|
|
359
|
+
},
|
|
360
|
+
/**
|
|
361
|
+
* 验证是否是【社会统一代码】
|
|
362
|
+
* @public
|
|
363
|
+
* @param {string} text 验证字符串
|
|
364
|
+
* @returns {boolean}
|
|
365
|
+
*/
|
|
366
|
+
isCompanyCode(text) {
|
|
367
|
+
const codeRegex = /^[^_IOZSVa-z\W]{2}\d{6}[^_IOZSVa-z\W]{10}$/;
|
|
368
|
+
return codeRegex.test(text);
|
|
369
|
+
},
|
|
370
|
+
/**
|
|
371
|
+
* 检查值是否为空
|
|
372
|
+
* @param value 要检查的值
|
|
373
|
+
* @returns 如果值为空返回 true,否则返回 false
|
|
374
|
+
*/
|
|
237
375
|
isEmpty(value) {
|
|
238
376
|
if (value == null) {
|
|
239
377
|
return true;
|
|
@@ -249,32 +387,6 @@ const Utils = {
|
|
|
249
387
|
}
|
|
250
388
|
return false;
|
|
251
389
|
},
|
|
252
|
-
/**
|
|
253
|
-
* 深拷贝对象
|
|
254
|
-
* @param obj 要拷贝的对象
|
|
255
|
-
* @returns 深拷贝后的新对象
|
|
256
|
-
*/
|
|
257
|
-
cloneDeep(obj) {
|
|
258
|
-
if (obj === null || typeof obj !== 'object') {
|
|
259
|
-
return obj;
|
|
260
|
-
}
|
|
261
|
-
if (obj instanceof Date) {
|
|
262
|
-
return new Date(obj.getTime());
|
|
263
|
-
}
|
|
264
|
-
if (obj instanceof Array) {
|
|
265
|
-
return obj.map(item => Utils.cloneDeep(item));
|
|
266
|
-
}
|
|
267
|
-
if (typeof obj === 'object') {
|
|
268
|
-
const clonedObj = {};
|
|
269
|
-
for (const key in obj) {
|
|
270
|
-
if (obj.hasOwnProperty(key)) {
|
|
271
|
-
clonedObj[key] = Utils.cloneDeep(obj[key]);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
return clonedObj;
|
|
275
|
-
}
|
|
276
|
-
return obj;
|
|
277
|
-
},
|
|
278
390
|
/**
|
|
279
391
|
* 判断 URL 是否是图片
|
|
280
392
|
* @param url 要检查的 URL
|
|
@@ -329,6 +441,9 @@ const Utils = {
|
|
|
329
441
|
return videoExtensions.test(url.toLowerCase());
|
|
330
442
|
}
|
|
331
443
|
},
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
var StringUtils = {
|
|
332
447
|
/**
|
|
333
448
|
* 将字符串多余长度转化为...
|
|
334
449
|
* @param str 字符串
|
|
@@ -359,6 +474,620 @@ const Utils = {
|
|
|
359
474
|
return '';
|
|
360
475
|
}
|
|
361
476
|
},
|
|
477
|
+
/**
|
|
478
|
+
* 生成随机字符串
|
|
479
|
+
* @param {number} len 长度
|
|
480
|
+
* @returns {string}
|
|
481
|
+
*/
|
|
482
|
+
generateNonceStr: (len) => {
|
|
483
|
+
let data = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
|
|
484
|
+
let str = "";
|
|
485
|
+
for (let i = 0; i < len; i++) {
|
|
486
|
+
str += data.charAt(Math.floor(Math.random() * data.length));
|
|
487
|
+
}
|
|
488
|
+
return str;
|
|
489
|
+
},
|
|
490
|
+
/**
|
|
491
|
+
* ecode
|
|
492
|
+
* @param url 加密链接
|
|
493
|
+
* @returns 处理好的链接
|
|
494
|
+
*/
|
|
495
|
+
urlEcode: (url) => {
|
|
496
|
+
return encodeURIComponent(url);
|
|
497
|
+
},
|
|
498
|
+
/**
|
|
499
|
+
* 解密
|
|
500
|
+
* @param url 解密链接
|
|
501
|
+
* @returns 处理好的链接
|
|
502
|
+
*/
|
|
503
|
+
urlDecode: (url) => {
|
|
504
|
+
return decodeURIComponent(url);
|
|
505
|
+
},
|
|
506
|
+
/**
|
|
507
|
+
* 颜色16进制转rgb
|
|
508
|
+
* @public
|
|
509
|
+
* @param {string} colorCode 16进制的颜色
|
|
510
|
+
* @param {number} opacity 透明度 0 < colorCode < 1
|
|
511
|
+
* @returns {string} rgb格式的颜色
|
|
512
|
+
*/
|
|
513
|
+
hexToRgbaColor(colorCode, opacity = 1) {
|
|
514
|
+
// 去除颜色码前面的 #
|
|
515
|
+
const cleanedColorCode = colorCode.replace('#', '');
|
|
516
|
+
// 将颜色码转换为十进制数
|
|
517
|
+
const decimalValue = parseInt(cleanedColorCode, 16);
|
|
518
|
+
// 分离红、绿、蓝三个分量
|
|
519
|
+
const red = (decimalValue >> 16) & 255;
|
|
520
|
+
const green = (decimalValue >> 8) & 255;
|
|
521
|
+
const blue = decimalValue & 255;
|
|
522
|
+
return `rgba(${red}, ${green}, ${blue}, ${opacity})`;
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* 方法命名规则format**
|
|
528
|
+
*/
|
|
529
|
+
var FormatUtils = {
|
|
530
|
+
/**
|
|
531
|
+
* 金额格式化
|
|
532
|
+
* @public
|
|
533
|
+
* @param {string | number} amount 金额
|
|
534
|
+
* @returns {string}
|
|
535
|
+
*/
|
|
536
|
+
formatAmount(amount) {
|
|
537
|
+
if (typeof amount === 'number')
|
|
538
|
+
return amount.toFixed(2);
|
|
539
|
+
if (typeof amount !== 'string')
|
|
540
|
+
return amount || 0;
|
|
541
|
+
return parseFloat(amount).toFixed(2);
|
|
542
|
+
},
|
|
543
|
+
/**
|
|
544
|
+
* 格式化时间
|
|
545
|
+
* @public
|
|
546
|
+
* @param {string} time 要格式化的时间(支持能被 Date 解析的字符串,如 ISO 字符串、时间戳字符串等)
|
|
547
|
+
* @param {string} format 时间格式,默认 'YYYY-MM-DD HH:mm:ss'
|
|
548
|
+
* @returns {string} 格式化后的时间字符串
|
|
549
|
+
*/
|
|
550
|
+
formatDate(time, format) {
|
|
551
|
+
// 入参校验:无时间值直接返回空字符串
|
|
552
|
+
if (!time)
|
|
553
|
+
return '';
|
|
554
|
+
// 初始化 Date 对象(兼容时间戳字符串/普通时间字符串)
|
|
555
|
+
let date;
|
|
556
|
+
// 处理时间戳字符串(如 "1735689600000")
|
|
557
|
+
if (/^\d+$/.test(time)) {
|
|
558
|
+
date = new Date(Number(time));
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
date = new Date(time);
|
|
562
|
+
}
|
|
563
|
+
// 校验 Date 对象是否有效
|
|
564
|
+
if (isNaN(date.getTime())) {
|
|
565
|
+
console.warn('formatDate: 传入的时间格式无效 →', time);
|
|
566
|
+
return '';
|
|
567
|
+
}
|
|
568
|
+
// 默认格式化模板
|
|
569
|
+
const fmt = format || 'YYYY-MM-DD HH:mm:ss';
|
|
570
|
+
// 定义时间补零函数(单个数字补 0,如 5 → "05")
|
|
571
|
+
const padZero = (num) => num.toString().padStart(2, '0');
|
|
572
|
+
// 🌟 关键修复:所有值都转为 string 类型,避免 number 混入
|
|
573
|
+
const timeMap = {
|
|
574
|
+
YYYY: date.getFullYear().toString(), // 4位年份(转为字符串)
|
|
575
|
+
MM: padZero(date.getMonth() + 1), // 月份(本身已是字符串)
|
|
576
|
+
DD: padZero(date.getDate()), // 日期(本身已是字符串)
|
|
577
|
+
HH: padZero(date.getHours()), // 小时(本身已是字符串)
|
|
578
|
+
mm: padZero(date.getMinutes()), // 分钟(本身已是字符串)
|
|
579
|
+
ss: padZero(date.getSeconds()), // 秒(本身已是字符串)
|
|
580
|
+
// 可选扩展的字段也统一为字符串
|
|
581
|
+
D: date.getDate().toString(),
|
|
582
|
+
M: (date.getMonth() + 1).toString(),
|
|
583
|
+
h: padZero(date.getHours() % 12 || 12),
|
|
584
|
+
};
|
|
585
|
+
// 🌟 修复 replace 回调的返回值类型:确保只返回 string
|
|
586
|
+
return fmt.replace(/YYYY|MM|DD|HH|mm|ss|D|M|h/g, (match) => {
|
|
587
|
+
// 找不到匹配的占位符时,返回原字符串(避免返回 undefined)
|
|
588
|
+
return timeMap[match] || match;
|
|
589
|
+
});
|
|
590
|
+
},
|
|
591
|
+
/**
|
|
592
|
+
* 中文日期格式转换
|
|
593
|
+
* @param {string} dateStr 字符串日期
|
|
594
|
+
* @return {string}
|
|
595
|
+
* @description YYYY-MM-DD -> YYYY年MM月DD日
|
|
596
|
+
*/
|
|
597
|
+
formatDateCn(dateStr) {
|
|
598
|
+
// 通过正则表达式提取年、月、日
|
|
599
|
+
const regex = /(\d{4})年(\d{1,2})月(\d{1,2})日/;
|
|
600
|
+
const match = dateStr.match(regex);
|
|
601
|
+
if (match) {
|
|
602
|
+
const year = match[1];
|
|
603
|
+
const month = String(match[2]).padStart(2, '0'); // 确保月是两位数
|
|
604
|
+
const day = String(match[3]).padStart(2, '0'); // 确保日是两位数
|
|
605
|
+
return `${year}年${month}月${day}日`;
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
return dateStr;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
var ObjectUtils = {
|
|
614
|
+
/**
|
|
615
|
+
* json字符串转对象
|
|
616
|
+
* @param {string} jsonStr JSON字符串
|
|
617
|
+
* @return {Record<string, any>}
|
|
618
|
+
*/
|
|
619
|
+
jsonStrToObj(jsonStr) {
|
|
620
|
+
if (!jsonStr)
|
|
621
|
+
return {};
|
|
622
|
+
try {
|
|
623
|
+
const obj = JSON.parse(jsonStr);
|
|
624
|
+
return obj;
|
|
625
|
+
}
|
|
626
|
+
catch (error) {
|
|
627
|
+
return {};
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
/**
|
|
631
|
+
* 对象转化成url params需要的字符串
|
|
632
|
+
* @public
|
|
633
|
+
* @param {Record<string, any>} params
|
|
634
|
+
* @returns {string}
|
|
635
|
+
*/
|
|
636
|
+
objectToParams(params) {
|
|
637
|
+
// 1. 校验入参:非对象/空对象直接返回空字符串(和lodash.isObject行为对齐)
|
|
638
|
+
if (!params ||
|
|
639
|
+
typeof params !== 'object' ||
|
|
640
|
+
Array.isArray(params) || // 排除数组(lodash.isObject认为数组是对象,这里按需调整)
|
|
641
|
+
Object.keys(params).length === 0) {
|
|
642
|
+
return '';
|
|
643
|
+
}
|
|
644
|
+
// 2. 原生遍历对象,拼接key=value(替代lodash.map)
|
|
645
|
+
return Object.entries(params)
|
|
646
|
+
// 过滤值为undefined/null的参数(可选,和lodash行为一致)
|
|
647
|
+
.filter(([_, value]) => value !== undefined && value !== null)
|
|
648
|
+
// 拼接key=value(注意:若需要URL编码,可加encodeURIComponent)
|
|
649
|
+
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
|
|
650
|
+
// 用&连接所有参数
|
|
651
|
+
.join('&');
|
|
652
|
+
},
|
|
653
|
+
/**
|
|
654
|
+
* 清除空字段
|
|
655
|
+
* @param {Record<string, any>} obj
|
|
656
|
+
* @returns {Record<string, any>}
|
|
657
|
+
*/
|
|
658
|
+
objectCleanEmpty(obj) {
|
|
659
|
+
if (!obj)
|
|
660
|
+
return obj;
|
|
661
|
+
// 使用 Object.entries 来遍历对象,过滤掉空数组、null、undefined
|
|
662
|
+
Object.keys(obj).forEach(key => {
|
|
663
|
+
const value = obj[key];
|
|
664
|
+
// 如果值是 null、undefined 或 空数组,则删除该属性
|
|
665
|
+
if (value === null || value === undefined || (Array.isArray(value) && value.length === 0)) {
|
|
666
|
+
delete obj[key];
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
return obj;
|
|
670
|
+
},
|
|
671
|
+
/**
|
|
672
|
+
* 洗牌算法
|
|
673
|
+
* @public
|
|
674
|
+
* @param {(Record<string, any> | string | number)[]} arr 需要洗牌的数组
|
|
675
|
+
* @returns {(Record<string, any> | string | number)[]}
|
|
676
|
+
*/
|
|
677
|
+
shuffle(arr) {
|
|
678
|
+
const newArr = arr;
|
|
679
|
+
for (let i = 0; i < newArr.length; i++) {
|
|
680
|
+
let j = Utils.getRandom(0, i);
|
|
681
|
+
const temp = newArr[i];
|
|
682
|
+
newArr[i] = newArr[j];
|
|
683
|
+
newArr[j] = temp;
|
|
684
|
+
}
|
|
685
|
+
return newArr;
|
|
686
|
+
},
|
|
687
|
+
/**
|
|
688
|
+
* 将数组转换为树结构数组
|
|
689
|
+
* @public
|
|
690
|
+
* @param {array} array 需要转换的数组
|
|
691
|
+
* @param {string} [id='id'] 数组中对象的唯一ID的别名
|
|
692
|
+
* @param {string} [parentId='pid'] 数组中对象的父ID的别名
|
|
693
|
+
* @param {string} [children='children'] 数组中对象的子级的别名
|
|
694
|
+
* @return {array} 返回一个树结构数组
|
|
695
|
+
*/
|
|
696
|
+
arrayToTree(array, id = 'id', parentId = 'pid', children = 'children') {
|
|
697
|
+
const result = [];
|
|
698
|
+
const hash = {};
|
|
699
|
+
const data = [...(array || [])];
|
|
700
|
+
// const newData: any[] = lodash.sortBy(data, (it: T & { sort: number }) => {
|
|
701
|
+
// return it?.sort;
|
|
702
|
+
// });
|
|
703
|
+
data.forEach((_item, index) => {
|
|
704
|
+
hash[data[index][id]] = data[index];
|
|
705
|
+
});
|
|
706
|
+
data.forEach((item) => {
|
|
707
|
+
// @ts-ignore
|
|
708
|
+
const hashParent = hash[item[parentId]];
|
|
709
|
+
if (hashParent) {
|
|
710
|
+
if (!hashParent[children]) {
|
|
711
|
+
hashParent[children] = [];
|
|
712
|
+
}
|
|
713
|
+
hashParent[children].push(item);
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
result.push(item);
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
return result;
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
// 当前用户位置
|
|
724
|
+
const CURRENT_LOCATION_KEY = 'LOCATION';
|
|
725
|
+
const setCurrentLocation = (value) => {
|
|
726
|
+
return Taro.setStorageSync(CURRENT_LOCATION_KEY, value);
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
/** 页面参数存储缓存key */
|
|
730
|
+
const CACHE_PARAMS_KEY = 'params';
|
|
731
|
+
const ENV_TEXT = {
|
|
732
|
+
weapp: '微信',
|
|
733
|
+
swan: '百度',
|
|
734
|
+
alipay: '支付宝',
|
|
735
|
+
tt: '字节跳动',
|
|
736
|
+
qq: 'QQ',
|
|
737
|
+
h5: 'h5'
|
|
738
|
+
};
|
|
739
|
+
var miniUtils = {
|
|
740
|
+
/**
|
|
741
|
+
* 开发中
|
|
742
|
+
*/
|
|
743
|
+
dev: () => {
|
|
744
|
+
Utils.showToast({ title: '开发中' });
|
|
745
|
+
},
|
|
746
|
+
/**
|
|
747
|
+
* 环境
|
|
748
|
+
* @param {string}isCapitalization 大写
|
|
749
|
+
* @return {string} weapp | alipay
|
|
750
|
+
*/
|
|
751
|
+
env: (isCapitalization = false) => {
|
|
752
|
+
var _a, _b, _c, _d;
|
|
753
|
+
return isCapitalization ? ((_c = (_b = (_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.TARO_ENV) === null || _b === void 0 ? void 0 : _b.toUpperCase) === null || _c === void 0 ? void 0 : _c.call(_b)) || '' : ((_d = process === null || process === void 0 ? void 0 : process.env) === null || _d === void 0 ? void 0 : _d.TARO_ENV) || '';
|
|
754
|
+
},
|
|
755
|
+
/**
|
|
756
|
+
* 环境中文
|
|
757
|
+
* @return {string} weapp | alipay
|
|
758
|
+
*/
|
|
759
|
+
envText: () => {
|
|
760
|
+
return ENV_TEXT[Utils.env()];
|
|
761
|
+
},
|
|
762
|
+
showToast: (params) => {
|
|
763
|
+
const { delay, ...restParams } = params;
|
|
764
|
+
const toast = () => Taro.showToast({ icon: 'none', mask: true, duration: 1500, ...restParams });
|
|
765
|
+
if (typeof delay === 'number') {
|
|
766
|
+
Utils.delay(delay).then(() => toast());
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
toast();
|
|
770
|
+
},
|
|
771
|
+
/**
|
|
772
|
+
* 设置拷贝内容到剪切盘
|
|
773
|
+
* @param content 拷贝内容
|
|
774
|
+
*/
|
|
775
|
+
setCopyContent(content) {
|
|
776
|
+
Taro.setClipboardData({
|
|
777
|
+
data: content,
|
|
778
|
+
success: function () {
|
|
779
|
+
Utils.showToast({ title: '拷贝成功', icon: 'success' });
|
|
780
|
+
},
|
|
781
|
+
fail: function (err) {
|
|
782
|
+
Utils.showToast({ title: `拷贝失败-${err}` });
|
|
783
|
+
}
|
|
784
|
+
});
|
|
785
|
+
},
|
|
786
|
+
/**
|
|
787
|
+
* 扫码
|
|
788
|
+
* @param {boolean} isonlyFromCamera 是否只支持相机扫码
|
|
789
|
+
* @returns {Promise<string>}
|
|
790
|
+
*/
|
|
791
|
+
scanCode: (isonlyFromCamera) => {
|
|
792
|
+
return new Promise((resolve) => {
|
|
793
|
+
Taro.scanCode({
|
|
794
|
+
onlyFromCamera: isonlyFromCamera || false,
|
|
795
|
+
scanType: 'QR_CODE',
|
|
796
|
+
success: (res) => {
|
|
797
|
+
let { result } = res;
|
|
798
|
+
if (!Utils.isText(result)) {
|
|
799
|
+
Utils.showToast({ title: '无法识别,请重试' });
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
resolve(result);
|
|
803
|
+
},
|
|
804
|
+
fail: (e) => {
|
|
805
|
+
console.error(e);
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
});
|
|
809
|
+
},
|
|
810
|
+
/**
|
|
811
|
+
* 小程序登录
|
|
812
|
+
* @returns 获取的code
|
|
813
|
+
*/
|
|
814
|
+
miniLogin: () => {
|
|
815
|
+
return new Promise((resolve) => {
|
|
816
|
+
Taro.login({
|
|
817
|
+
success: res => {
|
|
818
|
+
const { code } = res;
|
|
819
|
+
if (!code) {
|
|
820
|
+
console.error('登录失败.' + res.errMsg);
|
|
821
|
+
resolve();
|
|
822
|
+
}
|
|
823
|
+
else {
|
|
824
|
+
resolve(code);
|
|
825
|
+
}
|
|
826
|
+
},
|
|
827
|
+
fail: err => {
|
|
828
|
+
Utils.showToast({ title: err.errMsg });
|
|
829
|
+
console.error('登录失败.', err);
|
|
830
|
+
resolve();
|
|
831
|
+
},
|
|
832
|
+
});
|
|
833
|
+
});
|
|
834
|
+
},
|
|
835
|
+
/**
|
|
836
|
+
* 获取定位
|
|
837
|
+
* @returns {Promise<GeoLocation>}
|
|
838
|
+
*/
|
|
839
|
+
getLocation() {
|
|
840
|
+
return new Promise((resolve) => {
|
|
841
|
+
{
|
|
842
|
+
Taro.getLocation({ type: 'gcj02' }).then(res => {
|
|
843
|
+
const { longitude, latitude } = res;
|
|
844
|
+
setCurrentLocation({ longitude, latitude });
|
|
845
|
+
resolve({ longitude, latitude });
|
|
846
|
+
}).catch((error) => {
|
|
847
|
+
if ((error === null || error === void 0 ? void 0 : error.errMsg) === 'getLocation:fail auth deny' || (error === null || error === void 0 ? void 0 : error.errMsg) === 'getLocation:fail auth denied') {
|
|
848
|
+
// 用户拒绝授权
|
|
849
|
+
Taro.showModal({
|
|
850
|
+
title: '提示',
|
|
851
|
+
content: '获取位置未授权,请到我的->个人信息->设置页面中打开',
|
|
852
|
+
showCancel: false
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
else {
|
|
856
|
+
// 其他错误处理
|
|
857
|
+
Taro.showToast({
|
|
858
|
+
title: '获取位置失败',
|
|
859
|
+
icon: 'none'
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
resolve(null);
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
},
|
|
867
|
+
/**
|
|
868
|
+
* 检查小程序版本更新
|
|
869
|
+
*/
|
|
870
|
+
updateVersion() {
|
|
871
|
+
const updateManager = Taro.getUpdateManager();
|
|
872
|
+
updateManager.onCheckForUpdate(function (res) {
|
|
873
|
+
// 请求完新版本信息的回调
|
|
874
|
+
if (!res.hasUpdate)
|
|
875
|
+
Utils.showToast({ title: '已经是最新版本了' });
|
|
876
|
+
});
|
|
877
|
+
updateManager.onUpdateReady(function () {
|
|
878
|
+
Taro.showModal({
|
|
879
|
+
title: '更新提示',
|
|
880
|
+
content: '新版本已经准备好,是否重启应用?',
|
|
881
|
+
success: function (res) {
|
|
882
|
+
if (res.confirm) {
|
|
883
|
+
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
|
884
|
+
updateManager.applyUpdate();
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
});
|
|
889
|
+
updateManager.onUpdateFailed(function () {
|
|
890
|
+
// 新的版本下载失败
|
|
891
|
+
});
|
|
892
|
+
},
|
|
893
|
+
/**
|
|
894
|
+
* 打开地图导航
|
|
895
|
+
* @param [经度,纬度]location 经纬度
|
|
896
|
+
* @param options
|
|
897
|
+
*/
|
|
898
|
+
openLocation: (location, options) => {
|
|
899
|
+
if (location === undefined || Array.isArray(location)) {
|
|
900
|
+
Utils.showToast({ title: "定位信息不全" });
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
// 经度,范围为-180~180
|
|
904
|
+
const longitude = location === null || location === void 0 ? void 0 : location[0];
|
|
905
|
+
// 纬度,范围为-90~90
|
|
906
|
+
const latitude = location === null || location === void 0 ? void 0 : location[1];
|
|
907
|
+
const scale = (options === null || options === void 0 ? void 0 : options.scale) || 18;
|
|
908
|
+
const name = options === null || options === void 0 ? void 0 : options.name;
|
|
909
|
+
const address = options === null || options === void 0 ? void 0 : options.address;
|
|
910
|
+
const data = {
|
|
911
|
+
longitude, latitude, scale, name, address
|
|
912
|
+
};
|
|
913
|
+
if (Utils.isAlipay()) {
|
|
914
|
+
// @ts-ignore
|
|
915
|
+
my.openLocation(data);
|
|
916
|
+
}
|
|
917
|
+
else {
|
|
918
|
+
Taro.openLocation(data);
|
|
919
|
+
}
|
|
920
|
+
},
|
|
921
|
+
/**
|
|
922
|
+
* 打开全屏预览图片
|
|
923
|
+
* @param {string} current 当前点击的图片url
|
|
924
|
+
* @param {string} urlArr 所有图片url的数组
|
|
925
|
+
*/
|
|
926
|
+
previewImage(current, urlArr) {
|
|
927
|
+
if (!current)
|
|
928
|
+
return;
|
|
929
|
+
Taro.previewImage({
|
|
930
|
+
current,
|
|
931
|
+
urls: urlArr
|
|
932
|
+
});
|
|
933
|
+
},
|
|
934
|
+
/**
|
|
935
|
+
* 缓存页面参数存储
|
|
936
|
+
* @param params 存入页面的参数
|
|
937
|
+
*/
|
|
938
|
+
setCacheParams: (params) => {
|
|
939
|
+
Taro.setStorageSync(CACHE_PARAMS_KEY, params);
|
|
940
|
+
},
|
|
941
|
+
/**
|
|
942
|
+
* 缓存页面参数获取
|
|
943
|
+
* @returns {Record<string, any>}
|
|
944
|
+
*/
|
|
945
|
+
getCacheParams: () => {
|
|
946
|
+
return Taro.getStorageSync(CACHE_PARAMS_KEY);
|
|
947
|
+
},
|
|
948
|
+
/**
|
|
949
|
+
* 缓存页面参数删除
|
|
950
|
+
*/
|
|
951
|
+
removeCacheParams: () => {
|
|
952
|
+
Taro.removeStorageSync(CACHE_PARAMS_KEY);
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
var payUtils = {
|
|
957
|
+
/**
|
|
958
|
+
* 支付
|
|
959
|
+
* @param {WechatPayParams} payParams 微信支付参数
|
|
960
|
+
* @param {string} tradeId
|
|
961
|
+
* @returns {Promise<boolean>}
|
|
962
|
+
*/
|
|
963
|
+
onlinePay: (payParams, tradeId) => {
|
|
964
|
+
if (Utils.isWeapp()) {
|
|
965
|
+
return Utils.wechatPay(payParams, tradeId);
|
|
966
|
+
}
|
|
967
|
+
else if (Utils.isAlipay()) {
|
|
968
|
+
return Utils.aliPay(tradeId);
|
|
969
|
+
}
|
|
970
|
+
else {
|
|
971
|
+
console.log(`支付异常,未兼容${Utils.envText()}小程序`);
|
|
972
|
+
return Promise.resolve(false);
|
|
973
|
+
}
|
|
974
|
+
},
|
|
975
|
+
/**
|
|
976
|
+
* 微信支付
|
|
977
|
+
* @param {WechatPayParams} payParams 微信支付参数
|
|
978
|
+
* @param {string} tradeId
|
|
979
|
+
* @returns {Promise<boolean>}
|
|
980
|
+
*/
|
|
981
|
+
wechatPay: (payParams, tradeId) => {
|
|
982
|
+
console.log('payParams', payParams, tradeId);
|
|
983
|
+
return new Promise(resolve => {
|
|
984
|
+
// 优惠券
|
|
985
|
+
// if (tradeId === CouponPayId) {
|
|
986
|
+
// resolve(true)
|
|
987
|
+
// return
|
|
988
|
+
// }
|
|
989
|
+
Taro.requestPayment({
|
|
990
|
+
...payParams,
|
|
991
|
+
success: function (_res) {
|
|
992
|
+
console.log('支付结果', _res);
|
|
993
|
+
resolve(true);
|
|
994
|
+
},
|
|
995
|
+
fail: function (_res) {
|
|
996
|
+
console.log('支付失败', _res);
|
|
997
|
+
resolve(false);
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
});
|
|
1001
|
+
},
|
|
1002
|
+
/**
|
|
1003
|
+
* 支付宝支付
|
|
1004
|
+
* @param {string} tradeId
|
|
1005
|
+
* @returns {Promise<boolean>}
|
|
1006
|
+
*/
|
|
1007
|
+
aliPay: (tradeId) => {
|
|
1008
|
+
console.log('支付参数--->', tradeId);
|
|
1009
|
+
return new Promise(resolve => {
|
|
1010
|
+
// 优惠券
|
|
1011
|
+
// if (tradeId === CouponPayId) {
|
|
1012
|
+
// resolve(true)
|
|
1013
|
+
// return
|
|
1014
|
+
// }
|
|
1015
|
+
// @ts-ignore
|
|
1016
|
+
my.tradePay({
|
|
1017
|
+
tradeNO: tradeId, //从服务端获取
|
|
1018
|
+
success: (res) => {
|
|
1019
|
+
console.log('支付结果:' + JSON.stringify(res));
|
|
1020
|
+
// success:{"result":"","resultCode":"6001","callbackUrl":"","memo":"支付未完成","extendInfo":{}}
|
|
1021
|
+
if (res.resultCode !== '9000') {
|
|
1022
|
+
resolve(false);
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
else {
|
|
1026
|
+
resolve(true);
|
|
1027
|
+
}
|
|
1028
|
+
},
|
|
1029
|
+
});
|
|
1030
|
+
});
|
|
1031
|
+
},
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* 工具函数
|
|
1036
|
+
*/
|
|
1037
|
+
const Utils = {
|
|
1038
|
+
...IsUtils,
|
|
1039
|
+
...StringUtils,
|
|
1040
|
+
...FormatUtils,
|
|
1041
|
+
...ObjectUtils,
|
|
1042
|
+
...miniUtils,
|
|
1043
|
+
...payUtils,
|
|
1044
|
+
/**
|
|
1045
|
+
* 获取随机数
|
|
1046
|
+
* @public
|
|
1047
|
+
* @param {number} min 最小值
|
|
1048
|
+
* @param {number} max 最大值
|
|
1049
|
+
* @returns {number}
|
|
1050
|
+
*/
|
|
1051
|
+
getRandom(min, max) {
|
|
1052
|
+
return Math.floor(Math.random() * (max - min + 1) + min);
|
|
1053
|
+
},
|
|
1054
|
+
/**
|
|
1055
|
+
* base64转图片Url
|
|
1056
|
+
* @public
|
|
1057
|
+
* @param {string} base64Url base64 url
|
|
1058
|
+
* @returns {string}
|
|
1059
|
+
*/
|
|
1060
|
+
base64ToImgUrl(base64Url) {
|
|
1061
|
+
if (!base64Url)
|
|
1062
|
+
return base64Url;
|
|
1063
|
+
return `data:image/png;base64,${base64Url}`;
|
|
1064
|
+
},
|
|
1065
|
+
/**
|
|
1066
|
+
* 深拷贝对象
|
|
1067
|
+
* @param obj 要拷贝的对象
|
|
1068
|
+
* @returns 深拷贝后的新对象
|
|
1069
|
+
*/
|
|
1070
|
+
cloneDeep(obj) {
|
|
1071
|
+
if (obj === null || typeof obj !== 'object') {
|
|
1072
|
+
return obj;
|
|
1073
|
+
}
|
|
1074
|
+
if (obj instanceof Date) {
|
|
1075
|
+
return new Date(obj.getTime());
|
|
1076
|
+
}
|
|
1077
|
+
if (obj instanceof Array) {
|
|
1078
|
+
return obj.map(item => Utils.cloneDeep(item));
|
|
1079
|
+
}
|
|
1080
|
+
if (typeof obj === 'object') {
|
|
1081
|
+
const clonedObj = {};
|
|
1082
|
+
for (const key in obj) {
|
|
1083
|
+
if (obj.hasOwnProperty(key)) {
|
|
1084
|
+
clonedObj[key] = Utils.cloneDeep(obj[key]);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
return clonedObj;
|
|
1088
|
+
}
|
|
1089
|
+
return obj;
|
|
1090
|
+
},
|
|
362
1091
|
/**
|
|
363
1092
|
* 等待
|
|
364
1093
|
*/
|