<template>
  <el-main ref="tablePanel" class="ht-table-panel">
    <div class="ht-table-header">
      <div v-if="hasToolBar" ref="toolbarContainer" class="toolbar-container">
        <slot name="toolbar"></slot>
      </div>
      <div
        v-if="!noHeader && !justShowSearch"
        ref="toolbarPanel"
        class="toolbar-panel"
      >
        <div
          v-if="!justShowSearch"
          class="toolbar-panel__search"
          :class="{ 'ht-quick__search': !hideTableSearch }"
        >
          <div class="toolbar-panel__search-left">
            <ht-input
              v-if="
                quickSearchConfig && quickSearchConfig.length > 0 && !isMobile
              "
              ref="quickSearch"
              v-model.lazy="quickSearchWord"
              class="quick-search"
              :style="quickSearchWidthStyle"
              :placeholder="quickSearchPlaceholder"
              :autofocus="autofocus"
              :disabled="loading || showAdvancedSearch"
              :debounce="2000"
              suffix-icon="el-icon-search"
              style="margin-right: 8px"
              @keydown.enter.native="doQuickSearch"
              @click.native="clickQuickSearch"
            ></ht-input>
            <van-search
              v-if="
                quickSearchConfig && quickSearchConfig.length > 0 && isMobile
              "
              ref="quickSearch"
              v-model.lazy="quickSearchWord"
              :placeholder="quickSearchPlaceholder"
              :autofocus="true"
              :disabled="loading || showAdvancedSearch"
              :debounce="2000"
              @search="doQuickSearch"
              @click.native="clickQuickSearch"
            />
            <el-tooltip
              v-if="hasSearchPanel && !justShowSearch"
              :content="showAdvancedSearch ? '基础搜索' : '高级搜索'"
              placement="top"
              effect="light"
            >
              <el-button
                icon="icon-shaixuan"
                class="table-button refresh-btn-icon"
                @click="showAdvancedSearch = !showAdvancedSearch"
              ></el-button>
            </el-tooltip>
            <el-tooltip
              v-if="hasSearchPanel && hasOftenUsed && OftenUsedList.length > 0"
              :content="'常用搜索'"
              placement="top"
              effect="light"
            >
              <el-popover
                v-model="visible"
                popper-class="ht-table-often-used"
                placement="bottom-end"
                width="200"
                trigger="click"
              >
                <div class="often-used-container">
                  <template v-for="(item, i) of OftenUsedList">
                    <div
                      :key="i"
                      class="often-used-container-item"
                      :class="{
                        'often-used-container-item-active': item.activation,
                      }"
                    >
                      <span @click="handlerOftenUsedItem(item)">
                        {{ item.key }}
                      </span>
                      <i
                        class="icon-lanmushanchu"
                        @click="deleteOftenUsedItem(item, i)"
                      ></i>
                    </div>
                  </template>
                </div>
                <el-button
                  slot="reference"
                  class="table-button often-used-button"
                  @click="handleOftenUsed"
                >
                  常用
                </el-button>
              </el-popover>
            </el-tooltip>
          </div>

          <div class="common-tools">
            <template v-if="isShowFilterStatus && !isCardView">
              <div
                v-for="(filterConfig, index) of filterConfigList"
                :key="index"
                class="common-tools__status"
              >
                <el-button
                  :class="{
                    'is-active-status': statusVisible[index],
                  }"
                  :icon="
                    statusVisible[index]
                      ? 'el-icon-caret-top'
                      : 'el-icon-caret-bottom'
                  "
                  @click="handleStatusVisibleChange(index)"
                >
                  {{ filterConfig.label || '状态' }}
                </el-button>
                <div
                  v-if="statusVisible[index]"
                  class="common-tools__status__details"
                >
                  <div class="common-tools__status__details__top">
                    <el-checkbox-group v-model="statusCheckList[index]">
                      <el-checkbox
                        v-for="(item, i) of filterConfig.filters"
                        :key="i"
                        class="common-tools__status__details__content"
                        :label="item.value"
                      >
                        {{ item.text }}
                      </el-checkbox>
                    </el-checkbox-group>
                  </div>
                  <div class="common-tools__status__details__buttom">
                    <span
                      class="common-tools__status__details__buttom__left"
                      @click="handleStatusFilter(filterConfig, index)"
                    >
                      筛选
                    </span>
                    <span @click="handleStatusReset(filterConfig, index)">
                      重置
                    </span>
                  </div>
                </div>
              </div>
            </template>
            <el-tooltip
              v-if="showExport"
              content="导出数据"
              placement="top"
              effect="light"
            >
              <el-button @click="$emit('export')">
                <ht-icon name="arrow" class="button-export" />
              </el-button>
            </el-tooltip>

            <!-- <el-button-group v-if="multiViewSwitch" class="multiview-switcher"> -->
            <template v-if="multiViewSwitch">
              <el-tooltip content="卡片视图" placement="top" effect="light">
                <el-button
                  v-show="isCardView"
                  class="button-view"
                  :type="isCardView ? 'primary' : 'default'"
                  @click="handleCardView(false)"
                >
                  <ht-icon name="block" />
                </el-button>
              </el-tooltip>
              <el-tooltip content="表格视图" placement="top" effect="light">
                <el-button
                  v-show="!isCardView"
                  class="button-view"
                  :type="isCardView ? 'default' : 'primary'"
                  @click="handleCardView(true)"
                >
                  <ht-icon name="line" />
                </el-button>
              </el-tooltip>
            </template>

            <!-- </el-button-group> -->
            <el-tooltip
              v-if="showCustomColumn && !isCardView"
              content="自定义列"
              placement="top"
              effect="light"
            >
              <el-button @click="customColumnDialogVisible = true">
                <ht-icon name="setting" />
              </el-button>
            </el-tooltip>
            <el-tooltip content="刷新数据" placement="top" effect="light">
              <i
                v-if="isMobile && !isTablet"
                class="refresh-btn-icon icon-shuaxin1"
                @click="load(true)"
              ></i>
              <el-button
                v-else
                icon="el-icon-refresh"
                class="refresh-btn-icon"
                @click="load(true)"
              ></el-button>
            </el-tooltip>
          </div>
        </div>
      </div>
    </div>
    <el-collapse-transition>
      <div
        v-if="(showAdvancedSearch || justShowSearch) && hasSearchPanel"
        ref="searchPanel"
        class="search-panel"
      >
        <slot name="search"></slot>
      </div>
    </el-collapse-transition>

    <template v-if="!isCardView">
      <el-table
        v-if="!isOrderViews"
        ref="htTable"
        v-loading="loading && !noLoading"
        :stripe="stripe"
        :border="border"
        class="ht-table"
        :class="{
          'no-data-table': data && data.length < 1,
          'ht-checkbox-to-radio': showSelectType === 'radio',
        }"
        :data="data"
        :size="size"
        :empty-text="emptyText"
        :show-header="showHeader"
        :max-height="
          customTableMaxHeight
            ? customTableMaxHeight
            : tableMaxHeight > normHeight || customTableHeight
            ? tableMaxHeight
            : normHeight
        "
        :tooltip-effect="tooltipEffect"
        :default-querys="defaultQuerys"
        :header-row-class-name="headerRowClassName"
        :header-cell-class-name="headerCellClassName"
        :highlight-current-row="highlightCurrentRow"
        :row-class-name="rowClassName"
        :cell-class-name="cellClassName"
        :lazy="lazy"
        :tree-props="treeProps"
        :style="{
          height: customTableMaxHeight
            ? 'fit-content'
            : `${
                tableMaxHeight > normHeight || customTableHeight
                  ? tableMaxHeight
                  : normHeight
              }` + 'px',
        }"
        :row-key="rowKey"
        :load="
          (tree, treeNode, resolve) =>
            $emit('load-children', tree, treeNode, resolve, parentIdField)
        "
        @row-dblclick="
          (row, column, event) => $emit('row-dblclick', row, column, event)
        "
        @row-click="handleRowClick"
        @select="handleTableSelect"
        @select-all="handleTableSelect"
        @sort-change="handleSortChange"
        @filter-change="handleFilterChange"
        @selection-change="(selection) => handleSelectChange(selection)"
        @row-contextmenu="
          (row, column, event) => $emit('row-contextmenu', row, column, event)
        "
      >
        <el-table-column
          v-if="selectable"
          :key="refreshTableKey"
          type="selection"
          align="center"
          :reserve-selection="reserveSelection"
          width="45"
        />
        <slot></slot>
        <template slot="empty">
          <el-image :src="tableNoDataImg"></el-image>
          <p class="no-data-text">{{ emptyText || t('el.table.emptyText') }}</p>
        </template>
      </el-table>
      <template v-else>
        <transition>
          <div
            v-loading="loading && !noLoading"
            :style="{
              height:
                `${
                  tableMaxHeight > normHeight || customTableHeight
                    ? tableMaxHeight
                    : normHeight
                }` + 'px',
            }"
          >
            <template v-if="loading || (data && data.length > 0)">
              <slot name="orderViews" :data="data"></slot>
            </template>
            <div v-else class="empty-order-views">
              <el-image :src="tableNoDataImg"></el-image>
              <p class="no-data-text">
                {{ emptyText || t('el.table.emptyText') }}
              </p>
            </div>
          </div>
        </transition>
      </template>
    </template>
    <transition v-else>
      <div
        v-loading="loading && !noLoading"
        class="ht-card"
        :style="{
          height:
            `${
              tableMaxHeight > normHeight || customTableHeight
                ? tableMaxHeight
                : normHeight
            }` + 'px',
        }"
      >
        <template v-if="loading || (data && data.length > 0)">
          <div v-if="cardItemMode" class="ht-card__container">
            <el-card
              v-for="(item, index) in data"
              :key="index"
              shadow="hover"
              @click.native="$emit('card-click', item)"
            >
              <slot name="card" :item="item"></slot>
            </el-card>
          </div>
          <div v-else>
            <slot name="card" :data="data"></slot>
          </div>
        </template>
        <div v-else class="el-table__empty-block">
          <template v-if="data.length < 1 && !emptyText">
            <slot name="empty-card"></slot>
          </template>
          <span v-else-if="emptyText" class="el-table__empty-text">
            {{ emptyText || t('el.table.emptyText') }}
          </span>
        </div>
      </div>
    </transition>
    <div v-if="!nopagination" ref="paginationPanel" class="pagination-panel">
      <el-row type="flex" :justify="tablePaginationJustify">
        <el-pagination
          :small="small"
          :class="{ 'page-sizes__hidden': hidePageSizes }"
          :disabled="loading"
          :current-page="pagination.page"
          :page-sizes="pageSizes"
          :page-size="pagination.pageSize"
          :pager-count="pagerCount"
          :background="$paginationBackground"
          :layout="layout"
          :total="pagination.total"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        ></el-pagination>
      </el-row>
    </div>
    <custom-column
      :custom-columns="customColumns"
      :is-show-set-width="isShowSetWidth"
      :custom-columns-default="customColumnsDefault"
      :visible.sync="customColumnDialogVisible"
      @apply-custom-column="handleApplyCustomColumn"
    ></custom-column>
  </el-main>
