form-driver 0.3.14 → 0.4.0
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/m3.css +57 -0
- package/dist/m3.js +1 -1
- package/es/m3.css +57 -0
- package/es/m3.js +2186 -1385
- package/lib/m3.css +57 -0
- package/lib/m3.js +2184 -1381
- package/package.json +13 -9
- package/src/framework/Init.tsx +152 -150
- package/src/framework/M3.tsx +83 -59
- package/src/framework/MUtil.tsx +275 -140
- package/src/framework/MViewer.tsx +198 -106
- package/src/framework/Schema.ts +100 -87
- package/src/types/MSetType.ts +128 -71
- package/src/ui/editor/basic/ACheckBox.tsx +98 -50
- package/src/ui/editor/complex/ACheckDrag.tsx +356 -0
- package/src/ui/editor/complex/JsonEditor.tsx +32 -21
- package/src/ui/widget/DIYCheckbox.less +36 -0
- package/src/ui/widget/DIYCheckbox.tsx +154 -0
- package/src/ui/widget/SortDrag.less +32 -0
- package/src/ui/widget/SortDrag.tsx +145 -0
- package/types/framework/Assembly.d.ts +2 -2
- package/types/framework/M3.d.ts +2 -2
- package/types/framework/MUtil.d.ts +5 -5
- package/types/framework/MViewer.d.ts +1 -1
- package/types/framework/Schema.d.ts +13 -11
- package/types/framework/Validator.d.ts +1 -1
- package/types/types/MDecorationType.d.ts +3 -3
- package/types/types/MSetType.d.ts +1 -1
- package/types/ui/editor/basic/ACheckBox.d.ts +2 -2
- package/types/ui/editor/basic/ARangePicker.d.ts +6 -2
- package/types/ui/editor/complex/ACheckDrag.d.ts +28 -0
- package/types/ui/editor/complex/JsonEditor.d.ts +1 -1
- package/types/ui/widget/DIYCheckbox.d.ts +19 -0
- package/types/ui/widget/SegmentEditSwitch.d.ts +1 -1
- package/types/ui/widget/SortDrag.d.ts +14 -0
package/src/framework/MUtil.tsx
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import _ from "lodash";
|
|
2
2
|
import moment from "moment";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
M3UISpec,
|
|
5
|
+
MEnumField,
|
|
6
|
+
MFieldSchema,
|
|
7
|
+
MFieldSchemaAnonymity,
|
|
8
|
+
MValidationFail,
|
|
9
|
+
} from "./Schema";
|
|
10
|
+
import { JSONSchema6 } from "json-schema";
|
|
5
11
|
import React from "react";
|
|
6
|
-
import { SchemaFunc } from
|
|
12
|
+
import { SchemaFunc } from "./SchemaFunc";
|
|
7
13
|
|
|
8
14
|
export type HideMap = { [fieldName: string]: boolean };
|
|
9
15
|
|
|
@@ -15,24 +21,22 @@ let next = Date.now() - 1617265950471;
|
|
|
15
21
|
export let MUtil = {
|
|
16
22
|
/**
|
|
17
23
|
* 每次调用,返回不一样的数字
|
|
18
|
-
* @returns
|
|
24
|
+
* @returns
|
|
19
25
|
*/
|
|
20
|
-
unique(){
|
|
21
|
-
return next
|
|
26
|
+
unique() {
|
|
27
|
+
return next++;
|
|
22
28
|
},
|
|
23
29
|
|
|
24
|
-
/**
|
|
30
|
+
/**
|
|
25
31
|
* 枚举字段可以写成空格分隔的字符串,也能写成MEnumField[],这个函数将两种形式转换成统一的MEnumField[]
|
|
26
32
|
* @deprecated 改成用MUtils.option
|
|
27
33
|
*/
|
|
28
34
|
standardFields: (fs: string | MEnumField[] | undefined): MEnumField[] => {
|
|
29
|
-
if (typeof fs ===
|
|
30
|
-
return fs.split(" ").map(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
);
|
|
35
|
+
if (typeof fs === "string") {
|
|
36
|
+
return fs.split(" ").map((aEnum) => {
|
|
37
|
+
const kv = aEnum.split("=");
|
|
38
|
+
return { label: kv[0], value: kv[1] ?? kv[0] };
|
|
39
|
+
});
|
|
36
40
|
} else if (fs) {
|
|
37
41
|
return fs;
|
|
38
42
|
} else {
|
|
@@ -44,27 +48,25 @@ export let MUtil = {
|
|
|
44
48
|
* 获取enumFields或者setFields,返回标准的MEnumField[]
|
|
45
49
|
* @param f 如果f是nil,返回[]
|
|
46
50
|
*/
|
|
47
|
-
option: (f:MFieldSchemaAnonymity):MEnumField[] => {
|
|
51
|
+
option: (f: MFieldSchemaAnonymity): MEnumField[] => {
|
|
48
52
|
let result: MEnumField[];
|
|
49
|
-
if(_.isArray(f.option)){
|
|
53
|
+
if (_.isArray(f.option)) {
|
|
50
54
|
result = f.option;
|
|
51
55
|
} else {
|
|
52
56
|
let ori;
|
|
53
|
-
if(f.type == "set"){
|
|
57
|
+
if (f.type == "set") {
|
|
54
58
|
ori = f.setFields;
|
|
55
|
-
} else if(f.type == "enum"){
|
|
56
|
-
ori = f.enumFields
|
|
59
|
+
} else if (f.type == "enum") {
|
|
60
|
+
ori = f.enumFields;
|
|
57
61
|
} else {
|
|
58
62
|
ori = f.option ?? f.setFields ?? f.enumFields; // 只是为了保险
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
if (typeof ori ===
|
|
62
|
-
f.option = result = ori.split(" ").map(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
);
|
|
65
|
+
if (typeof ori === "string") {
|
|
66
|
+
f.option = result = ori.split(" ").map((aEnum) => {
|
|
67
|
+
const kv = aEnum.split("=");
|
|
68
|
+
return { label: kv[0], value: kv[1] ?? kv[0] };
|
|
69
|
+
});
|
|
68
70
|
} else {
|
|
69
71
|
f.option = result = ori; // TODO children 可能有递归的,还是得靠预处理解决
|
|
70
72
|
}
|
|
@@ -74,11 +76,29 @@ export let MUtil = {
|
|
|
74
76
|
},
|
|
75
77
|
|
|
76
78
|
/** 如果出错了,返回这么个元素,可能用在BaseEditor子类或者其他的东西上 */
|
|
77
|
-
error: function (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
error: function (
|
|
80
|
+
msg: string,
|
|
81
|
+
schema?: MFieldSchema | MFieldSchemaAnonymity
|
|
82
|
+
): JSX.Element {
|
|
83
|
+
return (
|
|
84
|
+
<div
|
|
85
|
+
key={Date.now()}
|
|
86
|
+
style={{
|
|
87
|
+
color: "white",
|
|
88
|
+
border: "1px solid darkgrey",
|
|
89
|
+
background: "red",
|
|
90
|
+
textAlign: "center",
|
|
91
|
+
borderRadius: "5px",
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
94
|
+
{msg}
|
|
95
|
+
{schema ? (
|
|
96
|
+
<pre style={{ whiteSpace: "pre-wrap", textAlign: "left" }}>
|
|
97
|
+
{JSON.stringify(schema)}
|
|
98
|
+
</pre>
|
|
99
|
+
) : undefined}
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
82
102
|
},
|
|
83
103
|
|
|
84
104
|
sign: function (v: number | null | undefined): number | null {
|
|
@@ -118,7 +138,7 @@ export let MUtil = {
|
|
|
118
138
|
|
|
119
139
|
/**
|
|
120
140
|
* 计算文字的宽度
|
|
121
|
-
* @param text
|
|
141
|
+
* @param text
|
|
122
142
|
*/
|
|
123
143
|
antdTextWidth(text?: string) {
|
|
124
144
|
if (!text) {
|
|
@@ -145,8 +165,11 @@ export let MUtil = {
|
|
|
145
165
|
}
|
|
146
166
|
},
|
|
147
167
|
|
|
148
|
-
fieldOfLayout: function (
|
|
149
|
-
|
|
168
|
+
fieldOfLayout: function (
|
|
169
|
+
fields: MFieldSchema[],
|
|
170
|
+
spec: M3UISpec
|
|
171
|
+
): MFieldSchema[] {
|
|
172
|
+
const objectFieldMap = _.chain(fields).keyBy("name").value();
|
|
150
173
|
let r: { [key: string]: MFieldSchema } = {};
|
|
151
174
|
for (let s of spec.segments ?? []) {
|
|
152
175
|
for (let f of s.fields ?? []) {
|
|
@@ -165,8 +188,8 @@ export let MUtil = {
|
|
|
165
188
|
* 跟lodash的get一样,除了:
|
|
166
189
|
* 1. path是nil时返回undefined
|
|
167
190
|
* 2. path是""时返回原始对象
|
|
168
|
-
* @param a
|
|
169
|
-
* @param path
|
|
191
|
+
* @param a
|
|
192
|
+
* @param path
|
|
170
193
|
*/
|
|
171
194
|
get: function (a?: any | null, path?: string | null) {
|
|
172
195
|
if (_.isNil(a) || _.isNil(path)) {
|
|
@@ -185,7 +208,7 @@ export let MUtil = {
|
|
|
185
208
|
set: function (a: any | null, path: string | null, v: any) {
|
|
186
209
|
if (path === "") {
|
|
187
210
|
// 如果 database 是数组,需要特殊处理
|
|
188
|
-
if (_.isArray(a)) a.length = v.length
|
|
211
|
+
if (_.isArray(a)) a.length = v.length;
|
|
189
212
|
_.assign(a, v);
|
|
190
213
|
} else {
|
|
191
214
|
_.set(a, path, v);
|
|
@@ -202,7 +225,12 @@ export let MUtil = {
|
|
|
202
225
|
* @param database 数据库,会被修改的
|
|
203
226
|
* @param path 路径
|
|
204
227
|
*/
|
|
205
|
-
applyDefaultValue: function (
|
|
228
|
+
applyDefaultValue: function (
|
|
229
|
+
schema: MFieldSchema,
|
|
230
|
+
database: any,
|
|
231
|
+
path: string
|
|
232
|
+
) {
|
|
233
|
+
// FIXME 多测试下,type是object或其他简单类型的情况
|
|
206
234
|
if (schema.type === "object") {
|
|
207
235
|
for (let f of schema.objectFields ?? []) {
|
|
208
236
|
this.applyDefaultValue(f, database, (path ? path + "." : "") + f.name);
|
|
@@ -214,8 +242,13 @@ export let MUtil = {
|
|
|
214
242
|
}
|
|
215
243
|
},
|
|
216
244
|
|
|
217
|
-
filterHide: function (schema: MFieldSchema, database: any[] | object) {
|
|
218
|
-
|
|
245
|
+
filterHide: function (schema: MFieldSchema, database: any[] | object) {
|
|
246
|
+
// TODO 要改成递归的
|
|
247
|
+
const hm = MUtil.hideMap(
|
|
248
|
+
database,
|
|
249
|
+
schema.objectFields ?? [],
|
|
250
|
+
schema.uispec
|
|
251
|
+
);
|
|
219
252
|
let finalData: any = _.isArray(database) ? [] : {};
|
|
220
253
|
for (let k in database) {
|
|
221
254
|
if (!hm[k]) {
|
|
@@ -230,21 +263,28 @@ export let MUtil = {
|
|
|
230
263
|
* 支持ShowIfFunc里的函数
|
|
231
264
|
* TODO 如果segment隐藏,里面的字段全都要隐藏
|
|
232
265
|
* @returns 示例:
|
|
233
|
-
* let {name,role,gender,alias,birthday,company,position,tel,email,citizenship,politicsCode,companyArch,address,work,edu,assistant,student,mib} = data;
|
|
266
|
+
* let {name,role,gender,alias,birthday,company,position,tel,email,citizenship,politicsCode,companyArch,address,work,edu,assistant,student,mib} = data;
|
|
234
267
|
* return {politicsCode: !(citizenship=='中国大陆'),"segment:学员信息": !(_.intersection(role, ['校友']).length > 0))}
|
|
235
|
-
* @param objectFields
|
|
268
|
+
* @param objectFields
|
|
236
269
|
* @param uispec 用来计算segment是不是要展示,不填就不计算
|
|
237
270
|
*/
|
|
238
|
-
hideMap: function (
|
|
271
|
+
hideMap: function (
|
|
272
|
+
database: any,
|
|
273
|
+
objectFields: MFieldSchema[],
|
|
274
|
+
uispec?: M3UISpec
|
|
275
|
+
): HideMap {
|
|
239
276
|
// 构造字段依赖计算的脚本,类似这样:
|
|
240
277
|
// let {name,role,gender,alias,tel,email,citizenship,student} = {"name":"aaa","alias":"bbb","tel":"1"};citizenship=='中国大陆'
|
|
241
278
|
|
|
242
|
-
let l1fields = _.uniq(
|
|
279
|
+
let l1fields = _.uniq(
|
|
280
|
+
// 名字要唯一
|
|
243
281
|
objectFields
|
|
244
|
-
.filter(e => !!e.name) // 过滤掉没有名字的字段
|
|
245
|
-
.map(e => _.first(e.name.split("."))) // 对于objectFields里类似student.no/student.state的字段,这里只要拼一个student就可以了
|
|
282
|
+
.filter((e) => !!e.name) // 过滤掉没有名字的字段
|
|
283
|
+
.map((e) => _.first(e.name.split("."))) // 对于objectFields里类似student.no/student.state的字段,这里只要拼一个student就可以了
|
|
246
284
|
);
|
|
247
|
-
let showIfScript = `let {${l1fields.join(
|
|
285
|
+
let showIfScript = `let {${l1fields.join(
|
|
286
|
+
","
|
|
287
|
+
)}} = data || {};\nlet hide = {`;
|
|
248
288
|
for (let f of objectFields) {
|
|
249
289
|
if (f.showIf) {
|
|
250
290
|
showIfScript += `'${f.name}': !(${f.showIf}),`;
|
|
@@ -259,7 +299,7 @@ export let MUtil = {
|
|
|
259
299
|
|
|
260
300
|
// 如果一个segment里的所有字段都隐藏,segment就要隐藏
|
|
261
301
|
for (let s of uispec?.segments ?? []) {
|
|
262
|
-
const cond = s.fields.map(f => "(hide['" + f + "'])").join(" && ");
|
|
302
|
+
const cond = s.fields.map((f) => "(hide['" + f + "'])").join(" && ");
|
|
263
303
|
showIfScript += `if(${cond}) { hide["segment:${s.label}"] = true }\n`;
|
|
264
304
|
}
|
|
265
305
|
|
|
@@ -267,12 +307,20 @@ export let MUtil = {
|
|
|
267
307
|
|
|
268
308
|
// eslint-disable-next-line no-new-func
|
|
269
309
|
try {
|
|
270
|
-
const fn = Object.keys(SchemaFunc)
|
|
271
|
-
const fv = Object.values(SchemaFunc)
|
|
272
|
-
let hideMap = new Function("_", "data", ...fn, showIfScript)(
|
|
310
|
+
const fn = Object.keys(SchemaFunc);
|
|
311
|
+
const fv = Object.values(SchemaFunc);
|
|
312
|
+
let hideMap = new Function("_", "data", ...fn, showIfScript)(
|
|
313
|
+
_,
|
|
314
|
+
database,
|
|
315
|
+
...fv
|
|
316
|
+
);
|
|
273
317
|
return hideMap;
|
|
274
|
-
} catch (e) {
|
|
275
|
-
console.error(
|
|
318
|
+
} catch (e: any) {
|
|
319
|
+
console.error(
|
|
320
|
+
"Calc hideMap failed: " + e.message,
|
|
321
|
+
"function(_,data){" + showIfScript + "}",
|
|
322
|
+
database
|
|
323
|
+
);
|
|
276
324
|
return {};
|
|
277
325
|
}
|
|
278
326
|
},
|
|
@@ -280,37 +328,53 @@ export let MUtil = {
|
|
|
280
328
|
/**
|
|
281
329
|
* 计算 showIf 的值
|
|
282
330
|
* @returns Boolean
|
|
283
|
-
* @param database
|
|
284
|
-
|
|
331
|
+
* @param database
|
|
332
|
+
* @param objectFields
|
|
285
333
|
*/
|
|
286
|
-
isShow: function (
|
|
287
|
-
|
|
334
|
+
isShow: function (
|
|
335
|
+
database: any,
|
|
336
|
+
objectFields: MFieldSchema[],
|
|
337
|
+
showIfExpr: string
|
|
338
|
+
) {
|
|
339
|
+
if (!showIfExpr) return true;
|
|
288
340
|
let l1fields = _.uniq(
|
|
289
341
|
objectFields
|
|
290
|
-
.filter(e => !!e.name)
|
|
291
|
-
.map(e => _.first(e.name.split(".")))
|
|
342
|
+
.filter((e) => !!e.name)
|
|
343
|
+
.map((e) => _.first(e.name.split(".")))
|
|
292
344
|
);
|
|
293
|
-
let showIfScript = `let {${l1fields.join(
|
|
345
|
+
let showIfScript = `let {${l1fields.join(
|
|
346
|
+
","
|
|
347
|
+
)}} = data || {};\n return ${showIfExpr}`;
|
|
294
348
|
try {
|
|
295
|
-
const fn = Object.keys(SchemaFunc)
|
|
296
|
-
const fv = Object.values(SchemaFunc)
|
|
297
|
-
let res = new Function("_", "data", ...fn, showIfScript)(
|
|
349
|
+
const fn = Object.keys(SchemaFunc);
|
|
350
|
+
const fv = Object.values(SchemaFunc);
|
|
351
|
+
let res = new Function("_", "data", ...fn, showIfScript)(
|
|
352
|
+
_,
|
|
353
|
+
database,
|
|
354
|
+
...fv
|
|
355
|
+
);
|
|
298
356
|
return res;
|
|
299
|
-
} catch (e) {
|
|
300
|
-
console.error(
|
|
357
|
+
} catch (e: any) {
|
|
358
|
+
console.error(
|
|
359
|
+
"Calc isShow failed: " + e.message,
|
|
360
|
+
"function(_,data){" + showIfScript + "}",
|
|
361
|
+
database
|
|
362
|
+
);
|
|
301
363
|
return true;
|
|
302
364
|
}
|
|
303
365
|
},
|
|
304
366
|
|
|
305
|
-
scoreOf: function(f:MFieldSchema, database:any) {
|
|
367
|
+
scoreOf: function (f: MFieldSchema, database: any) {
|
|
306
368
|
const v = _.get(database, f.name);
|
|
307
|
-
if(f.type == "enum"){
|
|
308
|
-
return _.toNumber(
|
|
309
|
-
|
|
369
|
+
if (f.type == "enum") {
|
|
370
|
+
return _.toNumber(
|
|
371
|
+
MUtil.standardFields(f.enumFields)?.find((e) => e.value == v)?.score
|
|
372
|
+
);
|
|
373
|
+
} else if (f.type == "set") {
|
|
310
374
|
let score = 0;
|
|
311
375
|
const opts = MUtil.standardFields(f.setFields);
|
|
312
|
-
for(let s of opts){
|
|
313
|
-
if(_.find(opts, {value:v})) {
|
|
376
|
+
for (let s of opts) {
|
|
377
|
+
if (_.find(opts, { value: v })) {
|
|
314
378
|
score += _.toNumber(s.score);
|
|
315
379
|
}
|
|
316
380
|
}
|
|
@@ -323,37 +387,44 @@ export let MUtil = {
|
|
|
323
387
|
/**
|
|
324
388
|
* 查找fs依赖(通过showIf)的所有字段
|
|
325
389
|
* @param fs
|
|
326
|
-
* @param all
|
|
390
|
+
* @param all
|
|
327
391
|
* @returns fs依赖的所有字段,包含fs。这个数组中下标小的元素,依赖下标大的元素
|
|
328
392
|
*/
|
|
329
|
-
|
|
393
|
+
dependency: function (fs: MFieldSchema[], all: MFieldSchema[]) {
|
|
330
394
|
// 先建个索引
|
|
331
395
|
const allFieldsIdx = _.keyBy(all, "name");
|
|
332
|
-
|
|
396
|
+
|
|
333
397
|
// 构造未被依赖的集合
|
|
334
398
|
let ndep = _.keyBy(all, "name"); // 全体
|
|
335
|
-
ndep = _.omit(
|
|
336
|
-
|
|
399
|
+
ndep = _.omit(
|
|
400
|
+
ndep,
|
|
401
|
+
fs.map((f) => f.name)
|
|
402
|
+
); // 去掉fs
|
|
403
|
+
|
|
337
404
|
// 构造被依赖的集合
|
|
338
405
|
let dep = new Map<string, MFieldSchema>();
|
|
339
|
-
fs.forEach(f => dep[f.name] = f);
|
|
340
|
-
|
|
406
|
+
fs.forEach((f) => (dep[f.name] = f));
|
|
407
|
+
|
|
341
408
|
// 循环从ndep里把被依赖的字段放到dep中,直到dep不再增加
|
|
342
409
|
// 算法有点粗暴,将就用吧
|
|
343
|
-
for(let i = 0; i < all.length; i
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
410
|
+
for (let i = 0; i < all.length; i++) {
|
|
411
|
+
// 轮数最多all.length,防止卡死
|
|
412
|
+
let newDepNames = [];
|
|
413
|
+
for (let dn in dep) {
|
|
414
|
+
const i = _.intersection(
|
|
415
|
+
dep[dn].showIf?.split(/[^a-zA-Z0-9_$]/),
|
|
416
|
+
Object.keys(ndep)
|
|
417
|
+
);
|
|
347
418
|
newDepNames = newDepNames.concat(i);
|
|
348
419
|
}
|
|
349
420
|
|
|
350
421
|
let prevSize = Object.keys(dep).length;
|
|
351
|
-
for(let n of newDepNames){
|
|
422
|
+
for (let n of newDepNames) {
|
|
352
423
|
dep[n] = allFieldsIdx[n];
|
|
353
|
-
delete
|
|
424
|
+
delete ndep[n];
|
|
354
425
|
}
|
|
355
426
|
let afterSize = Object.keys(dep).length;
|
|
356
|
-
if(prevSize == afterSize) {
|
|
427
|
+
if (prevSize == afterSize) {
|
|
357
428
|
break; // 如果找不到更多依赖,就可以结束了
|
|
358
429
|
}
|
|
359
430
|
}
|
|
@@ -367,11 +438,16 @@ export let MUtil = {
|
|
|
367
438
|
* @param dstFormat 转换成的数据格式,默认YYYY年MM月DD日
|
|
368
439
|
* @param fallback 如果原始数据是nil,返回fallback
|
|
369
440
|
*/
|
|
370
|
-
momentFormat: function (
|
|
441
|
+
momentFormat: function (
|
|
442
|
+
s: moment.MomentInput,
|
|
443
|
+
srcFormat: string = "x",
|
|
444
|
+
dstFormat: string = "YYYY年MM月DD日",
|
|
445
|
+
fallback: string = "不详"
|
|
446
|
+
) {
|
|
371
447
|
if (_.isNil(s)) {
|
|
372
448
|
return fallback;
|
|
373
449
|
}
|
|
374
|
-
return moment(s, srcFormat).format(dstFormat)
|
|
450
|
+
return moment(s, srcFormat).format(dstFormat);
|
|
375
451
|
},
|
|
376
452
|
|
|
377
453
|
/**
|
|
@@ -380,23 +456,29 @@ export let MUtil = {
|
|
|
380
456
|
* @param base 如果填了一个对象,转换出的属性会放在这个对象上
|
|
381
457
|
* @param template 如果有子结构,创建子结构的模板
|
|
382
458
|
*/
|
|
383
|
-
jsonSchema2MFieldSchema: function (
|
|
459
|
+
jsonSchema2MFieldSchema: function (
|
|
460
|
+
e: JSONSchema6,
|
|
461
|
+
base: MFieldSchema = { name: "", type: "string" },
|
|
462
|
+
template: Partial<MFieldSchema> = {}
|
|
463
|
+
): MFieldSchema {
|
|
384
464
|
switch (e.type) {
|
|
385
|
-
case
|
|
465
|
+
case "string":
|
|
386
466
|
if (e.enum) {
|
|
387
467
|
base.type = "enum";
|
|
388
|
-
base.enumFields =
|
|
468
|
+
base.enumFields =
|
|
469
|
+
base.enumFields ??
|
|
470
|
+
e.enum.map((v) => ({ value: (v ?? "").toString() }));
|
|
389
471
|
} else {
|
|
390
|
-
base.type = "string"
|
|
391
|
-
base.max = e.maxLength
|
|
472
|
+
base.type = "string";
|
|
473
|
+
base.max = e.maxLength;
|
|
392
474
|
}
|
|
393
475
|
break;
|
|
394
|
-
case
|
|
395
|
-
case
|
|
476
|
+
case "number":
|
|
477
|
+
case "integer":
|
|
396
478
|
base.type = "int";
|
|
397
479
|
break;
|
|
398
|
-
case
|
|
399
|
-
base.type = "object"
|
|
480
|
+
case "object":
|
|
481
|
+
base.type = "object";
|
|
400
482
|
base.objectFields = [];
|
|
401
483
|
base.uispec = {
|
|
402
484
|
type: "flowForm",
|
|
@@ -405,19 +487,24 @@ export let MUtil = {
|
|
|
405
487
|
};
|
|
406
488
|
for (let key in e.properties) {
|
|
407
489
|
let jsmField = e.properties[key];
|
|
408
|
-
let m3Field: MFieldSchema = _.assign({}, template, {
|
|
490
|
+
let m3Field: MFieldSchema = _.assign({}, template, {
|
|
491
|
+
name: key,
|
|
492
|
+
label: key,
|
|
493
|
+
type: "object",
|
|
494
|
+
});
|
|
409
495
|
if (!_.isBoolean(jsmField)) {
|
|
410
496
|
m3Field.label = jsmField.title ?? key;
|
|
411
497
|
this.jsonSchema2MFieldSchema(jsmField, m3Field, template);
|
|
412
498
|
base.objectFields.push(m3Field);
|
|
413
499
|
} else {
|
|
414
|
-
m3Field.type =
|
|
415
|
-
|
|
500
|
+
m3Field.type =
|
|
501
|
+
"不支持的json schema:object.properties的value是boolean";
|
|
502
|
+
base.objectFields.push();
|
|
416
503
|
}
|
|
417
504
|
}
|
|
418
505
|
break;
|
|
419
|
-
case
|
|
420
|
-
base.type = "array"
|
|
506
|
+
case "array":
|
|
507
|
+
base.type = "array";
|
|
421
508
|
base.arrayMember = { label: "", type: "array" };
|
|
422
509
|
if (_.isArray(e.items)) {
|
|
423
510
|
base.arrayMember.type = "不支持的json schema:array.items是数组";
|
|
@@ -429,9 +516,9 @@ export let MUtil = {
|
|
|
429
516
|
base.arrayMember.type = "不支持的json schema:array.items是undefined";
|
|
430
517
|
}
|
|
431
518
|
break;
|
|
432
|
-
case
|
|
433
|
-
case
|
|
434
|
-
case
|
|
519
|
+
case "null":
|
|
520
|
+
case "any":
|
|
521
|
+
case "boolean":
|
|
435
522
|
default:
|
|
436
523
|
base.type = "不支持的json schema:array.items是" + e.type;
|
|
437
524
|
break;
|
|
@@ -442,11 +529,15 @@ export let MUtil = {
|
|
|
442
529
|
/**
|
|
443
530
|
* 修改一个对象里的key
|
|
444
531
|
* @param object 要修改的对象,
|
|
445
|
-
* @param renameTo
|
|
532
|
+
* @param renameTo
|
|
446
533
|
* @param removeNotExistKey 是否在结果里面去除renameTo里不存在的key
|
|
447
534
|
* @returns 返回一个改过key名字的新对象
|
|
448
535
|
*/
|
|
449
|
-
renameKey: function (
|
|
536
|
+
renameKey: function (
|
|
537
|
+
object: any,
|
|
538
|
+
renameTo: { [oldKey: string]: string },
|
|
539
|
+
removeNotExistKey: boolean = false
|
|
540
|
+
): any {
|
|
450
541
|
let result: any = {};
|
|
451
542
|
for (let oldKey in object) {
|
|
452
543
|
let newKey = renameTo[oldKey];
|
|
@@ -463,7 +554,7 @@ export let MUtil = {
|
|
|
463
554
|
},
|
|
464
555
|
|
|
465
556
|
/** 啥也不干的空回调 */
|
|
466
|
-
doNothing: function () {
|
|
557
|
+
doNothing: function () {},
|
|
467
558
|
|
|
468
559
|
/**
|
|
469
560
|
* 去掉arr中的undefined和null,拼出来一个json path
|
|
@@ -477,7 +568,7 @@ export let MUtil = {
|
|
|
477
568
|
* @param path 如果path是空的返回也是空的
|
|
478
569
|
*/
|
|
479
570
|
parentPath: function (path: string): string {
|
|
480
|
-
const split = path.replace(/]/g,
|
|
571
|
+
const split = path.replace(/]/g, "").split(/[.\\[]/);
|
|
481
572
|
split.splice(-1, 1);
|
|
482
573
|
return split.join(".");
|
|
483
574
|
},
|
|
@@ -487,31 +578,45 @@ export let MUtil = {
|
|
|
487
578
|
* @param s 要校验的schema
|
|
488
579
|
* @returns 空数组表示校验通过,否则返回校验错误信息
|
|
489
580
|
*/
|
|
490
|
-
validateSchema: function (
|
|
581
|
+
validateSchema: function (
|
|
582
|
+
s: MFieldSchema,
|
|
583
|
+
parentPath?: string
|
|
584
|
+
): MValidationFail[] {
|
|
491
585
|
let result: MValidationFail[] = [];
|
|
492
|
-
const error = (msg: string) =>
|
|
586
|
+
const error = (msg: string) =>
|
|
587
|
+
result.push({ message: msg, path: MUtil.jsonPath(parentPath, s.name) });
|
|
493
588
|
const checkDup = (a: any[], msgIfFail: string) => {
|
|
494
589
|
if (_.uniq(a).length !== a.length) {
|
|
495
590
|
error(msgIfFail);
|
|
496
591
|
}
|
|
497
592
|
};
|
|
498
593
|
const checkVL = (fs: MEnumField[]) => {
|
|
499
|
-
checkDup(
|
|
500
|
-
|
|
501
|
-
|
|
594
|
+
checkDup(
|
|
595
|
+
fs.map((f) => f.value),
|
|
596
|
+
s.name + "值有重复"
|
|
597
|
+
);
|
|
598
|
+
checkDup(
|
|
599
|
+
fs.map((f) => f.label).filter((l) => l),
|
|
600
|
+
s.name + "文案有重复"
|
|
601
|
+
);
|
|
602
|
+
};
|
|
502
603
|
const stringOnlyEnum = (candidate: string | MEnumField[] | undefined) => {
|
|
503
|
-
const ns = MUtil.standardFields(candidate).find(
|
|
604
|
+
const ns = MUtil.standardFields(candidate).find(
|
|
605
|
+
(f) => !_.isString(f.value)
|
|
606
|
+
);
|
|
504
607
|
if (ns) {
|
|
505
|
-
error(
|
|
608
|
+
error(
|
|
609
|
+
"暂不支持的选项数据类型:" + JSON.stringify(ns) + ": " + typeof ns
|
|
610
|
+
);
|
|
506
611
|
}
|
|
507
|
-
}
|
|
612
|
+
};
|
|
508
613
|
|
|
509
614
|
if (s.type === "decoration") {
|
|
510
615
|
return [];
|
|
511
616
|
} else if (s.type === "enum") {
|
|
512
|
-
checkVL(MUtil.standardFields(s.enumFields))
|
|
617
|
+
checkVL(MUtil.standardFields(s.enumFields));
|
|
513
618
|
} else if (s.type === "set") {
|
|
514
|
-
checkVL(MUtil.standardFields(s.setFields))
|
|
619
|
+
checkVL(MUtil.standardFields(s.setFields));
|
|
515
620
|
} else if (s.type === "matrix") {
|
|
516
621
|
stringOnlyEnum(s.matrix.x);
|
|
517
622
|
stringOnlyEnum(s.matrix.y);
|
|
@@ -519,19 +624,32 @@ export let MUtil = {
|
|
|
519
624
|
if (!s.objectFields) {
|
|
520
625
|
error("object类型未定义成员");
|
|
521
626
|
} else {
|
|
522
|
-
checkDup(
|
|
627
|
+
checkDup(
|
|
628
|
+
s.objectFields
|
|
629
|
+
.filter((f) => f.type !== "decoration")
|
|
630
|
+
.map((f) => f.name),
|
|
631
|
+
"字段名有重复"
|
|
632
|
+
);
|
|
523
633
|
for (let f of s.objectFields) {
|
|
524
|
-
result = _.concat(
|
|
634
|
+
result = _.concat(
|
|
635
|
+
result,
|
|
636
|
+
MUtil.validateSchema(f, MUtil.jsonPath(parentPath, s.name))
|
|
637
|
+
);
|
|
525
638
|
}
|
|
526
639
|
|
|
527
640
|
if (s.uispec?.type === "segmentForm") {
|
|
528
641
|
if (!s.uispec.segments) {
|
|
529
642
|
error("分段未定义");
|
|
530
643
|
} else {
|
|
531
|
-
checkDup(
|
|
532
|
-
|
|
644
|
+
checkDup(
|
|
645
|
+
s.uispec.segments.map((f) => f.label),
|
|
646
|
+
"分段文案有重复"
|
|
647
|
+
);
|
|
648
|
+
const fieldsInSegments = _.flatten(
|
|
649
|
+
s.uispec.segments.map((f) => f.fields)
|
|
650
|
+
);
|
|
533
651
|
checkDup(fieldsInSegments, "分段字段有重复");
|
|
534
|
-
const fields = s.objectFields.map(f => f.name);
|
|
652
|
+
const fields = s.objectFields.map((f) => f.name);
|
|
535
653
|
checkDup(fields, "字段名有重复");
|
|
536
654
|
const notInSegment = _.difference(fields, fieldsInSegments);
|
|
537
655
|
if (notInSegment.length > 0) {
|
|
@@ -551,8 +669,8 @@ export let MUtil = {
|
|
|
551
669
|
/**
|
|
552
670
|
* 参考https://stackoverflow.com/questions/3362471/how-can-i-call-a-javascript-constructor-using-call-or-apply
|
|
553
671
|
* 示例: var d = applyToConstructor(Date, [2008, 10, 8, 00, 16, 34, 254]);
|
|
554
|
-
* @param constructor
|
|
555
|
-
* @param argArray
|
|
672
|
+
* @param constructor
|
|
673
|
+
* @param argArray
|
|
556
674
|
*/
|
|
557
675
|
applyToConstructor: function (constructor, argArray) {
|
|
558
676
|
var args = [null, ...argArray];
|
|
@@ -568,12 +686,21 @@ export let MUtil = {
|
|
|
568
686
|
* @param fallback 如果exprOrFunction无效,返回fallback
|
|
569
687
|
* @param _this this指针
|
|
570
688
|
*/
|
|
571
|
-
evalExprOrFunction: function (
|
|
689
|
+
evalExprOrFunction: function (
|
|
690
|
+
exprOrFunction,
|
|
691
|
+
paramName: string[],
|
|
692
|
+
paramValue: any[],
|
|
693
|
+
fallback: any = undefined,
|
|
694
|
+
_this: any = undefined
|
|
695
|
+
) {
|
|
572
696
|
if (_.isFunction(exprOrFunction)) {
|
|
573
697
|
return exprOrFunction.apply(_this, paramValue);
|
|
574
698
|
} else if (_.isString(exprOrFunction)) {
|
|
575
699
|
//return new Function("_", "value", "parent", "return (" + labelExpr + ");")(_, value, parent);
|
|
576
|
-
const func = MUtil.applyToConstructor(Function, [
|
|
700
|
+
const func = MUtil.applyToConstructor(Function, [
|
|
701
|
+
...paramName,
|
|
702
|
+
"return (" + exprOrFunction + ")",
|
|
703
|
+
]);
|
|
577
704
|
return func.apply(_this, paramValue);
|
|
578
705
|
} else {
|
|
579
706
|
return fallback;
|
|
@@ -585,7 +712,10 @@ export let MUtil = {
|
|
|
585
712
|
* @param hashPrefix nil表示不读取hash里的参数,字符串表示读取hash里的参数,并加上这个前缀返回。默认是返回,但前缀是空字符串
|
|
586
713
|
*/
|
|
587
714
|
getQuery: function (hashPrefix: string = ""): any {
|
|
588
|
-
const arrs = [
|
|
715
|
+
const arrs = [
|
|
716
|
+
...window.location.search.split(/[?&]/),
|
|
717
|
+
...window.location.hash.split(/[#?&]/),
|
|
718
|
+
];
|
|
589
719
|
const result = {};
|
|
590
720
|
arrs.forEach((item) => {
|
|
591
721
|
const kv = item.split(/=/);
|
|
@@ -602,16 +732,18 @@ export let MUtil = {
|
|
|
602
732
|
* @param id <style>的id,可以没有。如果已经存在,会被覆盖掉。
|
|
603
733
|
*/
|
|
604
734
|
setCss: function (css: string, id?: string) {
|
|
605
|
-
const s =
|
|
735
|
+
const s =
|
|
736
|
+
(document.getElementById(id) as HTMLStyleElement) ??
|
|
737
|
+
document.createElement("style");
|
|
606
738
|
s.id = id;
|
|
607
|
-
s.type =
|
|
739
|
+
s.type = "text/css";
|
|
608
740
|
s.innerHTML = css;
|
|
609
|
-
document.getElementsByTagName(
|
|
741
|
+
document.getElementsByTagName("head")[0].appendChild(s);
|
|
610
742
|
},
|
|
611
743
|
|
|
612
744
|
/**
|
|
613
745
|
* escape数值
|
|
614
|
-
* @param str - 字符串
|
|
746
|
+
* @param str - 字符串
|
|
615
747
|
* @returns 会带上引号,类似"abc",str=nil时会返回""
|
|
616
748
|
*/
|
|
617
749
|
escapeCsv: function (str?: string) {
|
|
@@ -627,27 +759,30 @@ export let MUtil = {
|
|
|
627
759
|
* @param v2 另一个值
|
|
628
760
|
* @param tolerate true用==判断,false用===判断
|
|
629
761
|
*/
|
|
630
|
-
isEquals: function(v1, v2, tolerate: boolean) {
|
|
631
|
-
if(tolerate) {
|
|
762
|
+
isEquals: function (v1, v2, tolerate: boolean) {
|
|
763
|
+
if (tolerate) {
|
|
632
764
|
return v1 == v2;
|
|
633
765
|
} else {
|
|
634
766
|
return v1 === v2;
|
|
635
767
|
}
|
|
636
|
-
}
|
|
637
|
-
}
|
|
768
|
+
},
|
|
769
|
+
};
|
|
638
770
|
|
|
639
771
|
/** 压缩数组,如果只有一个元素时,它是数据本身,多于一个元素时才是数组 */
|
|
640
772
|
export type CompactArrayType<T> = T | T[];
|
|
641
773
|
|
|
642
774
|
export let CompactArray = {
|
|
643
|
-
indexOf: function <T>(
|
|
775
|
+
indexOf: function <T>(
|
|
776
|
+
ca?: CompactArrayType<T> | null,
|
|
777
|
+
d?: T | null
|
|
778
|
+
): -1 | number {
|
|
644
779
|
if (_.isNil(d) || _.isNil(ca)) {
|
|
645
780
|
return -1;
|
|
646
781
|
}
|
|
647
782
|
if (_.isArray(ca)) {
|
|
648
783
|
return ca.indexOf(d);
|
|
649
784
|
} else {
|
|
650
|
-
return ca === d ? 0 : -1
|
|
785
|
+
return ca === d ? 0 : -1;
|
|
651
786
|
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
787
|
+
},
|
|
788
|
+
};
|