<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"
               popper-class="mu-select-add"
               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">
      <slot>
        <div class="mu-addHandle">
          <mu-btn :config="{type:'text', text:'新增', icon: 'icon-plus'}" @click="handleAdd"></mu-btn>
        </div>
      </slot>
      <el-option v-for="(option, index) in currentConfig.options" :key="index"
                 :label="option[currentConfig.optionsConfig.props.label]"
                 :disabled="option[currentConfig.optionsConfig.props.disabled]"
                 :value="option[currentConfig.optionsConfig.props.value]">
        <span style="float: left">{{option[currentConfig.optionsConfig.props.label]}}</span>
        <span style="float: right;">
          <mu-btn :config="{type:'text', text:'删除'}" @click="deleteItem($event, option, index)"></mu-btn>
        </span>
      </el-option>
    </el-select>
  </mu-form-item>
</template>

<script lang="ts">
  import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator';
  // import DtBtn from "src/components/Btn/index.vue";
  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,
    clearable?: boolean,
    filterable?: boolean,
    filterMethod?: Function,
    remote?: boolean,
    remoteMethod?: Function,
    options?: any,
    showDialog?: Function,
    handleAdd?: Function,
    optionsConfig?: {
      rowKey?: string
      props?: any,
      optionsLoad?: Function,
      sourceConfigs?: any
    },
    visibleChange?: Function
  }

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

    // 合并默认数据
    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;
    }

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

    mounted() {
      this.extension && this.extension({
        onHandleData: (type: string, params?: any, callback?: Function, index?: number) => {
          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();
              return this.handleLoad(currentSource, params, callback);
            }
            case "delete": {
              this.handleDelete(currentSource, params, index, callback);
              return;
            }
            default:
              return;
          }
        },
        handleOptions: (type: string, data: any, callback: any) => {
          switch (type) {
            case "add": {
              if (data instanceof Array) {
                this.config.options = this.config.options.concat(data);
              } else {
                this.config.options.push(data);
              }
              break;
            }
            case "delete": {
              const index = this.config.options.find((item: any) =>
                item[this.config.optionsConfig.rowKey] === data[this.config.optionsConfig.rowKey]);
              this.config.options.splice(index, 1);
              break;
            }
            default:
              break;
          }
          callback && callback();
        }
      });
    }

    /**
     * 加载数据
     * @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;
          if (onSuccess) this.config.options = onSuccess(ret.data, this.config) || ret.data;
          callback && callback(ret);
        }, (error: any) => {
          this.isLoading = false;
          onError && onError(error);
        });
      };
      onBeforeSubmit ? onBeforeSubmit({ ...api.params, ...params }, next, this.value) : next({ ...api.params, ...params });
    }

    /**
     * 删除数据
     * @author tanxj
     * @param source 数据源配置
     * @param data 可批量或者单条
     * @param callback 回调
     */
    handleDelete(source: any, data: any, index: number, callback?: Function) {
      if (!source) {
        this.config.options.splice(index, 1);
        return callback && callback();
      }
      const { api, onBeforeSubmit, onSuccess, onError } = source;
      const next = (params: any) => {
        const { serviceName, funcName, config } = api;
        SystemApi.handleApi({ serviceName, funcName, params: params }, config).then((ret: any) => {
          onSuccess && onSuccess(ret.data, this);
          this.config.options.splice(index, 1);
          callback && callback(ret);
        }, (error: any) => {
          onError && onError(error);
        });
      };
      onBeforeSubmit ? onBeforeSubmit({ ...api.params, ...data }, next, data) : next({ ...api.params, ...data });
    }

    /**
     * 删除事件
     * @author tanxj
     * @param event
     * @param currentItem 删除当前对象
     */
    deleteItem(event: any, currentItem: any, index: number) {
      event.preventDefault();
      event.stopPropagation();
      const currentSource = (this.config.optionsConfig.sourceConfigs || []).find((item: any) => item.type === 'delete');
      this.handleDelete(currentSource, currentItem, index)
    }

    /**
     * 表格单选
     * @author jie.shuai
     * @param value 值
     */
    handleCurrentChange(val: any) {
      this.currentValue = val;
    }

    /**
     * 弹出dialog框
     * @author jie.shuai
     */
    handleAdd() {
      this.config.showDialog && this.config.showDialog()
    }

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

    /**
     * 输入框值改变
     * @author tanxj
     * @param value 值
     */
    @Emit('on-change')
    handleChange(value: any) {
      this.$emit('input', 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>

