<template>
  <div id="c-form">
    <el-row type="flex" justify="space-around">
      <el-col :span="span">
        <el-form ref="formRef" :model="form" :rules="rules" :label-width="labelWidth" class="form" @submit.prevent>
          <template v-for="(item, index) in fields">
            <el-form-item v-if="display(item)" :key="'form-field-' + index" :label="getField('label', item)" :prop="item.model" :required="item.required">
              <template v-if="!item.custom">
                <template v-if="item.type === 'textarea'">
                  <el-input
                    clearable
                    v-model="form[item.model]"
                    :type="item.type"
                    :placeholder="getField('placeholder', item)"
                    v-bind="item.options"
                    @change="dataChange(item.model)"
                    show-word-limit
                    :disabled="item.readonly"
                  ></el-input>
                </template>
                <template v-else-if="item.type === 'numbers'">
                  <el-input-number
                    v-model="form[item.model]"
                    :placeholder="getField('placeholder', item)"
                    @change="dataChange(item.model)"
                    style="width: 100%"
                    :disabled="item.readonly"
                  />
                </template>
                <template v-else-if="item.type === 'radio'">
                  <el-radio-group v-model="form[item.model]" :type="item.type" v-bind="item.options" @change="dataChange(item.model)" :disabled="item.readonly">
                    <slot :name="item.model" v-bind="{ item }"></slot>
                  </el-radio-group>
                </template>
                <template v-else-if="item.type === 'checkbox'">
                  <el-checkbox-group v-model="form[item.model]" :type="item.type" v-bind="item.options" :disabled="item.readonly">
                    <slot :name="item.model" v-bind="{ item }"></slot>
                  </el-checkbox-group>
                </template>
                <template v-else-if="item.type === 'select'">
                  <el-select
                    clearable
                    filterable
                    v-model="form[item.model]"
                    :type="item.type"
                    :placeholder="getField('selectplaceholder', item)"
                    v-bind="item.options"
                    @change="dataChange(item.model)"
                    style="width: 100%"
                    :disabled="item.readonly"
                  >
                    <slot :name="item.model" v-bind="{ item }"></slot>
                  </el-select>
                </template>
                <template v-else-if="item.type === 'selectMany'">
                  <el-select
                    filterable
                    clearable
                    multiple
                    collapse-tags
                    v-model="form[item.model]"
                    :type="item.type"
                    :placeholder="getField('selectplaceholder', item)"
                    v-bind="item.options"
                    @change="dataChange(item.model)"
                    style="width: 100%"
                    :disabled="item.readonly"
                  >
                    <slot :name="item.model" v-bind="{ item }"></slot>
                  </el-select>
                </template>
                <template
                  v-else-if="
                    item.type === `year` ||
                    item.type == 'month' ||
                    item.type == 'date' ||
                    item.type == 'daterange' ||
                    item.type == 'datetime' ||
                    item.type == 'datetimerange'
                  "
                >
                  <el-date-picker
                    v-model="form[item.model]"
                    :type="item.type"
                    :placeholder="getField('selectplaceholder', item)"
                    :format="getDateFormat(item.type)"
                    :value-format="getDateFormat(item.type)"
                    v-bind="item.options"
                    @change="dataChange(item.model)"
                    range-separator="至"
                    style="width: 100%"
                    :disabled="item.readonly"
                  >
                  </el-date-picker>
                </template>
                <template v-else-if="item.type === `time`">
                  <el-time-picker
                    v-model="form[item.model]"
                    :placeholder="getField('selectplaceholder', item)"
                    :format="getDateFormat(item.type)"
                    :value-format="getDateFormat(item.type)"
                    v-bind="item.options"
                    @change="dataChange(item.model)"
                    style="width: 100%"
                    :disabled="item.readonly"
                  >
                  </el-time-picker>
                </template>
                <template v-else>
                  <el-input
                    clearable
                    v-model="form[item.model]"
                    :type="getField('type', item)"
                    :placeholder="getField('placeholder', item)"
                    :show-password="getField('type', item) === 'password'"
                    v-bind="item.options"
                    @change="dataChange(item.model)"
                    :disabled="item.readonly"
                  ></el-input>
                </template>
              </template>
              <template v-else>
                <slot :name="item.model" v-bind="{ item }"></slot>
              </template>
            </el-form-item>
          </template>
          <el-col :span="24" label="" class="btn" v-if="isSave">
            <slot name="submit">
              <el-button type="primary" @click="save(formRef)">{{ submitText }}</el-button>
            </slot>
          </el-col>
        </el-form>
      </el-col>
    </el-row>
  </div>
</template>

<script setup lang="ts">
import { ref, toRefs } from 'vue';
import type { FormInstance } from 'element-plus';
import _ from 'lodash';
// #region 传递
interface fieldsItem {
  model: string;
  type: string;
  readonly: string;
  options: object;
  custom: string;
  required: string;
  limit: number | undefined;
  url: string;
}
const props = defineProps({
  fields: { type: Array<fieldsItem>, default: () => [{ readonly: false }] },
  rules: { type: Object, default: () => {} },
  labelWidth: { type: String, default: '120px' },
  submitText: { type: String, default: '保存' },
  form: { type: Object, default: () => {} },
  reset: { type: Boolean, default: false },
  isSave: { type: Boolean, default: true },
  span: { type: Number, default: 24 }, // 限制两侧的距离,24就是整行全用
});
const { fields } = toRefs(props);
const { rules } = toRefs(props);
const { labelWidth } = toRefs(props);
const { submitText } = toRefs(props);
const { form } = toRefs(props);
const { reset } = toRefs(props);
const { isSave } = toRefs(props);
const { span } = toRefs(props);
const formRef = ref<FormInstance>();
const getField = (item: string, data: any) => {
  let res: string | null | boolean = _.get(data, item, null);
  if (item === 'type') res = res === null ? `text` : res;
  if (item === 'placeholder') res = res === null ? `请输入${data.label}` : res;
  if (item === `selectplaceholder`) res = res === null ? `请选择${data.label}` : res;
  if (item === 'required') res = res === null ? false : res;
  if (item === `error`) res = res === null ? `${data.label}错误` : res;
  return res;
};

const getDateFormat = (e: string) => {
  if (e === 'year') return 'YYYY';
  if (e === 'month') return 'MM';
  if (e === 'date') return 'YYYY-MM-DD';
  if (e === 'daterange') return 'YYYY-MM-DD';
  if (e === 'datetime') return 'YYYY-MM-DD HH:mm:ss';
  if (e === 'datetimerange') return 'YYYY-MM-DD HH:mm:ss';
  if (e === 'time') return 'HH:mm:ss';
};
const emit = defineEmits(['save', 'dataChange']);
const clear = ref<any>();
// 提交
const save = async (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  await formEl.validate((valid, fields) => {
    if (valid) {
      emit('save', form.value);
      if (reset.value) clear.value.resetFields();
    } else {
      console.log('error submit!', fields);
    }
  });
};
const display = (field: any) => {
  let dis = _.get(field, `display`);
  if (!_.isFunction(dis)) return true;
  else return dis(field, form);
};
const dataChange = (model: string) => {
  const value = form.value[model];
  emit('dataChange', { model, value });
};
</script>

<style scoped>
.btn {
  text-align: center;
}
</style>
