309 | {isNeedConditionOption(currentFormat) && (
310 |
314 |
315 |
321 | 条件字段
322 |
323 |
324 |
325 |
329 | {
335 | this.curConditionPropChange(checked, curKeyRoute);
336 | }}
337 | />
338 |
339 |
340 |
341 | )}
342 | {isNeedReadOnlyOption(currentFormat) && (
343 |
347 |
348 |
352 | 是否只读
353 |
354 |
355 |
356 |
357 | {
363 | this.handleValueChange('readOnly', checked);
364 | }}
365 | />
366 |
367 |
368 |
369 | )}
370 | {isNeedIsRequiredOption(currentFormat) && (
371 |
375 |
376 |
382 | 是否必填项
383 |
384 |
385 |
386 |
387 | {
393 | this.handleValueChange('isRequired', checked);
394 | }}
395 | />
396 |
397 |
398 |
399 | )}
400 | {isNeedDefaultOption(currentFormat) && (
401 |
402 |
403 |
404 | 默认值
405 |
406 |
407 |
408 |
409 | {this.renderDefaultContent(
410 | currentFormat,
411 | targetJsonSchema,
412 | nodeKey,
413 | )}
414 |
415 |
416 |
417 | )}
418 | {isNeedDescriptionOption(currentFormat) && (
419 |
423 |
424 |
428 | 字段描述
429 |
430 |
431 |
432 |
433 | {
438 | const { value } = event.target;
439 | this.handleValueChange('description', value);
440 | }}
441 | onBlur={(event) => {
442 | const { value } = event.target;
443 | this.handleValueChange('description', value);
444 | }}
445 | />
446 |
447 |
448 |
449 | )}
450 | {isNeedPlaceholderOption(currentFormat) && (
451 |
455 |
456 |
460 | 输入提示
461 |
462 |
463 |
464 |
465 | {
470 | const { value } = event.target;
471 | this.handleValueChange('placeholder', value);
472 | }}
473 | onBlur={(event) => {
474 | const { value } = event.target;
475 | this.handleValueChange('placeholder', value);
476 | }}
477 | />
478 |
479 |
480 |
481 | )}
482 | {isNeedMinMaxOption(currentFormat) && (
483 |
487 |
488 |
492 | 最小值
493 |
494 |
495 |
496 |
497 | {
501 | const { value } = event.target;
502 | this.handleValueChange('minimum', value);
503 | }}
504 | onBlur={(event) => {
505 | const { value } = event.target;
506 | this.handleValueChange('minimum', value);
507 | }}
508 | />
509 |
510 |
511 |
512 | )}
513 | {isNeedMinMaxOption(currentFormat) && (
514 |
518 |
519 |
523 | 最大值
524 |
525 |
526 |
527 |
528 | {
532 | const { value } = event.target;
533 | this.handleValueChange('maximum', value);
534 | }}
535 | onBlur={(event) => {
536 | const { value } = event.target;
537 | this.handleValueChange('maximum', value);
538 | }}
539 | />
540 |
541 |
542 |
543 | )}
544 | {isNeedMinMaxChildOption(currentFormat) && (
545 |
549 |
550 |
556 | 最少子项数
557 |
558 |
559 |
560 |
561 | {
565 | this.handleValueChange('minimum-child', newVal);
566 | }}
567 | />
568 |
569 |
570 |
571 | )}
572 | {isNeedMinMaxChildOption(currentFormat) && (
573 |
577 |
578 |
584 | 最多子项数
585 |
586 |
587 |
588 |
589 | {
593 | this.handleValueChange('maximum-child', newVal);
594 | }}
595 | />
596 |
597 |
598 |
599 | )}
600 | {!targetJsonSchema.hiddenRule && (
601 |
602 |
603 | 隐藏规则
604 |
605 |
606 |
613 |
614 |
615 | )}
616 | {targetJsonSchema.hiddenRule && (
617 |
618 |
619 |
隐藏规则:
620 |
621 |
624 |
625 |
626 |
627 |
隐藏条件:
628 |
629 |
654 |
655 |
等于
656 |
657 |
663 |
664 |
665 |
666 | )}
667 |
668 | );
669 | }
670 | }
671 |
672 | export default inject((stores) => ({
673 | getSchemaByIndexRoute: stores.jsonSchemaStore.getSchemaByIndexRoute,
674 | editSchemaData: stores.jsonSchemaStore.editSchemaData,
675 | checkConditionProp: stores.jsonSchemaStore.checkConditionProp,
676 | addConditionProp: stores.jsonSchemaStore.addConditionProp,
677 | indexRoute2keyRoute: stores.jsonSchemaStore.indexRoute2keyRoute,
678 | removeConditionProp: stores.jsonSchemaStore.removeConditionProp,
679 | deleteSchemaProp: stores.jsonSchemaStore.deleteSchemaProp,
680 | jsonSchema: stores.jsonSchemaStore.jsonSchema,
681 | }))(observer(AdvanceConfig));
682 |
--------------------------------------------------------------------------------
/src/components/AdvanceConfig/index.scss:
--------------------------------------------------------------------------------
1 | @charset "utf-8";
2 |
3 | .advance-config-model {
4 | position: relative;
5 | padding: 8px 10px;
6 | text-align: center;
7 |
8 | // 移动端的展示样式
9 | .small-screen-element-warp,
10 | .mobile-screen-element-warp {
11 | position: relative;
12 | margin-bottom: 12px;
13 | line-height: 38px;
14 | box-sizing: border-box;
15 | min-width: 280px;
16 |
17 | .element-title {
18 | display: block;
19 | word-break: keep-all;
20 | margin-right: 12px;
21 | text-align: left;
22 | white-space: nowrap;
23 | overflow: hidden;
24 | text-overflow: ellipsis;
25 | }
26 |
27 | .content-item {
28 | position: relative;
29 | text-align: left;
30 |
31 | > .small-screen-element-warp,
32 | > .mobile-screen-element-warp {
33 | min-width: 230px;
34 | }
35 |
36 | .color-item-form {
37 | width: 60px;
38 | }
39 |
40 | .add-rule-condition-btn {
41 | margin: 3px 0;
42 | }
43 | }
44 | }
45 |
46 | // 默认为宽屏的展示样式
47 | .wide-screen-element-warp {
48 | position: relative;
49 | line-height: 30px;
50 | box-sizing: border-box;
51 | min-width: 350px;
52 | margin-bottom: 6px;
53 | display: inline-flex;
54 | justify-content: flex-start;
55 | align-items: flex-start;
56 |
57 | .element-title {
58 | flex: 0 1 100px;
59 | word-break: keep-all;
60 | max-width: 100px;
61 | margin-right: 12px;
62 | padding-left: 12px;
63 | text-align: right;
64 | white-space: nowrap;
65 | overflow: hidden;
66 | text-overflow: ellipsis;
67 | }
68 |
69 | .content-item {
70 | flex: 1 1 200px;
71 | text-align: left;
72 |
73 | .color-item-form {
74 | width: 60px;
75 | }
76 |
77 | .add-rule-condition-btn {
78 | margin: 3px 0;
79 | }
80 | }
81 | }
82 |
83 | // CodeArea类型组件样式
84 | .code-area-item {
85 | min-width: 230px;
86 | max-width: 600px;
87 | }
88 | // 隐藏规则
89 | .hidden-rule-box {
90 | margin: 10px auto 0 auto;
91 | width: 450px;
92 | padding: 8px 15px;
93 | box-sizing: border-box;
94 | border-top: solid 1px #ccc;
95 |
96 | .rule-title {
97 | line-height: 30px;
98 | display: flex;
99 | justify-content: space-between;
100 | }
101 |
102 | .rule-condition-box {
103 | position: relative;
104 | background-color: #f8f8f8;
105 | padding: 8px 10px;
106 | min-height: 30px;
107 | line-height: 30px;
108 | box-sizing: border-box;
109 | display: flex;
110 | align-items: center;
111 |
112 | .condition-title {
113 | flex: 0 0 70px;
114 | text-align: center;
115 | }
116 | .condition-equal {
117 | flex: 0 0 40px;
118 | text-align: center;
119 | }
120 | .condition-prop {
121 | flex: 1 1 100px;
122 | text-align: left;
123 | }
124 | .condition-value {
125 | flex: 1 1 100px;
126 | text-align: left;
127 | }
128 | .ant-select-single {
129 | max-width: 145px;
130 | }
131 | }
132 | }
133 |
134 | // CodeArea类型组件格式错误提示相关的样式
135 | .warning-box {
136 | width: 100%;
137 | padding: 8px 0;
138 | color: red;
139 | font-size: 12px;
140 | background-color: rgb(254, 236, 235);
141 | transition-duration: 0.2s;
142 | transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
143 |
144 | display: flex;
145 | flex-direction: row;
146 | justify-content: flex-start;
147 | align-items: center;
148 |
149 | .warning-img {
150 | flex: 0 1 60px;
151 | display: flex;
152 | justify-content: center;
153 | align-items: center;
154 | }
155 |
156 | .warning-text {
157 | flex: 1 1 160px;
158 | display: flex;
159 | justify-content: flex-start;
160 | align-items: center;
161 | }
162 | }
163 |
164 | // 表单元素盒子样式,主要为了让表单元素垂直居中
165 | .form-item-box {
166 | min-height: 30px;
167 | display: flex;
168 | justify-content: stretch;
169 | align-items: center;
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/src/components/ArraySchema/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Tree } from 'antd';
3 | const { TreeNode } = Tree;
4 | import { getCurrentFormat } from '@wibetter/json-utils';
5 | import BaseFormSchema from '$components/BaseFormSchema/index';
6 | import MappingRender from '$components/MappingRender';
7 |
8 | /** 渲染当前字段的表单项(Tree的单项内容) */
9 | const getTreeNodeTitleCont = (params) =>
183 |
188 |
194 |
195 |
200 |
212 |
213 |
218 |
224 |
225 | {!hideOperaBtn && (
226 |
227 | {!readOnly && (
228 |
229 |
233 |
234 | )}
235 |
236 |
240 |
241 |
242 | {/* 自动排序功能 */}
243 | {isBoxElem && (
244 |
245 |
249 |
250 | )}
251 |
252 | {!readOnly && (
253 |
254 |
258 |
259 | )}
260 | {!readOnly && (
261 |
262 | {
265 | // 显示高级设置模态框
266 | this.setState({
267 | isShowAdvance: true,
268 | });
269 | }}
270 | />
271 |
272 | )}
273 | {!readOnly && (
274 |
275 |
276 |
277 | )}
278 |
279 | )}
280 | {hideOperaBtn && (
281 |
282 | {isShowAdvanceBtn && (
283 |
284 | {
287 | // 显示高级设置模态框
288 | this.setState({
289 | isShowAdvance: true,
290 | });
291 | }}
292 | />
293 |
294 | )}
295 |
296 |
297 | )}
298 | {isShowAdvance && (
299 |
{
303 | this.setState({
304 | isShowAdvance: false,
305 | });
306 | }}
307 | footer={[
308 | ,
319 | ]}
320 | >
321 |
328 |
329 | )}
330 |
331 | )}
332 | {!targetJsonSchema && (
333 |
23 |
24 |
28 | 条件字段:
29 |
30 |
31 |
32 | {conditionPropKeys.map((conditionKey) => {
33 | const conditionProp = conditionProps[conditionKey];
34 | return (
35 | {
40 | // 移除条件字段
41 | removeConditionProp(conditionProp.keyRoute);
42 | // 将isConditionProp设置为false
43 | cancelConditionProp(
44 | conditionProp.keyRoute,
45 | conditionProp.key,
46 | );
47 | }}
48 | >
49 | {conditionProp.key}({conditionProp.title})
50 |
51 | );
52 | })}
53 |
54 |
55 | );
56 | }
57 | };
58 |
59 | export default inject((stores) => ({
60 | jsonSchema: stores.jsonSchemaStore.jsonSchema,
61 | removeConditionProp: stores.jsonSchemaStore.removeConditionProp,
62 | cancelConditionProp: stores.jsonSchemaStore.cancelConditionProp,
63 | }))(observer(ConditionPropsSchema));
64 |
--------------------------------------------------------------------------------
/src/components/ConditionPropsSchema/index.scss:
--------------------------------------------------------------------------------
1 | @charset "utf-8";
2 |
3 | .condition-props-box {
4 | position: relative;
5 | padding: 8px 10px;
6 | display: flex;
7 |
8 | .title {
9 | flex: 0 0 70px;
10 | }
11 |
12 | .tags-box {
13 | flex: 1 1 100px;
14 |
15 | .ant-tag {
16 | margin-bottom: 5px;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/ConditionValueSchema/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Input, Select, Switch, Radio } from 'antd';
3 | import { inject, observer } from 'mobx-react';
4 | const { Option } = Select;
5 |
6 | /** 用于设置条件规则数值
7 | * 备注:目前仅在高级设置面板中使用
8 | */
9 | const ConditionValueSchema = (props) => {
10 | const { conditionRule, hiddenRuleConditionValueChange, getSchemaByKeyRoute } =
11 | props;
12 | // 获取当前条件字段的枚举值
13 | let curConditionValueItems = {};
14 | if (conditionRule.conditionProp && conditionRule.conditionProp.keyRoute) {
15 | const conditionSchema = getSchemaByKeyRoute(
16 | conditionRule.conditionProp.keyRoute,
17 | );
18 | if (conditionSchema.items) {
19 | curConditionValueItems = conditionSchema.items;
20 | }
21 | }
22 |
23 | if (
24 | conditionRule.conditionProp &&
25 | (conditionRule.conditionProp.format === 'radio' ||
26 | conditionRule.conditionProp.format === 'single-select')
27 | ) {
28 | return (
29 |
80 |
81 |
91 |
92 |
93 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | );
109 | }
110 | }
111 |
112 | export default inject((stores) => ({
113 | editSchemaData: stores.jsonSchemaStore.editSchemaData,
114 | updateSchemaData: stores.jsonSchemaStore.updateSchemaData,
115 | }))(observer(TypeSelectFormSchema));
116 |
--------------------------------------------------------------------------------
/src/components/TypeSelectFormSchema/index.scss:
--------------------------------------------------------------------------------
1 | @charset "utf-8";
2 |
3 | .typeSelect-schema-box {
4 | position: relative;
5 | min-height: 35px;
6 | box-sizing: border-box;
7 | display: flex;
8 | justify-content: center;
9 | align-items: center;
10 |
11 | .key-input-item {
12 | flex: 1 1 200px;
13 | padding-right: 8px;
14 |
15 | .ant-select {
16 | display: block;
17 | }
18 | }
19 |
20 | .type-select-item {
21 | flex: 0 1 120px;
22 | padding-right: 8px;
23 | }
24 |
25 | .title-input-item {
26 | flex: 0 1 200px;
27 | }
28 |
29 | .operate-item {
30 | flex: 0 1 110px;
31 | padding-left: 10px;
32 | display: inline-flex;
33 | justify-content: flex-start;
34 | align-items: center;
35 |
36 | .operate-btn {
37 | flex: 0 0 auto;
38 | width: 15px;
39 | margin-right: 8px;
40 | color: #2395f1;
41 | cursor: pointer !important;
42 | }
43 |
44 | .delete-operate {
45 | color: #ff561b;
46 | }
47 |
48 | .drag-btn {
49 | display: inline-block;
50 | width: 18px;
51 | height: 18px;
52 | color: #8a8a8a;
53 | background-image: url('//storage.jd.local/cdnnpm/jdw-web/img/drag-default.svg');
54 | background-size: contain;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/data/TypeList.js:
--------------------------------------------------------------------------------
1 | // 功能类型可选项
2 | export const FUNCSCHEME_TYPE = [
3 | 'input',
4 | 'boolean',
5 | 'date',
6 | 'date-time',
7 | 'time',
8 | 'url',
9 | 'textarea',
10 | 'text-editor',
11 | 'number',
12 | 'radio',
13 | 'single-select',
14 | 'select',
15 | 'codearea',
16 | 'array',
17 | 'object',
18 | ];
19 | // 样式类型可选项
20 | export const STYLESCHEME_TYPE = [
21 | 'input',
22 | 'boolean',
23 | 'color',
24 | 'url',
25 | 'number',
26 | 'radio',
27 | 'single-select',
28 | 'select',
29 | 'quantity',
30 | 'box-style', // 盒子模型样式:用于设置margin、padding类数值
31 | 'htmlarea',
32 | 'text-editor',
33 | 'array',
34 | 'object',
35 | ];
36 | // 数据类型可选项
37 | export const DATASCHEME_TYPE = [
38 | 'input',
39 | 'number',
40 | 'json',
41 | 'codearea',
42 | 'htmlarea',
43 | 'text-editor',
44 | 'dynamic-data',
45 | 'datasource',
46 | 'event',
47 | 'object',
48 | 'array',
49 | ];
50 | // 对象类型可选项
51 | export const OBJECT_TYPE = [
52 | 'input',
53 | 'boolean',
54 | 'color',
55 | 'date',
56 | 'date-time',
57 | 'time',
58 | 'url',
59 | 'textarea',
60 | 'text-editor',
61 | 'number',
62 | 'radio',
63 | 'single-select',
64 | 'select',
65 | 'object',
66 | 'array',
67 | ];
68 |
69 | // 数组&对象类型可选项(仅用于Array的items子项)
70 | export const ARRAY_OBJECT_TYPE = [
71 | 'input',
72 | 'boolean',
73 | 'color',
74 | 'date',
75 | 'date-time',
76 | 'time',
77 | 'url',
78 | 'textarea',
79 | 'text-editor',
80 | 'number',
81 | 'radio',
82 | 'single-select',
83 | 'select',
84 | 'array',
85 | ];
86 |
87 | // 数组类型可选项
88 | export const ARRAY_TYPE = ['object'];
89 |
90 | // 所有的字段类型
91 | export const ALL_TYPE = [
92 | 'input',
93 | 'boolean',
94 | 'number',
95 | 'color',
96 | 'url',
97 | 'textarea',
98 | 'text-editor',
99 | 'radio',
100 | 'single-select',
101 | 'select',
102 | 'date',
103 | 'date-time',
104 | 'time',
105 | 'quantity',
106 | 'json',
107 | 'codearea',
108 | 'htmlarea',
109 | 'datasource',
110 | 'dynamic-data',
111 | 'event',
112 | 'array',
113 | 'object',
114 | ];
115 | // radio单选类型可选项
116 | export const RADIO_TYPE = ['string'];
117 |
118 | // select多选类型可选项
119 | export const SELECT_TYPE = ['string'];
120 |
121 | // 类型清单
122 | export const TypeList = {
123 | func: FUNCSCHEME_TYPE,
124 | style: STYLESCHEME_TYPE,
125 | data: DATASCHEME_TYPE,
126 | object: OBJECT_TYPE,
127 | array: ARRAY_TYPE,
128 | 'array-object': ARRAY_OBJECT_TYPE,
129 | radio: RADIO_TYPE,
130 | 'single-select': RADIO_TYPE,
131 | select: SELECT_TYPE,
132 | all: ALL_TYPE,
133 | };
134 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |