初始化模版工程
This commit is contained in:
156
components/image-editor/hooks/use-persistence.ts
Normal file
156
components/image-editor/hooks/use-persistence.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
import { useEffect, useCallback, useRef, useState } from 'react'
|
||||
import { shallow } from 'zustand/shallow'
|
||||
import {
|
||||
saveDomiBoardContent,
|
||||
getDomiBoardContent,
|
||||
} from '../service/api'
|
||||
import { useDominoStoreInstance } from '../components/canvas'
|
||||
import type { SceneElement, DominoCanvasData } from '../components/canvas'
|
||||
|
||||
export function usePersistence(options: {
|
||||
taskId: string
|
||||
setLoading: (loading: boolean) => void
|
||||
}) {
|
||||
const { taskId, setLoading } = options
|
||||
const store = useDominoStoreInstance()
|
||||
|
||||
const isFirstLoad = useRef(true)
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
|
||||
// 任务切换时重置状态
|
||||
useEffect(() => {
|
||||
isFirstLoad.current = true
|
||||
setInitialized(false)
|
||||
}, [taskId])
|
||||
|
||||
const loadBoard = useCallback(async () => {
|
||||
if (!taskId) {
|
||||
setLoading(false)
|
||||
setInitialized(true)
|
||||
return
|
||||
}
|
||||
const currentTaskId = taskId
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
const res = (await getDomiBoardContent(taskId)) as
|
||||
| DominoCanvasData
|
||||
| string
|
||||
|
||||
if (taskId !== currentTaskId) return
|
||||
|
||||
if (res) {
|
||||
try {
|
||||
const parsed = (
|
||||
typeof res === 'string' ? JSON.parse(res) : res
|
||||
) as DominoCanvasData
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
const { elements, elementOrder, createdAt, updatedAt } = parsed
|
||||
const state = store.getState()
|
||||
|
||||
state.clearElements()
|
||||
Object.values(elements).forEach(el => {
|
||||
state.addElement(el)
|
||||
})
|
||||
// addElement might have added them in different order, so we overwrite it.
|
||||
store.setState({
|
||||
elementOrder,
|
||||
metadata: {
|
||||
createdAt: createdAt || Date.now(),
|
||||
updatedAt: updatedAt || Date.now(),
|
||||
},
|
||||
})
|
||||
|
||||
state.resetHistory()
|
||||
|
||||
setLoading(false)
|
||||
isFirstLoad.current = false
|
||||
setInitialized(true)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to parse saved DomiBoard content', e)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load DomiBoard content', e)
|
||||
} finally {
|
||||
if (taskId === currentTaskId) {
|
||||
if (isFirstLoad.current) {
|
||||
isFirstLoad.current = false
|
||||
}
|
||||
setLoading(false)
|
||||
setInitialized(true)
|
||||
store.getState().resetHistory()
|
||||
}
|
||||
}
|
||||
}, [taskId, setLoading])
|
||||
|
||||
const saveTimerRef = useRef<NodeJS.Timeout | null>(null)
|
||||
|
||||
// Auto-save logic
|
||||
useEffect(() => {
|
||||
let lastState = {
|
||||
elements: store.getState().elements,
|
||||
elementOrder: store.getState().elementOrder,
|
||||
}
|
||||
|
||||
const unsubscribe = store.subscribe(state => {
|
||||
const curr = {
|
||||
elements: state.elements,
|
||||
elementOrder: state.elementOrder,
|
||||
}
|
||||
|
||||
// Check if relevant state changed using shallow comparison
|
||||
if (shallow(lastState, curr)) return
|
||||
lastState = curr
|
||||
|
||||
if (isFirstLoad.current || !taskId) return
|
||||
|
||||
if (saveTimerRef.current) {
|
||||
clearTimeout(saveTimerRef.current)
|
||||
}
|
||||
|
||||
saveTimerRef.current = setTimeout(async () => {
|
||||
try {
|
||||
const currentMetadata = store.getState().metadata || {}
|
||||
const createdAt = currentMetadata.createdAt || Date.now()
|
||||
const persistentElements: Record<string, SceneElement> = {}
|
||||
const persistentOrder: string[] = []
|
||||
|
||||
Object.values(curr.elements).forEach(el => {
|
||||
if (el.type !== 'placeholder') {
|
||||
persistentElements[el.id] = el
|
||||
}
|
||||
})
|
||||
curr.elementOrder.forEach((id: string) => {
|
||||
if (curr.elements[id] && curr.elements[id].type !== 'placeholder') {
|
||||
persistentOrder.push(id)
|
||||
}
|
||||
})
|
||||
|
||||
const persistenceData: DominoCanvasData = {
|
||||
elements: persistentElements,
|
||||
elementOrder: persistentOrder,
|
||||
createdAt,
|
||||
updatedAt: Date.now(),
|
||||
}
|
||||
await saveDomiBoardContent({
|
||||
task_id: taskId,
|
||||
data: persistenceData,
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('Failed to auto-save DomiBoard content', e)
|
||||
}
|
||||
}, 2000) // 2 second debounce
|
||||
})
|
||||
|
||||
return () => {
|
||||
unsubscribe()
|
||||
if (saveTimerRef.current) {
|
||||
clearTimeout(saveTimerRef.current)
|
||||
}
|
||||
}
|
||||
}, [taskId, store])
|
||||
|
||||
return { loadBoard, initialized }
|
||||
}
|
||||
Reference in New Issue
Block a user