Commit fc47e3068307c90630c79e0dcc1c9f420934776d

Authored by qiang.tian
1 parent 5ccc9c43

refactor: condition

... ... @@ -680,6 +680,8 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({
680 680 mode = 'condition',
681 681 node,
682 682 nodes,
  683 + subset,
  684 + params
683 685 }) => {
684 686 const valuesObj = value?.valuesObj?.[0] || {};
685 687 const [open, setOpen] = useState(false);
... ... @@ -731,6 +733,8 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({
731 733 node: node,
732 734 nodes: nodes,
733 735 limitTypes: [field.fieldType],
  736 + value: valuesObj?.value,
  737 + subset
734 738 });
735 739
736 740 const getName = (values: any[]) => {
... ... @@ -740,6 +744,7 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({
740 744 const RenderContent = (
741 745 <>
742 746 <QxFieldSetter
  747 + params={params || field?.params}
743 748 value={value?.valuesObj}
744 749 fieldGroupType={value?.fieldGroupType}
745 750 onChange={handleChange}
... ... @@ -747,6 +752,7 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({
747 752 isRange={optValTypeCheck.isRangeType(value?.opt)}
748 753 disabled={optValTypeCheck.isEmptyType(value?.opt)}
749 754 getName={getName}
  755 + widget={field.extract?.widget}
750 756 />
751 757 {mode === 'variable' && (
752 758 <ControlOutlined
... ... @@ -812,6 +818,7 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({
812 818 value={valuesObj?.value}
813 819 onChange={handleAssignment}
814 820 limitTypes={[field.fieldType]}
  821 + subset={subset}
815 822 >
816 823 {RenderContent}
817 824 </QxFlowNodeFieldSelector>
... ... @@ -841,5 +848,6 @@ export interface QxBaseConditionItemProps {
841 848 mode?: string;
842 849 node?: INode;
843 850 nodes?: INode[];
  851 + [key: string]: any
844 852 // customDisplay?: (val: string) => React.ReactNode;
845 853 }
... ...
1 1 import React, { useEffect, useState } from 'react';
2 2 import { QxBaseConditionItem } from '../qx-base-condition-item';
3   -import './index.less';
4 3 import { INode } from '../qx-flow-node-selector';
  4 +import './index.less';
5 5
6   -export enum FieldBaseType {
7   - STRING = 'TEXT',
8   - DOUBLE = 'NUM',
9   - YEAR_SEC = 'DATE',
10   -}
  6 +const FieldBaseType = {
  7 + STRING: 'TEXT',
  8 + DOUBLE: 'NUM',
  9 + NUMBER: 'NUM',
  10 + YEAR_SEC: 'DATE',
  11 +};
11 12
12 13 export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => {
13 14 const [localOptions, setLocalOptions] = useState(props.options || []);
14 15
15 16 const getDefaultConditionOptions = (item: QxBaseConditionField) => ({
16 17 ...item,
17   - // @ts-ignore
18   - fieldGroupType: FieldBaseType[item.fieldType] || 'TEXT',
  18 + fieldGroupType:
  19 + FieldBaseType[item.fieldType] ||
  20 + item.fieldGroupType ||
  21 + item.fieldType ||
  22 + 'TEXT',
19 23 mappingValues: [],
20 24 opt: 'IS',
21 25 valuesObj: [],
... ... @@ -49,7 +53,7 @@ export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => {
49 53 )}
50 54 <QxBaseConditionItem
51 55 key={item.code || key}
52   - mode={props.mode}
  56 + mode={props.mode || 'condition'}
53 57 {...item}
54 58 value={Object.assign(
55 59 {},
... ... @@ -59,6 +63,7 @@ export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => {
59 63 nodes={props.nodes}
60 64 node={props.node}
61 65 field={item}
  66 + subset={props.subset}
62 67 onChange={(val) => handleItemChange(val, key)}
63 68 remove={() => handleDelete(key)}
64 69 />
... ... @@ -74,11 +79,12 @@ export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => {
74 79
75 80 export interface QxBaseConditionField {
76 81 field: string;
77   - fieldType: string;
  82 + fieldType: keyof typeof FieldBaseType;
78 83 fieldName: string;
79 84 fieldGroupType: string;
80 85 qxProps?: string;
81   - extract?: any;
  86 + extract: any;
  87 + params?: any
82 88 }
83 89
84 90 export interface QxBaseConditionOptionsProps extends QxBaseConditionField {
... ... @@ -96,6 +102,7 @@ export interface QxBaseConditionProps {
96 102 options: QxBaseConditionOptionsProps[];
97 103 value: any[];
98 104 onChange?: (val: any[]) => void;
99   - nodes?: INode[]
100   - node?: INode
  105 + nodes?: INode[];
  106 + node?: INode;
  107 + subset?: boolean;
101 108 }
... ...
... ... @@ -80,6 +80,7 @@ export const AddressSetter: React.FC<InputSetterProps> = ({ value, onChange, ...
80 80 closable
81 81 onClose={(e) => removeItem(e, item)}
82 82 onClick={(e) => e.stopPropagation()}
  83 + bordered={false}
83 84 >
84 85 {/*// @ts-ignore*/}
85 86 {props.getName && props.getName([item])}
... ... @@ -95,6 +96,7 @@ export const AddressSetter: React.FC<InputSetterProps> = ({ value, onChange, ...
95 96 placeholder="请选择"
96 97 disabled={props.disabled}
97 98 onChange={handleManualChange}
  99 + schema={{}}
98 100 />
99 101 )}
100 102 </>
... ...
... ... @@ -76,6 +76,7 @@ export const InputSetter: React.FC<InputSetterProps> = ({ value, onChange, ...pr
76 76 title={props.getCompleteName && props.getCompleteName([item])}
77 77 onClose={(e) => removeItem(e, item)}
78 78 onClick={(e) => e.stopPropagation()}
  79 + bordered={false}
79 80 >
80 81 {props.getName && props.getName([item])}
81 82 </Tag>
... ...
... ... @@ -217,6 +217,7 @@ export const OrgSetter: React.FC<OrgSetterProps> = ({
217 217 closable
218 218 onClose={(e) => removeItem(e, id)}
219 219 onClick={(e) => e.stopPropagation()}
  220 + bordered={false}
220 221 >
221 222 {valueMap[id]}
222 223 </Tag>
... ...
... ... @@ -265,6 +265,7 @@ export const RelSetter: React.FC<UserSelectProps> = ({
265 265 closable
266 266 onClose={(e) => removeItem(e, item.value)}
267 267 onClick={(e) => e.stopPropagation()}
  268 + bordered={false}
268 269 >
269 270 {valueMap[item.value]}
270 271 </Tag>
... ...
... ... @@ -287,6 +287,7 @@ export const RelTreeSetter: React.FC<UserSelectProps> = ({
287 287 closable
288 288 onClose={(e) => removeItem(e, item.value)}
289 289 onClick={(e) => e.stopPropagation()}
  290 + bordered={false}
290 291 >
291 292 {valueMap[item.value]}
292 293 </Tag>
... ...
... ... @@ -219,6 +219,7 @@ export const UserSetter: React.FC<UserSelectProps> = ({
219 219 closable
220 220 onClose={(e) => removeItem(e, id)}
221 221 onClick={(e) => e.stopPropagation()}
  222 + bordered={false}
222 223 >
223 224 {valueMap[id]}
224 225 </Tag>
... ...
... ... @@ -3,7 +3,7 @@ import { QxWidgetIcon } from '@qx/common';
3 3 import { Collapse, Dropdown, Empty, Tag } from 'antd';
4 4 import cls from 'classnames';
5 5 import { cloneDeep } from 'lodash-es';
6   -import React, { useEffect, useMemo, useState } from 'react';
  6 +import React, { useEffect, useState } from 'react';
7 7 import { QxBaseIcon } from '../qx-base-icon';
8 8 import { request } from '../utils';
9 9 import './index.less';
... ... @@ -68,6 +68,8 @@ interface NodeFieldDisPlay {
68 68 node?: INode;
69 69 nodes?: INode[];
70 70 limitTypes?: string[];
  71 + value?: string;
  72 + subset?: boolean;
71 73 }
72 74
73 75 const icon = (icon: any) => {
... ... @@ -85,52 +87,18 @@ export const useNodeFieldDisplay = ({
85 87 node,
86 88 nodes,
87 89 limitTypes,
  90 + value,
  91 + subset = true,
88 92 }: NodeFieldDisPlay) => {
89   - const sourceParentNodes =
  93 + const sourceParentNodes = cloneDeep(
90 94 getParentNodes(node, nodes).filter(
91 95 (node) => !['default_DF_BRANCH'].includes(node.type),
92   - ) || [];
93   -
94   - const optionalNodes = useMemo(() => {
95   - const targetParentNodes = cloneDeep(sourceParentNodes);
96   - if (!limitTypes) return targetParentNodes;
97   -
98   - function getEffectiveNodes(nodes: INode[]) {
99   - return nodes.reduce<INode[]>((pre, cur) => {
100   - const curNode = cur;
101   -
102   - if (Array.isArray(curNode.data?.result)) {
103   - const resultNodes = (curNode.data.result as FiledType[]).filter(
104   - (i) => {
105   - if (i.child && Array.isArray(i.child)) {
106   - // eslint-disable-next-line @typescript-eslint/no-use-before-define
107   - i.child = getEffectiveResult(i.child);
108   - }
109   - return limitTypes!.includes(i.type);
110   - },
111   - );
112   -
113   - if (resultNodes?.length) {
114   - curNode.data.result = resultNodes;
115   - pre.push(curNode);
116   - }
117   - }
118   -
119   - return pre;
120   - }, []);
121   - }
122   -
123   - function getEffectiveResult(result: FiledType[]) {
124   - return result.filter((item) => {
125   - if (item.child && Array.isArray(item.child)) {
126   - item.child = getEffectiveResult(item.child);
127   - }
128   - return limitTypes?.includes(item.fieldType);
129   - });
130   - }
  96 + ) || [],
  97 + );
131 98
132   - return getEffectiveNodes(targetParentNodes);
133   - }, [limitTypes, sourceParentNodes]);
  99 + // const [targetParentNodes, setTargetParentNodes] = useState(sourceParentNodes)
  100 + const [inputDisplay, setInputDisplay] = useState<React.ReactNode>();
  101 + const [optionalNodes, setOptionalNodes] = useState<INode[]>([]); // 根据 fieldType 过滤后的 nodes
134 102
135 103 const getId = (val?: string) => {
136 104 if (!val) return;
... ... @@ -150,11 +118,12 @@ export const useNodeFieldDisplay = ({
150 118 let index = 0;
151 119 while (n && index <= 20) {
152 120 displayConfig = [];
153   - const curNode = optionalNodes[index] || {};
  121 + // eslint-disable-next-line @typescript-eslint/no-use-before-define
  122 + const curNode = cloneDeep(optionalNodes[index]) || {};
154 123 displayConfig.push({
155 124 title: curNode.name,
156 125 icon: curNode.icon,
157   - ...(optionalNodes[index] || {}),
  126 + ...curNode,
158 127 });
159 128 // eslint-disable-next-line @typescript-eslint/no-use-before-define
160 129 recursionNodeResult(curNode.data?.result);
... ... @@ -187,20 +156,13 @@ export const useNodeFieldDisplay = ({
187 156 return (
188 157 <>
189 158 {displayConfig?.map((item, idx) => (
190   - <div
191   - key={idx}
192   - className='qx-node-select-input__content-item'
193   - >
  159 + <div key={idx} className="qx-node-select-input__content-item">
194 160 {item.icon && (
195   - <span
196   - className='qx-node-select-input__content-item__icon'
197   - >
  161 + <span className="qx-node-select-input__content-item__icon">
198 162 {icon(item.icon)}
199 163 </span>
200 164 )}
201   - <span
202   - className='qx-node-select-input__content-item__text'
203   - >
  165 + <span className="qx-node-select-input__content-item__text">
204 166 {item.type &&
205 167 FileTypeMap[item.type] &&
206 168 !item.icon &&
... ... @@ -208,9 +170,7 @@ export const useNodeFieldDisplay = ({
208 170 {item.title}
209 171 </span>
210 172 {idx !== displayConfig.length - 1 && (
211   - <span
212   - className='qx-node-select-input__content-item__arrow'
213   - >
  173 + <span className="qx-node-select-input__content-item__arrow">
214 174 <svg
215 175 xmlns="http://www.w3.org/2000/svg"
216 176 width="1em"
... ... @@ -227,9 +187,137 @@ export const useNodeFieldDisplay = ({
227 187 );
228 188 };
229 189
  190 + const renderInputDisplay = (val: string = value || '') => {
  191 + setInputDisplay(
  192 + <Tag bordered={false} className="qx-node-select-input__content">
  193 + {genDisplayDom(val)}
  194 + </Tag>,
  195 + );
  196 + };
  197 +
  198 + /***
  199 + * 查找有 formId 的 result
  200 + */
  201 + const findResultByFormId = () => {
  202 + const forms: FiledType[] = [];
  203 + sourceParentNodes.forEach((node) => {
  204 + if (Array.isArray(node.data?.result)) {
  205 + // eslint-disable-next-line @typescript-eslint/no-use-before-define
  206 + recursionNodeResult(node.data?.result);
  207 + }
  208 + });
  209 +
  210 + function recursionNodeResult(result: FiledType[] | FiledType) {
  211 + if (!Array.isArray(result) && result) {
  212 + if (result.qxProps && result.qxProps?.formId) {
  213 + forms.push(result);
  214 + }
  215 + }
  216 + if (Array.isArray(result)) {
  217 + result.forEach((i) => {
  218 + if (i.qxProps && i.qxProps?.formId) {
  219 + forms.push(i);
  220 + } else if (i.child) {
  221 + recursionNodeResult(i.child);
  222 + }
  223 + });
  224 + }
  225 + }
  226 +
  227 + return forms;
  228 + };
  229 +
  230 + /**
  231 + * 查询所有 formId 的字段,并给 result 添加 child
  232 + */
  233 + const handleGetAppsFields = async () => {
  234 + const forms = findResultByFormId();
  235 + const ids = forms.map((item) => item.qxProps?.formId);
  236 + if (Array.isArray(ids) && ids.length && subset) {
  237 + try {
  238 + const data = await getAppsFields(ids as any[]);
  239 + Object.keys(data).forEach((id) => {
  240 + const form = forms.find((item) => item.qxProps?.formId === id);
  241 + if (!form) return;
  242 +
  243 + const childItem = data[id].map((item: FiledType) => ({
  244 + ...item,
  245 + icon: (
  246 + <span className="qx-node-select-item__icon">
  247 + <QxWidgetIcon widgetName={item.extract?.widget || 'qxInput'} />
  248 + </span>
  249 + ),
  250 + title: item.name,
  251 + id: item.code,
  252 + type: item.extract?.fieldType,
  253 + }));
  254 +
  255 + if (Array.isArray(form.child)) {
  256 + form.child.push(childItem);
  257 + } else {
  258 + form.child = childItem;
  259 + }
  260 + });
  261 + // console.log(2222222, targetParentNodes, forms);
  262 + } catch (error) {
  263 + // appsFields = {};
  264 + } finally {
  265 + renderInputDisplay();
  266 + }
  267 + }
  268 + return sourceParentNodes;
  269 + };
  270 +
  271 + const getOptionalNodes = async () => {
  272 + const targetParentNodes = await handleGetAppsFields();
  273 + if (!limitTypes) return setOptionalNodes(targetParentNodes);
  274 +
  275 + function getEffectiveResult(result: FiledType[]) {
  276 + const newResult = [];
  277 + for (let i = 0; i < result.length; i++) {
  278 + const resultItem = result[i] || {};
  279 + if (resultItem.child) {
  280 + resultItem.child = getEffectiveResult(resultItem.child);
  281 + if (
  282 + (Array.isArray(resultItem.child) && resultItem.child.length) ||
  283 + limitTypes?.includes(resultItem.type)
  284 + ) {
  285 + newResult.push(resultItem);
  286 + }
  287 + } else if (limitTypes?.includes(resultItem.type)) {
  288 + newResult.push(resultItem);
  289 + }
  290 + }
  291 +
  292 + return newResult;
  293 + }
  294 +
  295 + function getEffectiveNodes(nodes: INode[]) {
  296 + for (let i = 0; i <= nodes.length; i++) {
  297 + const node = nodes[i] || {};
  298 + const nodeResult = node.data?.result;
  299 + if (Array.isArray(nodeResult) && nodeResult.length) {
  300 + node.data.result = getEffectiveResult(nodeResult);
  301 + }
  302 + }
  303 +
  304 + return nodes;
  305 + }
  306 +
  307 + const newNodes = getEffectiveNodes(targetParentNodes);
  308 + setOptionalNodes([...newNodes]);
  309 + };
  310 +
  311 + useEffect(() => {
  312 + getOptionalNodes();
  313 + }, []);
  314 +
230 315 return {
231 316 genDisplayDom,
232 317 optionalNodes,
  318 + // targetParentNodes,
  319 + renderInputDisplay,
  320 + inputDisplay,
233 321 };
234 322 };
235 323
... ... @@ -266,7 +354,7 @@ const SelectItem = (props: any) => {
266 354 );
267 355 }
268 356
269   - if (!props.child) {
  357 + if (!props.child || !props.child.length) {
270 358 return (
271 359 <div
272 360 className={cls('qx-node-select-item')}
... ... @@ -317,14 +405,10 @@ export const QxFlowNodeFieldSelector: React.FC<NodeFieldSelectProps> = (
317 405
318 406 const [visible, setVisible] = useState(false);
319 407
320   - const [inputDisplay, setInputDisplay] = useState<React.ReactNode>();
321   -
322   - const { optionalNodes, genDisplayDom } = useNodeFieldDisplay(props);
  408 + const { optionalNodes, renderInputDisplay, inputDisplay } =
  409 + useNodeFieldDisplay(props);
323 410
324 411 const getOptions = () => {
325   - if (!optionalNodes.length) {
326   - return <Empty />;
327   - }
328 412 return optionalNodes.map((node) => ({
329 413 label: (
330 414 <div className={cls('qx-node-select-dropdown-header')}>
... ... @@ -352,96 +436,6 @@ export const QxFlowNodeFieldSelector: React.FC<NodeFieldSelectProps> = (
352 436 }));
353 437 };
354 438
355   - const getForms = () => {
356   - const forms: FiledType[] = [];
357   - optionalNodes.forEach((node) => {
358   - if (Array.isArray(node.data?.result)) {
359   - // eslint-disable-next-line @typescript-eslint/no-use-before-define
360   - recursionNodeResult(node.data?.result);
361   - }
362   - });
363   -
364   - function recursionNodeResult(result: FiledType[] | FiledType) {
365   - if (!Array.isArray(result) && result) {
366   - if (result.qxProps && result.qxProps?.formId) {
367   - forms.push(result);
368   - }
369   - }
370   - if (Array.isArray(result)) {
371   - result.forEach((i) => {
372   - if (i.qxProps && i.qxProps?.formId) {
373   - forms.push(i);
374   - } else if (i.child) {
375   - recursionNodeResult(i.child);
376   - }
377   - });
378   - }
379   - }
380   -
381   - return forms;
382   - };
383   -
384   - const renderInputDisplay = (val: string = props.value || '') => {
385   - setInputDisplay(
386   - <Tag bordered={false} className="qx-node-select-input__content">
387   - {genDisplayDom(val)}
388   - </Tag>,
389   - );
390   - };
391   -
392   - const handleGetAppsFields = async () => {
393   - const forms = getForms();
394   - const ids = forms.map(
395   - (item) => item.qxProps?.formId && !props.limitTypes?.includes(item.type),
396   - );
397   - console.log(ids, 'ids')
398   - if (Array.isArray(ids) && ids.length) {
399   - try {
400   - const data = await getAppsFields(ids as any[]);
401   - Object.keys(data).forEach((id) => {
402   - forms.forEach((i) => {
403   - if (i.qxProps?.formId === id) {
404   - if (Array.isArray(i.child)) {
405   - i.child.push(
406   - data[id].map((item: FiledType) => ({
407   - icon: (
408   - <span className="qx-node-select-item__icon">
409   - <QxWidgetIcon
410   - widgetName={item.extract?.widget || 'qxInput'}
411   - />
412   - </span>
413   - ),
414   - title: item.name,
415   - code: item.code,
416   - id: item.code,
417   - type: item.extract?.fieldType,
418   - })),
419   - );
420   - } else {
421   - i.child = data[id].map((item: FiledType) => ({
422   - icon: (
423   - <span className="qx-node-select-item__icon">
424   - <QxWidgetIcon
425   - widgetName={item.extract?.widget || 'qxInput'}
426   - />
427   - </span>
428   - ),
429   - title: item.name,
430   - code: item.code,
431   - id: item.code,
432   - type: item.extract?.fieldType,
433   - }));
434   - }
435   - }
436   - });
437   - });
438   - renderInputDisplay();
439   - } catch (error) {
440   - // appsFields = {};
441   - }
442   - }
443   - };
444   -
445 439 const handleItemClick = (nodeKey: string, item: any) => {
446 440 const newValue = '${' + `${nodeKey}|${item.id}` + '}';
447 441 props.onChange?.(newValue, item);
... ... @@ -452,23 +446,27 @@ export const QxFlowNodeFieldSelector: React.FC<NodeFieldSelectProps> = (
452 446 };
453 447
454 448 useEffect(() => {
455   - handleGetAppsFields();
456   - }, []);
457   -
458   - useEffect(() => {
459 449 setVisible(props.open ?? false);
460 450 }, [props.open]);
461 451
  452 + const dropdownRender = () => {
  453 + const items = getOptions();
  454 + if (Array.isArray(items) && items.length) {
  455 + return <Collapse ghost expandIconPosition="end" items={items} />;
  456 + } else {
  457 + return <Empty />;
  458 + }
  459 + };
  460 +
462 461 return (
463 462 <div className={cls('qx-node-select')}>
464 463 <Dropdown
  464 + destroyPopupOnHide
465 465 trigger={['click']}
466 466 overlayStyle={{ width: `${props?.width}px` }}
467 467 overlayClassName={cls('qx-node-select-dropdown')}
468 468 open={visible}
469   - dropdownRender={() => (
470   - <Collapse ghost expandIconPosition="end" items={getOptions()} />
471   - )}
  469 + dropdownRender={dropdownRender}
472 470 onOpenChange={(open) => {
473 471 if (mode === 'select') {
474 472 setVisible(open);
... ... @@ -505,6 +503,7 @@ export interface NodeFieldSelectProps {
505 503 width?: number;
506 504 mode?: 'select' | 'variable';
507 505 open?: boolean;
  506 + subset?: boolean;
508 507 }
509 508
510 509 export interface FiledType {
... ...