<template>
	<div class="query-form">
		<el-form ref="formRef" :model="modelValue" :label-width="labelWidth" :inline="inline">
			<el-row :gutter="gutter">
				<template v-for="(item, index) in fields" :key="item.prop">
					<div class="form-item-wrapper" v-show="showAll || index < defaultFieldCount">
						<el-form-item :label="item.label" :prop="item.prop" :rules="item.rules">
							<!-- 插槽优先 -->
							<slot :name="item.prop" :item="item" :form="modelValue">
								<!-- 动态组件渲染 -->
								<component
									:is="getComponent(item.type)"
									v-model="modelValue[item.prop]"
									v-bind="getProps(item)"
									@keyup.enter="item.type === 'input' && handleSearch()"
								>
									<!-- 下拉选项 -->
									<template v-if="item.type === 'select'" #default>
										<el-option
											v-for="opt in item.options || []"
											:key="opt.value"
											:label="opt.label"
											:value="opt.value"
										/>
									</template>
								</component>
							</slot>
						</el-form-item>
					</div>
				</template>

				<!-- 操作按钮 -->
				<div class="form-item-wrapper actions">
					<el-form-item>
						<slot name="actions">
							<el-button type="primary" :icon="Search" size="default" @click="handleSearch">
								搜索
							</el-button>
							<el-button :icon="Refresh" size="default" @click="handleReset">重置</el-button>
							<el-button link v-if="fields.length > defaultFieldCount" @click="toggleSearch">
								{{ word }}
								<el-icon>
									<ele-ArrowUp v-if="showAll" />
									<ele-ArrowDown v-else />
								</el-icon>
							</el-button>
						</slot>
					</el-form-item>
				</div>
			</el-row>
		</el-form>
	</div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue';
import { Search, Refresh } from '@element-plus/icons-vue';
import type { FormInstance } from 'element-plus';
import { QueryFormField } from '../type';
interface Props {
	fields: QueryFormField[];
	modelValue: Record<string, any>; // 双向绑定
	defaultFieldCount?: number;
	labelWidth?: string;
	inline?: boolean;
	gutter?: number;
}

const props = withDefaults(defineProps<Props>(), {
	fields: () => [] as QueryFormField[],
	modelValue: () => ({}),
	defaultFieldCount: 3,
	labelWidth: '100px',
	inline: true,
	gutter: 20,
});
defineOptions({ name: 'QueryForm' });

const emit = defineEmits<{
	(e: 'update:modelValue', val: Record<string, any>): void;
	(e: 'search', val: Record<string, any>): void;
	(e: 'reset'): void;
}>();

const formRef = ref<FormInstance>();
const showAll = ref(false);
const toggleSearch = () => (showAll.value = !showAll.value);

const word = computed(() => (showAll.value ? '收起搜索' : '展开搜索'));

const dates = ['daterange', 'datetimerange'];

/**
 * 初始化表单
 */
const initForm = () => {
	const form: Record<string, any> = {};
	props.fields.forEach((item) => {
		form[item.prop] = item.defaultValue ?? '';
	});
	return form;
};

/**
 * 更新父组件的值
 */
const updateModel = (val: Record<string, any>) => {
	emit('update:modelValue', val);
};

/**
 * 动态组件映射
 */
const componentMap: Record<string, any> = {
	input: 'el-input',
	select: 'el-select',
	daterange: 'el-date-picker',
	datetimerange: 'el-date-picker',
};

const getComponent = (type: string) => componentMap[type] || 'el-input';

/**
 * 获取组件属性
 */
const getProps = (item: QueryFormField) => {
	const commonProps = {
		size: item.size || 'default',
		placeholder: item.placeholder || '请输入',
	};
	if (item.type === 'select') {
		return { ...commonProps, filterable: true };
	}
	if (dates.includes(item.type)) {
		return {
			...commonProps,
			type: item.type,
			'value-format': item.valueFormat || 'YYYY-MM-DD',
			'range-separator': '至',
			'start-placeholder': item.staerPlaceholder || '开始日期',
			'end-placeholder': item.endPlaceholder || '结束日期',
			style: { width: '220px' },
		};
	}
	return commonProps;
};

const loadOptions = async () => {
	let oldFetchOptions:any = [];
	for (const field of props.fields) {
		if (field.fetchOptions) {
			if (!oldFetchOptions.includes(field.fetchOptions)) {
				field.options = await field.fetchOptions();
				oldFetchOptions.push(field.fetchOptions);
			}
		}
	}
};

onMounted(() => {
	loadOptions();
});

/**
 * 搜索事件（防抖）
 */
const handleSearch = () => emit('search', props.modelValue);

/**
 * 重置事件
 */
const handleReset = () => {
	const newForm = initForm();
	updateModel(newForm);
	emit('reset');
};

/**
 * 监听字段变化，保持双向绑定
 */
watch(
	() => props.modelValue,
	(val) => updateModel(val),
	{ deep: true }
);
</script>

<style scoped>
.form-item-wrapper {
	display: block;
}
.query-form {
	padding-bottom: 10px;
}
.actions {
	display: flex;
	align-items: center;
}
</style>
