<template>
  <div>
    <vxe-toolbar custom v-if="hasCustomToolbar">
      <template #buttons>
        <slot name="leftMenu"></slot>
      </template>
      <template #tools>
        <slot name="rightTools"></slot>
      </template>
    </vxe-toolbar>
    <vxe-toolbar v-else-if="hasToolBar">
      <template #buttons>
        <slot name="leftMenu"></slot>
      </template>
      <template #tools>
        <slot name="rightTools"></slot>
      </template>
    </vxe-toolbar>

    <a-row class="topbar" :gutter="10" v-if="selection || hasSearchBar">
      <a-col span="5" v-if="hasSearchBar">
        <vxe-input
          celarable
          class="fullBox"
          :placeholder="labels.tryFullTableFiltering"
          type="search"
          v-model="filterName1"
          @keyup="searchEvent"
        ></vxe-input>
      </a-col>
      <a-col span="15">
        <a-alert
          show-icon
          type="info"
          v-if="selection"
          :message="`${labels.allSelected}: ${fullSelectionSize}, ${labels.selectedInCurrentPage}: ${selectRecordsSize}, ${labels.totalInCurrentPage}: ${listSize}`"
        ></a-alert>
      </a-col>
    </a-row>
    <vxe-table
      border
      column-key
      highlight-hover-row
      ref="xTable"
      resizable
      row-id="uuid"
      show-header-overflow
      v-on="$listeners"
      :cell-class-name="cellClassName"
      :checkbox-config="checkboxConfig"
      :custom-config="customConfig"
      :data="list"
      :edit-config="editConfig"
      :edit-rules="validConfig"
      :height="height"
      :highlight-current-row="true"
      :id="id"
      :keyboard-config="keyboardConfig"
      :loading.sync="loading"
      :menu-config="menuConfig"
      :merge-cells="mergeCells"
      :Slots="{ empty: '--' }"
      :row-class-name="rowClassName"
      :scroll-y="scrollYConfig"
      :seq-config="sequenceConfig"
      :show-overflow="showOverflow"
      :size="option.size"
      :sort-config="sortConfig"
      :tooltip-config="tooltipConfig"
      :row-style="rowStyle"
      @cell-click="cellClickEvent"
      @cell-dblclick="cellDBLClickEvent"
      @cell-mouseenter="cellMouseenterEvent"
      @cell-mouseleave="cellMouseleaveEvent"
      @checkbox-all="checkboxAllEvent"
      @checkbox-change="checkboxChangeEvent"
      @current-change="currentChange"
      @custom="toolBarCustom"
      @edit-closed="editClosedEvent"
      @header-cell-click="headerCellClickEvent"
      @header-cell-dblclick="headerCellDBLClickEvent"
      @header-cell-menu="headerCellContextMenuEvent"
      @resizable-change="resizeColumn"
    >
      <vxe-table-column v-if="selection" type="checkbox" width="50" fixed="left"></vxe-table-column>
      <vxe-table-column type="seq" width="50" fixed="left"></vxe-table-column>
      <template v-for="item in tableColumn">
        <vxe-table-column
          show-overflow
          v-if="!item.slot && !item.component"
          :align="item.align"
          :edit-render="item.editRender"
          :field="item.field"
          :filters="item.filters"
          :filter-method="filterMethod"
          :formatter="getFormatter(item)"
          :fixed="item.fixed"
          :key="item.field"
          :min-width="item.minWidth"
          :sortable="sortable && item.sortable"
          :title="item.title"
          :type="item.type"
          :visible="item.visible"
          :width="item.width"
        >
        </vxe-table-column>
        <vxe-table-column
          show-overflow
          v-else
          :edit-render="item.editRender"
          :field="item.field"
          :filter-method="filterMethod"
          :filters="item.filters"
          :fixed="item.fixed"
          :key="item.field"
          :width="item.width"
          :min-width="item.minWidth"
          :sortable="sortable && item.sortable"
          :title="item.title"
          :visible="item.visible"
        >
          <template #edit="{ row }">
            <slot :name="item.field" :row="row" :cellEdit="true"></slot>
          </template>
          <template #default="{ row }">
            <slot v-if="!item.popup" :name="item.field" :row="row" :cellEdit="false">
              {{ row[item.field] }}
            </slot>
            <span v-else>
              <slot :name="item.field" :row="row" :cellEdit="true">{{
                row[item.field]
              }}</slot></span
            >
          </template>
        </vxe-table-column>
      </template>
      <!--
      进入编辑状态, 操作 button
      <vxe-table-column title="操作" width="160" v-if="hasOperationButton">
        <template #default="{ row }">
          <div>
            <template v-if="isActiveByRow(row)">
              <vxe-button @click="saveRowEvent(row)">保存</vxe-button>
              <vxe-button @click="cancelRowEvent(row)">取消</vxe-button>
            </template>
            <template v-else>
              <vxe-button @click="editRowEvent(row)">编辑</vxe-button>
            </template>
          </div>
        </template>
      </vxe-table-column>
      -->
      <vxe-table-column
        align="center"
        fixed="right"
        :title="labels.operation"
        show-overflow
        v-if="hasOperationButton"
        :width="operationColumnWidth"
      >
        <template #default="{ row }">
          <slot name="operation" :slot-scope="row" :cellEdit="false"></slot>
        </template>
      </vxe-table-column>
    </vxe-table>
    <vxe-pager
      v-if="hasPagerBar || (showType === 'page' && showPager)"
      :current-page.sync="page.currentPage"
      :layouts="[
        'Total',
        'Sizes',
        'PrevJump',
        'PrevPage',
        'Number',
        'NextPage',
        'NextJump',
        'FullJump'
      ]"
      :page-size.sync="page.pageSize"
      :page-sizes.sync="page.pageSizes"
      :total="page.total"
      @page-change="handlePageChange"
    ></vxe-pager>
  </div>
