qx-address.tsx 7.65 KB
import React, { useEffect, useState, useMemo, useRef } from 'react';
import { Input, Cascader } from 'antd';
import { getDictDetail } from '../service';
import { cloneDeep, isEqual, isEmpty } from 'lodash-es';

export interface FRWidgetProps {
  title?: string;
  placeholder?: string;
  format?: string;
  /** Widget schema */
  schema: any;
  /** 隐藏 */
  hidden?: boolean;
  /** 只读模式 */
  readOnly?: boolean;
  /** 禁用模式 */
  disabled?: boolean;
  /** 标签宽度 */
  labelWidth?: string | number;
  /*默认值*/
  default?: any;
  onChange: (data: any) => void;
  /* 编辑模式下无此属性*/
  addons?: {
    setValueByPath: (path: string, value: any) => void;
    getSchemaByPath: (path: string) => object;
    setSchemaByPath: (path: string, value: any) => void;
    setSchema: (settings: any) => void;
    setValues: (formData: any) => void;
    getValues: () => any;
    resetFields: (v: any) => void;
    dependValues: any[];
    [propName: string]: any;
  };
  value?: any;
  props?: any;
  qxProps?: any;
  relAppCode?: string;
  relFunCode?: string;
  relParameter?: any;
  needSmallIcon?: boolean;
  isQuick?: boolean;
  type?: string;
  isNavigation?: boolean;
}

interface FinalPropsType extends FRWidgetProps {
  casDefaultValue?: any[];
  textDefaultValue?: string;
  [key: string]: any;
}
/**
 * 表单设计器(XRender)
 * @constructor
 */

