index.tsx 6.58 KB
import { Button, Select } from 'antd';
import { cloneDeep, findIndex, isEqual } from 'lodash-es';
import React, { useEffect, useState } from 'react';

import { QxBaseIcon, getWidgetsIcon } from '@qx/common';

import './styles.less';

const { Option } = Select;

type SortProps = {
  key: string;
  asc: boolean;
};

interface OptionItemProps {
  name: string;
  code: string | number;
  extract?: {
    widget?: string;
  };
}

interface SortItemProps {
  label: string,
  value: string | number,
}

interface QxSortConditionProps {
  /**
   * @description 已选排序字段
   * @default "-"
   */
  value: SortProps[];
  /**
   * @description 字段变化方法
   * @default "-"
   */
  onChange: (val: SortProps[]) => void;
  /**
   * @description 可选字段
   * @default "-"
   */
  optionList: OptionItemProps[];
  sortList?: SortItemProps[];
  extraClassName?: string; // 定义额外 标签类名 覆盖排序原有样式
  disabled?: boolean; // 是否整体禁用
}

const defaultSortList = [
  {
    label: 'A → Z',
    value: 'true',
  },
  {
    label: 'Z → A',
    value: 'false',
  },
];

/**
 * 排序条件设置
 *
 * @param props
 * @constructor
 */
export const QxSortCondition: React.FC<QxSortConditionProps> = (props) => {
  const { value, onChange, optionList, sortList, extraClassName } = props;
  const [sorts, setSorts] = useState<any[]>([]);
  const [columns, setColumns] = useState<OptionItemProps[]>();

  useEffect(() => {
    setColumns(optionList);
  }, [optionList]);

  // 根据`code`获取对应列对象
  const getSortItemByDataIndex = (code: string) => {
    if (!columns || columns.length === 0) {
      return {};
    }
    const index = findIndex(columns, (o: OptionItemProps) => {
      return o.code === code;
    });
    return columns[index];
  };

  useEffect(() => {
    if (!columns) {
      return;
    }
    if (!value || value.length === 0) {
      const sortCol: any = getSortItemByDataIndex('created_at');
      const item: SortProps = {
        key: sortCol?.code,
        asc: false,
      };
      setSorts([item]);
    } else {
      setSorts(cloneDeep(value || []));
    }
  }, [columns, value]);

  /**
   * 通知到父组件
   */
  useEffect(() => {
    if (!sorts || (Array.isArray(sorts) && sorts.length === 0)) {
      return;
    }
    const isSame = isEqual(value, sorts);
    if (isSame) {
      return;
    }

    if (!value && sorts?.length === 0) {
      return;
    }

    // 更新父组件`columnsUser`
    onChange(sorts);
  }, [sorts]);

  /**
   * 获取未使用的`列`数组
   */
  const getUnSelCols = (cols: OptionItemProps[], exceptKey: string) => {
    const selectedKeyArr: string[] = [];
    (sorts || []).forEach((v: SortProps) => {
      // 跳过排除项
      if (!(exceptKey && v.key === exceptKey)) {
        selectedKeyArr.push(v.key);
      }
    });

    const unSelCols: OptionItemProps[] = [];
    cols.forEach((v2: OptionItemProps) => {
      let isIn = false;
      selectedKeyArr.forEach((v3) => {
        if (v2.code === v3) {
          isIn = true;
        }
      });
      if (!isIn) {
        unSelCols.push(v2);
      }
    });
    return unSelCols;
  };

  // 新增排序条件
  const addSort = () => {
    const colsTem = getUnSelCols(cloneDeep(columns || []), '') || [];
    const sortsNew = cloneDeep(sorts || []);
    sortsNew.push({
      key: colsTem[0]?.code,
      asc: true,
    });
    setSorts(sortsNew);
  };

  // 删除排序条件
  const removeSort = (index: number) => {
    const orderNew = cloneDeep(sorts || []);
    orderNew.splice(index, 1);
    setSorts(orderNew);
  };

  return (
    <div
      className={`${extraClassName || ' '} qx-sort-condition-container`}
      style={{ width: '100%' }}
    >
      {(sorts || []).map((v: any, k: any) => (
        <div
          style={{ marginBottom: sorts?.length - 1 === k ? 0 : '1em' }}
          key={v.key}
        >
          {columns && (
            <Select
              disabled={props?.disabled}
              defaultValue={v.key}
              getPopupContainer={(triggerNode) => triggerNode}
              value={v.key}
              style={{
                width: 'calc(100% - 86px - 64px - 8px)',
                marginRight: 8,
            }}
              showSearch={true}
              filterOption={(input, option) =>
                option?.children
                  ?.toString()
                  .toLowerCase()
                  .indexOf(input.toLowerCase()) !== -1
              }
              onChange={(val: string) => {
                const item = sorts[k];
                item.key = val;

                const sortsNew = cloneDeep(sorts || []);
                sortsNew.splice(k, 1, item);
                setSorts(sortsNew);
              }}
            >
              {getUnSelCols(cloneDeep(columns || []), v.key).map(
                (item: OptionItemProps) => (
                  <Option key={item?.code} value={item?.code}>
                    {getWidgetsIcon(item?.extract?.widget || '')}{item?.name}
                  </Option>
                ),
              )}
            </Select>
          )}
          <Select
            disabled={props?.disabled}
            defaultValue={String(v.asc)}
            getPopupContainer={(triggerNode) => triggerNode}
            value={String(v.asc)}
            style={{ width: '86px' }}
            onChange={(val: string) => {
              const item = sorts[k];
              item.asc = val === 'true';

              const sortsNew = cloneDeep(sorts || []);
              sortsNew.splice(k, 1, item);
              setSorts(sortsNew);
            }}
          >
            {(sortList || defaultSortList).map((item: SortItemProps) => {
              return (
                <Option key={item?.value} value={item.value}>
                  {item.label}
                </Option>
              );
            })}
          </Select>
          <span
            className={'qx-sort-condition-container__operate'}
            style={{ margin: '-2px 0 0 8px' }}
          >
            <Button
              className={'operate-button'}
              size="small"
              icon={<QxBaseIcon type={'qx-icon-minus'} />}
              disabled={props?.disabled || sorts.length <= 1}
              onClick={() => removeSort(k)}
            />
            <Button
              className={'operate-button'}
              size="small"
              icon={<QxBaseIcon type={'qx-icon-plus'} />}
              disabled={
                props?.disabled || (sorts.length >=
                ((columns || []).length > 3 ? 3 : (columns || []).length))
              }
              onClick={addSort}
            />
          </span>
        </div>
      ))}
    </div>
  );
};