初始化模版工程

This commit is contained in:
Cloud Bot
2026-03-20 07:33:46 +00:00
commit 23717e0ecd
386 changed files with 51675 additions and 0 deletions

View 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 }
}