import React, { useCallback, useEffect, useRef, useState } from 'react';
import { CRUDProps, CRUDState, PrintType, TableMode } from '../types';
import { createObject, extendObject, isMobile, isVisible, mapTree, uuidv4 } from '../../../utils/helper';
import { dealAdvacedCondition, getTableRowsData, getTableSelectedRowsData, headerCanShow, unitBulkActions } from '../utils';
import { message, Popover, Select } from 'antd';
import { IScopedContext } from '../../../Scoped';
import { Action, Schema, SchemaNode } from '../../../types';
import { ActionSchema } from '../../Action';
import { ActionSheet, buildApi, evalExpression, filter, SchemaApi } from '../../..';
import { ITableStore } from '../../../store/table';
import Button from '../../../components/Button';
import { Icon } from '../../../components/icons';
import LionCopyItem from '../../Lion/components/LionCopyItem';
import { DebouncedFunc, findIndex, isNil, isObject, omit } from 'lodash';
import { getLocalStorage, setLocalStorage } from '../../../utils/storage';
import { EDITWIDTHKEY } from '../../Table';
import getExprProperties from '../../../utils/filter-schema';
import { specialButtonType } from '../types';
import OverflowWrapper from '../../../components/OverflowWrapper';
import AiTool from '../../Table/AiTool';
import { getLodop } from '../../../utils/print/LodopFuncs';
import { tools } from '../../../utils/shell/tools';
import { downloadFile } from '../../Lion/utils/utils';
import { isEffectiveApi } from '../../../utils/api';
import { expressLabels } from '../../Lion/ExpressPrint/ExpressPrint';
import { confirmWithThreeButtons } from '../../../components/Lion/BatchOperation';
import { DATAKEYID } from '../../../store/crud';


// 表格体props
export interface CrudBodyProps {
  props: CRUDProps,
  // 新增的属性
  foldColumns: string[],
  tableRotate: Boolean,
  tableStore: ITableStore | null,
  controlRef: any,
  // 函数方法
  setCrudState: (...res: any) => any;
  setLoading: (loading: boolean) => void,
  handleAction: (e: React.UIEvent<any> | undefined,
    action: Action,
    ctx: any,
    throwErrors?: boolean,
    delegate?: IScopedContext,
    isItemAction?: boolean) => void,
  dataCheckRegist: (data: any) => void,
  handleSaveOrder: (moved: Array<object>, rows: Array<object>) => void,
  handleQuery: (query: any) => void,
  handleChildPopOverOpen: (popOver: any) => void,
  handleChildPopOverClose: (popOver: any) => void,
  handleFilterReset: (values: object, action: any) => void,
  handleFilterSubmit: (data: any) => void,
  handleFilterInit: (data: any) => void,
  markSort: () => void,
  renderFilter: () => any,
  handleLoadMore: () => void,
  handleResetData: () => void,
  getTableStore: (store: any) => any,
  getTableInstance: (table: any) => any,
  setTotal: (total: number) => void,
  clearSelectedItems: () => void,
  handleClickOffline: () => void,
  handleJump: (body: any) => void,
  hasBulkActions: () => boolean,
  filtercont: any,
  crudRef: any,
  currentSelectedRow: any,
  originFilterData: any,
  // 其他属性
  saveColApi?: SchemaApi,
  columnInfo?: any,
  showColumnsFilter: boolean,
  hasFetch: boolean,
  tabsdefer?: any,
  filterData?: any,
  initFetch?: boolean,
  name?: string,
  preSortAble?: boolean,
  handleFakeAnimation: DebouncedFunc<() => void>,
  tableInstance: any,
  search(values?: any, silent?: boolean, clearSelection?: boolean, forceReload?: boolean, resolve?: (value: any) => void, reject?: (error: any) => void, isChild?: boolean, postData?: any, init?: boolean): void,
  quickEditDataCheck: () => void,
  advanceFilterForm?: any,
  afterSearchFn: () => void,
  control?: any,
  showTableEditWarmModal: () => void,
  openFeedback(dialog: any, ctx: any): Promise<unknown>,
  reload: (subpath?: string, query?: any, ctx?: any, isItemAction?: boolean) => void,
  reloadTarget: (target: string, data: any) => void,
  closeTarget: (target: string) => void,
  context: any,
}


interface ToolButtonProps extends CrudBodyProps {
  toolbar: Schema;
  index: number;
  childProps: any,
  modes: "table" | "grid" | "cards" | "list" | "cross",
  autoWidth: boolean,
  renderMoreToolbar: (more: React.ReactNode[]) => React.ReactNode,
  renderToolbar: (toolbar?: SchemaNode, index?: number, childProps?: any, toolbarRenderer?: (toolbar: SchemaNode, index: number) => React.ReactNode, isFooter?: boolean) => JSX.Element | null,
  bulkActionRender: (toolbar: ActionSchema, index: number) => React.ReactNode,
  toolbarRenderer: ((toolbar: SchemaNode, index: number) => React.ReactNode) | undefined,
  setModes: React.Dispatch<React.SetStateAction<"table" | "grid" | "cards" | "list" | "cross">>,
  setAutoWidth: React.Dispatch<React.SetStateAction<boolean>>,
}

