import React from 'react';
import { Renderer, RendererProps } from '../../factory';
import { FormStore, IFormStore } from '../../store/form';
import { Api, SchemaNode, Schema, Action, Payload } from '../../types';
import { filter, evalExpression } from '../../utils/tpl';
import cx from 'classnames';
import getExprProperties from '../../utils/filter-schema';
import {
  promisify,
  difference,
  until,
  noop,
  isObject,
  isVisible,
  cloneObject,
  SkipOperation,
  isEmpty,
  getVariable,
  isObjectShallowModified,
  qsparse,
  isMobile
} from '../../utils/helper';
import debouce from 'lodash/debounce';
import flatten from 'lodash/flatten';
import find from 'lodash/find';
import {
  ScopedContext,
  IScopedContext,
  ScopedComponentType
} from '../../Scoped';
import { IComboStore } from '../../store/combo';
import { dataMapping } from '../../utils/tpl-builtin';
import { isApiOutdated, isEffectiveApi } from '../../utils/api';
import Spinner from '../../components/Spinner';
import { LazyComponent } from '../../components';
import { isAlive } from 'mobx-state-tree';
import {
  BaseSchema,
  SchemaApi,
  SchemaApiObject,
  SchemaClassName,
  SchemaCollection,
  SchemaDefaultData,
  SchemaExpression,
  SchemaMessage,
  SchemaName,
  SchemaObject,
  SchemaRedirect,
  SchemaReload
} from '../../Schema';
import { ActionSchema } from '../Action';
import { DialogSchemaBase } from '../Dialog';
import msgsub from '../Lion/utils/msgsub';
import throttle from 'lodash/throttle'; // Aug
import { createObject } from 'amis-formula';
import Checkbox from '../../components/Checkbox';
import Button from '../../components/Button'
import OptionTransfer from '../../components/Lion/OptionTransfer';
import Row from 'antd/lib/row'
import Col from 'antd/lib/col'
import { Dropdown, InputNumber, MenuProps, message, Modal, Select } from 'antd'
import { labelPrint } from '../../utils/print';
import { expressLabels, IExpress } from '../Lion/ExpressPrint/ExpressPrint';
import { buildLabelTemplate, setLabelTemplateData } from '../../utils/print/util';
import Divider from 'antd/lib/divider';
import { cloneDeep, isArray, isNil } from 'lodash';
import AdvancedModlePopup from '../../components/Lion/AdvancedModlePopup';
import { Icon } from '../../components/icons';
import { TableRenderer } from '../Table';
import { createRandomValue } from '../Lion/utils/utils';
import ScrollMb from '../../components/ScrollMB';
import { ModalPrint } from '../Lion/LabelPrint';
import { getLodop } from '../../utils/print/LodopFuncs';
import ModalFlow from '../../components/Mobileprocess/Workflow';
import { makeTranslator } from '../../locale';
import { FlowDetail } from '../../components/Mobileprocess/type';

/**
 * 枚举 RangeOptionsEnum 用于表示范围选项
 */
enum RangeOptionsEnum {
  Equal = 2,               // 等于
  GreaterThan = 3,         // 大于
  GreaterThanOrEqual = 4,  // 大于等于
  LessThan = 5,            // 小于
  LessThanOrEqual = 6,     // 小于等于
  Between = 7,             // 介于
  ContainWithin = 8,       // 包含于
  Contain = 9,             // 包含
  IsEmpty = 10,            // 为空
  Fuzzy = 11,              // 模糊
  DataTag = 12             // 数据标签
}

const rangeOptions: { label: string; value: RangeOptionsEnum; not?: boolean }[] = [
  { label: '等于', value: RangeOptionsEnum.Equal },
  { label: '大于', value: RangeOptionsEnum.GreaterThan },
  { label: '大于等于', value: RangeOptionsEnum.GreaterThanOrEqual },
  { label: '小于', value: RangeOptionsEnum.LessThan },
  { label: '小于等于', value: RangeOptionsEnum.LessThanOrEqual },
  { label: '介于', value: RangeOptionsEnum.Between },
  { label: '包含于', value: RangeOptionsEnum.ContainWithin },
  { label: '包含', value: RangeOptionsEnum.Contain },
  { label: '为空', value: RangeOptionsEnum.IsEmpty },
  { label: '模糊', value: RangeOptionsEnum.Fuzzy },
  { label: '不等于', value: RangeOptionsEnum.Equal, not: true },
  { label: '不大于', value: RangeOptionsEnum.GreaterThan, not: true },
  { label: '不大于等于', value: RangeOptionsEnum.GreaterThanOrEqual, not: true },
  { label: '不小于', value: RangeOptionsEnum.LessThan, not: true },
  { label: '不小于等于', value: RangeOptionsEnum.LessThanOrEqual, not: true },
  { label: '不介于', value: RangeOptionsEnum.Between, not: true },
  { label: '不包含于', value: RangeOptionsEnum.ContainWithin, not: true },
  { label: '不包含', value: RangeOptionsEnum.Contain, not: true },
  { label: '不为空', value: RangeOptionsEnum.IsEmpty, not: true },
  { label: '不模糊', value: RangeOptionsEnum.Fuzzy, not: true },
  { label: '属于标签', value: RangeOptionsEnum.DataTag }
];

// onlyEmptyRangeOptions 数组映射
const onlyEmptyRangeOptions: { label: string; value: RangeOptionsEnum }[] = [
  { label: '为空', value: RangeOptionsEnum.IsEmpty },
];

// 类型枚举类
enum TagTypeEnum {
  Select = 'select',
  TreeSelect = 'tree-select',
  TransferPicker = 'transfer-picker',
  TabsTransferPicker = 'tabs-transfer-picker',
  InputDateRange = 'input-date-range',
  InputDatetimeRange = 'input-datetime-range',
  InputMonthRange = 'input-month-range',
  InputYearRange = 'input-year-range',
  InputQuarterRange = 'input-quarter-range',
  InputTimeRange = 'input-time-range',
  InputTag = 'input-tag',
  NestedSelect = 'nested-select',
  InputNumber = 'input-number',
  InputText = 'input-text',
  InputDatetime = 'input-datetime',
  InputDate = 'input-date',//
  InputMonth = 'input-month',
  file = 'lion-upload', // 文件类型
  Picker = 'picker',//颜色
  Switch = 'switch', //开关
  Checkboxes = 'checkboxes'  //复选按钮
}

const notRange: string[] = [
  //   TagTypeEnum.Select,
  TagTypeEnum.TreeSelect,
  // TagTypeEnum.TransferPicker,
  TagTypeEnum.TabsTransferPicker,
  TagTypeEnum.InputDateRange,
  TagTypeEnum.InputDatetimeRange,
  TagTypeEnum.InputMonthRange,
  TagTypeEnum.InputYearRange,
  TagTypeEnum.InputQuarterRange,
  TagTypeEnum.InputTimeRange,
  TagTypeEnum.InputTag,
  TagTypeEnum.NestedSelect,
  TagTypeEnum.Switch
]

// type ScanAfterPort = IExpress
interface ScanAfterDo {
  cmd: 'STEP_PRINT_LABEL' | 'STEP_PORT' | 'STEP_SHOW' | 'STEP_VARS'
  body: ScanAfterLabelPrint | ScanAfterPort | ScanAfterShow | ScanAfterVars
}
interface ScanAfterLabelPrint {
  labelData: any[]
  labelTemplate: any
  labelPrinter: string
}

interface ScanAfterPort {
  afterApi?: Api
  body: IExpress
}

interface ScanAfterShow {
  showType: 0 | 1 | 2 | 10 | 11 | 12
  showMsg: string
  afterApi?: Api
}

interface ScanAfterVars {
  afterApi: Api
  body: SchemaCollection
  data: object
}

type FiltersArr = {
  field: string, // 字段名
  condition: number, // 0：或   1：且
  not: boolean, // 不
  op: RangeOptionsEnum, // 等于、大于...
  values?: string | number
  caseSensitive?: 0 | 1,
  dateLine?: boolean//是否日期类集合
  compareField?: string[] //储存values的nameid
  useFieldCompare?: boolean//判断是否为比较字段
}[]
type FiltersHeader = {
  label: string
  type: string
  name: string
  body?: []
}

export interface FormSchemaHorizontal {
  left?: number;
  right?: number;
  leftFixed?: boolean | number | 'xs' | 'sm' | 'md' | 'lg';
}

/**
 * Form 表单渲染器。
 *
 * 说明：https://baidu.gitee.io/amis/docs/components/form/index
 */
export interface FormSchema extends BaseSchema {
  /**
   * 指定为表单渲染器。
   */
  type: 'form';

  /**
   * 表单标题
   */
  title?: string;

  /**
   * 按钮集合，会固定在底部显示。
   */
  actions?: Array<ActionSchema>;

  /**
   * 表单项集合
   */
  body?: SchemaCollection;

  /**
   * 初始数据
   */
  data?: SchemaDefaultData;

  /**
   * 是否开启调试，开启后会在顶部实时显示表单项数据。
   */
  debug?: boolean;

  /**
   * 用来初始化表单数据
   */
  initApi?: SchemaApi;

  /**
   * Form 用来获取初始数据的 api,与initApi不同的是，会一直轮询请求该接口，直到返回 finished 属性为 true 才 结束。
   */
  initAsyncApi?: SchemaApi;

  /**
   * Jay
   * 自定义的一个字段
   * Form 用来获取初始数据的 api，与initApi不同的是，只执行一次,且不受target属性影响。
  */
  initOneApi?: SchemaApi;

  /**
   * 设置了initAsyncApi后，默认会从返回数据的data.finished来判断是否完成，也可以设置成其他的xxx，就会从data.xxx中获取
   */
  initFinishedField?: string;

  /**
   * 设置了initAsyncApi以后，默认拉取的时间间隔
   */
  initCheckInterval?: number;

  /**
   * 是否初始加载
   */
  initFetch?: boolean;

  /**
   * 建议改成 api 的 sendOn 属性。
   */
  initFetchOn?: SchemaExpression;

  /**
   * 设置后将轮询调用 initApi
   */
  interval?: number;

  /**
   * 是否静默拉取
   */
  silentPolling?: boolean;

  /**
   * 配置停止轮询的条件
   */
  stopAutoRefreshWhen?: string;

  /**
   * 是否开启本地缓存
   */
  persistData?: string;

  /**
   * 提交成功后清空本地缓存
   */
  clearPersistDataAfterSubmit?: boolean;

  /**
   * Form 用来保存数据的 api。
   *
   * 详情：https://baidu.gitee.io/amis/docs/components/form/index#%E8%A1%A8%E5%8D%95%E6%8F%90%E4%BA%A4
   */
  api?: SchemaApi;

  /**
   * Form 也可以配置 feedback。
   */
  feedback?: DialogSchemaBase;

  /**
   * 设置此属性后，表单提交发送保存接口后，还会继续轮询请求该接口，直到返回 finished 属性为 true 才 结束。
   */
  asyncApi?: SchemaApi;

  /**
   * 轮询请求的时间间隔，默认为 3秒。设置 asyncApi 才有效
   */
  checkInterval?: number;

  /**
   * 如果决定结束的字段名不是 `finished` 请设置此属性，比如 `is_success`
   */
  finishedField?: string;

  /**
   * 提交完后重置表单
   */
  resetAfterSubmit?: boolean;

  /**
   * 提交后清空表单
   */
  clearAfterSubmit?: boolean;

  /**
   * 配置表单项默认的展示方式。
   */
  mode?: 'normal' | 'inline' | 'horizontal';

  /**
   * 表单项显示为几列
   */
  columnCount?: number;

  /**
   * 如果是水平排版，这个属性可以细化水平排版的左右宽度占比。
   */
  horizontal?: FormSchemaHorizontal;

  /**
   * 是否自动将第一个表单元素聚焦。
   */
  autoFocus?: boolean;

  /**
   * 消息文案配置，记住这个优先级是最低的，如果你的接口返回了 msg，接口返回的优先。
   */
  messages?: {
    /**
     * 表单验证失败时的提示
     */
    validateFailed?: string;
  } & SchemaMessage;

  name?: SchemaName;

  /**
   * 配置容器 panel className
   */
  panelClassName?: SchemaClassName;

  /**
   * 设置主键 id, 当设置后，检测表单是否完成时（asyncApi），只会携带此数据。
   * @default id
   */
  primaryField?: string;

  redirect?: SchemaRedirect;

  reload?: SchemaReload;

  /**
   * 修改的时候是否直接提交表单。
   */
  submitOnChange?: boolean;

  /**
   * 表单初始先提交一次，联动的时候有用
   */
  submitOnInit?: boolean;

  /**
   * 默认的提交按钮名称，如果设置成空，则可以把默认按钮去掉。
   */
  submitText?: string;

  /**
   * 默认表单提交自己会通过发送 api 保存数据，但是也可以设定另外一个 form 的 name 值，或者另外一个 `CRUD` 模型的 name 值。 如果 target 目标是一个 `Form` ，则目标 `Form` 会重新触发 `initApi` 和 `schemaApi`，api 可以拿到当前 form 数据。如果目标是一个 `CRUD` 模型，则目标模型会重新触发搜索，参数为当前 Form 数据。
   */
  target?: string;

  /**
   * 是否用 panel 包裹起来
   */
  wrapWithPanel?: boolean;

  /**
   * 是否固定底下的按钮在底部。
   */
  affixFooter?: boolean;

  /**
   * 页面离开提示，为了防止页面不小心跳转而导致表单没有保存。
   */
  promptPageLeave?: boolean;

  /**
   * 具体的提示信息，选填。
   */
  promptPageLeaveMessage?: string;

  /**
   * 组合校验规则，选填
   */
  rules?: Array<{
    rule: string;
    message: string;
  }>;

  /**
   * 禁用回车提交
   */
  preventEnterSubmit?: boolean;

  _bindRef?: any;

  /**
   * Aug 是否自动布局排版
   */
  autoLayout?: boolean;
  /**
   * Aug 组件大小
   */
  formatSize?: 'xs' | 'sm' | 'md' | 'lg';
  columns?: any[];
  showModal?: 0 | 1;
  /**
   * 是否查看模式
   */
  isDetail?: boolean;
  /**
  * 判断是否流程上的表单
  */
  flowProcess?: boolean;
}

