<template>
  <div class="config-form">
    <el-form
      ref="formRef"
      :model="formData"
      :rules="formRules"
      :label-width="config.labelWidth || '120px'"
      :label-position="config.labelPosition || 'right'"
      :inline="config.inline || false"
      :disabled="config.disabled || false"
      :size="config.size || 'default'"
    >
      <el-row :gutter="config.gutter || 20">
        <el-col
          v-for="(item, index) in formItems"
          :key="item.prop || index"
          :span="item.span || 24"
          :offset="item.offset || 0"
          :xs="item.xs"
          :sm="item.sm"
          :md="item.md"
          :lg="item.lg"
          :xl="item.xl"
        >
          <el-form-item
            :label="item.label"
            :prop="item.prop"
            :required="item.required"
            :error="item.error"
            :show-message="item.showMessage !== false"
          >
            <!-- 输入框 -->
            <el-input
              v-if="item.type === 'input'"
              v-model="formData[item.prop]"
              :placeholder="item.placeholder || `请输入${item.label}`"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :readonly="item.readonly"
              :maxlength="item.maxlength"
              :show-word-limit="item.showWordLimit"
              :type="item.inputType || 'text'"
              :rows="item.rows"
              :autosize="item.autosize"
              @blur="handleBlur(item, $event)"
              @focus="handleFocus(item, $event)"
              @input="handleInput(item, $event)"
              @change="handleChange(item, $event)"
            >
              <template v-if="item.prepend" #prepend>{{
                item.prepend
              }}</template>
              <template v-if="item.append" #append>{{ item.append }}</template>
              <template v-if="item.prefix" #prefix>
                <el-icon><component :is="item.prefix" /></el-icon>
              </template>
              <template v-if="item.suffix" #suffix>
                <el-icon><component :is="item.suffix" /></el-icon>
              </template>
            </el-input>

            <!-- 文本域 -->
            <el-input
              v-else-if="item.type === 'textarea'"
              v-model="formData[item.prop]"
              type="textarea"
              :placeholder="item.placeholder || `请输入${item.label}`"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :readonly="item.readonly"
              :maxlength="item.maxlength"
              :show-word-limit="item.showWordLimit"
              :rows="item.rows || 3"
              :autosize="item.autosize"
              @blur="handleBlur(item, $event)"
              @focus="handleFocus(item, $event)"
              @input="handleInput(item, $event)"
              @change="handleChange(item, $event)"
            />

            <!-- 选择器 -->
            <el-select
              v-else-if="item.type === 'select'"
              v-model="formData[item.prop]"
              :placeholder="item.placeholder || `请选择${item.label}`"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :multiple="item.multiple"
              :filterable="item.filterable"
              :remote="item.remote"
              :remote-method="item.remoteMethod"
              :loading="item.loading"
              :no-match-text="item.noMatchText"
              :no-data-text="item.noDataText"
              @change="handleChange(item, $event)"
              @visible-change="handleVisibleChange(item, $event)"
              @remove-tag="handleRemoveTag(item, $event)"
              @clear="handleClear(item)"
            >
              <el-option
                v-for="option in item.options"
                :key="option.value"
                :label="option.label"
                :value="option.value"
                :disabled="option.disabled"
              >
                <span v-if="option.icon" style="margin-right: 8px">
                  <el-icon><component :is="option.icon" /></el-icon>
                </span>
                {{ option.label }}
              </el-option>
            </el-select>

            <!-- 单选框组 -->
            <el-radio-group
              v-else-if="item.type === 'radio'"
              v-model="formData[item.prop]"
              :disabled="item.disabled"
              :size="item.size"
              @change="handleChange(item, $event)"
            >
              <el-radio
                v-for="option in item.options"
                :key="option.value"
                :label="option.value"
                :disabled="option.disabled"
                :border="item.border"
              >
                {{ option.label }}
              </el-radio>
            </el-radio-group>

            <!-- 复选框组 -->
            <el-checkbox-group
              v-else-if="item.type === 'checkbox'"
              v-model="formData[item.prop]"
              :disabled="item.disabled"
              :size="item.size"
              :min="item.min"
              :max="item.max"
              @change="handleChange(item, $event)"
            >
              <el-checkbox
                v-for="option in item.options"
                :key="option.value"
                :label="option.value"
                :disabled="option.disabled"
                :border="item.border"
              >
                {{ option.label }}
              </el-checkbox>
            </el-checkbox-group>

            <!-- 日期选择器 -->
            <el-date-picker
              v-else-if="item.type === 'date'"
              v-model="formData[item.prop]"
              :type="item.dateType || 'date'"
              :placeholder="item.placeholder || `请选择${item.label}`"
              :format="item.format"
              :value-format="item.valueFormat"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :readonly="item.readonly"
              :editable="item.editable"
              :start-placeholder="item.startPlaceholder"
              :end-placeholder="item.endPlaceholder"
              :range-separator="item.rangeSeparator"
              :disabled-date="item.disabledDate"
              @change="handleChange(item, $event)"
              @blur="handleBlur(item, $event)"
              @focus="handleFocus(item, $event)"
            />

            <!-- 时间选择器 -->
            <el-time-picker
              v-else-if="item.type === 'time'"
              v-model="formData[item.prop]"
              :placeholder="item.placeholder || `请选择${item.label}`"
              :format="item.format"
              :value-format="item.valueFormat"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :readonly="item.readonly"
              :editable="item.editable"
              @change="handleChange(item, $event)"
              @blur="handleBlur(item, $event)"
              @focus="handleFocus(item, $event)"
            />

            <!-- 数字输入框 -->
            <el-input-number
              v-else-if="item.type === 'number'"
              v-model="formData[item.prop]"
              :min="item.min"
              :max="item.max"
              :step="item.step || 1"
              :step-strictly="item.stepStrictly"
              :precision="item.precision"
              :size="item.size"
              :disabled="item.disabled"
              :controls="item.controls !== false"
              :controls-position="item.controlsPosition"
              :name="item.name"
              @change="handleChange(item, $event)"
              @focus="handleFocus(item, $event)"
              @blur="handleBlur(item, $event)"
            />

            <!-- 开关 -->
            <el-switch
              v-else-if="item.type === 'switch'"
              v-model="formData[item.prop]"
              :disabled="item.disabled"
              :loading="item.loading"
              :size="item.size"
              :active-text="item.activeText"
              :inactive-text="item.inactiveText"
              :active-value="item.activeValue"
              :inactive-value="item.inactiveValue"
              @change="handleChange(item, $event)"
            />

            <!-- 滑块 -->
            <el-slider
              v-else-if="item.type === 'slider'"
              v-model="formData[item.prop]"
              :min="item.min || 0"
              :max="item.max || 100"
              :step="item.step || 1"
              :show-stops="item.showStops"
              :show-tooltip="item.showTooltip !== false"
              :disabled="item.disabled"
              :range="item.range"
              :vertical="item.vertical"
              :height="item.height"
              @change="handleChange(item, $event)"
            />

            <!-- 评分 -->
            <el-rate
              v-else-if="item.type === 'rate'"
              v-model="formData[item.prop]"
              :max="item.max || 5"
              :disabled="item.disabled"
              :allow-half="item.allowHalf"
              :low-threshold="item.lowThreshold"
              :high-threshold="item.highThreshold"
              :colors="item.colors"
              :void-color="item.voidColor"
              :disabled-void-color="item.disabledVoidColor"
              :icon-classes="item.iconClasses"
              :void-icon-class="item.voidIconClass"
              :disabled-void-icon-class="item.disabledVoidIconClass"
              :show-text="item.showText"
              :show-score="item.showScore"
              :texts="item.texts"
              @change="handleChange(item, $event)"
            />

            <!-- 颜色选择器 -->
            <el-color-picker
              v-else-if="item.type === 'color'"
              v-model="formData[item.prop]"
              :disabled="item.disabled"
              :size="item.size"
              :show-alpha="item.showAlpha"
              :color-format="item.colorFormat"
              :predefine="item.predefine"
              @change="handleChange(item, $event)"
              @active-change="handleActiveChange(item, $event)"
            />

            <!-- 树形选择器 -->
            <el-tree-select
              v-else-if="item.type === 'tree'"
              v-model="formData[item.prop]"
              :data="item.data"
              :props="
                item.props || {
                  label: 'name',
                  value: 'id',
                  children: 'children',
                }
              "
              :placeholder="item.placeholder || `请选择${item.label}`"
              :clearable="item.clearable !== false"
              :disabled="item.disabled"
              :filterable="item.filterable"
              :check-strictly="item.checkStrictly"
              :render-after-expand="item.renderAfterExpand !== false"
              :show-checkbox="item.showCheckbox"
              :multiple="item.multiple"
              :collapse-tags="item.collapseTags"
              :max-collapse-tags="item.maxCollapseTags"
              :node-key="item.nodeKey"
              :default-expanded-keys="item.defaultExpandedKeys"
              :default-checked-keys="item.defaultCheckedKeys"
              :current-node-key="item.currentNodeKey"
              :expand-on-click-node="item.expandOnClickNode !== false"
              :check-on-click-node="item.checkOnClickNode"
              :auto-expand-parent="item.autoExpandParent !== false"
              :default-expand-all="item.defaultExpandAll"
              :indent="item.indent"
              :icon="item.icon"
              :lazy="item.lazy"
              :load="item.load"
              :highlight-current="item.highlightCurrent"
              @change="handleChange(item, $event)"
              @node-click="handleNodeClick(item, $event)"
              @check="handleCheck(item, $event)"
              @node-expand="handleNodeExpand(item, $event)"
              @node-collapse="handleNodeCollapse(item, $event)"
            />

            <!-- 上传 -->
            <el-upload
              v-else-if="item.type === 'upload'"
              :action="item.action"
              :headers="item.headers"
              :method="item.method"
              :multiple="item.multiple"
              :data="item.data"
              :name="item.name"
              :with-credentials="item.withCredentials"
              :show-file-list="item.showFileList !== false"
              :drag="item.drag"
              :accept="item.accept"
              :auto-upload="item.autoUpload !== false"
              :limit="item.limit"
              :on-exceed="item.onExceed"
              :on-success="
                (response, file, fileList) =>
                  handleUploadSuccess(item, response, file, fileList)
              "
              :on-error="
                (error, file, fileList) =>
                  handleUploadError(item, error, file, fileList)
              "
              :on-progress="
                (event, file, fileList) =>
                  handleUploadProgress(item, event, file, fileList)
              "
              :on-change="
                (file, fileList) => handleUploadChange(item, file, fileList)
              "
              :on-remove="
                (file, fileList) => handleUploadRemove(item, file, fileList)
              "
              :on-preview="item.onPreview"
              :before-upload="item.beforeUpload"
              :before-remove="item.beforeRemove"
              :http-request="item.httpRequest"
            >
              <el-button v-if="!item.drag" type="primary">{{
                item.buttonText || "点击上传"
              }}</el-button>
              <div v-else class="upload-dragger">
                <el-icon class="el-icon--upload"><upload-filled /></el-icon>
                <div class="el-upload__text">
                  将文件拖到此处，或<em>点击上传</em>
                </div>
              </div>
              <template v-if="item.tip" #tip>
                <div class="el-upload__tip">{{ item.tip }}</div>
              </template>
            </el-upload>

            <!-- 自定义插槽 -->
            <slot
              v-else-if="item.type === 'slot'"
              :name="item.slotName || item.prop"
              :prop="item.prop"
              :item="item"
              :value="formData[item.prop]"
              :onChange="(value) => handleSlotChange(item, value)"
            />

            <!-- 纯文本显示 -->
            <span v-else-if="item.type === 'text'">{{
              formData[item.prop]
            }}</span>

            <!-- 自定义组件 -->
            <component
              v-else-if="item.type === 'component' && item.component"
              :is="item.component"
              v-model="formData[item.prop]"
              v-bind="item.componentProps"
              @change="handleChange(item, $event)"
            />
          </el-form-item>
        </el-col>
        <!-- 表单操作按钮 -->
        <el-col :span="24">
          <el-form-item
            v-if="config.showButtons !== false"
            class="form-buttons"
          >
            <el-button
              v-if="config.showSubmit !== false"
              type="primary"
              :loading="config.submitLoading"
              @click="handleSubmit"
            >
              {{ config.submitText || "提交" }}
            </el-button>
            <el-button
              v-for="btn in config.customButtons"
              :key="btn.key"
              :type="btn.type"
              :loading="btn.loading"
              @click="btn.handler"
            >
              {{ btn.text }}
            </el-button>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
  </div>
