<!--
 * @Description: In User Settings Edit
 * @Author: your name
 * @Date: 2019-08-21 16:26:44
 * @LastEditTime: 2019-11-21 14:43:34
 * @LastEditors: Please set LastEditors
 -->
<template>
  <div class="zte-item" :class="props.type" :title="valueTitle">
    <label v-if="disabled && props.type !== 'switch' || props.type === 'label'" class="label" :title="currentLabel || currentValue">
      {{currentLabel || currentValue}}
    </label>
    <el-input
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'text'"
      :maxlength="props.maxlength"
      :show-word-limit ="props.showLimit"
      :placeholder="placeholder"
      :disabled="props.disabled"
      :autofocus="props.enterEnAble"
      @keyup.enter.native="handlerEnter"
      v-model="currentValue"
      @input="() => { currentValue = trim ? currentValue.trim() : currentValue }"
      clearable>
    </el-input>
    <el-input
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'password'"
      :maxlength="props.maxlength"
      :placeholder="placeholder"
      :disabled="props.disabled"
      :autofocus="props.enterEnAble"
      @keyup.enter.native="handlerEnter"
      v-model="currentValue"
      @input="() => { currentValue = trim ? currentValue.trim() : currentValue }"
      show-password
    >
    </el-input>
    <!-- <el-input
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'num' && props.dataType === 'number'"
      :maxlength="props.maxlength"
      :placeholder="placeholder"
      :disabled="props.disabled"
      v-model.lazy="currentValue"
      :min="props.min"
      :max="props.max"
      @change="set2number"
      @keyup.enter.native="handlerEnter"
      onkeypress="return event.which ? event.which >=48 && event.which <= 57 : event.keyCode >= 48 && event.keyCode <= 57"
      type="number"
      @clear="clear"
      clearable>
      <template v-if="props.append" slot="append">
        {{ props.append }}
      </template>
    </el-input> -->
    <el-input-number
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'num'"
      :min="props.min"
      :max="props.max"
      :step="props.step"
      :step-strictly="props.strictly"
      :precision="props.precision"
      :disabled="props.disabled"
      :placeholder="placeholder"
      :controls="false"
      v-model="currentValue"
     >
    </el-input-number>
    <el-input-number
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'count'"
      :maxlength="props.maxlength"
      :placeholder="placeholder"
      :disabled="props.disabled"
      v-model="currentValue"
      :min="props.min"
      :max="props.max"
      @keyup.enter.native="handlerEnter"
      type="number"
      clearable>
      <template v-if="props.append" slot="append">
        {{ props.append }}
      </template>
    </el-input-number>
    <input-range
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'range'"
      :placeholder="placeholder"
      :range-type="props.rangeType"
      :astrict="props.astrict"
      v-model="currentValue"
      clearable>
    </input-range>
    <month-range
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'monthrange'"
      :placeholder="placeholder"
      v-model="currentValue"
      >
    </month-range>
    <el-input-number
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'counter'"
      :min="props.min || 1"
      :max="props.max || 100"
      :disabled="props.disabled"
      @keyup.enter.native="handlerEnter"
      v-model="currentValue"
      clearable>
    </el-input-number>
    <el-select
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'select'"
      :placeholder="placeholder"
      :currentLabel="currentLabel"
      :disabled="props.disabled"
      v-model="currentValue"
      :multiple="props.multiple"
      clearable
      filterable
      @change="handlerSelectChange">
      <el-option
        v-for="item in options"
        :key="item.value"
        :label="item.label"
        :value="item.value">
      </el-option>
    </el-select>
    <el-checkbox-group
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'check'"
      :disabled="props.disabled"
      v-model="currentValue"
      @change="handlerCheckChange">
      <el-checkbox
        v-for="item in options"
        :key="item.value"
        :label="item.value"
        :disabled="props.disabled">
        {{item.label}}
      </el-checkbox>
    </el-checkbox-group>
    <el-date-picker
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'date' || props.type === 'datetime' || props.type === 'month' || props.type === 'year'"
      :placeholder="placeholder"
      :disabled="props.disabled"
      :type="props.type"
      v-model="currentValue"
      clearable
      :format="props.dateFormat"
      :picker-options="props.pickerOptions"
      :value-format="dateFormat">
    </el-date-picker>
    <el-time-select
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'timeSelect'"
      v-model="currentValue"
      :disabled="props.disabled"
      :picker-options="props.pickerOptions"
      :placeholder="placeholder">
    </el-time-select>
    <el-time-picker
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'timePicker'"
      v-model="currentValue"
      :disabled="props.disabled"
      :value-format="props.valueFormat"
      :picker-options="props.pickerOptions"
      :placeholder="placeholder">
    </el-time-picker>
    <el-switch
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'switch'"
      :disabled="props.disabled"
      :active-value="props.on === undefined ? 'on' : props.on"
      :inactive-value="props.off === undefined ? 'off' : props.off"
      v-model="currentValue">
    </el-switch>
    <month-day
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'monthDay'"
      v-model="currentValue">
    </month-day>
    <el-input
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'table'"
      type="text"
      :size="props.size"
      :disabled="props.disabled"
      :placeholder="placeholder"
      :value="show"
      :clearable="!props.static"
      @clear="clear"
      @click.native="!props.disabled && handlerTableClick($event)"
      prefix-icon="el-icon-search">
    </el-input>
    <city-picker
      v-else-if="props.type === 'city'"
      :id="`${exId}_${props.code}`"
      :disabled="cityDisabled"
      @input="handlerAutoComplete"
      ref="cityPicker"
      >
      <template slot="input">
        <el-autocomplete
          ref="cityInput"
          v-model="currentValue"
          :value-key="props.showLabel"
          :fetch-suggestions="queryCity"
          :size="props.size || 'medium'"
          :trigger-on-focus="false"
          :placeholder="placeholder"
          @select="handlerAutoComplete"
          @input="handlerCitypInput"
          @focus="hanlerCityFocus"
          >
        </el-autocomplete>
      </template>
    </city-picker>
    <multi-month
      v-else-if="props.type === 'multi-mouth'"
      :id="`${exId}_${props.code}`"
      :disabled="props.disabled"
      v-model="currentValue"
    />
    <el-input
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'tree'"
      type="text"
      :maxlength="props.maxlength"
      :disabled="props.disabled"
      :placeholder="placeholder"
      :readonly="readOnly"
      :value="show"
      clearable
      @clear="clear"
      @click.native="!props.disabled && handlerTreeClick($event)"
      prefix-icon="el-icon-search">
    </el-input>
    <el-input
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'asyncTree'"
      type="text"
      :maxlength="props.maxlength"
      :disabled="props.disabled"
      :placeholder="placeholder"
      :readonly="readOnly"
      :value="show"
      clearable
      @clear="clear"
      @click.native="!props.disabled && handlerAsyncTreeClick($event)"
      prefix-icon="el-icon-search">
    </el-input>
    <input-currency
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'amount'"
      v-model.number="currentValue"
      :disabled="props.disabled"
      :negative="props.negative"
      :maxlength="props.maxlength"
      :size="props.size"
      clearable>
    </input-currency>
    <el-input
      :id="`${exId}_${props.code}`"
      v-else-if="props.type === 'textarea'"
      type="textarea"
      :autosize="autosize"
      :placeholder="placeholder"
      :disabled="props.disabled"
      :maxlength="props.maxlength"
      :show-word-limit ="props.showLimit"
      v-model="currentValue">
    </el-input>
    <el-upload
      v-else-if="props.type === 'upload'"
      :action="props.action || 'sys/file/upload'"
      :limit="props.limit"
      :accept="props.accept"
      :on-success="uploadSuccess"
      :on-remove="uploadRemove"
      :before-upload="beforeUpload"
      :file-list="currentValue"
    >
      <el-button size="small" type="primary"
      :id="`${exId}_upload_${props.code}`">点击上传</el-button>
      <div slot="tip" class="el-upload__tip">不限制文档类型，大小限制为30M</div>
    </el-upload>
    <img class="image" v-else-if="props.type === 'image'">
    <div v-else-if="props.type === 'temp'">
      <slot :name="props.code"></slot>
    </div>
    <table-picker
      v-if="props.type === 'table' && pickerVisible"
      :params="pickerParams"
      :dialogVisible.sync="pickerVisible"
      :service="props.service"
      :table-key="props.key"
      :title="props.label"
      :selected="currentValue"
      :row-key="props.rowKey || props.code"
      :row-name="props.rowName || props.showLabel"
      :row-trans="props.trans"
      :row-extends="props.extends"
      :config="props.config"
      :page-sizes="props.pageSizes"
      :request-url="props.requestUrl"
      :default-value.sync="currentDefaultValue"
      :is-default="!!props.defaultCode"
      @selectChange='pickerSelect'
      @singleSelectChange='singlePickerSelect'>
    </table-picker>
    <tree-picker
      v-if="props.type === 'tree' && treeVisible"
      :params="pickerParams"
      :dialogVisible.sync="treeVisible"
      :title="props.label"
      :service="props.service"
      :tree-key="props.key"
      :selected="currentValue"
      :request-url="props.requestUrl"
      :click-expand="props.clickExpand"
      :expand-all="props.expandAll"
      :click-check="props.clickCheck"
      :leaf-only="props.leafOnly"
      :half-checked="props.halfChecked"
      :show-checkbox="props.showCheckbox"
      @selectChange='treePickerSelect'>
    </tree-picker>
    <async-tree-picker
      v-if="props.type === 'asyncTree' && asyncTreeVisible"
      :params="Object.assign({}, params, props.params)"
      :dialogVisible.sync="asyncTreeVisible"
      :title="props.label"
      :filter-ajax="props.filterAjax"
      :tree-ajax="props.treeAjax"
      :selected-ajax="props.selectedAjax"
      :selected="currentValue"
      :click-expand="props.clickExpand"
      :expand-all="props.expandAll"
      :click-check="props.clickCheck"
      :leaf-only="props.leafOnly"
      :half-checked="props.halfChecked"
      @selectChange='treePickerSelect'>
    </async-tree-picker>
  </div>
