feat: 引入持久化访问状态管理,优化展品访问逻辑

- 在 Luxun 和 Sunzhongshan 的多个组件中引入 useLuxunStore 和 useSunzhongshanStore,替代原有的访问状态管理方式。
- 通过 markExhibitVisited 方法标记展品为已访问,提升状态管理的效率和一致性。
- 从 store 获取已访问展品的状态,确保数据的持久性和准确性。
This commit is contained in:
zhongyidian committed 2026-02-04 14:01:03 +08:00
1 parent 966b47ede3
commit ac5a2159a1
15 files changed
+392 -173

No files matched your search

+143
View File
@@ -0,0 +1,143 @@
import { create } from "zustand";
import { persist } from "zustand/middleware";
interface SunzhongshanStore {
// 存储每个场景(place)的已访问展品ID集合
// 格式:{ place1: Set<1, 2>, place2: Set<1, 2>, ... }
visitedExhibits: Record<string, Set<number>>;
// 体悟模块通用布尔状态(引导是否展示、场景是否完成等)
reflectionFlags: Record<string, boolean>;
// 标记展品为已访问
markExhibitVisited: (place: string, exhibitId: number) => void;
// 检查展品是否已访问
isExhibitVisited: (place: string, exhibitId: number) => boolean;
// 获取某个场景已访问的展品ID数组
getVisitedExhibits: (place: string) => number[];
// 重置某个场景的访问记录
resetPlace: (place: string) => void;
// 重置所有访问记录
resetAll: () => void;
// 设置体悟模块布尔状态
setReflectionFlag: (key: string, value: boolean) => void;
// 获取体悟模块布尔状态
getReflectionFlag: (key: string) => boolean;
}
// 将 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 useSunzhongshanStore = create<SunzhongshanStore>()(
persist(
(set, get) => ({
visitedExhibits: {},
reflectionFlags: {},
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: {}, reflectionFlags: {} });
},
setReflectionFlag: (key: string, value: boolean) => {
set((state) => ({
reflectionFlags: {
...state.reflectionFlags,
[key]: value,
},
}));
},
getReflectionFlag: (key: string) => {
const { reflectionFlags } = get();
return !!reflectionFlags[key];
},
}),
{
name: "sunzhongshan-storage",
partialize: (state) => ({
visitedExhibits: serializeVisitedExhibits(state.visitedExhibits),
reflectionFlags: state.reflectionFlags,
}),
onRehydrateStorage: () => (state) => {
if (state) {
state.visitedExhibits = deserializeVisitedExhibits(
state.visitedExhibits as any
);
if (
!state.reflectionFlags ||
typeof state.reflectionFlags !== "object"
) {
state.reflectionFlags = {};
}
}
},
}
)
);