<template>
  <el-dialog
    center
    :title="title"
    :class="dialogComponent"
    :visible.sync="visible"
    :width="width"
    @close="close"
    :append-to-body="appendToBody"
    :close-on-click-modal="closeModal"
  >
    <div class="main">
      <el-form
        :rules="rules"
        :model="form"
        ref="form"
        label-position="right"
        :label-width="labelWidth"
        @submit.native.prevent
      >
        <el-row>
          <template v-for="(item, index) in formDataSet">
            <el-col
              v-if="!item.hidden"
              :span="item.spanCount ? item.spanCount : countLine"
              :key="item.prop"
              :class="item.class"
            >
              <el-form-item
                :key="index"
                :label="item.label ? `${item.label}:` : ''"
                :label-width="item.labelWidth"
                :prop="item.prop"
                :rules="item.rules"
                :class="item.className"
                :style="item.style"
              >
                <!-- 按钮控制 -->
                <el-button
                  v-if="item.operation"
                  class="operBtn"
                  :type="item.operation.type ? item.operation.type : 'text'"
                  :autofocus="item.autofocus"
                  @click="item.operation.func ? item.operation.func(form) : {}"
                >
                  {{
                    item.operation.text ? item.operation.text : "新增"
                  }}</el-button
                >

                <!-- 提示 -->
                <el-tooltip
                  v-if="item.tips"
                  effect="dark"
                  :content="item.tips"
                  placement="top"
                  slot="label"
                >
                  <span :style="item.tipsStyle">{{ item.label }}：</span>
                </el-tooltip>

                <!-- 输入框 input -->
                <el-input
                  v-if="item.type === 'input'"
                  :type="item.inputType ? item.inputType : ''"
                  :maxlength="item.maxlength"
                  :minlength="item.minlength"
                  :placeholder="item.placeholder"
                  clearable
                  :disabled="item.disabled"
                  v-model="form[item.prop]"
                  @input="item.func ? item.func($event) : {}"
                  :resize="item.resize"
                  :rows="item.rows"
                  :autosize="item.autosize"
                >
                  <span
                    :slot="item.slot ? item.slot : 'append'"
                    v-if="item.unit"
                    >{{ item.unit }}</span
                  >
                </el-input>

                <!-- 数字输入框 -->
                <div
                  v-if="item.type === 'number'"
                  style="display: inline-table"
                >
                  <el-input-number
                    :min="item.min"
                    :max="item.max"
                    clearable
                    :precision="item.precision"
                    :controls="item.controls || false"
                    :disabled="item.disabled"
                    v-model="form[item.prop]"
                    :placeholder="item.placeholder"
                    @input="item.func ? item.func($event) : {}"
                    style="display: table-cell"
                  ></el-input-number>
                  <span
                    v-if="item.append"
                    class="el-input-group__append"
                    style="line-height: 28px"
                    >{{ item.append }}</span
                  >
                </div>
                <!-- 模糊查询输入 -->
                <el-autocomplete
                  v-else-if="item.type === 'autocomplete'"
                  popper-class="my-autocomplete"
                  v-model="form[item.prop]"
                  :fetch-suggestions="item.func"
                  :placeholder="item.placeholder"
                  @select="item.selectfun"
                  clearable
                >
                  <template slot-scope="{ item }">
                    <div class="name">
                      {{ item.value }}
                      <span v-if="item.specification"
                        >({{ item.specification }})</span
                      >
                    </div>
                    <span class="description">{{ item.description }}</span>
                  </template>
                </el-autocomplete>

                <!-- 选择器 -->
                <el-select
                  v-else-if="item.type === 'select'"
                  :multiple="item.multiple"
                  :disabled="item.disabled"
                  v-model="form[item.prop]"
                  :placeholder="item.placeholder ? item.placeholder : '请选择'"
                  :filterable="item.filterable ? false : true"
                  clearable
                  :value-key="item.key ? item.key : 'value'"
                  @change="item.func ? item.func($event) : {}"
                >
                  <el-option
                    v-for="(opt, optIndex) in item.opts"
                    :key="optIndex"
                    :label="opt.label"
                    :value="item.isSelect ? opt.selectValue : opt.value"
                    :disabled="opt.disabled"
                  >
                    <span style="float: left">{{ opt.label }}</span>
                    <span
                      style="float: right; color: #8492a6; font-size: 10px"
                      >{{ opt.description }}</span
                    >
                  </el-option>
                </el-select>

                <!-- 模糊查询选择 -->
                <el-select
                  v-else-if="item.type === 'remote'"
                  v-model="form[item.prop]"
                  filterable
                  remote
                  reserve-keyword
                  :placeholder="item.placeholder"
                  :remote-method="item.remoteFunc"
                  @change="item.func ? item.func($event) : {}"
                >
                  <el-option
                    v-for="(opt, optIndex) in item.opts"
                    :key="optIndex"
                    :label="opt.label"
                    :value="item.isSelect ? opt.selectValue : opt.value"
                  ></el-option>
                </el-select>

                <!-- 日期 -->
                <el-date-picker
                  v-else-if="item.type === 'date'"
                  v-model="form[item.prop]"
                  :type="item.dateType ? item.dateType : 'date'"
                  :placeholder="item.placeholder"
                  :picker-options="item.options"
                  :format="item.format"
                  :value-format="item.valueFormat"
                  @change="item.func ? item.func($event) : {}"
                ></el-date-picker>
                <!-- 时间 -->
                <el-time-picker
                  v-else-if="item.type === 'time'"
                  :format="item.format"
                  :value-format="item.valueFormat"
                  v-model="form[item.prop]"
                  :picker-options="item.options"
                  @change="item.func ? item.func($event) : {}"
                ></el-time-picker>
                <!-- 开关 -->
                <el-switch
                  v-else-if="item.type === 'switch'"
                  :disabled="item.disabled"
                  :active-value="item.activeValue || 1"
                  :inactive-value="item.inactiveValue || 0"
                  v-model="form[item.prop]"
                >
                </el-switch>

                <!-- 单选框 -->
                <el-radio
                  :class="item.class"
                  v-else-if="item.type === 'radio'"
                  v-model="form[item.prop]"
                  v-for="(opt, optIndex) in item.opts"
                  :key="optIndex"
                  :label="opt.value"
                  @change="item.func ? item.func($event) : {}"
                  >{{ opt.label }}</el-radio
                >

                <!-- 多选框 -->
                <el-checkbox-group
                  v-else-if="item.type === 'checkbox'"
                  v-model="form[item.prop]"
                >
                  <el-checkbox
                    v-for="(opt, optIndex) in item.opts"
                    :key="optIndex"
                    :label="opt.label"
                  ></el-checkbox>
                </el-checkbox-group>

                <!-- 级联 -->
                <el-cascader
                  v-else-if="item.type === 'cascader'"
                  :options="item.list"
                  v-model="form[item.prop]"
                  :clearable="true"
                  :filterable="true"
                ></el-cascader>

                <!-- 树形 -->
                <el-tree
                  v-else-if="item.type === 'tree'"
                  ref="tree"
                  :data="treeList"
                  show-checkbox
                  :node-key="item.nodeKey || 'id'"
                  :props="item.props || defaultProps"
                ></el-tree>

                <!-- 导入文件 -->
                <template v-else-if="item.type === 'import'">
                  <div class="import-container" @click="handleImport">
                    <span v-if="form[item.prop]">{{ form[item.prop] }}</span>
                    <span v-else class="wait">{{ item.placeholder }}</span>
                    <i class="el-icon-upload"></i>
                  </div>
                  <input
                    ref="fileInput"
                    type="file"
                    class="import-file"
                    :accept="item.accept"
                    @change="handleFileChange($event)"
                  />
                </template>

                <span v-else-if="item.type === 'text'">{{
                  form[item.prop]
                }}</span>
              </el-form-item>
            </el-col>
          </template>
        </el-row>
      </el-form>
    </div>
    <div slot="footer">
      <el-button size="medium" v-if="btnCancel" @click="visible = false"
        >取 消</el-button
      >
      <el-button
        size="medium"
        type="primary"
        :loading="loading"
        @click="handleConfirm"
        >{{ confirmText }}</el-button
      >
      <slot name="otherButton" :form="form"></slot>
    </div>
  </el-dialog>