export type FormGroup = FormSchema & {
  title?: string;
  className?: string;
};
export type FormGroupNode = FormGroup | FormGroupArray;
export interface FormGroupArray extends Array<FormGroupNode> { }

export type FormHorizontal = FormSchemaHorizontal;

export interface FormProps
  extends RendererProps,
  Omit<FormSchema, 'mode' | 'className'> {
  data: any;
  store: IFormStore;
  wrapperComponent: React.ElementType;
  canAccessSuperData: boolean;
  trimValues?: boolean;
  lazyLoad?: boolean;
  simpleMode?: boolean;
  onInit?: (values: object, props: any, isChild?: boolean) => any;
  onReset?: (values: object, action?: any) => void;
  onSubmit?: (values: object, action: any) => any;
  onChange?: (values: object, diff: object, props: any) => any;
  onFailed?: (reason: string, errors: any) => any;
  onFinished: (values: object, action: any) => any;
  onValidate: (values: object, form: any) => any;
  messages: {
    fetchSuccess?: string;
    fetchFailed?: string;
    saveSuccess?: string;
    saveFailed?: string;
    validateFailed?: string;
  };
  rules: Array<{
    rule: string;
    message: string;
  }>;
  lazyChange?: boolean; // 表单项的
  formLazyChange?: boolean; // 表单的
  preventModifySubmit?: boolean; // 配置表单数据未修改不提交
  // Jay
  getFilterColumns?: () => any[]
  defaultAdvancedQuery?: (val: 1 | 2 | 3) => void //
  advancedFilterVisible?: boolean;
  //判断来自移动端垂直模式下的编辑
  formMobileHorizontal?: boolean;
  //表格的快速查询
  tableFilter?: boolean;
}
//Aug
interface FormState {
  autoColumnCount: number
  filtersArr: FiltersArr
  defaultFilterArr: FiltersArr
  defaultHeader: any[]
  collpased: boolean
  filtersHeader: FiltersHeader[]
  userChange: boolean
  disabled: boolean
  inputfocus: boolean
  caseSensitive: boolean
  topN: number
  limitStatus: boolean
  printVisible: boolean
  flowModalVisible: boolean
  printInfo?: object
  //高级查询时间组选空
  emptyTimeSelected?: boolean
  formWidth: number
}
export default class Form extends React.Component<FormProps, FormState> {
  static defaultProps = {
    title: 'Form.title',
    submitText: 'Form.submit',
    initFetch: true,
    wrapWithPanel: true,
    mode: 'normal',
    collapsable: false,
    controlWidth: 'full',
    horizontal: {
      left: 2,
      right: 10,
      offset: 2
    },
    columnCount: 0,
    panelClassName: 'Panel--default',
    messages: {
      fetchFailed: 'fetchFailed',
      saveSuccess: 'saveSuccess',
      saveFailed: 'saveFailed'
    },
    wrapperComponent: '',
    finishedField: 'finished',
    initFinishedField: 'finished',
    flowProcess: false
  };
  static propsList: Array<string> = [
    'title',
    'header',
    'controls',
    'submitText',
    'initFetch',
    'wrapWithPanel',
    'mode',
    'columnCount',
    'collapsable',
    'horizontal',
    'panelClassName',
    'messages',
    'wrapperComponent',
    'resetAfterSubmit',
    'clearAfterSubmit',
    'submitOnInit',
    'submitOnChange',
    'onInit',
    'onReset',
    'onSubmit',
    'onChange',
    'onFailed',
    'onFinished',
    'onSaved',
    'canAccessSuperData',
    'lazyChange',
    'formLazyChange',
    'lazyLoad',
    'formInited',
    'simpleMode',
    'inputOnly',
    'value',
    'actions',
    'multiple'
  ];

  hooks: {
    [propName: string]: Array<() => Promise<any>>;
  } = {};
  asyncCancel: () => void;
  disposeOnValidate: () => void;
  disposeRulesValidate: () => void;
  shouldLoadInitApi: boolean = false;
  timer: ReturnType<typeof setTimeout>;
  mounted: boolean;
  lazyEmitChange = debouce(this.emitChange.bind(this), 250, {
    trailing: true,
    leading: false
  });
  unBlockRouting?: () => void;
  is_init?: any;
  is_edit?: any;
  _formName?: any;
  contentRef: React.RefObject<HTMLFormElement>; //Aug
  childCount: any
  changeFields: string[] = [];
  handleUserChange = () => this.setState({ userChange: true });
  changeTimes = 0;
  filterOptions: { label: string, value: string, type: string | undefined, isNumber?: boolean }[]
  filterObj: { [key: string]: any } = {}
  filterNorma: FiltersHeader[]
  filterOptionData: any
  filterOptionRef: React.RefObject<{ handleReset: () => void }>
  casestatr: boolean = true
  flowDetail?: FlowDetail
  limitInputRef: React.RefObject<HTMLInputElement> = React.createRef<HTMLInputElement>();
  constructor(props: FormProps) {
    super(props);

    this.onInit = this.onInit.bind(this);
    this.handleAction = this.handleAction.bind(this);
    this.handleQuery = this.handleQuery.bind(this);
    this.handleChange = this.handleChange.bind(this);
    // Jay
    this.handleInputTableChange = this.handleInputTableChange.bind(this)
    this.abandonFormItem = this.abandonFormItem.bind(this)
    this.received = false
    this.setEdited = this.setEdited.bind(this)
    this.setFormLoading = this.setFormLoading.bind(this)
    this.confirmAdvancedFilter.bind(this)
    this.resetAdvancedFilter.bind(this)
    this.props.getFilterForm?.(this)
    this.props.getAdvancedFilterForm?.(this)
    this.props.getFormInstance?.(this)
    this.buildExtendAction.bind(this)
    this.shouldCommit = this.shouldCommit.bind(this)
    this.handleDialogConfirm = this.handleDialogConfirm.bind(this);
    this.resetIsModleFilter = this.resetIsModleFilter.bind(this)
    this.handleDialogClose = this.handleDialogClose.bind(this);
    this.handleDrawerConfirm = this.handleDrawerConfirm.bind(this);
    this.handleDrawerClose = this.handleDrawerClose.bind(this);
    this.handleFormSubmit = this.handleFormSubmit.bind(this);
    this.validate = this.validate.bind(this);
    this.submit = this.submit.bind(this);
    this.addHook = this.addHook.bind(this);
    this.removeHook = this.removeHook.bind(this);
    this.emitChange = this.emitChange.bind(this);
    this.handleBulkChange = this.handleBulkChange.bind(this);
    this.renderFormItems = this.renderFormItems.bind(this);
    this.reload = this.reload.bind(this);
    this.silentReload = this.silentReload.bind(this);
    this.initInterval = this.initInterval.bind(this);
    this.blockRouting = this.blockRouting.bind(this);
    this.handleChangeFields = this.handleChangeFields.bind(this);
    this.beforePageUnload = this.beforePageUnload.bind(this);
    this.handleSendAction = this.handleSendAction.bind(this);
    //Aug 自适应布局
    this.computeAutoLayout = throttle(this.computeAutoLayout.bind(this), 500);

    this.handlerenew = this.handlerenew.bind(this);
    this.handleFiltersArr = this.handleFiltersArr.bind(this);
    this.contentRef = React.createRef();

    this.filterOptionRef = React.createRef()
    if (this.props.getAdvancedFilterForm) {
      this.getFiltersOptions()
    }
    this.state = {
      autoColumnCount: 0, //控制一行展示几列
      filtersArr: [],
      defaultHeader: [],
      defaultFilterArr: [],
      collpased: true,
      caseSensitive: this.casestatr, // 是否大小写敏感
      filtersHeader: [],
      userChange: false,
      disabled: false,
      inputfocus: false,
      topN: this.props.filtercont?.limitParam?.topN || 3000,
      limitStatus: this.props.filtercont?.limitParam?.limitStatus || false,
      printVisible: false,
      flowModalVisible: false,
      formWidth: 0
    }
    this._formName = props.name;
    const { store, canAccessSuperData, persistData, simpleMode } = props;
    store.setCanAccessSuperData(canAccessSuperData !== false);
    store.setPersistData(persistData);
    if (simpleMode) {
      store.setInited(true);
    }
    if (
      store &&
      store.parentStore &&
      store.parentStore.storeType === 'ComboStore'
    ) {
      const combo = store.parentStore as IComboStore;
      combo.addForm(store);
      combo.forms.forEach(form =>
        form.items.forEach(
          item => item.unique && item.syncOptions(undefined, form.data)
        )
      );
    }
  }

  valueChanged = false;

  allFromReadyInterval: any

  componentDidMount() {
    const {
      initApi,
      initFetch,
      initFetchOn,
      initAsyncApi,
      initOneApi,
      initFinishedField,
      initCheckInterval,
      store,
      messages: { fetchSuccess, fetchFailed },
      onValidate,
      promptPageLeave,
      env,
      rules,
      body
    } = this.props;
    if (this.props?._bindRef) {
      this.props._bindRef(this)
    }

    if (this.props.name) {
      this._formName = this.props.name;
    }
    // 高级查询打开，查询后，在打开一个有高级查询的弹窗会找到__super下会有高级查询的东西，导致输入值会将其他的值清空掉所以先给他清空初始化一下要是找到的话
    this.resetIsModleFilter()
    this.hanldeAdvancedQueryDefault()
    this.mounted = true;
    setTimeout(() => {
      this.is_edit = false;
    }, 0)
    this.is_edit = false;
    if (onValidate) {
      const finalValidate = promisify(onValidate);
      this.disposeOnValidate = this.addHook(async () => {
        const result = await finalValidate(store.data, store);

        if (result && isObject(result)) {
          Object.keys(result).forEach(key => {
            let msg = result[key];
            const items = store.getItemsByPath(key);

            // 没有找到
            if (!Array.isArray(items) || !items.length) {
              return;
            }

            // 在setError之前，提前把残留的error信息清除掉，否则每次onValidate后都会一直把报错 append 上去
            items.forEach(item => item.clearError());

            if (msg) {
              msg = Array.isArray(msg) ? msg : [msg];
              items.forEach(item => item.addError(msg));
            }

            delete result[key];
          });

          isEmpty(result)
            ? store.clearRestError()
            : store.setRestError(Object.keys(result).map(key => result[key]));
        }
      });
    }
    if (Array.isArray(rules) && rules.length) {
      this.disposeRulesValidate = this.addHook(() => {
        if (!store.valid) {
          return;
        }
        rules.forEach(
          item =>
            !evalExpression(item.rule, store.data) &&
            store.addRestError(item.message)
        );
      });
    }
    // Jay
    // 处理initOneApi字段
    if (isEffectiveApi(initOneApi, store.data, initFetch, initFetchOn)) {
      store
        .fetchInitData(initOneApi as any, store.data, {
          successMessage: fetchSuccess,
          errorMessage: fetchFailed,
          onSuccess: () => { }
        })
        .then(this.initInterval)
        .then(this.onInit);
    }

    else if (isEffectiveApi(initApi, store.data, initFetch, initFetchOn)) {
      store
        .fetchInitData(initApi as any, store.data, {
          successMessage: fetchSuccess,
          errorMessage: fetchFailed,
          onSuccess: () => {


            if (
              !isEffectiveApi(initAsyncApi, store.data) ||
              store.data[initFinishedField || 'finished']
            ) {
              return;
            }

            return until(
              () => store.checkRemote(initAsyncApi, store.data),
              (ret: any) => ret && ret[initFinishedField || 'finished'],
              cancel => (this.asyncCancel = cancel),
              initCheckInterval
            );
          }
        })
        .then(this.initInterval)
        .then(this.onInit);
    } else {
      setTimeout(this.onInit.bind(this), 4);
    }

    if (promptPageLeave) {
      window.addEventListener('beforeunload', this.beforePageUnload);
      this.unBlockRouting = env.blockRouting?.(this.blockRouting) ?? undefined;
    }

    //Aug
    this.computeAutoLayout()
    if (this.props.flowSpinning) {
      this.allFromReadyInterval = setInterval(() => {
        const subComponents = this.context.getAllChildrenComponets(this).filter((item: any) => !['dialog', 'drawer'].includes(item?.props?.type))
        // 所有子组件就绪状态
        const allComponentsReady = !subComponents.some((item: any) => item?.props?.store.loading)
        if (allComponentsReady) {
          this.props?.getSpinning?.(allComponentsReady, this.props?._formName)
          clearInterval(this.allFromReadyInterval)
        }
      }, 250)
    }
    window.addEventListener('resize', this.computeAutoLayout)
  }

  componentDidUpdate(prevProps: FormProps, prevState: FormState) {
    const props = this.props;
    const store = props.store;

    if (isApiOutdated(prevProps.initApi,
      props.initApi,
      prevProps.data,
      props.data,
    )
      || ((prevProps.initApi as SchemaApiObject)?.url !== (props.initApi as SchemaApiObject)?.url)
    ) {

      const { fetchSuccess, fetchFailed } = props;
      // Jay
      this.is_edit = false

      store[store.hasRemoteData ? 'fetchData' : 'fetchInitData'](
        props.initApi as Api,
        store.data,
        {
          successMessage: fetchSuccess,
          errorMessage: fetchFailed
        }
      ).then(this.initInterval);
    }
    // if (props.flowSpinning) {
    //   const spinArr: boolean[] = this.context.getComponents().filter((item: any) => item.props.type == 'service').map((item: any) => item.props.store.loading)
    //   const spin = spinArr.some(item => item)
    //   props?.getSpinning?.(store.loading || spin, props?._formName)
    // }

    if (prevProps.body !== props.body) {
      if (this.props.getAdvancedFilterForm) {
      } this.getFiltersOptions()
    }

    if(this.contentRef.current?.clientWidth && this.contentRef.current.clientWidth !== this.state.formWidth) {
      this.setState({formWidth: this.contentRef.current?.clientWidth})
    }
  }

  componentWillUnmount() {
    this.mounted = false;
    clearTimeout(this.timer);
    // this.lazyHandleChange.flush();
    this.lazyEmitChange.cancel();
    this.asyncCancel && this.asyncCancel();
    this.disposeOnValidate && this.disposeOnValidate();
    this.disposeRulesValidate && this.disposeRulesValidate();
    window.removeEventListener('beforeunload', this.beforePageUnload);
    this.unBlockRouting?.();

    // Aug
    window.removeEventListener('resize', this.computeAutoLayout);
  }

