<template>
  <div class="eno-table-select">
    <!-- 弹出框 -->
    <el-popover ref="table-popover" popper-class="tableSelectPopper" v-model="visible" :placement="placement" :disabled="tableSelectDisabled">
      <div class="eno-table-select-filter" v-if="props.filterable">
        <el-input :placeholder="props.filterText" v-model="searchKeyWords" @keydown.enter.native="getPageData()">
          <i slot="suffix" @click="getPageData()" class="el-input__icon el-icon-search"></i>
        </el-input>
      </div>
      <!-- 单选表格 -->
      <el-radio-group v-model="selectedRow" @change="selectRow">
        <el-table v-bind="$attrs" v-on="$listeners" :data="data" size="mini" :style="{
            width: tableWidth
          }">
          <el-table-column :width="30">
            <template slot-scope="{ row }">
              <el-radio :label="row[props.key]" :disabled="row[rowDisabledAttribute]">{{ '' }}</el-radio>
            </template>
          </el-table-column>
          <el-table-column v-for="column of columns" :key="column.key" :label="column.label" :prop="column.key" :width="column.width" show-overflow-tooltip>
            <template slot-scope="{ row, $index }">
              <slot :name="column.key" :row="row" :index="$index">{{ row[column.key] }}</slot>
            </template>
          </el-table-column>
        </el-table>
      </el-radio-group>
      <!-- 分页 -->
      <enoPaging v-if="paged" :total="dataLength" @pageChange="getPageData" :on-query="getPageData" :pager.sync="pager" layout="total, prev,pager, next"></enoPaging>
    </el-popover>
    <!-- 输入框 -->
    <el-input
      ref="reference"
      :class="{ 'is-focus': visible }"
      v-popover:table-popover
      v-model="selectedLabel"
      type="text"
      :placeholder="currentPlaceholder"
      :name="name"
      :id="id"
      :readonly="readonly"
      :disabled="tableSelectDisabled"
      @focus="handleFocus"
      @blur="handleBlur"
      @keyup.native="debouncedOnInputChange"
      @paste.native="debouncedOnInputChange"
    >
      <template slot="suffix">
        <i v-show="!showClose" :class="['el-select__caret', 'el-input__icon', 'el-icon-' + iconClass]"></i>
        <i v-if="showClose" class="el-select__caret el-input__icon el-icon-circle-close" @click="handleClearClick"></i>
      </template>
    </el-input>
  </div>
</template>

<script>
import { debounce } from 'throttle-debounce'
import { addResizeListener, removeResizeListener } from './resize-event'

