import React from 'react';
import { findDOMNode } from 'react-dom';
import { Renderer, RendererProps } from '../factory';
import { SchemaNode, Schema, Action } from '../types';
import { filter } from '../utils/tpl';
import Button from '../components/Button';
import Checkbox from '../components/Checkbox';
import { ListStore, IListStore, IItem } from '../store/list';
import omit = require('lodash/omit');
import {
  anyChanged,
  getScrollParent,
  difference,
  isVisible,
  isDisabled,
  noop,
  isClickOnInput,
  // Jay
  isMobile
} from '../utils/helper';
import {
  isPureVariable,
  resolveVariable,
  resolveVariableAndFilter
} from '../utils/tpl-builtin';
import QuickEdit, { SchemaQuickEdit } from './QuickEdit';
import PopOver, { SchemaPopOver } from './PopOver';
import Sortable from 'sortablejs';
import { TableCell } from './Table';
import Copyable, { SchemaCopyable } from './Copyable';
import { Icon } from '../components/icons';
import {
  BaseSchema,
  SchemaClassName,
  SchemaCollection,
  SchemaExpression,
  SchemaObject,
  SchemaTokenizeableString,
  SchemaTpl,
  SchemaUrlPath
} from '../Schema';
import { ActionSchema } from './Action';
import { SchemaRemark } from './Remark';
import iconMap from '../icons/font';
import { ContextMenu } from './Lion/components/LionContextMenu';
import TipsContanier from '../components/TipsContanier';
import offset from '../utils/offset';
import { getStyleNumber } from '../utils/dom';
import InfinteSroll from './Lion/components/InfinteSroll';
import { Modal, Popover } from 'antd';
import { FileSyncOutlined } from '@ant-design/icons';
import { FileX } from './Lion/components/Upload';
import { isCon } from './Lion/utils/utils';
import { Shell } from '../utils/shell';
import { linkJump, ModleHandleClick, openImageEnlarge } from '../utils/utils';
import Image from '../renderers/Image';

/**
 * 不指定类型默认就是文本
 */
export type ListBodyFieldObject = {
  /**
   * 列标题
   */
  label?: string;

  /**
   * label 类名
   */
  labelClassName?: SchemaClassName;

  /**
   * 绑定字段名
   */
  name?: string;

  /**
   * 配置查看详情功能
   */
  popOver?: SchemaPopOver;

  /**
   * 配置快速编辑功能
   */
  quickEdit?: SchemaQuickEdit;

  /**
   * 配置点击复制功能
   */
  copyable?: SchemaCopyable;
};

export type ListBodyField = SchemaObject & ListBodyFieldObject;

export interface ListItemSchema extends Omit<BaseSchema, 'type'> {
  actions?: Array<ActionSchema>;

  /**
   * 操作位置，默认在右侧，可以设置成左侧。
   */
  actionsPosition?: 'left' | 'right';

  /**
   * 图片地址
   */
  avatar?: SchemaUrlPath;
  /**
    * 图片显示比例
    */
  thumbRatio?: '1:1' | '4:3' | '16:9';
  /**
   * 内容区域
   */
  body?: Array<ListBodyField | ListBodyFieldObject>;

  /**
   * 描述
   */
  desc?: SchemaTpl;

  /**
   * tooltip 说明
   */
  remark?: SchemaRemark;

  /**
   * 标题
   */
  title?: SchemaTpl;

  /**
   * 副标题
   */
  subTitle?: SchemaTpl;

  /**
   * 标签
   */
  tags?: string;

  /**
   * 图标
   */
  icon?: string;
  // Jay
  /**
   * 超过num个折叠按钮
   */
  num?: number;
  /**
   * 行的底部展示
   */
  footable?: boolean | {
    expand: "all"
  };
  // 底部展示的列
  footBody?: { name: string, label: string, type: string, body: any }[]
}

/**
 * List 列表展示控件。
 * 文档：https://baidu.gitee.io/amis/docs/components/card
 */
export interface ListSchema extends BaseSchema {
  /**
   * 指定为 List 列表展示控件。
   */
  type: 'list' | 'static-list';

  /**
   * 标题
   */
  title?: SchemaTpl;

  /**
   * 底部区域
   */
  footer?: SchemaCollection;

  /**
   * 底部区域类名
   */
  footerClassName?: SchemaClassName;

  /**
   * 顶部区域
   */
  header?: SchemaCollection;

  /**
   * 顶部区域类名
   */
  headerClassName?: SchemaClassName;

  /**
   * 单条数据展示内容配置
   */
  listItem?: ListItemSchema;

  /**
   * 数据源: 绑定当前环境变量
   *
   * @default ${items}
   */
  source?: SchemaTokenizeableString;

  /**
   * 是否显示底部
   */
  showFooter?: boolean;

  /**
   * 是否显示头部
   */
  showHeader?: boolean;

  /**
   * 无数据提示
   *
   * @default 暂无数据
   */
  placeholder?: SchemaTpl;

  /**
   * 是否隐藏勾选框
   */
  hideCheckToggler?: boolean;

  /**
   * 是否固顶
   */
  affixHeader?: boolean;

  /**
   * 配置某项是否可以点选
   */
  itemCheckableOn?: SchemaExpression;

  /**
   * 配置某项是否可拖拽排序，前提是要开启拖拽功能
   */
  itemDraggableOn?: SchemaExpression;

  /**
   * 点击卡片的时候是否勾选卡片。
   */
  checkOnItemClick?: boolean;

  /**
   * 可以用来作为值的字段
   */
  valueField?: string;

  /**
   * 大小
   */
  size?: 'sm' | 'base';

  /**
   * 点击列表项的行为
   */
  itemAction?: ActionSchema;
}

export interface Column {
  type: string;
  [propName: string]: any;
}

export interface ListProps
  extends RendererProps,
  Omit<ListSchema, 'type' | 'className'> {
  store: IListStore;
  selectable?: boolean;
  selected?: Array<any>;
  draggable?: boolean;
  onSelect: (
    selectedItems: Array<object>,
    unSelectedItems: Array<object>
  ) => void;
  onSave?: (
    items: Array<object> | object,
    diff: Array<object> | object,
    rowIndexes: Array<number> | number,
    unModifiedItems?: Array<object>,
    rowOrigins?: Array<object> | object,
    resetOnFailed?: boolean
  ) => void;
  onSaveOrder?: (moved: Array<object>, items: Array<object>) => void;
  onQuery: (values: object) => void;
  thumbRatio?: '1:1' | '4:3' | '16:9',
  renderAggregate?: () => JSX.Element
}
interface ListState {
  hideCheckTogglerOpen?: boolean
  toolbarShow: boolean
}
export default class List extends React.Component<ListProps, ListState> {
  static propsList: Array<keyof ListProps> = [
    'header',
    'headerToolbarRender',
    'footer',
    'footerToolbarRender',
    'placeholder',
    'source',
    'selectable',
    'headerClassName',
    'footerClassName',
    'hideQuickSaveBtn',
    'hideCheckToggler',
    'itemCheckableOn',
    'itemDraggableOn',
    'actions',
    'items',
    'valueField',
    'thumbRatio'
  ];
  static defaultProps: Partial<ListProps> = {
    className: '',
    placeholder: 'placeholder.noData',
    source: '$items',
    selectable: false,
    headerClassName: '',
    footerClassName: '',
    affixHeader: true,
    hideCheckToggler: isMobile(),
    thumbRatio: '16:9'
  };

