@csqcsq/utils 1.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.
@@ -0,0 +1,124 @@
1
+ import { getRequestKey } from "../createRequest";
2
+ import type { AxiosResponse } from "axios";
3
+ import type { PluginCallbackParams, RequestKey } from "../createRequest";
4
+
5
+ interface CacheStore {
6
+ set: (key: string, value: any, keyPreFix?: string) => any;
7
+ get: (key: string, keyPreFix?: string) => any;
8
+ }
9
+
10
+ type CacheStoreType = "localStorage" | "sessionStorage" | CacheStore;
11
+
12
+ export interface ExtendRequestConfig {
13
+ cache?: boolean;
14
+ cacheStore?: CacheStoreType;
15
+ cacheKey?: RequestKey;
16
+ }
17
+ interface PluginConfig {
18
+ storageKeyFix?: string;
19
+ transformCache?: (response: AxiosResponse) => { cache: boolean; data?: any };
20
+ }
21
+
22
+ const cacheSet: { [key: string]: any } = {};
23
+ const cachePromiseSet: { [key: string]: Promise<any> } = {};
24
+
25
+ declare global {
26
+ interface RequestConfigExt extends ExtendRequestConfig {}
27
+ }
28
+
29
+ const createrStorager = (
30
+ target: typeof localStorage | typeof sessionStorage,
31
+ ) => ({
32
+ set(key: string, value: any) {
33
+ target.setItem(key, JSON.stringify(value));
34
+ },
35
+ get(key: string) {
36
+ const value = target.getItem(key);
37
+
38
+ if (value) {
39
+ return JSON.parse(value);
40
+ }
41
+ },
42
+ remove(key: string) {
43
+ target.removeItem(key);
44
+ },
45
+ });
46
+
47
+ const createCacheStore = (cacheStore?: CacheStoreType): CacheStore => {
48
+ if (cacheStore === "localStorage") {
49
+ return createrStorager(localStorage);
50
+ }
51
+
52
+ if (cacheStore === "sessionStorage") {
53
+ return createrStorager(sessionStorage);
54
+ }
55
+
56
+ if (typeof cacheStore === "object") {
57
+ return cacheStore as CacheStore;
58
+ }
59
+
60
+ return {
61
+ set: (key, value) => (cacheSet[key] = value),
62
+ get: (key) => cacheSet[key],
63
+ };
64
+ };
65
+
66
+ // 缓存,可以指定缓存仓库,最大缓存接口数。TODO:添加数据过期时间
67
+ export default function cachePlugin(pluginConfig?: PluginConfig) {
68
+ const {
69
+ storageKeyFix = "",
70
+ transformCache = (response: AxiosResponse) => ({
71
+ cache: true,
72
+ data: response,
73
+ }),
74
+ } = pluginConfig || {};
75
+
76
+ return ({
77
+ config,
78
+ beforeRequest,
79
+ afterRequest,
80
+ onResponse,
81
+ }: PluginCallbackParams) => {
82
+ const { cache, cacheKey, cacheStore } = config;
83
+
84
+ if (cache) {
85
+ const requestKey = getRequestKey(config, cacheKey);
86
+
87
+ const _cacheStore = createCacheStore(cacheStore);
88
+
89
+ beforeRequest((next) => {
90
+ const cachePromise = cachePromiseSet[requestKey];
91
+
92
+ const cacheData = _cacheStore.get(requestKey, storageKeyFix);
93
+
94
+ if (cachePromise) {
95
+ // 中断请求,复用上一个请求的promise
96
+ next(cachePromise.then(transformCache));
97
+ } else if (cacheData) {
98
+ // 中断请求,返回缓存数据
99
+ next(cacheData);
100
+ }
101
+ });
102
+
103
+ afterRequest((promise) => {
104
+ cachePromiseSet[requestKey] = promise;
105
+
106
+ promise.finally(() => {
107
+ // 完成请求,清空内存
108
+ delete cachePromiseSet[requestKey];
109
+ });
110
+ });
111
+
112
+ onResponse((response) => {
113
+ // 判断后端返回的结果是否正确 -> 将响应缓存起来
114
+ const { cache, data } = transformCache(response);
115
+
116
+ if (cache) {
117
+ _cacheStore.set(requestKey, data, storageKeyFix);
118
+ }
119
+
120
+ return response;
121
+ });
122
+ }
123
+ };
124
+ }
@@ -0,0 +1,109 @@
1
+ import { getRequestKey } from "../createRequest";
2
+ import type { PluginCallbackParams } from "../createRequest";
3
+
4
+ interface PluginConfig {
5
+ onIntercept?: (msg: string) => any;
6
+ }
7
+
8
+ export interface ExtendRequestConfig {
9
+ uuid?: string;
10
+ racekey?: string;
11
+ raceCancelMsg?: string;
12
+ }
13
+
14
+ interface RequestItem {
15
+ uuid: string;
16
+ controller: AbortController;
17
+ racekey?: string;
18
+ }
19
+
20
+ declare global {
21
+ interface RequestConfigExt extends ExtendRequestConfig {}
22
+ }
23
+
24
+ const requestList: RequestItem[] = [];
25
+
26
+ const getRequestIndex = (key: string, racekey?: string) => {
27
+ return requestList?.findIndex((item) => {
28
+ return racekey
29
+ ? item.uuid === key && item.racekey === racekey
30
+ : item.uuid === key;
31
+ });
32
+ };
33
+
34
+ // 取消所有请求
35
+ export const cancelAllRequest = () => {
36
+ requestList.map((request) => request.controller.abort());
37
+ };
38
+
39
+ // 取消指定请求
40
+ export const cancelRequest = (target: string | string[]) => {
41
+ if (typeof target === "string") {
42
+ // 取消当个请求
43
+ const sourceIndex = getRequestIndex(target);
44
+
45
+ sourceIndex >= 0 && requestList[sourceIndex]?.controller.abort();
46
+ } else {
47
+ target.forEach((uuid) => {
48
+ const sourceIndex = getRequestIndex(uuid);
49
+
50
+ sourceIndex >= 0 && requestList[sourceIndex]?.controller.abort();
51
+ });
52
+ }
53
+ };
54
+
55
+ // 取消接口请求插件
56
+ export default function cancelPlugin(pluginConfig?: PluginConfig) {
57
+ const { onIntercept } = pluginConfig || {};
58
+
59
+ return ({ config, beforeRequest, afterRequest }: PluginCallbackParams) => {
60
+ const { signal, racekey, raceCancelMsg, uuid } = config;
61
+
62
+ if (signal) {
63
+ console.warn(
64
+ `当前请求接口${config.url} --- 竞态取消/全局统一取消功能失效`,
65
+ );
66
+
67
+ return;
68
+ }
69
+
70
+ const requestkey = uuid || getRequestKey(config);
71
+
72
+ const controller = new AbortController();
73
+
74
+ const requestItem: RequestItem = { uuid: requestkey, racekey, controller };
75
+
76
+ beforeRequest(() => {
77
+ // 增加取消的配置
78
+ return { ...config, signal: controller.signal };
79
+ });
80
+
81
+ afterRequest((promise) => {
82
+ // 需要竞态取消
83
+ if (racekey) {
84
+ const sourceIndex = getRequestIndex(requestkey, racekey);
85
+
86
+ // 如果前面有未取消的请求,则执行取消
87
+ if (sourceIndex >= 0) {
88
+ const msg = raceCancelMsg || "竞态取消";
89
+
90
+ onIntercept && onIntercept(msg);
91
+
92
+ requestList[sourceIndex]?.controller.abort();
93
+ }
94
+ }
95
+
96
+ // 将当前请求存入,让下一次请求能执行取消当前请求
97
+ requestList.push(requestItem);
98
+
99
+ // 当前请求响应后,清除对应的requestItem
100
+ promise.finally(() => {
101
+ const sourceIndex = requestList.findIndex(
102
+ (item) => item === requestItem,
103
+ );
104
+
105
+ sourceIndex >= 0 && requestList.splice(sourceIndex, 1);
106
+ });
107
+ });
108
+ };
109
+ }
@@ -0,0 +1,44 @@
1
+ import type { PluginCallbackParams } from "../createRequest";
2
+
3
+ export interface ExtendRequestConfig {
4
+ concurrencyKey?: string;
5
+ concurrencyMsg?: string;
6
+ }
7
+
8
+ declare global {
9
+ interface RequestConfigExt extends ExtendRequestConfig {}
10
+ }
11
+
12
+ interface PluginConfig {
13
+ handleTips?: (msg: string) => any;
14
+ }
15
+
16
+ const pendingMap: { [key: string]: boolean } = {};
17
+
18
+ // 并发限制(请求1未响应,请求2无法发出)
19
+ export default function concurrencyPlugin(pluginConfig?: PluginConfig) {
20
+ const { handleTips } = pluginConfig || {};
21
+
22
+ return ({ config, beforeRequest, afterRequest }: PluginCallbackParams) => {
23
+ const { concurrencyKey, concurrencyMsg } = config;
24
+
25
+ if (concurrencyKey) {
26
+ beforeRequest((next) => {
27
+ // 如果前面接口还处于pending状态,则不要发出请求
28
+ if (pendingMap[concurrencyKey]) {
29
+ const msg = concurrencyMsg || "操作频繁";
30
+
31
+ handleTips && handleTips(msg);
32
+
33
+ next(Promise.reject({ message: msg }));
34
+ }
35
+ });
36
+
37
+ afterRequest((promise) => {
38
+ pendingMap[concurrencyKey] = true;
39
+
40
+ promise.finally(() => delete pendingMap[concurrencyKey]);
41
+ });
42
+ }
43
+ };
44
+ }
@@ -0,0 +1,59 @@
1
+ import createRequest from "../createRequest";
2
+ import type { RequestConfig, Request } from "../createRequest";
3
+
4
+ export type Method = "get" | "post" | "put" | "delete" | "patch";
5
+
6
+ export interface MethodRequest {
7
+ <P extends object = any, T = any>(
8
+ url: string,
9
+ baseParams?: P,
10
+ baseConfig?: RequestConfig,
11
+ ): (params?: P, config?: RequestConfig) => Promise<T>;
12
+ }
13
+
14
+ // 请求方法集合
15
+ export interface AxiosMethods {
16
+ get: MethodRequest;
17
+ post: MethodRequest;
18
+ put: MethodRequest;
19
+ delete: MethodRequest;
20
+ patch: MethodRequest;
21
+ }
22
+
23
+ export function createMethodRequst(request: Request, method: Method) {
24
+ return <P = AnalyserNode, T = any>(
25
+ url: string,
26
+ baseParams?: P,
27
+ baseConfig?: RequestConfig,
28
+ ) => {
29
+ return (params?: P, config?: RequestConfig): Promise<T> => {
30
+ const paramKey = ["post", "put", "patch"].includes(method)
31
+ ? "data"
32
+ : "params";
33
+
34
+ return request({
35
+ ...config,
36
+ ...baseConfig,
37
+ url,
38
+ method,
39
+ [paramKey]: baseParams ? { ...baseParams, ...params } : params,
40
+ });
41
+ };
42
+ };
43
+ }
44
+
45
+ const createAxios = (config: RequestConfig) => {
46
+ const { request, axiosInstance } = createRequest(config);
47
+
48
+ const axios: AxiosMethods = {
49
+ get: createMethodRequst(request, "get"),
50
+ post: createMethodRequst(request, "post"),
51
+ put: createMethodRequst(request, "put"),
52
+ delete: createMethodRequst(request, "delete"),
53
+ patch: createMethodRequst(request, "patch"),
54
+ };
55
+
56
+ return { axios, request, axiosInstance };
57
+ };
58
+
59
+ export default createAxios;
@@ -0,0 +1,179 @@
1
+ import axios from "axios";
2
+
3
+ import type { AxiosRequestConfig } from "axios";
4
+
5
+ declare global {
6
+ interface RequestConfigExt {}
7
+ }
8
+
9
+ // 请求配置扩展
10
+ export type RequestConfig = AxiosRequestConfig & RequestConfigExt;
11
+
12
+ // 插件类型
13
+ export interface Plugin {
14
+ ({
15
+ beforeRequest,
16
+ afterRequest,
17
+ onResponse,
18
+ config,
19
+ }: PluginCallbackParams): void;
20
+ }
21
+
22
+ export interface Request {
23
+ <T>(config: RequestConfig): Promise<T>;
24
+ use: (plugin: Plugin) => void;
25
+ }
26
+
27
+ // 请求拦截器
28
+ interface RequestInterceptor {
29
+ (
30
+ next: (value?: any) => void,
31
+ ): RequestConfig | void | Promise<void | RequestConfig>;
32
+ }
33
+
34
+ // 请求监听器
35
+ interface RequestListener {
36
+ (promise: Promise<any>): void;
37
+ }
38
+
39
+ // 响应正常处理
40
+ interface ResponseResolver {
41
+ (res: any): any;
42
+ }
43
+
44
+ // 响应错误处理
45
+ interface ResponseRejecter {
46
+ (err: any): any;
47
+ }
48
+
49
+ // 请求监听参数
50
+ export interface PluginCallbackParams {
51
+ beforeRequest: (requestInterceptor: RequestInterceptor) => void;
52
+ afterRequest: (requestListener: RequestListener) => void;
53
+ onResponse: (resolve: ResponseResolver, reject?: ResponseRejecter) => void;
54
+ config: RequestConfig;
55
+ }
56
+
57
+ // 请求key
58
+ export type RequestKey =
59
+ | "url"
60
+ | "urlParams"
61
+ | ((config: RequestConfig) => string);
62
+
63
+ /**
64
+ * 获取请求key,可以配置params、header是否参与计算,也可以自定义生成id的方法将该方法覆盖
65
+ * @param config 请求配置
66
+ * @param key 请求key
67
+ * @returns 数据
68
+ */
69
+ export const getRequestKey = (
70
+ config: RequestConfig,
71
+ key: RequestKey = "url",
72
+ ) => {
73
+ const { url, params, data } = config;
74
+
75
+ if (typeof key === "function") {
76
+ return key(config);
77
+ }
78
+
79
+ const createObj: any = { url };
80
+
81
+ if (key === "urlParams") createObj.params = Object.assign({}, params, data);
82
+
83
+ return JSON.stringify(createObj);
84
+ };
85
+
86
+ // 创建请求
87
+ export default function createRequest(axiosConfig: RequestConfig) {
88
+ const axiosInstance = axios.create(axiosConfig);
89
+
90
+ const plugins: Plugin[] = [];
91
+
92
+ // 请求方法
93
+ const request: Request = <T>(config: RequestConfig): Promise<T> => {
94
+ // 请求拦截器(这个阶段可以种植请求,可以自定义返回请求等)
95
+ const requestInterceptors: RequestInterceptor[] = [];
96
+
97
+ const beforeRequest = (requestInterceptor: RequestInterceptor) =>
98
+ requestInterceptors.push(requestInterceptor);
99
+
100
+ // 请求监听(这个阶段可以获取请求的promise/abort等)
101
+ const requestListeners: RequestListener[] = [];
102
+
103
+ const afterRequest = (requestListener: RequestListener) =>
104
+ requestListeners.push(requestListener);
105
+
106
+ // 响应拦截(这个阶段可以对最终返回结果进行操作,同axios响应拦截器)
107
+ const responseInterceptors: [
108
+ RequireResolve,
109
+ ResponseRejecter | undefined,
110
+ ][] = [];
111
+
112
+ const onResponse = (resolve: RequireResolve, reject?: ResponseRejecter) =>
113
+ responseInterceptors.push([resolve, reject]);
114
+
115
+ // 添加插件
116
+ plugins.forEach((callback) =>
117
+ callback({ beforeRequest, afterRequest, onResponse, config }),
118
+ );
119
+
120
+ return new Promise<T>(async (resolve) => {
121
+ // 处理请求之前
122
+ const handleBeforeRequest = async () => {
123
+ let needRequest = true;
124
+ let isBail = false;
125
+
126
+ for (
127
+ let i = 0, len = requestInterceptors?.length;
128
+ i < len && !isBail;
129
+ i++
130
+ ) {
131
+ const interceptor: RequestInterceptor | undefined =
132
+ requestInterceptors[i];
133
+
134
+ if (interceptor) {
135
+ const _config = await interceptor((value?: any) => {
136
+ if (value !== undefined) {
137
+ isBail = true;
138
+ needRequest = false;
139
+ return resolve(value);
140
+ }
141
+ });
142
+
143
+ Object.assign(config, _config);
144
+ }
145
+ }
146
+
147
+ return needRequest;
148
+ };
149
+
150
+ // 请求被拦截,阻止发送请求
151
+ if (!(await handleBeforeRequest())) return;
152
+
153
+ // 防止缓存
154
+ if (config.method === "get" || config.method === "delete") {
155
+ if (config.params) {
156
+ config.params._t = new Date().getTime();
157
+ } else {
158
+ config.params = { _t: new Date().getTime() };
159
+ }
160
+ }
161
+
162
+ let promise: Promise<any> = axiosInstance(config);
163
+
164
+ // 通过反复复制 promise,实现响应拦截的值处理
165
+ responseInterceptors.forEach((handlers) => {
166
+ promise = promise.then(handlers[0], handlers[1]);
167
+ });
168
+
169
+ // 遍历请求监听器
170
+ requestListeners.forEach((listener) => listener(promise));
171
+
172
+ return resolve(promise);
173
+ });
174
+ };
175
+
176
+ request.use = (plugin: Plugin) => plugins.push(plugin);
177
+
178
+ return { request, axiosInstance };
179
+ }
@@ -0,0 +1,20 @@
1
+ import type { PluginCallbackParams } from "../createRequest";
2
+
3
+ export interface ExtendRequestConfig {
4
+ flat?: boolean;
5
+ }
6
+
7
+ declare global {
8
+ interface RequestConfigExt extends ExtendRequestConfig {}
9
+ }
10
+
11
+ // 拉平响应,去除data外面那一层
12
+ export default function flatResponsePlugin() {
13
+ return ({ config, onResponse }: PluginCallbackParams) => {
14
+ const { flat } = config;
15
+
16
+ if (flat !== false) {
17
+ onResponse((response) => response?.data || response);
18
+ }
19
+ };
20
+ }
@@ -0,0 +1,26 @@
1
+ import type { PluginCallbackParams } from "../createRequest";
2
+
3
+ export interface ExtendRequestConfig {
4
+ loading?: boolean;
5
+ }
6
+
7
+ declare global {
8
+ interface RequestConfigExt extends ExtendRequestConfig {}
9
+ }
10
+
11
+ export type LoadingFunc = () => { close: Function };
12
+
13
+ // 加载中的插件
14
+ export default function loadingPlugin(loadingFunc: LoadingFunc) {
15
+ return ({ config, afterRequest }: PluginCallbackParams) => {
16
+ const { loading } = config;
17
+
18
+ if (loading) {
19
+ afterRequest((promise: Promise<any>) => {
20
+ const loadingInstance = loadingFunc();
21
+
22
+ promise.catch(() => {}).finally(() => loadingInstance.close());
23
+ });
24
+ }
25
+ };
26
+ }
@@ -0,0 +1,45 @@
1
+ import type { PluginCallbackParams } from "../createRequest";
2
+
3
+ export interface ExtendRequestConfig {
4
+ successTip?: boolean;
5
+ errorTip?: boolean;
6
+ defaultMsg?: boolean;
7
+ defaultErrMsg?: string;
8
+ }
9
+
10
+ declare global {
11
+ interface RequestConfigExt extends ExtendRequestConfig {}
12
+ }
13
+
14
+ export interface MessagePluginParams {
15
+ successTipFun?: (msg: string) => void;
16
+ errorTipFun?: (msg: string) => void;
17
+ successCodeList?: number[];
18
+ }
19
+
20
+ /**
21
+ * 统一提示插件
22
+ * @param param0 { successTipFun = console.log, errorTipFun = console.error, successCodeList = [200] }
23
+ */
24
+ export default function messagePlugin({
25
+ successTipFun = console.log,
26
+ errorTipFun = console.error,
27
+ successCodeList = [200],
28
+ }: MessagePluginParams = {}) {
29
+ return ({ onResponse, config }: PluginCallbackParams) => {
30
+ const { errorTip, successTip, defaultMsg, defaultErrMsg } = config;
31
+
32
+ onResponse((response) => {
33
+ const { code, msg, message } = response || {};
34
+
35
+ // 默认成功不提示,除非用户自己配置提示
36
+ if (successTip || successCodeList.includes(code)) {
37
+ successTipFun(msg || message || defaultErrMsg || "请求成功");
38
+ } else if (errorTip !== false && !successCodeList.includes(code)) {
39
+ errorTipFun(msg || message || defaultMsg || "未知错误");
40
+ }
41
+
42
+ return response;
43
+ });
44
+ };
45
+ }
package/index.ts ADDED
@@ -0,0 +1,63 @@
1
+ import { formatDate, dateDiff } from './modules/dateUtil'
2
+
3
+ import {
4
+ isEmptyString,
5
+ birsdayToAge,
6
+ getType,
7
+ isNumber,
8
+ isArray,
9
+ isArrayEmpty,
10
+ deepClone,
11
+ filterEmptyData,
12
+ round,
13
+ commafy,
14
+ numberPad,
15
+ numberRandom,
16
+ hideMobile,
17
+ strTrim,
18
+ checkPwd,
19
+ randomNumber
20
+ } from './modules/utils'
21
+
22
+ import { isPhone, isIdCard, isVehicleNumber } from './modules/validateUtils'
23
+
24
+ import cachePlugin from './aioxs/cachePlugin'
25
+ import cancelPlugin from './aioxs/cancelPlugin'
26
+ import concurrencyPlugin from './aioxs/concurrencyPlugin'
27
+ import createAxios from './aioxs/createAxios'
28
+ import createRequest from './aioxs/createRequest'
29
+ import flatResponsePlugin from './aioxs/flatResponsePlugin'
30
+ import loadingPlugin from './aioxs/loadingPlugin'
31
+ import messagePlugin from './aioxs/messagePlugin'
32
+
33
+ export {
34
+ cachePlugin,
35
+ cancelPlugin,
36
+ concurrencyPlugin,
37
+ createAxios,
38
+ createRequest,
39
+ flatResponsePlugin,
40
+ loadingPlugin,
41
+ messagePlugin,
42
+ formatDate,
43
+ dateDiff,
44
+ isEmptyString,
45
+ birsdayToAge,
46
+ getType,
47
+ isNumber,
48
+ isArray,
49
+ isArrayEmpty,
50
+ deepClone,
51
+ filterEmptyData,
52
+ round,
53
+ commafy,
54
+ numberPad,
55
+ numberRandom,
56
+ hideMobile,
57
+ strTrim,
58
+ checkPwd,
59
+ randomNumber,
60
+ isPhone,
61
+ isIdCard,
62
+ isVehicleNumber
63
+ }
@@ -0,0 +1,25 @@
1
+ import dayjs from "dayjs";
2
+
3
+ /**
4
+ * 格式化日期
5
+ * @param date 时间
6
+ * @param formatString 时间格式
7
+ */
8
+ export function formatDate(date: Date, formatString: string): string {
9
+ return dayjs(date).format(formatString);
10
+ }
11
+
12
+ //
13
+ /**
14
+ * 用于计算两个日期之间的差值
15
+ * @param start 开始时间
16
+ * @param end 结束时间
17
+ * @param unit dayjs.OpUnitType
18
+ */
19
+ export function dateDiff(
20
+ start: Date,
21
+ end: Date,
22
+ unit: dayjs.OpUnitType,
23
+ ): number {
24
+ return dayjs(end).diff(dayjs(start), unit);
25
+ }
@@ -0,0 +1,242 @@
1
+ interface InterfaceObj {
2
+ [key: string]: any;
3
+ }
4
+
5
+ /**
6
+ * 验证字符串是否为空(也不能为纯空格)
7
+ * @param str 字符串
8
+ * @returns {boolean} true--说明为空, false--说明不为空
9
+ */
10
+ export function isEmptyString(str: string) {
11
+ return (
12
+ str == undefined ||
13
+ typeof str == "undefined" ||
14
+ !str ||
15
+ str == "" ||
16
+ /^\s+$/gi.test(str)
17
+ );
18
+ }
19
+
20
+ /**
21
+ * 生日转为年龄(精确到月份)
22
+ * @param birsday 生日
23
+ * @returns {string}
24
+ */
25
+ export function birsdayToAge(birsday: string) {
26
+ const aDate = new Date();
27
+
28
+ const thisYear = aDate.getFullYear();
29
+
30
+ const bDate = new Date(birsday);
31
+
32
+ const brith = bDate.getFullYear();
33
+
34
+ let age = thisYear - brith;
35
+
36
+ if (aDate.getMonth() == bDate.getMonth()) {
37
+ if (aDate.getDate() < bDate.getDate()) {
38
+ age = age - 1;
39
+ }
40
+ } else {
41
+ if (aDate.getMonth() < bDate.getMonth()) {
42
+ age = age - 1;
43
+ }
44
+ }
45
+
46
+ return age;
47
+ }
48
+
49
+ /**
50
+ * 判断数据类型
51
+ * @param {any} val - 基本类型数据或者引用类型数据
52
+ * @return {string} - 可能返回的结果有,均为小写字符串
53
+ * number、boolean、string、null、undefined、array、object、function等
54
+ */
55
+ export function getType(val: any) {
56
+ //判断数据是 null 和 undefined 的情况
57
+ if (val == null) return val + "";
58
+
59
+ //判断数据是 数组类型
60
+ return typeof val === "object"
61
+ ? Object.prototype.toString.call(val).slice(8, -1).toLowerCase()
62
+ : typeof val;
63
+ }
64
+
65
+ /**
66
+ * 验证是否为数字
67
+ * @param n
68
+ */
69
+ export function isNumber(n: any) {
70
+ return !isNaN(parseFloat(n)) && isFinite(n);
71
+ }
72
+
73
+ /**
74
+ * 是否为数组
75
+ * @param obj
76
+ */
77
+ export function isArray(obj: any) {
78
+ return Object.prototype.toString.call(obj) === "[object Array]";
79
+ }
80
+
81
+ /**
82
+ * 是否空数组
83
+ * @param val
84
+ */
85
+ export function isArrayEmpty(val: any) {
86
+ return !(val && val instanceof Array && val.length > 0);
87
+ }
88
+
89
+ /**
90
+ * 递归深拷贝
91
+ * @param obj
92
+ */
93
+ export function deepClone(obj: any) {
94
+ if (obj === null) return null;
95
+
96
+ if (typeof obj !== "object") return obj;
97
+
98
+ if (obj.constructor === Date) return new Date(obj);
99
+
100
+ if (obj.constructor === RegExp) return new RegExp(obj);
101
+
102
+ let newObj: any = new obj.constructor();
103
+
104
+ for (let key in obj) {
105
+ if (obj.hasOwnProperty(key)) {
106
+ newObj[key] = deepClone(obj[key]);
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * 去除参数空数据(用于向后台传递参数的时候)
113
+ * @param obj Object[参数对象]
114
+ */
115
+ export function filterEmptyData(obj: InterfaceObj) {
116
+ for (let prop in obj) {
117
+ obj[prop] === "" ? delete obj[prop] : obj[prop];
118
+ }
119
+ return obj;
120
+ }
121
+
122
+ /**
123
+ * 数字四舍五入(保留n位小数)
124
+ * @param num 要处理的数字
125
+ * @param n 保留小数位数
126
+ * @returns 处理后的数字
127
+ */
128
+ export function round(num: number, n: number = 0) {
129
+ if (n <= 0) {
130
+ return Math.round(num);
131
+ } else {
132
+ return Math.round(num * Math.pow(10, n)) / Math.pow(10, n);
133
+ }
134
+ }
135
+
136
+ /**
137
+ * 数字每千位加逗号
138
+ * @param num 数字
139
+ */
140
+ export function commafy(num: number) {
141
+ return (
142
+ num &&
143
+ num.toString().replace(/\d+/, function (s) {
144
+ return s.replace(/(\d)(?=(\d{3})+$)/g, "$1,");
145
+ })
146
+ );
147
+ }
148
+
149
+ /**
150
+ * 数字补位,numberPad用于按照位数补0,默认为2
151
+ * @param source 数字
152
+ * @param length 补位位数
153
+ * @returns {string} 补位后的数字
154
+ */
155
+ export function numberPad(source: number, length: number = 2) {
156
+ let pre = "";
157
+
158
+ const negative = source < 0;
159
+
160
+ const string = String(Math.abs(source));
161
+
162
+ if (string.length < length) {
163
+ pre = new Array(length - string.length + 1).join("0");
164
+ }
165
+
166
+ return (negative ? "-" : "") + pre + string;
167
+ }
168
+
169
+ /**
170
+ * 随机数
171
+ * @param min 最小值
172
+ * @param max 最大值
173
+ */
174
+ export function numberRandom(min: number, max: number) {
175
+ return Math.floor(Math.random() * (max - min + 1) + min);
176
+ }
177
+
178
+ /**
179
+ * 手机号码中间4位隐藏花号(*)显示
180
+ * @param mobile 手机号
181
+ */
182
+ export function hideMobile(mobile: string) {
183
+ return mobile.replace(/^(\d{3})\d{4}(\d{4})$/, "$1****$2");
184
+ }
185
+
186
+ /**
187
+ * 去除字符串空格
188
+ * @param str 要处理的字符串
189
+ * @param type 1:所有空格 2:前后空格 3:前空格 4:后空格
190
+ */
191
+ export function strTrim(str: string, type: number) {
192
+ switch (type) {
193
+ case 1:
194
+ return str.replace(/\s+/g, "");
195
+ case 2:
196
+ return str.replace(/(^\s*)|(\s*$)/g, "");
197
+ case 3:
198
+ return str.replace(/(^\s*)/g, "");
199
+ case 4:
200
+ return str.replace(/(\s*$)/g, "");
201
+ default:
202
+ return str;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * 检测密码强度
208
+ * @param str 字符串
209
+ * @returns 1:密码弱 2:密码中等 3:密码强 4:密码很强
210
+ */
211
+ export function checkPwd(str: string) {
212
+ var nowLv = 0;
213
+ if (str.length < 6) {
214
+ return nowLv;
215
+ }
216
+ if (/[0-9]/.test(str)) {
217
+ nowLv++;
218
+ }
219
+ if (/[a-z]/.test(str)) {
220
+ nowLv++;
221
+ }
222
+ if (/[A-Z]/.test(str)) {
223
+ nowLv++;
224
+ }
225
+ return nowLv;
226
+ }
227
+
228
+ /**
229
+ * 返回指定某个区间的一个数字(可以不传参,不传就返回0-255之间的数;可以只传一个,返回0到传入的这个数字之间的某个值)
230
+ * @param n1 开始区间 例:5
231
+ * @param n2 结束区间 例:10
232
+ * @returns 返回这个区间的某个随机值
233
+ */
234
+ export function randomNumber(n1: number, n2: number) {
235
+ if (arguments.length === 2) {
236
+ return Math.round(n1 + Math.random() * (n2 - n1));
237
+ } else if (arguments.length === 1) {
238
+ return Math.round(Math.random() * n1);
239
+ } else {
240
+ return Math.round(Math.random() * 255);
241
+ }
242
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * 验证手机号是否合格
3
+ * @param phoneStr 手机号
4
+ * @returns {boolean} true--说明合格
5
+ */
6
+ export function isPhone(phoneStr: string) {
7
+ return !phoneStr;
8
+ }
9
+
10
+ /**
11
+ * 验证身份证号是否合格
12
+ * @param idCard 身份证号
13
+ * @returns {boolean} true--说明合格
14
+ */
15
+ export function isIdCard(idCard: string) {
16
+ return !idCard;
17
+ }
18
+
19
+ /**
20
+ * 验证车牌号是否合格
21
+ * @param vehicleNumber 车牌号
22
+ * @returns {boolean} true--说明合格
23
+ */
24
+ export function isVehicleNumber(vehicleNumber: string) {
25
+ let xreg: RegExp =
26
+ /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/;
27
+ let creg: RegExp =
28
+ /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/;
29
+ if (vehicleNumber.length == 7) {
30
+ return creg.test(vehicleNumber);
31
+ } else if (vehicleNumber.length == 8) {
32
+ return xreg.test(vehicleNumber);
33
+ } else {
34
+ return false;
35
+ }
36
+ }
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@csqcsq/utils",
3
+ "version": "1.0.13",
4
+ "private": false,
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://gitee.com/csq-cn/pnpm-monorepo"
8
+ },
9
+ "author": "csq",
10
+ "keywords": [
11
+ "utils",
12
+ "axios",
13
+ "format",
14
+ "money",
15
+ "phone"
16
+ ],
17
+ "description": "",
18
+ "main": "index.js",
19
+ "scripts": {
20
+ "build": "tsc"
21
+ },
22
+ "license": "ISC",
23
+ "dependencies": {
24
+ "axios": "^1.5.1",
25
+ "dayjs": "^1.11.10",
26
+ "typescript": "^5.0.2"
27
+ }
28
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "compilerOptions": {
3
+ "declaration": true,
4
+ "target": "esnext",
5
+ "useDefineForClassFields": true,
6
+ "module": "commonjs",
7
+ "moduleResolution": "node",
8
+ "jsx": "preserve",
9
+ "baseUrl": "./",
10
+ "sourceMap": true,
11
+ // 目标语言的版本
12
+ // 生成代码的模板标准
13
+ "lib": ["DOM", "ES5", "ES6", "ES7", "ScriptHost"],
14
+ // TS需要引用的库
15
+ "outDir": "./dist",
16
+ // 指定输出目录
17
+ "rootDir": "./",
18
+ // 指定输出文件目录(用于输出),用于控制输出目录结构
19
+ "allowJs": true,
20
+ // 允许编译器编译JS,JSX文件
21
+ "checkJs": true,
22
+ // 允许在JS文件中报错,通常与allowJS一起使用
23
+ "removeComments": true,
24
+ // 删除注释
25
+ "esModuleInterop": true,
26
+ // 允许export=导出,由import from 导入
27
+
28
+ /* 严格检查选项 */
29
+ "strict": true,
30
+ // 开启所有严格的类型检查
31
+ "alwaysStrict": true,
32
+ // 在代码中注入'use strict'
33
+ "noImplicitAny": true,
34
+ // 不允许隐式的any类型
35
+ "noImplicitThis": true,
36
+ // 不允许this有隐式的any类型
37
+ "strictNullChecks": true,
38
+ // 不允许把null、undefined赋值给其他类型的变量
39
+ "strictBindCallApply": true,
40
+ // 严格的bind/call/apply检查
41
+ "strictFunctionTypes": true,
42
+ // 不允许函数参数双向协变
43
+ "strictPropertyInitialization": true,
44
+ // 类的实例属性必须初始化
45
+
46
+ /* 额外检查 */
47
+ "noUnusedLocals": false,
48
+ //是否检查未使用的局部变量
49
+ "noUnusedParameters": false,
50
+ //是否检查未使用的参数
51
+ "noImplicitReturns": true,
52
+ //检查函数是否不含有隐式返回值
53
+ "noImplicitOverride": true,
54
+ //是否检查子类继承自基类时,其重载的函数命名与基类的函数不同步问题
55
+ "noFallthroughCasesInSwitch": true,
56
+ //检查switch中是否含有case没有使用break跳出
57
+ "noUncheckedIndexedAccess": true,
58
+ //是否通过索引签名来描述对象上有未知键但已知值的对象
59
+ "noPropertyAccessFromIndexSignature": true,
60
+ //是否通过" . “(obj.key) 语法访问字段和"索引”( obj[“key”]), 以及在类型中声明属性的方式之间的一致性
61
+
62
+ /* 实验选项 */
63
+ "experimentalDecorators": true,
64
+ //是否启用对装饰器的实验性支持,装饰器是一种语言特性,还没有完全被 JavaScript 规范批准
65
+ "emitDecoratorMetadata": true,
66
+ //为装饰器启用对发出类型元数据的实验性支持
67
+
68
+ /* 高级选项 */
69
+ "forceConsistentCasingInFileNames": true,
70
+ //是否区分文件系统大小写规则
71
+ "extendedDiagnostics": false,
72
+ //是否查看 TS 在编译时花费的时间
73
+ "noEmitOnError": true,
74
+ //有错误时不进行编译
75
+ "resolveJsonModule": true,
76
+ //是否解析 JSON 模块
77
+ "types": ["node"]
78
+ },
79
+ "exclude": ["node_modules", "dist"],
80
+ "include": ["./**/*.ts"]
81
+ }
@@ -0,0 +1,29 @@
1
+ ### 登录
2
+
3
+ ```
4
+ npm login
5
+ ```
6
+
7
+ ### 发布包
8
+
9
+ ```
10
+ npm publish --access public
11
+ ```
12
+
13
+ ### 删除已发布的包
14
+
15
+ ```
16
+ npm unpublish <package-name>@<version>
17
+ ```
18
+
19
+ ### 撤销发布
20
+
21
+ ```
22
+ npm unpublish <package-name>@<version> --force
23
+ ```
24
+
25
+ ### 修改版本号
26
+
27
+ ```
28
+ npm version <newversion>
29
+ ```