feat:init

This commit is contained in:
zhongyidian committed 2025-12-29 19:19:10 +08:00
1 parent 53d0eeac6b
commit ae0c050010
494 files changed
+17701 -2318

No files matched your search

+284
View File
@@ -0,0 +1,284 @@
import { useMemo, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import {
Image,
Video,
type VideoAnchor,
type DragFillResult,
} from "@/components";
import { getPublicPath, getStaticImage } from "@/lib/utils";
import { SuccessAlert, DragQuizPanel } from "@/components/layout";
import { MultipleChoiceQuizPanel } from "@/components/layout/quiz";
type QuizOption = {
value: string;
label: string;
isCorrect?: boolean;
explanation?: string; // 错误选项的解释
};
type QuizAnchor = {
id: string;
time: number;
title: string;
prompt: string;
type: "single" | "multiple" | "drag";
options: QuizOption[];
// 拖拽题专用
blanks?: { id: string; label: string }[];
};
// 星名固定为 chenyun
const starName = "chenyun";
// 锚点数据:可根据实际视频时长调整 time
const QUIZ_ANCHORS: QuizAnchor[] = [
{
id: "quiz-1",
time: 12,
title: "题目1",
prompt: "陈云经济思想的核心内容指的是( )。",
type: "multiple",
options: [
{ value: "A", label: "综合平衡", isCorrect: true },
{
value: "B",
label: "鸟笼比喻",
explanation: "鸟笼比喻是正确的处理好计划与市场的关系的一个发展阶段",
},
{ value: "C", label: "正确的处理好计划与市场的关系", isCorrect: true },
{ value: "D", label: "经济建设的目的论", isCorrect: true },
],
},
{
id: "quiz-2",
time: 30,
title: "题目2",
prompt: "陈云说过以下哪些话能着重体现出他的经济思想。",
type: "multiple",
options: [
{
value: "A",
label: "不唯上、不唯书、只唯实,交换、比较、反复",
isCorrect: true,
},
{ value: "B", label: "无农不稳,无粮则乱", isCorrect: true },
{ value: "C", label: "个人名利淡如水,党的事业重如山。", isCorrect: true },
{
value: "D",
label: "领导机关制定政策,要用百分之九十以上的时间作调查研究工作。",
isCorrect: true,
},
],
},
{
id: "quiz-3",
time: 48,
title: "题目3",
prompt: "我们新时代的青年可以从陈云同志身上学习到哪些精神",
type: "drag",
options: [
{ value: "积极的人生态度", label: "积极的人生态度", isCorrect: true },
{ value: "刻苦的学习精神", label: "刻苦的学习精神", isCorrect: true },
{ value: "朴素的节俭精神", label: "朴素的节俭精神", isCorrect: true },
{ value: "实事求是的精神", label: "实事求是的精神", isCorrect: true },
],
blanks: [
{ id: "blank-1", label: "____" },
{ id: "blank-2", label: "____" },
{ id: "blank-3", label: "____" },
{ id: "blank-4", label: "____" },
],
},
];
const ChenyunInternalization = () => {
const navigate = useNavigate();
const { moduleName } = useParams<{ moduleName: string }>();
const [activeSuccess, setActiveSuccess] = useState<string | null>(null);
const [successContent, setSuccessContent] = useState<string>("");
const [resumeCallback, setResumeCallback] = useState<(() => void) | null>(
null
);
// 拖拽题状态
const [dragQuizValues, setDragQuizValues] = useState<
Record<string, DragFillResult[]>
>({});
const [dragQuizErrors, setDragQuizErrors] = useState<Record<string, string>>(
{}
);
const anchors: VideoAnchor[] = useMemo(
() =>
QUIZ_ANCHORS.map((item) => {
const correctAnswers = item.options
.filter((opt) => opt.isCorrect)
.map((opt) => opt.value);
// 拖拽题处理
if (item.type === "drag" && item.blanks) {
return {
id: item.id,
time: item.time,
once: true,
afterResume: "remove",
render: ({ resume }) => {
const handleDragChange = (val: DragFillResult[]) => {
setDragQuizValues((prev) => ({ ...prev, [item.id]: val }));
setDragQuizErrors((prev) => ({ ...prev, [item.id]: "" }));
if (val.length < correctAnswers.length) return;
// 检查是否包含了所有正确答案(不要求顺序)
const filledAnswers = val.map((v) => v.optionValue);
const answerSet = new Set(correctAnswers);
const filledSet = new Set(filledAnswers);
const isCorrect =
answerSet.size === filledSet.size &&
[...answerSet].every((answer) => filledSet.has(answer));
if (isCorrect) {
setActiveSuccess(item.id);
setSuccessContent("回答正确,请继续探索。");
setResumeCallback(() => resume);
} else {
setDragQuizErrors((prev) => ({
...prev,
[item.id]: "再想一想,确保选择了所有正确答案~",
}));
}
};
return (
<>
<DragQuizPanel
visible={activeSuccess !== item.id}
zIndex={10000}
title={`${item.title}(拖拽)`}
questionPrefix={`${item.prompt}(`}
questionSuffix=")?"
options={item.options.map((opt) => ({
value: opt.value,
label: opt.label,
}))}
blanks={item.blanks || []}
value={dragQuizValues[item.id] || []}
error={dragQuizErrors[item.id]}
onChange={handleDragChange}
/>
<SuccessAlert
visible={activeSuccess === item.id}
title="恭喜你, 选择正确!"
content={successContent}
onContinue={() => {
setActiveSuccess(null);
setSuccessContent("");
setDragQuizValues((prev) => {
const next = { ...prev };
delete next[item.id];
return next;
});
setDragQuizErrors((prev) => {
const next = { ...prev };
delete next[item.id];
return next;
});
const cb = resumeCallback;
setResumeCallback(null);
cb?.();
}}
/>
</>
);
},
};
}
// 多选题处理
if (item.type === "multiple") {
return {
id: item.id,
time: item.time,
once: true,
afterResume: "remove",
render: ({ resume }) => (
<>
<MultipleChoiceQuizPanel
visible={activeSuccess !== item.id}
zIndex={10000}
title={`${item.title}(多选题):${item.prompt}`}
options={item.options.map((opt) => ({
value: opt.value,
label: `${opt.value}. ${opt.label}`,
}))}
correctAnswer={correctAnswers}
errorMessage="再思考一下,注意选择所有正确答案。"
onSubmit={(values: string[], isCorrect: boolean) => {
if (isCorrect) {
setActiveSuccess(item.id);
setSuccessContent("回答正确,请继续探索。");
setResumeCallback(() => resume);
}
}}
/>
<SuccessAlert
visible={activeSuccess === item.id}
title="恭喜你, 选择正确!"
content={successContent}
onContinue={() => {
setActiveSuccess(null);
setSuccessContent("");
const cb = resumeCallback;
setResumeCallback(null);
cb?.();
}}
/>
</>
),
};
}
// 单选题处理(保留原有逻辑,以防万一)
return {
id: item.id,
time: item.time,
once: true,
afterResume: "remove",
render: () => null,
};
}),
[
activeSuccess,
resumeCallback,
successContent,
dragQuizValues,
dragQuizErrors,
]
);
if (!moduleName) return null;
return (
<div className="relative h-full w-full bg-black">
{/* 离开按钮 */}
<Image
className="absolute right-8 top-8 z-10"
src={getStaticImage("components/离开")}
button
onClick={() => navigate(`/${moduleName}/${starName}/home`)}
/>
<Video
src={getPublicPath("video/chenyun/chenyun_neihua.mp4")}
className="h-full w-full"
anchors={anchors}
autoPlay
muted
playsInline
controls
/>
</div>
);
};
export default ChenyunInternalization;