<template>
  <div class="search-common-container">
    <!-- 左侧已选择内容 -->
    <div class="left-choose">
      <div
        v-for="(it, ind) in chooseList"
        :key="ind"
        class="choose-item"
        @click.stop="editItem(it, ind)"
      >
        {{ it.label + '：' + (it.objKey ? it.objKey : it.value) }}
        <i class="el-icon-close" @click.stop="deleteChoose(ind)"></i>
      </div>
      <!-- 中间label项 -->
      <div v-if="chooseActive" class="center-label">
        {{ chooseActive + ':' }}
      </div>
      <!-- 右侧选择框 -->
      <div ref="inputCont" class="input-cont" @click="clickInput">
        <el-cascader
          ref="cascaderRef"
          :options="cascaderOptionList"
          :props="{checkStrictly: true}"
          clearable
          filterable
          popper-class="cascader-dialog"
        ></el-cascader>
        <el-input
          ref="inputRef"
          v-model="inputVal"
          :placeholder="placeholder"
          @blur="closeInput"
          @input="inputHandel"
          @keyup.delete.native="deleteHandel"
          @keyup.enter.native="closeInput"
        />
      </div>
    </div>
    <div class="right-btn">
      <!-- 右侧删除按钮 -->
      <div v-if="chooseList.length || chooseActive" class="delete-all">
        <i class="el-icon-delete" @click="resetSearch"></i>
      </div>
      <!-- 右侧搜索按钮 -->
      <div class="search-btn">
        <i class="el-icon-search" @click="emitHandel"></i>
      </div>
    </div>
    <!-- 搜索下拉框 -->
    <div
      v-show="showSelect && allList.length"
      ref="selectCont"
      class="select-content"
    >
      <div
        v-for="(item, index) in allList"
        :key="index"
        class="select-item"
        @click="clickSelect(item)"
      >
        {{ item.title }}
      </div>
    </div>
    <!-- 下拉选择框 -->
    <div v-show="showPullContent" ref="pullCont" class="pull-content">
      <!-- 搜索框 -->
      <div class="pull-search">
        <el-input v-model="pullInputValue" placeholder="搜索">
          <template #append>
            <i class="el-icon-search" @click="searchSele"></i>
          </template>
        </el-input>
      </div>
      <div class="pull-main">
        <div
          v-if="pullOptionList.filter(it => it.show).length"
          class="pull-list"
        >
          <div
            v-for="(item, index) in pullOptionList.filter(it => it.show)"
            :key="index"
            :class="['pull-item', item.checkbox ? 'pull-active' : '']"
            @click="itemClickHandler(item)"
          >
            <el-checkbox
              v-if="currentSelectOption.multiple !== false"
              v-model="item.checkbox"
              size="large"
              @change="() => $forceUpdate()"
            />
            <span>{{ item.name }}</span>
          </div>
        </div>
        <div v-else class="no-data">
          <img src="@/assets/img/no-data.svg" />
          <span>暂无数据</span>
        </div>
      </div>
      <div v-if="currentSelectOption.multiple !== false" class="pull-footer">
        <span class="footer-item" @click="closePull">取消</span>
        <span class="footer-item" @click="handelPull">确定</span>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'SearchCommon',
  props: {
    optionList: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      placeholder: '', // input placeholder提示语
      inputVal: '', // 输入框所输入的值
      showSelect: false, // 控制选择框显隐
      showPullContent: false, // 控制type为select时选择框
      chooseActive: '', // 当前选择项
      chooseProp: '', // 当前选择项 Prop
      chooseType: '', // 当前选择项 类型
      allList: [], // 下拉选择数据
      chooseList: [], // 已选择数组
      defaultObj: {}, // 默认搜索项
      pullInputValue: '', // 下拉搜索选择
      pullOptionList: [], // 下拉数据
      cascaderOptionList: [],
      currentSelectOption: {} // 当前选择的select配置
    }
  },
  watch: {
    optionList: {
      handler(val) {
        this.showSelect = false
        this.showPullContent = false
      },
      deep: true
    }
  },
  created() {
    let hasInitialValue = false
    this.allList = this.optionList
    this.optionList.forEach(it => {
      if (it.default) {
        this.defaultObj = it
        this.placeholder = `请输入${it.title}，或选择其他查询项来搜索`
      }
      if (it.defaultValue !== undefined) {
        this.chooseList.push({
          label: it.title,
          value: it.defaultValue,
          prop: it.prop,
          objKey:
            it.type === 'select'
              ? it.option
                  .filter(option => it.defaultValue.includes(option.value))
                  .map(option => option.name)
                  .join(', ')
              : undefined
        })
        hasInitialValue = true
        this.placeholder = ''
      }
    })
    if (hasInitialValue) {
      this.emitHandel()
    }
  },
  methods: {
    // 已选择数据 和 全量数据去重
    filterateData() {
      this.allList = []
      this.optionList.forEach(it => {
        let isBoolen = true
        this.chooseList.forEach(item => {
          if (item.label === it.title) {
            isBoolen = false
          }
        })
        if (isBoolen) {
          this.allList.push(it)
        }
      })
    },
    // 下拉框选择事件
    clickSelect(item) {
      this.chooseActive = item.title
      this.chooseProp = item.prop
      this.placeholder = ''
      this.$refs.inputRef.focus()
      this.chooseType = item.type || ''
      this.currentSelectOption = item
      if (item.type === 'select') {
        this.pullOptionList = item.option
        this.pullOptionList.forEach(it => {
          it.show = true
          it.checkbox = false
        })
        this.showPullContent = true
        this.setSelect('pullCont')
      }
      if (item.type === 'cascader') {
        this.cascaderOptionList = item.option
        // 获取 el-cascader 组件的输入框元素
        const inputElement = this.$refs.cascaderRef.$refs.input.$refs.input
        // 创建并触发一个点击事件
        const clickEvent = new MouseEvent('click', {
          view: window,
          bubbles: true,
          cancelable: true
        })
        inputElement.dispatchEvent(clickEvent)
      }
    },
    // 点击输入框（点击事件 + 模拟入焦）
    clickInput() {
      this.filterateData()
      if (!this.chooseActive) {
        this.setSelect('selectCont')
        this.showSelect = !this.showSelect
      }
      if (this.chooseType === 'select') {
        this.showPullContent = !this.showPullContent
      }
      if (this.chooseType === 'cascader') {
        const inputElement = this.$refs.cascaderRef.$refs.input.$refs.input
        // 创建并触发一个点击事件
        const clickEvent = new MouseEvent('click', {
          view: window,
          bubbles: true,
          cancelable: true
        })
        inputElement.dispatchEvent(clickEvent)
      }
    },
    // 输入框 键盘”删除“事件
    deleteHandel() {
      if (!this.inputVal && !this.showPullContent) {
        this.chooseActive = ''
        this.chooseProp = ''
        this.showPullContent = false
        this.chooseType = ''
        if (this.chooseList.length) {
          this.showPullContent = false
          this.chooseType = ''
        }
        if (!this.chooseList.length) {
          this.placeholder = `请输入${this.defaultObj.title}，或选择其他查询项来搜索`
        }
        this.$refs.inputRef.blur()
        this.emitHandel()
      }
    },
    // 删除已选择项
    deleteChoose(index, emitHandel = true) {
      if (index === 'all') {
        this.chooseList = []
        this.chooseActive = ''
        this.showPullContent = false
        this.chooseType = ''
      } else {
        this.chooseList.splice(index, 1)
      }
      if (!this.chooseList.length) {
        this.placeholder = `请输入${this.defaultObj.title}，或选择其他查询项来搜索`
      }
      if (emitHandel) this.emitHandel()
    },
    // 设置选择框的位置
    setSelect(ele) {
      // 输入框dom
      let inputDom = this.$refs.inputCont
      // 选择框dom
      let selectDom = this.$refs[ele + '']
      let left = inputDom.getBoundingClientRect().left + 6
      let top = inputDom.getBoundingClientRect().top + 36
      // 设置选择框的位置
      selectDom.style.top = top + 'px'
      selectDom.style.left = left + 'px'
    },
    // 输入框失焦事件
    closeInput() {
      setTimeout(() => {
        if (this.inputVal) {
          let label = this.chooseActive
            ? this.chooseActive
            : this.defaultObj.title
          let prop = this.chooseProp ? this.chooseProp : this.defaultObj.prop
          this.chooseList.push({
            label: label,
            value: this.inputVal,
            prop: prop
          })
          this.inputVal = ''
          this.placeholder = ''
          this.chooseActive = ''
          if (!this.showSelect) this.emitHandel()
        }
        this.showSelect = false
      }, 150)
    },
    // 输入事件
    inputHandel(val) {
      if (
        (this.chooseList.length && !this.chooseActive) ||
        this.chooseType === 'select'
      ) {
        this.inputVal = ''
      } else {
        this.showSelect = false
      }
    },
    // 取消下拉框
    closePull() {
      this.showPullContent = false
    },
    // 确定下拉框
    handelPull() {
      let value, objKey
      if (this.currentSelectOption.multiple !== false) {
        value = this.pullOptionList.flatMap(it => (it.checkbox ? it.value : []))
        objKey = this.pullOptionList.flatMap(it => (it.checkbox ? it.name : []))
        if (!value.length) return
      } else {
        const selected = this.pullOptionList.find(it => it.checkbox)
        if (!selected) return
        value = selected.value
        objKey = selected.name
      }
      this.chooseList.push({
        label: this.chooseActive,
        value: value,
        prop: this.chooseProp,
        objKey: objKey
      })
      this.pullOptionList.forEach(it => (it.checkbox = false))
      this.showPullContent = false
      this.chooseActive = ''
      this.chooseType = ''
      this.$refs.inputRef.blur()
      this.pullInputValue = ''
      this.emitHandel()
    },
    // 下拉框搜索
    searchSele() {
      this.pullOptionList.forEach(it => {
        if (it.name.indexOf(this.pullInputValue) > -1) {
          it.show = true
        } else {
          it.show = false
        }
        this.$forceUpdate()
      })
    },
    // 右侧搜索按钮点击
    emitHandel() {
      setTimeout(() => {
        this.$emit(
          'search',
          this.optionList.map(i => {
            const {prop = '', title: label = '', isNumberValue = false} = i
            let value =
              this.chooseList.find(
                _i => JSON.stringify(_i.prop) === JSON.stringify(prop)
              )?.value || ''
            if (isNumberValue) {
              if (Array.isArray(value)) {
                value = value.map(_i => +_i)
              } else {
                value = +value
              }
            }
            return {
              prop,
              label,
              value
            }
          })
        )
      }, 200)
    },
    // 修改item
    editItem(item, index) {
      this.chooseList.splice(index, 1)
      let obj = {}
      this.optionList.forEach(it => {
        if (it.prop === item.prop) {
          obj = it
        }
      })
      this.chooseActive = obj.title
      this.chooseProp = obj.prop
      this.inputVal = item.value
      this.placeholder = ''
      this.$refs.inputRef.focus()
      this.chooseType = obj.type || ''
      this.currentSelectOption = obj
      if (obj.type === 'select') {
        this.inputVal = ''
        this.pullOptionList = obj.option
        this.pullOptionList.forEach(it => {
          it.show = true
          if (obj.multiple !== false) {
            item.value.forEach(respon => {
              if (it.value === respon) {
                it.checkbox = true
              }
            })
          } else {
            if (it.value === item.value) {
              it.checkbox = true
            }
          }
        })
        this.showPullContent = true
        this.setSelect('pullCont')
      }
    },

    // 重置搜索功能组件
    resetSearch() {
      this.deleteChoose('all')
      this.emitHandel()
    },
    // 单选和多选处理
    itemClickHandler(item) {
      if (this.currentSelectOption.multiple === false) {
        this.pullOptionList.forEach(it => {
          it.checkbox = false
        })
        item.checkbox = true
        this.handelPull()
        // this.emitHandel()
      }
    }
  }
}
</script>

