<template>
  <div ref="wrapRef" :class="getWrapperClass">
    <BasicForm submitOnReset v-bind="getFormProps" v-if="getBindValues.useSearchForm" :tableAction="tableAction"
      @register="registerForm" @submit="handleSearchInfoChange" @advanced-change="redoHeight">
      <template #[replaceFormSlotKey(item)]="data" v-for="item in getFormSlotKeys">
        <slot :name="item" v-bind="data || {}"></slot>
      </template>
    </BasicForm>

    <!-- antd v3 升级兼容，阻止数据的收集，防止控制台报错 -->
    <!-- https://antdv.com/docs/vue/migration-v3-cn -->
    <a-form-item-rest>
      <Table ref="tableElRef" v-bind="getBindValues" :rowClassName="getRowClassName" v-show="getEmptyDataIsShowTable"
        @resizeColumn="handleResizeColumn" @change="handleTableChange">
        <!-- antd的原生插槽直接传递 -->
        <template #[item]="data" v-for="item in slotNamesGroup.native" :key="item">
          <slot :name="item" v-bind="data || {}"></slot>
        </template>
        <template #headerCell="{ column }">
          <!-- update-begin--author:sunjianlei---date:220230630---for：【QQYUN-5571】自封装选择列，解决数据行选择卡顿问题 -->
          <CustomSelectHeader v-if="isCustomSelection(column)" v-bind="selectHeaderProps" />
          <HeaderCell v-else :column="column" />
          <!-- update-end--author:sunjianlei---date:220230630---for：【QQYUN-5571】自封装选择列，解决数据行选择卡顿问题 -->
        </template>
        <!-- 增加对antdv3.x兼容 -->
        <template #bodyCell="data">
          <!-- update-begin--author:liaozhiyang---date:220230717---for：【issues-179】antd3 一些警告以及报错(针对表格) -->
          <template v-if="data.column?.slotsBak?.customRender">
            <slot :name="data.column.slotsBak.customRender" v-bind="data || {}"></slot>
          </template>
          <template v-else>
            <slot name="bodyCell" v-bind="data || {}"></slot>
          </template>
          <!-- update-begin--author:liaozhiyang---date:22030717---for：【issues-179】antd3 一些警告以及报错(针对表格) -->
        </template>
      </Table>
    </a-form-item-rest>
  </div>
</template>
<script lang="ts">
import type { BasicTableProps, TableActionType, SizeType, ColumnChangeParam, BasicColumn } from './types/table';

import { defineComponent, ref, computed, unref, toRaw, inject, watchEffect, watch, onUnmounted, onMounted } from 'vue';
import { Table } from 'ant-design-vue';
import { BasicForm, useForm } from '/@/components/Form/index';
import { PageWrapperFixedHeightKey } from '/@/components/Page/injectionKey';
import CustomSelectHeader from './components/CustomSelectHeader.vue'
import expandIcon from './components/ExpandIcon';
import HeaderCell from './components/HeaderCell.vue';
import { InnerHandlers } from './types/table';
import { usePagination } from './hooks/usePagination';
import { useColumns } from './hooks/useColumns';
import { useDataSource } from './hooks/useDataSource';
import { useLoading } from './hooks/useLoading';
import { useRowSelection } from './hooks/useRowSelection';
import { useTableScroll } from './hooks/useTableScroll';
import { useCustomRow } from './hooks/useCustomRow';
import { useTableStyle } from './hooks/useTableStyle';
import { useTableHeader } from './hooks/useTableHeader';
import { useTableExpand } from './hooks/useTableExpand';
import { createTableContext } from './hooks/useTableContext';
import { useTableFooter } from './hooks/useTableFooter';
import { useTableForm } from './hooks/useTableForm';
import { useDesign } from '/@/hooks/web/useDesign';
import { useCustomSelection } from "./hooks/useCustomSelection";

import { omit } from 'lodash-es';
import { basicProps } from './props';
import { isFunction } from '/@/utils/is';
import { warn } from '/@/utils/log';

