core.tsx 7.14 KB
import * as React from 'react';
import { useCallback, useEffect, useImperativeHandle, useState } from 'react';
import { Checkbox, Empty, Input, Spin } from 'antd';
import Menu from 'antd/es/menu';
import {QxBaseIcon} from '@qx/common';
import { getGroups } from './service';
import { cloneDeep } from 'lodash-es';

type GroupCoreProps = {
  appId?: string;
  cRef?: any;
  multiple?: boolean;
  placeholder?: string;
  params?: any;
  onSelect?: (selectedKeys: string[], selectedData: GroupModel[]) => void;
  request: any;
};

export interface GroupModel {
  id: string;
  name: string;
  appId?: string;
  code: string;
  categoryId: string;
  visible?: boolean;
  groupList: GroupModel[];
}

const GroupSelCore: React.FC<GroupCoreProps> = ({
  appId,
  cRef,
  multiple,
  placeholder,
  onSelect,
  ...props
}) => {
  const [loading, setLoading] = useState<boolean>(true);

  const [data, setData] = useState<GroupModel[]>([]);

  const [selectedData, setSelectedData] = useState<GroupModel[]>([]);
  const [selectedKeys, setSelectedKeys] = useState<string[]>();
  const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
  const [keywords, setKeywords] = useState<string>('');

  const requestData = useCallback(() => {
    setLoading(true);
    // todo 当前为指定appCode,待接口修改为appId传入(不用appId了)
    getGroups(props.request).then((res) => {
      const groups: GroupModel[] = res;
      let _selectKey = '';
      if (groups) {
        const _expandedKeys: string[] = [];
        groups.forEach((item) => {
          _expandedKeys.push(item.id);
          if (!_selectKey && item.groupList && item.groupList.length > 0) {
            _selectKey = item.groupList[0].id;
          }
        });
        if (_selectKey && !multiple) {
          setSelectedKeys([_selectKey]);
        }
        setExpandedKeys(_expandedKeys);
        setData(groups);
        setLoading(false);
      }
    });
  }, []);

  useEffect(() => {
    requestData();
  }, [requestData]);

  useEffect(() => {
    const isOnSelect = onSelect ? onSelect : () => {};
    if (selectedKeys) {
      isOnSelect(selectedKeys, selectedData);
    }
  }, [onSelect, selectedKeys, selectedData]);

  const handleSelect = (selectData: { selectedKeys: string[] }) => {
    //单选走这里
    if (!multiple) {
      setSelectedKeys(selectData.selectedKeys);
    }
  };
  useImperativeHandle(cRef, () => ({
    // 暴露给父组件
    remove: (index: number) => {
      let _selectedKeys: string[] = [];
      let _selectedData: GroupModel[] = [];
      if (selectedKeys && selectedKeys.length > 0) {
        _selectedKeys = [...selectedKeys];
        _selectedData = [...selectedData];
        _selectedKeys.splice(index, 1);
        _selectedData.splice(index, 1);
        setSelectedData(_selectedData);
        setSelectedKeys(_selectedKeys);
      }
    },
    emptySelect: () => {
      setSelectedData([]);
      setSelectedKeys([]);
    },
  }));
  const handleMultiSelect = (checked: boolean, item: GroupModel) => {
    let _selectedKeys: string[] = [];
    let _selectedData: GroupModel[] = [];
    if (selectedKeys) {
      _selectedKeys = [...selectedKeys];
      _selectedData = [...selectedData];
    }

    if (checked) {
      _selectedKeys.push(item.id);
      _selectedData.push(item);
    } else {
      const index = _selectedKeys.indexOf(item.id);
      if (index > -1) {
        _selectedKeys.splice(index, 1);
        _selectedData.splice(index, 1);
      }
    }

    setSelectedData(_selectedData);
    setSelectedKeys(_selectedKeys);
  };

  //多选走这里
  const filter = (word: string) => {
    setKeywords(word);
    const traverse = function (node: any) {
      const childNodes = node.groupList || [];

      childNodes.forEach((child) => {
        child.visible = child.name.indexOf(word) > -1;

        traverse(child);
      });

      if (!node.visible && childNodes.length) {
        node.visible = childNodes.some((child) => child.visible);
      }
    };

    if (data) {
      const _data = cloneDeep(data);
      _data.forEach((item) => {
        traverse(item);
      });
      setData(_data);
    }
  };

  const handleSearch = (e: React.KeyboardEvent<HTMLInputElement>) => {
    e.stopPropagation();
    // @ts-ignore
    filter(e.target.value.trim());
  };
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    // @ts-ignore
    if (e.type === 'click' && e.target.value === '' && data) {
      //如果是清空
      filter('');
    }
  };

  const renderText = (text: string) => {
    let title = <> {text}</>;
    if (keywords) {
      const index = text.indexOf(keywords);
      if (index > -1) {
        title = (
          <>
            {text.substr(0, index)}
            <span className={'qx-keywords-highlight'}>{keywords}</span>
            {text.substr(index + keywords.length)}
          </>
        );
      }
    }
    return title;
  };

  return (
    <div className={'qx-search-menus__wrap'}>
      <Input
        // style={{ display: 'none' }}
        className={'qx-selector-sub-search'}
        placeholder={placeholder || '请输入群组名称,按回车键搜索'}
        allowClear
        prefix={<QxBaseIcon type={'icon-app-search-line'} />}
        onChange={(e) => {
          handleChange(e);
        }}
        onPressEnter={(e) => {
          handleSearch(e);
        }}
      />
      <div className="qx-search-menus">
        {expandedKeys.length ? (
          <Menu
            mode={'inline'}
            onSelect={handleSelect}
            selectedKeys={multiple ? [] : selectedKeys}
            multiple={!!multiple}
            defaultOpenKeys={expandedKeys}
          >
            {data.map((item) => {
              if (typeof item.visible === 'boolean' && !item.visible) {
                return null;
              }
              if (item.groupList) {
                return (
                  <Menu.SubMenu key={item.id} title={item.name}>
                    {item.groupList.map((child) => {
                      return typeof child.visible === 'boolean' && !child.visible ? null : (
                        <Menu.Item key={child.id}>
                          {multiple ? (
                            <Checkbox
                              checked={selectedKeys && selectedKeys.indexOf(child.id) > -1}
                              onChange={(e) => {
                                handleMultiSelect(e.target.checked, child);
                              }}
                            >
                              {renderText(child.name)}
                            </Checkbox>
                          ) : (
                            renderText(child.name)
                          )}
                        </Menu.Item>
                      );
                    })}
                  </Menu.SubMenu>
                );
              }
              return null;
            })}
          </Menu>
        ) : null}

        <Spin
          spinning={loading}
          style={{ width: '100%', marginTop: '40px' }}
          // indicator={<LoadingOutlined style={{ fontSize: 24, marginTop: '40px' }} spin />}
        />
        {!loading && data.length === 0 ? <Empty style={{ paddingTop: '30px' }} /> : null}
      </div>
    </div>
  );
};

export default GroupSelCore;