<template>
  <div
    v-if="isRender"
    class="es-selector"
    ref="esSelector"
    :class="{ 'es-pointer': !readonly && !filterable }"
    v-clickoutside="handleClose"
  >
    <template v-if="form">
      <el-button v-if="button" v-bind="button" @click="openDialog">
        <slot>
          <es-icon v-if="icon" :contents="icon"></es-icon>
          <template v-else>选择</template>
        </slot>
      </el-button>
      <template v-else>
        <div
          :class="[
            selectorSize ? 'el-select--' + selectorSize : 'es-selector-box',
            { 'es-selector-search': filterable }
          ]"
          @click.stop="toggleMenu"
        >
          <div
            v-if="multiple"
            ref="tags"
            class="el-select__tags"
            :class="{ 'es-selector-edit': !readonly }"
          >
            <div
              v-if="collapseTags && selected.length"
              class="es-selector-tags"
              :class="{ 'es-selector-more': selected.length > 1 }"
            >
              <el-tag
                v-for="(item, index) in selected.slice(
                  0,
                  collapseTags === true ? 1 : collapseTags
                )"
                :key="getValueKey(item)"
                :closable="
                  !selectorDisabled && !readonly && selected.length > min
                "
                type="info"
                disable-transitions
                @close="deleteTag($event, item, index)"
              >
                <span class="el-select__tags-text">{{ getLabel(item) }}</span>
              </el-tag>

              <el-tag
                v-if="
                  selected.length > (collapseTags === true ? 1 : collapseTags)
                "
                :closable="false"
                type="info"
                disable-transitions
                class="es-tags-more"
              >
                <span class="el-select__tags-text"
                  >+
                  {{
                    selected.length - (collapseTags === true ? 1 : collapseTags)
                  }}</span
                >
              </el-tag>
            </div>
            <transition-group v-else @after-leave="resetInputHeight">
              <el-tag
                v-for="(item, index) in selected"
                :key="getValueKey(item)"
                :closable="
                  !selectorDisabled && !readonly && selected.length > min
                "
                type="info"
                disable-transitions
                @close="deleteTag($event, item, index)"
              >
                <span class="el-select__tags-text">{{ getLabel(item) }}</span>
              </el-tag>
            </transition-group>
          </div>
          <div ref="reference" class="es-input__inner" v-if="readonly">
            <template v-if="!multiple">{{ selectedLabel }}</template>
          </div>
          <template v-else>
            <template v-if="multiple">
              <el-input
                type="text"
                ref="reference"
                autocomplete="off"
                v-model="words"
                :readonly="filterable ? false : true"
                :id="id"
                :placeholder="currentPlaceholder"
                :size="selectorSize"
                :disabled="selectorDisabled"
                :class="{
                  'is-focus': visible,
                  'es-plain': plain,
                  'es-pointer': !filterable,
                  'es-zindex-2': focus
                }"
                :tabindex="tabindex"
                v-popover:popover
                @dblclick.native="openDialog"
                @focus="handleFocus"
                @blur="handleBlur"
              >
                <template slot="append">
                  <el-button
                    ref="openDialog"
                    v-if="filterable || showButton"
                    @click.stop="openDialog"
                  >
                    <slot>
                      <es-icon v-if="icon" :contents="icon"></es-icon>
                      <template v-else>选择</template>
                    </slot>
                  </el-button>
                </template>
              </el-input>
              <el-input
                v-model="selectedLabel"
                readonly
                :name="name"
                type="text"
                v-show="false"
              ></el-input>
            </template>
            <el-input
              v-else
              v-model="selectedLabel"
              type="text"
              ref="reference"
              autocomplete="off"
              :clearable="clearable"
              showClearIcon
              :name="name"
              :readonly="filterable ? false : true"
              :active="actived"
              :id="id"
              :placeholder="currentPlaceholder"
              :size="selectorSize"
              :disabled="selectorDisabled"
              :class="{
                'is-focus': visible,
                'es-plain': this.plain,
                'es-pointer': !filterable
              }"
              :tabindex="tabindex"
              @dblclick.native="openDialog"
              @clear="handleClear"
            >
              <template slot="append">
                <el-button
                  ref="openDialog"
                  v-if="filterable || showButton"
                  @click.stop="openDialog"
                >
                  <slot>
                    <es-icon v-if="icon" :contents="icon"></es-icon>
                    <template v-else>选择</template>
                  </slot>
                </el-button>
              </template>
            </el-input>
          </template>
        </div>
        <el-popover
          v-model="show"
          placement="bottom-start"
          trigger="manual"
          popper-class="es-selector-popover"
          :width="minWidth"
          :queryParent="true"
          :reference="reference"
          :arrow-offset="20"
        >
          <el-scrollbar
            tag="ul"
            wrap-class="es-selector-dropdown__wrap"
            view-class="es-selector-dropdown__list"
            ref="scrollbar"
            v-show="options.length"
            maxHeight="228"
          >
            <li
              v-for="item in options"
              :key="item.id"
              @click="handleSelect(item)"
              class="es-selector-dropdown-item"
              :class="{ 'es-selected': item.selected }"
            >
              <span>
                {{ getDep(item) }}
                {{ item[labelKey] }}
              </span>
            </li>
          </el-scrollbar>
          <p v-if="options.length == 0" class="el-select-dropdown__empty">
            {{ noMatchText }}
          </p>
        </el-popover>
      </template>
    </template>
    <es-dialog
      v-if="!readonly"
      :title="title"
      :visible.sync="visible"
      :width="width"
      :height="height"
      :css="false"
      :append-to-body="true"
      :close-on-click-modal="false"
      class="es-selector-dialog"
    >
      <es-selector-panel
        v-if="isReset"
        v-model="selected"
        v-bind="$attrs"
        :multiple="multiple"
        width="100%"
        height="100%"
        :value-key="valueKey"
        :label-key="labelKey"
        :host="host"
        :type="types"
        :mix="mix"
        :isShowLevel3="isShowLevel3"
        @tabschage="tabschage"
        @click.capture="stopd"
        @confirm="handleConfirm"
        @cancel="handleCancel"
      ></es-selector-panel>
    </es-dialog>
  </div>
