core.tsx 7.82 KB
import { SearchOutlined } from '@ant-design/icons';
import { Checkbox, Empty, Input, Radio, Spin } from 'antd';
import Menu from 'antd/es/menu';
import { cloneDeep } from 'lodash-es';
import * as React from 'react';
import { useCallback, useEffect, useImperativeHandle, useState } from 'react';
import { getRoles, getRolesByAppCode } from './service';
// import _ from 'lodash-es';

type PosCoreProps = {
  appId?: string;
  cRef?: any;
  multiple?: boolean;
  placeholder?: string;
  params?: any;
  onSelect?: (selectedKeys: string[], selectedData: RoleModel[]) => void;
  request: any;
  isRole?: boolean; // 是否为设计时角色权限
  appCode?: string;
};

export interface RoleModel {
  id: string;
  name: string;
  appId?: string;
  code: string;
  visible?: boolean;
  disabled?: boolean;
  child: RoleModel[];
}

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

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

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

  const requestData = useCallback(() => {
    setLoading(true);
    let _getRole = getRoles;
    if (isRole) {
      _getRole = getRolesByAppCode;
    }
    // todo 当前为指定appCode,待接口修改为appId传入(不用appId了)
    _getRole(props.request, appCode || '').then((res) => {
      const roles: RoleModel[] = res.child || [];
      if (roles) {
        const _expandedKeys: string[] = [];
        roles.forEach((item) => {
          _expandedKeys.push(item.id);
        });
        setExpandedKeys(_expandedKeys);
        setData(roles);
        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: RoleModel[] = [];
      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: RoleModel) => {
    let _selectedKeys: string[] = [];
    let _selectedData: RoleModel[] = [];
    if (selectedKeys) {
      _selectedKeys = [...selectedKeys];
      _selectedData = [...selectedData];
    }
    // console.log(checked, item.id, _selectedKeys);

    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.child || [];

      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={<SearchOutlined />}
        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.child) {
                return (
                  <Menu.SubMenu key={item.id} title={item.name}>
                    {item.child.map((child) => {
                      return typeof child.visible === 'boolean' &&
                        !child.visible ? null : (
                        <Menu.Item key={child.id} disabled={child.disabled}>
                          {multiple ? (
                            <Checkbox
                              checked={
                                selectedKeys &&
                                selectedKeys.indexOf(child.id) > -1
                              }
                              disabled={child.disabled}
                              onChange={(e) => {
                                handleMultiSelect(e.target.checked, child);
                              }}
                            >
                              {renderText(child.name)}
                            </Checkbox>
                          ) : isRole ? (
                            <Radio
                              checked={
                                selectedKeys?.length &&
                                selectedKeys[0].indexOf(child.id) > -1
                              }
                              disabled={child.disabled}
                            >
                              {renderText(child.name)}
                            </Radio>
                          ) : (
                            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 RoleSelCore;