/**
|
* 通用表单数据管理组合式函数
|
* 提供表单数据的增删改查、验证、重置等功能
|
*/
|
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<Boolean>} 验证结果
|
*/
|
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<Boolean>} 提交结果
|
*/
|
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 };
|
}
|