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,86 @@
1
+ import React from "react";
2
+ import { Radio } from "antd";
3
+ import _ from "lodash";
4
+ import { MFieldViewer } from "../../../framework/MFieldViewer";
5
+ import { MUtil } from "../../../framework/MUtil";
6
+ import { BaseViewer } from '../../BaseViewer';
7
+ import { MEnumType } from "../../../types/MEnumType";
8
+ import { assembly } from "../../../framework/Assembly";
9
+
10
+ // "其他(请填写)"这样的开放选项Radio的value
11
+ const OPEN_ENUM_RADIO_VALUE = -1;
12
+
13
+ /**
14
+ * 单选框,用于enum
15
+ * 支持开放选项。
16
+ * 定义示例:
17
+ * {label:"1.1 您的性别是", name:"gendar", type:"enum", option: [{label:"男", value:"M"},{label:"女", value:"F"}] },
18
+ * {label:"1.1 您的性别是", name:"gendar", type:"enum", option:"男 女"},
19
+ */
20
+ export class ARadio extends BaseViewer {
21
+ /** 开放输入框的值 */
22
+ _inputBoxValue: string = "";
23
+
24
+ element(ctx) {
25
+ const value = super.getValue();
26
+ const option = MUtil.option(this.props.schema);
27
+ const style = (this.props.schema.layoutHint ?? "v") === "v" ? { display: "block" } : undefined;
28
+
29
+ let initIndex = undefined;
30
+ const options = option.map((m: any, index) => {
31
+ const isShow = MUtil.isShow(this.props.database, ctx.rootProps.schema?.objectFields, m.showIf)
32
+ if (!isShow) return null;
33
+ if (value === m.value) {
34
+ initIndex = index;
35
+ }
36
+ return <Radio disabled={this.props.disable} key={index} value={index} style={style}>{m.label ?? m.value}</Radio>;
37
+ });
38
+ if (initIndex === undefined) {
39
+ this._inputBoxValue = value;
40
+ if (!_.isNil(value)) {
41
+ initIndex = OPEN_ENUM_RADIO_VALUE;
42
+ }
43
+ }
44
+
45
+ if (this.props.schema.openOption) {
46
+ const editor = <MFieldViewer morph={this.props.morph} schema={this.props.schema.openOption} database={this} path="_inputBoxValue"
47
+ afterChange={(path: string, str: any, final: boolean) => {
48
+ const matchEnum = option.find(e => e.value === str);
49
+ if (matchEnum) { // 不能让用户输入了某个候选值
50
+ this._inputBoxValue = "";
51
+ super.changeValueEx(str, true, final);
52
+ } else {
53
+ this._inputBoxValue = str;
54
+ super.changeValueEx(this._inputBoxValue, false, final);
55
+ }
56
+ }}
57
+ parent={this.props.schema} forceValid={false} disable={initIndex !== OPEN_ENUM_RADIO_VALUE}
58
+ style={{ width: "inherit" }} />;
59
+
60
+ options.push(<Radio disabled={this.props.disable} key={"_open_"} value={OPEN_ENUM_RADIO_VALUE}>
61
+ <span style={{ marginRight: "10px" }}>{this.props.schema.openOption.label ?? "其他"}</span>
62
+ {editor}
63
+ </Radio>);
64
+ }
65
+
66
+ const p = this.props.schema.props ?? {};
67
+ return <Radio.Group
68
+ key={this.state.ctrlVersion}
69
+ defaultValue={initIndex}
70
+ onChange={(vv) => {
71
+ let v = vv.target.value;
72
+ if (v !== OPEN_ENUM_RADIO_VALUE) {
73
+ super.changeValue(option[v].value);
74
+ } else {
75
+ if (!this._inputBoxValue) {
76
+ this._inputBoxValue = "";
77
+ }
78
+ super.changeValue(this._inputBoxValue);
79
+ }
80
+ }}
81
+ {...p}
82
+ >
83
+ {options}
84
+ </Radio.Group>
85
+ }
86
+ }
@@ -0,0 +1,129 @@
1
+ import React, { Component, RefObject } from "react";
2
+ import { DatePicker } from "antd";
3
+ import zhCN from 'antd/lib/date-picker/locale/zh_CN';
4
+ import moment from "moment";
5
+ import { Button, Calendar } from "antd-mobile";
6
+ import ReactDOM from "react-dom";
7
+ import { RangePickerProps } from "antd/lib/date-picker";
8
+ import _ from "lodash";
9
+ import { Viewer, ViewerState } from '../../BaseViewer';
10
+ import { MUtil } from '../../../framework/MUtil';
11
+ import { MProp } from "../../../framework/Schema";
12
+ import { MDateRangeType } from '../../../types/MDateRangeType';
13
+ import { assembly } from '../../../framework/Assembly';
14
+
15
+ export type ARangePickerData = [
16
+ // 开始时间
17
+ string | null | undefined,
18
+ // 结束时间
19
+ string | null | undefined,
20
+ // 是否至今,如果true,结束时间是无效的
21
+ boolean | null | undefined
22
+ ];
23
+
24
+ type AntData = [moment.Moment | null, moment.Moment | null];
25
+
26
+ interface State extends ViewerState {
27
+ mobileDlg: boolean;
28
+ }
29
+
30
+ export class ARangePicker extends Viewer<State> {
31
+ _pickerRef: RefObject<Component<RangePickerProps, any, any>> = React.createRef();
32
+ _onCalendarChangeValue?: AntData | null;
33
+
34
+ constructor(p: MProp) {
35
+ super(p);
36
+ this.state = { ctrlVersion: 1, noValidate: false, mobileDlg: false };
37
+ }
38
+
39
+ componentDidUpdate() {
40
+ this._patchTillnow();
41
+ }
42
+
43
+ componentDidMount() {
44
+ this._patchTillnow();
45
+ }
46
+
47
+ _patchTillnow() {
48
+ const v = super.getValue();
49
+ if (_.get(v, "[2]")) { // tillnow
50
+ const dom = ReactDOM.findDOMNode(this._pickerRef.current);
51
+ if (dom) {
52
+ // @ts-ignore
53
+ let r = dom.querySelector(":nth-child(3)");
54
+ r.innerHTML = "<input readonly disabled size='12' autocomplete='off' value='至今' style='color: black'>";
55
+ }
56
+ }
57
+ }
58
+
59
+ /**
60
+ * RangePicker的数据转换成json上的数据类型
61
+ * @param r
62
+ */
63
+ _rangePicker2Data(v: AntData | null | undefined, tillNow: boolean): ARangePickerData | undefined {
64
+ if (!v) {
65
+ return undefined;
66
+ }
67
+ const dataFormat = this.props.schema.dataFormat ?? "x";
68
+ return [v[0]?.format(dataFormat), v[1]?.format(dataFormat), tillNow];
69
+ }
70
+
71
+ /**
72
+ * json上的数据转换成RangePicker的数据
73
+ * @param d
74
+ */
75
+ _data2rangePicker(d: ARangePickerData): AntData {
76
+ const dataFormat = this.props.schema.dataFormat ?? "x";
77
+ return [d[0] ? moment(d[0], dataFormat) : null, d[1] ? moment(d[1], dataFormat) : null];
78
+ }
79
+
80
+ element() {
81
+ const p = this.props.schema.props ?? {};
82
+ let rangePickerData = this._data2rangePicker(this.getValue() ?? []);
83
+ if (MUtil.phoneLike()) {
84
+ let show = MDateRangeType.toReadableN(assembly, this.props.schema, super.getValue());
85
+
86
+ return <>
87
+ <div className="backfill" onClick={() => this.setState({ mobileDlg: true })}> {show ?? '请点击选择'} </div>
88
+ <Calendar
89
+ visible={this.state.mobileDlg}
90
+ pickTime={this.props.schema.dateRange?.showTime}
91
+ minDate={this.props.schema.min ? new Date(this.props.schema.min) : undefined}
92
+ maxDate={this.props.schema.min ? new Date(this.props.schema.max) : undefined}
93
+ onCancel={() => this.setState({ mobileDlg: false })}
94
+ onConfirm={(start, end) => {
95
+ super.changeValueEx(this._rangePicker2Data([moment(start), moment(end)], false), true, true)
96
+ this.setState({ mobileDlg: false })
97
+ }}
98
+ {...p}
99
+ />
100
+ </>
101
+ } else {
102
+ // 构造元素
103
+ return <DatePicker.RangePicker
104
+ ref={this._pickerRef}
105
+ showTime={this.props.schema.dateRange?.showTime}
106
+ key={this.state.ctrlVersion}
107
+ renderExtraFooter={this.props.schema.dateRange?.hideTillNow || this.props.schema.dateRange?.showTime // TODO 显示时间时,“至今”无法支持
108
+ ? undefined
109
+ : (mode) => <div style={{ textAlign: "right" }} {...p}>
110
+ <Button
111
+ size="small" style={{ width: "100px", display: "inline-block", marginTop: "5px" }}
112
+ onClick={() => {
113
+ super.changeValueEx(this._rangePicker2Data(this._onCalendarChangeValue, true), true, true);
114
+ }}>至今</Button>
115
+ </div>
116
+ }
117
+ bordered={this.props.hideBorder ? false : true}
118
+ style={{ minWidth: "240px" }}
119
+ locale={zhCN}
120
+ defaultValue={rangePickerData}
121
+ onCalendarChange={(d) => {
122
+ this._onCalendarChangeValue = d;
123
+ }}
124
+ onChange={(vv) => {
125
+ super.changeValueEx(this._rangePicker2Data(vv, false), true, true)
126
+ }} />;
127
+ }
128
+ }
129
+ }
@@ -0,0 +1,8 @@
1
+ .ant-rate {
2
+ display: flex !important;
3
+ width : 100%;
4
+
5
+ .ant-rate-star {
6
+ flex: 1
7
+ }
8
+ }
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import _ from "lodash";
3
+ import { BaseViewer } from "../../BaseViewer";
4
+ import { Rate } from 'antd';
5
+ import './ARate.less';
6
+ import { MProp } from "../../../framework/Schema";
7
+
8
+ /**
9
+ * antd 的评分组件 https://ant.design/components/rate-cn/
10
+ * { editor: 'ARate', name: 'score', label: "评分", required: true, props: {count: 8} }
11
+ */
12
+ export class ARate extends BaseViewer {
13
+ value: string;
14
+
15
+ constructor(p:MProp){
16
+ super(p);
17
+ this.value = super.getValue() == 0 ? null : super.getValue();
18
+ }
19
+ element() {
20
+ const p = this.props.schema.props ?? {};
21
+ const props = {
22
+ count: this.props.schema.max,
23
+ defaultValue: this.value,
24
+ onChange: (value, label, extra)=>{
25
+ if (value == 0) value = null
26
+ if (p.onChange) p.onChange(value, label, extra)
27
+ super.changeValue(value);
28
+ },
29
+ onBlur: () =>{
30
+ if (p.onBlur) p.onBlur()
31
+ super.changeValue(super.getValue())
32
+ },
33
+ ...p,
34
+ }
35
+ return <Rate {...props} />
36
+ }
37
+ }
@@ -0,0 +1,116 @@
1
+
2
+ import React from "react";
3
+ import { Select, Spin } from 'antd';
4
+ import debounce from 'lodash/debounce';
5
+ import { Viewer, ViewerState } from '../../BaseViewer';
6
+ import { Ajax } from '../../../framework/Ajax';
7
+ import _ from "lodash";
8
+ import { MUtil } from '../../../framework/MUtil';
9
+ import { MFieldSchema } from '../../../framework/Schema';
10
+
11
+ interface State extends ViewerState {
12
+ candidate: any[],
13
+ fetching: boolean,
14
+ q: string;
15
+ }
16
+
17
+ // 这个Viewer可用的数据类型
18
+ const VALID_TYPES = {
19
+ "vl":true,
20
+ "array":true,
21
+ "string":true // 仅保存value
22
+ };
23
+
24
+ export function labelExpr(d: any, remote: MFieldSchema["remote"]){
25
+ let script = "const {" + _.keys(d).join(',') + "} = d; return " + remote.labelExpr;
26
+ return new Function("d", "_", script)(d, _);
27
+ }
28
+
29
+ export class ARemoteSelector extends Viewer<State> {
30
+ fetchCandidate: (key:string)=>void;
31
+
32
+ constructor(props) {
33
+ super(props);
34
+ this.state = {candidate: undefined, fetching: false, q:""};
35
+ this.fetchCandidate = debounce(q => {
36
+ this.setState({ fetching: true });
37
+ Ajax.get(this.props.schema.remote.url.replace("${q}", q))
38
+ .then(
39
+ d => {
40
+ _.assign(this.props.schema, {
41
+ _options: d
42
+ })
43
+ this.setState({ candidate: MUtil.get(d, this.props.schema.remote.dataPath), fetching: false })
44
+ }
45
+ );
46
+ }, 500);
47
+ }
48
+
49
+ element() {
50
+ const type = this.props.schema.type;
51
+ if(!VALID_TYPES[type]){
52
+ return MUtil.error("只适用类型" + Object.keys(VALID_TYPES).join(","), this.props.schema);
53
+ }
54
+
55
+ let defaultValue = super.getValue();
56
+ if(type === "string"){
57
+ defaultValue = {value: defaultValue, label: defaultValue};
58
+ }
59
+
60
+ let mode = undefined;
61
+ if(type === "array") {
62
+ if(!_.isArray(defaultValue)){ // 数据不对
63
+ defaultValue = []; // 干掉
64
+ }
65
+ mode = "multiple"
66
+ } else {
67
+ if(_.isNil(defaultValue?.value)){
68
+ defaultValue = undefined;
69
+ }
70
+ }
71
+
72
+ const p = this.props.schema.props ?? {};
73
+ return <Select
74
+ key={this.props.path}
75
+ showSearch
76
+ mode={mode}
77
+ // mode={"multiple"}
78
+ labelInValue
79
+ defaultValue={defaultValue}
80
+ placeholder={this.props.schema.placeholder}
81
+ notFoundContent={this.state.fetching ? <Spin size="small" /> : null}
82
+ filterOption={false}
83
+ onSearch={this.fetchCandidate}
84
+ style={{ width: '100%' }}
85
+ onFocus={()=>{
86
+ if(!this.state.candidate) {
87
+ this.fetchCandidate("");
88
+ }
89
+ }}
90
+ onChange={(v: any) => {
91
+ switch(type){
92
+ case "vl":
93
+ if (v) super.changeValue({value:v.value, label:v.label});
94
+ else super.changeValue(null);
95
+ break;
96
+ case "array":
97
+ if (v) super.changeValue(v.map(i=>({value:i.value, label:i.label })));
98
+ else super.changeValue(null);
99
+ break;
100
+ case "string":
101
+ if (v) super.changeValue(v.value);
102
+ else super.changeValue(null);
103
+ break;
104
+ }
105
+ }}
106
+ {...p}
107
+ >
108
+ {
109
+ this.state.candidate?.map(d => {
110
+ const v = MUtil.get(d, this.props.schema.remote.valuePath);
111
+ return <Select.Option key={v} value={v}>{labelExpr(d, this.props.schema.remote)}</Select.Option>
112
+ })
113
+ }
114
+ </Select>
115
+ }
116
+ }
@@ -0,0 +1,88 @@
1
+ import React from "react";
2
+ import { PlusOutlined } from "@ant-design/icons";
3
+ import { Button, Divider } from "antd";
4
+ import Select from "antd/lib/select";
5
+ import { MUtil } from "../../../framework/MUtil";
6
+ import { MEnumField, MProp } from '../../../framework/Schema';
7
+ import { BaseViewer } from '../../BaseViewer';
8
+ import { SelectBox } from "../../widget/SelectBox";
9
+ import _ from "lodash";
10
+ import { MFieldViewer } from '../../../framework/MFieldViewer';
11
+ import { MEnumType } from "../../../types/MEnumType";
12
+ import { assembly } from "../../../framework/Assembly";
13
+
14
+ /**
15
+ * 下拉选择框
16
+ * 定义示例: {label:"1.1 您的性别是", name:"gendar", type:"enum", typeArg: [{label:"男", value:"M"},{label:"女", value:"F"}] },
17
+ */
18
+ export class ASelector extends BaseViewer {
19
+ /** 开放输入框的值 */
20
+ _inputBoxValue: string = "";
21
+ _enums: MEnumField[];
22
+
23
+ constructor(p: MProp) {
24
+ super(p);
25
+ this._enums = _.cloneDeep(MUtil.option(this.props.schema));
26
+ }
27
+
28
+ element() {
29
+ const value =super.getValue();
30
+
31
+ const p = this.props.schema.props ?? {};
32
+ if (MUtil.phoneLike()) {
33
+ if (this.props.schema.openOption) {
34
+ return MUtil.error("手机上的ASelector还不支持openOption");
35
+ }
36
+ return <SelectBox
37
+ key={this.props.path}
38
+ data={value}
39
+ // @ts-ignore
40
+ options={this._enums.map(e => { return { label: e.label ?? e.value?.toString(), value: e.value } })}
41
+ {...p}
42
+ onChange={(newValue?: string) => { super.changeValue(newValue) }} />
43
+ } else {
44
+ let initIndex = undefined;
45
+ const options = this._enums.map((m, index) => {
46
+ if (value === m.value) {
47
+ initIndex = index;
48
+ }
49
+ return <Select.Option key={index} value={index}>{m.label ?? m.value}</Select.Option>
50
+ });
51
+ return <Select
52
+ key={this.props.path}
53
+ defaultValue={initIndex}
54
+ placeholder={super.getPlaceholder()}
55
+ bordered={this.props.hideBorder ? false : true}
56
+ //style={{minWidth: width + 20}}
57
+ dropdownRender={menu => {
58
+ return this.props.schema.openOption
59
+ ? <>
60
+ {menu}
61
+ <Divider key="分割线" style={{ margin: '4px 0' }} />
62
+ <div key="开放选择" style={{ display: 'flex', flexWrap: 'nowrap', padding: 8 }}>
63
+ <MFieldViewer morph={this.props.morph} schema={this.props.schema.openOption} database={this} path="_inputBoxValue" parent={this.props.schema} forceValid={false} style={{ width: "inherit" }} />
64
+ <Button shape="circle" icon={<PlusOutlined />} onClick={() => {
65
+ let matchEnum = this._enums.findIndex(e => e.value === this._inputBoxValue);
66
+ if (matchEnum < 0) {
67
+ matchEnum = this._enums.findIndex(e => e.label === this._inputBoxValue);
68
+ }
69
+ if (matchEnum >= 0) { // 不能让用户输入了某个候选值
70
+ super.changeValue(this._enums[matchEnum].value);
71
+ } else {
72
+ this._enums.unshift({ value: this._inputBoxValue, label: this._inputBoxValue });
73
+ this.setState({});
74
+ }
75
+ }} />
76
+ </div>
77
+ </>
78
+ : menu
79
+ }}
80
+ style={{ width: "100%" }}
81
+ onChange={(vv: any) => super.changeValue(this._enums[vv].value)}
82
+ {...p}
83
+ >
84
+ {options}
85
+ </Select>;
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,65 @@
1
+ import React from "react";
2
+ import { Select } from "antd";
3
+ import { MUtil } from "../../../framework/MUtil";
4
+ import { BaseViewer } from "../../BaseViewer";
5
+ import _ from "lodash";
6
+ import { MSetType } from '../../../types/MSetType';
7
+ import { assembly } from '../../../framework/Assembly';
8
+
9
+ /**
10
+ * 下拉框多选
11
+ * 示例:{label:"1.13 除爱人/对象之外,目前和您一起生活的家庭成员包括(多选):",name:"familyAccompany",type:"set", editor:"ASetSelector", option: "父亲 母亲 孩子 爱人/对象的父亲 爱人/对象的母亲 兄弟姐妹"},
12
+ * 值:["孩子", "父亲"]
13
+ */
14
+ export class ASetSelector extends BaseViewer {
15
+ element() {
16
+ if(this.props.schema.openOption){
17
+ return MUtil.error("尚不支持openOption", this.props.schema);
18
+ }
19
+ let initValues = super.getValue();
20
+
21
+ // 给字段定义加上序号
22
+ const option:any[] = MUtil.option(this.props.schema);
23
+ option.forEach((e,index)=> e.index =index)
24
+
25
+ // 把value数组转换成序号数组
26
+ const value2Fields = _.keyBy(option, "value");
27
+ const initIndexes = initValues?.map(v => value2Fields[v].index);
28
+
29
+ const p = this.props.schema.props ?? {};
30
+ return <Select
31
+ key={this.props.path + "/" + this.state.ctrlVersion}
32
+ mode="multiple"
33
+ placeholder={this.props.schema.placeholder}
34
+ optionFilterProp="children"
35
+ style={this.props.style}
36
+ defaultValue={initIndexes}
37
+ onChange={(newIndexes: any)=>{
38
+ let add = []; // 新加进去的
39
+ let baseValues = [] // 原来就有的
40
+ newIndexes.forEach(idx => {
41
+ const v = option[idx].value;
42
+ if(initValues?.indexOf(v) >= 0){
43
+ baseValues.push(v);
44
+ } else {
45
+ add.push(v);
46
+ }
47
+ });
48
+
49
+ if(add.length > 0){
50
+ add.forEach(newOne => {
51
+ baseValues = MSetType.change(true, newOne, baseValues, this.props.schema);
52
+ });
53
+ }
54
+ super.changeValueEx(baseValues, newIndexes?.length != baseValues.length, true);
55
+ }}
56
+ {...p}
57
+ >
58
+ {option.map((item,index) => (
59
+ <Select.Option key={index} value={index}>
60
+ {item.label ?? item.value}
61
+ </Select.Option>
62
+ ))}
63
+ </Select>;
64
+ }
65
+ }
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import { Input } from "antd";
3
+ import { BaseViewer } from '../../BaseViewer';
4
+
5
+ /**
6
+ * 手机号/邮箱等输入框
7
+ * cnPhone/tel/email
8
+ */
9
+ export class ASpecInputBox extends BaseViewer {
10
+ element() {
11
+ const p = this.props.schema.props ?? {};
12
+ return <Input
13
+ {...super.antProp()}
14
+ defaultValue={super.getValue()}
15
+ onBlur={() => this.changeValueEx(super.getValue(), false, true)}
16
+ onChange={(v) => this.changeValueEx(v.target.value, false, false)}
17
+ {...p}
18
+ />;
19
+ }
20
+ }
@@ -0,0 +1,41 @@
1
+ import React from "react";
2
+ import _ from "lodash";
3
+ import { BaseViewer } from "../../BaseViewer";
4
+ import { TreeSelect } from 'antd';
5
+
6
+ /**
7
+ * antd 的树型选择控件 https://ant.design/components/tree-select-cn/
8
+ * {
9
+ * "type": "array", arrayMember: {type: 'vl'}, toReadable: 'value.map(i=>i.label).join(",")',
10
+ * "editor": "ATreeSelect", "name": "tree1", "label": "多选树选择", props: {
11
+ * treeData: treeData,
12
+ * labelInValue: true,
13
+ * multiple: true
14
+ * }
15
+ * }
16
+ */
17
+ export class ATreeSelect extends BaseViewer {
18
+ value: string;
19
+
20
+ constructor(p){
21
+ super(p);
22
+ this.value = super.getValue();
23
+ }
24
+
25
+ element() {
26
+ const p = this.props.schema.props ?? {};
27
+ const props = {
28
+ defaultValue: this.value,
29
+ onChange: (value, label, extra) => {
30
+ if (p.onChange) p.onChange(value, label, extra)
31
+ super.changeValue(value);
32
+ },
33
+ onBlur: () => {
34
+ if (p.onBlur) p.onBlur()
35
+ super.changeValue(super.getValue())
36
+ },
37
+ ...p,
38
+ }
39
+ return <TreeSelect style={{ width: "100%" }} {...props} />
40
+ }
41
+ }