Showing
10 changed files
with
521 additions
and
195 deletions
1 | 1 | import { ControlOutlined } from '@ant-design/icons'; |
2 | 2 | import { Select, Tooltip } from 'antd'; |
3 | +import cls from 'classnames'; | |
3 | 4 | import { size } from 'lodash-es'; |
4 | -import React, { useState } from 'react'; | |
5 | +import React, { useEffect, useRef, useState } from 'react'; | |
5 | 6 | import { FieldBaseType, type QxBaseConditionField } from '../qx-base-condition'; |
6 | 7 | import { QxBaseIcon } from '../qx-base-icon'; |
7 | 8 | import { QxFieldSetter } from '../qx-field-setter'; |
... | ... | @@ -9,7 +10,6 @@ import type { INode } from '../qx-flow-node-selector'; |
9 | 10 | import { |
10 | 11 | FieldMapType, |
11 | 12 | QxFlowNodeFieldSelector, |
12 | - useNodeFieldDisplay, | |
13 | 13 | } from '../qx-flow-node-selector'; |
14 | 14 | import { QxWidgetIcon } from '../qx-widget-icon'; |
15 | 15 | |
... | ... | @@ -691,9 +691,13 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ |
691 | 691 | fieldGroupType, |
692 | 692 | showAssignment = true, |
693 | 693 | isMixValue, |
694 | + fieldType, | |
694 | 695 | }) => { |
695 | 696 | const valuesObj = value?.valuesObj?.[0] || {}; |
696 | 697 | const [open, setOpen] = useState(false); |
698 | + const fieldSelectorRef = useRef<any>(); | |
699 | + const [inputDisplay, setInputDisplay] = useState(); | |
700 | + const isMount = useRef(false); | |
697 | 701 | |
698 | 702 | const handleChange = (val: any[]) => { |
699 | 703 | onChange?.({ |
... | ... | @@ -738,23 +742,31 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ |
738 | 742 | setOpen(false); |
739 | 743 | }; |
740 | 744 | |
741 | - const baseType = FieldBaseType[field.extract?.fieldType] || field.extract?.fieldType | |
742 | - const limitTypes = fieldLimitTypes[baseType] ? fieldLimitTypes[baseType] : [baseType] | |
745 | + const baseType = FieldBaseType[fieldType] || fieldType; | |
746 | + const limitTypes = fieldLimitTypes[baseType] | |
747 | + ? fieldLimitTypes[baseType] | |
748 | + : [baseType]; | |
743 | 749 | |
744 | - const { genDisplayDom } = useNodeFieldDisplay({ | |
745 | - node: node, | |
746 | - nodes: nodes, | |
747 | - limitTypes, | |
748 | - value: valuesObj?.value, | |
749 | - subset, | |
750 | - }); | |
751 | - | |
752 | - const getName = (values: any[]) => { | |
753 | - return Array.isArray(values) | |
754 | - ? values.map((value) => genDisplayDom(value)) | |
755 | - : []; | |
750 | + const getName = () => { | |
751 | + console.log( | |
752 | + 'getName-1', | |
753 | + fieldSelectorRef.current?.getInputDisplay?.(), | |
754 | + inputDisplay, | |
755 | + ); | |
756 | + return fieldSelectorRef.current?.getInputDisplay?.() || inputDisplay; | |
756 | 757 | }; |
757 | 758 | |
759 | + useEffect(() => { | |
760 | + if (fieldSelectorRef.current && !isMount.current) { | |
761 | + setTimeout(() => { | |
762 | + console.log('getName-2', fieldSelectorRef.current.getInputDisplay?.()); | |
763 | + const display = fieldSelectorRef.current.getInputDisplay?.(); | |
764 | + isMount.current = !!display; | |
765 | + setInputDisplay(fieldSelectorRef.current.getInputDisplay?.()); | |
766 | + }, 10); | |
767 | + } | |
768 | + }); | |
769 | + | |
758 | 770 | const RenderContent = ( |
759 | 771 | <> |
760 | 772 | <QxFieldSetter |
... | ... | @@ -766,7 +778,7 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ |
766 | 778 | isRange={optValTypeCheck.isRangeType(value?.opt)} |
767 | 779 | disabled={optValTypeCheck.isEmptyType(value?.opt)} |
768 | 780 | getName={getName} |
769 | - widget={field.extract?.widget} | |
781 | + widget={field?.extract?.widget} | |
770 | 782 | isMixValue={isMixValue} |
771 | 783 | /> |
772 | 784 | |
... | ... | @@ -804,14 +816,18 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ |
804 | 816 | <div className="qx-base-condition-item__header"> |
805 | 817 | <div className="qx-base-condition-item__header-left"> |
806 | 818 | <span className="qx-base-condition-item__header-icon"> |
807 | - {field.extract?.widget ? ( | |
819 | + {field?.extract?.widget ? ( | |
808 | 820 | <QxWidgetIcon widgetName={field.extract.widget} /> |
809 | 821 | ) : ( |
810 | - `[${FieldMapType[field.extract.fieldType]}]` | |
822 | + `[${FieldMapType[fieldType]}]` | |
811 | 823 | )} |
812 | 824 | </span> |
813 | - <span className="qx-base-condition-item__header-text"> | |
814 | - {field.name} | |
825 | + <span | |
826 | + className={cls('qx-base-condition-item__header-text', { | |
827 | + error: !field, | |
828 | + })} | |
829 | + > | |
830 | + {field?.name || '已删除'} | |
815 | 831 | </span> |
816 | 832 | </div> |
817 | 833 | <div className="qx-base-condition-item__header-right"> |
... | ... | @@ -822,7 +838,7 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ |
822 | 838 | <Tooltip title="删除"> |
823 | 839 | <QxBaseIcon |
824 | 840 | type="qx-icon-delete" |
825 | - onClick={() => remove?.(field)} | |
841 | + onClick={() => remove?.(value)} | |
826 | 842 | /> |
827 | 843 | </Tooltip> |
828 | 844 | </span> |
... | ... | @@ -831,6 +847,7 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ |
831 | 847 | <div className="qx-base-condition-item__content"> |
832 | 848 | {showAssignment ? ( |
833 | 849 | <QxFlowNodeFieldSelector |
850 | + ref={fieldSelectorRef} | |
834 | 851 | mode="variable" |
835 | 852 | node={node!} |
836 | 853 | nodes={nodes!} | ... | ... |
... | ... | @@ -86,12 +86,13 @@ export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => { |
86 | 86 | key={item.code || key} |
87 | 87 | mode={props.mode || 'condition'} |
88 | 88 | {...item} |
89 | - fieldGroupType={getFieldGroupType(item.field.extract)} | |
89 | + fieldGroupType={getFieldGroupType(item.field?.extract || { fieldType: item.type })} | |
90 | 90 | value={Object.assign( |
91 | 91 | {}, |
92 | - getDefaultCondition(item.field), | |
92 | + getDefaultCondition(item.field || props.value?.[key]), | |
93 | 93 | props.value?.[key] || {}, |
94 | 94 | )} |
95 | + fieldType={item?.field?.fieldType || item.type} | |
95 | 96 | nodes={props.nodes} |
96 | 97 | node={props.node} |
97 | 98 | subset={props.subset} | ... | ... |
... | ... | @@ -17,6 +17,138 @@ group: |
17 | 17 | import { QxCondition } from '@qx/common'; |
18 | 18 | import { Form } from 'antd'; |
19 | 19 | |
20 | +const node = { | |
21 | + id: 'dfc29d5b64fa42489a65b3cfaeb999da', | |
22 | + type: 'default_DF_CONDITION', | |
23 | + name: '条件', | |
24 | + iconColor: '#F77234', | |
25 | + data: {}, | |
26 | + children: [], | |
27 | + previousId: 'b0a2c7925a7b45e884fe8f82a0f39e9b', | |
28 | +}; | |
29 | + | |
30 | +const nodes = [ | |
31 | + { | |
32 | + id: '4c4fc5213db149808c57d093b15e6295', | |
33 | + name: '开始', | |
34 | + type: 'default_DF_START', | |
35 | + data: { | |
36 | + nodeVersion: '3.0.0', | |
37 | + data: { | |
38 | + enablePropagation: false, | |
39 | + propagation: 'REQUIRED', | |
40 | + isolation: 'REPEATABLE_READ', | |
41 | + }, | |
42 | + result: [ | |
43 | + { | |
44 | + id: '9911c21704ba4d8da8651185f441f9d3', | |
45 | + code: '5sfuiz', | |
46 | + type: 'OBJECT', | |
47 | + title: '5sfuiz', | |
48 | + qxProps: {}, | |
49 | + pid: '', | |
50 | + description: '', | |
51 | + valueMapping: { mappingValues: [] }, | |
52 | + valuesObj: [], | |
53 | + child: [ | |
54 | + { | |
55 | + id: '022c007b4c304c58850ed592ef5c1774', | |
56 | + type: 'STRING', | |
57 | + pid: '9911c21704ba4d8da8651185f441f9d3', | |
58 | + code: 'gcc8qd', | |
59 | + title: 'gcc8qd', | |
60 | + }, | |
61 | + ], | |
62 | + }, | |
63 | + { | |
64 | + id: '6289083b52474567aba6d3f5fe9eda90', | |
65 | + code: '3coizb', | |
66 | + type: 'FORM', | |
67 | + title: '3coizb', | |
68 | + qxProps: { | |
69 | + appId: 'HQIXKC0dxbuYENalZzP', | |
70 | + formId: 'VX1TdanWSgYrKYn3vT8', | |
71 | + isTree: false, | |
72 | + }, | |
73 | + pid: '', | |
74 | + }, | |
75 | + | |
76 | + { | |
77 | + id: 'deb0705410b24087bf22ccee74e4e7e4', | |
78 | + code: 'tbxkuz', | |
79 | + type: 'FORM', | |
80 | + title: 'input', | |
81 | + qxProps: { | |
82 | + appId: 'k6cY4GqjTaxQTW3XLua', | |
83 | + formId: 'FhkvYvVgpWmijBVEbk2', | |
84 | + isTree: false, | |
85 | + }, | |
86 | + description: '', | |
87 | + valueMapping: { | |
88 | + mappingValues: [], | |
89 | + }, | |
90 | + required: false, | |
91 | + disabled: true, | |
92 | + }, | |
93 | + { | |
94 | + id: '3b1e0f82c6a049dca8a01d83a7a09b35', | |
95 | + code: 'vjo6ta', | |
96 | + type: 'OBJECT', | |
97 | + title: 'vjo6ta', | |
98 | + qxProps: {}, | |
99 | + pid: '', | |
100 | + description: '', | |
101 | + valueMapping: { | |
102 | + mappingValues: [], | |
103 | + }, | |
104 | + valuesObj: [], | |
105 | + child: [ | |
106 | + { | |
107 | + id: 'be3d37ae184144dc88c0d39a644fe2c1', | |
108 | + type: 'STRING', | |
109 | + pid: '3b1e0f82c6a049dca8a01d83a7a09b35', | |
110 | + code: '87b2ww', | |
111 | + title: '87b2ww', | |
112 | + }, | |
113 | + ], | |
114 | + }, | |
115 | + ], | |
116 | + }, | |
117 | + children: [], | |
118 | + }, | |
119 | + { | |
120 | + id: 'b0a2c7925a7b45e884fe8f82a0f39e9b', | |
121 | + name: '分支', | |
122 | + type: 'default_DF_BRANCH', | |
123 | + previousId: '4c4fc5213db149808c57d093b15e6295', | |
124 | + children: [ | |
125 | + { | |
126 | + id: 'dfc29d5b64fa42489a65b3cfaeb999da', | |
127 | + type: 'default_DF_CONDITION', | |
128 | + previousId: 'b0a2c7925a7b45e884fe8f82a0f39e9b', | |
129 | + name: '条件', | |
130 | + data: {}, | |
131 | + children: [], | |
132 | + }, | |
133 | + { | |
134 | + id: '003ca991f70548a3ba8c4f9b8d0daad2', | |
135 | + name: '条件', | |
136 | + type: 'default_DF_CONDITION', | |
137 | + previousId: 'b0a2c7925a7b45e884fe8f82a0f39e9b', | |
138 | + children: [], | |
139 | + }, | |
140 | + ], | |
141 | + }, | |
142 | + { | |
143 | + id: '576f817ce67846318d1132f231128f05', | |
144 | + name: '结束', | |
145 | + previousId: 'b0a2c7925a7b45e884fe8f82a0f39e9b', | |
146 | + type: 'default_DF_END', | |
147 | + data: { nodeVersion: '3.0.0' }, | |
148 | + children: [], | |
149 | + }, | |
150 | +]; | |
151 | + | |
20 | 152 | export default () => { |
21 | 153 | return ( |
22 | 154 | <div> |
... | ... | @@ -28,32 +160,44 @@ export default () => { |
28 | 160 | { |
29 | 161 | type: 'STRING', |
30 | 162 | name: '文本', |
31 | - mappingValues: [], | |
32 | - field: { | |
33 | - code: 'text', | |
34 | - name: '文本', | |
35 | - extract: { widget: 'qxInput', fieldType: 'STRING' }, | |
36 | - }, | |
37 | - }, | |
38 | - { | |
39 | - type: 'STRING', | |
40 | - name: '文本', | |
41 | - mappingValues: [], | |
163 | + code: '${4c4fc5213db149808c57d093b15e6295|022c007b4c304c58850ed592ef5c1774}', | |
164 | + mappingValues: [ | |
165 | + '${4c4fc5213db149808c57d093b15e6295|022c007b4c304c58850ed592ef5c1774}', | |
166 | + ], | |
42 | 167 | field: { |
43 | - code: 'text', | |
44 | - name: '文本', | |
45 | - extract: { widget: 'qxInput', fieldType: 'STRING' }, | |
168 | + id: '022c007b4c304c58850ed592ef5c1774', | |
169 | + type: 'STRING', | |
170 | + pid: '9911c21704ba4d8da8651185f441f9d3', | |
171 | + code: '4c4fc5213db149808c57d093b15e6295|022c007b4c304c58850ed592ef5c1774', | |
172 | + title: 'gcc8qd', | |
173 | + name: '2313123123123', | |
174 | + extract: { | |
175 | + fieldType: 'STRING', | |
176 | + fieldKey: '022c007b4c304c58850ed592ef5c1774', | |
177 | + }, | |
46 | 178 | }, |
179 | + valuesObj: [ | |
180 | + { | |
181 | + value: | |
182 | + '${4c4fc5213db149808c57d093b15e6295|022c007b4c304c58850ed592ef5c1774}', | |
183 | + type: 'FIELD', | |
184 | + }, | |
185 | + ], | |
47 | 186 | }, |
48 | 187 | ], |
49 | 188 | }, |
50 | 189 | }} |
51 | 190 | onValuesChange={(value, values) => { |
52 | - console.log('values', values) | |
191 | + console.log('values', values); | |
53 | 192 | }} |
54 | 193 | > |
55 | 194 | <Form.Item name="condition"> |
56 | - <QxCondition showAssignment={false} /> | |
195 | + <QxCondition | |
196 | + nodes={nodes} | |
197 | + node={node} | |
198 | + showHeader | |
199 | + formId="FhkvYvVgpWmijBVEbk2" | |
200 | + /> | |
57 | 201 | </Form.Item> |
58 | 202 | </Form> |
59 | 203 | </div> | ... | ... |
... | ... | @@ -7,8 +7,11 @@ import { |
7 | 7 | import { QxBaseIcon } from '../qx-base-icon'; |
8 | 8 | import { QxConditionSql, SqlType } from '../qx-condition-sql'; |
9 | 9 | import QxFieldPopover from '../qx-field/src/popover'; |
10 | -import FieldsCheckboxGroup from '../qx-field/src/popover/checkbox'; | |
11 | -import { INode, QxFlowNodeFieldSelector } from '../qx-flow-node-selector'; | |
10 | +import { | |
11 | + FiledType, | |
12 | + INode, | |
13 | + QxFlowNodeFieldSelector, | |
14 | +} from '../qx-flow-node-selector'; | |
12 | 15 | import { request } from '../utils'; |
13 | 16 | |
14 | 17 | import './index.less'; |
... | ... | @@ -32,12 +35,13 @@ export const QxCondition: React.FC<QxConditionProps> = ({ |
32 | 35 | headerLeft, |
33 | 36 | headerRight, |
34 | 37 | formId, |
35 | - multiple, | |
36 | - showHeader = false | |
38 | + showHeader = false, | |
37 | 39 | }) => { |
38 | - const [fields, setFields] = useState([]); | |
40 | + const [fields, setFields] = useState<FiledType[]>([]); | |
41 | + | |
42 | + const fieldSelectorRef = useRef<any>(); | |
39 | 43 | |
40 | - const fieldSelectorRef = useRef(); | |
44 | + const isMount = useRef(false); | |
41 | 45 | |
42 | 46 | const handleChange = (opt: Partial<QxConditionValueType>) => { |
43 | 47 | onChange?.(Object.assign({}, value, opt, { enabled })); |
... | ... | @@ -53,18 +57,32 @@ export const QxCondition: React.FC<QxConditionProps> = ({ |
53 | 57 | }; |
54 | 58 | |
55 | 59 | useEffect(() => { |
56 | - if (formId) handleGetFieldsList(formId); | |
60 | + if (formId && !showAssignment) handleGetFieldsList(formId); | |
57 | 61 | }, [formId]); |
58 | 62 | |
59 | - const PopoverComponent = multiple ? FieldsCheckboxGroup : QxFieldPopover; | |
63 | + const handleAddField = (val: any) => { | |
64 | + handleChange({ | |
65 | + operators: [ | |
66 | + ...(value?.operators || []), | |
67 | + { | |
68 | + field: val, | |
69 | + code: val.code, | |
70 | + name: val.name, | |
71 | + type: val.extract?.fieldType, | |
72 | + opt: 'IS', | |
73 | + mappingValues: [], | |
74 | + }, | |
75 | + ], | |
76 | + }); | |
77 | + }; | |
60 | 78 | |
61 | - const handleAddField = (val: any, opt: any) => { | |
79 | + const handleAddFlowNodeField = (val: any, opt: any) => { | |
62 | 80 | handleChange({ |
63 | 81 | operators: [ |
64 | 82 | ...(value?.operators || []), |
65 | 83 | { |
66 | 84 | field: opt, |
67 | - code: opt.code, | |
85 | + code: val, | |
68 | 86 | name: opt.name, |
69 | 87 | type: opt.extract?.fieldType, |
70 | 88 | opt: 'IS', |
... | ... | @@ -72,20 +90,40 @@ export const QxCondition: React.FC<QxConditionProps> = ({ |
72 | 90 | }, |
73 | 91 | ], |
74 | 92 | }); |
75 | - // setFieldValue( | |
76 | - // 'condition', | |
77 | - // Object.assign({}, condition, { | |
78 | - // operators: [ | |
79 | - // ...(condition.operators || []), | |
80 | - // { field: opt, code: val }, | |
81 | - // ], | |
82 | - // }), | |
83 | - // ); | |
84 | 93 | }; |
85 | 94 | |
86 | - // const fieldOpt = useMemo(() => { | |
87 | - // return fieldSelectorRef.current?.fieldMap || {}; | |
88 | - // }, []); | |
95 | + console.log('resultFieldMap-0', fieldSelectorRef.current); | |
96 | + | |
97 | + const handleGetResultMap = async () => { | |
98 | + if (!fieldSelectorRef.current || isMount.current) return; | |
99 | + isMount.current = true; | |
100 | + | |
101 | + console.log('resultFieldMap-1', fieldSelectorRef.current); | |
102 | + const resultFieldMap = | |
103 | + await fieldSelectorRef.current?.getResultFieldMap?.(); | |
104 | + console.log('resultFieldMap-2', resultFieldMap); | |
105 | + | |
106 | + const newOperators = Array.isArray(value?.operators) | |
107 | + ? value?.operators.map((item) => ({ | |
108 | + ...item, | |
109 | + field: showAssignment | |
110 | + ? resultFieldMap?.[item.field?.code] | |
111 | + : fields?.find((field) => item.code === field.code), | |
112 | + })) | |
113 | + : []; | |
114 | + | |
115 | + handleChange({ operators: newOperators }); | |
116 | + }; | |
117 | + | |
118 | + useEffect(() => { | |
119 | + handleGetResultMap(); | |
120 | + }, [fieldSelectorRef.current]); | |
121 | + | |
122 | + // useEffect(() => { | |
123 | + // if (Array.isArray(value?.operators)) { | |
124 | + // setOperators(value?.operators) | |
125 | + // } | |
126 | + // }, [value?.operators]) | |
89 | 127 | |
90 | 128 | const RenderHeader = header ? ( |
91 | 129 | header |
... | ... | @@ -98,13 +136,13 @@ export const QxCondition: React.FC<QxConditionProps> = ({ |
98 | 136 | )} |
99 | 137 | {!headerRight ? ( |
100 | 138 | <div className="qx-condition-header__right"> |
101 | - {node ? ( | |
139 | + {showAssignment && node ? ( | |
102 | 140 | <QxFlowNodeFieldSelector |
103 | 141 | ref={fieldSelectorRef} |
104 | 142 | node={node} |
105 | 143 | nodes={nodes!} |
106 | 144 | mode="variable" |
107 | - onChange={handleAddField} | |
145 | + onChange={handleAddFlowNodeField} | |
108 | 146 | > |
109 | 147 | <Button size="small" type="link"> |
110 | 148 | <QxBaseIcon style={{ fontSize: 16 }} type="qx-icon-plus" /> |
... | ... | @@ -112,17 +150,12 @@ export const QxCondition: React.FC<QxConditionProps> = ({ |
112 | 150 | </Button> |
113 | 151 | </QxFlowNodeFieldSelector> |
114 | 152 | ) : ( |
115 | - <PopoverComponent | |
116 | - ref={fieldSelectorRef} | |
117 | - data={fields} | |
118 | - onSelect={handleAddField} | |
119 | - onChange={handleAddField} | |
120 | - > | |
153 | + <QxFieldPopover data={fields} onSelect={handleAddField}> | |
121 | 154 | <Button size="small" type="link"> |
122 | 155 | <QxBaseIcon style={{ fontSize: 16 }} type="qx-icon-plus" /> |
123 | 156 | 添加字段 |
124 | 157 | </Button> |
125 | - </PopoverComponent> | |
158 | + </QxFieldPopover> | |
126 | 159 | )} |
127 | 160 | </div> |
128 | 161 | ) : ( |
... | ... | @@ -130,8 +163,6 @@ export const QxCondition: React.FC<QxConditionProps> = ({ |
130 | 163 | )} |
131 | 164 | </div> |
132 | 165 | ); |
133 | - | |
134 | - console.log('operators', fieldSelectorRef); | |
135 | 166 | |
136 | 167 | return ( |
137 | 168 | <div className={`qx-condition ${className && className}`} style={style}> | ... | ... |
1 | -import React, { useEffect, useState } from 'react'; | |
1 | +import { CloseOutlined } from '@ant-design/icons'; | |
2 | 2 | import { Tag } from 'antd'; |
3 | +import React, { useEffect, useState } from 'react'; | |
3 | 4 | import { ParamValueType } from '../../qx-filter-condition/filter'; |
4 | 5 | import { QxTagsInput } from '../../qx-tags-input'; |
5 | -import { CloseOutlined } from '@ant-design/icons'; | |
6 | 6 | |
7 | 7 | interface InputSetterProps { |
8 | 8 | value?: any[]; | ... | ... |
... | ... | @@ -15,6 +15,7 @@ group: |
15 | 15 | |
16 | 16 | ```tsx |
17 | 17 | import { QxFlowNodeFieldSelector } from '@qx/common'; |
18 | +import { Form } from 'antd'; | |
18 | 19 | |
19 | 20 | const node = { |
20 | 21 | id: 'dfc29d5b64fa42489a65b3cfaeb999da', |
... | ... | @@ -71,6 +72,46 @@ const nodes = [ |
71 | 72 | }, |
72 | 73 | pid: '', |
73 | 74 | }, |
75 | + | |
76 | + { | |
77 | + id: 'deb0705410b24087bf22ccee74e4e7e4', | |
78 | + code: 'tbxkuz', | |
79 | + type: 'FORM', | |
80 | + title: 'input', | |
81 | + qxProps: { | |
82 | + appId: 'k6cY4GqjTaxQTW3XLua', | |
83 | + formId: 'FhkvYvVgpWmijBVEbk2', | |
84 | + isTree: false, | |
85 | + }, | |
86 | + description: '', | |
87 | + valueMapping: { | |
88 | + mappingValues: [], | |
89 | + }, | |
90 | + required: false, | |
91 | + disabled: true, | |
92 | + }, | |
93 | + { | |
94 | + id: '3b1e0f82c6a049dca8a01d83a7a09b35', | |
95 | + code: 'vjo6ta', | |
96 | + type: 'OBJECT', | |
97 | + title: 'vjo6ta', | |
98 | + qxProps: {}, | |
99 | + pid: '', | |
100 | + description: '', | |
101 | + valueMapping: { | |
102 | + mappingValues: [], | |
103 | + }, | |
104 | + valuesObj: [], | |
105 | + child: [ | |
106 | + { | |
107 | + id: 'be3d37ae184144dc88c0d39a644fe2c1', | |
108 | + type: 'STRING', | |
109 | + pid: '3b1e0f82c6a049dca8a01d83a7a09b35', | |
110 | + code: '87b2ww', | |
111 | + title: '87b2ww', | |
112 | + }, | |
113 | + ], | |
114 | + }, | |
74 | 115 | ], |
75 | 116 | }, |
76 | 117 | children: [], |
... | ... | @@ -109,7 +150,18 @@ const nodes = [ |
109 | 150 | ]; |
110 | 151 | |
111 | 152 | export default () => { |
112 | - return <QxFlowNodeFieldSelector node={node} nodes={nodes} />; | |
153 | + return ( | |
154 | + <Form | |
155 | + initialValues={{ | |
156 | + field: | |
157 | + '${4c4fc5213db149808c57d093b15e6295|be3d37ae184144dc88c0d39a644fe2c1}', | |
158 | + }} | |
159 | + > | |
160 | + <Form.Item name="field"> | |
161 | + <QxFlowNodeFieldSelector node={node} nodes={nodes} /> | |
162 | + </Form.Item> | |
163 | + </Form> | |
164 | + ); | |
113 | 165 | }; |
114 | 166 | ``` |
115 | 167 | ... | ... |
... | ... | @@ -2,7 +2,7 @@ import { QxWidgetIcon } from '@qx/common'; |
2 | 2 | import { Collapse, Dropdown, Empty, Tag } from 'antd'; |
3 | 3 | import cls from 'classnames'; |
4 | 4 | import { cloneDeep } from 'lodash-es'; |
5 | -import React, { useEffect, useState } from 'react'; | |
5 | +import React, { useEffect, useImperativeHandle, useRef, useState } from 'react'; | |
6 | 6 | import { FieldBaseType } from '../qx-base-condition'; |
7 | 7 | import { QxBaseIcon } from '../qx-base-icon'; |
8 | 8 | import { request } from '../utils'; |
... | ... | @@ -48,19 +48,19 @@ export const getParentNodes = ( |
48 | 48 | return parentNode; |
49 | 49 | }; |
50 | 50 | |
51 | -export enum FieldMapType { | |
52 | - 'STRING' = '文本', | |
53 | - 'NUMBER' = '数字', | |
54 | - 'BOOL' = '布尔', | |
55 | - 'TIME' = '日期', | |
56 | - 'OBJECT' = '对象', | |
57 | - 'ARRAY' = '数组', | |
58 | - 'FORM' = '表单', | |
59 | - 'USER' = '人员', | |
60 | - 'ORG' = '部门', | |
61 | - 'FILE' = '文件', | |
62 | - 'PIC' = '图片', | |
63 | -} | |
51 | +export const FieldMapType = { | |
52 | + STRING: '文本', | |
53 | + NUMBER: '数字', | |
54 | + BOOL: '布尔', | |
55 | + TIME: '日期', | |
56 | + OBJECT: '对象', | |
57 | + ARRAY: '数组', | |
58 | + FORM: '表单', | |
59 | + USER: '人员', | |
60 | + ORG: '部门', | |
61 | + FILE: '文件', | |
62 | + PIC: '图片', | |
63 | +}; | |
64 | 64 | |
65 | 65 | interface NodeFieldDisPlay { |
66 | 66 | node?: INode; |
... | ... | @@ -95,7 +95,32 @@ export const useNodeFieldDisplay = ({ |
95 | 95 | ); |
96 | 96 | |
97 | 97 | const [inputDisplay, setInputDisplay] = useState<React.ReactNode>(); |
98 | - const [optionalNodes, setOptionalNodes] = useState<INode[]>([]); // 根据 fieldType 过滤后的 nodes | |
98 | + const [optionalNodes, setOptionalNodes] = useState<FiledType[]>([]); // 根据 fieldType 过滤后的 nodes | |
99 | + | |
100 | + const getResultFieldMap = (optionalNodes: FiledType[]) => { | |
101 | + const resultMap: Record<string, FiledType | INode> = {}; | |
102 | + | |
103 | + function genResultMap(result: FiledType[]) { | |
104 | + if (Array.isArray(result)) { | |
105 | + result.forEach((i) => { | |
106 | + resultMap[i.code] = i; | |
107 | + if (i.child) { | |
108 | + genResultMap(i.child); | |
109 | + } | |
110 | + }); | |
111 | + } | |
112 | + } | |
113 | + | |
114 | + genResultMap(optionalNodes); | |
115 | + return resultMap; | |
116 | + }; | |
117 | + | |
118 | + const resultFieldMap = useRef(getResultFieldMap(optionalNodes)); | |
119 | + | |
120 | + const displayDom = useRef<React.ReactNode>(); | |
121 | + | |
122 | + const resolveDisplayConfig = useRef<() => void>(); | |
123 | + const resolveFieldResultMap = useRef<(value: any) => void>(); | |
99 | 124 | |
100 | 125 | const getIds = (val?: string) => { |
101 | 126 | if (!val) return []; |
... | ... | @@ -122,35 +147,54 @@ export const useNodeFieldDisplay = ({ |
122 | 147 | ]; |
123 | 148 | }; |
124 | 149 | |
125 | - const getDisplayConfig = (value: string, nodes: INode[] = optionalNodes) => { | |
126 | - const itemIds = getIds(value); | |
127 | - | |
128 | - if (!itemIds || !itemIds.length) return []; | |
129 | - // eslint-disable-next-line @typescript-eslint/no-use-before-define | |
130 | - return itemIds | |
131 | - .map((id) => getResultFieldMaps(nodes)[id]) | |
132 | - .filter((i) => !!i); | |
150 | + const handleGetDisplayConfig = ( | |
151 | + value: string, | |
152 | + map: Record<string, any> = resultFieldMap.current, | |
153 | + ) => { | |
154 | + const itemIds = getIds(value) || []; | |
155 | + return itemIds.map((id) => map[id]); | |
133 | 156 | }; |
134 | 157 | |
135 | - const genDisplayDom = (value: string, nodes: INode[] = optionalNodes) => { | |
136 | - const displayConfig = getDisplayConfig(value, nodes); | |
158 | + const getDisplayConfig = async (val = value): Promise<FiledType[]> => { | |
159 | + return new Promise((resolve, reject) => { | |
160 | + resolveDisplayConfig.current = () => { | |
161 | + try { | |
162 | + console.log('handleGetDisplayConfig'); | |
163 | + resolve(handleGetDisplayConfig(val!)); | |
164 | + } catch (error) { | |
165 | + reject(error); | |
166 | + } | |
167 | + }; | |
168 | + }); | |
169 | + }; | |
137 | 170 | |
171 | + const genDisplayDom = async (val = value) => { | |
172 | + const displayConfig = await getDisplayConfig(val); | |
173 | + console.log('displayConfig', displayConfig); | |
138 | 174 | return ( |
139 | 175 | <> |
140 | - {displayConfig?.map((item, idx) => ( | |
176 | + {displayConfig?.map?.((item, idx) => ( | |
141 | 177 | <div key={idx} className="qx-node-select-input__content-item"> |
142 | - {item.icon && ( | |
143 | - <span className="qx-node-select-input__content-item__icon"> | |
144 | - {icon(item.icon)} | |
178 | + {item ? ( | |
179 | + <> | |
180 | + {item.icon && ( | |
181 | + <span className="qx-node-select-input__content-item__icon"> | |
182 | + {icon(item.icon)} | |
183 | + </span> | |
184 | + )} | |
185 | + <span className="qx-node-select-input__content-item__text"> | |
186 | + {item.type && | |
187 | + FieldMapType[item.type] && | |
188 | + !item.icon && | |
189 | + `[${FieldMapType[item.type]}]`} | |
190 | + {item.title || item.name} | |
191 | + </span> | |
192 | + </> | |
193 | + ) : ( | |
194 | + <span className="qx-node-select-input__content-item__text error"> | |
195 | + 已删除 | |
145 | 196 | </span> |
146 | 197 | )} |
147 | - <span className="qx-node-select-input__content-item__text"> | |
148 | - {item.type && | |
149 | - FieldMapType[item.type] && | |
150 | - !item.icon && | |
151 | - `[${FieldMapType[item.type]}]`} | |
152 | - {item.title || item.name} | |
153 | - </span> | |
154 | 198 | {idx !== displayConfig.length - 1 && ( |
155 | 199 | <span className="qx-node-select-input__content-item__arrow"> |
156 | 200 | <svg |
... | ... | @@ -169,15 +213,15 @@ export const useNodeFieldDisplay = ({ |
169 | 213 | ); |
170 | 214 | }; |
171 | 215 | |
172 | - const renderInputDisplay = ( | |
173 | - nodes: INode[] = optionalNodes, | |
174 | - val: string = value || '', | |
175 | - ) => { | |
176 | - setInputDisplay( | |
177 | - <Tag bordered={false} className="qx-node-select-input__content"> | |
178 | - {genDisplayDom(val, nodes)} | |
179 | - </Tag>, | |
180 | - ); | |
216 | + const renderInputDisplay = async (val = value) => { | |
217 | + displayDom.current = await genDisplayDom(val); | |
218 | + | |
219 | + setInputDisplay(displayDom.current); | |
220 | + }; | |
221 | + | |
222 | + const handleRenderInputDisplay = (val = value) => { | |
223 | + renderInputDisplay(val); | |
224 | + resolveDisplayConfig.current?.(); | |
181 | 225 | }; |
182 | 226 | |
183 | 227 | /*** |
... | ... | @@ -246,17 +290,15 @@ export const useNodeFieldDisplay = ({ |
246 | 290 | form.child = childItem; |
247 | 291 | } |
248 | 292 | }); |
249 | - // console.log(2222222, targetParentNodes, forms); | |
250 | 293 | } catch (error) { |
251 | - // appsFields = {}; | |
252 | - } finally { | |
294 | + console.error(error); | |
253 | 295 | } |
254 | 296 | } |
255 | 297 | return sourceParentNodes; |
256 | 298 | }; |
257 | 299 | |
258 | 300 | /** |
259 | - * 统一字段格式 | |
301 | + * 将result字段统一为表单字段格式 | |
260 | 302 | */ |
261 | 303 | const correctionNodeField = ( |
262 | 304 | fields: FiledType[] | FiledType, |
... | ... | @@ -269,7 +311,6 @@ export const useNodeFieldDisplay = ({ |
269 | 311 | } |
270 | 312 | } else if (fields) { |
271 | 313 | Object.assign(fields, { |
272 | - ...fields, | |
273 | 314 | name: fields.title, |
274 | 315 | code: |
275 | 316 | parent && ['ORG', 'FORM', 'USER'].includes(parent.type) |
... | ... | @@ -292,18 +333,35 @@ export const useNodeFieldDisplay = ({ |
292 | 333 | }; |
293 | 334 | |
294 | 335 | /** |
336 | + * 将node字段统一为表单字段格式 | |
337 | + */ | |
338 | + const correctionNode = (node: INode[] | INode): FiledType[] => { | |
339 | + if (Array.isArray(node)) { | |
340 | + for (let i = 0; i < node.length; i++) { | |
341 | + correctionNode(node[i]); | |
342 | + } | |
343 | + } else if (node) { | |
344 | + Object.assign(node, { | |
345 | + name: node.name, | |
346 | + code: node.id, | |
347 | + child: correctionNodeField(node.data?.result, node.id, node), | |
348 | + extract: { fieldType: node.type, fieldKey: node.id }, | |
349 | + }); | |
350 | + | |
351 | + if (node.children) { | |
352 | + correctionNode(node.children); | |
353 | + } | |
354 | + } | |
355 | + | |
356 | + return node as unknown as FiledType[]; | |
357 | + }; | |
358 | + | |
359 | + /** | |
295 | 360 | * 获取可被选择的节点和结果 |
296 | 361 | */ |
297 | 362 | const getOptionalNodes = async () => { |
298 | 363 | const targetParentNodes = await handleFormTypeAddChild(); // 给 form 类型的字段添加 child |
299 | - | |
300 | - for (let i = 0; i < targetParentNodes.length; i++) { | |
301 | - // TODO: 统一节点和 result 格式 | |
302 | - correctionNodeField( | |
303 | - targetParentNodes[i].data?.result || [], | |
304 | - targetParentNodes[i].id, | |
305 | - ); | |
306 | - } | |
364 | + let newNodes = correctionNode(targetParentNodes); | |
307 | 365 | |
308 | 366 | /** |
309 | 367 | * 根据 limitType 获取可选择的字段 |
... | ... | @@ -341,39 +399,32 @@ export const useNodeFieldDisplay = ({ |
341 | 399 | } |
342 | 400 | } |
343 | 401 | |
344 | - return nodes; | |
402 | + return nodes as unknown as FiledType[]; | |
345 | 403 | } |
346 | 404 | |
347 | - let newNodes = targetParentNodes; | |
348 | - | |
349 | 405 | // 有类型限制根据 limitType 筛选出可选的节点和 result |
350 | 406 | if (limitTypes && Array.isArray(limitTypes) && limitTypes.length) { |
351 | 407 | newNodes = getEffectiveNodes(targetParentNodes); |
352 | 408 | } |
353 | 409 | |
354 | 410 | setOptionalNodes(newNodes); |
355 | - renderInputDisplay(newNodes); | |
356 | - }; | |
411 | + resultFieldMap.current = getResultFieldMap(newNodes); | |
412 | + resolveFieldResultMap.current?.(resultFieldMap.current); | |
413 | + if (value) { | |
414 | + handleRenderInputDisplay(); | |
357 | 415 | |
358 | - const getResultFieldMaps = (optionalNodes: INode[]) => { | |
359 | - const resultMap: Record<string, FiledType | INode> = {}; | |
360 | - function genResultMap(result: FiledType[]) { | |
361 | - if (Array.isArray(result)) { | |
362 | - result.forEach((i) => { | |
363 | - resultMap[i.code] = i; | |
364 | - if (i.child) { | |
365 | - genResultMap(i.child); | |
366 | - } | |
367 | - }); | |
368 | - } | |
369 | - } | |
370 | - | |
371 | - for (let i = 0; i < optionalNodes.length; i++) { | |
372 | - resultMap[optionalNodes[i].id] = optionalNodes[i]; | |
373 | - genResultMap(optionalNodes[i]?.data?.result); | |
416 | + } else { | |
417 | + setTimeout(() => { | |
418 | + resolveDisplayConfig.current?.() | |
419 | + }, 1000) | |
374 | 420 | } |
421 | + }; | |
375 | 422 | |
376 | - return resultMap; | |
423 | + const handleGetResultFieldMap = () => { | |
424 | + return new Promise((resolve) => { | |
425 | + resolveFieldResultMap.current = (fieldResultMap: Record<string, any>) => | |
426 | + resolve(fieldResultMap); | |
427 | + }); | |
377 | 428 | }; |
378 | 429 | |
379 | 430 | useEffect(() => { |
... | ... | @@ -383,14 +434,16 @@ export const useNodeFieldDisplay = ({ |
383 | 434 | return { |
384 | 435 | genDisplayDom, |
385 | 436 | optionalNodes, |
386 | - renderInputDisplay, | |
437 | + renderInputDisplay: handleRenderInputDisplay, | |
387 | 438 | getDisplayConfig, |
388 | 439 | inputDisplay, |
389 | - getResultFieldMaps, | |
440 | + resultFieldMap, | |
441 | + getResultFieldMap: handleGetResultFieldMap, | |
442 | + resolveDisplayConfig: resolveDisplayConfig.current, | |
390 | 443 | }; |
391 | 444 | }; |
392 | 445 | |
393 | -const SelectItem = (props: any) => { | |
446 | +const SelectItem = (props: FiledType) => { | |
394 | 447 | if (props.type === 'FORM' && props.child?.length) { |
395 | 448 | return ( |
396 | 449 | <div className={cls('qx-node-select-item', 'qx-node-select-item__group')}> |
... | ... | @@ -401,7 +454,6 @@ const SelectItem = (props: any) => { |
401 | 454 | { |
402 | 455 | label: ( |
403 | 456 | <span> |
404 | - {/* @ts-ignore */} | |
405 | 457 | {`[${FieldMapType[props.extract?.fieldType]}]`} |
406 | 458 | {props.name} |
407 | 459 | </span> |
... | ... | @@ -429,7 +481,6 @@ const SelectItem = (props: any) => { |
429 | 481 | className={cls('qx-node-select-item')} |
430 | 482 | onClick={() => props.onClick(props)} |
431 | 483 | > |
432 | - {/* @ts-ignore */} | |
433 | 484 | {props.icon |
434 | 485 | ? props.icon |
435 | 486 | : `[${FieldMapType[props.extract?.fieldType]}]`} |
... | ... | @@ -479,52 +530,50 @@ export const QxFlowNodeFieldSelector = React.forwardRef< |
479 | 530 | optionalNodes, |
480 | 531 | renderInputDisplay, |
481 | 532 | inputDisplay, |
533 | + getDisplayConfig, | |
534 | + getResultFieldMap, | |
535 | + resultFieldMap, | |
482 | 536 | } = useNodeFieldDisplay(props); |
483 | - // console.log('111111', props, optionalNodes); | |
484 | 537 | |
485 | - const getOptions = () => { | |
486 | - return optionalNodes.map((node) => ({ | |
538 | + const handleItemClick = (item: any) => { | |
539 | + const newValue = '${' + item.code + '}'; | |
540 | + props.onChange?.(newValue, item); | |
541 | + renderInputDisplay(newValue); | |
542 | + setVisible(false); | |
543 | + }; | |
544 | + | |
545 | + const getOptions = (fields: FiledType[]) => { | |
546 | + return fields.map((field) => ({ | |
487 | 547 | label: ( |
488 | 548 | <div className={cls('qx-node-select-dropdown-header')}> |
489 | 549 | <span className={cls('qx-node-select-dropdown-header__icon')}> |
490 | - {icon(node.icon)} | |
550 | + {icon(field.icon)} | |
491 | 551 | </span> |
492 | - {node.name} | |
552 | + {field.name} | |
493 | 553 | </div> |
494 | 554 | ), |
495 | - key: node.id, | |
496 | - children: Array.isArray(node.data?.result) | |
497 | - ? (node.data.result as FiledType[])?.map((item) => { | |
498 | - return ( | |
499 | - <SelectItem | |
500 | - key={item.id} | |
501 | - {...item} | |
502 | - onClick={(value: FiledType) => { | |
503 | - // eslint-disable-next-line @typescript-eslint/no-use-before-define | |
504 | - handleItemClick(node.id, value || item); | |
505 | - }} | |
506 | - /> | |
507 | - ); | |
508 | - }) | |
509 | - : [], | |
555 | + key: field.id, | |
556 | + children: Array.isArray(field.child) | |
557 | + ? field.child.map((i) => ( | |
558 | + <SelectItem | |
559 | + key={i.id} | |
560 | + {...i} | |
561 | + onClick={(value: FiledType) => { | |
562 | + handleItemClick(value || i); | |
563 | + }} | |
564 | + /> | |
565 | + )) | |
566 | + : undefined, | |
510 | 567 | })); |
511 | 568 | }; |
512 | 569 | |
513 | - const handleItemClick = (nodeKey: string, item: any) => { | |
514 | - const newValue = '${' + item.code + '}'; | |
515 | - props.onChange?.(newValue, item); | |
516 | - if (!props.children) { | |
517 | - renderInputDisplay(optionalNodes, newValue); | |
518 | - } | |
519 | - setVisible(false); | |
520 | - }; | |
521 | - | |
522 | 570 | useEffect(() => { |
523 | 571 | setVisible(props.open ?? false); |
524 | 572 | }, [props.open]); |
525 | 573 | |
574 | + const items = getOptions(optionalNodes!); | |
575 | + | |
526 | 576 | const dropdownRender = () => { |
527 | - const items = getOptions(); | |
528 | 577 | if (Array.isArray(items) && items.length) { |
529 | 578 | return <Collapse ghost expandIconPosition="end" items={items} />; |
530 | 579 | } else { |
... | ... | @@ -542,6 +591,16 @@ export const QxFlowNodeFieldSelector = React.forwardRef< |
542 | 591 | }; |
543 | 592 | }, []); |
544 | 593 | |
594 | + useImperativeHandle(ref, () => ({ | |
595 | + getResultFieldMap, | |
596 | + getDisplayConfig, | |
597 | + resultFieldMap, | |
598 | + renderInputDisplay, | |
599 | + getInputDisplay: () => inputDisplay, | |
600 | + })); | |
601 | + | |
602 | + console.log('resultFieldMap', resultFieldMap, inputDisplay); | |
603 | + | |
545 | 604 | return ( |
546 | 605 | <div |
547 | 606 | className={cls('qx-node-select')} |
... | ... | @@ -550,7 +609,6 @@ export const QxFlowNodeFieldSelector = React.forwardRef< |
550 | 609 | }} |
551 | 610 | > |
552 | 611 | <Dropdown |
553 | - destroyPopupOnHide | |
554 | 612 | trigger={['click']} |
555 | 613 | overlayStyle={{ width: `${props?.width}px` }} |
556 | 614 | overlayClassName={cls('qx-node-select-dropdown')} |
... | ... | @@ -569,7 +627,12 @@ export const QxFlowNodeFieldSelector = React.forwardRef< |
569 | 627 | className={cls('qx-node-select-input')} |
570 | 628 | onClick={() => setVisible(!visible)} |
571 | 629 | > |
572 | - {inputDisplay} | |
630 | + {/* {inputDisplay} */} | |
631 | + {inputDisplay && ( | |
632 | + <Tag bordered={false} className="qx-node-select-input__content"> | |
633 | + {inputDisplay} | |
634 | + </Tag> | |
635 | + )} | |
573 | 636 | </div> |
574 | 637 | )} |
575 | 638 | </Dropdown> |
... | ... | @@ -591,7 +654,7 @@ export interface NodeFieldSelectProps { |
591 | 654 | } |
592 | 655 | |
593 | 656 | export interface FiledType { |
594 | - type: string; | |
657 | + type: keyof typeof FieldMapType; | |
595 | 658 | id: string; |
596 | 659 | title: string; |
597 | 660 | code: string; | ... | ... |
1 | 1 | import { createRequest } from '@qx/utils'; |
2 | 2 | import UploadFile from './uploadFile' |
3 | 3 | |
4 | -const request = createRequest(); | |
4 | +const request = createRequest({ | |
5 | + headers: { | |
6 | + // 你自己的 token | |
7 | + Authorization: 'dev_session:hqfnRxelSbjVSq2zLTM', | |
8 | + businessCode: 'design', | |
9 | + }, | |
10 | +}); | |
5 | 11 | export {UploadFile, request} |
6 | 12 | ... | ... |