</template>
<script>
  import Locale from '@/mixins/locale'
  import Emitter from '@/mixins/emitter'
  import utils from '@/utils.js'
  import CustomColumn from './CustomColumn.vue'
  import mobileMode from '@/mixins/mobileMode.js'
  import elementResizeDetectorMaker from 'element-resize-detector'
  export default {
    name: 'HtTable',
    components: { CustomColumn },
    mixins: [Locale, Emitter, mobileMode],
    inject: {
      registerAdvOptChild: {
        from: 'registerAdvOptChild',
        default: () => () => console.error('方法未注入'),
      },
    },
    props: {
      //是否使用小型分页样式
      small: {
        type: Boolean,
        default: false,
      },
      size: {
        type: String,
        default: 'mini',
      },
      tooltipEffect: {
        type: String,
        default: 'dark',
      },
      justShowSearch: {
        //为true时只显示高级搜索中的查询条件
        type: Boolean,
        default: false,
      },
      defaultShowSearch: {
        //为true时默认显示高级搜索中的查询条件
        type: Boolean,
        default: false,
      },
      paginationJustify: {
        type: String,
        default: 'start',
        validator: function (value) {
          return ['start', 'end', 'center'].indexOf(value) !== -1
        },
      },
      data: Array,
      showHeader: {
        type: Boolean,
        default: true,
      },
      pageResult: {
        type: Object,
        default: () => {
          return { page: 1, pageSize: 50, total: 0 }
        },
      },
      pageSizes: {
        type: Array,
        default: () => {
          return [10, 20, 50, 100, 200, 300]
        },
      },
      pagerCount: {
        type: Number,
        default: 7,
      },
      nopagination: {
        type: Boolean,
        default: false,
      },
      highlightCurrentRow: {
        type: Boolean,
        default: false,
      },
      selectable: {
        type: Boolean,
        default: true,
      },
      quickSearchProps: [String, Array],
      headerRowClassName: [String, Function],
      headerCellClassName: [String, Function],
      rowClassName: [String, Function],
      cellClassName: [String, Function],
      showExport: {
        type: Boolean,
        default: false,
      },
      showCustomColumn: {
        type: Boolean,
        default: true,
      },
      defaultQuerys: {
        type: Array,
        default() {
          return []
        },
      },
      defaultSorter: {
        type: Array,
        default() {
          return []
        },
      },
      isLoadTable: {
        //是否默认在mounted函数中请求table数据
        type: Boolean,
        default: true,
      },
      quickSearchWidth: {
        type: Number,
        default: 280,
      },
      //自定义传入固定高度 与 customTableMaxHeight的区别是 customTableHeight是整个控件固定高度且参与高度计算，customTableMaxHeight是eltable的最大高度
      customTableHeight: {
        type: [String, Number],
        validator: (val) => {
          if (typeof val == 'number') {
            return val > 0
          } else if (typeof val == 'string') {
            const numVal = Number(val)
            return !isNaN(numVal) && numVal > 0
          } else {
            return false
          }
        },
      },
      //自定义传入最大高度，与 customTableHeight的区别是 customTableHeight是整个控件固定高度且参与高度计算，customTableMaxHeight是eltable的最大高度
      customTableMaxHeight: {
        type: [String, Number],
        validator: (val) => {
          if (typeof val == 'number' && !Number.isNaN(val)) {
            return val > 0
          } else if (typeof val == 'string') {
            const numVal = Number(val)
            return !isNaN(numVal) && numVal > 0
          } else {
            return false
          }
        },
      },
      multiViewSwitch: {
        // 是否支持多视图切换
        type: Boolean,
        default: false,
      },
      cardView: {
        // 是否卡片视图
        type: Boolean,
        default: false,
      },
      cardItemMode: {
        // 是否单个卡片模式
        type: Boolean,
        default: true,
      },
      noHeader: {
        // 不显示整个工具栏
        type: Boolean,
        default: false,
      },
      emptyText: String,
      rowClickSelect: {
        // 单击行时是否选中该行数据
        type: Boolean,
        default: true,
      },
      autoFix: {
        //是否在表头高度改变时，触发doLayout操作
        type: Boolean,
        default: false,
      },
      hidePageSizes: {
        type: Boolean,
        default: false,
      },
      tableNoDataImg: {
        type: String,
        default: require('@/assets/table-no-data.png'),
      },
      noLoading: {
        type: Boolean,
        default: false,
      },
      rowKey: {
        type: [Function, String],
      },
      reserveSelection: {
        type: Boolean,
        default: false,
      },
      stripe: {
        type: Boolean,
        default: true,
      },
      layout: {
        type: String,
        default: 'total, sizes, prev, pager, next, jumper',
      },
      /* 是否是表单列表或数据列表 */
      isDataTemplateList: {
        type: Boolean,
        default: false,
      },
      border: {
        type: Boolean,
        default: true,
      },
      /** pc合并查询输入框是否自动聚焦 */
      autofocus: {
        type: Boolean,
        default: true,
      },
      //是否前端搜索（不分页）
      isFrontSearch: {
        type: Boolean,
        default: false,
      },
      //是否其他视图
      isOrderViews: {
        type: Boolean,
        default: false,
      },

      //是否常用按钮  启用后onlyOftenUsedKey 也是必需传的
      hasOftenUsed: {
        type: Boolean,
        default: false,
      },
      //常用按钮全局唯一key
      onlyOftenUsedKey: { type: String },

      //显示过滤按钮 与filterConfig 一起用
      isShowFilterStatus: {
        type: Boolean,
        default: false,
      },
      filterConfigList: {
        type: Array,
        default: () => {
          return []
          // {     label:''  //按钮名称  default:'状态'
          //    props: '', //过滤字段
          //     filters: [], //过滤所有条件  {text:text,value:value}
          //     }
        },
      },
      //是否显示自定义列的宽度设置
      isShowSetWidth: {
        type: Boolean,
        default: true,
      },
      isCustomChecked: {
        //自定义默认选择 true时只选择 有 checked，required 属性为true的显示
        type: Boolean,
        default: false,
      },
      treeProps: {
        type: Object,
        default: () => {
          return { hasChildren: 'hasChildren', children: 'children' }
        },
      },
      //是否懒加载
      lazy: {
        type: Boolean,
        default: false,
      },
      //选择框样式  none  check radio
      showSelectType: {
        type: String,
        default: 'check',
        validator(val) {
          return ['none', 'check', 'radio'].includes(val)
        },
      },
      parentIdField: String,
    },
    data() {
      return {
        resetDefaultFilter: [], // 重置时需把默认筛选条件重置
        querys: [],
        sorter: null,
        quickSearchWord: null,
        quickSearchPlaceholder: '请输入搜索内容',
        quickSearchConfig: null,
        hasSearchPanel: false,
        filters: {},
        pagination: { ...this.pageResult },
        tableMaxHeight: 320,
        normHeight: 320,
        showAdvancedSearch: false,
        loading: false,
        columns: [],
        customColumns: [],
        customColumnDialogVisible: false,
        selection: [],
        tablePanelHeight: 0,
        isCardView: this.cardView,
        visible: false,
        statusVisible: {},
        statusCheckList: {},
        OftenUsedList: [],
        refreshTableKey: Math.random(),
        unregister: null,
      }
    },
    computed: {
      // 默认列配置信息
      customColumnsDefault() {
        // 从插槽中获取到当前表格的所有列
        const ary = []
        this.columns = []
        if (
          !this.$slots ||
          !this.$slots.default ||
          this.$slots.default.length == 0
        ) {
          return ary
        }
        const count = this.$slots.default.length
        this.$slots.default &&
          this.$slots.default.forEach((n, index) => {
            // 将当前表格的列放入一个数组 多表头时需递归改造
            this.setColumns(n)
            if (n && n.componentOptions) {
              const pd = n.componentOptions.propsData
              // 将当前有有prop和label的列放入自定义列表项的数组中
              if (pd.label) {
                const hasChildren =
                  n.componentOptions.children &&
                  n.componentOptions.children.length > 0
                ary.push({
                  key: pd.prop
                    ? `${pd.prop}__${index}`
                    : `${pd.label}__${index}`,
                  value: pd.label,
                  checked: this.isCustomChecked
                    ? pd.checked === true || pd.required === true
                    : !(pd.hidden === true || pd.hidden === '') ||
                      pd.required === true ||
                      pd.required === '' ||
                      // index == count - 1 ||
                      hasChildren,
                  required:
                    pd.required === true ||
                    pd.required === '' ||
                    // index == count - 1 ||
                    hasChildren,
                  width: pd.width || 'auto',
                })
              }
            }
          })
        return ary
      },
      calDefaultQuerys: function () {
        let calQuerys = []
        let query = {
          group: 'defaultQueryGroup',
          operation: 'EQUAL',
          relation: 'AND',
        }
        this.defaultQuerys.forEach((c) => {
          // 如果有重置过筛选条件的 需在默认条件中剔除
          if (this.resetDefaultFilter.indexOf(c.property) === -1) {
            calQuerys.push({ ...query, ...c })
          }
        })
        return calQuerys
      },
      hasToolBar() {
        return this.$slots.toolbar && this.$slots.toolbar.length > 0
      },
      hideTableSearch() {
        const hasQuickSearch =
          this.quickSearchConfig && this.quickSearchConfig.length > 0
        return !this.showAdvancedSearch && !this.hasToolBar && !hasQuickSearch
      },
      customTableHeightNum() {
        return typeof this.customTableHeight == 'number'
          ? this.customTableHeight
          : Number(this.customTableHeight)
      },
      quickSearchWidthStyle() {
        return { width: `${this.quickSearchWidth}` + 'px' }
      },
      tablePaginationJustify() {
        return this.$allPaginationJustify || this.paginationJustify
      },
      isTablet() {
        //判断是否是平板设备  是全局isMobile里面做了，这里要做区分
        return window.matchMedia('(min-width: 768px) and (max-width: 1024px)')
          .matches
      },
    },
    watch: {
      justShowSearch: {
        handler(val) {
          if (val) {
            this.showAdvancedSearch = true
          }
        },
        immediate: true,
      },
      defaultShowSearch: {
        handler(val) {
          if (val) {
            this.showAdvancedSearch = true
          }
        },
        immediate: true,
      },
      isCardView: function (newVal, oldVal) {
        if (newVal !== oldVal) {
          this.clearSelection()
          this.$emit('view-change', newVal)
        }
      },
      customTableHeight() {
        this.calcTableHeight()
      },
      nopagination() {
        this.calcTableHeight()
      },
    },
    created() {
      this.initCustomColumns()
      this.hasOftenUsed && this.getOftenUsedList()
      this.$on('advance-search', (data, isSearchBtn, isOftenUsed) =>
        this.advanceSearch(data, isSearchBtn, isOftenUsed)
      )
      this.$on('update-often-search', () => this.getOftenUsedList())
      setTimeout(() => {
        this.quickSearchProps && this.generateQuickSearchConfig()
      }, 100)
      this.getCardView()
    },
    activated() {
      !this.isMobile && this.load(true)
      this.doLayout()
    },
    mounted() {
      // 判断是否有高级搜索面板
      this.hasSearchPanel = !!this.$scopedSlots.search

      if (this.isLoadTable) {
        this.load()
      }
      this.$nextTick(() => {
        this.$refs.tablePanel.$el.clientHeight
      })
      if (this.isDataTemplateList) {
        this.calcTableHeight(1000)
      } else {
        this.calcTableHeight()
      }
      this.$watch('showAdvancedSearch', (n, o) => {
        if (n !== o) {
          if (n) {
            this.quickSearchWord = null
          }
          // 显示或收起搜索面板时，重新计算表格高度
          this.$nextTick(() => {
            this.$refs.tablePanel.$el.clientHeight
          })
          this.calcTableHeight(800)
          this.$emit('advanced-show', n)
        }
      })
      this.$watch('pageResult', (n, o) => {
        if (n !== o) {
          this.pagination = { ...n }
        }
      })
      this.$root.$on('resize', () => {
        this.tablePanelHeight = 0
        this.calcTableHeight(500)
      })
      if (this.$refs.htTable && this.autoFix) {
        this.addResizeListener()
      }
      // 注册回调方法
      this.unregister = this.registerAdvOptChild((payload) => {
        this.showAdvancedSearch = false
      })
    },
    beforeDestroy() {
      this.$root.$off('resize', () => {
        this.tablePanelHeight = 0
        this.calcTableHeight(500)
      })
      this.unregister && this.unregister()
    },
    methods: {
      //有唯一key和本地有值则取本地
      getCardView() {
        if (
          this.onlyOftenUsedKey &&
          localStorage.getItem(`card-view-${this.onlyOftenUsedKey}`)
        ) {
          this.isCardView = JSON.parse(
            localStorage.getItem(`card-view-${this.onlyOftenUsedKey}`)
          )
        }
      },
      //视图改变
      handleCardView(val) {
        if (this.onlyOftenUsedKey) {
          localStorage.setItem(`card-view-${this.onlyOftenUsedKey}`, val)
        }
        this.isCardView = val
      },
      handleStatusVisibleChange(i) {
        this.$set(this.statusVisible, i, this.statusVisible[i] ? false : true)
        this.$set(this.statusCheckList, i, this.statusCheckList[i] || [])
      },
      handleStatusFilter(filterConfig, i) {
        //当传参含有 all-query-reset 时直接清空传参
        let list = this.statusCheckList[i]
        if (this.statusCheckList[i].includes('all-query-reset')) {
          list = []
        }
        this.handleFilterChange({
          [filterConfig.props]: list,
        })

        this.$set(this.statusVisible, i, false)
      },
      handleStatusReset(filterConfig, i) {
        this.statusCheckList[i] = []
        this.handleFilterChange({
          [filterConfig.props]: [],
        })
        this.$set(this.statusVisible, i, false)
      },
      setColumns(n) {
        if (n && n.componentOptions) {
          this.columns.push(n.componentOptions.propsData)
        }
        if (n && n.componentOptions && n.componentOptions.children) {
          n.componentOptions.children.forEach((i) => {
            this.setColumns(i)
          })
        }
      },
      initCustomColumns() {
        const me = this
        const ary = []
        this.columns = []
        setTimeout(() => {
          if (
            !me.$slots ||
            !me.$slots.default ||
            me.$slots.default.length == 0
          ) {
            return
          }
          const count = me.$slots.default.length
          // 从插槽中获取到当前表格的所有列
          me.$slots.default &&
            me.$slots.default.forEach((n, index) => {
              // 将当前表格的列放入一个数组 多表头时需递归改造
              me.setColumns(n)
              if (n && n.componentOptions) {
                const pd = n.componentOptions.propsData
                // 将当前有有prop和label的列放入自定义列表项的数组中
                if (pd.label) {
                  const hasChildren =
                    n.componentOptions.children &&
                    n.componentOptions.children.length > 0
                  ary.push({
                    key: pd.prop && pd.prop != '.' ? pd.prop : pd.label,
                    value: pd.label,
                    checked: this.isCustomChecked
                      ? pd.checked === true || pd.required === true
                      : !(pd.hidden === true || pd.hidden === '') ||
                        pd.required === true ||
                        pd.required === '' ||
                        // index == count - 1 ||
                        hasChildren,
                    required:
                      pd.required === true ||
                      pd.required === '' ||
                      // index == count - 1 ||
                      hasChildren,
                    width: pd.width || 'auto',
                  })
                }
              }
            })
          me.customColumns = ary
        }, 0)
      },
      handleApplyCustomColumn(columns) {
        this.$emit('reflashField', columns)
        this.broadcast('HtTableColumn', 'customColumn', columns)
        this.$nextTick(() => {
          setTimeout(() => this.doLayout(), 200)
        })
      },
      doQuickSearch() {
        // 先删除快速查询的查询条件
        this.clearQueryByGroupName('quick')
        this.clearQueryByGroupName('advance')
        this.quickSearchWord &&
          this.quickSearchConfig.forEach((c) => {
            let query = {
              property: c.prop,
              value: this.quickSearchWord.trim(),
              group: 'quick',
              relation: 'OR',
              operation: 'LIKE',
            }
            this.querys.push(query)
          })
        if (this.nopagination && this.isFrontSearch) {
          this.$emit('frontSearch', this.querys)
        } else {
          this.load('', true)
        }
      },
      clickQuickSearch($event) {
        if (
          !(this.loading || this.showAdvancedSearch) &&
          $event &&
          $event.target &&
          $event.target.tagName == 'I'
        ) {
          this.$nextTick(() => {
            this.doQuickSearch()
          })
        }
      },
      advanceSearch(data, isSearchBtn, isOftenUsed) {
        if ((this.loading || !this.showAdvancedSearch) && !isOftenUsed) {
          return
        }
        this.clearQueryByGroupName('quick')
        this.clearQueryByGroupName('advance')
        // 清空筛选过滤条件
        this.clearQueryByGroupName('filter')
        if (this.$refs.htTable && this.$refs.htTable.columns) {
          this.$refs.htTable.columns.forEach((item) => {
            item.filteredValue = []
          })
        }
        if (this.$refs.htTable) {
          this.$refs.htTable.clearFilter()
        }
        this.filters = {}
        data &&
          data.forEach((d) => {
            const shouldPush =
              d.value != null && d.value != undefined && d.value != ''
            // 高级搜索中支持一个搜索框中关联多个属性进行搜索
            if (d.prop.indexOf(',') > 0) {
              const propAry = utils.stringSplit(d.prop, ',')
              if (propAry && propAry.length > 0) {
                const groupName = `group_${propAry[0]}`
                this.clearQueryByGroupName(groupName)
                shouldPush &&
                  propAry.forEach((p) => {
                    this.querys.push({
                      property: p,
                      value: d.value,
                      group: groupName,
                      relation: 'OR',
                      operation: d.operation,
                    })
                  })
              }
            } else {
              shouldPush &&
                this.querys.push({
                  property: d.prop,
                  value: d.value,
                  group: 'advance',
                  relation: d.relation,
                  operation: d.operation,
                })
            }
          })
        this.load('', isSearchBtn)
      },
      // 加载数据
      load(doNotResetPage, isSearchBtn) {
        this.loading = true
        // 默认重置页码为第一页
        if (!doNotResetPage) {
          this.pagination.page = 1
        }
        let param = {
          pageBean: this.pagination,
          sorter: [],
        }

        if (this.sorter && this.sorter.length > 0) {
          param.sorter = this.sorter
        }
        // 处理默认排序字段。只有当用户没有选择排序字段才使用默认排序
        if (this.defaultSorter.length > 0 && param.sorter.length == 0) {
          param.sorter = [...this.defaultSorter]
        }
        // 处理过滤条件
        this.handleFilters()

        if (this.querys && this.querys.length > 0) {
          param.querys = this.querys
        }

        // 处理查询条件
        if (this.calDefaultQuerys.length > 0) {
          if (!param.querys) {
            param.querys = []
          }
          this.calDefaultQuerys.forEach((item) => {
            param.querys.remove(item)
          })
          // 默认查询条件和当前查询条件重复时，取消默认条件
          param.querys = param.querys.concat(
            this.calDefaultQuerys.filter((item) => {
              let index = param.querys.findIndex((sub) => {
                return sub.property === item.property
              })
              return index === -1
            })
          )
        }

        const me = this
        // 防止外部没有回调，设置10秒后自动取消加载中的状态
        let waitTime = 10000
        if (!this._events || !this._events.load || !this._events.load.length) {
          // 如果没有绑定在当前组件里的load事件，即组件仅仅作展示数据用 直接取消loading
          waitTime = 0
        }
        const finalTickCB = setTimeout(function () {
          me.loading = false
          me.clearSelection()
        }, waitTime)

        if (this.nopagination) {
          param.pageBean = {}
        }
        const loadedHandler = () => {
          // 外部已经回调的情况下，取消倒计时
          clearTimeout(finalTickCB)
          me.loading = false
          this.clearSelection()

          if (this.autofocus) {
            setTimeout(() => {
              me.$refs.quickSearch &&
                me.$refs.quickSearch.$children[0].$el.children[0].focus()
            })
          }
        }

        this.$emit('load', { ...param }, loadedHandler, isSearchBtn)
        this.$emit('loading', { ...param }, loadedHandler, isSearchBtn)
      },
      // 通过列属性获取列标签
      getColumnLabelByProp(prop) {
        let label = null
        if (!prop) {
          return label
        }
        this.columns.forEach((c) => {
          if (c.prop && c.prop === prop) {
            label = c.label
          }
        })
        return label
      },
      // 构建快速搜索配置项
      generateQuickSearchConfig() {
        let labelAry = []
        if (typeof this.quickSearchProps == 'string') {
          const props = utils.stringSplit(this.quickSearchProps, ',')
          this.quickSearchConfig = []
          props.forEach((prop) => {
            const label = this.getColumnLabelByProp(prop)
            if (label) {
              labelAry.push(label)
              this.quickSearchConfig.push({ prop, label })
            }
          })
        }
        if (typeof this.quickSearchProps == 'object') {
          this.quickSearchProps.forEach((prop) => {
            if (prop && prop.label) {
              labelAry.push(prop.label)
            }
          })
          this.quickSearchConfig = [...this.quickSearchProps]
        }
        //去除提示语中的请输入
        let labelAryMap = labelAry.map((item) => {
          return item.replace(new RegExp('请输入', 'g'), '')
        })
        this.quickSearchPlaceholder = `${this.t(
          'ht.common.enter'
        )}${labelAryMap.join(',')}${this.t('ht.common.toSearch')}`
      },
      // 通过分组名称清除对应查询条件
      clearQueryByGroupName(groupName) {
        // 待删除的查询条件
        let toDelete = []
        this.querys &&
          this.querys.forEach((query) => {
            if (query.group == groupName) {
              toDelete.push(query)
            }
          })
        toDelete.forEach((d) => {
          this.querys.remove(d)
        })
      },
      handleFilters() {
        this.clearQueryByGroupName('filter')
        // 将过滤条件添加查询参数数组中
        if (this.filters && Object.keys(this.filters).length > 0) {
          Object.keys(this.filters).forEach((k) => {
            const filter = this.filters[k]
            let query = {
              property: k,
              value: filter[0],
              group: 'filter',
              relation: 'AND',
            }
            if (filter.length == 1) {
              query.operation = 'EQUAL'
              this.querys.push(query)
            } else if (filter.length > 1) {
              query.operation = 'IN'
              query.value = filter
              this.querys.push(query)
            }
          })
        }
      },
      handleSizeChange(pageSize) {
        this.pagination = { ...this.pagination, pageSize }
        this.$emit('size-change', pageSize)
        this.load()
      },
      handleCurrentChange(page) {
        this.pagination = { ...this.pagination, page }
        // 翻页时不重置页码
        this.$emit('current-change', page)
        this.load(true)
      },
      handleSelectChange(selection) {
        if (this.showSelectType === 'check') {
          this.$emit('selection-change', selection)
        } else {
          this.$emit(
            'selection-change',
            selection.length > 1 ? [selection[selection.length - 1]] : selection
          )
        }
      },
      handleRowClick(row, column, event) {
        if (this.showSelectType !== 'check') {
          this.$refs.htTable.clearSelection()
        }
        if (this.rowClickSelect) {
          if (this.selection.some((s) => s === row)) {
            this.selection.remove(row)
          } else {
            this.selection.push(row)
          }
          this.$refs.htTable.toggleRowSelection(row)
        }

        this.$emit('row-click', row, column, event)
      },
      handleTableSelect(selection, row) {
        if (this.showSelectType === 'check') {
          this.selection = selection
        } else {
          selection.length > 1 &&
            this.$refs.htTable.toggleRowSelection(selection[0])
          this.$set(this, 'selection', [row])
        }
        if (row) {
          this.$emit('select', this.selection, row)
        } else {
          this.$emit('select-all', this.selection)
        }
      },
      handleSortChange(column) {
        if (!column.order) {
          this.sorter = null
        } else {
          this.sorter = [
            {
              property: column.prop,
              direction: column.order == 'ascending' ? 'ASC' : 'DESC',
            },
          ]
        }
        this.load(true)
        this.$emit('sort-change', column)
      },
      handleFilterChange(m) {
        // 如果是点击的是重置 筛选条件 需把默认的筛选条件里数据也删除掉
        if (m) {
          Object.keys(m).forEach((key) => {
            if (
              m[key] &&
              m[key].length == 0 &&
              this.resetDefaultFilter.indexOf(key) === -1
            ) {
              this.resetDefaultFilter.push(key)
            }
          })
        }
        this.filters = { ...this.filters, ...m }
        Object.keys(this.filters).forEach((k) => {
          if (!this.filters[k] || this.filters[k].length == 0) {
            delete this.filters[k]
          }
        })
        this.$emit('filter-change', m)
        this.load()
      },
      doLayout() {
        this.$nextTick(() => {
          this.$refs.htTable && this.$refs.htTable.doLayout()
        })
      },
      initTablePanelHeight() {
        this.tablePanelHeight = this.$refs.tablePanel.$el.clientHeight
      },
      calcTableHeight(delay) {
        //当有自定义高度时，且是 显示为 el-table 控件时 ，不自适应高度
        if (
          this.customTableMaxHeight &&
          !this.isOrderViews &&
          !this.isCardView
        ) {
          return
        }
        // 动态计算表格的高度，自适应当前容器
        setTimeout(() => {
          const toolbarPanelHeight =
            (this.$refs.toolbarPanel && this.$refs.toolbarPanel.clientHeight) ||
            0

          const searchPanelHeight =
            (this.$refs.searchPanel && this.$refs.searchPanel.offsetHeight) || 0

          //toolbarContainerHeight和toolbarPanelHeight 合并为一行 所以设置其中一个为0
          const toolbarContainerHeight = 0
          // (this.$refs.toolbarContainer &&
          //   this.$refs.toolbarContainer.clientHeight) ||
          // 0

          const paginationPanelHeight =
            (this.$refs.paginationPanel &&
              this.$refs.paginationPanel.clientHeight) ||
            0
          // 下外边距
          const searchPanelBottom = searchPanelHeight > 0 ? 16 : 0 //
          const toolbarPanelBottom = toolbarPanelHeight > 0 ? 8 : 0
          const toolbarContainerBottom = toolbarContainerHeight > 0 ? 10 : 0
          const showAdvancedHeight = this.showAdvancedSearch ? 25 : 25

          //2为边框
          // 表格之外的高度
          const tableOuterHeight =
            toolbarPanelHeight +
            toolbarPanelBottom +
            searchPanelHeight +
            searchPanelBottom +
            toolbarContainerHeight +
            toolbarContainerBottom +
            paginationPanelHeight +
            showAdvancedHeight +
            10

          if (this.$refs.tablePanel) {
            this.tablePanelHeight = this.$refs.tablePanel.$el.clientHeight || 0
          }
          if (this.customTableHeightNum) {
            this.tableMaxHeight = this.customTableHeightNum - tableOuterHeight
          } else {
            if (!this.$refs.tablePanel) {
              return
            }
            if (this.tablePanelHeight == 0) {
              this.initTablePanelHeight()
            }
            const tableHeight = this.tablePanelHeight - tableOuterHeight
            this.tableMaxHeight = tableHeight
          }
        }, delay || 0)
      },
      addResizeListener() {
        //监听表头高度变化，如果
        this.$nextTick(() => {
          let erd = elementResizeDetectorMaker()

          erd.listenTo(
            this.$refs.htTable.$refs.headerWrapper.getElementsByTagName(
              'tr'
            )[0],
            this.doLayout
          )
        })
      },
      // 清空选中的数据
      clearSelection() {
        this.selection = []
        this.$refs.htTable && this.$refs.htTable.clearSelection()
      },
      getOftenUsedList() {
        this.$requestConfig.commonList(this.onlyOftenUsedKey).then((res) => {
          this.OftenUsedList = res
        })
      },
      //常用
      handleOftenUsed() {
        this.OftenUsedList.forEach((item, index) => {
          item.activation = false
        })
        this.visible = false
        this.$requestConfig.commonList(this.onlyOftenUsedKey).then((res) => {
          this.OftenUsedList = res
          let idList = []
          if (sessionStorage.getItem('tableSearchItemId')) {
            idList = JSON.parse(sessionStorage.getItem('tableSearchItemId'))
          }
          if (idList && idList.length > 0 && this.OftenUsedList.length > 0) {
            this.OftenUsedList.forEach((item, index) => {
              if (idList.some((itemList) => itemList.id == item.id)) {
                item.activation = true
              }
            })
          }
          this.visible = true
        })
      },
      //点击常用的item
      handlerOftenUsedItem(item) {
        let list = JSON.parse(item.content)
        sessionStorage.setItem('tableSearchFormType', true)

        this.broadcast(
          'HtTableSearchPanel',
          'change-TableSearchPanel-fieldArray',
          [list, item.id]
        )

        this.visible = false
      },
      //删除常用的item
      deleteOftenUsedItem(item, index) {
        this.$requestConfig.deleteCommonList(item.id).then((res) => {
          this.OftenUsedList.splice(index, 1)
          if (res.state) {
            this.$message.success('删除成功')
          } else {
            this.$message.error('删除失败')
          }
        })
      },
    },
  }
