forked from zhongyidian/food-add-edu
feat: 模板适配层、易班能力与全局状态
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
3995656175
commit
d3ae0a8ca7
45 files changed
+6931
-179
No files matched your search
@@ -0,0 +1,136 @@
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import { appConfig } from "@/app.config";
|
||||
import type { GuideDialogState } from "../types/dialog.types";
|
||||
|
||||
const getDialogKey = (courseId: string, dialogId: string) =>
|
||||
`${courseId}:${dialogId}`;
|
||||
|
||||
const getInitialState = () => ({
|
||||
open: false,
|
||||
courseId: null,
|
||||
dialogId: null,
|
||||
steps: [],
|
||||
current: 0,
|
||||
showOnce: true,
|
||||
});
|
||||
|
||||
export const useDialogStore = create<GuideDialogState>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
...getInitialState(),
|
||||
completedDialogMap: {},
|
||||
|
||||
startDialog: ({
|
||||
courseId,
|
||||
dialogId,
|
||||
steps,
|
||||
showOnce = true,
|
||||
initialStep = 0,
|
||||
}) => {
|
||||
if (steps.length === 0) return;
|
||||
|
||||
const key = getDialogKey(courseId, dialogId);
|
||||
if (showOnce && get().completedDialogMap[key]) {
|
||||
return;
|
||||
}
|
||||
|
||||
set({
|
||||
open: true,
|
||||
courseId,
|
||||
dialogId,
|
||||
steps,
|
||||
current: Math.min(Math.max(initialStep, 0), steps.length - 1),
|
||||
showOnce,
|
||||
});
|
||||
},
|
||||
|
||||
closeDialog: () => {
|
||||
set(getInitialState());
|
||||
},
|
||||
|
||||
nextStep: () => {
|
||||
const { current, steps, finishDialog } = get();
|
||||
if (current >= steps.length - 1) {
|
||||
finishDialog();
|
||||
return;
|
||||
}
|
||||
set({ current: current + 1 });
|
||||
},
|
||||
|
||||
prevStep: () => {
|
||||
const { current } = get();
|
||||
set({ current: Math.max(current - 1, 0) });
|
||||
},
|
||||
|
||||
setStep: (index) => {
|
||||
const { steps } = get();
|
||||
if (steps.length === 0) return;
|
||||
set({ current: Math.min(Math.max(index, 0), steps.length - 1) });
|
||||
},
|
||||
|
||||
selectOption: (optionId) => {
|
||||
const { current, steps, setStep, finishDialog, nextStep } = get();
|
||||
const step = steps[current];
|
||||
const option = step?.options?.find((item) => item.id === optionId);
|
||||
if (!option) return;
|
||||
|
||||
if (option.finish) {
|
||||
finishDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
if (option.nextId) {
|
||||
const nextIndex = steps.findIndex(
|
||||
(item) => item.id === option.nextId,
|
||||
);
|
||||
if (nextIndex >= 0) {
|
||||
setStep(nextIndex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nextStep();
|
||||
},
|
||||
|
||||
finishDialog: () => {
|
||||
const { courseId, dialogId, completedDialogMap } = get();
|
||||
if (!courseId || !dialogId) {
|
||||
set(getInitialState());
|
||||
return;
|
||||
}
|
||||
|
||||
const key = getDialogKey(courseId, dialogId);
|
||||
set({
|
||||
...getInitialState(),
|
||||
completedDialogMap: {
|
||||
...completedDialogMap,
|
||||
[key]: true,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
skipDialog: () => {
|
||||
get().finishDialog();
|
||||
},
|
||||
|
||||
resetDialog: (courseId, dialogId) => {
|
||||
const key = getDialogKey(courseId, dialogId);
|
||||
const { [key]: _removed, ...rest } = get().completedDialogMap;
|
||||
const isCurrentDialog =
|
||||
get().courseId === courseId && get().dialogId === dialogId;
|
||||
|
||||
set({
|
||||
...(isCurrentDialog ? getInitialState() : {}),
|
||||
completedDialogMap: rest,
|
||||
});
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: `${appConfig.storage.prefix}-dialog-storage`,
|
||||
partialize: (state) => ({
|
||||
completedDialogMap: state.completedDialogMap,
|
||||
}),
|
||||
},
|
||||
),
|
||||
);
|
||||
Reference in new issue
Block a user