<template>
  <div class="by-form">
    <el-form :model="formData" :label-width="formOption.labelWidth || '100px'" :inline="formOption.inline || false" :rules="rules"
             :labelPosition="formOption.labelPosition || 'right'" ref="byForm" :disabled="formOption.disabled || false">
      <template v-for="i in formConfig" :key="i.model">
        <el-form-item :label="i.label" :prop="i.prop" v-if="(Object.keys(i).length>0)&& (i.isShow || i.isShow == undefined)" :style="
            (i.type == 'title'||i.type == 'title1')
              ? 'width:100%'
              : i.itemWidth
              ? 'width:' + i.itemWidth + '%'
              : formOption.itemWidth
              ? 'width:' + formOption.itemWidth + '%'
              : '100%'
          " :class="
            (i.type == 'title'||i.type == 'title1')?
             'formTitle'
              : ''
          ">
          <el-input v-if="i.type == 'input'" v-model="formData[i.prop]" :placeholder="i.placeholder || $t('common.pleaseEnter')"
                    @input="(e) => commonsEmit(e, i)" @change="(e) => commonsEmitChange(e, i)" :type="i.itemType ? i.itemType : 'text'"
                    :disabled="i.disabled ? i.disabled : false" :max="i.max" :min="i.min" :maxlength="i.maxlength"
                    :readonly="i.readonly ? i.readonly : false" :style="i.style" />
          <el-input v-if="i.type == 'selectInput'" v-model="formData[i.prop]" :placeholder="i.placeholder || $t('common.pleaseEnter')"
                    @input="(e) => commonsEmit(e, i)" :type="i.itemType ? i.itemType : 'text'" :disabled="i.disabled ? i.disabled : false"
                    :max="i.max" :min="i.min" :maxlength="i.maxlength" :readonly="i.readonly ? i.readonly : false">
            <template #prepend>
              <el-select v-model="formData[i.selectProp]" :placeholder="i.selectPlaceholder || $t('common.pleaseSelect')"
                         @change="(e) => commonsEmit(e, i)" :disabled="i.disabledSelect ? i.disabledSelect : false"
                         :readonly="i.readonly ? i.readonly : false" style="width: 80px">
                <el-option :label="j.dictValue || j.name || j.label" :value="j.dictKey||j.id || j.value" v-for="j in i.data"
                           :key="j.id || j.dictKey || j.value">
                </el-option>
              </el-select>
            </template>
          </el-input>
          <div v-else-if="i.type == 'text'">
            {{formData[i.prop]}}
          </div>
          <el-select v-model="formData[i.prop]" :multiple="i.multiple || false" v-else-if="i.type == 'select'"
                     :placeholder="i.placeholder || $t('common.pleaseSelect')" @change="(e) => commonsEmit(e, i)"
                     :disabled="i.disabled ? i.disabled : false" :clearable="i.clearable ? i.clearable : false"
                     :filterable="i.filterable ? true : true" :style="i.style?i.style:{width:'100%'}" :readonly="i.readonly ? i.readonly : false">
            <el-option :label="j.dictValue || j.name || j.label" :value="j.dictKey||j.id || j.value" v-for="j in i.data"
                       :key="j.id || j.dictKey || j.value" :disabled="j.disabled ?j.disabled:false ">
            </el-option>
          </el-select>
          <el-tree-select v-model="formData[i.prop]" :multiple="i.multiple || false" v-else-if="i.type == 'treeSelect'" :data="i.data"
                          :readonly="i.readonly ? i.readonly : false" :props="{
              value: i.propsTreeValue || 'id',
              label: i.propsTreeLabel || 'label',
              children: i.propsTreeChildren || 'children',
              disabled:i.propsTreeDisabled || 'disabled'
            }" value-key="id" :filterable="i.filterable ? true : true" :clearable="i.clearable ? i.clearable : false"
                          :placeholder="i.placeholder || $t('common.pleaseSelect')" :disabled="i.disabled ? i.disabled : false" check-strictly
                          :style="i.style?i.style:{width:'100%'}" default-expand-all @change="(e) => commonsEmit(e, i)" />
          <el-date-picker v-model="formData[i.prop]" :readonly="i.readonly ? i.readonly : false" v-else-if="i.type == 'date'" :type="i.itemType"
                          :placeholder="i.placeholder || $t('common.pleaseSelectTime')" @change="(e) => commonsEmit(e, i)"
                          :disabled="i.disabled ? i.disabled : false" :format="i.format ? i.format : dateFormatInit(i.itemType)"
                          :value-format="i.format ? i.format : dateFormatInit(i.itemType)" :style="i.style?i.style:{width:'100%'}"
                          :disabled-date="i.disabledFn ? i.disabledFn :()=>false" />
          <el-switch :disabled="i.disabled ? i.disabled : false" v-else-if="i.type == 'switch'" :readonly="i.readonly ? i.readonly : false"
                     v-model="formData[i.prop]" />
          <el-checkbox-group v-else-if="i.type == 'checkbox'" v-model="formData[i.prop]" :readonly="i.readonly ? i.readonly : false"
                             :disabled="i.disabled ? i.disabled : false">
            <el-checkbox v-for="j in i.data" :key="j.id || j.value" :label="j.id || j.value" name="type">
              {{ j.name || j.label }}
            </el-checkbox>
          </el-checkbox-group>
          <el-radio-group v-else-if="i.type == 'radio'" v-model="formData[i.prop]" :readonly="i.readonly ? i.readonly : false"
                          :disabled="i.disabled ? i.disabled : false" @change="(e) => commonsEmit(e, i)">
            <el-radio :border="i.border ? i.border : false" v-for="j in i.data" :key="j.id || j.value ||j.dictKey"
                      :label="j.id ||j.dictKey || j.value" name="type">
              {{j.dictValue || j.name || j.label }}
            </el-radio>
          </el-radio-group>
          <el-input-number v-else-if="i.type == 'number'" v-model="formData[i.prop]" :readonly="i.readonly ? i.readonly : false"
                           :placeholder="i.placeholder || $t('common.pleaseEnter')" @change="(e) => commonsEmit(e, i)"
                           :disabled="i.disabled ? i.disabled : false" :min="i.min ? i.min : 0" :max="i.max ? i.max : 9999999999"
                           :step="i.step ? i.step : 1" :precision="i.precision !== '' ? i.precision : 2"
                           :controls="i.controls === false ? false : true" :style="i.style?i.style:{width:'100%'}" onmousewheel="return false;">
          </el-input-number>
          <el-tree v-else-if="i.type == 'tree'" :data="i.data" :props="i.props" :readonly="i.readonly ? i.readonly : false"
                   :show-checkbox="i.showCheckbox || true">
          </el-tree>
          <el-cascader v-else-if="i.type == 'cascader'" :options="i.data" :props="i.props" :readonly="i.readonly ? i.readonly : false"
                       :placeholder="i.placeholder || $t('common.pleaseSelect')" @change="(e) => commonsEmit(e, i)"
                       :disabled="i.disabled ? i.disabled : false" :style="i.style">
          </el-cascader>
          <!-- <div class="form-title" v-else-if="i.type == 'title'">
            {{ i.title }}
          </div> -->

          <div v-else-if="i.type == 'title'" style="width:100%">
            <div v-if="i.haveLine" style="width:calc(100% + 80px);margin-left:-45px;background:#F0F2F5;height:15px"></div>
            <div :style="{marginTop:i.haveLine?'15px':''}" style="margin-left:-15px;">
              <TitleInfo :content="i.title"></TitleInfo>
            </div>
          </div>

          <div v-else-if="i.type == 'title1'" style="width:100%">
            <div>
              <TitleInfo :content="i.title"></TitleInfo>
            </div>
          </div>

          <slot :name="i.slotName" v-else-if="i.type == 'slot'">
            {{ i.slotName }}插槽占位符
          </slot>

          <div class="upload" v-else-if="i.type == 'upload'">
            <el-upload :file-list="formData[i.prop]?formData[i.prop]:[]" multiple :action="uploadUrl" :data="uploadData"
                       :list-type="i.listType ? i.listType : 'text'" :accept="i.accept?i.accept :''" :limit="i.limit?i.limit:3"
                       :before-upload="(file)=>handleBeforeUpload(file,i)" :on-success="()=>handleSuccess(i)"
                       :on-remove="(file)=>handleRemove(file,i)" :on-exceed="()=>handleExceed(i)" :on-preview="onPreviewFile">

              <el-icon v-if="i.listType=='picture-card'">
                <Plus />
              </el-icon>
              <span v-else-if="formOption.disabled" style="color:#409EFF">已上传:</span>
              <el-button type="primary" plain v-else>点击上传</el-button>
            </el-upload>
          </div>

          <div class="upload" v-else-if="i.type == 'uploadImg'">
            <el-upload :action="uploadUrl" accept=".gif, .jpeg, .jpg, .png" :show-file-list="false" :data="uploadData"
                       :before-upload="(file)=>handleBeforeUploadOne(file,i.prop,i.imgProp)" :on-success="()=>handleSuccessOne(i.imgProp)">
              <div v-loading="imgLoading">
                <img v-if="formData[i.imgProp]" :src="formData[i.imgProp]" class="picOne" />
                <el-icon v-else class="avatar-uploader-icon">
                  <Plus />
                </el-icon>
              </div>
            </el-upload>
          </div>
          <div v-else-if="i.type == 'table'" class="by-form-table" style="width: 100%">
            <el-table :data="formData[i.prop]" style="width: 100%">
              <el-table-column :prop="j.prop" :label="j.label" :width="i.width" v-for="(j, jindex) in i.column">
                <template #default="scope" v-if="j.type">
                  <component @change="(e) => formTableChange(e, scope, j)" v-model="scope.row[j.prop]" :is="formTableObj[j.type]"
                             :placeholder="j.placeholder || $t('common.pleaseEnter')" :type="j.type == 'number' ? 'number' : 'text'">
                    <el-option :label="n.title || n.name || n.label" :value="n.id || n.value" v-for="n in j.data" :key="n.id"
                               v-if="j.type == 'select'">
                    </el-option>
                  </component>
                </template>
              </el-table-column>
            </el-table>
          </div>
          <!-- <div v-else-if="i.type == 'json'">
            <byForm :formConfig="i.json" :formOption="formOption" v-model="formData[i.prop]" ref="byform" :rules="rules">
            </byForm>
          </div> -->
        </el-form-item>
      </template>
    </el-form>
  </div>