</script>
<style lang="scss" scoped>
  .ht-table-panel {
    padding: 0px;
    height: 100%;
    overflow: hidden;
    .toolbar-panel {
      flex: 1;
    }
    .toolbar-panel,
    .toolbar-container {
      margin-bottom: 8px;
      box-sizing: border-box;
    }
    .toolbar-container {
      white-space: nowrap;
      margin-right: 12px;
      ::v-deep {
        .el-button span {
          max-width: 85px;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
          display: inline-block;
        }
      }
    }
    .search-panel {
      background-color: #f9f9f9;
      padding: 16px 16px 0px 16px;
      margin-bottom: 16px;
      box-sizing: border-box;
      border: 1px solid #ebebeb;
    }
  }
  .ht-table-header {
    display: flex;
    flex-wrap: nowrap;
  }

  .ht-table {
    width: 100%;
    //min-height: 500px;
  }
  ::v-deep .el-table__body-wrapper {
    height: 100%;
  }
  .no-data-table {
    ::v-deep .el-table__body-wrapper {
      height: 100%;
      .el-table__empty-text {
        line-height: unset;
      }
      .no-data-text {
        margin: 8px 0;
        line-height: 20px;
        font-size: 14px;
      }
    }
  }
  .ht-card {
    .el-table__empty-block {
      height: 100%;
    }
  }
  .toolbar-panel__search {
    display: flex;
    justify-content: space-between;
    width: 100%;
    .el-button + .el-tooltip {
      margin-left: 8px;
    }
    &-left {
      display: flex;
    }
  }

  .search-container__col {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -ms-flex-align: center;
    flex-direction: row;
    align-items: center;
  }

  .ht-quick__search {
    margin-bottom: 8px;
    max-height: 34px;
  }

  .quick-search {
    margin-right: 20px;
    overflow: hidden !important;
    ::v-deep {
      .el-input__inner {
        height: 34px !important;
        line-height: 34px !important;
      }
    }
    ::v-deep .el-icon-search {
      font-size: 16px;
      color: #262626;
      font-weight: 600;
    }
  }

  ::v-deep .el-icon-refresh {
    font-size: 16px;
  }
  .quick-search + .el-divider {
    margin-right: 20px;
  }

  ::v-deep .el-input__inner,
  ::v-deep .el-input-group__append {
    border-radius: 0;
  }
  .table-button {
    height: 34px;
    padding: 6px;
    border-radius: 0;
    padding: 8px !important;

    ::v-deep {
      i {
        font-size: 16px;
      }
    }
  }
  .often-used-button {
    line-height: 16px;
  }
  .common-tools {
    display: flex;
    justify-content: flex-end;

    .el-button-group {
      margin: 0 0 0 16px;
    }

    .el-button {
      padding: 6px;
      border-radius: 0;
    }

    .advance-search__button {
      padding: 6px 12px;
    }

    .common-tools__status {
      position: relative;
      ::v-deep {
        .el-button {
          display: flex;
          flex-direction: row-reverse;
          background: #fff;
          color: #262626;
          i {
            margin-left: 8px;
            color: #8c8c8c;
            font-size: 16px;
          }
        }
      }
      & + .common-tools__status,
      & + .el-button {
        margin-left: 8px;
      }
      .is-active-status {
        border-color: var(--themeColor);
        color: var(--themeColor);
      }
    }
    .common-tools__status__details {
      z-index: 9;
      position: absolute;
      margin-top: 4px;
      min-width: 110px;
      background: #ffffff;
      box-shadow: 0px 2px 8px 1px rgba(0, 0, 0, 0.15);
      border-radius: 8px 8px 8px 8px;
      right: 0;
      ::v-deep {
        .el-checkbox-group {
          display: flex;
          flex-direction: column;
          min-width: 144px;
        }
        .el-checkbox__input.is-checked + .el-checkbox__label {
          color: #262626;
        }
      }

      &__content {
        padding: 6px 8px;
        height: 16px;
        margin-right: 0;
        display: flex;
        &:hover {
          background: #f9f9f9;
          border-radius: 8px 8px 8px 8px;
        }
      }
      ::v-deep {
        .el-checkbox__label {
          display: inline-block;
          max-width: 200px;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }
      }
      &__top {
        max-height: 400px;
        overflow-y: auto;
        padding: 8px;
      }
      &__buttom {
        border-top: 1px solid #ebebeb;
        padding: 6px 16px;

        span {
          cursor: pointer;
          font-weight: 400;
          font-size: 14px;
          color: #262626;
          line-height: 22px;

          & + span {
            margin-left: 16px;
          }
        }
        &__left {
          color: var(--themeColor) !important;
        }
      }
    }
  }

  ::v-deep .ht-table .sort-caret.descending {
    bottom: 0px;
  }

  ::v-deep .ht-table .sort-caret.ascending {
    top: -2px;
  }

  ::v-deep .ht-table .caret-wrapper {
    height: 20px;
  }

  ::v-deep .ht-table .el-table__column-filter-trigger {
    line-height: 20px;
  }

  .pagination-panel {
    padding: 10px 0;
  }
  .button-view {
    background: #fff !important;
    color: var(--themeColor) !important;
  }
  .button-export {
    color: var(--themeColor);
  }
  .multiview-switcher {
    width: 59px;
    height: 32px;
    overflow: hidden;
  }

  .ht-card {
    @include base-scrollbar;
    overflow: auto;

    .ht-card__container {
      &::after {
        content: '';
        display: block;
        clear: both;
      }

      .el-card {
        cursor: pointer;
        float: left;
        margin: 8px;

        ::v-deep .el-card__body {
          padding: 16px;
        }
      }
    }
  }

  .page-sizes__hidden {
    ::v-deep .el-pagination__sizes {
      display: none;
    }
  }
  .empty-order-views {
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
  }
  .often-used-container {
    max-height: 200px;
    overflow-y: auto;

    &-item {
      height: 20px;
      line-height: 20px;
      padding: 6px 8px;
      display: flex;

      align-items: center;

      span {
        cursor: pointer;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        display: inline-block;
        width: calc(100% - 24px);
      }
      i {
        cursor: pointer;
        margin-left: 8px;
        color: #8c8c8c;
        font-size: 16px;
      }
      &:hover {
        color: var(--themeColor);
        background: #f9f9f9;
        border-radius: 8px 8px 8px 8px;
      }
    }
    &-item-active {
      color: var(--themeColor);
    }
  }
</style>

<style lang="scss">
  .el-popover.el-popper.ht-table-often-used {
    margin-top: 4px;
    max-width: 250px;
    padding: 8px;
    background: #ffffff;
    box-shadow: 0px 2px 8px 1px rgba(0, 0, 0, 0.15);
    border-radius: 8px 8px 8px 8px;
    .popper__arrow {
      display: none;
    }
  }

  .ht-table.ht-checkbox-to-radio {
    .el-table__header {
      .el-table-column--selection .el-checkbox {
        display: none !important;
      }
    }
    .el-table__row .el-table-column--selection .el-checkbox__inner {
      border-radius: 50% !important;
    }
  }
</style>