  // Aug 计算自适应布局
  computeAutoLayout() {
    const { autoLayout, classPrefix: ns, mode, useMobileUI } = this.props;
    if (!autoLayout) {
      return;
    }
    let count: number

    if (useMobileUI && isMobile()) {
      // 移动端布局总是一列 ，赋值0或者1其实都可以
      count = 0
    } else {
      const wrapperWidth = this.contentRef.current.offsetWidth
      // 水平模式下 label跟input一行，宽度给大一点
      const itemWidth = mode === 'horizontal' ? 320 : 260
      count = Math.floor(wrapperWidth / itemWidth)
    }

    if (count !== this.state.autoColumnCount) {
      this.setState({ autoColumnCount: count })
    }
  }

  handleInputFocus = () => {
    this.setState({ inputfocus: false })
  }

  hanldeAdvancedQueryDefault = () => {
    let filtersArr: FiltersArr = []
    let filtersHeader: FiltersHeader[] = []
    if (this.filterOptions?.length) {
      filtersArr = this.getDefaultFilterArrs()
    }
    if (this.filterNorma?.length) {
      filtersHeader = this.filterNorma
    }
    if (this.props?.filtercont && Object.keys(this.props.filtercont).length) {
      const { advancedFilter, handlePrefix, store, body } = this.props
      const conten = handlePrefix?.(this.props.filtercont)
      const prefix: FiltersArr = conten ? [...conten?.advancedFilter, ...conten?.advancedFilterSub] : []
      let defaultHeader: any = []
      let defaultFilterArr: FiltersArr = []
      if (conten?.advancedHeader) {
        defaultHeader = Object.entries(conten?.advancedHeader).map(([key, value]) => ({ key, value }))
      }
      if (advancedFilter && this.filterOptions?.length && prefix.length) {
        defaultFilterArr = prefix
        let newList: FiltersArr = [];
        prefix.forEach((item) => {
          newList.push({
            field: item.field,
            condition: item.condition,
            not: item.not,
            op: item.op,
            dateLine: item.dateLine
          })
          if (item.field.includes('--')) {
            const originField = item.field.split('--')[0]
            this.dealFilterOptions(originField, item.field)
          }
        })
        const dateList = this.getDateArr();
        const dateLineItem = newList.find(item => item.dateLine)
        filtersArr = dateList.length > 0 && !dateLineItem ? [
          {
            field: dateList[0].name,
            condition: 1,
            not: false,
            op: 7,
            dateLine: true
          },
          ...newList
        ] : [...newList];
        this.casestatr = prefix?.[0]?.caseSensitive == 0 ? false : true
      }
      // 高级查询默认值
      if (defaultFilterArr.length) {
        const filter = advancedFilter?.body?.find((item: any) => item.name == "advancedFilter")


        defaultFilterArr.map((item, key) => {
          let isTime = false
          if (filter) {
            const data = filter.body?.find((data: any) => data.name == item?.field)
            if (data && [TagTypeEnum.InputDatetime, TagTypeEnum.InputDate, TagTypeEnum.InputMonth].some(item => item == data?.type)) {
              isTime = true
            } else {
              isTime = false
            }
          }
          let values = item?.values
          const compareField = cloneDeep(item.compareField)
          if (values && typeof values == 'string' && values.includes('(') && values.includes(')') && compareField) {
            const columns = (body as any)?.find((item: any) => item.name == 'advancedFilter')?.body ?? []
            let result = values.substring(1, values.length - 1)
            compareField.forEach((item) => {
              const match = item
              const regex = new RegExp(match, 'g')
              // advancedFilter 默认值设置完善
              const content = columns.find((item: any) => item.name == `advancedFilter.${match}` || item.name == `advancedFilterSub.${match}`);
              if (content) {
                result = (result as string).replace(regex, `[${content.label}]`)
              }
            })
            if (!!result) {
              filtersArr[key].compareField = compareField
              store.changeValue(item.field, result, false);
            }
          } else {
            if (item.op == 7 && item?.values && !isTime) {
              const between = (item?.values as string).split(",")
              if (between.length == 2) {
                between.forEach((val, index) => {
                  if (index == 0) {
                    store.changeValue(item.field + '-a8', val, false);
                  } else {
                    store.changeValue(item.field + '-b8', val, false);
                  }
                })
                return
              }
            }
            store.changeValue(item.field, item?.values, false);
          }
        })
      }
      // 高级查询默认值高级查询默认值中的advancedHeader
      if (defaultHeader.length) {
        defaultHeader.map((item: any) => {
          store.changeValue(item.key, item?.value, false);
        })
      }
      this.setState({ filtersHeader, defaultHeader, defaultFilterArr, filtersArr })
    } else {
      this.setState({ filtersArr, filtersHeader })
    }
  }


  blockRouting(): any {
    const store = this.props.store;
    const { promptPageLeaveMessage, promptPageLeave } = this.props;

    if (promptPageLeave && store.modified) {
      return promptPageLeaveMessage || '新的修改没有保存，确认要离开？';
    }
  }

  beforePageUnload(e: any): any {
    const blocked = this.blockRouting();

    if (blocked) {
      e.preventDefault();
      e.returnValue = '';
    }
  }

  async onInit() {
    const { onInit, store, persistData, submitOnInit, advancedFilterVisible } = this.props;
    if (!isAlive(store)) {
      return;
    }

    // 先拿出来数据，主要担心 form 被什么东西篡改了，然后又应用出去了
    // 之前遇到过问题，所以拿出来了。但是 options  loadOptions 默认值失效了。
    // 所以目前需要两个都要设置一下，再 init Hook 里面。
    let data = cloneObject(store.data);
    const initedAt = store.initedAt;
    store.setInited(true);
    const hooks: Array<(data: any) => Promise<any>> = this.hooks['init'] || [];
    await Promise.all(hooks.map(hook => hook(data)));
    if (!isAlive(store)) {
      return;
    }

    if (store.initedAt !== initedAt) {
      // 说明，之前的数据已经失效了。
      // 比如 combo 一开始设置了初始值，然后 form 的 initApi 又返回了新的值。
      // 这个时候 store 的数据应该已经 init 了新的值。但是 data 还是老的，这个时候
      // onInit 出去就是错误的。
      data = {
        ...data,
        ...store.data
      };
    }

    persistData && store.getLocalPersistData();
    //处理高级查询初始化的时候就查询一次
    !isMobile() && !advancedFilterVisible && onInit && onInit(data, this.props, true);

    this.is_edit = false // Jay

    submitOnInit &&
      this.handleAction(
        undefined,
        {
          type: 'submit'
        },
        store.data
      );
  }

  reload(subPath?: string, query?: any, ctx?: any, silent?: boolean) {
    if (query) {
      return this.receive(query);
    }

    const {
      store,
      initApi,
      initAsyncApi,
      initFinishedField,
      messages: { fetchSuccess, fetchFailed }
    } = this.props;

    isEffectiveApi(initAsyncApi, store.data) &&
      store.updateData({
        [initFinishedField || 'finished']: false
      });

    isEffectiveApi(initApi, store.data)
      ? store
        .fetchInitData(initApi, store.data, {
          successMessage: fetchSuccess,
          errorMessage: fetchFailed,
          silent,
          onSuccess: () => {
            if (
              !isEffectiveApi(initAsyncApi, store.data) ||
              store.data[initFinishedField || 'finished']
            ) {
              return;
            }

            return until(
              () => store.checkRemote(initAsyncApi, store.data),
              (ret: any) => ret && ret[initFinishedField || 'finished'],
              cancel => (this.asyncCancel = cancel)
            );
          }
        })
        .then((result: Payload) => {
          if (result?.ok) {
            this.initInterval(result);
            store.reset(undefined, false);
          }
        })
      : store.reset(undefined, false);
  }
  // Jay 标记receive函数执行
  received: boolean

  receive(values: object) {
    const { store } = this.props;
    // Jay
    this.received = true
    store.updateData(values, store.data);
    this.reload();
  }

  silentReload(target?: string, query?: any) {
    this.reload(target, query, undefined, true);
  }

  initInterval(value: any) {
    const { interval, silentPolling, stopAutoRefreshWhen, data } = this.props;

    clearTimeout(this.timer);
    interval &&
      this.mounted &&
      (!stopAutoRefreshWhen || !evalExpression(stopAutoRefreshWhen, data)) &&
      (this.timer = setTimeout(
        silentPolling ? this.silentReload : this.reload,
        Math.max(interval, 1000)
      ));
    return value;
  }

  isValidated() {
    return this.props.store.validated;
  }

  validate(forceValidate?: boolean): Promise<boolean> {
    const { store } = this.props;

    this.flush();
    return store.validate(this.hooks['validate'] || [], forceValidate);
  }

  clearErrors() {
    const { store } = this.props;

    return store.clearErrors();
  }

  getValues() {
    const { store } = this.props;
    this.flush();
    return store.data;
  }

  setValues(value: any) {
    const { store } = this.props;
    this.flush();
    store.setValues(value);
  }

  submit(fn?: (values: object) => Promise<any>): Promise<any> {
    const { store, messages, translate: __ } = this.props;
    this.flush();

    return store.submit(
      fn,
      this.hooks['validate'] || [],
      __(messages && messages.validateFailed)
    );
  }

  // 如果开启了 lazyChange，需要一个 flush 方法把队列中值应用上。
  flush() {
    const hooks = this.hooks['flush'] || [];
    hooks.forEach(fn => fn());
    this.lazyEmitChange.flush();
  }

  reset() {
    const { store, onReset } = this.props;
    store.reset(onReset);
  }

  addHook(fn: () => any, type: 'validate' | 'init' | 'flush' = 'validate') {
    this.hooks[type] = this.hooks[type] || [];
    this.hooks[type].push(type === 'flush' ? fn : promisify(fn));
    return () => {
      this.removeHook(fn, type);
      fn = noop;
    };
  }

  removeHook(fn: () => any, type: string = 'validate') {
    const hooks = this.hooks[type];

    if (!hooks) {
      return;
    }

    for (let i = 0, len = hooks.length; i < len; i++) {
      let hook = hooks[i];

      if (hook === fn || (hook as any).raw === fn) {
        hooks.splice(i, 1);
        len--;
        i--;
      }
    }
  }

  // Jay
  // input-table组件增删改时的处理函数
  // 传递：form->wrapControl->input-table
  // exec：是否执行
  handleInputTableChange(value: any, name: string) {
    const { store, onFormChange } = this.props;
    !this.changeFields?.includes(name) && (this.changeFields = [...this.changeFields, name]);
    this.is_edit = true
    this.valueChanged = true
    onFormChange?.(value, name);
    store.changeInputTableValue(value, name);
  }

  // Jay
  abandonFormItem(value: any, name: string) {
    const { store } = this.props;
    store.abandonFormItem(value, name)
  }
  // Jay
  setEdited() {
    this.is_edit = true
  }

  // Jay
  setFormLoading(loading: boolean) {
    const { store } = this.props
    store.markFetching(loading)
  }

  handleChange(
    value: any,
    name: string,
    submit: boolean,
    changePristine = false,
    type: any,
  ) {
    const { store, formLazyChange, handleFilterOptions, handleSaveData } = this.props;
    if (typeof name !== 'string') {
      return;
    }

    store.changeValue(name, value, changePristine);
    handleFilterOptions && handleFilterOptions?.(store.data)

    if (store.items) {
      store.items.forEach((item) => {
        if (item.name == name && item.options && item.options.length) {
          handleSaveData && handleSaveData?.(name, item.options)
        }
      })
    }
    // 首次初始化：componentDidmount将is_edit置为false

    // 再次点击编辑：富文本插件会触发一次onChange，在componentDidMount之后触发
    //               富文本内进行了处理 ---> Tinymce组件

    // 数据被修改，直接将标识符设为true
    if (!this.is_edit) {
      this.is_edit = true;
    }

    if (!changePristine) {
      if (!this.valueChanged) this.valueChanged = true;
      if (this.props.api && !this.changeFields?.includes(name)) {
        this.changeFields = [...this.changeFields, name]
      }
      (formLazyChange === false ? this.emitChange : this.lazyEmitChange)(
        submit
      );
    }

    if (store.persistData && store.inited) {
      store.setLocalPersistData();
    }
  }

  emitChange(submit: boolean) {
    const { onChange, store, submitOnChange } = this.props;

    if (!isAlive(store)) {
      return;
    }

    this.props.getFormStore?.(store?.inputTableData)
    onChange &&
      onChange(store.data, difference(store.data, store.pristine), this.props);

    store.clearRestError();

    (submit || (submitOnChange && store.inited)) &&
      this.handleAction(
        undefined,
        {
          type: 'submit'
        },
        store.data
      );
  }

  handleBulkChange(values: Object, submit: boolean, is_mount?: boolean) {
    const { onChange, store, formLazyChange } = this.props;

    store.updateData(values);

    store.items.forEach(formItem => {
      const updatedValue = getVariable(values, formItem.name, false);

      if (updatedValue !== undefined) {
        // 更新验证状态但保留错误信息
        formItem.reset(true);
        // 这里需要更新value，否则提交时不会使用新的字段值校验
        formItem.changeTmpValue(updatedValue);
        formItem.validateOnChange && formItem.validate(values);
      }
    });

    // 数据被修改，将标识符设为true
    this.is_edit = true;
    if (is_mount) {
      this.is_edit = false;
    }

    (formLazyChange === false ? this.emitChange : this.lazyEmitChange)(submit);
  }

  handleFormSubmit(e: React.UIEvent<any>) {
    const { preventEnterSubmit } = this.props;
    e.preventDefault();
    e.stopPropagation()
    if (preventEnterSubmit) {
      return false;
    }

    return this.handleAction(
      e,
      {
        type: 'submit'
      },
      this.props.store.data
    );
  }

  //判断是否提交数据
  shouldCommit(action: Action, isReload: boolean = false) {
    /**
      * @author:Chencicsy
      * @description:控制当数据未修改时不进行api请求
      * @param:preventModifySubmit,is_edit
    **/
    const { store, onFinished, env, onReset } = this.props;
    if (action.redirect) {
      const redirect =
        action.redirect && filter(action.redirect, store.data);
      redirect && env.jumpTo(redirect, action);
    } else if (action.reload && isReload) {
      this.reloadTarget(action.reload, store.data);
    }
    action.close && this.closeTarget(action.close);
    action.close && this.props.onDialogClose?.();

    onFinished(store.data, action)
    store.reset(onReset)
    msgsub._warning('未修改数据', env?.getModalContainer as any)
  }

