index.tsx 10.3 KB
import { Divider, Input, Menu, Popover } from 'antd';

import * as React from 'react';
import type { ReactElement } from 'react';
import { useEffect, useState } from 'react';
import { QxFieldItem } from '@qx/common';
import { useDebounceFn } from 'ahooks';
import { isEmpty } from 'lodash-es';
import { QxBaseIcon } from '@qx/common';
import './index.less';

export type OptionFieldExtract = {
  fieldType?: string;
  widget: string;
  design?: any;
  relId?: string;
  //关联数据集的才有
  optionsRef?: string;
  //关联属性,真实的字段组件
  refWidget?: string;
  //关联属性,真实的字段类型
  refType?: string;
  required?: boolean;
  // 是否是默认系统字段,值为true时是未配置的系统字段
  $default?: boolean;
  // 卡片设计 特殊字段配置 回显所用
  renderData?: any;
};

export type OptionField = {
  code: string;
  name: string;
  disabled?: boolean;
  //当disabled=true的时候extract不存在
  extract?: OptionFieldExtract;
};

interface QxFieldPopoverProp {
  data: OptionField[];
  widgets?: string[]; //需要展示的widgets
  exclude?: string[]; //排除的字段
  width?: string; //pop 宽度
  trigger?: 'click' | 'hover' | undefined;
  onSelect: (field: OptionField) => void;
  disabled?: boolean;
  hiddenAfterTrigger?: boolean;
  popFooter?: ReactElement;
  children?: any;
}