export default {
  name: 'enoTableSelect',
  inheritAttrs: false,
  inject: {
    ElForm: {
      default: '',
    },
    ElFormItem: {
      default: '',
    },
  },
  props: {
    id: String,
    name: String,
    columns: Array,
    value: {
      required: true,
    },
    size: String,
    data: Array,
    dataLength: {
      type: Number,
      default: 0,
    },
    tableWidth: {
      type: String,
      default: '400px',
    },
    filterText: {
      type: String,
      default: '请搜索',
    },
    disabled: Boolean,
    clearable: Boolean,
    collapseTags: Boolean,
    filterable: Boolean,
    filterMethod: Function,
    paged: {
      type: Boolean,
      default: true,
    },
    layout: String,
    pageSize: Number,
    currentPage: Number,
    props: Object,
    placeholder: {
      type: String,
      default() {
        return '请选择'
      },
    },
    placement: {
      type: String,
      default: 'bottom',
    },
    initLabel: String,
  },
  data() {
    return {
      initTag: false,
      inputLength: 20,
      inputWidth: 0,
      initialInputHeight: 0,
      selectedLabel: '', // 输入框显示值
      query: '', // 搜索输入值 (多选)
      selectedRow: null, // 选中节点 (单选)
      checkedRows: [], // 选中节点数组 (多选)
      checkedKeys: [], // 选中节点key值数组 (多选)
      currentPlaceholder: '', // 输入框占位符
      cachedPlaceHolder: '', // 占位符缓存
      softFocus: false,
      visible: false, // 弹出框显示
      page: this.currentPage,
      searchKeyWords: '',
      pager: {
        size: 10,
        current: 1,
      },
    }
  },
  computed: {
    iconClass() {
      return this.visible ? 'arrow-up is-reverse' : 'arrow-up'
    },
    _elFormItemSize() {
      return (this.elFormItem || {}).elFormItemSize
    },
    tableSelectSize() {
      return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size
    },
    collapseTagSize() {
      return ['small', 'mini'].indexOf(this.tableSelectSize) > -1
        ? 'mini'
        : 'small'
    },
    // 表示列选项禁用的属性
    rowDisabledAttribute() {
      return this.props.disabled || 'disabled'
    },
    tableSelectDisabled() {
      return this.disabled || (this.ElForm || {}).disabled
    },
    readonly() {
      return !this.filterable || !this.visible
    },
    // 是否显示清空按钮
    showClose() {
      const hasValue =
        this.value !== undefined && this.value !== null && this.value !== ''
      const criteria = this.clearable && !this.tableSelectDisabled && hasValue
      return criteria
    },
  },
  watch: {
    placeholder(val) {
      this.cachedPlaceHolder = this.currentPlaceholder = val
    },
    visible(val) {
      if (val) {
        this.setSelected()
      } else {
         if (this.searchKeyWords) {
          this.searchKeyWords = ''
          this.getPageData()
        }
      }
      this.$emit('visible-change', val)
    },
    query(val) {
      if (val && this.visible == false) {
        this.visible = true
      }
    },
    // 通过sync方式更新currentPage
    page(val) {
      this.$emit('update:current-page', val)
    },
    currentPage(val) {
      this.page = val
    },

    initLabel(val) {
      this.selectedLabel = val
    },
  },
  methods: {
    init() {
      if (this.initTag) {
        return
      }
      this.pager = { size: this.props.size, current: this.props.current }

      // 初始树没有渲染，显示弹出框将树渲染出来，设置已选中节点再隐藏弹出框
      this.visible = true
      this.checkedKeys = this.value
      this.setSelected()
      this.visible = false

      addResizeListener(this.$el, this.handleResize)

      const reference = this.$refs.reference
      if (reference && reference.$el) {
        const sizeMap = {
          medium: 36,
          small: 32,
          mini: 28,
        }
        const input = reference.$el.querySelector('input')
        this.initialInputHeight =
          input.getBoundingClientRect().height || sizeMap[this.tableSelectSize]
      }
      this.$nextTick(() => {
        if (reference && reference.$el) {
          this.inputWidth = reference.$el.getBoundingClientRect().width
        }
      })
      this.initTag = true
    },
    valueEquals(a, b) {
      // see: https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
      if (a === b) return true
      if (!(a instanceof Array)) return false
      if (!(b instanceof Array)) return false
      if (a.length !== b.length) return false
      for (let i = 0; i !== a.length; ++i) {
        if (a[i] !== b[i]) return false
      }
      return true
    },
    handleFocus(event) {
      this.init()
      if (this.softFocus) {
        this.softFocus = false
      }
    },
    blur() {
      this.visible = false
      this.$refs.reference.blur()
    },
    handleBlur(event) {
      setTimeout(() => {
        this.$emit('blur', event)
      }, 50)
      this.softFocus = false
    },
    // 根据key值找到对应数据行
    findRowByKey(key) {
      return this.data.find((item) => item[this.props.key] === key)
    },
    //选节点
    selectRow(val) {
      const row = this.findRowByKey(val)
      if (!row && this.selectedLabel) {
        return
      }
      this.selectedLabel = row ? row[this.props.label] : ''
      this.visible = false
      this.$emit('input', row)
    },

    // 设置选中节点
    setSelected() {
      this.selectedRow = this.value
      return
    },
    // 点击清空按钮触发
    handleClearClick(event) {
      this.deleteSelected(event)
    },
    getPageData(params) {
      if (!params) {
        this.pager.current = 1;
        params = {
          current: 1,
          size: this.pager.size,
        }
      }
      params[this.props.filterKey] = this.searchKeyWords
      this.$emit('pageChange', params)
    },
    // 清空选项
    deleteSelected(event) {
      event.stopPropagation()
      const value = ''
      this.$emit('input', value)
      this.emitChange(value)
      this.visible = false
      this.$emit('clear')
    },
    // 值改变向上传递时间
    emitChange(val) {
      if (!this.valueEquals(this.value, val)) {
        this.$emit('change', val)
      }
    },
    // 删除标签
    deleteTag(event, tag) {
      const index = this.checkedKeys.indexOf(tag)
      if (index > -1 && !this.tableSelectDisabled) {
        this.checkedKeys.splice(index, 1)
        this.$emit('remove-tag', tag)
      }
      event.stopPropagation()
    },
    // 搜索输入变化
    onInputChange() {
      if (this.filterable && this.query !== this.selectedLabel) {
        this.query = this.selectedLabel
      }
    },
    handleInputClick(e) {},
    handleResize() {
      this.resetInputWidth()
    },
    // 重置标签框与过滤输入框宽度
    resetInputWidth() {
      this.inputWidth = this.$refs.reference.$el.getBoundingClientRect().width
    },
    // 根据标签数量重置输入框高度（多选）
    resetInputHeight() {
      if (this.collapseTags && !this.filterable) return
      this.$nextTick(() => {
        if (!this.$refs.reference) return
        const inputChildNodes = this.$refs.reference.$el.childNodes
        const input = [].filter.call(
          inputChildNodes,
          (item) => item.tagName === 'INPUT'
        )[0]
        const tags = this.$refs.tags
        const sizeInMap = this.initialInputHeight || 40
        input.style.height =
          this.checkedKeys.length === 0
            ? sizeInMap + 'px'
            : Math.max(
                tags
                  ? tags.clientHeight + (tags.clientHeight > sizeInMap ? 6 : 0)
                  : 0,
                sizeInMap
              ) + 'px'
        if (this.visible && this.emptyText !== false) {
          // this.broadcast('enoSelectDropdown', 'updatePopper')
        }
      })
    },
    // 搜索有输入时重置输入框高度 (多选)
    resetInputState() {
      this.inputLength = this.$refs.input.value.length * 15 + 20
      this.resetInputHeight()
    },
  },
  created() {
    this.cachedPlaceHolder = this.currentPlaceholder = this.placeholder

    this.debouncedOnInputChange = debounce(() => {
      this.onInputChange()
    }, 0)
    this.debouncedQueryChange = debounce((e) => {
      this.handleQueryChange(e.target.value)
    }, 0)
  },
  mounted() {
    if (this.initLabel) {
      this.selectedLabel = this.initLabel
    }
  },
  destroyed() {
    if (this.$el && this.handleResize)
      removeResizeListener(this.$el, this.handleResize)
  },
}
</script>

