<template>
  <!-- 表单组件（支持各类型表单框） -->
  <el-form v-if="form" :model="form" ref="form" :rules="rules">
    <my-row>
      <my-col
        :span="item.col || 24"
        v-for="(item, index) of formList"
        :key="index"
      >
        <!-- 自定义form表单 -->
        <template v-if="item.formItemSlot">
          <el-form-item
            class="formItemSlot"
            :prop="item.prop"
            label-position="top"
          >
            <span class="span" slot="label">{{ item.label }}</span>
            <slot v-if="item.slot" :name="item.slot" :item="item" />
          </el-form-item>
        </template>
        <!-- 根据type选择form表单 -->
        <el-form-item
          v-else
          :label="item.label"
          :prop="item.prop"
          :label-position="item.labelPosition || 'right'"
          :label-width="item.labelWidth || '80px'"
        >
          <template v-if="item.formItemLabelSlot" slot="label">
            <slot :name="item.formItemLabelSlot" :item="item" />
          </template>
          <!-- 没有嵌套 -->
          <template v-if="!item.slot">
            <!-- 文字 -->
            <template v-if="item.type == 'span'">
              <span>{{ form[item.prop] }}</span>
              <span class="unit" v-if="form[item.prop] && item.unit">{{
                item.unit
              }}</span>
            </template>
            <!-- 输入框 -->
            <template v-if="item.type == 'text'">
              <el-input
                v-model.trim="form[item.prop]"
                :disabled="item.disabled || false"
                :readonly="item.readonly || false"
                :placeholder="item.placeholder || ''"
                @change="(value) => handleInpTextChange(value, item)"
                @focus="(value) => handleFocus(value, item)"
              ></el-input>
              <span v-if="item.unit">{{ item.unit }}</span>
            </template>
            <!-- 文本数字输入框 -->
            <template v-if="item.type == 'textNumber'">
              <el-input
                v-model.trim="form[item.prop]"
                type="number"
                :disabled="item.disabled || false"
                :readonly="item.readonly || false"
                :placeholder="item.placeholder || ''"
                @change="(value) => handleInpTextChange(value, item)"
              ></el-input>
              <span v-if="item.unit">{{ item.unit }}</span>
            </template>
            <!-- 文本框 -->
            <template v-if="item.type == 'textarea'">
              <el-input
                type="textarea"
                resize="none"
                v-model.trim="form[item.prop]"
                :disabled="item.disabled || false"
                :placeholder="item.placeholder || ''"
              ></el-input>
              <span v-if="item.unit">{{ item.unit }}</span>
            </template>
            <!-- 下拉框 -->
            <template v-if="item.type == 'select'">
              <el-select
                v-model.trim="form[item.prop]"
                :clearable="item.clearable || true"
                :disabled="item.disabled || false"
                :placeholder="item.placeholder || ''"
                :filterable="true"
                @change="(value) => handleChange(value, item)"
              >
                <el-option
                  v-for="(item2, index) in item.dropProp.list"
                  :key="index"
                  :label="
                    item.dropProp.label ? item2[item.dropProp.label] : item2
                  "
                  :value="
                    item.dropProp.value ? item2[item.dropProp.value] : item2
                  "
                >
                </el-option>
              </el-select>
              <!-- 下拉框是否带单位 -->
              <span v-if="item.unit">{{ item.unit }}</span>
            </template>
            <!-- 数字输入框 -->
            <template v-if="item.type == 'number'">
              <el-input-number
                v-model.trim="form[item.prop]"
                controls-position="right"
                :size="item.size || 'small'"
                :disabled="item.disabled || false"
                :min="item.countProp.min"
                :max="item.countProp.max"
              ></el-input-number>
              <template v-if="item.countProp.unit">
                （{{ item.countProp.unit }}）
              </template>
              <template v-if="item.countProp.toopicMsg">
                <el-tooltip
                  class="item"
                  effect="dark"
                  :content="item.countProp.toopicMsg"
                  placement="top"
                >
                  <i style="cursor: pointer" class="el-icon-question"></i>
                </el-tooltip>
              </template>
            </template>
            <!-- 年份 -->
            <template v-if="item.type === 'year'">
              <el-date-picker
                v-model="form[item.prop]"
                type="year"
                placeholder="选择年份"
                value-format="yyyy"
              >
              </el-date-picker>
              <span v-if="item.unit">{{ item.unit }}</span>
            </template>
            <!-- 日期选择框 -->
            <template v-if="item.type == 'date'">
              <el-date-picker
                v-model="form[item.prop]"
                type="date"
                placeholder="选择日期"
                value-format="yyyy-MM-dd"
                :disabled="item.disabled || false"
              >
              </el-date-picker>
              <span v-if="item.unit">{{ item.unit }}</span>
            </template>
            <!-- 时间选择框 -->
            <template v-if="item.type == 'datetime'">
              <el-date-picker
                v-model="form[item.prop]"
                type="datetime"
                placeholder="选择日期时间"
                value-format="yyyy-MM-dd HH:mm:ss"
              >
              </el-date-picker>
              <span v-if="item.unit">{{ item.unit }}</span>
            </template>
            <!-- 时间段选择框 -->
            <template v-if="item.type == 'datetimerange'">
              <el-date-picker
                v-model="form[item.prop]"
                type="datetimerange"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                placeholder="选择日期时间"
                value-format="yyyy-MM-dd HH:mm:ss"
              >
              </el-date-picker>
            </template>
            <!-- 上传图片（建议不使用，需要改） -->
            <template v-if="item.type == 'uploadFile'">
              <!-- 上传图片(多组上传)（建议不使用，需要改） -->
              <div class="uploadFileArr" v-if="item.fileArrProp">
                <el-upload
                  class="uploadFileArrItem"
                  v-for="(item2, index2) of item.fileArrProp"
                  :key="index2"
                  ref="uploadFileArrItem"
                  :disabled="item2.disabled || false"
                  :action="fileObj.uploadUrl"
                  :headers="headersToken"
                  :limit="item2.limit"
                  :list-type="fileObj.listType"
                  :on-success="
                    (res, file) => {
                      handleFileSuccess({ res, item: item2, file });
                    }
                  "
                  :on-exceed="
                    (file) => {
                      handleFileExceed2(file, item2);
                    }
                  "
                  :before-upload="handleFileBeforeUpload"
                  :file-list="item2.fileList"
                  :show-file-list="true"
                >
                  <span class="fs12">{{ item2.label }}</span>
                  <div class="fileList" slot="file" slot-scope="{ file }">
                    <el-image
                      class="uploadingImage"
                      v-if="file.status === 'uploading'"
                    >
                      <div slot="error" class="image-slot">
                        <i v-loading="true"></i>
                      </div>
                    </el-image>
                    <el-image
                      v-else
                      :src="handleUploadSpecial(file.url)"
                      class="fileImg"
                      fit="fill"
                      :lazy="true"
                      :preview-src-list="[handleUploadSpecial(file.url)]"
                    ></el-image>
                    <div
                      class="delete"
                      :style="varColor"
                      @click.stop="
                        (e) => {
                          handleFileRemove({
                            e,
                            file,
                            item: item2,
                            ref: 'uploadFileArrItem',
                          });
                        }
                      "
                    >
                      <i class="el-icon-circle-close"></i>
                    </div>
                  </div>
                </el-upload>
              </div>
              <!-- 上传图片(单组上传)（建议不使用需要改） -->
              <el-upload
                v-else
                class="upload"
                ref="upload"
                :disabled="item.disabled || false"
                :action="fileObj.uploadUrl"
                :headers="headersToken"
                :limit="fileObj.limit"
                :list-type="fileObj.listType"
                :on-success="
                  (res, file) => {
                    handleFileSuccess({ res, item, file });
                  }
                "
                :on-exceed="handleFileExceed"
                :before-upload="handleFileBeforeUpload"
                :file-list="item.fileList"
              >
                <i class="el-icon-plus"></i>
                <div class="fileList" slot="file" slot-scope="{ file }">
                  <el-image
                    class="uploadingImage"
                    v-if="file.status === 'uploading'"
                  >
                    <div slot="error" class="image-slot">
                      <i v-loading="true"></i>
                    </div>
                  </el-image>
                  <el-image
                    v-else
                    :src="handleUploadSpecial(file.url)"
                    class="fileImg"
                    fit="fill"
                    :lazy="true"
                    :preview-src-list="[handleUploadSpecial(file.url)]"
                  ></el-image>
                  <div
                    class="delete"
                    :style="varColor"
                    @click.stop="
                      (e) => {
                        handleFileRemove({ e, file, item, ref: 'upload' });
                      }
                    "
                  >
                    <i class="el-icon-circle-close"></i>
                  </div>
                </div>
              </el-upload>
            </template>
            <!-- 上传文件 -->
            <template v-if="item.type == 'upload'">
              <my-upload
                ref="myUpload"
                :uploadFileUrl="item.uploadFileUrl"
                :value="item.value"
                @handleSuccess="
                  (list) => {
                    handleSuccess({ list, prop: item.prop });
                  }
                "
                @handleRemove="
                  (list) => {
                    handleRemove({ list, prop: item.prop });
                  }
                "
              ></my-upload>
            </template>
          </template>
          <!-- slot -->
          <template v-else>
            <slot :name="item.slot" :item="item" :index="index" :form="form" />
          </template>
        </el-form-item>
      </my-col>
    </my-row>
  </el-form>