export const QxFieldPopover: React.FC<QxFieldPopoverProp> = (props) => {
  // const [fieldFlatten, setFieldFlatten] = useState<any>({})
  const [fields, setFields] = useState<any>([]);
  const [filterFields, setFilterFields] = useState<any>([]);
  const [visible, setVisible] = useState<boolean>(false);
  //TODO 搜索
  const [keyword, setKeyword] = useState<string>();

  const getUsefulFieldProp = (field: any) => {
    let mode = 'widget'; //TODO 接口废弃,后续要删掉
    if (field?.extract) {
      mode = 'option';
    }
    let widget = field?.propertyWidget || field.widget;
    let code = field?.fieldName || field.code;
    let name = field?.fieldComment || field.title;
    let relFunId = field?.relFunId;
    if (mode === 'option') {
      widget = field?.extract.widget;
      relFunId = field?.extract.relId;
      code = field?.code;
      name = field?.name;
    }
    return {
      widget,
      code,
      name,
      relFunId,
    };
  };
  // @ts-ignore
  const excludeFields = (list: OptionField[]) => {
    // @ts-ignore
    return list.filter((item: any) => {
      if (item.children && item.children.length === 0) {
        return false;
      }

      let allow = true;
      const { widget, code } = getUsefulFieldProp(item);
      if (props.widgets && props.widgets.length > 0 && props.widgets.indexOf(widget) === -1) {
        return false;
      }
      if (!props.exclude || props.exclude.length === 0) {
        allow = true;
      } else {
        allow = props.exclude.indexOf(code) === -1;
      }
      return allow;
    });
  };
  useEffect(() => {
    if (!isEmpty(props.data)) {
      const _fields = excludeFields(props.data);
      setFields(_fields);
      setFilterFields(_fields);
      // setFieldFlatten(flatFields(_fields))
    }
  }, [props.data]);

  const handleClick = (item: any) => {
    if (props.hiddenAfterTrigger) {
      setVisible(false);
    }
    props.onSelect(item);
  };

  const { run } = useDebounceFn((field) => handleClick(field), {
    wait: 300,
    leading: true,
    trailing: false,
  });

  useEffect(() => {
    if (!keyword) {
      setFilterFields([...fields]);
    } else {
      const _filterFields: any = [];

      fields.forEach((item: any) => {
        const _item = { ...item };
        _item.children = [];
        if (item?.children?.length) {
          item?.children.forEach((children: any) => {
            if (
              children?.titleStr?.indexOf(keyword) > -1 ||
              children?.name?.indexOf(keyword) > -1
            ) {
              _item.children.push(children);
            }
          });
          if (_item.children?.length) {
            _filterFields.push(_item);
          }
        } else {
          if (item?.titleStr?.indexOf(keyword) > -1 || item?.name?.indexOf(keyword) > -1) {
            _filterFields.push(item);
          }
        }
      });
      /*const _filterFields = fields.filter(
        (item) => item?.titleStr?.indexOf(keyword) > -1 || item?.name?.indexOf(keyword) > -1,
      );*/
      setFilterFields(_filterFields);
    }
  }, [keyword, fields]);

  const handleChange = (_keyword: string) => {
    setKeyword(_keyword.trim());
  };

  const fieldsPopContent = () => {
    return (
      <div style={{ width: props.width || '192px' }}>
        {!fields?.length ? (
          <div
            className={'ant-empty-normal'}
            style={{
              textAlign: 'center',
              margin: '10px 0',
            }}
          >
            没有可选字段
          </div>
        ) : (
          <>
            <div
              onMouseDown={(e) => {
                e.preventDefault();
              }}
            >
              <Input
                bordered={false}
                value={keyword}
                className={'qx-fields-popover__search'}
                placeholder={'搜索'}
                allowClear
                prefix={<QxBaseIcon type={'icon-app-search-line'} />}
                onChange={(e) => {
                  handleChange(e.target.value);
                }}
              />
            </div>
            <Divider style={{ margin: 0 }} />
            {!filterFields.length ? (
              <div
                className={'ant-empty-normal'}
                style={{
                  textAlign: 'center',
                  margin: '10px 0',
                }}
              >
                暂无相关字段
              </div>
            ) : (
              <Menu
                mode="inline"
                className={'qx-fields-pop-content'}
                selectedKeys={[]}
                inlineIndent={12}
              >
                {filterFields.map((field: any) => {
                  if (!!field?.children?.length) {
                    return (
                      <Menu.SubMenu
                        key={field.code}
                        title={
                          field.title || (
                            <QxFieldItem
                              widget={field.extract && field.extract.widget}
                              name={field.name}
                            />
                          )
                        }
                      >
                        {field.children.map((item: any) => {
                          if ((item.children || []).length) {
                            return (
                              <Menu.SubMenu
                                key={item.code}
                                title={
                                  item.title || (
                                    <QxFieldItem
                                      widget={field.extract && field.extract.widget}
                                      name={field.name}
                                    />
                                  )
                                }
                              >
                                {(item.children || []).map((_it: any) => {
                                  return (
                                    <Menu.Item
                                      key={_it.code}
                                      onClick={() => {
                                        handleClick(_it);
                                      }}
                                    >
                                      {_it.title || (
                                        <QxFieldItem
                                          widget={field.extract && field.extract.widget}
                                          name={field.name}
                                        />
                                      )}
                                    </Menu.Item>
                                  );
                                })}
                              </Menu.SubMenu>
                            );
                          } else {
                            return (
                              <Menu.Item
                                key={item.code}
                                onClick={() => {
                                  handleClick(item);
                                }}
                              >
                                {item.title || (
                                  <QxFieldItem
                                    widget={field.extract && field.extract.widget}
                                    name={field.name}
                                  />
                                )}
                              </Menu.Item>
                            );
                          }
                        })}
                      </Menu.SubMenu>
                    );
                  } else {
                    return (
                      <Menu.Item
                        style={{
                          display:
                            keyword && field?.name?.indexOf(keyword) === -1 ? 'none' : 'block',
                        }}
                        onClick={() => {
                          run(field);
                        }}
                        key={field.code}
                      >
                        {field.title || (
                          <QxFieldItem
                            widget={field.extract && field.extract.widget}
                            name={field.name}
                          />
                        )}
                      </Menu.Item>
                    );
                  }
                })}
              </Menu>
            )}
          </>
        )}
        {props.popFooter ? <div className="qx-field-pop__footer">{props.popFooter}</div> : null}
      </div>
    );
  };

  return (
    <Popover
      overlayClassName={'qx-fields-popover'}
      // getPopupContainer={(triggerNode) => triggerNode}
      content={fieldsPopContent()}
      placement={'bottomRight'}
      trigger={props.disabled ? undefined : props.trigger || 'click'}
      open={visible}
      onOpenChange={(v) => {
        if (!v) {
          setTimeout(() => {
            setKeyword('');
            setFilterFields([...fields]);
          }, 0);
        }
        setVisible(v);
      }}
    >
      {props.children}
    </Popover>
  );
}