<style lang="scss" scoped>
@import '@/assets/css/element-variables';

.search-common-container {
  box-sizing: border-box;
  width: 100%;
  min-height: 38px;
  padding: 4px 10px;
  font-size: 14px;
  border: 1px solid $--system-border-color2;
  border-radius: 2px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  transition: 0.3s;

  * {
    transition: all 0.2s;
  }

  .left-choose {
    display: flex;
    flex-wrap: wrap;
    row-gap: 5px;
    column-gap: 5px;
    flex: 1;

    .choose-item {
      cursor: pointer;
      position: relative;
      font-size: 13px;
      line-height: 24px;
      padding: 2px 22px 2px 9px;
      border-radius: 2px;
      max-width: 300px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      background: $--system-box-color1;
      color: $--color-white;
      border: 1px solid $--system-border-color3;
      box-sizing: border-box;

      .el-icon-close {
        position: absolute;
        top: 2px;
        right: 0;
        font-size: 13px;
        padding: 4px;
        cursor: pointer;
        transition: color 0.15s;
        color: $--color-text-placeholder;

        &:hover {
          color: $--color-danger;
        }
      }

      &:nth-child(1) {
        margin-left: 0;
      }
    }

    .input-cont {
      flex: 1;
      display: flex;
      align-items: center;
    }
  }

  .center-label {
    font-size: 14px;
    display: flex;
    align-items: center;
    white-space: nowrap;
    margin-left: 10px;
    color: $--color-white;
  }

  &:hover {
    border-color: $--system-border-color1;
  }

  .right-btn {
    display: flex;

    .delete-all {
      display: flex;
      align-items: center;
      justify-content: center;
      margin-right: 10px;

      .el-icon-delete {
        font-size: 16px;
        color: $--color-text-placeholder;
        cursor: pointer;

        &:hover {
          color: $--color-danger;
        }
      }
    }

    .search-btn {
      width: 20px;
      display: flex;
      padding: 0 0 0 10px;
      justify-content: center;
      align-items: center;
      position: relative;

      .el-icon-search {
        font-size: 16px;
        color: $--color-text-placeholder;
        cursor: pointer;

        &:hover {
          color: $--system-hover-active-text;
        }
      }

      &::before {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        width: 1px;
        height: 16px;
        background-color: $--color-text-secondary;
      }
    }
  }

  .select-content {
    min-width: 120px;
    max-height: 320px;
    overflow: auto;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 900;
    background: $--system-module-color2;
    border: 1px solid $--system-border-color1;
    animation: slide-in-top 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
    border-radius: 3px;

    .select-item {
      color: $--color-white;
      font-size: 14px;
      height: 22px;
      line-height: 22px;
      padding: 5px 12px;
      transition: 0.3s;
      cursor: pointer;

      &:hover {
        color: $--system-hover-active-text;
        background: $--system-active-bgColor;
      }
    }
  }

  .pull-content {
    min-width: 240px;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 5;
    background: $--system-module-color2;
    border: 1px solid $--system-border-color1;
    border-radius: 3px;
    animation: slide-in-top 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;

    .pull-search {
      position: relative;
      padding: 12px;

      .el-input-group {
        border: 1px solid $--system-border-color3;
        border-radius: 5px;

        &:hover {
          border: 1px solid $--system-border-color1;
        }

        .el-icon-search {
          color: $--color-text-placeholder;
          cursor: pointer;
        }

        ::v-deep .el-input__inner {
          border: none;
        }
      }
    }

    .pull-main {
      max-height: 240px;
      border-bottom: 1px solid $--system-border-color3;
      border-top: 1px solid $--system-border-color3;
      overflow: auto;

      &::-webkit-scrollbar {
        width: 6px !important;
      }

      /* 滚动条滑块 */
      &::-webkit-scrollbar-thumb {
        border-radius: 6px;
      }

      .pull-list {
        padding: 10px 0;

        .pull-item {
          height: 34px;
          font-size: 14px;
          padding: 0 10px;
          margin-top: 1px;
          display: flex;
          justify-content: flex-start;
          align-items: center;
          cursor: pointer;
          transition: 0.3s;

          span {
            margin-left: 6px;
            vertical-align: middle;
            font-size: 14px;
            color: $--system-table-text-color;
          }

          &:hover {
            background-color: $--system-active-bgColor;
          }

          &.pull-active {
            background-color: $--system-active-bgColor;

            span {
              color: $--system-hover-active-text;
            }
          }
        }
      }

      .no-data {
        height: 170px;
        display: flex;
        justify-content: center;
        align-items: center;
        flex-direction: column;

        span {
          margin-top: 10px;
        }
      }
    }

    .pull-footer {
      padding: 10px;
      display: flex;
      justify-content: space-between;
      align-items: center;

      .footer-item {
        cursor: pointer;
        color: $--system-table-text-color;
      }
    }
  }

  @keyframes slide-in-top {
    0% {
      opacity: 0;
    }
    100% {
      opacity: 1;
    }
  }
}

::v-deep .el-input__inner {
  border: 0;
  height: 100%;
  padding: 0 10px;
  font-size: 14px !important;
}

::v-deep .el-input {
  height: 100%;
}

::v-deep .el-checkbox .el-checkbox__input {
  width: 16px;
  height: 16px;

  &::after {
    width: 5px;
  }
}

::v-deep .el-input-group__append {
  padding: 10px;
  background-color: $--system-module-color1;
  border: none;
  box-shadow: none;
}

::v-deep .el-cascader {
  width: 0;
  height: 22px;
  opacity: 0;
  pointer-events: none;
  animation: none !important;

  .el-input__inner {
    pointer-events: none;
  }

  .el-input__suffix {
    pointer-events: none;
  }

  .el-icon-arrow-down {
    pointer-events: none;
  }

  .el-input__suffix-inner {
    pointer-events: none;
  }

  .el-cascader-menu {
    animation: none !important;
  }
}
</style>

<style lang="scss">
.cascader-dialog {
  animation: none !important;

  .popper__arrow {
    display: none;
  }
}
</style>