  dragTip?: HTMLElement;
  sortable?: Sortable;
  parentNode?: any;
  body?: any;
  renderedToolbars: Array<string>;
  constructor(props: ListProps) {
    super(props);

    this.handleAction = this.handleAction.bind(this);
    this.handleCheck = this.handleCheck.bind(this);
    this.handleCheckAll = this.handleCheckAll.bind(this);
    this.handleQuickChange = this.handleQuickChange.bind(this);
    this.handleSave = this.handleSave.bind(this);
    this.handleSaveOrder = this.handleSaveOrder.bind(this);
    this.reset = this.reset.bind(this);
    this.dragTipRef = this.dragTipRef.bind(this);
    this.getPopOverContainer = this.getPopOverContainer.bind(this);
    this.affixDetect = this.affixDetect.bind(this);
    this.bodyRef = this.bodyRef.bind(this);
    this.renderToolbar = this.renderToolbar.bind(this);

    const {
      store,
      selectable,
      draggable,
      orderBy,
      orderDir,
      multiple,
      hideCheckToggler,
      itemCheckableOn,
      itemDraggableOn,
    } = props;

    store.update({
      multiple,
      selectable,
      draggable,
      orderBy,
      orderDir,
      hideCheckToggler,
      itemCheckableOn,
      itemDraggableOn
    });

    this.state = {
      hideCheckTogglerOpen: hideCheckToggler ?? false,
      toolbarShow: false
    }

    List.syncItems(store, this.props) && this.syncSelected();
  }

  static syncItems(store: IListStore, props: ListProps, prevProps?: ListProps) {
    const source = props.source;
    const value = props.value || props.items;
    let items: Array<object> = [];
    let updateItems = false;

    if (
      Array.isArray(value) &&
      (!prevProps || (prevProps.value || prevProps.items) !== value)
    ) {
      items = value;
      updateItems = true;
    } else if (typeof source === 'string') {
      const resolved = resolveVariableAndFilter(source, props.data, '| raw');
      const prev = prevProps
        ? resolveVariableAndFilter(source, prevProps.data, '| raw')
        : null;

      if (prev && prev === resolved) {
        updateItems = false;
      } else if (Array.isArray(resolved)) {
        items = resolved;
        updateItems = true;
      }
    }

    updateItems && store.initItems(items);
    Array.isArray(props.selected) &&
      store.updateSelected(props.selected, props.valueField);
    return updateItems;
  }

  componentDidMount() {
    let parent: HTMLElement | Window | null = getScrollParent(
      findDOMNode(this) as HTMLElement
    );
    if (!parent || parent === document.body) {
      parent = window;
    }
    this.updateAutoFillHeight()
    this.parentNode = parent;
    this.affixDetect();
    parent.addEventListener('scroll', this.affixDetect);
    window.addEventListener('resize', this.affixDetect);
  }

  componentDidUpdate(prevProps: ListProps) {
    const props = this.props;
    const store = props.store;

    if (
      anyChanged(
        [
          'selectable',
          'draggable',
          'orderBy',
          'orderDir',
          'multiple',
          'hideCheckToggler',
          'itemCheckableOn',
          'itemDraggableOn'
        ],
        prevProps,
        props
      )
    ) {
      store.update({
        multiple: props.multiple,
        selectable: props.selectable,
        draggable: props.draggable,
        orderBy: props.orderBy,
        orderDir: props.orderDir,
        hideCheckToggler: props.hideCheckToggler,
        itemCheckableOn: props.itemCheckableOn,
        itemDraggableOn: props.itemDraggableOn
      });
    }

    if (
      anyChanged(['source', 'value', 'items'], prevProps, props) ||
      (!props.value &&
        !props.items &&
        (props.data !== prevProps.data ||
          (typeof props.source === 'string' && isPureVariable(props.source))))
    ) {
      List.syncItems(store, props, prevProps) && this.syncSelected();
    } else if (prevProps.selected !== props.selected) {
      store.updateSelected(props.selected || [], props.valueField);
    }
    if (props.tabsdefer !== prevProps.tabsdefer) {
      this.updateAutoFillHeight()
    }
  }

  componentWillUnmount() {
    const parent = this.parentNode;

    parent && parent.removeEventListener('scroll', this.affixDetect);
    window.removeEventListener('resize', this.affixDetect);
  }

  bodyRef(ref: HTMLDivElement) {
    this.body = ref;
  }

  affixDetect() {
    if (!this.props.affixHeader || !this.body) {
      return;
    }

    const ns = this.props.classPrefix;
    const dom = findDOMNode(this) as HTMLElement;
    const afixedDom = dom.querySelector(`.${ns}List-fixedTop`) as HTMLElement;

    if (!afixedDom) {
      return;
    }

    const clip = (this.body as HTMLElement).getBoundingClientRect();
    const offsetY =
      this.props.affixOffsetTop ?? this.props.env.affixOffsetTop ?? 0;
    const affixed = clip.top < offsetY && clip.top + clip.height - 40 > offsetY;

    this.body.offsetWidth &&
      (afixedDom.style.cssText = `top: ${offsetY}px;width: ${this.body.offsetWidth}px;`);
    affixed ? afixedDom.classList.add('in') : afixedDom.classList.remove('in');
    // store.markHeaderAffix(clip.top < offsetY && (clip.top + clip.height - 40) > offsetY);
  }

  getPopOverContainer() {
    return findDOMNode(this);
  }

  handleAction(e: React.UIEvent<any>, action: Action, ctx: object) {
    const { onAction } = this.props;

    // todo
    onAction(e, action, ctx);
  }

  handleCheck(item: IItem) {
    item.toggle();
    this.syncSelected();
  }