<style lang="less" scoped>
  :focus {
    outline: 0;
  }
  .eno-table-select-filter {
    height: 32px;
    width: 100%;
    line-height: 32px;
    margin-bottom: 10px;
  }
  /deep/.el-table {
    min-height: 389px;
    margin-bottom: 12px;
    .el-table__header {
      thead {
        th {
          background-color: @bgColor;
          font-size: 14px;
          color: @textColor;
          border-bottom: none;
          .cell {
            font-size: 13px;
          }
        }
      }
    }
  }

  /deep/.pagination_wrapper {
    span {
      display: none;
    }
  }

  /deep/.tableSelectPopper {
    padding-bottom: 0;
  }

  .el-icon-search {
    cursor: pointer;
  }
  .eno-table-select {
    display: inline-block;
    position: relative;
  }
  .eno-table-select > .el-input {
    display: block;
  }
  .eno-table-select .el-input__inner {
    cursor: pointer;
  }
  .eno-table-select .el-input .el-select__caret {
    color: #c0c4cc;
    font-size: 14px;
    transition: transform 0.3s;
    transform: rotateZ(180deg);
    cursor: pointer;
  }
  .eno-table-select .el-input .el-select__caret.is-reverse {
    transform: rotateZ(0);
  }
  .eno-table-select .el-input.is-focus .el-input__inner {
    border-color: #409eff;
  }
  .eno-table-select .el-input__inner:focus {
    border-color: #409eff;
  }
  .eno-table-select__tags {
    position: absolute;
    line-height: normal;
    white-space: normal;
    z-index: 1;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
  }
  .eno-table-select .el-tag {
    box-sizing: border-box;
    border-color: transparent;
    margin: 2px 0 2px 6px;
    background-color: #f0f2f5;
  }
  .eno-table-select .el-tag__close.el-icon-close {
    background-color: #c0c4cc;
    right: -7px;
    top: 0;
    color: #fff;
  }
</style>
