<template>
  <div>
    <div ref="wrapRef" :class="getWrapperClass">
      <Table
        ref="tableElRef"
        v-bind="getBindValues"
        :rowClassName="getRowClassName"
        v-show="getEmptyDataIsShowTable"
        :position="['topRight']"
        @change="handleTableChange"
      >
        <template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
          <slot :name="item" v-bind="data || {}" />
        </template>
        <template #headerCell="{ column }">
          <HeaderCell :column="column" />
        </template>
        <!-- 增加对antdv3.x兼容 -->
        <template #bodyCell="data">
          <slot name="bodyCell" v-bind="data || {}" />
        </template>
      </Table>
    </div>
    <div class="p-2 batch_style" :style="{ left: batchLeft }" v-if="getSelectRowKeys()?.length">
      <Checkbox
        :indeterminate="indeterminate"
        :checked="checkedAll"
        @change="onCheckAllChange"
        style="margin-right: 10px"
      />
      <Button
        type="primary"
        ghost
        @click="batchExport"
        v-if="getProps.batchExportApi"
        v-auth="getProps.exportAuthList"
        >导出选中项</Button
      >
      <Button danger @click="batchDel" v-if="getProps.batchDelApi" v-auth="getProps.delAuthList"
        >删除选中项</Button
      >
      <span>当前选中"{{ getSelectRowKeys()?.length }}"行列表</span>
    </div>
  </div>
</template>
<script lang="ts">
  import type { BasicTableProps, TableActionType, SizeType } from './types/table';

  import { defineComponent, ref, computed, unref, toRaw, inject, watchEffect, watch } from 'vue';
  import { Checkbox, Table, Button } from 'ant-design-vue';
  import { useForm } from '/@/components/Form/index';
  import { PageWrapperFixedHeightKey } from '/@/components/Page';
  import HeaderCell from './components/HeaderCell.vue';
  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 { useTableScrollTo } from './hooks/useScrollTo';
  import { useCustomRow } from './hooks/useCustomRow';
  import { useTableStyle } from './hooks/useTableStyle';
  import { useTableExpand } from './hooks/useTableExpand';
  import { createTableContext } from './hooks/useTableContext';
  import { useTableFooter } from './hooks/useTableFooter';
  import { useDesign } from '/@/hooks/web/useDesign';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { downloadByBase64 } from '/@/utils/file/download';

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

  export default defineComponent({
    components: {
      Checkbox,
      // eslint-disable-next-line vue/no-reserved-component-names
      Table,
      // eslint-disable-next-line vue/no-reserved-component-names
      Button,
      HeaderCell,
    },
    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',
    ],
    setup(props, { attrs, emit, expose }) {
      const useApp = useAppStore();
      const batchLeft = ref(useApp.getMenuSetting?.collapsed ? '80px' : '190px');
      const indeterminate = ref(true);
      const checkedAll = ref(false);

      const tableElRef = ref(null);
      const tableData = ref<Recordable[]>([]);

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

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

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

      function setProps(props: Partial<BasicTableProps>) {
        innerPropsRef.value = { ...unref(innerPropsRef), ...props };
      }
      const isFixedHeightPage = inject(PageWrapperFixedHeightKey, false);
      watch(
        () => useApp.getMenuSetting,
        (value, _oldValue) => {
          // console.log('value', value);
          // console.log('oldValue', oldValue);
          batchLeft.value = value.collapsed ? '80px' : '190px';
        },
      );

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

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

      const {
        handleTableChange: onTableChange,
        getDataSourceRef,
        getDataSource,
        getRawDataSource,
        setTableData,
        updateTableDataRecord,
        deleteTableDataRecord,
        insertTableDataRecord,
        findTableDataRecord,
        getRowKey,
        reload,
        getAutoCreateKey,
        updateTableData,
      } = useDataSource(
        getProps,
        {
          tableData,
          getPaginationInfo,
          setLoading,
          setPagination,
          getFieldsValue: formActions.getFieldsValue,
          clearSelectedRowKeys,
        },
        emit,
      );
      // 动态变化底部margin
      const mbottom = ref('margin0');
      const getWrapperClass = computed(() => {
        const values = unref(getBindValues);
        return [
          prefixCls,
          attrs.class,
          {
            [`${prefixCls}-form-container`]: values.useSearchForm,
            [`${prefixCls}--inset`]: values.inset,
          },
          mbottom.value,
        ];
      });

      watchEffect(() => {
        indeterminate.value =
          getSelectRowKeys()?.length && getSelectRowKeys()?.length < getDataSource()?.length;
        mbottom.value = getSelectRowKeys()?.length > 0 ? 'margin70' : 'margin0';
        checkedAll.value = getSelectRowKeys()?.length === getDataSource()?.length;
        unref(isFixedHeightPage) &&
          props.canResize &&
          warn(
            "'canResize' of BasicTable may not work in PageWrapper with 'fixedHeight' (especially in hot updates)",
          );
      });

      function handleTableChange(...args) {
        onTableChange.call(undefined, ...args);
        emit('change', ...args);
        // 解决通过useTable注册onChange时不起作用的问题
        const { onChange } = unref(getProps);
        onChange && isFunction(onChange) && onChange.call(undefined, ...args);
      }
      // 批量删除
      const { createMessage, createConfirm } = useMessage();
      function batchDel() {
        if (!innerPropsRef.value.batchDelApi || !isFunction(innerPropsRef.value.batchDelApi)) {
          createMessage.error('未找到批量操作入口！');
          return;
        }
        createConfirm({
          content: '确定要删除选中数据?',
          iconType: 'warning',
          onOk: async () => {
            const keys = getSelectRowKeys();
            await innerPropsRef.value.batchDelApi(keys);
            createMessage.success('删除成功！');
            await reload();
            clearSelectedRowKeys();
          },
        });
      }
      // 批量导出
      async function batchExport() {
        // const selectRow = getSelectRows();
        if (
          !innerPropsRef.value.batchExportApi ||
          !isFunction(innerPropsRef.value.batchExportApi)
        ) {
          createMessage.error('未找到批量操作入口！');
          return;
        }
        const keys = getSelectRowKeys();
        await innerPropsRef.value.batchExportApi(keys).then(res => {
          console.log('res：：：：：：：：', res && res);
          if (res && res.fileName && res.base64) {
            downloadByBase64(res.base64, res.fileName + '.xlsx');
          } else {
            createMessage.error('获取导出文件失败！');
          }
        });
      }
      const {
        getViewColumns,
        getColumns,
        setCacheColumnsByField,
        setColumns,
        getColumnsRef,
        getCacheColumns,
      } = useColumns(getProps, getPaginationInfo);

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

      const { scrollTo } = useTableScrollTo(tableElRef, getDataSourceRef);

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

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

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

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

      const getBindValues = computed(() => {
        const dataSource = unref(getDataSourceRef);
        let propsData: Recordable = {
          ...attrs,
          customRow,
          ...unref(getProps),
          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),
        };

        propsData = omit(propsData, ['class', 'onChange']);
        return propsData;
      });

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

      function onCheckAllChange(e: any) {
        if (e.target.checked) {
          const selectRows = [];
          getDataSource().forEach(data => {
            selectRows.push(data.id);
          });
          setSelectedRowKeys(selectRows);
        } else {
          clearSelectedRowKeys();
        }
      }

      const tableAction: TableActionType = {
        reload,
        getSelectRows,
        setSelectedRows,
        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,
        expandRows,
        collapseAll,
        scrollTo,
        getSize: () => {
          return unref(getBindValues).size as SizeType;
        },
      };
      createTableContext({ ...tableAction, wrapRef, getBindValues });

      expose(tableAction);

      emit('register', tableAction, formActions);

      return {
        formRef,
        tableElRef,
        getBindValues,
        getLoading,
        registerForm,
        getEmptyDataIsShowTable,
        handleTableChange,
        getRowClassName,
        wrapRef,
        tableAction,
        redoHeight,
        getWrapperClass,
        columns: getViewColumns,
        getSelectRowKeys,
        batchDel,
        batchExport,
        batchLeft,
        indeterminate,
        checkedAll,
        onCheckAllChange,
        getProps,
      };
    },
  });