  async handleSendAction() {
    const { store, env, translate: __, e } = this.props;
    const result = await store.submit();
    if (!result) {
      env.notify('error', __('Form.validateFailed'));
    }
    return result
  }

  autoFocusFirstInputControl() {
    // 如果在表单内部存在一个需要保持聚焦的输入框，则在清空的时候自动聚焦-多个只取第一个
    setTimeout(() => find(this.context.getComponents(), (component => {
      return component.input && component?.props?.$schema?.keepcursor
    }))?.focus(), 200);
  }

  async handleScanAfter(scanAfterDo: ScanAfterDo[], data: object) {
    const { env, showModal } = this.props;
    for (const key in scanAfterDo) {
      if (Object.prototype.hasOwnProperty.call(scanAfterDo, key)) {
        const element = scanAfterDo[key];
        const cmd = element.cmd
        switch (cmd) {
          case 'STEP_PRINT_LABEL':
            const printBody = element.body as ScanAfterLabelPrint
            const baseUrl = process.env.NODE_ENV === 'production' ? env.axiosInstance?.defaults?.baseURL : 'https://saasdev.fastlion.cn/saas'
            const labelTemplate = buildLabelTemplate(printBody.labelTemplate.tempContent)
            const templateDatas = setLabelTemplateData(labelTemplate, printBody.labelData, baseUrl)
            labelPrint({
              templateDatas,
              marginTop: 0,
              marginLeft: 0,
              pageWidth: 210,
              pageHeight: 297,
              direction: true,
              preview: false,
              printer: printBody?.labelPrinter,
              count: 1
            })
            break
          case 'STEP_PORT':
            const portBody = element.body as ScanAfterPort
            await expressLabels(portBody?.body, env.fetcher, this.props.translate, showModal === 1)
            if (portBody.afterApi) {
              await env.fetcher(portBody.afterApi, data)
            }
            break
          case 'STEP_SHOW':
            const { showMsg, showType, afterApi } = element.body as ScanAfterShow
            if (showType == 0 || showType == 10) {
              if (this.props.reload) {
                this.reloadTarget(this.props.reload, this.props.store.data);
              }
              msgsub._info(showMsg)
              if (afterApi) {
                const payload = await env.fetcher(afterApi, data)
                if (payload.ok && payload.status == 20003) {
                  await this.handleScanAfter(payload.data.scanAfterDo, data)
                }
              }
            } else if (showType == 1 || showType == 11) {
              const confirm = await env.confirm(showMsg)
              if (confirm && afterApi) {
                const payload = await env.fetcher(afterApi, data)
                if (payload.ok && payload.status == 20003) {
                  await this.handleScanAfter(payload.data.scanAfterDo, data)
                }
              }
            } else if (showType == 2 || showType == 12) {
              await env.confirm(showMsg, undefined, undefined, false)
            }
            break
          case 'STEP_VARS':
            const varsBody = element.body as ScanAfterVars
            const formData = await env.prompt(varsBody?.body, varsBody?.data)
            if (formData !== false) {
              const payload = await env.fetcher(varsBody?.afterApi, { ...formData, ...data })
              if (payload.ok && payload.status == 20003) {
                await this.handleScanAfter(payload.data.scanAfterDo, data)
              }
            }
            break
          default:
            break
        }
        this.setState({ inputfocus: true })
      }
    }

  }

  handleAction(
    e: React.UIEvent<any> | void,
    action: Action,
    data: object,
    throwErrors: boolean = false,
    delegate?: IScopedContext
  ): any {
    const {
      store,
      onSubmit,
      api,
      asyncApi,
      finishedField,
      checkInterval,
      messages: { saveSuccess, saveFailed },
      resetAfterSubmit,
      clearAfterSubmit,
      onAction,
      onSaved,
      onReset,
      onFinished,
      onFailed,
      redirect,
      reload,
      target,
      env,
      onChange,
      clearPersistDataAfterSubmit,
      trimValues,
      translate: __,
      preventModifySubmit
    } = this.props;
    // 做动作之前，先把数据同步一下。
    this.flush();
    if (trimValues) {
      store.trimValues();
    }
    // 如果 data 就是当前层，则 flush 一下。
    if (data === this.props.data) {
      data = store.data;
    }

    if (Array.isArray(action.required) && action.required.length) {
      return store.validateFields(action.required).then(result => {
        if (!result) {
          env.notify('error', __('Form.validateFailed'));
        } else {
          this.handleAction(
            e,
            { ...action, required: undefined },
            data,
            throwErrors,
            delegate
          );
        }
      });
    }
    if (
      action.type === 'submit' ||
      action.actionType === 'submit' ||
      action.actionType === 'confirm' ||
      action.actionType === 'reset-and-submit' ||
      action.actionType === 'clear-and-submit'
    ) {
      store.setCurrentAction(action);
      this.props.handleReset?.()
      if (action.actionType === 'reset-and-submit') {
        store.reset(onReset);
      } else if (action.actionType === 'clear-and-submit') {
        store.clear(onReset);
      }
      if (action.actionType == "flow_save_drat") {
        store.updateData({ FLOW_SAVE_DRAT_VALUE: 1 })
      }
      return this.submit(async (values: any) => {
        if (onSubmit && onSubmit(values, action) === false) {
          return Promise.resolve(false);
        }
        if (preventModifySubmit && !this.is_edit && !this.valueChanged) {
          this.shouldCommit(action)
          return;
        }

        if (target) {
          this.submitToTarget(target, values);
        } else if (action.actionType === 'reload') {
          action.target && this.reloadTarget(action.target, values);
        } else if (action.actionType === 'dialog') {
          store.openDialog(data);
        } else if (action.actionType === 'drawer') {
          store.openDrawer(data);
        } else if (isEffectiveApi(action.api || api, values)) {
          // Jay
          // 这是对表单项input-table的数据结构做改造，覆盖掉values中key为input-table的name的值
          // 如果不需要进行改造，直接取values即可
          // 顺序不能乱
          // let data = { ...values, ...store.hiddenIputTable, ...store.inputTableData }

          let data = Object.assign(values, store.hiddenIputTable, store.inputTableData, { changeFields: this.changeFields?.join() });

          let finnalAsyncApi = action.asyncApi || asyncApi;

          isEffectiveApi(finnalAsyncApi, store.data) &&
            store.updateData({
              [finishedField || 'finished']: false
            });
          return store
            .saveRemote(action.api || (api as Api), data, {
              successMessage: saveSuccess,
              errorMessage: saveFailed,
              onSuccess: () => {
                if (
                  !isEffectiveApi(finnalAsyncApi, store.data) ||
                  store.data[finishedField || 'finished']
                ) {
                  return;
                }

                return until(
                  () => store.checkRemote(finnalAsyncApi as Api, store.data),
                  (ret: any) => ret && ret[finishedField || 'finished'],
                  cancel => (this.asyncCancel = cancel),
                  checkInterval
                );
              }
            })
            .then(async response => {
              onSaved && onSaved(values, response);
              const feedback = action.feedback || this.props.feedback;
              // const _data = createObject(data, response)

              // if ((_data as any)?.status === 10003) {
              //   handleActionCallback_10003(_data, store, this.handleAction, () => { action.close && this.closeTarget(action.close) }, false, env)
              //   return;
              // }

              if (response?.status === 20003) {
                const scanAfterDo: ScanAfterDo[] = response?.scanAfterDo ?? []
                await this.handleScanAfter(scanAfterDo, data)
                this.setState({ inputfocus: true })
              }

              // submit 也支持 feedback
              if (feedback && isVisible(feedback, store.data)) {
                const confirmed = await this.openFeedback(feedback, store.data);

                // 如果 feedback 配置了，取消就跳过原有逻辑。
                if (feedback.skipRestOnCancel && !confirmed) {
                  throw new SkipOperation();
                } else if (feedback.skipRestOnConfirm && confirmed) {
                  throw new SkipOperation();
                }
              }

              // return values;
            });
        }
        return Promise.resolve(null);
      })
        .then(values => {
          // 有可能 onSubmit return false 了，那么后面的就不应该再执行了。
          if (values === false) {
            return store.data;
          }

          if (onFinished && onFinished(values, action) === false) {
            return values;
          }
          resetAfterSubmit && store.reset(onReset);
          clearAfterSubmit && store.clear(onReset);
          clearPersistDataAfterSubmit && store.clearLocalPersistData();
          if (action.redirect || redirect) {
            const finalRedirect = filter(
              action.redirect || redirect,
              store.data
            );
            finalRedirect && env.jumpTo(finalRedirect, action);
          } else if ((action.reload || reload)) {
            this.reloadTarget(action.reload || reload!, store.data)
          }

          action.close && this.closeTarget(action.close);
          return values;
        })
        .catch(reason => {
          if (reason instanceof SkipOperation) {
            return;
          }

          onFailed && onFailed(reason, store.errors);

          if (throwErrors) {
            throw reason;
          }
        });
    } else if (action.type === 'reset' || action.actionType === 'reset') {
      this.props.handledelVisible?.(undefined, true)
      store.setCurrentAction(action);
      store.reset((data: any) => onReset?.(data, action));
      this.props.handleFilterOptions?.(store.data)
      this.props.handleReset?.()
      // 如果在表单内部存在一个需要保持聚焦的输入框，则在清空的时候自动聚焦-多个只取第一个
      this.autoFocusFirstInputControl()
    } else if (action.actionType === 'clear') {
      store.setCurrentAction(action);
      store.clear(onReset);
    } else if (action.actionType === 'dialog') {
      store.setCurrentAction(action);
      store.openDialog(data);
    } else if (action.actionType === 'drawer') {
      store.setCurrentAction(action);
      store.openDrawer(data);
    } else if (action.actionType === 'ajax') {
      store.setCurrentAction(action);
      if (!isEffectiveApi(action.api)) {
        return env.alert(__(`当 actionType 为 ajax 时，请设置 api 属性`));
      }

      if (preventModifySubmit && !this.is_edit && !this.valueChanged) {
        return this.shouldCommit(action, true)
      }

      return store
        .saveRemote(action.api as Api, data, {
          successMessage: __(
            (action.messages && action.messages.success) || saveSuccess
          ),
          errorMessage: __(
            (action.messages && action.messages.failed) || saveFailed
          )
        })
        .then(async response => {
          response &&
            onChange &&
            onChange(
              store.data,
              difference(store.data, store.pristine),
              this.props
            );
          const _data = createObject(data, response)
          // if ((_data as any)?.status === 10003) {
          //   handleActionCallback_10003(_data, store, this.handleAction, () => { action.close && this.closeTarget(action.close) }, false, env)
          //   return;
          // }
          if (store.validated) {
            await this.validate(true);
          }

          if (action.feedback && isVisible(action.feedback, store.data)) {
            await this.openFeedback(action.feedback, store.data);
          }

          const redirect =
            action.redirect && filter(action.redirect, store.data);
          redirect && env.jumpTo(redirect, action);

          action.reload && this.reloadTarget(action.reload, store.data);
          action.close && this.closeTarget(action.close);
          // Jay
          // ajax类型支持关闭dialog
          action.close && this.props.onDialogClose?.()
        })
        .catch(e => {
          onFailed && onFailed(e, store.errors);
          if (throwErrors) {
            throw e;
          }
        });
    } else if (action.actionType === 'reload') {
      store.setCurrentAction(action);
      if (action.target) {
        this.reloadTarget(action.target, data);
      } else {
        // 刷自己
        this.receive(data);
      }
      // action.target && this.reloadTarget(action.target, data);
    } else if (action.actionType === 'advanced-filter') {

      this.props.handleFilterOptions?.(store.data)
      // 高级查询
      this.props.handleFilterAdvanced?.()
    } else if (action.actionType === 'form-print') {
      const LODOP = getLodop()
      if (LODOP) {
        this.setState({ printVisible: true, printInfo: action.printInfo })
        this.contentRef.current?.setAttribute('id', `FORM_${this.props.name ?? 'detail'}`)
      }
    } else if (onAction) {
      // 不识别的丢给上层去处理。
      return onAction(e, action, data, throwErrors, delegate || this.context);
    }
  }
  handleJump = (body: any) => {
    if (body.redirectType === '2') {
      this.props.env.fetcher(body.linkUrl, body.bodydata).then(res => {
        if (res.ok && res.data != null) {
          this.flowDetail = res.data
          this.setState({ flowModalVisible: true })
        } else {
          message.error(res.msg)
        }
      })
      return
    }
    const types = isMobile() ? 'drawer' : 'dialog'
    const action: any = {
      type: "action",
      actionType: types,
      close: true
    }
    action[types] = {
      title: body.linkTitle,
      type: types,
      name: `form-dialog-service-${createRandomValue()}`,
      size: body.linkSize ?? 'lg',
      bodyClassName: `overflow-y-auto max-h-nestSide-${types}`,
      className: "h-full",
      actions: [],
      body: {
        schemaApi: {
          "method": "get",
          "url": body.linkUrl
        },
        type: "service",
        name: `form-service-${createRandomValue()}`
      }
    }
    this.handleAction(this.props.e, action, body.bodydata)
  }
  handleQuery(query: any) {
    if (this.props.initApi) {
      this.receive(query);
    } else {
      this.props.onQuery?.(query);
    }
  }

  handleDialogConfirm(
    values: object[],
    action: Action,
    ctx: any,
    targets: Array<any>
  ) {
    const { store, onChange } = this.props;
    if (
      (action.mergeData || store.action.mergeData) &&
      values.length === 1 &&
      values[0] &&
      targets[0].props.type === 'form'
    ) {
      this.handleBulkChange(values[0], false);
    }
    store.closeDialog(true);
  }

  handleDialogClose(confirmed = false, formInstance?: any, tableInstance?: TableRenderer) {
    const { store } = this.props;
    const { translate: __, env } = this.props;
    if (tableInstance) {
      const count = tableInstance.props.store.modified;
      if (count > 0) {
        Modal.warning({
          title: (
            <div>
              <div style={{ position: 'absolute', right: '10px', top: '10px', fontSize: '12px', cursor: "pointer" }} onClick={() => { Modal.destroyAll() }} >
                <Icon icon="close" className="icon" />
              </div>
            </div>
          ),
          content: '当前表格存在已修改的数据，请先提交或放弃，再进行其他操作!',
          getContainer: env.getModalContainer,
          zIndex: 1020,
          okText: __('confirm')
        });
        return;
      }
    }

    store.closeDialog(confirmed);
  }


