index.tsx 5.36 KB
import { Button } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import {
  QxBaseCondition,
  QxBaseConditionValueType,
} from '../qx-base-condition';
import { QxBaseIcon } from '../qx-base-icon';
import { QxConditionSql, SqlType } from '../qx-condition-sql';
import QxFieldPopover from '../qx-field/src/popover';
import {
  FiledType,
  INode,
  QxFlowNodeFieldSelector,
} from '../qx-flow-node-selector';
import { request } from '../utils';

import './index.less';

const excludeCodes = ['id'];

export function getFieldsByFunId(funId: string, params?: { useKey: boolean }) {
  return request.get(`/qx-apaas-lowcode/app/form/${funId}/field`, { params });
}

export const QxCondition: React.FC<QxConditionProps> = ({
  value,
  className,
  style,
  enabled = true,
  showAssignment = true,
  onChange,
  node,
  nodes,
  header,
  headerLeft,
  headerRight,
  formId,
  showHeader = false,
}) => {
  const [fields, setFields] = useState<FiledType[]>([]);

  const fieldSelectorRef = useRef<any>();

  const isMount = useRef(false);

  const handleChange = (opt: Partial<QxConditionValueType>) => {
    onChange?.(Object.assign({}, value, opt, { enabled }));
  };

  const handleGetFieldsList = async (formId: string) => {
    try {
      const data = await getFieldsByFunId(formId);
      setFields(data.filter((i) => !excludeCodes.includes(i.code)));
    } catch (error) {
      setFields([]);
    }
  };

  useEffect(() => {
    if (formId && !showAssignment) handleGetFieldsList(formId);
  }, [formId]);

  const handleAddField = (val: any) => {
    handleChange({
      operators: [
        ...(value?.operators || []),
        {
          field: val,
          code: val.code,
          name: val.name,
          type: val.extract?.fieldType,
          opt: 'IS',
          mappingValues: [],
        },
      ],
    });
  };

  const handleAddFlowNodeField = (val: any, opt: any) => {
    handleChange({
      operators: [
        ...(value?.operators || []),
        {
          field: opt,
          code: val,
          name: opt.name,
          type: opt.extract?.fieldType,
          opt: 'IS',
          mappingValues: [],
        },
      ],
    });
  };

  const handleGetResultMap = async () => {
    if (!fieldSelectorRef.current || isMount.current) return;
    isMount.current = true;

    const resultFieldMap =
      await fieldSelectorRef.current?.getResultFieldMap?.();

    const newOperators = Array.isArray(value?.operators)
      ? value?.operators.map((item) => ({
          ...item,
          field: showAssignment
            ? resultFieldMap?.[item.field?.code]
            : fields?.find((field) => item.code === field.code),
        }))
      : [];

    handleChange({ operators: newOperators });
  };

  useEffect(() => {
    handleGetResultMap();
  }, [fieldSelectorRef.current]);

  // useEffect(() => {
  //   if (Array.isArray(value?.operators)) {
  //     setOperators(value?.operators)
  //   }
  // }, [value?.operators])

  const RenderHeader = header ? (
    header
  ) : (
    <div className="qx-condition-header">
      {!headerLeft ? (
        <div className="qx-condition-header__title">条件配置</div>
      ) : (
        headerLeft
      )}
      {!headerRight ? (
        <div className="qx-condition-header__right">
          {showAssignment && node ? (
            <QxFlowNodeFieldSelector
              width={240}
              ref={fieldSelectorRef}
              node={node}
              nodes={nodes!}
              mode="variable"
              onChange={handleAddFlowNodeField}
            >
              <Button size="small" type="link">
                <QxBaseIcon style={{ fontSize: 16 }} type="qx-icon-plus" />
                添加字段
              </Button>
            </QxFlowNodeFieldSelector>
          ) : (
            <QxFieldPopover data={fields} onSelect={handleAddField}>
              <Button size="small" type="link">
                <QxBaseIcon style={{ fontSize: 16 }} type="qx-icon-plus" />
                添加字段
              </Button>
            </QxFieldPopover>
          )}
        </div>
      ) : (
        headerRight
      )}
    </div>
  );

  return (
    <div className={`qx-condition ${className && className}`} style={style}>
      {showHeader && RenderHeader}
      <QxBaseCondition
        mode="condition"
        nodes={nodes}
        node={node}
        showAssignment={showAssignment}
        value={value?.operators}
        onChange={(condition) => {
          handleChange({
            operators: condition,
          });
        }}
      />

      {(value?.operators?.length || 0) >= 2 ? (
        <QxConditionSql value={value} onChange={handleChange} />
      ) : null}
    </div>
  );
};

export interface QxConditionValueType {
  /**
   * 是否启用条件
   */
  enabled?: boolean;
  /**
   * 条件组合类型
   */
  sqlType: SqlType;
  /**
   * 自定义条件表达式
   */
  expression: string;
  /**
   * 算子
   */
  operators: OperatorsType[];
}

export type OperatorsType = QxBaseConditionValueType;

export interface QxConditionProps {
  [key: string]: any;
  value?: QxConditionValueType;
  onChange?: (value: QxConditionValueType) => void;
  className?: string;
  style?: React.CSSProperties;
  node?: INode;
  nodes?: INode[];
  showAssignment?: boolean;
  header?: React.ReactNode;
  headerRight?: React.ReactNode;
  headerLeft?: React.ReactNode;
  multiple?: boolean;
  formId?: string;
  showHeader?: boolean;
}