@tmagic/utils 1.4.8 → 1.4.10
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/tmagic-utils.js +1 -1
- package/dist/tmagic-utils.js.map +1 -1
- package/dist/tmagic-utils.umd.cjs +1 -1
- package/dist/tmagic-utils.umd.cjs.map +1 -1
- package/package.json +4 -3
- package/src/dom.ts +124 -0
- package/src/index.ts +436 -0
- package/src/resetcss.css +446 -0
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.4.
|
|
2
|
+
"version": "1.4.10",
|
|
3
3
|
"name": "@tmagic/utils",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/tmagic-utils.umd.cjs",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
|
21
|
-
"types"
|
|
21
|
+
"types",
|
|
22
|
+
"src"
|
|
22
23
|
],
|
|
23
24
|
"license": "Apache-2.0",
|
|
24
25
|
"engines": {
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
},
|
|
41
42
|
"peerDependencies": {
|
|
42
43
|
"typescript": "*",
|
|
43
|
-
"@tmagic/schema": "1.4.
|
|
44
|
+
"@tmagic/schema": "1.4.10"
|
|
44
45
|
},
|
|
45
46
|
"peerDependenciesMeta": {
|
|
46
47
|
"typescript": {
|
package/src/dom.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
export const asyncLoadJs = (() => {
|
|
2
|
+
// 正在加载或加载成功的存入此Map中
|
|
3
|
+
const documentMap = new Map();
|
|
4
|
+
|
|
5
|
+
return (url: string, crossOrigin?: string, document = globalThis.document) => {
|
|
6
|
+
let loaded = documentMap.get(document);
|
|
7
|
+
if (!loaded) {
|
|
8
|
+
loaded = new Map();
|
|
9
|
+
documentMap.set(document, loaded);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// 正在加载或已经加载成功的,直接返回
|
|
13
|
+
if (loaded.get(url)) return loaded.get(url);
|
|
14
|
+
|
|
15
|
+
const load = new Promise<void>((resolve, reject) => {
|
|
16
|
+
const script = document.createElement('script');
|
|
17
|
+
script.type = 'text/javascript';
|
|
18
|
+
if (crossOrigin) {
|
|
19
|
+
script.crossOrigin = crossOrigin;
|
|
20
|
+
}
|
|
21
|
+
script.src = url;
|
|
22
|
+
document.body.appendChild(script);
|
|
23
|
+
script.onload = () => {
|
|
24
|
+
resolve();
|
|
25
|
+
};
|
|
26
|
+
script.onerror = () => {
|
|
27
|
+
reject(new Error('加载失败'));
|
|
28
|
+
};
|
|
29
|
+
setTimeout(() => {
|
|
30
|
+
reject(new Error('timeout'));
|
|
31
|
+
}, 60 * 1000);
|
|
32
|
+
}).catch((err) => {
|
|
33
|
+
// 加载失败的,从map中移除,第二次加载时,可以再次执行加载
|
|
34
|
+
loaded.delete(url);
|
|
35
|
+
throw err;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
loaded.set(url, load);
|
|
39
|
+
return loaded.get(url);
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
|
|
43
|
+
export const asyncLoadCss = (() => {
|
|
44
|
+
// 正在加载或加载成功的存入此Map中
|
|
45
|
+
const documentMap = new Map();
|
|
46
|
+
|
|
47
|
+
return (url: string, document = globalThis.document) => {
|
|
48
|
+
let loaded = documentMap.get(document);
|
|
49
|
+
if (!loaded) {
|
|
50
|
+
loaded = new Map();
|
|
51
|
+
documentMap.set(document, loaded);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 正在加载或已经加载成功的,直接返回
|
|
55
|
+
if (loaded.get(url)) return loaded.get(url);
|
|
56
|
+
|
|
57
|
+
const load = new Promise<void>((resolve, reject) => {
|
|
58
|
+
const node = document.createElement('link');
|
|
59
|
+
node.rel = 'stylesheet';
|
|
60
|
+
node.href = url;
|
|
61
|
+
document.head.appendChild(node);
|
|
62
|
+
node.onload = () => {
|
|
63
|
+
resolve();
|
|
64
|
+
};
|
|
65
|
+
node.onerror = () => {
|
|
66
|
+
reject(new Error('加载失败'));
|
|
67
|
+
};
|
|
68
|
+
setTimeout(() => {
|
|
69
|
+
reject(new Error('timeout'));
|
|
70
|
+
}, 60 * 1000);
|
|
71
|
+
}).catch((err) => {
|
|
72
|
+
// 加载失败的,从map中移除,第二次加载时,可以再次执行加载
|
|
73
|
+
loaded.delete(url);
|
|
74
|
+
throw err;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
loaded.set(url, load);
|
|
78
|
+
return loaded.get(url);
|
|
79
|
+
};
|
|
80
|
+
})();
|
|
81
|
+
|
|
82
|
+
export const addClassName = (el: Element, doc: Document, className: string) => {
|
|
83
|
+
const oldEl = doc.querySelector(`.${className}`);
|
|
84
|
+
if (oldEl && oldEl !== el) removeClassName(oldEl, className);
|
|
85
|
+
if (!el.classList.contains(className)) el.classList.add(className);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const removeClassName = (el: Element, ...className: string[]) => {
|
|
89
|
+
el.classList.remove(...className);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const removeClassNameByClassName = (doc: Document, className: string) => {
|
|
93
|
+
const el: HTMLElement | null = doc.querySelector(`.${className}`);
|
|
94
|
+
el?.classList.remove(className);
|
|
95
|
+
return el;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const injectStyle = (doc: Document, style: string) => {
|
|
99
|
+
const styleEl = doc.createElement('style');
|
|
100
|
+
styleEl.innerHTML = style;
|
|
101
|
+
doc.head.appendChild(styleEl);
|
|
102
|
+
return styleEl;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const createDiv = ({ className, cssText }: { className: string; cssText: string }) => {
|
|
106
|
+
const el = globalThis.document.createElement('div');
|
|
107
|
+
el.className = className;
|
|
108
|
+
el.style.cssText = cssText;
|
|
109
|
+
return el;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const getDocument = () => globalThis.document;
|
|
113
|
+
|
|
114
|
+
export const calcValueByFontsize = (doc: Document | undefined, value: number) => {
|
|
115
|
+
if (!doc) return value;
|
|
116
|
+
const { fontSize } = doc.documentElement.style;
|
|
117
|
+
|
|
118
|
+
if (fontSize) {
|
|
119
|
+
const times = globalThis.parseFloat(fontSize) / 100;
|
|
120
|
+
return Number((value / times).toFixed(2));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return value;
|
|
124
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import dayjs from 'dayjs';
|
|
20
|
+
import utc from 'dayjs/plugin/utc';
|
|
21
|
+
import { cloneDeep, set as objectSet } from 'lodash-es';
|
|
22
|
+
|
|
23
|
+
import type { DataSchema, DataSourceDeps, Id, MComponent, MNode } from '@tmagic/schema';
|
|
24
|
+
import { NodeType } from '@tmagic/schema';
|
|
25
|
+
|
|
26
|
+
export * from './dom';
|
|
27
|
+
|
|
28
|
+
export const sleep = (ms: number): Promise<void> =>
|
|
29
|
+
new Promise((resolve) => {
|
|
30
|
+
const timer = setTimeout(() => {
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
resolve();
|
|
33
|
+
}, ms);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const datetimeFormatter = (
|
|
37
|
+
v: string | Date,
|
|
38
|
+
defaultValue = '-',
|
|
39
|
+
format = 'YYYY-MM-DD HH:mm:ss',
|
|
40
|
+
): string | number => {
|
|
41
|
+
if (v) {
|
|
42
|
+
let time: string | number;
|
|
43
|
+
if (['x', 'timestamp'].includes(format)) {
|
|
44
|
+
time = dayjs(v).valueOf();
|
|
45
|
+
} else if ((typeof v === 'string' && v.includes('Z')) || v.constructor === Date) {
|
|
46
|
+
dayjs.extend(utc);
|
|
47
|
+
// UTC字符串时间或Date对象格式化为北京时间
|
|
48
|
+
time = dayjs(v).utcOffset(8).format(format);
|
|
49
|
+
} else {
|
|
50
|
+
time = dayjs(v).format(format);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (time !== 'Invalid Date') {
|
|
54
|
+
return time;
|
|
55
|
+
}
|
|
56
|
+
return defaultValue;
|
|
57
|
+
}
|
|
58
|
+
return defaultValue;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// 驼峰转换横线
|
|
62
|
+
export const toLine = (name = '') => name.replace(/\B([A-Z])/g, '-$1').toLowerCase();
|
|
63
|
+
|
|
64
|
+
export const toHump = (name = ''): string => name.replace(/-(\w)/g, (all, letter) => letter.toUpperCase());
|
|
65
|
+
|
|
66
|
+
export const emptyFn = (): any => undefined;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 通过id获取组件在应用的子孙路径
|
|
70
|
+
* @param {number | string} id 组件id
|
|
71
|
+
* @param {Array} data 要查找的根容器节点
|
|
72
|
+
* @return {Array} 组件在data中的子孙路径
|
|
73
|
+
*/
|
|
74
|
+
export const getNodePath = (id: Id, data: MNode[] = []): MNode[] => {
|
|
75
|
+
const path: MNode[] = [];
|
|
76
|
+
|
|
77
|
+
const get = function (id: number | string, data: MNode[]): MNode | null {
|
|
78
|
+
if (!Array.isArray(data)) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (let i = 0, l = data.length; i < l; i++) {
|
|
83
|
+
const item = data[i];
|
|
84
|
+
|
|
85
|
+
path.push(item);
|
|
86
|
+
if (`${item.id}` === `${id}`) {
|
|
87
|
+
return item;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (item.items) {
|
|
91
|
+
const node = get(id, item.items);
|
|
92
|
+
if (node) {
|
|
93
|
+
return node;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
path.pop();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return null;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
get(id, data);
|
|
104
|
+
|
|
105
|
+
return path;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const filterXSS = (str: string) =>
|
|
109
|
+
str.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
|
110
|
+
|
|
111
|
+
export const getUrlParam = (param: string, url?: string) => {
|
|
112
|
+
const u = url || location.href;
|
|
113
|
+
const reg = new RegExp(`[?&#]${param}=([^&#]+)`, 'gi');
|
|
114
|
+
|
|
115
|
+
const matches = u.match(reg);
|
|
116
|
+
let strArr;
|
|
117
|
+
if (matches && matches.length > 0) {
|
|
118
|
+
strArr = matches[matches.length - 1].split('=');
|
|
119
|
+
if (strArr && strArr.length > 1) {
|
|
120
|
+
// 过滤XSS字符
|
|
121
|
+
return filterXSS(strArr[1]);
|
|
122
|
+
}
|
|
123
|
+
return '';
|
|
124
|
+
}
|
|
125
|
+
return '';
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const isObject = (obj: any) => Object.prototype.toString.call(obj) === '[object Object]';
|
|
129
|
+
|
|
130
|
+
export const isPop = (node: MComponent | null): boolean => Boolean(node?.type?.toLowerCase().endsWith('pop'));
|
|
131
|
+
|
|
132
|
+
export const isPage = (node?: MComponent | null): boolean => {
|
|
133
|
+
if (!node) return false;
|
|
134
|
+
return Boolean(node.type?.toLowerCase() === NodeType.PAGE);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const isPageFragment = (node?: MComponent | null): boolean => {
|
|
138
|
+
if (!node) return false;
|
|
139
|
+
return Boolean(node.type?.toLowerCase() === NodeType.PAGE_FRAGMENT);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const isNumber = (value: string) => /^(-?\d+)(\.\d+)?$/.test(value);
|
|
143
|
+
|
|
144
|
+
export const getHost = (targetUrl: string) => targetUrl.match(/\/\/([^/]+)/)?.[1];
|
|
145
|
+
|
|
146
|
+
export const isSameDomain = (targetUrl = '', source = globalThis.location.host) => {
|
|
147
|
+
const isHttpUrl = /^(http[s]?:)?\/\//.test(targetUrl);
|
|
148
|
+
|
|
149
|
+
if (!isHttpUrl) return true;
|
|
150
|
+
|
|
151
|
+
return getHost(targetUrl) === source;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 生成指定位数的GUID,无【-】格式
|
|
156
|
+
* @param digit 位数,默认值8
|
|
157
|
+
* @returns
|
|
158
|
+
*/
|
|
159
|
+
export const guid = (digit = 8): string =>
|
|
160
|
+
'x'.repeat(digit).replace(/[xy]/g, (c) => {
|
|
161
|
+
const r = (Math.random() * 16) | 0;
|
|
162
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
163
|
+
return v.toString(16);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
export const getValueByKeyPath = (
|
|
167
|
+
keys: number | string | string[] = '',
|
|
168
|
+
data: Record<string | number, any> = {},
|
|
169
|
+
): any => {
|
|
170
|
+
// 将 array[0] 转成 array.0
|
|
171
|
+
const keyArray = Array.isArray(keys) ? keys : `${keys}`.replaceAll(/\[(\d+)\]/g, '.$1').split('.');
|
|
172
|
+
return keyArray.reduce((accumulator, currentValue: any) => {
|
|
173
|
+
if (isObject(accumulator) || Array.isArray(accumulator)) {
|
|
174
|
+
return accumulator[currentValue];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return void 0;
|
|
178
|
+
}, data);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export const setValueByKeyPath = (keys: string | number, value: any, data: Record<string | number, any> = {}): any =>
|
|
182
|
+
objectSet(data, keys, value);
|
|
183
|
+
|
|
184
|
+
export const getNodes = (ids: Id[], data: MNode[] = []): MNode[] => {
|
|
185
|
+
const nodes: MNode[] = [];
|
|
186
|
+
|
|
187
|
+
const get = function (ids: Id[], data: MNode[]) {
|
|
188
|
+
if (!Array.isArray(data)) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
for (let i = 0, l = data.length; i < l; i++) {
|
|
193
|
+
const item = data[i];
|
|
194
|
+
const index = ids.findIndex((id: Id) => `${id}` === `${item.id}`);
|
|
195
|
+
|
|
196
|
+
if (index > -1) {
|
|
197
|
+
ids.slice(index, 1);
|
|
198
|
+
nodes.push(item);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (item.items) {
|
|
202
|
+
get(ids, item.items);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
get(ids, data);
|
|
208
|
+
|
|
209
|
+
return nodes;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
export const getDepKeys = (dataSourceDeps: DataSourceDeps = {}, nodeId: Id) =>
|
|
213
|
+
Array.from(
|
|
214
|
+
Object.values(dataSourceDeps).reduce((prev, cur) => {
|
|
215
|
+
(cur[nodeId]?.keys || []).forEach((key) => prev.add(key));
|
|
216
|
+
return prev;
|
|
217
|
+
}, new Set<Id>()),
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
export const getDepNodeIds = (dataSourceDeps: DataSourceDeps = {}) =>
|
|
221
|
+
Array.from(
|
|
222
|
+
Object.values(dataSourceDeps).reduce((prev, cur) => {
|
|
223
|
+
Object.keys(cur).forEach((id) => {
|
|
224
|
+
prev.add(id);
|
|
225
|
+
});
|
|
226
|
+
return prev;
|
|
227
|
+
}, new Set<string>()),
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* 将新节点更新到data或者parentId对应的节点的子节点中
|
|
232
|
+
* @param newNode 新节点
|
|
233
|
+
* @param data 需要修改的数据
|
|
234
|
+
* @param parentId 父节点 id
|
|
235
|
+
*/
|
|
236
|
+
export const replaceChildNode = (newNode: MNode, data?: MNode[], parentId?: Id) => {
|
|
237
|
+
const path = getNodePath(newNode.id, data);
|
|
238
|
+
const node = path.pop();
|
|
239
|
+
let parent = path.pop();
|
|
240
|
+
|
|
241
|
+
if (parentId) {
|
|
242
|
+
parent = getNodePath(parentId, data).pop();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (!node) throw new Error('未找到目标节点');
|
|
246
|
+
if (!parent) throw new Error('未找到父节点');
|
|
247
|
+
|
|
248
|
+
const index = parent.items?.findIndex((child: MNode) => child.id === node.id);
|
|
249
|
+
parent.items.splice(index, 1, newNode);
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
export const DSL_NODE_KEY_COPY_PREFIX = '__magic__';
|
|
253
|
+
|
|
254
|
+
export const compiledNode = (
|
|
255
|
+
compile: (value: any) => any,
|
|
256
|
+
node: MNode,
|
|
257
|
+
dataSourceDeps: DataSourceDeps = {},
|
|
258
|
+
sourceId?: Id,
|
|
259
|
+
) => {
|
|
260
|
+
let keys: Id[] = [];
|
|
261
|
+
if (!sourceId) {
|
|
262
|
+
keys = getDepKeys(dataSourceDeps, node.id);
|
|
263
|
+
} else {
|
|
264
|
+
const dep = dataSourceDeps[sourceId];
|
|
265
|
+
keys = dep?.[node.id].keys || [];
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
keys.forEach((key) => {
|
|
269
|
+
const keys = `${key}`.replaceAll(/\[(\d+)\]/g, '.$1').split('.');
|
|
270
|
+
|
|
271
|
+
const cacheKey = keys.map((key, index) => {
|
|
272
|
+
if (index < keys.length - 1) {
|
|
273
|
+
return key;
|
|
274
|
+
}
|
|
275
|
+
return `${DSL_NODE_KEY_COPY_PREFIX}${key}`;
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const value = getValueByKeyPath(key, node);
|
|
279
|
+
let templateValue = getValueByKeyPath(cacheKey, node);
|
|
280
|
+
|
|
281
|
+
if (typeof templateValue === 'undefined') {
|
|
282
|
+
setValueByKeyPath(cacheKey.join('.'), value, node);
|
|
283
|
+
templateValue = value;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
let newValue;
|
|
287
|
+
try {
|
|
288
|
+
newValue = compile(templateValue);
|
|
289
|
+
} catch (e) {
|
|
290
|
+
console.error(e);
|
|
291
|
+
newValue = '';
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
setValueByKeyPath(key, newValue, node);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
return node;
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
export const compiledCond = (op: string, fieldValue: any, inputValue: any, range: number[] = []): boolean => {
|
|
301
|
+
if (typeof fieldValue === 'string' && typeof inputValue === 'undefined') {
|
|
302
|
+
inputValue = '';
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
switch (op) {
|
|
306
|
+
case 'is':
|
|
307
|
+
return fieldValue === inputValue;
|
|
308
|
+
case 'not':
|
|
309
|
+
return fieldValue !== inputValue;
|
|
310
|
+
case '=':
|
|
311
|
+
return fieldValue === inputValue;
|
|
312
|
+
case '!=':
|
|
313
|
+
return fieldValue !== inputValue;
|
|
314
|
+
case '>':
|
|
315
|
+
return fieldValue > inputValue;
|
|
316
|
+
case '>=':
|
|
317
|
+
return fieldValue >= inputValue;
|
|
318
|
+
case '<':
|
|
319
|
+
return fieldValue < inputValue;
|
|
320
|
+
case '<=':
|
|
321
|
+
return fieldValue <= inputValue;
|
|
322
|
+
case 'between':
|
|
323
|
+
return range.length > 1 && fieldValue >= range[0] && fieldValue <= range[1];
|
|
324
|
+
case 'not_between':
|
|
325
|
+
return range.length < 2 || fieldValue < range[0] || fieldValue > range[1];
|
|
326
|
+
case 'include':
|
|
327
|
+
return fieldValue?.includes?.(inputValue);
|
|
328
|
+
case 'not_include':
|
|
329
|
+
return typeof fieldValue === 'undefined' || !fieldValue.includes?.(inputValue);
|
|
330
|
+
default:
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return false;
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
export const getDefaultValueFromFields = (fields: DataSchema[]) => {
|
|
338
|
+
const data: Record<string, any> = {};
|
|
339
|
+
|
|
340
|
+
const defaultValue: Record<string, any> = {
|
|
341
|
+
string: undefined,
|
|
342
|
+
object: {},
|
|
343
|
+
array: [],
|
|
344
|
+
boolean: undefined,
|
|
345
|
+
number: undefined,
|
|
346
|
+
null: null,
|
|
347
|
+
any: undefined,
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
fields.forEach((field) => {
|
|
351
|
+
if (typeof field.defaultValue !== 'undefined') {
|
|
352
|
+
if (field.type === 'array' && !Array.isArray(field.defaultValue)) {
|
|
353
|
+
data[field.name] = defaultValue.array;
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (field.type === 'object' && !isObject(field.defaultValue)) {
|
|
358
|
+
if (typeof field.defaultValue === 'string') {
|
|
359
|
+
try {
|
|
360
|
+
data[field.name] = JSON.parse(field.defaultValue);
|
|
361
|
+
} catch (e) {
|
|
362
|
+
data[field.name] = defaultValue.object;
|
|
363
|
+
}
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
data[field.name] = defaultValue.object;
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
data[field.name] = cloneDeep(field.defaultValue);
|
|
372
|
+
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (field.type === 'object') {
|
|
377
|
+
data[field.name] = field.fields ? getDefaultValueFromFields(field.fields) : defaultValue.object;
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (field.type) {
|
|
382
|
+
data[field.name] = defaultValue[field.type];
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
data[field.name] = undefined;
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
return data;
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
export const DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX = 'ds-field::';
|
|
393
|
+
|
|
394
|
+
export const DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX = 'ds-field-changed';
|
|
395
|
+
|
|
396
|
+
export const getKeys = Object.keys as <T extends object>(obj: T) => Array<keyof T>;
|
|
397
|
+
|
|
398
|
+
export const calculatePercentage = (value: number, percentageStr: string) => {
|
|
399
|
+
const percentage = globalThis.parseFloat(percentageStr) / 100; // 先将百分比字符串转换为浮点数,并除以100转换为小数
|
|
400
|
+
const result = value * percentage;
|
|
401
|
+
return result;
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
export const isPercentage = (value: number | string) => /^(\d+)(\.\d+)?%$/.test(`${value}`);
|
|
405
|
+
|
|
406
|
+
export const convertToNumber = (value: number | string, parentValue = 0) => {
|
|
407
|
+
if (typeof value === 'number') {
|
|
408
|
+
return value;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (typeof value === 'string' && isPercentage(value)) {
|
|
412
|
+
return calculatePercentage(parentValue, value);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return parseFloat(value);
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* 添加参数到URL
|
|
420
|
+
* @param obj 参数对象
|
|
421
|
+
* @param global window对象
|
|
422
|
+
* @param needReload 是否需要刷新
|
|
423
|
+
*/
|
|
424
|
+
export const addParamToUrl = (obj: Record<string, any>, global = globalThis, needReload = true) => {
|
|
425
|
+
const url = new URL(global.location.href);
|
|
426
|
+
const { searchParams } = url;
|
|
427
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
428
|
+
searchParams.set(k, v);
|
|
429
|
+
}
|
|
430
|
+
const newUrl = url.toString();
|
|
431
|
+
if (needReload) {
|
|
432
|
+
global.location.href = newUrl;
|
|
433
|
+
} else {
|
|
434
|
+
global.history.pushState({}, '', url);
|
|
435
|
+
}
|
|
436
|
+
};
|