</template>

<script>
import { monthValue } from './utils/monthTrans';
import Emitter from './mixins/emitter';
import inputRange from './input-range';
import inputCurrency from './input-currency';
import monthRange from './month-range';
import monthDay from './month-day';
import multiMonth from './multi-month';
import cityPicker from './mixins/cityPicker';

export default {
  name: 'zteItem',
  components: {
    inputRange,
    monthRange,
    monthDay,
    multiMonth,
    inputCurrency,
    tablePicker: () => import('./table-picker'),
    treePicker: () => import('./tree-picker'),
    asyncTreePicker: () => import('./async-tree-picker'),
    cityPicker: () => import('./city-picker'),
  },
  mixins: [Emitter, cityPicker],
  props: {
    props: {
      type: Object,
      default: () => ({}),
    },
    value: {
      type: [String, Number, Array],
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    show: {
      type: String,
    },
    params: {
      type: Object,
    },
    prevcode: {
      type: Object,
      default: () => ({}),
    },
    defaultValue: String,
    exId: String,
  },
  computed: {
    placeholder() {
      if (this.disabled || this.props.disabled) {
        return '';
      }
      const { props } = this;
      const type = [
        'monthrange',
        'select',
        'date',
        'datetime',
        'month',
        'year',
        'timeSelect',
        'timePicker',
        'table',
        'tree',
        'asyncTree'
      ].includes(props.type) ? '请选择' : '请输入';
      const placeholder = this.$t(props.placeholder) || (this.$t(type) + this.$t(props.label));
      return placeholder;
    },
    optionProps() {
      const optionProps = Object.assign({ label: 'label', value: 'value' }, this.props.optionProps);
      return optionProps;
    },
    options() {
      const { optionProps = {}, options = [] , filter } = this.props;
      const { label, value } = optionProps;
      const result = options
        .map(opt => ({
          label: opt[label],
          value: opt[value],
          ...opt,
        }))
        .filter(opt => !filter || !filter.includes(opt.value));
      return result;
    },
    currentLabel() {
      let label = '';
      if (this.props.type === 'select' && this.props.options) {
        if (this.props.multiple) {
          const options = this.props.options.filter(opt => this.currentValue.includes(opt[this.optionProps.value]));
          label = options.length ? options.map(op => op[this.optionProps.label]).join(',') : ' ';
        } else {
          const option = this.props.options.filter(opt => opt[this.optionProps.value] === this.currentValue)[0];
          label = option && option[this.optionProps.label];
        }
        if (this.props.labelCode) {
          this.$emit('select-label-change', this.props.labelCode, label);
        }
      }
      if (['table', 'tree', 'asyncTree'].includes(this.props.type)) {
        label = this.show;
      }
      if ('multi-mouth' === this.props.type) {
        label = monthValue(this.currentValue ? this.currentValue.split(',') : []);
      }
      return label;
    },
    dateFormat() {
      let format = '';
      if (this.props.type === 'date') {
        format = 'yyyy-MM-dd';
      }
      if (this.props.type === 'datetime') {
        format = 'yyyy-MM-dd HH:mm:ss';
      }
      if (this.props.type === 'month') {
        format = 'yyyy-MM';
      }
      if (this.props.type ==='year') {
        format = 'yyyy';
      }
      return this.props.valueFormat || format;
    },
    isMultiple() {
      const isMultiple =
        this.props.type === 'check' ||
        (this.props.type === 'select' && this.props.multiple === true);
      return isMultiple;
    },
    pickerParams() {
      return Object.assign({}, this.params, this.props.params);
    },
    valueTitle() {
      if (!this.props.showTitle) {
        return '';
      }
      return this.show || this.currentValue;
    },
    readOnly() {
      return 'readOnly' in this.props ? this.props.readOnly : true;
    },
    trim() {
      // 默认开启去空格
      if (this.props.trim === undefined) {
        return true;
      }
      return !!this.props.trim;
    },
  },
  data() {
    return {
      currentValue: (this.props.type === 'check' || (this.props.type === 'select' && this.props.multiple === true)) ? (this.value && this.value.split('^') || []) : this.value,
      pickerVisible: false,
      treeVisible: false,
      prevParams: null,
      currentDefaultValue: this.defaultValue,
      asyncTreeVisible: false,
      autosize: { minRows: 4, maxRows: 8 },
    };
  },
  watch: {
    value(val) {
      this.currentValue = (this.props.type === 'check' || this.isMultiple) ? (val && val.split('^') || []) : val;
      this.dispatch('ElFormItem', 'el.form.change', [val]);
      if (this.props.sumTo) {
        this.$emit('sum-to-form-filed', this.props.sumTo);
      }
    },
    currentValue(val, oldValue) {
      if ('maxValue' in this.props && val > this.props.maxValue) { // 数字类型限制最大输入值
        this.currentValue = oldValue;
      } else {
        const value = (this.props.type === 'check' || this.isMultiple) && val instanceof Array ? val.join('^') : val;
        this.$emit('input', value);
        if (this.props.type === 'range' || this.props.type === 'monthrange') this.$emit('range-change', value);
      }
    },
    params: {
      deep: true,
      handler() {
        if (this.props.prev
        && Object.keys(this.params).length > 0
        && this.checkPrev(this.params, this.prevParams)) {
          this.prevParams = this.params;
          if (!this.props.unClear) this.clear();
        }
      },
    },
    fileList(val) {
      this.currentValue = val.map(file => file.url).join(',');
    },
    defaultValue(val) {
      this.currentDefaultValue = val;
    },
  },
  methods: {
    set2number(val) {
      this.currentValue = parseFloat(val);
    },
    beforeRemove(file) {
      return this.$confirm(`确定移除 ${file.name}？`);
    },
    beforeUpload(file) {
      if (this.props.maxSize && file.size > (this.props.maxSize * 1024 * 1024 * 1024)) {
        this.$message.warning('warning', `文件大小超过${this.props.maxSize}M`, file);
        return false;
      }
      return true;
    },
    uploadSuccess(res) {
      if (res.code === 0) {
        res.name = res.filename;
        this.currentValue.push(res);
      }
    },
    uploadRemove(file) {
      const index = this.currentValue.indexOf(file);
      this.currentValue.splice(index, 1);
    },
    ctnChange(val) {
      this.currentValue = val;
    },
    handlerTableClick(e) {
      if (this.checkPrevParams() && e.target.tagName === 'INPUT') {
        this.pickerVisible = true;
      }
    },
    handlerTreeClick(e) {
      if (this.checkPrevParams() && e.target.tagName === 'INPUT') {
        this.treeVisible = true;
      }
    },
    handlerAsyncTreeClick(e) {
      if (this.checkPrevParams() && e.target.tagName === 'INPUT') {
        this.asyncTreeVisible = true;
      }
    },
    showLabel(value) {
      let showLabel = '';
      if (value) {
        if (value.label) {
          showLabel = value[this.props.showLabel];
        } else if (value.length) {
          showLabel = value.map(item => item[this.props.showLabel]).join(',');
        }
      }
      return showLabel;
    },
    bindKey(rows) {
      if (this.props.type === 'table' && rows) {
        return rows.map(item => item[this.props.code]).join('^');
      }
      return '';
    },
    setExtendInfo(rows) {
      const extendObj = {};
      for (const extend of this.props.extends) {
        extendObj[extend.to] = rows.map(item => item[extend.from]).join('^') || '';
      }
      return extendObj;
    },
    pickerSelect(rows) {
      this.$emit('picker-change', rows, this.props);
      this.$emit('show-change', this.props.showLabel, this.showLabel(rows), this.props.defaultCode, this.currentDefaultValue);
      this.currentValue = this.bindKey(rows);
      if (this.props.extends && this.props.extends.length) {
        this.$emit('single-picker-change', this.setExtendInfo(rows), this.props);
      }
    },
    singlePickerSelect(row) {
      this.$emit('single-picker-change', row[0], this.props);
    },
    treePickerSelect(checked, halfChecked) {
      if (halfChecked) {
        this.$emit('tree-pick-change',
          this.props.showLabel, checked.map(d => d.name).join(','),
          this.props.halfId, halfChecked.map(d => d.id).join(','));
      } else {
        this.$emit('tree-pick-change',
          this.props.showLabel, checked.map(d => d.name).join(','));
      }
      this.currentValue = checked.map(d => d.id).join('^');
    },
    handlerSelectChange(val) {
      this.$emit('select-change', val);
    },
    handlerEnter() {
      this.$emit('enter');
    },
    handlerCheckChange(val) {
      this.$emit('check-change', val);
    },
    checkPrev(newObj, oldObj) {
      for (const key of Object.keys(newObj)) {
        if ((!oldObj[key] && newObj[key]) || newObj[key] !== oldObj[key]) {
          return true;
        }
      }
      return false;
    },
    checkPrevParams() {
      if (this.props.prev && Object.keys(this.props.prev).length > 0 && !this.props.unCheckPrev) {
        for (const key of Object.keys(this.props.prev)) {
          if ((!this.prevParams[this.props.prev[key]]
          || this.prevParams[this.props.prev[key]] === '')
          && this.prevcode[key]
        ) {
            this.$emit('prev-need', key);
            return false;
          }
        }
      }
      return true;
    },
    clear() {
      if (['table', 'tree', 'asyncTree'].includes(this.props.type)) {
        const obj = {};
        // tree类型目前没有trans功能，主要借助single-picker-change清空showLabel
        if (this.props.trans instanceof Array) {
          this.props.trans.forEach((el) => {
            // 当改字段需要带出prev里面字段的值的时候，若是有配置unClear属性为true，则在清空该字段的值的时候
            // 不去清空prev里面关联的字段的值
            if (!(this.props.unClear && this.props.prev && Object.keys(this.props.prev).includes(el.to))) {
              obj[el.to] = '';
            }
          });
        } else {
          obj[this.props.showLabel] = '';
        }
        this.$emit('single-picker-change', obj, this.props);
      }
      this.currentValue = '';
    },
  },
  created() {
    this.prevParams = this.params;
  },
};
</script>

<style lang="scss">
.zte-item {
  .el-input {
    &.is-disabled .el-input__inner {
      color: #606266;
    }
    input::-webkit-outer-spin-button,
    input::-webkit-inner-spin-button {
      -webkit-appearance: none;
    }
    input[type="number"]{
      -moz-appearance: textfield;
    }
  }
}
</style>
