<template>
  <div class="by-form">
    <el-form
      :model="formData"
      :label-width="formOption.labelWidth"
      :inline="formOption.inline || false"
      :rules="rules"
      :labelPosition="formOption.labelPosition || 'top'"
      ref="byForm"
      :disabled="formOption.disabled || false"
    >
      <el-form-item
        :label="i.label"
        v-for="i in formConfig"
        :key="i.model"
        :prop="i.prop"
        v-show="i.isShow || i.isShow == undefined"
        :style="
          i.type == 'title'
            ? 'width:100%'
            : i.itemWidth
            ? 'width:' + i.itemWidth + '%'
            : formOption.itemWidth
            ? 'width:' + formOption.itemWidth + '%'
            : '100%'
        "
        :class="i.type == 'json' ? i.isHide ? 'by-form-json dn' : 'by-form-json' : i.isHide ? 'dn' : ''"
      >
        <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.disabled ? i.disabled : false"
              :readonly="i.readonly ? i.readonly : false"
              style="width: 80px"
            >
              <el-option
                :label="j.title || j.name || j.label"
                :value="j.id || j.value"
                v-for="j in i.data"
                :key="j.id"
              >
              </el-option>
            </el-select>
          </template>
        </el-input>
        <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 : false"
          :style="i.style"
          :readonly="i.readonly ? i.readonly : false"
        >
          <el-option
            :label="j.title || j.name || j.label"
            :value="j.id || j.value"
            v-for="j in i.data"
            :key="j.id"
          >
          </el-option>
        </el-select>
        <el-tree-select
          v-model="formData[i.prop]"
          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',
          }"
          value-key="id"
          :placeholder="i.placeholder || $t('common.pleaseSelect')"
          :disabled="i.disabled ? i.disabled : false"
          check-strictly
          :style="i.style"
        />
        <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)"
        />
        <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"
        >
          <el-radio
            :border="i.border ? i.border : false"
            v-for="j in i.data"
            :key="j.id || j.value"
            :label="j.id || j.value"
            name="type"
          >
            {{ 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"
          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>
        <slot :name="i.slotName" v-else-if="i.type == 'slot'">
          {{ i.slotName }}插槽占位符
        </slot>
        <div class="upload" v-else-if="i.type == 'upload'">
          <el-upload
            v-model="formData[i.prop]"
            action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
            :data="uploadData"
            list-type="picture-card"
            :on-remove="handleRemove"
            :on-success="handleSuccess"
            :before-upload="handleBeforeUpload"
          >
            <!-- <el-icon class="el-icon--upload"><upload-filled /></el-icon> -->
            <el-icon><Plus /></el-icon>
          </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>
    </el-form>
  </div>
</template>
<script>
export default {
  name: "byForm",
};
</script>
<script  setup>
import { set } from "@vueuse/shared";
import { reactive } from "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 handleSuccess = (res, file, files) => {
  emit("update:modelValue", formData.value);
};

const handleRemove = (file) => {
  const index = fileListCopy.value.findIndex(
    (x) => x.uid === file.uid || x.id === file.id
  );
  fileListCopy.value.splice(index, 1);
};

const handleBeforeUpload = async (file) => {
  const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  uploadData.value = res.uploadBody;
  fileListCopy.value.push({
    id: res.id,
    fileName: res.fileName,
    path: res.fileUrl,
    url: res.fileUrl,
    uid: file.uid,
  });
};

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 HH:mm:ss",
    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;
    }
  } catch (err) {
    console.log("请检查表单！", err);
    return false;
  }
};
const byform = ref(null); // 延迟使用，因为还没有返回跟挂载
onMounted(() => {});
defineExpose({
  handleSubmit,
});
formDataInit();
loadInit();
</script>

<style>
.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;
}

/* .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;
}
</style>