  handleDrawerConfirm(
    values: object[],
    action: Action,
    ctx: any,
    targets: Array<any>
  ) {
    const { store, onChange } = this.props;
    if (
      (action.mergeData || store.action.mergeData) &&
      values.length === 1 &&
      values[0] &&
      targets[0].props.type === 'form'
    ) {
      store.updateData(values[0]);
      onChange &&
        onChange(
          store.data,
          difference(store.data, store.pristine),
          this.props
        );
    }

    store.closeDrawer(true);
  }

  handleDrawerClose() {
    const { store } = this.props;
    store.closeDrawer(false);
  }

  submitToTarget(target: string, values: object) {
    // 会被覆写
  }

  reloadTarget(target: string, data?: any) {
    // 会被覆写
  }

  closeTarget(target: string) {
    // 会被覆写
  }

  openFeedback(dialog: any, ctx: any) {
    return new Promise(resolve => {
      const { store } = this.props;
      store.setCurrentAction({
        type: 'button',
        actionType: 'dialog',
        dialog: dialog
      });
      store.openDialog(ctx, undefined, confirmed => {
        resolve(confirmed);
      });
    });
  }

  buildActions() {
    const { actions, submitText, body, translate: __ } = this.props;
    if (
      typeof actions !== 'undefined' ||
      !submitText ||
      (Array.isArray(body) &&
        body.some(
          item =>
            item &&
            !!~['submit', 'button', 'button-group', 'reset',].indexOf(
              (item as any)?.body?.[0]?.type ||
              (item as any)?.body?.type ||
              (item as SchemaObject).type
            )
        ))
    ) {
      return actions;
    }

    return [
      {
        type: 'submit',
        label: __(submitText),
        primary: true
      }
    ];
  }

  handleChangeFields(autoFillObj: { [key: string]: any } = {}) {
    Object.keys(autoFillObj).forEach(item => {
      if (!this.changeFields?.includes(item)) {
        this.changeFields = [...this.changeFields, item]
      }
    })
  }

  // Jay CRUD顶部表单渲染展开/收起按钮
  buildExtendAction() {
    const { translate: __ } = this.props
    const { collpased } = this.state;
    return <Button level='link' onClick={() => {
      this.setState({ collpased: !collpased })
    }}>
      {collpased ? __('More') : __('PutAway')}
      <i style={{
        transform: `${collpased ? 'translateY(-3px) rotate(135deg)' : 'rotate(-45deg)'}`,
      }} />
    </Button>
  }

  renderFormItems(
    schema: Partial<FormSchema> & {
      controls?: Array<any>;
    },
    region: string = '',
    otherProps: Partial<FormProps> = {}
  ): React.ReactNode {
    let body: Array<any> = Array.isArray(schema.body)
      ? schema.body
      : schema.body
        ? [schema.body]
        : [];

    // 旧用法，让 wrapper 走走 compat 逻辑兼容旧用法
    // 后续可以删除。
    if (!body.length && schema.controls) {
      console.warn('请用 body 代替 controls');
      body = [
        {
          size: 'none',
          type: 'wrapper',
          wrap: false,
          controls: schema.controls
        }
      ];
    }
    return this.renderChildren(body, region, otherProps);
  }

  renderChildren(
    children: Array<any>,
    region: string,
    otherProps: Partial<FormProps> = {}
  ): React.ReactNode {
    children = children || [];

    if (!Array.isArray(children)) {
      children = [children];
    }

    if (this.props.mode === 'row') {
      const ns = this.props.classPrefix;

      children = flatten(children).filter(item => {
        if ((item as Schema)?.hidden || (item as Schema)?.visible === false) {
          return false;
        }

        const exprProps = getExprProperties(
          item as Schema,
          this.props.store.data,
          undefined,
          this.props
        );
        if (exprProps?.hidden || exprProps?.visible === false) {
          return false;
        }

        return true;
      });

      if (!children.length) {
        return null;
      }

      return (
        <div className={`${ns}Form-row`}>
          {children.map((control, key) =>
            ~['hidden', 'formula'].indexOf((control as any).type) ||
              (control as any).mode === 'inline' ? (
              this.renderChild(control, key, otherProps)
            ) : (
              <div
                key={key}
                className={cx(
                  `${ns}Form-col`,
                  (control as Schema).columnClassName
                )}
              >
                {this.renderChild(control, '', {
                  ...otherProps,
                  mode: 'row'
                })}
              </div>
            )
          )}
        </div>
      );
    }

    return children.map((control, key) =>
      this.renderChild(control, key, otherProps, region)
    );
  }

  renderChild(
    control: SchemaNode,
    key: any = '',
    otherProps: Partial<FormProps> = {},
    region: string = ''
  ): React.ReactNode {
    let butColor = false
    if ((control as Schema).actionType === 'advanced-filter') {
      if (this.props.advancedFilter === undefined) {
        return
      }
      const filt = this.props.filtercont
      if (Object.keys(filt || {}).length && (filt?.advancedFilter?.length || filt?.advancedFitlerSub?.length || Object.keys(filt?.advancedHeader || {}).length)
      ) {
        butColor = true
      }
    }

    if (!control) {
      return null;
    } else if (typeof control === 'string') {
      control = {
        type: 'tpl',
        tpl: control
      };
    }

    const props = {
      ...this.props,
      ...otherProps
    };

    const form = this.props.store;
    const {
      render,
      mode,
      horizontal,
      store,
      disabled,
      controlWidth,
      resolveDefinitions,
      lazyChange,
      preventEnterSubmit,
      formMobileHorizontal,
      isDetail,
      flowProcess,
      initApi,
      notPrintFieldList
    } = props;

    const subProps = {
      formStore: form,
      data: store.data,
      key: `${(control as Schema).name || ''}-${(control as Schema).type
        }-${key}`,
      formInited: form.inited,
      formSubmited: form.submited,
      formMode: mode,
      readOnlyItem: preventEnterSubmit,
      formHorizontal: horizontal,
      controlWidth,
      butColor,
      disabled: disabled || (control as Schema).disabled || form.loading,
      btnDisabled: form.loading || form.validating,
      onAction: this.handleAction,
      onQuery: this.handleQuery,
      onChange: this.handleChange,
      handleChangeFields: this.handleChangeFields,
      // Jay
      // 下发给子组件（wrapControl）
      onInputTableChange: this.handleInputTableChange,
      abandonFormItem: this.abandonFormItem,
      setEdited: this.setEdited, // 标记表单项被修改过
      setFormLoading: this.setFormLoading,
      store,
      //Aug
      autoLayout: this.props.autoLayout,
      formatSize: this.props.formatSize,

      onBulkChange: this.handleBulkChange,
      userChange: this.state.userChange,
      handleUserChange: this.handleUserChange,
      addHook: this.addHook,
      removeHook: this.removeHook,
      renderFormItems: this.renderFormItems,
      formPristine: form.pristine,
      _formName: this.props.name,
      inputfocus: this.state.inputfocus,
      handleInputFocus: this.handleInputFocus,
      handleJump: this.handleJump,
      isDetail,
      flowProcess,
      isShowHide: !!initApi && isDetail && isMobile(),
      isNumber: (control as Schema).isNumber,
      notPrintFieldList,
      inputFocusShowPicker: props.inputFocusShowPicker,
      inputBlurCheckValue: props.inputBlurCheckValue,
      validations: props.validations,
      // value: (control as any)?.name
      //   ? getVariable(form.data, (control as any)?.name, canAccessSuperData)
      //   : (control as any)?.value,
      // defaultValue: (control as any)?.value
    };

    let subSchema: any = {
      ...control
    };

    if (subSchema.$ref) {
      subSchema = {
        ...resolveDefinitions(subSchema.$ref),
        ...subSchema
      };
    }

    lazyChange === false && (subSchema.changeImmediately = true);
    return render(`${region ? `${region}/` : ''}${key}`, subSchema, subProps);
  }

  //处理高级查询对应的下拉选择列表，允许字段重复出现，需要构造key
  dealFilterOptions = (value: string, createName: string) => {
    const origin = this.filterObj[value]
    this.filterObj[createName] = { ...origin, name: createName };
    if (!this.filterOptions.find(item => item.value === createName)) {
      this.filterOptions.push({ label: (origin.groupName ? `${origin.groupName} · ` : '') + (origin.label || origin.placeholder), value: createName, type: origin.type, isNumber: origin.isNumber || null })
    }
  }

  // Jay
  changeCondition(val: number, index: number) {
    const { filtersArr } = this.state
    filtersArr[index].condition = val === 0 ? 1 : 0
    this.setState({ filtersArr })
  }
  changeField(value: string, index: number) {
    const { store } = this.props
    const { filtersArr } = this.state
    const repeatList = filtersArr.filter(item => item.field.includes(value));
    let repeatNum = 0
    if (repeatList.length > 0) {
      const lastINdex = repeatList[repeatList.length - 1].field.split('--')?.[1]
      repeatNum = lastINdex ? Number(lastINdex) + 1 : 1
    }
    const createName = repeatNum > 0 ? value + `--${repeatNum}` : value
    filtersArr[index].field = createName
    repeatNum > 0 && this.dealFilterOptions(value, createName);
    const filter = this.filterObj[value]
    if (filter.type === "switch") {
      store.changeValue(filter.name, filter.falseValue, false);
    }
  }
  changeNot(value: boolean, index: number) {
    const { filtersArr } = this.state
    filtersArr[index].not = value
    this.setState({ filtersArr })
  }
  changeRange(value: number, index: number) {
    const { filtersArr } = this.state
    const { store } = this.props
    if (filtersArr[index].op === RangeOptionsEnum.Between && value !== RangeOptionsEnum.Between) {
      store.changeValue(filtersArr[index].field, '', false)
    }
    filtersArr[index].op = value
    this.setState({ filtersArr, emptyTimeSelected: false })
  }
  changePare = (value: any, index: number) => {
    const { filtersArr } = this.state
    filtersArr[index].compareField = value
    this.setState({ filtersArr })
  }
  filterPropsArr() {
    return this.filterOptions || []
  }
  selectEmptyTime = (index: number) => {
    const { filtersArr } = this.state
    const { store } = this.props
    store.changeValue(filtersArr[index].field, '', false)
    filtersArr[index].op = 2
    this.setState({ filtersArr, emptyTimeSelected: true })
  }
  getDateArr = () => {
    const { body, advancedQueryFields } = this.props
    let filters: Array<any> = Array.isArray(body) ? body : body
      ? [body] : [];
    const adv = filters.find(item => item.name === 'advancedFilter')?.body;
    if (adv?.length) {
      let list = adv.filter((item: any) => item.type && ['input-date', 'input-datetime', 'input-time', 'input-month', 'input-quarter', 'input-year'].includes(item.type))
      if (advancedQueryFields) {
        list = list.filter((item: any) => advancedQueryFields.includes(item.name?.split('.')?.[1]))
      }
      return list
    }
    return [];
  }
  getDefaultFilterArrs = () => {
    const body = this.filterPropsArr();
    const dateList = this.getDateArr();
    const defaultCondition = {
      field: body[0].value,
      condition: 1,
      not: false,
      op: 2
    }
    if (dateList.length > 0 && defaultCondition.field === dateList[0].name) {
      this.dealFilterOptions(defaultCondition.field, defaultCondition.field + '--1')
    }
    const list = dateList.length > 0 ? [
      {
        field: dateList[0].name,
        condition: 1,
        not: false,
        op: 7,
        dateLine: true
      },
      { ...defaultCondition, field: defaultCondition.field === dateList[0].name ? defaultCondition.field + '--1' : defaultCondition.field }
    ] : [{ ...defaultCondition }];
    return list;
  }
  addFilter() {
    const { filtersArr } = this.state
    const body = this.filterPropsArr()
    //该条件已有的数量
    const repeatList = filtersArr.filter(item => item.field.includes(body[0].value));
    let repeatNum = 0
    if (repeatList.length > 0) {
      const lastINdex = repeatList[repeatList.length - 1].field.split('--')[1]
      repeatNum = lastINdex ? Number(lastINdex) + 1 : 1
    }
    const createName = repeatNum > 0 ? body[0].value + `--${repeatNum}` : body[0].value
    filtersArr.push({
      field: createName,
      condition: 1,
      not: false,
      op: body[0].type == TagTypeEnum.file ? RangeOptionsEnum.IsEmpty : RangeOptionsEnum.Equal,
    })
    this.setState({ filtersArr })
    if (repeatNum > 0) {
      const origin = this.filterObj[body[0].value]
      this.filterObj[createName] = { ...origin, name: createName };
      if (!this.filterOptions.find(item => item.value === createName)) {
        this.filterOptions.push({ label: (origin.groupName ? `${origin.groupName} · ` : '') + (origin.label || origin.placeholder), value: createName, type: origin.type, isNumber: origin.isNumber || null })
      }
    }
  }