</template>

<script setup>
import { ref, reactive, computed, watch, onMounted } from "vue";
import { UploadFilled } from "@element-plus/icons-vue";

const props = defineProps({
  // 表单配置
  config: {
    type: Object,
    default: () => ({}),
  },
  // 表单项配置
  items: {
    type: Array,
    default: () => [],
  },
  // 表单数据
  modelValue: {
    type: Object,
    default: () => ({}),
  },
  // 表单规则
  rules: {
    type: Object,
    default: () => ({}),
  },
});

const emit = defineEmits([
  "update:modelValue",
  "submit",
  "reset",
  "change",
  "blur",
  "focus",
  "input",
  "validate",
]);

const formRef = ref();
const formData = reactive({});

// 表单项配置
const formItems = computed(() => props.items);

// 表单验证规则
const formRules = computed(() => {
  const rules = { ...props.rules };
  formItems.value.forEach((item) => {
    if (item.rules) {
      rules[item.prop] = item.rules;
    }
  });
  return rules;
});

// 初始化表单数据
const initFormData = () => {
  Object.keys(formData).forEach((key) => {
    delete formData[key];
  });
  formItems.value.forEach((item) => {
    if (item.prop) {
      if (props.modelValue[item.prop] !== undefined) {
        formData[item.prop] = props.modelValue[item.prop];
      } else {
        formData[item.prop] =
          item.defaultValue !== undefined
            ? item.defaultValue
            : getDefaultValue(item.type);
      }
    }
  });
};