  // 0全选 1反选 2不选
  handleCheckAll(index?: number) {
    const { store } = this.props;
    switch (index) {
      case 0:
        store.toggleAll();
        break;
      case 1:
        store.checkReverse();
        break;
      case 2:
        store.clear();
        break;
      case 3:
        store.toggleAll();
        break;
      default:
        store.toggleAll();
        return;
    }
    this.syncSelected();
  }

  syncSelected() {
    const { store, onSelect } = this.props;

    onSelect &&
      onSelect(
        store.selectedItems.map(item => item.data),
        store.unSelectedItems.map(item => item.data)
      );
  }

  updateAutoFillHeight = () => {
    const { autoFillHeight, classPrefix: ns, isPick } = this.props
    if (!this.body) return;
    const listHtml = findDOMNode(this) as HTMLElement;
    const drawerFooter = listHtml.closest(`.${ns}Drawer-content`)?.querySelector(`.${ns}Drawer-footer`);
    // 循环计算父级节点的 pddding，这里不考虑父级节点还可能会有其它兄弟节点的情况了
    let allParentPaddingButtom = 0;
    let parentNode = listHtml;
    while (parentNode) {
      const paddingButtom = getStyleNumber(parentNode, 'padding-bottom');
      const borderBottom = getStyleNumber(parentNode, 'border-bottom-width');
      allParentPaddingButtom =
        allParentPaddingButtom + paddingButtom + borderBottom;
      parentNode = parentNode.parentElement as HTMLElement;
    }

    let tableHeight =
      document.body.clientHeight -
      offset(listHtml).top -
      (drawerFooter ? drawerFooter.clientHeight + 1 : 0) -
      allParentPaddingButtom;
    // tab情况下，后面的table由于display：none，所以offset(table).top为0，所以继承最小的那个

    if (offset(listHtml).top === 0) {
      const tabsContent = listHtml.closest(`.${ns}Tabs-content`) as HTMLDivElement;
      tableHeight =
        document.body.clientHeight -
        offset(tabsContent).top -
        (drawerFooter ? drawerFooter.clientHeight + 1 : 0) -
        allParentPaddingButtom - 24;//多出来的24是tabs-pane的padding
    }
    if (autoFillHeight && tableHeight >= 400) {
      //当表格可展示高度大于350的占满剩余空间
      listHtml.style.height = tableHeight + 'px';
      listHtml.style.maxHeight = 'unset';
    } else {
      listHtml.style.maxHeight = document.body.clientHeight - 38 + 'px';
    }

  }


  handleQuickChange(
    item: IItem,
    values: object,
    saveImmediately?: boolean | any,
    savePristine?: boolean,
    resetOnFailed?: boolean
  ) {
    item.change(values, savePristine);

    if (!saveImmediately || savePristine) {
      return;
    }

    if (saveImmediately && saveImmediately.api) {
      this.props.onAction(
        null,
        {
          actionType: 'ajax',
          api: saveImmediately.api
        },
        values
      );
      return;
    }

    const { onSave, primaryField } = this.props;

    if (!onSave) {
      return;
    }

    onSave(
      item.data,
      difference(item.data, item.pristine, ['id', primaryField]),
      item.index,
      undefined,
      item.pristine,
      resetOnFailed
    );
  }

  handleSave() {
    const { store, onSave, primaryField } = this.props;

    if (!onSave || !store.modifiedItems.length) {
      return;
    }

    const items = store.modifiedItems.map(item => item.data);
    const itemIndexes = store.modifiedItems.map(item => item.index);
    const diff = store.modifiedItems.map(item =>
      difference(item.data, item.pristine, ['id', primaryField])
    );
    const unModifiedItems = store.items
      .filter(item => !item.modified)
      .map(item => item.data);
    onSave(
      items,
      diff,
      itemIndexes,
      unModifiedItems,
      store.modifiedItems.map(item => item.pristine)
    );
  }

  handleSaveOrder() {
    const { store, onSaveOrder } = this.props;

    if (!onSaveOrder || !store.movedItems.length) {
      return;
    }

    onSaveOrder(
      store.movedItems.map(item => item.data),
      store.items.map(item => item.data)
    );
  }

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