export default defineComponent({
  components: {
    Table,
    BasicForm,
    HeaderCell,
    CustomSelectHeader,
  },
  props: basicProps,
  emits: [
    'fetch-success',
    'fetch-error',
    'selection-change',
    'register',
    'row-click',
    'row-dbClick',
    'row-contextmenu',
    'row-mouseenter',
    'row-mouseleave',
    'edit-end',
    'edit-cancel',
    'edit-row-end',
    'edit-change',
    'expanded-rows-change',
    'change',
    'columns-change',
    'table-redo',
  ],
  setup(props, { attrs, emit, slots, expose }) {
    const tableElRef = ref(null);
    const tableData = ref<Recordable[]>([]);

    const wrapRef = ref(null);
    const innerPropsRef = ref<Partial<BasicTableProps>>();

    const { prefixCls } = useDesign('basic-table');
    const [registerForm, formActions] = useForm();

    const getProps = computed(() => {
      return { ...props, ...unref(innerPropsRef) } as BasicTableProps;
    });

    const isFixedHeightPage = inject(PageWrapperFixedHeightKey, false);
    watchEffect(() => {
      unref(isFixedHeightPage) &&
        props.canResize &&
        warn("'canResize' of BasicTable may not work in PageWrapper with 'fixedHeight' (especially in hot updates)");
    });

    const { getLoading, setLoading } = useLoading(getProps);
    const { getPaginationInfo, getPagination, setPagination, setShowPagination, getShowPagination } = usePagination(getProps);

    // update-begin--author:sunjianlei---date:220230630---for：【QQYUN-5571】自封装选择列，解决数据行选择卡顿问题

    // const { getRowSelection, getRowSelectionRef, getSelectRows, clearSelectedRowKeys, getSelectRowKeys, deleteSelectRowByKey, setSelectedRowKeys } =
    //   useRowSelection(getProps, tableData, emit);

    // 子级列名
    const childrenColumnName = computed(() => getProps.value.childrenColumnName || 'children');

    // 自定义选择列
    const {
      getRowSelection,
      getSelectRows,
      getSelectRowKeys,
      setSelectedRowKeys,
      getRowSelectionRef,
      selectHeaderProps,
      isCustomSelection,
      handleCustomSelectColumn,
      clearSelectedRowKeys,
      deleteSelectRowByKey,
      getExpandIconColumnIndex,
    } = useCustomSelection(
      getProps,
      emit,
      wrapRef,
      getPaginationInfo,
      tableData,
      childrenColumnName
    )
    // update-end--author:sunjianlei---date:220230630---for：【QQYUN-5571】自封装选择列，解决数据行选择卡顿问题

    const {
      handleTableChange: onTableChange,
      getDataSourceRef,
      getDataSource,
      getRawDataSource,
      setTableData,
      updateTableDataRecord,
      deleteTableDataRecord,
      insertTableDataRecord,
      findTableDataRecord,
      fetch,
      getRowKey,
      reload,
      getAutoCreateKey,
      updateTableData,
    } = useDataSource(
      getProps,
      {
        tableData,
        getPaginationInfo,
        setLoading,
        setPagination,
        validate: formActions.validate,
        clearSelectedRowKeys,
      },
      emit
    );

    function handleTableChange(...args) {
      onTableChange.call(undefined, ...args);
      emit('change', ...args);
      // 解决通过useTable注册onChange时不起作用的问题
      const { onChange } = unref(getProps);
      onChange && isFunction(onChange) && onChange.call(undefined, ...args);
    }

    const { getViewColumns, getColumns, setCacheColumnsByField, setColumns, getColumnsRef, getCacheColumns } = useColumns(
      getProps,
      getPaginationInfo,
      // update-begin--author:sunjianlei---date:220230630---for：【QQYUN-5571】自封装选择列，解决数据行选择卡顿问题
      handleCustomSelectColumn,
      // update-end--author:sunjianlei---date:220230630---for：【QQYUN-5571】自封装选择列，解决数据行选择卡顿问题
    );

    const { getScrollRef, redoHeight } = useTableScroll(getProps, tableElRef, getColumnsRef, getRowSelectionRef, getDataSourceRef);

    const { customRow } = useCustomRow(getProps, {
      setSelectedRowKeys,
      getSelectRowKeys,
      clearSelectedRowKeys,
      getAutoCreateKey,
      emit,
    });

    const { getRowClassName } = useTableStyle(getProps, prefixCls);

    const { getExpandOption, expandAll, collapseAll } = useTableExpand(getProps, tableData, emit);

    const handlers: InnerHandlers = {
      onColumnsChange: (data: ColumnChangeParam[]) => {
        emit('columns-change', data);
        // support useTable
        unref(getProps).onColumnsChange?.(data);
      },
    };

    const { getHeaderProps } = useTableHeader(getProps, slots, handlers);

    const { getFooterProps } = useTableFooter(getProps, slots, getScrollRef, tableElRef, getDataSourceRef);

    const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange } = useTableForm(getProps, slots, fetch, getLoading);

    const getBindValues = computed(() => {
      const dataSource = unref(getDataSourceRef);
      let propsData: Recordable = {
        // ...(dataSource.length === 0 ? { getPopupContainer: () => document.body } : {}),
        ...attrs,
        customRow,
        //树列表展开使用AntDesignVue默认的加减图标 author:scott date:20210914
        //expandIcon: slots.expandIcon ? null : expandIcon(),
        ...unref(getProps),
        ...unref(getHeaderProps),
        scroll: unref(getScrollRef),
        loading: unref(getLoading),
        tableLayout: 'fixed',
        rowSelection: unref(getRowSelectionRef),
        rowKey: unref(getRowKey),
        columns: toRaw(unref(getViewColumns)),
        pagination: toRaw(unref(getPaginationInfo)),
        dataSource,
        footer: unref(getFooterProps),
        ...unref(getExpandOption),
        // 【QQYUN-5837】动态计算 expandIconColumnIndex
        expandIconColumnIndex: getExpandIconColumnIndex.value,
      };

      //update-begin---author:wangshuai ---date:20230214  for：[QQYUN-4237]代码生成 内嵌子表模式 没有滚动条------------
      //额外的展开行存在插槽时会将滚动移除掉,注释掉
      /*if (slots.expandedRowRender) {
        propsData = omit(propsData, 'scroll');
      }*/
      //update-end---author:wangshuai ---date:20230214  for：[QQYUN-4237]代码生成 内嵌子表模式 没有滚动条------------ 

      // update-begin--author:sunjianlei---date:220230630---for：【QQYUN-5571】自封装选择列，解决数据行选择卡顿问题
      // 自定义选择列，需要去掉原生的
      delete propsData.rowSelection
      // update-end--author:sunjianlei---date:220230630---for：【QQYUN-5571】自封装选择列，解决数据行选择卡顿问题

      // update-begin--author:liaozhiyang---date:20230919---for：【QQYUN-6387】展开写法（去掉报错）
      !propsData.isTreeTable && delete propsData.expandIconColumnIndex;
      propsData.expandedRowKeys === null && delete propsData.expandedRowKeys;
      // update-end--author:liaozhiyang---date:20230919---for：【QQYUN-6387】展开写法（去掉报错）
      propsData = omit(propsData, ['class', 'onChange']);
      return propsData;
    });

    // 统一设置表格列宽度
    const getMaxColumnWidth = computed(() => {
      const values = unref(getBindValues);
      return values.maxColumnWidth > 0 ? values.maxColumnWidth + 'px' : null;
    });

    const getWrapperClass = computed(() => {
      const values = unref(getBindValues);
      return [
        prefixCls,
        attrs.class,
        {
          [`${prefixCls}-form-container`]: values.useSearchForm,
          [`${prefixCls}--inset`]: values.inset,
          [`${prefixCls}-col-max-width`]: getMaxColumnWidth.value != null,
          // 是否显示表尾合计
          [`${prefixCls}--show-summary`]: values.showSummary,
        },
      ];
    });

    const getEmptyDataIsShowTable = computed(() => {
      const { emptyDataIsShowTable, useSearchForm } = unref(getProps);
      if (emptyDataIsShowTable || !useSearchForm) {
        return true;
      }
      return !!unref(getDataSourceRef).length;
    });

    function setProps(props: Partial<BasicTableProps>) {
      innerPropsRef.value = { ...unref(innerPropsRef), ...props };
    }

    const tableAction: TableActionType = {
      reload,
      getSelectRows,
      clearSelectedRowKeys,
      getSelectRowKeys,
      deleteSelectRowByKey,
      setPagination,
      setTableData,
      updateTableDataRecord,
      deleteTableDataRecord,
      insertTableDataRecord,
      findTableDataRecord,
      redoHeight,
      setSelectedRowKeys,
      setColumns,
      setLoading,
      getDataSource,
      getRawDataSource,
      setProps,
      getRowSelection,
      getPaginationRef: getPagination,
      getColumns,
      getCacheColumns,
      emit,
      updateTableData,
      setShowPagination,
      getShowPagination,
      setCacheColumnsByField,
      expandAll,
      collapseAll,
      getSize: () => {
        return unref(getBindValues).size as SizeType;
      },
    };
    createTableContext({ ...tableAction, wrapRef, getBindValues });

    // update-begin--author:sunjianlei---date:220230718---for：【issues/179】兼容新老slots写法，移除控制台警告
    // 获取分组之后的slot名称
    const slotNamesGroup = computed<{
      // AntTable原生插槽
      native: string[];
      // 列自定义插槽
      custom: string[];
    }>(() => {
      const native: string[] = [];
      const custom: string[] = [];
      const columns = unref<Recordable[]>(getViewColumns) as BasicColumn[];
      const allCustomRender = columns.map<string>((column) => column.slotsBak?.customRender);
      for (const name of Object.keys(slots)) {
        // 过滤特殊的插槽
        if (['bodyCell'].includes(name)) {
          continue;
        }
        if (allCustomRender.includes(name)) {
          custom.push(name);
        } else {
          native.push(name);
        }
      }
      return { native, custom };
    });
    // update-end--author:sunjianlei---date:220230718---for：【issues/179】兼容新老slots写法，移除控制台警告

    expose(tableAction);

    emit('register', tableAction, formActions);

    // update-begin--author:liaozhiyang---date:20230804---for：【issues/638】表格合计，列表table和合计table滚动联动
    if (getProps.value.showSummary) {
      let tableBody;
      const handleSroll = function () {
        const scrollLeft = this.scrollLeft;
        tableBody.forEach((elem) => (elem.scrollLeft = scrollLeft));
      };
      onMounted(() => {
        const unwatch = watch(
          getDataSourceRef,
          (newVal) => {
            if (newVal.length > 0) {
              setTimeout(() => {
                unwatch();
                tableBody = wrapRef.value.querySelectorAll('.ant-table-body');
                tableBody.forEach((elem) => {
                  elem.addEventListener('scroll', handleSroll, false);
                });
              }, 0);
              console.log("---表格合计滚动---")
            }
          },
          { immediate: true }
        );
      });
      onUnmounted(() => {
        if (tableBody.length) {
          tableBody.forEach((elem) => elem.removeEventListener('scroll', handleSroll));
        }
      });
    }
    // update-begin--author:liaozhiyang---date:20230804---for：【issues/638】表格合计，列表table和合计table滚动联动

    return {
      tableElRef,
      getBindValues,
      getLoading,
      registerForm,
      handleSearchInfoChange,
      getEmptyDataIsShowTable,
      handleTableChange,
      getRowClassName,
      wrapRef,
      tableAction,
      redoHeight,
      handleResizeColumn: (w, col) => {
        col.width = w;
      },
      getFormProps: getFormProps as any,
      replaceFormSlotKey,
      getFormSlotKeys,
      getWrapperClass,
      getMaxColumnWidth,
      columns: getViewColumns,

      // update-begin--author:sunjianlei---date:220230630---for：【QQYUN-5571】自封装选择列，解决数据行选择卡顿问题
      selectHeaderProps,
      isCustomSelection,
      // update-end--author:sunjianlei---date:220230630---for：【QQYUN-5571】自封装选择列，解决数据行选择卡顿问题
      slotNamesGroup,
    };
  },
});
</script>
<style lang="less">
@border-color: #cecece4d;

