Showing
10 changed files
with
907 additions
and
176 deletions
| 1 | { | 1 | { |
| 2 | "name": "@qx/common", | 2 | "name": "@qx/common", |
| 3 | - "version": "3.0.0-alpha.16", | 3 | + "version": "3.0.0-alpha.17", |
| 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', |
| @@ -56,14 +56,11 @@ export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => { | @@ -56,14 +56,11 @@ export const QxBaseCondition: React.FC<QxBaseConditionProps> = (props) => { | ||
| 56 | getDefaultConditionOptions(item), | 56 | getDefaultConditionOptions(item), |
| 57 | props.value?.[key] || {}, | 57 | props.value?.[key] || {}, |
| 58 | )} | 58 | )} |
| 59 | + nodes={props.nodes} | ||
| 60 | + node={props.node} | ||
| 59 | field={item} | 61 | field={item} |
| 60 | onChange={(val) => handleItemChange(val, key)} | 62 | onChange={(val) => handleItemChange(val, key)} |
| 61 | remove={() => handleDelete(key)} | 63 | remove={() => handleDelete(key)} |
| 62 | - ValueAssignmentPopup={ | ||
| 63 | - item.showValueAssignmentPopup ?? true | ||
| 64 | - ? props.ValueAssignmentPopup | ||
| 65 | - : undefined | ||
| 66 | - } | ||
| 67 | /> | 64 | /> |
| 68 | </div> | 65 | </div> |
| 69 | )); | 66 | )); |
| @@ -85,7 +82,7 @@ export interface QxBaseConditionField { | @@ -85,7 +82,7 @@ export interface QxBaseConditionField { | ||
| 85 | } | 82 | } |
| 86 | 83 | ||
| 87 | export interface QxBaseConditionOptionsProps extends QxBaseConditionField { | 84 | export interface QxBaseConditionOptionsProps extends QxBaseConditionField { |
| 88 | - showValueAssignmentPopup?: boolean; | 85 | + showValueAssignment?: boolean; |
| 89 | isMultiple?: boolean; | 86 | isMultiple?: boolean; |
| 90 | isRange?: boolean; | 87 | isRange?: boolean; |
| 91 | [key: string]: any; | 88 | [key: string]: any; |
| @@ -99,5 +96,6 @@ export interface QxBaseConditionProps { | @@ -99,5 +96,6 @@ export interface QxBaseConditionProps { | ||
| 99 | options: QxBaseConditionOptionsProps[]; | 96 | options: QxBaseConditionOptionsProps[]; |
| 100 | value: any[]; | 97 | value: any[]; |
| 101 | onChange?: (val: any[]) => void; | 98 | onChange?: (val: any[]) => void; |
| 102 | - ValueAssignmentPopup?: React.FC<ValueAssignmentPopupProps>; | 99 | + nodes?: INode[] |
| 100 | + node?: INode | ||
| 103 | } | 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 | * 名称转换 |
src/qx-flow-node-selector/index.less
0 → 100644
| 1 | +@import '~@qx/ui/src/style/variable.less'; | ||
| 2 | +@ant-prefix-cls: ~'ant'; | ||
| 3 | + | ||
| 4 | +.qx-node-select { | ||
| 5 | + &-dropdown { | ||
| 6 | + max-height: calc(8 * 32px); | ||
| 7 | + overflow: auto; | ||
| 8 | + background-color: white; | ||
| 9 | + box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), | ||
| 10 | + 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05); | ||
| 11 | + border-radius: 8px; | ||
| 12 | + | ||
| 13 | + &-header { | ||
| 14 | + display: flex; | ||
| 15 | + align-items: center; | ||
| 16 | + &__icon { | ||
| 17 | + width: 14px; | ||
| 18 | + height: 14px; | ||
| 19 | + font-size: 14px; | ||
| 20 | + line-height: 14px; | ||
| 21 | + // color: @N7; | ||
| 22 | + margin-right: 4px; | ||
| 23 | + display: inline-block; | ||
| 24 | + border-radius: 50%; | ||
| 25 | + overflow: hidden; | ||
| 26 | + // border: 1px solid @N6; | ||
| 27 | + display: flex; | ||
| 28 | + align-items: center; | ||
| 29 | + justify-content: center; | ||
| 30 | + | ||
| 31 | + > img { | ||
| 32 | + width: 14px; | ||
| 33 | + height: 14px; | ||
| 34 | + } | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + .qx-node-select-item__icon { | ||
| 39 | + margin-right: 4px; | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + .@{ant-prefix-cls}-collapse-header, | ||
| 43 | + .@{ant-prefix-cls}-collapse-content { | ||
| 44 | + padding: 7px !important; | ||
| 45 | + font-size: 14px; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + .@{ant-prefix-cls}-collapse-content { | ||
| 49 | + background-color: @N3 !important; | ||
| 50 | + padding: 0 !important; | ||
| 51 | + | ||
| 52 | + &-box { | ||
| 53 | + padding: 0 !important; | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + &-item { | ||
| 59 | + width: 100%; | ||
| 60 | + padding: 7px 16px 7px 32px !important; | ||
| 61 | + &:hover { | ||
| 62 | + background-color: @N4; | ||
| 63 | + cursor: pointer; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + &__group { | ||
| 67 | + padding: 0 0 0px 32px !important; | ||
| 68 | + | ||
| 69 | + &:hover { | ||
| 70 | + background-color: transparent; | ||
| 71 | + } | ||
| 72 | + .@{ant-prefix-cls}-collapse-header { | ||
| 73 | + padding: 7px 0 !important; | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + &-input { | ||
| 79 | + box-sizing: border-box; | ||
| 80 | + margin: 0; | ||
| 81 | + font-variant: tabular-nums; | ||
| 82 | + list-style: none; | ||
| 83 | + font-feature-settings: 'tnum', 'tnum'; | ||
| 84 | + position: relative; | ||
| 85 | + display: inline-block; | ||
| 86 | + width: 100%; | ||
| 87 | + height: 32px; | ||
| 88 | + min-width: 0; | ||
| 89 | + padding: 4px 32px 4px 4px; | ||
| 90 | + color: rgba(0, 0, 0, 0.85); | ||
| 91 | + font-size: 14px; | ||
| 92 | + line-height: 1.5715; | ||
| 93 | + background-color: #fff; | ||
| 94 | + background-image: none; | ||
| 95 | + border: 1px solid #d9d9d9; | ||
| 96 | + border-radius: 4px; | ||
| 97 | + transition: all 0.3s; | ||
| 98 | + | ||
| 99 | + &:hover { | ||
| 100 | + border-color: @B8; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + &__content { | ||
| 104 | + display: inline-flex; | ||
| 105 | + color: @N9; | ||
| 106 | + font-size: 14px; | ||
| 107 | + | ||
| 108 | + &-item { | ||
| 109 | + margin-right: 4px; | ||
| 110 | + display: flex; | ||
| 111 | + align-items: center; | ||
| 112 | + | ||
| 113 | + &__icon { | ||
| 114 | + width: 14px; | ||
| 115 | + height: 14px; | ||
| 116 | + font-size: 14px; | ||
| 117 | + line-height: 14px; | ||
| 118 | + // color: @N7; | ||
| 119 | + margin-right: 4px; | ||
| 120 | + display: inline-block; | ||
| 121 | + border-radius: 50%; | ||
| 122 | + // overflow: hidden; | ||
| 123 | + // border: 1px solid @N6; | ||
| 124 | + display: flex; | ||
| 125 | + align-items: center; | ||
| 126 | + justify-content: center; | ||
| 127 | + | ||
| 128 | + > img { | ||
| 129 | + width: inherit; | ||
| 130 | + height: inherit; | ||
| 131 | + } | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + &__arrow { | ||
| 135 | + display: inline-flex; | ||
| 136 | + align-items: center; | ||
| 137 | + color: @N6; | ||
| 138 | + } | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + &__suffix { | ||
| 143 | + position: absolute; | ||
| 144 | + right: 10px; | ||
| 145 | + top: 50%; | ||
| 146 | + transform: translateY(-50%); | ||
| 147 | + } | ||
| 148 | + } | ||
| 149 | +} | ||
| 150 | + | ||
| 151 | +:global { | ||
| 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 | + } | ||
| 161 | +} |
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 styles from './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={styles['qx-node-select-input__content-item']} | ||
| 193 | + > | ||
| 194 | + {item.icon && ( | ||
| 195 | + <span | ||
| 196 | + className={styles['qx-node-select-input__content-item__icon']} | ||
| 197 | + > | ||
| 198 | + {icon(item.icon)} | ||
| 199 | + </span> | ||
| 200 | + )} | ||
| 201 | + <span | ||
| 202 | + className={styles['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={styles['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 | +}; |