Commit 04129d565215a68f370e114fd2b5491455fccd46
Merge remote-tracking branch 'origin/feature/dataflow' into feature/dataflow
Showing
11 changed files
with
917 additions
and
180 deletions
1 | { | 1 | { |
2 | "name": "@qx/common", | 2 | "name": "@qx/common", |
3 | - "version": "3.0.0-alpha.19", | 3 | + "version": "3.0.0-alpha.21", |
4 | "description": "A react library developed with dumi", | 4 | "description": "A react library developed with dumi", |
5 | "license": "MIT", | 5 | "license": "MIT", |
6 | "module": "dist/index.js", | 6 | "module": "dist/index.js", |
@@ -15,5 +15,7 @@ export * from './qx-btn'; | @@ -15,5 +15,7 @@ export * from './qx-btn'; | ||
15 | export * from './qx-progress'; | 15 | export * from './qx-progress'; |
16 | export * from './qx-search-input'; | 16 | export * from './qx-search-input'; |
17 | export * from './qx-dynamic-component'; | 17 | export * from './qx-dynamic-component'; |
18 | +export * from './qx-widget-icon'; | ||
19 | +export * from './qx-flow-node-selector'; | ||
18 | 20 | ||
19 | 21 |
@@ -53,16 +53,10 @@ | @@ -53,16 +53,10 @@ | ||
53 | color: @N7; | 53 | color: @N7; |
54 | } | 54 | } |
55 | 55 | ||
56 | - &-value-render { | ||
57 | - position: absolute; | ||
58 | - background-color: #fff; | ||
59 | - width: calc(100% - 33px); | ||
60 | - height: 30px; | ||
61 | - display: flex; | ||
62 | - align-items: center; | ||
63 | - top: 1px; | ||
64 | - left: 8px; | ||
65 | - z-index: 1; | 56 | + .qx-field-setter { |
57 | + .ant-tag { | ||
58 | + display: flex; | ||
59 | + } | ||
66 | } | 60 | } |
67 | } | 61 | } |
68 | 62 |
1 | import { ControlOutlined } from '@ant-design/icons'; | 1 | import { ControlOutlined } from '@ant-design/icons'; |
2 | -import { Select, Tooltip, Input } from 'antd'; | 2 | +import { Select, Tooltip } from 'antd'; |
3 | import { size } from 'lodash-es'; | 3 | import { size } from 'lodash-es'; |
4 | import React, { useState } from 'react'; | 4 | import React, { useState } from 'react'; |
5 | import type { QxBaseConditionField } from '../qx-base-condition'; | 5 | import type { QxBaseConditionField } from '../qx-base-condition'; |
6 | import { QxBaseIcon } from '../qx-base-icon'; | 6 | import { QxBaseIcon } from '../qx-base-icon'; |
7 | import { QxFieldSetter } from '../qx-field-setter'; | 7 | import { QxFieldSetter } from '../qx-field-setter'; |
8 | +import type { INode } from '../qx-flow-node-selector'; | ||
9 | +import { | ||
10 | + QxFlowNodeFieldSelector, | ||
11 | + useNodeFieldDisplay, | ||
12 | +} from '../qx-flow-node-selector'; | ||
13 | +import { QxWidgetIcon } from '../qx-widget-icon'; | ||
8 | 14 | ||
9 | import './index.less'; | 15 | import './index.less'; |
10 | 16 | ||
@@ -666,147 +672,22 @@ const optValTypeCheck = { | @@ -666,147 +672,22 @@ const optValTypeCheck = { | ||
666 | }, | 672 | }, |
667 | }; | 673 | }; |
668 | 674 | ||
669 | -export const WidgetsIcon = ({ widgetName }: { widgetName: string }) => { | ||
670 | - let iconType: string = ''; | ||
671 | - switch (widgetName) { | ||
672 | - case 'qxInput': | ||
673 | - iconType = 'icon-field-text'; | ||
674 | - break; | ||
675 | - case 'qxNumber': | ||
676 | - iconType = 'icon-field-num'; | ||
677 | - break; | ||
678 | - case 'dateTime': | ||
679 | - case 'qxDatetime': | ||
680 | - iconType = 'icon-field-datetime'; | ||
681 | - break; | ||
682 | - case 'qxTime': | ||
683 | - iconType = 'icon-field-time'; | ||
684 | - break; | ||
685 | - case 'qxSwitch': | ||
686 | - iconType = 'icon-field-boolean'; | ||
687 | - break; | ||
688 | - case 'qxSelect': | ||
689 | - iconType = 'icon-field-select'; | ||
690 | - break; | ||
691 | - case 'qxMultiSelect': | ||
692 | - iconType = 'icon-field-multi-select'; | ||
693 | - break; | ||
694 | - case 'qxMobile': | ||
695 | - iconType = 'icon-field-mobile'; | ||
696 | - break; | ||
697 | - case 'qxMoney': | ||
698 | - iconType = 'icon-field-finance'; | ||
699 | - break; | ||
700 | - case 'qxEmail': | ||
701 | - iconType = 'icon-field-email'; | ||
702 | - break; | ||
703 | - case 'qxPercent': | ||
704 | - iconType = 'icon-field-percent'; | ||
705 | - break; | ||
706 | - case 'qxUpload': | ||
707 | - iconType = 'icon-field-file'; | ||
708 | - break; | ||
709 | - case 'qxUploadImage': | ||
710 | - iconType = 'icon-field-img'; | ||
711 | - break; | ||
712 | - case 'qxAddress': | ||
713 | - iconType = 'icon-field-address'; | ||
714 | - break; | ||
715 | - case 'qxRichText': | ||
716 | - iconType = 'icon-field-richtext'; | ||
717 | - break; | ||
718 | - case 'qxLocation': | ||
719 | - iconType = 'icon-field-location'; | ||
720 | - break; | ||
721 | - case 'orgSelector': | ||
722 | - iconType = 'icon-field-department'; | ||
723 | - break; | ||
724 | - case 'userSelector': | ||
725 | - iconType = 'icon-field-user'; | ||
726 | - break; | ||
727 | - case 'createdBy': | ||
728 | - case 'created_by': | ||
729 | - iconType = 'icon-field-created-by'; | ||
730 | - break; | ||
731 | - case 'createdAt': | ||
732 | - case 'created_at': | ||
733 | - iconType = 'icon-field-created-at'; | ||
734 | - break; | ||
735 | - case 'updatedBy': | ||
736 | - case 'updated_by': | ||
737 | - iconType = 'icon-field-updated-by'; | ||
738 | - break; | ||
739 | - case 'updatedAt': | ||
740 | - case 'updated_at': | ||
741 | - iconType = 'icon-field-updated-at'; | ||
742 | - break; | ||
743 | - case 'qxBizNo': | ||
744 | - iconType = 'icon-field-no'; | ||
745 | - break; | ||
746 | - case 'relSelector': | ||
747 | - iconType = 'icon-field-rel'; | ||
748 | - break; | ||
749 | - case 'relField': | ||
750 | - iconType = 'icon-field-ref'; | ||
751 | - break; | ||
752 | - case 'subform': | ||
753 | - case 'table': | ||
754 | - iconType = 'icon-field-subform'; | ||
755 | - break; | ||
756 | - case 'qxTree': | ||
757 | - iconType = 'icon-field-tree'; | ||
758 | - break; | ||
759 | - case 'qxFormula': | ||
760 | - iconType = 'icon-field-formula'; | ||
761 | - break; | ||
762 | - case 'qxDivider': | ||
763 | - iconType = 'icon-field-divider'; | ||
764 | - break; | ||
765 | - case 'qxRemark': | ||
766 | - iconType = 'icon-field-remark'; | ||
767 | - break; | ||
768 | - case 'qxEmbed': | ||
769 | - iconType = 'icon-field-embed '; | ||
770 | - break; | ||
771 | - case 'qxTabs': | ||
772 | - iconType = 'icon-editor_tab'; | ||
773 | - break; | ||
774 | - case 'qxLayout': | ||
775 | - iconType = 'icon-editor_grid'; | ||
776 | - break; | ||
777 | - case 'simple': | ||
778 | - iconType = 'icon-editor_layout'; | ||
779 | - break; | ||
780 | - case 'tabC': | ||
781 | - iconType = 'icon-editor_tab'; | ||
782 | - break; | ||
783 | - case 'layout': | ||
784 | - iconType = 'icon-editor_grid'; | ||
785 | - break; | ||
786 | - default: | ||
787 | - iconType = 'icon-field-text'; | ||
788 | - break; | ||
789 | - } | ||
790 | - return <QxBaseIcon type={iconType} />; | ||
791 | -}; | ||
792 | - | ||
793 | export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ | 675 | export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ |
794 | value, | 676 | value, |
795 | field, | 677 | field, |
796 | remove, | 678 | remove, |
797 | onChange, | 679 | onChange, |
798 | mode = 'condition', | 680 | mode = 'condition', |
799 | - ValueAssignmentPopup, | 681 | + node, |
682 | + nodes, | ||
800 | }) => { | 683 | }) => { |
801 | - const [CustomValueRender, setCustomValueRender] = | ||
802 | - useState<() => React.ReactNode>(); | ||
803 | - | 684 | + const valuesObj = value?.valuesObj?.[0] || {}; |
804 | const [open, setOpen] = useState(false); | 685 | const [open, setOpen] = useState(false); |
805 | 686 | ||
806 | - const handleChange = (val: any) => { | 687 | + const handleChange = (val: any[]) => { |
807 | onChange?.({ | 688 | onChange?.({ |
808 | ...(value || {}), | 689 | ...(value || {}), |
809 | - mappingValues: val?.map((i: any) => i.value), | 690 | + mappingValues: val?.length ? val?.map((i: any) => i.value) : [], |
810 | valuesObj: val, | 691 | valuesObj: val, |
811 | }); | 692 | }); |
812 | }; | 693 | }; |
@@ -841,23 +722,23 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ | @@ -841,23 +722,23 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ | ||
841 | onChange?.(newValue); | 722 | onChange?.(newValue); |
842 | }; | 723 | }; |
843 | 724 | ||
844 | - const handleDefaultValueSettingChange = ( | ||
845 | - val: any, | ||
846 | - valueRender: () => React.ReactNode, | ||
847 | - ) => { | ||
848 | - handleChange(val); | ||
849 | - setCustomValueRender(() => valueRender); | 725 | + const handleAssignment = (value: string) => { |
726 | + handleChange([{ type: 'FIELD', value }]); | ||
727 | + setOpen(false); | ||
850 | }; | 728 | }; |
851 | 729 | ||
852 | - const handleOpenChange = setOpen; | 730 | + const { genDisplayDom } = useNodeFieldDisplay({ |
731 | + node: node, | ||
732 | + nodes: nodes, | ||
733 | + limitTypes: [field.fieldType], | ||
734 | + }); | ||
735 | + | ||
736 | + const getName = (values: any[]) => { | ||
737 | + return values.map((value) => genDisplayDom(value)) | ||
738 | + } | ||
853 | 739 | ||
854 | const RenderContent = ( | 740 | const RenderContent = ( |
855 | <> | 741 | <> |
856 | - {typeof CustomValueRender === 'function' && ( | ||
857 | - <div className="qx-base-condition-item__content-value-render"> | ||
858 | - {CustomValueRender()} | ||
859 | - </div> | ||
860 | - )} | ||
861 | <QxFieldSetter | 742 | <QxFieldSetter |
862 | value={value?.valuesObj} | 743 | value={value?.valuesObj} |
863 | fieldGroupType={value?.fieldGroupType} | 744 | fieldGroupType={value?.fieldGroupType} |
@@ -865,11 +746,12 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ | @@ -865,11 +746,12 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ | ||
865 | isMultiple={multipleType.includes(value?.fieldGroupType)} | 746 | isMultiple={multipleType.includes(value?.fieldGroupType)} |
866 | isRange={optValTypeCheck.isRangeType(value?.opt)} | 747 | isRange={optValTypeCheck.isRangeType(value?.opt)} |
867 | disabled={optValTypeCheck.isEmptyType(value?.opt)} | 748 | disabled={optValTypeCheck.isEmptyType(value?.opt)} |
749 | + getName={getName} | ||
868 | /> | 750 | /> |
869 | - {typeof ValueAssignmentPopup !== 'undefined' && ( | 751 | + {mode === 'variable' && ( |
870 | <ControlOutlined | 752 | <ControlOutlined |
871 | onClick={() => { | 753 | onClick={() => { |
872 | - handleOpenChange(!open); | 754 | + setOpen(!open); |
873 | }} | 755 | }} |
874 | className="qx-base-condition-item__content-suffix" | 756 | className="qx-base-condition-item__content-suffix" |
875 | /> | 757 | /> |
@@ -900,7 +782,7 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ | @@ -900,7 +782,7 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ | ||
900 | <div className="qx-base-condition-item__header"> | 782 | <div className="qx-base-condition-item__header"> |
901 | <div className="qx-base-condition-item__header-left"> | 783 | <div className="qx-base-condition-item__header-left"> |
902 | <span className="qx-base-condition-item__header-icon"> | 784 | <span className="qx-base-condition-item__header-icon"> |
903 | - <WidgetsIcon widgetName={field?.extract?.widget} /> | 785 | + <QxWidgetIcon widgetName={field?.extract?.widget} /> |
904 | </span> | 786 | </span> |
905 | <span className="qx-base-condition-item__header-text"> | 787 | <span className="qx-base-condition-item__header-text"> |
906 | {field.fieldName} | 788 | {field.fieldName} |
@@ -921,16 +803,18 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ | @@ -921,16 +803,18 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ | ||
921 | </div> | 803 | </div> |
922 | </div> | 804 | </div> |
923 | <div className="qx-base-condition-item__content"> | 805 | <div className="qx-base-condition-item__content"> |
924 | - {typeof ValueAssignmentPopup !== 'undefined' ? ( | ||
925 | - <ValueAssignmentPopup | 806 | + {mode === 'variable' ? ( |
807 | + <QxFlowNodeFieldSelector | ||
808 | + mode={mode} | ||
809 | + node={node!} | ||
810 | + nodes={nodes!} | ||
926 | open={open} | 811 | open={open} |
927 | - value={value} | ||
928 | - field={field} | ||
929 | - onChange={handleDefaultValueSettingChange} | ||
930 | - onOpenChange={handleOpenChange} | 812 | + value={valuesObj?.value} |
813 | + onChange={handleAssignment} | ||
814 | + limitTypes={[field.fieldType]} | ||
931 | > | 815 | > |
932 | {RenderContent} | 816 | {RenderContent} |
933 | - </ValueAssignmentPopup> | 817 | + </QxFlowNodeFieldSelector> |
934 | ) : ( | 818 | ) : ( |
935 | RenderContent | 819 | RenderContent |
936 | )} | 820 | )} |
@@ -942,9 +826,10 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ | @@ -942,9 +826,10 @@ export const QxBaseConditionItem: React.FC<QxBaseConditionItemProps> = ({ | ||
942 | export interface ValueAssignmentPopupProps | 826 | export interface ValueAssignmentPopupProps |
943 | extends Omit<QxBaseConditionItemProps, 'onChange'> { | 827 | extends Omit<QxBaseConditionItemProps, 'onChange'> { |
944 | children?: React.ReactNode; | 828 | children?: React.ReactNode; |
945 | - onChange?: (val: any, valueRender: () => React.ReactNode) => void; | 829 | + onChange?: (val: any) => void; |
946 | open?: boolean; | 830 | open?: boolean; |
947 | onOpenChange?: (open: boolean) => void; | 831 | onOpenChange?: (open: boolean) => void; |
832 | + onClear?: () => void; | ||
948 | } | 833 | } |
949 | 834 | ||
950 | export interface QxBaseConditionItemProps { | 835 | export interface QxBaseConditionItemProps { |
@@ -952,6 +837,9 @@ export interface QxBaseConditionItemProps { | @@ -952,6 +837,9 @@ export interface QxBaseConditionItemProps { | ||
952 | value?: any; | 837 | value?: any; |
953 | onChange?: (val: any) => void; | 838 | onChange?: (val: any) => void; |
954 | remove?: (field: QxBaseConditionField) => void; | 839 | remove?: (field: QxBaseConditionField) => void; |
955 | - ValueAssignmentPopup?: React.FC<ValueAssignmentPopupProps>; | 840 | + ValueAssignment?: React.FC<ValueAssignmentPopupProps>; |
956 | mode?: string; | 841 | mode?: string; |
842 | + node?: INode; | ||
843 | + nodes?: INode[]; | ||
844 | + // customDisplay?: (val: string) => React.ReactNode; | ||
957 | } | 845 | } |
1 | import React, { useEffect, useState } from 'react'; | 1 | import React, { useEffect, useState } from 'react'; |
2 | -import type { ValueAssignmentPopupProps } from '../qx-base-condition-item'; | ||
3 | import { QxBaseConditionItem } from '../qx-base-condition-item'; | 2 | import { QxBaseConditionItem } from '../qx-base-condition-item'; |
4 | import './index.less'; | 3 | import './index.less'; |
4 | +import { INode } from '../qx-flow-node-selector'; | ||
5 | 5 | ||
6 | export enum FieldBaseType { | 6 | export enum FieldBaseType { |
7 | STRING = 'TEXT', | 7 | STRING = 'TEXT', |
@@ -9,9 +9,8 @@ export enum FieldBaseType { | @@ -9,9 +9,8 @@ export enum FieldBaseType { | ||
9 | YEAR_SEC = 'DATE', | 9 | YEAR_SEC = 'DATE', |
10 | } | 10 | } |
11 | 11 | ||
12 | - | ||
13 | export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => { | 12 | export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => { |
14 | - const [localOptions, setLocalOptions] = useState(props.value || props.options || []); | 13 | + const [localOptions, setLocalOptions] = useState(props.options || []); |
15 | 14 | ||
16 | const getDefaultConditionOptions = (item: QxBaseConditionField) => ({ | 15 | const getDefaultConditionOptions = (item: QxBaseConditionField) => ({ |
17 | ...item, | 16 | ...item, |
@@ -36,7 +35,7 @@ export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => { | @@ -36,7 +35,7 @@ export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => { | ||
36 | const handleDelete = (key: number) => { | 35 | const handleDelete = (key: number) => { |
37 | localOptions.splice(key, 1); | 36 | localOptions.splice(key, 1); |
38 | setLocalOptions([...localOptions]); | 37 | setLocalOptions([...localOptions]); |
39 | - props.onChange?.([...localOptions]) | 38 | + props.onChange?.([...localOptions]); |
40 | }; | 39 | }; |
41 | 40 | ||
42 | useEffect(() => { | 41 | useEffect(() => { |
@@ -52,13 +51,16 @@ export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => { | @@ -52,13 +51,16 @@ export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => { | ||
52 | key={item.code || key} | 51 | key={item.code || key} |
53 | mode={props.mode} | 52 | mode={props.mode} |
54 | {...item} | 53 | {...item} |
55 | - value={props.value?.[key] || getDefaultConditionOptions(item)} | 54 | + value={Object.assign( |
55 | + {}, | ||
56 | + getDefaultConditionOptions(item), | ||
57 | + props.value?.[key] || {}, | ||
58 | + )} | ||
59 | + nodes={props.nodes} | ||
60 | + node={props.node} | ||
56 | field={item} | 61 | field={item} |
57 | onChange={(val) => handleItemChange(val, key)} | 62 | onChange={(val) => handleItemChange(val, key)} |
58 | remove={() => handleDelete(key)} | 63 | remove={() => handleDelete(key)} |
59 | - ValueAssignmentPopup={ | ||
60 | - (item.showValueAssignmentPopup ?? true) ? props.ValueAssignmentPopup : undefined | ||
61 | - } | ||
62 | /> | 64 | /> |
63 | </div> | 65 | </div> |
64 | )); | 66 | )); |
@@ -80,13 +82,13 @@ export interface QxBaseConditionField { | @@ -80,13 +82,13 @@ export interface QxBaseConditionField { | ||
80 | } | 82 | } |
81 | 83 | ||
82 | export interface QxBaseConditionOptionsProps extends QxBaseConditionField { | 84 | export interface QxBaseConditionOptionsProps extends QxBaseConditionField { |
83 | - showValueAssignmentPopup?: boolean; | 85 | + showValueAssignment?: boolean; |
84 | isMultiple?: boolean; | 86 | isMultiple?: boolean; |
85 | isRange?: boolean; | 87 | isRange?: boolean; |
86 | [key: string]: any; | 88 | [key: string]: any; |
87 | } | 89 | } |
88 | 90 | ||
89 | -export type QxBaseConditionMode = 'condition' | 'variable' | 91 | +export type QxBaseConditionMode = 'condition' | 'variable'; |
90 | 92 | ||
91 | export interface QxBaseConditionProps { | 93 | export interface QxBaseConditionProps { |
92 | showIdx?: boolean; | 94 | showIdx?: boolean; |
@@ -94,5 +96,6 @@ export interface QxBaseConditionProps { | @@ -94,5 +96,6 @@ export interface QxBaseConditionProps { | ||
94 | options: QxBaseConditionOptionsProps[]; | 96 | options: QxBaseConditionOptionsProps[]; |
95 | value: any[]; | 97 | value: any[]; |
96 | onChange?: (val: any[]) => void; | 98 | onChange?: (val: any[]) => void; |
97 | - ValueAssignmentPopup?: React.FC<ValueAssignmentPopupProps>; | 99 | + nodes?: INode[] |
100 | + node?: INode | ||
98 | } | 101 | } |
@@ -156,6 +156,7 @@ export interface paramColSelectProps extends ColSelectProps { | @@ -156,6 +156,7 @@ export interface paramColSelectProps extends ColSelectProps { | ||
156 | iconText?: string; // Popover-icon 自定义 后面跟随文本 | 156 | iconText?: string; // Popover-icon 自定义 后面跟随文本 |
157 | allowClear?: boolean; | 157 | allowClear?: boolean; |
158 | popupOnBody?: boolean; // 下拉 跟随 body 还是自身 | 158 | popupOnBody?: boolean; // 下拉 跟随 body 还是自身 |
159 | + getName?: (val: any) => void | ||
159 | } | 160 | } |
160 | 161 | ||
161 | export const QxFieldSetter: React.FC<paramColSelectProps> = ({ | 162 | export const QxFieldSetter: React.FC<paramColSelectProps> = ({ |
@@ -355,7 +356,7 @@ export const QxFieldSetter: React.FC<paramColSelectProps> = ({ | @@ -355,7 +356,7 @@ export const QxFieldSetter: React.FC<paramColSelectProps> = ({ | ||
355 | * @param str 字符串形式 | 356 | * @param str 字符串形式 |
356 | * @param joinParent 拼接父节点 | 357 | * @param joinParent 拼接父节点 |
357 | */ | 358 | */ |
358 | - const getName = (val: string[], str?: boolean, joinParent?: boolean) => { | 359 | + const getName = props?.getName || ((val: string[], str?: boolean, joinParent?: boolean) => { |
359 | const name: any[] = []; | 360 | const name: any[] = []; |
360 | let flag: boolean = false; | 361 | let flag: boolean = false; |
361 | (colsTree || []).map((tree) => { | 362 | (colsTree || []).map((tree) => { |
@@ -440,7 +441,7 @@ export const QxFieldSetter: React.FC<paramColSelectProps> = ({ | @@ -440,7 +441,7 @@ export const QxFieldSetter: React.FC<paramColSelectProps> = ({ | ||
440 | } else { | 441 | } else { |
441 | return flag ? name : val; | 442 | return flag ? name : val; |
442 | } | 443 | } |
443 | - }; | 444 | + }); |
444 | 445 | ||
445 | /** | 446 | /** |
446 | * 名称转换 | 447 | * 名称转换 |
@@ -41,7 +41,9 @@ export default () => { | @@ -41,7 +41,9 @@ export default () => { | ||
41 | hideCurrentOrg={true} | 41 | hideCurrentOrg={true} |
42 | hideCurrentUser={true} | 42 | hideCurrentUser={true} |
43 | isMixValue={false} | 43 | isMixValue={false} |
44 | - onChange={() => {}} | 44 | + onChange={(val) => { |
45 | + console.log(222222,val) | ||
46 | + }} | ||
45 | tableFields={optionsList} | 47 | tableFields={optionsList} |
46 | params={{ funCoded: 'cjQhMZnwkO2QoVzxVPC', useId: true }} | 48 | params={{ funCoded: 'cjQhMZnwkO2QoVzxVPC', useId: true }} |
47 | value={{ | 49 | value={{ |
src/qx-flow-node-selector/index.less
0 → 100644
1 | +@import '~@qx/ui/src/style/variable.less'; | ||
2 | + | ||
3 | +@ant-prefix-cls: ~'ant'; | ||
4 | + | ||
5 | +.qx-node-select { | ||
6 | + &-dropdown { | ||
7 | + max-height: calc(8 * 32px); | ||
8 | + overflow: auto; | ||
9 | + background-color: white; | ||
10 | + box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), | ||
11 | + 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05); | ||
12 | + border-radius: 8px; | ||
13 | + | ||
14 | + &-header { | ||
15 | + display: flex; | ||
16 | + align-items: center; | ||
17 | + &__icon { | ||
18 | + width: 14px; | ||
19 | + height: 14px; | ||
20 | + font-size: 14px; | ||
21 | + line-height: 14px; | ||
22 | + // color: @N7; | ||
23 | + margin-right: 4px; | ||
24 | + display: inline-block; | ||
25 | + border-radius: 50%; | ||
26 | + overflow: hidden; | ||
27 | + // border: 1px solid @N6; | ||
28 | + display: flex; | ||
29 | + align-items: center; | ||
30 | + justify-content: center; | ||
31 | + | ||
32 | + > img { | ||
33 | + width: 14px; | ||
34 | + height: 14px; | ||
35 | + } | ||
36 | + } | ||
37 | + } | ||
38 | + | ||
39 | + .qx-node-select-item__icon { | ||
40 | + margin-right: 4px; | ||
41 | + } | ||
42 | + | ||
43 | + .@{ant-prefix-cls}-collapse-header, | ||
44 | + .@{ant-prefix-cls}-collapse-content { | ||
45 | + padding: 7px !important; | ||
46 | + font-size: 14px; | ||
47 | + } | ||
48 | + | ||
49 | + .@{ant-prefix-cls}-collapse-content { | ||
50 | + background-color: @N3 !important; | ||
51 | + padding: 0 !important; | ||
52 | + | ||
53 | + &-box { | ||
54 | + padding: 0 !important; | ||
55 | + } | ||
56 | + } | ||
57 | + } | ||
58 | + | ||
59 | + &-item { | ||
60 | + width: 100%; | ||
61 | + padding: 7px 16px 7px 32px !important; | ||
62 | + &:hover { | ||
63 | + background-color: @N4; | ||
64 | + cursor: pointer; | ||
65 | + } | ||
66 | + | ||
67 | + &__group { | ||
68 | + padding: 0 0 0px 32px !important; | ||
69 | + | ||
70 | + &:hover { | ||
71 | + background-color: transparent; | ||
72 | + } | ||
73 | + .@{ant-prefix-cls}-collapse-header { | ||
74 | + padding: 7px 0 !important; | ||
75 | + } | ||
76 | + } | ||
77 | + } | ||
78 | + | ||
79 | + &-input { | ||
80 | + box-sizing: border-box; | ||
81 | + margin: 0; | ||
82 | + font-variant: tabular-nums; | ||
83 | + list-style: none; | ||
84 | + font-feature-settings: 'tnum', 'tnum'; | ||
85 | + position: relative; | ||
86 | + display: inline-block; | ||
87 | + width: 100%; | ||
88 | + height: 32px; | ||
89 | + min-width: 0; | ||
90 | + padding: 4px 32px 4px 4px; | ||
91 | + color: rgba(0, 0, 0, 0.85); | ||
92 | + font-size: 14px; | ||
93 | + line-height: 1.5715; | ||
94 | + background-color: #fff; | ||
95 | + background-image: none; | ||
96 | + border: 1px solid #d9d9d9; | ||
97 | + border-radius: 4px; | ||
98 | + transition: all 0.3s; | ||
99 | + | ||
100 | + &:hover { | ||
101 | + border-color: @B8; | ||
102 | + } | ||
103 | + | ||
104 | + &__content { | ||
105 | + display: inline-flex; | ||
106 | + color: @N9; | ||
107 | + font-size: 14px; | ||
108 | + | ||
109 | + &-item { | ||
110 | + margin-right: 4px; | ||
111 | + display: flex; | ||
112 | + align-items: center; | ||
113 | + | ||
114 | + &__icon { | ||
115 | + width: 14px; | ||
116 | + height: 14px; | ||
117 | + font-size: 14px; | ||
118 | + line-height: 14px; | ||
119 | + // color: @N7; | ||
120 | + margin-right: 4px; | ||
121 | + display: inline-block; | ||
122 | + border-radius: 50%; | ||
123 | + // overflow: hidden; | ||
124 | + // border: 1px solid @N6; | ||
125 | + display: flex; | ||
126 | + align-items: center; | ||
127 | + justify-content: center; | ||
128 | + | ||
129 | + > img { | ||
130 | + width: inherit; | ||
131 | + height: inherit; | ||
132 | + } | ||
133 | + } | ||
134 | + | ||
135 | + &__arrow { | ||
136 | + display: inline-flex; | ||
137 | + align-items: center; | ||
138 | + color: @N6; | ||
139 | + } | ||
140 | + } | ||
141 | + } | ||
142 | + | ||
143 | + &__suffix { | ||
144 | + position: absolute; | ||
145 | + right: 10px; | ||
146 | + top: 50%; | ||
147 | + transform: translateY(-50%); | ||
148 | + } | ||
149 | + } | ||
150 | +} | ||
151 | + | ||
152 | +.qx-node-select-dropdown { | ||
153 | + > .@{ant-prefix-cls}-collapse { | ||
154 | + > .@{ant-prefix-cls}-collapse-item { | ||
155 | + > .@{ant-prefix-cls}-collapse-content { | ||
156 | + padding-right: 7px !important; | ||
157 | + } | ||
158 | + } | ||
159 | + } | ||
160 | +} |
src/qx-flow-node-selector/index.tsx
0 → 100644
1 | +import { ControlOutlined } from '@ant-design/icons'; | ||
2 | +import { QxWidgetIcon } from '@qx/common'; | ||
3 | +import { Collapse, Dropdown, Empty, Tag } from 'antd'; | ||
4 | +import cls from 'classnames'; | ||
5 | +import { cloneDeep } from 'lodash-es'; | ||
6 | +import React, { useEffect, useMemo, useState } from 'react'; | ||
7 | +import { QxBaseIcon } from '../qx-base-icon'; | ||
8 | +import { request } from '../utils'; | ||
9 | +import './index.less'; | ||
10 | +// import type { FiledType } from '@/interface'; | ||
11 | +// import type { INode } from '@qx/flow'; | ||
12 | + | ||
13 | +const getAppsFields = (params: string[], appId = 'default') => { | ||
14 | + return request.post(`/qx-apaas-lowcode/app/${appId}/fields`, { | ||
15 | + data: params, | ||
16 | + }); | ||
17 | +}; | ||
18 | + | ||
19 | +export const getNodesMap = ( | ||
20 | + nodes: INode[], | ||
21 | + map: Record<string, INode> = {}, | ||
22 | +) => { | ||
23 | + if (!nodes) return {}; | ||
24 | + for (let i = 0; i < nodes.length; i++) { | ||
25 | + const node = nodes[i]; | ||
26 | + if (!map[node.id]) { | ||
27 | + map[node.id] = node; | ||
28 | + } | ||
29 | + | ||
30 | + if (node.children && Array.isArray(node.children)) { | ||
31 | + getNodesMap(node.children, map); | ||
32 | + } | ||
33 | + } | ||
34 | + | ||
35 | + return map; | ||
36 | +}; | ||
37 | + | ||
38 | +export const getParentNodes = ( | ||
39 | + node?: INode, | ||
40 | + treeNodes?: INode[], | ||
41 | + parentNode: INode[] = [], | ||
42 | + allNodes = getNodesMap(treeNodes!), | ||
43 | +) => { | ||
44 | + if (!node || !treeNodes) return []; | ||
45 | + if (node.previousId) { | ||
46 | + parentNode.push(allNodes[node.previousId]); | ||
47 | + getParentNodes(allNodes[node.previousId], treeNodes, parentNode, allNodes); | ||
48 | + } | ||
49 | + | ||
50 | + return parentNode; | ||
51 | +}; | ||
52 | + | ||
53 | +export enum FileTypeMap { | ||
54 | + 'STRING' = '文本', | ||
55 | + 'NUMBER' = '数字', | ||
56 | + 'BOOL' = '布尔', | ||
57 | + 'TIME' = '日期', | ||
58 | + 'OBJECT' = '对象', | ||
59 | + 'ARRAY' = '数组', | ||
60 | + 'FORM' = '表单', | ||
61 | + 'USER' = '人员', | ||
62 | + 'ORG' = '部门', | ||
63 | + 'FILE' = '文件', | ||
64 | + 'PIC' = '图片', | ||
65 | +} | ||
66 | + | ||
67 | +interface NodeFieldDisPlay { | ||
68 | + node?: INode; | ||
69 | + nodes?: INode[]; | ||
70 | + limitTypes?: string[]; | ||
71 | +} | ||
72 | + | ||
73 | +const icon = (icon: any) => { | ||
74 | + if (icon?.$$typeof) { | ||
75 | + return icon; | ||
76 | + } | ||
77 | + if (typeof icon !== 'string' && icon) { | ||
78 | + return <QxBaseIcon type={icon.props.type} />; | ||
79 | + } | ||
80 | + | ||
81 | + return <img src={icon} />; | ||
82 | +}; | ||
83 | + | ||
84 | +export const useNodeFieldDisplay = ({ | ||
85 | + node, | ||
86 | + nodes, | ||
87 | + limitTypes, | ||
88 | +}: NodeFieldDisPlay) => { | ||
89 | + const sourceParentNodes = | ||
90 | + getParentNodes(node, nodes).filter( | ||
91 | + (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 | + } | ||
131 | + | ||
132 | + return getEffectiveNodes(targetParentNodes); | ||
133 | + }, [limitTypes, sourceParentNodes]); | ||
134 | + | ||
135 | + const getId = (val?: string) => { | ||
136 | + if (!val) return; | ||
137 | + const startIndex = val.indexOf('|') + 1; | ||
138 | + const endIndex = val.indexOf('}'); | ||
139 | + if (startIndex < endIndex) { | ||
140 | + return val.substring(startIndex, endIndex); | ||
141 | + } | ||
142 | + return null; | ||
143 | + }; | ||
144 | + | ||
145 | + const genDisplayDom = (value: string) => { | ||
146 | + const itemId = getId(value); | ||
147 | + if (!itemId) return; | ||
148 | + let displayConfig: any[] = []; | ||
149 | + let n = true; | ||
150 | + let index = 0; | ||
151 | + while (n && index <= 20) { | ||
152 | + displayConfig = []; | ||
153 | + const curNode = optionalNodes[index] || {}; | ||
154 | + displayConfig.push({ | ||
155 | + title: curNode.name, | ||
156 | + icon: curNode.icon, | ||
157 | + ...(optionalNodes[index] || {}), | ||
158 | + }); | ||
159 | + // eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
160 | + recursionNodeResult(curNode.data?.result); | ||
161 | + index++; | ||
162 | + } | ||
163 | + | ||
164 | + function recursionNodeResult(result: FiledType[], idx = 1) { | ||
165 | + if (Array.isArray(result)) { | ||
166 | + for (let i = 0; i < result.length; i++) { | ||
167 | + const item = result[i]; | ||
168 | + if (!n) return; | ||
169 | + | ||
170 | + displayConfig.splice(idx, 1, item); | ||
171 | + displayConfig = displayConfig.slice(0, idx + 1); | ||
172 | + | ||
173 | + if (itemId === item.id) { | ||
174 | + n = false; | ||
175 | + return; | ||
176 | + } | ||
177 | + | ||
178 | + if (Array.isArray(item.child)) { | ||
179 | + recursionNodeResult(item.child, idx + 1); | ||
180 | + } | ||
181 | + } | ||
182 | + } else { | ||
183 | + n = false; | ||
184 | + } | ||
185 | + } | ||
186 | + | ||
187 | + return ( | ||
188 | + <> | ||
189 | + {displayConfig?.map((item, idx) => ( | ||
190 | + <div | ||
191 | + key={idx} | ||
192 | + className='qx-node-select-input__content-item' | ||
193 | + > | ||
194 | + {item.icon && ( | ||
195 | + <span | ||
196 | + className='qx-node-select-input__content-item__icon' | ||
197 | + > | ||
198 | + {icon(item.icon)} | ||
199 | + </span> | ||
200 | + )} | ||
201 | + <span | ||
202 | + className='qx-node-select-input__content-item__text' | ||
203 | + > | ||
204 | + {item.type && | ||
205 | + FileTypeMap[item.type] && | ||
206 | + !item.icon && | ||
207 | + `[${FileTypeMap[item.type]}]`} | ||
208 | + {item.title} | ||
209 | + </span> | ||
210 | + {idx !== displayConfig.length - 1 && ( | ||
211 | + <span | ||
212 | + className='qx-node-select-input__content-item__arrow' | ||
213 | + > | ||
214 | + <svg | ||
215 | + xmlns="http://www.w3.org/2000/svg" | ||
216 | + width="1em" | ||
217 | + height="1em" | ||
218 | + fill="currentColor" | ||
219 | + > | ||
220 | + <path d="M5.80469 13.6423L4.86188 12.6995L9.57592 7.98548L4.86188 3.27143L5.80469 2.32863L10.9901 7.51403C10.9901 7.51406 10.9901 7.51407 10.5187 7.98548L10.9901 7.51403L11.4615 7.98548L5.80469 13.6423Z" /> | ||
221 | + </svg> | ||
222 | + </span> | ||
223 | + )} | ||
224 | + </div> | ||
225 | + ))} | ||
226 | + </> | ||
227 | + ); | ||
228 | + }; | ||
229 | + | ||
230 | + return { | ||
231 | + genDisplayDom, | ||
232 | + optionalNodes, | ||
233 | + }; | ||
234 | +}; | ||
235 | + | ||
236 | +const SelectItem = (props: any) => { | ||
237 | + if (props.type === 'FORM') { | ||
238 | + return ( | ||
239 | + <div className={cls('qx-node-select-item', 'qx-node-select-item__group')}> | ||
240 | + <Collapse | ||
241 | + ghost | ||
242 | + expandIconPosition="end" | ||
243 | + items={[ | ||
244 | + { | ||
245 | + label: ( | ||
246 | + <span> | ||
247 | + {/* @ts-ignore */} | ||
248 | + {`[${FileTypeMap[props.type]}]`} | ||
249 | + {props.title} | ||
250 | + </span> | ||
251 | + ), | ||
252 | + key: props.id, | ||
253 | + children: props.child?.map((item: any, idx: number) => { | ||
254 | + return ( | ||
255 | + <SelectItem | ||
256 | + key={item.code || idx} | ||
257 | + {...item} | ||
258 | + onClick={props.onClick} | ||
259 | + /> | ||
260 | + ); | ||
261 | + }), | ||
262 | + }, | ||
263 | + ]} | ||
264 | + /> | ||
265 | + </div> | ||
266 | + ); | ||
267 | + } | ||
268 | + | ||
269 | + if (!props.child) { | ||
270 | + return ( | ||
271 | + <div | ||
272 | + className={cls('qx-node-select-item')} | ||
273 | + onClick={() => props.onClick(props)} | ||
274 | + > | ||
275 | + {/* @ts-ignore */} | ||
276 | + {props.icon ? props.icon : `[${FileTypeMap[props.type]}]`} | ||
277 | + {props.title} | ||
278 | + </div> | ||
279 | + ); | ||
280 | + } | ||
281 | + | ||
282 | + return ( | ||
283 | + <div className={cls('qx-node-select-item', 'qx-node-select-item__group')}> | ||
284 | + <Collapse | ||
285 | + ghost | ||
286 | + expandIconPosition="end" | ||
287 | + items={[ | ||
288 | + { | ||
289 | + label: ( | ||
290 | + <span> | ||
291 | + {/* @ts-ignore */} | ||
292 | + {`[${FileTypeMap[props.type]}]`} | ||
293 | + {props.title} | ||
294 | + </span> | ||
295 | + ), | ||
296 | + key: props.id, | ||
297 | + children: props.child?.map((item: any, idx: number) => { | ||
298 | + return ( | ||
299 | + <SelectItem | ||
300 | + key={item.code || idx} | ||
301 | + {...item} | ||
302 | + onClick={props.onClick} | ||
303 | + /> | ||
304 | + ); | ||
305 | + }), | ||
306 | + }, | ||
307 | + ]} | ||
308 | + /> | ||
309 | + </div> | ||
310 | + ); | ||
311 | +}; | ||
312 | + | ||
313 | +export const QxFlowNodeFieldSelector: React.FC<NodeFieldSelectProps> = ( | ||
314 | + props, | ||
315 | +) => { | ||
316 | + const { mode = 'select' } = props; | ||
317 | + | ||
318 | + const [visible, setVisible] = useState(false); | ||
319 | + | ||
320 | + const [inputDisplay, setInputDisplay] = useState<React.ReactNode>(); | ||
321 | + | ||
322 | + const { optionalNodes, genDisplayDom } = useNodeFieldDisplay(props); | ||
323 | + | ||
324 | + const getOptions = () => { | ||
325 | + if (!optionalNodes.length) { | ||
326 | + return <Empty />; | ||
327 | + } | ||
328 | + return optionalNodes.map((node) => ({ | ||
329 | + label: ( | ||
330 | + <div className={cls('qx-node-select-dropdown-header')}> | ||
331 | + <span className={cls('qx-node-select-dropdown-header__icon')}> | ||
332 | + {icon(node.icon)} | ||
333 | + </span> | ||
334 | + {node.name} | ||
335 | + </div> | ||
336 | + ), | ||
337 | + key: node.id, | ||
338 | + children: Array.isArray(node.data?.result) | ||
339 | + ? (node.data.result as FiledType[])?.map((item) => { | ||
340 | + return ( | ||
341 | + <SelectItem | ||
342 | + key={item.id} | ||
343 | + {...item} | ||
344 | + onClick={(value: FiledType) => { | ||
345 | + // eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
346 | + handleItemClick(node.id, value || item); | ||
347 | + }} | ||
348 | + /> | ||
349 | + ); | ||
350 | + }) | ||
351 | + : [], | ||
352 | + })); | ||
353 | + }; | ||
354 | + | ||
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 | + const handleItemClick = (nodeKey: string, item: any) => { | ||
446 | + const newValue = '${' + `${nodeKey}|${item.id}` + '}'; | ||
447 | + props.onChange?.(newValue, item); | ||
448 | + if (!props.children) { | ||
449 | + renderInputDisplay(newValue); | ||
450 | + } | ||
451 | + setVisible(false); | ||
452 | + }; | ||
453 | + | ||
454 | + useEffect(() => { | ||
455 | + handleGetAppsFields(); | ||
456 | + }, []); | ||
457 | + | ||
458 | + useEffect(() => { | ||
459 | + setVisible(props.open ?? false); | ||
460 | + }, [props.open]); | ||
461 | + | ||
462 | + return ( | ||
463 | + <div className={cls('qx-node-select')}> | ||
464 | + <Dropdown | ||
465 | + trigger={['click']} | ||
466 | + overlayStyle={{ width: `${props?.width}px` }} | ||
467 | + overlayClassName={cls('qx-node-select-dropdown')} | ||
468 | + open={visible} | ||
469 | + dropdownRender={() => ( | ||
470 | + <Collapse ghost expandIconPosition="end" items={getOptions()} /> | ||
471 | + )} | ||
472 | + onOpenChange={(open) => { | ||
473 | + if (mode === 'select') { | ||
474 | + setVisible(open); | ||
475 | + } | ||
476 | + }} | ||
477 | + > | ||
478 | + {props.children ? ( | ||
479 | + props.children | ||
480 | + ) : ( | ||
481 | + <div className={cls('qx-node-select-input')}> | ||
482 | + {inputDisplay} | ||
483 | + {mode === 'variable' && ( | ||
484 | + <span | ||
485 | + className="qx-node-select-input__suffix" | ||
486 | + onClick={() => setVisible(!visible)} | ||
487 | + > | ||
488 | + <ControlOutlined /> | ||
489 | + </span> | ||
490 | + )} | ||
491 | + </div> | ||
492 | + )} | ||
493 | + </Dropdown> | ||
494 | + </div> | ||
495 | + ); | ||
496 | +}; | ||
497 | + | ||
498 | +export interface NodeFieldSelectProps { | ||
499 | + node: INode; | ||
500 | + nodes: INode[]; | ||
501 | + onChange?: (val: any, opt?: FiledType) => void; | ||
502 | + value?: string; | ||
503 | + children?: React.ReactNode; | ||
504 | + limitTypes?: string[]; | ||
505 | + width?: number; | ||
506 | + mode?: 'select' | 'variable'; | ||
507 | + open?: boolean; | ||
508 | +} | ||
509 | + | ||
510 | +export interface FiledType { | ||
511 | + type: string; | ||
512 | + id: string; | ||
513 | + title: string; | ||
514 | + code: string; | ||
515 | + valueOpt?: string; | ||
516 | + mappingValues?: any[]; | ||
517 | + detailValues?: any; | ||
518 | + condition?: any; | ||
519 | + child?: FiledType[]; | ||
520 | + qxProps?: { | ||
521 | + formId?: string; | ||
522 | + }; | ||
523 | + [key: string]: any; | ||
524 | +} | ||
525 | + | ||
526 | +export interface INode { | ||
527 | + id: string; | ||
528 | + type: string; | ||
529 | + name: string; | ||
530 | + data?: any; | ||
531 | + children?: INode[]; | ||
532 | + path?: string[]; | ||
533 | + configuring?: boolean; | ||
534 | + validateStatusError?: boolean; | ||
535 | + next?: string[]; | ||
536 | + tools?: string[] | React.FC<any>[]; | ||
537 | + debuggerError?: boolean; | ||
538 | + debuggerSuccess?: boolean; | ||
539 | + [key: string]: any; | ||
540 | +} |
src/qx-widget-icon/index.md
0 → 100644
1 | +--- | ||
2 | +nav: | ||
3 | + path: /component | ||
4 | + title: 组件 | ||
5 | + order: 1 | ||
6 | +group: | ||
7 | + path: /common | ||
8 | + title: 表单字段图标 | ||
9 | + order: 0 | ||
10 | +--- | ||
11 | + | ||
12 | +## QxWidgetIcon 表单字段图标 | ||
13 | + | ||
14 | +### 表单字段图标 | ||
15 | + | ||
16 | +```tsx | ||
17 | +import { QxWidgetIcon } from '@qx/common'; | ||
18 | + | ||
19 | +export default () => { | ||
20 | + return <QxWidgetIcon widgetName="qxInput" />; | ||
21 | +}; | ||
22 | +``` |
src/qx-widget-icon/index.tsx
0 → 100644
1 | +import { QxBaseIcon } from '../qx-base-icon'; | ||
2 | + | ||
3 | +export const QxWidgetIcon = ({ widgetName }: { widgetName: string }) => { | ||
4 | + let iconType: string = ''; | ||
5 | + switch (widgetName) { | ||
6 | + case 'qxInput': | ||
7 | + iconType = 'icon-field-text'; | ||
8 | + break; | ||
9 | + case 'qxNumber': | ||
10 | + iconType = 'icon-field-num'; | ||
11 | + break; | ||
12 | + case 'dateTime': | ||
13 | + case 'qxDatetime': | ||
14 | + iconType = 'icon-field-datetime'; | ||
15 | + break; | ||
16 | + case 'qxTime': | ||
17 | + iconType = 'icon-field-time'; | ||
18 | + break; | ||
19 | + case 'qxSwitch': | ||
20 | + iconType = 'icon-field-boolean'; | ||
21 | + break; | ||
22 | + case 'qxSelect': | ||
23 | + iconType = 'icon-field-select'; | ||
24 | + break; | ||
25 | + case 'qxMultiSelect': | ||
26 | + iconType = 'icon-field-multi-select'; | ||
27 | + break; | ||
28 | + case 'qxMobile': | ||
29 | + iconType = 'icon-field-mobile'; | ||
30 | + break; | ||
31 | + case 'qxMoney': | ||
32 | + iconType = 'icon-field-finance'; | ||
33 | + break; | ||
34 | + case 'qxEmail': | ||
35 | + iconType = 'icon-field-email'; | ||
36 | + break; | ||
37 | + case 'qxPercent': | ||
38 | + iconType = 'icon-field-percent'; | ||
39 | + break; | ||
40 | + case 'qxUpload': | ||
41 | + iconType = 'icon-field-file'; | ||
42 | + break; | ||
43 | + case 'qxUploadImage': | ||
44 | + iconType = 'icon-field-img'; | ||
45 | + break; | ||
46 | + case 'qxAddress': | ||
47 | + iconType = 'icon-field-address'; | ||
48 | + break; | ||
49 | + case 'qxRichText': | ||
50 | + iconType = 'icon-field-richtext'; | ||
51 | + break; | ||
52 | + case 'qxLocation': | ||
53 | + iconType = 'icon-field-location'; | ||
54 | + break; | ||
55 | + case 'orgSelector': | ||
56 | + iconType = 'icon-field-department'; | ||
57 | + break; | ||
58 | + case 'userSelector': | ||
59 | + iconType = 'icon-field-user'; | ||
60 | + break; | ||
61 | + case 'createdBy': | ||
62 | + case 'created_by': | ||
63 | + iconType = 'icon-field-created-by'; | ||
64 | + break; | ||
65 | + case 'createdAt': | ||
66 | + case 'created_at': | ||
67 | + iconType = 'icon-field-created-at'; | ||
68 | + break; | ||
69 | + case 'updatedBy': | ||
70 | + case 'updated_by': | ||
71 | + iconType = 'icon-field-updated-by'; | ||
72 | + break; | ||
73 | + case 'updatedAt': | ||
74 | + case 'updated_at': | ||
75 | + iconType = 'icon-field-updated-at'; | ||
76 | + break; | ||
77 | + case 'qxBizNo': | ||
78 | + iconType = 'icon-field-no'; | ||
79 | + break; | ||
80 | + case 'relSelector': | ||
81 | + iconType = 'icon-field-rel'; | ||
82 | + break; | ||
83 | + case 'relField': | ||
84 | + iconType = 'icon-field-ref'; | ||
85 | + break; | ||
86 | + case 'subform': | ||
87 | + case 'table': | ||
88 | + iconType = 'icon-field-subform'; | ||
89 | + break; | ||
90 | + case 'qxTree': | ||
91 | + iconType = 'icon-field-tree'; | ||
92 | + break; | ||
93 | + case 'qxFormula': | ||
94 | + iconType = 'icon-field-formula'; | ||
95 | + break; | ||
96 | + case 'qxDivider': | ||
97 | + iconType = 'icon-field-divider'; | ||
98 | + break; | ||
99 | + case 'qxRemark': | ||
100 | + iconType = 'icon-field-remark'; | ||
101 | + break; | ||
102 | + case 'qxEmbed': | ||
103 | + iconType = 'icon-field-embed '; | ||
104 | + break; | ||
105 | + case 'qxTabs': | ||
106 | + iconType = 'icon-editor_tab'; | ||
107 | + break; | ||
108 | + case 'qxLayout': | ||
109 | + iconType = 'icon-editor_grid'; | ||
110 | + break; | ||
111 | + case 'simple': | ||
112 | + iconType = 'icon-editor_layout'; | ||
113 | + break; | ||
114 | + case 'tabC': | ||
115 | + iconType = 'icon-editor_tab'; | ||
116 | + break; | ||
117 | + case 'layout': | ||
118 | + iconType = 'icon-editor_grid'; | ||
119 | + break; | ||
120 | + default: | ||
121 | + iconType = 'icon-field-text'; | ||
122 | + break; | ||
123 | + } | ||
124 | + return <QxBaseIcon type={iconType} />; | ||
125 | +}; |