<template>
  <div>
    <el-input v-model="dataValue" :disabled="disabled" placeholder="请输入内容" readonly @focus="handlerFocus"/>
    <ed-dialog ref="elsDialog" :height="height" :title="title" :visible="visible" :width="width" @close="handlerClose"
               @ok="handlerOk">
      <!-- 查询表单 -->
      <ed-form ref="elsForm" v-model="model" :form-desc="formDesc">
        <template v-for="item in formSlots" #[item]="data">
          <slot :name="item" v-bind="data || {}"></slot>
        </template>
        <template v-slot:form-btn>
          <el-button icon="el-icon-search" type="primary" @click="handlerSearch">搜索</el-button>
          <el-button icon="el-icon-delete" @click="handlerClear">清空</el-button>
        </template>
      </ed-form>

      <!-- 数据表格 -->
      <ed-table ref="elsTable" :column-type="columnType" :columns="columns" :data="tables" :height="tableHeight"
                :loading.sync="loading" :pagination.sync="paging ? pagination : undefined"
                @change="initRequest" @row-click="handlerRowClick" @selection-change="handleSelectionChange">
        <template v-for="item in tableSlots" #[item]="data">
          <slot :name="item" v-bind="data || {}"></slot>
        </template>
      </ed-table>

    </ed-dialog>
  </div>
</template>

<script>
import Fetch        from "./Fetch"
import {getVarType} from "../../../tools/utils";

/**
 * 弹窗表格组件
 * - 示例
 *
 * ```vue
 * <ed-input-table v-model="value" :columns="columns" :data="data">
 * </ed-input-table>
 * ```
 *
 * [](./EdInputTableProps.md ':include')
 */