    store.reset();
  }

  bulkUpdate(value: object, items: Array<object>) {
    const { store } = this.props;

    const items2 = store.items.filter(item => ~items.indexOf(item.pristine));
    items2.forEach(item => item.change(value));
  }

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

    return store.selectedItems.map(item => item.data);
  }

  dragTipRef(ref: any) {
    if (!this.dragTip && ref) {
      this.initDragging();
    } else if (this.dragTip && !ref) {
      this.destroyDragging();
    }

    this.dragTip = ref;
  }

  initDragging() {
    const store = this.props.store;
    const dom = findDOMNode(this) as HTMLElement;
    const ns = this.props.classPrefix;
    this.sortable = new Sortable(
      dom.querySelector(`.${ns}List-items`) as HTMLElement,
      {
        group: 'table',
        animation: 150,
        handle: `.${ns}ListItem-dragBtn`,
        ghostClass: 'is-dragging',
        onEnd: (e: any) => {
          // 没有移动
          if (e.newIndex === e.oldIndex) {
            return;
          }

          const parent = e.to as HTMLElement;
          if (e.oldIndex < parent.childNodes.length - 1) {
            parent.insertBefore(e.item, parent.childNodes[e.oldIndex]);
          } else {
            parent.appendChild(e.item);
          }

          store.exchange(e.oldIndex, e.newIndex);
        }
      }
    );
  }

  destroyDragging() {
    this.sortable && this.sortable.destroy();
  }

  renderActions(region: string) {
    let {
      actions,
      render,
      store,
      classPrefix: ns,
      classnames: cx,
      headerBulkActions,
      footerBulkActions,
      headerActions
    } = this.props;
    const bulkActions = (headerBulkActions?.length ?? 0) + (footerBulkActions?.length ?? 0)

    let btn;
    actions = Array.isArray(actions) ? actions.concat() : [];
    if(region === 'header') {
      actions = actions.concat(headerActions || [], (headerBulkActions || []).map((item: any) => ({...item, isBulk: true})))
    }
    if (region === 'footer' &&
      !~this.renderedToolbars.indexOf('check-all') &&
      bulkActions > 0 &&
      (btn = this.renderCheckAll())
    ) {
      actions.unshift({
        type: 'button',
        children: btn
      });
    }

    // if (
    //   region === 'header' &&
    //   !~this.renderedToolbars.indexOf('drag-toggler') &&
    //   (btn = this.renderDragToggler())
    // ) {
    //   actions.unshift({
    //     type: 'button',
    //     children: btn
    //   });
    // }

    return Array.isArray(actions) && actions.length ? (
      <div className={cx('List-actions')}>
        {actions.map((action, key) =>
          action.isBulk ? this.props.bulkActionRender?.(action, key) : render(
            `action/${key}`,
            {
              type: 'button',
              ...action
            },
            {
              onAction: this.handleAction,
              key,
              btnDisabled: store.dragging
            }
          )
        )}
      </div>
    ) : null;
  }

  renderHeading() {
    let { title, store, hideQuickSaveBtn, classnames: cx, data } = this.props;

    if (title || (store.modified && !hideQuickSaveBtn) || store.moved) {
      return (
        <div className={cx('List-heading')}>
          {store.modified && !hideQuickSaveBtn ? (
            <span>
              {`当前有 ${store.modified} 条记录修改了内容, 但并没有提交。请选择:`}
              <button
                type="button"
                className={cx('Button Button--xs Button--success m-l-sm')}
                onClick={this.handleSave}
              >
                <Icon icon="check" className="icon m-r-xs" />
                提交
              </button>
              <button
                type="button"
                className={cx('Button Button--xs Button--danger m-l-sm')}
                onClick={this.reset}
              >
                <Icon icon="close" className="icon m-r-xs" />
                放弃
              </button>
            </span>
          ) : store.moved ? (
            <span>
              {`当前有 ${store.moved} 条记录修改了顺序, 但并没有提交。请选择:`}
              <button
                type="button"
                className={cx('Button Button--xs Button--success m-l-sm')}
                onClick={this.handleSaveOrder}
              >
                <Icon icon="check" className="icon m-r-xs" />
                提交
              </button>
              <button
                type="button"
                className={cx('Button Button--xs Button--danger m-l-sm')}
                onClick={this.reset}
              >
                <Icon icon="close" className="icon m-r-xs" />
                放弃
              </button>
            </span>
          ) : title ? (
            filter(title, data)
          ) : (
            ''
          )}
        </div>
      );
    }

    return null;
  }

  renderTools = () => {
    const {
      headerToolbar,
      translate: __,
      classnames: cx,
      env,
      store,
      data,
      filterRender,
      isPick,
      clearSelectedItems,
      crudRenderToolbarFunc,
      multiple,
    } = this.props;
    if (!headerToolbar?.length) return null;
    const { hideCheckTogglerOpen } = this.state

    /** 折叠在工具里的tools */
    const foldedHeaderTools = [];
    /** 在筛选/多选右侧的tools */
    const unfoldedHeaderTools = [];
    headerToolbar.forEach((item) => {
      const { type, isToolBar, foldable } = item;
      /** 是否是移动端的工具 */
      if (isToolBar) {
        /** foldable: 是否归到折叠菜单中 */
        /** 配置非折叠的工具 */
        if (!foldable) {
          unfoldedHeaderTools.push(item);
        } else {
          foldedHeaderTools.push(item);
        }
      }
    });
    {
      /* 搜索 */
    }
    const isFilter = !!Object.keys(data.filterParam || {}).length;
    const filterNode = filterRender && filterRender(isFilter);
    {
      /* 批量 */
    }
    const checkAll =
      isPick && multiple ? (
        this.renderCheckAll()
      ) : this.props.headerBulkActions?.length ||
        this.props.footerBulkActions?.length ? (
        <span
          className={cx('Mobile-batch-manage', {
            'is-active': !store.hideCheckToggler
          })}
          onClick={e => {
            e.preventDefault();
            clearSelectedItems?.();
            store.toggableHideCheck();
            store.clear();
            this.setState({ hideCheckTogglerOpen: !hideCheckTogglerOpen })
          }}
        >
          {store.hideCheckToggler ? (
            <>
              {/* <i className="fa fa-tasks batch-manage-icon"></i> */}
              <Icon icon="#icon-tooltool_list" className="batch-manage-icon" />
              <span className="batch-text">{__('CRUD.select')}</span>
            </>
          ) : (
            __('Wizard.finish')
          )}
        </span>
      ) : null;
    return (<>
      {foldedHeaderTools?.length ? (<Popover showArrow={false} placement="bottom" getPopupContainer={env.getModalContainer}
        trigger="click" overlayClassName="table-toolbar-pop" autoAdjustOverflow visible={this.state.toolbarShow}
        onOpenChange={(open) => this.setState({ toolbarShow: open })}
        content={
          <div className='toolbar-container' onClick={() => this.setState({ toolbarShow: false })}>
            {
              foldedHeaderTools.map((item: any, index: number) => {
                return this.renderToolbar(item) ?? crudRenderToolbarFunc(item);
              })
            }
          </div>}>
        <div className={cx('Mobile-batch-manage')} onClick={() => this.setState({ toolbarShow: true })}>
          {/* <i className="fa fa-cog" aria-hidden="true"></i> */}
          <Icon icon='#icon-toolbox' className="icon" />
          <span className='batch-text'>{__('Table.tools')}</span>
        </div>
      </Popover>) : null}
      {/* 前端维护的固定的刷新/筛选 */}
      {filterNode}
      {checkAll}

      {/* 手动配置的 展示在右侧的按钮 */}
      {
        unfoldedHeaderTools.map((item) => {
          return (
            <div className={cx('Mobile-batch-manage')}>
              {this.renderToolbar(item) ?? crudRenderToolbarFunc(item)}
            </div>
          )
        })
      }
    </>)
  }

  renderHeader() {
    const {
      header,
      headerClassName,
      headerToolbarRender,
      render,
      showHeader,
      store,
      data,
      translate: __,
      classnames: cx
    } = this.props;

    const { hideCheckTogglerOpen } = this.state

    if (showHeader === false) {
      return null;
    }

    // Aug
    if (isMobile()) {
      return <div className={cx('Mobile-header-toolbar-wrapper')}>
        {/* 页眉 */}
        {/* {this.props.tipsHeader ? <TipsContanier
          data={store.data}
          cx={cx}
          props={this.props}
          contentString={'你好 页眉'}
          tipsContent={this.props.tipsHeader}
          pageUniqueMark={this.props.name + 'header'}
        ></TipsContanier> : null} */}
        {
          this.props.tipsHeader && isMobile() ? render('alert', this.props.tipsHeader, { cx, pageUniqueMark: this.props.name + 'header', data: store.data }) : null
        }
        {/* 页眉 */}
        <div style={{ marginTop: '4px' }}>
          <div className="filter-conditions">
            {typeof data.total == 'number' ? __('CRUD.total', { total: data.total }) : null}
            {data.selectedItems?.length ? (
              <span
                style={{ marginLeft: 10 }}
              >{__('CRUD.checked', { count: data.selectedItems.length })}</span>
            ) : null}
          </div>
          <div className="header-btns">
            {this.renderTools()}
          </div>
        </div>
      </div>
    }
    const child = headerToolbarRender
      ? headerToolbarRender(
        {
          ...this.props,
          selectedItems: store.selectedItems.map(item => item.data),
          items: store.items.map(item => item.data),
          unSelectedItems: store.unSelectedItems.map(item => item.data)
        },
        this.renderToolbar,
        isMobile() ? null : this.renderPageNation
      )
      : null;
    const actions = this.renderActions('header');

    const toolbarNode =
      actions || child || store.dragging ? (
        <div
          className={cx('List-toolbar', headerClassName)}
          key="header-toolbar"
        >
          {actions}
          {child}
          {store.dragging ? (
            <div className={cx('List-dragTip')} ref={this.dragTipRef}>
              请拖动左边的按钮进行排序
            </div>
          ) : null}
        </div>
      ) : null;
    const headerNode =
      header && (!Array.isArray(header) || header.length) ? (
        <div className={cx('List-header', headerClassName)} key="header">
          {render('header', header)}
        </div>
      ) : null;
    return headerNode && toolbarNode
      ? [headerNode, toolbarNode]
      : headerNode || toolbarNode || null;
  }

  renderPageNation = () => {
    const {
      footerClassName,
      footerToolbar,
      footerToolbarRender,
      store,
      classnames: cx
    } = this.props;
    let _footer = footerToolbar || [];
    const child = footerToolbarRender
      ? footerToolbarRender(
        {
          ...this.props,
          selectedItems: store.selectedItems.map(item => item.data),
          items: store.items.map(item => item.data),
          unSelectedItems: store.unSelectedItems.map(item => item.data)
        },
        this.renderToolbar,
        isMobile() ? _footer : _footer.filter((item: any) => item.align == 'right')
      )
      : null;

    const actions = this.renderActions('footer');

    const toolbarNode =
      actions || child ? (
        <div
          className={cx('List-toolbar', 'List-toolbar-page', footerClassName, isMobile() ? 'List-toolbar-mobile' : '')}
          key="footer-toolbar"
        >
          {actions}
          {child}
        </div>
      ) : null;
    return toolbarNode;
  }

  renderFooter() {
    const {
      footer,
      footerClassName,
      footerToolbar,
      footerToolbarRender,
      render,
      showFooter,
      headerToolbar,
      store,
      headerActions,
      classnames: cx
    } = this.props;
    if (showFooter === false) {
      return null;
    }
    let _footer = footerToolbar || [];
    if (isMobile()) {
      // 勾选批量状态时
      if (!store.hideCheckToggler) {
        _footer = ['headerBulkActions', 'footerBulkActions'];
      } else {
        if (headerToolbar) {
          // 移动端将所有操作统一放在在底部
          _footer = _footer.concat(headerActions || [], headerToolbar);
        }
        // 非勾选状态不渲染批量操作 分页也不渲染
        _footer = _footer.filter((item: any) => {
          const type = (item as Schema).type || item;
          return ![
            'bulk-actions',
            'headerBulkActions',
            'footerBulkActions',
            'bulkActions',
            'pagination',
            'statistics',
            'switch-per-page',
          ].includes(type);
        });
      }
      const child = footerToolbarRender
        ? footerToolbarRender(
          {
            ...this.props,
            selectedItems: store.selectedItems.map(item => item.data),
            items: store.items.map(item => item.data),
            unSelectedItems: store.unSelectedItems.map(item => item.data)
          },
          this.renderToolbar,
          isMobile() ? _footer : _footer.filter((item: any) => item.align == 'right')
        )
        : null;
      const actions = this.renderActions('footer');
      const toolbarNode =
        actions || child ? (
          <div
            className={cx('List-toolbar', footerClassName, isMobile() ? 'List-toolbar-mobile' : '')}
            key="footer-toolbar"
          >
            {actions}
            {child}
          </div>
        ) : null;
      const footerNode =
        footer && (!Array.isArray(footer) || footer.length) ? (
          <div className={cx('List-footer', footerClassName)} key="footer">
            {render('footer', footer)}
          </div>
        ) : null;
      return footerNode && toolbarNode ? [toolbarNode, footerNode] : footerNode || toolbarNode || null;
    }
    return null;
  }

  renderCheckAll() {
    const { store, multiple, selectable, classPrefix: ns, } = this.props;

    if (
      !store.selectable ||
      !multiple ||
      !selectable ||
      store.dragging ||
      !store.items.length
    ) {
      return null;
    }
    if (isMobile() && this.state.hideCheckTogglerOpen) {
      return null;
    }
    return (
      <ContextMenu
        menuItems={[
          { id: 0, title: '全选' },
          { id: 1, title: '反选' },
          { id: 2, title: '不选' }
        ]}
        onItemClick={index => this.handleCheckAll(index)}
        key={Date()}
      >
        <th onClick={() => { this.handleCheckAll(3) }}>
          <Checkbox
            classPrefix={ns}
            partial={!store.allChecked}
            checked={store.someChecked}
            disabled={store.disabledHeadCheckbox}
          // onChange={this.handleCheckAll}
          />
        </th>
      </ContextMenu>
    );
  }

  renderDragToggler() {
    const { store, multiple, selectable, env } = this.props;

    if (!store.draggable || store.items.length < 2) {
      return null;
    }

    return (
      <Button
        iconOnly
        key="dragging-toggle"
        tooltip="对列表进行排序操作"
        tooltipContainer={
          env?.getTopModalContainer || undefined
        }
        size="sm"
        active={store.dragging}
        onClick={(e: React.MouseEvent<any>) => {
          e.preventDefault();
          store.toggleDragging();
          store.dragging && store.clear();
        }}
      >
        <Icon icon="exchange" className="icon r90" />
      </Button>
    );
  }

  renderToolbar(toolbar: SchemaNode, index?: number) {

    const type = (toolbar as Schema).type || (toolbar as string);

    if (type === 'drag-toggler') {
      this.renderedToolbars.push(type);
      return this.renderDragToggler();
    } else if (type === 'check-all') {
      this.renderedToolbars.push(type);
      return this.renderCheckAll();
    } else if (type === 'columns-toggler') {
      return null
    }

    return void 0;
  }

  render() {
    const {
      className,
      itemClassName,
      store,
      placeholder,
      render,
      multiple,
      listItem,
      onAction,
      hideCheckToggler,
      checkOnItemClick,
      itemAction,
      affixHeader,
      classnames: cx,
      classPrefix: ns,
      size,
      translate: __,
      onLoadMore,
      loadHasMore,
      infinteLoad,
      data,
      loadDataOnce,
      loadmoreLoading,
      columns,
      thumbRatio,
      renderAggregate
    } = this.props;

    const inCombination = Boolean(this.body?.closest(`.${ns}Panel-Combination`))
    this.renderedToolbars = [];
    const heading = this.renderHeading();
    const header = isMobile() && inCombination ? null : this.renderHeader();

    return (
      <div
        className={cx('List', className, {
          [`List--${size}`]: size,
          'List--unsaved': !!store.modified || !!store.moved
        })}
        id={'List-item-content'}
        ref={this.bodyRef}
      >
        {renderAggregate?.()}
        {affixHeader && heading && header ? (
          <div className={cx('List-fixedTop')}>
            {header}
            {heading}
          </div>
        ) : null}

        {header}
        {heading}
        {store.items.length ? (
          <div className={cx('List-items')} >
            {store.items.map((item, index) =>
              render(
                `${index}`,
                {
                  type: 'list-item',
                  ...listItem
                },
                {
                  key: item.index,
                  className: cx(itemClassName, {
                    'is-checked': item.checked,
                    'is-modified': item.modified,
                    'is-moved': item.moved
                  }),
                  selectable: store.selectable,
                  checkable: item.checkable,
                  multiple,
                  item,
                  itemIndex: item.index,
                  hideCheckToggler: this.state.hideCheckTogglerOpen,
                  checkOnItemClick,
                  itemAction,
                  selected: item.checked,
                  onCheck: this.handleCheck,
                  dragging: store.dragging,
                  onAction,
                  data: item.locals,
                  onQuickChange: store.dragging ? null : this.handleQuickChange,
                  popOverContainer: this.getPopOverContainer,
                  dataColumns: columns,
                  thumbRatio
                }
              )
            )}
            {(!inCombination && infinteLoad) && <InfinteSroll loadMore={onLoadMore} hasMore={loadHasMore} hasData={!!data?.items?.length} loadDataOnce={loadDataOnce} loadmoreLoading={loadmoreLoading} />}
          </div>
        ) : (
          <div className={cx('List-placeholder')}>
            {render('placeholder', __(placeholder))}
          </div>
        )}
        {this.renderFooter()}
      </div>
    );
  }
}

