Files
Aether/frontend/src/composables/useFormDialog.ts
T

120 lines
3.1 KiB
TypeScript
Raw Normal View History

2025-12-12 20:22:09 +08:00
import { computed, watch, type Ref, type ComputedRef } from 'vue'
2025-12-10 20:52:44 +08:00
/**
* 表单对话框通用逻辑
*
* 统一处理:
* - 编辑/创建模式切换
* - 对话框打开/关闭
* - 表单重置
* - 数据加载
* - Loading 状态阻止关闭
*
* @example
* ```typescript
* const { isEditMode, handleDialogUpdate, handleCancel } = useFormDialog({
* isOpen: () => props.modelValue,
* entity: () => props.provider,
* isLoading: loading,
* onClose: () => emit('update:modelValue', false),
* loadData: loadProviderData,
* resetForm,
* })
* ```
*/
export interface UseFormDialogOptions<E> {
/** 对话框是否打开(getter 函数) */
isOpen: () => boolean
/** 编辑的实体(getter 函数,返回 null/undefined 表示创建模式) */
entity: () => E | null | undefined
/** 是否处于加载状态 */
isLoading: Ref<boolean> | ComputedRef<boolean>
/** 关闭对话框的回调 */
onClose: () => void
/** 加载实体数据的函数(编辑模式时调用) */
loadData: () => void
/** 重置表单的函数 */
resetForm: () => void
/** 额外的加载状态(如清理缓存等),可选 */
extraLoadingStates?: Array<Ref<boolean> | ComputedRef<boolean>>
}
export interface UseFormDialogReturn {
/** 是否为编辑模式 */
isEditMode: ComputedRef<boolean>
/** 处理对话框更新事件(用于 @update:model-value) */
handleDialogUpdate: (value: boolean) => void
/** 处理取消按钮点击 */
handleCancel: () => void
}
export function useFormDialog<E>(
options: UseFormDialogOptions<E>
): UseFormDialogReturn {
const {
isOpen,
entity,
isLoading,
onClose,
loadData,
resetForm,
extraLoadingStates = [],
} = options
// 是否为编辑模式
const isEditMode = computed(() => !!entity())
// 检查是否有任何加载状态
const isAnyLoading = computed(() => {
if (isLoading.value) return true
return extraLoadingStates.some((state) => state.value)
})
// 处理对话框更新事件
function handleDialogUpdate(value: boolean) {
// 加载中不允许关闭
if (!value && isAnyLoading.value) {
return
}
// 关闭时重置表单
if (!value) {
resetForm()
}
onClose()
}
// 处理取消按钮
function handleCancel() {
if (isAnyLoading.value) return
onClose()
}
// 监听打开状态变化
watch(isOpen, (val) => {
if (val) {
if (isEditMode.value && entity()) {
loadData()
} else {
resetForm()
}
}
})
// 监听实体变化(编辑模式切换)
// 注意:不使用 deep: true,只在实体引用变化时触发(如从 user A 切换到 user B)
// 使用 deep: true 会导致实体的深层属性变化时也触发,覆盖用户正在编辑的数据
watch(entity, (newEntity, oldEntity) => {
// 只在实体引用真正变化时(如切换用户)才重新加载
// 避免深层属性变化时意外触发
if (newEntity && isOpen() && newEntity !== oldEntity) {
2025-12-10 20:52:44 +08:00
loadData()
}
}, { immediate: true })
2025-12-10 20:52:44 +08:00
return {
isEditMode,
handleDialogUpdate,
handleCancel,
}
}