Commit a4eadc5d8e72a1071c4cd75aff2e14c3a7166884

Authored by qiang.tian
1 parent f9ac2b90

refactor: qx-base-condition-item

... ... @@ -70,6 +70,12 @@
70 70 text-align: right;
71 71 }
72 72
  73 + &__header-text {
  74 + &.error {
  75 + color: @E3
  76 + }
  77 + }
  78 +
73 79 &:hover {
74 80 .qx-base-condition-item__header-right {
75 81 transform: translateX(0);
... ...
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[];
... ...
... ... @@ -137,6 +137,12 @@
137 137 align-items: center;
138 138 color: @N6;
139 139 }
  140 +
  141 + &__text {
  142 + &.error {
  143 + color: @E3;
  144 + }
  145 + }
140 146 }
141 147 }
142 148
... ...
... ... @@ -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
... ...