@Renderer({
  type: 'list',
  storeType: ListStore.name
})
export class ListRenderer extends List {
  dragging: boolean;
  selectable: boolean;
  selected: boolean;
  title?: string;
  subTitle?: string;
  desc?: string;
  avatar?: string;
  avatarClassName?: string;
  body?: SchemaNode;
  actions?: Array<Action>;
  onCheck: (item: IItem) => void;
}

export interface ListItemProps
  extends RendererProps,
  Omit<ListItemSchema, 'type' | 'className'> {
  hideCheckToggler?: boolean;
  item: IItem;
  itemIndex?: number;
  checkable?: boolean;
  checkOnItemClick?: boolean;
  itemAction?: ActionSchema;
}
interface ListItemState {
  visible: boolean
}

export class ListItem extends React.Component<ListItemProps, ListItemState> {
  // Jay
  touchStartTime: number;

  static defaultProps: Partial<ListItemProps> = {
    avatarClassName: 'thumb avatar m-r-sm',
    titleClassName: 'h5'
  };

  static propsList: Array<string> = [
    'avatarClassName',
    'titleClassName',
    'itemAction'
  ];

  constructor(props: ListItemProps) {
    super(props);
    this.itemRender = this.itemRender.bind(this);
    this.handleAction = this.handleAction.bind(this);
    this.handleClick = this.handleClick.bind(this);
    this.handleCheck = this.handleCheck.bind(this);
    // Jay
    this.touchStartTime = 0
    this.state = {
      visible: false
    }
  }