  deleteFilter(index: number) {
    const { filtersArr } = this.state
    // 只有一个的时候禁止删除
    if (filtersArr.length === 1) return
    const prevField = filtersArr[index].field;
    filtersArr.splice(index, 1)
    this.setState({ filtersArr })
    this.props.store.changeValue(prevField, undefined)
  }
  // saveEmptyValue 是否保存空值
  confirmAdvancedFilter(saveEmptyValue = false) {
    const { filtersArr, caseSensitive, topN, limitStatus } = this.state
    const { name, store, handleSaveData } = this.props
    if (!name) return
    const dataArr: FiltersArr = []
    //与高级查询一样，只是字段名不一样，后端需要做区分
    const advancedFilterSub: FiltersArr = []
    filtersArr.forEach(item => {
      const filterFields = (isArray(this.props.body) ? this.props.body.find(col => (col as any).name === 'advancedFilter') :
        this.props.body?.['advancedFilter'])?.body;
      let storeData = (item.field.includes('advancedFilterSub') ? store.data['advancedFilterSub'] : store.data[name]) || {};
      const itemName = item.field.split('.').pop();
      if (!itemName) return;
      if (isNil(this.filterObj[item.field]) && !item.field.includes('--')) return;
      const temp: any = { ...item, field: itemName }
      if (item.op === RangeOptionsEnum.Between) {
        if (this.filterObj[item.field].type === TagTypeEnum.InputNumber || this.filterObj[item.field]?.isNumber) {
          const v1 = storeData[`${itemName}-a8`]
          const v2 = storeData[`${itemName}-b8`]
          if ((isNil(v1) || isNil(v2)) && !saveEmptyValue) return
          let values = [v1, v2].join(',');
          temp.values = values === ',' ? '' : values;
        } else if (this.filterObj[item.field].type === TagTypeEnum.InputDatetime || this.filterObj[item.field].type === TagTypeEnum.InputDate) {
          let values = storeData[itemName]
          if (!values && values !== 0 && !saveEmptyValue) return
          temp.values = values
        } else return
      } else if (item.op !== RangeOptionsEnum.IsEmpty) {
        let values = storeData[itemName]
        if (!values && values !== 0 && !saveEmptyValue) return
        if (typeof values == 'string' && values.includes('[') && values.includes(']')) {
          const list = values.match(/\[(.*?)\]/g)?.map(str => filterFields.find((fcol: any) => fcol.label === str.replace('[', '').replace(']', ''))?.name.split('.')?.[1]) ?? []
          temp.compareField = list;
          const result = values.replace(/\[(.*?)\]/g, (match: any) => {
            let index = values.match(/\[([^\]]*)\]/g)?.indexOf(match);
            if (!index && index !== 0) return ''
            if (!isNaN(index) && index >= 0 && index < list.length) {
              return `${list[index]}`;
            }
            return match;
          });
          temp.values = `(${result})`
          temp.useFieldCompare = +list?.length > 0
        } else {
          if (temp.compareField) {
            delete temp.compareField
          }
          temp.values = values
        }
      }

      // caseSensitive 区分大小写敏感 1区分 0不区分
      // 因为在需求中这个操作是单个按钮完成
      // 但是后端接口中这个字段实际上是每个字段都需要的字段
      // 故写成这样 需求原型http://172.28.40.72:7080/zentao/task-view-1027.html
      temp.caseSensitive = Number(caseSensitive)
      temp.field.includes('--') && (temp.field = temp.field.split('--')[0])
      // 同步一下valuesAlia 防止展示与查询不同步的问题
      temp.valuesAlia = temp.value
      item.field.includes('advancedFilterSub') ? advancedFilterSub.push(temp) : dataArr.push(temp)
    })
    const dataHeader: any = {}
    this.filterNorma && this.filterNorma.forEach((item) => {
      this.circulation(item, dataHeader)
    })
    const data: any = isMobile() ? store.data.filterParam : this.props.filterOptions.filterParam
    store.items.forEach((item) => {
      if (item.options.length > 0) {
        handleSaveData && handleSaveData(item.name, item.options)
      }
    })

    const query = {
      [name]: dataArr,
      advancedHeader: dataHeader,
      filterParam: data,
      advancedFilterSub,
      filterOptionData: this.filterOptionData,
      limitParam: { topN, limitStatus }
    }

    if (this.props.target)
      this.reloadTarget(this.props.target, query)

