Files
shanghai-residences/src/store/chenyunStore.ts
T
zhongyidian e0fa47d21a 更新依赖项及历史人物相关内容资源
- 更新 package.json 和 package-lock.json 中的依赖项
- 新增/更新陈云、黄炎培、鲁迅、孙中山的音频文件
- 新增场景和组件的图片资源
- 清理未使用的音频和图片文件
- 优化多个组件和页面的实现逻辑
2026-04-20 13:27:18 +08:00

176 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
import { STORE_NAMES } from './storeNames'
import { setUserDefine } from '@/lib/utils/api-common'
interface ChenyunStore {
// 存储每个场景(place)的已访问展品ID集合
// 格式:{ place1: Set<1, 2>, place2: Set<1, 2>, ... }
visitedExhibits: Record<string, Set<number>>
// 标记展品为已访问
markExhibitVisited: (place: string, exhibitId: number) => void
// 检查展品是否已访问
isExhibitVisited: (place: string, exhibitId: number) => boolean
// 获取某个场景已访问的展品ID数组
getVisitedExhibits: (place: string) => number[]
// 重置某个场景的访问记录
resetPlace: (place: string) => void
// 重置所有访问记录
resetAll: () => void
// ========== 断点续读 ==========
// 上次访问的场景(place1~place9)
lastVisitedPlace: string | null
setLastVisitedPlace: (place: string) => void
// ========== 体悟模块状态 ==========
// 银元之战是否已解决
isYinyuanSolved: boolean
// 设置银元之战解决状态
setYinyuanSolved: (solved: boolean) => void
// 米棉之战是否已解决
isMimianSolved: boolean
// 设置米棉之战解决状态
setMimianSolved: (solved: boolean) => void
}
// 将 Set 转换为数组以便序列化
const serializeVisitedExhibits = (
visitedExhibits: Record<string, Set<number>>
): Record<string, number[]> => {
const serialized: Record<string, number[]> = {}
for (const [place, exhibits] of Object.entries(visitedExhibits)) {
serialized[place] = Array.from(exhibits)
}
return serialized
}
// 将数组转换回 Set
const deserializeVisitedExhibits = (
serialized: Record<string, number[]> | undefined
): Record<string, Set<number>> => {
if (!serialized || typeof serialized !== 'object') {
return {}
}
const visitedExhibits: Record<string, Set<number>> = {}
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 useChenyunStore = create<ChenyunStore>()(
persist(
(set, get) => ({
visitedExhibits: {},
markExhibitVisited: (place: string, exhibitId: number) => {
set((state) => {
const currentExhibits = state.visitedExhibits[place] || new Set<number>()
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 }),
// ========== 体悟模块状态 ==========
isYinyuanSolved: false,
setYinyuanSolved: (solved: boolean) => {
set({ isYinyuanSolved: solved })
},
isMimianSolved: false,
setMimianSolved: (solved: boolean) => {
set({ isMimianSolved: solved })
},
}),
{
name: STORE_NAMES.CHENYUN, // localStorage key
partialize: (state) => ({
visitedExhibits: serializeVisitedExhibits(state.visitedExhibits),
isYinyuanSolved: state.isYinyuanSolved,
isMimianSolved: state.isMimianSolved,
lastVisitedPlace: state.lastVisitedPlace,
}),
onRehydrateStorage: () => (state) => {
if (state) {
// 确保反序列化后的数据格式正确
state.visitedExhibits = deserializeVisitedExhibits(state.visitedExhibits as any)
// 确保解决状态有默认值
if (state.isYinyuanSolved === undefined) {
state.isYinyuanSolved = false
}
if (state.isMimianSolved === undefined) {
state.isMimianSolved = false
}
if (state.lastVisitedPlace === undefined) {
state.lastVisitedPlace = null
}
}
},
}
)
)
// ========== 易班平台数据保存 ==========
export const CHENYUN_LESSON_ID = 'Cheny_duihua'
export const CHENYUN_KEY = 22
export const saveChenyunStore = (): void => {
const state = useChenyunStore.getState()
const payload = {
visitedExhibits: serializeVisitedExhibits(state.visitedExhibits),
isYinyuanSolved: state.isYinyuanSolved,
isMimianSolved: state.isMimianSolved,
lastVisitedPlace: state.lastVisitedPlace,
}
try {
setUserDefine(CHENYUN_LESSON_ID, CHENYUN_KEY, JSON.stringify(payload))
} catch (error) {
console.error('Failed to save Chenyun store', error)
}
}