  handleClick(e: React.MouseEvent<HTMLDivElement>) {
    if (isClickOnInput(e)) {
      return;
    }
    const { itemAction, onAction, item } = this.props;
    if (itemAction) {
      onAction && onAction(e, itemAction, item?.data);
      return;
    }

    this.props.onCheck && this.props.onCheck(item);
  }

  handleCheck() {
    const item = this.props.item;
    this.props.onCheck && this.props.onCheck(item);
  }

  handleAction(e: React.UIEvent<any>, action: Action, ctx: object) {
    const { onAction, item } = this.props;
    this.setState({ visible: false });
    onAction && onAction(e, action, ctx || item.data);
  }

  handleQuickChange(
    values: object,
    saveImmediately?: boolean,
    savePristine?: boolean,
    resetOnFailed?: boolean
  ) {
    const { onQuickChange, item } = this.props;
    onQuickChange &&
      onQuickChange(item, values, saveImmediately, savePristine, resetOnFailed);
  }

  renderLeft() {
    const {
      dragging,
      selectable,
      selected,
      checkable,
      multiple,
      hideCheckToggler,
      checkOnItemClick,
      classnames: cx,
      classPrefix: ns,
      headerBulkActions,
      footerBulkActions
    } = this.props;
    const bulkActions = (headerBulkActions?.length ?? 0) + (footerBulkActions?.length ?? 0)

    if (dragging) {
      return (
        <div className={cx('ListItem-dragBtn')}>
          <Icon icon="drag-bar" className="icon" />
        </div>
      );
    } else if (selectable && !hideCheckToggler && bulkActions > 0) {
      return (
        <div className={cx('ListItem-checkBtn')}>
          <Checkbox
            classPrefix={ns}
            type={multiple ? 'checkbox' : 'radio'}
            disabled={!checkable}
            checked={selected}
            onChange={checkOnItemClick ? noop : this.handleCheck}
            inline
          />
        </div>
      );
    }

    return null;
  }

  renderRight() {
    const { actions, render, data, dragging, classnames: cx, num } = this.props;

    if (Array.isArray(actions)) {
      {/* Jay */ }
      const actionsTmp: any[] = []
      const mobileUI = isMobile()
      if (mobileUI) {
        actions.forEach(action => {
          if (isVisible(action, data)) {
            actionsTmp.push({ ...action, onAction: this.handleAction, disabled: dragging || isDisabled(action, data) })
          }
        })
      } else {
        actions.forEach((action, index) => {
          if (isVisible(action, data)) {
            actionsTmp.push({
              ...action,
              size: 'sm',
              type: 'button',
              onAction: this.handleAction,
              disabled: dragging || isDisabled(action, data),
              key: index
            })
          }
        })
      }
      return (
        <div className={cx('ListItem-actions')}>
          {/* Jay */}
          {!mobileUI ?
            render(
              `action`,
              {
                type: "operation",
                buttons: actionsTmp
              },
              {
                num
              }
            )
            :
            actions.map((action, key) =>
              render(`action/${key}`, { ...action }, {
                onAction: this.handleAction,
                type: 'button',
                disabled: dragging || isDisabled(action, data),
                key
              })
            )
          }

        </div>
      );
    }

    return null;
  }

