import { create } from 'zustand' import { persist } from 'zustand/middleware' import { STORE_NAMES } from './storeNames' import { setUserDefine } from '@/lib/utils/api-common' interface NieerStore { // 存储每个场景(place)的已访问展品ID集合 // 格式:{ place1: Set<1,2>, place2: Set<1,2>, ... } visitedExhibits: Record> // 标记展品为已访问 markExhibitVisited: (place: string, exhibitId: number) => void // 检查展品是否已访问 isExhibitVisited: (place: string, exhibitId: number) => boolean // 获取某个场景已访问的展品ID数组 getVisitedExhibits: (place: string) => number[] // 重置某个场景的访问记录 resetPlace: (place: string) => void // 重置所有访问记录 resetAll: () => void // ========== 断点续读 ========== lastVisitedPlace: string | null setLastVisitedPlace: (place: string) => void // ========== 体悟模块状态 ========== // 存储每个reflection场景的已完成cursor ID集合 visitedReflectionCursors: Record> // 标记reflection cursor为已完成 markReflectionCursorVisited: (scene: string, cursorId: number) => void // 检查reflection cursor是否已完成 isReflectionCursorVisited: (scene: string, cursorId: number) => boolean // 获取某个reflection场景已完成的cursor ID数组 getVisitedReflectionCursors: (scene: string) => number[] // 重置某个reflection场景的cursor记录 resetReflectionScene: (scene: string) => void // 重置所有reflection cursor记录 resetAllReflectionCursors: () => void // ========== 旅行箱成果 ========== // 每个 scene 对应一次分享后的成果快照(用于旅行箱展示) reflectionWorks: Record> setReflectionWork: (sceneId: number, payload: Record) => void resetReflectionWorks: () => void // 是否已经看过体悟首页学习引导 hasSeenReflectionGuide: boolean markReflectionGuideSeen: () => void // 是否已经看过旅行箱提示 hasSeenBoxHint: boolean markBoxHintSeen: () => void } // 将 Set 转换为数组以便序列化 const serializeVisitedExhibits = ( visitedExhibits: Record> ): Record => { const serialized: Record = {} for (const [place, exhibits] of Object.entries(visitedExhibits)) { serialized[place] = Array.from(exhibits) } return serialized } // 将数组转换回 Set const deserializeVisitedExhibits = ( serialized: Record | undefined ): Record> => { if (!serialized || typeof serialized !== 'object') { return {} } const visitedExhibits: Record> = {} for (const [place, exhibits] of Object.entries(serialized)) { if (Array.isArray(exhibits)) { visitedExhibits[place] = new Set(exhibits) } else { visitedExhibits[place] = new Set() } } return visitedExhibits } export const useNieerStore = create()( persist( (set, get) => ({ visitedExhibits: {}, markExhibitVisited: (place: string, exhibitId: number) => { set((state) => { const currentExhibits = state.visitedExhibits[place] || new Set() if (!currentExhibits.has(exhibitId)) { const newExhibits = { ...state.visitedExhibits, [place]: new Set([...currentExhibits, exhibitId]), } return { visitedExhibits: newExhibits } } return state }) }, isExhibitVisited: (place: string, exhibitId: number) => { const { visitedExhibits } = get() return visitedExhibits[place]?.has(exhibitId) || false }, getVisitedExhibits: (place: string) => { const { visitedExhibits } = get() return Array.from(visitedExhibits[place] || []) }, resetPlace: (place: string) => { set((state) => { const newExhibits = { ...state.visitedExhibits } delete newExhibits[place] return { visitedExhibits: newExhibits } }) }, resetAll: () => { set({ visitedExhibits: {} }) }, lastVisitedPlace: null, setLastVisitedPlace: (place: string) => set({ lastVisitedPlace: place }), // ========== 体悟模块状态 ========== visitedReflectionCursors: {}, reflectionWorks: {}, hasSeenReflectionGuide: false, hasSeenBoxHint: false, markReflectionCursorVisited: (scene: string, cursorId: number) => { set((state) => { const currentCursors = state.visitedReflectionCursors[scene] || new Set() if (!currentCursors.has(cursorId)) { const newCursors = { ...state.visitedReflectionCursors, [scene]: new Set([...currentCursors, cursorId]), } return { visitedReflectionCursors: newCursors } } return state }) }, isReflectionCursorVisited: (scene: string, cursorId: number) => { const { visitedReflectionCursors } = get() return visitedReflectionCursors[scene]?.has(cursorId) || false }, getVisitedReflectionCursors: (scene: string) => { const { visitedReflectionCursors } = get() return Array.from(visitedReflectionCursors[scene] || []) }, resetReflectionScene: (scene: string) => { set((state) => { const newCursors = { ...state.visitedReflectionCursors } delete newCursors[scene] return { visitedReflectionCursors: newCursors } }) }, resetAllReflectionCursors: () => { set({ visitedReflectionCursors: {} }) }, setReflectionWork: (sceneId: number, payload: Record) => { set((state) => ({ reflectionWorks: { ...state.reflectionWorks, [sceneId]: { ...state.reflectionWorks[sceneId], ...payload, updatedAt: Date.now(), }, }, })) }, resetReflectionWorks: () => { set({ reflectionWorks: {} }) }, markReflectionGuideSeen: () => { set({ hasSeenReflectionGuide: true }) }, markBoxHintSeen: () => { set({ hasSeenBoxHint: true }) }, }), { name: STORE_NAMES.NIEER, partialize: (state) => ({ visitedExhibits: serializeVisitedExhibits(state.visitedExhibits), visitedReflectionCursors: serializeVisitedExhibits(state.visitedReflectionCursors), lastVisitedPlace: state.lastVisitedPlace, reflectionWorks: state.reflectionWorks, hasSeenReflectionGuide: state.hasSeenReflectionGuide, hasSeenBoxHint: state.hasSeenBoxHint, }), onRehydrateStorage: () => (state) => { if (state) { state.visitedExhibits = deserializeVisitedExhibits(state.visitedExhibits as any) state.visitedReflectionCursors = deserializeVisitedExhibits( state.visitedReflectionCursors as any ) if (state.lastVisitedPlace === undefined) { state.lastVisitedPlace = null } if (!state.reflectionWorks || typeof state.reflectionWorks !== 'object') { state.reflectionWorks = {} } if ((state as any).hasSeenReflectionGuide === undefined) { ;(state as any).hasSeenReflectionGuide = false } if ((state as any).hasSeenBoxHint === undefined) { ;(state as any).hasSeenBoxHint = false } } }, } ) ) // ========== 易班平台数据保存(与陈云对齐) ========== export const NIEER_LESSON_ID = 'Nieer_duihua' export const NIEER_KEY = 5 export const saveNieerStore = (): void => { const state = useNieerStore.getState() const payload = { visitedExhibits: serializeVisitedExhibits(state.visitedExhibits), lastVisitedPlace: state.lastVisitedPlace, } try { setUserDefine(NIEER_LESSON_ID, NIEER_KEY, JSON.stringify(payload)) } catch (error) { console.error('Failed to save Nieer store', error) } }