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.
Files changed (168) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/m3.css +310 -0
  4. package/dist/m3.js +1 -0
  5. package/es/m3.css +310 -0
  6. package/es/m3.js +20919 -0
  7. package/lib/m3.css +310 -0
  8. package/lib/m3.js +20959 -0
  9. package/package.json +132 -0
  10. package/src/.DS_Store +0 -0
  11. package/src/framework/Ajax.ts +96 -0
  12. package/src/framework/Assembly.tsx +165 -0
  13. package/src/framework/Init.tsx +196 -0
  14. package/src/framework/M3.tsx +94 -0
  15. package/src/framework/MContext.ts +15 -0
  16. package/src/framework/MFieldViewer.tsx +32 -0
  17. package/src/framework/MUtil.tsx +653 -0
  18. package/src/framework/MViewer.less +128 -0
  19. package/src/framework/MViewer.tsx +180 -0
  20. package/src/framework/MViewerDebug.tsx +95 -0
  21. package/src/framework/Persistant.ts +90 -0
  22. package/src/framework/Schema.ts +386 -0
  23. package/src/framework/SchemaFunc.ts +30 -0
  24. package/src/framework/Validator.ts +160 -0
  25. package/src/framework/editorMap.ts +109 -0
  26. package/src/index.ts +33 -0
  27. package/src/types/MArrayType.ts +73 -0
  28. package/src/types/MCascadeType.ts +35 -0
  29. package/src/types/MCnAddressType.ts +54 -0
  30. package/src/types/MDateRangeType.ts +52 -0
  31. package/src/types/MDateTimeType.ts +53 -0
  32. package/src/types/MDecorationType.ts +6 -0
  33. package/src/types/MEnumType.ts +65 -0
  34. package/src/types/MExperienceType.ts +81 -0
  35. package/src/types/MFloatType.ts +10 -0
  36. package/src/types/MGB2260Type.ts +56 -0
  37. package/src/types/MIntDiffType.ts +6 -0
  38. package/src/types/MIntType.ts +44 -0
  39. package/src/types/MKvSetType.ts +50 -0
  40. package/src/types/MMatrixType.ts +52 -0
  41. package/src/types/MObjectType.ts +89 -0
  42. package/src/types/MSetType.ts +220 -0
  43. package/src/types/MStringType.ts +27 -0
  44. package/src/types/MTelType.ts +14 -0
  45. package/src/types/MType.ts +77 -0
  46. package/src/types/MVLPairType.ts +35 -0
  47. package/src/types/gb2260.json +1 -0
  48. package/src/ui/BaseViewer.tsx +110 -0
  49. package/src/ui/editor/.DS_Store +0 -0
  50. package/src/ui/editor/basic/.DS_Store +0 -0
  51. package/src/ui/editor/basic/ACascadePicker.tsx +114 -0
  52. package/src/ui/editor/basic/ACheckBox.tsx +104 -0
  53. package/src/ui/editor/basic/ADatetimePicker.tsx +76 -0
  54. package/src/ui/editor/basic/AGB2260.tsx +52 -0
  55. package/src/ui/editor/basic/AInputBox.tsx +59 -0
  56. package/src/ui/editor/basic/AIntBox.tsx +39 -0
  57. package/src/ui/editor/basic/AKvSet.less +9 -0
  58. package/src/ui/editor/basic/AKvSet.tsx +90 -0
  59. package/src/ui/editor/basic/ARadio.tsx +86 -0
  60. package/src/ui/editor/basic/ARangePicker.tsx +129 -0
  61. package/src/ui/editor/basic/ARate.less +8 -0
  62. package/src/ui/editor/basic/ARate.tsx +37 -0
  63. package/src/ui/editor/basic/ARemoteSelector.tsx +116 -0
  64. package/src/ui/editor/basic/ASelector.tsx +88 -0
  65. package/src/ui/editor/basic/ASetSelector.tsx +65 -0
  66. package/src/ui/editor/basic/ASpecInputBox.tsx +20 -0
  67. package/src/ui/editor/basic/ATreeSelect.tsx +41 -0
  68. package/src/ui/editor/basic/AUpload.tsx +119 -0
  69. package/src/ui/editor/basic/NPS.less +21 -0
  70. package/src/ui/editor/basic/NPS.tsx +47 -0
  71. package/src/ui/editor/complex/AArray.less +10 -0
  72. package/src/ui/editor/complex/AArray.tsx +104 -0
  73. package/src/ui/editor/complex/AArrayGrid.tsx +115 -0
  74. package/src/ui/editor/complex/ACnAddress.less +15 -0
  75. package/src/ui/editor/complex/ACnAddress.tsx +61 -0
  76. package/src/ui/editor/complex/ADialogForm.tsx +45 -0
  77. package/src/ui/editor/complex/AExperience.tsx +85 -0
  78. package/src/ui/editor/complex/AForm.less +35 -0
  79. package/src/ui/editor/complex/AForm.tsx +340 -0
  80. package/src/ui/editor/complex/AIntDiff.tsx +77 -0
  81. package/src/ui/editor/complex/AMatrix.less +18 -0
  82. package/src/ui/editor/complex/AMatrix.tsx +242 -0
  83. package/src/ui/editor/complex/ATable.less +4 -0
  84. package/src/ui/editor/complex/ATable.tsx +33 -0
  85. package/src/ui/editor/complex/JsonEditor.tsx +37 -0
  86. package/src/ui/readable/A.tsx +33 -0
  87. package/src/ui/readable/ArrayViewer.tsx +46 -0
  88. package/src/ui/readable/DecorationViewer.tsx +76 -0
  89. package/src/ui/readable/DivViewer.tsx +11 -0
  90. package/src/ui/widget/Collapsible.tsx +156 -0
  91. package/src/ui/widget/Segment.less +39 -0
  92. package/src/ui/widget/Segment.tsx +40 -0
  93. package/src/ui/widget/SegmentEditSwitch.tsx +46 -0
  94. package/src/ui/widget/SelectBox.tsx +43 -0
  95. package/src/ui/widget/UnderlineInputBox.less +47 -0
  96. package/src/ui/widget/UnderlineInputBox.tsx +10 -0
  97. package/types/framework/Ajax.d.ts +5 -0
  98. package/types/framework/Assembly.d.ts +59 -0
  99. package/types/framework/Init.d.ts +4 -0
  100. package/types/framework/M3.d.ts +6 -0
  101. package/types/framework/MContext.d.ts +11 -0
  102. package/types/framework/MFieldViewer.d.ts +8 -0
  103. package/types/framework/MUtil.d.ts +180 -0
  104. package/types/framework/MViewer.d.ts +75 -0
  105. package/types/framework/MViewerDebug.d.ts +11 -0
  106. package/types/framework/Persistant.d.ts +17 -0
  107. package/types/framework/Schema.d.ts +306 -0
  108. package/types/framework/SchemaFunc.d.ts +14 -0
  109. package/types/framework/Validator.d.ts +53 -0
  110. package/types/framework/editorMap.d.ts +107 -0
  111. package/types/index.d.ts +21 -0
  112. package/types/types/MArrayType.d.ts +2 -0
  113. package/types/types/MCascadeType.d.ts +11 -0
  114. package/types/types/MCnAddressType.d.ts +2 -0
  115. package/types/types/MDateRangeType.d.ts +7 -0
  116. package/types/types/MDateTimeType.d.ts +11 -0
  117. package/types/types/MDecorationType.d.ts +7 -0
  118. package/types/types/MEnumType.d.ts +2 -0
  119. package/types/types/MExperienceType.d.ts +5 -0
  120. package/types/types/MFloatType.d.ts +2 -0
  121. package/types/types/MGB2260Type.d.ts +9 -0
  122. package/types/types/MIntDiffType.d.ts +2 -0
  123. package/types/types/MIntType.d.ts +2 -0
  124. package/types/types/MKvSetType.d.ts +11 -0
  125. package/types/types/MMatrixType.d.ts +5 -0
  126. package/types/types/MObjectType.d.ts +11 -0
  127. package/types/types/MSetType.d.ts +7 -0
  128. package/types/types/MStringType.d.ts +2 -0
  129. package/types/types/MTelType.d.ts +4 -0
  130. package/types/types/MType.d.ts +46 -0
  131. package/types/types/MVLPairType.d.ts +5 -0
  132. package/types/ui/BaseViewer.d.ts +45 -0
  133. package/types/ui/editor/basic/ACascadePicker.d.ts +11 -0
  134. package/types/ui/editor/basic/ACheckBox.d.ts +17 -0
  135. package/types/ui/editor/basic/ADatetimePicker.d.ts +15 -0
  136. package/types/ui/editor/basic/AGB2260.d.ts +10 -0
  137. package/types/ui/editor/basic/AInputBox.d.ts +8 -0
  138. package/types/ui/editor/basic/AIntBox.d.ts +9 -0
  139. package/types/ui/editor/basic/AKvSet.d.ts +19 -0
  140. package/types/ui/editor/basic/ARadio.d.ts +14 -0
  141. package/types/ui/editor/basic/ARangePicker.d.ts +30 -0
  142. package/types/ui/editor/basic/ARate.d.ts +13 -0
  143. package/types/ui/editor/basic/ARemoteSelector.d.ts +15 -0
  144. package/types/ui/editor/basic/ASelector.d.ts +14 -0
  145. package/types/ui/editor/basic/ASetSelector.d.ts +10 -0
  146. package/types/ui/editor/basic/ASpecInputBox.d.ts +9 -0
  147. package/types/ui/editor/basic/ATreeSelect.d.ts +18 -0
  148. package/types/ui/editor/basic/AUpload.d.ts +33 -0
  149. package/types/ui/editor/basic/NPS.d.ts +13 -0
  150. package/types/ui/editor/complex/AArray.d.ts +11 -0
  151. package/types/ui/editor/complex/AArrayGrid.d.ts +13 -0
  152. package/types/ui/editor/complex/ACnAddress.d.ts +10 -0
  153. package/types/ui/editor/complex/ADialogForm.d.ts +11 -0
  154. package/types/ui/editor/complex/AExperience.d.ts +16 -0
  155. package/types/ui/editor/complex/AForm.d.ts +46 -0
  156. package/types/ui/editor/complex/AIntDiff.d.ts +14 -0
  157. package/types/ui/editor/complex/AMatrix.d.ts +48 -0
  158. package/types/ui/editor/complex/ATable.d.ts +9 -0
  159. package/types/ui/editor/complex/JsonEditor.d.ts +9 -0
  160. package/types/ui/readable/A.d.ts +5 -0
  161. package/types/ui/readable/ArrayViewer.d.ts +5 -0
  162. package/types/ui/readable/DecorationViewer.d.ts +3 -0
  163. package/types/ui/readable/DivViewer.d.ts +5 -0
  164. package/types/ui/widget/Collapsible.d.ts +46 -0
  165. package/types/ui/widget/Segment.d.ts +18 -0
  166. package/types/ui/widget/SegmentEditSwitch.d.ts +20 -0
  167. package/types/ui/widget/SelectBox.d.ts +13 -0
  168. 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,9 @@
1
+ .MEditor {
2
+ .kvSet_v {
3
+ display: inline
4
+ }
5
+ .kvSet_h {
6
+ display: inline-block;
7
+ white-space: nowrap;
8
+ }
9
+ }
@@ -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
+ }