<template>
  <div class="inputs">
    <el-select
      style="width: 100%;"
      @click.native="clickNative"
      v-show="inputWriteable"
      v-validate="inputValidate"
      :name="inputName"
      v-model="inputVal"
      :loading="loading"
      :size="size"
      :clearable="clearable"
      :disabled="readonly || disabled"
      :placeholder="placeholder?placeholder:'请选择'"
      :filterable="filterable"
      :allow-create="allowCreate"
      :multiple="multiple"
      :remote="remote"
      :remote-method="handleRemoteMethod"
      v-if="inputWriteable"
      @change="change"
      @visible-change="visibleChange"
      @remove-tag="removeTag"
      @clear="handleClear"
      @blur="handleBlur"
      @focus="handleFocus"
    >
      <slot
        v-if="optionsAry && optionsAry.constructor == Array && optionsAry.length > 0"
        :options="optionsAry"
        :prop-key="propKey"
        :prop-value="propValue"
      >
        <el-option
          v-for="item in optionsAry"
          :key="item[propKey]"
          :label="item[propValue]"
          :value="item[propKey]"
        ></el-option>
      </slot>
    </el-select>
    <ht-field-tail 
      v-if="permission!='n'"
      :writeable.sync="writeable"
      :fieldName="inputName"
      :readonly="!inputWriteable"
      :inputValue="inputVal"
      :tag-format-value="tagFormatValue"
    />
  </div>
</template>
<script>
import utils from "@/utils.js";
import service from "@/service.js";
import HtFieldTail from "@/components/HtFieldTail.vue";
import { Promise } from "q";
import { setTimeout } from "timers";
import deepmerge from "deepmerge";