    return query
  }
  circulation(Current: FiltersHeader, data: any) {
    if (Current.body) {
      Current.body?.map((item: FiltersHeader) => {
        if (item?.body) this.circulation(item, data)
        else this.multiplexing(item, data)
      })
    } else this.multiplexing(Current, data)
  }
  // 复用
  multiplexing(Current: FiltersHeader, data: any) {
    const { store } = this.props;
    const itemName = Current?.name?.split('.').pop() as string
    const header = store.data?.advancedHeader;
    const empty = header?.[itemName]
    if (!itemName && empty == undefined && empty == null) return
    if (typeof empty == "number") {
      data[itemName] = empty;
    } else if (empty?.replace(/\s+/g, "").length) {
      data[itemName] = empty;
    }
  }
  resetAdvancedFilter() {
    const { store, name, filtercont } = this.props
    if (filtercont?.limitParam) {
      this.setState({
        topN: filtercont.limitParam.topN,
        limitStatus: filtercont.limitParam.limitStatus
      })
    }
    if (!this.filterOptions?.length && !this.filterNorma?.length) return
    if (this.filterOptions?.length) {
      name && store.changeValue(name, undefined);
      const list = this.getDefaultFilterArrs();
      this.setState({
        filtersArr: list
      })
    }
    if (this.filterNorma?.length) {
      store.changeValue("advancedHeader", undefined);
      this.setState({
        filtersHeader: this.filterNorma
      })
    }
  }

  resetAdvancedOptionsFilter() {
    this.filterOptionRef.current?.handleReset()
  }

  resetIsModleFilter(e?: any) {
    const { store } = this.props
    store.reset(undefined, false);
    // 如果自己本身没有 filterParam 参数 进行参数初始化 防止取到父级的 filterParam
    if ((store?.data?.filterParam || store?.data?.['__prev']?.filterParam) && !store.data.hasOwnProperty('filterParam') && ['filterParam', 'advancedFilter'].some(item => this.props.name?.includes(item)) || e) {
      store.changeValue('filterParam', {})
    }
    this.resetAdvancedFilter()
  }

  handlerenew(arr: boolean, val?: any, keyName?: string) {
    const { store } = this.props
    const { filtersArr, filtersHeader } = this.state;
    const list = this.getDefaultFilterArrs();
    if (arr) {
      filtersArr.forEach(item => store.changeValue(item.field, ""))
      filtersHeader?.forEach(Item => {
        if (Item?.body) {
          Item.body.forEach((item: any) => store.changeValue(item.name, ""))
        } else {
          store.changeValue(Item.name, "")
        }
      })
      this.setState({ filtersArr: list })
    } else {
      if (val.includes('advancedFilter')) {
        const targetIndex = filtersArr.findIndex(item => item.field == (keyName || val))
        if (filtersArr[targetIndex].dateLine) {
          store.changeValue(keyName || val, undefined)
          this.setState({ filtersArr: [...filtersArr] })
        } else {
          this.deleteFilter(targetIndex)
        }
        if (filtersArr.length == 0) {
          this.setState({ filtersArr: list })
        }
      }
      store.changeValue(keyName || val, "")
    }
  }
  handleFiltersArr(body: any) {
    const { store, body: FilterBody, filtercont } = this.props
    // 根据查询条件去columns
    const columns: any[] = [];
    (FilterBody as any)?.find((item: any) => item.name == 'advancedFilter')?.body.map((column: any) => { if (column.label) columns.push({ ...column, name: column.name.replace(/advancedFilter(Sub)?./, '') }) })
    if (filtercont?.limitParam) {
      this.setState({
        topN: filtercont.limitParam.topN,
        limitStatus: filtercont.limitParam.limitStatus
      })
    }
    if (Object.keys(body.advancedHeader).length) {
      const data = body.advancedHeader
      for (const key in data) {
        store.changeValue(key, data[key], false);
      }
    }

    const CompareFiledsDeal = (conditions: any[]) => conditions.map((item: any) => {
      const val = item
      const values = item.values
      const compareField = cloneDeep(item.compareField)
      if (values && typeof values == 'string' && values.includes('(') && values.includes(')') && columns && compareField) {
        let result = values.substring(1, values.length - 1)
        compareField.forEach((item: any) => {
          const match = item
          const regex = new RegExp(match, 'g')
          const content = columns.find((item: any) => item.name == match);
          if (content) {
            result = (result as string).replace(regex, `[${content.label}]`)
          }
        })
        if (!!result) {
          val.compareField = compareField
          val.values = result
          return val
        }
      }
      return item
    })

    const advancedFilterArr = CompareFiledsDeal(body.advancedFilter)

    // sub也做下处理
    const advancedFilterSubArr = CompareFiledsDeal(body.advancedFilterSub)

    const filter: any[] = [...advancedFilterArr, ...advancedFilterSubArr]

    if (filter.length)
      filter.forEach((element: any) => {
        if (element.field.includes('--')) {
          const originField = element.field.split('--')[0]
          this.dealFilterOptions(originField, element.field)
        }
        store.changeValue(element.field, element?.values, false);
      });

    if (!filter.length) {
      store.changeValue('advancedFilter', "")
      const list = this.getDefaultFilterArrs();
      this.setState({
        filtersArr: list
      })
    }
    if (!Object.keys(body.advancedHeader).length) {
      store.changeValue("advancedHeader", {});
      this.setState({
        filtersHeader: this.filterNorma
      })
    }
    this.setState({ filtersArr: filter, caseSensitive: filter[0].caseSensitive == 0 ? false : true })
  }
  // 当前过滤条件是否展示输入的判断
  isShowInputItem(item: { op: RangeOptionsEnum }, type: TagTypeEnum, isPc: boolean = false) {
    // 操作符不为空 并且 不是文件类型的渲染
    if (isPc) {
      return item.op !== RangeOptionsEnum.IsEmpty && type !== TagTypeEnum.file
    }
    return item.op !== RangeOptionsEnum.IsEmpty && type !== TagTypeEnum.file && item.op !== RangeOptionsEnum.DataTag
  }

  getFiltersOptions() {
    const { body, advancedQueryFields, handlePrefix, filtercont } = this.props
    let filters: Array<any> = Array.isArray(body) ? body : body
      ? [body] : [];
    const queryFields = advancedQueryFields && advancedQueryFields.split(",");
    const data = handlePrefix?.(filtercont)['advancedHeader']
    filters.forEach(item => {
      if (item.name?.includes("advancedFilter")) {
        this.filterOptions = (advancedQueryFields ? this.getSameEle(item?.body, queryFields) : item?.body)?.map((items: any) => {
          this.filterObj[items.name] = items
          return { label: (items.groupName ? `${items.groupName} · ` : '') + (items.label || items.placeholder), value: items.name, type: items.type, isNumber: items.isNumber || null }
        })
      } else if (item.name == "advancedHeader") {
        this.filterNorma = item?.body?.map((items: any) => {
          if (items?.body) {
            return { ...items, body: this.handlesetHeader(items.body, data), label: (items.groupName ? `${items.groupName} · ` : '') + (items.label || items.placeholder), type: items.type, name: items.name }
          }
          return { ...items, label: (items.groupName ? `${items.groupName} · ` : '') + (items.label || items.placeholder), type: items.type, name: items.name }
        })
      }
    })
  }

  handlesetHeader(body: any, data: any) {
    return body.map((item: any) => {
      if (item?.body) {
        this.handlesetHeader(body, data)
      }
      return { ...item, value: data?.[item.name] ?? '' }
    })
  }

  getSameEle = (marr1: Array<any>, marr2: Array<string>) => {
    const eleIsInArr = (ele: any, arr: Array<string>) => arr.some(m => m === ele.name.split(".")[1]);
    return marr1.filter((x: any) => eleIsInArr(x, marr2))
  };

  handleOptionTransfer = () => {
    const { columns, filtercont } = this.props
    const allFileds = columns?.filter(column => !column?.hidden && column.type !== 'operation')
      .map(option => ({ type: option.type, comparable: option.comparable ?? true, isNumerical: option.isNumerical, label: (option.groupName ? `${option.groupName} · ` : '') + String(option.label), name: option.name ?? '' })) ?? []
    return <OptionTransfer
      ref={this.filterOptionRef}
      defaultOptionsParam={filtercont?.optionsParam}
      allFields={allFileds}
      onChange={data => this.filterOptionData = data}
    />
  }

  // 范围生成
  rangeGenerator(item: any) {
    // 2等于// 3大于// 4大于等于//5 小于// 6小于等于// 7介于// 8包含于// 9包含// 10为空// 11模糊
    const options = this.rangeOptios()
    const options1 = this.rangeOptios([RangeOptionsEnum.Equal, RangeOptionsEnum.Contain, RangeOptionsEnum.IsEmpty].concat(this.filterObj[item.field]?.dataTag ? RangeOptionsEnum.DataTag : []))
    const options2 = this.rangeOptios([RangeOptionsEnum.Between, RangeOptionsEnum.Equal, RangeOptionsEnum.GreaterThan, RangeOptionsEnum.GreaterThanOrEqual, RangeOptionsEnum.LessThan, RangeOptionsEnum.LessThanOrEqual, RangeOptionsEnum.IsEmpty].concat(this.filterObj[item.field]?.dataTag ? RangeOptionsEnum.DataTag : []))
    const options3 = this.rangeOptios([RangeOptionsEnum.Equal, RangeOptionsEnum.IsEmpty, RangeOptionsEnum.Fuzzy])
    const options4 = this.rangeOptios([RangeOptionsEnum.Equal, RangeOptionsEnum.IsEmpty])
    const options5 = this.rangeOptios([RangeOptionsEnum.IsEmpty])
    // // 文件类型只有为空
    if ([TagTypeEnum.file].includes(this.filterObj[item.field].type)) {
      if (isMobile()) {
        return options5
      }
      return onlyEmptyRangeOptions
    }

    // // 如果是数字类型
    // if (this.filterObj[item.field]?.isNumber) return rangeOptions1
    // // 如果是数字类型 或者 inputNumber类型并且不是 inputText类型的 都展示为 rangeOptions1
    // if ([TagTypeEnum.inputNumber].includes(this.filterObj[item.field].type) || this.filterObj[item.field].type !== TagTypeEnum.inputText) return rangeOptions1
    if (this.filterObj[item.field]?.isNumber) return options2
    if ([TagTypeEnum.InputText].includes(this.filterObj[item.field].type)) return options1
    if ([TagTypeEnum.InputDate, TagTypeEnum.InputMonth, TagTypeEnum.InputDatetime].includes(this.filterObj[item.field].type)) return options2
    if ([TagTypeEnum.Select, TagTypeEnum.TransferPicker].includes(this.filterObj[item.field].type)) return options4
    // 默认范围2
    return options3
  }
  rangeOptios(val?: number[]) {
    if (val && val.length) {
      return rangeOptions.filter(item =>
        val.some(items =>
          isMobile() ? (item.value == items) :
            (item.value == items && !item?.not)
        ))
    }
    return rangeOptions
  }
  handleMenuClick: MenuProps['onClick'] = (body) => {
    const { item } = body
    const { store } = this.props
    const val: any = item
    if (val.props) {
      const name = val.props.name
      const head = name.split(".")[0]
      const advancedName = name.split(".").pop()
      const data = store.data?.[head] ?? {}
      const value = data?.[advancedName] ?? ''
      const current = val.props.value
      const key = val.props.valKey
      const headPare = current.value.split(".").pop()
      // 所有的条件
      let selectList = val.props.items
      //将字符串变成数组只有携带【】的
      const valMatch = value.match(/\[([^\]]*)\]/g)
      //汉字从selectList获取对应的id name获取到后面的
      const valList = valMatch?.map((item: string) => {
        let labelToFind = item.substring(1, item.length - 1); // 去除方括号
        let foundItem = selectList.find((obj: any) => obj.label === labelToFind);
        if (foundItem) {
          return foundItem.value.split(".").pop(); // 替换为匹配的value值
        }
        return item; // 如果没找到匹配项，则保持原值不变
      });
      // 要是stort中没有值就只取当前上的值
      const List = valList ? [...valList, headPare] : [headPare];
      // 能一直写  而不是更新
      const valueList = `${value}[${current.label}]`
      this.changePare(List, key)
      store.changeValue(name, valueList, false)
    }
  }

  // 下拉框参数获取
  getDownCondition = () => {
    const options = this.filterPropsArr().map(item => ({ ...item, value: item.value.split('--')[0] }))
    const selectList: typeof options = []
    options.forEach((item: any) => {
      if (!selectList.some((i: any) => i.value === item.value)) {
        selectList.push(item)
      }
    })
    return selectList.filter(val => (val.type && ['input-number', 'input-text', 'input-date', 'input-datetime'].includes(val.type)) || val.isNumber)
  }

  //粘贴
  pasteContent = async (item: { field: string, condition: number, not: boolean, op: RangeOptionsEnum }) => {
    try {
      if (navigator.clipboard && typeof navigator.clipboard.readText === 'function') {
        const content = await navigator.clipboard.readText();
        if (!isNil(content) && content !== '') {
          const { store } = this.props
          const name = item.field;
          const [parentName, fieldName] = name.split(".")
          const obj = store.data?.[parentName] ?? {}
          const value = obj?.[fieldName] ?? ''
          store.changeValue(name, value + content, false)
        }
      } else {
        message.warning('当前浏览器不支持此功能')
      }
    } catch (error) {
      console.error('读取剪切板内容时发生错误:', error);
      message.warning('读取剪切板失败');
    }
  }

  // Jay 渲染高级查询
  renderAdvancedFilter() {
    const { classnames, env, hideAdvancedFilter, filter, handleActionDisplay, advancedFilterVisible,
      filtercont, showAdvancedOption, translate } = this.props
    if (!advancedFilterVisible) return
    const { filtersArr, filtersHeader, caseSensitive, topN, limitStatus } = this.state
    const options = this.filterPropsArr().map(item => ({ ...item, value: item.value.split('--')[0] }));
    const Modle = isMobile()
    let selectList: typeof options = []
    options.forEach(item => {
      if (!selectList.some(i => i.value === item.value)) {
        selectList.push(item)
      }
    })
    const dateList = this.getDateArr();
    const dateOptions = dateList.map((item: any) => selectList.find(sel => sel.value === item.name))
    if (dateOptions.length) {
      dateOptions.unshift({
        label: translate('Select.emptyItem'),
        value: 'advancedFilter.noneData'
      })
    }
    const downCont = selectList.filter(val => (val.type && ['input-number', 'input-text', 'input-date', 'input-datetime'].includes(val.type)) || val.isNumber)
    return <>
      {Modle ? <>
        <AdvancedModlePopup
          env={env}
          filtersArr={filtersArr}
          filtersHeader={filtersHeader}
          filterOptions={this.filterOptions}
          filterObj={this.filterObj}
          hideAdvancedFilter={hideAdvancedFilter}
          filter={filter}
          notRange={notRange}
          caseSensitive={caseSensitive}
          onCheckbox={() => { this.setState({ caseSensitive: !this.state.caseSensitive }) }}
          rangeGenerator={this.rangeGenerator.bind(this)}
          addFilter={this.addFilter.bind(this)}
          handleChange={this.handleChange}
          handleOptionTransfer={this.handleOptionTransfer}
          renderChild={this.renderChild.bind(this)}
          changeRange={this.changeRange.bind(this)}
          changeField={this.changeField.bind(this)}
          changeNot={this.changeNot.bind(this)}
          deleteFilter={this.deleteFilter.bind(this)}
          isShowInputItem={this.isShowInputItem.bind(this)}
          handleActionDisplay={handleActionDisplay}
          filtercont={filtercont}
          showAdvancedOption={showAdvancedOption}
          topN={topN}
          limitStatus={limitStatus}
          changeTopN={(num: number) => this.setState({ topN: num })}
          changeLimitStatus={(check: boolean) => this.setState({ limitStatus: check })}
          selectEmptyTime={this.selectEmptyTime}
          emptyTimeSelected={this.state.emptyTimeSelected}
          translate={translate}
        />
      </> :
        <div className={'Modal-advanced-body'}>
          {filtersHeader && filtersHeader?.length !== 0 && <>
            <Divider orientation="left" >条件查询</Divider>
            <div className={'Modal-advanced-body-condition'}>
              <Row className='filter-row' gutter={24} style={{ margin: 0 }}>
                {
                  filtersHeader.map((item: any) => {
                    return (
                      // 
                      <Col style={{ padding: 0 }} span={12}>
                        {this.renderChild(item)}
                      </Col>
                      // 
                    )
                  })
                }
              </Row>
            </div>
          </>
          }
          {filtersArr.map((item, index) => {
            if (isNil(this.filterObj[item.field]) && !item.field.includes('--')) return null
            //是否时间类型
            const isTimeType = ['input-date', 'input-datetime', 'input-time'].includes(this.filterObj[item.field]?.type)
            return (
              <Row className='advanced-filter-row' gutter={24} key={item.field + index} >
                <Col span={1.5} style={{ paddingRight: 0, }} >
                  {!item.dateLine ? <div className={classnames('condition', {
                    'or': item.condition === (dateList.length ? 1 : 0),
                    'not': index === (dateList.length ? 1 : 0)
                  })} onClick={() => {
                    if (index === (dateList.length ? 1 : 0)) return
                    this.changeCondition(item.condition, index)
                  }}>
                    {item.condition === 0 ? '或' : '且'}
                  </div> : <div style={{ width: 20 }}></div>}
                </Col>
                <Col span={5} className='advanced-filter-row-select'>
                  {item.dateLine && this.state.emptyTimeSelected ? <Select
                    value={'advancedFilter.noneData'}
                    options={dateOptions}
                    showSearch
                    dropdownClassName={`dropdown-select-style`}
                    allowClear={false} filterOption={(input: string, option?: { label: string; value: string }) => (option?.label ?? '').includes(input.toLowerCase()) || (option?.value ?? '').toLowerCase().includes(input.toLowerCase())}
                    getPopupContainer={env.getModalContainer}
                    onChange={(val) => {
                      this.changeRange(this.filterObj[val].type === TagTypeEnum.file ? RangeOptionsEnum.IsEmpty : [TagTypeEnum.InputDate, TagTypeEnum.InputMonth, TagTypeEnum.InputDatetime].includes(this.filterObj[val].type) ? RangeOptionsEnum.Between : RangeOptionsEnum.Equal, index)
                      this.changeField(val, index)
                    }}
                  /> : <Select
                    value={this.filterOptions.find(idx => idx.value == item.field)?.label}
                    showSearch
                    dropdownClassName={`dropdown-select-style`}
                    allowClear={false}
                    filterOption={(input: string, option?: { label: string; value: string }) => (option?.label ?? '').includes(input.toLowerCase()) || (option?.value ?? '').toLowerCase().includes(input.toLowerCase())}
                    options={item.dateLine ? dateOptions : selectList}
                    getPopupContainer={env.getModalContainer}
                    onChange={(val) => {
                      if (val === 'advancedFilter.noneData') {
                        this.selectEmptyTime(index)
                      } else {
                        this.changeRange(this.filterObj[val].type === TagTypeEnum.file ? RangeOptionsEnum.IsEmpty : [TagTypeEnum.InputDate, TagTypeEnum.InputMonth, TagTypeEnum.InputDatetime].includes(this.filterObj[val].type) ? RangeOptionsEnum.Between : RangeOptionsEnum.Equal, index)
                        this.changeField(val, index)
                      }
                    }}
                  />}
                </Col>
                <Col span={2.5} style={{ padding: 0 }}>
                  <Checkbox disabled={item.dateLine && this.state.emptyTimeSelected} value={item.not} onChange={(val) => { this.changeNot(val, index) }}>不</Checkbox>
                </Col>
                {/* 等于、大于 */}

                <Col span={5} className='advanced-filter-row-select'>
                  <Select dropdownClassName={`dropdown-select-style`}
                    disabled={notRange.includes(this.filterObj[item.field].type) ||
                      (item.dateLine && this.state.emptyTimeSelected)} value={item.op} allowClear={false}
                    getPopupContainer={env.getModalContainer}
                    options={this.rangeGenerator(item)}
                    onChange={(val) => {
                      this.changeRange(val, index)
                    }} />
                </Col>

                {this.isShowInputItem(item, this.filterObj[item.field].type, true) ? <>
                  <Dropdown
                    menu={{
                      items: downCont.map((val, idx) => ({
                        key: idx, valKey: index, label: val.label, type: val.type, value: val,
                        name: item.field, data: item, items: downCont
                      })),
                      onClick: this.handleMenuClick
                    }}
                    trigger={['contextMenu']}
                    overlayStyle={{ overflow: 'hidden' }}
                    disabled={!(['input-number', 'input-text', 'input-date', 'input-datetime', 'input-time'].includes(this.filterObj[item.field]?.type) || this.filterObj[item.field]?.isNumber) || item.op == 7}
                    dropdownRender={(menu) => (
                      <div style={{
                        backgroundColor: '#fff',
                        boxShadow: 'rgba(0, 0, 0, 0.08) 0px 6px 16px 0px, rgba(0, 0, 0, 0.12) 0px 3px 6px -4px, rgba(0, 0, 0, 0.05) 0px 9px 28px 8px',
                        maxHeight: 300, overflow: 'hidden', display: 'flex', flexDirection: 'column'
                      }}>
                        <div style={{ flex: 1, overflow: 'auto' }}>
                          {React.cloneElement(menu as React.ReactElement, { style: { boxShadow: 'none' } })}
                        </div>
                        {/* <Divider style={{ margin: 0 }} />
                        <div onClick={() => this.pasteContent(item)} style={{ padding: '5px 12px', cursor: 'pointer' }}>{translate('sticky')}</div> */}
                      </div>
                    )}
                  >
                    <Col span={10} style={{ paddingRight: 0 }}>
                      {item.op == RangeOptionsEnum.DataTag ?
                        this.renderChild({ ...this.filterObj[item.field]?.dataTag, name: item.field }, 'dataTag')
                        : item.op === RangeOptionsEnum.Between && (this.filterObj[item.field].type === TagTypeEnum.InputNumber || this.filterObj[item.field]?.isNumber)
                          ?
                          <div className="double">
                            {this.renderChild({ ...this.filterObj[item.field], name: this.filterObj[item.field].name + '-a8', isMultipleValues: false, label: undefined }, 'a')}
                            <span style={{ margin: '0 4px' }}></span>
                            {this.renderChild({ ...this.filterObj[item.field], name: this.filterObj[item.field].name + '-b8', isMultipleValues: false, label: undefined }, 'b')}
                          </div>
                          :
                          item.op !== RangeOptionsEnum.IsEmpty && item.op === RangeOptionsEnum.Between && (this.filterObj[item.field].type === TagTypeEnum.InputDatetime || this.filterObj[item.field].type === TagTypeEnum.InputDate || this.filterObj[item.field].type === TagTypeEnum.InputMonth)
                            ?
                            this.renderChild({ ...this.filterObj[item.field], ranges: this.filterObj[item.field].ranges ?? this.filterObj[item.field].shortcuts, type: this.filterObj[item.field].type + "-range", label: undefined }, undefined)
                            :
                            this.renderChild({
                              ...this.filterObj[item.field],
                              "validations": (() => {
                                if (this.filterObj[item.field]?.isNumber)
                                  return {
                                    "isExprOrNumeric": true
                                  }
                                if (isTimeType)
                                  return {
                                    "isExprOrDate": true
                                  }
                                return null
                              })(),
                              value: this.filterObj?.[item.field]?.value?.includes(',') && isTimeType ? this.filterObj[item.field].value.split(',')[0] : this.filterObj[item.field].value,
                              label: undefined, isNumber: this.filterObj[item.field]?.isNumber,
                              disabled: item.dateLine && this.state.emptyTimeSelected
                            }, undefined, { inputFocusShowPicker: false, inputBlurCheckValue: false })
                      }
                    </Col>
                  </Dropdown>
                </>
                  : null}

                {!item.dateLine && <Col span={1} >
                  <i className={classnames('fa fa-minus-square-o', {
                    'not': filtersArr.length === 1 // 只有一个数组项的时候不允许删除
                  })} onClick={() => {
                    this.deleteFilter(index)
                  }} />
                </Col>}
              </Row>
            )
          })
          }
          <div className={'Modal-advanced-body-but'} >
            <Button block onClick={this.addFilter.bind(this)}>新增+</Button>
          </div>
          <Row className={'Modal-advanced-body-caseSensitive'} >
            <Col span={4}>
              <label
                onChange={(e) => this.setState({ caseSensitive: !this.state.caseSensitive })}
                style={{ cursor: "pointer" }}> <Checkbox checked={this.state.caseSensitive}
                /> 区分大小写</label>
            </Col>
            <Col span={20}>
              <label
                onChange={(e) => {
                  this.setState({ limitStatus: !limitStatus }, () => {
                    this.state.limitStatus && this.limitInputRef.current?.focus()
                  })
                }}
                style={{ cursor: "pointer" }}>
                <Checkbox checked={limitStatus} />仅查前</label>
              <InputNumber ref={this.limitInputRef} size='small' min={1} precision={0} onChange={(value) => this.setState({ topN: value || 0 })}
                style={{ margin: '0 8px', width: '110px' }} value={topN} />项
            </Col>
          </Row>
          {this.props.showAdvancedOption && <Divider orientation="left">选项查询</Divider>}
          {this.props.showAdvancedOption && this.handleOptionTransfer()}
        </div>}
    </>
  }

  pullDown = () => {
    const { initApi, store, initAsyncApi, initFinishedField, initCheckInterval, messages: { fetchFailed, fetchSuccess } } = this.props;
    return store
      .fetchInitData(initApi as any, store.data, {
        successMessage: fetchSuccess,
        errorMessage: fetchFailed,
        onSuccess: () => {
          if (
            !isEffectiveApi(initAsyncApi, store.data) ||
            store.data[initFinishedField || 'finished']
          ) {
            return;
          }
          return until(
            () => store.checkRemote(initAsyncApi, store.data),
            (ret: any) => ret && ret[initFinishedField || 'finished'],
            cancel => (this.asyncCancel = cancel),
            initCheckInterval
          );
        }
      })
      .then(this.initInterval)
      .then(this.onInit);
  }

  renderBody() {
    const {
      body,
      mode,
      className,
      classnames: cx,
      debug,
      $path,
      store,
      columnCount,
      render,
      //Aug
      autoLayout,
      formatSize,
      inModal,
      quickEditForm,
      initApi,
      isDetail,
      flowProcess,
      flowSpinning,
      tableFilter
    } = this.props;
    const { restError, } = store;

    // Aug 配置自动布局会使columnCount属性失效
    const _columnCount = autoLayout ? this.state.autoColumnCount : columnCount
    const { collpased } = this.state
    let conditionCount = 4;
    if(this.contentRef.current?.clientWidth && Array.isArray(body)) {
      const conditionArr = body.filter((item: SchemaObject) => {
        return !['submit', 'button', 'button-group', 'reset'].includes(item.type) && item.actionType !== 'advanced-filter'
      })
      let widthCount = 0;
      for(let i = 0;i<conditionArr.length;i++) {
        const curWidth = conditionArr[i].type.includes('range') ? 450 : conditionArr[i].type.includes('datetime') ? 260 : conditionArr[i].type === 'picker' ? 230 : 160;
        widthCount += (curWidth + 4)
        if(widthCount >= this.contentRef.current.clientWidth - 220) {
          conditionCount = i;
          break;
        }
      }
    }
    const showExtBtn = Array.isArray(body) && body.length > conditionCount;
    const actionArr: any[] = []
    let frontFormItems: any[] = []
    let endFormItems: any[] = []
    if (showExtBtn) {
      const tempArr = (body as any[]).filter((item: SchemaObject) => {
        if (!!~['submit', 'button', 'button-group', 'reset'].indexOf(item.type)) {
          actionArr.push(item)
          return false
        }
        if ((item as any).actionType === 'advanced-filter') {
          actionArr.push(item)
          return false
        }
        return true
      })
      frontFormItems = (tempArr as any[]).slice(0, conditionCount)
      endFormItems = (tempArr as any[]).slice(conditionCount)
    }
    const hideExtBtn = Array.isArray(body) && body.length - actionArr.length > conditionCount;
    const WrapperComponent =
      this.props.wrapperComponent ||
      (/(?:\/|^)form\//.test($path as string) ? 'div' : 'form');

    let hasFieldSet = false;
    try {
      if (isArray(body)) {
        hasFieldSet = body.some((item: SchemaObject) => item.type === 'fieldSet')
      }
    } catch { }
    const warpNode = (
      <WrapperComponent
        className={cx(
          `Form`,
          `Form--${mode || 'normal'}`,
          !collpased ? 'extend' : null,
          hasFieldSet ? 'hasFieldSet' : '',
          (inModal == true && isMobile()) ? 'inModal' : '',
          _columnCount ? `Form--column Form--column-${_columnCount}` : null,
          formatSize ? `Form--format-${formatSize}` : null,
          className
        )}
        onSubmit={this.handleFormSubmit}
        onKeyDown={(e: any) => {
          if (e.key == 'Enter') {
            if (this.props.advancedFilterVisible) {
              setTimeout(() => {
                this.props?.handleAdvanceSearch()
              }, 200);
            } else this.handleFormSubmit(e)
          }
        }}
        noValidate
        ref={this.contentRef} //Aug
      >
        {/* 实现回车自动提交 */}
        {/* <input type="submit" style={{ display: 'none' }} /> */}

        {
          debug ? (
            <pre>
              <code>{JSON.stringify(store.data, null, 2)}</code>
            </pre>
          ) : null
        }

        {!flowSpinning && <Spinner show={store.loading || this.context.getComponents().filter((item: any) => ['service', 'form'].includes(item.props.type)).some((item: any) => item.props.store.loading)} overlay />}

        {/* Jay 在上面提示 */}
        {restError && restError.length ? (
          <ul className={cx('Form-restError', 'Form-feedback')}>
            {restError.map((item, idx) => (
              <li key={idx}>{item}</li>
            ))}
          </ul>
        ) : null}

        {this.props.advancedFilterVisible ? this.renderAdvancedFilter() : isMobile() ? this.renderAdvancedFilter() : null}
        {!this.props.advancedFilterVisible && <>
          {
            hideExtBtn && tableFilter ?
              <>
                {this.renderFormItems({
                  body: [...frontFormItems, ...actionArr]
                })}
                <div className={cx('Form-extendBtn')}>
                  {this.buildExtendAction()}
                </div>
                {!collpased &&this.renderFormItems({body: endFormItems})}
              </>
              :
              this.renderFormItems({
                body
              })
          }
        </>
        }

        {/* 显示没有映射上的 errors */}
        {/* {restError && restError.length ? (
        <ul className={cx('Form-restError', 'Form-feedback')}>
          {restError.map((item, idx) => (
            <li key={idx}>{item}</li>
          ))}
        </ul>
        ) : null} */}
        {/* cell内部不用渲染这两个 */}
        {(!quickEditForm && store.dialogOpen) ?
          render(
            'modal',
            {
              ...((store.action as Action) &&
                ((store.action as Action).dialog as object)),
              type: 'dialog'
            },
            {
              key: 'dialog',
              data: store.dialogData,
              onConfirm: this.handleDialogConfirm,
              onClose: this.handleDialogClose,
              show: store.dialogOpen
            }
          ) : null
        }
        {/* cell内部不用渲染这两个 */}
        {(!quickEditForm && store.drawerOpen) ?
          render(
            'modal',
            {
              ...((store.action as Action) &&
                ((store.action as Action).drawer as object)),
              type: 'drawer'
            },
            {
              key: 'drawer',
              data: store.drawerData,
              onConfirm: this.handleDrawerConfirm,
              onClose: this.handleDrawerClose,
              show: store.drawerOpen
            }
          ) : null
        }


      </WrapperComponent >
    )
    return !!initApi && isDetail && !flowProcess && isMobile() ? (
      <ScrollMb
        scrollConfig={{ pullDownRefresh: true, }}
        onPullingDown={this.pullDown}
      >
        {warpNode}
      </ScrollMb>
    ) : warpNode
  }

  renderPrintModal() {
    if (!this.state.printVisible) {
      return null
    }
    return (
      <ModalPrint
        {...this.props}
        show={this.state.printVisible}
        printType={'detail'}
        printInfo={this.state.printInfo}
        type={'lion-print'}
        columns={[]}
        defValEditApi={''}
        defValAddApi={''}
        defValDelApi={''}
        defValGetApi={''}
        labelDataApi={''}
        templateApi={''}
        callbackApi={undefined}
        ctx={{ items: [], rows: [], selectedItems: [], unSelectedItems: [], ids: '', primaryField: undefined }}
        onHide={() => { this.setState({ printVisible: false }) }}
      />
    )
  }

  renderFlowModal() {
    if (!this.state.flowModalVisible || this.flowDetail == undefined) {
      return null
    }
    return <ModalFlow
      visible={this.state.flowModalVisible}
      onClose={reload => { this.flowDetail = undefined; this.setState({ flowModalVisible: false }) }}
      env={this.props.env}
      render={this.props.render}
      onImageEnlarge={this.props.onImageEnlarge}
      language={makeTranslator()}
      classnames={this.props.classnames}
      flowDetail={this.flowDetail}
    />
  }

  render() {
    const {
      $path,
      $schema,
      wrapWithPanel,
      render,
      title,
      store,
      panelClassName,
      headerClassName,
      footerClassName,
      footerWrapClassName,
      actionsClassName,
      bodyClassName,
      classnames: cx,
      affixFooter,
      lazyLoad,
      translate: __,
      footer,
      isDialogMode,
      // formStore,
      isDetail
    } = this.props;

    let body: JSX.Element = this.renderBody();

    if (wrapWithPanel) {
      body = render(
        'body',
        {
          type: 'panel',
          title: __(title)
        },
        {
          className: cx(panelClassName, 'Panel--form'),
          formStore: this.props.store,
          children: body,
          actions: this.buildActions(),
          onAction: this.handleAction,
          onQuery: this.handleQuery,
          disabled: store.loading,
          btnDisabled: store.loading || store.validating,
          headerClassName,
          footer,
          footerClassName,
          footerWrapClassName,
          actionsClassName,
          bodyClassName,
          affixFooter,
          isDialogMode,
          wrapWithPanel,
          btnMapdisable: this.state.disabled,
          isDetail
        }
      ) as JSX.Element;
    }

    if (lazyLoad) {
      body = <LazyComponent>{body}</LazyComponent>;
    }

    return <>{body}{this.renderPrintModal()}{this.renderFlowModal()}</>;
  }
}