</template>

<script>
// 示例
// formList = [
//     {
//         prop: "materialName",
//         label: "物资名称",
//         labelWidth: '160px',
//         type: 'text',
//         col: 12,
//     },
//     {
//         prop: "specification", //字段名
//         label: "型号规格", //名称
//         labelWidth: '160px',//文字宽度
//         type: 'text',  //输入框类型
//         col: 12,       //列数
//     },
//      {
//         prop: "specification", //字段名
//         label: "型号规格", //名称
//         labelWidth: '160px',//文字宽度
//         slot: 'specification',  //插槽名（如需自定义可定义插槽名）
//         col: 12,       //列数
//     },
// ]
export default {
  props: {
    // 上传文件配置
    fileObj: {
      type: Object,
      default: () => {
        return {
          imgStyle: "width: 80px; height: 80px",
          uploadUrl: "",
          limit: 6,
          listType: "picture-card",
          fileType: ["png", "jpg", "jpeg"],
          fileSize: 5,
          fileList: [],
        };
      },
    },
    //表单参数集合
    form: {
      type: Object,
    },
    //表单验证规则
    rules: {
      type: Object,
    },
    //表单list
    formList: {
      type: Array,
    },
  },
  methods: {
    handleRowClick({ item }) {
      this.$emit("handleRowClick", { item });
    },
    // 下拉框更改
    handleChange(value, item) {
      if (!item.changeFn) {
        return;
      }
      this.$emit(item.changeFn, { value, item });
    },
    // 输入框更改
    handleInpTextChange(value, item) {
      if (!item.changeTextFn) return;
      this.$emit(item.changeTextFn, { value, item });
    },
    // 获取焦点
    handleFocus(value, item) {
      if (!item.focueTextFn) return;
      this.$emit(item.focueTextFn, { value, item });
    },
    // 文件个数超出
    handleFileExceed2(file, item2) {
      this.$message.error(`上传文件数量不能超过 ${item2.limit} 个!`);
    },
    handleFileExceed() {
      this.$message.error(`上传文件数量不能超过 ${this.formObj.limit} 个!`);
    },
    // 上传前校检格式和大小
    handleFileBeforeUpload(file) {
      const fileData = file;
      return new Promise((resolve, reject) => {
        // 校检文件类型
        if (this.fileObj.fileType) {
          let fileExtension = "";
          if (file.name.lastIndexOf(".") > -1) {
            fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
          }
          const isTypeOk = this.fileObj.fileType.some((type) => {
            if (file.type.indexOf(type) > -1) return true;
            if (fileExtension && fileExtension.indexOf(type) > -1) return true;
            return false;
          });
          if (!isTypeOk) {
            this.$message.error(
              `文件格式不正确, 请上传${this.fileObj.fileType.join(
                "/"
              )}格式文件!`
            );
            return reject();
          }
        }
        // 校检文件大小
        if (this.fileObj.fileSize) {
          const isLt = file.size / 1024 / 1024 < this.fileObj.fileSize;
          if (!isLt) {
            this.$message.error(
              `上传文件大小不能超过 ${this.fileObj.fileSize} MB!`
            );
            return reject();
          }
        }
        //校验图片内容
        if (this.fileObj.isIdentifyImage) {
          let data = new FormData();
          data.append("file", fileData);
          request({
            url: `${this.fileObj.identifyImageUrl}?matchCharacters1=${this.identifyImageData.projectName}&matchCharacter2=${this.identifyImageData.uploadFileName}`,
            method: "post",
            data,
            headers: {
              "Content-Type": "multipart/form-data",
            },
          })
            .then((res) => {
              if (res.data.code == 0 && res.data.data.ocrResult == 1) {
                return resolve();
              } else {
                this.$message.warning("识别错误，请重新上传正确文件！");
                return reject();
              }
            })
            .catch(() => {
              return reject();
            });
        }
        return resolve();
      });
    },
    // 上传成功
    handleFileSuccess({ res, item, file }) {
      if (res.code == 0 && res.data) {
        this.$emit("uploadSuccess", { data: res.data, item });
      } else {
        this.$message.warning(res.msg || "上传失败");
        item.fileList = item.fileList.filter((o) => o.url === file.url);
      }
    },
    //移除文件
    handleFileRemove({ e, file, item, ref }) {
      this.$refs[ref][item.index].handleRemove(file);
      const filePath = file.url;
      this.$emit("uploadRemove", { file, filePath, item });
    },
    //移除文件
    handleRemove({ list, prop }) {
      this.$emit("handleRemove", { list, prop });
    },
    // 上传成功
    handleSuccess({ list, prop }) {
      this.$emit("handleSuccess", { list, prop });
    },
    //清除表单
    clear() {
      this.$nextTick(() => {
        if (this.$refs.form) {
          this.$refs.form.clearValidate();
        }
      });
    },
    //清除上传文件
    clearUploadFile() {
      this.$nextTick(() => {
        if (this.$refs.myUpload) {
          this.$refs.myUpload.forEach((res) => {
            res.clear();
          });
        }
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.fs12 {
  font-size: 12px;
}
.uploadFileItem {
  margin: 0 0 10px 0;
}
.fileImg {
  width: var(--imgWidth);
  height: var(--imgWidth);
}
::v-deep {
  .el-form-item {
    width: 100%;
  }
  .el-upload--picture-card {
    width: var(--imgWidth);
    height: var(--imgWidth);
    line-height: var(--imgWidth);
  }
  .el-upload-list__item {
    width: var(--imgWidth);
    height: var(--imgWidth);
  }
  .el-upload-list--picture-card .el-upload-list__item {
    width: var(--imgWidth);
    height: var(--imgWidth);
  }
  .uploadFileArrItem .el-upload-list--picture-card .el-upload-list__item {
    margin: 4px 8px 0 0 !important;
  }
  .formItemSlot .el-form-item__label {
    line-height: 36px;
  }
}
.uploadFileArr {
  display: flex;
  align-items: center;
  .uploadFileArrItem {
    display: flex;
    align-items: center;
    margin: 0 10px 0 0;
  }
}
.fileList {
  position: relative;
  width: 100%;
  height: 100%;
  .delete {
    position: absolute;
    top: 0;
    right: 0;
    cursor: pointer;
    i {
      color: #ffda00;
      font-size: 18px;
    }
  }
}
.span {
  display: flex;
  justify-content: flex-start;
  line-height: 36px;
}
.formItemSlot {
  display: flex;
  justify-content: flex-start;
  flex-direction: column;
}
</style>
