jinbi-utils 1.0.20 → 1.0.21

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.
Files changed (83) hide show
  1. package/.babelrc +19 -0
  2. package/.cz-config.js +55 -0
  3. package/.dockerignore +3 -0
  4. package/.editorconfig +12 -0
  5. package/.eslintignore +8 -0
  6. package/.eslintrc.js +54 -0
  7. package/.versionrc.json +9 -0
  8. package/CHANGELOG.md +49 -49
  9. package/CHUNK_OPTIMIZER_USAGE.md +132 -0
  10. package/Dockerfile +3 -0
  11. package/QUICK_RELEASE.md +85 -0
  12. package/README.md +189 -189
  13. package/RELEASE_GUIDE.md +243 -0
  14. package/api-extractor.json +15 -0
  15. package/commitlint.config.js +3 -0
  16. package/jest.config.js +15 -0
  17. package/package.json +82 -109
  18. package/rollup.config.chunk-optimizer.js +32 -0
  19. package/rollup.config.js +73 -0
  20. package/src/array/index.ts +85 -0
  21. package/src/build/chunk-optimizer/ARCHITECTURE.md +347 -0
  22. package/src/build/chunk-optimizer/QUICK_START.md +370 -0
  23. package/src/build/chunk-optimizer/README.md +240 -0
  24. package/src/build/chunk-optimizer/core/chunk-generator.ts +166 -0
  25. package/src/build/chunk-optimizer/core/classifier.ts +148 -0
  26. package/src/build/chunk-optimizer/core/dependency-reader.ts +138 -0
  27. package/src/build/chunk-optimizer/examples/basic-usage.ts +234 -0
  28. package/src/build/chunk-optimizer/index.ts +166 -0
  29. package/src/build/chunk-optimizer/rules/common-rules.ts +131 -0
  30. package/src/build/chunk-optimizer/rules/framework-rules.ts +93 -0
  31. package/src/build/chunk-optimizer/rules/index.ts +27 -0
  32. package/src/build/chunk-optimizer/test.ts +94 -0
  33. package/src/build/chunk-optimizer/types.ts +128 -0
  34. package/src/color/index.ts +58 -0
  35. package/src/common/index.ts +353 -0
  36. package/src/constant/common.constant.ts +13 -0
  37. package/src/date/index.ts +143 -0
  38. package/src/dom/index.ts +198 -0
  39. package/src/file/index.ts +319 -0
  40. package/src/http/apiBuilder/README.md +648 -0
  41. package/src/http/apiBuilder/api-builder.ts +502 -0
  42. package/src/http/apiBuilder/example.ts +243 -0
  43. package/src/http/apiBuilder/index.ts +1 -0
  44. package/src/http/apiBuilder//345/277/253/351/200/237/345/217/202/350/200/203.md +199 -0
  45. package/src/http/http.ts +79 -0
  46. package/src/http/httpEnums.ts +61 -0
  47. package/src/iam/index.ts +46 -0
  48. package/src/index.ts +20 -0
  49. package/src/middleware/requestLogger.middware.ts +371 -0
  50. package/src/middleware/requestLoggerUnified.ts +371 -0
  51. package/src/number/index.ts +362 -0
  52. package/src/object/index.ts +54 -0
  53. package/src/print/index.ts +102 -0
  54. package/src/string/index.ts +189 -0
  55. package/src/utils/curl.ts +108 -0
  56. package/src/validate/index.ts +100 -0
  57. package/src/websocket/emitter.ts +39 -0
  58. package/src/websocket/index.ts +6 -0
  59. package/src/websocket/manager.ts +151 -0
  60. package/src/websocket/pinia-store.ts +91 -0
  61. package/src/websocket/service.ts +34 -0
  62. package/src/websocket/types.ts +45 -0
  63. package/test/common/index.test.ts +19 -0
  64. package/test/date/index.test.ts +107 -0
  65. package/test/file/index.test.ts +104 -0
  66. package/test/number/index.test.ts +108 -0
  67. package/test/object/index.test.ts +20 -0
  68. package/test/string/index.test.ts +82 -0
  69. package/tsconfig.json +39 -0
  70. package/typedoc.json +12 -0
  71. package/types/file/index.d.ts +7 -0
  72. package/types/index.d.ts +1 -0
  73. package/types/websocket/emitter.d.ts +16 -0
  74. package/types/websocket/index.d.ts +6 -0
  75. package/types/websocket/manager.d.ts +36 -0
  76. package/types/websocket/pinia-store.d.ts +25 -0
  77. package/types/websocket/service.d.ts +13 -0
  78. package/types/websocket/types.d.ts +34 -0
  79. package/dist/chunk-optimizer.cjs +0 -703
  80. package/dist/index.esm.js +0 -2791
  81. package/dist/index.esm.min.js +0 -15
  82. package/dist/index.umd.js +0 -2899
  83. package/dist/index.umd.min.js +0 -16
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Chunk Optimizer 测试脚本
3
+ * 运行: npx tsx build/chunk-optimizer/test.ts
4
+ */
5
+
6
+ import { createChunkOptimizer } from './index';
7
+
8
+ console.log('\n' + '='.repeat(70));
9
+ console.log('🧪 Testing Chunk Optimizer');
10
+ console.log('='.repeat(70) + '\n');
11
+
12
+ // 创建优化器实例
13
+ const optimizer = createChunkOptimizer({
14
+ framework: 'vue',
15
+ debug: true,
16
+ customRules: {
17
+ // 测试自定义规则
18
+ 'test-lib': 'vendor-test',
19
+ },
20
+ exclude: ['@types/*'],
21
+ });
22
+
23
+ // 打印分析报告
24
+ optimizer.printReport();
25
+
26
+ // 获取分析结果
27
+ const result = optimizer.analyze();
28
+
29
+ console.log('\n' + '='.repeat(70));
30
+ console.log('📊 Detailed Analysis');
31
+ console.log('='.repeat(70) + '\n');
32
+
33
+ console.log(`Framework: ${result.detectedFramework}`);
34
+ console.log(`Total Dependencies: ${result.dependencies.length}`);
35
+ console.log(`Production Dependencies: ${result.dependencies.filter(d => !d.isDev).length}`);
36
+ console.log(`Dev Dependencies: ${result.dependencies.filter(d => d.isDev).length}`);
37
+
38
+ console.log('\n📦 Top 10 Dependencies by Category:\n');
39
+
40
+ // 按分类分组
41
+ const grouped = result.dependencies.reduce((acc, dep) => {
42
+ if (dep.category) {
43
+ if (!acc[dep.category]) {
44
+ acc[dep.category] = [];
45
+ }
46
+ acc[dep.category].push(dep.name);
47
+ }
48
+ return acc;
49
+ }, {} as Record<string, string[]>);
50
+
51
+ // 打印每个分类的前几个包
52
+ Object.entries(grouped)
53
+ .sort(([, a], [, b]) => b.length - a.length)
54
+ .slice(0, 10)
55
+ .forEach(([category, packages]) => {
56
+ console.log(`${category}:`);
57
+ packages.slice(0, 5).forEach(pkg => {
58
+ console.log(` - ${pkg}`);
59
+ });
60
+ if (packages.length > 5) {
61
+ console.log(` ... and ${packages.length - 5} more`);
62
+ }
63
+ console.log('');
64
+ });
65
+
66
+ // 生成 manualChunks 函数
67
+ const manualChunks = optimizer.generate();
68
+
69
+ console.log('='.repeat(70));
70
+ console.log('✅ Test completed successfully!');
71
+ console.log('='.repeat(70) + '\n');
72
+
73
+ // 测试 manualChunks 函数
74
+ console.log('🧪 Testing manualChunks function:\n');
75
+
76
+ const testCases = [
77
+ 'node_modules/vue/dist/vue.js',
78
+ 'node_modules/element-plus/es/index.js',
79
+ 'node_modules/axios/index.js',
80
+ 'node_modules/@iconify/vue/dist/index.js',
81
+ '/src/views/system/user/index.vue',
82
+ '/src/views/dashboard/index.vue',
83
+ '/src/components/Button/index.vue',
84
+ '/src/utils/request.ts',
85
+ '/src/store/user.ts',
86
+ ];
87
+
88
+ testCases.forEach(testCase => {
89
+ const result = manualChunks(testCase, { getModuleInfo: () => null });
90
+ console.log(`${testCase.padEnd(50)} -> ${result || '(default)'}`);
91
+ });
92
+
93
+ console.log('\n' + '='.repeat(70) + '\n');
94
+
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Chunk Optimizer 类型定义
3
+ */
4
+
5
+ /**
6
+ * 框架类型
7
+ */
8
+ export type Framework = 'vue' | 'react' | 'angular' | 'svelte' | 'auto';
9
+
10
+ /**
11
+ * 分包策略
12
+ */
13
+ export type Strategy = 'balanced' | 'aggressive' | 'conservative';
14
+
15
+ /**
16
+ * 依赖分类
17
+ */
18
+ export type DependencyCategory =
19
+ | 'vendor-vue'
20
+ | 'vendor-react'
21
+ | 'vendor-router'
22
+ | 'vendor-state'
23
+ | 'vendor-element'
24
+ | 'vendor-ui'
25
+ | 'vendor-utils'
26
+ | 'vendor-icons'
27
+ | 'vendor-i18n'
28
+ | 'vendor-vueuse'
29
+ | 'vendor-pro'
30
+ | 'vendor-libs'
31
+ | string;
32
+
33
+ /**
34
+ * 规则定义
35
+ */
36
+ export interface Rule {
37
+ /** 包名或模式 */
38
+ match: string | RegExp;
39
+ /** 分类 */
40
+ category: DependencyCategory;
41
+ /** 优先级(数字越大优先级越高) */
42
+ priority?: number;
43
+ /** 描述 */
44
+ description?: string;
45
+ }
46
+
47
+ /**
48
+ * 业务代码分包策略
49
+ */
50
+ export interface SourceCodeStrategy {
51
+ /** 是否按 views 模块分包 */
52
+ views?: boolean;
53
+ /** 是否将公共组件单独分包 */
54
+ components?: boolean;
55
+ /** 是否将工具函数分包 */
56
+ utils?: boolean;
57
+ /** 是否将 store 分包 */
58
+ store?: boolean;
59
+ /** 自定义业务代码分包规则 */
60
+ custom?: Array<{
61
+ pattern: RegExp;
62
+ chunkName: string;
63
+ }>;
64
+ }
65
+
66
+ /**
67
+ * 优化器配置选项
68
+ */
69
+ export interface ChunkOptimizerOptions {
70
+ /** 框架类型,默认 'auto' 自动检测 */
71
+ framework?: Framework;
72
+
73
+ /** 分包策略,默认 'balanced' */
74
+ strategy?: Strategy;
75
+
76
+ /** 自定义规则(会覆盖默认规则) */
77
+ customRules?: Record<string, DependencyCategory>;
78
+
79
+ /** 排除某些包不参与分包 */
80
+ exclude?: string[];
81
+
82
+ /** 最小 chunk 大小(KB),小于此大小的包会合并,默认 0 */
83
+ minChunkSize?: number;
84
+
85
+ /** 是否启用调试模式,会输出详细的分包信息 */
86
+ debug?: boolean;
87
+
88
+ /** 业务代码分包策略 */
89
+ sourceCodeStrategy?: SourceCodeStrategy;
90
+
91
+ /** package.json 路径,默认为项目根目录 */
92
+ packageJsonPath?: string;
93
+ }
94
+
95
+ /**
96
+ * 依赖信息
97
+ */
98
+ export interface DependencyInfo {
99
+ /** 包名 */
100
+ name: string;
101
+ /** 版本 */
102
+ version: string;
103
+ /** 是否为开发依赖 */
104
+ isDev: boolean;
105
+ /** 分类 */
106
+ category?: DependencyCategory;
107
+ }
108
+
109
+ /**
110
+ * 分析结果
111
+ */
112
+ export interface AnalysisResult {
113
+ /** 所有依赖 */
114
+ dependencies: DependencyInfo[];
115
+ /** 检测到的框架 */
116
+ detectedFramework?: Framework;
117
+ /** 分类统计 */
118
+ categoryStats: Record<DependencyCategory, number>;
119
+ }
120
+
121
+ /**
122
+ * ManualChunks 函数类型
123
+ */
124
+ export type ManualChunksFunction = (
125
+ id: string,
126
+ { getModuleInfo }: { getModuleInfo: (id: string) => any }
127
+ ) => string | undefined;
128
+
@@ -0,0 +1,58 @@
1
+ /**
2
+ * 颜色处理相关
3
+ * @packageDocumentation
4
+ * @module Color
5
+ * @preferred
6
+ */
7
+
8
+ /**
9
+ * 将 Hex 颜色转换为 RGB 数组
10
+ * @param hex - Hex 格式颜色值(如 #ffffff)
11
+ * @returns RGB 数组 [r, g, b]
12
+ */
13
+ export function hexToRgb(hex: string): number[] {
14
+ const result = hex.replace('#', '').match(/../g);
15
+ return result ? result.map(val => parseInt(val, 16)) : [0, 0, 0];
16
+ }
17
+
18
+ /**
19
+ * 将 RGB 值转换为 Hex 颜色
20
+ * @param r - 红色值 (0-255)
21
+ * @param g - 绿色值 (0-255)
22
+ * @param b - 蓝色值 (0-255)
23
+ * @returns Hex 格式颜色值(如 #ffffff)
24
+ */
25
+ export function rgbToHex(r: number, g: number, b: number): string {
26
+ const toHex = (n: number) => {
27
+ const hex = n.toString(16);
28
+ return hex.length === 1 ? '0' + hex : hex;
29
+ };
30
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
31
+ }
32
+
33
+ /**
34
+ * 颜色加深
35
+ * 使用 RGB 线性计算:color * (1 - level)
36
+ * @param color - Hex 格式颜色值
37
+ * @param level - 加深程度 (0-1)
38
+ * @returns 加深后的 Hex 颜色值
39
+ */
40
+ export function darken(color: string, level: number): string {
41
+ const rgb = hexToRgb(color);
42
+ const darkened = rgb.map(val => Math.floor(val * (1 - level)));
43
+ return rgbToHex(darkened[0], darkened[1], darkened[2]);
44
+ }
45
+
46
+ /**
47
+ * 颜色变浅
48
+ * 使用 RGB 线性计算:(255 - color) * level + color
49
+ * @param color - Hex 格式颜色值
50
+ * @param level - 变浅程度 (0-1)
51
+ * @returns 变浅后的 Hex 颜色值
52
+ */
53
+ export function lighten(color: string, level: number): string {
54
+ const rgb = hexToRgb(color);
55
+ const lightened = rgb.map(val => Math.floor((255 - val) * level + val));
56
+ return rgbToHex(lightened[0], lightened[1], lightened[2]);
57
+ }
58
+
@@ -0,0 +1,353 @@
1
+ /**
2
+ * 通用函数
3
+ * @packageDocumentation
4
+ * @module Common
5
+ * @preferred
6
+ */
7
+
8
+ import {fromTypeMap, IFromType} from "@/constant/common.constant";
9
+
10
+ /**
11
+ * 延迟函数(Promise 版本)
12
+ * @param ms - 延迟毫秒数
13
+ * @returns Promise
14
+ */
15
+ export function delay(ms: number): Promise<void> {
16
+ return new Promise(resolve => setTimeout(resolve, ms));
17
+ }
18
+
19
+ /**
20
+ * 检测设备是否为移动设备
21
+ * @returns 是否为移动设备
22
+ */
23
+ export function deviceDetection(): boolean {
24
+ if (typeof window === 'undefined') return false;
25
+
26
+ const userAgent = navigator.userAgent.toLowerCase();
27
+ const isMidp = /midp/i.test(userAgent);
28
+ const isUcweb = /ucweb/i.test(userAgent);
29
+ const isAndroid = /android/i.test(userAgent);
30
+ const isIos = /iphone os/i.test(userAgent);
31
+ const isWinCe = /windows ce/i.test(userAgent);
32
+ const isWinMobile = /windows mobile/i.test(userAgent);
33
+ const isRv = /rv:1.2.3.4/i.test(userAgent);
34
+
35
+ return (
36
+ isMidp || isUcweb || isAndroid || isIos || isWinCe || isWinMobile || isRv
37
+ );
38
+ }
39
+
40
+ /**
41
+ * 判断val 是否是空值
42
+ #### 使用说明
43
+ ```
44
+ isEmpty('') 返回 true
45
+ isEmpty(null) 返回 true
46
+ isEmpty(undefined) 返回 true
47
+ isEmpty(12323) 返回 false
48
+ ```
49
+ */
50
+ export function isEmpty(val: any): boolean {
51
+ return val === null || val === '' || val === undefined;
52
+ }
53
+
54
+ // from jinbizhihui
55
+
56
+
57
+ // 获取环境变量
58
+ // export const getEnvValue = (type: string) => {
59
+ // return import.meta.env[type]
60
+ // }
61
+
62
+
63
+
64
+ export const clearLoginData = () => {
65
+ // 这里做指定的 key 清除 是为了 避免 清除掉 jsapiticket 等一些需要有的字段 防止多次请求
66
+ localStorage.removeItem('wecom_userinfo')
67
+ localStorage.removeItem('wecom_token')
68
+ localStorage.removeItem('projectActive')
69
+ localStorage.removeItem('loginTime')
70
+ localStorage.removeItem('projectInfo')
71
+ }
72
+
73
+ // 获取url中参数
74
+ export const getQueryString = (url: string, queryKey: string) => {
75
+ const reg = new RegExp(`&{1}${queryKey}\\=[a-zA-Z0-9_-]+`, 'g')
76
+ const matchResult = url.replace(/\?/g, '&').match(reg)![0]
77
+ return matchResult.substr(matchResult.indexOf('=') + 1)
78
+ }
79
+
80
+ export const getQueryVariable = (variable) => {
81
+ var query = window.location.search.substring(1)
82
+ var vars = query.split('&')
83
+ for (var i = 0; i < vars.length; i++) {
84
+ var pair = vars[i].split('=')
85
+ if (pair[0] === variable) { return pair[1] }
86
+ }
87
+ return (false)
88
+ }
89
+
90
+ export const getWecomToken = () => {
91
+ return localStorage.getItem('wecom_token')
92
+ }
93
+ // 判断设备类型
94
+ export const getDeviceType = (): IFromType => {
95
+ const ua = navigator.userAgent.toLowerCase();
96
+ const isWxWork = /wxwork/.test(ua); // 企业微信
97
+ const isWeixin = /micromessenger/.test(ua) && !isWxWork; // 微信,排除企业微信
98
+
99
+ // 使用屏幕宽度判断是否移动设备
100
+ const isMobileScreen = window.innerWidth <= 768;
101
+
102
+ return {
103
+ isWxWork,
104
+ isWeixin,
105
+ isMobileScreen,
106
+ isMobileAny: isWxWork || isWeixin || isMobileScreen,
107
+ };
108
+ };
109
+
110
+ export const getFromType = (res: IFromType) => {
111
+ let result = 'wecom'
112
+ for( let key in res) {
113
+ const value = res[key]
114
+ if (value) {
115
+ result = fromTypeMap[key]
116
+ break;
117
+ }
118
+ }
119
+ return result;
120
+ }
121
+ export function randomString(e) {
122
+ e = e || 32
123
+ let t = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
124
+ let a = t.length
125
+ let n = ''
126
+ for (let i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a))
127
+ return n
128
+ }
129
+ export const getCookie = (cookieName) => {
130
+ let cookie = ''
131
+ let cookieArr = document.cookie.split('; ')
132
+ for (let i = 0; i < cookieArr.length; i++) {
133
+ var valueArr = cookieArr[i].split('=')
134
+ if (valueArr[0] === cookieName) {
135
+ cookie = valueArr[1]
136
+ break
137
+ }
138
+ }
139
+ return cookie
140
+ }
141
+ // || 'cc51882c781d8035b98335ccb44787b42dd9d91ba3b85a45ff3e867857a526bfbbddcdc27b8edce9a52882d1838e0b8e6ccf658ed105df9a898b1c977c588bd1'
142
+ export const buildUUID = () => {
143
+ const hexList: string[] = []
144
+ for (let i = 0; i <= 15; i++) {
145
+ hexList[i] = i.toString(16) as string
146
+ }
147
+ let uuid = ''
148
+ for (let i = 1; i <= 36; i++) {
149
+ if (i === 9 || i === 14 || i === 19 || i === 24) {
150
+ uuid += '-'
151
+ } else if (i === 15) {
152
+ uuid += 4
153
+ } else if (i === 20) {
154
+ uuid += hexList[(Math.random() * 4) | 8];
155
+ } else {
156
+ uuid += hexList[(Math.random() * 16) | 0];
157
+ }
158
+ }
159
+ return uuid.replace(/-/g, '')
160
+ }
161
+
162
+ export const getTicket = () => {
163
+ return localStorage.getItem('jsapiTicket')
164
+ }
165
+ export const setTicket = (jsapiTicket) => {
166
+ return localStorage.setItem('jsapiTicket', jsapiTicket)
167
+ }
168
+ export const removeTicket = () => {
169
+ return localStorage.removeItem('jsapiTicket')
170
+ }
171
+
172
+
173
+ export const formateTimestamp = (timestamp: number | null, type = 'YYYY年MM月DD日 hh:mm:ss') => {
174
+ if (!timestamp) {
175
+ return '-'
176
+ }
177
+ const date = new Date(timestamp)
178
+ const year = date.getFullYear() + ''
179
+ const month = date.getMonth() + 1
180
+ const day = date.getDate()
181
+ const houre = date.getHours() > 9 ? date.getHours() : '0' + date.getHours()
182
+ const minute = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes()
183
+ const second = date.getSeconds() > 9 ? date.getSeconds() : '0' + date.getSeconds()
184
+ const result = type.replace('YYYY', year + '').replace('MM', month + '').replace('DD', day + '').replace('hh', houre + '').replace('mm', minute + '').replace('ss', second + '')
185
+ return result
186
+
187
+ }
188
+
189
+
190
+ export const convertBase64UrlToBlob = (urlData) => {
191
+ // console.log('urlData', urlData)
192
+ // 将以base64的图片url数据转换为Blob
193
+ var bytes = window.atob(urlData.split(',')[1]) // 去掉url的头,并转换为byte
194
+ // 处理异常,将ascii码小于0的转换为大于0
195
+ var ab = new ArrayBuffer(bytes.length)
196
+ var ia = new Uint8Array(ab)
197
+ for (var i = 0; i < bytes.length; i++) {
198
+ ia[i] = bytes.charCodeAt(i)
199
+ }
200
+ return new Blob([ab], { type: 'image/png' })
201
+ }
202
+
203
+
204
+ export const getEnvironment = () => {
205
+ const isMobile = window.navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i); // 是否手机端
206
+ const isWx = /micromessenger/i.test(navigator.userAgent); // 是否微信
207
+ const isComWx = /wxwork/i.test(navigator.userAgent); // 是否企业微信
208
+
209
+ if (isComWx && isMobile) { //手机端企业微信
210
+ return 'com-wx-mobile'
211
+ }
212
+ else if (isComWx && !isMobile) { //PC端企业微信
213
+ return 'com-wx-pc'
214
+ }
215
+ else if (isWx && isMobile) { // 手机端微信
216
+ return 'wx-mobile';
217
+ }
218
+ else if (isWx && !isMobile) { // PC端微信
219
+ return 'wx-pc';
220
+ }
221
+ else {
222
+ return 'other';
223
+ }
224
+ }
225
+
226
+ export const getIsComWx = () => {
227
+ const isComWx = /wxwork/i.test(navigator.userAgent); // 是否企业微信
228
+ return isComWx
229
+ }
230
+ export const getIsDevelopment = () => {
231
+ let result = false
232
+ if (location.origin === 'uat2-h5-wecom.hengdayun.com' || location.origin === '127.0.0.1:8081' || location.origin === 'localhost:8081') {
233
+ result = true
234
+ }
235
+
236
+ return result
237
+ }
238
+ // 处理时间,企微不能通过dayjs以及moment处理时间
239
+
240
+ // 过滤数组重复数据
241
+ export const filterRepeat = (arr: any[], fieldName: string) => {
242
+ const set = new Set()
243
+ return arr.filter(item => {
244
+ const key = item[fieldName]
245
+ if (set.has(key)) {
246
+ return false
247
+ } else {
248
+ set.add(key)
249
+ return true
250
+ }
251
+ })
252
+ }
253
+
254
+ // 将 base64 转换为 Blob
255
+ export const base64ToBlob = (base64) => {
256
+ var arr = base64.split(","),
257
+ mime = arr[0].match(/:(.\*?);/)[1],
258
+ bstr = atob(arr[1]),
259
+ n = bstr.length,
260
+ u8arr = new Uint8Array(n);
261
+ while (n--) {
262
+ u8arr[n] = bstr.charCodeAt(n);
263
+ }
264
+ return new Blob([u8arr], {
265
+ type: mime,
266
+ });
267
+ }
268
+ // 将 base64 转换为 File
269
+ export const base64ToFile = (base64, fileName) => {
270
+ let arr = base64.split(",");
271
+ let mime = arr[0].match(/:(.*);/)[1];
272
+
273
+ let bstr = atob(arr[1]);
274
+ let n = bstr.length;
275
+ let u8arr = new Uint8Array(n);
276
+
277
+ while (n--) {
278
+ u8arr[n] = bstr.charCodeAt(n);
279
+ }
280
+ return new File([u8arr], fileName, { type: mime });
281
+ }
282
+
283
+ // 处理时间,企微不能通过dayjs以及moment处理时间
284
+ export const isImage = (type: string) => {
285
+ return /^image\//i.test(type);
286
+ }
287
+
288
+ // 获取文件数据
289
+ export const getFileData = (optionName: string) => {
290
+ const [name = '', url = ''] = optionName.split(',')
291
+ return {
292
+ name: decodeURIComponent(name),
293
+ url: decodeURIComponent(url)
294
+ }
295
+ }
296
+ // 验证是否为数字
297
+ export const validateTwoDecimal = (v: number | string) => {
298
+ if (!v || v === '') return true
299
+ return /^(\d+)(\.\d{1,2})?$/.test(v.toString())
300
+ }
301
+ // 生成uuid
302
+ export const uuid = (len, radix) => {
303
+ let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
304
+ let uuid: string[] = [], i: string | number;
305
+ radix = radix || chars.length;
306
+
307
+ if (len) {
308
+ // Compact form
309
+ for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
310
+ } else {
311
+ // rfc4122, version 4 form
312
+ let r;
313
+
314
+ // rfc4122 requires these characters
315
+ uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
316
+ uuid[14] = '4';
317
+
318
+ // Fill in random data. At i==19 set the high bits of clock sequence as
319
+ // per rfc4122, sec. 4.1.5
320
+ for (i = 0; i < 36; i++) {
321
+ if (!uuid[i]) {
322
+ r = 0 | Math.random() * 16;
323
+ uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
324
+ }
325
+ }
326
+ }
327
+
328
+ return uuid.join('');
329
+ }
330
+
331
+ export const getToken = (cacheType: string, key = 'token') => {
332
+ let token = ''
333
+ const cacheTypeToLower = cacheType.toLowerCase();
334
+ if (cacheTypeToLower === 'localstorage') {
335
+ token = localStorage.getItem(key) || '';
336
+ } else if (cacheTypeToLower === 'sessionstorage') {
337
+ token = sessionStorage.getItem(key) || '';
338
+ } else {
339
+ token = localStorage.getItem(key) || sessionStorage.getItem('token') || '';
340
+ }
341
+ return token;
342
+ }
343
+ export const removeToken = (cacheType: string, key = 'token') => {
344
+ const cacheTypeToLower = cacheType.toLowerCase();
345
+ if (cacheTypeToLower === 'localstorage') {
346
+ localStorage.removeItem(key);
347
+ } else if (cacheTypeToLower === 'sessionstorage') {
348
+ sessionStorage.removeItem(key);
349
+ } else {
350
+ localStorage.removeItem(key);
351
+ sessionStorage.removeItem(key);
352
+ }
353
+ }
@@ -0,0 +1,13 @@
1
+ // 判断设备类型
2
+ export interface IFromType {
3
+ isWxWork: boolean;
4
+ isWeixin: boolean;
5
+ isMobileScreen: boolean;
6
+ isMobileAny: boolean;
7
+ }
8
+ export const fromTypeMap = {
9
+ isWxWork: 'wecom',
10
+ isWeixin: 'wechat',
11
+ isMobile: 'mobile',
12
+ isMobileAny: 'mobile',
13
+ }