// 获取不同类型的默认值
const getDefaultValue = (type) => {
  switch (type) {
    case "checkbox":
      return [];
    case "switch":
      return false;
    case "number":
      return 0;
    case "rate":
      return 0;
    default:
      return "";
  }
};

// 监听表单数据变化
watch(
  formData,
  (newVal) => {
    emit("update:modelValue", { ...newVal });
    emit("change", newVal);
  },
  { deep: true },
);

// 监听外部数据变化
watch(
  () => props.modelValue,
  (newVal) => {
    Object.keys(newVal).forEach((key) => {
      if (formData.hasOwnProperty(key)) {
        formData[key] = newVal[key];
      }
    });
  },
  { deep: true },
);

// 事件处理
const handleInput = (item, value) => {
  emit("input", item.prop, value);
};

const handleChange = (item, value) => {
  emit("change", item.prop, value);
};

const handleBlur = (item, event) => {
  emit("blur", item.prop, event);
};

const handleFocus = (item, event) => {
  emit("focus", item.prop, event);
};

const handleVisibleChange = (item, visible) => {
  emit("visible-change", item.prop, visible);
};

const handleRemoveTag = (item, tag) => {
  emit("remove-tag", item.prop, tag);
};

const handleClear = (item) => {
  emit("clear", item.prop);
};

