zmdms-utils 0.0.82 → 0.0.84

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/es/math.js CHANGED
@@ -107,6 +107,7 @@ function divide(num1, num2, precision) {
107
107
  * 四舍五入保留小数
108
108
  */
109
109
  function exactRound(num, ratio) {
110
+ var _a;
110
111
  try {
111
112
  var _num1 = num == null ? NaN : Number(num);
112
113
  if (isNaN(_num1)) {
@@ -116,12 +117,27 @@ function exactRound(num, ratio) {
116
117
  var value = new Decimal(num).toFixed(ratio);
117
118
  // 设置exactRound去掉小数位后面的0
118
119
  var exactRoundType = window.__EXACT_ROUND_TYPE__;
119
- var exactRoundTypePrecision = window
120
- .__EXACT_ROUND_TYPE_PRECISION__;
120
+ var exactRoundTypePrecision = (_a = window.__EXACT_ROUND_TYPE_PRECISION__) !== null && _a !== void 0 ? _a : 2;
121
121
  if (exactRoundType === "TRIM_ZEROS" &&
122
122
  (exactRoundTypePrecision || ratio) === ratio) {
123
123
  value = Number(value);
124
124
  }
125
+ else if (exactRoundType === "PRESERVE_TRAILING_ZEROS" &&
126
+ ratio > exactRoundTypePrecision) {
127
+ var str = String(Number(value));
128
+ // 如果包含小数点
129
+ if (str.includes(".")) {
130
+ // 根据exactRoundTypePrecision控制保留的位数
131
+ // 提取整数部分和小数部分
132
+ var _b = str.split("."), intPart = _b[0], decimalPart = _b[1];
133
+ // 确保小数部分至少有precision位,不足则补0
134
+ var paddedDecimal = decimalPart;
135
+ if (paddedDecimal.length > exactRoundTypePrecision) {
136
+ paddedDecimal = paddedDecimal.padEnd(exactRoundTypePrecision, "0");
137
+ }
138
+ value = "".concat(intPart, ".").concat(paddedDecimal);
139
+ }
140
+ }
125
141
  return value;
126
142
  // return Number(num).toFixed(ratio);
127
143
  }
@@ -43,5 +43,172 @@ var isChineseValidate = {
43
43
  regex: /[\u4e00-\u9fa5]/,
44
44
  message: "请输入中文!",
45
45
  };
46
+ var alphabet1 = [
47
+ "abcdefghijklmnopqrstuvwxyz",
48
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
49
+ "0123456789",
50
+ ];
51
+ var alphabet2 = ["qwertyuiop", "asdfghjkl", "zxcvbnm"];
52
+ var alphabet3 = ["qaz", "wsx", "edc", "rfv", "tgb", "yhn", "ujm"];
53
+ function isConsecutiveChars(char1, char2, alphabetArr) {
54
+ // const lowerCaseAlphabet = 'abcdefghijklmnopqrstuvwxyz'; // 小写字母
55
+ // const upperCaseAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; // 大写字母
56
+ // const numeric = '0123456789'; // 数字
57
+ // 找到包含两个字符的字符集
58
+ var alphabet = alphabetArr.find(function (alph) { return alph.includes(char1) && alph.includes(char2); });
59
+ if (!alphabet) {
60
+ return false; // 如果两个字符不在同一字符集中,那么它们不可能连续
61
+ }
62
+ var index1 = alphabet.indexOf(char1);
63
+ var index2 = alphabet.indexOf(char2);
64
+ // return Math.abs(index1 - index2) === 1; // 如果两个字符在字符集中的位置相邻,那么它们是连续的
65
+ return index1 - index2;
66
+ }
67
+ function validatePassword(password, username) {
68
+ // 用正则表达式检查密码基本规则
69
+ var regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,}$/;
70
+ if (!regex.test(password)) {
71
+ return {
72
+ result: false,
73
+ message: "密码中必须包含大小写字母、数字、特殊字符,且长度必须大于8个字符!",
74
+ };
75
+ }
76
+ // 检查密码是否与用户名相同
77
+ if (password === username) {
78
+ return {
79
+ result: false,
80
+ message: "密码与用户名相同!",
81
+ };
82
+ }
83
+ // 检查密码中是否有相同且连续的字符 超过三次
84
+ var count1 = 0;
85
+ for (var i = 0; i < password.length - 1; i++) {
86
+ if (password[i] === password[i + 1]) {
87
+ count1++;
88
+ if (count1 >= 2) {
89
+ return {
90
+ result: false,
91
+ message: "密码中有相同且连续超过三次的字符!",
92
+ };
93
+ }
94
+ }
95
+ else {
96
+ count1 = 0;
97
+ }
98
+ }
99
+ // 检查密码中是否有连续的字母或数字 连续超过三次
100
+ var count = 0;
101
+ var startChart = 0;
102
+ var currentConsecutiveCount = 0; // 记录上次是递增还是递减
103
+ // 第一次循环 找出 连续字母 数字
104
+ for (var i = 0; i < password.length - 1; i++) {
105
+ var consecutiveCount = isConsecutiveChars(password[i], password[i + 1], alphabet1);
106
+ // 是递增 还是 递减
107
+ if (consecutiveCount === 1 || consecutiveCount === -1) {
108
+ if (currentConsecutiveCount === 0) {
109
+ currentConsecutiveCount = consecutiveCount;
110
+ }
111
+ if (count === 0) {
112
+ startChart = i;
113
+ }
114
+ // 如果记录到上次跟本次的连续规则相同
115
+ if (currentConsecutiveCount === consecutiveCount) {
116
+ count++;
117
+ if (count >= 2) {
118
+ // 密码中不应含有连续的字母或数字
119
+ return {
120
+ result: false,
121
+ message: "\u4ECE\u7B2C".concat(startChart + 1, "\u4E2A\u5B57\u7B26\u5F00\u59CB\uFF0C\u6709\u8FDE\u7EED").concat(currentConsecutiveCount === 1 ? "递减" : "递增", "\u8D85\u8FC7\u4E09\u4F4D\u7684\u5B57\u6BCD\u6216\u6570\u5B57!"),
122
+ };
123
+ }
124
+ }
125
+ else {
126
+ // 需要重置规则
127
+ count = 0;
128
+ startChart = 0;
129
+ }
130
+ currentConsecutiveCount = consecutiveCount;
131
+ }
132
+ else {
133
+ count = 0;
134
+ startChart = 0;
135
+ currentConsecutiveCount = 0;
136
+ }
137
+ }
138
+ // 第二次循环 找出键盘连续横排字母
139
+ for (var i = 0; i < password.length - 1; i++) {
140
+ var consecutiveCount = isConsecutiveChars(password[i], password[i + 1], alphabet2);
141
+ // 是递增 还是 递减
142
+ if (consecutiveCount === 1 || consecutiveCount === -1) {
143
+ if (currentConsecutiveCount === 0) {
144
+ currentConsecutiveCount = consecutiveCount;
145
+ }
146
+ if (count === 0) {
147
+ startChart = i;
148
+ }
149
+ // 如果记录到上次跟本次的连续规则相同
150
+ if (currentConsecutiveCount === consecutiveCount) {
151
+ count++;
152
+ if (count >= 2) {
153
+ // 密码中不应含有连续的字母或数字
154
+ return {
155
+ result: false,
156
+ message: "\u4ECE\u7B2C".concat(startChart + 1, "\u4E2A\u5B57\u7B26\u5F00\u59CB\uFF0C\u6709\u6309\u952E\u76D8\u6A2A\u5411\u8FDE\u7EED").concat(currentConsecutiveCount === 1 ? "递减" : "递增", "\u8D85\u8FC7\u4E09\u4F4D\u7684\u5B57\u6BCD!"),
157
+ };
158
+ }
159
+ }
160
+ else {
161
+ // 需要重置规则
162
+ count = 0;
163
+ startChart = 0;
164
+ }
165
+ currentConsecutiveCount = consecutiveCount;
166
+ }
167
+ else {
168
+ count = 0;
169
+ startChart = 0;
170
+ currentConsecutiveCount = 0;
171
+ }
172
+ }
173
+ // 第三次循环 找出键盘连续竖排字母
174
+ for (var i = 0; i < password.length - 1; i++) {
175
+ var consecutiveCount = isConsecutiveChars(password[i], password[i + 1], alphabet3);
176
+ // 是递增 还是 递减
177
+ if (consecutiveCount === 1 || consecutiveCount === -1) {
178
+ if (currentConsecutiveCount === 0) {
179
+ currentConsecutiveCount = consecutiveCount;
180
+ }
181
+ if (count === 0) {
182
+ startChart = i;
183
+ }
184
+ // 如果记录到上次跟本次的连续规则相同
185
+ if (currentConsecutiveCount === consecutiveCount) {
186
+ count++;
187
+ if (count >= 2) {
188
+ // 密码中不应含有连续的字母或数字
189
+ return {
190
+ result: false,
191
+ message: "\u4ECE\u7B2C".concat(startChart + 1, "\u4E2A\u5B57\u7B26\u5F00\u59CB\uFF0C\u6709\u6309\u952E\u76D8\u7AD6\u5411\u8FDE\u7EED").concat(currentConsecutiveCount === 1 ? "递减" : "递增", "\u8D85\u8FC7\u4E09\u4F4D\u7684\u5B57\u6BCD\u6216\u6570\u5B57!"),
192
+ };
193
+ }
194
+ }
195
+ else {
196
+ // 需要重置规则
197
+ count = 0;
198
+ startChart = 0;
199
+ }
200
+ currentConsecutiveCount = consecutiveCount;
201
+ }
202
+ else {
203
+ count = 0;
204
+ startChart = 0;
205
+ currentConsecutiveCount = 0;
206
+ }
207
+ }
208
+ // 如果通过了所有的检查,则返回true
209
+ return {
210
+ result: true,
211
+ };
212
+ }
46
213
 
47
- export { emailValidate, idCardValidate, isChineseValidate, morePhoneValidate, phoneValidate, strLenValidate };
214
+ export { emailValidate, idCardValidate, isChineseValidate, morePhoneValidate, phoneValidate, strLenValidate, validatePassword };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zmdms-utils",
3
- "version": "0.0.82",
3
+ "version": "0.0.84",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
package/publish.py CHANGED
@@ -3,7 +3,7 @@ import os
3
3
  os.system('yarn')
4
4
  os.system('npm config set registry https://registry.npmjs.org')
5
5
  os.system('yarn config set registry https://registry.yarnpkg.com')
6
- os.system('npm config set proxy http://127.0.0.1:7890')
6
+ # os.system('npm config set proxy http://127.0.0.1:7890')
7
7
  os.system('yarn build')
8
8
  os.system('npm publish')
9
9
  os.system('npm config set registry https://registry.npmmirror.com')
@@ -1,18 +1,18 @@
1
- import i18next from "i18next";
2
- import { initReactI18next } from "react-i18next";
3
-
4
- type InitOptions = Parameters<typeof i18next.init>;
5
-
6
- /**
7
- * 初始化逻辑
8
- * - 本函数主要用于初始化 i18next 实例,同时使用 react-i18next 插件进行 react 组件的支持
9
- * - 本函数的调用时机,一般是在项目的入口文件中进行调用,如 src/main.tsx 中
10
- * @param options 参数 同i18next.init 第一个参数
11
- * @param callback 参数 同i18next.init 第二个参数
12
- * @returns
13
- */
14
- function initLocale(options: InitOptions[0], callback?: InitOptions[1]) {
15
- return i18next.use(initReactI18next).init(options, callback);
16
- }
17
-
18
- export { initLocale, i18next as i18n };
1
+ import i18next from "i18next";
2
+ import { initReactI18next } from "react-i18next";
3
+
4
+ type InitOptions = Parameters<typeof i18next.init>;
5
+
6
+ /**
7
+ * 初始化逻辑
8
+ * - 本函数主要用于初始化 i18next 实例,同时使用 react-i18next 插件进行 react 组件的支持
9
+ * - 本函数的调用时机,一般是在项目的入口文件中进行调用,如 src/main.tsx 中
10
+ * @param options 参数 同i18next.init 第一个参数
11
+ * @param callback 参数 同i18next.init 第二个参数
12
+ * @returns
13
+ */
14
+ function initLocale(options: InitOptions[0], callback?: InitOptions[1]) {
15
+ return i18next.use(initReactI18next).init(options, callback);
16
+ }
17
+
18
+ export { initLocale, i18next as i18n };
@@ -1,8 +1,8 @@
1
- // i18n实例 及 初始化方法
2
- export { i18n, initLocale } from "./i18n";
3
-
4
- // 代理的 useTranslation 函数
5
- export { useTranslation, Trans } from "./use-translation";
6
-
7
- // 导出 t 函数(应对在非 react 组件环境下进行使用的场景)
8
- export { safeT } from "./t-in-non-react";
1
+ // i18n实例 及 初始化方法
2
+ export { i18n, initLocale } from "./i18n";
3
+
4
+ // 代理的 useTranslation 函数
5
+ export { useTranslation, Trans } from "./use-translation";
6
+
7
+ // 导出 t 函数(应对在非 react 组件环境下进行使用的场景)
8
+ export { safeT } from "./t-in-non-react";
@@ -1,65 +1,65 @@
1
- /**
2
- * t 函数封装:
3
- * - 本文件的几个 t 函数,主要用于弥补一些在 React 组件之外使用的场景
4
- * - 常规情况下,在 react 组件中,更加推荐的是使用 react-i18next 包中的 t 函数,即 const { t } = useTranslate(); 形式
5
- */
6
- import { i18n } from "./i18n";
7
- import type { TOpionsEx } from "./t-options";
8
- import { getTFuncArgs } from "./t-options";
9
-
10
- /** 包裹一层 try-catch 的 t 函数 */
11
- const tryT = (
12
- key: string,
13
- defaultValueOrOptions: string | TOpionsEx
14
- ): string => {
15
- const { defaultValue, options } = getTFuncArgs(defaultValueOrOptions);
16
- if (!key) {
17
- // 情况1:键名为空,返回默认值或键名
18
- console.error(
19
- `tryT: 请不要传入空 key 值进行 i18n.t 函数执行,这将会导致直接返回空字符串!`
20
- );
21
- return defaultValue || key;
22
- }
23
- if (!i18n.exists(key)) {
24
- // 情况2:键名不存在,返回默认值或键名
25
- console.error(
26
- `tryT: i18n-key '${key}' 不存在,请检查对应的 @/locales/resources/locales/xx.json 中是否存在对应值`
27
- );
28
- return defaultValue || key;
29
- }
30
- try {
31
- // 情况3:尝试执行 i18n.t 函数
32
- return i18n.t(key, options);
33
- } catch (err) {
34
- // 情况4:执行 i18n.t 函数异常,返回默认值或键名
35
- console.error(`tryT: i18n.t key=${key} 函数执行异常:err=`, err);
36
- return defaultValue || key;
37
- }
38
- };
39
-
40
- /**
41
- * 同步版本的 i18n.t 函数(应对在 react 组件外使用的翻译函数)
42
- * - 如果 i18n 未初始化,则返回默认值或键名
43
- * - 如果 i18n 初始化后,键名不存在,则返回默认值或键名
44
- * - 其他正常情况(已经初始化+键名存在),则返回翻译值
45
- * @description 本函数为在非 react 组件中使用的翻译函数;(在react中请求使用 useTranslate() 返回的 t 函数)
46
- * @param {string} key
47
- * @param {TOpionsEx|string} defaultValue 必填值
48
- * @returns {string}
49
- * @example
50
- * const txt = t('someLocaleKey', '兜底默认值');
51
- */
52
- export function safeT(
53
- key: string,
54
- defaultValueOrOptions: string | TOpionsEx
55
- ): string {
56
- if (i18n.isInitialized) {
57
- return tryT(key, defaultValueOrOptions);
58
- }
59
- // 异常情况:没有初始化完成时,返回默认值
60
- const { defaultValue } = getTFuncArgs(defaultValueOrOptions);
61
- console.warn(
62
- `safeT: i18n is not initialized. Returning defaultValue(${defaultValue}) or origin key (${key}).`
63
- );
64
- return defaultValue || key;
65
- }
1
+ /**
2
+ * t 函数封装:
3
+ * - 本文件的几个 t 函数,主要用于弥补一些在 React 组件之外使用的场景
4
+ * - 常规情况下,在 react 组件中,更加推荐的是使用 react-i18next 包中的 t 函数,即 const { t } = useTranslate(); 形式
5
+ */
6
+ import { i18n } from "./i18n";
7
+ import type { TOpionsEx } from "./t-options";
8
+ import { getTFuncArgs } from "./t-options";
9
+
10
+ /** 包裹一层 try-catch 的 t 函数 */
11
+ const tryT = (
12
+ key: string,
13
+ defaultValueOrOptions: string | TOpionsEx
14
+ ): string => {
15
+ const { defaultValue, options } = getTFuncArgs(defaultValueOrOptions);
16
+ if (!key) {
17
+ // 情况1:键名为空,返回默认值或键名
18
+ console.error(
19
+ `tryT: 请不要传入空 key 值进行 i18n.t 函数执行,这将会导致直接返回空字符串!`
20
+ );
21
+ return defaultValue || key;
22
+ }
23
+ if (!i18n.exists(key)) {
24
+ // 情况2:键名不存在,返回默认值或键名
25
+ console.error(
26
+ `tryT: i18n-key '${key}' 不存在,请检查对应的 @/locales/resources/locales/xx.json 中是否存在对应值`
27
+ );
28
+ return defaultValue || key;
29
+ }
30
+ try {
31
+ // 情况3:尝试执行 i18n.t 函数
32
+ return i18n.t(key, options);
33
+ } catch (err) {
34
+ // 情况4:执行 i18n.t 函数异常,返回默认值或键名
35
+ console.error(`tryT: i18n.t key=${key} 函数执行异常:err=`, err);
36
+ return defaultValue || key;
37
+ }
38
+ };
39
+
40
+ /**
41
+ * 同步版本的 i18n.t 函数(应对在 react 组件外使用的翻译函数)
42
+ * - 如果 i18n 未初始化,则返回默认值或键名
43
+ * - 如果 i18n 初始化后,键名不存在,则返回默认值或键名
44
+ * - 其他正常情况(已经初始化+键名存在),则返回翻译值
45
+ * @description 本函数为在非 react 组件中使用的翻译函数;(在react中请求使用 useTranslate() 返回的 t 函数)
46
+ * @param {string} key
47
+ * @param {TOpionsEx|string} defaultValue 必填值
48
+ * @returns {string}
49
+ * @example
50
+ * const txt = t('someLocaleKey', '兜底默认值');
51
+ */
52
+ export function safeT(
53
+ key: string,
54
+ defaultValueOrOptions: string | TOpionsEx
55
+ ): string {
56
+ if (i18n.isInitialized) {
57
+ return tryT(key, defaultValueOrOptions);
58
+ }
59
+ // 异常情况:没有初始化完成时,返回默认值
60
+ const { defaultValue } = getTFuncArgs(defaultValueOrOptions);
61
+ console.warn(
62
+ `safeT: i18n is not initialized. Returning defaultValue(${defaultValue}) or origin key (${key}).`
63
+ );
64
+ return defaultValue || key;
65
+ }
@@ -1,24 +1,24 @@
1
- "use strict";
2
- import type { TOptions } from "i18next";
3
-
4
- export interface TOpionsEx extends TOptions {
5
- defaultValue: string; // 必须填值
6
- }
7
-
8
- /**
9
- * 获取 t 函数的参数
10
- * @param {string | TOpionsEx} defaultValueOrOptions 默认值或者选项
11
- * @returns { {defaultValue: string, options: TOpionsEx} } 默认值和选项
12
- */
13
- export function getTFuncArgs(defaultValueOrOptions: string | TOpionsEx) {
14
- let options: TOpionsEx | null = null;
15
- let defaultValue = "";
16
- if (typeof defaultValueOrOptions === "string") {
17
- defaultValue = defaultValueOrOptions;
18
- options = { defaultValue };
19
- } else {
20
- options = defaultValueOrOptions;
21
- defaultValue = options.defaultValue;
22
- }
23
- return { defaultValue, options };
24
- }
1
+ "use strict";
2
+ import type { TOptions } from "i18next";
3
+
4
+ export interface TOpionsEx extends TOptions {
5
+ defaultValue: string; // 必须填值
6
+ }
7
+
8
+ /**
9
+ * 获取 t 函数的参数
10
+ * @param {string | TOpionsEx} defaultValueOrOptions 默认值或者选项
11
+ * @returns { {defaultValue: string, options: TOpionsEx} } 默认值和选项
12
+ */
13
+ export function getTFuncArgs(defaultValueOrOptions: string | TOpionsEx) {
14
+ let options: TOpionsEx | null = null;
15
+ let defaultValue = "";
16
+ if (typeof defaultValueOrOptions === "string") {
17
+ defaultValue = defaultValueOrOptions;
18
+ options = { defaultValue };
19
+ } else {
20
+ options = defaultValueOrOptions;
21
+ defaultValue = options.defaultValue;
22
+ }
23
+ return { defaultValue, options };
24
+ }
@@ -1,76 +1,76 @@
1
- import { useTranslation, Trans } from "react-i18next";
2
- import type { TOpionsEx } from "./t-options";
3
- import { getTFuncArgs } from "./t-options";
4
-
5
- type Prams = Parameters<typeof useTranslation>;
6
- type NS = Prams[0];
7
- type Options = Prams[1];
8
-
9
- type EnhanceTFunc = (
10
- key: string,
11
- defaultValueOrOptions: string | TOpionsEx
12
- ) => string;
13
-
14
- /**
15
- * 这里只是简单代理一下useTranslation,方便后续扩展或添加其他逻辑
16
- * @param ns 命名空间 大多数情况下都不需要传入这个参数,除非你用到了命名空间。
17
- * @param options 其他参数 大多数情况下,都不需要关注这个参数。
18
- * options.keyPrefix 为所有翻译键添加前缀
19
- * // JSON 文件:{ "greeting": { "welcome": "Welcome" } }
20
- * const { t } = useTranslation('common', { keyPrefix: 'greeting' });
21
- * // 使用时省略前缀
22
- * t('welcome'); // 等价于 t('greeting:welcome')
23
- * @returns { t, i18n, ready }
24
- * t: 翻译方法
25
- * i18n: i18next实例 访问 i18next 的完整 API(如切换语言、加载命名空间)
26
- * i18n.changeLanguage('zh-CN'); 使用它切换语言,可以触发组件渲染。但是当前项目中是使用全局刷新的模式,来更新语言的。
27
- * ready: 是否加载完成
28
- */
29
- function useZtTranslation(ns?: NS, options?: Options) {
30
- const { t: _tOld, i18n, ready } = useTranslation(ns, options);
31
-
32
- // 扩展t方法,用于处理嵌套的翻译键
33
- const tEnhance: EnhanceTFunc = (key, defaultValueOrOptions) => {
34
- const { defaultValue, options } = getTFuncArgs(defaultValueOrOptions);
35
-
36
- if (!key) {
37
- // 情况1:键名为空,返回默认值或键名
38
- console.error(
39
- `tEnhance: 请不要传入空 key 值进行 t 函数执行,这将会导致直接返回空字符串!`
40
- );
41
- return defaultValue || key;
42
- }
43
- if (!i18n.exists(key)) {
44
- // 情况2:键名不存在,返回默认值或键名
45
- console.error(
46
- `tEnhance: i18n-key '${key}' 不存在,请检查对应的 @/locales/resources/locales/xx.json 中是否存在对应值`
47
- );
48
- return defaultValue || key;
49
- }
50
- try {
51
- return _tOld(key, options);
52
- } catch (error) {
53
- console.warn(`tEnhance: t 函数执行异常,请检查! key=${key}, err=`, error);
54
- return defaultValue || key || "unknown";
55
- }
56
- };
57
-
58
- return {
59
- /**
60
- * t函数的使用方式:基本上使用1、2两种方式就可以了。
61
- * 1、t('key') // 基础用法
62
- * 2、t('greeting', { name: 'John' }); // 对应 JSON: "greeting": "Hello {{name}}"
63
- * 3、t('auth:login'); // 显式指定命名空间
64
- *
65
- * 关于t函数的第二个参数的说明。
66
- * 为了防止一些异常情况,翻译失败。可以传入一个默认值。这个默认值就是原本的中文就行。
67
- * 1、t('key', '默认值');
68
- * 2、t('key', { defaultValue: '默认值', ...otherOptions });
69
- */
70
- t: tEnhance,
71
- i18n,
72
- ready,
73
- };
74
- }
75
-
76
- export { useZtTranslation as useTranslation, Trans };
1
+ import { useTranslation, Trans } from "react-i18next";
2
+ import type { TOpionsEx } from "./t-options";
3
+ import { getTFuncArgs } from "./t-options";
4
+
5
+ type Prams = Parameters<typeof useTranslation>;
6
+ type NS = Prams[0];
7
+ type Options = Prams[1];
8
+
9
+ type EnhanceTFunc = (
10
+ key: string,
11
+ defaultValueOrOptions: string | TOpionsEx
12
+ ) => string;
13
+
14
+ /**
15
+ * 这里只是简单代理一下useTranslation,方便后续扩展或添加其他逻辑
16
+ * @param ns 命名空间 大多数情况下都不需要传入这个参数,除非你用到了命名空间。
17
+ * @param options 其他参数 大多数情况下,都不需要关注这个参数。
18
+ * options.keyPrefix 为所有翻译键添加前缀
19
+ * // JSON 文件:{ "greeting": { "welcome": "Welcome" } }
20
+ * const { t } = useTranslation('common', { keyPrefix: 'greeting' });
21
+ * // 使用时省略前缀
22
+ * t('welcome'); // 等价于 t('greeting:welcome')
23
+ * @returns { t, i18n, ready }
24
+ * t: 翻译方法
25
+ * i18n: i18next实例 访问 i18next 的完整 API(如切换语言、加载命名空间)
26
+ * i18n.changeLanguage('zh-CN'); 使用它切换语言,可以触发组件渲染。但是当前项目中是使用全局刷新的模式,来更新语言的。
27
+ * ready: 是否加载完成
28
+ */
29
+ function useZtTranslation(ns?: NS, options?: Options) {
30
+ const { t: _tOld, i18n, ready } = useTranslation(ns, options);
31
+
32
+ // 扩展t方法,用于处理嵌套的翻译键
33
+ const tEnhance: EnhanceTFunc = (key, defaultValueOrOptions) => {
34
+ const { defaultValue, options } = getTFuncArgs(defaultValueOrOptions);
35
+
36
+ if (!key) {
37
+ // 情况1:键名为空,返回默认值或键名
38
+ console.error(
39
+ `tEnhance: 请不要传入空 key 值进行 t 函数执行,这将会导致直接返回空字符串!`
40
+ );
41
+ return defaultValue || key;
42
+ }
43
+ if (!i18n.exists(key)) {
44
+ // 情况2:键名不存在,返回默认值或键名
45
+ console.error(
46
+ `tEnhance: i18n-key '${key}' 不存在,请检查对应的 @/locales/resources/locales/xx.json 中是否存在对应值`
47
+ );
48
+ return defaultValue || key;
49
+ }
50
+ try {
51
+ return _tOld(key, options);
52
+ } catch (error) {
53
+ console.warn(`tEnhance: t 函数执行异常,请检查! key=${key}, err=`, error);
54
+ return defaultValue || key || "unknown";
55
+ }
56
+ };
57
+
58
+ return {
59
+ /**
60
+ * t函数的使用方式:基本上使用1、2两种方式就可以了。
61
+ * 1、t('key') // 基础用法
62
+ * 2、t('greeting', { name: 'John' }); // 对应 JSON: "greeting": "Hello {{name}}"
63
+ * 3、t('auth:login'); // 显式指定命名空间
64
+ *
65
+ * 关于t函数的第二个参数的说明。
66
+ * 为了防止一些异常情况,翻译失败。可以传入一个默认值。这个默认值就是原本的中文就行。
67
+ * 1、t('key', '默认值');
68
+ * 2、t('key', { defaultValue: '默认值', ...otherOptions });
69
+ */
70
+ t: tEnhance,
71
+ i18n,
72
+ ready,
73
+ };
74
+ }
75
+
76
+ export { useZtTranslation as useTranslation, Trans };
package/src/math.ts CHANGED
@@ -116,13 +116,30 @@ export function exactRound(num: numType, ratio: number) {
116
116
  let value: numType = new Decimal(num).toFixed(ratio);
117
117
  // 设置exactRound去掉小数位后面的0
118
118
  const exactRoundType = (window as any).__EXACT_ROUND_TYPE__;
119
- const exactRoundTypePrecision = (window as any)
120
- .__EXACT_ROUND_TYPE_PRECISION__;
119
+ const exactRoundTypePrecision =
120
+ (window as any).__EXACT_ROUND_TYPE_PRECISION__ ?? 2;
121
121
  if (
122
122
  exactRoundType === "TRIM_ZEROS" &&
123
123
  (exactRoundTypePrecision || ratio) === ratio
124
124
  ) {
125
125
  value = Number(value);
126
+ } else if (
127
+ exactRoundType === "PRESERVE_TRAILING_ZEROS" &&
128
+ ratio > exactRoundTypePrecision
129
+ ) {
130
+ const str = String(Number(value));
131
+ // 如果包含小数点
132
+ if (str.includes(".")) {
133
+ // 根据exactRoundTypePrecision控制保留的位数
134
+ // 提取整数部分和小数部分
135
+ const [intPart, decimalPart] = str.split(".");
136
+ // 确保小数部分至少有precision位,不足则补0
137
+ let paddedDecimal = decimalPart;
138
+ if (paddedDecimal.length > exactRoundTypePrecision) {
139
+ paddedDecimal = paddedDecimal.padEnd(exactRoundTypePrecision, "0");
140
+ }
141
+ value = `${intPart}.${paddedDecimal}`;
142
+ }
126
143
  }
127
144
  return value;
128
145
  // return Number(num).toFixed(ratio);
package/src/validate.ts CHANGED
@@ -48,3 +48,201 @@ export const isChineseValidate = {
48
48
  regex: /[\u4e00-\u9fa5]/,
49
49
  message: "请输入中文!",
50
50
  };
51
+
52
+ const alphabet1 = [
53
+ "abcdefghijklmnopqrstuvwxyz",
54
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
55
+ "0123456789",
56
+ ];
57
+
58
+ const alphabet2 = ["qwertyuiop", "asdfghjkl", "zxcvbnm"];
59
+ const alphabet3 = ["qaz", "wsx", "edc", "rfv", "tgb", "yhn", "ujm"];
60
+
61
+ function isConsecutiveChars(
62
+ char1: string,
63
+ char2: string,
64
+ alphabetArr: string[]
65
+ ) {
66
+ // const lowerCaseAlphabet = 'abcdefghijklmnopqrstuvwxyz'; // 小写字母
67
+ // const upperCaseAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; // 大写字母
68
+ // const numeric = '0123456789'; // 数字
69
+
70
+ // 找到包含两个字符的字符集
71
+ const alphabet = alphabetArr.find(
72
+ (alph) => alph.includes(char1) && alph.includes(char2)
73
+ );
74
+
75
+ if (!alphabet) {
76
+ return false; // 如果两个字符不在同一字符集中,那么它们不可能连续
77
+ }
78
+
79
+ const index1 = alphabet.indexOf(char1);
80
+ const index2 = alphabet.indexOf(char2);
81
+
82
+ // return Math.abs(index1 - index2) === 1; // 如果两个字符在字符集中的位置相邻,那么它们是连续的
83
+ return index1 - index2;
84
+ }
85
+
86
+ export function validatePassword(password: string, username: string) {
87
+ // 用正则表达式检查密码基本规则
88
+ const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,}$/;
89
+ if (!regex.test(password)) {
90
+ return {
91
+ result: false,
92
+ message:
93
+ "密码中必须包含大小写字母、数字、特殊字符,且长度必须大于8个字符!",
94
+ };
95
+ }
96
+
97
+ // 检查密码是否与用户名相同
98
+ if (password === username) {
99
+ return {
100
+ result: false,
101
+ message: "密码与用户名相同!",
102
+ };
103
+ }
104
+
105
+ // 检查密码中是否有相同且连续的字符 超过三次
106
+ let count1 = 0;
107
+ for (let i = 0; i < password.length - 1; i++) {
108
+ if (password[i] === password[i + 1]) {
109
+ count1++;
110
+ if (count1 >= 2) {
111
+ return {
112
+ result: false,
113
+ message: "密码中有相同且连续超过三次的字符!",
114
+ };
115
+ }
116
+ } else {
117
+ count1 = 0;
118
+ }
119
+ }
120
+
121
+ // 检查密码中是否有连续的字母或数字 连续超过三次
122
+ let count = 0;
123
+ let startChart = 0;
124
+ let currentConsecutiveCount = 0; // 记录上次是递增还是递减
125
+
126
+ // 第一次循环 找出 连续字母 数字
127
+ for (let i = 0; i < password.length - 1; i++) {
128
+ const consecutiveCount = isConsecutiveChars(
129
+ password[i],
130
+ password[i + 1],
131
+ alphabet1
132
+ );
133
+ // 是递增 还是 递减
134
+ if (consecutiveCount === 1 || consecutiveCount === -1) {
135
+ if (currentConsecutiveCount === 0) {
136
+ currentConsecutiveCount = consecutiveCount;
137
+ }
138
+ if (count === 0) {
139
+ startChart = i;
140
+ }
141
+ // 如果记录到上次跟本次的连续规则相同
142
+ if (currentConsecutiveCount === consecutiveCount) {
143
+ count++;
144
+ if (count >= 2) {
145
+ // 密码中不应含有连续的字母或数字
146
+ return {
147
+ result: false,
148
+ message: `从第${startChart + 1}个字符开始,有连续${
149
+ currentConsecutiveCount === 1 ? "递减" : "递增"
150
+ }超过三位的字母或数字!`,
151
+ };
152
+ }
153
+ } else {
154
+ // 需要重置规则
155
+ count = 0;
156
+ startChart = 0;
157
+ }
158
+ currentConsecutiveCount = consecutiveCount;
159
+ } else {
160
+ count = 0;
161
+ startChart = 0;
162
+ currentConsecutiveCount = 0;
163
+ }
164
+ }
165
+ // 第二次循环 找出键盘连续横排字母
166
+ for (let i = 0; i < password.length - 1; i++) {
167
+ const consecutiveCount = isConsecutiveChars(
168
+ password[i],
169
+ password[i + 1],
170
+ alphabet2
171
+ );
172
+ // 是递增 还是 递减
173
+ if (consecutiveCount === 1 || consecutiveCount === -1) {
174
+ if (currentConsecutiveCount === 0) {
175
+ currentConsecutiveCount = consecutiveCount;
176
+ }
177
+ if (count === 0) {
178
+ startChart = i;
179
+ }
180
+ // 如果记录到上次跟本次的连续规则相同
181
+ if (currentConsecutiveCount === consecutiveCount) {
182
+ count++;
183
+ if (count >= 2) {
184
+ // 密码中不应含有连续的字母或数字
185
+ return {
186
+ result: false,
187
+ message: `从第${startChart + 1}个字符开始,有按键盘横向连续${
188
+ currentConsecutiveCount === 1 ? "递减" : "递增"
189
+ }超过三位的字母!`,
190
+ };
191
+ }
192
+ } else {
193
+ // 需要重置规则
194
+ count = 0;
195
+ startChart = 0;
196
+ }
197
+ currentConsecutiveCount = consecutiveCount;
198
+ } else {
199
+ count = 0;
200
+ startChart = 0;
201
+ currentConsecutiveCount = 0;
202
+ }
203
+ }
204
+ // 第三次循环 找出键盘连续竖排字母
205
+ for (let i = 0; i < password.length - 1; i++) {
206
+ const consecutiveCount = isConsecutiveChars(
207
+ password[i],
208
+ password[i + 1],
209
+ alphabet3
210
+ );
211
+ // 是递增 还是 递减
212
+ if (consecutiveCount === 1 || consecutiveCount === -1) {
213
+ if (currentConsecutiveCount === 0) {
214
+ currentConsecutiveCount = consecutiveCount;
215
+ }
216
+ if (count === 0) {
217
+ startChart = i;
218
+ }
219
+ // 如果记录到上次跟本次的连续规则相同
220
+ if (currentConsecutiveCount === consecutiveCount) {
221
+ count++;
222
+ if (count >= 2) {
223
+ // 密码中不应含有连续的字母或数字
224
+ return {
225
+ result: false,
226
+ message: `从第${startChart + 1}个字符开始,有按键盘竖向连续${
227
+ currentConsecutiveCount === 1 ? "递减" : "递增"
228
+ }超过三位的字母或数字!`,
229
+ };
230
+ }
231
+ } else {
232
+ // 需要重置规则
233
+ count = 0;
234
+ startChart = 0;
235
+ }
236
+ currentConsecutiveCount = consecutiveCount;
237
+ } else {
238
+ count = 0;
239
+ startChart = 0;
240
+ currentConsecutiveCount = 0;
241
+ }
242
+ }
243
+
244
+ // 如果通过了所有的检查,则返回true
245
+ return {
246
+ result: true,
247
+ };
248
+ }