fix: 完善学习进度同步与拼图收集流程

统一阶段拼图配置和进度上报,增加同步写入协调与失败重试,优化收集确认及同步反馈,并展示菜单探索进度。补充相关回归测试与字体素材。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
zhongyidianandClaude Opus 5 committed 2026-10-12 09:29:21 +08:00
1 parent 6491b0c918
commit 9ab67b1bd3
63 files changed
+2141 -360

No files matched your search

+68
View File
@@ -0,0 +1,68 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const { setUserDefine } = vi.hoisted(() => ({
setUserDefine: vi.fn().mockResolvedValue({ success: true }),
}))
vi.mock('@/lib/utils/api-common', () => ({ setUserDefine }))
beforeEach(() => {
vi.resetModules()
setUserDefine.mockClear()
const storage = new Map<string, string>()
vi.stubGlobal('localStorage', {
getItem: (key: string) => storage.get(key) ?? null,
setItem: (key: string, value: string) => storage.set(key, value),
removeItem: (key: string) => storage.delete(key),
})
vi.stubGlobal('window', { localStorage })
})
afterEach(() => vi.unstubAllGlobals())
const image = 'data:image/jpeg;base64,YWJj'
describe('local-only artwork', () => {
it('keeps Zhang Leping artwork locally and excludes even short data URLs from sync', async () => {
const { useZhanglepingStore, saveZhanglepingStore, applyZhanglepingPersistedState } =
await import('./zhanglepingStore')
useZhanglepingStore.getState().setDrawArtwork(image, 'caption')
await saveZhanglepingStore()
const payload = JSON.parse(setUserDefine.mock.calls[0]![2])
expect(payload).not.toHaveProperty('drawArtworkDataUrl')
expect(payload.drawArtworkCaption).toBe('caption')
expect(payload.hasDrawArtwork).toBe(true)
applyZhanglepingPersistedState(payload)
expect(useZhanglepingStore.getState().drawArtworkDataUrl).toBe(image)
expect(JSON.parse(localStorage.getItem('zhangleping-storage')!).state.drawArtworkDataUrl).toBe(
image
)
})
it('keeps Nie Er previews locally while syncing other work fields', async () => {
const { useNieerStore, saveNieerStore, applyNieerPersistedState } = await import('./nieerStore')
useNieerStore.getState().setReflectionWork(6, { previewImageDataUrl: image, paradeId: '1' })
await saveNieerStore()
const payload = JSON.parse(setUserDefine.mock.calls[0]![2])
expect(payload.reflectionWorks[6]).not.toHaveProperty('previewImageDataUrl')
expect(payload.reflectionWorks[6].paradeId).toBe('1')
expect(useNieerStore.getState().reflectionWorks[6]?.previewImageDataUrl).toBe(image)
applyNieerPersistedState(payload)
expect(useNieerStore.getState().reflectionWorks[6]?.previewImageDataUrl).toBe(image)
expect(
JSON.parse(localStorage.getItem('nieer-storage')!).state.reflectionWorks[6]
.previewImageDataUrl
).toBe(image)
})
it('does not restore legacy remote images over local images', async () => {
const { useZhanglepingStore, applyZhanglepingPersistedState } =
await import('./zhanglepingStore')
const { useNieerStore, applyNieerPersistedState } = await import('./nieerStore')
useZhanglepingStore.getState().setDrawArtwork(image, 'caption')
useNieerStore.getState().setReflectionWork(6, { previewImageDataUrl: image })
applyZhanglepingPersistedState({ drawArtworkDataUrl: 'remote' })
applyNieerPersistedState({ reflectionWorks: { 6: { previewImageDataUrl: 'remote' } } })
expect(useZhanglepingStore.getState().drawArtworkDataUrl).toBe(image)
expect(useNieerStore.getState().reflectionWorks[6]?.previewImageDataUrl).toBe(image)
})
})