@Renderer({
  type: 'form',
  storeType: FormStore.name,
  isolateScope: true,
  shouldSyncSuperStore: (store, props, prevProps) => {
    // 如果是 QuickEdit，让 store 同步 __super 数据。
    if (
      props.quickEditFormRef &&
      props.onQuickChange &&
      (isObjectShallowModified(prevProps.data, props.data) ||
        isObjectShallowModified(prevProps.data.__super, props.data.__super) ||
        isObjectShallowModified(
          prevProps.data.__super?.__super,
          props.data.__super?.__super
        ))
    ) {
      return true;
    }

    return undefined;
  }
})
export class FormRenderer extends Form {
  static contextType = ScopedContext;

  constructor(props: FormProps, context: IScopedContext) {
    super(props);

    const scoped = context;
    scoped.registerComponent(this);
  }

  componentDidMount() {
    super.componentDidMount();
    this.is_edit = false;

    if (this.props.autoFocus) {
      const scoped = this.context as IScopedContext;
      const inputs = scoped.getComponents();
      let focuableInput = find(
        inputs,
        input => input.focus
      ) as ScopedComponentType;
      focuableInput && setTimeout(() => focuableInput.focus!(), 200);
    }
  }

  componentWillUnmount() {
    const scoped = this.context as IScopedContext;
    this.is_edit = false;
    this.valueChanged = false;
    scoped.unRegisterComponent(this);

    super.componentWillUnmount();
  }

  doAction(
    action: Action,
    data: object = this.props.store.data,
    throwErrors: boolean = false
  ) {
    return this.handleAction(undefined, action, data, throwErrors);
  }

  handleAction(
    e: React.UIEvent<any> | undefined,
    action: Action,
    ctx: object,
    throwErrors: boolean = false,
    delegate?: IScopedContext
  ) {
    // 禁用了不要做任何动作。@先注释掉，会引起其他问题
    // if (this.props.disabled) {
    //   return;
    // }


    if (action.target && action.actionType !== 'reload') {
      const scoped = this.context as IScopedContext;
      return Promise.all(
        action.target.split(',').map(name => {
          let target = scoped.getComponentByName(name);
          return (
            target &&
            target.doAction &&
            target.doAction(
              {
                ...action,
                target: undefined
              },
              ctx,
              throwErrors
            )
          );
        })
      );
    } else {
      return super.handleAction(e, action, ctx, throwErrors, delegate);
    }
  }

  handleDialogConfirm(
    values: object[],
    action: Action,
    ctx: any,
    targets: Array<any>
  ) {
    super.handleDialogConfirm(values, action, ctx, targets);
    const store = this.props.store;
    const scoped = this.context as IScopedContext;

    if (action.reload) {
      scoped.reload(action.reload, ctx);
    } else if (store.action && store.action.reload) {
      scoped.reload(store.action.reload, ctx);
    }
  }

  submitToTarget(target: string, values: object) {
    const scoped = this.context as IScopedContext;
    scoped.send(target, values);
  }

  reloadTarget(target: string, data: any) {
    const scoped = this.context as IScopedContext;
    scoped.reload(target, data);
  }

  closeTarget(target: string) {
    const scoped = this.context as IScopedContext;
    scoped.close(target);
  }

  reload(target?: string, query?: any, ctx?: any, silent?: boolean) {
    if (ctx === null) {
      return this.props.store?.clear?.();
    }
    if (query) {
      return this.receive(query);
    }
    // Jay
    if (!this.received) {
      this.received = false
      const { initOneApi, initFetch, initFetchOn, store,
        messages: { fetchSuccess, fetchFailed },
      } = this.props

      if (isEffectiveApi(initOneApi, store.data, initFetch, initFetchOn)) {
        store
          .fetchInitData(initOneApi as any, store.data, {
            successMessage: fetchSuccess,
            errorMessage: fetchFailed,
            onSuccess: () => {
              store?.setUpdateType('reload')
            }
          })
          .then(this.initInterval)
          .then(this.onInit);
      }
    }


    const scoped = this.context as IScopedContext;
    let subPath: string = '';
    let idx: number;
    let subQuery: any = null;
    if (target && ~(idx = target.indexOf('.'))) {
      subPath = target.substring(idx + 1);
      target = target.substring(0, idx);
    }
    const idx2 = target ? target.indexOf('?') : -1;
    if (~idx2) {
      subQuery = dataMapping(
        qsparse((target as string).substring(idx2 + 1)),
        ctx
      );
      target = (target as string).substring(0, idx2);
    }

    let component;
    if (
      target &&
      (component = scoped.getComponentByName(target)) &&
      component.reload
    ) {
      component.reload(subPath, subQuery, ctx);
    } else if (target === '*') {
      super.reload(target, query, ctx, silent);
      const components = scoped.getComponents();
      components.forEach(
        (component: any) =>
          component.reload && component.reload('', subQuery, ctx)
      );
    } else {
      super.reload(target, query, ctx, silent);
    }
  }

  receive(values: object, name?: string) {
    if (name) {
      const scoped = this.context as IScopedContext;
      const idx = name.indexOf('.');
      let subPath = '';

      if (~idx) {
        subPath = name.substring(1 + idx);
        name = name.substring(0, idx);
      }

      const component = scoped.getComponentByName(name);
      component && component.receive && component.receive(values, subPath);
      return;
    }

    return super.receive(values);
  }
}