const handleActiveChange = (item, color) => {
  emit("active-change", item.prop, color);
};

const handleSlotChange = (item, value) => {
  formData[item.prop] = value;
  emit("change", item.prop, value);
};

// 树形选择器事件处理
const handleNodeClick = (item, data) => {
  emit("node-click", item.prop, data);
};

const handleCheck = (item, data) => {
  emit("check", item.prop, data);
};

const handleNodeExpand = (item, data) => {
  emit("node-expand", item.prop, data);
};

const handleNodeCollapse = (item, data) => {
  emit("node-collapse", item.prop, data);
};

// 上传事件处理
const handleUploadSuccess = (item, response, file, fileList) => {
  if (item.onSuccess) {
    item.onSuccess(response, file, fileList);
  }
  emit("upload-success", item.prop, response, file, fileList);
};

const handleUploadError = (item, error, file, fileList) => {
  if (item.onError) {
    item.onError(error, file, fileList);
  }
  emit("upload-error", item.prop, error, file, fileList);
};

const handleUploadProgress = (item, event, file, fileList) => {
  if (item.onProgress) {
    item.onProgress(event, file, fileList);
  }
  emit("upload-progress", item.prop, event, file, fileList);
};

const handleUploadChange = (item, file, fileList) => {
  if (item.onChange) {
    item.onChange(file, fileList);
  }
  emit("upload-change", item.prop, file, fileList);
};

const handleUploadRemove = (item, file, fileList) => {
  if (item.onRemove) {
    item.onRemove(file, fileList);
  }
  emit("upload-remove", item.prop, file, fileList);
};

// 表单提交
const handleSubmit = async () => {
  try {
    const valid = await formRef.value.validate();
    if (valid) {
      emit("submit", { ...formData });
    }
  } catch (error) {
    emit("validate", false, error);
  }
};

// 表单重置
const handleReset = () => {
  formRef.value.resetFields();
  emit("reset");
};

// 表单验证
const validate = async () => {
  try {
    const valid = await formRef.value.validate();
    emit("validate", true);
    return valid;
  } catch (error) {
    emit("validate", false, error);
    return false;
  }
};

// 验证指定字段
const validateField = async (prop) => {
  try {
    await formRef.value.validateField(prop);
    return true;
  } catch (error) {
    return false;
  }
};

// 清除验证
const clearValidate = (props) => {
  formRef.value.clearValidate(props);
};

// 暴露方法
defineExpose({
  validate,
  validateField,
  clearValidate,
  resetFields: handleReset,
  formRef,
});

onMounted(() => {
  initFormData();
});
</script>

<style lang="less" scoped>
.config-form {
  .upload-dragger {
    text-align: center;
  }

  :deep(.el-form-item__label) {
    font-weight: 500;
  }

  :deep(.el-form-item) {
    margin-bottom: 18px;
  }

  .form-buttons {
    :deep(.el-form-item__content) {
      display: flex;
      justify-content: flex-end;
      gap: 10px;
    }
  }

  :deep(.el-input-number) {
    width: 100%;
  }

  :deep(.el-select) {
    width: 100%;
  }

  :deep(.el-date-editor) {
    width: 100%;
  }

  :deep(.el-time-picker) {
    width: 100%;
  }
  :deep(.el-form-item) {
    &:last-child {
      .el-form-item__content {
        // justify-content: flex-end;
      }
    }
  }
  :deep(.el-form--inline .el-form-item) {
    display: flex;
  }
}
</style>
