form-driver 0.4.1 → 0.4.3
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 +128 -0
- package/dist/m3.js +1 -1
- package/es/m3.css +128 -0
- package/es/m3.js +1100 -278
- package/lib/m3.css +128 -0
- package/lib/m3.js +1096 -274
- package/package.json +2 -1
- package/src/framework/Assembly.tsx +53 -23
- package/src/framework/Init.tsx +4 -0
- package/src/framework/M3.tsx +2 -2
- package/src/framework/MViewer.tsx +32 -8
- package/src/framework/Validator.ts +131 -68
- package/src/types/MSetType.ts +1 -1
- package/src/types/MWeightType.ts +113 -0
- package/src/ui/BaseViewer.tsx +64 -42
- package/src/ui/editor/complex/AArrayGrid.tsx +229 -101
- package/src/ui/editor/complex/AForm.tsx +273 -125
- package/src/ui/editor/complex/AWeight.tsx +257 -0
- package/src/ui/widget/EnhancedSortDrag.less +142 -0
- package/src/ui/widget/EnhancedSortDrag.tsx +498 -0
- package/types/framework/Assembly.d.ts +1 -1
- package/types/framework/MViewer.d.ts +1 -0
- package/types/framework/Validator.d.ts +2 -2
- package/types/types/MWeightType.d.ts +2 -0
- package/types/ui/editor/complex/AArrayGrid.d.ts +1 -1
- package/types/ui/editor/complex/AForm.d.ts +2 -2
- package/types/ui/editor/complex/AWeight.d.ts +42 -0
- package/types/ui/widget/EnhancedSortDrag.d.ts +59 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { MUtil } from "../framework/MUtil";
|
|
2
|
+
import { MFieldSchemaAnonymity, MValidationResult } from "../framework/Schema";
|
|
3
|
+
import { MType } from "./MType";
|
|
4
|
+
|
|
5
|
+
import { validateRequired } from "../framework/Validator";
|
|
6
|
+
import { assembly, Assembly } from "../framework/Assembly";
|
|
7
|
+
import _ from "lodash";
|
|
8
|
+
|
|
9
|
+
// 验证比重值的合法性
|
|
10
|
+
function validateWeightValue(
|
|
11
|
+
a: Assembly,
|
|
12
|
+
schema: any,
|
|
13
|
+
value: any,
|
|
14
|
+
path: string
|
|
15
|
+
): MValidationResult {
|
|
16
|
+
if (_.isNil(value)) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!_.isObject(value)) {
|
|
21
|
+
return { message: "比重值格式错误", path };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const fs = MUtil.option(schema) as any;
|
|
25
|
+
const totalWeight = schema.weight ?? 100; // 默认总比重为100
|
|
26
|
+
let currentTotal = 0;
|
|
27
|
+
|
|
28
|
+
// 计算当前已分配比重
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
currentTotal = value?.reduce?.((acc, val) => acc + val.value, 0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 比重题的校验文案都是固定显示在表单上,所以返回的 message 都是空的
|
|
34
|
+
// 验证总比重是否小于目标值
|
|
35
|
+
if (schema.weight && currentTotal < schema.weight && currentTotal !== 0) {
|
|
36
|
+
return {
|
|
37
|
+
message: `已分配比重不得小于总比重`,
|
|
38
|
+
path,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 验证总比重是否超过最大值
|
|
43
|
+
if (schema.weight !== undefined && currentTotal > schema.weight) {
|
|
44
|
+
return {
|
|
45
|
+
message: ``,
|
|
46
|
+
path,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
console.log("验证参数", value, currentTotal, schema.weight);
|
|
50
|
+
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const MWeightType: MType = {
|
|
55
|
+
validators: [validateRequired, validateWeightValue],
|
|
56
|
+
|
|
57
|
+
toReadable: (
|
|
58
|
+
assembly: Assembly,
|
|
59
|
+
s: MFieldSchemaAnonymity,
|
|
60
|
+
vs: any
|
|
61
|
+
): string => {
|
|
62
|
+
const fs = MUtil.option(s) as any;
|
|
63
|
+
if (_.isNil(vs)) {
|
|
64
|
+
return assembly.theme.READABLE_BLANK;
|
|
65
|
+
} else if (!_.isObject(vs)) {
|
|
66
|
+
return assembly.theme.READABLE_ERROR;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const parts: string[] = [];
|
|
70
|
+
for (let f of fs) {
|
|
71
|
+
const weight = vs[f.value];
|
|
72
|
+
if (!_.isNil(weight) && weight !== 0) {
|
|
73
|
+
parts.push(`${f.label}: ${weight}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return parts.length > 0 ? parts.join(", ") : assembly.theme.READABLE_BLANK;
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
standardValue: (a: Assembly, s: any, vs: any, strict: boolean): any => {
|
|
81
|
+
if (!_.isObject(vs)) {
|
|
82
|
+
return s.defaultValue;
|
|
83
|
+
}
|
|
84
|
+
if (!strict) {
|
|
85
|
+
return vs;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const fs = MUtil.option(s) as any;
|
|
89
|
+
const result: any = {};
|
|
90
|
+
|
|
91
|
+
for (let f of fs) {
|
|
92
|
+
const weight = vs[f.value];
|
|
93
|
+
if (!_.isNil(weight) && _.isNumber(weight) && weight >= 0) {
|
|
94
|
+
// 如果要求整数,则转换为整数
|
|
95
|
+
if (s.requireInteger) {
|
|
96
|
+
result[f.value] = Math.round(weight);
|
|
97
|
+
} else {
|
|
98
|
+
result[f.value] = weight;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return result;
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
createDefaultValue: (assembly: Assembly, s: MFieldSchemaAnonymity): any => {
|
|
107
|
+
if (s.defaultValue) {
|
|
108
|
+
return _.clone(s.defaultValue);
|
|
109
|
+
} else {
|
|
110
|
+
return {}; // 默认为空对象
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
};
|
package/src/ui/BaseViewer.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { ReactNode } from "react";
|
|
2
2
|
import { MProp } from "../framework/Schema";
|
|
3
3
|
import _ from "lodash";
|
|
4
|
-
import { assembly } from
|
|
5
|
-
import { MContext } from
|
|
4
|
+
import { assembly } from "../framework/Assembly";
|
|
5
|
+
import { MContext } from "../framework/MContext";
|
|
6
6
|
import { MUtil } from "../framework/MUtil";
|
|
7
7
|
|
|
8
8
|
export interface ViewerState {
|
|
@@ -16,24 +16,27 @@ export interface ViewerState {
|
|
|
16
16
|
* 每一个Viewer,都用来表达(展示readable/编辑editor)json上的一个值 / 或者不会改变数据的装饰物
|
|
17
17
|
* 这个类负责展示校验错误,提供数据存取api
|
|
18
18
|
*/
|
|
19
|
-
export abstract class Viewer<S extends ViewerState> extends React.Component<
|
|
19
|
+
export abstract class Viewer<S extends ViewerState> extends React.Component<
|
|
20
|
+
MProp,
|
|
21
|
+
S
|
|
22
|
+
> {
|
|
20
23
|
/**
|
|
21
24
|
* 获取此字段在database中的值
|
|
22
25
|
*/
|
|
23
|
-
getValue(){
|
|
26
|
+
getValue() {
|
|
24
27
|
return MUtil.get(this.props.database, this.props.path);
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
31
|
* 修复全局 Scheme
|
|
29
32
|
*/
|
|
30
|
-
changeSchema(v){
|
|
33
|
+
changeSchema(v) {
|
|
31
34
|
if (this.props.changeSchema) {
|
|
32
|
-
|
|
35
|
+
this.props.changeSchema(v);
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
getParentValue(){
|
|
39
|
+
getParentValue() {
|
|
37
40
|
return MUtil.get(this.props.database, MUtil.parentPath(this.props.path));
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -44,76 +47,95 @@ export abstract class Viewer<S extends ViewerState> extends React.Component<MPro
|
|
|
44
47
|
* @param updateCtrlVersion - 子类可以用state.ctrlVersion作为key的一部分,在数据变化时用changeValue(value, true)改变输入框的内容
|
|
45
48
|
* @param final - 参考AFTER_CHANGE_CALLBACK
|
|
46
49
|
*/
|
|
47
|
-
changeValueEx(v:any, updateCtrlVersion:boolean, final:boolean) {
|
|
50
|
+
changeValueEx(v: any, updateCtrlVersion: boolean, final: boolean) {
|
|
48
51
|
// 字段校验状态是否变化
|
|
49
52
|
MUtil.set(this.props.database, this.props.path, v);
|
|
50
53
|
this.props.afterChange?.(this.props.path, v, final);
|
|
51
|
-
this.setState((p) =>{
|
|
52
|
-
return {
|
|
54
|
+
this.setState((p) => {
|
|
55
|
+
return {
|
|
56
|
+
ctrlVersion: updateCtrlVersion
|
|
57
|
+
? (p.ctrlVersion ?? 0) + 1
|
|
58
|
+
: p.ctrlVersion ?? 0,
|
|
59
|
+
};
|
|
53
60
|
});
|
|
54
61
|
}
|
|
55
62
|
|
|
56
63
|
/**
|
|
57
64
|
* changeValueEx(v, false, true)的快捷方式
|
|
58
|
-
* @param v
|
|
65
|
+
* @param v
|
|
59
66
|
*/
|
|
60
|
-
changeValue(v:any) {
|
|
67
|
+
changeValue(v: any) {
|
|
61
68
|
this.changeValueEx(v, false, true);
|
|
62
69
|
}
|
|
63
70
|
|
|
64
71
|
/**
|
|
65
72
|
* 子类实现编辑器元素的渲染,render根据这个元素再加上校验
|
|
66
73
|
*/
|
|
67
|
-
protected abstract element(ctx?: any):ReactNode;
|
|
74
|
+
protected abstract element(ctx?: any): ReactNode;
|
|
68
75
|
|
|
69
76
|
render() {
|
|
70
|
-
return
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
} else {
|
|
79
|
-
// 加上校验错误提示
|
|
80
|
-
if(!ctx?.forceValid) {
|
|
77
|
+
return (
|
|
78
|
+
<MContext.Consumer>
|
|
79
|
+
{(ctx) => {
|
|
80
|
+
// const isShow = MUtil.isShow(this.props.database, ctx.rootProps.schema?.objectFields, this.props.schema.showIf)
|
|
81
|
+
// // 隐藏的字段不展示
|
|
82
|
+
// if (!isShow) return null
|
|
83
|
+
const childElement = this.element(ctx);
|
|
84
|
+
if (this.props.morph === "readable" || this.state?.noValidate) {
|
|
81
85
|
return childElement;
|
|
86
|
+
} else {
|
|
87
|
+
// 加上校验错误提示
|
|
88
|
+
if (!ctx?.forceValid) {
|
|
89
|
+
return childElement;
|
|
90
|
+
}
|
|
91
|
+
const v = assembly.validate(
|
|
92
|
+
this.props.schema,
|
|
93
|
+
this.getValue(),
|
|
94
|
+
this.props.path
|
|
95
|
+
);
|
|
96
|
+
return [
|
|
97
|
+
childElement,
|
|
98
|
+
v?.message ? (
|
|
99
|
+
<div
|
|
100
|
+
key="错误提示"
|
|
101
|
+
className="ant-form-item-explain ant-form-item-explain-error"
|
|
102
|
+
>
|
|
103
|
+
{v.message}
|
|
104
|
+
</div>
|
|
105
|
+
) : undefined,
|
|
106
|
+
];
|
|
82
107
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
v?.message ? <div key="错误提示" className="ant-form-item-explain ant-form-item-explain-error">{v.message}</div> : undefined
|
|
87
|
-
];
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}</MContext.Consumer>
|
|
108
|
+
}}
|
|
109
|
+
</MContext.Consumer>
|
|
110
|
+
);
|
|
91
111
|
}
|
|
92
112
|
|
|
93
|
-
getPlaceholder(index:number = 0): string|undefined {
|
|
113
|
+
getPlaceholder(index: number = 0): string | undefined {
|
|
94
114
|
let p = this.props.schema.placeholder;
|
|
95
|
-
if(_.isString(p)){
|
|
115
|
+
if (_.isString(p)) {
|
|
96
116
|
return p;
|
|
97
|
-
} else if(p) {
|
|
117
|
+
} else if (p) {
|
|
98
118
|
return p[index];
|
|
99
119
|
} else {
|
|
100
120
|
return undefined;
|
|
101
121
|
}
|
|
102
122
|
}
|
|
103
123
|
|
|
104
|
-
antProp(useVersionCtrl:boolean = false){
|
|
124
|
+
antProp(useVersionCtrl: boolean = false) {
|
|
105
125
|
return {
|
|
106
|
-
key: useVersionCtrl
|
|
126
|
+
key: useVersionCtrl
|
|
127
|
+
? this.props.path + "/" + this.state.ctrlVersion
|
|
128
|
+
: this.props.path,
|
|
107
129
|
placeholder: this.getPlaceholder(),
|
|
108
130
|
bordered: !this.props.hideBorder,
|
|
109
|
-
disabled: this.props.disable
|
|
110
|
-
}
|
|
131
|
+
disabled: this.props.disable,
|
|
132
|
+
};
|
|
111
133
|
}
|
|
112
134
|
}
|
|
113
135
|
|
|
114
136
|
export abstract class BaseViewer extends Viewer<ViewerState> {
|
|
115
|
-
constructor(p:MProp){
|
|
137
|
+
constructor(p: MProp) {
|
|
116
138
|
super(p);
|
|
117
|
-
this.state = {ctrlVersion: 1, noValidate: false};
|
|
139
|
+
this.state = { ctrlVersion: 1, noValidate: false };
|
|
118
140
|
}
|
|
119
|
-
}
|
|
141
|
+
}
|
|
@@ -1,38 +1,42 @@
|
|
|
1
|
-
|
|
2
1
|
import _ from "lodash";
|
|
3
|
-
import { Button, message, Popconfirm } from
|
|
4
|
-
import {
|
|
5
|
-
|
|
2
|
+
import { Button, message, Popconfirm } from "antd";
|
|
3
|
+
import {
|
|
4
|
+
CaretDownOutlined,
|
|
5
|
+
CaretUpOutlined,
|
|
6
|
+
CloseOutlined,
|
|
7
|
+
} from "@ant-design/icons";
|
|
8
|
+
import { BaseViewer } from "../../BaseViewer";
|
|
6
9
|
import { MUtil } from "../../../framework/MUtil";
|
|
7
10
|
import { MFieldViewer } from "../../../framework/MFieldViewer";
|
|
8
11
|
import React from "react";
|
|
9
|
-
import { assembly } from
|
|
12
|
+
import { assembly } from "../../../framework/Assembly";
|
|
13
|
+
import EnhancedSortDrag, { DragItem } from "../../widget/EnhancedSortDrag";
|
|
10
14
|
|
|
11
15
|
function uuid(len = 8, radix = 16) {
|
|
12
|
-
let chars =
|
|
16
|
+
let chars =
|
|
17
|
+
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("");
|
|
13
18
|
let uuid = [];
|
|
14
19
|
let i = 0;
|
|
15
20
|
radix = radix || chars.length;
|
|
16
21
|
|
|
17
22
|
if (len) {
|
|
18
|
-
|
|
23
|
+
for (i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];
|
|
19
24
|
} else {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
25
|
+
let r;
|
|
26
|
+
uuid[8] = uuid[13] = uuid[18] = uuid[23] = "-";
|
|
27
|
+
uuid[14] = "4";
|
|
28
|
+
|
|
29
|
+
for (i = 0; i < 36; i++) {
|
|
30
|
+
if (!uuid[i]) {
|
|
31
|
+
r = 0 | (Math.random() * 16);
|
|
32
|
+
uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
|
|
29
33
|
}
|
|
34
|
+
}
|
|
30
35
|
}
|
|
31
36
|
|
|
32
|
-
return uuid.join(
|
|
37
|
+
return uuid.join("");
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
|
|
36
40
|
/**
|
|
37
41
|
* 数据表格
|
|
38
42
|
* 数据是这样的数组:
|
|
@@ -50,17 +54,27 @@ export class AArrayGrid extends BaseViewer {
|
|
|
50
54
|
return MUtil.error("arrayMember未定义", schema);
|
|
51
55
|
}
|
|
52
56
|
|
|
53
|
-
const members = schema.arrayMember.objectFields
|
|
54
|
-
|
|
57
|
+
const members = schema.arrayMember.objectFields || [
|
|
58
|
+
// 成员是复杂结构
|
|
59
|
+
{ name: undefined, ...schema.arrayMember },
|
|
60
|
+
]; // 成员是简单结构
|
|
55
61
|
// if(!members) {
|
|
56
62
|
// return MUtil.error("AArrayGrid只适用于对象数组", schema);
|
|
57
63
|
// }
|
|
58
64
|
|
|
59
65
|
let data = super.getValue();
|
|
60
|
-
if (!_.isArray(data)) {
|
|
66
|
+
if (!_.isArray(data)) {
|
|
67
|
+
// 只接受数组
|
|
61
68
|
data = [];
|
|
62
69
|
}
|
|
63
70
|
|
|
71
|
+
data = data.map((d) => {
|
|
72
|
+
if (!d.uniqueId) {
|
|
73
|
+
d.uniqueId = uuid();
|
|
74
|
+
}
|
|
75
|
+
return d;
|
|
76
|
+
});
|
|
77
|
+
|
|
64
78
|
const cols = 1 + members.length;
|
|
65
79
|
|
|
66
80
|
//let headTh = [<td key=":操作栏" width="40px" align="center" style={{backgroundImage: "linear-gradient(to bottom left, transparent calc(50% - 1px), #d3d3d3, transparent calc(50% + 1px))"}}></td>]
|
|
@@ -68,90 +82,204 @@ export class AArrayGrid extends BaseViewer {
|
|
|
68
82
|
let rows = [];
|
|
69
83
|
for (let idx = 0; idx < data.length; idx++) {
|
|
70
84
|
const i = idx;
|
|
71
|
-
rows.push(
|
|
72
|
-
{
|
|
73
|
-
|
|
74
|
-
members.map((f, idx) =>
|
|
85
|
+
rows.push(
|
|
86
|
+
<tr key={i}>
|
|
87
|
+
{/* 各个字段 */}
|
|
88
|
+
{members.map((f, idx) => (
|
|
75
89
|
<td key={f.name + idx}>
|
|
76
|
-
<MFieldViewer
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
90
|
+
<MFieldViewer
|
|
91
|
+
key={this.state.ctrlVersion + "." + f.name}
|
|
92
|
+
parent={schema}
|
|
93
|
+
morph={this.props.morph}
|
|
94
|
+
schema={f}
|
|
95
|
+
database={data}
|
|
96
|
+
path={MUtil.jsonPath("[" + i + "]", f.name)}
|
|
97
|
+
hideBorder={true}
|
|
98
|
+
afterChange={(path, v, final): void => {
|
|
99
|
+
super.changeValueEx(data, false, final);
|
|
100
|
+
}}
|
|
101
|
+
/>
|
|
102
|
+
</td>
|
|
103
|
+
))}
|
|
104
|
+
|
|
105
|
+
{/* 操作栏 */}
|
|
106
|
+
<td key=":option" align="center">
|
|
107
|
+
<CaretUpOutlined
|
|
108
|
+
style={{ display: "block" }}
|
|
109
|
+
hidden={data.length <= 1}
|
|
110
|
+
onClick={() => {
|
|
111
|
+
if (i === 0) {
|
|
112
|
+
message.warn("已经到顶了");
|
|
113
|
+
} else {
|
|
114
|
+
const prev = data[i - 1];
|
|
115
|
+
data[i - 1] = data[i];
|
|
116
|
+
data[i] = prev;
|
|
117
|
+
super.changeValueEx(data, true, true);
|
|
118
|
+
}
|
|
119
|
+
}}
|
|
120
|
+
/>
|
|
121
|
+
<Popconfirm
|
|
122
|
+
title="确定要删除吗这一项吗?"
|
|
123
|
+
onConfirm={() => {
|
|
124
|
+
data.splice(i, 1);
|
|
125
|
+
super.changeValueEx(data, true, true);
|
|
126
|
+
}}
|
|
127
|
+
okText="删除"
|
|
128
|
+
cancelText="不删"
|
|
129
|
+
>
|
|
130
|
+
<CloseOutlined
|
|
131
|
+
style={{ display: "block" }}
|
|
132
|
+
hidden={data.length == (schema.min ?? 0)}
|
|
133
|
+
/>
|
|
134
|
+
</Popconfirm>
|
|
135
|
+
<CaretDownOutlined
|
|
136
|
+
style={{ display: "block" }}
|
|
137
|
+
hidden={data.length <= 1}
|
|
138
|
+
onClick={() => {
|
|
139
|
+
console.log("当前选择数据", data);
|
|
140
|
+
if (i === data.length - 1) {
|
|
141
|
+
message.warn("已经到底了");
|
|
142
|
+
} else {
|
|
143
|
+
const prev = data[i + 1];
|
|
144
|
+
data[i + 1] = data[i];
|
|
145
|
+
data[i] = prev;
|
|
146
|
+
super.changeValueEx(data, true, true);
|
|
147
|
+
}
|
|
148
|
+
}}
|
|
149
|
+
/>
|
|
150
|
+
</td>
|
|
151
|
+
</tr>
|
|
152
|
+
);
|
|
116
153
|
}
|
|
117
154
|
|
|
118
155
|
const isMax = data.length >= (schema.max ?? Number.MAX_VALUE);
|
|
156
|
+
|
|
157
|
+
// 处理拖拽后的数据变化
|
|
158
|
+
const handleDragChange = (newItems: DragItem[]) => {
|
|
159
|
+
// 根据拖拽后的新顺序,重新排列原始表格数据
|
|
160
|
+
const newData = newItems.map((item) => {
|
|
161
|
+
// 从原始数据中找到对应的行数据
|
|
162
|
+
const originalRow = data.find(
|
|
163
|
+
(row) => String(row.uniqueId) === item.id
|
|
164
|
+
);
|
|
165
|
+
// 正常情况下一定能找到对应的行数据,因为我们是基于原始数据创建的拖拽项
|
|
166
|
+
return { ...originalRow! }; // 使用 ! 断言,因为我们确信能找到匹配项
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
super.changeValueEx(newData, true, true);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const handleDragFail = () => {};
|
|
173
|
+
|
|
119
174
|
return (
|
|
120
|
-
<table
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
175
|
+
<table
|
|
176
|
+
key={this.props.path}
|
|
177
|
+
className="AExperience M3_table"
|
|
178
|
+
style={{ width: "100%" }}
|
|
179
|
+
>
|
|
180
|
+
<tbody>
|
|
181
|
+
<tr key=":header">
|
|
182
|
+
<th key={"拖拽"}></th>
|
|
183
|
+
{members.map((f, i) => (
|
|
184
|
+
<th key={f.name + i + ":first"}>
|
|
185
|
+
{f.required ? <span style={{ color: "red" }}>*</span> : null}
|
|
186
|
+
{f.label ?? f.name}
|
|
187
|
+
</th>
|
|
188
|
+
))}
|
|
189
|
+
<td key=":操作栏" width="40px" align="center"></td>
|
|
190
|
+
</tr>
|
|
191
|
+
<EnhancedSortDrag
|
|
192
|
+
items={data.map((row, index) => {
|
|
193
|
+
return {
|
|
194
|
+
id: String(row.uniqueId),
|
|
195
|
+
cpn: (
|
|
196
|
+
<>
|
|
197
|
+
{members.map((f, idx) => (
|
|
198
|
+
<td key={f.name + idx}>
|
|
199
|
+
<MFieldViewer
|
|
200
|
+
key={this.state.ctrlVersion + "." + f.name}
|
|
201
|
+
parent={schema}
|
|
202
|
+
morph={this.props.morph}
|
|
203
|
+
schema={f}
|
|
204
|
+
database={data}
|
|
205
|
+
path={MUtil.jsonPath("[" + index + "]", f.name)}
|
|
206
|
+
hideBorder={true}
|
|
207
|
+
afterChange={(path, v, final): void => {
|
|
208
|
+
super.changeValueEx(data, false, final);
|
|
209
|
+
}}
|
|
210
|
+
/>
|
|
211
|
+
</td>
|
|
212
|
+
))}
|
|
213
|
+
|
|
214
|
+
<Popconfirm
|
|
215
|
+
title="确定要删除吗这一项吗?"
|
|
216
|
+
onConfirm={() => {
|
|
217
|
+
data.splice(index, 1);
|
|
218
|
+
super.changeValueEx(data, true, true);
|
|
219
|
+
}}
|
|
220
|
+
okText="删除"
|
|
221
|
+
cancelText="不删"
|
|
222
|
+
>
|
|
223
|
+
<td>
|
|
224
|
+
<CloseOutlined
|
|
225
|
+
style={{ display: "block" }}
|
|
226
|
+
hidden={data.length == (schema.min ?? 0)}
|
|
227
|
+
/>
|
|
228
|
+
</td>
|
|
229
|
+
</Popconfirm>
|
|
230
|
+
</>
|
|
231
|
+
),
|
|
232
|
+
isChecked: true,
|
|
233
|
+
label: `${row.name}`,
|
|
234
|
+
checkedIndex: index,
|
|
235
|
+
};
|
|
236
|
+
})}
|
|
237
|
+
onChange={handleDragChange}
|
|
238
|
+
enableAnimation={true}
|
|
239
|
+
isTableRow={true}
|
|
240
|
+
onDragFail={handleDragFail}
|
|
241
|
+
/>
|
|
242
|
+
{/* {rows} */}
|
|
243
|
+
<tr key=":footer">
|
|
244
|
+
{/* 增加按钮 */}
|
|
245
|
+
<th key=":add" colSpan={cols}>
|
|
246
|
+
<Button
|
|
247
|
+
disabled={isMax}
|
|
248
|
+
key=":add"
|
|
249
|
+
onClick={() => {
|
|
250
|
+
let newItem = assembly.types[
|
|
251
|
+
schema.arrayMember.type
|
|
252
|
+
]?.createDefaultValue(assembly, schema.arrayMember);
|
|
253
|
+
{
|
|
254
|
+
/* 新增时支持要带入上一项的数据 */
|
|
255
|
+
}
|
|
256
|
+
if (schema.arrayMember.copyFields && data.length > 0) {
|
|
257
|
+
const last = data[data.length - 1];
|
|
258
|
+
if (last) {
|
|
259
|
+
newItem = {};
|
|
260
|
+
schema.arrayMember.copyFields.forEach((item) => {
|
|
261
|
+
newItem[item] = last[item];
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
data.push(newItem);
|
|
266
|
+
if (schema.autoValue) {
|
|
267
|
+
// 自动增加 value 属性
|
|
268
|
+
data.forEach((element) => {
|
|
269
|
+
if (!element.value) element.value = uuid();
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
console.log("data", data);
|
|
273
|
+
super.changeValue(data);
|
|
274
|
+
}}
|
|
275
|
+
>
|
|
276
|
+
增加一项
|
|
277
|
+
</Button>
|
|
278
|
+
{this.props.extra}
|
|
279
|
+
</th>
|
|
280
|
+
</tr>
|
|
281
|
+
</tbody>
|
|
282
|
+
</table>
|
|
283
|
+
);
|
|
156
284
|
}
|
|
157
285
|
}
|