diff --git a/src/assets/images/components/internalization/bg.png b/src/assets/images/components/internalization/bg.png index 42d8335..f97294d 100644 Binary files a/src/assets/images/components/internalization/bg.png and b/src/assets/images/components/internalization/bg.png differ diff --git a/src/assets/images/components/quiz/效果图.png b/src/assets/images/components/quiz/效果图.png new file mode 100644 index 0000000..7306c1b Binary files /dev/null and b/src/assets/images/components/quiz/效果图.png differ diff --git a/src/assets/images/components/quiz/未选中.png b/src/assets/images/components/quiz/未选中.png new file mode 100644 index 0000000..168ac55 Binary files /dev/null and b/src/assets/images/components/quiz/未选中.png differ diff --git a/src/assets/images/components/quiz/正确.png b/src/assets/images/components/quiz/正确.png new file mode 100644 index 0000000..7b22eb3 Binary files /dev/null and b/src/assets/images/components/quiz/正确.png differ diff --git a/src/assets/images/components/quiz/继续前进.png b/src/assets/images/components/quiz/继续前进.png new file mode 100644 index 0000000..b63e5af Binary files /dev/null and b/src/assets/images/components/quiz/继续前进.png differ diff --git a/src/assets/images/components/quiz/选中_副本.png b/src/assets/images/components/quiz/选中_副本.png new file mode 100644 index 0000000..c123637 Binary files /dev/null and b/src/assets/images/components/quiz/选中_副本.png differ diff --git a/src/assets/images/components/quiz/重做.png b/src/assets/images/components/quiz/重做.png new file mode 100644 index 0000000..e8fbf36 Binary files /dev/null and b/src/assets/images/components/quiz/重做.png differ diff --git a/src/assets/images/components/quiz/错误.png b/src/assets/images/components/quiz/错误.png new file mode 100644 index 0000000..419032d Binary files /dev/null and b/src/assets/images/components/quiz/错误.png differ diff --git a/src/assets/images/components/quiz/问题题板.png b/src/assets/images/components/quiz/问题题板.png new file mode 100644 index 0000000..4882c0a Binary files /dev/null and b/src/assets/images/components/quiz/问题题板.png differ diff --git a/src/components/layout/quiz/DragQuizPanel.tsx b/src/components/layout/quiz/DragQuizPanel.tsx index 2ed0842..7afc7f7 100644 --- a/src/components/layout/quiz/DragQuizPanel.tsx +++ b/src/components/layout/quiz/DragQuizPanel.tsx @@ -22,7 +22,7 @@ const DragQuizPanel = ({ className="fixed inset-0 flex items-center justify-center bg-black/40" style={{ zIndex }} > -
+
{/* 题干卡片 */}
diff --git a/src/components/layout/quiz/SingleChoiceQuizPanel.tsx b/src/components/layout/quiz/SingleChoiceQuizPanel.tsx index 8b69f19..50459d7 100644 --- a/src/components/layout/quiz/SingleChoiceQuizPanel.tsx +++ b/src/components/layout/quiz/SingleChoiceQuizPanel.tsx @@ -36,6 +36,7 @@ const SingleChoiceQuizPanel = ({ correctAnswer, errorMessage, onSubmit, + onWrongSelect, onError, disabled = false, }: SingleChoiceQuizPanelProps) => { @@ -65,7 +66,9 @@ const SingleChoiceQuizPanel = ({ } else { // 答题失败:清空状态,执行 onError,允许重新选择 setSelectedValue(""); - const errorMsg = errorMessage || "很抱歉,你选错了!请你再思考一下吧!"; + const customError = onWrongSelect?.(value); + const errorMsg = + customError || errorMessage || "很抱歉,你选错了!请你再思考一下吧!"; setError(errorMsg); onError?.(errorMsg); } diff --git a/src/components/layout/quiz/types.ts b/src/components/layout/quiz/types.ts index 7a308ec..32d22cc 100644 --- a/src/components/layout/quiz/types.ts +++ b/src/components/layout/quiz/types.ts @@ -45,6 +45,8 @@ export interface SingleChoiceQuizPanelProps { errorMessage?: string; /** 提交回调,返回用户选择和是否正确 */ onSubmit?: (value: string, isCorrect: boolean) => void; + /** 答错时回调,可返回自定义解析文案覆盖默认 errorMessage */ + onWrongSelect?: (value: string) => string | void; /** 错误回调(可选) */ onError?: (error: string) => void; /** 是否禁用 */ diff --git a/src/pages/chenyun/internalization.tsx b/src/pages/chenyun/internalization.tsx index aecf87d..08f34ff 100644 --- a/src/pages/chenyun/internalization.tsx +++ b/src/pages/chenyun/internalization.tsx @@ -30,6 +30,7 @@ type QuizAnchor = { options: QuizOption[]; // 拖拽题专用 blanks?: { id: string; label: string }[]; + explanation?: string; }; // 星名固定为 chenyun @@ -48,11 +49,11 @@ const QUIZ_ANCHORS: QuizAnchor[] = [ { value: "B", label: "鸟笼比喻", - explanation: "鸟笼比喻是正确的处理好计划与市场的关系的一个发展阶段", }, { value: "C", label: "正确的处理好计划与市场的关系", isCorrect: true }, { value: "D", label: "经济建设的目的论", isCorrect: true }, ], + explanation: "鸟笼比喻是正确的处理好计划与市场的关系的一个发展阶段", }, { id: "quiz-2", @@ -234,7 +235,9 @@ const ChenyunInternalization = () => { label: `${opt.value}. ${opt.label}`, }))} correctAnswer={correctAnswers} - errorMessage="再思考一下,注意选择所有正确答案。" + errorMessage={ + item.explanation || "再思考一下,注意选择所有正确答案。" + } onSubmit={(values: string[], isCorrect: boolean) => { if (isCorrect) { setActiveSuccess(item.id); diff --git a/src/pages/huangyanpei/internalization.tsx b/src/pages/huangyanpei/internalization.tsx index 76f526e..8a7ced9 100644 --- a/src/pages/huangyanpei/internalization.tsx +++ b/src/pages/huangyanpei/internalization.tsx @@ -29,6 +29,7 @@ type QuizAnchor = { type: "single" | "multiple" | "drag"; options: QuizOption[]; blanks?: { id: string; label: string }[]; + explanation?: string; }; const starName = "huangyanpei"; @@ -47,12 +48,12 @@ const QUIZ_ANCHORS: QuizAnchor[] = [ { value: "B", label: "自动控制", - explanation: - "这一工程理论框架成形于20世纪中叶,70年代实现集中控制,新中国成立前,没有相关学科基础、设备与技术条件", }, { value: "C", label: "木工", isCorrect: true }, { value: "D", label: "纽扣科", isCorrect: true }, ], + explanation: + "自动控制”这一工程理论框架成形于20世纪中叶,70年代实现集中控制,在民国时期,没有相关学科基础、设备与技术条件", }, { id: "quiz-2", @@ -75,7 +76,6 @@ const QUIZ_ANCHORS: QuizAnchor[] = [ { value: "C", label: "学习四书五经、八股文", - explanation: "黄炎培认为教育不能只谈书本、脱离实际", }, { value: "D", @@ -83,6 +83,7 @@ const QUIZ_ANCHORS: QuizAnchor[] = [ isCorrect: true, }, ], + explanation: "黄炎培认为教育不能只谈书本、脱离实际", }, { id: "quiz-3", @@ -125,10 +126,10 @@ const QUIZ_ANCHORS: QuizAnchor[] = [ { value: "D", label: "美术设计与制作→影像与影视技术", - explanation: - "两个专业为不同技能方向的学习,前者为平面绘画等,后者以视频为主", }, ], + explanation: + "美术设计与制作专业侧重于平面设计,而影像与影视技术专业侧重于影视特效后期,两者的专业核心课程涉及的软硬件也有差异", }, ]; @@ -286,7 +287,9 @@ const HuangyanpeiInternalization = () => { label: `${opt.value}. ${opt.label}`, }))} correctAnswer={correctAnswers} - errorMessage="再思考一下,注意选择所有正确答案。" + errorMessage={ + item.explanation || "再思考一下,注意选择所有正确答案。" + } onSubmit={(values: string[], isCorrect: boolean) => { if (isCorrect) { setActiveSuccess(item.id); diff --git a/src/pages/huangyanpei/place/place3.tsx b/src/pages/huangyanpei/place/place3.tsx index 6b958c4..c8dc724 100644 --- a/src/pages/huangyanpei/place/place3.tsx +++ b/src/pages/huangyanpei/place/place3.tsx @@ -9,6 +9,7 @@ import { GuideStepsItem, SingleChoiceQuizPanel, } from "@/components"; +import { SuccessAlert } from "@/components/layout"; import { getBackgroundImage, getStaticImage } from "@/lib/utils"; import { useNavigate, useParams } from "react-router-dom"; @@ -38,6 +39,8 @@ const HuangyanpeiPlace3 = () => { const [guide3Step, setGuide3Step] = useState(0); // 光标3的题目显示状态 const [showQuiz3, setShowQuiz3] = useState(false); + // 成功提示状态 + const [showSuccessAlert, setShowSuccessAlert] = useState(false); // 光标1、2的引导对话状态(在两者都浏览后显示) const [guide12Visible, setGuide12Visible] = useState(false); @@ -69,7 +72,7 @@ const HuangyanpeiPlace3 = () => { const handleQuiz3Submit = (value: string, isCorrect: boolean) => { if (isCorrect) { setShowQuiz3(false); - setVisited((prev) => prev.add(3)); + setShowSuccessAlert(true); } }; @@ -212,6 +215,22 @@ const HuangyanpeiPlace3 = () => { onSubmit={handleQuiz3Submit} /> + {/* 成功提示 */} + { + setShowSuccessAlert(false); + setVisited((prev) => { + const next = new Set(prev); + next.add(3); + return next; + }); + }} + onClose={() => { + setShowSuccessAlert(false); + }} + /> + {/* 光标1、2的引导对话 */} { const [showVideo, setShowVideo] = useState(false); // 题目显示状态 const [showQuiz, setShowQuiz] = useState(false); + // 成功提示状态 + const [showSuccessAlert, setShowSuccessAlert] = useState(false); const videoRef = useRef(null); const handleOpenExhibit = (index: 1 | 2 | 3 | 4 | 5) => { @@ -62,6 +65,7 @@ const HuangyanpeiPlace4 = () => { const handleQuizSubmit = (value: string, isCorrect: boolean) => { if (isCorrect) { setShowQuiz(false); + setShowSuccessAlert(true); } }; @@ -225,6 +229,17 @@ const HuangyanpeiPlace4 = () => { zIndex={10001} /> + {/* 成功提示 */} + { + setShowSuccessAlert(false); + }} + onClose={() => { + setShowSuccessAlert(false); + }} + /> + {/* 学习引导(进入场景即显示,与 place1 保持一致) */} { 新中国成立后,黄炎培先生还继续从事教育工作吗?我们现在的中职教育体系,是不是也有他当年的理念呀? - 当然啦!1949年10月19日,71岁的黄炎培出任政务院副总理兼轻工业部部长,依然没有放下他毕生追求的职业教育事业。他把中华职教社的骨干力量全部调到北京,亲自起草《关于改革学制的决定》,第一次把"中等专业学校"正式纳入国家学制,让职业教育有了明确的国家定位。 + 当然啦!1949年10月19日,71岁的黄炎培出任政务院副总理兼轻工业部部长,依然没有放下他毕生追求的职业教育事业。他把中华职教社的骨干力量全部调到北京,亲自起草《关于改革学制的决定》... - 1952年,他又推动建立了上海机械学校、南京航空学校等五所中专,这些学校为国家"一五"计划输送了6.3万名技术工人,为工业发展提供了坚实的人才支撑。 + 第一次把"中等专业学校"正式纳入国家学制,让职业教育有了明确的国家定位。1952年,他又推动建立了上海机械学校、南京航空学校等五所中专,这些学校为国家"一五"计划输送了6.3万名技术工人,为工业发展提供了坚实的人才支撑。 黄炎培先生曾说过:"我要把最后一滴血,滴在职业教育的讲台上。"他用一生践行了这句话,而我们现在中职教育强调的"工学结合、德技并修",正是对他"手脑并用、注重实践"理念的传承和发展。 diff --git a/src/pages/luxun/internalization.tsx b/src/pages/luxun/internalization.tsx index 9035c60..c22d1de 100644 --- a/src/pages/luxun/internalization.tsx +++ b/src/pages/luxun/internalization.tsx @@ -30,6 +30,7 @@ type QuizAnchor = { prompt: string; type: "single" | "multiple"; options: QuizOption[]; + explanation?: string; }; const starName = "luxun"; @@ -62,9 +63,10 @@ const QUIZ_ANCHORS: QuizAnchor[] = [ { value: "D", label: "让青年都去参军", - explanation: "鲁迅先生还是在文学和思想领域培养青年一代,传递思想的火苗", }, ], + explanation: + "虽然鲁迅热爱革命,但他主要通过文学社团、木刻艺术和纪念文章来教育和启发青年,而不是通过参军来培养青年。", }, { id: "quiz-3", @@ -189,7 +191,9 @@ const LuxunInternalization = () => { label: `${opt.value}. ${opt.label}`, }))} correctAnswer={correctAnswers} - errorMessage="再思考一下,注意选择所有正确答案。" + errorMessage={ + item.explanation || "再思考一下,注意选择所有正确答案。" + } onSubmit={(values: string[], isCorrect: boolean) => { if (isCorrect) { setActiveSuccess(item.id); diff --git a/src/pages/luxun/place/place1.tsx b/src/pages/luxun/place/place1.tsx index f54c76f..9fb8a6e 100644 --- a/src/pages/luxun/place/place1.tsx +++ b/src/pages/luxun/place/place1.tsx @@ -5,10 +5,11 @@ import { Image, Title, Cursor, + StudyGuideModal, } from "@/components"; import { useNavigate, useParams } from "react-router-dom"; import { getBackgroundImage, getStaticImage } from "@/lib/utils"; -import { useState } from "react"; +import { useState, useEffect } from "react"; // starName 固定为 luxun const starName = "luxun"; @@ -25,8 +26,18 @@ const LuxunPlace1 = () => { moduleName: string; }>(); + // 学习引导弹窗 + const [showGuideModal, setShowGuideModal] = useState(true); + // 对话结束后的学习引导弹窗 + const [showAfterDialogGuide, setShowAfterDialogGuide] = useState(false); + const [afterDialogGuideShown, setAfterDialogGuideShown] = useState(false); // 引导对话显示状态 - const [visible, setVisible] = useState(true); + const [visible, setVisible] = useState(false); + // 浏览完展品后的对话显示状态 + const [showAfterExhibitDialog, setShowAfterExhibitDialog] = useState(false); + const [afterExhibitDialogShown, setAfterExhibitDialogShown] = useState(false); + // 对话结束后是否显示前进按钮 + const [showForwardButton, setShowForwardButton] = useState(false); // 当前激活的展品 ID(只存 ID,不直接存路径,便于作为唯一标识) const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | null>(null); // 已浏览展品的 ID 集合 @@ -39,6 +50,14 @@ const LuxunPlace1 = () => { const progressCount = visited.size; const total = 2; const completed = progressCount >= total; + + // 当两个展品都浏览完成后,自动显示对话 + useEffect(() => { + if (completed && !afterExhibitDialogShown) { + setShowAfterExhibitDialog(true); + setAfterExhibitDialogShown(true); + } + }, [completed, afterExhibitDialogShown]); const subtitle = completed ? "探索鲁迅故居一楼客厅(已完成)" : `探索鲁迅故居一楼客厅(${progressCount}/${total})`; @@ -85,8 +104,8 @@ const LuxunPlace1 = () => { read={visited.has(2)} /> - {/* 继续前进 - 仅在完成所有展品后显示 */} - {completed && ( + {/* 继续前进 - 仅在完成所有展品且对话结束后显示 */} + {showForwardButton && ( { { if (activeExhibitId !== null) { setVisited((prev) => { @@ -113,19 +137,81 @@ const LuxunPlace1 = () => { }} /> + {/* 学习引导词 */} + { + setShowGuideModal(false); + setVisible(true); + }} + > + {`同学你好,欢迎来到走进故居-对话学习模块! +进入鲁迅故居后,我们一起来了解鲁迅先生经历的5个阶段:"风雨前夕的思想淬炼"->"杂文集里的匕首与投枪"->"历史新编中的现实呐喊"->"为亡友编纂的精神丰碑"->"6平方米的红色庇护所";`} + + {/* 引导 */} { + setVisible(nextVisible); + if (!nextVisible && !afterDialogGuideShown) { + setAfterDialogGuideShown(true); + setShowAfterDialogGuide(true); + } + }} showMask={true} highlightSelectors={[]} > - - 同学你好,欢迎来到走进故居-对话学习模块! - 进入鲁迅故居纪念馆后,我们一起来了解鲁迅先生的思想历程和文学成就。 + + 小沪!我知道鲁迅是1933年搬到大陆新村9号的,那在这之前他为什么会选择来到上海,又有哪些思想转变呢? - 在这个场景中,我们将探索鲁迅故居一楼客厅,了解风雨前夕的思想淬炼。 + 你问得很关键!而1927年是鲁迅思想的重要转折点,这一年他在广州亲历了"四一二"反革命政变,亲眼看见进步青年和革命志士倒在血泊中,曾经对"温和改革"的幻想彻底破灭。 + + + 此前他写下《狂人日记》《阿Q正传》批判封建礼教,参加语丝社针砭时弊,但始终在"彷徨"中摸索救国之路。广州的血雨腥风,让他认清了反动派的真面目。 + + + + {/* 对话结束后的学习引导 */} + setShowAfterDialogGuide(false)} + ailgn="left" + > + 1、场景中出现动态光点的展品表示未浏览,可通过点击光点来了解展品背后的故事,通过滚轮可以放大展品,浏览展品后蓝色动态光点会变为已浏览状态; + {"\n"} + 2、在学习过程中会掉落拼图碎片,拼图碎片会自动收入拼图盒中,拼图盒可以点开查看当前拼图收集情况,点击单个拼图可以回到获得拼图的场景再次学习; + {"\n"} + 3、所有动态光点的展品全部学习后才能进入下一个场景学习; + + + {/* 浏览完展品后的对话 */} + { + setShowAfterExhibitDialog(nextVisible); + if (!nextVisible) { + setShowForwardButton(true); + } + }} + showMask={true} + highlightSelectors={[]} + > + + 刚到上海的鲁迅住在哪里,又在做什么? + + + 1927年10月,鲁迅带着许广平来到上海,先住进了虹口区横浜路景云里。在景云里的两年半,他结识了冯雪峰等共产党员,参与发起中国左翼作家联盟,从"独战的英雄"转变为革命文艺战线的旗手。 + + + 这段时间他写下《三闲集》《二心集》,表达他在当时历史条件下针对社会现象、文化问题和论战的看法与社会批判,此间还翻译了大量马列文艺理论著作,为此后的战斗打下了坚实思想基础。 + + + 鲁迅在发起成立左联后,为躲避国民党当局监视,1930年5月,与许广平、周海婴迁居到拉摩斯公寓。1933年4月,受战火纷扰影响,为安全及健康计,同时也为了更方便开展革命文化工作,鲁迅以"内山书店职员"的名义,搬到了大陆新村9号。 + + + 这个过程的确十分曲折。
diff --git a/src/pages/luxun/place/place2.tsx b/src/pages/luxun/place/place2.tsx index 9848a2d..270002d 100644 --- a/src/pages/luxun/place/place2.tsx +++ b/src/pages/luxun/place/place2.tsx @@ -1,4 +1,12 @@ -import { ExhibitOverlay, Image, Title, Cursor } from "@/components"; +import { + ExhibitOverlay, + Image, + Title, + Cursor, + StudyGuideModal, + GuideSteps, + GuideStepsItem, +} from "@/components"; import { useNavigate, useParams } from "react-router-dom"; import { getBackgroundImage, getStaticImage } from "@/lib/utils"; import { useState } from "react"; @@ -19,13 +27,57 @@ const LuxunPlace2 = () => { moduleName: string; }>(); + // 学习引导弹窗 + const [showGuideModal, setShowGuideModal] = useState(true); + const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | 3 | null>( null ); const [visited, setVisited] = useState>(new Set()); + // 光标1的引导对话状态 + const [guide1Visible, setGuide1Visible] = useState(false); + const [guide1Step, setGuide1Step] = useState(0); + + // 光标2的引导对话状态 + const [guide2Visible, setGuide2Visible] = useState(false); + const [guide2Step, setGuide2Step] = useState(0); + const handleOpenExhibit = (index: 1 | 2 | 3) => { - setActiveExhibitId(index); + if (index === 1) { + // 光标1:点击时同时打开展品和引导对话 + setActiveExhibitId(1); + setGuide1Visible(true); + setGuide1Step(0); + } else if (index === 2) { + // 光标2:点击时同时打开展品和引导对话 + setActiveExhibitId(2); + setGuide2Visible(true); + setGuide2Step(0); + } else { + // 光标3:直接打开 + setActiveExhibitId(index); + } + }; + + // 监听光标1的引导对话步骤变化 + const handleGuide1StepChange = (step: number) => { + setGuide1Step(step); + }; + + // 监听光标1的引导对话关闭 + const handleGuide1VisibleChange = (visible: boolean) => { + setGuide1Visible(visible); + }; + + // 监听光标2的引导对话步骤变化 + const handleGuide2StepChange = (step: number) => { + setGuide2Step(step); + }; + + // 监听光标2的引导对话关闭 + const handleGuide2VisibleChange = (visible: boolean) => { + setGuide2Visible(visible); }; const progressCount = visited.size; @@ -63,19 +115,21 @@ const LuxunPlace2 = () => { }} /> - {/* 展品 */} + {/* 光标1 */} handleOpenExhibit(1)} read={visited.has(1)} /> + {/* 光标2 */} handleOpenExhibit(2)} read={visited.has(2)} /> + {/* 光标3 */} { { if (activeExhibitId !== null) { setVisited((prev) => { @@ -108,6 +167,58 @@ const LuxunPlace2 = () => { setActiveExhibitId(null); }} /> + + {/* 光标1的引导对话 */} + + + 小沪,这里的《且介亭杂文》就是鲁迅先生在大陆新村9号创作的吧,有人将先生的杂文评价为"匕首与投枪",《且介亭杂文》中有具体体现吗? + + + 当然有!20世纪30年代,国民党"文化围剿"愈烈,进步思想遭严控,鲁迅在大陆新村9号创作出《且介亭杂文》等集子。这些杂文聚焦文化乱象与社会沉疴,篇幅精炼却直击要害,像匕首般刺穿虚伪表象,似投枪般直戳问题核心... + + + 用锋利文字与黑暗势力对峙,成为那个时代最具战斗力的思想武器,"匕首与投枪"的赞誉恰是其战斗性的生动写照。 + + + + {/* 光标2的引导对话 */} + + + 那《南腔北调集》这个名字又有什么深意呢? + + + 这是鲁迅的自嘲,他曾说"我不会说绵软的苏白,不会打响亮的京腔,不入调,不入流",所以戏称自己的文章是"南腔北调"。这本书里的《〈守常全集》题记》,赞美了李大钊同志,说"他的遗文却将永驻,因为这是先驱者的遗产,革命史上的丰碑。" + + + + {/* 学习引导 */} + setShowGuideModal(false)} + ailgn="left" + > + 1、场景中出现动态光点的展品表示未浏览,可通过点击光点来了解展品背后的故事,通过滚轮可以放大展品,浏览展品后蓝色动态光点会变为已浏览状态; + {"\n"} + 2、在学习过程中会掉落拼图碎片,拼图碎片会自动收入拼图盒中,拼图盒可以点开查看当前拼图收集情况,点击单个拼图可以回到获得拼图的场景再次学习; + {"\n"} + 3、所有动态光点的展品全部学习后才能进入下一个场景学习; +
); }; diff --git a/src/pages/luxun/place/place3.tsx b/src/pages/luxun/place/place3.tsx index 39ba363..b3b41c8 100644 --- a/src/pages/luxun/place/place3.tsx +++ b/src/pages/luxun/place/place3.tsx @@ -1,7 +1,17 @@ -import { ExhibitOverlay, Image, Title, Cursor } from "@/components"; +import { + ExhibitOverlay, + Image, + Title, + Cursor, + StudyGuideModal, + GuideSteps, + GuideStepsItem, + SingleChoiceQuizPanel, +} from "@/components"; import { useNavigate, useParams } from "react-router-dom"; import { getBackgroundImage, getStaticImage } from "@/lib/utils"; import { useState } from "react"; +import SuccessAlert from "@/components/layout/alert/success-alert"; // starName 固定为 luxun const starName = "luxun"; @@ -15,19 +25,84 @@ const exhibitSrcMap: Record<1 | 2 | 3 | 4 | 5, string> = { 5: "luxun/place3/10", }; +const quiz2DefaultError = "再想一想,注意题干中的时间和提示信息哦~"; +const quiz2Explanations: Record = { + A: "鲁迅身处旧中国文艺思惰僵化、缺乏革新活力的时代,他认为“没有拿来的,人不能自成为新人”。翻译外国作品正是为了打破文化封闭,为中国文艺引进新思想、新方法,为沉寂的文坛注入新血液。", + B: "当时中国青年普遍受传统旧思想束缚,接触先进文化的渠道有限。鲁迅希望通过翻译外国进步作品,让青年接触世界范围内的先进文化理念、思想成果,拓宽视野、启发心智,助力青年觉醒。", + C: "鲁迅的核心斗争方式是“以笔为刃”,通过文学创作、翻译、杂文批判等方式开展思想启蒙和文化斗争,从未直接参与武装革命的战略部署。", + D: "在国民党“文化围剿”、进步思想遭严控的背景下,鲁迅将翻译视为重要的斗争武器——通过引进外国进步文学、马克思主义理论等,揭露旧中国的黑暗与愚昧,唤醒民众的思想意识,助力思想启蒙运动。", +}; + +// 光标5-题目:纪念瞿秋白的译文集 +const quiz5DefaultError = "再想一想,结合前面的旁白内容哦~"; +const quiz5Explanations: Record = { + A: "《仿自由书》是鲁迅在上海创作的杂文集,收录了1933年所作的多篇杂文,核心内容是针砭国民党当局的虚伪统治、批判社会乱象,并非为纪念瞿秋白编校的译文集。", + B: "《南腔北调集》是鲁迅的一部杂文集,收录了1927年至1933年的杂文作品,书名源于鲁迅对自己文章“不入调、不入流”的自嘲,内容涵盖文化批判、社会评论等,与纪念瞿秋白及译文集无关。", + C: "恭喜你,选对啦。", + D: "《故事新编》是鲁迅的历史小说集,酝酿多年后在大陆新村9号完成定稿。作品以神话传说、历史典故为载体借古讽今,批判现实社会的腐朽与愚昧,并非译文集,更与纪念瞿秋白无关。", +}; + const LuxunPlace3 = () => { const navigate = useNavigate(); const { moduleName } = useParams<{ moduleName: string; }>(); + // 学习引导弹窗 + const [showGuideModal, setShowGuideModal] = useState(true); + const [activeExhibitId, setActiveExhibitId] = useState< 1 | 2 | 3 | 4 | 5 | null >(null); const [visited, setVisited] = useState>(new Set()); + // 光标1的引导对话状态 + const [guide1Visible, setGuide1Visible] = useState(false); + const [guide1Step, setGuide1Step] = useState(0); + + // 光标2的题目状态 + const [quiz2Visible, setQuiz2Visible] = useState(false); + const [successAlert2Visible, setSuccessAlert2Visible] = useState(false); + const [quiz2Error, setQuiz2Error] = useState(quiz2DefaultError); + + // 光标3的引导对话状态 + const [guide3Visible, setGuide3Visible] = useState(false); + const [guide3Step, setGuide3Step] = useState(0); + + // 光标4的引导对话状态 + const [guide4Visible, setGuide4Visible] = useState(false); + const [guide4Step, setGuide4Step] = useState(0); + + // 光标5的题目 & 成功提示 & 引导对话状态 + const [quiz5Visible, setQuiz5Visible] = useState(false); + const [quiz5Error, setQuiz5Error] = useState(quiz5DefaultError); + const [successAlert5Visible, setSuccessAlert5Visible] = useState(false); + const [guide5Visible, setGuide5Visible] = useState(false); + const [guide5Step, setGuide5Step] = useState(0); + const handleOpenExhibit = (index: 1 | 2 | 3 | 4 | 5) => { - setActiveExhibitId(index); + if (index === 1) { + // 光标1:点击时同时打开展品和引导对话 + setActiveExhibitId(1); + setGuide1Visible(true); + setGuide1Step(0); + } else if (index === 2) { + // 光标2:只打开展品(带描述) + setActiveExhibitId(2); + } else if (index === 3) { + // 光标3:点击时同时打开展品和引导对话 + setActiveExhibitId(3); + setGuide3Visible(true); + setGuide3Step(0); + } else if (index === 4) { + // 光标4:点击时同时打开展品和引导对话 + setActiveExhibitId(4); + setGuide4Visible(true); + setGuide4Step(0); + } else { + // 光标5:先打开展品,关闭后进入答题 + setActiveExhibitId(index); + } }; const progressCount = visited.size; @@ -65,31 +140,35 @@ const LuxunPlace3 = () => { }} /> - {/* 展品 */} + {/* 光标1 */} handleOpenExhibit(1)} size={0.6} read={visited.has(1)} /> + {/* 光标2 */} handleOpenExhibit(2)} size={0.6} read={visited.has(2)} /> + {/* 光标3 */} handleOpenExhibit(3)} size={0.6} read={visited.has(3)} /> + {/* 光标4 */} handleOpenExhibit(4)} size={0.6} read={visited.has(4)} /> + {/* 光标5 */} handleOpenExhibit(5)} @@ -111,17 +190,266 @@ const LuxunPlace3 = () => { { - if (activeExhibitId !== null) { + if (activeExhibitId === 2) { + // 光标2:关闭展品框后显示题目 + setActiveExhibitId(null); + setQuiz2Visible(true); + } else if (activeExhibitId === 5) { + // 光标5:关闭展品框后显示题目 + setActiveExhibitId(null); + setQuiz5Visible(true); + } else if (activeExhibitId === 1 || activeExhibitId === 3) { + // 光标1和光标3:只关闭展品,不标记为已读(等对话关闭时再标记) + setActiveExhibitId(null); + } else if (activeExhibitId === 4) { + // 光标4:只关闭展品,不标记为已读(等对话关闭时再标记) + setActiveExhibitId(null); + } else { + // 其他光标:正常关闭并标记为已读 + if (activeExhibitId !== null) { + setVisited((prev) => { + const next = new Set(prev); + next.add(activeExhibitId); + return next; + }); + } + setActiveExhibitId(null); + } + }} + /> + + {/* 光标1的引导对话 */} + { + setGuide1Visible(visible); + if (!visible) { + // 对话关闭时,标记光标1为已读 setVisited((prev) => { const next = new Set(prev); - next.add(activeExhibitId); + next.add(1); return next; }); } - setActiveExhibitId(null); + }} + currentStep={guide1Step} + onStepChange={setGuide1Step} + showMask={false} + highlightSelectors={[]} + zIndex={10000} + > + + 小沪,书架上还有《故事新编》,这不是历史小说吗?鲁迅为什么要在这个时期写古代故事呢? + + + 《故事新编》是鲁迅酝酿十几年的作品,最终在大陆新村9号完成定稿。表面上写的是神话传说和历史典故,实则句句都在影射现实。当时反动派妄图用复古思想麻痹民众,鲁迅就用"故事新编"的方式,借古讽今,唤醒民众。 + + + + {/* 光标2的题目 */} + { + if (isCorrect) { + setQuiz2Error(quiz2DefaultError); + setQuiz2Visible(false); + setSuccessAlert2Visible(true); + } + }} + onWrongSelect={(value) => { + const explanation = quiz2Explanations[value]; + if (explanation) { + setQuiz2Error(explanation); + return explanation; + } + setQuiz2Error(quiz2DefaultError); + return quiz2DefaultError; + }} + zIndex={10001} + /> + + {/* 光标2的成功提示 */} + { + setSuccessAlert2Visible(false); + // 标记光标2为已读 + setVisited((prev) => { + const next = new Set(prev); + next.add(2); + return next; + }); }} /> + + {/* 光标3的引导对话 */} + { + setGuide3Visible(visible); + if (!visible) { + // 对话关闭时,标记光标3为已读 + setVisited((prev) => { + const next = new Set(prev); + next.add(3); + return next; + }); + } + }} + currentStep={guide3Step} + onStepChange={setGuide3Step} + showMask={false} + highlightSelectors={[]} + zIndex={10000} + > + + 我还看到书架上有很多翻译作品,这也是他在这儿完成的吗? + + + 没错!鲁迅在这儿翻译了《死魂灵》《表》等大量外国作品。他说"没有拿来的,人不能自成为新人",就是想通过翻译,为中国文艺引进新思想、新方法,让更多人看到世界的真相,找到救国的道路。 + + + + {/* 光标4的引导对话 */} + { + setGuide4Visible(visible); + if (!visible) { + // 对话关闭时,标记光标4为已读 + setVisited((prev) => { + const next = new Set(prev); + next.add(4); + return next; + }); + } + }} + currentStep={guide4Step} + onStepChange={setGuide4Step} + showMask={false} + highlightSelectors={[]} + zIndex={10000} + > + + 小沪,这两本书看起来格外厚重,它和鲁迅在这儿的经历有什么关联呢? + + + 这不是鲁迅的著作,却是他在大陆新村9号倾注了全部心血的作品——为亡友瞿秋白编辑的译文集《海上述林》。1935年6月,瞿秋白被国民党反动派杀害,鲁迅悲痛万分,当即决定要为挚友出版译文集,让他的思想和精神流传下去。 + + + + {/* 光标5的题目 */} + { + if (isCorrect) { + setQuiz5Error(quiz5DefaultError); + setQuiz5Visible(false); + setSuccessAlert5Visible(true); + } + }} + onWrongSelect={(value) => { + const explanation = quiz5Explanations[value]; + if (explanation) { + setQuiz5Error(explanation); + return explanation; + } + setQuiz5Error(quiz5DefaultError); + return quiz5DefaultError; + }} + zIndex={10001} + /> + + {/* 光标5的成功提示 */} + { + setSuccessAlert5Visible(false); + // 标记光标5为已读 + setVisited((prev) => { + const next = new Set(prev); + next.add(5); + return next; + }); + // 打开光标5的引导对话 + setGuide5Visible(true); + setGuide5Step(0); + }} + /> + + {/* 光标5的引导对话 */} + { + setGuide5Visible(visible); + }} + currentStep={guide5Step} + onStepChange={setGuide5Step} + showMask={false} + highlightSelectors={[]} + zIndex={10000} + > + + 原来这本书不仅是译文集,更是两人革命友谊和共同信仰的见证! + + + 太对了!鲁迅和瞿秋白的故事不仅在于《海上述林》的字里行间,这座小楼的三楼也藏着他们为了革命事业并肩战斗的初心。 + + + + {/* 学习引导 */} + setShowGuideModal(false)} + ailgn="left" + > + 1、场景中出现动态光点的展品表示未浏览,可通过点击光点来了解展品背后的故事,通过滚轮可以放大展品,浏览展品后蓝色动态光点会变为已浏览状态; + {"\n"} + 2、在学习过程中会掉落拼图碎片,拼图碎片会自动收入拼图盒中,拼图盒可以点开查看当前拼图收集情况,点击单个拼图可以回到获得拼图的场景再次学习; + {"\n"} + 3、所有动态光点的展品全部学习后才能进入下一个场景学习; +
); }; diff --git a/src/pages/luxun/place/place4.tsx b/src/pages/luxun/place/place4.tsx index 406ad8b..a834303 100644 --- a/src/pages/luxun/place/place4.tsx +++ b/src/pages/luxun/place/place4.tsx @@ -1,7 +1,18 @@ -import { ExhibitOverlay, Image, Title, Cursor } from "@/components"; +import { + ExhibitOverlay, + GuideSteps, + GuideStepsItem, + Image, + Title, + Cursor, + StudyGuideModal, + SingleChoiceQuizPanel, + Video, +} from "@/components"; import { useNavigate, useParams } from "react-router-dom"; -import { getBackgroundImage, getStaticImage } from "@/lib/utils"; +import { getBackgroundImage, getPublicPath, getStaticImage } from "@/lib/utils"; import { useState } from "react"; +import SuccessAlert from "@/components/layout/alert/success-alert"; // starName 固定为 luxun const starName = "luxun"; @@ -13,18 +24,50 @@ const exhibitSrcMap: Record<1 | 2 | 3, string> = { 3: "luxun/place4/展品13", }; +const quizDefaultError = "请结合刚刚的旁白内容,再思考一下吧!"; +const quizExplanations: Record = { + A: "陈独秀与鲁迅有思想交往,但他并未在这间“红色庇护所”中避难、与鲁迅夜谈革命议题。", + B: "恭喜你,选对啦。", + C: "李大钊于1927年牺牲,时间上不符合这间客房被用作“红色庇护所”的背景。", + D: "周恩来虽长期在上海从事革命活动,但并未在这里避难并与鲁迅夜谈。", +}; + const LuxunPlace5 = () => { const navigate = useNavigate(); const { moduleName } = useParams<{ moduleName: string; }>(); + // 学习引导弹窗 + const [showGuideModal, setShowGuideModal] = useState(true); + const [introGuideVisible, setIntroGuideVisible] = useState(false); + const [introGuideStep, setIntroGuideStep] = useState(0); + const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | 3 | null>( null ); const [visited, setVisited] = useState>(new Set()); + // 光标2的题目状态 + const [quizVisible, setQuizVisible] = useState(false); + const [quizError, setQuizError] = useState(quizDefaultError); + const [successAlertVisible, setSuccessAlertVisible] = useState(false); + + // 光标3的引导对话状态 + const [guide3Visible, setGuide3Visible] = useState(false); + const [guide3Step, setGuide3Step] = useState(0); + + // 结尾视频与对话 + const [showEndingVideo, setShowEndingVideo] = useState(false); + const [endingGuideVisible, setEndingGuideVisible] = useState(false); + const handleOpenExhibit = (index: 1 | 2 | 3) => { + if (index === 3) { + setActiveExhibitId(3); + setGuide3Visible(true); + setGuide3Step(0); + return; + } setActiveExhibitId(index); }; @@ -83,10 +126,11 @@ const LuxunPlace5 = () => { {completed && ( { - navigate(`/${moduleName}/${starName}/home`); + // 完成后先播放视频,不立即跳转页面 + setShowEndingVideo(true); }} /> )} @@ -94,17 +138,183 @@ const LuxunPlace5 = () => { { - if (activeExhibitId !== null) { - setVisited((prev) => { - const next = new Set(prev); - next.add(activeExhibitId); - return next; - }); + if (activeExhibitId === 2) { + setActiveExhibitId(null); + setQuizVisible(true); + return; } + if (activeExhibitId === 3) { + // 对话关闭时再标记已读 + setActiveExhibitId(null); + return; + } + setVisited((prev) => { + const next = new Set(prev); + if (activeExhibitId !== null) { + next.add(activeExhibitId); + } + return next; + }); setActiveExhibitId(null); }} /> + + {/* 学习引导结束后的对话 */} + + + 你说的是这间小小的客房吗,这里为什么会被称为"红色庇护所"呢? + + + 你可别小看这间仅6平方米的客房,在白色恐怖笼罩的1933年至1936年,这里是很多共产党人的"安全港湾"。1933年,瞿秋白夫妇第三次到鲁迅家避难,就秘密住进了这里。 + + + 当时反动派到处搜捕共产党人,鲁迅冒着生命危险掩护他们,两人常彻夜长谈。瞿秋白的夫人杨之华回忆道:"秋白和鲁迅在一起,往往感觉夜太短。深刻的友谊的交谈,从政治到文艺,从实际到理论,从希腊到莫斯科,轻松,愉快,活泼。" + + + + {/* 光标2的题目 */} + { + if (isCorrect) { + setQuizError(quizDefaultError); + setQuizVisible(false); + setSuccessAlertVisible(true); + } + }} + onWrongSelect={(value) => { + const explanation = quizExplanations[value]; + if (explanation) { + setQuizError(explanation); + return explanation; + } + setQuizError(quizDefaultError); + return quizDefaultError; + }} + zIndex={10001} + /> + + {/* 光标2的成功提示 */} + { + setSuccessAlertVisible(false); + setVisited((prev) => { + const next = new Set(prev); + next.add(2); + return next; + }); + }} + /> + + {/* 光标3的引导对话 */} + { + setGuide3Visible(visible); + if (!visible) { + setVisited((prev) => { + const next = new Set(prev); + next.add(3); + return next; + }); + } + }} + currentStep={guide3Step} + onStepChange={setGuide3Step} + showMask={false} + highlightSelectors={[]} + zIndex={10000} + > + + 除了瞿秋白,还有其他共产党人来过这里吗 + + + 当然!1936年4月,中共中央特派员冯雪峰到上海开展工作,也先住进了这间客房。冯雪峰把红军长征胜利、遵义会议召开的消息告诉鲁迅,还带来了毛泽东同志提出的抗日民族统一战线主张。 + + + 鲁迅听后格外振奋,激动地说"我做一个小兵还是胜任的,用笔!",这句话也成了他晚年投身抗日救亡运动的誓言。 + + + + {/* 结尾视频播放 */} + {showEndingVideo && ( +
); }; diff --git a/src/pages/luxun/reflection/scene1.tsx b/src/pages/luxun/reflection/scene1.tsx index 82cae27..600dbd7 100644 --- a/src/pages/luxun/reflection/scene1.tsx +++ b/src/pages/luxun/reflection/scene1.tsx @@ -1,6 +1,6 @@ import { useState, useEffect } from "react"; import { useNavigate, useParams } from "react-router-dom"; -import { Image } from "@/components"; +import { GuideSteps, GuideStepsItem, Image } from "@/components"; import SuccessAlert from "@/components/layout/alert/success-alert"; import { getBackgroundImage, getStaticImage } from "@/lib/utils"; @@ -77,8 +77,13 @@ const LuxunReflectionScene1 = () => { const [showSuccessAlert, setShowSuccessAlert] = useState(false); // 是否全部完成 const [allCompleted, setAllCompleted] = useState(false); + // 引导对话是否显示 + const [guideVisible, setGuideVisible] = useState(true); const progress = clickedCities.size; + // 当前应当点亮的城市索引(按照 cityConfig 顺序) + const nextCityIndex = progress; + const nextCityId = cityConfig[nextCityIndex]?.id; const totalTasks = cityConfig.length; // 检查是否全部完成 @@ -90,7 +95,9 @@ const LuxunReflectionScene1 = () => { }, [progress, totalTasks, allCompleted]); const handleCityClick = (cityId: number) => { + // 仅允许按照 cityConfig 顺序点击 if (clickedCities.has(cityId)) return; // 已点击过的不再处理 + if (cityId !== nextCityId) return; // 不是当前应点击的城市则不响应 setClickedCities((prev) => { const next = new Set(prev); @@ -130,6 +137,7 @@ const LuxunReflectionScene1 = () => {
{cityConfig.map((city) => { const isClicked = clickedCities.has(city.id); + const isNext = city.id === nextCityId; return (
{ }} > {/* 点一点提示 - 始终显示 */} - {!isClicked && ( + {/* 仅对当前应点击的城市显示点一点提示 */} + {!isClicked && isNext && (
{ alt="点一点" /> {
{/* 任务展示窗口 */} -
- {allCompleted - ? // 全部完成后显示详细信息 - cityConfig.map((city) => ( +
+ {allCompleted ? ( + // 全部完成后显示详细信息 +
+ {cityConfig.map((city) => (
{city.location}
@@ -246,29 +256,53 @@ const LuxunReflectionScene1 = () => { {city.description}
- )) - : // 未完成时显示任务列表 - cityConfig.map((city, index) => { - const isCompleted = clickedCities.has(city.id); - return ( -
- {index + 1}.点击图标{city.location} -
- ); - })} + ))} +
+ ) : ( +
+ { + // 未完成时显示任务列表 + cityConfig.map((city, index) => { + const isCompleted = clickedCities.has(city.id); + return ( +
+ {index + 1}.点击图标{city.location} +
+ ); + }) + } +
+ )}
{/* 成功提示弹窗 */} + {/* 学习引导对话 */} + + + 跟着先生的脚步, 解锁文字里的温度与力量! + + + 请根据年代由远及近的顺序,依“手指提示”点亮先生的创作足迹,解锁更多的故事背景! + +
); }; diff --git a/src/pages/luxun/reflection/scene2.tsx b/src/pages/luxun/reflection/scene2.tsx index 274615d..0cedae6 100644 --- a/src/pages/luxun/reflection/scene2.tsx +++ b/src/pages/luxun/reflection/scene2.tsx @@ -1,8 +1,7 @@ import { useState, useEffect, useMemo, useCallback } from "react"; import { useNavigate, useParams } from "react-router-dom"; -import { Image, DragFill } from "@/components"; +import { Image, DragFill, GuideSteps, GuideStepsItem } from "@/components"; import type { DragFillResult } from "@/components"; -import SuccessAlert from "@/components/layout/alert/success-alert"; import ErrorAlert from "@/components/layout/alert/error-alert"; import { getBackgroundImage, getStaticImage } from "@/lib/utils"; @@ -149,13 +148,15 @@ const LuxunReflectionScene2 = () => { // DragFill 的值 const [dragFillValue, setDragFillValue] = useState([]); - // 是否显示成功提示 - const [showSuccessAlert, setShowSuccessAlert] = useState(false); // 是否全部完成 const [allCompleted, setAllCompleted] = useState(false); // 错误提示相关状态 const [showErrorAlert, setShowErrorAlert] = useState(false); const [errorHint, setErrorHint] = useState(""); + // 引导对话是否显示 + const [guideVisible, setGuideVisible] = useState(true); + // 通关提示对话是否显示 + const [completionGuideVisible, setCompletionGuideVisible] = useState(false); // 转换为 DragFill 的 options const options = useMemo( @@ -243,14 +244,11 @@ const LuxunReflectionScene2 = () => { useEffect(() => { if (progress === totalTasks && !allCompleted) { setAllCompleted(true); - setShowSuccessAlert(true); + // 任务完成后自动显示通关提示对话 + setCompletionGuideVisible(true); } }, [progress, totalTasks, allCompleted]); - const handleSuccessAlertClose = () => { - setShowSuccessAlert(false); - }; - const handleErrorAlertClose = () => { setShowErrorAlert(false); setErrorHint(""); @@ -518,14 +516,6 @@ const LuxunReflectionScene2 = () => {
- {/* 成功提示弹窗 */} - - {/* 错误提示弹窗 */} { onClose={handleErrorAlertClose} onMaskClick={handleErrorAlertClose} /> + + {/* 学习引导对话 */} + + + 这些线索藏在先生的文字里,长按卡片拖到对应地标旁,还原创作故事! + + + + {/* 通关提示对话 */} + + + 你读懂了鲁迅文字与土地的联结,再深入看看文字里的初心! + + ); }; diff --git a/src/pages/luxun/reflection/scene3.tsx b/src/pages/luxun/reflection/scene3.tsx index 5b9394d..f43f8b8 100644 --- a/src/pages/luxun/reflection/scene3.tsx +++ b/src/pages/luxun/reflection/scene3.tsx @@ -1,7 +1,7 @@ import { getBackgroundImage, getStaticImage } from "@/lib/utils"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { useNavigate, useParams } from "react-router-dom"; -import { Image } from "@/components"; +import { Image, GuideSteps, GuideStepsItem } from "@/components"; import { SingleChoiceQuizPanel } from "@/components/layout/quiz"; const starName = "luxun"; @@ -21,11 +21,22 @@ const LuxunReflectionScene3 = () => { const [completedQuiz1, setCompletedQuiz1] = useState(false); // 题目1是否完成 const [completedQuiz2, setCompletedQuiz2] = useState(false); // 题目2是否完成 const [showSummary, setShowSummary] = useState(false); // 是否显示总结 + const [completionGuideVisible, setCompletionGuideVisible] = useState(false); // 通关提示对话是否显示 const allCompleted = completedQuiz1 && completedQuiz2; const progress = (completedQuiz1 ? 1 : 0) + (completedQuiz2 ? 1 : 0); const totalTasks = 2; + // 当显示总结后,延迟1秒显示通关提示对话 + useEffect(() => { + if (showSummary) { + const timer = setTimeout(() => { + setCompletionGuideVisible(true); + }, 1000); + return () => clearTimeout(timer); + } + }, [showSummary]); + // 点击"鲁迅1"的处理 const handleLuxun1Click = () => { setShowTopics(true); @@ -277,6 +288,23 @@ const LuxunReflectionScene3 = () => { errorMessage='不是哦,先生的创作从不是为了自己哦!"请回忆先生"弃医从文"的初心。"' onSubmit={handleQuiz2Submit} /> + + {/* 通关提示对话 */} + { + if (!visible) { + setCompletionGuideVisible(false); + } + }} + showMask={false} + highlightSelectors={[]} + zIndex={10000} + > + + 恭喜你读懂了鲁迅的文字与初心,愿这份精神能伴你前行 + + ); }; diff --git a/src/pages/sunzhongshan/internalization.tsx b/src/pages/sunzhongshan/internalization.tsx index 54b7ee3..f8b870f 100644 --- a/src/pages/sunzhongshan/internalization.tsx +++ b/src/pages/sunzhongshan/internalization.tsx @@ -30,6 +30,7 @@ type QuizAnchor = { options: QuizOption[]; // 拖拽题专用 blanks?: { id: string; label: string }[]; + explanation?: string; }; // 星名固定为 sunzhongshan @@ -53,8 +54,6 @@ const QUIZ_ANCHORS: QuizAnchor[] = [ value: "B", label: "当时的中国正遭受帝国主义列强的野蛮侵略和封建专制制度的腐朽统治,对于新时代的意义不大", - explanation: - '"振兴中华"需要每一代人的努力,先生当年在上海撰写的《实业计划》里如今已经实现的那些宏伟计划就是我国国家代代相传的结果', }, { value: "C", @@ -68,6 +67,8 @@ const QUIZ_ANCHORS: QuizAnchor[] = [ isCorrect: true, }, ], + explanation: + "“振兴中华”需要每一代人的努力,先生当年在上海撰写的《实业计划》里如今已经实现的那些宏伟计划就是我们国家代代相传的结果。答案B的观点错误", }, { id: "quiz-2", @@ -234,7 +235,9 @@ const ChenyunInternalization = () => { label: `${opt.value}. ${opt.label}`, }))} correctAnswer={correctAnswers} - errorMessage="再想一想,确保选择了所有正确答案~" + errorMessage={ + item.explanation || "再想一想,确保选择了所有正确答案~" + } onSubmit={(values: string[], isCorrect: boolean) => { if (isCorrect) { setActiveSuccess(item.id);