</template>

<script>
export default {
  data() {
    return {
      loading: false,
      visible: false,
      form: {},
      defaultProps: {
        children: "children",
        label: "name",
      },
    }
  },
  props: {
    confirmText: {
      type: String,
      default: "确 认",
    },
    appendToBody: {
      type: Boolean,
      default: false,
    },
    closeModal: {
      type: Boolean,
      default: false,
    },
    title: {
      type: String,
      default: "系统提示",
    },
    countLine: {
      // 一行排列几个
      default: 24,
    },
    width: {
      type: String,
      default: "365px",
    },
    labelWidth: {
      type: String,
      default: "100px",
    },
    btnCancel: {
      type: Boolean,
      default: true,
    },
    formData: {
      type: Array,
    },
    formEdit: {
      type: Object,
    },

    rules: {
      type: Object,
    },
    dialogComponent: {
      type: String,
      default: "dialog-component",
    },
    treeList: {
      type: Array,
    },
  },
  methods: {
    open() {
      this.visible = true
    },

    close() {
      this.loading = false
      this.visible = false
    },

    handleConfirm() {
      this.loading = true
      this.$refs.form.validate((valid) => {
        if (valid) {
          if (this.$refs.tree) {
            const halfChecks = this.$refs.tree[0].getHalfCheckedKeys()
            const checks = this.$refs.tree[0].getCheckedKeys()
            this.form.treeList = [...new Set(checks.concat(halfChecks))]
          }
          this.$emit("handleConfirm", this.form)
        } else {
          this.loading = false
        }
      })
    },

    // 初始化整个表单（可在初始化时赋值）
    initforms(formEdit) {
      const form = {}
      this.formData.forEach((item) => {
        if (!item.prop || item.hidden) return false
        if (item.type === "select-input" || item.type === "input-input") {
          form[item.prop1] = ""
          form[item.prop2] = ""
        } else if (
          item.type === "checkbox" ||
          item.type === "cascader" ||
          item.multiple
        ) {
          form[item.prop] = []
        } else if (item.type === "number") {
          form[item.prop] = undefined
        } else {
          form[item.prop] = ""
        }
      })
      // 树形菜单
      if (this.treeList) {
        this.$nextTick(() => {
          this.$refs.tree[0].setCheckedKeys([])
          const list = (this.formEdit && this.formEdit.treeList) || []
          list.forEach((item) => {
            this.$refs.tree[0].setChecked(item, true)
          })
        })
        if (this.formEdit && this.formEdit.imageUrl) {
          this.imageUrl = this.webDomain + this.formEdit.imageUrl
        }
      }
      if (formEdit) {
        this.form = Object.assign(form, formEdit)
      }
      if (this.formEdit) {
        this.form = Object.assign(form, this.formEdit)
      } else {
        this.form = Object.assign({}, form)
      }
      this.loading = false

      this.$nextTick(() => {
        if (this.$refs.fileInput && this.$refs.fileInput[0]) {
          this.$refs.fileInput[0].value = ""
        }
        this.$refs.form.clearValidate()
      })
    },

    // 给表单部分字段赋值（此时表单已初始化）
    initFields(obj) {
      for (const key in obj) {
        this.form[key] = obj[key]
      }
      this.$nextTick(() => {
        this.$refs.form.clearValidate()
      })
    },
  },
  watch: {
    visible() {
      if (this.visible) {
        this.initforms()
      }
    },
  },
  computed: {
    formDataSet() {
      return this.formData.map((item) => {
        if (
          item.optsFormatter &&
          Object.prototype.toString.call(item.optsFormatter) ===
            "[object Function]"
        ) {
          try {
            item.opts = item.optsFormatter()
          } catch (error) {}
        }
        return {
          ...item,
        }
      })
    },
  },
}
</script>

