chore: 更新素材和组件优化
- 更新展品图片(鲁迅/毛泽东/孙中山/黄炎培/聂耳/张乐平故居) - 新增点击查看图标、报纸素材 - 优化视频组件、拼图组件、展品组件 - 更新陈云音频资源 - 新增输入验证文档和工具函数 - 组件布局和动画优化 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
73d02eb62d
commit
73f6df92ce
130 files changed
+2345
-759
No files matched your search
@@ -1,7 +1,11 @@
|
||||
import { create } from 'zustand'
|
||||
import { persist } from 'zustand/middleware'
|
||||
import { STORE_NAMES } from './storeNames'
|
||||
import { setUserDefine } from '@/lib/utils/api-common'
|
||||
import {
|
||||
setUserDefine,
|
||||
getUserDefineResult,
|
||||
type UserDefineFetchStatus,
|
||||
} from '@/lib/utils/api-common'
|
||||
|
||||
export interface Clue {
|
||||
id: string
|
||||
@@ -53,6 +57,9 @@ interface SunzhongshanStore {
|
||||
|
||||
// 获取体悟模块布尔状态
|
||||
getReflectionFlag: (key: string) => boolean
|
||||
|
||||
completedVideos: Record<string, boolean>
|
||||
markVideoCompleted: (videoKey: string) => void
|
||||
}
|
||||
|
||||
// 将 Set 转换为数组以便序列化
|
||||
@@ -84,6 +91,21 @@ const deserializeVisitedExhibits = (
|
||||
return visitedExhibits
|
||||
}
|
||||
|
||||
const resolveReflectionRoute = (route: unknown): string =>
|
||||
typeof route === 'string' &&
|
||||
['reflection', 'reflection1', 'reflection2', 'reflection3'].includes(route)
|
||||
? route
|
||||
: 'reflection'
|
||||
|
||||
interface SunzhongshanPersistedState {
|
||||
visitedExhibits?: Record<string, number[]>
|
||||
reflectionFlags?: Record<string, boolean>
|
||||
lastVisitedPlace?: string | null
|
||||
reflectionRoute?: string
|
||||
clues?: Clue[]
|
||||
completedVideos?: Record<string, boolean>
|
||||
}
|
||||
|
||||
export const useSunzhongshanStore = create<SunzhongshanStore>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
@@ -92,6 +114,13 @@ export const useSunzhongshanStore = create<SunzhongshanStore>()(
|
||||
lastVisitedPlace: null,
|
||||
reflectionRoute: 'reflection',
|
||||
clues: [],
|
||||
completedVideos: {},
|
||||
|
||||
markVideoCompleted: (videoKey: string) => {
|
||||
set((state) => ({
|
||||
completedVideos: { ...state.completedVideos, [videoKey]: true },
|
||||
}))
|
||||
},
|
||||
|
||||
markExhibitVisited: (place: string, exhibitId: number) => {
|
||||
set((state) => {
|
||||
@@ -132,6 +161,7 @@ export const useSunzhongshanStore = create<SunzhongshanStore>()(
|
||||
lastVisitedPlace: null,
|
||||
reflectionRoute: 'reflection',
|
||||
clues: [],
|
||||
completedVideos: {},
|
||||
})
|
||||
},
|
||||
|
||||
@@ -202,6 +232,7 @@ export const useSunzhongshanStore = create<SunzhongshanStore>()(
|
||||
lastVisitedPlace: state.lastVisitedPlace,
|
||||
reflectionRoute: state.reflectionRoute,
|
||||
clues: state.clues,
|
||||
completedVideos: state.completedVideos,
|
||||
}),
|
||||
onRehydrateStorage: () => (state) => {
|
||||
if (state) {
|
||||
@@ -218,6 +249,9 @@ export const useSunzhongshanStore = create<SunzhongshanStore>()(
|
||||
if (!(state as any).clues || !Array.isArray((state as any).clues)) {
|
||||
;(state as any).clues = []
|
||||
}
|
||||
if (!state.completedVideos || typeof state.completedVideos !== 'object') {
|
||||
state.completedVideos = {}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -233,8 +267,11 @@ export const saveSunzhongshanStore = (): void => {
|
||||
|
||||
const payload = {
|
||||
visitedExhibits: serializeVisitedExhibits(state.visitedExhibits),
|
||||
reflectionFlags: state.reflectionFlags,
|
||||
lastVisitedPlace: state.lastVisitedPlace,
|
||||
reflectionRoute: state.reflectionRoute,
|
||||
clues: state.clues,
|
||||
completedVideos: state.completedVideos,
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -243,3 +280,32 @@ export const saveSunzhongshanStore = (): void => {
|
||||
console.error('Failed to save Sunzhongshan store', error)
|
||||
}
|
||||
}
|
||||
|
||||
export const applySunzhongshanPersistedState = (payload: SunzhongshanPersistedState): void => {
|
||||
useSunzhongshanStore.setState({
|
||||
visitedExhibits: deserializeVisitedExhibits(payload.visitedExhibits),
|
||||
reflectionFlags: payload.reflectionFlags ?? {},
|
||||
lastVisitedPlace: payload.lastVisitedPlace ?? null,
|
||||
reflectionRoute: resolveReflectionRoute(payload.reflectionRoute),
|
||||
clues: Array.isArray(payload.clues) ? payload.clues : [],
|
||||
completedVideos: payload.completedVideos ?? {},
|
||||
})
|
||||
}
|
||||
|
||||
export const loadSunzhongshanStore = async (): Promise<UserDefineFetchStatus> => {
|
||||
try {
|
||||
const result = await getUserDefineResult(SUNZHONGSHAN_LESSON_ID, SUNZHONGSHAN_KEY)
|
||||
if (result.status !== 'success') {
|
||||
if (result.status === 'empty') {
|
||||
useSunzhongshanStore.getState().resetAll()
|
||||
}
|
||||
return result.status
|
||||
}
|
||||
|
||||
applySunzhongshanPersistedState(JSON.parse(result.content) as SunzhongshanPersistedState)
|
||||
return result.status
|
||||
} catch (error) {
|
||||
console.error('Failed to load Sunzhongshan store', error)
|
||||
return 'error'
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user