<template>
  <el-table-column v-bind="config" :key="field">
    <slot> </slot>
    <template slot-scope="scope">
      <template v-if="isForm && !isReadOnly(scope)">
        <el-form-item
          v-if="!(type === 'handle' && !scope.row.hideHandle)"
          :name="name"
          :prop="field || prop"
          :rules="isNotRule(scope) ? [] : rules"
          :index="scope.$index"
        >
          <component
            v-if="getType(scope.row.formConfigs, 'component')"
            :is="tag"
            v-bind="getOptions(scope.row.formConfigs)"
            v-model="scope.row[field || prop]"
            :data="getData(scope.row.formOptions)"
            @blur="
              (event) => {
                handleBlur({
                  item: config,
                  event: event,
                  data: scope.row,
                  scope: scope
                });
              }
            "
            @focus="
              (event) => {
                handleFocus({
                  item: config,
                  event: event,
                  data: scope.row,
                  scope: scope
                });
              }
            "
            @change="
              (value) => {
                handleChange({
                  item: config,
                  name: field || prop,
                  value: value,
                  data: scope.row,
                  scope: scope
                });
              }
            "
          ></component>
          <es-select
            v-else-if="getType(scope.row.formConfigs, 'select')"
            v-bind="getOptions(scope.row.formConfigs)"
            v-model="scope.row[field || prop]"
            :data="getData(scope.row.formOptions)"
            @blur="
              (event) => {
                handleBlur({
                  item: config,
                  event: event,
                  data: scope.row,
                  scope: scope
                });
              }
            "
            @focus="
              (event) => {
                handleFocus({
                  item: config,
                  event: event,
                  data: scope.row,
                  scope: scope
                });
              }
            "
            @change="
              (value) => {
                handleChange({
                  item: config,
                  name: field || prop,
                  value: value,
                  data: scope.row,
                  scope: scope
                });
              }
            "
          >
          </es-select>
          <es-cascader
            v-else-if="getType(scope.row.formConfigs, 'cascader')"
            v-bind="getOptions(scope.row.formConfigs)"
            v-model="scope.row[field || prop]"
            :data="getData(scope.row.formOptions)"
            @blur="
              (event) => {
                handleBlur({
                  item: config,
                  event: event,
                  data: scope.row,
                  scope: scope
                });
              }
            "
            @focus="
              (event) => {
                handleFocus({
                  item: config,
                  event: event,
                  data: scope.row,
                  scope: scope
                });
              }
            "
            @change="
              (value) => {
                handleChange({
                  item: config,
                  name: field || prop,
                  value: value,
                  data: scope.row,
                  scope: scope
                });
              }
            "
          >
          </es-cascader>
          <es-select-ganged
            v-else-if="getType(scope.row.formConfigs, 'ganged')"
            v-bind="getOptions(scope.row.formConfigs)"
            v-model="scope.row[field || prop]"
            :data="init(getData(scope.row.formOptions), config)"
            @change="
              (value) => {
                handleChange({
                  name: field || prop,
                  value: value,
                  data: scope.row,
                  item: item
                });
              }
            "
          >
          </es-select-ganged>
          <es-radio-group
            v-else-if="getType(scope.row.formConfigs, 'radio')"
            v-bind="getOptions(scope.row.formConfigs)"
            v-model="scope.row[field || prop]"
            :data="getData(scope.row.formOptions)"
            @change="
              (value) => {
                handleChange({
                  item: config,
                  name: field || prop,
                  value: value,
                  data: scope.row
                });
              }
            "
          >
          </es-radio-group>
          <es-checkbox-group
            v-else-if="getType(scope.row.formConfigs, 'checkbox')"
            v-bind="getOptions(scope.row.formConfigs)"
            v-model="scope.row[field || prop]"
            :data="getData(scope.row.formOptions)"
            @change="
              (value) => {
                handleChange({
                  item: config,
                  name: field || prop,
                  value: value,
                  data: scope.row
                });
              }
            "
          >
          </es-checkbox-group>
          <es-switch
            v-else-if="getType(scope.row.formConfigs, 'switch')"
            v-bind="getOptions(scope.row.formConfigs)"
            v-model="scope.row[field || prop]"
            :data="getData(scope.row.formOptions)"
            @change="
              (value) => {
                handleChange({
                  item: config,
                  name: field || prop,
                  value: value,
                  data: scope.row
                });
              }
            "
          >
          </es-switch>
          <es-date-picker
            v-else-if="
              config.date ||
              getType(scope.row.formConfigs, [
                'date',
                'year',
                'month',
                'date',
                'dates',
                'week',
                'datetime',
                'datetimerange',
                'daterange',
                'monthrange',
                'quarter',
                'halfyear'
              ])
            "
            v-bind="getOptions(scope.row.formConfigs)"
            v-model="scope.row[field || prop]"
            :type="type"
            @blur="
              (event) => {
                handleBlur({
                  item: config,
                  event: event,
                  data: scope.row,
                  scope: scope
                });
              }
            "
            @focus="
              (event) => {
                handleFocus({
                  item: config,
                  event: event,
                  data: scope.row,
                  scope: scope
                });
              }
            "
            @change="
              (value) => {
                handleChange({
                  item: config,
                  name: field || prop,
                  value: value,
                  data: scope.row,
                  scope: scope
                });
              }
            "
          >
          </es-date-picker>
          <es-input-number
            v-else-if="getType(scope.row.formConfigs, 'number')"
            v-bind="getOptions(scope.row.formConfigs)"
            v-model="scope.row[field || prop]"
            @blur="
              (event) => {
                handleBlur({
                  item: config,
                  event: event,
                  data: scope.row,
                  scope: scope
                });
              }
            "
            @focus="
              (event) => {
                handleFocus({
                  item: config,
                  event: event,
                  data: scope.row,
                  scope: scope
                });
              }
            "
            @change="
              (value) => {
                handleChange({
                  item: config,
                  name: field || prop,
                  value: value,
                  data: scope.row,
                  scope: scope
                });
              }
            "
          >
          </es-input-number>
          <es-selector
            v-else-if="getType(scope.row.formConfigs, 'selector')"
            v-bind="getOptions(scope.row.formConfigs)"
            v-model="scope.row[field || prop]"
            v-on="
              exclAttribute({
                data: events,
                attrs: 'change'
              })
            "
            @change="
              (value) => {
                handleChange({
                  item: config,
                  name: field || prop,
                  value: value,
                  data: scope.row
                });
              }
            "
          >
          </es-selector>
          <template
            v-else-if="
              getType(scope.row.formConfigs, ['text', 'input', 'textarea'])
            "
          >
            <template v-if="config.lazy">
              <input
                v-if="getType(scope.row.formConfigs, ['text', 'input'])"
                class="el-input__inner"
                v-bind="getOptions(scope.row.formConfigs)"
                v-model.lazy="scope.row[field]"
                @blur="
                  (event) => {
                    handleBlur({
                      item: config,
                      event: event,
                      data: scope.row,
                      scope: scope
                    });
                  }
                "
                @focus="
                  (event) => {
                    handleFocus({
                      item: config,
                      event: event,
                      data: scope.row,
                      scope: scope
                    });
                  }
                "
                @change="
                  (value) => {
                    handleChange({
                      item: config,
                      name: field || prop,
                      value: value,
                      data: scope.row,
                      scope: scope
                    });
                  }
                "
              />
              <textarea
                v-else
                class="el-textarea__inner"
                v-bind="getOptions(scope.row.formConfigs)"
                v-model.lazy="scope.row[field]"
                @blur="
                  (event) => {
                    handleBlur({
                      item: config,
                      event: event,
                      data: scope.row,
                      scope: scope
                    });
                  }
                "
                @focus="
                  (event) => {
                    handleFocus({
                      item: config,
                      event: event,
                      data: scope.row,
                      scope: scope
                    });
                  }
                "
                @change="
                  (value) => {
                    handleChange({
                      item: config,
                      name: field || prop,
                      value: value,
                      data: scope.row,
                      scope: scope
                    });
                  }
                "
              ></textarea>
            </template>
            <es-input
              v-else
              v-bind="getOptions(scope.row.formConfigs)"
              :type="type"
              :scope="scope"
              v-model="scope.row[field || prop]"
              @blur="
                (event) => {
                  handleBlur({
                    item: config,
                    event: event,
                    data: scope.row,
                    scope: scope
                  });
                }
              "
              @focus="
                (event) => {
                  handleFocus({
                    item: config,
                    event: event,
                    data: scope.row,
                    scope: scope
                  });
                }
              "
              @change="
                (value) => {
                  handleChange({
                    item: config,
                    name: field || prop,
                    value: value,
                    data: scope.row,
                    scope: scope
                  });
                }
              "
            >
            </es-input>
          </template>
        </el-form-item>
      </template>
      <expand-dom
        v-else-if="render"
        :column="config"
        :row="scope.row"
        :render="render"
        :index="indexs"
        :options="optionDatas"
      >
      </expand-dom>
      <template v-else-if="dateFormat">
        {{ formatDate(scope.row[field || prop], dateFormat) }}
      </template>
      <span
        v-else-if="type === 'textarea'"
        v-html="format(scope.row, true)"
        :style="styles ? styles[scope.row[prop]] : {}"
      ></span>
      <span
        v-else
        :style="styles ? styles[scope.row[prop]] : {}"
        v-html="format(scope.row)"
      ></span>
      <!-- {{ format(scope.row) }} -->
      <es-button-group
        v-if="type === 'handle' && !scope.row.hideHandle"
        v-bind="
          exclAttribute({
            data: config,
            attrs: ['contents', 'events', 'type', 'width', 'template', 'title']
          })
        "
        stop
        :mode="mode"
        :contents="contents || events"
        :data="scope"
        @handleClick="handleClick"
        v-model="btnWidth"
      ></es-button-group>
    </template>
  </el-table-column>