</template>
<script>
import XEUtils from 'xe-utils';
import { DEFAULT_OPERATION_COLUMN_WIDTH } from '../../../lib/const.js';

import { ft } from '../../../lib/utils';

const LABELS = {
  allSelected: ft('i18n_common_all_selected', '所有已选中'),
  date: ft('i18n_common_date', '日期'),
  operation: ft('i18n_common_operation', '操作'),
  partialSaveSuccessfully: ft('i18n_common_Partial_save_successfully', '局部保存成功'),
  pleaseSelect: ft('i18n_common_please_select', '请选择'),
  saveSuccessfully: ft('i18n_common_saved_successfully', '保存成功'),
  selectedInCurrentPage: ft('i18n_common_all_selected_in_current_page', '当前分页已选中'),
  time: ft('Time', '时间'),
  totalInCurrentPage: ft('i18n_common_total_in_current_page', '当前分页共计'),
  tryFullTableFiltering: ft(
    'i18n_common_try_full_table_filtering_the_selected_state_of_the_current_page_will_be_reset',
    '试试全表过滤, 当前分页选中状态将重置'
  ),
  validationErrorOnLine: ft('i18n_common_validation_error_on_line', '第?行校验错误')
};

LABELS.pleaseSelectDate = `${LABELS.pleaseSelect}${LABELS.date}`;
LABELS.pleaseSelectDateTime = `${LABELS.pleaseSelect}${LABELS.date}${LABELS.time}`;

const EMBEDDED_DATATYPE = {
  date: '$input',
  datetime: '$input',
  input: 'input',
  number: '$input',
  money: '$input',
  popup: '$input',
  bizDic: '$select',
  select: '$select'
};

const NUMBER_DATATYPE = {
  number: 'number',
  money: 'money'
};

const RENDER_TYPE = {
  seq: 'seq',
  checkbox: 'checkbox',
  radio: 'radio',
  expand: 'expand',
  html: 'html'
};