</script>
<style lang="less">
  @border-color: #cecece4d;

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

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

  .margin0 {
    margin-bottom: 0;
  }

  .margin70 {
    margin-bottom: 70px;
  }
  .@{prefix-cls} {
    max-width: 100%;
    height: 100%;

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

    &-form-container {
      margin-bottom: 62px;
      padding: 16px;
      background: #f4f6f9 !important;

      .ant-form {
        width: 100%;
        padding: 12px 10px 6px;
        margin-bottom: 16px;
        background-color: #f4f6f9;
        border-radius: 2px;
      }
    }

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

    .ant-table-wrapper {
      padding: 0 !important;
      background-color: #f4f6f9;
      border-radius: 2px;

      .ant-table-thead > tr > th {
        background: #f4f6f9;
      }

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

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

      .ant-table.ant-table-bordered > .ant-table-container {
        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;
      }

      .ant-table-body {
        background: #f4f6f9;
        border: none !important;
        height: auto !important;
        max-height: 100% !important;
      }

      .ant-checkbox-inner {
        border-spacing: 0;
      }

      .ant-table-body > table {
        border: none !important;
        border-collapse: separate;
        border-spacing: 0 12px;
        margin-top: -20px;

        tr {
          border: none !important;

          td {
            border: none !important;
          }
        }

        .ant-table-tbody > tr {
          background: #fff;
        }
      }

      .ant-table-thead > tr > th {
        background: #f4f6f9 !important;
        color: #818694 !important;
        border: none !important;
      }
    }

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

    .ant-table-footer {
      padding: 0;

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

      table {
        border: none !important;
      }

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

      td {
        padding: 12px 8px;
      }
    }

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

  .batch_style {
    position: fixed; // 使按钮固定于可视窗口的底部
    bottom: 0;
    right: 8px;
    height: 62px; // 设置固定高度
    line-height: 62px;
    background: #fff;
    z-index: 3;
    width: 100%;
    // border: #9b9ea8 solid 1px;
    box-shadow: 0 -2px 18px 0 rgb(0 37 74 / 12%);

    button {
      margin-right: 10px;
    }
  }
</style>