@prefix-cls: ~'@{namespace}-basic-table';

[data-theme='dark'] {

  .ant-table-tbody>tr:hover.ant-table-row-selected>td,
  .ant-table-tbody>tr.ant-table-row-selected td {
    background-color: #262626;
  }

  .@{prefix-cls} {

    //表格选择工具栏样式
    .alert {
      background-color: #323232;
      border-color: #424242;
    }
  }
}

.@{prefix-cls} {
  max-width: 100%;

  &-row__striped {
    td {
      background-color: @app-content-background;
    }
  }

  &-form-container {
    padding: 10px;

    .ant-form {
      padding: 12px 10px 6px 10px;
      margin-bottom: 8px;
      background-color: @component-background;
      border-radius: 2px;
    }
  }

  .ant-tag {
    margin-right: 0;
  }

  //update-begin-author:liusq---date:20230517--for: [issues/526]RangePicker 设置预设范围按钮样式问题---
  .ant-picker-preset {
    .ant-tag {
      margin-right: 8px !important;
    }
  }

  //update-end-author:liusq---date:20230517--for: [issues/526]RangePicker 设置预设范围按钮样式问题---

  .ant-table-wrapper {
    padding: 6px;
    background-color: @component-background;
    border-radius: 2px;

    .ant-table-title {
      min-height: 40px;
      padding: 0 0 8px 0 !important;
    }

    .ant-table.ant-table-bordered .ant-table-title {
      border: none !important;
    }
  }

  .ant-table {
    width: 100%;
    overflow-x: hidden;

    &-title {
      display: flex;
      padding: 8px 6px;
      border-bottom: none;
      justify-content: space-between;
      align-items: center;
    }

    //定义行颜色
    .trcolor {
      background-color: rgba(255, 192, 203, 0.31);
      color: red;
    }

    //.ant-table-tbody > tr.ant-table-row-selected td {
    //background-color: fade(@primary-color, 8%) !important;
    //}
  }

  .ant-pagination {
    margin: 10px 0 0 0;
  }

  .ant-table-footer {
    padding: 0;

    .ant-table-wrapper {
      padding: 0;
    }

    table {
      border: none !important;
    }

    .ant-table-content {
      overflow-x: hidden !important;
      //  overflow-y: scroll !important;
    }

    td {
      padding: 12px 8px;
    }
  }

  //表格选择工具栏样式
  .alert {
    height: 38px;
    background-color: #e6f7ff;
    border-color: #91d5ff;
  }

  &--inset {
    .ant-table-wrapper {
      padding: 0;
    }
  }

  // ------ 统一设置表格列最大宽度 ------
  &-col-max-width {

    .ant-table-thead tr th,
    .ant-table-tbody tr td {
      max-width: v-bind(getMaxColumnWidth);
    }
  }

  // ------ 统一设置表格列最大宽度 ------

  // update-begin--author:sunjianlei---date:220230718---for：【issues/622】修复表尾合计错位的问题
  &--show-summary {
    .ant-table>.ant-table-footer {
      padding: 12px 0 0;
    }

    .ant-table.ant-table-bordered>.ant-table-footer {
      border: 0;
    }
  }

  // update-end--author:sunjianlei---date:220230718---for：【issues/622】修复表尾合计错位的问题
}</style>