export default {
  name: 'vxeRender',
  props: {
    // cellClassName: 用于设置 列 的 className, 参数: row, rowIndex, column, columnIndex
    cellClassName: {
      type: Function,
      default: null
    },

    readOnly: {
      type: Boolean,
      default: false
    },

    checkKey: {
      type: String,
      default: 'uuid'
    },

    data: {
      type: Array,
      default: () => {
        return [];
      }
    },
    // 判断行是否可编辑 return true/false
    enableEditRowFn: {
      type: Function,
      default: null
    },

    // hasCustomToolbar 控制是否生成 vxe-table 右上角的 自定义列配置项 (列设置)
    hasCustomToolbar: {
      type: Boolean,
      default: false
    },

    hasOperationButton: {
      type: Boolean,
      default: false
    },

    // 显示分页栏, 与原来的 showType 逻辑分离
    hasPagerBar: {
      type: Boolean,
      default: false
    },

    hasSearchBar: {
      type: Boolean,
      default: true
    },

    hasToolBar: {
      type: Boolean,
      default: true
    },

    height: {
      type: String,
      default: '500'
    },

    id: {
      type: String,
      default: '001'
    },

    // 动态设置表格字段显示的最小宽度
    isDynamicMinWidth: {
      type: Boolean,
      default: false
    },

    listApi: {
      type: Object,
      default: () => {
        return {};
      }
    },

    listParams: {
      type: Object,
      default: () => {
        return {};
      }
    },

    loadingState: {
      type: Boolean,
      default: false
    },

    mergeCells: {
      type: Array,
      default: function () {
        return null;
      }
    },

    /**
     * mergeSpanMethodFn: rowspan merge method
     * @deprecated since version 1.0.0
     * @see mergeCells
     */
    mergeSpanMethodFn: {
      type: Function,
      default: null
    },

    operationColumnWidth: {
      type: Number,
      default: DEFAULT_OPERATION_COLUMN_WIDTH
    },

    option: {
      type: Object,
      default: () => {
        return {};
      }
    },

    page: {
      type: Object,
      default: () => {
        return {
          pageSize: 50,
          currentPage: 0
        };
      }
    },

    popupColumn: {
      type: Object,
      default: () => {
        return {};
      }
    },
    // rowStyle: 用于设置行样式
    rowStyle: {
      type: Function,
      default: function () {
        return null;
      }
    },
    selection: {
      type: Boolean,
      default: true
    },

    showEditColumnIcon: {
      type: Boolean,
      default: true
    },

    // showOverflow: boolean | string, ellipsis(只显示省略号), title(并且显示为原生 title), tooltip(并且显示为 tooltip 提示)
    showOverflow: {
      type: String,
      default: 'tooltip'
    },

    showPager: {
      // 是否展示分页
      type: Boolean,
      default: true
    },

    showType: {
      type: String,
      default: ''
    },

    sortable: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      labels: LABELS,
      list: this.data,
      loading: this.loadingState || false,
      isAllChecked: false,
      isReload: false,
      fullSelection: [],
      selectRecords: [],
      filterName1: '',
      validRules: {},
      validQueue: [],

      // default configurations
      baseCheckboxConfig: { reserve: true },
      baseCustomConfig: { storage: true, resizable: true },
      baseEditConfig: {
        trigger: 'click',
        mode: 'row',
        showIcon: this.showEditColumnIcon === false ? false : !this.readOnly,
        activeMethod: this.activeRowMethod
      },
      keyboardConfig: { isArrow: true, isDel: true, isEnter: true, isTab: true, isEdit: true },
      baseMenuConfig: { enabled: false },
      baseScrollYConfig: { gt: 20 },
      baseSortConfig: { trigger: 'cell' },
      tooltipConfig: { showAll: false },

      // default values
      defaultMinWidth: 150,

      formatType: {
        date: this.formatDate,
        datetime: this.formatTime
      }
    };
  },
  watch: {
    data: {
      handler: function (newVal, oldVar) {
        this.list = newVal || [];
        if (this.list.length > 0) {
          this.loading = false;
        }
      },
      deep: true,
      immediate: true
    },
    option: {
      handler: function (newVal, oldVar) {
        this.isReload = true;
      },
      deep: true,
      immediate: true
    },

    loadingState(newVal) {
      this.loading = newVal;
    }
  },
  computed: {
    checkboxConfig() {
      if (this.option.checkboxConfig) {
        return Object.assign(this.baseCheckboxConfig, this.option.checkboxConfig);
      }
      return this.baseCheckboxConfig;
    },

    customConfig() {
      if (this.option.customConfig) {
        return Object.assign(this.baseCustomConfig, this.option.customConfig);
      }
      return this.baseCustomConfig;
    },

    editConfig() {
      if (this.option.editConfig) {
        return Object.assign(this.baseEditConfig, this.option.editConfig);
      }
      return this.baseEditConfig;
    },

    fullSelectionSize() {
      return this.fullSelection.length;
    },

    listSize() {
      return this.list.length;
    },

    menuConfig() {
      if (this.option.menuConfig) {
        return Object.assign(this.baseMenuConfig, this.option.menuConfig);
      }
      return this.baseMenuConfig;
    },

    scrollYConfig() {
      if (this.option.sortConfig) {
        return Object.assign(this.baseScrollYConfig, this.option.scrollYConfig);
      }
      return this.baseScrollYConfig;
    },

    selectRecordsSize() {
      // return this.selectRecords.length;
      const xTable = this.$refs.xTable;

      if (xTable && xTable.getCheckboxRecords) {
        // const isAllSelected = xTable.isAllSelected;
        // const isIndeterminate = xTable.isIndeterminate;

        const checkboxRecords = xTable.getCheckboxRecords();

        return checkboxRecords.length;
      } else {
        return this.selectRecords.length;
      }
    },

    sequenceConfig() {
      return {
        seqMethod: this.generateSequence
      };
    },

    sortConfig() {
      if (this.option.sortConfig) {
        return Object.assign(this.baseSortConfig, this.option.sortConfig);
      }
      return this.baseSortConfig;
    },

    tableColumn() {
      if (this.isReload) {
        this.$nextTick(() => {
          this.isReload = false;
        });
      }

      return this.handlerColumn(this.option.column || []);
    },

    validConfig() {
      if (this.option.validRules) {
        return Object.assign(this.validRules, this.option.validRules);
      }
      return this.validRules;
    }
  },

  methods: {
    activeRowMethod({ row, rowIndex, column, columnIndex }) {
      if (this.readOnly) {
        return false;
      }

      // if (column?.editRender?.attrs?.disabled === true) {
      //   return false;
      // }

      // 检查有验证未通过的行，不允许编辑其他行，避免死锁
      if (this.validQueue.length > 0 && !this.validQueue.includes(rowIndex)) {
        return false;
      }

      if (typeof this.enableEditRowFn === 'function') {
        return this.enableEditRowFn({ row, rowIndex, column, columnIndex });
      }

      this.$emit('row-click', row);

      return true;
    },

    add2selection(selection, fullItems = this.fullSelection) {
      const key = this.checkKey;

      const selectionKeyValue = selection[key];
      const fullSelection = this.fullSelection;

      const itemIndex = fullSelection.findIndex((item) => item[key] === selectionKeyValue);

      if (itemIndex < 0) {
        fullSelection.push(selection);
      }
    },

    add2selections(items = [], fullItems = this.fullSelection) {
      const key = this.checkKey;
      const existItems = {};

      for (const fullItem of fullItems) {
        existItems[fullItem[key]] = fullItem;
      }

      for (const item of items) {
        if (!existItems[item[key]]) {
          this.fullSelection.push(item);
        }
      }
    },

    cellClickEvent({ column }) {
      this.$emit('cell-click', column);
      // console.log(`单元格点击${column.title}`);
    },

    cellContextMenuEvent({ row }) {
      // console.log(`右键行 ${row.name}`);
    },

    cellDBLClickEvent({ column }) {
      // console.log(`单元格双击${column.title}`);
    },

    cellMouseenterEvent({ column }) {
      this.$emit('cell-enter', column);
      // console.log(`鼠标进入单元格${column.title}`);
    },

    cellMouseleaveEvent({ column }) {
      this.$emit('cell-leave', column);
      // console.log(`鼠标离开单元格${column.title}`);
    },

    changeFilterEvent(evnt, option, $panel) {
      $panel.changeOption(evnt, !!option.data, option);
    },

    checkboxAllEvent({ records, reserves, indeterminates, checked, $event }) {
      this.checkboxChange({ records, reserves, indeterminates, checked, $event });
    },

    checkboxChange({
      records,
      reserves,
      indeterminates,
      checked,
      row,
      rowIndex,
      $rowIndex,
      column,
      columnIndex,
      $columnIndex,
      $event
    }) {
      this.isAllChecked = this.$refs.xTable.isAllCheckboxChecked();
      this.isIndeterminate = this.$refs.xTable.isAllCheckboxIndeterminate();

      if (checked && records.length > 0) {
        typeof rowIndex === 'undefined' ? this.add2selections(records) : this.add2selection(row);
      } else if (typeof rowIndex === 'undefined') {
        this.remove2selections(records);
      } else {
        this.remove2selection(row);
      }

      this.selectRecords = records;
      this.$emit('selection-change', this.fullSelection);
    },

    checkboxChangeEvent({
      records,
      reserves,
      indeterminates,
      checked,
      row,
      rowIndex,
      $rowIndex,
      column,
      columnIndex,
      $columnIndex,
      $event
    }) {
      this.checkboxChange({
        records,
        reserves,
        indeterminates,
        checked,
        row,
        rowIndex,
        $rowIndex,
        column,
        columnIndex,
        $columnIndex,
        $event
      });
    },

    clearSelection() {
      this.$refs.xTable.clearCheckboxRow();

      this.fullSelection = [];
      this.selectRecords = [];
    },

    countAllAmount(data) {
      return XEUtils.sum(data.map((row) => this.countAmount(row)));
    },

    countAmount(row) {
      return XEUtils.multiply(row.amount, row.number);
    },

    currentChange(data) {
      this.$emit('current-change', data);
    },

    async editClosedEvent({ row, rowIndex, $rowIndex, column, columnIndex, $columnIndex }) {
      const $table = this.$refs.xTable;
      const field = column.property;
      const cellValue = row[field];

      if (!this.validQueue.includes(rowIndex)) {
        this.validQueue.push(rowIndex);
      }

      try {
        await this.validRowEvent(row, $rowIndex);

        // 判断单元格值是否被修改
        if ($table.isUpdateByRow(row, field)) {
          setTimeout(() => {
            this.$XModal.message({
              content: `${LABELS.partialSaveSuccessfully}. ${field}=${cellValue}`,
              status: 'success'
            });
            // 局部更新单元格为已保存状态
            $table.reloadRow(row, null, field);
          }, 300);
        }

        this.$emit('row-update', {
          row,
          rowIndex,
          $rowIndex,
          column,
          columnIndex,
          $columnIndex,
          field
        });

        setTimeout(() => {
          const queueIndex = this.validQueue.indexOf(rowIndex);
          this.validQueue.splice(queueIndex, 1);
        }, 100);
      } catch (err) {
        console.log('validate row error', err);
      }
    },

    // 要不要，原版本没有, 中控有
    editRowEvent(row) {
      const $table = this.$refs.xTable;
      $table.setActiveRow(row);
    },

    filterMethod({ value, row, column }) {
      const myvalue = XEUtils.toValueString(row[column.property]);
      const isRight = myvalue.toLowerCase().indexOf(value.toLowerCase()) > -1;
      return isRight;
    },

    formatter({ cellValue, column, columnIndex, row, rowIndex }) {
      const cellType = column?.type;

      return cellType && this.formatType[cellType]
        ? this.formatType[cellType]({ cellValue, column, columnIndex, row, rowIndex })
        : cellValue;
    },

    formatDate({ cellValue, column, columnIndex, row, rowIndex }) {
      return XEUtils.toDateString(cellValue, 'yyyy-MM-dd');
    },

    formatTime({ cellValue, column, columnIndex, row, rowIndex }) {
      return XEUtils.toDateString(cellValue, 'yyyy-MM-dd HH:mm:ss');
    },

    async fullValidEvent() {
      const $table = this.$refs.xTable;
      const errMap = await $table.fullValidate().catch((errMap) => errMap);

      if (errMap) {
        const msgList = [];
        Object.values(errMap).forEach((errList) => {
          errList.forEach((params) => {
            const { rowIndex, column, rules } = params;
            rules.forEach((rule) => {
              msgList.push(
                `${LABELS.validationErrorOnLine.replace('?', (rowIndex + 1).toString())} - ${
                  column.title
                }: ${rule.message}`
              );
            });
          });
        });
        this.$message.error({
          status: 'error',
          message: () => {
            return [
              <div class="red" style="max-height: 400px;overflow: auto;">
                {msgList.map((msg) => (
                  <div>{msg}</div>
                ))}
              </div>
            ];
          }
        });
        return false;
      } else {
        return true;
      }
    },

    /***
     * 生成表格的序号, 不分页时不计算当前页数
     * @see https://xuliangzhan_admin.gitee.io/vxe-table/?hmsr=aladdin1e5#/table/api
     */
    generateSequence({ seq }) {
      // { $rowIndex:. rowIndex, columnIndex, rowIndex, seq }
      const currentPage = this.page?.currentPage || 0;
      const pageSize = this.page?.pageSize;

      return currentPage > 0 && pageSize ? (currentPage - 1) * pageSize + seq : seq;
    },

    getAllProp() {
      const list = this.tableColumn.map((item) => {
        return item.field;
      });
      return list;
    },

    /**
     * 获取表格字段的默认最小宽度
     * @param {object} item
     * @returns
     */
    getDefaultMinWidth(item) {
      return this.isDynamicMinWidth ? this.getDynamicMinWidth(item) : this.defaultMinWidth;
    },

    /**
     * 动态获取字段的默认最小宽度: 字段名称中包含(数量, 单价, 单位, 日期)
     * @param {object} item
     * @returns
     */
    getDynamicMinWidth(item) {
      // TODO: 暂时未处理多语言时非中文的判断
      return item.label.includes('数量') ||
        item.label.includes('单价') ||
        item.label.includes('单位')
        ? 80
        : item.label.includes('日期')
        ? 100
        : this.defaultMinWidth;
    },

    getFormatter(item = {}) {
      const datatype = item?.editRender?.props?.type;
      return datatype && this.formatType[datatype] ? this.formatType[datatype] : null;
    },

    getRender(item) {
      const ctype = item.datatype;
      let embeddedDatatype = EMBEDDED_DATATYPE[ctype];
      let prop = {};
      const obj = {};

      // 根据配置生成规则
      if (ctype === 'popup' || ctype === 'popupName') {
        embeddedDatatype = 'input';
      } else if (ctype === 'number') {
        prop = { type: 'number' };
      } else if (ctype === 'date' || item.type === 'date' || item.prop === 'createDate') {
        embeddedDatatype = '$input';
        prop = { type: 'date', placeholder: LABELS.pleaseSelectDate };
      } else if (ctype === 'datetime' || item.type === 'datetime') {
        embeddedDatatype = '$input';
        prop = { type: 'datetime', placeholder: LABELS.pleaseSelectDateTime };
      } else if (ctype === 'money') {
        embeddedDatatype = '$input';
        prop = { type: 'float', digits: 2 };
      } else if (ctype === 'bizDic' || item.bizDic) {
        embeddedDatatype = '$select';
        obj.options = item.dicData;
        obj.props = { clearable: true };
      } else if (item.prop === 'taxCode') {
        embeddedDatatype = '$select';
        obj.options = item.dicData;
        obj.events = { change: this.taxCodeChangeEvent };
      }

      obj.name = embeddedDatatype || 'input';
      obj.props = prop;

      if (obj.name.startsWith('$')) {
        Object.assign(obj.props, { disabled: !!item.disabled });
      } else {
        obj.attrs = { disabled: !!item.disabled };
      }

      return obj;
    },

    headerCellClickEvent({ column }) {
      // console.log(`表头单元格点击${column.title}`);
    },

    headerCellContextMenuEvent({ column }) {
      // console.log(`右键列 ${column.title}`);
    },

    headerCellDBLClickEvent({ column }) {
      // console.log(`表头单元格双击${column.title}`);
    },

    handlerColumn(columns) {
      const list = [];

      for (const item of columns) {
        const { label, prop } = item;
        const newItem = {
          align: item.align, // 对齐
          cell: item.cell, // 单元格编辑状态
          component: item.component,
          field: prop,
          filters: item.dicData,
          popup: item.datatype === 'popup', // 是否默认弹窗
          prop: prop,
          fixed: item.fixed,
          readonly: item.isReadOnly,
          slot: item.slot, // 是否插槽
          title: label,
          type: RENDER_TYPE[item.type] || '', // 渲染类型
          visible: item.visible,
          width: item.width || '',
          minWidth: item.minWidth || this.getDefaultMinWidth(item)
        };

        newItem.editRender = this.getRender(item);

        this.setValidRule(item);

        this.setAlign(newItem, item);
        this.setSortable(newItem, item);
        this.setSlot(newItem, item);

        list.push(newItem);
      }

      return list;
    },

    handlePageChange({ type, currentPage, pageSize, $event }) {
      this.page.currentPage = currentPage;
      this.page.pageSize = pageSize;
      this.loading = true;
      this.$emit('update:page', this.page);
      this.$emit('page-change', this.page);
    },

    isActiveByRow(row) {
      return this.$refs.xTable.isActiveByRow(row);
    },

    /** merge span method
     * @param {Object} [option={ row, rowindex, $rowindex, _rowindex, column, columnindex, $columnindex, _columnindex, data }]
     * @returns {Object} { rowspan: number, colspan: number}
     */
    mergeSpanMethod(option) {
      if (this.mergeSpanMethodFn && typeof this.mergeSpanMethodFn === 'function') {
        return this.mergeSpanMethodFn(option);
      }

      return null;
    },

    remove2selection(selection) {
      const key = this.checkKey;
      const selectionKeyValue = selection[key];
      const fullSelection = this.fullSelection;

      const itemIndex = fullSelection.findIndex((item) => item[key] === selectionKeyValue);

      if (itemIndex > -1) {
        fullSelection.splice(itemIndex, 1);
      }
    },

    remove2selections(items = [], fullItems = this.fullSelection) {
      const key = this.checkKey;
      const pageItems = {};
      const newItems = [];

      for (const dataItem of this.data) {
        pageItems[dataItem[key]] = dataItem;
      }

      // 保留非当前页面数据
      for (const fullItem of fullItems) {
        if (!pageItems[fullItem[key]]) {
          newItems.push(fullItem);
        }
      }

      // 添加当前页选中数据
      newItems.concat(items);

      this.fullSelection = newItems;
    },

    resizeColumn(column) {},

    rowClassName({ row }) {
      if (row.className) {
        return row.className;
      }
    },

    async saveRowEvent() {
      try {
        // await this.fullValidEvent();
        await this.validAllEvent();

        const $table = this.$refs.xTable;

        $table.clearActived().then(() => {
          this.loading = true;

          setTimeout(() => {
            this.loading = false;
            this.$XModal.message({ content: LABELS.saveSuccessfully, status: 'success' });
          }, 300);
        });
      } catch (err) {
        console.log('save row error', err);
      }
    },

    searchEvent() {
      const filterName = XEUtils.toValueString(this.filterName1).trim().toLowerCase();
      if (filterName) {
        const filterRE = new RegExp(filterName, 'gi');
        const searchProps = this.getAllProp();
        const rest = this.data.filter((item) =>
          searchProps.some(
            (key) => XEUtils.toValueString(item[key]).toLowerCase().indexOf(filterName) > -1
          )
        );
        this.list = rest.map((row) => {
          const item = Object.assign({}, row);
          searchProps.forEach((key) => {
            item[key] = XEUtils.toValueString(item[key]).replace(filterRE, (match) => `${match}`);
          });
          return item;
        });
      } else {
        this.list = this.data;
      }

      this.selectRecords = [];
      this.$emit('selection-change', []);
    },

    setAlign(newItem, item) {
      if (
        NUMBER_DATATYPE[item.datatype] ||
        item.label.includes('数量') ||
        item.label.includes('款') ||
        item.label.includes('价') ||
        item.label.includes('金额') ||
        item.label.includes('总额')
      ) {
        newItem.align = 'right';
      }
    },

    setMergeCells({ row, col, rowspan, colspan }) {
      // { row: number, col: number, rowspan: number, colspan: number }
    },

    setSlot(newItem, item) {
      if (item.datatype === 'popup') {
        newItem.slot = true;
      }
    },

    setSortable(newItem, item) {
      if (
        NUMBER_DATATYPE[item.datatype] ||
        item.label.includes('量') ||
        item.label.includes('行号') ||
        item.label.includes('编号') ||
        item.label.includes('编码') ||
        item.label.includes('时间') ||
        item.label.includes('款') ||
        item.label.includes('价') ||
        item.label.includes('金额') ||
        item.label.includes('总额') ||
        item.label.includes('日期') ||
        item.sortable
      ) {
        newItem.sortable = true;
      }
    },

    setValidRule(item) {
      if (
        item.rules &&
        Array.isArray(item.rules) &&
        item.rules.length > 0 &&
        !this.validRules[item.prop]
      ) {
        const ruleItems = [...item.rules];

        this.validRules[item.prop] = ruleItems;
      }
    },

    taxCodeChangeEvent(data, { $event, value }) {
      // { row, rowIndex, $rowIndex, column, columnIndex, $columnIndex } = data
      const { row } = data;
      this.$emit('tax-code-change', { $event, value, row });
    },

    toolBarCustom(event) {
      this.$emit('column-confirm', event);
    },

    async validAllEvent() {
      const $table = this.$refs.xTable;
      const errMap = await $table.validate(true).catch((errMap) => errMap);

      if (errMap) {
        // this.$XModal.message({ status: 'error', message: '校验不通过' });

        const keys = Object.keys(errMap);

        if (keys.length > 0) {
          throw new Event(`valid cell fail: ${keys[0]}`);
        } else {
          throw new Event(`valid cell fail: unknown field.`);
        }
      }
      // else {
      //   this.$XModal.message({ status: 'success', message: '校验成功' });
      // }
    },

    async validRowEvent(row, rowIndex) {
      const $table = this.$refs.xTable;
      const errMap = await $table.validate(row).catch((errMap) => errMap);

      if (errMap) {
        // this.$XModal.message({ status: 'error', message: '校验不通过' });
        throw new Error(`valid ${rowIndex} error`);
      }
    },

    async validateEvent() {
      const $table = this.$refs.xTable;
      const errMap = await $table.validate($table.data).catch((errMap) => errMap);

      // for (const row of $table.data) {
      //   await this.validRowEvent(row, row.$index);
      // }

      if (errMap) {
        // this.$XModal.message({ status: 'error', message: '校验不通过' });

        const keys = Object.keys(errMap);

        if (keys.length > 0) {
          throw new Event(`valid cell fail: ${keys[0]}`);
        } else {
          throw new Event(`valid cell fail: unknown field.`);
        }
      }
      // else {
      //   this.$XModal.message({ status: 'success', message: '校验成功' });
      // }
    }
  }
};
</script>
<style>
.fullBox .vxe-input--inner {
  height: 39px;
  width: 100%;
}
.fullBox.vxe-input {
  width: 100% !important;
  margin-right: 10px;
}
.topbar {
  padding-bottom: 8px;
}
</style>