  renderChild(
    node: SchemaNode,
    region: string = 'body',
    key: any = 0
  ): React.ReactNode {
    const { render } = this.props;
    if (typeof node === 'string' || typeof node === 'number') {
      return render(region, node, { key }) as JSX.Element;
    }

    const childNode: Schema = node as Schema;

    if (childNode.type === 'hbox' || childNode.type === 'grid') {
      return render(region, node, {
        key,
        itemRender: this.itemRender
      }) as JSX.Element;
    }

    return this.renderFeild(region, childNode, key, this.props);
  }

  itemRender(field: any, index: number, props: any) {
    return this.renderFeild(`column/${index}`, field, index, props);
  }

  renderFeild(region: string, field: any, key: any, props: any) {
    const { dataColumns, tableLayout } = this.props
    const render = props?.render || this.props.render;
    const data = this.props.data;
    const cx = this.props.classnames;
    const itemIndex = this.props.itemIndex;

    const $$id = field.$$id ? `${field.$$id}-field` : '';
    if (!isVisible(field, data)) {
      return null;
    }
    const label = field.label
    const itemData = dataColumns.filter((item: any) => ['mapping', 'progress', 'link', 'lion-upload', 'color'].some(Item => item.type == Item)).find((item: any) => item.name == field.name)
    const canJump = field.linkId ? linkJump(field.linkId ?? '', data, field.jumpDisabledOn) : false;
    return (
      <div key={key} className={cx('ListItem-field')}>
        {label ? (
          <label className={cx('ListItem-fieldLabel', field.labelClassName)} title={field.label}>
            <span>{label}</span>:
          </label>
        ) : null}
        <div className={cx('ListItem-fieldValue', field.linkUrl && canJump ? 'is-linkUrl' : '')}
          style={{ flex: 1 }} title={field.name ? resolveVariable(field.name, data) : undefined}
          onClick={(e) => {
            if (canJump) {
              e.stopPropagation()
              ModleHandleClick({ ...this.props, ...field, value: data[field.name] }, e.target)
            }
          }}
        >
          {
            itemData ?
              render(
                region, itemData,
                {
                  rowIndex: itemIndex,
                  colIndex: key,
                  className: cx('ListItem-fieldValue', field.className, field.linkUrl && canJump ? 'is-linkUrl' : ''),
                  label: undefined,
                  mode: tableLayout ?? 'normal',
                  value: field.name ? resolveVariable(field.name, data) : undefined,
                  onAction: this.handleAction,
                  onQuickChange: this.handleQuickChange
                }
              ) :
              render(
                region,
                {
                  ...field,
                  field: field,
                  $$id,
                  type: 'list-item-field'
                },
                {
                  rowIndex: itemIndex,
                  colIndex: key,
                  className: cx('ListItem-fieldValue', field.className, field.linkUrl && canJump ? 'is-linkUrl' : ''),
                  value: field.name ? resolveVariable(field.name, data) : undefined,
                  onAction: this.handleAction,
                  onQuickChange: this.handleQuickChange
                }
              ) as JSX.Element
          }
        </div>
      </div>
    );
  }

  renderBody() {
    const { body } = this.props;

    if (!body) {
      return null;
    } else if (Array.isArray(body)) {
      return body.map((child, index) =>
        this.renderChild(
          {
            type: 'plain',
            ...(typeof child === 'string' ? { type: 'tpl', tpl: child } : child)
          },
          `body/${index}`,
          index
        )
      );
    }

    return this.renderChild(body, 'body');
  }

  previewImage(file: FileX, index: number, e: React.MouseEvent<any>) {
    e.preventDefault();
    const { onImageEnlarge } = this.props;
    if (onImageEnlarge) {
      onImageEnlarge({
        // 预览地址
        src: file.thumbnailAddr as string,
        originalSrc: file.preview as string,
        index
      });
    }
  }

  handelRenderDom = (name: string, value?: string) => {
    const { dataColumns, data, render } = this.props
    const itemData = dataColumns.find((items: any) => ['mapping'].some(item => items.type == item) && items.name == name)
    if (itemData) {
      if (value) {
        return render(name, itemData, { value: value })
      }
      return render(name, itemData)
    }
    return data[name]
  }

