form-driver 0.1.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/LICENSE +21 -0
- package/README.md +37 -0
- package/dist/m3.css +310 -0
- package/dist/m3.js +1 -0
- package/es/m3.css +310 -0
- package/es/m3.js +20919 -0
- package/lib/m3.css +310 -0
- package/lib/m3.js +20959 -0
- package/package.json +132 -0
- package/src/.DS_Store +0 -0
- package/src/framework/Ajax.ts +96 -0
- package/src/framework/Assembly.tsx +165 -0
- package/src/framework/Init.tsx +196 -0
- package/src/framework/M3.tsx +94 -0
- package/src/framework/MContext.ts +15 -0
- package/src/framework/MFieldViewer.tsx +32 -0
- package/src/framework/MUtil.tsx +653 -0
- package/src/framework/MViewer.less +128 -0
- package/src/framework/MViewer.tsx +180 -0
- package/src/framework/MViewerDebug.tsx +95 -0
- package/src/framework/Persistant.ts +90 -0
- package/src/framework/Schema.ts +386 -0
- package/src/framework/SchemaFunc.ts +30 -0
- package/src/framework/Validator.ts +160 -0
- package/src/framework/editorMap.ts +109 -0
- package/src/index.ts +33 -0
- package/src/types/MArrayType.ts +73 -0
- package/src/types/MCascadeType.ts +35 -0
- package/src/types/MCnAddressType.ts +54 -0
- package/src/types/MDateRangeType.ts +52 -0
- package/src/types/MDateTimeType.ts +53 -0
- package/src/types/MDecorationType.ts +6 -0
- package/src/types/MEnumType.ts +65 -0
- package/src/types/MExperienceType.ts +81 -0
- package/src/types/MFloatType.ts +10 -0
- package/src/types/MGB2260Type.ts +56 -0
- package/src/types/MIntDiffType.ts +6 -0
- package/src/types/MIntType.ts +44 -0
- package/src/types/MKvSetType.ts +50 -0
- package/src/types/MMatrixType.ts +52 -0
- package/src/types/MObjectType.ts +89 -0
- package/src/types/MSetType.ts +220 -0
- package/src/types/MStringType.ts +27 -0
- package/src/types/MTelType.ts +14 -0
- package/src/types/MType.ts +77 -0
- package/src/types/MVLPairType.ts +35 -0
- package/src/types/gb2260.json +1 -0
- package/src/ui/BaseViewer.tsx +110 -0
- package/src/ui/editor/.DS_Store +0 -0
- package/src/ui/editor/basic/.DS_Store +0 -0
- package/src/ui/editor/basic/ACascadePicker.tsx +114 -0
- package/src/ui/editor/basic/ACheckBox.tsx +104 -0
- package/src/ui/editor/basic/ADatetimePicker.tsx +76 -0
- package/src/ui/editor/basic/AGB2260.tsx +52 -0
- package/src/ui/editor/basic/AInputBox.tsx +59 -0
- package/src/ui/editor/basic/AIntBox.tsx +39 -0
- package/src/ui/editor/basic/AKvSet.less +9 -0
- package/src/ui/editor/basic/AKvSet.tsx +90 -0
- package/src/ui/editor/basic/ARadio.tsx +86 -0
- package/src/ui/editor/basic/ARangePicker.tsx +129 -0
- package/src/ui/editor/basic/ARate.less +8 -0
- package/src/ui/editor/basic/ARate.tsx +37 -0
- package/src/ui/editor/basic/ARemoteSelector.tsx +116 -0
- package/src/ui/editor/basic/ASelector.tsx +88 -0
- package/src/ui/editor/basic/ASetSelector.tsx +65 -0
- package/src/ui/editor/basic/ASpecInputBox.tsx +20 -0
- package/src/ui/editor/basic/ATreeSelect.tsx +41 -0
- package/src/ui/editor/basic/AUpload.tsx +119 -0
- package/src/ui/editor/basic/NPS.less +21 -0
- package/src/ui/editor/basic/NPS.tsx +47 -0
- package/src/ui/editor/complex/AArray.less +10 -0
- package/src/ui/editor/complex/AArray.tsx +104 -0
- package/src/ui/editor/complex/AArrayGrid.tsx +115 -0
- package/src/ui/editor/complex/ACnAddress.less +15 -0
- package/src/ui/editor/complex/ACnAddress.tsx +61 -0
- package/src/ui/editor/complex/ADialogForm.tsx +45 -0
- package/src/ui/editor/complex/AExperience.tsx +85 -0
- package/src/ui/editor/complex/AForm.less +35 -0
- package/src/ui/editor/complex/AForm.tsx +340 -0
- package/src/ui/editor/complex/AIntDiff.tsx +77 -0
- package/src/ui/editor/complex/AMatrix.less +18 -0
- package/src/ui/editor/complex/AMatrix.tsx +242 -0
- package/src/ui/editor/complex/ATable.less +4 -0
- package/src/ui/editor/complex/ATable.tsx +33 -0
- package/src/ui/editor/complex/JsonEditor.tsx +37 -0
- package/src/ui/readable/A.tsx +33 -0
- package/src/ui/readable/ArrayViewer.tsx +46 -0
- package/src/ui/readable/DecorationViewer.tsx +76 -0
- package/src/ui/readable/DivViewer.tsx +11 -0
- package/src/ui/widget/Collapsible.tsx +156 -0
- package/src/ui/widget/Segment.less +39 -0
- package/src/ui/widget/Segment.tsx +40 -0
- package/src/ui/widget/SegmentEditSwitch.tsx +46 -0
- package/src/ui/widget/SelectBox.tsx +43 -0
- package/src/ui/widget/UnderlineInputBox.less +47 -0
- package/src/ui/widget/UnderlineInputBox.tsx +10 -0
- package/types/framework/Ajax.d.ts +5 -0
- package/types/framework/Assembly.d.ts +59 -0
- package/types/framework/Init.d.ts +4 -0
- package/types/framework/M3.d.ts +6 -0
- package/types/framework/MContext.d.ts +11 -0
- package/types/framework/MFieldViewer.d.ts +8 -0
- package/types/framework/MUtil.d.ts +180 -0
- package/types/framework/MViewer.d.ts +75 -0
- package/types/framework/MViewerDebug.d.ts +11 -0
- package/types/framework/Persistant.d.ts +17 -0
- package/types/framework/Schema.d.ts +306 -0
- package/types/framework/SchemaFunc.d.ts +14 -0
- package/types/framework/Validator.d.ts +53 -0
- package/types/framework/editorMap.d.ts +107 -0
- package/types/index.d.ts +21 -0
- package/types/types/MArrayType.d.ts +2 -0
- package/types/types/MCascadeType.d.ts +11 -0
- package/types/types/MCnAddressType.d.ts +2 -0
- package/types/types/MDateRangeType.d.ts +7 -0
- package/types/types/MDateTimeType.d.ts +11 -0
- package/types/types/MDecorationType.d.ts +7 -0
- package/types/types/MEnumType.d.ts +2 -0
- package/types/types/MExperienceType.d.ts +5 -0
- package/types/types/MFloatType.d.ts +2 -0
- package/types/types/MGB2260Type.d.ts +9 -0
- package/types/types/MIntDiffType.d.ts +2 -0
- package/types/types/MIntType.d.ts +2 -0
- package/types/types/MKvSetType.d.ts +11 -0
- package/types/types/MMatrixType.d.ts +5 -0
- package/types/types/MObjectType.d.ts +11 -0
- package/types/types/MSetType.d.ts +7 -0
- package/types/types/MStringType.d.ts +2 -0
- package/types/types/MTelType.d.ts +4 -0
- package/types/types/MType.d.ts +46 -0
- package/types/types/MVLPairType.d.ts +5 -0
- package/types/ui/BaseViewer.d.ts +45 -0
- package/types/ui/editor/basic/ACascadePicker.d.ts +11 -0
- package/types/ui/editor/basic/ACheckBox.d.ts +17 -0
- package/types/ui/editor/basic/ADatetimePicker.d.ts +15 -0
- package/types/ui/editor/basic/AGB2260.d.ts +10 -0
- package/types/ui/editor/basic/AInputBox.d.ts +8 -0
- package/types/ui/editor/basic/AIntBox.d.ts +9 -0
- package/types/ui/editor/basic/AKvSet.d.ts +19 -0
- package/types/ui/editor/basic/ARadio.d.ts +14 -0
- package/types/ui/editor/basic/ARangePicker.d.ts +30 -0
- package/types/ui/editor/basic/ARate.d.ts +13 -0
- package/types/ui/editor/basic/ARemoteSelector.d.ts +15 -0
- package/types/ui/editor/basic/ASelector.d.ts +14 -0
- package/types/ui/editor/basic/ASetSelector.d.ts +10 -0
- package/types/ui/editor/basic/ASpecInputBox.d.ts +9 -0
- package/types/ui/editor/basic/ATreeSelect.d.ts +18 -0
- package/types/ui/editor/basic/AUpload.d.ts +33 -0
- package/types/ui/editor/basic/NPS.d.ts +13 -0
- package/types/ui/editor/complex/AArray.d.ts +11 -0
- package/types/ui/editor/complex/AArrayGrid.d.ts +13 -0
- package/types/ui/editor/complex/ACnAddress.d.ts +10 -0
- package/types/ui/editor/complex/ADialogForm.d.ts +11 -0
- package/types/ui/editor/complex/AExperience.d.ts +16 -0
- package/types/ui/editor/complex/AForm.d.ts +46 -0
- package/types/ui/editor/complex/AIntDiff.d.ts +14 -0
- package/types/ui/editor/complex/AMatrix.d.ts +48 -0
- package/types/ui/editor/complex/ATable.d.ts +9 -0
- package/types/ui/editor/complex/JsonEditor.d.ts +9 -0
- package/types/ui/readable/A.d.ts +5 -0
- package/types/ui/readable/ArrayViewer.d.ts +5 -0
- package/types/ui/readable/DecorationViewer.d.ts +3 -0
- package/types/ui/readable/DivViewer.d.ts +5 -0
- package/types/ui/widget/Collapsible.d.ts +46 -0
- package/types/ui/widget/Segment.d.ts +18 -0
- package/types/ui/widget/SegmentEditSwitch.d.ts +20 -0
- package/types/ui/widget/SelectBox.d.ts +13 -0
- package/types/ui/widget/UnderlineInputBox.d.ts +6 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
|
+
import { MProp } from "../framework/Schema";
|
|
3
|
+
import _ from "lodash";
|
|
4
|
+
import { assembly } from '../framework/Assembly';
|
|
5
|
+
import { MContext } from '../framework/MContext';
|
|
6
|
+
import { MUtil } from "../framework/MUtil";
|
|
7
|
+
|
|
8
|
+
export interface ViewerState {
|
|
9
|
+
// 纯粹是用来刷新控件内容的
|
|
10
|
+
ctrlVersion?: number;
|
|
11
|
+
// true表示不校验,比如子form就不需要校验
|
|
12
|
+
noValidate?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 每一个Viewer,都用来表达(展示readable/编辑editor)json上的一个值 / 或者不会改变数据的装饰物
|
|
17
|
+
* 这个类负责展示校验错误,提供数据存取api
|
|
18
|
+
*/
|
|
19
|
+
export abstract class Viewer<S extends ViewerState> extends React.Component<MProp, S> {
|
|
20
|
+
/**
|
|
21
|
+
* 获取此字段在database中的值
|
|
22
|
+
*/
|
|
23
|
+
getValue(){
|
|
24
|
+
return MUtil.get(this.props.database, this.props.path);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getParentValue(){
|
|
28
|
+
return MUtil.get(this.props.database, MUtil.parentPath(this.props.path));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 当字段值变化时,调用此方法把值写回database,并且回调afterChange
|
|
33
|
+
* 调用changeValue后Editor会刷新,不需要额外再setState了
|
|
34
|
+
* @param v - 编辑器在数组中时,子编辑器changeValue(undefined)表示它要删除此元素
|
|
35
|
+
* @param updateCtrlVersion - 子类可以用state.ctrlVersion作为key的一部分,在数据变化时用changeValue(value, true)改变输入框的内容
|
|
36
|
+
* @param final - 参考AFTER_CHANGE_CALLBACK
|
|
37
|
+
*/
|
|
38
|
+
changeValueEx(v:any, updateCtrlVersion:boolean, final:boolean) {
|
|
39
|
+
// 字段校验状态是否变化
|
|
40
|
+
MUtil.set(this.props.database, this.props.path, v);
|
|
41
|
+
this.props.afterChange?.(this.props.path, v, final);
|
|
42
|
+
this.setState((p) =>{
|
|
43
|
+
return {ctrlVersion: updateCtrlVersion? (p.ctrlVersion ?? 0 )+1 : (p.ctrlVersion ?? 0)}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* changeValueEx(v, false, true)的快捷方式
|
|
49
|
+
* @param v
|
|
50
|
+
*/
|
|
51
|
+
changeValue(v:any) {
|
|
52
|
+
this.changeValueEx(v, false, true);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 子类实现编辑器元素的渲染,render根据这个元素再加上校验
|
|
57
|
+
*/
|
|
58
|
+
protected abstract element(ctx?: any):ReactNode;
|
|
59
|
+
|
|
60
|
+
render() {
|
|
61
|
+
return <MContext.Consumer>{
|
|
62
|
+
ctx =>{
|
|
63
|
+
// const isShow = MUtil.isShow(this.props.database, ctx.rootProps.schema?.objectFields, this.props.schema.showIf)
|
|
64
|
+
// // 隐藏的字段不展示
|
|
65
|
+
// if (!isShow) return null
|
|
66
|
+
const childElement = this.element(ctx);
|
|
67
|
+
if(this.props.morph === "readable" || this.state?.noValidate){
|
|
68
|
+
return childElement;
|
|
69
|
+
} else {
|
|
70
|
+
// 加上校验错误提示
|
|
71
|
+
if(!ctx?.forceValid) {
|
|
72
|
+
return childElement;
|
|
73
|
+
}
|
|
74
|
+
const v = assembly.validate(this.props.schema, this.getValue(), this.props.path);
|
|
75
|
+
return [
|
|
76
|
+
childElement,
|
|
77
|
+
v?.message ? <div key="错误提示" className="ant-form-item-explain ant-form-item-explain-error">{v.message}</div> : undefined
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}</MContext.Consumer>
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
getPlaceholder(index:number = 0): string|undefined {
|
|
85
|
+
let p = this.props.schema.placeholder;
|
|
86
|
+
if(_.isString(p)){
|
|
87
|
+
return p;
|
|
88
|
+
} else if(p) {
|
|
89
|
+
return p[index];
|
|
90
|
+
} else {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
antProp(useVersionCtrl:boolean = false){
|
|
96
|
+
return {
|
|
97
|
+
key: useVersionCtrl ? this.props.path + "/" + this.state.ctrlVersion : this.props.path,
|
|
98
|
+
placeholder: this.getPlaceholder(),
|
|
99
|
+
bordered: !this.props.hideBorder,
|
|
100
|
+
disabled: this.props.disable
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export abstract class BaseViewer extends Viewer<ViewerState> {
|
|
106
|
+
constructor(p:MProp){
|
|
107
|
+
super(p);
|
|
108
|
+
this.state = {ctrlVersion: 1, noValidate: false};
|
|
109
|
+
}
|
|
110
|
+
};
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Ajax } from '../../../framework/Ajax';
|
|
4
|
+
import _ from "lodash";
|
|
5
|
+
import { MUtil } from '../../../framework/MUtil';
|
|
6
|
+
import { Cascader } from 'antd';
|
|
7
|
+
import { MFieldSchema } from '../../../framework/Schema';
|
|
8
|
+
import { Picker } from 'antd-mobile';
|
|
9
|
+
import { BaseViewer } from "../../..";
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
export function labelExpr(d: any, remote: MFieldSchema["remote"]) {
|
|
13
|
+
let script = "const {" + _.keys(d).join(',') + "} = d; return " + remote.labelExpr;
|
|
14
|
+
return new Function("d", "_", script)(d, _);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function convert(node = {}, dataPath, valuePath, childPath) {
|
|
18
|
+
var newNode = {};
|
|
19
|
+
newNode['value'] = node[valuePath];
|
|
20
|
+
newNode['label'] = node[dataPath];
|
|
21
|
+
|
|
22
|
+
if (node[childPath] && node[childPath].length > 0) {
|
|
23
|
+
let child = [];
|
|
24
|
+
node[childPath].map((item) => {
|
|
25
|
+
child.push(convert(item, dataPath, valuePath, childPath))
|
|
26
|
+
})
|
|
27
|
+
newNode['children'] = child
|
|
28
|
+
}
|
|
29
|
+
return newNode
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* 树的查找 如该数据格式下查找id为3的元素
|
|
33
|
+
{id: 2, name: 'test', data: [{id: 3, name: 'yy'}]} => {id: 3, name: 'yy', type: 'ORG'}
|
|
34
|
+
*/
|
|
35
|
+
export function findById(node, id, labelPath, valuePath, childPath) {
|
|
36
|
+
if (node[valuePath] == id) {
|
|
37
|
+
let res = {
|
|
38
|
+
label: node[labelPath],
|
|
39
|
+
value: id
|
|
40
|
+
}
|
|
41
|
+
return res;
|
|
42
|
+
}
|
|
43
|
+
if (node[childPath] && node[childPath].length > 0) {
|
|
44
|
+
for (var i = 0; i < node[childPath].length; i++) {
|
|
45
|
+
let findItem = findById(node[childPath][i], id, labelPath, valuePath, childPath);
|
|
46
|
+
if (findItem !== -1) {
|
|
47
|
+
return findItem
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return -1
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class ACascadePicker extends BaseViewer {
|
|
55
|
+
fetchCandidate: (key: string) => void;
|
|
56
|
+
|
|
57
|
+
constructor(props) {
|
|
58
|
+
super(props);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
element() {
|
|
62
|
+
let show = super.getValue() || [];
|
|
63
|
+
if (!_.isArray(show)) {
|
|
64
|
+
show = [];
|
|
65
|
+
}
|
|
66
|
+
const candidate = MUtil.option(this.props.schema);
|
|
67
|
+
|
|
68
|
+
const p = this.props.schema.props ?? {};
|
|
69
|
+
|
|
70
|
+
if (MUtil.phoneLike()) {
|
|
71
|
+
return <>
|
|
72
|
+
{/* <Picker
|
|
73
|
+
data={this.props.schema.option}
|
|
74
|
+
extra="请选择(可选)"
|
|
75
|
+
cols={2}
|
|
76
|
+
value={show}
|
|
77
|
+
onChange={v => {
|
|
78
|
+
console.log(v);
|
|
79
|
+
super.changeValue(v);
|
|
80
|
+
}}
|
|
81
|
+
onOk={v => {
|
|
82
|
+
console.log(v);
|
|
83
|
+
super.changeValue(v);
|
|
84
|
+
}}
|
|
85
|
+
{...p}
|
|
86
|
+
>
|
|
87
|
+
<div className="backfill"> {show.length > 0 ? show.join('-') : '请点击选择' } </div>
|
|
88
|
+
</Picker> */}
|
|
89
|
+
</>
|
|
90
|
+
} else {
|
|
91
|
+
return <Cascader
|
|
92
|
+
key="v"
|
|
93
|
+
options={candidate}
|
|
94
|
+
defaultValue={show.map((item) => item.value)}
|
|
95
|
+
changeOnSelect
|
|
96
|
+
placeholder={super.getPlaceholder()}
|
|
97
|
+
onChange={v => {
|
|
98
|
+
const vLabel = [];
|
|
99
|
+
v.map((item) => {
|
|
100
|
+
let findItem;
|
|
101
|
+
candidate.map((dataItem) => {
|
|
102
|
+
findItem = findById(dataItem, item, 'label', 'value', 'children');
|
|
103
|
+
if (findItem != -1) {
|
|
104
|
+
vLabel.push(findItem)
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
super.changeValue(vLabel);
|
|
109
|
+
}}
|
|
110
|
+
{...p}
|
|
111
|
+
/>
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Checkbox } from "antd";
|
|
3
|
+
import _ from "lodash";
|
|
4
|
+
import { MUtil } from "../../../framework/MUtil";
|
|
5
|
+
import { BaseViewer } from '../../BaseViewer';
|
|
6
|
+
import { MEnumField, MProp, ValueConst } from '../../../framework/Schema';
|
|
7
|
+
import { MSetType } from '../../../types/MSetType';
|
|
8
|
+
import { MFieldViewer } from "../../../framework/MFieldViewer";
|
|
9
|
+
import { assembly } from "../../../framework/Assembly";
|
|
10
|
+
|
|
11
|
+
function ACheckBoxLabel(field: MEnumField) {
|
|
12
|
+
if (field.html) {
|
|
13
|
+
return <div dangerouslySetInnerHTML={{ __html: field.html }} />
|
|
14
|
+
} else {
|
|
15
|
+
return field.label ?? field.value
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 多选
|
|
21
|
+
* 示例:{label:"1.13 除爱人/对象之外,目前和您一起生活的家庭成员包括(多选):",name:"familyAccompany",type:"set", option: "父亲 母亲 孩子 爱人/对象的父亲 爱人/对象的母亲 兄弟姐妹"},
|
|
22
|
+
* 值:["孩子", "父亲"]
|
|
23
|
+
*/
|
|
24
|
+
export class ACheckBox extends BaseViewer {
|
|
25
|
+
_enumFields: MEnumField[];
|
|
26
|
+
_enumValues: ValueConst[];
|
|
27
|
+
|
|
28
|
+
/** 这个是开放输入框的值 */
|
|
29
|
+
_inputBoxValue: ValueConst;
|
|
30
|
+
|
|
31
|
+
constructor(p: MProp) {
|
|
32
|
+
super(p);
|
|
33
|
+
this._enumFields = MUtil.option(this.props.schema);
|
|
34
|
+
this._enumValues = this._enumFields.map(e => e.value);
|
|
35
|
+
|
|
36
|
+
const openOpt = p.schema.openOption ?? p.schema.setOpen;
|
|
37
|
+
if(openOpt) {
|
|
38
|
+
this._inputBoxValue =
|
|
39
|
+
_.first(_.difference(super.getValue(), this._enumValues)) ??
|
|
40
|
+
assembly.types[openOpt.type].createDefaultValue(assembly, openOpt);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
_createBr() {
|
|
45
|
+
return this.props.schema.layoutHint == "h" ? undefined : <div key={MUtil.unique()} />;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
element(ctx) {
|
|
49
|
+
let data: any[] = super.getValue()
|
|
50
|
+
|
|
51
|
+
const openIndex = MSetType.openValueIndex(this.props.schema, data);
|
|
52
|
+
let checkboxs: any[] = this._enumFields.map((m: any, index) => {
|
|
53
|
+
const isShow = MUtil.isShow(this.props.database, ctx.rootProps.schema?.objectFields, m.showIf)
|
|
54
|
+
if (!isShow) return null;
|
|
55
|
+
return [
|
|
56
|
+
<Checkbox key={index} disabled={this.props.disable} checked={_.includes(data, m.value)} onChange={(e) =>
|
|
57
|
+
super.changeValue(MSetType.change(e.target.checked, m.value, data, this.props.schema))}>
|
|
58
|
+
{ACheckBoxLabel(m)}
|
|
59
|
+
</Checkbox>,
|
|
60
|
+
this._createBr()
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// 开放选项
|
|
65
|
+
if (this.props.schema.openOption) {
|
|
66
|
+
checkboxs.push(
|
|
67
|
+
<Checkbox
|
|
68
|
+
disabled={this.props.disable}
|
|
69
|
+
key="opened:"
|
|
70
|
+
checked={openIndex >= 0}
|
|
71
|
+
onChange={(e) => {
|
|
72
|
+
if(e.target.checked) {
|
|
73
|
+
super.changeValue(MSetType.change(true, this._inputBoxValue, data, this.props.schema))
|
|
74
|
+
} else {
|
|
75
|
+
super.changeValue(MSetType.clearOpenValue(this.props.schema, data, false)) // 不能用MSetType.change,因为可能有多个开放值
|
|
76
|
+
}
|
|
77
|
+
}}>
|
|
78
|
+
<span style={{ marginRight: "10px" }}>{this.props.schema.openOption.label ?? "其他"}</span>
|
|
79
|
+
<MFieldViewer morph={this.props.morph} schema={this.props.schema.openOption} database={this} path="_inputBoxValue" afterChange={(path: string, str: any, final: boolean) => {
|
|
80
|
+
const matchEnum = this._enumFields.find(e => e.value === str);
|
|
81
|
+
if (matchEnum) { // 不能让用户输入某个枚举值
|
|
82
|
+
this._inputBoxValue = "";
|
|
83
|
+
_.remove(data, (e) => !this._enumValues.includes(e))
|
|
84
|
+
if (!data.includes(str)) {
|
|
85
|
+
data.push(str);
|
|
86
|
+
}
|
|
87
|
+
super.changeValueEx(data, true, final);
|
|
88
|
+
} else {
|
|
89
|
+
const idx = data.findIndex(v => !this._enumValues.includes(v));
|
|
90
|
+
if (!_.isNil(idx)) {
|
|
91
|
+
this._inputBoxValue = str;
|
|
92
|
+
data[idx] = str;
|
|
93
|
+
super.changeValueEx(data, false, final);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}} parent={this.props.schema} forceValid={false} disable={openIndex < 0} style={{ width: "inherit" }} />
|
|
97
|
+
</Checkbox>,
|
|
98
|
+
this._createBr()
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return checkboxs;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { DatePicker } from "antd";
|
|
3
|
+
import { DatePicker as DatePickerM } from 'antd-mobile';
|
|
4
|
+
import moment from "moment";
|
|
5
|
+
import zhCN from 'antd/lib/date-picker/locale/zh_CN';
|
|
6
|
+
import _ from "lodash";
|
|
7
|
+
import { MDateTimeType } from "../../../types/MDateTimeType";
|
|
8
|
+
import { MUtil } from "../../../framework/MUtil";
|
|
9
|
+
import { BaseViewer } from '../../BaseViewer';
|
|
10
|
+
/**
|
|
11
|
+
* 日期选择框
|
|
12
|
+
* 配置示例:
|
|
13
|
+
* {label:"1.2 您的出生年份是",name:"birthday", type:"AYearPicker"},
|
|
14
|
+
* {label:"1.14 您是什么时间来到现在这个城市的?",name:"enterCity", type:"yearAndMonth"},
|
|
15
|
+
* 类型是year时,dataFormat默认是YYYY,例如: 2020,表示2020年
|
|
16
|
+
* 类型是yearAndMonth时,dataFormat默认是YYYYMM,例如:202001,表示2020年1月
|
|
17
|
+
* 类型是yearMonthDay时,dataFormat默认是YYYYMMDD,例如:20200101,表示2020年1月1号
|
|
18
|
+
* 类型是dateTime时,dataFormat默认是x,例如1608897466955
|
|
19
|
+
*/
|
|
20
|
+
export class ADatetimePicker extends BaseViewer {
|
|
21
|
+
element() {
|
|
22
|
+
const antConf = MDateTimeType.antConf(this.props.schema);
|
|
23
|
+
if (!antConf) {
|
|
24
|
+
return MUtil.error(`无效的类型${this.props.schema.type}`, this.props.schema);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let data = this.getValue();
|
|
28
|
+
|
|
29
|
+
const dataAsMoment = data ? moment(data, antConf.dataFormat) : undefined;
|
|
30
|
+
const dataAsDate = dataAsMoment?.toDate();
|
|
31
|
+
const onChange = (vv: Date | moment.Moment | null) => {
|
|
32
|
+
if (vv) {
|
|
33
|
+
const vvAsM = _.isDate(vv) ? moment(vv) : vv;
|
|
34
|
+
super.changeValue(vvAsM.format(antConf.dataFormat))
|
|
35
|
+
} else {
|
|
36
|
+
super.changeValue(undefined);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const p = this.props.schema.props ?? {};
|
|
40
|
+
// 构造元素
|
|
41
|
+
if (MUtil.phoneLike()) { // 手机
|
|
42
|
+
return <DatePickerM
|
|
43
|
+
disabled={this.props.disable}
|
|
44
|
+
value={dataAsDate}
|
|
45
|
+
key={this.props.path}
|
|
46
|
+
minDate={this.props.schema.min ? moment(this.props.schema.min, antConf.dataFormat).toDate() : undefined}
|
|
47
|
+
maxDate={this.props.schema.max ? moment(this.props.schema.max, antConf.dataFormat).toDate() : undefined}
|
|
48
|
+
mode={antConf.mode}
|
|
49
|
+
onChange={onChange}
|
|
50
|
+
{...p}
|
|
51
|
+
>
|
|
52
|
+
<div className="backfill">{dataAsDate ? moment(dataAsDate).format(antConf.readableFormat) : "请点击选择"}</div>
|
|
53
|
+
</DatePickerM>;
|
|
54
|
+
} else { // 大屏
|
|
55
|
+
return <DatePicker
|
|
56
|
+
key={this.props.path}
|
|
57
|
+
disabled={this.props.disable}
|
|
58
|
+
bordered={this.props.hideBorder ? false : true}
|
|
59
|
+
disabledDate={(m) => {
|
|
60
|
+
const d =
|
|
61
|
+
(this.props.schema.min && moment(this.props.schema.min, antConf.dataFormat).isAfter(m)) ||
|
|
62
|
+
(this.props.schema.max && moment(this.props.schema.max, antConf.dataFormat).isBefore(m));
|
|
63
|
+
return !!d;
|
|
64
|
+
}}
|
|
65
|
+
format={antConf.readableFormat}
|
|
66
|
+
style={this.props.style}
|
|
67
|
+
locale={zhCN}
|
|
68
|
+
defaultValue={dataAsMoment}
|
|
69
|
+
showTime={antConf.showTime}
|
|
70
|
+
picker={antConf.mode}
|
|
71
|
+
onChange={onChange}
|
|
72
|
+
{...p}
|
|
73
|
+
/>;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Cascader } from 'antd';
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import { Picker } from 'antd-mobile';
|
|
5
|
+
import { MUtil } from "../../../framework/MUtil";
|
|
6
|
+
import { BaseViewer } from '../../BaseViewer';
|
|
7
|
+
import { MGB2260Type } from '../../../types/MGB2260Type';
|
|
8
|
+
/**
|
|
9
|
+
* 选择中国的省市县
|
|
10
|
+
* 示例:{label:"1.5 您目前的居住地",name:"reside", type:"gb2260"},
|
|
11
|
+
* 数据是gb2260的地区代码
|
|
12
|
+
*/
|
|
13
|
+
export class AGB2260 extends BaseViewer {
|
|
14
|
+
element() {
|
|
15
|
+
const v = super.getValue();
|
|
16
|
+
const empty = { label: ["请选择"], code: undefined };
|
|
17
|
+
const looked = _.isNil(v) ? empty : (MGB2260Type.lookup(v) ?? empty);
|
|
18
|
+
const p = this.props.schema.props ?? {};
|
|
19
|
+
|
|
20
|
+
if (MUtil.phoneLike()) { // 手机
|
|
21
|
+
return <Picker
|
|
22
|
+
extra={super.getPlaceholder()}
|
|
23
|
+
disabled={this.props.disable}
|
|
24
|
+
key={this.props.path}
|
|
25
|
+
className="AGB2260"
|
|
26
|
+
data={MGB2260Type.gb2260}
|
|
27
|
+
value={looked.code}
|
|
28
|
+
title={this.props.schema.label}
|
|
29
|
+
onDismiss={() => console.log('dismiss')}
|
|
30
|
+
onOk={e => super.changeValue(_.last(e))}
|
|
31
|
+
{...p}
|
|
32
|
+
>
|
|
33
|
+
<div className="backfill" style={this.props.style}>{looked?.label?.join("/")}</div>
|
|
34
|
+
</Picker>
|
|
35
|
+
} else { // PC
|
|
36
|
+
return <Cascader
|
|
37
|
+
options={MGB2260Type.gb2260}
|
|
38
|
+
disabled={this.props.disable}
|
|
39
|
+
key={this.props.path}
|
|
40
|
+
placeholder={super.getPlaceholder()}
|
|
41
|
+
bordered={this.props.hideBorder ? false : true}
|
|
42
|
+
className="AGB2260"
|
|
43
|
+
style={this.props.style}
|
|
44
|
+
defaultValue={looked.code}
|
|
45
|
+
onChange={(vv) => {
|
|
46
|
+
super.changeValue(_.last(vv));
|
|
47
|
+
}}
|
|
48
|
+
{...p}
|
|
49
|
+
/>;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CloseOutlined } from "@ant-design/icons";
|
|
3
|
+
import { Input } from "antd";
|
|
4
|
+
import TextArea from "antd/lib/input/TextArea";
|
|
5
|
+
import _ from "lodash";
|
|
6
|
+
import { BaseViewer } from '../../BaseViewer';
|
|
7
|
+
import { MProp } from "../../../framework/Schema";
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export class AInputBox extends BaseViewer {
|
|
11
|
+
value: string;
|
|
12
|
+
|
|
13
|
+
constructor(p:MProp){
|
|
14
|
+
super(p);
|
|
15
|
+
this.value = super.getValue();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
element() {
|
|
19
|
+
const lines = this.props.schema.stringLines ?? 1;
|
|
20
|
+
const p = this.props.schema.props ?? {};
|
|
21
|
+
const commonProps = {
|
|
22
|
+
defaultValue:this.getValue(),
|
|
23
|
+
key:this.props.path,
|
|
24
|
+
onChange: (v:any)=> { this.value = v.target.value; this.changeValueEx(this.value, false, false) },
|
|
25
|
+
onBlur: () => this.changeValue(this.value),
|
|
26
|
+
placeholder: super.getPlaceholder(),
|
|
27
|
+
bordered: this.props.hideBorder ? false : true,
|
|
28
|
+
disabled: this.props.disable,
|
|
29
|
+
maxLength: this.props.schema.max,
|
|
30
|
+
...p,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
if(lines === 1) { // 单行
|
|
34
|
+
let addon = undefined;
|
|
35
|
+
if(!_.isNil(this.props.removeButton)){
|
|
36
|
+
addon = <CloseOutlined
|
|
37
|
+
className={this.props.removeButton ? "AForm_removeBtn" : "AForm_removeBtn_disabled"}
|
|
38
|
+
onClick={() => super.changeValue(undefined)}
|
|
39
|
+
disabled={this.props.removeButton}/>
|
|
40
|
+
}
|
|
41
|
+
const inputProps = {
|
|
42
|
+
className: "AInputBox",
|
|
43
|
+
style: this.props.style,
|
|
44
|
+
...commonProps
|
|
45
|
+
}
|
|
46
|
+
//if(addon) {
|
|
47
|
+
return <Input {...inputProps} addonAfter={addon}/>
|
|
48
|
+
// } else {
|
|
49
|
+
// return <UnderlineInputBox {...inputProps}/>; // 等 UnderlineInputBox 支持addonAfter,上面的就能干掉了
|
|
50
|
+
// }
|
|
51
|
+
} else{ // 多行
|
|
52
|
+
let styles:any = {minHeight: lines + "em"};
|
|
53
|
+
if(this.props.hideBorder){
|
|
54
|
+
styles.border = "none";
|
|
55
|
+
}
|
|
56
|
+
return <TextArea style={styles} {...commonProps}/>
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import _ from "lodash";
|
|
3
|
+
import { BaseViewer } from "../../BaseViewer";
|
|
4
|
+
import { InputNumber } from "antd";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 输入整数的输入框
|
|
8
|
+
* 定义示例:{label:"2.3 请问今年以来您平均每月工作多少天?",name:"workdayPerMonth", type:"int"},
|
|
9
|
+
*/
|
|
10
|
+
export class AIntBox extends BaseViewer {
|
|
11
|
+
element() {
|
|
12
|
+
const p = this.props.schema.props ?? {};
|
|
13
|
+
const props = {
|
|
14
|
+
...super.antProp(),
|
|
15
|
+
bordered: undefined,
|
|
16
|
+
style: {border: this.props.hideBorder ? "none" : undefined, ...this.props.style},
|
|
17
|
+
min: this.props.schema.min,
|
|
18
|
+
max: this.props.schema.max,
|
|
19
|
+
// type: "number",
|
|
20
|
+
pattern: "\\d*",
|
|
21
|
+
defaultValue: super.getValue(),
|
|
22
|
+
onChange: (v)=>{
|
|
23
|
+
let n: number | undefined = Number(v)
|
|
24
|
+
if(_.isNaN(n)){
|
|
25
|
+
n = undefined;
|
|
26
|
+
}
|
|
27
|
+
if (p.onChange) p.onChange(n)
|
|
28
|
+
console.log(n)
|
|
29
|
+
this.changeValueEx(n, false, false);
|
|
30
|
+
},
|
|
31
|
+
onBlur: () =>{
|
|
32
|
+
if (p.onBlur) p.onBlur()
|
|
33
|
+
this.changeValueEx(super.getValue(), false, true);
|
|
34
|
+
},
|
|
35
|
+
...p,
|
|
36
|
+
}
|
|
37
|
+
return <InputNumber {...props}></InputNumber>
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Checkbox } from "antd";
|
|
3
|
+
import _ from "lodash";
|
|
4
|
+
import { MUtil } from "../../../framework/MUtil";
|
|
5
|
+
import { BaseViewer } from '../../BaseViewer';
|
|
6
|
+
import { MEnumField, MProp, ValueConst, MFieldSchemaAnonymity } from '../../../framework/Schema';
|
|
7
|
+
import { MFieldViewer } from "../../../framework/MFieldViewer";
|
|
8
|
+
import "./AKvSet.less";
|
|
9
|
+
|
|
10
|
+
const defaultBoxSchema = {type:"string", name:""} as MFieldSchemaAnonymity;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 可以填值的多选,max=1时可以当单选用
|
|
14
|
+
* B8: 您现在在做的事业务部门的岗位吗?
|
|
15
|
+
* 1. 是,具体职位是 _______
|
|
16
|
+
* 2. 否,我的部门是 _______
|
|
17
|
+
*/
|
|
18
|
+
export class AKvSet extends BaseViewer {
|
|
19
|
+
_enumFields: MEnumField[];
|
|
20
|
+
_enumValues: ValueConst[];
|
|
21
|
+
|
|
22
|
+
/** 这个是开放输入框的值 */
|
|
23
|
+
_inputBoxValue: ValueConst[];
|
|
24
|
+
|
|
25
|
+
constructor(p:MProp){
|
|
26
|
+
super(p);
|
|
27
|
+
|
|
28
|
+
const data = super.getValue();
|
|
29
|
+
this._enumFields = MUtil.option(this.props.schema);
|
|
30
|
+
this._enumValues = this._enumFields.map(e=>e.value);
|
|
31
|
+
this._inputBoxValue = this._enumFields.map(f=> data?.[f.value.toString()]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
_createBr(){
|
|
35
|
+
return this.props.schema.layoutHint == "h" ? undefined: <div key={MUtil.unique()}/>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
element() {
|
|
39
|
+
let data = super.getValue();
|
|
40
|
+
if(!_.isPlainObject(data)) {
|
|
41
|
+
data = {};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let checkboxs = this._enumFields.map((m, index)=>{
|
|
45
|
+
const select = _.has(data, m.value.toString());
|
|
46
|
+
const itemKey = m.value?.toString();
|
|
47
|
+
return <div key={itemKey} className={`kvSet_${this.props.schema.layoutHint}`}>
|
|
48
|
+
<Checkbox disabled={this.props.disable} checked={select} onChange={(e)=>{
|
|
49
|
+
let c = e.target.checked;
|
|
50
|
+
let update = false;
|
|
51
|
+
if(c) {
|
|
52
|
+
data[itemKey] = this._inputBoxValue?.[index];
|
|
53
|
+
const keys = Object.keys(data);
|
|
54
|
+
for(let k of keys) {
|
|
55
|
+
if(Object.keys(data).length > this.props.schema.max) {
|
|
56
|
+
if( k != itemKey ) {
|
|
57
|
+
delete data[k];
|
|
58
|
+
update = true;
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
delete data[m.value?.toString()]
|
|
66
|
+
}
|
|
67
|
+
super.changeValueEx(data, update, true);
|
|
68
|
+
}}/>
|
|
69
|
+
|
|
70
|
+
<div style={{display: "inline-block", marginLeft:5, marginRight:10, marginBottom:3}}>
|
|
71
|
+
{m.label ?? m.value}
|
|
72
|
+
<div style={{display:"inline-block", paddingLeft: 10}}>
|
|
73
|
+
<MFieldViewer
|
|
74
|
+
morph={this.props.morph}
|
|
75
|
+
schema={this.props.schema.openOption ?? defaultBoxSchema}
|
|
76
|
+
database={this}
|
|
77
|
+
parent={this.props.schema} forceValid={false}
|
|
78
|
+
disable={this.props.disable || !select}
|
|
79
|
+
path={"_inputBoxValue[" + index + "]"} afterChange={(path:string, str:any, final:boolean) => {
|
|
80
|
+
data[m.value?.toString()] = this._inputBoxValue[index];
|
|
81
|
+
super.changeValueEx(data, false, final);
|
|
82
|
+
}} />
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
{this._createBr()}
|
|
86
|
+
</div>
|
|
87
|
+
});
|
|
88
|
+
return checkboxs;
|
|
89
|
+
}
|
|
90
|
+
}
|