'use client' import { useState, useEffect, useCallback, useRef } from 'react' import { saveDraft, getDraft, deleteDraft, hasDraft, checkConflict, generateDraftId, formatDraftTime, DraftData, DraftStorageConfig, } from '@/lib/draft-storage' interface UseDraftStorageOptions extends DraftStorageConfig { formType: string entityId?: string onRestore?: (data: T) => void onConflict?: (otherDraft: DraftData) => void autoSave?: boolean } interface UseDraftStorageReturn { // 状态 draftId: string hasDraft: boolean lastSaved: string | null isConflict: boolean conflictDraft: DraftData | null // 操作 save: (data: T) => boolean restore: () => T | null clear: () => void checkForConflict: () => boolean // 格式化 formatLastSaved: () => string } /** * 草稿自动保存 Hook */ export function useDraftStorage>( options: UseDraftStorageOptions ): UseDraftStorageReturn { const { formType, entityId, onRestore, onConflict, autoSave = true, ...config } = options // 生成草稿ID const draftId = generateDraftId(formType, entityId) // 状态 const [hasDraftState, setHasDraftState] = useState(false) const [lastSaved, setLastSaved] = useState(null) const [isConflict, setIsConflict] = useState(false) const [conflictDraft, setConflictDraft] = useState | null>(null) // 自动保存定时器 const autoSaveTimerRef = useRef(null) const pendingDataRef = useRef(null) // 检查是否存在草稿 useEffect(() => { const exists = hasDraft(draftId, config) setHasDraftState(exists) if (exists) { const draft = getDraft(draftId, config) if (draft) { setLastSaved(draft.updatedAt) // 检查冲突 const conflict = checkConflict(draftId, config) if (conflict.hasConflict && conflict.otherTabDraft) { setIsConflict(true) setConflictDraft(conflict.otherTabDraft) onConflict?.(conflict.otherTabDraft) } } } }, [draftId]) // 保存草稿 const save = useCallback((data: T): boolean => { const result = saveDraft(draftId, formType, data, config) if (result.success) { setHasDraftState(true) setLastSaved(new Date().toISOString()) setIsConflict(false) setConflictDraft(null) } return result.success }, [draftId, formType, config]) // 恢复草稿 const restore = useCallback((): T | null => { const draft = getDraft(draftId, config) if (draft) { onRestore?.(draft.data) return draft.data } return null }, [draftId, config, onRestore]) // 清除草稿 const clear = useCallback(() => { deleteDraft(draftId, config) setHasDraftState(false) setLastSaved(null) setIsConflict(false) setConflictDraft(null) }, [draftId, config]) // 检查冲突 const checkForConflict = useCallback((): boolean => { const conflict = checkConflict(draftId, config) setIsConflict(conflict.hasConflict) if (conflict.hasConflict && conflict.otherTabDraft) { setConflictDraft(conflict.otherTabDraft) } return conflict.hasConflict }, [draftId, config]) // 格式化最后保存时间 const formatLastSaved = useCallback((): string => { if (!lastSaved) return '' return formatDraftTime(lastSaved) }, [lastSaved]) // 自动保存逻辑 const scheduleAutoSave = useCallback((data: T) => { if (!autoSave) return pendingDataRef.current = data if (autoSaveTimerRef.current) { clearTimeout(autoSaveTimerRef.current) } autoSaveTimerRef.current = setTimeout(() => { if (pendingDataRef.current) { save(pendingDataRef.current) pendingDataRef.current = null } }, config.autoSaveInterval || 3000) }, [autoSave, save, config.autoSaveInterval]) // 清理定时器 useEffect(() => { return () => { if (autoSaveTimerRef.current) { clearTimeout(autoSaveTimerRef.current) } } }, []) return { draftId, hasDraft: hasDraftState, lastSaved, isConflict, conflictDraft, save, restore, clear, checkForConflict, formatLastSaved, } } /** * 草稿恢复提示组件的 Props */ export interface DraftRecoveryPromptProps { hasDraft: boolean lastSaved: string | null onRestore: () => void onDiscard: () => void formatLastSaved: () => string }