ph-utils 0.4.1 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/clipboard.d.ts +11 -0
- package/lib/clipboard.js +101 -0
- package/lib/copy.js +17 -21
- package/lib/crypto_node.d.ts +2 -2
- package/lib/crypto_node.js +23 -20
- package/lib/date.d.ts +4 -2
- package/lib/date.js +44 -28
- package/lib/index.d.ts +6 -0
- package/lib/index.js +44 -30
- package/lib/storage.d.ts +1 -1
- package/lib/storage.js +8 -4
- package/package.json +1 -1
@@ -0,0 +1,11 @@
|
|
1
|
+
/**
|
2
|
+
* 复制数据, 可以从多种类型的数据
|
3
|
+
* 1. 直接复制文本: await copy("待复制的文本")
|
4
|
+
* 2. 复制节点上的 data-copy-text:
|
5
|
+
* <button data-copy-text="这是待复制的文本">复制</button>
|
6
|
+
* await copy(e.target) // or await copy("#a") or await copy(document.querySelector('#a'))
|
7
|
+
* 3. 直接复制节点本身数据: await copy('#a')
|
8
|
+
* @param {string | HTMLElement} source 复制源, 从中解析待复制的数据
|
9
|
+
* @returns {Promise<boolean>} 是否复制成功
|
10
|
+
*/
|
11
|
+
export declare function copy(source: string | HTMLElement): Promise<boolean>;
|
package/lib/clipboard.js
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
/**
|
2
|
+
* 创建一个临时节点缓存待复制数据
|
3
|
+
* @param {String} value - 待复制文本
|
4
|
+
* @return {HTMLElement}
|
5
|
+
*/
|
6
|
+
function createFakeElement(value) {
|
7
|
+
const fakeElement = document.createElement("textarea");
|
8
|
+
fakeElement.style.border = "0";
|
9
|
+
fakeElement.style.padding = "0";
|
10
|
+
fakeElement.style.margin = "0";
|
11
|
+
fakeElement.style.position = "absolute";
|
12
|
+
fakeElement.style.left = "-9999px";
|
13
|
+
fakeElement.style.top = "-9999";
|
14
|
+
fakeElement.setAttribute("readonly", "");
|
15
|
+
fakeElement.value = value;
|
16
|
+
return fakeElement;
|
17
|
+
}
|
18
|
+
/** 通过执行 execCommand 来执行复制 */
|
19
|
+
function copyFromCommand(text) {
|
20
|
+
// 添加节点
|
21
|
+
const fakeEl = createFakeElement(text);
|
22
|
+
document.body.append(fakeEl);
|
23
|
+
fakeEl.focus();
|
24
|
+
fakeEl.select();
|
25
|
+
// 执行复制
|
26
|
+
const res = document.execCommand("copy");
|
27
|
+
fakeEl.remove(); // 删除节点
|
28
|
+
return Promise.resolve(res);
|
29
|
+
}
|
30
|
+
/** 使用 navigator.clipboard 复制 */
|
31
|
+
function copyFromClipboard(text) {
|
32
|
+
const theClipboard = navigator.clipboard;
|
33
|
+
if (theClipboard != null) {
|
34
|
+
return theClipboard
|
35
|
+
.writeText(text)
|
36
|
+
.then(() => {
|
37
|
+
Promise.resolve(true);
|
38
|
+
})
|
39
|
+
.catch(() => Promise.resolve(false));
|
40
|
+
}
|
41
|
+
return Promise.resolve(false);
|
42
|
+
}
|
43
|
+
/** 解析待复制的文本 */
|
44
|
+
function parseCopyText(source) {
|
45
|
+
let copyText = null; // 待复制文本
|
46
|
+
let sourceEl = null;
|
47
|
+
// 获取待复制数据
|
48
|
+
if (typeof source === "string") {
|
49
|
+
// 从节点拿数据
|
50
|
+
if (source.startsWith("#") || source.startsWith(".")) {
|
51
|
+
sourceEl = document.querySelector(source);
|
52
|
+
if (sourceEl == null) {
|
53
|
+
copyText = source;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
else {
|
57
|
+
copyText = source;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
if (source instanceof HTMLElement) {
|
61
|
+
sourceEl = source;
|
62
|
+
}
|
63
|
+
// 从节点获取待复制数据
|
64
|
+
if (sourceEl != null) {
|
65
|
+
if (sourceEl.hasAttribute("data-copy-text")) {
|
66
|
+
copyText = sourceEl.getAttribute("data-copy-text");
|
67
|
+
}
|
68
|
+
else {
|
69
|
+
const tagName = sourceEl.tagName;
|
70
|
+
if (tagName === "INPUT" || tagName === "TEXTAREA") {
|
71
|
+
copyText = sourceEl.value;
|
72
|
+
}
|
73
|
+
else {
|
74
|
+
copyText = sourceEl.textContent;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
return copyText;
|
79
|
+
}
|
80
|
+
/**
|
81
|
+
* 复制数据, 可以从多种类型的数据
|
82
|
+
* 1. 直接复制文本: await copy("待复制的文本")
|
83
|
+
* 2. 复制节点上的 data-copy-text:
|
84
|
+
* <button data-copy-text="这是待复制的文本">复制</button>
|
85
|
+
* await copy(e.target) // or await copy("#a") or await copy(document.querySelector('#a'))
|
86
|
+
* 3. 直接复制节点本身数据: await copy('#a')
|
87
|
+
* @param {string | HTMLElement} source 复制源, 从中解析待复制的数据
|
88
|
+
* @returns {Promise<boolean>} 是否复制成功
|
89
|
+
*/
|
90
|
+
export async function copy(source) {
|
91
|
+
// 待复制文本
|
92
|
+
const copyText = parseCopyText(source);
|
93
|
+
if (copyText == null) {
|
94
|
+
return Promise.resolve(false);
|
95
|
+
}
|
96
|
+
const v = await copyFromClipboard(copyText);
|
97
|
+
if (v === false) {
|
98
|
+
return copyFromCommand(copyText);
|
99
|
+
}
|
100
|
+
return Promise.resolve(true);
|
101
|
+
}
|
package/lib/copy.js
CHANGED
@@ -4,14 +4,14 @@
|
|
4
4
|
* @return {HTMLElement}
|
5
5
|
*/
|
6
6
|
function createFakeElement(value) {
|
7
|
-
const fakeElement = document.createElement(
|
8
|
-
fakeElement.style.border =
|
9
|
-
fakeElement.style.padding =
|
10
|
-
fakeElement.style.margin =
|
11
|
-
fakeElement.style.position =
|
12
|
-
fakeElement.style.left =
|
13
|
-
fakeElement.style.top =
|
14
|
-
fakeElement.setAttribute(
|
7
|
+
const fakeElement = document.createElement("textarea");
|
8
|
+
fakeElement.style.border = "0";
|
9
|
+
fakeElement.style.padding = "0";
|
10
|
+
fakeElement.style.margin = "0";
|
11
|
+
fakeElement.style.position = "absolute";
|
12
|
+
fakeElement.style.left = "-9999px";
|
13
|
+
fakeElement.style.top = "-9999";
|
14
|
+
fakeElement.setAttribute("readonly", "");
|
15
15
|
fakeElement.value = value;
|
16
16
|
return fakeElement;
|
17
17
|
}
|
@@ -23,13 +23,13 @@ function copyFromCommand(text) {
|
|
23
23
|
fakeEl.focus();
|
24
24
|
fakeEl.select();
|
25
25
|
// 执行复制
|
26
|
-
const res = document.execCommand(
|
26
|
+
const res = document.execCommand("copy");
|
27
27
|
fakeEl.remove(); // 删除节点
|
28
28
|
return Promise.resolve(res);
|
29
29
|
}
|
30
30
|
/** 使用 navigator.clipboard 复制 */
|
31
31
|
function copyFromClipboard(text) {
|
32
|
-
|
32
|
+
const theClipboard = navigator.clipboard;
|
33
33
|
if (theClipboard != null) {
|
34
34
|
return theClipboard
|
35
35
|
.writeText(text)
|
@@ -38,18 +38,16 @@ function copyFromClipboard(text) {
|
|
38
38
|
})
|
39
39
|
.catch(() => Promise.resolve(false));
|
40
40
|
}
|
41
|
-
|
42
|
-
return Promise.resolve(false);
|
43
|
-
}
|
41
|
+
return Promise.resolve(false);
|
44
42
|
}
|
45
43
|
/** 解析待复制的文本 */
|
46
44
|
function parseCopyText(source) {
|
47
45
|
let copyText = null; // 待复制文本
|
48
46
|
let sourceEl = null;
|
49
47
|
// 获取待复制数据
|
50
|
-
if (typeof source ===
|
48
|
+
if (typeof source === "string") {
|
51
49
|
// 从节点拿数据
|
52
|
-
if (source.startsWith(
|
50
|
+
if (source.startsWith("#") || source.startsWith(".")) {
|
53
51
|
sourceEl = document.querySelector(source);
|
54
52
|
if (sourceEl == null) {
|
55
53
|
copyText = source;
|
@@ -64,12 +62,12 @@ function parseCopyText(source) {
|
|
64
62
|
}
|
65
63
|
// 从节点获取待复制数据
|
66
64
|
if (sourceEl != null) {
|
67
|
-
if (sourceEl.hasAttribute(
|
68
|
-
copyText = sourceEl.getAttribute(
|
65
|
+
if (sourceEl.hasAttribute("data-copy-text")) {
|
66
|
+
copyText = sourceEl.getAttribute("data-copy-text");
|
69
67
|
}
|
70
68
|
else {
|
71
69
|
const tagName = sourceEl.tagName;
|
72
|
-
if (tagName ===
|
70
|
+
if (tagName === "INPUT" || tagName === "TEXTAREA") {
|
73
71
|
copyText = sourceEl.value;
|
74
72
|
}
|
75
73
|
else {
|
@@ -99,7 +97,5 @@ export async function copy(source) {
|
|
99
97
|
if (v === false) {
|
100
98
|
return copyFromCommand(copyText);
|
101
99
|
}
|
102
|
-
|
103
|
-
return Promise.resolve(true);
|
104
|
-
}
|
100
|
+
return Promise.resolve(true);
|
105
101
|
}
|
package/lib/crypto_node.d.ts
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
type HashAlgorithmName =
|
1
|
+
type HashAlgorithmName = "md5" | "sha1" | "sha256";
|
2
2
|
/**
|
3
3
|
* 进行 md5|sha1|sha256 数据摘要签名
|
4
4
|
* @param d 待加密的数据
|
5
|
-
* @param algorithm 签名算法, md5、sha1. Defaults to "
|
5
|
+
* @param algorithm 签名算法, md5、sha1、sha256. Defaults to "sha256".
|
6
6
|
* @param upper 返回的结果是否需要大写. Defaults to False.
|
7
7
|
*/
|
8
8
|
export declare function hashDigest(d: string, algorithm?: HashAlgorithmName, upper?: boolean): string;
|
package/lib/crypto_node.js
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
import { createHash, createCipheriv, randomBytes, generateKeyPair, createDecipheriv, privateDecrypt, publicEncrypt, } from
|
1
|
+
import { createHash, createCipheriv, randomBytes, generateKeyPair, createDecipheriv, privateDecrypt, publicEncrypt, } from "node:crypto";
|
2
2
|
/**
|
3
3
|
* 进行 md5|sha1|sha256 数据摘要签名
|
4
4
|
* @param d 待加密的数据
|
5
|
-
* @param algorithm 签名算法, md5、sha1. Defaults to "
|
5
|
+
* @param algorithm 签名算法, md5、sha1、sha256. Defaults to "sha256".
|
6
6
|
* @param upper 返回的结果是否需要大写. Defaults to False.
|
7
7
|
*/
|
8
|
-
export function hashDigest(d, algorithm =
|
9
|
-
const hashed = createHash(algorithm).update(d).digest(
|
8
|
+
export function hashDigest(d, algorithm = "sha256", upper = false) {
|
9
|
+
const hashed = createHash(algorithm).update(d).digest("hex");
|
10
10
|
return upper ? hashed.toUpperCase() : hashed;
|
11
11
|
}
|
12
12
|
/**
|
@@ -15,15 +15,15 @@ export function hashDigest(d, algorithm = 'sha256', upper = false) {
|
|
15
15
|
*/
|
16
16
|
export async function keyPair() {
|
17
17
|
return new Promise((resolve, reject) => {
|
18
|
-
generateKeyPair(
|
18
|
+
generateKeyPair("rsa", {
|
19
19
|
modulusLength: 2048,
|
20
20
|
publicKeyEncoding: {
|
21
|
-
type:
|
22
|
-
format:
|
21
|
+
type: "spki",
|
22
|
+
format: "pem",
|
23
23
|
},
|
24
24
|
privateKeyEncoding: {
|
25
|
-
type:
|
26
|
-
format:
|
25
|
+
type: "pkcs8",
|
26
|
+
format: "pem",
|
27
27
|
},
|
28
28
|
}, (err, publicKey, privateKey) => {
|
29
29
|
if (err == null) {
|
@@ -44,10 +44,13 @@ export async function keyPair() {
|
|
44
44
|
*/
|
45
45
|
export function aesEncrypt(key, input, upper = false) {
|
46
46
|
const iv = randomBytes(16);
|
47
|
-
const cipher = createCipheriv(
|
48
|
-
let encryptedData = cipher.update(input,
|
49
|
-
encryptedData += cipher.final(
|
50
|
-
return [
|
47
|
+
const cipher = createCipheriv("aes-256-cbc", Buffer.from(key, "hex"), iv);
|
48
|
+
let encryptedData = cipher.update(input, "utf-8", "hex");
|
49
|
+
encryptedData += cipher.final("hex");
|
50
|
+
return [
|
51
|
+
upper === true ? encryptedData.toUpperCase() : encryptedData,
|
52
|
+
iv.toString("hex"),
|
53
|
+
];
|
51
54
|
}
|
52
55
|
/**
|
53
56
|
* AES 解密
|
@@ -57,9 +60,9 @@ export function aesEncrypt(key, input, upper = false) {
|
|
57
60
|
* @returns
|
58
61
|
*/
|
59
62
|
export function aesDecrypt(input, key, iv) {
|
60
|
-
const cipher = createDecipheriv(
|
61
|
-
let decryptedData = cipher.update(input,
|
62
|
-
decryptedData += cipher.final(
|
63
|
+
const cipher = createDecipheriv("aes-256-cbc", Buffer.from(key, "hex"), Buffer.from(iv, "hex"));
|
64
|
+
let decryptedData = cipher.update(input, "hex", "utf-8");
|
65
|
+
decryptedData += cipher.final("utf-8");
|
63
66
|
return decryptedData;
|
64
67
|
}
|
65
68
|
/**
|
@@ -71,8 +74,8 @@ export function aesDecrypt(input, key, iv) {
|
|
71
74
|
export function rsaEncrypt(input, publicKey) {
|
72
75
|
return publicEncrypt({
|
73
76
|
key: publicKey,
|
74
|
-
oaepHash:
|
75
|
-
}, Buffer.from(input)).toString(
|
77
|
+
oaepHash: "sha256",
|
78
|
+
}, Buffer.from(input)).toString("base64");
|
76
79
|
}
|
77
80
|
/**
|
78
81
|
* RSA 解密
|
@@ -83,6 +86,6 @@ export function rsaEncrypt(input, publicKey) {
|
|
83
86
|
export function rsaDecrypt(encrtypData, privateKey) {
|
84
87
|
return privateDecrypt({
|
85
88
|
key: privateKey,
|
86
|
-
oaepHash:
|
87
|
-
}, Buffer.from(encrtypData,
|
89
|
+
oaepHash: "sha256",
|
90
|
+
}, Buffer.from(encrtypData, "base64")).toString("utf-8");
|
88
91
|
}
|
package/lib/date.d.ts
CHANGED
@@ -37,12 +37,14 @@ export declare function endOf(date?: Date | string | number, unit?: string): Dat
|
|
37
37
|
* @param pre 精度, s - 精确到秒, ms - 精确到毫秒, 默认: s
|
38
38
|
* @returns
|
39
39
|
*/
|
40
|
-
export declare function timeStamp(ctime?: Date | string | number, pre?:
|
40
|
+
export declare function timeStamp(ctime?: Date | string | number, pre?: "s" | "ms"): number;
|
41
41
|
/**
|
42
42
|
* 日期加上指定时间后的日期
|
43
43
|
* @param date 指定的日期
|
44
44
|
* @param num 需要添加的数字, 如果这个参数传递一个小于0的数字,则就是日期减去相应的数字
|
45
|
-
* @param unit 需要添加的单位,date
|
45
|
+
* @param unit 需要添加的单位,date、month、year、hours、minute、second
|
46
|
+
*
|
47
|
+
* 查阅文档: {@link https://gitee.com/towardly/ph/wikis/utils/date ph-utils}
|
46
48
|
*/
|
47
49
|
export declare function add(date: Date | string | number | null, num: number, unit: string): Date;
|
48
50
|
/**
|
package/lib/date.js
CHANGED
@@ -10,13 +10,19 @@ const ofArgs = {
|
|
10
10
|
end: [0, 11, -2, 23, 59, 59, 999],
|
11
11
|
};
|
12
12
|
const units = {
|
13
|
-
Date: [
|
14
|
-
Month: [
|
15
|
-
Year: [
|
16
|
-
Hours: [
|
17
|
-
Minutes: [
|
18
|
-
Seconds: [
|
19
|
-
Milliseconds: [
|
13
|
+
Date: ["date", "Date", "day", "Day", "D", "d"],
|
14
|
+
Month: ["Month", "month", "m"],
|
15
|
+
Year: ["Year", "year", "y"],
|
16
|
+
Hours: ["Hours", "hours", "H"],
|
17
|
+
Minutes: ["Minutes", "Minute", "minute", "minutes", "M"],
|
18
|
+
Seconds: ["Seconds", "seconds", "Second", "second", "s"],
|
19
|
+
Milliseconds: [
|
20
|
+
"Milliseconds",
|
21
|
+
"Millisecond",
|
22
|
+
"milliseconds",
|
23
|
+
"illisecond",
|
24
|
+
"S",
|
25
|
+
],
|
20
26
|
};
|
21
27
|
/**
|
22
28
|
* 不足位数, 前位补 0
|
@@ -29,7 +35,7 @@ function p(s, l = 2) {
|
|
29
35
|
* 由于年份最多为4为,所以前面先添3个0
|
30
36
|
* slice() 从后开始提前字符串
|
31
37
|
*/
|
32
|
-
return
|
38
|
+
return `000${s}`.slice(l * -1);
|
33
39
|
}
|
34
40
|
/**
|
35
41
|
* 将单位转换为首字母大写, 例如:hours -> Hours
|
@@ -38,7 +44,7 @@ function p(s, l = 2) {
|
|
38
44
|
*/
|
39
45
|
function getUnit(unit) {
|
40
46
|
let period = null;
|
41
|
-
for (
|
47
|
+
for (const [key, value] of Object.entries(units)) {
|
42
48
|
if (value.includes(unit)) {
|
43
49
|
period = key;
|
44
50
|
break;
|
@@ -68,16 +74,16 @@ function getLastDayOfYear(date, month) {
|
|
68
74
|
* @param date 日期
|
69
75
|
* @param pattern 格式化字符串 yyyy - 年, mm - 月, dd - 日, HH - 小时, MM - 分钟, ss - 秒
|
70
76
|
*/
|
71
|
-
export function format(date, pattern =
|
77
|
+
export function format(date, pattern = "yyyy-mm-dd HH:MM") {
|
72
78
|
// eslint-disable-next-line
|
73
79
|
date = parse(date);
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
80
|
+
const d = date.getDate();
|
81
|
+
const y = date.getFullYear();
|
82
|
+
const m = date.getMonth();
|
83
|
+
const H = date.getHours();
|
84
|
+
const M = date.getMinutes();
|
85
|
+
const s = date.getSeconds();
|
86
|
+
const flags = {
|
81
87
|
yy: p(y),
|
82
88
|
yyyy: y,
|
83
89
|
m: m + 1,
|
@@ -111,13 +117,13 @@ export function parse(date) {
|
|
111
117
|
return new Date();
|
112
118
|
if (date instanceof Date)
|
113
119
|
return date;
|
114
|
-
if (typeof date ===
|
120
|
+
if (typeof date === "string" && !/Z$/i.test(date)) {
|
115
121
|
const d = date.match(REGEX_PARSE);
|
116
122
|
if (d) {
|
117
123
|
return new Date(d[1], d[2] - 1, d[3] || 1, d[4] || 0, d[5] || 0, d[6] || 0, d[7] || 0);
|
118
124
|
}
|
119
125
|
}
|
120
|
-
if (typeof date ===
|
126
|
+
if (typeof date === "number") {
|
121
127
|
return new Date(date <= 9999999999 ? date * 1000 : date);
|
122
128
|
}
|
123
129
|
return new Date();
|
@@ -130,18 +136,28 @@ export function parse(date) {
|
|
130
136
|
*/
|
131
137
|
export function dateOf(date, unit, isEnd = false) {
|
132
138
|
/* 如果是设置某一天的开始时刻, 就需要将时、分、秒、毫秒设置为0,依次类推设置 */
|
133
|
-
const periods = [
|
134
|
-
|
139
|
+
const periods = [
|
140
|
+
"Year",
|
141
|
+
"Month",
|
142
|
+
"Date",
|
143
|
+
"Hours",
|
144
|
+
"Minutes",
|
145
|
+
"Seconds",
|
146
|
+
"Milliseconds",
|
147
|
+
];
|
148
|
+
let index = periods.indexOf(getUnit(unit || "Date"));
|
135
149
|
const clone = parse(date);
|
136
150
|
index++;
|
137
|
-
const setValues = ofArgs[isEnd === true ?
|
151
|
+
const setValues = ofArgs[isEnd === true ? "end" : "start"];
|
138
152
|
for (const len = periods.length; index < len; index++) {
|
139
153
|
let value = setValues[index];
|
140
154
|
if (value === -2) {
|
141
155
|
// 设置为某个月的最后一天的日期
|
142
156
|
value = getLastDayOfYear(clone);
|
143
157
|
}
|
144
|
-
Date.prototype[
|
158
|
+
Date.prototype["set" + periods[index]].apply(clone, [
|
159
|
+
setValues[index],
|
160
|
+
]);
|
145
161
|
}
|
146
162
|
return clone;
|
147
163
|
}
|
@@ -169,9 +185,9 @@ export function endOf(date, unit) {
|
|
169
185
|
* @param pre 精度, s - 精确到秒, ms - 精确到毫秒, 默认: s
|
170
186
|
* @returns
|
171
187
|
*/
|
172
|
-
export function timeStamp(ctime, pre =
|
188
|
+
export function timeStamp(ctime, pre = "s") {
|
173
189
|
let tm = parse(ctime).getTime();
|
174
|
-
return pre ===
|
190
|
+
return pre === "s" ? Math.floor(tm / 1000) : tm;
|
175
191
|
}
|
176
192
|
/**
|
177
193
|
* 日期加上指定时间后的日期
|
@@ -188,13 +204,13 @@ export function add(date, num, unit, fmt) {
|
|
188
204
|
}
|
189
205
|
// eslint-disable-next-line
|
190
206
|
unit = getUnit(unit);
|
191
|
-
let fn =
|
192
|
-
let gn =
|
207
|
+
let fn = "set" + unit;
|
208
|
+
let gn = "get" + unit;
|
193
209
|
// @ts-ignore
|
194
210
|
let oldValue = Date.prototype[gn].apply(sdate);
|
195
211
|
// @ts-ignore
|
196
212
|
Date.prototype[fn].apply(sdate, [oldValue + num]);
|
197
|
-
if (typeof fmt ===
|
213
|
+
if (typeof fmt === "string") {
|
198
214
|
return format(sdate, fmt);
|
199
215
|
}
|
200
216
|
else {
|
package/lib/index.d.ts
CHANGED
@@ -80,4 +80,10 @@ export declare class BaseError extends Error {
|
|
80
80
|
* @return string
|
81
81
|
*/
|
82
82
|
export declare function formatMoney(number: number): string;
|
83
|
+
/**
|
84
|
+
* 将风格由大写风格转换为下划线风格: HelloWorld -> hello-world
|
85
|
+
* @param name 命名, 例如: HelloWorld
|
86
|
+
* @param connector 连接符, 默认为: _
|
87
|
+
*/
|
88
|
+
export declare function snakeCaseStyle(name: string, connector?: string): string;
|
83
89
|
export {};
|
package/lib/index.js
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
* node 和 web 通用的工具类
|
3
3
|
*/
|
4
4
|
/** 包含字母+数字的随机数字符 */
|
5
|
-
const RANDOM_CHARS =
|
5
|
+
const RANDOM_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
6
6
|
/** 只包含字母的随机数字符 */
|
7
|
-
const NUMBER_RANDOM_CHARTS =
|
7
|
+
const NUMBER_RANDOM_CHARTS = "0123456789";
|
8
8
|
/**
|
9
9
|
* 验证字符串是否为空
|
10
10
|
* @param str 待验证的字符串
|
@@ -22,14 +22,14 @@ export function isBlank(str, ignoreWhitespace = true) {
|
|
22
22
|
* @returns 屏蔽后的手机号,例如:123 **** 1234
|
23
23
|
*/
|
24
24
|
export function shieldMobile(mobile) {
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
const x1 = Math.floor(mobile.length / 2);
|
26
|
+
const x2 = Math.ceil(x1 / 2);
|
27
|
+
const shields = [" "];
|
28
28
|
for (let i = 0; i < x1 - 1; i++) {
|
29
|
-
shields.push(
|
29
|
+
shields.push("*");
|
30
30
|
}
|
31
|
-
shields.push(
|
32
|
-
return mobile.substring(0, x2) + shields.join(
|
31
|
+
shields.push(" ");
|
32
|
+
return (mobile.substring(0, x2) + shields.join("") + mobile.substring(x2 + x1 - 1));
|
33
33
|
}
|
34
34
|
/**
|
35
35
|
* 验证参数是否是数字
|
@@ -41,9 +41,9 @@ export function shieldMobile(mobile) {
|
|
41
41
|
*/
|
42
42
|
export function isNumeric(str, numericParam) {
|
43
43
|
numericParam = { isPositive: false, isFloat: true, ...(numericParam || {}) };
|
44
|
-
|
45
|
-
|
46
|
-
return new RegExp(
|
44
|
+
const symbol = numericParam.isPositive ? "[+]?" : "[+-]?";
|
45
|
+
const main = numericParam.isFloat ? "([0-9]*[.])?[0-9]+" : "[0-9]+";
|
46
|
+
return new RegExp("^" + symbol + main + "$").test(str);
|
47
47
|
}
|
48
48
|
/**
|
49
49
|
* 验证参数是否是Boolean 类型
|
@@ -51,7 +51,7 @@ export function isNumeric(str, numericParam) {
|
|
51
51
|
* @returns
|
52
52
|
*/
|
53
53
|
export function isBoolean(str) {
|
54
|
-
return [
|
54
|
+
return ["true", "false"].indexOf(str) >= 0;
|
55
55
|
}
|
56
56
|
/**
|
57
57
|
* 生成随机数
|
@@ -61,7 +61,7 @@ export function isBoolean(str) {
|
|
61
61
|
* @returns
|
62
62
|
*/
|
63
63
|
export function random(opts) {
|
64
|
-
if (typeof opts ===
|
64
|
+
if (typeof opts === "object" && opts.min != null && opts.max != null) {
|
65
65
|
const randomNum = Math.random();
|
66
66
|
/* 生成两个数字之间的随机数(number) */
|
67
67
|
const end = opts.hasEnd ? 1 : 0;
|
@@ -69,18 +69,20 @@ export function random(opts) {
|
|
69
69
|
return opts.isInteger !== false ? Math.floor(resRandom) : resRandom;
|
70
70
|
}
|
71
71
|
else {
|
72
|
-
if (typeof opts ===
|
73
|
-
throw new Error(
|
72
|
+
if (typeof opts === "object" && opts.length == null) {
|
73
|
+
throw new Error("random_length_cannot_null");
|
74
74
|
}
|
75
|
-
const len = typeof opts ===
|
75
|
+
const len = typeof opts === "object" ? opts.length : opts;
|
76
76
|
/* 生成指定长度的随机数 */
|
77
77
|
const charLens = RANDOM_CHARS.length;
|
78
78
|
let chars = RANDOM_CHARS;
|
79
|
-
if (typeof opts ===
|
79
|
+
if (typeof opts === "object" && opts.hasLetter === false) {
|
80
80
|
chars = NUMBER_RANDOM_CHARTS;
|
81
81
|
}
|
82
|
-
const resRandom = Array.from({ length: len }, () => chars.charAt(Math.floor(Math.random() * charLens))).join(
|
83
|
-
if (typeof opts ===
|
82
|
+
const resRandom = Array.from({ length: len }, () => chars.charAt(Math.floor(Math.random() * charLens))).join("");
|
83
|
+
if (typeof opts === "object" &&
|
84
|
+
opts.firstIsZero === false &&
|
85
|
+
resRandom.indexOf("0") === 0) {
|
84
86
|
return random(opts);
|
85
87
|
}
|
86
88
|
else {
|
@@ -100,7 +102,7 @@ export class BaseError extends Error {
|
|
100
102
|
constructor() {
|
101
103
|
if (arguments.length === 1) {
|
102
104
|
super(arguments[0]);
|
103
|
-
this.name =
|
105
|
+
this.name = "BaseError";
|
104
106
|
}
|
105
107
|
else {
|
106
108
|
super(arguments[1]);
|
@@ -114,25 +116,37 @@ export class BaseError extends Error {
|
|
114
116
|
* @return string
|
115
117
|
*/
|
116
118
|
export function formatMoney(number) {
|
117
|
-
if (typeof Intl.NumberFormat !==
|
118
|
-
const formatter = new Intl.NumberFormat(
|
119
|
-
style:
|
119
|
+
if (typeof Intl.NumberFormat !== "undefined") {
|
120
|
+
const formatter = new Intl.NumberFormat("zh-CN", {
|
121
|
+
style: "decimal",
|
120
122
|
maximumFractionDigits: 2,
|
121
123
|
});
|
122
124
|
return formatter.format(number);
|
123
125
|
}
|
124
126
|
else {
|
125
127
|
number = number || 0;
|
126
|
-
|
127
|
-
|
128
|
-
|
128
|
+
const negative = "";
|
129
|
+
const base = String(parseInt(number, 10)); // 获取数字整数部分
|
130
|
+
const mod = base.length > 3 ? base.length % 3 : 0;
|
129
131
|
/*
|
130
132
|
* 利用 正则前瞻 (?=) 将3位数字后面还紧跟一位数字的三位数字替换为 数字, 的形式
|
131
133
|
*/
|
132
|
-
|
133
|
-
|
134
|
-
let dotStr = usePrecision > 0 ? numberStr.slice(usePrecision + 1) :
|
134
|
+
const numberStr = String(number);
|
135
|
+
const usePrecision = numberStr.indexOf(".");
|
136
|
+
let dotStr = usePrecision > 0 ? numberStr.slice(usePrecision + 1) : "00";
|
135
137
|
dotStr = dotStr.length > 2 ? dotStr.slice(0, 2) : dotStr;
|
136
|
-
return (negative +
|
138
|
+
return (negative +
|
139
|
+
(mod ? base.slice(0, mod) + "," : "") +
|
140
|
+
base.slice(mod).replace(/(\d{3})(?=\d)/g, "$1,") +
|
141
|
+
"." +
|
142
|
+
dotStr);
|
137
143
|
}
|
138
144
|
}
|
145
|
+
/**
|
146
|
+
* 将风格由大写风格转换为下划线风格: HelloWorld -> hello-world
|
147
|
+
* @param name 命名, 例如: HelloWorld
|
148
|
+
* @param connector 连接符, 默认为: _
|
149
|
+
*/
|
150
|
+
export function snakeCaseStyle(name, connector = "-") {
|
151
|
+
return name.replace(/([A-Z])/g, (match, p1, offset) => (offset > 0 ? connector : "") + match.toLowerCase());
|
152
|
+
}
|
package/lib/storage.d.ts
CHANGED
package/lib/storage.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
function getStorage(storage =
|
2
|
-
return storage ===
|
1
|
+
function getStorage(storage = "session") {
|
2
|
+
return storage === "session" ? sessionStorage : localStorage;
|
3
3
|
}
|
4
4
|
/**
|
5
5
|
* 存储值到 Storage 中
|
@@ -9,7 +9,11 @@ function getStorage(storage = 'session') {
|
|
9
9
|
* @param expire 数据有效期, 单位秒, 默认: -1 - 永久存储
|
10
10
|
*/
|
11
11
|
export function set(key, value, option) {
|
12
|
-
const opts = {
|
12
|
+
const opts = {
|
13
|
+
expire: -1,
|
14
|
+
storage: "session",
|
15
|
+
...(option || {}),
|
16
|
+
};
|
13
17
|
const saveData = JSON.stringify({
|
14
18
|
value,
|
15
19
|
time: Date.now(),
|
@@ -41,7 +45,7 @@ export function remove(key, storage) {
|
|
41
45
|
* @returns Storage 中 key 对应的数据
|
42
46
|
*/
|
43
47
|
export function get(key, defaultValue, option) {
|
44
|
-
|
48
|
+
const opts = (option || { delete: false });
|
45
49
|
const storage = getStorage(opts.storage);
|
46
50
|
let data = storage.getItem(key);
|
47
51
|
if (data == null) {
|