<style lang="scss">
.dialog-component {
  .el-form-item {
    // margin-bottom: 15px;
  }
  .el-select,
  .el-input {
    width: 100%;
  }
  .el-input-number .el-input__inner {
    text-align: left;
  }
  .input-with-select {
    .el-input__suffix {
      position: relative !important;
      right: 20px;
      font-size: 14px;
    }
    .el-input__inner {
      width: 130px;
    }
    .el-input--mini .el-input__inner {
      text-align: center;
    }
  }
  .el-input-group__prepend {
    padding: 0;
  }
  .input-with-input {
    .el-input-group__prepend {
      background-color: #ffffff;
      width: 120px;
      padding: 0;
      border: 0;
    }
  }
  .red-background .el-input__inner {
    background: #c92639;
    color: #fff;
    border-color: #c30d23 !important;
  }
  .blue-background .el-input__inner {
    background: #0097ff;
    color: #fff;
    border-color: #036eb8 !important;
  }
}
</style>

<style lang="scss" scoped>
.avatar-line {
  text-align: center;
  img {
    width: 120px;
  }
}

.my-autocomplete {
  li {
    line-height: normal;
    padding: 7px;
    .name {
      text-overflow: ellipsis;
      overflow: hidden;
      + .description,
      span {
        font-size: 12px;
      }
      + .description {
        color: #b4b4b4;
      }
    }

    .highlighted .description {
      color: #ddd;
    }
  }
}

.dialog-component .el-input__suffix {
  position: relative !important;
}

.el-autocomplete {
  width: 100%;
}
</style>
