@mi-avalon/libs 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ItemsRow/index.d.ts +10 -2
- package/dist/components/ItemsRow/index.js +26 -10
- package/dist/components/MForm/index.d.ts +2 -4
- package/dist/components/MForm/index.js +38 -21
- package/dist/constants/date.d.ts +42 -11
- package/dist/constants/date.js +29 -0
- package/dist/constants/pattern.d.ts +96 -89
- package/dist/constants/pattern.js +134 -89
- package/dist/hooks/useFuncRequest.d.ts +1 -0
- package/dist/hooks/useFuncRequest.js +9 -7
- package/dist/hooks/useInterval.d.ts +2 -2
- package/dist/hooks/useInterval.js +5 -2
- package/dist/hooks/useQuery.d.ts +1 -3
- package/dist/hooks/useQuery.js +51 -4
- package/dist/hooks/useTimeout.js +11 -4
- package/dist/index.es.js +7370 -7174
- package/dist/index.umd.js +83 -83
- package/dist/utils/util.d.ts +55 -5
- package/dist/utils/util.js +245 -46
- package/package.json +2 -2
|
@@ -1,90 +1,135 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
*
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
*
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
*
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 正则表达式模式常量 - 增强版本,提供验证函数和类型安全
|
|
3
|
+
*/
|
|
4
|
+
export class PatternValidator {
|
|
5
|
+
// 基础数字模式
|
|
6
|
+
static patterns = {
|
|
7
|
+
/** 整数 */
|
|
8
|
+
integer: /^-?\d+$/,
|
|
9
|
+
/** 正整数 */
|
|
10
|
+
positiveInteger: /^[1-9]\d*$/,
|
|
11
|
+
/** 负整数 */
|
|
12
|
+
negativeInteger: /^-[1-9]\d*$/,
|
|
13
|
+
/** 浮点数 */
|
|
14
|
+
float: /^-?\d+(\.\d+)?$/,
|
|
15
|
+
/** 字母 */
|
|
16
|
+
letter: /^[a-zA-Z]+$/,
|
|
17
|
+
/** 汉字 */
|
|
18
|
+
chinese: /^[\u4e00-\u9fa5]+$/,
|
|
19
|
+
/** 数字 */
|
|
20
|
+
number: /^[0-9]*$/,
|
|
21
|
+
// 用户相关模式
|
|
22
|
+
/** 用户名:字母开头,允许字母数字下划线,长度4-16 */
|
|
23
|
+
username: /^[a-zA-Z]\w{3,15}$/,
|
|
24
|
+
/** 强用户名:必须包含大小写字母和数字,6-20位 */
|
|
25
|
+
strongUsername: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{6,20}$/,
|
|
26
|
+
/** 密码:至少8位,包含字母和数字 */
|
|
27
|
+
password: /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/,
|
|
28
|
+
/** 强密码:至少8位,包含大小写字母、数字和特殊字符 */
|
|
29
|
+
strongPassword: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
|
|
30
|
+
// 联系方式模式
|
|
31
|
+
/** 中国大陆手机号 */
|
|
32
|
+
phone: /^1[3-9]\d{9}$/,
|
|
33
|
+
/** 带区号的手机号 */
|
|
34
|
+
phoneWithAreaCode: /^\+?\d{2,3}-?\d{8,11}$/,
|
|
35
|
+
/** 邮箱 */
|
|
36
|
+
email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
|
|
37
|
+
/** 身份证 */
|
|
38
|
+
idCard: /^[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)$/,
|
|
39
|
+
/** 银行卡 */
|
|
40
|
+
bankCard: /^[1-9]\d{3,30}$/,
|
|
41
|
+
/** 邮政编码 */
|
|
42
|
+
zipCode: /^[1-9]\d{5}$/,
|
|
43
|
+
// 技术模式
|
|
44
|
+
/** IP地址 */
|
|
45
|
+
ip: /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/,
|
|
46
|
+
/** URL */
|
|
47
|
+
url: /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([\/\w .-]*)*\/?$/,
|
|
48
|
+
/** 车牌号 */
|
|
49
|
+
carNumber: /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-HJ-NP-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$/,
|
|
50
|
+
// 时间日期模式
|
|
51
|
+
/** 时间格式 hh:mm:ss */
|
|
52
|
+
time: /^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/,
|
|
53
|
+
/** 日期格式 YYYY-MM-DD */
|
|
54
|
+
date: /^(\d{4})-(\d{2})-(\d{2})$/,
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* 验证字符串是否匹配指定模式
|
|
58
|
+
* @param type 模式类型
|
|
59
|
+
* @param value 要验证的值
|
|
60
|
+
* @returns 是否匹配
|
|
61
|
+
*/
|
|
62
|
+
static validate(type, value) {
|
|
63
|
+
const pattern = this.patterns[type];
|
|
64
|
+
if (!pattern) {
|
|
65
|
+
throw new Error(`Unknown pattern type: ${type}`);
|
|
66
|
+
}
|
|
67
|
+
return pattern.test(value);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 获取指定模式的正则表达式
|
|
71
|
+
* @param type 模式类型
|
|
72
|
+
* @returns 正则表达式
|
|
73
|
+
*/
|
|
74
|
+
static getPattern(type) {
|
|
75
|
+
const pattern = this.patterns[type];
|
|
76
|
+
if (!pattern) {
|
|
77
|
+
throw new Error(`Unknown pattern type: ${type}`);
|
|
78
|
+
}
|
|
79
|
+
return pattern;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 验证邮箱(特殊处理,支持更复杂的验证)
|
|
83
|
+
* @param email 邮箱地址
|
|
84
|
+
* @returns 是否有效
|
|
85
|
+
*/
|
|
86
|
+
static validateEmail(email) {
|
|
87
|
+
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
88
|
+
return emailRegex.test(email) && email.length <= 254;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 验证手机号(支持更多运营商)
|
|
92
|
+
* @param phone 手机号
|
|
93
|
+
* @returns 是否有效
|
|
94
|
+
*/
|
|
95
|
+
static validatePhone(phone) {
|
|
96
|
+
const phoneRegex = /^1[3-9]\d{9}$/;
|
|
97
|
+
return phoneRegex.test(phone);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 验证身份证(包含校验位验证)
|
|
101
|
+
* @param idCard 身份证号
|
|
102
|
+
* @returns 是否有效
|
|
103
|
+
*/
|
|
104
|
+
static validateIdCard(idCard) {
|
|
105
|
+
const pattern = this.patterns.idCard;
|
|
106
|
+
if (!pattern.test(idCard))
|
|
107
|
+
return false;
|
|
108
|
+
// 校验位验证
|
|
109
|
+
const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
|
|
110
|
+
const codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
|
|
111
|
+
let sum = 0;
|
|
112
|
+
for (let i = 0; i < 17; i++) {
|
|
113
|
+
sum += parseInt(idCard[i]) * weights[i];
|
|
114
|
+
}
|
|
115
|
+
const checkCode = codes[sum % 11];
|
|
116
|
+
return idCard[17].toUpperCase() === checkCode;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 创建自定义验证函数
|
|
120
|
+
* @param pattern 正则表达式
|
|
121
|
+
* @param errorMessage 错误消息
|
|
122
|
+
* @returns 验证函数
|
|
123
|
+
*/
|
|
124
|
+
static createValidator(pattern, errorMessage) {
|
|
125
|
+
return (value) => {
|
|
126
|
+
const valid = pattern.test(value);
|
|
127
|
+
return {
|
|
128
|
+
valid,
|
|
129
|
+
message: valid ? undefined : (errorMessage || 'Invalid format')
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
}
|
|
90
133
|
}
|
|
134
|
+
// 保持向后兼容的别名
|
|
135
|
+
export const PatternType = PatternValidator;
|
|
@@ -5,6 +5,7 @@ export type UseFuncRequestOptions<T extends (...args: any[]) => Promise<any>> =
|
|
|
5
5
|
onSuccess?: (data: UnwrapPromise<ReturnType<T>>) => void | Promise<void>;
|
|
6
6
|
onError?: (error: Error) => void | Promise<void>;
|
|
7
7
|
onFinally?: () => void | Promise<void>;
|
|
8
|
+
autoRunDeps?: any[];
|
|
8
9
|
};
|
|
9
10
|
export declare function useFuncRequest<T extends (...args: any[]) => Promise<any>>(asyncFunc: T, options?: UseFuncRequestOptions<T>): {
|
|
10
11
|
run: (...args: Parameters<T>) => Promise<any>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from 'react';
|
|
1
|
+
import { useEffect, useRef, useState, useMemo, useCallback } from 'react';
|
|
2
2
|
export function useFuncRequest(
|
|
3
3
|
// 异步函数
|
|
4
4
|
asyncFunc,
|
|
@@ -9,12 +9,12 @@ options) {
|
|
|
9
9
|
const [data, setData] = useState(null);
|
|
10
10
|
const abortControllerRef = useRef(undefined);
|
|
11
11
|
const requestIdRef = useRef(0);
|
|
12
|
-
const cancel = () => {
|
|
12
|
+
const cancel = useCallback(() => {
|
|
13
13
|
abortControllerRef.current?.abort();
|
|
14
14
|
setLoading(false);
|
|
15
15
|
setError(null);
|
|
16
|
-
};
|
|
17
|
-
const run = async (...args) => {
|
|
16
|
+
}, []);
|
|
17
|
+
const run = useCallback(async (...args) => {
|
|
18
18
|
const currentRequestId = ++requestIdRef.current;
|
|
19
19
|
cancel();
|
|
20
20
|
const abortController = new AbortController();
|
|
@@ -56,12 +56,14 @@ options) {
|
|
|
56
56
|
await options?.onFinally?.();
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
};
|
|
59
|
+
}, [asyncFunc, options, cancel]);
|
|
60
|
+
// 使用 useMemo 优化依赖项,避免 JSON.stringify 的性能问题
|
|
61
|
+
const autoRunDeps = useMemo(() => [...(options?.autoRunDeps || []), options?.autoRunArgs], [options?.autoRunDeps, options?.autoRunArgs]);
|
|
60
62
|
useEffect(() => {
|
|
61
63
|
if (options?.autoRunArgs) {
|
|
62
64
|
run(...options.autoRunArgs).catch(() => { });
|
|
63
65
|
}
|
|
64
66
|
return cancel;
|
|
65
|
-
},
|
|
66
|
-
return { run, cancel, loading, error, data };
|
|
67
|
+
}, autoRunDeps);
|
|
68
|
+
return useMemo(() => ({ run, cancel, loading, error, data }), [run, cancel, loading, error, data]);
|
|
67
69
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
type Callback = () => void;
|
|
2
|
-
interface
|
|
2
|
+
interface UseIntervalReturn {
|
|
3
3
|
start: Callback;
|
|
4
4
|
isRunning: boolean;
|
|
5
5
|
clear: Callback;
|
|
6
6
|
}
|
|
7
|
-
declare function useInterval(callback: Callback, delay: number | null, immediate?: boolean):
|
|
7
|
+
declare function useInterval(callback: Callback, delay: number | null, immediate?: boolean): UseIntervalReturn;
|
|
8
8
|
export { useInterval };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
function useInterval(callback, delay, immediate = false) {
|
|
3
3
|
const timerRef = useRef(undefined);
|
|
4
4
|
const savedCallback = useRef(callback);
|
|
5
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
5
6
|
useEffect(() => {
|
|
6
7
|
savedCallback.current = callback;
|
|
7
8
|
}, [callback]);
|
|
@@ -9,6 +10,7 @@ function useInterval(callback, delay, immediate = false) {
|
|
|
9
10
|
if (timerRef.current) {
|
|
10
11
|
clearInterval(timerRef.current);
|
|
11
12
|
timerRef.current = undefined;
|
|
13
|
+
setIsRunning(false);
|
|
12
14
|
}
|
|
13
15
|
}, []);
|
|
14
16
|
const start = useCallback(() => {
|
|
@@ -18,6 +20,7 @@ function useInterval(callback, delay, immediate = false) {
|
|
|
18
20
|
if (immediate) {
|
|
19
21
|
savedCallback.current();
|
|
20
22
|
}
|
|
23
|
+
setIsRunning(true);
|
|
21
24
|
timerRef.current = setInterval(() => savedCallback.current(), delay);
|
|
22
25
|
}
|
|
23
26
|
}, [delay, clear, immediate]);
|
|
@@ -25,6 +28,6 @@ function useInterval(callback, delay, immediate = false) {
|
|
|
25
28
|
useEffect(() => {
|
|
26
29
|
return clear;
|
|
27
30
|
}, [clear]);
|
|
28
|
-
return { start, clear, isRunning
|
|
31
|
+
return { start, clear, isRunning };
|
|
29
32
|
}
|
|
30
33
|
export { useInterval };
|
package/dist/hooks/useQuery.d.ts
CHANGED
package/dist/hooks/useQuery.js
CHANGED
|
@@ -1,6 +1,53 @@
|
|
|
1
|
+
import { useMemo, useEffect, useState } from 'react';
|
|
1
2
|
export function useQuery() {
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const [query, setQuery] = useState(() => {
|
|
4
|
+
// SSR兼容性检查
|
|
5
|
+
if (typeof window === 'undefined') {
|
|
6
|
+
return {};
|
|
7
|
+
}
|
|
8
|
+
const search = window.location.search;
|
|
9
|
+
if (!search)
|
|
10
|
+
return {};
|
|
11
|
+
const params = new URLSearchParams(search);
|
|
12
|
+
return Object.fromEntries(params.entries());
|
|
13
|
+
});
|
|
14
|
+
// 使用 useMemo 优化性能,避免每次渲染都重新计算
|
|
15
|
+
const memoizedQuery = useMemo(() => query, [query]);
|
|
16
|
+
// 监听路由变化(popstate, pushstate, replacestate)
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (typeof window === 'undefined')
|
|
19
|
+
return;
|
|
20
|
+
const updateQuery = () => {
|
|
21
|
+
const search = window.location.search;
|
|
22
|
+
if (!search) {
|
|
23
|
+
setQuery({});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const params = new URLSearchParams(search);
|
|
27
|
+
const newQuery = Object.fromEntries(params.entries());
|
|
28
|
+
setQuery(newQuery);
|
|
29
|
+
};
|
|
30
|
+
// 监听浏览器前进/后退
|
|
31
|
+
window.addEventListener('popstate', updateQuery);
|
|
32
|
+
// 拦截 pushState 和 replaceState
|
|
33
|
+
const originalPushState = history.pushState;
|
|
34
|
+
const originalReplaceState = history.replaceState;
|
|
35
|
+
history.pushState = function (...args) {
|
|
36
|
+
originalPushState.apply(history, args);
|
|
37
|
+
setTimeout(updateQuery, 0);
|
|
38
|
+
};
|
|
39
|
+
history.replaceState = function (...args) {
|
|
40
|
+
originalReplaceState.apply(history, args);
|
|
41
|
+
setTimeout(updateQuery, 0);
|
|
42
|
+
};
|
|
43
|
+
// 监听 hashchange(对于 hash 路由)
|
|
44
|
+
window.addEventListener('hashchange', updateQuery);
|
|
45
|
+
return () => {
|
|
46
|
+
window.removeEventListener('popstate', updateQuery);
|
|
47
|
+
window.removeEventListener('hashchange', updateQuery);
|
|
48
|
+
history.pushState = originalPushState;
|
|
49
|
+
history.replaceState = originalReplaceState;
|
|
50
|
+
};
|
|
51
|
+
}, []);
|
|
52
|
+
return memoizedQuery;
|
|
6
53
|
}
|
package/dist/hooks/useTimeout.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
function useTimeout(callback, delay, immediate = false) {
|
|
3
3
|
const timerRef = useRef(undefined);
|
|
4
4
|
const savedCallback = useRef(callback);
|
|
5
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
5
6
|
useEffect(() => {
|
|
6
7
|
savedCallback.current = callback;
|
|
7
8
|
}, [callback]);
|
|
8
9
|
const clear = useCallback(() => {
|
|
9
10
|
if (timerRef.current) {
|
|
10
|
-
|
|
11
|
+
clearTimeout(timerRef.current);
|
|
11
12
|
timerRef.current = undefined;
|
|
13
|
+
setIsRunning(false);
|
|
12
14
|
}
|
|
13
15
|
}, []);
|
|
14
16
|
const start = useCallback(() => {
|
|
@@ -18,13 +20,18 @@ function useTimeout(callback, delay, immediate = false) {
|
|
|
18
20
|
if (immediate) {
|
|
19
21
|
savedCallback.current();
|
|
20
22
|
}
|
|
21
|
-
|
|
23
|
+
setIsRunning(true);
|
|
24
|
+
timerRef.current = setTimeout(() => {
|
|
25
|
+
savedCallback.current();
|
|
26
|
+
setIsRunning(false);
|
|
27
|
+
timerRef.current = undefined;
|
|
28
|
+
}, delay);
|
|
22
29
|
}
|
|
23
30
|
}, [delay, clear, immediate]);
|
|
24
31
|
// 只负责清理
|
|
25
32
|
useEffect(() => {
|
|
26
33
|
return clear;
|
|
27
34
|
}, [clear]);
|
|
28
|
-
return { start, clear, isRunning
|
|
35
|
+
return { start, clear, isRunning };
|
|
29
36
|
}
|
|
30
37
|
export { useTimeout };
|