export default {
  name: "ht-select",
  props: {
    validate: [String, Object],
    value: [String, Number, Boolean, Array],
    name: String,
    permission: {
      type: String,
      default: "w",
      validator: function(value) {
        return ["b", "w", "r", "n"].indexOf(value) !== -1;
      }
    },
    size: {
      type: String,
      default: "small"
    },
    options: Array,
    props: {
      type: Object,
      default: function() {
        return {
          key: "key",
          value: "value"
        };
      }
    },
    disabled: {
      type: Boolean,
      default: false
    },
    readonly: {
      type: Boolean,
      default: false
    },
    multiple: {
      type: Boolean,
      default: false
    },
    clearable: {
      type: Boolean,
      default: false
    },
    filterable: {
      type: Boolean,
      default: false
    },
    allowCreate: {
      type: Boolean,
      default: false
    },
    linkage: [Object, Array],
    placeholder: String,
    remoteMethod: Function,
    remote: {
      type: Boolean,
      default: false
    }
  },
  components: {
    HtFieldTail
  },
  data() {
    return {
      optionsAry: [],
      tagFormatValue: [],
      remoteMethodFn: null,
      inputName: null,
	  writeable: true,
      isRemote: false,
      loading: false,
      oldValue: this.value,
      remoteLoaded: false
    };
  },
  watch: {
    options: {
      handler: function(newVal, oldValue) {
        if (newVal && newVal.constructor === Array) {
          // 在加载了数据时，标记远程方法调用状态为已调用
          this.remoteLoaded = true;
          this.optionsAry = [...newVal];
          // 异步加载数据 下拉框不会回显 需要加载完options 重新赋值
          if (
            (!oldValue || oldValue.length == 0) &&
            !utils.isEmpty(this.oldValue)
          ) {
            this.$emit("input", this.oldValue);
          }
        }
      },
      immediate: true
    }
  },
  computed: {
    inputVal: {
      get() {
        if (
          utils.isEmpty(this.value) ||
          !this.optionsAry ||
          this.optionsAry.length == 0
        ) {
          return utils.isEmpty(this.value) ? "" : this.value;
        }
        if (this.value.constructor == String) {
          const ary = this.value === "" ? [] : this.value.split(",");
          if (this.inputWriteable) {
            if (this.multiple) {
              return ary;
            } else {
              return this.value;
            }
          } else {
            // 只读 多选
            if (this.multiple) {
              const ary = this.value === "" ? [] : this.value.split(",");
              let optionVals = [];
              let tempAry = deepmerge([], ary, { clone: true });
              ary.forEach(m => {
                this.optionsAry.find(opt => {
                  if (opt[this.propKey] === m) {
                    optionVals.push(opt[this.propValue]);
                    tempAry.remove(m);
                  }
                  if (opt.children && opt.children.length > 0) {
                    opt.children.find(childOpt => {
                      if (childOpt[this.propKey] === m) {
                        optionVals.push(childOpt[this.propValue]);
                        tempAry.remove(m);
                      }
                    });
                  }
                });
              });
              optionVals = optionVals.concat(tempAry);
              this.tagFormatValue = optionVals;
              return ary;
            }
            if (this.optionsAry && this.optionsAry.length > 0) {
              let optionVals = [];
              let tempAry = deepmerge([], ary, { clone: true });
              ary.forEach(m => {
                this.optionsAry.find(opt => {
                  if (opt[this.propKey] === m) {
                    optionVals.push(opt[this.propValue]);
                    tempAry.remove(m);
                  }
                  if (opt.children && opt.children.length > 0) {
                    opt.children.find(childOpt => {
                      if (childOpt[this.propKey] === m) {
                        optionVals.push(childOpt[this.propValue]);
                        tempAry.remove(m);
                      }
                    });
                  }
                });
              });
              optionVals = optionVals.concat(tempAry);
              this.tagFormatValue = optionVals;
              return this.value;
            }
          }
        }
        return this.value;
      },
      set(val) {
        let result = "";
        if (this.multiple) {
          if (val && val.constructor === Array && val.length > 0) {
            if (val[0].constructor === Number) {
              throw "多选不支持数字类型";
            }
            result = val.join(",");
          }
        } else {
          result = val;
        }
        this.$emit("input", result);
      }
    },
    inputWriteable: function() {
      return this.writeable ? utils.getWriteable(this.permission):this.writeable;
    },
    inputValidate: function() {
      return utils.addRequiredOrNot(this.permission, this.validate, this);
    },
    propKey: function() {
      if (this.props && this.props.key) {
        return this.props.key;
      }
      return "key";
    },
    propValue: function() {
      if (this.props && this.props.value) {
        return this.props.value;
      }
      return "value";
    }
  },
  mounted() {
    // 字段联动规则
    const _me = this;
    this.mountedLinkage();
    if (this.value) {
      this.handleRemoteMethod();
    }
  },
  created() {
    this.inputName = this.name ? this.name : utils.getName();
    this.remoteMethodFn = this.remoteMethod;
    this.isRemote =
      (this.remoteMethodFn && this.remoteMethodFn.constructor === Function) ||
      !!(
        this.$vnode.data.directives &&
        this.$vnode.data.directives.find(m => m.name == "query")
      );
    this.$validator = this.$root.$validator;
  },
  methods: {
    mountedLinkage(){
      if (this.linkage) {
        const exp = this.linkage;
        //如果要联动的字段权限是只读“r”,则把联动配置里面要联动的字段权限“w”改为只读“r”
        if (exp && exp.length > 0) {
          const frmInst = utils.getOnlineFormInstance(this);
          //表单所有字段的初始权限
          if (frmInst && frmInst.permission) {
            exp.forEach((item) => {
              let effect = item.effect;
              effect.forEach((effectItem) => {
                let initPermission = utils.getValueByPath(frmInst,effectItem.target);
                if (
                  effectItem.target &&
                  effectItem.target.indexOf("permission") != -1 &&
                  effectItem.value != "n" && initPermission == "r"
                ) {
                  effectItem.value =  initPermission;
                }
              });
            });
          }
        }
        service.linkageHandler(this, exp);
      }
    },
    clickNative: function() {
      // 在远程方法未调用时才触发远程调用
      if (!this.remoteLoaded) {
        this.handleRemoteMethod();
      }
    },
    handleRemoteMethod: function(query) {
      let _me = this;
      if (this.isRemote) {
        this.loading = true;
        var result = this.remoteMethodFn(query);
        if (result && result.finally) {
          result.finally(() => {
            this.loading = false;
          });
        } else {
          setTimeout(() => {
            this.loading = false;
          }, 1000);
        }
      }
    },
    change: function(data) {
      let selectObj = this.optionsAry.find(opt => opt[this.propKey] === data);
      this.$emit("change", data, selectObj);
    },
    clearValue: function() {
      this.oldValue = "";
      this.inputVal = "";
    },
    visibleChange: function(m) {
      this.$emit("visible-change", m);
    },
    removeTag: function(tag) {
      this.$emit("remove-tag", tag);
    },
    handleClear: function() {
      this.$emit("clear");
    },
    handleBlur: function(event) {
      this.$emit("blur", event);
    },
    handleFocus: function(event) {
      this.$emit("focus", event);
    }
  }
};
</script>
<style lang="scss" scoped>
div[aria-invalid='true'] >>> .el-input__inner, div[aria-invalid='true'] >>> .el-input__inner:focus {
  border-color: #f56c6c;
}
</style>