// 渲染具体工具按钮的方法-容器方法在外部调用
const ToolButton: React.FC<ToolButtonProps> = ({
  props,
  reload,
  toolbar,
  index = 0,
  childProps = {},
  toolbarRenderer,
  renderToolbar,
  getTableStore,
  filtercont,
  tableStore,
  handleQuery,
  handleAction,
  tableInstance,
  setCrudState,
  advanceFilterForm,
  search,
  afterSearchFn,
  control,
  modes,
  quickEditDataCheck,
  crudRef,
  handleFakeAnimation,
  setModes,
  setAutoWidth,
  bulkActionRender,
  renderMoreToolbar,
  originFilterData,
  setTotal,
  showColumnsFilter,
  autoWidth,
}) => {
  const {
    render,
    name,
    store,
    translate: __,
    card,
    listItem,
    cross,
    header,
    filter,
    classnames: cx,
    primaryField,
    mode,
    headerBulkActions,
    footerBulkActions,
    headerToolbar,
    headerActions,
    inModal
  } = props;
  const [toolActionSwitch, setToolActionSwitch] = useState(false); //工具栏按钮开关按钮

  const pageSwitchRef = useRef<HTMLDivElement | null>(null);

  const type = toolbar.type || toolbar;

  const toolBarAction = () => { reload() }

  const inSmallDialog = () => {
    return !!crudRef?.current?.closest('div[role="dialog"]')?.className.includes('Modal--sm')
  }

  const handleItemAction = (action: Action, ctx: any) => {
    handleAction(undefined, action, ctx, false);
  }
  const handleChangePage = async (page: number, perPage?: number) => {
    const {
      syncLocation,
      env,
      pageField,
      perPageField,
      autoJumpToTopOnPagerChange,
      affixOffsetTop,
      loadDataOnce
    } = props;
    let query: any = {
      [pageField || 'page']: page
    };

    // 如果不是前端分页，检查一下是否有快速编辑
    if (!loadDataOnce)
      await quickEditDataCheck()

    if (perPage) {
      query[perPageField || 'perPage'] = perPage;
    }
    store.updateQuery(
      query,
      syncLocation && env?.updateLocation ? env.updateLocation : undefined,
      pageField,
      perPageField
    );
    let queryParams: any;

    if (advanceFilterForm?.confirmAdvancedFilter()) {
      const advanced = advanceFilterForm?.confirmAdvancedFilter()
      const filter = advanced?.advancedFilter.length || advanced?.advancedFilterSub.length || Object.keys(advanced?.advancedHeader).length
      if (filter) {
        queryParams = advanceFilterForm?.confirmAdvancedFilter()
      }
    }

    if (Object.keys(filtercont).length) {
      queryParams = filtercont;
    }
    search(
      undefined,
      undefined,
      undefined,
      false,
      afterSearchFn,
      undefined,
      undefined,
      queryParams
    );

    if (autoJumpToTopOnPagerChange && control) {
      control?.scrollIntoView();
      const scrolledY = window.scrollY;
      const offsetTop = affixOffsetTop ?? env?.affixOffsetTop ?? 0;
      scrolledY && window.scroll(0, scrolledY - offsetTop);
    }
  }

  const renderType = (schema?: any) => {
    const { ctx, classnames: cx, classPrefix: ns, translate: __, card, listItem, cross, env } = props;
    return (
      <>
        <LionCopyItem
          showItems={[{
            value: schema.name ?? schema.labelId ?? "",
            label: __('Alert.copyName'),
            icon: "fa fa-sticky-note-o"
          }]}
          env={env}
        >
          {/* 没有卡片和列表项的报文的时候不进行渲染按钮入口 */}
          <Popover placement="bottomLeft" overlayClassName={cx('Tool-action')} getPopupContainer={env.getModalContainer} trigger={['hover']} content={() => {
            if (!(listItem || card || cross)) return <></>
            return <div className='crud-mode-exchange'>
              <Button
                disabled={modes == 'table' || modes == undefined}
                classPrefix={ns}
                onClick={() => {
                  setModes('table');
                  handleFakeAnimation()
                }}
                size="sm"
              >
                <Icon icon={'#icon-tooltool_table'} className="icon" symbol />
                表格
              </Button>
              {listItem && <Button
                disabled={modes == 'list'}
                classPrefix={ns}
                onClick={() => {
                  getTableStore(null)
                  setModes('list')
                  handleFakeAnimation()
                }} size="sm"
              >
                <Icon icon={'#icon-tooltool_list'} className="icon" symbol />
                列表
              </Button>}
              {card && <Button
                disabled={modes == 'cards'}
                classPrefix={ns}
                onClick={() => {
                  getTableStore(null)
                  setModes('cards')
                  handleFakeAnimation()
                }} size="sm"
              >
                <Icon icon={'#icon-toolqiapianxingshi'} className="icon" symbol />
                卡片
              </Button>}
              {cross && <Button
                disabled={modes == 'cross'}
                classPrefix={ns}
                onClick={() => {
                  setModes('cross')
                  handleFakeAnimation()
                }} size="sm"
              >
                <Icon icon={'#icon-tooltool_table'} className="icon" symbol />
                交叉
              </Button>}
            </div>
          }
          }>
            <Button
              disabled={schema.disabled || evalExpression(schema.disabledOn, ctx)}
              classPrefix={ns}
              // onClick={this.debounceChangeMode}
              size="sm"
            >
              {schema?.icon ?
                <Icon icon={schema?.icon} className="icon" symbol /> :
                <Icon style={{ width: '14px', height: '15px', fill: autoWidth ? '#005bff' : '#000', stroke: '#005bff' }} icon="auto-width" className="icon" />}
              {schema?.label && schema?.label}
            </Button>
          </Popover>
        </LionCopyItem>
      </>
    );
  }
  const renderAutoWidth = (toolbar: Schema) => {
    const { env } = props;
    return (
      <Button
        tooltip={autoWidth ? '宽松列宽' : '紧凑列宽'}
        size="sm"
        iconOnly
        butColor={autoWidth}
        tooltipContainer={env?.getTopModalContainer || undefined}
        onClick={() => {
          const autoWidthPage = getLocalStorage('autoWidthPage') || {}
          autoWidthPage[name || ''] = !autoWidth
          setLocalStorage('autoWidthPage', autoWidthPage)
          setAutoWidth(!autoWidth)
          const localEditWidthMap = getLocalStorage(EDITWIDTHKEY) || {}
          delete localEditWidthMap?.[name || '']
          setLocalStorage(EDITWIDTHKEY, localEditWidthMap)
        }}
      >
        {toolbar?.icon ?
          <Icon icon={toolbar?.icon} className="icon" symbol /> :
          <Icon style={{ width: '14px', height: '15px', fill: autoWidth ? '#005bff' : '#000', stroke: '#005bff' }} icon="auto-width" className="icon" />}

        {toolbar?.label && toolbar?.label}
      </Button>
    );
  }
  const renderPrint = (schema?: any, isFilePrint?: boolean) => {
    const { store, classPrefix: ns, env } = props;
    const selectedItems = getTableSelectedRowsData(store, tableStore);

    let ids = selectedItems
      .map(item =>
        item.hasOwnProperty(primaryField) ? item[primaryField as string] : null
      )
      .filter(item => item)
      .join(',');
    const ctx = createObject(store.mergedData, {
      ...selectedItems[0], // 第一行所有行数据
      items: getTableRowsData(store, tableStore), // 选中行数据
      selectedItems, // 选中行数据
      ids,
      primaryField
    });
    return (
      <>
        <LionCopyItem
          showItems={[{
            value: schema.name ?? schema.labelId ?? "",
            label: __('Alert.copyName'),
            icon: "fa fa-sticky-note-o"
          }]}
          env={env}
        >
          <Button
            disabled={schema.disabled || evalExpression(schema.disabledOn, ctx)}
            classPrefix={ns}
            onClick={() => {
              const LODOP = getLodop();
              if (LODOP) {
                setCrudState({
                  ModalProps: {
                    ...schema,
                    show: true,
                    ctx
                  },
                  printType: isFilePrint
                    ? 'file'
                    : schema.actionType === 'label-print'
                      ? 'label'
                      : 'bill'
                })
              }
            }}
            size="sm"
          >
            {__(
              schema.label
                ? schema.label
                : !isFilePrint
                  ? 'CRUD.labelPrint'
                  : 'CRUD.filePrint'
            )}
          </Button>
        </LionCopyItem>
      </>
    );
  }
  const renderColumnsFilterBtn = (toolbar: Schema) => {
    const { env, loadDataOnce } = props

    return (
      <Button
        tooltip={'列过滤'}
        size="sm"
        iconOnly
        butColor={showColumnsFilter}
        tooltipContainer={env?.getTopModalContainer || undefined}
        onClick={() => {
          if (showColumnsFilter) {
            setCrudState({ filterDrawerVisible: true })
          } else {
            const value = localStorage.getItem(name ?? '')
            if (value) {
              const obj = JSON.parse(value)
              Object.keys(obj).forEach(key => tableStore?.filterColumns.set(key, obj[key]))
            }
            if (showColumnsFilter) {
              setCrudState({ filterDrawerVisible: true })
            } else {
              const items = tableStore?.handleMutilSort(loadDataOnce)
              if (loadDataOnce && Array.isArray(items)) setTotal(items.length)
              setCrudState({ showColumnsFilter: !showColumnsFilter })
            }
          }
        }}
      >
        {toolbar?.icon ?
          <Icon icon={toolbar?.icon} className="icon" symbol /> :
          <Icon icon="packet-filtery" className="icon" />}
        {toolbar?.label && toolbar?.label}
      </Button>
    )
  }
  const renderPagination = (toolbar: SchemaNode) => {
    const { store, render, classnames: cx, alwaysShowPagination } = props;
    const { page, lastPage } = store;
    if (
      store.mode !== 'simple' &&
      store.lastPage < 2 &&
      !alwaysShowPagination
    ) {
      return <></>;
    }

    const extraProps: any = {};
    if (typeof toolbar !== 'string') {
      extraProps.showPageInput = (toolbar as Schema).showPageInput;
      extraProps.maxButtons = (toolbar as Schema).maxButtons;
    }

    return (
      <div className={cx('Crud-pager')}>
        {render(
          'pagination',
          {
            type: 'pagination'
          },
          {
            ...extraProps,
            inSmallDialog: inSmallDialog(),
            activePage: page,
            lastPage: lastPage,
            hasNext: store.hasNext,
            mode: store.mode,
            onPageChange: handleChangePage
          }
        )}
      </div>
    );
  }
  const renderAiTool = (action: Action) => {
    const { api, env } = props;
    const newData = createObject(
      store.filterData,
      store.query,
      {},
      true
    );
    const { curApiForCache = '' } = store.getRawCacheData()
    return (
      <AiTool
        pageId={name ?? ''}
        env={{ ...env, container: crudRef?.current }}
        action={action}
        data={newData}
        paramData={curApiForCache || (api as any)?.url}
        render={render}
      />
    )
  }
  const renderStatistics = () => {
    return (
      <div className={cx('Crud-statistics')}>
        {mode == 'cross' ?
          __('CRUD.total', { total: mode == 'cross' ? tableStore?.rows?.length : store.data?.total }) :
          __('CRUD.stat', { total: store.total })}
      </div>
    );
  }
  const renderSwitchPerPage = (childProps: any) => {
    const { perPageAvailable } = props;

    const perPages = (perPageAvailable || [5, 10, 20, 50, 100]).map(
      (item: any) => ({
        // Jay 修改分页器样式
        label: item + (inSmallDialog() ? '' : ` ${__('CRUD.countPage')}`), // 小弹窗不显示页数
        value: item
      })
    );

    return (
      <div className={cx('Crud-pageSwitch')} ref={pageSwitchRef}>
        {/* Jay 修改分页器 */}
        {/* {__('CRUD.perPage')} */}
        <Select
          options={perPages}
          placeholder={__('Select.placeholder')}
          defaultValue={perPages[0]?.value || ''}
          onChange={(value: any) => {
            handleChangePage(1, value);
          }}
          getPopupContainer={() => pageSwitchRef.current as HTMLElement}
        ></Select>
      </div>
    );
  }
  const renderLoadMore = (toolbar: Schema) => {
    const { classPrefix: ns } = props;
    const { page, lastPage } = store;

    return page < lastPage ? (
      <div className={cx('Crud-loadMore')}>
        <Button
          classPrefix={ns}
          onClick={() =>
            search({ page: page + 1, loadDataMode: 'load-more' })
          }
          size="sm"
        >
          {toolbar?.icon &&
            <Icon icon={toolbar?.icon} className="icon" symbol />}
          {toolbar?.label ? toolbar?.label : __('CRUD.loadMore')}
        </Button>
      </div>
    ) : (
      <></>
    );
  }
  const renderFilterToggler = () => {
    if (!store.filterTogggable) {
      return <></>;
    }

    return (
      <button
        onClick={() => store.setFilterVisible(!store.filterVisible)}
        className={cx('Button Button--sm Button--default', {
          'is-active': store.filterVisible
        })}
      >
        <Icon icon="filter" className="icon m-r-xs" />
        {__('CRUD.filter')}
      </button>
    );
  }
  const renderExportCSV = (toolbar: Schema) => {
    const { classPrefix: ns, loadDataOnce } = props;
    const api = (toolbar as Schema).api;
    return (
      <Button
        classPrefix={ns}
        onClick={() =>
          store.exportAsCSV({
            loadDataOnce,
            api
          })
        }
        size="sm"
      >
        {toolbar.label || __('CRUD.exportCSV')}
      </Button>
    );
  }
  const renderExport = (toolbar: Schema) => {
    const { classPrefix: ns, env } = props;

    const ctx = createObject({}, {
      items: getTableRowsData(store, tableStore),
      selectedItems: getTableSelectedRowsData(store, tableStore),
      unSelectedItems: store.unSelectedItems.concat()
    })

    return (
      <LionCopyItem
        showItems={[{
          value: toolbar.name ?? toolbar.labelId ?? "",
          label: __('Alert.copyName'),
          icon: "fa fa-sticky-note-o"
        }]}
        env={env}
      >
        <div style={{ position: 'relative' }} className='exportExcel'>
          <Button
            classPrefix={ns}
            onClick={(e) => { handleAction(e, toolbar as Action, ctx) }}
            size="sm"
          >
            {toolbar?.icon && <Icon icon={toolbar?.icon} className="icon" symbol />}
            {toolbar.label || __('CRUD.exportExcel')}
          </Button>
          {toolbar.redDot === true && <div style={{ position: 'absolute', display: 'inline-block', right: 0, top: 0, background: 'red', width: 6, height: 6, borderRadius: 4 }} />}
        </div>
      </LionCopyItem>
    );
  }
  const renderReload = (toolbar: Schema, index: number) => {
    if (toolbar.isToolBar && isMobile()) {
      return (
        <div className='toolbar-item' onClick={toolBarAction}>
          <div className='toolbar-item-icon'><Icon icon={toolbar.icon} ></Icon></div>
          <div className='toolbar-item-name'>{__('reload')}</div>
        </div>
      )
    } else {
      let reloadButton = {
        label: '',
        icon: toolbar.icon,
        tooltip: __('reload'),
        tooltipPlacement: 'top',
        type: 'button'
      };
      if (typeof toolbar === 'object') {
        reloadButton = { ...reloadButton, ...omit(toolbar, ['type', 'align']) };
      }
      return render(`toolbar/${index}`, reloadButton, {
        onAction: toolBarAction
      });
    }
  }

  const renderBulkActions = (childProps: any, bulkActions?: Array<ActionSchema>) => {
    let {
      itemActions,
      store,
      render,
      classnames: cx,
      useMobileUI,
      primaryField,
      inModal,
    } = props;


    const items = childProps.items;

    if (
      !items.length ||
      ((!bulkActions || !bulkActions.length) &&
        (!itemActions || !itemActions.length))
    ) {
      return null;
    }

    const selectedItems = getTableSelectedRowsData(store, tableStore);

    let bulkBtns: Array<ActionSchema> = [];
    let itemBtns: Array<ActionSchema> = [];

    const ctx = store.mergedData;

    if (
      bulkActions &&
      bulkActions.length &&
      (!itemActions || !itemActions.length || selectedItems.length > 1)
    ) {
      bulkBtns = bulkActions
        .filter((toolbar: any) =>
          isVisible(toolbar, inModal ? originFilterData : store.filterData)
        )
        .map(item => ({
          ...item,
          ...getExprProperties(item as Schema, ctx)
        }))
        .filter(item => item?.visible !== false);
    }

    const itemData = createObject(
      store.data,
      selectedItems.length ? selectedItems[0] : {}
    );

    if (itemActions && selectedItems.length <= 1) {
      itemBtns = itemActions
        .map(item => ({
          ...item,
          ...getExprProperties(item as Schema, itemData)
        }))
        .filter(item => item?.visible !== false);
    }

    const ids = selectedItems
      .map(item =>
        item.hasOwnProperty(primaryField) ? item[primaryField as string] : null
      )
      .filter(item => item)
      .join(',');
    // Aug

    const renderBulk = bulkBtns.length
      ? bulkBtns.map((btn, index) => bulkActionRender(btn, index)
      ) : [];
    const renderItem = itemBtns.length
      ? itemBtns.map((btn, index) =>
        render(
          `bulk-action/${index}`,
          {
            ...omit(btn, ['visibleOn', 'hiddenOn', 'disabledOn']),
            type: specialButtonType.includes(btn.type) ? btn.type : 'button'
          },
          {
            key: `item-${index}`,
            data: itemData,
            disabled: btn.disabled || selectedItems.length !== 1,
            onAction: handleItemAction
          }
        )
      )
      : [];
    let children = [...renderBulk, ...renderItem];
    if (useMobileUI && isMobile() && children.length > 3) {
      const more = children.splice(2);
      children.splice(0, 0, renderMoreToolbar(more));
    }
    return (
      <div className={cx('Crud-actions', 'Crud-bulkActions')}>
        {children}
      </div>
    );
  }

  const renderToolAction = (
    toolbar?: any,
    index: number = 0,
    childProps: any = {},
    toolbarRenderer?: (toolbar: SchemaNode, index: number) => React.ReactNode
  ) => {
    const { classnames: cx, translate: __, env } = props;
    return <Popover placement="bottomLeft"
      overlayClassName={cx('Tool-action')}
      getPopupContainer={env.getModalContainer}
      onVisibleChange={(visible) => setToolActionSwitch(visible)}
      trigger={isMobile() ? 'click' : 'hover'}
      visible={toolActionSwitch} overlay content={
        <>
          <div className={cx('Tool-action-body')}
            onClick={(e) => setToolActionSwitch(false)}
          >
            {toolbar.toolBarItems.map((toolbar: any, index: number) => renderToolbar(toolbar, index, childProps, toolbarRenderer))}
          </div>
        </>
      }>
      <Button>
        <Icon icon={`${toolbar?.icon ?? `#icon-tooltool_process--`}`} className="icon" symbol />
        {(toolbar?.label && toolbar?.label) ?? __('Table.tools')}
      </Button>
    </Popover>
  }


  switch (type) {
    case 'headerBulkActions':
      return renderBulkActions(childProps, isMobile() ? unitBulkActions({
        headerActions: headerActions,
        headerToolbar: headerToolbar,
        headerBulkActions: headerBulkActions
      }) : headerBulkActions);
    case 'footerBulkActions':
      return renderBulkActions(childProps, footerBulkActions);
    //以下的都是只有表格才有的
    case 'tool-bar-action':
      return renderToolAction(toolbar, index, childProps, toolbarRenderer)
    case 'data-statics':
    case 'data-cross':
    case 'columns-filter':
    case 'find-replace':
    case 'data-chart':
      // 统计模式卡片列表中移除-这个给表格模式预留的
      if (modes == 'cards' || modes == 'list') {
        return <></>
      } else if (type === 'columns-filter') {
        return renderColumnsFilterBtn(toolbar)
      }
      break;
    case "detail-model":
      return <></>
    case 'pagination':
      return renderPagination(toolbar);
    case 'ai-tool':
      return renderAiTool((toolbar as Action));
    case 'statistics':
      return renderStatistics();
    case 'switch-per-page':
      return renderSwitchPerPage(childProps);
    case 'load-more':
      return renderLoadMore(toolbar);
    case 'filter-toggler':
      return renderFilterToggler();
    case 'auto-width':
      return renderAutoWidth(toolbar);
    case 'export-csv':
      return renderExportCSV(toolbar);
    case 'reload':
      return renderReload(toolbar as Schema, index);
    case 'label-print':
    case 'bill-print':
    case 'file-print':
      return renderPrint(toolbar);
    case 'columns-toggler':
      if (modes == 'cards' || modes == 'list') {
        return <></>
      } else break;
    case 'export':
      return renderExport(toolbar as Schema)
    case 'type-conversion':
      if ((!card && !listItem && !cross) || isMobile()) {
        return <></>
      }
      return renderType(toolbar)
  }


  // 这个是用于渲染子组件的方法-意思是如果子组件有注册实现的话就用子组件的渲染方法
  // 后期看看这个能不能优化到同一处理
  const childToolBottunResult = toolbarRenderer?.(toolbar, index)
  if (childToolBottunResult) {
    return (childToolBottunResult as any) || <></>
  }


  // 以下是通用方法的渲染
  const $$editable = childProps.$$editable;
  return render(`toolbar/${index}`, toolbar, {
    // 包两层，主要是为了处理以下 case
    // 里面放了个 form，form 提交过来的时候不希望把 items 这些发送过来。
    // 因为会把数据呈现在地址栏上。
    data: createObject(
      createObject(inModal ? originFilterData : store.filterData, {
        items: childProps.items,
        selectedItems: childProps.selectedItems,
        unSelectedItems: childProps.unSelectedItems
      }),
      {}
    ),
    headerCanShow: headerCanShow(header, filter, filtercont, tableStore),
    page: store.page,
    lastPage: store.lastPage,
    perPage: store.perPage,
    total: store.total,
    onQuery: handleQuery,
    onAction: handleAction,
    onChangePage: handleChangePage,
    $$editable,
    updateAutoFillHeight: tableInstance?.updateAutoFillHeight
  });
}



export const CrudBody: React.FC<CrudBodyProps> = (crudBodyProps) => {
  const {
    props,
    foldColumns,
    tableRotate,
    controlRef,
    // 函数方法
    setCrudState,
    setLoading,
    handleAction,
    dataCheckRegist,
    handleSaveOrder,
    handleQuery,
    handleChildPopOverOpen,
    handleChildPopOverClose,
    handleFilterReset,
    handleFilterSubmit,
    handleFilterInit,
    markSort,
    renderFilter,
    handleLoadMore,
    handleResetData,
    getTableStore,
    getTableInstance,
    setTotal,
    clearSelectedItems,
    handleClickOffline,
    handleJump,
    currentSelectedRow,
    crudRef,
    hasBulkActions,
    filtercont,
    // 其他属性
    saveColApi,
    columnInfo,
    tabsdefer,
    initFetch,
    name,
    showColumnsFilter,
    hasFetch,
    preSortAble,
    tableStore,
    tableInstance,
    search,
    afterSearchFn,
    control,
    filterData,
    showTableEditWarmModal,
    openFeedback,
    reloadTarget,
    closeTarget,
    originFilterData,
    context,
    advanceFilterForm
  } = crudBodyProps;
  const {
    className,
    bodyClassName,
    filter:SearchFilter,
    render,
    store,
    mode,
    syncLocation,
    children,
    headerBulkActions,
    footerBulkActions,
    pickerMode,
    multiple,
    showIndex,
    valueField,
    primaryField,
    value,
    hideQuickSaveBtn,
    itemActions,
    classnames: cx,
    keepItemSelectionOnPageChange,
    maxKeepItemSelectionLength,
    onAction,
    popOverContainer,
    translate: __,
    onQuery,
    autoGenerateFilter,
    onSelect,
    autoFillHeight,
    useMobileUI, // Aug
    columns,
    advancedFilter,
    advancedQueryFields,
    onImageEnlarge,
    offlineSchema,
    advancedFilterApi,
    tableLayout,
    header,
    footer,
    ...rest
  } = props

  const [modes, setModes] = useState(mode || 'table');
  // 自动过滤, 移动端默认为true 或者这个表格没有自动列宽这个属性的话 也默认使用true -- 即进来就自动适用自动列宽计算逻辑
  const [autoWidth, setAutoWidth] = useState(isMobile() ? true : (!isNil(getLocalStorage('autoWidthPage')?.[name || '']) ? getLocalStorage('autoWidthPage')?.[name || ''] : true))
  const [moreIsOpened, setMoreIsOpened] = useState(false) // Aug 更多操作面板,]
  const [toolChildMaxCount, setToolChildMaxCount] = useState<number>();

  const toolActionsRef = useRef<HTMLDivElement | null>(null);


  useEffect(() => {
    const mobileUI = isMobile() && useMobileUI;
    if (mobileUI) calcToolActionsMaxCount();
  }, [])

  // 提前计算需要计算的属性
  const computedMultiple = multiple === void 0
    ? (headerBulkActions && headerBulkActions.length > 0) ||
      (footerBulkActions && footerBulkActions.length > 0)
      ? true
      : false
    : multiple;

  const computedSelected = pickerMode || keepItemSelectionOnPageChange
    ? store.selectedItems
    : undefined;

  const computedLoadHasMore = (store.data.items?.length > 0 && store.data.total > 0 && store.data.total > store.data.items.length) ||
    (!store.data.items?.length && store.loading) ||
    !!((store.data.total || store.data.count) && !(
      store.page > store.lastPage ||
      store.data.items?.length >=
      (store.data.total ?? store.data.count)
    ));

  const computedPlaceholder = rest.placeholder ||
    (!initFetch && !hasFetch && SearchFilter
      ? 'placeholder.trySearch'
      : undefined);

  const computedSelectable = !!(
    hasBulkActions() ||
    pickerMode ||
    multiple
  );

  const computedTableLayout = isMobile() ? (tableLayout || 'horizontal') : 'horizontal';

  //移动端处理工具栏按钮中的可批量操作的按钮，加入到headerBulkActions中
  const handleUnitBulkActions = () => {
    const { headerToolbar, headerBulkActions, headerActions } = props
    return unitBulkActions({ headerToolbar, headerBulkActions, headerActions })
  }
  const computedUnitBulkActions = handleUnitBulkActions();
  const computedHeaderCanShow = headerCanShow(header, SearchFilter, filtercont, tableStore);

  const getAllData = async (showFields: string[]) => {
    const { api, env, data } = props;
    let allData: object | null = {};
    if (api) {
      let params: any = {};
      if (Object.keys(filtercont || {}).length) {
        params = {
          advancedFilter: dealAdvacedCondition(filtercont?.advancedFilter),
          advancedFilterSub: dealAdvacedCondition(filtercont?.advancedFilterSub),
          advancedHeader: filtercont?.advancedHeader,
          optionsParam: showFields?.length > 0 ? { ...filtercont?.optionsParam, queryField: showFields } : filtercont?.optionsParam,
          filterParam: filtercont?.filterParam
        }
        if (filtercont?.filterOptionData) {
          const { optionsParam } = filtercont?.filterOptionData;
          params = {
            ...params,
            ...optionsParam
          }
        }
      } else {
        if (showFields?.length > 0) {
          params.optionsParam = { queryField: showFields }
        }
      }
      const paramsData = {
        ...params,
        index: 1,
        filterParam: store.query?.filterParam,
        topN: filtercont?.limitParam?.limitStatus ? filtercont?.limitParam?.topN : undefined
      }
      const res = await env.fetcher(api, createObject(data, paramsData))
      if (res.ok && res.data) {
        allData = res.data
      } else {
        allData = null
        message.error(res.msg)
      }
      return allData
    }
    return allData
  }

  // Aug
  const moreHandleTouch = (e: React.MouseEvent<HTMLDivElement>) => {
    e.stopPropagation();
    setMoreIsOpened(true);
  }

  // Aug更多操作
  const renderMoreToolbar = (children: Array<any>) => {
    const { classnames: cx, translate: __, env: { getModalContainer } } = props;
    return (
      <ActionSheet
        key={Date.now() + '-actionSheet'}
        isOpened={moreIsOpened}
        container={getModalContainer}
        round
        onHide={(e: any) => {
          e.stopPropagation();
          setMoreIsOpened(false);
        }}
        popupContent={
          <div style={{ width: '100%' }}>
            {children.map((child: any, idx: number) => {
              return (
                <div
                  key={idx}
                  data-index={idx}
                  id="amis-action-sheet-btn-wrapper"
                  className="action-sheet-btn-wrapper"
                  onClick={e => {
                    // e.stopPropagation();
                    setMoreIsOpened(false);
                  }}
                >
                  {child.dom || child}
                </div>
              );
            })}
          </div>
        }
      >
        <span
          className={cx('Button', 'Button--link')}
          onClick={moreHandleTouch}
        >
          <i className={cx('Button-icon', 'fa', 'fa-reorder')}></i>
          <span>{__('More')}</span>
        </span>
      </ActionSheet>
    );
  }

  const renderToolbar = (
    toolbar?: SchemaNode,
    index: number = 0,
    childProps: any = {},
    toolbarRenderer?: (toolbar: SchemaNode, index: number) => React.ReactNode,
    // Jay
    isFooter?: boolean
  ) => {
    if (!toolbar) {
      return null;
    }
    const {
      inModal,
      store,
      translate: __,
      useMobileUI,
      env,
      headerToolbar,
      footerToolbar
    } = props;

    // 多个工具方法展示
    if (Array.isArray(toolbar) && toolbar.length !== 0) {
      const children: Array<any> = toolbar
        .filter((toolbar: any) =>
          isVisible(toolbar, inModal ? originFilterData : store.filterData) &&
          !(isMobile() && (toolbar.type == 'columns-toggler' || toolbar.isToolBar))
        )
        .map((toolbar, index) => ({
          dom: renderToolbar(toolbar, index, childProps, toolbarRenderer),
          toolbar
        }))
        .filter(item => item.dom);
      // Jay
      // 对分页器的几个元素进行排序
      const sortFooterbar: any = {
        'statistics': 1,
        'pagination': 2,
        'switch-per-page': 3
      };
      children.sort((a, b) => {
        if (b.toolbar.align === 'right') {
          if (
            a.toolbar.align === 'left' ||
            sortFooterbar[a.toolbar?.type] > sortFooterbar[b.toolbar?.type]
          ) {
            return -1;
          } else if (
            sortFooterbar[a.toolbar.type] < sortFooterbar[b.toolbar.type]
          ) {
            return 1;
          }
        }
        return 0;
      });

      const len = children.length;
      if (len) {
        // Aug 移动端超过三个显示更多
        if (useMobileUI && isMobile() && toolChildMaxCount && len > toolChildMaxCount) {
          const moreToolbar = children.splice(toolChildMaxCount);
          const moreToolbarDom = renderMoreToolbar(moreToolbar);
          children.splice(0, 0, { dom: moreToolbarDom, toolbar: { type: 'more' } });
        }
        let button = children.filter(({ toolbar }, index) => toolbar.align == 'right' && !isFooter).reverse();
        const searchBtnIndex = button.findIndex(({ toolbar }) => toolbar.actionType === 'advanced-filter');

        let leftBtns = children.filter(({ toolbar }, index) => (toolbar.align !== 'right' || isFooter) && toolbar.type !== 'paginator');
        const paginator = children.find(({ toolbar }) => toolbar.type === 'paginator');
        // 工具栏里面啥都没有的情况之前返回空
        if (!headerToolbar?.length && !footerToolbar?.filter((_: any) => _.type !== 'footerBulkActions').length) return <div style={{ marginTop: 0, border: 0 }}></div>
        return (
          <div className={cx('Crud-toolbar', { footer: isFooter })} key={index}>
            {leftBtns.length > 0 && <div ref={toolActionsRef} className={cx('Crud-toolbar-tool--actions')}>
              {
                leftBtns.map(({ toolbar, dom: child }, index) => {
                  // const type = (toolbar as Schema).type || toolbar;
                  // let align = toolbar.align || (type === 'pagination' ? 'right' : 'left');
                  return (<div key={index} className={cx('Crud-toolbar-item', toolbar.className)} > {child} </div>
                  )
                })
              }
            </div>}
            {(paginator || (!isFooter && button.length > 0)) && <div className={cx('Crud-toolbar-tool--head')}>
              {paginator && paginator.toolbar.renderPagenation?.()}
              {!isFooter && button.length > 0 && <div className={cx('Crud-toolbar-tool')}>
                <div className={cx('Crud-toolbar-tool-content')}>
                  <OverflowWrapper env={env} classPrefix={cx} itemClassName={'toolbar-btn-item'}
                    showFixRight={searchBtnIndex > -1}
                    fixRightRenderIndex={searchBtnIndex}
                    items={
                      button.map(({ toolbar, dom: child }, index) => {
                        return (
                          {
                            key: index,
                            children: (<div key={index} className={cx('Crud-toolbar-item', 'toolbar-btn-item', toolbar.className)} > {child} </div>)
                          }
                        );
                      })
                    }>
                  </OverflowWrapper>
                </div>
              </div>}
            </div>}
          </div>
        );
      }
      return null;
    }

    return <ToolButton
      {...crudBodyProps}
      renderToolbar={renderToolbar}
      renderMoreToolbar={renderMoreToolbar}
      bulkActionRender={bulkActionRender}
      toolbar={(toolbar as any as Schema)}
      index={index}
      childProps={childProps}
      toolbarRenderer={toolbarRenderer}
      modes={modes}
      setModes={setModes}
      autoWidth={autoWidth}
      setAutoWidth={setAutoWidth}

    ></ToolButton>
  }


  const renderHeaderToolbar = (
    childProps: any,
    toolbarRenderer?: (toolbar: SchemaNode, index: number) => React.ReactNode,
    renderPagenation?: () => void
  ) => {
    let { toolbar, toolbarInline, headerToolbar } = props;

    let privateHeadrToolBar = [...headerToolbar || []]

    if (renderPagenation) {
      privateHeadrToolBar.push({
        type: 'paginator',
        align: 'left',
        renderPagenation: renderPagenation
      })
    }
    if (toolbar) {
      if (Array.isArray(privateHeadrToolBar)) {
        privateHeadrToolBar = toolbarInline
          ? privateHeadrToolBar.concat(toolbar)
          : [privateHeadrToolBar, toolbar];
      } else if (privateHeadrToolBar) {
        privateHeadrToolBar = [privateHeadrToolBar, toolbar];
      } else {
        privateHeadrToolBar = toolbar;
      }
    }
    return renderToolbar(
      privateHeadrToolBar || [],
      0,
      childProps,
      toolbarRenderer
    );
  }

  const renderFooterToolbar = (
    childProps: any,
    toolbarRenderer?: (toolbar: SchemaNode, index: number) => React.ReactNode,
    customToolbar?: any // Aug
  ) => {
    let { toolbar, toolbarInline } = props;
    let footerToolbar = customToolbar || props.footerToolbar; // Aug
    if (toolbar || footerToolbar) {
      if (Array.isArray(footerToolbar)) {
        if (footerToolbar.length) {
          footerToolbar = (toolbarInline
            ? footerToolbar.concat(toolbar)
            : [footerToolbar, toolbar]).filter(Boolean);
          if (footerToolbar.find((item: any) => item.type == 'pagination')) {
            !footerToolbar.find((item: any) => item.type == 'switch-per-page') && footerToolbar.push({
              "type": "switch-per-page",
              "align": "right"
            })
          }
        } else {
          footerToolbar = null
        }
      } else if (footerToolbar) {
        footerToolbar = [footerToolbar, toolbar];
      } else {
        footerToolbar = toolbar || null;
      }
    } else {
      footerToolbar = null;
    }
    return renderToolbar(
      footerToolbar,
      0,
      childProps,
      toolbarRenderer,
      true
    );
  }

  const renderAggregate = () => {
    const { aggregate } = props;
    if (aggregate) {
      const query = { ...store.query, ...filtercont }
      if (query.advancedFilter) {
        query.advancedFilter = dealAdvacedCondition(query.advancedFilter)
      }
      return (
        <div className={cx('Table-statistics', isMobile() ? 'Table-statistic-mobile' : '')}>
          {render('aggregate', aggregate, { items: getTableRowsData(store, tableStore), query })}
        </div>
      )
    }
    return null
  }



  const calcToolActionsMaxCount = () => {
    const toolActionsElement = toolActionsRef.current
    if (toolActionsElement) {
      let width = 0
      for (let i = 0; i < toolActionsElement.children.length; i++) {
        const element = toolActionsElement.children.item(i) as HTMLDivElement
        width += element.clientWidth + 12
        if (width > toolActionsElement.clientWidth - 70) {
          setToolChildMaxCount(i)
          break
        }
      }
    }
  }

  const handleTableRotate = () => {
    const { classPrefix } = props;
    setCrudState({
      tableRotate: !tableRotate
    })
    setToolChildMaxCount(undefined);
    calcToolActionsMaxCount()
    if (tools.isIOS) {
      const crud = crudRef?.current;
      const container = crud.querySelector(
        `.${classPrefix}Table-content`
      ) as HTMLElement;
      setTimeout(() => {
        const origin = container.scrollLeft;
        container.scrollTo({ left: origin + 1 });
      }, 800)
    }
  }

  const handleBulkAction = (
    selectedItems: Array<any>,
    unSelectedItems: Array<any>,
    e: React.UIEvent<any>,
    action: Action,
    btn?: any
  ) => {
    const {
      store,
      primaryField,
      messages,
      pageField,
      env,
      fullDataApi,
      translate: __
    } = props;
    if (tableInstance.props.store.modified > 0) {
      showTableEditWarmModal();
      return;
    }

    if (!selectedItems.length && action.requireSelected !== false) {
      return;
    }

    let ids = selectedItems
      .map(item =>
        item.hasOwnProperty(primaryField) ? item[primaryField as string] : null
      )
      .filter(item => item)
      .join(',');

    let ctx = createObject(store.mergedData, {
      ...selectedItems[0],
      rows: selectedItems,
      items: selectedItems,
      selectedItems: selectedItems,
      unSelectedItems: unSelectedItems,
      ids
    });
    let fn = async () => {
      if (action.actionType === 'batch-download') {
        const api = buildApi(action.api as any, ctx);
        const baseURL = env?.axiosInstance?.defaults?.baseURL || env?.ajaxApi;
        api.url && downloadFile((baseURL ?? '') + api.url, '')
      } else if (action?.actionType === 'dialog') {
        return handleAction(
          e,
          {
            ...action,
            __from: 'bulkAction'
          },
          ctx
        );
      } else if (action.actionType === 'ajax') {
        isEffectiveApi(action.api, ctx) &&
          store
            .saveRemote(action.api as string, ctx, {
              successMessage:
                (action.messages && action.messages.success) ||
                (messages && messages.saveSuccess),
              errorMessage:
                (action.messages && action.messages.failed) ||
                (messages && messages.saveFailed)
            })
            .then(async (payload: object) => {
              const data = createObject(ctx, payload);
              if (action.feedback && isVisible(action.feedback, data)) {
                await openFeedback(action.feedback, data);
              }

              // Jay 菜鸟打印 打印按钮是bulkActions，actionType 为 'ajax'，根据状态码判断
              if ((data as any)?.status === 20001) {
                await expressLabels(data as any, env.fetcher, __);
              }

              action.reload
                ? reloadTarget(action.reload, data)
                : search(
                  { [pageField || 'page']: 1 },
                  undefined,
                  true,
                  true
                );
              action.close && closeTarget(action.close);

              const redirect = action.redirect && filter(action.redirect, data);
              redirect && env.jumpTo(redirect, action);
            })
            .catch(() => null);
      } else {
        handleAction(e, action, ctx, false, context);
      }
      return undefined;
    };
    const actionbut = async () => {
      if (btn && btn?.openFullSelect && btn?.confirmApi) {
        const data = createObject(props.data, {
          ...props.data,
          ...ctx
        });
        ctx = data;
        const confirmMsg = btn?.confirmApi && await env.fetcher(btn?.confirmApi, data).catch(() => { });
        if (confirmMsg?.status === 10004 || confirmMsg?.status === 10001 || confirmMsg?.status === 1) {
          env.notify('warning', confirmMsg?.msg)
          return;
        } else if (confirmMsg?.status === 500) {
          return;
        } else if (confirmMsg?.status === 10003) {
          env
            .confirm(filter(confirmMsg?.data?.showText ?? '', ctx))
            .then((confirmed: boolean) => { confirmed && fn() });
          return
        } fn()

      } else if (action.confirmText && env.confirm) {
        env
          .confirm(filter(action.confirmText, ctx))
          .then((confirmed: boolean) => { confirmed && fn() });
      } else fn()
    }

    if (selectedItems.length && !unSelectedItems.length && btn && btn?.openFullSelect && fullDataApi) {
      confirmWithThreeButtons({ env, translate: __, }).then((result) => {
        if (result === 1) actionbut()
        else if (result === 2) {
          const data = createObject(store.mergedData, {
            ...filterData, action_id: btn.name
          })
          env.fetcher(fullDataApi, data).then((res) => {
            const items = res.data
            const ids = res.data.map((item: any) => Object.values(item)[0]).join(',');
            ctx = { ...ctx, items, ids }

            actionbut()
          })
        }
      })
    } else actionbut()
  }

  const changeSelectedRow = (index = 0) => {
    setCrudState({ currentSelectedRow: index })
  }

  const bulkActionRender = (btn: ActionSchema, index: number) => {
    const { fullDataApi } = props;
    const ctx = store.mergedData;
    const selectedItems = getTableSelectedRowsData(store, tableStore);
    const unSelectedItems = store.unSelectedItems;
    const ids = selectedItems.map((item: any) =>
      item.hasOwnProperty(primaryField) ? item[primaryField as string] : null
    ).filter((item: any) => item).join(',');
    const btnDisabled = (btn.disabled ||
      (btn.requireSelected !== false ? (isMobile() && isObject((btn as any)?.api?.data) && Object.keys((btn as any)?.api?.data).includes('SELECTION_IDS') && selectedItems.length > 0 ? false : !selectedItems.length) : false))

    return render(
      `bulk-action/${index}`,
      {
        ...omit(btn, ['visibleOn', 'hiddenOn', 'disabledOn']),
        type: specialButtonType.includes(btn.type) ? btn.type : 'button',
        ignoreConfirm: true,
        hidden: false
      },
      {
        key: `bulk-${index}`,
        data: extendObject(store.data, { ...ctx, ids }),
        filterData: filterData,
        fullDataApi: fullDataApi,
        disabled: btnDisabled,
        onAction: (e: any, action: any) =>
          handleBulkAction(
            selectedItems.concat(),
            unSelectedItems.concat(),
            e,
            action,
            btn
          )
      }
    )
  }

  const handleSelect = (items: Array<any>, unSelectedItems: Array<any>) => {
    const {
      keepItemSelectionOnPageChange,
      multiple,
      pickerMode,
      onSelect
    } = props;

    let newItems = items;
    let newUnSelectedItems = unSelectedItems;

    if (keepItemSelectionOnPageChange && store.selectedItems.length) {
      const oldItems = store.selectedItems.concat();
      const oldUnselectedItems = store.unSelectedItems.concat();

      items.forEach(item => {
        const idx = findIndex(
          oldItems,
          a =>
            a === item ||
            (a[primaryField || 'id'] &&
              a[primaryField || 'id'] == item[primaryField || 'id'])
        );

        if (~idx) {
          oldItems[idx] = item;
        } else {
          oldItems.push(item);
        }

        const idx2 = findIndex(
          oldUnselectedItems,
          a =>
            a === item ||
            (a[primaryField || 'id'] &&
              a[primaryField || 'id'] == item[primaryField || 'id'])
        );

        if (~idx2) {
          oldUnselectedItems.splice(idx2, 1);
        }
      });

      unSelectedItems.forEach(item => {
        const idx = findIndex(
          oldUnselectedItems,
          a =>
            a === item ||
            (a[primaryField || 'id'] &&
              a[primaryField || 'id'] == item[primaryField || 'id'])
        );

        const idx2 = findIndex(
          oldItems,
          a =>
            a === item ||
            (a[primaryField || 'id'] &&
              a[primaryField || 'id'] == item[primaryField || 'id'])
        );

        if (~idx) {
          oldUnselectedItems[idx] = item;
        } else {
          oldUnselectedItems.push(item);
        }

        ~idx2 && oldItems.splice(idx2, 1);
      });

      newItems = oldItems;
      newUnSelectedItems = oldUnselectedItems;
    }

    if (pickerMode && multiple === false && newItems.length > 1) {
      newUnSelectedItems.push.apply(
        newUnSelectedItems,
        newItems.splice(0, newItems.length - 1)
      );
    }

    store.setSelectedItems(newItems);
    store.setUnSelectedItems(newUnSelectedItems);
    onSelect && onSelect(newItems);
  }

  const handleSave = (
    rows: Array<object> | object,
    diff: Array<object> | object,
    indexes: Array<string>,
    unModifiedItems?: Array<any>,
    rowsOrigin?: Array<object> | object,
    resetOnFailed?: boolean,
    shouldHideLoaing?: boolean
  ) => {
    const {
      quickSaveApi,
      quickSaveItemApi,
      env,
      messages,
      reload,
      quickReloadTarget,
      quickDataReload
    } = props;

    if (Array.isArray(rows)) {
      if (!isEffectiveApi(quickSaveApi)) {
        env && env.alert('CRUD quickSaveApi is required');
        return;
      }
      //书豪说这里改成mergedData
      const data: any = createObject(store.mergedData, {
        rows,
        rowsDiff: diff,
        indexes: indexes,
        rowsOrigin
      });

      if (Array.isArray(rows) && rows.length && rows[0].hasOwnProperty(primaryField || 'id')) {
        data.ids = rows
          .map(item => (item as any)[primaryField || 'id'])
          .join(',');
      }

      if (unModifiedItems) {
        data.unModifiedItems = unModifiedItems;
      }

      if (quickDataReload) store.markFetching(true)
      store
        .saveRemote(quickSaveApi, data, {
          shouldHideLoaing: shouldHideLoaing,
          successMessage: messages && messages.saveFailed,
          errorMessage: messages && messages.saveSuccess
        })
        .then(() => {
          if (quickDataReload) store.markFetching(false)
          reload && reloadTarget(reload, data);
          quickReloadTarget && reloadTarget(quickReloadTarget, data)
          if (quickDataReload) {
            search(undefined, undefined, true, true, afterSearchFn);
          } else {
            // 解除readonly限制
            const _items = JSON.parse(JSON.stringify(mode == 'cross' ? [...(tableStore?.data.items ?? [])] : [...store.data.items]))
            const _itemsRaw = JSON.parse(JSON.stringify(mode == 'cross' ? [...(tableStore?.data.items ?? [])] : [...store.data.itemsRaw]))

            // 增加映射 加快查找速度 防止极端情况下复杂度指数增长
            const _itemIdMap: Record<string, any> = {}
            mapTree(_items, (_) => _itemIdMap[_[DATAKEYID]] = _)
            const _itemRawIdMap: Record<string, any> = {}
            mapTree(_itemsRaw, (_) => _itemRawIdMap[_[DATAKEYID]] = _)
            if (data.rowsDiff.length) {
              for (const changeRows of data.rowsDiff) {
                const changeItem = _itemIdMap[changeRows.changeItemKey]
                const changeItemRaw = _itemRawIdMap[changeRows.changeItemKey]
                if (changeItem) Object.assign(changeItem, changeRows.diff)
                if (changeItemRaw) Object.assign(changeItemRaw, changeRows.diff)
              }
            }
            const newData = {
              ...store.data,
              items: _items,
              itemsRaw: _itemsRaw,
              dataSetId: uuidv4(), // 更新数据集id
            }
            if (props.openCache)
              store.updateCacheData(newData)
            mode == 'cross' ? tableStore?.reInitData(newData) : store.reInitData(newData)
            afterSearchFn()
          }
        })
        .catch((e) => {
          console.log(e)
          store.markFetching(false)
        });
    } else {
      if (!isEffectiveApi(quickSaveItemApi)) {
        env && env.alert('CRUD quickSaveItemApi is required!');
        return;
      }

      const data = createObject(store.data, {
        item: rows,
        modified: diff,
        origin: rowsOrigin
      });

      const sendData = createObject(data, rows);
      store.saveRemote(quickSaveItemApi, sendData, { shouldHideLoaing })
        .then(() => {
          reload && reloadTarget(reload, data);
          quickReloadTarget && reloadTarget(quickReloadTarget, data)
          search(undefined, undefined, true, true);
        })
        .catch(() => {
          resetOnFailed && control.reset();
        });
    }
  }

  return render(
    'body',
    {
      ...rest,
      foldColumns,
      columns: store.columns ?? columns,
      type: modes,
      setLoading: setLoading,
      tableLayout: computedTableLayout
    },
    {
      key: 'body',
      foldColumns,
      tipsHeader: header,
      tipsFooter: footer,
      className: cx('Crud-body', bodyClassName),
      ref: controlRef,
      autoGenerateFilter: !filter && autoGenerateFilter,
      autoFillHeight: autoFillHeight,
      selectable: computedSelectable,
      itemActions,
      multiple: computedMultiple,
      selected: computedSelected,
      keepItemSelectionOnPageChange,
      showIndex: showIndex,
      maxKeepItemSelectionLength,
      valueField: valueField || primaryField,
      primaryField: primaryField,
      hideQuickSaveBtn,
      items: store.data.items,
      itemsRaw: store.data.itemsRaw,
      query: store.query,
      orderBy: store.query.orderBy,
      orderDir: store.query.orderDir,
      popOverContainer,
      data: store.mergedData,
      loadHasMore: computedLoadHasMore,
      // Jay
      placeholder: computedPlaceholder,
      setChildStore: store.setChildStore,
      onAction: handleAction,
      onSave: handleSave,
      dataCheckRegist: dataCheckRegist,
      onSaveOrder: handleSaveOrder,
      onQuery: handleQuery,
      onSelect: handleSelect,
      onPopOverOpened: handleChildPopOverOpen,
      onPopOverClosed: handleChildPopOverClose,
      onSearchableFromReset: handleFilterReset,
      onSearchableFromSubmit: handleFilterSubmit,
      onSearchableFromInit: handleFilterInit,
      headerToolbarRender: renderHeaderToolbar,
      footerToolbarRender: renderFooterToolbar,
      crudRenderToolbarFunc: renderToolbar,
      bulkActionRender: bulkActionRender,
      markSort: markSort,
      filterRender: renderFilter,
      onLoadMore: handleLoadMore,
      handleResetData: handleResetData,
      saveColApi: saveColApi,
      crudName: name,
      columnInfo: columnInfo,
      setBorder: rest.setBorder,
      storeForAiTool: store,
      tableRotate,
      getTableStore: getTableStore,
      getTableInstance: getTableInstance,
      setLoading: setLoading,
      setTotal: setTotal,
      showColumnsFilter: showColumnsFilter,
      preSortAble: preSortAble,
      loading: store.loading,
      headerBulkActions: isMobile() ? computedUnitBulkActions : headerBulkActions,
      footerBulkActions,
      clearSelectedItems: clearSelectedItems, //清空用户选择
      handleTableRotate: handleTableRotate,
      handleClickOffline: handleClickOffline,
      offlineSchema,
      autoWidth: autoWidth,
      handleJump: handleJump,
      tabsdefer: tabsdefer,
      filterData: filtercont,
      changeSelectedRow: changeSelectedRow,
      getAllData: getAllData,
      currentSelectedRow: currentSelectedRow,
      renderAggregate: renderAggregate,
      afterSearchFn: afterSearchFn,
      headerCanShow: computedHeaderCanShow,
      crudRef: crudRef,
    }
  )
};