</template>
<script>
export default {
  name: "byForm",
};
</script>
<script  setup>
import { set } from "@vueuse/shared";
import { reactive } from "vue";
import TitleInfo from "@/components/TitleInfo/index.vue";
defineProps({
  modelValue: {
    type: Object,
    default: false,
  },
  formConfig: {
    type: Array,
    default: false,
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  formOption: {
    type: Object,
    default: false,
  },
  rules: {
    type: Object,
    default: false,
  },
});
const formTableChange = (e, scope, column) => {
  if (column.fn) {
    column.fn(e, scope);
  }
  console.log(formData);
  console.log(e, scope);
};
const formTableObj = {
  number: "el-input",
  text: "el-input",
  select: "el-select",
  input: "el-input",
};
const fileList = ref([]);
const fileListCopy = ref([]);
const uploadData = ref({});
const fileData = ref({});

//文件上传相关方法
const handleSuccess = (item) => {
  if (fileData.value && fileData.value.fileUrl) {
    formData.value[item.prop].push({
      id: fileData.value.id,
      fileName: fileData.value.fileName,
      name: fileData.value.fileName,
      url: fileData.value.fileUrl,
      fileUrl: fileData.value.fileUrl,
    });
  }
  emit("update:modelValue", formData.value);
};

const handleRemove = (file, item) => {
  let index = formData.value[item.prop].findIndex(
    (x) => x.id == file.id || x.id == file.raw.id
  );
  if (index > -1) {
    formData.value[item.prop].splice(index, 1);
  }
};

const handleBeforeUpload = async (file, item) => {
  fileData.value = {};
  const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  file.id = res.id;
  file.fileUrl = res.fileUrl;
  uploadData.value = res.uploadBody;
  fileData.value = res;
  return true;
};

const handleExceed = (item) => {
  let limit = item.limit || 3;
  return proxy.msgTip(`上传文件数量不可大于${limit}`, 2);
};
const onPreviewFile = (file, a) => {
  if (file && file.fileUrl) {
    window.open(file.fileUrl, "_blank");
  } else {
    window.open(file.raw.fileUrl, "_blank");
  }
};
const imgLoading = ref(false);
const handleBeforeUploadOne = async (file, prop, imgProp) => {
  imgLoading.value = true;
  fileData.value = {};
  const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  uploadData.value = res.uploadBody;
  formData.value[prop] = [
    {
      id: res.id,
      fileName: res.fileName,
      fileUrl: res.fileUrl,
    },
  ];
  fileData.value = res;
  return true;
};
const handleSuccessOne = (imgProp) => {
  if (fileData.value && fileData.value.fileUrl) {
    formData.value[imgProp] = fileData.value.fileUrl;
    emit("update:modelValue", formData.value);
  }
  setTimeout(() => {
    imgLoading.value = false;
  }, 400);
};

const isInit = ref(false);
const { proxy } = getCurrentInstance();
const emit = defineEmits(["update:modelValue"]);
const formData = computed(() => {
  return proxy.modelValue;
});
const formDataReset = ref({ ...proxy.modelValue });
const commonsEmit = (prop, item) => {
  if (item.type == "input" && item.itemType == "number") {
    console.log(formData.value);
  }

  if (item.fn) {
    item.fn(prop);
  }
  emit("update:modelValue", formData.value);
};
const commonsEmitChange = (prop, item) => {
  if (item.type == "input") {
    formData.value[item.prop] = prop.trim();
  }
  if (item.fn) {
    item.fn(prop);
  }
  emit("update:modelValue", formData.value);
};
const loadInit = () => {
  const v = this;
  for (let i = 0; i < proxy.formConfig.length; i++) {
    const element = proxy.formConfig[i];
    if (element.isLoad) {
      commonGetdata(element.isLoad, i);
    }
  }
};
const dateFormatInit = (itemType) => {
  const formatObj = {
    year: "YYYY",
    month: "YYYY-MM",
    date: "YYYY-MM-DD",
    dates: "YYYY-MM-DD",
    datetime: "YYYY-MM-DD HH:mm:ss",
    monthrange: "YYYY-MM-DD HH:mm:ss",
    datetimerange: "YYYY-MM-DD HH:mm:ss",
    daterange: "YYYY-MM-DD HH:mm:ss",
  };
  return formatObj[itemType];
};

//公用递归,保证key,val统一
const commonRecursive = (arr, labelKey, labelVal, childrenName) => {
  for (let i = 0; i < arr.length; i++) {
    if (labelKey == "stringArray") {
      arr[i] = {
        label: arr[i],
        value: arr[i],
        id: arr[i],
        title: arr[i],
      };
    } else {
      arr[i].title = arr[i].label = arr[i][labelKey];
      arr[i].id = arr[i].value = arr[i][labelVal];
    }

    if (childrenName) {
      arr[i].children = arr[i][childrenName];
    }
    arr[i].checked = false;
    typeof arr[i][labelVal] == String
      ? (arr[i].key = arr[i][labelVal])
      : (arr[i].key = JSON.stringify(arr[i][labelVal]));
    if (childrenName) {
      this.commonRecursive(
        arr[i][childrenName],
        labelKey,
        labelVal,
        childrenName
      );
    }
  }
};

//请求form表单所需数据字典
const commonGetdata = (isLoad, i) => {
  proxy[isLoad.method](isLoad.url, isLoad.req).then((message) => {
    console.log(message);
    if (getFormat(isLoad.resUrl, message) == undefined) {
      console.log("请查看isLoad配置是否正确url:" + isLoad.url);
      return;
    }
    proxy.formConfig[i].data = getFormat(isLoad.resUrl, message);
    if (isLoad.labelKey) {
      commonRecursive(
        proxy.formConfig[i].data,
        isLoad.labelKey,
        isLoad.labelVal,
        isLoad.childrenName
      );
    }
    console.log(proxy.formConfig[i].data);
  });
};

//根据resurl获取数据
const getFormat = (formatStr, props) => {
  if (!formatStr) return props;
  return formatStr
    .split(".")
    .reduce((total, cur) => (!total ? "" : total[cur]), props);
};

//初始化所有表单

const formDataInit = () => {
  var map = {
    input: "",
    radio: null,
    select: null,
    checkbox: [],
    date: "",
    datetime: "",
    daterange: [],
    datetimerange: [],
    year: null,
    month: null,
    switch: false,
    inputNumber: 0,
    cascader: [],
    Solt: null,
    Transfer: [],
    Upload: { path: null, id: null, name: null },
    password: "",
    treeSelect: "",
    json: {},
  };
  const formDataCopy = { ...formData.value };
  for (let i = 0; i < proxy.formConfig.length; i++) {
    const element = proxy.formConfig[i];

    if (formDataCopy[element.prop] || element.type === "slot") {
      continue;
    }

    if (map[element.itemType] != undefined) {
      formData.value[element.prop] = map[element.itemType];
    } else {
      formData.value[element.prop] = element.multiple ? [] : map[element.type];
    }
  }

  emit("update:modelValue", formData.value);
};

const handleSubmit = async (onSubmit) => {
  try {
    const flag = await proxy.$refs["byForm"].validate();
    if (flag) {
      const form = { ...formData.value };
      proxy.formConfig.map((item) => {
        // if (item.type == "json") {
        //   form[item.prop] = JSON.stringify(form[item.prop]);
        // }
        // if (item.type == 'input') {
        //   form[item.prop] = form[item.prop].trim();
        // }
      });
      emit("update:modelValue", form);
      onSubmit();
      return true;
    } else {
    }
  } catch (err) {
    setTimeout(() => {
      const errorDiv = document.getElementsByClassName("is-error");
      if (errorDiv && errorDiv[0]) {
        errorDiv[0].scrollIntoView({
          behavior: "smooth",
          block: "center",
          inline: "nearest",
        });
      }
    }, 0);
    console.log("请检查表单!", err);
    return false;
  }
};
const byform = ref(null); // 延迟使用,因为还没有返回跟挂载
onMounted(() => {});
defineExpose({
  handleSubmit,
});
formDataInit();
loadInit();
</script>

<style scope>
.form-title {
  font-size: 14px;
  font-weight: bold;
  margin-top: 22px;
  color: #333333;
}
.by-form .el-form--inline .el-form-item {
  margin-right: 0px;

  box-sizing: border-box;
}
.by-form .el-form--inline > .el-form-item {
  padding: 0 10px 0 0px;
}
.by-form .el-form--inline .formTitle {
  padding: 0px !important;
}

/* .el-form--inline.el-form--label-top{
  justify-content: space-between;
} */

.dn {
  display: none !important;
}
/* .by-form-json .by-form .el-form .el-form-item {
  margin-bottom: 18px;
} */

/* .by-form-json {
  padding: 0px !important;
} */

.picOne {
  object-fit: contain;
  width: 80px;
  height: 80px;
  cursor: pointer;
  vertical-align: middle;
}
.el-icon.avatar-uploader-icon {
  font-size: 20px;
  color: #8c939d;
  width: 80px;
  height: 80px;
  text-align: center;
  border: 1px dashed var(--el-border-color);
}
</style>