<template>
  <mu-form-item :label="currentConfig.label" :prop="currentConfig.key" :inline="currentConfig.inline"
                :tip="currentConfig.tip" :validators="currentConfig.validators" trigger="change">
    <el-select class="mu-select" :class="['mu-'+ currentConfig.size, !!currentConfig.disabled ? 'mu-disabled': '' ]"
               popper-class="mu-select-option"
               v-model="currentValue"
               :name="currentConfig.name"
               :size="currentConfig.size==='large' ? 'small' : 'mini'"
               :multiple="currentConfig.multiple"
               :disabled="currentConfig.disabled"
               :placeholder="currentConfig.placeholder"
               :clearable="currentConfig.clearable"
               :filterable="currentConfig.filterable"
               :filter-method="currentConfig.filterMethod"
               :remote="currentConfig.remote"
               :remote-method="currentConfig.remoteMethod"
               no-match-text="未搜寻到相关资料"
               :loading="isLoading"
               @visible-change="handleShowChange"
               @change="handleChange"
               @focus="handleFocus"
               @blur="handleBlur">
      <el-option :key="option.key || option.id" :label="option[currentConfig.optionsConfig.props.label]"
                 :value="option[currentConfig.optionsConfig.props.value]"
                 :disabled="option[currentConfig.optionsConfig.props.disabled]"
                 v-for="option in (config.options || [])">
        <el-checkbox v-if="currentConfig.multiple" class="mu-checkbox" v-model="currentValue"
                     :label="option[currentConfig.optionsConfig.props.value]"
                     @click.prevent.native="()=>{}" :disabled="option[currentConfig.optionsConfig.props.disabled]">
        </el-checkbox>
        <span>{{option[currentConfig.optionsConfig.props.label]}}</span>
      </el-option>
    </el-select>
  </mu-form-item>
</template>

<script lang="ts">
  import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator';
  import { SystemApi } from '../../../api';

  type Size = 'small' | 'medium' | 'large';

  interface InputConfig {
    name?: string,
    size?: Size,
    disabled?: boolean,
    placeholder?: string
    label?: string,
    key?: string,
    inline?: boolean,
    tip?: string,
    validators?: any,
    multiple?: boolean,
    clearable?: boolean,
    filterable?: boolean,
    filterMethod?: Function,
    remote?: boolean,
    remoteMethod?: Function,
    options?: any,
    optionsConfig?: {
      props?: any,
      optionsLoad?: Function,
      sourceConfigs?: any
    },
    visibleChange?: Function
  }

  @Component({
    name: 'mcSelect'
  })
  export default class extends Vue {
    @Prop({ default: () => [] }) private value!: any;
    @Prop({ default: () => [] }) private config!: InputConfig;
    @Prop() private extension?: (value: any) => void;
    private currentValue: any = this.config.multiple ? this.value || [] : this.value;
    private isLoading: boolean = false;
    private defaultConfig: any = {
      size: 'medium',
      placeholder: '请选择',
      optionsConfig: {
        props: {
          label: 'label',
          value: 'value',
          disabled: 'disabled'
        }
      }
    };

    // 检测值
    @Watch("value")
    onValueChanged(val: any) {
      this.currentValue = val;
    }

    // 合并默认数据
    get currentConfig() {
      const result = this.config;
      Object.keys(this.defaultConfig).forEach((key: string) => {
        if (this.config[key] === undefined) return result[key] = this.defaultConfig[key];
        // 处理options的配置
        if (key === 'optionsConfig' && this.config.optionsConfig) {
          Object.keys(this.defaultConfig.optionsConfig).forEach((optionKey: string) => {
            if (this.config.optionsConfig[optionKey] === undefined)
              result.optionsConfig[optionKey] = this.defaultConfig.optionsConfig[optionKey];
          });
          return;
        }
      });
      return result;
    }

    mounted() {
      this.extension && this.extension({
        onHandleData: (type: string, params?: any, callback?: Function) => {
          const { sourceConfigs, optionsLoad } = this.config.optionsConfig;
          const currentSource = (sourceConfigs || []).find((item: any) => item.type === type);
          switch (type) {
            case "load":
              if (!this.config.options) this.$set(this.config, 'options', []);
              if (optionsLoad) return this.config.options = optionsLoad();
              if (!currentSource) return callback && callback();
              this.handleLoad(currentSource, params, (ret: any, result: any) => {
                this.config.options = result;
                callback && callback(result)
              });
              return;
            default:
              return;
          }
        }
      });
    }

    /**
     * 加载数据
     * @author tanxj
     * @param source 数据源配置
     * @param params 加载数据参数
     * @param callback 回调
     */
    handleLoad(source: any, params?: any, callback?: Function) {
      this.isLoading = true;
      const { api, onBeforeSubmit, onSuccess, onError } = source;
      const next = (currentParams: any) => {
        const { serviceName, funcName, config } = api;
        SystemApi.handleApi({ serviceName, funcName, params: currentParams }, config).then(async (ret: any) => {
          this.isLoading = false;
          const result = onSuccess ? onSuccess(ret.data, this) : ret.data;
          callback && callback(ret, result);
        }, (error: any) => {
          this.isLoading = false;
          onError && onError(error);
        });
      };
      onBeforeSubmit ? onBeforeSubmit({ ...api.params, ...params }, next, this.value) : next({ ...api.params, ...params });
    }

    /**
     * 输入框值改变
     * @author tanxj
     * @param value 值
     */
    @Emit('on-change')
    handleChange(value: any) {
      this.$emit('input', value);
    }

    /**
     * 下拉框出现/隐藏时触发
     * @author tanxj
     * @param value 值
     */
    handleShowChange(value: any) {
      this.currentConfig.visibleChange && this.currentConfig.visibleChange(value);
    }

    /**
     * 失去焦点事件
     * @author tanxj
     * @param any event 事件
     */
    handleBlur(event: any) {
      this.$emit('on-blur', event.target.value, event, this.config.key);
    }

    /**
     * 使input 获取焦点
     * @author tanxj
     * @param any event 事件
     */
    handleFocus(event: any) {
      this.$emit('on-focus', event);
    }
  }
</script>