const QxAddress: React.FC<FRWidgetProps> = (props) => {
  const [localCasValue, setLocalCasValue] = useState<string[]>([]);
  const [localTextValue, setLocalTextValue] = useState<string | undefined>();
  const [allOptions, setAllOptions] = useState<any>([]);
  const [options, setOptions] = useState<any>([]);
  const [detail, setDetail] = useState<boolean>(false);
  const [showLevel, setShowLevel] = useState<number>(0);
  const isDisabled = !props.addons && !props.schema.$ref && props.readOnly;

  const countRef = useRef(1);

  // 默认值处理
  const handlePropChange = (v: any) => {
    props.onChange(v);
    if (countRef.current !== 0) {
      countRef.current = 0;
    }
  };

  const genOption = (array: any) => {
    // eslint-disable-next-line @typescript-eslint/no-shadow
    const options: any[] = [];
    Object.keys(array).forEach((key: string) => {
      const option: any = {
        key: array[key].id,
        value: array[key].name,
        label: array[key].name,
      };

      options.push(option);
      if (array[key].children) {
        option.children = genOption(array[key].children);
      }
    });

    return options;
  };

  const excuteOption = (level: number, opArr: any) => {
    // eslint-disable-next-line @typescript-eslint/no-shadow
    const options: any = [];
    Object.keys(opArr).forEach((key) => {
      let num = cloneDeep(level);
      const option: any = {
        value: opArr[key].value,
        label: opArr[key].label,
      };

      options.push(option);
      if (opArr[key].children && num > 1) {
        num--;
        option.children = excuteOption(num, opArr[key].children);
      }
    });

    return options;
  };
  const handleSearch = () => {
    getDictDetail('F2021110010').then((res: any) => {
      if (res.children) {
        const option = genOption(res.children);
        setAllOptions(option);
      }
    });
  };

  // useEffect(() => {
  //   handleSearch()
  // }, []);

  const schema = props.schema;

  useEffect(() => {
    let _defaultVal: any = '';
    if (props.addons && props.value) {
      _defaultVal = props.value.toString();
    }

    let _localCasValue = localCasValue;
    let _localTextValue = localTextValue;
    if (_defaultVal) {
      _defaultVal = _defaultVal.split('|');
      _localCasValue = _defaultVal[0].split(',');
      _localTextValue = _defaultVal[1];
    } else {
      _localCasValue = [];
      _localTextValue = '';
    }
    if (!isEqual(_localCasValue, localCasValue)) {
      setLocalCasValue(_localCasValue);
    }
    if (!isEqual(_localTextValue, localTextValue)) {
      setLocalTextValue(_localTextValue);
    }
  }, [props.value]);

  useEffect(() => {
    const _finalProps: FinalPropsType = {
      ...props,
    };

    const _mode = schema.qxProps && schema.qxProps.mode;
    let level = 3;
    if (_mode) {
      setDetail(_mode === 'P_C_D_A');
      // console.log("=======level==" + schema.addressLevel);
    }
    switch (_mode) {
      case 'P':
        level = 1;
        break;
      case 'P_C':
        level = 2;
        break;
    }
    if (level !== showLevel && allOptions.length > 0) {
      setOptions(excuteOption(level, allOptions));
      setShowLevel(level);
    }

    if (!_finalProps.placeholder) {
      _finalProps.placeholder = schema.placeholder;
    }
  }, [schema.qxProps, schema.placeholder, allOptions, props.value]);

  const needAutoSave = useMemo(() => {
    return schema.props?.editable && !schema.readOnly && schema.autoSave;
  }, [schema.props?.editable, schema.readOnly, schema.autoSave]);

  function filter(inputValue: string, path: any) {
    return path.some(
      (option: any) => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1,
    );
  }

  const handleChange = (changeObj: any) => {
    const newObj = { localCasValue, localTextValue, ...changeObj };
    if (!isEqual(localCasValue, newObj.localCasValue)) {
      setLocalCasValue(newObj.localCasValue);
    }
    if (!isEqual(localTextValue, newObj.localTextValue)) {
      setLocalTextValue(newObj.localTextValue);
    }

    const curValString = [newObj.localCasValue?.join(',') ?? '', newObj.localTextValue || '']
      .filter((a) => !!a)
      .join('|');

    // setFinalProps({ ...other, ..._props });
    //需要自动保存
    if (needAutoSave) {
      return;
    }
    console.log(curValString);

    handlePropChange(curValString);
  };

  return (
    <>
      <div style={{ width: '100%' }}>
        <Cascader
          disabled={props.disabled || isDisabled}
          value={localCasValue}
          placeholder={props.placeholder}
          style={{ width: '100%' }}
          showSearch={{ filter }}
          onFocus={() => {
            if (!allOptions.length) {
              handleSearch();
            }
          }} // @ts-ignore
          changeOnSelect={props.changeOnSelect}
          options={options}
          onChange={(value: any) => {
            handleChange({
              localCasValue: value || [],
              ...(!value && detail ? { localTextValue: undefined } : null),
            });
          }}
          getPopupContainer={(triggerNode: any) => {
            if (schema.belongSubForm || schema.belongEditRelForm) {
              return triggerNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode
                .parentNode.parentNode;
            } else if (schema.queryList || !!schema?.popupOnBody) {
              //schema.queryList 适用于查询器
              // schema?.popupOnBody 自定义筛选 地址下拉弹框 不跟随
              return document.body;
            }
            return triggerNode;
          }}
        />
        {detail ? (
          <Input
            disabled={props.disabled || isEmpty(localCasValue) || isDisabled}
            //  defaultValue={finalProps.textDefaultValue}
            value={localTextValue}
            style={{ marginTop: '10px' }}
            placeholder={'请输入地址详情'}
            showCount
            maxLength={200}
            onChange={(e: any) => {
              const val = e.target.value;
              // handleChange({ textDefaultValue: val });
              setLocalTextValue(val || undefined);
            }}
            onBlur={(e: any) => {
              const val = e.target.value;
              handleChange({ localTextValue: val });
            }}
          />
        ) : null}
      </div>
    </>
  );
};

export default QxAddress;