/** * 通用表单数据管理组合式函数 * 提供表单数据的增删改查、验证、重置等功能 */ import { ref, reactive, computed, nextTick } from "vue"; import { ElMessage, ElMessageBox } from "element-plus"; import { clone } from "lodash"; /** * 创建表单数据管理功能 * @param {Object} options 配置选项 * @param {Object} options.defaultForm 默认表单结构 * @param {Function} options.addApi 新增API函数 * @param {Function} options.updateApi 更新API函数 * @param {Function} options.getDetailApi 获取详情API函数 * @param {Object} options.rules 表单验证规则 * @param {Function} options.beforeSubmit 提交前的数据处理函数 * @param {Function} options.afterSubmit 提交后的回调函数 * @param {Boolean} options.autoReset 提交成功后是否自动重置表单 * @returns {Object} 返回表单管理相关的方法和状态 */ export function useFormData(options = {}) { const { defaultForm = {}, addApi, updateApi, getDetailApi, rules = {}, beforeSubmit, afterSubmit, autoReset = true } = options; // 表单状态 const form = ref({ ...defaultForm }); const originalForm = ref({ ...defaultForm }); const loading = ref(false); const dialogVisible = ref(false); const mode = ref('add'); // 'add', 'edit', 'view' const title = ref(''); const formRef = ref(null); // 计算属性 const isAdd = computed(() => mode.value === 'add'); const isEdit = computed(() => mode.value === 'edit'); const isView = computed(() => mode.value === 'view'); const isReadonly = computed(() => mode.value === 'view'); const submitButtonText = computed(() => { return isAdd.value ? '新增' : '保存'; }); /** * 打开表单对话框 * @param {String} formMode 表单模式:'add', 'edit', 'view' * @param {Object} data 编辑/查看时的数据 * @param {String} customTitle 自定义标题 */ const openForm = async (formMode = 'add', data = null, customTitle = '') => { mode.value = formMode; // 设置标题 if (customTitle) { title.value = customTitle; } else { const titleMap = { add: '新增', edit: '编辑', view: '查看' }; title.value = titleMap[formMode] || '表单'; } // 根据模式处理数据 if (formMode === 'add') { resetForm(); } else if (data) { // 编辑/查看模式,如果有详情API则获取最新数据 if (getDetailApi && data.id) { loading.value = true; try { const res = await getDetailApi(data.id); if (res.code === 200) { setFormData(res.data); } else { ElMessage.error('获取详情失败'); setFormData(data); } } catch (error) { console.error('获取详情失败:', error); setFormData(data); } finally { loading.value = false; } } else { setFormData(data); } } dialogVisible.value = true; }; /** * 设置表单数据 * @param {Object} data 表单数据 */ const setFormData = (data) => { form.value = { ...defaultForm, ...data }; originalForm.value = { ...form.value }; }; /** * 重置表单 */ const resetForm = () => { form.value = { ...defaultForm }; originalForm.value = { ...defaultForm }; if (formRef.value) { formRef.value.resetFields(); } }; /** * 恢复表单到原始状态 */ const restoreForm = () => { form.value = { ...originalForm.value }; if (formRef.value) { formRef.value.clearValidate(); } }; /** * 表单验证 * @returns {Promise} 验证结果 */ const validateForm = async () => { if (!formRef.value) return true; try { await formRef.value.validate(); return true; } catch (error) { console.log('表单验证失败:', error); return false; } }; /** * 提交表单 * @param {Object} customData 自定义提交数据 * @returns {Promise} 提交结果 */ const submitForm = async (customData = null) => { // 验证表单 const isValid = await validateForm(); if (!isValid) { ElMessage.warning('请检查表单数据'); return false; } // 准备提交数据 let submitData = customData || { ...form.value }; // 执行提交前处理 if (beforeSubmit && typeof beforeSubmit === 'function') { try { submitData = await beforeSubmit(submitData, mode.value); } catch (error) { console.error('提交前处理失败:', error); ElMessage.error('数据处理失败'); return false; } } loading.value = true; try { let res; if (isAdd.value && addApi) { res = await addApi(submitData); } else if (isEdit.value && updateApi) { res = await updateApi(submitData); } else { ElMessage.error('未配置相应的API接口'); return false; } if (res.code === 200) { const action = isAdd.value ? '新增' : '更新'; ElMessage.success(`${action}成功`); // 执行提交后回调 if (afterSubmit && typeof afterSubmit === 'function') { await afterSubmit(res.data, mode.value, submitData); } // 自动重置表单 if (autoReset) { closeForm(); } return true; } else { ElMessage.error(res.msg || '操作失败'); return false; } } catch (error) { console.error('提交失败:', error); ElMessage.error('操作失败,请稍后重试'); return false; } finally { loading.value = false; } }; /** * 关闭表单对话框 */ const closeForm = () => { dialogVisible.value = false; resetForm(); }; /** * 检查表单是否有变更 * @returns {Boolean} 是否有变更 */ const hasChanges = computed(() => { return JSON.stringify(form.value) !== JSON.stringify(originalForm.value); }); /** * 带确认的关闭表单 */ const closeFormWithConfirm = async () => { if (hasChanges.value && !isView.value) { try { await ElMessageBox.confirm('表单数据已修改,确定要离开吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }); closeForm(); } catch { // 用户取消 } } else { closeForm(); } }; /** * 设置表单字段值 * @param {String} field 字段名 * @param {Any} value 字段值 */ const setFieldValue = (field, value) => { form.value[field] = value; }; /** * 获取表单字段值 * @param {String} field 字段名 * @returns {Any} 字段值 */ const getFieldValue = (field) => { return form.value[field]; }; /** * 批量设置表单字段值 * @param {Object} values 字段值对象 */ const setFieldValues = (values) => { Object.keys(values).forEach(key => { if (form.value.hasOwnProperty(key)) { form.value[key] = values[key]; } }); }; /** * 清除字段验证 * @param {String|Array} fields 字段名或字段名数组 */ const clearValidate = (fields = null) => { if (formRef.value) { formRef.value.clearValidate(fields); } }; return { // 状态 form, loading, dialogVisible, mode, title, formRef, // 计算属性 isAdd, isEdit, isView, isReadonly, submitButtonText, hasChanges, // 方法 openForm, setFormData, resetForm, restoreForm, validateForm, submitForm, closeForm, closeFormWithConfirm, setFieldValue, getFieldValue, setFieldValues, clearValidate }; } // 向后兼容的默认导出 export default function useFormDataSimple(initData) { const form = reactive(clone(initData, true)); function resetForm() { const initData2 = JSON.parse(JSON.stringify(initData)); Object.keys(initData).forEach(key => { form[key] = initData2[key]; }); } return { form, resetForm }; }