/** * 表单验证组合式函数 */ import { ref, reactive, computed } from 'vue' import { ElMessage } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus' /** * 使用表单验证 */ export const useFormValidation = >( initialData: T, rules: FormRules ) => { const formRef = ref() const formData = reactive({ ...initialData }) const errors = ref>({}) const isValidating = ref(false) /** * 验证整个表单 */ const validateForm = async (): Promise => { if (!formRef.value) return false try { isValidating.value = true await formRef.value.validate() errors.value = {} return true } catch (error) { console.error('表单验证失败:', error) return false } finally { isValidating.value = false } } /** * 验证指定字段 */ const validateField = async (field: keyof T): Promise => { if (!formRef.value) return false try { await formRef.value.validateField(field as string) delete errors.value[field as string] return true } catch (error) { errors.value[field as string] = error as string return false } } /** * 清除验证结果 */ const clearValidation = (fields?: (keyof T)[]) => { if (!formRef.value) return if (fields) { formRef.value.clearValidate(fields as string[]) fields.forEach(field => { delete errors.value[field as string] }) } else { formRef.value.clearValidate() errors.value = {} } } /** * 重置表单 */ const resetForm = () => { if (!formRef.value) return formRef.value.resetFields() Object.assign(formData, initialData) errors.value = {} } /** * 设置字段错误 */ const setFieldError = (field: keyof T, message: string) => { errors.value[field as string] = message } /** * 清除字段错误 */ const clearFieldError = (field: keyof T) => { delete errors.value[field as string] } /** * 获取字段错误 */ const getFieldError = (field: keyof T) => { return errors.value[field as string] } /** * 检查表单是否有错误 */ const hasErrors = computed(() => { return Object.keys(errors.value).length > 0 }) /** * 检查表单是否有效 */ const isValid = computed(() => { return !hasErrors.value && !isValidating.value }) return { formRef, formData, errors: computed(() => errors.value), isValidating: computed(() => isValidating.value), hasErrors, isValid, validateForm, validateField, clearValidation, resetForm, setFieldError, clearFieldError, getFieldError } } /** * 常用验证规则 */ export const validationRules = { /** * 必填验证 */ required: (message = '此字段为必填项') => ({ required: true, message, trigger: 'blur' }), /** * 邮箱验证 */ email: (message = '请输入正确的邮箱格式') => ({ type: 'email' as const, message, trigger: 'blur' }), /** * 手机号验证 */ phone: (message = '请输入正确的手机号格式') => ({ pattern: /^1[3-9]\d{9}$/, message, trigger: 'blur' }), /** * 长度验证 */ length: (min: number, max: number, message?: string) => ({ min, max, message: message || `长度必须在${min}-${max}位之间`, trigger: 'blur' }), /** * 最小长度验证 */ minLength: (min: number, message?: string) => ({ min, message: message || `长度不能少于${min}位`, trigger: 'blur' }), /** * 最大长度验证 */ maxLength: (max: number, message?: string) => ({ max, message: message || `长度不能超过${max}位`, trigger: 'blur' }), /** * 正则验证 */ pattern: (pattern: RegExp, message: string) => ({ pattern, message, trigger: 'blur' }), /** * 自定义验证 */ custom: (validator: (rule: any, value: any, callback: any) => void) => ({ validator, trigger: 'blur' }), /** * 账号验证(字母数字下划线) */ account: (message = '账号只能包含字母、数字和下划线,长度4-20位') => ({ pattern: /^[a-zA-Z0-9_]{4,20}$/, message, trigger: 'blur' }), /** * 密码验证 */ password: (min = 6, max = 20, message?: string) => ({ min, max, message: message || `密码长度必须在${min}-${max}位之间`, trigger: 'blur' }), /** * 确认密码验证 */ confirmPassword: (passwordField: string, message = '两次输入的密码不一致') => ({ validator: (rule: any, value: any, callback: any) => { if (!value) { callback(new Error('请再次输入密码')) return } // 这里需要访问表单数据,在实际使用时需要传入表单数据 callback() }, trigger: 'blur' }) } /** * 使用实时验证 */ export const useRealtimeValidation = >( formData: T, rules: FormRules ) => { const errors = ref>({}) const validFields = ref>(new Set()) /** * 验证单个字段 */ const validateField = async (field: keyof T, value: any) => { const fieldRules = rules[field as string] if (!fieldRules) return true try { // 这里简化处理,实际应该使用async-validator const ruleArray = Array.isArray(fieldRules) ? fieldRules : [fieldRules] for (const rule of ruleArray) { if (rule.required && (!value || value === '')) { throw new Error(rule.message || '此字段为必填项') } if (rule.min && value && value.length < rule.min) { throw new Error(rule.message || `长度不能少于${rule.min}位`) } if (rule.max && value && value.length > rule.max) { throw new Error(rule.message || `长度不能超过${rule.max}位`) } if (rule.pattern && value && !rule.pattern.test(value)) { throw new Error(rule.message || '格式不正确') } } delete errors.value[field as string] validFields.value.add(field as string) return true } catch (error: any) { errors.value[field as string] = error.message validFields.value.delete(field as string) return false } } /** * 检查所有字段是否有效 */ const isAllValid = computed(() => { const requiredFields = Object.keys(rules) return requiredFields.every(field => validFields.value.has(field)) && Object.keys(errors.value).length === 0 }) return { errors: computed(() => errors.value), validFields: computed(() => validFields.value), isAllValid, validateField } }