foreign-admin-ui/src/components/common/Form.vue

128 lines
6.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-bind="$attrs">
<!-- 动态表单项 -->
<el-row :gutter="props.rowGutter || 0">
<template v-for="(item, index) in formItems" :key="index">
<el-col :span="props.colSpan || 24">
<el-form-item :label="item.label" :prop="item.prop" :required="item.required" :label-position="item.labelPosition || 'left'"
:label-width="item.labelWidth || '100px'" :class="item.class">
<!-- 输入框 -->
<el-input v-if="item.type === 'input'" v-model="formData[item.prop]"
:placeholder="item.placeholder" :disabled="item.disabled" clearable />
<!-- 密码输入框 -->
<el-input v-else-if="item.type === 'password'" v-model="formData[item.prop]"
:placeholder="item.placeholder" :disabled="item.disabled" clearable show-password type="password" />
<!-- 下拉选择框 -->
<el-select v-else-if="item.type === 'select'" v-model="formData[item.prop]"
:placeholder="item.placeholder" :disabled="item.disabled" clearable style="width: 100%"
@change="handleItemChange(item.prop, formData[item.prop])">
<el-option v-for="option in props.optionsMap?.[item.prop] || []" :key="option.value"
:label="option.label" :value="option.value">
<template v-if="option.icon" #label>
<span style="display: flex; align-items: center; gap: 8px;">
<el-icon v-if="option.icon">
<component :is="option.icon" />
</el-icon>
<span>{{ option.label }}</span>
</span>
</template>
</el-option>
</el-select>
<!-- 数字输入框 -->
<el-input-number v-else-if="item.type === 'number'" v-model="formData[item.prop]"
:min="item.min" :max="item.max" :placeholder="item.placeholder" :disabled="item.disabled"
style="width: 100%" />
<!-- 单选框组 -->
<el-radio-group v-else-if="item.type === 'radio'" v-model="formData[item.prop]">
<el-radio v-for="option in props.optionsMap?.[item.prop] || []" :key="option.value"
:value="option.value">
{{ option.label }}
</el-radio>
</el-radio-group>
<!-- 复选框组 -->
<el-checkbox-group v-else-if="item.type === 'checkbox'" v-model="formData[item.prop]">
<el-checkbox v-for="option in props.optionsMap?.[item.prop] || []" :key="option.value"
:value="option.value">
{{ option.label }}
</el-checkbox>
</el-checkbox-group>
<el-switch v-else-if="item.type === 'switch'" v-model="formData[item.prop]" :active-value="1"
:inactive-value="2" />
<!-- 日期选择器(单个/范围) -->
<el-date-picker v-else-if="item.type === 'date'" v-model="formData[item.prop]"
:type="item.dateType || 'date'" :range-separator="item.rangeSeparator || '至'"
:start-placeholder="item.startPlaceholder || '开始时间'"
:end-placeholder="item.endPlaceholder || '结束时间'"
:value-format="item.valueFormat || 'YYYY-MM-DD'" :clearable="item.clearable ?? true"
:disabled-date="item.disabledDate" :locale="'zhCn'" />
<!-- 时间选择器(单个/范围) -->
<el-time-picker v-else-if="item.type === 'time'" v-model="formData[item.prop]"
:range-separator="item.rangeSeparator || '至'"
:start-placeholder="item.startPlaceholder || '开始时间'"
:end-placeholder="item.endPlaceholder || '结束时间'"
:value-format="item.valueFormat || 'HH:mm:ss'" is-range />
<!-- 自定义插槽 -->
<slot v-else :name="item.slotName" :formData="formData" />
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
</template>
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import type { Component } from 'vue'
interface FormItem {
type: 'input' | 'select' | 'number' | 'radio' | 'slot' | 'checkbox' | 'date' | 'switch' | 'edit' | 'password' | 'time' | 'upload'
label: string
prop: string
placeholder?: string
required?: boolean
disabled?: boolean
min?: number
max?: number
slotName?: string // 自定义插槽名称
labelPosition?: 'left' | 'right' | 'top'
labelWidth?: string
class?: string
dateType?: 'date' | 'daterange' | 'monthrange' | 'yearrange' | 'datetimerange'
timeType?: 'time' | 'timerange'
rangeSeparator?: string
startPlaceholder?: string
endPlaceholder?: string
valueFormat?: string
clearable?: boolean
disabledDate?: (time: Date) => boolean
}
interface Props {
formData: Record<string, any>
formRules: FormRules
formItems: FormItem[]
optionsMap?: Record<string, Array<{
label: string | undefined
value: string | number
icon?: Component
}>>
rowGutter?: number // 新增全局栅格间距默认0
colSpan?: number // 新增全局表单项列宽默认24
}
const formRef = ref<FormInstance>()
const props = defineProps<Props>()
const emit = defineEmits(['form-item-change'])
const handleItemChange = (field: string, value: any) => {
emit('form-item-change', field, value)
}
// 暴露表单验证方法
defineExpose({
validate: () => formRef.value?.validate(),
resetFields: () => formRef.value?.resetFields()
})
</script>