</template>

<script type="text/babel">
import { findSysCode, getDictList } from 'eoss-ui/src/config/api.js';
import util from 'eoss-ui/src/utils/util';
export default {
  name: 'Column',
  components: {
    expandDom: {
      functional: true,
      props: {
        row: Object,
        render: [Function, String],
        index: Number,
        column: {
          type: Object,
          default: null
        },
        options: Object
      },
      render: (h, ctx) => {
        const params = {
          row: ctx.props.row,
          index: ctx.props.index
        };
        if (ctx.props.column) {
          params.column = ctx.props.column;
        }
        if (typeof ctx.props.render == 'string') {
          try {
            return util.toFunction(ctx.props.render)(
              h,
              params,
              ctx.props.options
            );
          } catch (error) {
            throw error;
          }
        }
        return ctx.props.render(h, params, ctx.props.options);
      }
    }
  },
  inject: {
    elForm: {
      default: ''
    },
    tableReload: {
      default: ''
    },
    table: {
      default: ''
    }
  },
  props: {
    tag: String,
    mode: String,
    service: String,
    form: Boolean,
    readonly: Boolean,
    name: String,
    filterIcon: [Boolean, String],
    title: String,
    label: String,
    labelKey: String,
    valueKey: String,
    field: String,
    prop: String,
    sortable: [Boolean, String],
    sort: [Boolean, String],
    className: String,
    labelClassName: String,
    type: String,
    required: Boolean,
    width: [Number, String],
    minWidth: [Number, String],
    hide: Boolean,
    showOverflowTooltip: [Boolean, Number],
    render: [Function, String],
    contents: Array,
    events: [Array, Object],
    dateFormat: String,
    dateValue: {
      type: String,
      default: ''
    },
    styles: [Array, Object],
    sysCode: String,
    valueToString: Boolean,
    symbol: String,
    rules: [Array, Object],
    method: String,
    indexs: {
      type: Number,
      default: null
    },
    data: [Object, Array],
    optionData: {
      type: Object,
      default() {
        return {};
      }
    }
  },
  watch: {
    optionData: {
      deep: true,
      handler(val) {
        this.optionDatas = val;
      }
    },
    width: {
      immediate: true,
      handler(val) {
        if (val) {
          this.btnWidth = parseInt(val, 10) + 'px';
        }
      }
    }
  },
  computed: {
    config() {
      let config = {
        label: this.label || this.title,
        width: this.btnWidth || this.width
      };
      if (this.type === 'expand') {
        config = { type: this.type, ...config, ...this.$attrs };
        return config;
      }
      let required = this.required;
      if (this.rules && !required) {
        if (Array.isArray(this.rules)) {
          this.rules.map((item) => {
            if (item.required) {
              required = item.required;
            }
          });
        } else if (this.rules.required) {
          required = this.rules.required;
        }
      }
      if (this.type === 'handle') {
        config.sort = true;
        config.outside = false;
      }
      return {
        ...config,
        filterIcon: this.icon,
        sortable: this.sortable || this.sort,
        minWidth: this.minWidth || this.table.minWidth,
        className: [
          this.className ? this.className : '',
          this.type ? ' es-table-' + this.type + '-box' : '',
          this.showOverflowTooltip ? ' es-text-ellipsis' : ''
        ].join(' '),
        labelClassName: [
          this.labelClassName ? this.labelClassName : '',
          required ? 'es-required' : ''
        ].join(' '),
        showOverflowTooltip: this.showOverflowTooltip,
        prop: this.field || this.prop,
        field: this.field,
        ...this.$attrs
      };
    },
    formOption() {
      let config = {
        labelKey: this.sysCode
          ? this.service
            ? 'label'
            : 'shortName'
          : this.labelKey,
        valueKey: this.sysCode
          ? this.service
            ? 'value'
            : 'cciValue'
          : this.valueKey,
        rules: this.rules,
        events: this.events,
        ...this.$attrs
      };
      return config;
    },
    icon() {
      if (this.filterIcon === true) {
        return 'es-icon-yingyong';
      }
      return false;
    },
    isForm() {
      let type = this.type ? this.type.toLowerCase() : '';
      let flag =
        (this.form &&
          [
            'input',
            'text',
            'textarea',
            'checkbox',
            'radio',
            'select',
            'handle',
            'date',
            'year',
            'month',
            'date',
            'dates',
            'week',
            'datetime',
            'datetimerange',
            'daterange',
            'monthrange',
            'quarter',
            'halfyear',
            'switch',
            'selector',
            'ganged',
            'number'
          ].indexOf(type) > -1) ||
        ['space', 'slot', 'component'].indexOf(type) > -1;
      return flag;
    },
    option() {
      const field = this.field || this.prop;
      return this.data ? this.data : this.optionDatas[this.sysCode || field];
    },
    findCode() {
      if (this.service) {
        return `/${this.service}${getDictList}`;
      }
      return findSysCode;
    }
  },
  data() {
    return {
      btnWidth: '',
      searchs: [],
      optionDatas: this.optionData
    };
  },
  mounted() {},
  methods: {
    init(data, value, item) {
      if (data && value) {
        if (Array.isArray(value) && value.length) {
          if (item.url || this.sysCode) {
            value.forEach(async (val, index) => {
              if (
                val.hasSub == false ||
                this.searchs.indexOf(val[this.valueKey] || val.value) > -1
              ) {
                return;
              }
              this.searchs.push(val[this.valueKey] || val.value);
              if ((item.ganged && index < item.ganged - 1) || val.hasSub) {
                let option = data[index + 1];
                let lists = [];
                if (option) {
                  let v = val[this.valueKey] || val.value;
                  lists = option.filter((list) => {
                    return list[item.filtrateKey] == v;
                  });
                }
                if (lists.length == 0) {
                  let queryKey = item.queryKey;
                  let param = {};
                  if (queryKey) {
                    for (let i in queryKey) {
                      param[i] = val[queryKey[i]];
                    }
                  }
                  let params = util.extend(
                    true,
                    this.sysCode
                      ? { sysAppCode: this.sysCode, code: sysCode }
                      : {},
                    item.param ? item.param : {},
                    param
                  );
                  await util
                    .ajax({
                      url: this.sysCode ? this.findCode : item.url,
                      method: this.method,
                      params: params,
                      data: params
                    })
                    .then((res) => {
                      if (res.rCode === 0) {
                        let options = JSON.parse(JSON.stringify(data));
                        if (options[index + 1]) {
                          this.$set(
                            data,
                            index + 1,
                            options[index + 1].concat(
                              JSON.parse(JSON.stringify(res.results))
                            )
                          );
                        } else {
                          this.$set(
                            data,
                            index + 1,
                            JSON.parse(JSON.stringify(res.results))
                          );
                        }
                      } else {
                        let msg = res.msg || '系统错误，请联系管理员！';
                        this.$message.error(msg);
                      }
                    })
                    .catch((err) => {
                      if (err.message && err.message !== 'canceled') {
                        this.$message.error(err.message);
                      }
                    });
                }
              }
            });
          }
        }
      }
      return data;
    },
    getType(config, types) {
      let type =
        config && config[this.field || this.prop]
          ? config[this.field || this.prop]['type'] ||
            config[this.field || this.prop]
          : this.type;
      return Array.isArray(types) ? types.includes(type) : type == types;
    },
    getOptions(config) {
      let option = config && config[this.field || this.prop];
      return option && typeof option == 'object'
        ? { ...this.formOption, ...option }
        : this.formOption;
    },
    getData(res) {
      return res && res[this.field || this.prop]
        ? res[this.field || this.prop]
        : this.option;
    },
    exclAttribute({ data, attrs }) {
      return util.exclAttribute({ data, attrs });
    },
    format(rows, flag) {
      const field = this.field || this.prop;
      let data = this.option;
      let str = '';
      let column = rows[field] || rows[field] == 0 ? JSON.parse(JSON.stringify(rows[field])) : '';
      if (typeof column == 'string' && column.includes(',')) {
        column = column.split(',');
      }
      if (util.isObject(column)) {
        str =
          column[this.labelKey] ||
          column['name'] ||
          column['label'] ||
          column['shortName'];
      } else if (Array.isArray(column)) {
        const vals = column.map((item) => {
          if (util.isObject(item)) {
            return (
              item[this.labelKey] ||
              item['name'] ||
              item['label'] ||
              item['shortName']
            );
          } else {
            if (data && data.length && util.isObject(data[0])) {
              return this.getLabel(data, item);
            }
            return item;
          }
        });
        str = vals.join(this.symbol ? this.symbol : ',');
      } else {
        if (this.valueToString) {
          const vals = column.split(',').map((item) => {
            if (data && data.length && util.isObject(data[0])) {
              return this.getLabel(data, item);
            }
            return item;
          });
          str = vals.join(this.symbol ? this.symbol : ',');
        } else {
          if (data && data.length && util.isObject(data[0])) {
            str = this.getLabel(data, column);
          } else {
            str = column;
          }
        }
      }
      if (str && flag) {
        str = str.replace(RegExp('\\n', 'g'), '<br/>');
        str = str.replace(RegExp(' ', 'g'), '&nbsp;');
      }
      return str;
    },
    getLabel(obj, val) {
      for (let i = 0; i < obj.length; i++) {
        let item = obj[i];
        let value = item[this.valueKey || 'cciValue'] || item['value'];
        if (value == val) {
          console.log('value', value);
          return (
            item[this.labelKey] ||
            item['name'] ||
            item['label'] ||
            item['shortName']
          );
        } else if (item.children && item.children.length) {
          return this.getLabel(item.children, val);
        }
      }
      return val;
    },
    isReadOnly(scope) {
      return (
        scope.row.canEdit === false ||
        this.readonly ||
        this.$attrs.editable === false ||
        (scope.row.cantEditKey &&
          scope.row.cantEditKey.indexOf(this.field || this.prop) > -1)
      );
    },
    isNotRule(scope) {
      if (
        scope.row.canRule === false ||
        (scope.row.notRules &&
          scope.row.notRules.indexOf(this.field || this.prop) > -1)
      ) {
        this.elForm && this.elForm.clearValidate(this.field || this.prop);
        return true;
      }
      return false;
    },
    handleBlur(data) {
      this.events && this.events.blur && this.events.blur(data);
      this.$emit('formBlur', data);
      this.$emit('form-blur', data);
    },
    handleFocus(data) {
      this.events && this.events.focus && this.events.focus(data);
      this.$emit('formFocus', data);
      this.$emit('form-focus', data);
    },
    handleChange(datas) {
      let { item, name, data } = datas;
      if (
        item &&
        ((data.formConfigs && data.formConfigs[name] == 'ganged') ||
          this.type == 'ganged')
      ) {
        let { index, value } = datas.value;
        if (
          (item.url || this.sysCode) &&
          ((item.ganged && index > item.ganged - 1) || value.hasSub)
        ) {
          let filte = value[this.valueKey] || value.value;
          let datas = [];
          if (this.optionDatas[this.field || this.prop][index + 1]) {
            datas = this.optionDatas[this.field || this.prop][index + 1].filter(
              (items) => {
                return filte == items[item.filtrateKey];
              }
            );
          }
          if (datas.length == 0) {
            let queryKey = item.queryKey;
            let param = {};
            if (queryKey) {
              for (let i in queryKey) {
                param[i] = value[queryKey[i]];
              }
            }
            let params = util.extend(
              true,
              this.sysCode ? { sysAppCode: this.sysCode, code: sysCode } : {},
              item.param ? item.param : {},
              param
            );
            util
              .ajax({
                url: this.sysCode ? this.findCode : item.url,
                method: this.method,
                params: params,
                data: params
              })
              .then((res) => {
                if (res.rCode === 0) {
                  let options = JSON.parse(
                    JSON.stringify(this.optionDatas[this.sysCode])
                  );
                  if (options[index + 1]) {
                    options[index + 1] = options[index + 1].concat(
                      JSON.parse(JSON.stringify(res.results))
                    );
                  } else {
                    options.push(JSON.parse(JSON.stringify(res.results)));
                  }
                  this.$set(this.optionDatas, this.sysCode, options);
                } else {
                  let msg = res.msg || '系统错误，请联系管理员！';
                  this.$message.error(msg);
                }
              })
              .catch((err) => {
                if (err.message && err.message !== 'canceled') {
                  this.$message.error(err.message);
                }
              });
          }
        }
      }
      this.events && this.events.change && this.events.change(datas);
      this.$emit('formChange', datas);
      this.$emit('form-change', datas);
    },
    handleClick(data) {
      this.$emit('handleClick', data);
      this.$emit('handle-click', data);
    },
    formatDate(date, fmt) {
      return date ? util.formatDate(date, fmt) : this.dateValue;
    }
  }
};
</script>