export default {
  name: "EdInputTable",
  props: {
    // 是否多选
    multiple: {type: Boolean, default: false},
    // 是否禁用
    disabled: {type: Boolean, default: false},
    // 值
    value: {type: [String, Object, Array], default: () => []},
    // 标题
    title: {type: String, default: "表格选择器"},
    // 表格列的配置描述
    columns: {type: [Array, String]},
    // table 数据数组
    data: {type: Array, default: () => []},
    // 输入框显示字段分隔符
    split: {type: String, default: "-"},
    // 弹窗宽度
    width: {type: [String, Number]},
    // 弹窗高度
    height: {type: [String, Number]},
    // 表格高度
    tbHeight: {type: [String, Number]},
    // 覆盖默认的上传行为，可以自定义上传的实现：仅支持Promise
    httpRequest: {type: Function, default: Fetch},
    // 是否分页查询
    paging: {type: Boolean, default: false},
    // 上传的地址
    action: {type: String, default: ""},
    // 设置查询的请求头部
    headers: {type: [Object, String]},
    // 查询时附带的额外参数
    params: {type: [Object, String]},
    // 查询成功时的钩子
    onSuccess: {
      type: Function,
      default: function () {
      }
    },
    // 查询失败时的钩子
    onError: {
      type: Function,
      default: function () {
      }
    },
    // 请求的类型；GET 或 POST
    method: {type: String, default: "POST"},
  },
  data() {
    return {
      loading: true,
      visible: false,
      dataValue: "", // input值
      currentRow: {},
      formDesc: [],
      model: {},
      tables: this.data,
      radioVal: "",
      defHeaders: {
        'Content-Type': 'application/json;charset=utf-8'
      },
      // 输入框显示字段
      rowKey: [],
      pagination: {
        current: 1,
        pageSize: 10,
        total: 0,
        pageSizes: [10, 20, 30]
      },
      cardHeight: "300px"
    }
  },
  computed: {
    columnType() {
      return this.multiple ? 'selection' : "radio"
    },
    isAjax() {
      return this.action !== ""
    },
    tableSlots() {
      let slots = []
      this.columns.map(col => slots.push(col.prop + 'Column'))
      return slots
    },
    formSlots() {
      let slots = []
      this.formDesc.map(col => slots.push(col.prop))
      return slots
    },
    tableHeight() {
      if (!this.tbHeight) {
        return this.paging ? 315 - 32 : 315
      } else {
        return this.tbHeight
      }
    }
  },
  watch: {
    columns: {
      handler(nVal, oVal) {
        if (nVal) {
          let column = this.columns.filter(i => i.rowKey)
          if (column.length > 0) this.rowKey = column.map(col => col.prop)

          this.initTableColumns()
          this.initFormDesc()
          this.initDataValue()
        }
      },
      deep: true,
      immediate: true
    },
    value: {
      handler(nVal, oVal) {
        if (nVal && this.columns.length > 0) {
          this.initDataValue()
        }
      },
      deep: true
    },
    action: {
      deep: true,
      immediate: true,
      handler(newVal, oldVal) {
        if (newVal && this.data.length === 0) {
          this.initRequest()
        }
      }
    }
  },
  methods: {
    // 初始化Columns，formDesc
    initRequest() {
      const options = {
        method: this.method,
        headers: Object.assign({}, this.defHeaders, this.headers),
        action: this.action,
        data: this.getAjaxData(),
      }

      this.httpRequest(options).then(res => {
        if (getVarType(res.data) === 'array') {
          this.tables = res.data
        } else {
          this.tables = res.data.records
          if (Object.keys(res.data).includes("total")) this.pagination.total = res.data.total
        }

        this.onSuccess(res);
      }).catch(error => {
        this.onError(error)
      })
    },

    // 初始化TableColumns
    initTableColumns() {
      this.columns.map(column => {
        if (column.formatter && getVarType(column.formatter) === 'string') {
          column.formatter = new Function('return ' + column.formatter)();
        }
      })
    },

    // 初始化FormDesc
    initFormDesc() {
      this.formDesc = []
      this.columns.map(i => {
        if (i.query) {
          this.formDesc.push({
            label: i.label,
            prop: i.map ? i.map : i.prop,
            precise: i.precise ? i.precise : false,
            children: {
              tags: "el-input",
              attrs: {
                placeholder: `请输入${i.label}`
              }
            }
          })
          this.model[i.map ? i.map : i.prop] = ""
        }
      })
    },

    // 初始化input值
    initDataValue() {
      if (getVarType(this.value) === 'object') {
        this.dataValue = this.rowKey.map(prop => this.value[prop]).join(this.split)
      } else if (getVarType(this.value) === 'array') {
        let value = this.value.map(val => this.rowKey.map(prop => val[prop]).join(this.split))
        this.dataValue = value.join(",")
      }
    },

    // 获取焦点时,打开弹窗
    handlerFocus() {
      this.visible = true
      this.$nextTick(() => {
        this.multiple ? this.toggleRowSelection() : this.setCurrentRow()
      })
    },

    // 初始化table选中项 - 单选
    setCurrentRow() {
      if (getVarType(this.value === 'object')) {
        let index = this.isEqualIndex(this.tables, this.value)
        this.$refs.elsTable.setCurrentRow(this.tables[index])
      } else if (getVarType(this.value) === 'array') {
        let index = this.isEqualIndex(this.tables, this.value[0])
        this.$refs.elsTable.setCurrentRow(this.tables[index])
        console.warn("请注意：取值数组第一项，单选模式下传入了Array，应为Object")
      }
    },

    // 初始化table选中项 - 多选
    toggleRowSelection() {
      if (getVarType(this.value) === 'array') {
        this.value.map((row) => {
          let index = this.isEqualIndex(this.tables, row)
          this.$refs.elsTable.toggleRowSelection(this.tables[index])
        })
      } else if (getVarType(this.value) === 'object') {
        let index = this.isEqualIndex(this.tables, this.value)
        this.$refs.elsTable.toggleRowSelection(this.tables[index])
        console.warn("请注意：多选模式下传入了Object，应为Array")
      }
    },

    // 弹窗确认
    handlerOk() {
      this.$emit('input', this.currentRow)
      this.handlerClose()
    },

    // 关闭弹窗
    handlerClose() {
      this.visible = false
    },

    // table单选
    handlerRowClick(row, column, event) {
      if (!this.multiple) {
        this.currentRow = row
      }
    },

    // table多选
    handleSelectionChange(val) {
      if (this.multiple) {
        this.currentRow = val
      }
    },

    // 搜索
    handlerSearch() {
      if (this.isAjax) {
        this.initRequest()
      } else {
        let tableData = []
        Object.keys(this.model).map(key => {
          let data = this.tables.filter(i => i[key].includes(this.model[key]))
          if (this.model[key] && data.length > 0) {
            tableData = [...tableData, ...data]
          } else {
            tableData = this.data
          }
        })
        this.tables = tableData
      }
    },

    // 清空
    handlerClear() {
      this.$refs.elsForm.resetFields()

      if (this.isAjax) {
        this.init()
      } else {
        this.tables = this.data
      }
    },

    // 检测table数组中是否包含传输值，返回其索引值
    isEqualIndex(arr, obj) {
      return arr.findIndex(i => this.rowKey.find(prop => i[prop] === obj[prop]))
    },

    // 组装请求数据
    getAjaxData() {
      let data = Object.assign({}, this.params)
      let page = {current: this.pagination.current, size: this.pagination.pageSize}

      if (this.paging && this.method.toUpperCase() !== "GET") {
        data.page = page
        data.wheres = this.getWheresData()
      } else {
        data = this.paging ? Object.assign(data, page, this.model) : Object.assign(data, this.model)
      }
      return data
    },

    // 组装分页请求数据
    getWheresData() {
      return this.formDesc.map(item => {
        return {label: item.prop, value: this.model[item.prop], precise: item.precise}
      })
    },
  }
}
</script>

<style lang="scss" scoped>
@import "../../../style/index";

.ed-input-table--card {
  border: none;
}

::v-deep {
  .ed-input-table--card .el-card__body {
    height: 100%;
  }
}
</style>