</template>
<script>
import util from 'eoss-ui/src/utils/util.js';
import { getSelectorOrgDetail, getSysParam } from 'eoss-ui/src/config/api.js';
import Clickoutside from 'eoss-element/src/utils/clickoutside';
export default {
  name: 'EsSelector',
  inheritAttrs: false,
  inject: {
    elForm: {
      default: ''
    },
    elFormItem: {
      default: ''
    }
  },
  directives: { Clickoutside },
  props: {
    form: {
      type: Boolean,
      default: true
    },
    isShowLevel3: {
      type: Boolean,
      default: true
    },
    value: [Array, Object],
    action: {
      type: String,
      default: getSelectorOrgDetail
    },
    host: {
      type: String,
      default: ''
    },
    title: {
      type: String,
      default: '公用选择器'
    },
    width: {
      type: String,
      default: '900px'
    },
    height: {
      type: String,
      default: '560px'
    },
    multiple: {
      type: Boolean,
      default: true
    },
    valueKey: {
      type: String,
      default: 'showid'
    },
    labelKey: {
      type: String,
      default: 'showname'
    },
    valueType: {
      type: String,
      default: 'object',
      validator: function (value) {
        return ['string', 'object'].includes(value);
      }
    },
    size: String,
    id: String,
    disabled: Boolean,
    clearable: {
      type: Boolean,
      default: true
    },
    placeholder: {
      type: String,
      default: '请选择'
    },
    autocomplete: {
      type: String,
      default: 'off'
    },
    name: String,
    readonly: Boolean,
    collapseTags: [Boolean, Number],
    plain: Boolean,
    types: {
      type: Array,
      default() {
        return ['enterprise', 'person'];
      }
    },
    tabindex: {
      type: [String, Number],
      default: -1
    },
    //是否显示搜索框
    filterable: Boolean,
    //搜索列表是否显示部门信息
    showFilterListDep: {
      type: Boolean,
      default: true
    },
    //是否根据搜索值创建新的数据
    createable: Boolean,
    showButton: Boolean,
    button: Object,
    icon: String,
    active: String,
    keywords: {
      type: String,
      default: 'namelike'
    },
    //输入框搜索参数
    where: {
      type: Object,
      default() {
        return {
          mid: '0-0-0-0-0'
        };
      }
    },
    //混选
    mix: Boolean,
    //混选时是否分类显示
    classify: {
      type: Boolean,
      default: true
    },
    noMatchText: {
      type: String,
      default: '无匹配数据'
    },
    emptySerach: Boolean,
    reset: Boolean,
    useCaseCode: String,
    businessData: [String, Array, Object],
    inputHeight: {
      type: Number,
      default: 40
    },
    min: {
      type: Number,
      default: 0
    },
    select: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      selected: [],
      visible: false,
      menuVisibleOnFocus: false,
      inputHovering: false,
      styles: {},
      words: '',
      minWidth: '',
      options: '',
      show: false,
      focus: false,
      reference: undefined,
      timer: null
    };
  },
  computed: {
    isRender() {
      let useCaseCodes = util.getStorage('useCaseCodes');
      if (useCaseCodes && this.useCaseCode) {
        return useCaseCodes.indexOf(this.useCaseCode) > -1;
      }
      return true;
    },
    isReset() {
      return this.reset ? this.visible : true;
    },
    _elFormItemSize() {
      return (this.elFormItem || {}).elFormItemSize;
    },
    actived() {
      if (this.active) {
        return this.active;
      }
      return this.types[0];
    },
    selectorSize() {
      return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
    },
    selectorDisabled() {
      return this.disabled || (this.elForm || {}).disabled;
    },
    selectedLabel: {
      get() {
        if (this.selected) {
          if (typeof this.selected === 'string') {
            return this.selected;
          } else if (util.isObject(this.selected)) {
            return this.selected[this.labelKey];
          } else if (Array.isArray(this.selected)) {
            return this.selected
              .map((item) => {
                return typeof item === 'string' ? item : item[this.labelKey];
              })
              .join(',');
          }
        }
        return '';
      },
      set(val) {
        this.selected = [val];
        this.words = val;
        return val;
      }
    },
    currentPlaceholder() {
      if (this.selected && this.selected.length) {
        return '';
      } else if (this.filterable) {
        return '输入关键字搜索';
      } else {
        return this.placeholder;
      }
    }
  },
  watch: {
    value: {
      immediate: true,
      deep: true,
      handler(val) {
        if (util.isExist(val)) {
          if (util.isObject(val)) {
            this.selected = [val];
          } else {
            this.selected = val;
          }
        } else {
          this.selected = [];
        }
      }
    },
    selected: {
      deep: true,
      handler(val) {
        this.$emit(
          'change',
          Array.isArray(val) ? val : [val],
          this.businessData
        );
        if (this.multiple) {
          this.resetInputHeight();
        }
      }
    },
    words(val) {
      if (this.emptySerach || val !== '') {
        clearTimeout(this.timer);
        this.timer = setTimeout(this.handleSearch, 500);
      }
    },
    mix(val) {
      if (val) {
        this.getSysParam();
      }
    }
  },
  created() {
    this.reference = this.$refs.esSelector;
    this.mix && this.getSysParam();
  },
  mounted() {
    this.resetInputHeight();
    if (this.filterable) {
      this.$nextTick(() => {
        this.$refs.reference &&
          (this.minWidth = this.$refs.reference.$el.children[0].offsetWidth);
      });
    }
    if (this.$refs.openDialog) {
      this.$refs.openDialog.$el.parentNode.addEventListener('click', () => {
        this.openDialog();
      });
    }
  },
  methods: {
    getSysParam() {
      if (util.getStorage('sysorgname') && util.getStorage('sysdepname')) {
        return;
      }
      util
        .ajax({
          url: getSysParam,
          params: {
            paramCode: 'sysorgname,sysdepname'
          }
        })
        .then((res) => {
          if (res.rCode === 0) {
            let params = res.results.split(',');
            sessionStorage.setItem('sysorgname', params[0]);
            sessionStorage.setItem('sysdepname', params[1]);
          }
        });
    },
    getDep(res) {
      if (!this.showFilterListDep) {
        return '';
      }
      const attr = res.attr ? JSON.parse(res.attr) : null;
      return attr && attr.depShortName ? `[${attr.depShortName}]` : '';
    },
    getValueKey(obj) {
      return util.isObject(obj) ? obj[this.valueKey] : obj;
    },
    toggleMenu() {
      if (
        !this.selectorDisabled &&
        !this.readonly &&
        !this.filterable &&
        this.select
      ) {
        this.visible = true;
      }
    },
    openDialog() {
      if (!this.selectorDisabled && !this.readonly && this.select) {
        this.visible = true;
      }
    },
    handleSearch() {
      let options = [];
      if (this.createable) {
        options = [
          {
            [this.labelKey]: this.words,
            [this.valueKey]: this.words
          }
        ];
      }
      if (this.filterable) {
        let params = {
          type: this.actived
        };
        params[this.keywords] = this.words;
        params = util.extend({}, params, this.where);
        util
          .ajax({
            url: this.action,
            params: params
          })
          .then((res) => {
            if (res.rCode === 0) {
              this.options = [...options, ...res.results];
              if (this.selected.length && this.multiple) {
                this.selected.forEach((item) => {
                  let i = util.indexOfObj(this.options, item, this.valueKey);
                  if (i > -1) {
                    this.options[i].selected = true;
                  }
                });
              }
              this.show = true;
            }
          })
          .catch((err) => {
            if (err.message && err.message !== 'canceled') {
              this.$message.error(err.message);
            }
          });
      } else if (this.createable) {
        this.options = options;
        this.show = true;
      }
    },
    handleFocus() {
      if (this.filterable) {
        this.focus = true;
      }
    },
    handleBlur() {
      this.focus = false;
    },
    tabschage(trees, active) {
      this.$emit('tabs-change', trees, active);
    },
    handleClose(res) {
      if (!this.multiple && this.selected[0] === this.words) {
        this.selected = [];
      }
      this.show = false;
    },
    handleSelect(res) {
      this.words = '';
      if (!res.selected) {
        if (this.multiple) {
          if (this.selected.length) {
            if (!res.selected) {
              res.selected = true;
              this.selected.push(res);
              this.selected = util.arrUnique(this.selected, this.valueKey);
            }
          } else {
            res.selected = true;
            this.selected = [res];
          }
        } else {
          res.selected = true;
          if (Array.isArray(this.selected)) {
            if (
              this.selected[0] &&
              typeof this.selected[0] !== 'string' &&
              this.selected[0][this.valueKey] !== res[this.valueKey]
            ) {
              this.selected[0].selected = false;
            }
            this.selected = [res];
          } else {
            if (
              this.selected &&
              typeof this.selected !== 'string' &&
              this.selected[this.valueKey] !== res[this.valueKey]
            ) {
              this.selected.selected = false;
            }
            this.selected = [res];
          }
        }
      }
      this.$emit('input', this.selected);
      this.$emit('confirm', this.selected);
    },
    handleConfirm(res) {
      this.visible = false;
      let val = util.isObject(res) ? [res] : res;
      if (this.mix) {
        val.forEach((item, index) => {
          val[index]._typeName = util.getTypeName(item.stype);
        });
      }
      this.$emit('input', val);
      this.$emit('confirm', val, this.businessData);
      let inputChildNodes = this.$refs.reference
        ? this.$refs.reference.$el.childNodes
        : null;
      let input = inputChildNodes
        ? [].filter.call(inputChildNodes, (item) => item.tagName === 'INPUT')[0]
        : null;
      if (input) {
        input.focus();
        input.blur();
      }
      if (this.reset) {
        this.selected = [];
      }
    },
    handleClear() {
      this.$emit('input', []);
      this.$emit('clear');
    },
    handleCancel() {
      this.visible = false;
      this.$emit('cancel');
    },
    deleteTag(event, item, index) {
      event;
      item;
      index = index === undefined ? 0 : index;
      this.selected.length > this.min && this.selected.splice(index, 1);
    },
    resetInputHeight() {
      if (this.collapseTags) return;
      this.$nextTick(() => {
        if (!this.$refs.reference) return;
        const sizeInMap = this.inputHeight;
        let height = '';
        if (this.selected !== undefined && this.selected.length === 0) {
          height = sizeInMap + 'px';
        } else if (this.$refs.tags) {
          if (this.$refs.tags.clientHeight > sizeInMap) {
            height += this.$refs.tags.clientHeight + 2 + 'px';
          } else {
            height = sizeInMap + 'px';
          }
        }
        if (height) {
          if (this.readonly) {
            this.$refs.reference.style.height = height;
          } else {
            let inputChildNodes = this.$refs.reference.$el.childNodes;
            let input = [].filter.call(
              inputChildNodes,
              (item) => item.tagName === 'INPUT'
            )[0];
            input.style.height = height;
          }
        }
      });
    },
    getLabel(res) {
      let tag = '';
      if (this.mix) {
        tag = this.classify?util.getTypeName(res.stype) : '';
      } else if (this.showFilterListDep) {
        tag = this.getDep(res);
      }
      return (
        tag +
        (typeof res == 'string'
          ? res
          : res[this.labelKey]
          ? res[this.labelKey]
          : res.label || res[this.valueKey])
      );
    }
  },
  beforeDestroy() {
    this.$el.removeEventListener('keyup', this.doSearch);
    if (this.$refs.openDialog) {
      this.$refs.openDialog.$el.parentNode.removeEventListener('click', () => {
        this.openDialog();
      });
    }
  }
};
</script>