  render() {
    const {
      className,
      data,
      titleClassName,
      avatarClassName,
      checkOnItemClick,
      render,
      checkable,
      classnames: cx,
      actionsPosition,
      itemAction,
      // Jay
      footable,
      footBody,
      title,
      subTitle,
      avatar,
      icon,
      desc,
      tags,
      env,
      itemIndex,
      onImageEnlarge,
      dataColumns,
      classPrefix,
      thumbRatio
    } = this.props;
    const itemTags = tags && data[tags]?.split?.(',');
    const itemIcon = iconMap[itemIndex ?? 0];
    const baseUrl = env?.axiosInstance?.defaults?.baseURL || env?.ajaxApi || '';
    const { visible } = this.state
    const imgUrl = (data[avatar || '']?.info?.[0].addr as string)?.startsWith("http") ? data[avatar || '']?.info?.[0].addr : ((baseUrl ? baseUrl : '') + data[avatar || '']?.info?.[0].addr)
    let linkParam = {};
    let canJump = false;
    const targetCol = dataColumns.find((col: obj) => col.name === title);
    if (targetCol?.linkId) {
      linkParam = targetCol;
      canJump = linkJump(targetCol.linkId, data, targetCol.jumpDisabledOn);
    }
    return (
      <div className={cx('ListItem-wapper')}>
        <div
          className={cx(
            `ListItem ListItem--actions-at-${actionsPosition || 'right'}`,
            {
              'ListItem--hasItemAction': itemAction
            },
            className,
            typeof (footable) === 'object' && footable.expand === 'all' && 'expand'
          )}
          onTouchStart={() => {
            footable && (this.touchStartTime = +new Date())
          }}
          // 这里不能用onTouchEnd，否则会有一些bug
          onClick={(e) => {
            if (footable && (+ new Date() - this.touchStartTime < 300)) {
              if (/expand/.test(e.currentTarget.className)) {
                e.currentTarget.classList.remove('expand')
              } else {
                e.currentTarget.classList.add('expand')
              }
            }
            ((checkOnItemClick && checkable) || itemAction)
              && this.handleClick(e)
          }}
        >
          {this.renderLeft()}
          <div className={cx('ListItem-content')} >
            <div className='listItem-box'>
              {avatar ? <div className={'listItem-head'}>
                <div className='listItem-image'>
                  {data[avatar]?.value ?
                    <div className={cx('Card-img-container')} onClick={(e) => {
                      e.stopPropagation()
                      openImageEnlarge([data[avatar].info[0]], baseUrl, onImageEnlarge, env)
                    }}><Image
                        autoCalc
                        className={'Auto-calc-size'}
                        src={imgUrl}
                        thumbMode={'cover'}
                        thumbRatio={thumbRatio}
                        classPrefix={classPrefix}
                      /></div> :
                    <span className='resources'>
                      <Icon icon='no-resources' />
                      No image
                    </span>
                  }
                </div>
              </div> : null}
              <div className='listItem-body'
              // onClick={() => { this.setState({ visible: true }) }}
              >
                <div className='top-content'>

                  {itemIcon && icon && data[icon] ? <div className='listItem-icon'>
                    {render('', {
                      type: 'icon',
                      icon: data[icon] || 'cloud',
                      color: '#fff',
                      bgColor: itemIcon?.color || '#1890ff'
                    })}
                  </div> : null}

                  {title && data[title] ? <p style={{ cursor: canJump ? 'pointer' : 'unset' }} onClick={(e) => {
                    if (canJump) ModleHandleClick({ ...this.props, ...linkParam, value: data[title] }, e.target)
                  }} className={cx('ListItem-title', titleClassName, {
                    'ListItemtitile': !(subTitle && data[subTitle]) && !itemTags?.length
                  })} title={data[title]}>
                    {data[title]}
                  </p> : title ? <p className={cx('ListItem-title')}>--</p> : null}

                  {subTitle && data[subTitle] ? (
                    <div className='top-item'>
                      <small className={cx('ListItem-subtitle')} title={data[subTitle]}>
                        {/* {data[subTitle]} */}
                        {this.handelRenderDom(subTitle)}
                      </small>
                    </div>
                  ) : null}

                  {
                    tags && data[tags] ? <div className='top-item tags'>
                      {itemTags.map((item: string) => <div className='tag-item' title={item}> {this.handelRenderDom(tags, item)}
                      </div>
                      )}
                      {/* {this.handelRenderDom(tags)} */}
                    </div> : null
                  }
                </div>

                {this.renderBody()}

                {desc && data[desc] ? <div className='listItem-desc'> {this.handelRenderDom(desc)} </div> : null}

              </div>
            </div>
          </div>
          {!isMobile() && this.renderRight()}
        </div>
        {footable && footBody?.length &&
          <div className={cx('ListItem-footable', 'flex-wrap')}>
            {
              footBody?.map((column, index) =>
                <div key={index} className={'footItem flex items-center'}>
                  <span className="label">{column.label} :</span>
                  <span className="value">
                    {column.type ? render(`field`, column, { key: index, data }) : (data[column.name] || '-')}
                  </span>
                </div>)
            }
          </div>
        }
        {isMobile() && <Modal
          zIndex={9}
          className={cx('Modal-mobile', 'List-modal')}
          bodyStyle={{ overflowY: 'auto', padding: 0 }}
          closable={false}
          visible={visible}
          getContainer={this.props.env.getModalContainer}
          footer={false}
          centered
          onCancel={(e) => {
            e.stopPropagation();
            this.setState({ visible: false });
          }}
        >
          <div className={cx('List-modal-content')}>
            <div className={cx('List-modal-head')}>
              {avatar ? <div className={cx('List-modal-head-image')}>
                <div className='listItem-image'>
                  {data[avatar]?.value ?
                    <img className={cx('Card-img')} src={imgUrl} onClick={(e) => { openImageEnlarge([data[avatar].info[0]], baseUrl, onImageEnlarge, env) }} /> :
                    <span className='resources'>
                      <Icon icon='no-resources' />
                      No image
                    </span>
                  }
                </div>
              </div> : null}
              <div className={cx('List-modal-head-content')}>
                {
                  tags && data[tags] ? <div className='top-item tags'>
                    {itemTags.map((item: string) => <div className='tag-item' title={item}> {this.handelRenderDom(tags, item)}
                    </div>
                    )}
                    {/* {this.handelRenderDom(tags)} */}
                  </div> : null
                }

                {title && data[title] ? <p className={cx('ListItem-title', titleClassName, {
                  'ListItemtitile': !(subTitle && data[subTitle]) && !itemTags?.length
                })} title={data[title]}>
                  {data[title]}
                </p> : title ? <p className={cx('ListItem-title')}>--</p> : null}

                {subTitle && data[subTitle] ? (
                  <div className='top-item'>
                    <small className={cx('ListItem-subtitle')} title={data[subTitle]}>
                      {/* {data[subTitle]} */}
                      {this.handelRenderDom(subTitle)}
                    </small>
                  </div>
                ) : null}
              </div>
            </div>
            <div className={cx('List-modal-body')} >
              {this.renderBody()}
              {desc && data[desc] ? <div className='listItem-desc'> {this.handelRenderDom(desc)} </div> : null}
            </div>
            <div className={cx('List-modal-footer')}>
              {this.renderRight()}
            </div>
          </div>
        </Modal>}
      </div>
    );
  }
}

@Renderer({
  test: /(^|\/)(?:list|list-group)\/(?:.*\/)?list-item$/,
  name: 'list-item'
})
export class ListItemRenderer extends ListItem {
  static propsList = ['multiple', ...ListItem.propsList];
}

@Renderer({
  type: 'list-item-field'
})
@QuickEdit()
@PopOver()
@Copyable()
export class ListItemFieldRenderer extends TableCell {
  static defaultProps = {
    ...TableCell.defaultProps,
    wrapperComponent: 'div'
  };
  static propsList = [
    'quickEdit',
    'quickEditEnabledOn',
    'popOver',
    'copyable',
    'inline',
    ...TableCell.propsList
  ];

  render() {
    let {
      className,
      render,
      style,
      wrapperComponent: Component,
      labelClassName,
      value,
      data,
      children,
      width,
      innerClassName,
      label,
      tabIndex,
      onKeyUp,
      field,
      ...rest
    } = this.props;

    const schema = {
      ...field,
      className: innerClassName,
      type: (field && field.type) || 'plain'
    };

    let body = children
      ? children
      : render('field', schema, {
        ...omit(rest, Object.keys(schema)),
        value,
        data
      });

    if (width) {
      style = style || {};
      style.width = style.width || width;
      body = (
        <div style={{ width: !/%/.test(String(width)) ? width : '' }}>{body}</div>
      );
    }

    if (!Component) {
      return body as JSX.Element;
    }

    return (
      <Component
        style={style}
        className={className}
        tabIndex={tabIndex}
        onKeyUp={onKeyUp}
      >
        {body}
      </Component>
    );
  }
}
