import React from 'react';
import { Renderer, RendererProps } from '../factory';
import { SchemaNode, Schema, Action, PlainObject, Api } from '../types';
import { CRUDStore, DATAKEYID, ICRUDStore } from '../store/crud';
import {
  createObject,
  extendObject,
  anyChanged,
  isObjectShallowModified,
  isVisible,
  getPropValue,
  getVariable,
  qsstringify,
  qsparse,
  isArrayChildrenModified,
  // Aug
  isMobile,
  uuidv4,
  functionInOneFrame,
  uuid,
  numberFormatter,
  findTree
} from '../utils/helper';
import { ScopedContext, IScopedContext } from '../Scoped';
import Button from '../components/Button';
import getExprProperties from '../utils/filter-schema';
import pick from 'lodash/pick';
import isEqual from 'lodash/isEqual';
import { findDOMNode } from 'react-dom';
import { evalExpression, filter } from '../utils/tpl';
import { isEffectiveApi, isApiOutdated, str2function, buildApi, normalizeApi } from '../utils/api';
import omit from 'lodash/omit';
import find from 'lodash/find';
import findIndex from 'lodash/findIndex';
import Html from '../components/Html';
import { Spinner, toast } from '../components';
import { Icon } from '../components/icons';
import {
  BaseSchema,
  SchemaApi,
  SchemaClassName,
  SchemaCollection,
  SchemaExpression,
  SchemaMessage,
  SchemaName,
  SchemaObject,
  SchemaTokenizeableString,
  SchemaTpl
} from '../Schema';
import { ActionSchema } from './Action';
import { CardsSchema } from './Cards';
import { ListSchema } from './List';
import { TableRenderer, TableSchema } from './Table';
import { filterDate, isPureVariable, resolveVariableAndFilter } from '../utils/tpl-builtin';
// Jay
import { ModalPrint } from './Lion/LabelPrint';
import { templateDesign } from '../utils/print';
import { getLodop } from '../utils/print/LodopFuncs';
import { expressLabels } from './Lion/ExpressPrint/ExpressPrint';
import { message, Modal, Select as AntdSelect, Button as AntdButton, Spin, Progress, Input, Select, Popconfirm, Popover, Checkbox, Tag, Space } from 'antd';
import ActionSheet from '../components/Lion/ActionSheet';
import { isImg, getMediaIcon, getDiffRowData, downloadFile } from './Lion/utils/utils';
import { buildLabelTemplate } from '../utils/print/util';
import { makeTranslator, setDefaultLocale } from '../locale';
import { Shell } from '../utils/shell';
import { checkDuplicateKeys } from '../utils/utils';
import ScanOutlined from '@ant-design/icons/lib/icons/ScanOutlined';
import { unGzip, Gzip } from '../utils/gzip';
import { tools } from '../utils/shell/tools';
import LoadingOutlined from '@ant-design/icons/lib/icons/LoadingOutlined';
import { confirmWithThreeButtons } from '../components/Lion/BatchOperation';
import VirtualTable from '../components/VirtualTable';
import cloneDeep from 'lodash/cloneDeep';
import LionCopyItem from './Lion/components/LionCopyItem';
import { EventEnum, EventSub } from '../utils/sub';
import ModalFlow from '../components/Mobileprocess/Workflow';
import { eventStation, RuleTypes } from '../utils/shell/shell';
import { clone, debounce, difference, flatMap, isNil, isObject } from 'lodash';
import { SecondFilterDrawer } from '../components/table/SecondFilter/SecondFilterDrawer';
import { Drawer } from '../components/antdCompoentsProxy';
import TipsContanier from '../components/TipsContanier';
import { getLocalStorage, setLocalStorage } from '../utils/storage';
import DefaultListPopup from '../components/Lion/DefaultListPopup';
import { CheckOutlined, CloseOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons';
import FingerPrintModal from '../components/Lion/FingerprintModal';
import { IColumn, ITableStore } from '../store/table';
import { exportXLSX, exportXLSXFromCross } from '../utils/xlsx';
import AiTool from './Table/AiTool';
// import modalStore from '../components/DragModal/modalStore';
import { Provider } from 'mobx-react';
import tableCtxMenuStore from './Table/tableCtxMenuStore';
import { getHeadRows } from '../store/utils/commonTableFunction';
import { RFIDTrigeerCodeEnum, windowRFIDTriger } from '../utils/RfidUtil';
import { availableRanges, advancedRanges } from '../components/DateRangePicker';
import DatePicker, { availableShortcuts, advancedShortcuts, DatePicker } from '../components/DatePicker';
import moment from 'moment';

export type CRUDBultinToolbarType =
  | 'columns-toggler'
  | 'columns-filter'
  | 'auto-width'
  | 'drag-toggler'
  | 'pagination'
  | 'headerBulkActions'
  | 'footerBulkActions'
  | 'bulk-actions'
  | 'statistics'
  | 'switch-per-page'
  | 'load-more'
  | 'filter-toggler'
  | 'export-csv'
  | 'export-excel';

export interface CRUDBultinToolbar extends Omit<BaseSchema, 'type'> {
  type: CRUDBultinToolbarType;
}
interface CheckPictureType {
  addr: string;
  name: string;
  preview: string;
  thumbnailAddr?: string;
}
export type filterTpl = {
  value?: string;
  label?: string;
  name?: string;
  labelName?: string;
  valuesAlia?: string;
  keyName?: string;
  advancedFilterIndex?: number
};
export type CRUDToolbarChild = SchemaObject | CRUDBultinToolbar;

export type CRUDToolbarObject = {
  /**
   * 对齐方式
   */
  align?: 'left' | 'right';
};

// 不做处理的按钮类型
const specialButtonType = ['rfid-action']

export interface CRUDCommonSchema extends BaseSchema {
  /**
   *  指定为 CRUD 渲染器。
   */
  type: 'crud';

  /**
   * 指定内容区的展示模式。
   */
  mode?: 'table' | 'grid' | 'cards' | /* grid 的别名*/ 'list' | 'lion-bi-table' | 'cross';

  /**
   * 初始化数据 API
   */
  api?: SchemaApi;
  /**
   * 顶部批量操作
   */
  headerBulkActions?: Array<ActionSchema>;
  /**
   * 底部批量操作
   */
  footerBulkActions?: Array<ActionSchema>;
  /**
   * 单条操作
   */
  itemActions?: Array<ActionSchema>;

  /**
   * 每页个数，默认为 10，如果不是请设置。
   *
   * @default 10
   */
  perPage?: number;

  /**
   * 可以默认给定初始参数如： {\"perPage\": 24}
   */
  defaultParams?: PlainObject;

  /**
   * 是否可通过拖拽排序
   */
  draggable?: boolean;

  /**
   * 是否可通过拖拽排序，通过表达式来配置
   */
  draggableOn?: SchemaExpression;

  name?: SchemaName;
  // 页脚
  footer: any;
  /**
   * 过滤器表单
   */
  filter?: any; // todo

  /**
   * 初始是否拉取
   * @deprecated 建议用 api 的 sendOn 代替。
   */
  initFetch?: boolean;

  /**
   * 初始是否拉取，用表达式来配置。
   * @deprecated 建议用 api 的 sendOn 代替。
   */
  initFetchOn?: SchemaExpression;

  /**
   * 配置内部 DOM 的 className
   */
  innerClassName?: SchemaClassName;

  /**
   * 设置自动刷新时间
   */
  interval?: number;

  /**
   * 设置用来确定位置的字段名，设置后新的顺序将被赋值到该字段中。
   */
  orderField?: string;

  /**
   * 设置分页页码字段名。
   * @default page
   */
  pageField?: string;

  /**
   * 设置分页一页显示的多少条数据的字段名。
   * @default perPage
   */
  perPageField?: string;

  /**
   * 快速编辑后用来批量保存的 API
   */
  quickSaveApi?: SchemaApi;

  /**
   * 快速编辑配置成及时保存时使用的 API
   */
  quickSaveItemApi?: SchemaApi;

  /**
   * 保存排序的 api
   */
  saveOrderApi?: SchemaApi;

  /**
   * 是否将过滤条件的参数同步到地址栏,默认为true
   * @default true
   */
  syncLocation?: boolean;
  // 页眉
  header: any;
  /**
   * 顶部工具栏
   */
  headerToolbar?: Array<
    (CRUDToolbarChild & CRUDToolbarObject) | CRUDBultinToolbarType
  >;

  /**
   * 底部工具栏
   */
  footerToolbar?: Array<
    (CRUDToolbarChild & CRUDToolbarObject) | CRUDBultinToolbarType
  >;

  /**
   * 每页显示多少个空间成员的配置如： [10, 20, 50, 100]。
   */
  perPageAvailable?: Array<number>;

  messages?: SchemaMessage;

  /**
   * 是否隐藏快速编辑的按钮。
   */
  hideQuickSaveBtn?: boolean;

  /**
   * 是否自动跳顶部，当切分页的时候。
   */
  autoJumpToTopOnPagerChange?: boolean;

  /**
   * 静默拉取
   */
  silentPolling?: boolean;
  stopAutoRefreshWhen?: SchemaExpression;

  stopAutoRefreshWhenModalIsOpen?: boolean;
  filterTogglable?: boolean;
  filterDefaultVisible?: boolean;

  /**
   * 是否将接口返回的内容自动同步到地址栏，前提是开启了同步地址栏。
   */
  syncResponse2Query?: boolean;

  /**
   * 分页的时候是否保留用户选择。
   */
  keepItemSelectionOnPageChange?: boolean;

  /**
   * 当配置 keepItemSelectionOnPageChange 时有用，用来配置已勾选项的文案。
   */
  labelTpl?: SchemaTpl;

  /**
   * 是否为前端单次加载模式，可以用来实现前端分页。
   */
  loadDataOnce?: boolean;

  /**
   * 在开启loadDataOnce时，filter时是否去重新请求api
   */
  loadDataOnceFetchOnFilter?: boolean;

  /**
   * 也可以直接从环境变量中读取，但是不太推荐。
   */
  source?: SchemaTokenizeableString;

  /**
   * 如果时内嵌模式，可以通过这个来配置默认的展开选项。
   */
  expandConfig?: {
    /**
     * 默认是展开第一个、所有、还是都不展开。
     */
    expand?: 'first' | 'all' | 'none';

    /**
     * 是否显示全部切换按钮
     */
    expandAll?: boolean;

    /**
     * 是否为手风琴模式
     */
    accordion?: boolean;
  };

  /**
   * 默认只有当分页数大于 1 是才显示，如果总是想显示请配置。
   */
  alwaysShowPagination?: boolean;

  /**
   * 开启查询区域，会根据列元素的searchable属性值，自动生成查询条件表单
   */
  autoGenerateFilter?: boolean;

  /**
   * 内容区域占满屏幕剩余空间
   */
  autoFillHeight?: boolean;

  /**
   * 无限加载
   */
  infinteLoad?: boolean;

  /**
   * 行勾选禁用表达式
   */
  itemCheckableOn?: string

  primaryField: string;
  // Jay
  // 保存列配置接口
  saveColApi?: SchemaApi;
  columnInfo?: Record<string, { index: number; hidden: number }>; // 列排序、隐藏配置

  // chencicsy
  setBorder?: boolean;
  preSortAble?: boolean;
  advancedFilter: any;
  tableLayout?: 'vertical' | 'horizontal';

  aggregate?: SchemaObject;
  /**
   * 配置高级查询可查询字段
   */

  advancedQueryFields?: string;

  /**
   * 高级查询弹窗类型
   * normal: 默认不弹窗且显示所有查询
   * popup-normal: 默认弹窗且显示所有查询
   * condition: 默认不弹窗且只显示条件查询
   * popup-condition: 默认弹窗且只显示条件查询
   */
  advancedMode?: 'normal' | 'popup-normal' | 'condition' | 'popup-condition'
  /**
  * 配置批量按钮全量数据获取数据
  */
  fullDataApi?: SchemaApi;
  /**
  * 为当前表单添加排序
  */
  showIndex?: boolean;
  //离线报文
  offlineSchema: {
    actions: Array<ActionSchema>,
    columns: any[],
    source: SchemaApi,
    offlinePageType: 'table' | 'detail',
    actionLabel?: {
      dataLabel?: string;
      codeLabel?: string;
    }
  };
  /**
   * 表格总结行位置
   * 0显示再表格最后一行，1显示在左下角底部工具栏位置，2都显示
   */
  affixRowPosition?: 0 | 1 | 2;
}

type OfflineData = {
  offlineData: {
    items: obj[];
    total: number;
  };
  offlineZipResourceDown?: {
    url: string;
    method: string;
    requestParam?: obj;
  }
}

export type CRUDCardsSchema = CRUDCommonSchema & {
  mode: 'cards';
} & Omit<CardsSchema, 'type'>;

export type CRUDListSchema = CRUDCommonSchema & {
  mode: 'list';
} & Omit<ListSchema, 'type'>;

export type CRUDTableSchema = CRUDCommonSchema & {
  mode?: 'table';
} & Omit<TableSchema, 'type'>;

/**
 * CRUD 增删改查渲染器。
 * 文档：https://baidu.gitee.io/amis/docs/components/crud
 */
export type CRUDSchema = CRUDCardsSchema | CRUDListSchema | CRUDTableSchema;

export interface CRUDProps
  extends RendererProps,
  Omit<CRUDCommonSchema, 'type' | 'className'> {
  store: ICRUDStore;
  pickerMode?: boolean; // 选择模式，用做表单中的选择操作
  OnSelectedItems?: (items: any[]) => void;
  getTableInstance?: (tableInstance: any) => void;
  isStatic?: boolean;//是否是统计
}
interface CRUDState {
  autoWidth: boolean,
  printType: "html" | "label" | "bill" | "file" | 'report' | undefined,
  flowModalVisible: boolean
  fingerModalVisible: boolean
  showColumnsFilter: boolean
  filterDrawerVisible: boolean
  mobileFilterShow: boolean,
  hasFetch: boolean, // Jay 标记是否发送过请求
  ModalProps: any,
  filterData: obj,
  flowModalProps: obj,//流程数据传递下一层
  advancedFilterVisible: boolean,
  multipleDefault: string,
  defaultVisible: boolean,
  selectTmpShow: boolean,
  defaultList: any[]
  defaultTempKey: string,
  moreIsOpened: boolean, // Aug 更多操作面板,
  foldColumns: Array<string>, //折叠的操作列
  filtercont: obj, //获取高级查询中的数据，上层获取不到储存到这里
  filterOptions: obj, //只是文字写入，将上层数据导入到高级查询数据中
  filtertpl: Array<filterTpl>, //高级查询展示在form中的内容
  filterExist: boolean,//在移动端判断筛选按钮是否高亮判断基础查询是否有默认值，仅首次加载有效
  filData: obj,//body查询
  transferSubmission: obj, //储存表单送签信息
  tableRotate: boolean, //移动端表格横屏模式
  offline: boolean,  //是否离线
  offlineColumns: Array<obj>,//离线表格的列集
  offlineData: Array<obj>,//离线数据集
  offlineFormShow: boolean,//离线表格
  currentRow: obj | null,//当前行数据
  position: { x: number, y: number },//扫码按钮位置
  offlineLoading: boolean,//离线loading
  offlineTemplist: Array<string>,//离线脏数据
  offlineProgress: number,//离线进度条
  offlineStatus: boolean,//离线上传下载状态
  openModle: {
    open?: boolean,
    width?: string,
    openModleBody?: any,
    linkTitle?: string,
    bodydata?: any
  },
  codeVisible: boolean;
  codeValue: string;
  advancedFilterAction: boolean;//控制移动端查询条件当中的按钮展示
  formSwitch: boolean;//头部展示开关按钮
  templateSwitch: boolean;//新增模板开关按钮
  toolActionSwitch: boolean;//工具栏按钮开关按钮
  modes: 'table' | 'grid' | 'cards' | /* grid 的别名*/ 'list' | 'lion-bi-table' | 'cross';
  staticExportShow: boolean;//二次加工工具导出面板
  staticExportRange: '0' | '1' | '2';//二次加工工具导出范围
  keepDataFormat: '0' | '1';
}

export default class CRUD extends React.Component<CRUDProps, CRUDState> {
  static propsList: Array<keyof CRUDProps> = [
    'headerBulkActions',
    'footerBulkActions',
    'itemActions',
    'mode',
    'orderField',
    'syncLocation',
    'toolbar',
    'toolbarInline',
    'messages',
    'value',
    'options',
    'multiple',
    'valueField',
    'defaultParams',
    'bodyClassName',
    'perPageAvailable',
    'pageField',
    'perPageField',
    'hideQuickSaveBtn',
    'autoJumpToTopOnPagerChange',
    'interval',
    'silentPolling',
    'stopAutoRefreshWhen',
    'stopAutoRefreshWhenModalIsOpen',
    'api',
    'affixHeader',
    'columnsTogglable',
    'placeholder',
    'tableClassName',
    'headerClassName',
    'footerClassName',
    // 'toolbarClassName',
    'headerToolbar',
    'footerToolbar',
    'filterTogglable',
    'filterDefaultVisible',
    'autoGenerateFilter',
    'syncResponse2Query',
    'keepItemSelectionOnPageChange',
    'labelTpl',
    'labelField',
    'loadDataOnce',
    'loadDataOnceFetchOnFilter',
    'source',
    'header',
    'columns',
    'size',
    'onChange',
    'onInit',
    'onSaved',
    'onQuery',
    'formStore',
    'autoFillHeight',
    'preSortAble',
    'showIndex'
  ];
  static defaultProps = {
    toolbarInline: true,
    headerToolbar: ['headerBulkActions'], // Aug
    footerToolbar: [], // 初始化默认给空
    primaryField: 'id',
    syncLocation: true,
    pageField: 'page',
    perPageField: 'perPage',
    hideQuickSaveBtn: false,
    autoJumpToTopOnPagerChange: true,
    silentPolling: false,
    filterTogglable: false,
    filterDefaultVisible: true,
    loadDataOnce: false,
    loadDataOnceFetchOnFilter: true,
    autoFillHeight: true, // Aug 移动端让他自由滚动
    infinteLoad: isMobile(), // Aug 移动端默认启用滚动加载,
    setBorder: false,
    preSortAble: true,
    tableLayout: 'horizontal',
    showIndex: false
  };

  control: any;
  lastQuery: any;
  timer: ReturnType<typeof setTimeout>;
  mounted: boolean;
  // Jay
  pageSwitchRef: React.RefObject<HTMLDivElement>;
  dom: React.RefObject<any>;
  filterForm: any;
  advanceFilterForm: any;
  tableStore: ITableStore | null;
  tableInstance: any;
  sort = false;
  saveData = new Map<string, any[]>();
  startX = 0
  startY = 0
  //离线的原始数据，用于重置按钮
  originOfflineData = []
  offlineForm: React.RefObject<HTMLDivElement> = React.createRef();
  codeEvent: Function;//红外线扫码
  hash: string = '';
  filterDrawerOpened = false
  crudRef: React.RefObject<HTMLDivElement> | null = React.createRef();
  advancedMode: 'normal' | 'popup-normal' | 'condition' | 'popup-condition';
  fingerprintModalData = undefined
  hasToolBars = false //是否有工具栏判断

  constructor(props: CRUDProps) {
    super(props);
    this.state = {
      // 移动端默认为true 或者这个表格没有自动列宽这个属性的话 也默认使用true -- 即进来就自动适用自动列宽计算逻辑
      autoWidth: isMobile() ? true : getLocalStorage('autoWidthPage')?.[this.props.name || ''], // 自动过滤
      printType: undefined,
      flowModalVisible: false,
      fingerModalVisible: false,
      filterDrawerVisible: false,
      showColumnsFilter: false,
      mobileFilterShow: false,
      hasFetch: false, // Jay 标记是否发送过请求
      ModalProps: {
        show: false,
        onHide: null
      },
      filterData: {},
      flowModalProps: {},//流程数据传递下一层
      defaultVisible: false,
      selectTmpShow: false,
      defaultList: [],
      defaultTempKey: '',
      advancedFilterVisible: (!this.props.initFetch && (props.advancedMode === 'popup-normal' || props.advancedMode === 'popup-condition')) ? true : false,
      moreIsOpened: false, // Aug 更多操作面板,
      foldColumns: [], //折叠的操作列
      filtercont: {}, //获取高级查询中的数据，上层获取不到储存到这里
      filterOptions: {}, //只是文字写入，将上层数据导入到高级查询数据中
      multipleDefault: '',
      filtertpl: [], //高级查询展示在form中的内容
      filterExist: false,//在移动端判断筛选按钮是否高亮判断基础查询是否有默认值，仅首次加载有效
      filData: {},//body查询
      transferSubmission: {}, //储存表单送签信息
      tableRotate: false, //移动端表格横屏模式
      offline: false,  //是否离线
      offlineColumns: [],
      offlineData: [],
      offlineFormShow: false,
      currentRow: null,
      position: { x: document.body.clientWidth / 2 - 135, y: document.body.clientHeight - 200 },
      offlineLoading: false,
      offlineTemplist: [],
      offlineProgress: 0,
      offlineStatus: false,
      openModle: {
        open: false,
        width: '65rem',
        openModleBody: null,
        linkTitle: '',
        bodydata: null
      },
      codeVisible: false,
      codeValue: '',
      advancedFilterAction: false,
      formSwitch: false,
      templateSwitch: false,
      modes: props?.mode || 'table',
      toolActionSwitch: false,
      staticExportShow: false,
      staticExportRange: '0',
      keepDataFormat: '1'
    };
    this.advancedMode = props.advancedMode ?? 'normal'

    this.controlRef = this.controlRef.bind(this);
    this.handleFilterReset = this.handleFilterReset.bind(this);
    this.handleFilterSubmit = this.handleFilterSubmit.bind(this);
    this.handleFilterInit = this.handleFilterInit.bind(this);
    this.handleAction = this.handleAction.bind(this);
    this.handleBulkAction = this.handleBulkAction.bind(this);
    this.handleChangePage = this.handleChangePage.bind(this);
    this.handleFilterOptions = this.handleFilterOptions.bind(this);
    this.handleSaveData = this.handleSaveData.bind(this);
    this.handledelVisible = this.handledelVisible.bind(this);
    this.handleReset = this.handleReset.bind(this);
    this.handleBulkGo = this.handleBulkGo.bind(this);
    this.handleDialogConfirm = this.handleDialogConfirm.bind(this);
    this.handleDrawerConfirm = this.handleDrawerConfirm.bind(this);
    this.baseModalConfirm = this.baseModalConfirm.bind(this);
    this.handleDialogClose = this.handleDialogClose.bind(this);
    this.handleDrawerClose = this.handleDrawerClose.bind(this);
    this.handleBaseModalClose = this.handleBaseModalClose.bind(this);
    this.handleSave = this.handleSave.bind(this);
    this.handleSaveOrder = this.handleSaveOrder.bind(this);
    this.handleSelect = this.handleSelect.bind(this);
    this.handleChildPopOverOpen = this.handleChildPopOverOpen.bind(this);
    this.handleChildPopOverClose = this.handleChildPopOverClose.bind(this);
    this.search = this.search.bind(this);
    this.silentSearch = this.silentSearch.bind(this);
    this.afterSearchFn = this.afterSearchFn.bind(this);
    this.handleQuery = this.handleQuery.bind(this);
    this.setTotal = this.setTotal.bind(this)
    this.renderHeaderToolbar = this.renderHeaderToolbar.bind(this);
    this.renderFooterToolbar = this.renderFooterToolbar.bind(this);
    /** 将renderToolbar方法传递给子组件，提供给移动端工具渲染定义的工具 */
    this.renderToolbar = this.renderToolbar.bind(this);
    this.clearSelection = this.clearSelection.bind(this);
    //aug
    this.renderFilter = this.renderFilter.bind(this);
    // Jay
    this.pageSwitchRef = React.createRef();
    this.handleFilterAdvanced = this.handleFilterAdvanced.bind(this);
    this.hideAdvancedFilter = this.hideAdvancedFilter.bind(this);
    this.handleActionDisplay = this.handleActionDisplay.bind(this);
    this.getTableInstance = this.getTableInstance.bind(this);
    this.getFilterColumns = this.getFilterColumns.bind(this);
    // chencicsy 多列排序
    this.handleMutilSort = this.handleMutilSort.bind(this);
    this.handleColumnFilter = this.handleColumnFilter.bind(this)
    this.handleAdvanced = this.handleAdvanced.bind(this);
    // 高级查询默认值
    this.defaultAdvancedQuery = this.defaultAdvancedQuery.bind(this);
    this.renderAggregate = this.renderAggregate.bind(this)
    const {
      location,
      store,
      pageField,
      perPageField,
      syncLocation,
      loadDataOnce
    } = props;

    this.mounted = true;

    if (syncLocation && location && (location.query || location.search)) {
      store.updateQuery(
        qsparse(location.search.substring(1)),
        undefined,
        pageField,
        perPageField
      );
    } else if (syncLocation && !location && window.location.search) {
      store.updateQuery(
        qsparse(window.location.search.substring(1)) as object,
        undefined,
        pageField,
        perPageField
      );
    }

    this.props.store.setFilterTogglable(
      !!this.props.filterTogglable,
      this.props.filterDefaultVisible
    );

    // 如果有 api，data 里面先写个 空数组，面得继承外层的 items
    // 比如 crud 打开一个弹框，里面也是个 crud，默认一开始其实显示
    // 的是外层 crud 的数据，等接口回来后就会变成新的。
    // 加上这个就是为了解决这种情况
    if (this.props.api) {
      this.props.store.updateData({ items: [], itemsRaw: [], sortItemsRaw: [] });
    }

    if (this.props.isStatic) {
      this.props.store.initStaticData(this.props.data as any, { page: 1, perPage: this.props.perPage || 20 })
    }
  }
  getInitParam = () => {
    const { translate: __ } = this.props;
    let filterParam = {}
    this.props.filter.body.forEach((item: any) => {
      if (!isNil(item.value)) {
        const key = item.name.split('.')?.[1]
        const delimiter = item.delimiter || ','
        const format = item.inputFormat || item.format
        if (['input-date-range', 'input-datetime-range', 'input-time-range'].includes(item.type)) {
          let itemValue = item.value.includes(delimiter) ? item.value.split(delimiter)
            .map((val: string) => filterDate(val, undefined, format).format(format)
            ).join(delimiter) : item.value
          if (availableRanges[item.value]) {
            const range = availableRanges[item.value];
            const now = moment();
            const startDate = range.startDate(now.clone()).format(format);
            const endDate = range.endDate(now.clone()).format(format);
            itemValue = [startDate, endDate].join(delimiter);
          } else {
            // 通过正则尝试匹配
            for (let i = 0, len = advancedRanges.length; i < len; i++) {
              let value = advancedRanges[i];
              const m = value.regexp.exec(item.value);
              if (m) {
                const range = value.resolve.apply(item.value, [__, ...m]);
                const now = moment();
                const startDate = range.startDate(now.clone()).format(format);
                const endDate = range.endDate(now.clone()).format(format);
                itemValue = [startDate, endDate].join(delimiter);
              }
            }
          }
          filterParam = {
            ...filterParam,
            [key]: itemValue
          }
        } else if (['input-date', 'input-datetime', 'input-time', 'input-month', 'input-quarter', 'input-year'].includes(item.type)) {
          //实现时间点的解析
          let itemValue = item.value.includes(delimiter) ? item.value : filterDate(item.value, undefined, format).format(format);
          if (availableShortcuts[item.value]) {
            const value = availableShortcuts[item.value];
            const now = moment();
            itemValue = value.date(now).format(format);
          } else {
            for (let i = 0, len = advancedShortcuts.length; i < len; i++) {
              let value = advancedShortcuts[i];
              const m = value.regexp.exec(item.value);
              if (m) {
                const range = value.resolve.apply(item.value, [__, ...m]);
                const now = moment();
                itemValue = range.date(now).format(format);
              }
            }
          }
          filterParam = {
            ...filterParam,
            [key]: itemValue
          }
        } else {
          filterParam = {
            ...filterParam,
            [key]: item.value
          }
        }
      }
    })
    return filterParam
  }
  filterData = {};
  // 判断条件是否是个合法空值 如果是 空 的情况 默认是true 如果不是 则判断 是不是 undefined null ''
  advancefilterValueIsLegalEmptyValue = (item: any) => {
    return item.op !== 10 && (isNil(item.values) || item.values === '')
  }
  componentDidMount() {
    const store = this.props.store;
    const { useMobileUI, offlineSchema } = this.props;
    const mobileUI = isMobile() && useMobileUI;
    if (this.props.offlineSchema)
      windowRFIDTriger.addEventListener(RFIDTrigeerCodeEnum.TRIGGERCLICK, this.handleScanCode)

    this.hasToolBars = !!this.crudRef?.current?.querySelector("[class*='headToolbar']")
    // 判断是否在小弹窗中
    if (localStorage.getItem('g_user_lang') == 'en_US') {
      setDefaultLocale('en-US');
    } if (localStorage.getItem('g_user_lang') == 'zh_CN') {
      setDefaultLocale('zh-CN');
    }

    if (mobileUI && this.advanceFilterForm?.props?.store?.data) {
      const data = this.advanceFilterForm.props.store.data
      const existAdvancedFilter = Object.keys(data?.advancedFilter?.filter((item: any) => { if (this.advancefilterValueIsLegalEmptyValue(item)) { return false } return true }) || {}).length
      const existAdvancedHeader = Object.keys(data?.advancedHeader || {}).length
      const existFilterParam = Object.keys(data?.filterParam || {}).length
      const existAdvancedFilterSub = Object.keys(data?.advancedFilterSub || {}).length
      const exist = existAdvancedFilter + existAdvancedHeader + existFilterParam + existAdvancedFilterSub
      if (exist > 0) {
        this.setState({ filterExist: true, filtercont: data })
      }
    }

    if (this.props.perPage) {
      store.changePage(store.page, isMobile() ? (this.props.perPage < 20 ? 20 : this.props.perPage) : this.props.perPage);
    }

    if (!this.props.filter || (store.filterTogggable && !store.filterVisible)) {
      this.handleFilterInit({});
    } else if (mobileUI) {
      //解决移动端初始化没有携带普通查询的默认值
      if (this.props.advancedMode !== 'popup-normal' && this.props.advancedMode !== 'popup-condition') {
        this.handleFilterInit({ filterParam: this.getInitParam() }, undefined, true);
      } else {
        this.handleFilterInit({});
      }
    }

    let val: any;
    if (this.props.pickerMode && (val = getPropValue(this.props))) {
      store.setSelectedItems(val);
    }
    if (Shell.hasShell() && isMobile() && offlineSchema) {
      this.hash = window.location.hash.slice(1);
      this.codeEvent = eventStation.subscription<{ code: string; href: string }>(RuleTypes.ShellCode, ({ code, href }) => {
        if (this.hash == href) {
          this.scanCode(code)
        }
      })
      this.initOffline()
    }
    const tmp = localStorage.getItem('offlineTemplist')
    if (tmp) {
      const lastTmp = JSON.parse(tmp);
      !!lastTmp.length && this.setState({ offlineTemplist: lastTmp })
    }
    EventSub.on(EventEnum.DomPrint, (formName, cb) => {
      if (this.props.$path.includes('form')) {
        cb({ name: this.props.name, label: this.props.tabTitle ?? this.props.name, columns: this.tableStore?.filteredColumns ?? this.props.columns })
      }
    })
  }



  //记录当前选中行，以便再数据更新时向目标组件传送选中行的数据
  currentSelectedRow = 0;
  changeSelectedRow = (index = 0) => {
    this.currentSelectedRow = index
  }

  componentDidUpdate(prevProps: CRUDProps, prevState: CRUDState) {
    const props = this.props;
    const store = prevProps.store;
    this.filterData = store.filterData;
    if (
      anyChanged(
        [
          'toolbar',
          'headerToolbar',
          'footerToolbar',
          'headerBulkActions',
          'footerBulkActions'
        ],
        prevProps,
        props
      )
    ) {
      // 来点参数变化。
      this.renderHeaderToolbar = this.renderHeaderToolbar.bind(this);
      this.renderFooterToolbar = this.renderFooterToolbar.bind(this);
    }
    if (anyChanged(['data'], prevProps, props) && props.itemAction) {
      //itemAction中的某个字段在当前表格中不存在，会被赋值为undefined传到目标组件，导致目标组件获取不到该字段
      const queryParam = createObject(props.data, props.store.query, {}, true);
      const TableData = this.getTableRowsData()
      const ctx = createObject(queryParam, TableData?.[this.currentSelectedRow] || TableData?.[0], {}, true);
      props.itemAction &&
        props.data?.items.length &&
        setTimeout(() => this.handleAction(
          undefined,
          props.itemAction,
          ctx,
          undefined,
          undefined,
          true
        ), 50);
    }

    let val: any;
    if (
      this.props.pickerMode &&
      isArrayChildrenModified(
        (val = getPropValue(this.props)),
        getPropValue(prevProps)
      )
    ) {
      store.setSelectedItems(val);
    }

    if (this.props.filterTogglable !== prevProps.filterTogglable) {
      store.setFilterTogglable(
        !!props.filterTogglable,
        props.filterDefaultVisible
      );
    }

    let dataInvalid = false;

    if (
      prevProps.syncLocation &&
      prevProps.location &&
      prevProps.location.search !== props.location.search
    ) {
      // 同步地址栏，那么直接检测 query 是否变了，变了就重新拉数据
      store.updateQuery(
        qsparse(props.location.search.substring(1)),
        undefined,
        props.pageField,
        props.perPageField
      );
      dataInvalid = !!(
        props.api && isObjectShallowModified(store.query, this.lastQuery, false)
      );
    }

    if (dataInvalid) {
      // 要同步数据
    } else if (
      prevProps.api &&
      props.api &&
      isApiOutdated(
        prevProps.api,
        props.api,
        store.fetchCtxOf(prevProps.data, {
          pageField: prevProps.pageField,
          perPageField: prevProps.perPageField
        }),
        store.fetchCtxOf(props.data, {
          pageField: props.pageField,
          perPageField: props.perPageField
        })
      )
    ) {
      dataInvalid = true;
    } else if (!props.api && isPureVariable(props.source)) {
      const prev = resolveVariableAndFilter(
        prevProps.source,
        prevProps.data,
        '| raw'
      );
      const next = resolveVariableAndFilter(props.source, props.data, '| raw');

      if (prev !== next) {
        store.initFromScope(props.data, props.source);
      }
    }

    if (dataInvalid && !this.sort) {
      this.search();
    }
    this.sort = false;
    if (prevState.offlineLoading !== this.state.offlineLoading && !this.state.offlineLoading) {
      this.setState({ offlineProgress: 0, offlineStatus: false })
    }
    if (this.state.offlineTemplist !== prevState.offlineTemplist) {
      //存到本地以便下次进入时恢复临时数据
      localStorage.setItem('offlineTemplist', JSON.stringify(this.state.offlineTemplist))
    }
  }

  //获取全量数据，用于统计
  getAllData = async () => {
    const { api, env } = this.props;
    let allData: object | null = {};
    if (api) {
      let params = {};
      if (Object.keys(this.state.filtercont || {}).length) {
        params = {
          advancedFilter: this.state.filtercont?.advancedFilter?.filter((item: any) => {
            if (this.advancefilterValueIsLegalEmptyValue(item)) {
              return false
            }
            return true
          }),
          advancedHeader: this.state.filtercont?.advancedHeader,
          advancedFilterSub: this.state.filtercont?.advancedFilterSub,
          optionsParam: this.state.filtercont?.optionsParam,
          filterParam: this.state.filtercont?.filterParam
        }
        if (this.state.filtercont?.filterOptionData) {
          const { optionsParam } = this.state.filtercont?.filterOptionData;
          params = {
            ...params,
            ...optionsParam
          }
        }
      }
      const paramsData = {
        ...params,
        index: 1,
        filterParam: this.props.store.query?.filterParam,
        topN: this.state.filtercont?.limitParam?.limitStatus ? this.state.filtercont?.limitParam?.topN : undefined
      }
      const res = await env.fetcher(api, createObject(this.props.data, paramsData))
      if (res.ok && res.data) {
        allData = res.data
      } else {
        allData = null
        message.error(res.msg)
      }
      return allData
    }
    return allData
  }

  dealCellValue = (originValue: any, columnName: string) => {
    const { columns } = this.props;
    const keepFormat = this.state.keepDataFormat === '1'
    let value = originValue
    const column = columns.find((column: any) => column.name === columnName)
    const prefix = column.prefix ?? column?.pristine?.prefix ?? ''
    const suffix = column.suffix ?? column?.pristine?.suffix ?? ''
    if (column?.type === 'mapping') {
      value = column?.map?.[originValue] ?? (originValue ?? '')
    } else if (column?.type === 'number' && keepFormat) {
      const kilobitSeparator = column.kilobitSeparator ?? column?.pristine?.kilobitSeparator ?? false
      const precision = column.precision ?? column?.pristine?.precision
      if (kilobitSeparator && originValue != null) {
        value = numberFormatter(originValue, precision)
      }
    } else if (column?.type === 'number' && !keepFormat) {
      value = isNil(originValue) ? originValue : value / 100
    }
    if (value != null) {
      return typeof value == 'object' ? '[文件]' : `${keepFormat ? prefix : ''}${typeof value == 'string' ? value.replaceAll('\n', '').replaceAll('\r', '') : value}${keepFormat ? suffix : ''}`
    }
    return ''
  }
  //导出统计数据
  handleExportStatic = () => {
    const { columns, data } = this.props;
    const { staticExportRange } = this.state;
    let selItems = [];
    if (staticExportRange === '1') {
      selItems = this.getTableSelectedRowsData()
      if (!selItems || selItems.length == 0) {
        message.warn('选中数据为空')
        return;
      }
    }
    const cols = columns.map((item: any) => item.label);
    const excelData = (staticExportRange === '0' ? data.items :
      staticExportRange === '1' ? selItems :
        data.itemsRaw).map((row: any) => columns.map((item: any) => this.dealCellValue(row[item.name], item.name)));
    exportXLSX(cols, excelData, `${this.props.aliasTitle?.trim?.() || '统计'}.xlsx`)
  }

  handleExportCross = () => {
    const { staticExportRange } = this.state
    const tableHeadRows = this.tableStore!.tableHeadRows.map(row => row.filter(item => item.name != 'SF_CHECK' && item.name != 'SF_PSEUDO'))
    const columns = this.tableStore!.filteredColumns.filter(item => item.type !== '__checkme' && item.type != '__pseudoColumn')
    const excelData = flatMap(this.tableStore!.rows ?? [], (row: any) => {
      if (staticExportRange == '1') {
        return row.checked ? row.data : []
      }
      return row.data
    })
    exportXLSXFromCross(tableHeadRows, columns, excelData, `${this.props.aliasTitle?.trim?.() || '交叉制表'}.xlsx`, this.state.keepDataFormat === '1')
  }

  // 判断元素是否在小型弹窗里
  inSmallDialog = () => {
    return !!this.crudRef?.current?.closest('div[role="dialog"]')?.className.includes('Modal--sm')
  }


  markSort = () => {
    this.sort = true;
  };

  componentWillUnmount() {
    this.mounted = false;
    if (this.props.offlineSchema)
      windowRFIDTriger.removeEventListener(RFIDTrigeerCodeEnum.TRIGGERCLICK, this.handleScanCode)
    this.quickEditDataCheck = () => null // 重置 防止发生相互引用
    this.crudRef = null
    this.tableStore = null
    delete this.tableInstance
    delete this.filterForm
    // 清空子store  清空缓存数据
    this.props.store.clearChildStore()
    this.props.store.clearCacheData()
    this.codeEvent?.()
    clearTimeout(this.timer);
    EventSub.off(EventEnum.DomPrint)
  }

  controlRef(control: any) {
    // 因为 control 有可能被 n 层 hoc 包裹。
    while (control && control.getWrappedInstance) {
      control = control.getWrappedInstance();
    }

    this.control = control;
  }

  handleAction(
    e: React.UIEvent<any> | undefined,
    action: Action,
    ctx: any,
    throwErrors: boolean = false,
    delegate?: IScopedContext,
    isItemAction: boolean = false
  ): any {
    const {
      onAction,
      store,
      messages,
      pickerMode,
      env,
      pageField,
      stopAutoRefreshWhenModalIsOpen,
      columns,
      data
    } = this.props;
    if (this.tableInstance?.props?.store.modified > 0 && !isItemAction) {
      this.showModal();
      return;
    }

    if (['dialog', 'drawer'].includes(action.actionType || '')) {
      const replace: any = {}
      store.setCurrentAction(action);
      const idx: number = (ctx as any)?.index;
      const tableRows = this.getTableRowsData()
      const length = tableRows.length;
      stopAutoRefreshWhenModalIsOpen && clearTimeout(this.timer);
      const openContanierFunction = ({
        'dialog': store.openDialog,
        'drawer': store.openDrawer,
      })[action.actionType as any]

      openContanierFunction(ctx, {
        hasNext: idx < length - 1,
        nextIndex: idx + 1,
        hasPrev: idx > 0,
        prevIndex: idx - 1,
        index: idx
      });
      const ctxId = tableRows?.findIndex((item: any) => isEqual(item, ctx))
      replace.current = ctx
      if (ctxId == 0) {
        replace.next = tableRows[ctxId + 1]
        replace.revious = undefined
      } else if (ctxId == length) {
        replace.revious = tableRows[ctxId - 1]
        replace.revious = undefined
      } else {
        replace.revious = tableRows[ctxId - 1]
        replace.next = tableRows[ctxId + 1]
      }
      if (!isEqual(replace, store.replace) && Object.keys(replace).length) {
        store.replaceDialog(replace)
      }

    } else if (action.actionType === 'advanced-filter') {
      this.handleFilterAdvanced()
    } else if (action.actionType === 'ajax') {
      store.setCurrentAction(action);
      const data = ctx;
      // 由于 ajax 一段时间后再弹出，肯定被浏览器给阻止掉的，所以提前弹。
      const redirect = action.redirect && filter(action.redirect, data);
      redirect && action.blank && env.jumpTo(redirect, action);

      return store
        .saveRemote(action.api!, data, {
          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);

          // Jay 菜鸟预览 预览按钮是放在操作列，actionType 为 'ajax'，根据状态码判断
          if ((data as any)?.status === 20002) {
            expressLabels(data as any, env.fetcher, this.props.translate);
            if (!action.redirect && !action.reload && !action.close) return;
          }

          if (action.feedback && isVisible(action.feedback, data)) {
            await this.openFeedback(action.feedback, data);
            stopAutoRefreshWhenModalIsOpen && clearTimeout(this.timer);
          }
          const redirect = action.redirect && filter(action.redirect, data);
          redirect && !action.blank && env.jumpTo(redirect, action);
          action.reload
            ? this.reloadTarget(action.reload, data)
            : redirect
              ? null
              : this.search(undefined, undefined, true, true, this.afterSearchFn);
          action.close && this.closeTarget(action.close);
          return null;
        })
        .catch(() => { });
    } else if (
      pickerMode &&
      (action.actionType === 'confirm' || action.actionType === 'submit')
    ) {
      store.setCurrentAction(action);
      return Promise.resolve({ items: store.selectedItems.concat() });
    } else if (action.onClick) {
      store.setCurrentAction(action);
      let onClick = action.onClick;
      if (typeof onClick === 'string') {
        onClick = str2function(onClick, 'event', 'props', 'data');
      }
      onClick && onClick(e, this.props, ctx);
    } else if (action.actionType === 'label-design') {
      templateDesign(ctx, value => {
        Modal.confirm({
          title: '确认提交该模板吗？',
          okText: '确认',
          cancelText: '取消',
          getContainer: env.getModalContainer,
          onOk: () => {
            if (action.api) {
              const labelTemplate = buildLabelTemplate(value);
              const tableFields = labelTemplate.labelTables
                .map(table => table.fieldName ?? '')
                .join(',');
              env
                .fetcher(action.api, {
                  tableFields,
                  tempId: ctx.TEMP_ID,
                  content: value
                })
                .then(res => {
                  if (res.status === 0) {
                    message.success(res.msg);
                    // 重新获取数据列表
                    this.search(undefined, undefined, true, true);
                  } else {
                    message.error(res.msg);
                  }
                });
            }
          }
        });
      });
    } else if (action.actionType === 'register-finger') {
      if (Object.keys(ctx).includes('USERID')) {
        this.fingerprintModalData = ctx
        this.setState({ fingerModalVisible: true })
      } else {
        message.error('数据出错，无法获取USERID')
      }
    } else if (action.actionType === 'export') {
      if (this.props.isStatic || this.props.mode === 'lion-bi-table' || this.props.mode === 'cross') {
        this.setState({ staticExportShow: true });
        return;
      }
      store.setCurrentAction(action);
      let exportData: any = {};
      let _ids: string = '';
      let _selectedItems: any[] = this.getTableSelectedRowsData()

      const optionsParam = this.state.filtercont?.filterOptionData?.optionsParam

      const advancedFilter = this.state.filtercont?.advancedFilter?.filter((item: any) => {
        if (this.advancefilterValueIsLegalEmptyValue(item)) {
          return false
        }
        return true
      });
      const advancedHeader = this.state.filtercont?.advancedHeader;
      const advancedFilterSub = this.state.filtercont?.advancedFilterSub;

      _selectedItems.map((_select: any) => {
        _ids += _select.hasOwnProperty(this.props.primaryField)
          ? _select[this.props.primaryField] + ','
          : '';
      });

      exportData = { ...exportData, ...this.props?.store?.query, pageId: this.props.name };
      exportData.selectedItems = _selectedItems;
      exportData.primaryField = this.props.primaryField;
      exportData.ids = _ids.slice(0, _ids.length - 1);
      exportData.tempIds = ctx[this.props.primaryField as any]
      if (this.state.filtercont?.limitParam?.limitStatus === true) {
        exportData.topN = this.state.filtercont?.limitParam?.topN
      }
      if (!this.itemActionData) {
        exportData.optionsParam = optionsParam
        exportData.advancedFilter = advancedFilter
        exportData.advancedHeader = advancedHeader
        exportData.advancedFilterSub = advancedFilterSub
      }
      const exportSetColumnFields: string[] = [];
      this.tableInstance?.sortCols.forEach((col: any) => {
        if (!col?.hidden && col.name) {
          exportSetColumnFields.push(col.name);
        }
      });
      exportData.exportSetColumnFields = exportSetColumnFields;
      const orderBy = this.tableStore?.orderColumnsParam();
      orderBy && (exportData.orderBy = orderBy);
      store.openLionExport(
        this.itemActionData ? createObject(this.itemActionData, { ...exportData, ...ctx, handleExportDefault: this.handleExportDefault }, {}, true) : { ...exportData, ...ctx, handleExportDefault: this.handleExportDefault },
        env,
        undefined,
        isReload => {
          if (isReload) {
            action.reload && this.reloadTarget(action.reload, {});
          }
        }
      );
      return false;
    } else if (action.actionType === 'loginAmazon') {
      store.setCurrentAction(action);
      store.openAmazonLoginPage(ctx, env);
    } else if (
      action.actionType === 'label-print' ||
      action.actionType === 'bill-print' ||
      action.actionType === 'report-print'
    ) {
      // Jay
      store.setCurrentAction(action);
      const { primaryField } = this.props;
      const { translate: __ } = this.props;
      const LODOP = getLodop();
      const ids = this.getTableSelectedRowsData().map(item => item.hasOwnProperty(primaryField) ? item[primaryField as string] : null).filter(item => item).join(',');
      if (LODOP) {
        this.setState({
          ModalProps: {
            ...action,
            show: true,
            ctx: { ...ctx.__super, ...ctx, primaryField, ids },
            onHide: () => {
              this.setState({ printType: undefined });
            }
          },
          printType: action.actionType.slice(0, action.actionType.indexOf('-')) as any
        });
      }
    } else if (action.actionType === 'bpm_detail') {
      if (action.api) {
        this.setState({ flowModalVisible: true });
        env.fetcher(action.api, ctx).then(res => {
          if (res.status === 0) {
            this.setState({ flowModalProps: { flowDetail: res.data, ctx } })
          } else {
            message.error(res.msg);
            this.setState({ flowModalVisible: false });
          }
        });
      }
    } else if (action.actionType === 'batch-image-view') {
      // Aug 批量查看图片
      const { onImageEnlarge } = this.props;
      if (!onImageEnlarge) return;
      if (!isMobile()) {
        onImageEnlarge({
          src: '',
          originalSrc: '',
          index: 0,
          list: []
        });
      }
      store.setCurrentAction(action);
      store
        .saveRemote(action.api as string, ctx, {
          errorMessage:
            (action.messages && action.messages.failed) ||
            (messages && messages.saveSuccess)
        })
        .then(async res => {
          const { onImageEnlarge } = this.props;
          const baseURL =
            env?.axiosInstance?.defaults?.baseURL || env?.ajaxApi || '';
          let prints: CheckPictureType[] = [];
          res.prints.forEach((item: CheckPictureType) => {
            if (item.thumbnailAddr) {
              prints.push(item);
            }
          });
          this.openImageEnlarge(prints, baseURL, onImageEnlarge);
          // this.imageViewData()
        })
        .catch(() => { });
    } else if (action.actionType?.includes('scale')) {
      const { foldColumns } = this.state;
      if (foldColumns?.includes(action.actionType)) {
        let newFoldCols = foldColumns?.filter(
          (col: string) => col != action.actionType
        );
        this.setState({ foldColumns: newFoldCols });
      } else {
        this.setState({ foldColumns: [...foldColumns, action.actionType] });
      }
    }
    else {
      // 这个就是刷新对应action的方法
      onAction(e, action, ctx, throwErrors, delegate || this.context, this.props.name, isItemAction);
    }
  }

  /**
    * 
    * @param keepDataFormat 保留格式
    * @param isTemplate 导出方式
    */
  handleExportDefault = (keepDataFormat: boolean, exportType: 'column' | 'template', exportFields?: string[]) => {
    let tableHeadRows = this.tableStore!.tableHeadRows.map(row => row.filter(item => item.column.type !== 'lion-upload' && item.name != 'SF_CHECK' && item.name != 'SF_PSEUDO' && item.name !== 'operation'))
    let columns = this.tableStore!.filteredColumns.filter(item => item.type !== 'lion-upload' && item.type !== '__checkme' && item.type != '__pseudoColumn' && item.name !== 'operation')
    if (exportType === 'template' && exportFields?.length) {
      let exportCols: IColumn[] = [];
      const cols = this.tableStore?.columns;
      exportFields.forEach(item => {
        const targetItem = cols?.find(col => col.name === item);
        if (targetItem) exportCols.push(targetItem)
      })
      tableHeadRows = getHeadRows(exportCols).map(row => {
        return row.filter(item => item.column.type !== 'lion-upload' && item.name != 'SF_CHECK' && item.name != 'SF_PSEUDO' && item.name !== 'operation' && item.name && exportFields.includes(item.name))
      })
      columns = exportCols.filter(item => item.type !== 'lion-upload' && item.type !== '__checkme' && item.type != '__pseudoColumn' && item.name !== 'operation' && item.name && exportFields.includes(item.name))
    }
    const excelData: obj[] = [];
    (this.tableStore!.rows ?? []).forEach((row: obj) => {
      if (row.checked) excelData.push(row.data)
    })
    exportXLSXFromCross(tableHeadRows, columns, excelData, `${this.props.aliasTitle?.trim?.() || '导出'}.xlsx`, keepDataFormat)
  }

  handleJump = (body: any) => {
    if (body.redirectType === '2') {
      this.props.env.fetcher(body.linkUrl, body.bodydata).then(res => {
        if (res.ok && res.data != null) {
          this.setState({ flowModalProps: { flowDetail: res.data }, 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,
      size: body.linkSize ?? 'lg',
      bodyClassName: `overflow-y-auto max-h-nestSide-${types}`,
      className: "h-full",
      actions: [],
      overlay: isMobile() ? false : true,
      body: {
        schemaApi: {
          "method": "get",
          "url": body.linkUrl
        },
        type: "service"
      }
    }
    this.handleAction(this.props.e, action, body.bodydata)
  }
  // 打开预览组件
  openImageEnlarge(data: Array<any>, baseURL: string, onImageEnlarge: any) {
    let isNotImg = false;
    let list: any = data.map((item: any) => {
      isNotImg = !isImg(item.name);
      return {
        src: isNotImg
          ? getMediaIcon(item.name)
          : baseURL + (item.thumbnailAddr || item?.addr),
        originalSrc: baseURL + item.preview,
        downloadSrc: baseURL + item?.addr,
        title: item.name || '',
        isNotImg
      };
    });
    if (isMobile()) {
      if (Shell.hasShell()) {
        if (tools.isAndroid) {
          Shell.previewFile({ urls: list.map((val: any) => { return val.originalSrc }) })
        } else {
          const urls = list.map((attachment: any) => {
            const url = new URL(encodeURI(attachment.originalSrc))
            const search = url.search == '' ? `?fileName=${Date.now() + attachment.title}` : `${url.search}&fileName=${Date.now() + attachment.title}`
            url.search = search
            return url.href
          })
          Shell.previewFile({ urls, current: 0 })
        }
        return
      } else if (this.props?.env?.previewImagesMb) {
        const urls = list.map((val: any) => { return val.originalSrc })
        this.props.env.previewImagesMb(urls, 0)
        return
      }

    }
    onImageEnlarge &&
      onImageEnlarge({
        src: list[0].src,
        originalSrc: list[0].originalSrc,
        index: 0,
        list
      });
  }
  extractFilenameFromContentDisposition(contentDisposition: any) {
    const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
    const matches = contentDisposition.match(filenameRegex);
    if (matches && matches.length > 1) {
      return decodeURIComponent(matches[1].replace(/['"]/g, ''))// 去除可能的引号
    }
    return null;
  }

  handleBulkAction(
    selectedItems: Array<any>,
    unSelectedItems: Array<any>,
    e: React.UIEvent<any>,
    action: Action,
    btn?: any
  ) {
    const {
      store,
      primaryField,
      onAction,
      messages,
      pageField,
      stopAutoRefreshWhenModalIsOpen,
      env,
      fullDataApi,
      translate: __
    } = this.props;
    if (this.tableInstance.props.store.modified > 0) {
      this.showModal();
      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 this.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 this.openFeedback(action.feedback, data);
                stopAutoRefreshWhenModalIsOpen && clearTimeout(this.timer);
              }

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

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

              const redirect = action.redirect && filter(action.redirect, data);
              redirect && env.jumpTo(redirect, action);
            })
            .catch(() => null);
      }
      // else if (onAction) {
      //   onAction(e, action, ctx, false, this.context);
      // }
      // Aug
      else {
        this.handleAction(e, action, ctx, false, this.context);
      }
      return undefined;
    };
    const actionbut = async () => {
      if (btn && btn?.openFullSelect && btn?.confirmApi) {
        const data = createObject(this.props.data, {
          ...this.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 = {
            ...this.state.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()
  }
  // 表格数据获取统一规范一下
  getTableRowsData = () => {
    return this.tableStore?.rows.map(row => row.data) || this.props.store.data.items || []
  }

  getTableSelectedRowsData = () => {
    return this.tableStore?.selectedRows.map(row => row.data) || this.props.store.selectedItems.concat() || []
  }
  handleItemAction(action: Action, ctx: any) {
    this.doAction(action, ctx);
  }

  async handleFilterInit(values: object, isChild: boolean = false, init?: boolean) {
    const { defaultParams, data, store } = this.props;
    if (this.props?.advancedFilterApi) {
      await this.defaultAdvancedQuery(1)
    }
    this.handleFilterSubmit(
      {
        ...defaultParams,
        ...values,
        ...store.query
      },
      false,
      true,
      this.props.initFetch !== false,
      isChild,
      init
    );

    store.setPristineQuery();

    const { pickerMode, options } = this.props;

    pickerMode &&
      store.updateData({
        items: options || []
      });
  }

  handleFilterReset(values: object, action: any) {
    const { store, syncLocation, env, pageField, perPageField } = this.props;
    store.updateQuery(
      store.pristineQuery,
      syncLocation && env && env.updateLocation
        ? (location: any) => env.updateLocation(location)
        : undefined,
      pageField,
      perPageField,
      true
    );
    this.lastQuery = store.query;
    if (action.type == "reset") {
      return;
    }

    this.search();
  }

  // 上拉加载更多数据
  lionPullRequest = (values: object, init?: boolean): Promise<any> => {
    return new Promise((resolve, reject) => {
      const { defaultParams, data, store } = this.props;

      const { syncLocation, pageField, perPageField } = this.props;

      values = syncLocation
        ? qsparse(
          qsstringify(
            {
              ...defaultParams,
              ...values,
              ...store.query
            },
            undefined,
            true
          )
        )
        : values;

      store.changePage(init ? store.page : store.page + 1, isMobile() ? ((this.props?.perPage ?? 10) < 20 ? 20 : this.props.perPage) : this.props.perPage);

      store.updateQuery(
        {
          ...values,
          [pageField || 'page']: store.page
        },
        undefined,
        pageField,
        perPageField
      );
      this.search(
        { page: store.page, loadDataMode: 'load-more' },
        undefined,
        false,
        undefined,
        resolve,
        reject
      );

      store.setPristineQuery();
    });
  };

  handleLoadMore = () => {
    // if (!this.props.loadDataOnce) {
    this.search({ page: this.props.store.page + 1, loadDataMode: 'load-more' })
    // }
  }
  //移动端刷新或查询时需要滚动到顶部，不然会逐页请求数据
  handleScrollToTop = () => {
    if (isMobile()) {
      const { classPrefix } = this.props;
      const crud = findDOMNode(this) as HTMLElement;
      const container = crud.querySelector(
        `.${classPrefix}Table-content`
      ) as HTMLElement;
      if (container) {
        container.scrollTo({ top: 0 })
      }
      const Listitems = crud.querySelector(
        `.${classPrefix}List-items`
      ) as HTMLElement;
      if (Listitems) {
        Listitems.scrollTo({ top: 0 })
      }
    }
  }
  //刷新数据，带查询条件
  handleResetData = () => {
    this.handleScrollToTop();
    this.search({ page: 1 });
  }

  handleFilterSubmit(
    values: object,
    jumpToFirstPage: boolean = true,
    replaceLocation: boolean = false,
    search: boolean = true,
    isChild?: boolean,
    init?: boolean
  ) {
    const {
      store,
      syncLocation,
      env,
      pageField,
      perPageField,
      loadDataOnceFetchOnFilter
    } = this.props;
    values = syncLocation
      ? qsparse(qsstringify(values, undefined, true))
      : values;

    store.updateQuery(
      {
        ...values,
        [pageField || 'page']: jumpToFirstPage ? 1 : store.page
      },
      syncLocation && env && env.updateLocation
        ? (location: any) => env.updateLocation(location, replaceLocation)
        : undefined,
      pageField,
      perPageField
    );
    this.lastQuery = store.query;
    search &&
      this.search(
        undefined,
        undefined,
        undefined,
        loadDataOnceFetchOnFilter,
        this.afterSearchFn,
        undefined,
        isChild,
        undefined,
        init
      );
  }

  // 点击高级查询按钮
  handleFilterAdvanced() {
    if (!isMobile() && !this.props?.advancedFilter?.body?.some((item: any) => item?.body)) {
      message.error("暂无查询条件")
      return
    }
    this.setState({ advancedFilterVisible: true });
  }
  hideAdvancedFilter() {
    this.setState({ advancedFilterVisible: false });
  }
  handleActionDisplay(val: string) {
    switch (val) {
      case '0':
        this.setState({ advancedFilterAction: false });
        break;
      case '1':
      case '2':
        this.setState({ advancedFilterAction: true });
        break;
      default:
        break;
    }
  }

  // 获取普同查寻的数据
  handleFilterOptions(value: any) {
    this.setState({ filterOptions: value });
  }
  handleSaveData(val: string, cont: any[]) {
    if (val.includes('advancedFilter')) {
      const name = val.split('.')
      if (name[name.length - 1].includes('--')) {
        if (!!this.saveData.set(name[name.length - 1].split('--')[0], cont)) {
          this.saveData.set(name[name.length - 1].split('--')[0], cont);
        }
      } else
        this.saveData.set(name[name.length - 1], cont);
    } else {
      this.saveData.set(val, cont);
    }
  }

  // 查询1
  // selectApi
  // 修改2
  // modifyApi
  // 删除3
  // deleteApi
  async defaultAdvancedQuery(val = 1 | 2 | 3, body?: any, senior?: boolean) {
    const { env, advancedFilterApi: { selectApi, modifyApi, deleteApi } } = this.props
    const { defaultTempKey, defaultList } = this.state
    try {
      if (val == 1) {
        const { filtercont } = this.state
        let filter
        if (body && defaultList.some((item) => body.tempKey == item.tempKey)) {
          filter = defaultList.find(item => body.tempKey == item.tempKey).columnInfo
          const list = defaultList.find(item => body.tempKey == item.tempKey)
          this.setState({
            filtercont: { ...filtercont, ...filter },
            multipleDefault: list.tempName,
            defaultTempKey: list.tempKey
          }, () => { this.handlefilters(); });
          if (this.advancedMode == 'condition' || this.advancedMode == 'popup-condition') {
            filter.optionsParam = undefined
          }
          const data = this.handlePrefix(filter)
          this.advanceFilterForm?.handleFiltersArr(data)
        } else {
          const api = selectApi
          if (!api) return true
          const res = await env.fetcher(api)
          if (res.status == 0 && res.data) {
            const body = res.data
            if (Array.isArray(body)) {
              filter = cloneDeep(body[0].columnInfo)
              const options = filter.optionsParam
              //过滤掉不存在的字段
              if (Array.isArray(filter.advancedFilter)) {
                let filterBody = this.props.advancedFilter?.body;
                filterBody = Array.isArray(filterBody) ? filterBody : filterBody ? [filterBody] : [];
                const filters = filterBody.find((item: any) => item.name === 'advancedFilter')?.body;
                filter.advancedFilter = filter.advancedFilter.filter((item: any) => {
                  const isInside = !!filters.find((col: any) => col.name?.split('.')?.[1] === item.field)
                  return isInside
                })

                filter.advancedFilterSub = filter.advancedFilterSub.filter((item: any) => {
                  const isInside = !!filters.find((col: any) => col.name?.split('.')?.[1] === item.field)
                  return isInside
                })
              }
              if (this.advancedMode == 'condition' || this.advancedMode == 'popup-condition') {
                filter.optionsParam = undefined
              } else if (options) {
                if (options.itemCount === false && options.itemRepeat === false && options.itemSumCount === false && options.section === false &&
                  options.showFields?.length === 0 && options.sortFields?.length === 0 && options.groupByFields?.length === 0) {
                  filter.optionsParam = undefined
                }
              }
              const defaultBody = body.map((item) => {
                if (!item?.tempKey) {
                  return { columnInfo: item, tempKey: item?.tempKey ?? uuid(), tempName: item?.tempName ?? '默认设置' }
                }
                return item
              })
              this.setState({
                defaultList: defaultBody,
                multipleDefault: body[0].tempName,
                defaultTempKey: body[0].tempKey
              })
            } else {
              if (res.data?.columnInfo) {
                filter = cloneDeep(res.data.columnInfo)
              } else {
                filter = cloneDeep(res.data)
                this.setState({ defaultList: [] })
              }
              if (this.advancedMode == 'condition' || this.advancedMode == 'popup-condition') {
                filter.optionsParam = undefined
              }
              this.setState({ defaultList: [{ columnInfo: filter, tempKey: res.data?.tempKey ?? uuid(), tempName: res.data?.tempName ?? '默认设置' }] })
            }
            // const filter = cloneDeep(res.data.columnInfo)
            this.setState({ filtercont: { ...filtercont, ...filter } }, () => {
              this.handlefilters();
            });
            const data = this.handlePrefix(filter)
            this.advanceFilterForm?.handleFiltersArr(data)
          }
        }
      } else if (val == 2) {
        const api = modifyApi
        if (!api) return true
        const queryParams: any = this.advanceFilterForm?.confirmAdvancedFilter(true);
        const rawShowFields = queryParams?.filterOptionData?.rawShowFields
        const optionsParam = queryParams?.filterOptionData?.optionsParam
        if (rawShowFields?.length == 0) {
          message.warning('显示字段不能为空');
          return true
        }
        queryParams.optionsParam = optionsParam
        //初始化的时候，高级查询中的select取不到对应的label，所以传给后端，保存起来
        if (queryParams.advancedFilter?.length > 0) {
          const newAdvancedFilter = queryParams.advancedFilter.map((filterItem: any) => {
            const optionsData = this.saveData.get(filterItem.field);
            let data = filterItem.values;
            if (optionsData && optionsData?.length > 0) {
              if (typeof filterItem?.values == 'string' && filterItem?.values?.indexOf(',') !== -1) {
                data = filterItem.values.split(',').map((name_item: any) =>
                  findTree(optionsData, current => current.value == name_item)?.label
                )?.join(',');
              } else {
                data = findTree(optionsData, (item) => item.value == filterItem.values)?.label
              }
            }
            return { ...filterItem, valuesAlia: data }
          })
          queryParams.advancedFilter = newAdvancedFilter
        }
        if (body) {
          const url: any = {
            method: "post",
            url: api?.url || '',
            data: {
              tempName: "${tempName |default:undefined}",
              tempKey: "${tempKey |default:undefined}",
              columnInfo: {
                advancedFilter: "${advancedFilter |default:undefined}",
                advancedFilterSub: "${advancedFilterSub |default:undefined}",
                advancedHeader: "${advancedHeader |default:undefined}",
                optionsParam: "${optionsParam |default:undefined}",
                limitParam: "${limitParam |default:undefined}"
              }
            }
          }

          let columnInfo
          let data
          if (!senior && defaultList.length > 0 && !!defaultList.find(item => body.tempKey == item.tempKey)) {
            columnInfo = defaultList.find(item => body.tempKey == item.tempKey).columnInfo
          } else if (senior) {
            columnInfo = queryParams
          }

          if (!!defaultTempKey && columnInfo) {
            data = { ...body, ...columnInfo };
          } else if (columnInfo) {
            data = { ...body, ...columnInfo };
          } else {
            data = { ...body, ...queryParams };
          }
          const { msg } = await env.fetcher(url, data);
          message.info(msg);
          this.defaultAdvancedQuery(1)
        } else {
          const res = await env.fetcher(api, queryParams)
          if (res.status == 0) {
            message.success(res.msg)
          }
          this.defaultAdvancedQuery(1)
        }
      }
      else if (val == 3) {
        const api = deleteApi
        if (!api) return true
        const url: any = { method: api.method, url: api.url + '&tempKey=' + body || '', }
        const res = await env.fetcher(url, { tempKey: body })
        if (res.status == 0) {
          message.success(res.msg)
          this.setState({ defaultList: defaultList.filter(item => item.tempKey !== body) }, () => {
            const list = defaultList.filter(item => item.tempKey !== body)
            if (list.length == 0) {
              this.setState({ selectTmpShow: false })
            }
          })
        }
        this.defaultAdvancedQuery(1)
      }
      return true
    } catch {
      return true
    }
  }
  handlePrefix(body: any) {
    const { advancedQueryFields } = this.props;
    const filtercont = {}
    for (const key in body) {
      if (key == "advancedFilter" || key == "advancedHeader" || key == "advancedFilterSub")
        if (typeof body[key] == 'object') {
          if (Array.isArray(body[key])) {
            const content = cloneDeep(body[key]);
            let newArr: any[] = [];
            const dateLineItem = content.find((item: any) => item.dateLine);
            if (content.length && key === 'advancedFilter' && !dateLineItem) {
              let filterBody = this.props.advancedFilter?.body;
              filterBody = Array.isArray(filterBody) ? filterBody : filterBody ? [filterBody] : [];
              const filters = filterBody.find((item: any) => item.name === 'advancedFilter')?.body;
              let dateList = filters.filter((filterItem: any) => filterItem.type && ['input-date', 'input-datetime', 'input-time', 'input-month', 'input-quarter', 'input-year'].includes(filterItem.type));
              if (advancedQueryFields) {
                dateList = dateList.filter((info: any) => advancedQueryFields.includes(info.name.split('.')?.[1]))
              }
              if (dateList?.length > 0) {
                newArr.push({
                  caseSensitive: 1,
                  condition: 1,
                  dateLine: true,
                  field: dateList[0].name,
                  not: false,
                  op: 7
                })
              }
            }
            content.forEach((item: any) => {
              const repeatNum = newArr.filter(pItem => pItem.field.includes(item.field)).length
              const element = item
              element.field = key + "." + item.field + (repeatNum > 0 ? `--${repeatNum}` : '')
              newArr.push(element);
            })
            filtercont[key] = newArr
          } else {
            const content = cloneDeep(body[key])
            const data = {}
            for (const item in content) {
              data[`${key}.${item}`] = content[item]
            }
            filtercont[key] = data
          }
        }
    }
    return filtercont
  }
  // 判断是否有高级查询的数据将基础查询重置
  handleReset() {
    let filtercont: any = cloneDeep(this.state.filtercont)
    if (Object.keys(filtercont).length) {
      filtercont.filterParam = cloneDeep(this.state.filterOptions.filterParam)
      this.setState({ filtercont: filtercont });
    }
  }
  // 删除高级查询条件
  handledelVisible(
    value: any,
    whole = false,
    e?: React.MouseEvent<HTMLElement>,
    delIndex?: number
  ) {
    e?.preventDefault();
    let filtercont: any = cloneDeep(this.state.filtercont);
    filtercont.filterParam = cloneDeep(this.state.filterOptions.filterParam)
    if (whole) {
      filtercont.advancedFilter = [];
      filtercont.advancedFilterSub = [];
      filtercont.advancedHeader = {};
      this.advanceFilterForm?.handlerenew?.(whole);
    } else {
      const head = value.name.split('.')[0];
      const name = value.name.split('.')[1];
      if (head.includes('advancedFilter') || head.includes('advancedFilterSub')) {
        let newList = [...filtercont[head]]
        if (delIndex !== undefined) {
          newList.splice(delIndex, 1);
        } else {
          newList = filtercont[head].filter(
            (item: any) => item.field != name
          );
        }
        filtercont[head] = newList;
      } else {
        let replacement: any = {};
        for (const key in filtercont[head]) {
          if (key !== name) {
            replacement[key] = filtercont[head]?.[key];
          }
        }
        filtercont[head] = replacement;
      }
      this.advanceFilterForm?.handlerenew?.(whole, value.name, value.keyName);
    }

    this.setState(
      {
        filtercont: filtercont
      },
      () => {
        this.handlefilters();
      }
    );
  }
  handleSelectStructure = (select: any[]): any[] => {
    const newArray: any[] = [];

    const pushChildren = (item: any, newArray: any[]) => {
      newArray.push(item);
      if (item.children && item.children.length > 0) {
        item.children.forEach((child: any) => {
          pushChildren(child, newArray);
        });
      }
    }

    select.forEach((item: any) => {
      pushChildren(item, newArray);
    });

    return newArray;
  }


  // 高级查询内容展示
  handlefilters() {
    const { advancedFilter, advancedQueryFields } = this.props;
    const { filtercont } = this.state;
    if (!advancedFilter) return;
    const { body } = advancedFilter;
    const filters = Array.isArray(body) ? body : body ? [body] : [];
    const { advancedFilter: advancedFilterCont, advancedFilterSub } = filtercont || {};
    const allAdvancedFilters = [...(advancedFilterCont || []), ...(advancedFilterSub || [])];
    const dateLineItem = allAdvancedFilters.find(filItem => filItem.dateLine)

    const filtertpl: filterTpl[] = allAdvancedFilters.reduce((result, value, currentIndex) => {
      filters.forEach(item => {
        if (item.name.includes('advancedFilter')) {
          item.body.forEach((items: any) => {
            const long = items.name.split('.');
            if (long[long.length - 1] === value.field) {
              const currentValue = this.saveData.get(value.field);
              let data = null;
              if (currentValue) {
                if (typeof value?.values == 'string' && value?.values?.indexOf(',') !== -1) {
                  data = value.values.split(',').map((name_item: any) => {
                    if (value.op == 12) {
                      const newArray = this.handleSelectStructure(currentValue)
                      return newArray.find(current => current.value == name_item)?.label
                    }
                    return findTree(currentValue, (current => current.value == name_item))?.label
                  }
                  );
                } else data = currentValue.find(item => item.value == value.values)?.label
              }
              let dateList = item.body.filter((filterItem: any) => filterItem.type && ['input-date', 'input-datetime', 'input-time', 'input-month', 'input-quarter', 'input-year'].includes(filterItem.type));
              if (advancedQueryFields) {
                dateList = dateList.filter((info: any) => advancedQueryFields.includes(info.name.split('.')?.[1]))
              }
              let cop: filterTpl = {};

              if (this.advanceFilterForm?.state?.filtersArr?.length) {
                cop.keyName = this.advanceFilterForm?.state?.filtersArr[!dateList.length || dateLineItem ? currentIndex : currentIndex + 1]?.field || 'advancedFilter.' + value.field
              } else {
                const repeatNum = result.filter((resItem: filterTpl) => resItem.name === 'advancedFilter.' + value.field).length + (dateList.length && !dateLineItem && dateList[0].name === 'advancedFilter.' + value.field ? 1 : 0);
                const keyName = 'advancedFilter.' + value.field + (repeatNum > 0 ? `--${repeatNum}` : '');
                cop.keyName = keyName;
              }
              cop.value = data ? typeof data === 'object' ? data.join(',') : data : value.values;
              cop.label = items?.label || items?.placeholder;
              cop.name = items.name;


              if (value.valuesAlia) {
                cop.valuesAlia = value.valuesAlia
              }
              switch (value.op) {
                case 2:
                  if (cop.value) {
                    if (value.not) {
                      cop.value = `![${cop.value}]`
                    } else {
                      cop.value = `[${cop.value}]`
                    }
                  }
                  if (value.valuesAlia) {
                    if (value.not) {
                      cop.valuesAlia = `![${cop.valuesAlia}]`
                    } else {
                      cop.valuesAlia = `[${cop.valuesAlia}]`
                    }
                  }
                  break;
                case 3:
                  if (cop.value) {
                    if (value.not) {
                      cop.value = `!（${cop.value}，∞)`
                    } else {
                      cop.value = `（${cop.value}，∞)`
                    }
                  }
                  if (value.valuesAlia) {
                    if (value.not) {
                      cop.valuesAlia = `!（${cop.valuesAlia}，∞)`
                    } else {
                      cop.valuesAlia = `（${cop.valuesAlia}，∞)`
                    }
                  }
                  break;
                case 4:
                  if (cop.value) {
                    if (value.not) {
                      cop.value = `![${cop.value}，∞)`
                    } else {
                      cop.value = `[${cop.value}，∞)`
                    }
                  }
                  if (value.valuesAlia) {
                    if (value.not) {
                      cop.valuesAlia = `![${cop.valuesAlia}，∞)`
                    } else {
                      cop.valuesAlia = `[${cop.valuesAlia}，∞)`
                    }
                  }
                  break;
                case 5:
                  if (cop.value) {
                    if (value.not) {
                      cop.value = `!（-∞,${cop.value}）`
                    } else {
                      cop.value = `（-∞,${cop.value}）`
                    }
                  }
                  if (value.valuesAlia) {
                    if (value.not) {
                      cop.valuesAlia = `!（-∞,${cop.valuesAlia}）`
                    } else {
                      cop.valuesAlia = `（-∞,${cop.valuesAlia}）`
                    }
                  }
                  break;
                case 6:
                  if (cop.value) {
                    if (value.not) {
                      cop.value = `!（-∞,${cop.value}]`
                    } else {
                      cop.value = `（-∞,${cop.value}]`
                    }
                  }
                  if (value.valuesAlia) {
                    if (value.not) {
                      cop.valuesAlia = `!（-∞,${cop.valuesAlia}]`
                    } else {
                      cop.valuesAlia = `（-∞,${cop.valuesAlia}]`
                    }
                  }
                  break;
                case 7:
                  if (value.values) {
                    cop.value = `[${value.values}]`
                    cop.valuesAlia = `[${value.values}]`
                  }
                  break;
                case 9:
                  if (cop.value) {
                    if (value.not) {
                      cop.value = `!${cop.value}`
                    } else
                      cop.value = `${cop.value}`
                  }
                  if (value.valuesAlia) {
                    if (value.not) {
                      cop.valuesAlia = `!${cop.valuesAlia}`
                    } else
                      cop.valuesAlia = `${cop.valuesAlia}`
                  }
                  break;
                case 10:
                  if (value.not) {
                    cop.value = '[不为空]'
                  } else {
                    cop.value = '[为空]'
                  }
                  break;

                case 12:
                  if (cop.value) {
                    if (value.not) {
                      cop.value = `!属于标签 ${cop.value}`
                    } else {
                      cop.value = `属于标签 ${cop.value}`
                    }
                  }
                  if (value.valuesAlia) {
                    if (value.not) {
                      cop.valuesAlia = `!属于标签${cop.valuesAlia}`
                    } else {
                      cop.valuesAlia = `属于标签${cop.valuesAlia}`
                    }
                  }
                  break;
                default:
                  break;
              }
              if (!this.advancefilterValueIsLegalEmptyValue(value)) {
                // 加一个在高级查询中的位置 方便移除
                result.push({ ...cop, advancedFilterIndex: currentIndex });
              }

            }
          });
        }
      });
      return result;
    }, []);
    const { advancedHeader } = filtercont || {};
    if (advancedHeader && Object.keys(advancedHeader).length) {
      Object.keys(advancedHeader).forEach(key => {
        filters.forEach(item => {
          if (item.name === 'advancedHeader') {
            item.body.forEach((items: any) => {
              if (items?.body) {
                items.body.forEach((it: any) => {
                  const long = it.name.split('.');
                  if (long[long.length - 1] === key) {
                    const currentValue = this.saveData.get(it.name);
                    let cop: filterTpl = {};
                    if (currentValue) {
                      const currentLabel = currentValue.find(
                        opp => opp.value === advancedHeader[key]
                      );
                      cop.labelName = currentLabel?.label;
                    }
                    cop.value = advancedHeader[key];
                    cop.label = it.placeholder || it.label;
                    cop.name = it.name;
                    filtertpl.push(cop);
                  }
                });
              } else {
                const long = items.name.split('.');
                if (long[long.length - 1] === key) {
                  const currentValue = this.saveData.get(items.name);
                  let cop: filterTpl = {};
                  if (currentValue) {
                    const currentLabel = currentValue.find(
                      opp => opp.value === advancedHeader[key]
                    );
                    cop.labelName = currentLabel?.label;
                  }
                  cop.value = advancedHeader[key];
                  cop.label = items.placeholder || items.label;
                  cop.name = items.name;
                  filtertpl.push(cop);
                }
              }
            });
          }
        });
      });
    }
    this.setState({ filtertpl });
  }

  handleBulkGo(
    selectedItems: Array<any>,
    unSelectedItems: Array<any>,
    e: React.MouseEvent<any>
  ) {
    const action = this.props.store.selectedAction;
    const env = this.props.env;

    if (action.confirmText) {
      return env
        .confirm(action.confirmText)
        .then(
          (confirmed: boolean) =>
            confirmed &&
            this.handleBulkAction(
              selectedItems,
              unSelectedItems,
              e as any,
              action
            )
        );
    }

    return this.handleBulkAction(
      selectedItems,
      unSelectedItems,
      e as any,
      action
    );
  }

  showModal() {
    const { env, translate: __ } = this.props;
    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')
    });
  }

  baseModalConfirm(type: 'drawer' | 'dialog') {
    return async (values: object[],
      action: Action,
      ctx: any,
      components: Array<any>) => {
      const {
        store,
        pageField,
        stopAutoRefreshWhenModalIsOpen,
        interval,
        silentPolling,
        env
      } = this.props;
      // Jay 下一个、上一个不用关闭
      if (!['next', 'prev'].includes(action.actionType || '')) {
        switch (type) {
          case 'drawer':
          default:
            store.closeDrawer(true);
            break
          case 'dialog':
            store.closeDialog(true);
            break;
        }
      }

      const tableRows: any[] = this.getTableRowsData()

      const dialogAction = store.action as Action;

      // 自动聚焦第一个搜索栏，释放内存
      functionInOneFrame(() =>
        (this.crudRef?.current?.querySelector('input[type="text"]') as HTMLElement)?.focus()
      )


      if (stopAutoRefreshWhenModalIsOpen && interval) {
        this.timer = setTimeout(
          silentPolling ? this.silentSearch : this.search,
          Math.max(interval, 1000)
        );
      }

      if (
        action.actionType === 'next' &&
        typeof ctx.nextIndex === 'number' &&
        tableRows[ctx.nextIndex]
      ) {
        if (this.tableInstance) {
          const count = this.tableInstance.props.store.modified;
          if (count > 0) {
            this.showModal();
            return;
          }
        }
        return this.handleAction(
          undefined,
          {
            ...dialogAction
          },
          createObject(
            createObject(store.data, {
              index: ctx.nextIndex
              // Jay
              // initApiDisable: 0
            }),
            tableRows[ctx.nextIndex]
          )
        );
      } else if (
        action.actionType === 'prev' &&
        typeof ctx.prevIndex === 'number' &&
        tableRows[ctx.prevIndex]
      ) {
        if (this.tableInstance) {
          const count = this.tableInstance.props.store.modified;
          if (count > 0) {
            this.showModal();
            return;
          }
        }
        return this.handleAction(
          undefined,
          {
            ...dialogAction
          },
          createObject(
            createObject(store.data, {
              index: ctx.prevIndex
              // Jay
              // initApiDisable: 0
            }),
            tableRows[ctx.prevIndex]
          )
        );
      } else if (values.length) {
        const value = values[0];
        ctx = createObject(ctx, value);
        const component = components[0];

        // 提交来自 form
        if (component && component.props.type === 'form') {
          // 数据保存了，说明列表数据已经无效了，重新刷新。
          if (value && (value as any).__saved) {
            const reload = action.reload ?? dialogAction.reload;
            // 配置了 reload 则跳过自动更新。
            reload ||
              this.search(
                dialogAction.__from ? { [pageField || 'page']: 1 } : undefined,
                undefined,
                true,
                true,
                this.afterSearchFn
              );
          } else if (
            value &&
            ((value.hasOwnProperty('items') && (value as any).items) ||
              value.hasOwnProperty('ids')) &&
            this.control.bulkUpdate
          ) {
            this.control.bulkUpdate(value, (value as any).items);
          }
        }
      }

      const reload = action.reload ?? dialogAction.reload;
      if (reload) {
        this.reloadTarget(reload, ctx);
      }

      let redirect = action.redirect ?? dialogAction.redirect;
      redirect = redirect && filter(redirect, ctx);
      redirect && env.jumpTo(redirect, dialogAction);
    }
  }

  async handleDialogConfirm(
    values: object[],
    action: Action,
    ctx: any,
    components: Array<any>,
  ) {
    return await this.baseModalConfirm('dialog')(values, action, ctx,
      components)
  }

  async handleDrawerConfirm(
    values: object[],
    action: Action,
    ctx: any,
    components: Array<any>,
  ) {
    return await this.baseModalConfirm('drawer')(values, action, ctx,
      components)
  }


  handleBaseModalClose(type: 'dialog' | 'drawer') {
    return (confirmed?: boolean,
      formInstance?: any,
      tableInstance?: TableRenderer) => {

      // 自动聚焦第一个搜索栏，释放内存
      functionInOneFrame(() =>
        (this.crudRef?.current?.querySelector('input[type="text"]') as HTMLElement)?.focus()
      )

      const { translate: __, env } = this.props;
      if (tableInstance) {
        const count = tableInstance.props.store.modified;
        if (count > 0) {
          this.showModal();
          return;
        }
      }
      // Jay
      if (formInstance) {
        const { promptPageLeave } = formInstance.props;
        if (promptPageLeave && formInstance.is_edit) {
          Modal.confirm({
            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'),
            cancelText: __('cancel'),
            onOk: () => this.closeModal(type),
            className: 'ant-modal-adaptation-style'
          });
          return;
        }
      }
      this.closeModal(type);
    }
  }
  handleDialogClose(
    confirmed?: boolean,
    formInstance?: any,
    tableInstance?: TableRenderer
  ) {
    return this.handleBaseModalClose('dialog')(confirmed, formInstance, tableInstance)
  }

  handleDrawerClose(
    confirmed?: boolean,
    formInstance?: any,
    tableInstance?: TableRenderer
  ) {
    return this.handleBaseModalClose('drawer')(confirmed, formInstance, tableInstance)
  }



  closeModal(type: 'dialog' | 'drawer' = 'dialog') {
    const { store, stopAutoRefreshWhenModalIsOpen, silentPolling, interval } =
      this.props;
    switch (type) {
      case 'dialog':
        store.closeDialog();
        break;
      case 'drawer':
        store.closeDrawer();
        break;
    }
    if (stopAutoRefreshWhenModalIsOpen && interval) {
      this.timer = setTimeout(
        silentPolling ? this.silentSearch : this.search,
        Math.max(interval, 1000)
      );
    }
  }


  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);
      });
    });
  }
  handleOptions = (body: any) => {
    const { columns } = this.props
    const optionsParam = cloneDeep(body)
    const compare1 = columns.map((item: any) => item.name)
    const compare2 = optionsParam?.showFields
    if (compare1 && compare2 && isEqual(compare1, compare2)) {
      optionsParam.showFields = []
    }
    return optionsParam
  }

  search(
    values?: any,
    silent?: boolean,
    clearSelection?: boolean,
    forceReload = false,
    resolve?: (value: any) => void,
    reject?: (error: any) => void,
    isChild?: boolean,
    postData?: any, // Jay
    init?: boolean
  ) {
    const {
      store,
      api,
      messages,
      pageField,
      perPageField,
      interval,
      stopAutoRefreshWhen,
      stopAutoRefreshWhenModalIsOpen,
      silentPolling,
      syncLocation,
      syncResponse2Query,
      keepItemSelectionOnPageChange,
      pickerMode,
      env,
      loadDataOnce,
      loadDataOnceFetchOnFilter,
      source
    } = this.props;
    // Jay
    //这里原先的备注是：
    //     Jay  Jay, 9个月前   (4 26th, 2022 4:49 下午)
    // 优化CRUD-filter的submit按钮target重复查询、查询条件问题
    //但是实测没有起到优化的效果，并且会导致左右页面的一个bug，回车提交查询主表数据为空时，从表数据没有更新
    // if (store.searching) return
    // reload 需要清空用户选择。
    if (keepItemSelectionOnPageChange && clearSelection && !pickerMode) {
      store.setSelectedItems([]);
      store.setUnSelectedItems([]);
    }

    let loadDataMode = '';
    if (values && typeof values.loadDataMode === 'string') {
      loadDataMode = 'load-more';
      delete values.loadDataMode;
    }

    clearTimeout(this.timer);
    values &&
      store.updateQuery(
        values,
        !loadDataMode && syncLocation && env && env.updateLocation
          ? env.updateLocation
          : undefined,
        pageField,
        perPageField
      );
    this.lastQuery = store.query;
    let data = postData ?? createObject(store.data, store.query); // Jay
    if (!postData && Object.keys(this.state.filtercont || {}).length) {
      data.advancedFilter = this.state.filtercont?.advancedFilter
      data.advancedHeader = this.state.filtercont?.advancedHeader;
      data.advancedFilterSub = this.state.filtercont?.advancedFilterSub;
      data.optionsParam = this.state.filtercont?.optionsParam
      if (this.state.filtercont?.limitParam?.limitStatus) {
        data.topN = this.state.filtercont.limitParam.topN
      }
      if (isMobile()) {
        if (init) {
          data.filterParam = this.getInitParam()
        } else {
          data.filterParam = this.state.filtercont?.filterParam
        }
      }
      // if (this.state.filtercont?.filterOptionData) {
      //   const { optionsParam } = this.state.filtercont?.filterOptionData;
      //   data.optionsParam = optionsParam
      // }
    } else if (postData !== undefined && postData.filterOptionData) {
      const { optionsParam } = postData.filterOptionData;
      data.optionsParam = optionsParam
    }

    if (data.advancedFilter) {
      data.advancedFilter = data.advancedFilter.filter((item: any) => {
        if (this.advancefilterValueIsLegalEmptyValue(item)) {
          return false
        }
        return true
      });
    }

    try {
      if (this.props.isStatic) {
        store.initStaticData(undefined, values)
      } else {
        // ai-tool 的查询条件
        this.props.aiQuery && (data = createObject(data, this.props.aiQuery));
        isEffectiveApi(api, data)
          ? store
            .fetchInitData(api, data, {
              successMessage: messages && messages.fetchSuccess,
              errorMessage: messages && messages.fetchFailed,
              autoAppend: true,
              forceReload,
              loadDataOnce,
              loadDataOnceFetchOnFilter,
              source,
              silent,
              openCache: this.props.openCache,
              pageField,
              perPageField,
              loadDataMode,
              syncResponse2Query
            })
            .then(value => {
              // Jay
              // WithStore.tsx: else if (props.data && (props.data as any).__super) 中的 store.hasRemoteData
              // 若不设置，store.initData不会合并之前的store.data.items（items:请求回来的data.items）
              this.setState({ filterData: data })
              // this.tableStore?.clearOrderColumn?.();
              store.setHasRemoteData();
              if (!this.state.hasFetch) this.setState({ hasFetch: true });
              this.props.setTotalNum &&
                this.props.setTotalNum(
                  this.props.totalTab?.key,
                  value?.data?.total,
                  this.props.name,
                  this.props.bodyName
                );
              resolve && resolve(value);
              this.props.onAiFinished?.()

              interval &&
                this.mounted &&
                (!stopAutoRefreshWhen ||
                  !(
                    (stopAutoRefreshWhenModalIsOpen && store.hasModalOpened) ||
                    evalExpression(stopAutoRefreshWhen, data)
                  )) &&
                (this.timer = setTimeout(
                  silentPolling
                    ? this.silentSearch.bind(this, undefined, undefined, true)
                    : this.search.bind(
                      this,
                      undefined,
                      undefined,
                      undefined,
                      true
                    ),
                  Math.max(interval, 1000)
                ));
              return value;
            })
          : source && store.initFromScope(data, source);
      }
    } catch (err) {
      reject && reject(err);
      return;
    }
  }

  silentSearch(values?: object, clearSelection?: boolean, forceReload = false) {
    return this.search(values, true, clearSelection, forceReload);
  }

  afterSearchFn() {
    const orderColumns = this.tableStore?.orderColumns
    const filterColumns = this.tableStore?.filterColumns

    if (this.props.mode === 'lion-bi-table') {
      if (this.props.loadDataOnce) {
        if (filterColumns?.size > 0 || orderColumns?.size > 0) {
          this.handleMutilSort(orderColumns, filterColumns, true)
        }
      } else {
        if (filterColumns?.size > 0 || orderColumns?.size > 0) {
          this.handleColumnFilter(filterColumns, orderColumns)
        }
      }
    } else {
      const total = this.tableStore?.handleMutilSort(this.props.loadDataOnce)
      if (total != undefined) this.setTotal(total)
    }
  }

  async handleChangePage(page: number, perPage?: number) {
    const {
      store,
      syncLocation,
      env,
      pageField,
      perPageField,
      autoJumpToTopOnPagerChange,
      affixOffsetTop,
      loadDataOnce
    } = this.props;
    let query: any = {
      [pageField || 'page']: page
    };

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

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

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

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

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

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

    if (Array.isArray(rows)) {
      if (!isEffectiveApi(quickSaveApi)) {
        env && env.alert('CRUD quickSaveApi is required');
        return;
      }

      if (groupBy?.groupByField && groupFields && levelField) {
        rows = getDiffRowData(this.props.data.items, Array.isArray(diff) ? diff : [diff], primaryField, levelField, groupBy.groupByField, groupFields)
      }

      const data: any = createObject(store.data, {
        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 && this.reloadTarget(reload, data);
          quickReloadTarget && this.reloadTarget(quickReloadTarget, data)
          if (quickDataReload) {
            this.search(undefined, undefined, true, true, this.afterSearchFn);
          } else {
            // item-id的映射 加快查找速度
            const _itemIdIndexMap = {}
            const _items = mode == 'cross' ? [...(this.tableStore?.data.items ?? [])] : [...store.data.items]
            _items.map((_, index) => _itemIdIndexMap[_[DATAKEYID]] = index)

            // itemRaw-id的映射 加快查找速度
            const _itemRawIdIndexMap = {}
            const _itemsRaw = mode == 'cross' ? [...(this.tableStore?.data.items ?? [])] : [...store.data.itemsRaw]
            _itemsRaw.map((_, index) => _itemRawIdIndexMap[_[DATAKEYID]] = index)
            // 根据更新的数据进行原始数据替换
            if (data.rowsDiff.length) {
              for (const changeRows of data.rowsDiff) {
                if (!isNil(_itemIdIndexMap[changeRows.changeItemKey])) {
                  _items[_itemIdIndexMap[changeRows.changeItemKey]] = { ..._items[_itemIdIndexMap[changeRows.changeItemKey]], ...changeRows.diff }
                }
                if (!isNil(_itemRawIdIndexMap[changeRows.changeItemKey])) {
                  _itemsRaw[_itemRawIdIndexMap[changeRows.changeItemKey]] = { ..._itemsRaw[_itemRawIdIndexMap[changeRows.changeItemKey]], ...changeRows.diff }
                }
              }
            }
            const newData = {
              ...store.data,
              items: _items,
              itemsRaw: _itemsRaw,
              dataSetId: uuidv4(), // 更新数据集id
              sortItemsRaw: _items
            }
            if (this.props.openCache)
              store.updateCacheData(newData)
            mode == 'cross' ? this.tableStore?.reInitData(newData) : store.reInitData(newData)
            this.afterSearchFn()
          }
        })
        .catch(() => {
          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 && this.reloadTarget(reload, data);
          quickReloadTarget && this.reloadTarget(quickReloadTarget, data)
          this.search(undefined, undefined, true, true);
        })
        .catch(() => {
          resetOnFailed && this.control.reset();
        });
    }
  }

  handleSaveOrder(moved: Array<object>, rows: Array<object>) {
    const { store, saveOrderApi, orderField, primaryField, env, reload } =
      this.props;

    if (!saveOrderApi) {
      env && env.alert('CRUD saveOrderApi is required!');
      return;
    }

    const model: {
      insertAfter?: any;
      insertBefore?: any;
      idMap?: any;
      rows?: any;
      ids?: any;
      order?: any;
    } = createObject(store.data);

    let insertAfter: any;
    let insertBefore: any;
    const holding: Array<object> = [];
    const hasIdField =
      primaryField &&
      rows[0] &&
      (rows[0] as object).hasOwnProperty(primaryField);

    hasIdField || (model.idMap = {});

    model.insertAfter = {};
    rows.forEach((item: any) => {
      if (~moved.indexOf(item)) {
        if (insertAfter) {
          let insertAfterId = hasIdField
            ? (insertAfter as any)[primaryField as string]
            : rows.indexOf(insertAfter);
          model.insertAfter[insertAfterId] =
            (model as any).insertAfter[insertAfterId] || [];

          hasIdField || (model.idMap[insertAfterId] = insertAfter);
          model.insertAfter[insertAfterId].push(
            hasIdField ? item[primaryField as string] : item
          );
        } else {
          holding.push(item);
        }
      } else {
        insertAfter = item;
        insertBefore = insertBefore || item;
      }
    });

    if (insertBefore && holding.length) {
      let insertBeforeId = hasIdField
        ? insertBefore[primaryField as string]
        : rows.indexOf(insertBefore);
      hasIdField || (model.idMap[insertBeforeId] = insertBefore);
      model.insertBefore = {};
      model.insertBefore[insertBeforeId] = holding.map((item: any) =>
        hasIdField ? item[primaryField as string] : item
      );
    } else if (holding.length) {
      const first: any = holding[0];
      const firstId = hasIdField
        ? first[primaryField as string]
        : rows.indexOf(first);

      hasIdField || (model.idMap[firstId] = first);
      model.insertAfter[firstId] = holding
        .slice(1)
        .map((item: any) => (hasIdField ? item[primaryField as string] : item));
    }

    if (orderField) {
      const start = (store.page - 1) * store.perPage || 0;
      rows = rows.map((item, key) =>
        extendObject(item, {
          [orderField]: start + key + 1
        })
      );
    }

    model.rows = rows.concat();
    hasIdField &&
      (model.ids = rows
        .map((item: any) => item[primaryField as string])
        .join(','));
    hasIdField &&
      orderField &&
      (model.order = rows.map(item =>
        pick(item, [primaryField as string, orderField])
      ));

    isEffectiveApi(saveOrderApi, model) &&
      store
        .saveRemote(saveOrderApi, model)
        .then(() => {
          reload && this.reloadTarget(reload, model);
          this.search(undefined, undefined, true, true);
        })
        .catch(() => { });
  }

  handleSelect(items: Array<any>, unSelectedItems: Array<any>) {
    const {
      store,
      keepItemSelectionOnPageChange,
      primaryField,
      multiple,
      pickerMode,
      onSelect
    } = this.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;

      // const thisBatch = items.concat(unSelectedItems);
      // let notInThisBatch = (item: any) =>
      //   !find(
      //     thisBatch,
      //     a => a[primaryField || 'id'] == item[primaryField || 'id']
      //   );

      // newItems = store.selectedItems.filter(notInThisBatch);
      // newUnSelectedItems = store.unSelectedItems.filter(notInThisBatch);

      // newItems.push(...items);
      // newUnSelectedItems.push(...unSelectedItems);
    }

    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);
  }

  handleChildPopOverOpen(popOver: any) {
    if (
      this.props.interval &&
      popOver &&
      ~['dialog', 'drawer'].indexOf(popOver.mode)
    ) {
      this.props.stopAutoRefreshWhenModalIsOpen && clearTimeout(this.timer);
      this.props.store.setInnerModalOpened(true);
    }
  }

  handleChildPopOverClose(popOver: any) {
    const { stopAutoRefreshWhenModalIsOpen, silentPolling, interval } =
      this.props;

    if (popOver && ~['dialog', 'drawer'].indexOf(popOver.mode)) {
      this.props.store.setInnerModalOpened(false);

      if (stopAutoRefreshWhenModalIsOpen && interval) {
        this.timer = setTimeout(
          silentPolling ? this.silentSearch : this.search,
          Math.max(interval, 1000)
        );
      }
    }
  }
  // modifiedData 编辑数据 如有有编辑的话 要用编辑的数据进行排序
  handleMutilSort(orderMap: Map<string, any>, filterMap?: Map<string, any>, loadDataOnce = false, modifiedData?: any) {
    this.props.store.sortColumns(orderMap, filterMap, loadDataOnce, this.props.mode === 'lion-bi-table' || this.props.mode === 'cross', modifiedData);
  }

  handleColumnFilter(filterMap: Map<string, any>, orderMap?: Map<string, any>, caseSensitive = false) {
    this.props.store.filterColumns(filterMap, orderMap, this.props.loadDataOnce, this.props.mode === 'lion-bi-table' || this.props.mode === 'cross', caseSensitive)
  }

  setTotal(total: number) {
    this.props.store.changeTotal(total)
  }

  handleQuery(values: object, forceReload: boolean = false) {
    const { store, syncLocation, env, pageField, perPageField, loadDataOnce } = this.props;
    const saveFilter = values['filterParam'] == null
    // Jay crud filter是点击submit按钮才更新query，现在需要拿到实时的form的data
    const tmpValues: any = {
      ...values,
      [pageField || 'page']: 1
    };
    const temp = this.filterForm?.props.store.data[this.props.filter?.name];
    if (temp) {
      tmpValues[this.props.filter!.name] = temp;
    }

    store.updateQuery(
      tmpValues,
      syncLocation && env && env.updateLocation
        ? env.updateLocation
        : undefined,
      pageField,
      perPageField
    );
    // 如果需要缓存数据 阐释静默加载数据进缓存

    this.search(undefined, undefined, undefined, forceReload, saveFilter ? this.afterSearchFn : () => {
      this.filterDrawerOpened = false
      this.tableStore?.filterColumns?.clear()
      this.setState({ showColumnsFilter: false }, () => {
        const orderColumns = this.tableStore?.orderColumns
        if (orderColumns?.size > 0) {
          this.handleMutilSort(orderColumns, undefined, loadDataOnce)
        }
      })
    });
  }

  //记录itemAction传下来的高级查询参数
  itemActionData: any;

  // 当itemaction触发的时候 subpath query ctx 都会有 走的是this.receive的逻辑
  reload(subpath?: string, query?: any, ctx?: any, isItemAction?: boolean) {
    // 我被触发了
    this.handleScrollToTop()
    if (this.props.api) {
      if (ctx === null) {
        this.props?.store?.clearData();
        this.props?.setTotalNum?.(
          this.props.totalTab?.key,
          0,
          this.props.name,
          this.props.bodyName
        )
      } else {
        if (query) {
          if (isItemAction) {
            this.itemActionData = query;
          }
          // 讨巧写法，同步方法中带有把参数合并的方法 handlequery 等同步代码执行完了再执行静默更新，保证查询条件时同步的
          setTimeout(() => {
            // 初始化查询条件之后在进行获取缓存
            if (this.props.openCache && this.props.api) {
              this.props.store.preFetchDataSlience(this.props.api, ctx, {
                forceReload: false,
                loadDataOnce: this.props.loadDataOnce,
                pageField: this.props.pageField,
                perPageField: this.props.perPageField,
                source: this.props.source,
                syncResponse2Query: this.props.syncResponse2Query,
              })
            }
          }, 100)
          return this.receive(isMobile() ? { ...query, page: 1 } : query);
        } else {

          const advanceFilter = this.advanceFilterForm?.confirmAdvancedFilter()
          const postData = advanceFilter ? { ...advanceFilter, filterParam: this.props.store?.query?.filterParam } : undefined
          // reload时候的快速查询条件会因为 已经有高级查询条件导致条件被固定，产生问题
          this.search(
            isMobile() ? { page: 1 } : undefined,
            undefined,
            true,
            true,
            this.afterSearchFn,
            undefined,
            undefined,
            postData
          );
        }
      }
    } else if (ctx.items) {
      // 没有api的情况下用其他的方式init
      this.props.store.reInitData({ items: ctx.items }, true)
    }
  }

  receive(values: object) {
    // 根据是否需要根据主表缓存数据，决定在由主表触发reload的时候是否要进行强制刷新
    this.handleQuery(values, !this.props.openCache);
  }

  reloadTarget(target: string, data: any) {
    // implement this.
  }

  closeTarget(target: string) {
    // implement this.
  }

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

  unSelectItem(item: any, index: number) {

    const { store } = this.props;
    const data = this.control?.props?.store?.rows.concat()
    const Item = data?.find((items: any) => isEqual(item, items.data))
    if (Item) {
      this.control?.handleCheck?.(Item)
    }
    const selected = store.selectedItems.concat()
    const unSelected = store.unSelectedItems.concat();

    const idx = selected.indexOf(item);
    ~idx && unSelected.push.apply(unSelected, selected.splice(idx, 1));

    store.setSelectedItems(selected);
    store.setUnSelectedItems(unSelected);
  }

  clearSelection() {
    const { store, OnSelectedItems } = this.props;
    this.control?.handleCheckAll(2)
    const selected = store.selectedItems.concat()
    const unSelected = store.unSelectedItems.concat();

    store.setSelectedItems([]);
    store.setUnSelectedItems(unSelected.concat(selected));
  }

  hasBulkActionsToolbar() {
    const { headerToolbar, footerToolbar } = this.props;

    const isBulkActions = (item: any) =>
      ~[
        'headerBulkActions',
        'footerBulkActions',
        'bulkActions',
        'bulk-actions'
      ].indexOf(item.type || item);
    return (
      (Array.isArray(headerToolbar) && find(headerToolbar, isBulkActions)) ||
      (Array.isArray(footerToolbar) && find(footerToolbar, isBulkActions))
    );
  }

  hasBulkActions() {
    const { headerBulkActions, footerBulkActions, itemActions, store } =
      this.props;

    if (
      (!headerBulkActions || !headerBulkActions.length) &&
      (!footerBulkActions || !footerBulkActions.length) &&
      (!itemActions || !itemActions.length)
    ) {
      return false;
    }

    let bulkHeaderBtns: Array<ActionSchema> = [];
    let bulkFooterBtns: Array<ActionSchema> = [];
    let itemBtns: Array<ActionSchema> = [];
    const ctx = store.mergedData;

    if (headerBulkActions && headerBulkActions.length) {
      bulkHeaderBtns = headerBulkActions
        .map(item => ({
          ...item,
          ...getExprProperties(item as Schema, ctx)
        }))
        .filter(item => !item?.hidden && item?.visible !== false);
    }

    if (footerBulkActions && footerBulkActions.length) {
      bulkFooterBtns = footerBulkActions
        .map(item => ({
          ...item,
          ...getExprProperties(item as Schema, ctx)
        }))
        .filter(item => !item?.hidden && item?.visible !== false);
    }

    const selectedItems = this.getTableSelectedRowsData()

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

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

    return bulkHeaderBtns.length || bulkFooterBtns.length || itemBtns.length;
  }

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

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

    const selectedItems = this.getTableSelectedRowsData();
    const unSelectedItems = store.unSelectedItems;

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

    const ctx = store.mergedData;

    // const ctx = createObject(store.data, {
    //     ...store.query,
    //     items: childProps.items,
    //     selectedItems: childProps.selectedItems,
    //     unSelectedItems: childProps.unSelectedItems
    // });

    if (
      bulkActions &&
      bulkActions.length &&
      (!itemActions || !itemActions.length || selectedItems.length > 1)
    ) {
      bulkBtns = bulkActions
        .filter((toolbar: any) =>
          isVisible(toolbar, inModal ? this.filterData : 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) => this.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: this.handleItemAction.bind(this, btn, itemData)
          }
        )
      )
      : [];
    let children = [...renderBulk, ...renderItem];
    if (useMobileUI && isMobile() && children.length > 3) {
      const more = children.splice(2);
      children.splice(0, 0, this.renderMoreToolbar(more));
    }
    return (
      <div className={cx('Crud-actions', 'Crud-bulkActions')}>
        {...children}
      </div>
    );
  }

  bulkActionRender = (btn: ActionSchema, index: number) => {
    const {render, store, fullDataApi, primaryField} = this.props;
    const ctx = store.mergedData;
    const selectedItems = this.getTableSelectedRowsData();
    const unSelectedItems = store.unSelectedItems;
    const ids = selectedItems.map(item =>
      item.hasOwnProperty(primaryField) ? item[primaryField as string] : null
    ).filter(item => item).join(',');
    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: this.state.filterData,
        fullDataApi: fullDataApi,
        disabled:
          btn.disabled ||
          (btn.requireSelected !== false ? (isMobile() && isObject((btn as any)?.api?.data) && Object.keys((btn as any)?.api?.data).includes('SELECTION_IDS') ? false : !selectedItems.length) : false),
        onAction: (e: any, action: any) =>
          this.handleBulkAction(
            selectedItems.concat(),
            unSelectedItems.concat(),
            e,
            action,
            btn
          )
      }
    )
  }

  renderPagination(toolbar: SchemaNode) {
    const { store, render, classnames: cx, alwaysShowPagination } = this.props;

    const { page, lastPage } = store;

    if (
      store.mode !== 'simple' &&
      store.lastPage < 2 &&
      !alwaysShowPagination
    ) {
      return null;
    }

    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: this.inSmallDialog(),
            activePage: page,
            lastPage: lastPage,
            hasNext: store.hasNext,
            mode: store.mode,
            onPageChange: this.handleChangePage
          }
        )}
      </div>
    );
  }

  renderStatistics() {
    const {
      store,
      classnames: cx,
      translate: __,
      mode
    } = this.props;

    return (
      <div className={cx('Crud-statistics')}>
        {mode == 'cross' ?
          __('CRUD.total', { total: mode == 'cross' ? this.tableStore?.rows?.length : store.data?.total }) :
          __('CRUD.stat', { total: store.total })}
      </div>
    );
  }

  renderSwitchPerPage(childProps: any) {
    const {
      store,
      perPageAvailable,
      classnames: cx,
      classPrefix: ns,
      translate: __
    } = this.props;

    // const items = childProps.items;

    // if (!items.length) {
    //   return null;
    // }

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

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

  renderLoadMore(toolbar: Schema) {
    const { store, classPrefix: ns, classnames: cx, translate: __ } = this.props;
    const { page, lastPage } = store;

    return page < lastPage ? (
      <div className={cx('Crud-loadMore')}>
        <Button
          classPrefix={ns}
          onClick={() =>
            this.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>
    ) : (
      ''
    );
  }

  renderColumnsFilterBtn(toolbar: Schema) {
    const { showColumnsFilter, filterDrawerVisible } = this.state
    const { env } = this.props
    return (
      <Button
        tooltip={'列过滤'}
        size="sm"
        iconOnly
        butColor={showColumnsFilter}
        tooltipContainer={env?.getTopModalContainer || undefined}
        onClick={() => {
          if (this.filterDrawerOpened) {
            this.setState({ filterDrawerVisible: true })
          } else {
            const value = localStorage.getItem(this.props.name ?? '')
            if (value) {
              const obj = JSON.parse(value)
              Object.keys(obj).forEach(key => this.tableStore?.filterColumns.set(key, obj[key]))
            }
            if (showColumnsFilter) {
              this.filterDrawerOpened = true
              this.setState({ filterDrawerVisible: true })
            } else {
              if (this.props.mode == 'lion-bi-table') {
                this.handleColumnFilter(this.tableStore?.filterColumns)
              } else {
                const total = this.tableStore?.handleMutilSort(this.props.loadDataOnce)
                if (total != undefined) this.setTotal(total)
              }
              this.setState({ showColumnsFilter: !showColumnsFilter })
            }
          }
        }}
      >
        {toolbar?.icon ?
          <Icon icon={toolbar?.icon} className="icon" symbol /> :
          <Icon icon="packet-filtery" className="icon" />}
        {toolbar?.label && toolbar?.label}
      </Button>
    )
  }

  renderToolAction(
    toolbar?: any,
    index: number = 0,
    childProps: any = {},
    toolbarRenderer?: (toolbar: SchemaNode, index: number) => React.ReactNode
  ) {
    const { classnames: cx, translate: __, env } = this.props;
    const { toolActionSwitch } = this.state
    return <Popover placement="bottomLeft"
      overlayClassName={cx('Tool-action')}
      getPopupContainer={env.getModalContainer}
      onVisibleChange={(visible) => { this.setState({ toolActionSwitch: visible }) }}
      trigger={isMobile() ? 'click' : 'hover'}
      visible={toolActionSwitch} overlay content={
        <>
          <div className={cx('Tool-action-body')}
            onClick={(e) => { this.setState({ toolActionSwitch: false }) }}
          // onMouseEnter={() => { this.setState({ toolActionSwitch: true }) }}
          // onMouseLeave={() => { this.setState({ toolActionSwitch: false }) }}
          >
            {toolbar.toolBarItems.map((toolbar: any, index: number) => this.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>
  }
  exchangeMode = () => {
    const { listItem, card, cross } = this.props;
    const { modes } = this.state;
    if (card && listItem && cross) {
      return
    }
    if (modes == 'table' || modes == undefined) {
      this.setState({ modes: listItem ? 'list' : cross ? 'cross' : 'cards' }, this.handleFakeAnimation)
    } else {
      this.setState({ modes: 'table' }, this.handleFakeAnimation)
    }
  }
  //函数防抖，3s内只触发第一次
  debounceChangeMode = debounce(this.exchangeMode.bind(this), 3000, { leading: true, trailing: false })
  handleFakeAnimation = debounce(() => {
    // // 加载假动画 在线上没问题amis上有问题
    setTimeout(() => {
      this.control?.props?.setLoading?.(true)
    }, 0);
    setTimeout(() => {
      this.control?.props?.setLoading?.(false)
    }, 1000);
  }, 1000)
  renderType(schema?: any) {
    const { ctx, classnames: cx, classPrefix: ns, translate: __, card, listItem, cross, env } = this.props;
    const { modes } = this.state
    return (
      <>
        <LionCopyItem
          showItems={[{
            value: schema.name ?? schema.labelId ?? "",
            label: __('Alert.copyName'),
            icon: "fa fa-sticky-note-o"
          }]}
          env={this.props?.env!}
        >
          {/* 没有卡片和列表项的报文的时候不进行渲染按钮入口 */}
          <Popover placement="bottomLeft" overlayClassName={cx('Tool-action')} getPopupContainer={env.getModalContainer} trigger={['click']} content={() => {
            if (!(listItem && card && cross)) return
            return <div className='crud-mode-exchange'>
              <Button
                disabled={modes == 'table' || modes == undefined}
                classPrefix={ns}
                onClick={() => {
                  this.setState({ modes: 'table' }, this.handleFakeAnimation)
                }} size="sm"
              >
                <Icon icon={'#icon-tooltool_list'} className="icon" symbol />
                表格
              </Button>
              {listItem && <Button
                disabled={modes == 'list'}
                classPrefix={ns}
                onClick={() => {

                  this.setState({ modes: 'list' }, this.handleFakeAnimation)
                }} size="sm"
              >
                <Icon icon={'#icon-tooltool_column'} className="icon" symbol />
                列表
              </Button>}
              {card && <Button
                disabled={modes == 'cards'}
                classPrefix={ns}
                onClick={() => {
                  this.setState({ modes: 'cards' }, this.handleFakeAnimation)
                }} size="sm"
              >
                <Icon icon={'#icon-tooltool_table'} className="icon" symbol />
                卡片
              </Button>}
              {cross && <Button
                disabled={modes == 'cross'}
                classPrefix={ns}
                onClick={() => {
                  this.setState({ modes: 'cross' }, this.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: this.state.autoWidth ? '#005bff' : '#000', stroke: '#005bff' }} icon="auto-width" className="icon" />}
              {schema?.label && schema?.label}
            </Button>
          </Popover>
        </LionCopyItem>
      </>
    );
  }
  renderAiTool(action: Action) {
    // if (isMobile()) return null
    const newData = createObject(
      this.props.store.filterData,
      this.props.store.query,
      {},
      true
    );
    const { curApiForCache = '' } = this.props.store.getRawCacheData()
    return (
      <AiTool
        pageId={this.props.name ?? ''}
        env={{ ...this.props.env, container: this.crudRef?.current }}
        action={action}
        data={newData}
        paramData={curApiForCache}
        render={this.props.render}
      />
    )
  }

  renderAggregate() {
    const { aggregate, classnames: cx, render, store } = this.props;
    if (aggregate) {
      const query = { ...store.query, ...this.state.filtercont }
      if (query.advancedFilter) {
        query.advancedFilter = query.advancedFilter.filter((item: any) => {
          if (this.advancefilterValueIsLegalEmptyValue(item)) {
            return false
          }
          return true
        })
      }
      return (
        <div className={cx('Table-statistics', isMobile() ? 'Table-statistic-mobile' : '')}>
          {render('aggregate', aggregate, { items: this.getTableRowsData(), query })}
        </div>
      )
    }
    return null
  }

  renderFilterToggler() {
    const { store, classnames: cx, translate: __ } = this.props;

    if (!store.filterTogggable) {
      return null;
    }

    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>
    );
  }

  renderAutoWidth(toolbar: Schema) {
    const { env } = this.props

    return (
      <Button
        tooltip={this.state.autoWidth ? '宽松列宽' : '紧凑列宽'}
        size="sm"
        iconOnly
        butColor={this.state.autoWidth}
        tooltipContainer={env?.getTopModalContainer || undefined}
        onClick={() => {
          const autoWidthPage = getLocalStorage('autoWidthPage') || {}
          autoWidthPage[this.props.name || ''] = !this.state.autoWidth
          setLocalStorage('autoWidthPage', autoWidthPage)
          this.setState({ autoWidth: !this.state.autoWidth })
        }}
      >
        {toolbar?.icon ?
          <Icon icon={toolbar?.icon} className="icon" symbol /> :
          <Icon style={{ width: '14px', height: '15px', fill: this.state.autoWidth ? '#005bff' : '#000', stroke: '#005bff' }} icon="auto-width" className="icon" />}

        {toolbar?.label && toolbar?.label}
      </Button>
    );
  }
  renderExportCSV(toolbar: Schema) {
    const {
      store,
      classPrefix: ns,
      classnames: cx,
      translate: __,
      loadDataOnce
    } = this.props;

    const api = (toolbar as Schema).api;

    return (
      <Button
        classPrefix={ns}
        onClick={() =>
          store.exportAsCSV({
            loadDataOnce,
            api
          })
        }
        size="sm"
      >
        {toolbar.label || __('CRUD.exportCSV')}
      </Button>
    );
  }

  renderExport(toolbar: Schema) {
    const {
      store,
      classPrefix: ns,
      classnames: cx,
      translate: __,
      env
    } = this.props;

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

    return (
      <LionCopyItem
        showItems={[{
          value: toolbar.name ?? toolbar.labelId ?? "",
          label: __('Alert.copyName'),
          icon: "fa fa-sticky-note-o"
        }]}
        env={this.props?.env!}
      >
        <div style={{ position: 'relative' }} className='exportExcel'>
          <Button
            classPrefix={ns}
            onClick={(e) => { this.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>
    );
  }

  /**
   * Jay
   * 标签、文件打印
   */
  renderPrint(schema?: any, isFilePrint?: boolean) {
    const {
      store,
      classPrefix: ns,
      classnames: cx,
      translate: __,
      primaryField
    } = this.props;
    const selectedItems = this.getTableSelectedRowsData();

    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: this.getTableRowsData(), // 选中行数据
      selectedItems, // 选中行数据
      ids,
      primaryField
    });
    return (
      <>
        <LionCopyItem
          showItems={[{
            value: schema.name ?? schema.labelId ?? "",
            label: __('Alert.copyName'),
            icon: "fa fa-sticky-note-o"
          }]}
          env={this.props?.env!}
        >
          <Button
            disabled={schema.disabled || evalExpression(schema.disabledOn, ctx)}
            classPrefix={ns}
            onClick={() => {
              const LODOP = getLodop();
              if (LODOP) {
                this.setState({
                  ModalProps: {
                    ...schema,
                    show: true,
                    ctx,
                    onHide: () => {
                      this.setState({ printType: undefined });
                    }
                  },
                  printType: isFilePrint
                    ? 'file'
                    : schema.actionType === 'label-print'
                      ? 'label'
                      : 'bill'
                });
              }
            }}
            size="sm"
          >
            {__(
              schema.label
                ? schema.label
                : !isFilePrint
                  ? 'CRUD.labelPrint'
                  : 'CRUD.filePrint'
            )}
          </Button>
        </LionCopyItem>
      </>
    );
  }

  // Aug
  private moreHandleTouch(e: React.TouchEvent<HTMLDivElement>) {
    e.stopPropagation();
    this.setState({ moreIsOpened: true });
  }

  renderActionGroup(toolbar: any, index: number, childProps: any) {
    const {
      size,
      block,
      className,
      translate: __,
      classnames: cx,
      classPrefix: ns,
      groupName,
      groupLevel,
    } = this.props;


    return <Popover
      content={() => {
        return <div className={cx('Group-action-items')}>
          {toolbar.actionItems.map((_: SchemaNode) => {
            return this.renderToolbar(_, index, childProps)
          })}
        </div>
      }}>
      <Button
        className={cx('Group-display-button', className)}
        level={groupLevel || 'primary'}
        block={block}
        size={size}>
        <span className={cx('Group-text')}>
          {toolbar.groupName}
        </span>
        <span className={cx('Group-icon')}>
          <Icon icon={'#icon-tooltool_down'} className="icon" symbol />
        </span>
      </Button>
    </Popover>
  }
  // Aug更多操作
  renderMoreToolbar(children: Array<any>) {
    const {
      classnames: cx,
      translate: __,
      env: { getModalContainer },
      render
    } = this.props;

    return (
      <ActionSheet
        key={Date.now() + '-actionSheet'}
        isOpened={this.state.moreIsOpened}
        container={getModalContainer}
        round
        onHide={(e: any) => {
          e.stopPropagation();
          this.setState({ moreIsOpened: 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();
                    this.setState({ moreIsOpened: false });
                  }}
                >
                  {child.dom || child}
                </div>
              );
            })}
          </div>
        }
      >
        <span
          className={cx('Button', 'Button--link')}
          onClick={this.moreHandleTouch.bind(this)}
        >
          <i className={cx('Button-icon', 'fa', 'fa-reorder')}></i>
          <span>{__('More')}</span>
        </span>
      </ActionSheet>
    );
  }
  toolBarAction = () => {
    this.reload(undefined, undefined, undefined);
  }
  renderReload = (toolbar, index) => {
    const {
      render,
      translate: __,
    } = this.props;
    if (toolbar.isToolBar && isMobile()) {
      return (
        <div className='toolbar-item' onClick={() => this.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: this.toolBarAction
      });
    }
  }
  tableToolRef: React.RefObject<HTMLDivElement> = React.createRef();
  ellipsisFlag = false;
  renderToolbar(
    toolbar?: SchemaNode,
    index: number = 0,
    childProps: any = {},
    toolbarRenderer?: (toolbar: SchemaNode, index: number) => React.ReactNode,
    // Jay
    isFooter?: boolean
  ) {
    if (!toolbar) {
      return null;
    }
    const {
      render,
      store,
      translate: __,
      useMobileUI,
      headerBulkActions,
      footerBulkActions,
      inModal,
      card,
      listItem,
      cross
    } = this.props;
    const { modes } = this.state
    const type = (toolbar as Schema).type || toolbar;
    const actionType = (toolbar as Schema).actionType;
    if (type === 'headerBulkActions') {
      return this.renderBulkActions(childProps, isMobile() ? this.unitBulkActions() : headerBulkActions);
    } else if (type === 'data-statics' || type === 'data-cross' || type === 'find-replace' || type === 'data-chart') {
      // 统计模式卡片列表中移除
      if (modes == 'cards' || modes == 'list') {
        return null
      }
    } else if (type === "detail-model") {
      return null
    } else if (type === 'footerBulkActions') {
      return this.renderBulkActions(childProps, footerBulkActions);
    } else if (type === 'pagination') {
      return this.renderPagination(toolbar);
    } else if (type === 'ai-tool') {
      return this.renderAiTool(toolbar as any);
    } else if (type === 'statistics') {
      return this.renderStatistics();
    } else if (type === 'switch-per-page') {
      return this.renderSwitchPerPage(childProps);
    } else if (type === 'load-more') {
      return this.renderLoadMore(toolbar as Schema);
    } else if (type === 'filter-toggler') {
      return this.renderFilterToggler();
    } else if (type === 'auto-width') {
      return this.renderAutoWidth(toolbar as Schema);
    } else if (type === 'export-csv') {
      return this.renderExportCSV(toolbar as Schema);
    } else if (type === 'reload') {
      return this.renderReload(toolbar as Schema, index);
    } else if (actionType === 'label-print' || actionType === 'bill-print') {
      return this.renderPrint(toolbar);
    } else if (actionType === 'export') {
      return this.renderExport(toolbar as Schema)
      // } else if (actionType === "action-group") {
      //   return this.renderActionGroup(toolbar as Schema, index, childProps, this.toolbarRenderer)
    } else if (type === 'file-print') {
      return this.renderPrint(toolbar, true);
    } else if (type === 'columns-filter') {
      if (modes == 'cards' || modes == 'list') {
        return
      }
      return this.renderColumnsFilterBtn(toolbar as Schema)
    } else if (type === 'tool-bar-action') {
      return this.renderToolAction(toolbar, index, childProps, toolbarRenderer)
    } else if (type === 'type-conversion') {
      if (!card && !listItem && !cross || isMobile()) {
        return
      }
      return this.renderType(toolbar)
    } else if (Array.isArray(toolbar)) {
      const children: Array<any> = toolbar
        .filter((toolbar: any) =>
          isVisible(toolbar, inModal ? this.filterData : store.filterData) && !(isMobile() && (toolbar.type == 'columns-toggler' || toolbar.isToolBar))
        )
        .map((toolbar, index) => ({
          dom: this.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;
      const cx = this.props.classnames;
      if (len) {
        // Aug 移动端超过三个显示更多
        if (useMobileUI && isMobile() && len > 3) {
          const moreToolbar = children.splice(2);
          const moreToolbarDom = this.renderMoreToolbar(moreToolbar);
          children.splice(0, 0, { dom: moreToolbarDom, toolbar: { type: 'more' } });
        }
        let button = children.filter(({ toolbar }, index) => toolbar.align == 'right' && !isFooter)
        let leftBtns = children.filter(({ toolbar }, index) => (toolbar.align !== 'right' || isFooter) && toolbar.type !== 'paginator');
        const paginator = children.find(({ toolbar }) => toolbar.type === 'paginator');
        let restBtns = [];
        if(this.tableToolRef?.current) {
          const toolContent = this.tableToolRef.current.querySelector(`.${this.props.classPrefix}Crud-toolbar-tool-content`)
          let flagIndex = leftBtns.length;
          if(toolContent) {
            let widthSum = 0;
            for(let i = 0;i<toolContent.childNodes.length;i++) {
              widthSum += (toolContent.childNodes[i] as HTMLDivElement).clientWidth
              if(widthSum >= toolContent.clientWidth) {
                if(this.ellipsisFlag) {
                  break
                } else {
                  flagIndex = i;
                  this.ellipsisFlag = true;
                }
                break;
              }
            }
            if(this.ellipsisFlag) {
              restBtns = button.slice(flagIndex - 3)
              button = button.slice(0, flagIndex - 3)
            }
          }
        }
        return (
          <div className={cx('Crud-toolbar', { footer: isFooter })} key={index}>
            {leftBtns.length > 0 && <div 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')} ref={this.tableToolRef}>
                <div className={cx('Crud-toolbar-tool-content')}>
                  {button.map(({ toolbar, dom: child }, index) => {
                    return (
                      <div
                        key={index}
                        className={cx(
                          'Crud-toolbar-item',
                          toolbar.className
                        )}
                      >
                        {child}
                      </div>
                    );
                  })}
                  {
                    this.ellipsisFlag && restBtns.length > 0 && <div
                    key={index}
                    className={cx(
                      'Crud-toolbar-item'
                    )}
                    >
                      {render('', {
                        actionGroups: [{"actionItems": restBtns.map(item => ({
                          groupName: item.toolbar.label,
                          children: item.dom
                        }))}],
                        columnNum: 1,
                        groupName: "更多",
                        groupType: 0,
                        actionType: "action-group",
                        type: "action",
                        name: "更多"
                      }, childProps)}
                    </div>
                  }
                </div>
              </div>}
            </div>}
          </div>
        );
      }
      return null;
    }
    const result = toolbarRenderer
      ? toolbarRenderer(toolbar, index)
      : undefined;

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

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

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

  renderFooterToolbar(
    childProps: any,
    toolbarRenderer?: (toolbar: SchemaNode, index: number) => React.ReactNode,
    customToolbar?: any // Aug
  ) {
    let footerToolbar = customToolbar || this.props.footerToolbar; // Aug
    let { toolbar, toolbarInline } = this.props;
    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 this.renderToolbar(
      footerToolbar,
      0,
      childProps,
      toolbarRenderer,
      true
    );
  }

  renderSelection(): React.ReactNode {
    const {
      store,
      classnames: cx,
      labelField,
      labelTpl,
      primaryField,
      translate: __
    } = this.props;

    if (!store.selectedItems.length) {
      return null;
    }
    // this?.tableInstance?.updateAutoFillHeight?.()

    return (
      <div className={cx('Crud-selection')}>
        <div className={cx('Crud-selectionLabel')}>{__('CRUD.selected')}</div>
        {store.selectedItems.map((item, index) => {

          return <div key={index} className={cx(`Crud-value`)}>
            <span
              data-tooltip={__('delete')}
              data-position="bottom"
              className={cx('Crud-valueIcon')}
              onClick={this.unSelectItem.bind(this, item, index)}
            >
              ×
            </span>
            <span className={cx('Crud-valueLabel')}>
              {labelTpl ? (
                <Html html={filter(labelTpl, item)} />
              ) : (
                getVariable(item, labelField || 'label') ||
                getVariable(item, primaryField || 'id')
              )}
            </span>
          </div>
        })}
        <a onClick={this.clearSelection} className={cx('Crud-selectionClear')}>
          {__('clear')}
        </a>
      </div>
    );
  }
  // Aug
  renderFilter(isFilter = false) {
    const {
      filter,
      store,
      useMobileUI,
      render,
      translate: __,
      classnames: cx,
      advancedFilter,
      advancedFilterApi
    } = this.props;
    const mobileUI = useMobileUI && isMobile();
    const { filterExist } = this.state

    if (filter && (!store.filterTogggable || store.filterVisible)) {
      return !mobileUI
        ? render(
          //默认
          'filter',
          {
            title: __('CRUD.filter'),
            mode: 'inline',
            submitText: __('search'),
            ...filter,
            type: 'form',
            api: null
          },
          {
            key: 'filter',
            panelClassName: cx(
              'Crud-filter',
              filter.panelClassName || 'Panel--default'
            ),
            data: store.filterData,
            onReset: this.handleFilterReset,
            onSubmit: this.handleFilterSubmit,
            onInit: this.handleFilterInit,
            formStore: undefined,
            advancedFilterVisible: false,
            advancedFilterApi,
            defaultAdvancedQuery: this.defaultAdvancedQuery,
            getFilterForm: this.getFilterForm, // Jay
            handleFilterAdvanced: this.handleFilterAdvanced,
            advancedFilter: this.props.advancedFilter,
            filtercont: this.state.filtercont,
            handleFilterOptions: this.handleFilterOptions,
            handledelVisible: this.handledelVisible,
            handleReset: this.handleReset,
            tableFilter: true
          }
        )
        :
        <div className={cx('Mobile-filter')} onClick={() =>
          // this.setState({ mobileFilterShow: true })
          this.handleFilterAdvanced()
        }>
          <Icon icon="#icon-tooltool_filter" style={{ color: (filterExist || isFilter) ? '#1890FF' : '#999' }}></Icon>
          <span className={`filter-text ${(filterExist || isFilter) ? 'has-filter' : ''}`}>{__('CRUD.filter')}</span>
        </div >
    } else if (mobileUI && advancedFilter) {
      return <div className={cx('Mobile-filter')} onClick={() =>
        this.handleFilterAdvanced()
      }>
        <Icon icon="#icon-tooltool_filter" style={{ color: (filterExist || isFilter) ? '#1890FF' : '#999' }}></Icon>
        <span className={`filter-text ${(filterExist || isFilter) ? 'has-filter' : ''}`}>{__('CRUD.filter')}</span>
      </div >
    }
    return null;
  }

  filtBoolean = () => {
    const { filtercont: filt } = this.state
    return this.tableStore?.filterColumns?.size > 0 || (filt && Object.keys(filt || {}).length && (filt?.advancedFilter?.length || filt?.advancedFilterSub?.length || Object.keys(filt?.advancedHeader || {}).length) ? true : false);
  }

  // 展示头部判断
  headerCanShow = () => {
    const { header, filter } = this.props
    return !!header || !!filter || this.filtBoolean()
  }

  renderAdvacendFilterQuery() {
    const { classnames, advancedFilter } = this.props
    const { filtercont: filt, filtertpl } = this.state
    const filtboolean: boolean = this.filtBoolean()
    if (!filtboolean) return null
    if (!filtertpl?.length) return null

    const columns = advancedFilter?.body.find((item: any) => item.name == 'advancedFilter')?.body ?? []
    return (
      <Space style={{ padding: '8px 8px 0 8px' }} size={[4, 8]} wrap>
        {filtertpl?.length > 0 && filtertpl.map((item: filterTpl, index: number) => {
          let val
          if (typeof item?.value === "number") {
            if (item?.labelName?.includes(",")) {
              val = (item?.labelName as string).split(",")[0] + "..."
            } else {
              val = item?.labelName
            }
            // } else if (item?.value?.includes(",")) {
            //   val = (item?.valuesAlia || item?.value).split(",")[0] + "..."
          }

          const values = item.value
          if (values && typeof values == 'string' && values.includes('(') && values.includes(')') && columns) {
            // 做一个从小到大的排序
            const compareField = columns.filter((item: any) => values.includes(item.name.split('.').pop())).map((item: any) => item.name.split('.').pop())?.sort((cur: string, next: string) => next.length - cur.length)
            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.split('.').pop() == match);
              if (content) {
                result = (result as string).replace(regex, `[${content.label}]`)
              }
            })
            val = result
          }
          if (!(val ? val : (item?.valuesAlia || item?.value))) return null

          return <Popover getPopupContainer={() => document.getElementById('amis-modal-container')! || document.body} key={item.name + String(index)} content={
            <div className={classnames('Form-query-Tag-content')}>
              <label>{item.label + ":"}</label>
              <span>{(val ? val : (item.labelName || item.valuesAlia || item.value))}</span>
            </div>
          } overlayStyle={{ maxWidth: 500 }}>
            <Tag className={classnames('Form-query')} color="blue" closable onClose={(e) => { this.handledelVisible(item, false, e, item.advancedFilterIndex) }} >
              <span className={classnames('Form-queryConstent')}>
                {item.label + ":" + `${val ? val : (item?.labelName || item?.valuesAlia || item?.value)}`}
              </span>
            </Tag >
          </Popover>
        })
        }
        {filtertpl?.length > 0 &&
          <Tag className={classnames(`Form-site-tag-plus`)} onClick={() => { this.handledelVisible?.(this.props.data, true) }}>
            <Icon icon='#icon-tooltool_delete' symbol></Icon>
          </Tag>
        }
      </Space>
    )
  }

  // Jay
  getTableStore = (store: any) => {
    this.tableStore = store;
  }
  getTableInstance(table: any) {
    this.tableInstance = table;
    this.props.getTableInstance?.(table);
  }
  getFilterColumns() {
    return this.tableStore?.filteredColumns;
  }

  handleAdvanceSearch = async () => {
    const res = await this.advanceFilterForm.validate()
    if (!res) return

    this.handleScrollToTop();
    let queryParams: any =
    {
      ...  this.advanceFilterForm?.confirmAdvancedFilter(), page: 1
    }; // 添加默认设置值为1
    const optionsParam = queryParams?.filterOptionData?.rawOptionsParams
    const rawShowFields = queryParams?.filterOptionData?.rawShowFields
    if (queryParams?.limitParam.limitStatus) {
      queryParams = { ...queryParams, topN: queryParams.limitParam.topN }
    } else {
      queryParams = { ...queryParams, topN: undefined }
    }
    if (this.advancedMode == 'normal' || this.advancedMode == 'popup-normal') {
      const { itemCount, itemSumCount, showFields, sortFields, groupByFields } = optionsParam;
      if (!itemCount && !itemSumCount) {
        if (rawShowFields.length == 0) {
          message.warning('显示字段不能为空');
          return;
        }
      }

      if (sortFields.length > 0 && groupByFields.length > 0) {
        let temp = true;
        for (let i = 0; i < sortFields.length; i++) {
          const sortField = sortFields[i];
          const include = showFields.some((showField: string) => sortField.includes(showField));
          if (!include) {
            temp = false;
            break;
          }
        }
        if (!temp) {
          message.warning('同时使用排序和分组时，排序字段必须出现在显示字段中');
          return;
        }
      }
    }

    const { advancedFilterVisible, filterExist } = this.state
    if (isMobile() && advancedFilterVisible && filterExist) {
      this.setState({ filterExist: false })
    }

    this.props.store.updateQuery(queryParams);
    this.setState({ filtercont: queryParams }, () => {
      this.handlefilters();
      this.search(
        undefined,
        undefined,
        undefined,
        true,
        res => {
          if (optionsParam?.itemCount) {
            if (res.status === 0) {
              const count = res.data.items[0]['ITEM_NUMBER']
              if (count) {
                Modal.info({ icon: null, title: '提示', content: `项数: ${count}`, okText: '确定' })
              }
            }
          }
        },
        undefined,
        undefined,
        queryParams
      );
      this.filterDrawerOpened = false
      this.tableStore?.filterColumns?.clear()
      this.tableStore?.orderColumns?.clear()
      this.setState({ showColumnsFilter: false })
    });
    this.hideAdvancedFilter();
  }

  renderAdvancedFilterAction: React.ReactNode = (
    <>
      <span style={{ display: 'inline-block', marginRight: 10 }}>
        <Button onClick={(e) => {
          this.advanceFilterForm?.resetIsModleFilter(e)
        }}>
          {this.props.translate('reset')}
        </Button>
      </span>
      <Button
        level="primary"
        onClick={() => { this.handleAdvanceSearch() }} >
        {this.props.translate('confirm')}
      </Button>
    </>
  );

  renderAdvancedModalFooter = () => {
    const { defaultList, templateSwitch } = this.state
    return <div className='defaultModal-footer'>
      {!isMobile() && <div className='defaultModal-footer-left'>
        <Button level="primary" disabled={templateSwitch} onClick={() => {
          this.setState({
            templateSwitch: true,
            multipleDefault: '',
            defaultTempKey: ''
          })
        }} >
          + 新增默认
        </Button>
        {templateSwitch ? <div className='template-name'>
          <Input placeholder="请输入模版名称" onChange={(e) => this.setState({ multipleDefault: e.target.value ?? '' })} />
          <Button onClick={() => {
            this.defaultOnOk()
            this.setState({ templateSwitch: false })
          }} >
            <CheckOutlined />
          </Button>
          <Button onClick={() => {
            this.setState({
              templateSwitch: false,
              multipleDefault: defaultList?.[0]?.tempName,
              defaultTempKey: defaultList?.[0]?.tempKey
            })
          }} >
            <CloseOutlined />
          </Button>
        </div> :
          <div>
            {defaultList.length > 0 &&
              <Select
                // allowClear={true}
                className='defaultModal-select-content'
                dropdownClassName={`dropdown-select-style`}
                bordered
                placeholder='全部'
                style={{ textAlign: 'left' }}
                getPopupContainer={this.props.env.getModalContainer}
                defaultActiveFirstOption
                // defaultValue={defaultList.length > 0 ? defaultList[0].tempName : ''}
                value={defaultList.length > 0 ? defaultList[0].tempKey : ''}
                onSelect={(value) => {
                  const item = defaultList.find(item => item.tempKey == value)
                  this.defaultTemplate(item.tempKey, item.tempName)
                  this.defaultOnOk(item.tempName, item.tempKey)
                }}
                onChange={(value) => {
                  if (defaultList[0].tempKey == value) return
                  const item = defaultList.find(item => item.tempKey == value)
                  this.defaultAdvancedQuery(2, { tempName: item.tempName, tempKey: item.tempKey })
                }}
              >
                {defaultList.map(item => (
                  <Select.Option value={item.tempKey} key={item.tempKey} className='defaultModal-select-content-option'>
                    <div className='defaultModal-select-content-option-tempName'>
                      {item.tempName}
                    </div>
                    <div className='defaultModal-select-content-option-click' onClick={e => e.stopPropagation()} >
                      <EditOutlined onClick={e => this.defaultModify(e, item.tempKey, item.tempName)} />
                      <div>
                        <Popconfirm title="确定要删除吗?" onConfirm={() => this.defaultDelete(item.tempKey)} okText={this.props.translate('confirm')} cancelText={this.props.translate('cancel')} >
                          <DeleteOutlined />
                        </Popconfirm>
                      </div>
                    </div>
                  </Select.Option>
                ))}
              </Select>}
          </div>}
      </div>}
      <div className='defaultModal-footer-right'>
        {
          this.props.advancedFilterApi && <>
            <span style={{ display: 'inline-block', marginRight: 10 }}>
              {isMobile() &&
                <Button onClick={() => {
                  // this.defaultAdvancedQuery(1)
                  defaultList.length > 0 && this.setState({ selectTmpShow: true })
                }}>
                  {this.props.translate('application')}
                </Button>
              }
            </span>
            <span style={{ display: 'inline-block', marginRight: 10 }}>
              <Button disabled={templateSwitch} onClick={() => {
                isMobile() && this.setState({ defaultVisible: true })
                !isMobile() && defaultList.length > 0 && this.defaultOnOk(false, false, true)
                // this.defaultAdvancedQuery(2)
              }}>
                {this.props.translate('default')}
              </Button>
            </span>
          </>}

        <span style={{ display: 'inline-block', marginRight: 10 }}>
          <Button onClick={() => {
            this.advanceFilterForm?.resetAdvancedOptionsFilter()
            this.advanceFilterForm?.resetAdvancedFilter()
          }} >
            {this.props.translate('reset')}
          </Button>
        </span>
        <Button
          level="primary"
          onClick={this.handleAdvanceSearch} >
          {this.props.translate('confirm')}
        </Button>
      </div>
    </div>
  }

  editHeader() {
    return <div className='edit-row-header Modle_edit-row-header' >
      <span className='close-edit' onClick={this.hideAdvancedFilter}>
        <Icon icon='title-left' className="icon" style={{ width: '16px', height: '16px' }} />
      </span>
      <div className='close-title'>
        搜索
      </div>
      <span className='close-edit'>
      </span>
    </div>
  }

  handleTableRotate = () => {
    const { tableRotate } = this.state;
    const { classPrefix } = this.props;
    this.setState({ tableRotate: !tableRotate }, () => {
      if (tools.isIOS) {
        const crud = findDOMNode(this) as HTMLElement;
        const container = crud.querySelector(
          `.${classPrefix}Table-content`
        ) as HTMLElement;
        setTimeout(() => {
          const origin = container.scrollLeft;
          container.scrollTo({ left: origin + 1 });
        }, 800)
      }
    });
  }

  clearSelectedItems = () => {
    this.props.store.setSelectedItems([])
  }

  handleAdvanced = () => {

    const {
      render,
      translate: __,
      advancedFilter,
      columns,
      advancedQueryFields,
      filter,
      advancedFilterApi
    } = this.props;

    const {
      advancedFilterVisible,
      filterOptions,
      filtertpl,
      filtercont
    } = this.state;

    return render(
      //默认
      'advancedFilter',
      {
        title: __('CRUD.filter'),
        submitText: __('search'),
        ...this.props.advancedFilter,
        type: 'form',
        api: null
      },
      {
        key: 'advancedFilter',
        onInit: this.handleFilterInit,
        formStore: undefined,
        advancedFilterVisible: isMobile() ? true : advancedFilterVisible,
        advancedFilterApi,
        showAdvancedOption: this.advancedMode == 'normal' || this.advancedMode == 'popup-normal',
        getFilterColumns: this.getFilterColumns,
        getAdvancedFilterForm: (form: any) => {
          // 避免进行重复设置
          if (!this.advanceFilterForm)
            this.advanceFilterForm = form;
        },
        advancedFilter,
        filterOptions,
        filtertpl,
        filtercont,
        filter,
        columns,
        advancedQueryFields,
        handlePrefix: this.handlePrefix.bind(this),
        handleSaveData: this.handleSaveData,
        hideAdvancedFilter: this.hideAdvancedFilter,
        handleActionDisplay: this.handleActionDisplay,
        handleAdvanceSearch: this.handleAdvanceSearch,
        handleFilterOptions: (val: any) => {
          isMobile() && this.handleFilterOptions(val)
        },
        onReset: this.handleFilterReset,
      }
    )
  }

  //移动端处理工具栏按钮中的可批量操作的按钮，加入到headerBulkActions中
  unitBulkActions = () => {
    const { headerToolbar, headerBulkActions, footerToolbar } = this.props;
    const bulkHeaderToolActions = headerToolbar?.filter((item: any) => {
      if (isObject(item.api?.data) && Object.keys(item.api.data).includes('SELECTION_IDS')) return true;
      return false;
    })
    const bulkFooterToolActions = footerToolbar?.filter((item: any) => {
      if (isObject(item.api?.data) && Object.keys(item.api.data).includes('SELECTION_IDS')) return true;
      return false;
    })
    if ((!headerBulkActions || headerBulkActions?.length === 0) && (!bulkHeaderToolActions || bulkHeaderToolActions?.length === 0) && (!bulkFooterToolActions || bulkFooterToolActions?.length === 0)) {
      return headerBulkActions
    } else {
      return ([] as Array<any>).concat(headerBulkActions ?? [], bulkHeaderToolActions ?? [], bulkFooterToolActions ?? [])
    }
  }

  //离线相关函数
  initOffline = async () => {
    const res = await this.hasDownload();
    if (!res) {
      await this.createTable()
    }
    if (this.props.offlineSchema.offlinePageType === 'detail') {
      this.setState({
        offlineFormShow: true
      }, () => this.initOfflineData(res))
    }
  }

  /**
   * 进入离线页面时初始化数据
   * @param hasDownload 是否已下载数据
   */
  initOfflineData = (hasDownload: boolean) => {
    const { name = '', translate: __ } = this.props;
    if (hasDownload) {
      Modal.confirm({
        content: '已有下载数据，是否重新下载？',
        okText: __('Offline.reload'),
        cancelText: __('Offline.continue'),
        onOk: async () => {
          await this.clear(name);
          this.setState({ offlineTemplist: [] })
          this.download();
        },
        onCancel: () => {
          this.offlineOpt()
        }
      })
    } else {
      this.download()
    }
  }

  // 清空表中所有数据
  clear = async (tableName: string): Promise<void> => {
    await Shell.execDelete(tableName);
    await Shell.deleteFile(tableName);
    return Promise.resolve();
  }

  // 模拟假的进度增长
  offlineInterval: any;
  offlineTimeout: any;
  handleOfflineProgress = () => {
    this.offlineInterval = setInterval(() => {
      this.setState((prevState) => ({ offlineProgress: prevState.offlineProgress + 4 }));
    }, 100);

    // 设置一个定时器，让进度条增长到 100 后停止
    this.offlineTimeout = setTimeout(() => {
      clearInterval(this.offlineInterval);
    }, 2400); // 毫秒后停止假的进度增长
  }

  //下载操作
  download = () => {
    this.setState({ offlineLoading: true, offlineStatus: true })
    this.handleOfflineProgress();
    const { env, primaryField, name = '', store } = this.props;
    let params = {};
    if (Object.keys(this.state.filtercont || {}).length) {
      params = {
        advancedFilter: store.query?.advancedFilter,
        advancedHeader: store.query?.advancedHeader,
        advancedFilterSub: store.query?.advancedFilterSub
      }
      if (this.state.filtercont?.filterOptionData) {
        const { optionsParam } = this.state.filtercont?.filterOptionData;
        params = {
          ...params,
          ...optionsParam,
          filterParam: store.query?.filterParam
        }
      }
    }
    env.fetcher(this.props.offlineSchema.source, params).then(async res => {
      let tableData: OfflineData;
      if (!res.ok) {
        message.error(res.msg || '下载数据失败！');
        this.setState({ offlineLoading: false, offlineStatus: false });
        return false;
      }
      try {
        tableData = unGzip(res.data);
      } catch (error) {
        message.error('解压失败!')
        this.setState({ offlineLoading: false, offlineStatus: false })
        return false;
      }
      if (tools.isEmpty(tableData.offlineData)) {
        message.info('暂无数据可下载!')
        this.setState({ offlineLoading: false, offlineStatus: false })
        return false;
      }
      if (checkDuplicateKeys(tableData.offlineData.items, primaryField)) {
        message.warning('主键重复，请调整数据后重试！')
        this.setState({ offlineLoading: false, offlineStatus: false })
        return false;
      }
      /**终端下载资源包 */
      if (tableData.offlineZipResourceDown) {
        const { method, url, requestParam = {} } = tableData.offlineZipResourceDown
        const baseURL = env?.axiosInstance?.defaults?.baseURL || env?.ajaxApi || 'https://sasdev.sanfu.com/saas_dev';
        let downloadResult = await Shell.downloadImgZip(baseURL + url, method, JSON.stringify(requestParam));
        if (downloadResult.success === false) {
          message.error('下载资源包失败');
          this.setState({ offlineLoading: false, offlineStatus: false })
          return false;
        }
      }
      const result = await this.insertMany(name, tableData.offlineData.items, primaryField)
      if (!result) {
        message.error('数据插入失败，请检查数据！');
        return false;
      }
      clearInterval(this.offlineInterval)
      clearTimeout(this.offlineTimeout)
      this.setState({ offlineProgress: 100 }, async () => {
        await this.offlineOpt()
        this.setState({ offlineLoading: false, offlineStatus: false })
      })
      return;
    }).catch(async (err) => {
      //下载数据没数据，后端直接报错，那就执行这里，有坑
      console.error(err)
      try {
        await this.clear(name)
      } catch (error) {
        throw new Error(error)
      }
      this.setState({ offlineLoading: false, offlineStatus: false })
    })
  }
  //获取全部数据
  findAll = async (tableName: string) => {
    if (Shell.hasShell()) {
      let res = await Shell.execFind(tableName)
      if (res.success) {
        var list = res?.data?.content ? JSON.parse(res.data.content) : [];
        return Promise.resolve(list)
      }
      if (res.success === false) {
        message.error(res.msg)
      }
    }
  }
  //创建数据库
  createTable = async (): Promise<void> => {
    const { name = '', primaryField } = this.props;
    return new Promise(async (resolve, reject) => {
      try {
        await Shell.execCreateTable(name, primaryField)
        resolve()
      } catch (error) {
        console.error(error)
        reject()
      }
    })
  }
  //列转化
  columnExchange = (col: any) => {
    const { render, name = '', primaryField, classPrefix: ns, columns, tableLayout } = this.props;
    let width = 0;
    // const hidePrimary = !columns.find((item: obj) => item.name === primaryField)
    if (tableLayout === 'horizontal') {
      const childList = (findDOMNode(this) as HTMLDivElement).querySelector(`.${ns}Table-content`)?.getElementsByTagName('thead')[0].children[0].childNodes
      const index = columns.findIndex((item: obj) => item.name === col.name)
      width = (childList?.[index + 1] as HTMLDivElement)?.clientWidth || 0;
    } else {
      const childList = (findDOMNode(this) as HTMLDivElement).querySelector(`.${ns}Table-content`)?.querySelector(`.${ns}Table-footTable`)?.getElementsByTagName('tbody')[0].childNodes
      const index = columns.findIndex((item: obj) => item.name === col.name)
      const thWidth = ((childList?.[index + 1] as HTMLDivElement)?.childNodes?.[0] as HTMLDivElement)?.clientWidth
      const tdWidth = ((childList?.[index + 1] as HTMLDivElement)?.childNodes?.[1] as HTMLDivElement)?.clientWidth
      width = thWidth > tdWidth ? thWidth : tdWidth
    }
    return {
      title: col.label,
      key: col.name,
      width: col.width || (width > 0 ? width + 10 : 100),
      dataIndex: col.name,
      align: col.align,
      ellipsis: true,
      cellClick: (record: obj) => {
        this.setState({
          currentRow: record,
          offlineFormShow: true,
          offline: false
        })
      },
      render: (text: any, record: obj, index: number) => {
        if (!text) {
          return <span className='text-muted'>-</span>
        }
        if (col.type === 'lion-upload') {
          return render('', { ...col, type: 'offline-image' }, {
            offlineData: text,
            offline: {
              tableName: name,
              primaryKey: primaryField,
              primaryValue: record?.[primaryField]
            }
          })
        }
        if (['radios', 'checkboxes', 'select'].includes(col.type)) {
          return text ? (text as string).split(',').map(data => {
            return col.options.find((item: obj) => item.value === data)?.label
          }).join(',') || text : <span className='text-muted'>-</span >
        }
        if (['select'].includes(col.type)) {
          return col.options?.find((data: obj) => data.value === text)?.label || text
        }
        if (col.type.includes('color')) {
          return render('', { ...col, type: 'color' }, { data: record, showValue: false })
        }
        if (col.type.includes('html')) {
          return text ? render('', { ...col, html: text }) : <span className='text-muted'>-</span >
        }
        if (col.type === 'textarea') {
          return render('', { ...col, label: null, type: 'tpl', defaultOpen: true }, { data: record })
        }
        if (['static-mapping'].includes(col.type)) {
          return text ? col.map?.[text] : <span className='text-muted'>-</span >
        }
        if (['input-date', 'input-datetime', 'input-time', 'input-month', 'input-quarter', 'input-year',
          'date', 'datetime', 'time', 'static-date', 'static-datetime', 'static-time'].includes(col.type)) {
          return text ? render('', { ...col, type: 'date', value: record[col.name] }, {
            value: text,
            data: record,
            name: col.name,
            format: col.format || col.inputFormat
          }) : <span className='text-muted'>-</span>
        }
        if (col.type.includes('switch')) {
          return text == col.trueValue ? col.onText : col.offText
        }
        if (col.type.includes('tpl') || col.type.includes('html')) {
          return render('', { ...col, type: 'tpl' }, { data: record })
        }
        if (['input-number', 'number'].includes(col.type)) {
          return render('', { ...col, type: 'number' }, { data: record, value: record[col.name] })
        }
        if (col.type.includes('input') || col.type.includes('static')) {
          return text ?? <span className='text-muted'>-</span >
        }
        return text
      }
    }
  }

  //批量插入  多条数据  key 列主键
  insertMany = async (tableName: string, dataList: obj[], key: string) => {
    const res = await Shell.execInsert(tableName, dataList, key);
    return Promise.resolve(res.success);
  }

  //更新表中某条数据
  update = async (tableName: string, newData: obj, key: string): Promise<boolean> => {
    const res = await Shell.execUpdate(tableName, [newData], key);
    return Promise.resolve(res.success);
  }

  //删除表中的某条数据
  deleteByKey = async (tableName: string, keyValue?: string, key?: string): Promise<boolean> => {
    const res = await Shell.execDelete(tableName, keyValue, key);
    return Promise.resolve(res.success);
  }

  //查找表中的某条数据
  findByKey = async (tableName: string, keyValue: any, key: string): Promise<obj> => {
    let res = await Shell.execFind(tableName, keyValue, key)
    if (res.success) {
      let result = res?.data?.content ? JSON.parse(res.data.content) : []
      let data = result?.length > 0
        ? typeof result[0] === 'string'
          ? JSON.parse(result[0])
          : result[0]
        : null
      return Promise.resolve(data)
    } else {
      console.error('查找出错', res)
      return Promise.reject();
    }
  }
  //判断是否已经下载过数据
  hasDownload = async (): Promise<boolean> => {
    return new Promise(async (resolve, reject) => {
      var data = await this.findAll(this.props.name || '');
      if (data?.length > 0) {
        resolve(true)
      } else {
        resolve(false)
      }
    })
  }

  //点击离线按钮，切换离线状态
  handleClickOffline = async () => {
    const res = await this.hasDownload();
    Modal.confirm({
      content: '是否确认进入离线模式？',
      okText: '确定',
      cancelText: '取消',
      onOk: async () => {
        this.setState({ offlineFormShow: true }, () => this.initOfflineData(res))
      }
    })
  }
  handleDownload = async () => {
    const res = await this.hasDownload();
    const { name = '', translate: __ } = this.props;
    if (res) {
      Modal.confirm({
        content: '已有下载数据，是否重新下载？',
        okText: __('Offline.reload'),
        cancelText: __('Offline.continue'),
        onOk: async () => {
          await this.clear(name);
          this.setState({ offlineTemplist: [] })
          this.download();
        }
      })
    } else {
      this.download()
    }
  }
  //删除
  handleDelete = () => {
    const { name = '', primaryField } = this.props;
    const { currentRow, offlineTemplist, offlineData } = this.state;
    Modal.confirm({
      content: '是否确认删除本条数据？',
      okText: '确定',
      cancelText: '取消',
      onOk: async () => {
        const value = currentRow?.[primaryField];
        const res = await this.deleteByKey(name, value, primaryField);
        if (res) {
          if (offlineTemplist.includes(value)) {
            const restTmp = offlineTemplist.filter(k => k !== value);
            this.setState({ offlineTemplist: restTmp });
          }
          const deleteIndex = offlineData.findIndex(item => item[primaryField] === value);
          if (deleteIndex != -1) {
            const newData = [...offlineData];
            newData.splice(deleteIndex, 1);
            this.setState({ offlineData: newData, currentRow: null });
            message.success('删除成功！')
          }
        }
      }
    })
  }
  //重置
  resetOfflineData = async () => {
    const { name = '', primaryField } = this.props;
    Modal.confirm({
      content: '是否确认重置数据？',
      okText: '确定',
      cancelText: '取消',
      onOk: async () => {
        this.setState({ offlineLoading: true })
        const res = await Shell.execDelete(name);
        if (!res.success) {
          this.setState({ offlineLoading: false })
          return message.warn('操作失败！')
        }
        const insertRes = await this.insertMany(name, [...this.originOfflineData], primaryField)
        if (!insertRes) {
          this.setState({ offlineLoading: false })
          return message.warn('操作失败！')
        }
        this.setState({
          offlineLoading: false, offlineTemplist: [], offlineData: [...this.originOfflineData],
          offlineProgress: 0, currentRow: null
        })
        message.success('已重置数据')
      }
    })
  }
  //清空
  clearOfflineData = async () => {
    const { name = '' } = this.props;
    Modal.confirm({
      content: '是否确认清空数据？',
      okText: '确定',
      cancelText: '取消',
      onOk: async () => {
        this.setState({ offlineLoading: true });
        await this.clear(name);
        this.setState({
          offlineLoading: false, offlineTemplist: [], offlineProgress: 0,
          offlineData: [], currentRow: null
        });
        message.success('已清空数据')
      }
    })
  }
  //获取数据，渲染离线表格
  offlineOpt = async () => {
    const { name = '', offlineSchema: { columns } } = this.props;
    const shellData = await this.findAll(name);
    this.setState({ offlineData: shellData || [] });
    this.originOfflineData = shellData || [];
    const cols = columns.map(item => this.columnExchange(item));
    this.setState({
      offlineFormShow: true,
      offlineColumns: cols
    }, this.fixOfflineTmpList)
  }
  //临时数据改变时，将临时数据置顶
  fixOfflineTmpList = () => {
    const { offlineTemplist, offlineData } = this.state;
    const { primaryField } = this.props;
    if (offlineTemplist.length) {
      const restData = offlineData.filter(item => !offlineTemplist.includes(item[primaryField]));
      const tempDataList: any[] = offlineTemplist.map(k => offlineData.find(item => item[primaryField] == k)).filter(item => item !== undefined);
      this.setState({ offlineData: [...tempDataList, ...restData] })
    }
  }
  //提交数据
  commitFormData = async (updateData: obj) => {
    const { offlineData, offlineTemplist } = this.state
    const { name = '', primaryField } = this.props;
    const result = await this.update(name, updateData, primaryField);
    if (!result) return message.error('数据更新失败！')
    const data: obj = await this.findByKey(name, updateData?.[primaryField], primaryField);
    const primaryValue = data?.[primaryField]
    if (!offlineTemplist.includes(primaryValue)) {
      this.setState({
        offlineTemplist: [...offlineTemplist, primaryValue]
      })
    }
    if (data) {
      const newData = offlineData.map((item: obj) => {
        if (item?.[primaryField] === data?.[primaryField]) {
          return data
        }
        return item
      })
      this.setState({ offlineData: newData }, this.fixOfflineTmpList)
    }
  }

  //扫码查询
  handleScanCode = async () => {
    return Shell.getScanCode(0, {
      input: true
    }).then((e) => {
      if (e.success === false) {
        return Promise.reject('');
      } else {
        let res = e.data.content;
        res && message.success('扫描成功')
        return this.scanCode(res);
      }
    });
  }
  scanCode = async (code: string) => {
    if (!code) {
      message.error('该码无效！')
    } else {
      const { name = '', primaryField } = this.props;
      const { offlineTemplist } = this.state;
      this.setState({ offlineLoading: true })
      const data = await this.findByKey(name, code, primaryField)
      if (data) {
        const primaryValue = data?.[primaryField]
        if (!offlineTemplist.includes(primaryValue)) {
          this.setState({
            offlineTemplist: [...offlineTemplist, primaryValue]
          }, this.fixOfflineTmpList)
        }
        this.setState({ currentRow: data, offlineFormShow: true, offline: false, codeVisible: false })
      } else {
        message.warning('无对应数据，请重新扫码！')
      }
      this.setState({ offlineLoading: false })
    }
  }
  //上传数据
  handleUpload = async (uploadAction: ActionSchema) => {
    const { offlineTemplist } = this.state;
    if (!offlineTemplist.length) {
      message.warning('当前数据暂未修改或进行扫描，无需上传！')
      return;
    }
    Modal.confirm({
      content: '是否确认上传离线操作数据？',
      okText: '上传',
      okType: 'danger',
      cancelText: '取消',
      onOk: async () => {
        const { name = '', env, primaryField } = this.props;
        const baseURL = env?.axiosInstance?.defaults?.baseURL || env?.ajaxApi || 'https://sasdev.sanfu.com/saas_dev';
        this.setState({ offlineLoading: true, offlineStatus: true })
        this.handleOfflineProgress()
        let uploadResult = await Shell.offlineUloadImg(name, baseURL + '/api/v1/upload/offline/picture', 'post');
        if (uploadResult.success === false) {
          message.error('图片上传失败！')
          this.setState({ offlineLoading: false, offlineStatus: false })
          throw new Error('图片上传失败！')
        }
        try {
          const allData = await this.findAll(name);
          const uploadData = offlineTemplist.map(item => allData.find((row: obj) => row[primaryField] === item))
          let zipData = Gzip(JSON.stringify(uploadData));
          const tmpList = [...offlineTemplist];
          env.fetcher({ url: (uploadAction as any).api.url, method: (uploadAction as any).api.method },
            { data: zipData }, { silent: true }).then(res => {
              if (res.status === 0) {
                clearInterval(this.offlineInterval)
                clearTimeout(this.offlineTimeout)
                this.offlineTimeout = null;
                this.setState({ offlineProgress: 100 }, async () => {
                  message.success(`本次上传成功${offlineTemplist.length}包`);
                  const restData = allData.filter((item: any) => !offlineTemplist.includes(item[primaryField]))
                  this.setState({
                    offlineLoading: false, offlineTemplist: [], offlineProgress: 0,
                    offlineData: restData, offlineStatus: false, currentRow: null
                  });
                  this.originOfflineData = restData;
                  for (const iterator of tmpList) {
                    this.deleteByKey(name, iterator, primaryField)
                  }
                  this.search();
                })
              } else {
                message.error(res.msg || '数据上传失败!')
                this.setState({ offlineLoading: false, offlineStatus: false });
              }
            })
        } catch (err) {
          message.error('提交数据出错！')
          this.setState({ offlineLoading: false, offlineStatus: false })
          throw new Error(err)
        }
      }
    })
  }
  //离线状态时的按钮
  renderOfflineUpload = () => {
    const { offlineSchema } = this.props;
    const uploadAction = offlineSchema.actions.find(item => item.actionType === 'offline-upload')
    return <div>
      <AntdButton size='small' type='primary' onClick={this.handleScanCode}>{offlineSchema?.actionLabel?.codeLabel || '扫码'}</AntdButton>
      {!!uploadAction && <AntdButton size='small' style={{ marginLeft: 12 }} disabled={this.state.offlineTemplist.length < 1} type='primary' onClick={() => this.handleUpload(uploadAction)}>{uploadAction.label}</AntdButton>}
      <AntdButton size='small' style={{ marginLeft: 12, background: '#ffa200', color: '#fff' }} onClick={this.resetOfflineData}>重置</AntdButton>
      <AntdButton size='small' style={{ marginLeft: 12 }} danger type='primary' onClick={this.clearOfflineData}>清空</AntdButton>
    </div>
  }
  //离线上传本地图片
  addOfflineImage = (list: string[], fieldName: string) => {
    const { currentRow } = this.state
    const oldData = currentRow?.[fieldName]
    let valueList: string[] = []
    const info = list.map(item => {
      const name = item.replace('localfile:///', '');
      valueList.push(item)
      return {
        addr: item,
        name,
        fileName: name
      }
    })
    if (oldData.value) {
      const newValue = [oldData.value, ...valueList].join(',')
      const newInfo = [...oldData.info, ...info]
      this.setState({
        currentRow: {
          ...currentRow,
          [fieldName]: {
            value: newValue,
            info: newInfo
          }
        }
      }, () => {
        this.commitFormData({
          ...currentRow,
          [fieldName]: {
            value: newValue,
            info: newInfo
          }
        })
      })
    } else {
      this.setState({
        currentRow: {
          ...currentRow,
          [fieldName]: {
            value: valueList.join(','),
            info
          }
        }
      }, () => {
        this.commitFormData({
          ...currentRow,
          [fieldName]: {
            value: valueList.join(','),
            info
          }
        })
      })
    }
  }
  // 检查数据预留的方法-会被替换掉
  quickEditDataCheck = () => { }
  // 注册检查数据预留的方法
  dataCheckRegist = (fn: any) => this.quickEditDataCheck = fn
  setLoading = (loading: boolean) => {
    this.props.store.markFetching(loading);
  }
  //离线删除本地图片
  delOfflineImage = (fieldName: string, fileIndex: number) => {
    const { currentRow } = this.state;
    const oldData = currentRow?.[fieldName];
    let valueList = oldData.value.split(',')
    let info = [...oldData.info]
    valueList.splice(fileIndex, 1)
    info.splice(fileIndex, 1)
    this.setState({
      currentRow: {
        ...currentRow,
        [fieldName]: {
          value: valueList.join(','),
          info
        }
      }
    }, () => {
      this.commitFormData({
        ...currentRow,
        [fieldName]: {
          value: valueList.join(','),
          info
        }
      })
    })
  }
  //退出离线页面
  offlineClose = async () => {
    const res = await this.hasDownload()
    const { offlineSchema: { offlinePageType } } = this.props;
    if (this.state.offlineStatus) {
      return message.warning('请在数据上传下载完成后再操作！')
    }
    if (res) {
      Modal.confirm({
        content: '当前离线数据未上传，是否确认退出离线模式？',
        okText: '确定',
        cancelText: '取消',
        onOk: () => {
          if (offlinePageType === 'detail') {
            history.back()
          } else {
            this.setState({
              offline: false,
              offlineColumns: [],
              offlineData: [],
              offlineFormShow: false,
              currentRow: null
            })
          }
        }
      })
    } else {
      if (offlinePageType === 'detail') {
        history.back()
      } else {
        this.setState({
          offline: false,
          offlineColumns: [],
          offlineData: [],
          offlineFormShow: false,
          currentRow: null
        })
      }
    }
  }
  getFilterForm = (form: any) => {
    this.filterForm = form;
  }
  offlineFormFooter = () => {
    const { offlineSchema: { actions, actionLabel } } = this.props;
    const uploadAction = actions.find(item => item.actionType === 'offline-upload');
    return <div>
      {!!uploadAction && <AntdButton size='small' type='primary' disabled={this.state.offlineTemplist.length == 0} onClick={() => this.handleUpload(uploadAction)}>{uploadAction.label}</AntdButton>}
      <AntdButton size='small' style={{ marginLeft: 12 }} type='primary' onClick={this.handleDownload}>下载</AntdButton>
      <AntdButton size='small' disabled={!(this.state.offlineData?.length > 0)} style={{ marginLeft: 12 }} onClick={() => {
        this.setState({ offline: true })
        this.offlineForm.current?.closest('.ant-drawer-body')?.scrollTo({ top: 0 })
      }} type='primary'>{actionLabel?.dataLabel || '本次下载信息'}</AntdButton>
    </div>
  }

  defaultOnOk = (tempName?: string | boolean, tempKey?: string | boolean, senior?: boolean) => {
    const { multipleDefault, defaultTempKey } = this.state
    if (tempKey && tempName) {
      const body = {
        tempName: tempName,
        tempKey: tempKey
      }
      this.defaultAdvancedQuery(1, body)
      this.setState({ selectTmpShow: false })
    } else {
      if (!!multipleDefault) {
        let body = {}
        if (defaultTempKey) {
          body = {
            tempName: multipleDefault,
            tempKey: defaultTempKey
          }
        } else {
          body = {
            tempName: multipleDefault,
            tempKey: uuid()
          }
        }

        this.defaultAdvancedQuery(2, body, senior)
        this.setState({
          defaultVisible: false,
          selectTmpShow: false,
          multipleDefault: '',
          defaultTempKey: ''
        })
      } else {
        message.warning('请输入名称')
      }
    }
  }

  defaultClose = () => {
    this.setState({ defaultVisible: false, multipleDefault: '' })
  }

  defaultDelete = (tempKey: string) => {
    this.defaultAdvancedQuery(3, tempKey)
  }

  defaultModify = (e: any, tempKey: string, tempName: string) => {
    e.stopPropagation();
    this.setState({
      defaultVisible: true,
      multipleDefault: tempName,
      defaultTempKey: tempKey
    })
  }

  defaultTemplate = (tempKey: string, tempName: string) => {
    this.setState({
      multipleDefault: tempName,
      defaultTempKey: tempKey
    })
  }

  render() {
    const {
      className,
      bodyClassName,
      filter,
      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
    } = this.props;
    // Aug
    const mobileUI = useMobileUI && isMobile();
    const language = makeTranslator();
    const {
      foldColumns,
      tableRotate,
      flowModalProps,
      offline,
      offlineColumns,
      offlineData,
      offlineFormShow,
      currentRow,
      position,
      offlineLoading,
      offlineProgress,
      offlineStatus,
      offlineTemplist,
      codeVisible,
      codeValue,
      defaultVisible,
      multipleDefault,
      defaultList,
      selectTmpShow,
      filtercont,
      formSwitch,
      modes
    } = this.state;
    const advancedTitle = this.props.tabTitle ?? this.props.aliasTitle ?? '';
    return (
      <div
        ref={this.crudRef}
        className={cx('Crud', className, {
          'is-loading': !mobileUI && store.loading,
          tableRotate
        })}
      >
        <Provider tableCtxMenuStore={tableCtxMenuStore} >
          {/* 移动端或者没有查询条件没有过滤 没有头部的情况下 不渲染此行 */}
          {(!isMobile() || this.headerCanShow()) &&
            <div className={cx('Crud-head')}>
              {/* 页眉 */}
              {
                header && !isMobile() ? render('alert', header, { style: { marginBottom: this.hasToolBars ? 'unset' : '8px' }, cx, pageUniqueMark: this.props.name + 'header', data: store.data }) : null
              }
              {/* {header && !isMobile() ? <TipsContanier
                data={store.data}
                cx={cx}
                style={{ marginBottom: this.hasToolBars ? 'unset' : '8px' }}
                props={this.props}
                contentString={'你好 页眉'}
                tipsContent={header}
                pageUniqueMark={this.props.name + 'header'}
              ></TipsContanier> : null} */}
              {/* 页眉 */}
              {/* 2024/8/7 去除filter隐藏功能 */}
              {/* <div className={cx('Crud-head-filter', { 'Crud-head-height': formSwitch })}>
                {(filter && (!store.filterTogggable || store.filterVisible) || (header && header.length > 0)) && <div className={cx('Crud-head-action')} onClick={() => { this.setState({ formSwitch: !formSwitch }) }}>
                  <Icon icon={formSwitch ? '#icon-tooltool_down' : '#icon-tooltool_up'} symbol className="icon" />
                </div>}
                {formSwitch && <div className={cx('Crud-head-empty')}></div>}
              </div> */}
              {/* Aug 移动端不需要这里的过滤 */}
              {!mobileUI && this.renderFilter()}
              {!mobileUI && this.renderAdvacendFilterQuery()}

            </div>
          }
          {/* Jay 存在勾选框（存在批量按钮或multiple）且不是移动端，则显示详细勾选条目 */}
          {/* Aug 增加 !mobileUI 判断， 移动端不展示详细勾选条目 */}
          {((this.hasBulkActionsToolbar() && this.hasBulkActions()) ||
            multiple) &&
            keepItemSelectionOnPageChange &&
            !mobileUI
            ? this.renderSelection()
            : null}


          {render(
            'body',
            {
              ...rest,
              foldColumns,
              columns: store.columns ?? columns,
              type: modes,
              setLoading: this.setLoading,
              tableLayout: isMobile() ? tableLayout : 'horizontal'
            },
            {
              key: 'body',
              foldColumns,
              tipsHeader: this.props.header,
              tipsFooter: this.props.footer,
              className: cx('Crud-body', bodyClassName),
              ref: this.controlRef,
              autoGenerateFilter: !filter && autoGenerateFilter,
              autoFillHeight: autoFillHeight,
              selectable: !!(
                (
                  (this.hasBulkActionsToolbar() && this.hasBulkActions()) ||
                  pickerMode ||
                  multiple
                ) // Jay multiple true 显示勾选框
              ),
              itemActions,
              multiple:
                multiple === void 0
                  ? (headerBulkActions && headerBulkActions.length > 0) ||
                    (footerBulkActions && footerBulkActions.length > 0)
                    ? true
                    : false
                  : multiple,
              selected:
                pickerMode || keepItemSelectionOnPageChange
                  ? store.selectedItems
                  : undefined,
              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,
              setChildStore: store.setChildStore,
              onAction: this.handleAction,
              onSave: this.handleSave,
              dataCheckRegist: this.dataCheckRegist,
              onSaveOrder: this.handleSaveOrder,
              onQuery: this.handleQuery,
              onSelect: this.handleSelect,
              onPopOverOpened: this.handleChildPopOverOpen,
              onPopOverClosed: this.handleChildPopOverClose,
              onSearchableFromReset: this.handleFilterReset,
              onSearchableFromSubmit: this.handleFilterSubmit,
              onSearchableFromInit: this.handleFilterInit,
              headerToolbarRender: this.renderHeaderToolbar,
              footerToolbarRender: this.renderFooterToolbar,
              crudRenderToolbarFunc: this.renderToolbar,
              bulkActionRender: this.bulkActionRender,
              loadmoreLoading: store.loadmoreLoading,
              markSort: this.markSort,
              // chencicsy
              data: store.mergedData,
              // Aug
              filterRender: this.renderFilter,
              onLoadMore: this.handleLoadMore,
              handleResetData: this.handleResetData,
              loadHasMore: (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)
                )),
              // Jay
              placeholder:
                rest.placeholder ||
                (!this.props.initFetch && !this.state.hasFetch && filter
                  ? 'placeholder.trySearch'
                  : undefined),
              saveColApi: this.props.saveColApi,
              crudName: this.props.name,
              columnInfo: this.props.columnInfo,
              setBorder: this.props.setBorder,
              getTableStore: this.getTableStore,
              getTableInstance: this.getTableInstance,
              setLoading: this.setLoading,
              setTotal: this.setTotal,
              handleMutilSort: this.handleMutilSort,
              handleColumnFilter: this.handleColumnFilter,
              showColumnsFilter: this.state.showColumnsFilter,
              preSortAble: this.props.preSortAble,
              loading: store.loading,
              headerBulkActions: isMobile() ? this.unitBulkActions() : headerBulkActions,
              footerBulkActions,
              clearSelectedItems: this.clearSelectedItems, //清空用户选择
              tableRotate,
              handleTableRotate: this.handleTableRotate,
              handleClickOffline: this.handleClickOffline,
              offlineSchema,
              autoWidth: this.state.autoWidth,
              handleJump: this.handleJump,
              tabsdefer: this.props.tabsdefer,
              filterData: filtercont,
              changeSelectedRow: this.changeSelectedRow,
              getAllData: this.getAllData,
              // originColumns: columns,
              currentSelectedRow: this.currentSelectedRow,
              /** 透传store给ai-tool */
              storeForAiTool: store,
              renderAggregate: this.renderAggregate,
            }
          )}

          {/* 页脚 */}
          {
            footer && !isMobile() ? render('alert', footer, { cx, pageUniqueMark: this.props.name + 'footer', data: store.data }) : null
          }
          {/* {footer && !isMobile() ? <TipsContanier
            data={store.data}
            contentString={'你好 页脚'}
            cx={cx}
            props={this.props}
            tipsContent={footer}
            pageUniqueMark={this.props.name + 'footer'}
          ></TipsContanier> : null} */}
          {/* 页脚 */}
          {/* Aug */}
          <Spinner
            overlay
            size={this.props.formStore ? undefined : 'md'}
            key="info"
            show={store.loading || store.filterLoading}
            className={`${tableRotate ? 'horizontal-mode' : ''}`}
          />

          {/* Jay 打印标签弹窗 */}
          {
            this.state.printType && (
              <ModalPrint
                printType={this.state.printType}
                {...this.props}
                {...this.state.ModalProps}
                columns={this.tableStore?.filteredColumns ?? this.props.columns}
                query={{ ...store.query, ...this.state.filtercont }}
                orderParam={this.tableStore?.orderColumnsParam()}
              />
            )
          }
          <ModalFlow
            visible={this.state.flowModalVisible}
            onClose={reload => {
              this.setState({ flowModalVisible: false, flowModalProps: { flowDetail: undefined } });
              if (reload) {
                this.search(undefined, undefined, true, true);
              }
            }}
            env={this.props.env}
            render={this.props.render}
            onImageEnlarge={onImageEnlarge}
            language={language}
            classnames={cx}
            {...flowModalProps}
          />

          {(filter || advancedFilter) ?
            isMobile() ? <Drawer
              visible={this.state.advancedFilterVisible}
              placement="bottom"
              height={"100%"}
              zIndex={1011}
              forceRender
              className={`${advancedFilter ? 'drawer-advanced' : "row-edit-drawer"}`}
              closable={false}
              getContainer={this.props.env.getTopModalContainer}
              footer={
                advancedFilter ?
                  this.state.advancedFilterAction ? <>
                    {this.renderAdvancedModalFooter()}
                  </> : this.renderAdvancedFilterAction :
                  <AntdButton
                    onClick={() => {
                      this.handleScrollToTop()
                      this.hideAdvancedFilter()
                      this.handleFilterSubmit(this.filterForm.props.data)
                    }}
                    type='primary'>{__('search')}</AntdButton>
              }
              bodyStyle={{ padding: 0 }}
            >
              {
                advancedFilter ? <>
                  {this.handleAdvanced()}
                </> :
                  <>
                    {this.editHeader()}
                    {
                      render('filter', {
                        type: 'form',
                        ...filter,
                        title: '',
                        api: null
                      }, {
                        className: 'Form-advanced',
                        data: store.filterData,
                        onReset: this.handleFilterReset,
                        onSubmit: this.handleFilterSubmit,
                        // onInit: this.handleFilterInit,
                        formStore: null,
                        getFilterForm: this.getFilterForm, // Jay
                        handleFilterAdvanced: this.handleFilterAdvanced,
                        advancedFilter: this.props.advancedFilter,
                        advancedFilterApi: advancedFilterApi,
                        filtercont: this.state.filtercont,
                        filtertpl: this.state.filtertpl,
                        filterMap: this.tableStore?.filterColumns,
                        handleFilterOptions: this.handleFilterOptions,
                        handledelVisible: this.handledelVisible,
                        handleReset: this.handleReset

                      })
                    }
                  </>}

            </Drawer> :
              <Modal
                zIndex={9}
                title={__('CRUD.advancedFilter') + (advancedTitle ? ` - ${advancedTitle}` : '')}
                width={1000}
                className={'Modal-advanced'}
                bodyStyle={{ overflowY: 'auto' }}
                maskClosable={false}
                visible={this.state.advancedFilterVisible}
                onCancel={this.hideAdvancedFilter}
                getContainer={this.props.env.getTopModalContainer}
                footer={<>{this.renderAdvancedModalFooter()} </>}
              >
                {this.handleAdvanced()}
              </Modal> : null
          }

          <DefaultListPopup
            onCancel={() => this.setState({ defaultVisible: false })}
            defaultVisible={defaultVisible}
            defaultList={defaultList}
            defaultOnOk={this.defaultOnOk}
            defaultClose={this.defaultClose}
            defaultDelete={this.defaultDelete}
            multipleDefault={multipleDefault}
            onChange={(tempName) => this.setState({ multipleDefault: tempName })}
            props={this.props}
            defaultModify={this.defaultModify}
            selectTmpShow={selectTmpShow}
            onDrawerCancel={() => this.setState({ selectTmpShow: false })}
            defaultAdvancedQuery={this.defaultAdvancedQuery}
          />
          {<SecondFilterDrawer
            visible={this.state.filterDrawerVisible}
            showColumnsFilter={this.state.showColumnsFilter}
            columns={this.tableStore?.filteredColumns.map((column: any) => ({ type: column.type, name: column.name, label: column.label, groupName: column.groupName, map: column.map, format: column.pristine.valueFormat })) ?? []}
            filterMap={this.tableStore?.filterColumns ?? new Map()}
            getContainer={this.props.env.getModalContainer}
            crudName={this.props.name}
            onClose={() => this.setState({ filterDrawerVisible: false })}
            onCheckedChange={(checked, filterMap, caseSensitive) => {
              this.setState({ showColumnsFilter: checked })
              if (checked) {
                this.tableStore?.update({ filterColumns: filterMap })
                if (this.props.mode == 'lion-bi-table') {
                  this.handleColumnFilter(filterMap, this.tableStore?.orderColumns, caseSensitive)
                } else {
                  const total = this.tableStore?.handleMutilSort(this.props.loadDataOnce, caseSensitive)
                  if (total != undefined) this.setTotal(total)
                }
              } else {
                this.tableStore?.filterColumns.clear()
                if (this.props.mode == 'lion-bi-table') {
                  this.handleColumnFilter(new Map(), this.tableStore?.orderColumns)
                } else {
                  const total = this.tableStore?.handleMutilSort(this.props.loadDataOnce, caseSensitive)
                  if (total != undefined) this.setTotal(total)
                }
              }
            }}
            onConfirm={(filterMap, caseSensitive) => {
              this.tableStore?.update({ filterColumns: filterMap })
              this.setState({ filterDrawerVisible: false })
              if (this.props.mode == 'lion-bi-table') {
                this.handleColumnFilter(filterMap, this.tableStore?.orderColumns, caseSensitive)
              } else {
                const total = this.tableStore?.handleMutilSort(this.props.loadDataOnce, caseSensitive)
                if (total != undefined) this.setTotal(total)
              }
            }}
            translate={__}
            classPrefix={this.props.classPrefix}
            classnames={cx}
          />
          }
          {this.state.fingerModalVisible && <FingerPrintModal visible={this.state.fingerModalVisible} userData={this.fingerprintModalData} env={this.props.env} onClose={() => this.setState({ fingerModalVisible: false })} />}
          {
            offlineLoading && <>
              <div className='offline-progress-mask'>
              </div>
              <div className='offline-progress-spinner'>
                {offlineStatus ?
                  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
                    <div style={{ fontSize: 14, background: '#fcfcfa' }}>正在下载数据，请稍等...</div>
                    <Progress status={'active'} style={{ width: 300, height: 18 }} percent={offlineProgress} size="default" />
                  </div>
                  : <Spin size='large' indicator={<LoadingOutlined style={{ fontSize: 32 }} spin />} spinning={offlineLoading} />
                }
              </div>
            </>
          }
          {
            offlineFormShow && <Drawer
              visible={offlineFormShow}
              width="100%"
              className="offline-drawer"
              closeIcon={<Icon icon='title-left' className="icon" style={{ width: '16px', height: '16px' }} />}
              onClose={this.offlineClose}
              destroyOnClose
              mask={false}
              getContainer={this.props.env.getModalContainer}
              zIndex={11}
              title={this.props.menuName || this.props.aliasTitle || '离线'}
              footer={this.offlineFormFooter()}
            >
              <div
                className='offline-form-container'
                style={{ position: 'relative' }}
                key={currentRow?.[primaryField]}
                ref={this.offlineForm}
              >
                <div className='offline-scan-num'>
                  <div onClick={() => {
                    this.setState({ offline: true })
                    this.offlineForm.current?.closest('.ant-drawer-body')?.scrollTo({ top: 0 })
                  }}>扫描项：{offlineTemplist?.length ?? 0}</div>
                </div>
                {
                  render('', {
                    name: "offlineForm",
                    title: "",
                    type: "form",
                    wrapWithPanel: false,
                    onChange: (values: any, fields: { [key: string]: any }, formPristine: any) => {
                      if (currentRow?.[primaryField]) {
                        this.setState({ currentRow: { ...currentRow, ...fields } })
                        this.commitFormData({ ...currentRow, ...fields })
                      } else {
                        message.warning('请先扫码！')
                      }
                    },
                    data: currentRow,
                    body: this.props.offlineSchema.columns.map(item => {
                      if (item.type === 'lion-upload') {
                        return {
                          ...item,
                          env: this.props.env,
                          type: 'offline-image',
                          formItem: true,
                          offlineData: currentRow?.[item.name],
                          offline: {
                            tableName: this.props.name,
                            primaryKey: primaryField,
                            primaryValue: currentRow?.[primaryField],
                            fieldName: item.name
                          },
                          offlineChange: this.addOfflineImage,
                          offlineDelete: this.delOfflineImage
                        }
                      } else {
                        return {
                          ...item,
                          type: item.type || 'static',
                          value: currentRow?.[item.name],
                          format: item.format || item.inputFormat
                        }
                      }
                    })
                  })
                }
                <div style={{ marginTop: 8, padding: 16, background: '#fff' }}>
                  <AntdButton disabled={!currentRow} style={{ borderRadius: 8 }} onClick={this.handleDelete} danger type='primary' size='large' block >删除</AntdButton>
                </div>
                {
                  codeVisible && <Modal className="scan-code-modal" afterClose={() => {
                    this.setState({ codeValue: '' })
                  }} visible={codeVisible} closable={false}
                    okText="确定" cancelText="取消" width={320} style={{ top: 200 }}
                    maskClosable={false}
                    onCancel={() => {
                      this.setState({ codeVisible: false, codeValue: '' })
                    }}
                    zIndex={1011}
                    onOk={() => {
                      if (codeValue) {
                        this.scanCode(codeValue)
                      } else {
                        message.warn('请输入条码内容!')
                      }
                    }}
                    getContainer={this.props.env.getModalContainer}
                  >
                    <div className="code-input-container">
                      <div className="title">请输入条码内容</div>
                      <div className="input-box">
                        <Input onChange={(e) => {
                          this.setState({ codeValue: e.target.value })
                        }} autoFocus value={codeValue} />
                      </div>
                    </div>
                  </Modal>
                }
                <div
                  onTouchStart={(e) => {
                    e.persist()
                    e.preventDefault()
                    e.stopPropagation()
                    if (e.touches.length > 0) {
                      const touch = e.touches[0];
                      this.startX = touch.clientX; // 记录触摸开始的横坐标
                      this.startY = touch.clientY; // 记录触摸开始的纵坐标
                    }
                  }}
                  // onTouchMove={(e) => {
                  //   e.preventDefault()
                  // }}
                  onTouchEnd={(e) => {
                    e.persist()
                    // e.preventDefault()
                    // e.stopPropagation()
                    if (e.changedTouches.length > 0) {
                      const touch = e.changedTouches[0];
                      const endX = touch.clientX; // 触摸结束的横坐标
                      const endY = touch.clientY; // 触摸结束的纵坐标
                      const moveX = endX - this.startX; // 横向移动距离
                      const moveY = endY - this.startY; // 纵向移动距离
                      if (moveX == 0 && moveY == 0) {
                        // this.handleScanCode()
                      } else {
                        this.setState({
                          position: {
                            x: position.x + moveX,
                            y: position.y + moveY
                          }
                        })
                      }
                    }
                  }}
                >
                  <AntdButton
                    onClick={this.handleScanCode}
                    type="primary" size="large" shape="round"
                    style={{ position: 'fixed', height: '46px', width: '196px', zIndex: '11', left: position.x + 'px', top: position.y + 'px' }}
                    icon={<ScanOutlined />}>{offlineSchema?.actionLabel?.codeLabel || '点击扫码'}</AntdButton>
                  <AntdButton
                    type="link"
                    size="large"
                    style={{ position: 'fixed', backgroundColor: 'rgba(0,0,0,0.26)', color: 'white', paddingLeft: 30, left: position.x + 172 + 'px', top: position.y + 'px', borderColor: 'transparent', width: 104, height: 46, borderTopRightRadius: 40, borderBottomRightRadius: 40 }}
                    onClick={(e) => { e.stopPropagation(); this.setState({ codeVisible: true }) }}
                  >输入</AntdButton>
                </div>
              </div>
            </Drawer>
          }
          {
            offline && <Drawer
              visible={offline}
              width="100%"
              className="offline-drawer"
              closeIcon={<Icon icon='title-left' className="icon" style={{ width: '16px', height: '16px' }} />}
              onClose={() => { this.setState({ offline: false }) }}
              title={this.props.menuName || this.props.aliasTitle || '离线'}
              mask={false}
              getContainer={this.props.env.getModalContainer}
              footer={this.renderOfflineUpload()}
            >
              <div className='offline-table-container' style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
                <div className='offline-scan-num'>
                  <div>扫描项：{offlineTemplist?.length ?? 0}</div>
                </div>
                <div style={{ height: document.body.clientHeight - 38 - 45 - 64, overflow: 'hidden' }}>
                  <VirtualTable tempList={offlineTemplist} bordered rowKey={primaryField} columns={offlineColumns} dataSource={offlineData} scroll={{ y: document.body.clientHeight - 38 - 38 - 45 - 64, x: '100vw' }} />
                </div>
              </div>
            </Drawer>
          }
          {
            !isMobile() && this.state.staticExportShow && <Modal
              title="文件导出"
              visible={this.state.staticExportShow} closable={false}
              okText="确定" cancelText="取消" width={320} style={{ top: 200 }}
              maskClosable={false}
              bodyStyle={{ padding: '8 16' }}
              onCancel={() => {
                this.setState({ staticExportShow: false })
              }}
              zIndex={1011}
              onOk={this.props.mode === 'cross' || this.props.mode === 'lion-bi-table' ? this.handleExportCross : this.handleExportStatic}
              getContainer={this.props.env.getModalContainer}
            >
              <div>
                <div>
                  <div style={{ marginBottom: '4px' }}>导出范围</div>
                  <AntdSelect
                    style={{ width: '100%' }}
                    options={[{ label: '当前页数据', value: '0' }, { label: '选中数据', value: '1' }, { label: '全部数据', value: '2' }]}
                    placeholder={__('Select.placeholder')}
                    value={this.state.staticExportRange}
                    onChange={value => this.setState({ staticExportRange: value })}
                  />
                </div>
                <div style={{ marginTop: '16px' }}>
                  <div style={{ marginBottom: '4px' }}>数据格式</div>
                  <div>
                    <AntdSelect
                      style={{ width: '100%' }}
                      options={[{ label: '保留数据格式', value: '1' }, { label: '导出为原始数据', value: '0' }]}
                      placeholder='导出方式'
                      value={this.state.keepDataFormat}
                      onChange={type => this.setState({ keepDataFormat: type })}
                    />
                  </div>
                </div>
              </div>
            </Modal>
          }
          {
            this.props.store.dialogOpen ?
              render(
                'dialog',
                {
                  ...((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,
                  replace: store.replace
                }
              ) : null
          }
          {
            this.props.store.drawerOpen ?
              render(
                'drawer',
                {
                  ...((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,
                  onAction: this.handleAction,
                }
              ) : null
          }
        </Provider>
      </div>
    );
  }
}

@Renderer({
  type: 'crud',
  storeType: CRUDStore.name,
  isolateScope: true
})
export class CRUDRenderer extends CRUD {
  static contextType = ScopedContext;

  constructor(props: CRUDProps, context: IScopedContext) {
    super(props);
    const scoped = context;
    EventSub.emit(EventEnum.ClearMappingAcahe, this?.props?.name)
    EventSub.emit(EventEnum.ClearSelectCache, this?.props?.name)
    scoped.registerComponent(this);
  }

  componentWillUnmount() {
    super.componentWillUnmount();
    const scoped = this.context as IScopedContext;
    scoped.unRegisterComponent(this);
  }

  reload(subpath?: string, query?: any, ctx?: any, isItemAction?: boolean) {
    const scoped = this.context as IScopedContext;
    if (subpath) {
      return scoped.reload(
        query ? `${subpath}?${qsstringify(query)}` : subpath,
        ctx
      );
    }

    return super.reload(subpath, query, ctx, isItemAction);
  }

  receive(values: any, subPath?: string) {
    const scoped = this.context as IScopedContext;
    if (subPath) {
      return scoped.send(subPath, values);
    }

    return super.receive(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);
  }
}
