feat: 更新音频和引导对话,优化用户体验

- 在多个场景中添加音频资源,增强学习互动性。
- 更新引导对话文本,确保信息准确性和一致性。
- 调整组件结构,清理不必要的代码,提升可维护性。
- 引入结束窗口,鼓励用户深入了解历史背景。
This commit is contained in:
zhongyidian committed 2026-01-15 19:30:17 +08:00
1 parent d7ff7d3a45
commit 6e106032fd
141 files changed
+1375 -479

No files matched your search

+57 -60
View File
@@ -36,31 +36,31 @@ const starName = "huangyanpei";
// 锚点数据:根据视频时长调整 time
const QUIZ_ANCHORS: QuizAnchor[] = [
{
id: "quiz-1",
time: 96, // 1:36
title: "题目1",
prompt:
"当年黄炎培先生创办中华职业学校,开设的专业都是当时中国最需要的实业领域,分别是( )。",
type: "multiple",
options: [
{ value: "A", label: "铁工", isCorrect: true },
{
value: "B",
label: "自动控制",
},
{ value: "C", label: "木工", isCorrect: true },
{ value: "D", label: "纽扣科", isCorrect: true },
],
explanation:
"自动控制”这一工程理论框架成形于20世纪中叶,70年代实现集中控制,在民国时期,没有相关学科基础、设备与技术条件",
},
// {
// id: "quiz-1",
// time: 96, // 1:36
// title: "题目1",
// prompt:
// "当年黄炎培先生创办中华职业学校,开设的专业都是当时中国最需要的实业领域,分别是( )。",
// type: "multiple",
// options: [
// { value: "A", label: "铁工", isCorrect: true },
// {
// value: "B",
// label: "自动控制",
// },
// { value: "C", label: "木工", isCorrect: true },
// { value: "D", label: "纽扣科", isCorrect: true },
// ],
// explanation:
// "自动控制”这一工程理论框架成形于20世纪中叶,70年代实现集中控制,在民国时期,没有相关学科基础、设备与技术条件",
// },
{
id: "quiz-2",
time: 221, // 3:41
title: "题目2",
prompt:
"黄炎培先生主导设计的课程与现在中职学校强调的理实一体这一理念相通是( )。",
"黄炎培先生主导设计的课程与现在中职学校强调的理实一体这一理念相通是:",
type: "multiple",
options: [
{
@@ -96,9 +96,9 @@ const QUIZ_ANCHORS: QuizAnchor[] = [
{ value: "特斯拉", label: "特斯拉" },
{ value: "比亚迪", label: "比亚迪" },
{ value: "华为", label: "华为" },
{ value: "上海电气", label: "上海电气" },
{ value: "江南造船", label: "江南造船" },
{ value: "光明食品", label: "光明食品" },
{ value: "拼多多", label: "拼多多" },
{ value: "C919飞机", label: "C919飞机" },
],
blanks: [
{ id: "blank-1", label: "国产企业1" },
@@ -108,29 +108,29 @@ const QUIZ_ANCHORS: QuizAnchor[] = [
{ id: "blank-5", label: "国产企业5" },
],
},
{
id: "quiz-4",
time: 467, // 7:47
title: "题目4",
prompt:
'当年现在的中职教育一直在"因时求变",许多专业的新增和关联正确的是( )。',
type: "multiple",
options: [
{ value: "A", label: "汽修专业→学新能源汽车检测与维修", isCorrect: true },
{
value: "B",
label: "会计专业→要掌握大数据财务和智能记账",
isCorrect: true,
},
{ value: "C", label: "国货推销→跨境电商、直播带货", isCorrect: true },
{
value: "D",
label: "美术设计与制作→影像与影视技术",
},
],
explanation:
"美术设计与制作专业侧重于平面设计,而影像与影视技术专业侧重于影视特效后期,两者的专业核心课程涉及的软硬件也有差异",
},
// {
// id: "quiz-4",
// time: 467, // 7:47
// title: "题目4",
// prompt:
// '当年现在的中职教育一直在"因时求变",许多专业的新增和关联正确的是( )。',
// type: "multiple",
// options: [
// { value: "A", label: "汽修专业→学新能源汽车检测与维修", isCorrect: true },
// {
// value: "B",
// label: "会计专业→要掌握大数据财务和智能记账",
// isCorrect: true,
// },
// { value: "C", label: "国货推销→跨境电商、直播带货", isCorrect: true },
// {
// value: "D",
// label: "美术设计与制作→影像与影视技术",
// },
// ],
// explanation:
// "美术设计与制作专业侧重于平面设计,而影像与影视技术专业侧重于影视特效后期,两者的专业核心课程涉及的软硬件也有差异",
// },
];
const HuangyanpeiInternalization = () => {
@@ -203,7 +203,7 @@ const HuangyanpeiInternalization = () => {
if (hasInvalidOption) {
setDragQuizErrors((prev) => ({
...prev,
[item.id]: "特斯拉不是中国国产企业哦~",
[item.id]: "特斯拉为外资企业哦~",
}));
return;
}
@@ -214,9 +214,9 @@ const HuangyanpeiInternalization = () => {
const validAnswers = [
"比亚迪",
"华为",
"上海电气",
"江南造船",
"光明食品",
"拼多多",
"C919飞机",
];
const filledAnswers = val.map((v) => v.optionValue);
const isCorrect = filledAnswers.every((answer) =>
@@ -240,9 +240,9 @@ const HuangyanpeiInternalization = () => {
<DragQuizPanel
visible={activeSuccess !== item.id}
zIndex={10000}
title={`${item.title}(拖拽)`}
title={`【拖拽】`}
questionPrefix={item.prompt}
questionSuffix=""
questionSuffix="。"
options={item.options.map((opt) => ({
value: opt.value,
label: opt.label,
@@ -292,7 +292,7 @@ const HuangyanpeiInternalization = () => {
<MultipleChoiceQuizPanel
visible={activeSuccess !== item.id}
zIndex={10000}
title={`${item.title}(多选题):${item.prompt}`}
title={`【多选】${item.prompt}`}
options={item.options.map((opt) => ({
value: opt.value,
label: `${opt.value}. ${opt.label}`,
@@ -381,11 +381,9 @@ const HuangyanpeiInternalization = () => {
setPostGuideVisible(true);
if (audioRef.current) {
audioRef.current.currentTime = 0;
audioRef.current
.play()
.catch((error) => {
console.warn("背景音乐播放失败:", error);
});
audioRef.current.play().catch((error) => {
console.warn("背景音乐播放失败:", error);
});
}
}}
/>
@@ -404,13 +402,13 @@ const HuangyanpeiInternalization = () => {
showMask={false}
>
<GuideStepsItem speaker="student">
小沪,刚刚结束的"任之成长记"太有意思了!我变成百年前的川沙少年选课程、做手工、设计国货推销方案,好像真的走进了黄炎培先生的职教世界。
小沪,刚刚结束的"小职成长记"太有意思了!我变成百年前的川沙少年选课程、做手工、设计国货推销方案,好像真的走进了黄炎培先生的职教世界。
</GuideStepsItem>
<GuideStepsItem speaker="student">
但我还有一个疑问:先生当年倡导的"手脑并用、工学结合",放在我们现在的中职学习中,到底有什么样的意义呢?
</GuideStepsItem>
<GuideStepsItem speaker="guide">
这个问题问到点子上啦!黄炎培先生的职教思想,从来不是尘封的历史,而是活在当下的行动指南。今天我们特别邀请到中华职业教育社第十三届理事会常务理事、中华职业学校党总支书记、校长黄玉璟,让她带我们解码先生精神的时代密码!
这个问题问到点子上啦!黄炎培先生的职教思想,从来不是尘封的历史,而是活在当下的行动指南。今天我们特别邀请到中华职业教育社第十三届理事会常务理事、中华职业学校党总支副书记、校长黄玉璟,让她带我们解码先生精神的时代密码!
</GuideStepsItem>
</GuideSteps>
@@ -452,8 +450,7 @@ const HuangyanpeiInternalization = () => {
navigate(`/${moduleName}/${starName}/home`);
}}
>
恭喜你已经顺利完成了黄炎培故居的学习,至此,你已经完成了本课程所有故居的学习,
希望你能有所收获,学习八位名人的优秀品质和精神,在新时代为中华民族伟大复兴发光发热!
恭喜你已经顺利完成了黄炎培故居的学习,请继续前往下一个故居吧!
</StudyGuideModal>
</div>
);
+4 -4
View File
@@ -88,7 +88,7 @@ const HuangyanpeiPlace1 = () => {
{completed && (
<Image
className="absolute bottom-0 right-0"
src={getStaticImage("/components/place/继续前进")}
src={getStaticImage("components/place/继续前进")}
button
onClick={() => {
navigate(`/${moduleName}/${starName}/place2`);
@@ -154,11 +154,11 @@ const HuangyanpeiPlace1 = () => {
onContinue={() => setShowAfterDialogGuide(false)}
ailgn="left"
>
1、场景中出现动态光点的展品表示未浏览,可通过点击光点来了解展品背后的故事,通过滚轮可以放大展品,浏览展品后蓝色动态光点会变为已浏览状态;
1.场景中出现动态光点的展品表示未浏览,可通过点击光点来了解展品背后的故事,通过滚轮可以放大展品,浏览展品后蓝色动态光点会变为已浏览状态。
{"\n"}
2、在学习过程中会掉落拼图碎片,拼图碎片会自动收入拼图盒中,拼图盒可以点击查看当前拼图收集情况,点击单个拼图可以回到获得拼图的场景再次学习;
2.在学习过程中会掉落拼图碎片,拼图碎片会自动收入拼图盒中,拼图盒可以点击查看当前拼图收集情况,点击单个拼图可以回到获得拼图的场景再次学习。
{"\n"}
3、所有动态光点的展品全部学习后才能进入下一个场景学习;
3.所有动态光点的展品全部学习后才能进入下一个场景学习。
</StudyGuideModal>
</div>
);
+2 -2
View File
@@ -32,8 +32,8 @@ const HuangyanpeiPlace3 = () => {
);
const [visited, setVisited] = useState<Set<number>>(new Set());
const { isEnabled } = useCursorController({
initialEnabled: [1],
dependencies: { 2: [1], 3: [1, 2] },
initialEnabled: [3],
dependencies: { 2: [3], 1: [2] },
visited,
});
+7 -8
View File
@@ -31,16 +31,15 @@ const HuangyanpeiPlace4 = () => {
moduleName: string;
}>();
const [activeExhibitId, setActiveExhibitId] = useState<
1 | 2 | 3 | 4 | 5 | null
>(null);
const [activeExhibitId, setActiveExhibitId] = useState<1 | 3 | 4 | 5 | null>(
null
);
const [visited, setVisited] = useState<Set<number>>(new Set());
const { isEnabled } = useCursorController({
initialEnabled: [1],
initialEnabled: [3, 5],
dependencies: {
3: [1],
4: [3],
5: [4],
1: [3, 5],
4: [1],
// 2 已注释,不计入顺序
},
visited,
@@ -66,7 +65,7 @@ const HuangyanpeiPlace4 = () => {
const [showSuccessAlert, setShowSuccessAlert] = useState(false);
const videoRef = useRef<VideoRef>(null);
const handleOpenExhibit = (index: 1 | 2 | 3 | 4 | 5) => {
const handleOpenExhibit = (index: 1 | 3 | 4 | 5) => {
setActiveExhibitId(index);
if (index === 1) {
setGuide1Step(0);
+1 -1
View File
@@ -9,7 +9,7 @@ import {
} from "@/components";
import { getBackgroundImage, getStaticImage } from "@/lib/utils";
import { useNavigate, useParams } from "react-router-dom";
import { EndingOverlay } from "@/pages/chenyun/reflection/shared/EndingOverlay";
import { EndingOverlay } from "@/components/overlay/EndingOverlay";
const starName = "huangyanpei";
@@ -0,0 +1,225 @@
import { useState, useEffect, useMemo, useCallback } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { cn, getStaticImage } from "@/lib/utils";
import { Image } from "@/components";
import { SuccessAlert } from "@/components/layout";
export interface QuizDialogProps {
/** 是否可见 */
visible?: boolean;
/** 关闭回调 */
onClose?: () => void;
/** 完成回调 */
onComplete?: () => void;
}
/**
* 喇叭考题弹窗
*/
const QuizDialog = ({
visible = true,
onClose,
onComplete,
}: QuizDialogProps) => {
const maskSrc = getStaticImage("components/蒙版遮罩");
const backSrc = getStaticImage("components/关闭");
const [mounted, setMounted] = useState(false);
const [successVisible, setSuccessVisible] = useState(false);
// SSR 兼容
useEffect(() => {
setMounted(true);
}, []);
const handleClose = useCallback(
(e: React.MouseEvent<HTMLImageElement>) => {
e.stopPropagation();
onClose?.();
},
[onClose]
);
// 关闭成功提示
const handleSuccessContinue = useCallback(() => {
setSuccessVisible(false);
// 关闭提示后,完成并关闭弹窗
onComplete?.();
onClose?.();
}, [onComplete, onClose]);
// 可选话术选项
const options = useMemo(
() => [
{
value: "option1",
label: "加入义勇军(军事训练)",
},
{
value: "option2",
label: "制作军需物资",
},
{
value: "option3",
label: "宣传抗日募捐",
},
],
[]
);
// 样式
const overlayStyle = useMemo<React.CSSProperties>(
() => ({
position: "fixed",
inset: 0,
zIndex: 9999,
pointerEvents: "none",
}),
[]
);
if (!mounted) return null;
const content = (
<AnimatePresence>
{visible && (
<motion.div
key="towel-sales-dialog"
style={overlayStyle}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.3, ease: "easeInOut" }}
>
<div
className={cn("absolute inset-0 flex flex-col", "bg-black/70")}
style={{ pointerEvents: "auto" }}
>
{/* 背景蒙版 */}
{maskSrc && (
<Image
src={maskSrc}
className="absolute inset-0 w-full h-full object-cover select-none pointer-events-none"
aria-hidden
/>
)}
{/* 返回按钮 */}
{onClose && (
<Image
src={backSrc}
onClick={handleClose}
alt="返回"
className="absolute top-5 right-5 z-20"
button
/>
)}
{/* 内容区域 */}
<div className="relative z-10 w-full h-full flex flex-col px-30 py-16 pt-30 text-[#432800]">
<div className="w-full h-full flex flex-col">
{/* 顶部:题目文本和毛巾区域 */}
<div className="flex justify-between gap-10 mb-8">
{/* 题目文本 */}
<div className="flex-1">
<div className="text-5xl font-bold mb-6 -ml-[26px]">
【单选】
</div>
<div className="text-4xl leading-relaxed">
国难当头,黄先生说“职教救国”,中华职校的师生都行动起来了!你要加入哪支爱国队伍?
</div>
</div>
{/* 右侧:毛巾区域 */}
<div className="w-180 flex flex-col items-center">
<Image
src={getStaticImage(
"huangyanpei/reflection/components/题目图"
)}
/>
</div>
</div>
{/* 底部:可选话术区域 - 使用 DragFill */}
<div className="flex-1">
<div className="text-5xl font-bold mb-6">答题区</div>
<div className="grid grid-cols-2 gap-10">
{options.map((option, index) => (
<div
className={cn(
"cursor-pointer px-10 py-10 rounded-2xl border-3 text-3xl font-medium transition-all select-none",
"border-[#79471f] bg-black/20 text-white",
"hover:border-[#f0be75] hover:shadow-[0_12px_40px_rgba(240,190,117,0.7)]"
)}
key={option.value}
onClick={() => {
setSuccessVisible(true);
}}
>
{index + 1}. {option.label}
</div>
))}
</div>
{/* <DragFill
options={options}
blanks={blanks}
value={value}
onChange={handleValueChange}
allowDuplicate={false}
layout="horizontal-options"
optionClassName="grid grid-cols-2 gap-10"
hideLabels={true}
showSubmitButton={false}
className="w-full"
renderOption={(option, isUsed) => {
const index = options.findIndex(
(opt) => opt.value === option.value
);
return (
<div
className={cn(
"px-10 py-10 rounded-2xl border-3 text-3xl font-medium transition-all select-none",
isUsed
? "border-[#8b7355] bg-[#3d3329] text-[#a89378] cursor-not-allowed opacity-50"
: "border-[#79471f] bg-black/20 text-white cursor-move hover:border-[#f0be75] hover:shadow-[0_12px_40px_rgba(240,190,117,0.7)]"
)}
>
{index + 1}. {option.label}
</div>
);
}}
renderDragging={(option) => {
return (
<div className="w-[638px] h-[90px] flex items-center justify-center rounded-2xl border-3 text-2xl font-medium border-[#f0be75] bg-black/40 text-white shadow-[0_12px_40px_rgba(240,190,117,0.7)]">
{option.label}
</div>
);
}}
renderBlank={() => {
// 返回隐藏元素,实际的空白区域在页面中通过 data-blank-id 定位
return <div className="hidden" />;
}}
/> */}
</div>
</div>
</div>
{/* 成功提示 */}
<SuccessAlert
content="好样的!不管是上前线还是做后援,都是在用学到的本事报效国家,黄先生一定会为你骄傲!"
visible={successVisible}
onContinue={handleSuccessContinue}
/>
</div>
</motion.div>
)}
</AnimatePresence>
);
return content;
};
export default QuizDialog;
@@ -2,3 +2,5 @@ export { default as QuestionModal } from "./question-modal";
export type { QuestionModalProps } from "./question-modal";
export { BambooPuzzleGame } from "./game";
export { default as QuizDialog } from "./dialog";
+3 -3
View File
@@ -77,9 +77,9 @@ const HuangyanpeiReflectionScene1 = () => {
setShowGuideModal(false);
}}
>
你好呀!现在是1903年,欢迎你进入川沙小学堂,请开启你的求学第一课吧。
{"\n"}
接下来你将在“任之”校长所在的学校学习,根据所知和所学,努力完成校长给你的考验,完成全部任务后,可进入到下一阶段的学习。
同学你好,欢迎来到“跨越时空·体悟”学习模块!{"\n"}
请登陆“时空回溯・亲历时代”体验仓,下一站:1903,川沙小学堂。{"\n"}
你将在“任之”校长所在的学校学习,根据所知和所学,努力完成校长给你的考验,完成全部任务后,可进入到下一阶段的学习。时空门已开,请做好准备迎接考验吧!
</StudyGuideModal>
<Cursor
@@ -231,11 +231,11 @@ const ChoiceDialog1 = ({
}}
/>
<ErrorAlert
{/* <ErrorAlert
visible={showErrorAlert}
text="不对哦~黄先生虽然反对歧视女子、轻视手工,但创办浦东中学的核心是打破“读书只为当官”的旧思想,再选一次吧!"
onClose={() => setShowErrorAlert(false)}
/>
/> */}
</div>
</motion.div>
)}
@@ -115,7 +115,7 @@ const ChoiceDialog2 = ({
onContinue={() => setShowGuide(false)}
verticalAlign="center"
>
在浦东中学,你可以选未来的方向啦!不管选哪个,黄先生都会支持,因为“三百六十行,行行出状元”
在浦东中学,你可以选未来的方向啦!不管选哪个,黄先生都会支持,因为“三百六十行,行行出状元”!
</StudyGuideModal>
{/* 返回按钮 */}
@@ -190,7 +190,8 @@ const ChoiceDialog2 = ({
<SuccessAlert
visible={showSuccessAlert}
content="选得好!不管是做工匠还是做买卖,学好本事就能报效国家,这个选择会影响你在中华职业学校的专业哦"
title="选得好!"
content="不管是做工匠还是做买卖,学好本事就能报效国家,这个选择会影响你在中华职业学校的专业哦!"
onContinue={handleSuccessAlertContinue}
onClose={handleSuccessAlertContinue}
/>
+35 -6
View File
@@ -6,6 +6,7 @@ import { getBackgroundImage, getStaticImage, getPublicPath } from "@/lib/utils";
import { useNavigate, useParams } from "react-router-dom";
import ViseAssemblyDialog from "./scene3/ViseAssemblyDialog";
import type { VideoRef } from "@/components/video";
import { QuizDialog } from "./components";
const starName = "huangyanpei";
@@ -15,6 +16,9 @@ const HuangyanpeiReflectionScene3 = () => {
moduleName: string;
}>();
//喇叭考题弹窗
const [showQuizDialog, setShowQuizDialog] = useState(false);
const [showGuide1, setShowGuide1] = useState(true);
const [showDialog, setShowDialog] = useState(false);
const [showQuiz, setShowQuiz] = useState(false);
@@ -30,11 +34,11 @@ const HuangyanpeiReflectionScene3 = () => {
}
const progressCount = visited.size;
const total = 2;
const total = 3;
const completed = progressCount >= total;
const subtitle = completed
? "探索中华职业学院·立业之本·铁工科(已完成)"
: `探索中华职业学院·立业之本·铁工科(${progressCount}/${total})`;
? "探索中华职业学校·立业之本·铁工科(已完成)"
: `探索中华职业学校·立业之本·铁工科(${progressCount}/${total})`;
const subtitleClassName = completed
? "text-[#fff998] [text-shadow:_0_8px_8px_rgba(0,0,0,0.35),_0_0_16px_rgba(0,0,0,0.25)]"
: undefined;
@@ -64,6 +68,15 @@ const HuangyanpeiReflectionScene3 = () => {
}}
/>
<Image
className="absolute left-5 top-5"
src={getStaticImage("huangyanpei/reflection/components/喇叭1")}
button
onClick={() => {
setShowQuizDialog(true);
}}
/>
{/* 第一段引导 */}
<StudyGuideModal
visible={showGuide1}
@@ -73,7 +86,7 @@ const HuangyanpeiReflectionScene3 = () => {
>
终于到中华职业学校啦!这里是中国近代职教的摇篮,"免学费、包分配",还能学真手艺,快来练就一技之长。
{"\n"}
你选了学技术,那就来挑战制作中华职校的"明星产品"——台钳吧!当年这台钳还拿过巴拿马万国博览会金奖呢
你选了学技术,那就来挑战制作中华职校的"明星产品"——台钳吧!当年这台钳还拿过巴拿马万国博览会金奖呢!
</StudyGuideModal>
{/* 互动展品光标:组装台钳互动 */}
@@ -120,7 +133,7 @@ const HuangyanpeiReflectionScene3 = () => {
{/* 多选题答题框 */}
<MultipleChoiceQuizPanel
visible={showQuiz}
title="题目1 (多选题) 制作台钳需要哪些工具?(多选)"
title="【多选】 制作台钳需要哪些工具?"
options={[
{ value: "A", label: "A. 锯子" },
{ value: "B", label: "B. 毛笔" },
@@ -128,7 +141,14 @@ const HuangyanpeiReflectionScene3 = () => {
{ value: "D", label: "D. 铁锤" },
]}
correctAnswer={["A", "C", "D"]}
errorMessage="毛笔是写字的哦! 台钳是铁制品,得用锯子、锉刀、铁锤这些工具,再选一次。"
errorMessage={(selectedValues) => {
// 如果选择了B,显示包含"毛笔是写字的哦"的提示
if (selectedValues.includes("B")) {
return "毛笔是写字的哦!台钳是铁制品,得用锯子、锉刀、铁锤这些工具,再选一次吧!";
}
// 其他情况(单选A或C或D,或者AC、CD、AD等组合)
return "台钳是铁制品,得用锯子、锉刀、铁锤这些工具,再选一次吧!";
}}
minSelections={1}
onSubmit={(values, isCorrect) => {
if (isCorrect) {
@@ -194,6 +214,15 @@ const HuangyanpeiReflectionScene3 = () => {
}}
/>
)}
<QuizDialog
visible={showQuizDialog}
onClose={() => setShowQuizDialog(false)}
onComplete={() => {
setShowQuizDialog(false);
setVisited((prev) => new Set(prev).add(3));
}}
/>
</div>
);
};
+26 -7
View File
@@ -6,6 +6,7 @@ import { getBackgroundImage, getStaticImage, getPublicPath } from "@/lib/utils";
import { useNavigate, useParams } from "react-router-dom";
import TowelSalesDialog from "./scene4/TowelSalesDialog";
import type { VideoRef } from "@/components/video";
import { QuizDialog } from "./components";
const starName = "huangyanpei";
@@ -24,6 +25,9 @@ const HuangyanpeiReflectionScene4 = () => {
const videoRef = useRef<VideoRef>(null);
const [showGuide1, setShowGuide1] = useState(true);
//喇叭考题弹窗
const [showQuizDialog, setShowQuizDialog] = useState(false);
// 处理成功提示的继续和关闭
const handleSuccessAlertContinue = useCallback(() => {
setShowSuccessAlert(false);
@@ -50,7 +54,7 @@ const HuangyanpeiReflectionScene4 = () => {
}
const progressCount = visited.size;
const total = 2;
const total = 3;
const completed = progressCount >= total;
const subtitle = completed
? "探索中华职业学院·立业之本·商科(已完成)"
@@ -75,6 +79,15 @@ const HuangyanpeiReflectionScene4 = () => {
className="absolute top-10 left-1/2 -translate-x-1/2"
/>
<Image
className="absolute left-5 top-5"
src={getStaticImage("huangyanpei/reflection/components/喇叭2")}
button
onClick={() => {
setShowQuizDialog(true);
}}
/>
<Image
className="absolute right-5 top-5"
src={getStaticImage("components/离开")}
@@ -101,7 +114,7 @@ const HuangyanpeiReflectionScene4 = () => {
{/* 选择题1:中华职校商科的核心教学目标 */}
<MultipleChoiceQuizPanel
visible={showQuiz1}
title={`题目 1 (多选题)\n\n中华职校商科的核心教学目标是什么? (多选)`}
title={`【选题】中华职校商科的核心教学目标是什么? `}
options={[
{
value: "A",
@@ -121,7 +134,7 @@ const HuangyanpeiReflectionScene4 = () => {
},
]}
correctAnswer={["B", "C"]}
errorMessage='不对哦! 黄先生倡导"商科要为民族工商业服务", 商科是要培养诚信经营、助力国货发展的人才, 可不能想着投机发财呀, 再选一次;'
errorMessage="不对哦!黄先生倡导“商科要为民族工商业服务”,商科是要培养诚信经营、助力国货发展的人才,可不能想着投机发财呀,再选一次吧!"
minSelections={1}
onSubmit={(values: string[], isCorrect: boolean) => {
if (isCorrect) {
@@ -130,9 +143,6 @@ const HuangyanpeiReflectionScene4 = () => {
setShowSuccessAlert(true);
}
}}
onError={(_error: string) => {
// 答题错误时的处理(组件内部已显示错误信息)
}}
/>
{/* 答题成功提示 */}
@@ -178,7 +188,7 @@ const HuangyanpeiReflectionScene4 = () => {
>
终于到中华职业学校啦!这里是中国近代职教的摇篮,“免学费、包分配”,还能学真手艺,快来练就一技之长。
{"\n"}
现在要完成你的第一个任务:推销中华职校生产的“国货精品”——手工纽扣和纯棉毛巾!当年学生们就是带着这些国货,走街串巷做推销呢
现在要完成你的第一个任务:推销中华职校生产的“国货精品”——手工纽扣和纯棉毛巾!当年学生们就是带着这些国货,走街串巷做推销呢!
</StudyGuideModal>
{showVideo && (
@@ -195,6 +205,15 @@ const HuangyanpeiReflectionScene4 = () => {
}}
/>
)}
<QuizDialog
visible={showQuizDialog}
onClose={() => setShowQuizDialog(false)}
onComplete={() => {
setShowQuizDialog(false);
setVisited((prev) => new Set(prev).add(3));
}}
/>
</div>
);
};
@@ -209,7 +209,6 @@ const TowelSalesDialog = ({
<div className="flex justify-between gap-10 mb-8">
{/* 题目文本 */}
<div className="flex-1">
<div className="text-5xl font-bold mb-6">题目文本</div>
<div className="text-4xl leading-relaxed">
从以下话术里,挑选3句组成你的推销语 (拖拽至对话框)
</div>