feat:修改英文双引号
This commit is contained in:
commit
4a2be3b4d0
1351 files changed
+56547
No files matched your search
@@ -0,0 +1,365 @@
|
||||
import {
|
||||
ExhibitOverlay,
|
||||
GuideSteps,
|
||||
GuideStepsItem,
|
||||
Image,
|
||||
Title,
|
||||
Cursor,
|
||||
StudyGuideModal,
|
||||
} from '@/components'
|
||||
import { MatchQuizPanel, MultipleChoiceQuizPanel } from '@/components/layout/quiz'
|
||||
import { SuccessAlert } from '@/components/layout'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { getBackgroundImage, getPublicPath, getStaticImage } from '@/lib/utils'
|
||||
import { useState } from 'react'
|
||||
import { useCursorController } from '@/hooks/useCursorController'
|
||||
import { usePuzzleAnimation } from '@/contexts/PuzzleAnimationContext'
|
||||
import { useLuxunStore, saveLuxunStore } from '@/store/luxunStore'
|
||||
|
||||
// starName 固定为 luxun
|
||||
const starName = 'luxun'
|
||||
|
||||
// 展品 ID 与资源路径映射,ID 用来做唯一标识
|
||||
const exhibitSrcMap: Record<1 | 2, string> = {
|
||||
1: 'luxun/place1/展品1',
|
||||
2: 'luxun/place1/展品2',
|
||||
}
|
||||
|
||||
const LuxunPlace1 = () => {
|
||||
const navigate = useNavigate()
|
||||
const { moduleName } = useParams<{
|
||||
moduleName: string
|
||||
}>()
|
||||
|
||||
//碎片动画触发方法
|
||||
const { triggerPuzzleAnimation } = usePuzzleAnimation()
|
||||
|
||||
// 学习引导弹窗
|
||||
const [showGuideModal, setShowGuideModal] = useState(true)
|
||||
// 对话结束后的学习引导弹窗
|
||||
const [showAfterDialogGuide, setShowAfterDialogGuide] = useState(false)
|
||||
const [afterDialogGuideShown, setAfterDialogGuideShown] = useState(false)
|
||||
// 引导对话显示状态
|
||||
const [visible, setVisible] = useState(false)
|
||||
const [visibleIndex, setVisibleIndex] = useState(0)
|
||||
|
||||
// 打开展品2后的对话显示状态
|
||||
const [showAfterExhibitDialog, setShowAfterExhibitDialog] = useState(false)
|
||||
const [afterExhibitDialogStep, setAfterExhibitDialogStep] = useState(0)
|
||||
// 当前激活的展品 ID(只存 ID,不直接存路径,便于作为唯一标识)
|
||||
const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | null>(null)
|
||||
// 使用持久化的访问状态
|
||||
const place = 'place1'
|
||||
const { markExhibitVisited, getVisitedExhibits, setLastVisitedPlace } = useLuxunStore()
|
||||
|
||||
// 从 store 获取已访问的展品,转换为 Set 用于兼容现有代码
|
||||
const visitedExhibits = getVisitedExhibits(place)
|
||||
const visited = new Set(visitedExhibits)
|
||||
// 连线题显示状态(展品1关闭后)
|
||||
const [showMatchQuiz, setShowMatchQuiz] = useState(false)
|
||||
// 连线题成功提示状态
|
||||
const [showMatchQuizSuccess, setShowMatchQuizSuccess] = useState(false)
|
||||
const [showExhibit2Quiz, setShowExhibit2Quiz] = useState(false)
|
||||
const [showExhibit2QuizSuccess, setShowExhibit2QuizSuccess] = useState(false)
|
||||
|
||||
// Cursor 顺序控制:1 -> 2
|
||||
const { isEnabled } = useCursorController({
|
||||
initialEnabled: [1],
|
||||
dependencies: {
|
||||
2: [1],
|
||||
},
|
||||
visited: visited,
|
||||
})
|
||||
|
||||
const handleOpenExhibit = (index: 1 | 2) => {
|
||||
if (index === 1) {
|
||||
setVisibleIndex(0)
|
||||
setVisible(true)
|
||||
}
|
||||
|
||||
if (index === 2) {
|
||||
setAfterExhibitDialogStep(0)
|
||||
setShowAfterExhibitDialog(true)
|
||||
}
|
||||
setActiveExhibitId(index)
|
||||
}
|
||||
|
||||
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}`
|
||||
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
|
||||
|
||||
return (
|
||||
<div
|
||||
className="w-full h-full bg-cover bg-center bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: getBackgroundImage(`luxun/place1/背景`),
|
||||
}}
|
||||
>
|
||||
{/* 标题 */}
|
||||
<Title
|
||||
title="风雨前夕的思想淬炼"
|
||||
subtitle={subtitle}
|
||||
subtitleClassName={subtitleClassName}
|
||||
className="absolute top-10 left-1/2 -translate-x-1/2"
|
||||
/>
|
||||
|
||||
<Image
|
||||
className="absolute right-5 top-5"
|
||||
src={getStaticImage('components/离开')}
|
||||
button
|
||||
onClick={() => {
|
||||
if (moduleName && starName) {
|
||||
navigate(`/${moduleName}/${starName}/home`)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 展品1 */}
|
||||
<Cursor
|
||||
className="absolute left-[calc(50%-48px)] top-80"
|
||||
onClick={() => handleOpenExhibit(1)}
|
||||
read={visited.has(1)}
|
||||
disabled={!isEnabled(1)}
|
||||
/>
|
||||
{/* 展品2 */}
|
||||
<Cursor
|
||||
className="absolute left-[calc(50%)] bottom-60"
|
||||
onClick={() => handleOpenExhibit(2)}
|
||||
read={visited.has(2)}
|
||||
disabled={!isEnabled(2)}
|
||||
/>
|
||||
|
||||
{/* 继续前进 - 仅在完成所有展品且对话结束后显示 */}
|
||||
{completed && (
|
||||
<Image
|
||||
className="absolute bottom-0 right-0"
|
||||
src={getStaticImage('components/place/继续前进')}
|
||||
button
|
||||
onClick={() => {
|
||||
setLastVisitedPlace('place2')
|
||||
saveLuxunStore()
|
||||
navigate(`/${moduleName}/${starName}/place2`)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 遮罩层 */}
|
||||
<ExhibitOverlay
|
||||
visible={activeExhibitId !== null}
|
||||
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ''}
|
||||
onOpen={() => {
|
||||
if (activeExhibitId === 1) {
|
||||
triggerPuzzleAnimation(1)
|
||||
}
|
||||
if (activeExhibitId === 2) {
|
||||
triggerPuzzleAnimation(2)
|
||||
}
|
||||
}}
|
||||
// description={
|
||||
// activeExhibitId == 1
|
||||
// ? `1892-1898年,少年时期在绍兴三味书屋求学积淀;\n1919-1923年,于北京八道湾参加新文化运动、酝酿《阿Q正传》;\n1926年9-12月,赴厦门大学任教期间聚焦底层创作杂文;\n1927年3-9月,广州白云楼整理旧作定稿《朝花夕拾》部分篇章。`
|
||||
// : undefined
|
||||
// }
|
||||
onClose={() => {
|
||||
if (activeExhibitId !== null) {
|
||||
// 如果是展品1关闭,显示连线题
|
||||
if (activeExhibitId === 1) {
|
||||
setShowMatchQuiz(true)
|
||||
} else {
|
||||
setShowExhibit2Quiz(true)
|
||||
}
|
||||
}
|
||||
setActiveExhibitId(null)
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 学习引导词 */}
|
||||
<StudyGuideModal
|
||||
visible={showGuideModal}
|
||||
onContinue={() => {
|
||||
setShowGuideModal(false)
|
||||
if (!visible && !afterDialogGuideShown) {
|
||||
setAfterDialogGuideShown(true)
|
||||
setShowAfterDialogGuide(true)
|
||||
}
|
||||
}}
|
||||
audioSrc={getPublicPath('audio/luxun/mp3_luxun_02.mp3')}
|
||||
ailgn="left"
|
||||
>
|
||||
1.场景中出现动态光点的展品表示未浏览,可通过点击光点来了解展品背后的故事,通过滚轮可以放大展品,浏览展品后蓝色动态光点会变为已浏览状态。
|
||||
{'\n'}
|
||||
2.在学习过程中会掉落拼图碎片,拼图碎片会自动收入拼图盒中,拼图盒可以点开查看当前拼图收集情况,点击单个拼图可以回到获得拼图的场景再次学习。
|
||||
{'\n'}
|
||||
3.所有动态光点的展品全部学习后才能进入下一个场景学习。
|
||||
</StudyGuideModal>
|
||||
|
||||
{/* 引导 */}
|
||||
<GuideSteps
|
||||
visible={visible}
|
||||
currentStep={visibleIndex}
|
||||
onStepChange={setVisibleIndex}
|
||||
onVisibleChange={(nextVisible) => {
|
||||
setVisible(nextVisible)
|
||||
}}
|
||||
showMask={false}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_03.mp3')}>
|
||||
小沪!我知道鲁迅是1933年搬到大陆新村9号的,那在这之前他为什么会选择来到上海,又有哪些思想转变呢?
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_04.mp3')}>
|
||||
你问得很关键!从1892-1898年少年时期在绍兴三味书屋求学积淀,到1919-1923年于北京八道湾参加新文化运动、酝酿《阿Q正传》,再到1926年9-12月赴厦门大学任教期间聚焦底层创作杂文。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide">
|
||||
1927年3-9月广州白云楼整理旧作定稿《朝花夕拾》部分篇章,鲁迅的创作足迹跨越南北,而1927年是鲁迅思想的重要转折点,这一年他在广州亲历了“四一二”反革命政变,亲眼看见进步青年和革命志士倒在血泊中,曾经对“温和改革”的幻想彻底破灭。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide">
|
||||
此前他写下《狂人日记》《阿Q正传》批判封建礼教,参加语丝社针砭时弊,但始终在“彷徨”中摸索救国之路。广州的血雨腥风,让他认清了反动派的真面目。
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
|
||||
{/* 对话结束后的学习引导 */}
|
||||
<StudyGuideModal
|
||||
visible={showAfterDialogGuide}
|
||||
onContinue={() => setShowAfterDialogGuide(false)}
|
||||
audioSrc={getPublicPath('audio/luxun/mp3_luxun_01.mp3')}
|
||||
>
|
||||
{`同学你好,欢迎来到“走进故居·对话”学习模块!
|
||||
此刻你正立在鲁迅故居的一楼客厅里,接下来请随旧时光的纹路,一同翻开先生思想长卷里的5段深刻轨迹:风雨前夕的思想淬炼、杂文集里的匕首与投枪、历史新编中的现实呐喊、为亡友编纂的精神丰碑、6平方米的红色庇护所。准备好共赴这场笔尖与灵魂的滚烫相遇了吗?`}
|
||||
</StudyGuideModal>
|
||||
|
||||
{/* 浏览完展品后的对话 */}
|
||||
<GuideSteps
|
||||
visible={showAfterExhibitDialog}
|
||||
currentStep={afterExhibitDialogStep}
|
||||
onStepChange={setAfterExhibitDialogStep}
|
||||
onVisibleChange={(nextVisible) => {
|
||||
setShowAfterExhibitDialog(nextVisible)
|
||||
}}
|
||||
showMask={false}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_05.mp3')}>
|
||||
这张照片也是鲁迅在上海期间的住所吗?
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_06.mp3')}>
|
||||
不错!1927年10月,鲁迅带着许广平来到上海,先住进了虹口区横浜路景云里。在景云里的两年半,他结识了冯雪峰等共产党员,参与发起中国左翼作家联盟,从"独战的英雄"转变为革命文艺战线的旗手。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide">
|
||||
这段时间他写下《三闲集》《二心集》,表达他在当时历史条件下针对社会现象、文化问题和论战的看法与社会批判,此间还翻译了大量马列文艺理论著作,为此后的战斗打下了坚实思想基础。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_07.mp3')}>
|
||||
鲁迅在发起成立左联后,为躲避国民党当局监视,1930年5月,与许广平、周海婴迁居到拉摩斯公寓。1933年4月,受战火纷扰影响,为安全及健康计,同时也为了更方便开展革命文化工作,鲁迅以"内山书店职员"的名义,搬到了大陆新村9号。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_08.mp3')}>
|
||||
这个过程的确十分曲折。
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
|
||||
{/* 连线题(展品1关闭后) */}
|
||||
<MatchQuizPanel
|
||||
visible={showMatchQuiz}
|
||||
title="【连线】请将左侧的日期与右侧对应的事件进行连线:"
|
||||
leftItems={[
|
||||
{ id: '1', label: '1892-1898年' },
|
||||
{ id: '2', label: '1919-1923年' },
|
||||
{ id: '3', label: '1926年9-12月' },
|
||||
{ id: '4', label: '1927年3-9月' },
|
||||
]}
|
||||
rightItems={[
|
||||
{ id: 'a', label: '在绍兴三味书屋求学积淀' },
|
||||
{ id: 'b', label: '于北京八道湾参加新文化运动、酝酿《阿Q正传》' },
|
||||
{ id: 'c', label: '赴厦门大学任教,聚焦底层创作杂文' },
|
||||
{ id: 'd', label: '在广州白云楼整理旧作定稿《朝花夕拾》部分篇章' },
|
||||
]}
|
||||
correctMatches={[
|
||||
{ leftId: '1', rightId: 'a' },
|
||||
{ leftId: '2', rightId: 'b' },
|
||||
{ leftId: '3', rightId: 'c' },
|
||||
{ leftId: '4', rightId: 'd' },
|
||||
]}
|
||||
errorMessage="连线不正确,请重新尝试!"
|
||||
onSubmit={(matches, isCorrect) => {
|
||||
if (isCorrect) {
|
||||
setShowMatchQuiz(false)
|
||||
setShowMatchQuizSuccess(true)
|
||||
}
|
||||
}}
|
||||
zIndex={10001}
|
||||
/>
|
||||
|
||||
{/* 连线题成功提示 */}
|
||||
<SuccessAlert
|
||||
title="恭喜你,匹配正确!"
|
||||
visible={showMatchQuizSuccess}
|
||||
onContinue={() => {
|
||||
setShowMatchQuizSuccess(false)
|
||||
// 标记展品1为已访问
|
||||
markExhibitVisited(place, 1)
|
||||
}}
|
||||
onClose={() => {
|
||||
setShowMatchQuizSuccess(false)
|
||||
// 标记展品1为已访问
|
||||
markExhibitVisited(place, 1)
|
||||
}}
|
||||
/>
|
||||
|
||||
<MultipleChoiceQuizPanel
|
||||
visible={showExhibit2Quiz}
|
||||
title="【多选】鲁迅先生居住在上海景云里的两年半,写下的作品包括:"
|
||||
options={[
|
||||
{ value: 'A', label: 'A. 阿 Q 正传' },
|
||||
{ value: 'B', label: 'B. 三闲集' },
|
||||
{ value: 'C', label: 'C. 二心集' },
|
||||
{ value: 'D', label: 'D. 朝花夕拾' },
|
||||
]}
|
||||
correctAnswer={['B', 'C']}
|
||||
errorMessage={(selectedValues) => {
|
||||
const picked = new Set(selectedValues)
|
||||
|
||||
if (picked.has('A')) {
|
||||
return '《阿 Q 正传》创作于 1921—1922 年,最初发表于《晨报副刊》,早于鲁迅居住在上海景云里时期。请你再想想吧!'
|
||||
}
|
||||
if (picked.has('D')) {
|
||||
return '《朝花夕拾》创作于 1926 年,最初以《旧事重提》为总题发表,早于鲁迅居住在上海景云里时期。请你再想想吧!'
|
||||
}
|
||||
return '请你再想想吧!'
|
||||
}}
|
||||
onSubmit={(_values, isCorrect) => {
|
||||
if (isCorrect) {
|
||||
setShowExhibit2Quiz(false)
|
||||
setShowExhibit2QuizSuccess(true)
|
||||
}
|
||||
}}
|
||||
zIndex={10001}
|
||||
/>
|
||||
|
||||
<SuccessAlert
|
||||
title="恭喜你,选择正确!"
|
||||
visible={showExhibit2QuizSuccess}
|
||||
onContinue={() => {
|
||||
setShowExhibit2QuizSuccess(false)
|
||||
markExhibitVisited(place, 2)
|
||||
}}
|
||||
onClose={() => {
|
||||
setShowExhibit2QuizSuccess(false)
|
||||
markExhibitVisited(place, 2)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LuxunPlace1
|
||||
@@ -0,0 +1,356 @@
|
||||
import { ExhibitOverlay, Image, Title, Cursor, GuideSteps, GuideStepsItem } from '@/components'
|
||||
import { DragQuizPanel } from '@/components/layout/quiz'
|
||||
import { SuccessAlert } from '@/components/layout'
|
||||
import ScaledPortal from '@/components/layout/ScaledPortal'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { getBackgroundImage, getPublicPath, getStaticImage } from '@/lib/utils'
|
||||
import { useState } from 'react'
|
||||
import { useCursorController } from '@/hooks/useCursorController'
|
||||
import { usePuzzleAnimation } from '@/contexts/PuzzleAnimationContext'
|
||||
import type { DragFillResult } from '@/components'
|
||||
import { useLuxunStore, saveLuxunStore } from '@/store/luxunStore'
|
||||
|
||||
// starName 固定为 luxun
|
||||
const starName = 'luxun'
|
||||
|
||||
// 展品 ID 与资源路径映射
|
||||
const exhibitSrcMap: Record<1 | 2 | 3, string> = {
|
||||
1: 'luxun/place2/展品3',
|
||||
2: 'luxun/place2/展品4',
|
||||
3: 'luxun/place2/展品5',
|
||||
}
|
||||
|
||||
const LuxunPlace2 = () => {
|
||||
const navigate = useNavigate()
|
||||
const { moduleName } = useParams<{
|
||||
moduleName: string
|
||||
}>()
|
||||
|
||||
//碎片动画触发方法
|
||||
const { triggerPuzzleAnimation } = usePuzzleAnimation()
|
||||
|
||||
const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | 3 | null>(null)
|
||||
|
||||
// 使用持久化的访问状态
|
||||
const place = 'place2'
|
||||
const { markExhibitVisited, getVisitedExhibits, setLastVisitedPlace } = useLuxunStore()
|
||||
|
||||
// 从 store 获取已访问的展品,转换为 Set 用于兼容现有代码
|
||||
const visitedExhibits = getVisitedExhibits(place)
|
||||
const visited = new Set(visitedExhibits)
|
||||
|
||||
// Cursor 顺序控制:1 -> 2 -> 3
|
||||
const { isEnabled } = useCursorController({
|
||||
initialEnabled: [1],
|
||||
dependencies: {
|
||||
2: [3],
|
||||
3: [1],
|
||||
},
|
||||
visited: visited,
|
||||
})
|
||||
|
||||
// 光标1的引导对话状态
|
||||
const [guide1Visible, setGuide1Visible] = useState(false)
|
||||
const [guide1Step, setGuide1Step] = useState(0)
|
||||
|
||||
// 光标2的引导对话状态
|
||||
const [guide2Visible, setGuide2Visible] = useState(false)
|
||||
const [guide2Step, setGuide2Step] = useState(0)
|
||||
|
||||
// 光标3的引导对话状态
|
||||
const [guide3Visible, setGuide3Visible] = useState(false)
|
||||
const [guide3Step, setGuide3Step] = useState(0)
|
||||
// 拖拽题显示状态(包含那句话的步骤结束后)
|
||||
const [showDragQuiz, setShowDragQuiz] = useState(false)
|
||||
// 标记是否已经显示过题目(避免重复显示)
|
||||
const [quizShown, setQuizShown] = useState(false)
|
||||
// 拖拽题的值
|
||||
const [dragQuizValue, setDragQuizValue] = useState<DragFillResult[]>([])
|
||||
// 拖拽题错误提示
|
||||
const [dragQuizError, setDragQuizError] = useState<string>('')
|
||||
// 拖拽题成功提示状态
|
||||
const [showDragQuizSuccess, setShowDragQuizSuccess] = useState(false)
|
||||
|
||||
const handleOpenExhibit = (index: 1 | 2 | 3) => {
|
||||
if (index === 1) {
|
||||
// 光标1:点击时同时打开展品和引导对话
|
||||
setActiveExhibitId(1)
|
||||
setGuide1Visible(true)
|
||||
setGuide1Step(0)
|
||||
} else if (index === 2) {
|
||||
// 光标2:点击时同时打开展品和引导对话
|
||||
setActiveExhibitId(2)
|
||||
setGuide2Visible(true)
|
||||
setGuide2Step(0)
|
||||
} else if (index === 3) {
|
||||
setActiveExhibitId(3)
|
||||
setGuide3Visible(true)
|
||||
setGuide3Step(0)
|
||||
setQuizShown(false) // 重置题目显示标记
|
||||
} 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)
|
||||
}
|
||||
|
||||
// 监听光标3的引导对话步骤变化
|
||||
const handleGuide3StepChange = (step: number) => {
|
||||
// 在步骤2(包含那句话的步骤)结束后,进入步骤3前先弹题
|
||||
if (step === 3 && !quizShown) {
|
||||
setGuide3Step(2) // 保持在步骤2
|
||||
setShowDragQuiz(true)
|
||||
setQuizShown(true)
|
||||
return
|
||||
}
|
||||
setGuide3Step(step)
|
||||
}
|
||||
|
||||
const progressCount = visited.size
|
||||
const total = 3
|
||||
const completed = progressCount >= total
|
||||
const subtitle = completed ? '已完成' : `${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
|
||||
|
||||
return (
|
||||
<div
|
||||
className="w-full h-full bg-cover bg-center bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: getBackgroundImage(`luxun/place2/背景`),
|
||||
}}
|
||||
>
|
||||
<Title
|
||||
title="杂文集里的匕首与投枪"
|
||||
subtitle={subtitle}
|
||||
subtitleClassName={subtitleClassName}
|
||||
className="absolute top-10 left-1/2 -translate-x-1/2"
|
||||
/>
|
||||
<Image
|
||||
className="absolute right-5 top-5"
|
||||
src={getStaticImage('components/离开')}
|
||||
button
|
||||
onClick={() => {
|
||||
if (moduleName && starName) {
|
||||
navigate(`/${moduleName}/${starName}/place1`)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/* 光标1 */}
|
||||
<Cursor
|
||||
className="absolute right-218 bottom-104"
|
||||
size={0.4}
|
||||
onClick={() => handleOpenExhibit(1)}
|
||||
read={visited.has(1)}
|
||||
disabled={!isEnabled(1)}
|
||||
/>
|
||||
{/* 光标2 */}
|
||||
<Cursor
|
||||
className="absolute right-225 bottom-95"
|
||||
size={0.4}
|
||||
onClick={() => handleOpenExhibit(2)}
|
||||
read={visited.has(2)}
|
||||
disabled={!isEnabled(2)}
|
||||
/>
|
||||
{/* 光标3 */}
|
||||
<Cursor
|
||||
className="absolute right-232 bottom-84"
|
||||
size={0.4}
|
||||
onClick={() => handleOpenExhibit(3)}
|
||||
read={visited.has(3)}
|
||||
disabled={!isEnabled(3)}
|
||||
/>
|
||||
{completed && (
|
||||
<Image
|
||||
className="absolute bottom-10 left-42"
|
||||
src={getStaticImage('luxun/place2/前进')}
|
||||
button
|
||||
onClick={() => {
|
||||
setLastVisitedPlace('place3')
|
||||
saveLuxunStore()
|
||||
navigate(`/${moduleName}/${starName}/place3`)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<ExhibitOverlay
|
||||
visible={activeExhibitId !== null}
|
||||
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ''}
|
||||
onOpen={() => {
|
||||
if (activeExhibitId === 1) {
|
||||
triggerPuzzleAnimation(3)
|
||||
}
|
||||
if (activeExhibitId === 3) {
|
||||
triggerPuzzleAnimation(4)
|
||||
}
|
||||
if (activeExhibitId === 2) {
|
||||
triggerPuzzleAnimation(5)
|
||||
}
|
||||
}}
|
||||
// description={
|
||||
// activeExhibitId === 3
|
||||
// ? '这篇《中国人失掉自信力了吗》收录于《且介亭杂文》中,它将"匕首与投枪"的特质发挥到极致。当时国民党当局接连丧权辱国,一些文人却散布"中国人失掉自信力"的悲观论调,迎合反动派的卖国行径。鲁迅直接驳斥这种谬论,一针见血指出:"我们从古以来,就有埋头苦干的人,有拼命硬干的人,有为民请命的人,有舍身求法的人……这就是中国的脊梁。"文字如利刃般戳破虚假论调,揭露了反动派掩盖自身无能、麻痹民众的阴谋,唤醒国人的民族自信,尽显战斗文字的锋芒与力量。'
|
||||
// : undefined
|
||||
// }
|
||||
onClose={() => {
|
||||
if (activeExhibitId !== null) {
|
||||
markExhibitVisited(place, activeExhibitId)
|
||||
}
|
||||
setActiveExhibitId(null)
|
||||
}}
|
||||
/>
|
||||
{/* 光标1的引导对话 */}
|
||||
<GuideSteps
|
||||
visible={guide1Visible}
|
||||
onVisibleChange={handleGuide1VisibleChange}
|
||||
currentStep={guide1Step}
|
||||
onStepChange={handleGuide1StepChange}
|
||||
showMask={false}
|
||||
highlightSelectors={[]}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_09.mp3')}>
|
||||
小沪,这里的《且介亭杂文》就是鲁迅先生在大陆新村9号创作的吧,有人将先生的杂文评价为"匕首与投枪",《且介亭杂文》中有具体体现吗?
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_10.mp3')}>
|
||||
当然有!20世纪30年代,国民党"文化围剿"愈烈,进步思想遭严控,鲁迅在大陆新村9号创作出《且介亭杂文》等集子。这些杂文聚焦文化乱象与社会沉疴,篇幅精炼却直击要害,像匕首般刺穿虚伪表象,似投枪般直戳问题核心。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide">
|
||||
用锋利文字与黑暗势力对峙,成为那个时代最具战斗力的思想武器,“匕首与投枪”的赞誉恰是其战斗性的生动写照。
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
{/* 光标2的引导对话 */}
|
||||
<GuideSteps
|
||||
visible={guide2Visible}
|
||||
onVisibleChange={handleGuide2VisibleChange}
|
||||
currentStep={guide2Step}
|
||||
onStepChange={handleGuide2StepChange}
|
||||
showMask={false}
|
||||
highlightSelectors={[]}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_13.mp3')}>
|
||||
那《南腔北调集》这个名字又有什么深意呢?
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_14.mp3')}>
|
||||
这是鲁迅的自嘲,他曾说“我不会说绵软的苏白,不会打响亮的京腔,不入调,不入流”,所以戏称自己的文章是“南腔北调”。这本书里的《〈守常全集》题记》,赞美了李大钊同志,说“他的遗文却将永驻,因为这是先驱者的遗产,革命史上的丰碑。”
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
{/* 光标3的引导对话 */}
|
||||
<GuideSteps
|
||||
visible={guide3Visible}
|
||||
onVisibleChange={setGuide3Visible}
|
||||
currentStep={guide3Step}
|
||||
onStepChange={handleGuide3StepChange}
|
||||
showMask={false}
|
||||
highlightSelectors={[]}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_11.mp3')}>
|
||||
我们初中学的《中国人失掉自信力了吗》就是收录于《且介亭杂文》中的!
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_12.mp3')}>
|
||||
那你应该更有体会!这篇《中国人失掉自信力了吗》是将“匕首与投枪”的特质发挥到极致。当时国民党当局接连丧权辱国,一些文人却散布“中国人失掉自信力”的悲观论调,迎合反动派的卖国行径。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide">
|
||||
鲁迅直接驳斥这种谬论,一针见血指出:“我们从古以来,就有埋头苦干的人,有拼命硬干的人,有为民请命的人,有舍身求法的人……这就是中国的脊梁。”
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide">
|
||||
文字如利刃般戳破虚假论调,揭露了反动派掩盖自身无能、麻痹民众的阴谋,唤醒国人的民族自信,尽显战斗文字的锋芒与力量。
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
|
||||
{/* 拖拽题和成功提示(使用 ScaledPortal 保证层级与缩放) */}
|
||||
<ScaledPortal enabled={showDragQuiz || showDragQuizSuccess} zIndex={10050}>
|
||||
<>
|
||||
<DragQuizPanel
|
||||
visible={showDragQuiz}
|
||||
title=""
|
||||
questionPrefix="【拖拽】我们从古以来,就有"
|
||||
questionSuffix="......这就是中国的脊梁。"
|
||||
options={[
|
||||
{ value: '埋头苦干的人', label: 'A. 埋头苦干的人' },
|
||||
{ value: '拼命硬干的人', label: 'B. 拼命硬干的人' },
|
||||
{ value: '为民请命的人', label: 'C. 为民请命的人' },
|
||||
{ value: '舍身求法的人', label: 'D. 舍身求法的人' },
|
||||
]}
|
||||
blanks={[
|
||||
{ id: 'blank-1', label: '' },
|
||||
{ id: 'blank-2', label: '' },
|
||||
{ id: 'blank-3', label: '' },
|
||||
{ id: 'blank-4', label: '' },
|
||||
]}
|
||||
blankSeparators={[',有', ',有', ',有']}
|
||||
value={dragQuizValue}
|
||||
error={dragQuizError}
|
||||
onChange={(value) => {
|
||||
setDragQuizValue(value)
|
||||
setDragQuizError('')
|
||||
|
||||
// 检查是否所有空白都已填充
|
||||
if (value.length < 4) return
|
||||
|
||||
// 验证顺序:必须是 ABCD 顺序
|
||||
const correctOrder = ['埋头苦干的人', '拼命硬干的人', '为民请命的人', '舍身求法的人']
|
||||
|
||||
const isCorrect = value.every((v, index) => {
|
||||
return v.optionValue === correctOrder[index]
|
||||
})
|
||||
|
||||
if (isCorrect) {
|
||||
// 答题成功
|
||||
setShowDragQuiz(false)
|
||||
setShowDragQuizSuccess(true)
|
||||
} else {
|
||||
// 答题失败:顺序不对
|
||||
setDragQuizError('请你按照鲁迅先生《中国人失掉自信力了吗》的原文拖拽哦~')
|
||||
}
|
||||
}}
|
||||
zIndex={10000}
|
||||
/>
|
||||
|
||||
<SuccessAlert
|
||||
visible={showDragQuizSuccess}
|
||||
onContinue={() => {
|
||||
setShowDragQuizSuccess(false)
|
||||
setDragQuizValue([])
|
||||
setDragQuizError('')
|
||||
// 题目完成后,继续对话到步骤3
|
||||
setGuide3Visible(true)
|
||||
setGuide3Step(3)
|
||||
}}
|
||||
onClose={() => {
|
||||
setShowDragQuizSuccess(false)
|
||||
setDragQuizValue([])
|
||||
setDragQuizError('')
|
||||
// 题目完成后,继续对话到步骤3
|
||||
setGuide3Visible(true)
|
||||
setGuide3Step(3)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
</ScaledPortal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LuxunPlace2
|
||||
@@ -0,0 +1,488 @@
|
||||
import {
|
||||
ExhibitOverlay,
|
||||
Image,
|
||||
Title,
|
||||
Cursor,
|
||||
GuideSteps,
|
||||
GuideStepsItem,
|
||||
SingleChoiceQuizPanel,
|
||||
} from '@/components'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { getBackgroundImage, getPublicPath, getStaticImage } from '@/lib/utils'
|
||||
import { useState } from 'react'
|
||||
import SuccessAlert from '@/components/layout/alert/success-alert'
|
||||
import { useCursorController } from '@/hooks/useCursorController'
|
||||
import { usePuzzleAnimation } from '@/contexts/PuzzleAnimationContext'
|
||||
import { useLuxunStore, saveLuxunStore } from '@/store/luxunStore'
|
||||
|
||||
// starName 固定为 luxun
|
||||
const starName = 'luxun'
|
||||
|
||||
// 展品 ID 与资源路径映射
|
||||
const exhibitSrcMap: Record<1 | 2 | 3 | 4 | 5, string> = {
|
||||
1: 'luxun/place3/6',
|
||||
2: 'luxun/place3/7',
|
||||
3: 'luxun/place3/8',
|
||||
4: 'luxun/place3/9',
|
||||
5: 'luxun/place3/10',
|
||||
}
|
||||
|
||||
const quiz2DefaultError = '再想一想,注意题干中的时间和提示信息哦~'
|
||||
const quiz2Explanations: Record<string, string> = {
|
||||
A: '鲁迅身处旧中国文艺思惰僵化、缺乏革新活力的时代,他认为“没有拿来的,人不能自成为新人”。翻译外国作品正是为了打破文化封闭,为中国文艺引进新思想、新方法,为沉寂的文坛注入新血液。',
|
||||
B: '当时中国青年普遍受传统旧思想束缚,接触先进文化的渠道有限。鲁迅希望通过翻译外国进步作品,让青年接触世界范围内的先进文化理念、思想成果,拓宽视野、启发心智,助力青年觉醒。',
|
||||
C: '鲁迅的核心斗争方式是“以笔为刃”,通过文学创作、翻译、杂文批判等方式开展思想启蒙和文化斗争,从未直接参与武装革命的战略部署。',
|
||||
D: '在国民党“文化围剿”、进步思想遭严控的背景下,鲁迅将翻译视为重要的斗争武器——通过引进外国进步文学、马克思主义理论等,揭露旧中国的黑暗与愚昧,唤醒民众的思想意识,助力思想启蒙运动。',
|
||||
}
|
||||
|
||||
// 光标5-题目:纪念瞿秋白的译文集
|
||||
const quiz5DefaultError = '再想一想,结合前面的旁白内容哦~'
|
||||
const quiz5Explanations: Record<string, string> = {
|
||||
A: '《仿自由书》是鲁迅在上海创作的杂文集,收录了1933年所作的多篇杂文,核心内容是针砭国民党当局的虚伪统治、批判社会乱象,并非为纪念瞿秋白编校的译文集。',
|
||||
B: '《南腔北调集》是鲁迅的一部杂文集,收录了1927年至1933年的杂文作品,书名源于鲁迅对自己文章“不入调、不入流”的自嘲,内容涵盖文化批判、社会评论等,与纪念瞿秋白及译文集无关。',
|
||||
C: '恭喜你,选对啦。',
|
||||
D: '《故事新编》是鲁迅的历史小说集,酝酿多年后在大陆新村9号完成定稿。作品以神话传说、历史典故为载体借古讽今,批判现实社会的腐朽与愚昧,并非译文集,更与纪念瞿秋白无关。',
|
||||
}
|
||||
|
||||
const LuxunPlace3 = () => {
|
||||
const navigate = useNavigate()
|
||||
const { moduleName } = useParams<{
|
||||
moduleName: string
|
||||
}>()
|
||||
|
||||
//碎片动画触发方法
|
||||
const { triggerPuzzleAnimation } = usePuzzleAnimation()
|
||||
|
||||
const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | 3 | 4 | 5 | null>(null)
|
||||
|
||||
// 使用持久化的访问状态
|
||||
const place = 'place3'
|
||||
const { markExhibitVisited, getVisitedExhibits, setLastVisitedPlace } = useLuxunStore()
|
||||
|
||||
// 从 store 获取已访问的展品,转换为 Set 用于兼容现有代码
|
||||
const visitedExhibits = getVisitedExhibits(place)
|
||||
const visited = new Set(visitedExhibits)
|
||||
|
||||
// Cursor 顺序控制:1 -> 2 -> 3 -> 4 -> 5
|
||||
const { isEnabled } = useCursorController({
|
||||
initialEnabled: [1],
|
||||
dependencies: {
|
||||
2: [1],
|
||||
3: [2],
|
||||
4: [3],
|
||||
5: [4],
|
||||
},
|
||||
visited: visited,
|
||||
})
|
||||
|
||||
// 光标1的引导对话状态
|
||||
const [guide1Visible, setGuide1Visible] = useState(false)
|
||||
const [guide1Step, setGuide1Step] = useState(0)
|
||||
|
||||
// 光标2的引导对话状态
|
||||
const [guide2Visible, setGuide2Visible] = useState(false)
|
||||
const [guide2Step, setGuide2Step] = 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) => {
|
||||
if (index === 1) {
|
||||
// 光标1:点击时同时打开展品和引导对话
|
||||
setActiveExhibitId(1)
|
||||
setGuide1Visible(true)
|
||||
setGuide1Step(0)
|
||||
} else if (index === 2) {
|
||||
// 光标2:只打开展品(带描述)
|
||||
setActiveExhibitId(2)
|
||||
setGuide2Visible(true)
|
||||
setGuide2Step(0)
|
||||
} 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
|
||||
const total = 5
|
||||
const completed = progressCount >= total
|
||||
const subtitle = completed ? '已完成' : `${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
|
||||
|
||||
return (
|
||||
<div
|
||||
className="w-full h-full bg-cover bg-center bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: getBackgroundImage(`luxun/place3/背景`),
|
||||
}}
|
||||
>
|
||||
<Title
|
||||
title={`历史新编中的现实呐喊\n为亡友编纂的精神丰碑`}
|
||||
subtitle={subtitle}
|
||||
subtitleClassName={subtitleClassName}
|
||||
className="absolute top-10 left-1/2 -translate-x-1/2"
|
||||
/>
|
||||
|
||||
<Image
|
||||
className="absolute right-5 top-5"
|
||||
src={getStaticImage('components/离开')}
|
||||
button
|
||||
onClick={() => {
|
||||
if (moduleName && starName) {
|
||||
navigate(`/${moduleName}/${starName}/place2`)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 光标1 */}
|
||||
<Cursor
|
||||
className="absolute right-114 bottom-130"
|
||||
onClick={() => handleOpenExhibit(1)}
|
||||
size={0.6}
|
||||
read={visited.has(1)}
|
||||
disabled={!isEnabled(1)}
|
||||
/>
|
||||
{/* 光标2 */}
|
||||
<Cursor
|
||||
className="absolute right-130 bottom-115"
|
||||
onClick={() => handleOpenExhibit(2)}
|
||||
size={0.6}
|
||||
read={visited.has(2)}
|
||||
disabled={!isEnabled(2)}
|
||||
/>
|
||||
{/* 光标3 */}
|
||||
<Cursor
|
||||
className="absolute left-76 bottom-140"
|
||||
onClick={() => handleOpenExhibit(3)}
|
||||
size={0.6}
|
||||
read={visited.has(3)}
|
||||
disabled={!isEnabled(3)}
|
||||
/>
|
||||
{/* 光标4 */}
|
||||
<Cursor
|
||||
className="absolute right-238 bottom-125"
|
||||
onClick={() => handleOpenExhibit(4)}
|
||||
size={0.6}
|
||||
read={visited.has(4)}
|
||||
disabled={!isEnabled(4)}
|
||||
/>
|
||||
{/* 光标5 */}
|
||||
<Cursor
|
||||
className="absolute right-258 bottom-118"
|
||||
onClick={() => handleOpenExhibit(5)}
|
||||
size={0.6}
|
||||
read={visited.has(5)}
|
||||
disabled={!isEnabled(5)}
|
||||
/>
|
||||
|
||||
{completed && (
|
||||
<Image
|
||||
className="absolute bottom-0 right-130"
|
||||
src={getStaticImage('luxun/place3/前进按钮')}
|
||||
button
|
||||
onClick={() => {
|
||||
setLastVisitedPlace('place4')
|
||||
saveLuxunStore()
|
||||
navigate(`/${moduleName}/${starName}/place4`)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<ExhibitOverlay
|
||||
visible={activeExhibitId !== null}
|
||||
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ''}
|
||||
onOpen={() => {
|
||||
if (activeExhibitId === 1) {
|
||||
triggerPuzzleAnimation(6)
|
||||
}
|
||||
if (activeExhibitId === 2) {
|
||||
triggerPuzzleAnimation(7)
|
||||
}
|
||||
if (activeExhibitId === 3) {
|
||||
triggerPuzzleAnimation(8)
|
||||
}
|
||||
if (activeExhibitId === 4) {
|
||||
triggerPuzzleAnimation(9)
|
||||
}
|
||||
if (activeExhibitId === 5) {
|
||||
triggerPuzzleAnimation(10)
|
||||
}
|
||||
}}
|
||||
description={
|
||||
activeExhibitId === 5
|
||||
? '为了妥善出版亡友遗著,鲁迅亲自选稿、校对、设计封面。为了躲避反动派的审查,他还特意用“诸夏怀霜社”的名义出版,“怀霜”就是为了纪念瞿秋白。1936年《海上述林》上卷出版时,鲁迅的身体已经极度虚弱,但他仍一遍遍翻看样书,说“这是我对秋白最好的纪念”。'
|
||||
: undefined
|
||||
}
|
||||
audioSrc={activeExhibitId === 5 ? getPublicPath('audio/luxun/mp3_luxun_23.mp3') : undefined}
|
||||
onClose={() => {
|
||||
if (activeExhibitId === 2) {
|
||||
setActiveExhibitId(null)
|
||||
} else if (activeExhibitId === 5) {
|
||||
// 光标5:关闭展品框后显示题目
|
||||
setActiveExhibitId(null)
|
||||
setQuiz5Visible(true)
|
||||
} else if (activeExhibitId === 1) {
|
||||
// 光标1:只关闭展品,不标记为已读(等对话关闭时再标记)
|
||||
setActiveExhibitId(null)
|
||||
} else if (activeExhibitId === 3) {
|
||||
setActiveExhibitId(null)
|
||||
setQuiz2Visible(true)
|
||||
} else if (activeExhibitId === 4) {
|
||||
// 光标4:只关闭展品,不标记为已读(等对话关闭时再标记)
|
||||
setActiveExhibitId(null)
|
||||
} else {
|
||||
// 其他光标:正常关闭并标记为已读
|
||||
if (activeExhibitId !== null) {
|
||||
markExhibitVisited(place, activeExhibitId)
|
||||
}
|
||||
setActiveExhibitId(null)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 光标1的引导对话 */}
|
||||
<GuideSteps
|
||||
visible={guide1Visible}
|
||||
onVisibleChange={(visible) => {
|
||||
setGuide1Visible(visible)
|
||||
if (!visible) {
|
||||
// 对话关闭时,标记光标1为已读
|
||||
markExhibitVisited(place, 1)
|
||||
}
|
||||
}}
|
||||
currentStep={guide1Step}
|
||||
onStepChange={setGuide1Step}
|
||||
showMask={false}
|
||||
highlightSelectors={[]}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_15.mp3')}>
|
||||
小沪,书架上还有《故事新编》,这不是历史小说吗?鲁迅为什么要在这个时期写古代故事呢?
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_16.mp3')}>
|
||||
《故事新编》是鲁迅酝酿十几年的作品,最终在大陆新村9号完成定稿。表面上写的是神话传说和历史典故,实则句句都在影射现实。当时反动派妄图用复古思想麻痹民众,鲁迅就用"故事新编"的方式,借古讽今,唤醒民众。
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
|
||||
{/* 光标2的引导对话 */}
|
||||
<GuideSteps
|
||||
visible={guide2Visible}
|
||||
onVisibleChange={(visible) => {
|
||||
setGuide2Visible(visible)
|
||||
if (!visible) {
|
||||
markExhibitVisited(place, 2)
|
||||
}
|
||||
}}
|
||||
currentStep={guide2Step}
|
||||
onStepChange={setGuide2Step}
|
||||
showMask={false}
|
||||
highlightSelectors={[]}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_17.mp3')}>
|
||||
这本书里面还收录了《理水》,是大禹治水的故事吗?
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_18.mp3')}>
|
||||
不错,文章写的是大禹治水“三过家门而不入”的上古传说,实则藏着对现实的尖锐针砭。当时反动派统治腐朽,面对内忧外患只会粉饰太平,还有一群空谈理论、脱离实际的“学者”混淆视听。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide">
|
||||
大禹带领民众跋山涉水、实地勘察,摒弃“堵”的旧法改用“疏”的良方,历经千辛万苦终平水患。这哪里是写古代治水?分明是在赞颂脚踏实地、敢破敢立的实干精神,讽刺那些庸碌无为的当权者与空谈家,用远古的正义之光映照现实的黑暗。
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
|
||||
{/* 光标3的题目 */}
|
||||
<SingleChoiceQuizPanel
|
||||
visible={quiz2Visible}
|
||||
title="【单选】鲁迅在上海大陆新村9号居住期间,翻译外国作品的核心目的不包括:"
|
||||
options={[
|
||||
{
|
||||
value: 'A',
|
||||
label: 'A.为中国文艺引进新思想、新血液',
|
||||
},
|
||||
{
|
||||
value: 'B',
|
||||
label: 'B.让中国青年接触更先进的文化理念',
|
||||
},
|
||||
{
|
||||
value: 'C',
|
||||
label: 'C.直接参与武装革命的战略部署',
|
||||
},
|
||||
{
|
||||
value: 'D',
|
||||
label: 'D.以翻译为武器助力思想启蒙',
|
||||
},
|
||||
]}
|
||||
correctAnswer="C"
|
||||
errorMessage={quiz2Error}
|
||||
onSubmit={(value, isCorrect) => {
|
||||
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}
|
||||
/>
|
||||
|
||||
{/* 光标3的成功提示 */}
|
||||
<SuccessAlert
|
||||
visible={successAlert2Visible}
|
||||
content={
|
||||
'鲁迅的核心斗争方式是“以笔为刃”,通过文学创作、翻译、杂文批判等方式开展思想启蒙和文化斗争,从未直接参与武装革命的战略部署。'
|
||||
}
|
||||
onContinue={() => {
|
||||
setSuccessAlert2Visible(false)
|
||||
markExhibitVisited(place, 3)
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 光标3的引导对话 */}
|
||||
<GuideSteps
|
||||
visible={guide3Visible}
|
||||
onVisibleChange={(visible) => {
|
||||
setGuide3Visible(visible)
|
||||
}}
|
||||
currentStep={guide3Step}
|
||||
onStepChange={setGuide3Step}
|
||||
showMask={false}
|
||||
highlightSelectors={[]}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_19.mp3')}>
|
||||
我还看到书架上有很多翻译作品,这也是他在这儿完成的吗?
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_20.mp3')}>
|
||||
没错!鲁迅在这儿翻译了《死魂灵》《表》等大量外国作品。他说“没有拿来的,人不能自成为新人”,就是想通过翻译,为中国文艺引进新思想、新方法,让更多人看到世界的真相,找到救国的道路。
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
|
||||
{/* 光标4的引导对话 */}
|
||||
<GuideSteps
|
||||
visible={guide4Visible}
|
||||
onVisibleChange={(visible) => {
|
||||
setGuide4Visible(visible)
|
||||
if (!visible) {
|
||||
// 对话关闭时,标记光标4为已读
|
||||
markExhibitVisited(place, 4)
|
||||
}
|
||||
}}
|
||||
currentStep={guide4Step}
|
||||
onStepChange={setGuide4Step}
|
||||
showMask={false}
|
||||
highlightSelectors={[]}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_21.mp3')}>
|
||||
小沪,这两本书看起来格外厚重,它和鲁迅在这儿的经历有什么关联呢?
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_22.mp3')}>
|
||||
这不是鲁迅的著作,却是他在大陆新村9号倾注了全部心血的作品——为亡友瞿秋白编校的译文集《海上述林》。1935年6月,瞿秋白被国民党反动派杀害,鲁迅悲痛万分,当即决定要为挚友出版译文集,让他的思想和精神流传下去。
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
|
||||
{/* 光标5的题目 */}
|
||||
<SingleChoiceQuizPanel
|
||||
visible={quiz5Visible}
|
||||
title="【单选】鲁迅在上海大陆新村9号居住期间,为纪念瞿秋白编校的译文集是:"
|
||||
options={[
|
||||
{ value: 'A', label: 'A.《仿自由书》' },
|
||||
{ value: 'B', label: 'B.《南腔北调集》' },
|
||||
{ value: 'C', label: 'C.《海上述林》' },
|
||||
{ value: 'D', label: 'D.《故事新编》' },
|
||||
]}
|
||||
correctAnswer="C"
|
||||
errorMessage={quiz5Error}
|
||||
onSubmit={(value, isCorrect) => {
|
||||
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的成功提示 */}
|
||||
<SuccessAlert
|
||||
visible={successAlert5Visible}
|
||||
onContinue={() => {
|
||||
setSuccessAlert5Visible(false)
|
||||
// 标记光标5为已读
|
||||
markExhibitVisited(place, 5)
|
||||
// 打开光标5的引导对话
|
||||
setGuide5Visible(true)
|
||||
setGuide5Step(0)
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 光标5的引导对话 */}
|
||||
<GuideSteps
|
||||
visible={guide5Visible}
|
||||
onVisibleChange={(visible) => {
|
||||
setGuide5Visible(visible)
|
||||
}}
|
||||
currentStep={guide5Step}
|
||||
onStepChange={setGuide5Step}
|
||||
showMask={false}
|
||||
highlightSelectors={[]}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_24.mp3')}>
|
||||
原来这本书不仅是译文集,更是两人革命友谊和共同信仰的见证!
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_25.mp3')}>
|
||||
太对了!鲁迅和瞿秋白的故事不仅在于《海上述林》的字里行间,这座小楼的三楼也藏着他们为了革命事业并肩战斗的初心。
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LuxunPlace3
|
||||
@@ -0,0 +1,399 @@
|
||||
import {
|
||||
ExhibitOverlay,
|
||||
GuideSteps,
|
||||
GuideStepsItem,
|
||||
Image,
|
||||
Title,
|
||||
Cursor,
|
||||
SingleChoiceQuizPanel,
|
||||
Video,
|
||||
type VideoAnchor,
|
||||
} from '@/components'
|
||||
import type { VideoRef } from '@/components/video'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { getBackgroundImage, getPublicPath, getStaticImage } from '@/lib/utils'
|
||||
import { useState, useRef, useMemo } from 'react'
|
||||
import SuccessAlert from '@/components/layout/alert/success-alert'
|
||||
import { useCursorController } from '@/hooks/useCursorController'
|
||||
import { usePuzzleAnimation } from '@/contexts/PuzzleAnimationContext'
|
||||
import { useLuxunStore, saveLuxunStore } from '@/store/luxunStore'
|
||||
import { setCourseTimeProgress } from '@/lib/utils/api-common'
|
||||
|
||||
// starName 固定为 luxun
|
||||
const starName = 'luxun'
|
||||
|
||||
// 展品 ID 与资源路径映射
|
||||
const exhibitSrcMap: Record<1 | 2 | 3, string> = {
|
||||
1: 'luxun/place4/展品11',
|
||||
2: 'luxun/place4/展品12',
|
||||
3: 'luxun/place4/展品13',
|
||||
}
|
||||
|
||||
const quizDefaultError = '请结合刚刚的旁白内容,再思考一下吧!'
|
||||
const quizExplanations: Record<string, string> = {
|
||||
// A: "陈独秀与鲁迅有思想交往,但他并未在这间“红色庇护所”中避难、与鲁迅夜谈革命议题。",
|
||||
// B: "恭喜你,选对啦。",
|
||||
// C: "李大钊于1927年牺牲,时间上不符合这间客房被用作“红色庇护所”的背景。",
|
||||
// D: "周恩来虽长期在上海从事革命活动,但并未在这里避难并与鲁迅夜谈。",
|
||||
A: '请你结合刚刚学习的内容,再思考一下吧!',
|
||||
B: '恭喜你,选择正确!',
|
||||
C: '请你结合刚刚学习的内容,再思考一下吧!',
|
||||
D: '请你结合刚刚学习的内容,再思考一下吧!',
|
||||
}
|
||||
|
||||
const LuxunPlace5 = () => {
|
||||
const navigate = useNavigate()
|
||||
const { moduleName } = useParams<{
|
||||
moduleName: string
|
||||
}>()
|
||||
|
||||
//碎片动画触发方法
|
||||
const { triggerPuzzleAnimation } = usePuzzleAnimation()
|
||||
|
||||
const [introGuideVisible, setIntroGuideVisible] = useState(true)
|
||||
const [introGuideStep, setIntroGuideStep] = useState(0)
|
||||
|
||||
const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | 3 | null>(null)
|
||||
|
||||
// 使用持久化的访问状态
|
||||
const place = 'place4'
|
||||
const { markExhibitVisited, getVisitedExhibits, setLastVisitedPlace } = useLuxunStore()
|
||||
|
||||
// 从 store 获取已访问的展品,转换为 Set 用于兼容现有代码
|
||||
const visitedExhibits = getVisitedExhibits(place)
|
||||
const visited = new Set(visitedExhibits)
|
||||
|
||||
// Cursor 顺序控制:1 -> 2 -> 3
|
||||
const { isEnabled } = useCursorController({
|
||||
initialEnabled: [1],
|
||||
dependencies: {
|
||||
2: [1],
|
||||
3: [2],
|
||||
},
|
||||
visited: visited,
|
||||
})
|
||||
|
||||
// 光标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 [activeVideoSuccess, setActiveVideoSuccess] = useState(false)
|
||||
const [resumeVideoCallback, setResumeVideoCallback] = useState<(() => void) | null>(null)
|
||||
const videoRef = useRef<VideoRef>(null)
|
||||
|
||||
const handleOpenExhibit = (index: 1 | 2 | 3) => {
|
||||
if (index === 3) {
|
||||
setActiveExhibitId(3)
|
||||
setGuide3Visible(true)
|
||||
setGuide3Step(0)
|
||||
return
|
||||
}
|
||||
setActiveExhibitId(index)
|
||||
}
|
||||
|
||||
// 视频锚点配置
|
||||
const videoAnchors: VideoAnchor[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'quiz-anchor',
|
||||
time: 41,
|
||||
once: true,
|
||||
afterResume: 'remove',
|
||||
render: ({ resume }) => (
|
||||
<>
|
||||
<SingleChoiceQuizPanel
|
||||
visible={!activeVideoSuccess}
|
||||
title='【单选】毛泽东主席称赞鲁迅先生为“最伟大和最英勇的___”。'
|
||||
options={[
|
||||
{ value: 'A', label: 'A. 旗手' },
|
||||
{ value: 'B', label: 'B. 作家' },
|
||||
{ value: 'C', label: 'C. 战士' },
|
||||
]}
|
||||
correctAnswer="A"
|
||||
onWrongSelect={(value: string) => {
|
||||
switch (value) {
|
||||
case 'B':
|
||||
return '这不是毛泽东主席的原话。请你再想想吧!'
|
||||
case 'C':
|
||||
return '这不是毛泽东主席的原话。请你再想想吧!'
|
||||
default:
|
||||
return '请你再想想吧!'
|
||||
}
|
||||
}}
|
||||
onSubmit={(value: string, isCorrect: boolean) => {
|
||||
if (isCorrect) {
|
||||
setActiveVideoSuccess(true)
|
||||
setResumeVideoCallback(() => resume)
|
||||
}
|
||||
}}
|
||||
zIndex={20000}
|
||||
/>
|
||||
|
||||
<SuccessAlert
|
||||
visible={activeVideoSuccess}
|
||||
onContinue={() => {
|
||||
setActiveVideoSuccess(false)
|
||||
const cb = resumeVideoCallback
|
||||
setResumeVideoCallback(null)
|
||||
cb?.()
|
||||
}}
|
||||
onClose={() => {
|
||||
setActiveVideoSuccess(false)
|
||||
const cb = resumeVideoCallback
|
||||
setResumeVideoCallback(null)
|
||||
cb?.()
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
},
|
||||
],
|
||||
[activeVideoSuccess, resumeVideoCallback]
|
||||
)
|
||||
|
||||
const progressCount = visited.size
|
||||
const total = 3
|
||||
const completed = progressCount >= total
|
||||
const subtitle = completed ? '已完成' : `${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
|
||||
|
||||
return (
|
||||
<div
|
||||
className="w-full h-full bg-cover bg-center bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: getBackgroundImage(`luxun/place4/背景`),
|
||||
}}
|
||||
>
|
||||
<Title
|
||||
title="6平方米的红色庇护所"
|
||||
subtitle={subtitle}
|
||||
subtitleClassName={subtitleClassName}
|
||||
className="absolute top-10 left-1/2 -translate-x-1/2"
|
||||
/>
|
||||
|
||||
<Image
|
||||
className="absolute right-5 top-5"
|
||||
src={getStaticImage('components/离开')}
|
||||
button
|
||||
onClick={() => {
|
||||
if (moduleName && starName) {
|
||||
navigate(`/${moduleName}/${starName}/place3`)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 展品 */}
|
||||
<Cursor
|
||||
className="absolute left-167 bottom-30"
|
||||
onClick={() => handleOpenExhibit(1)}
|
||||
read={visited.has(1)}
|
||||
disabled={!isEnabled(1)}
|
||||
/>
|
||||
<Cursor
|
||||
className="absolute left-228 bottom-30"
|
||||
onClick={() => handleOpenExhibit(2)}
|
||||
read={visited.has(2)}
|
||||
disabled={!isEnabled(2)}
|
||||
/>
|
||||
<Cursor
|
||||
className="absolute right-115 bottom-18 z-20"
|
||||
onClick={() => handleOpenExhibit(3)}
|
||||
read={visited.has(3)}
|
||||
disabled={!isEnabled(3)}
|
||||
/>
|
||||
|
||||
{completed && (
|
||||
<Image
|
||||
className="absolute bottom-0 right-0"
|
||||
src={getStaticImage('components/place/继续前进')}
|
||||
button
|
||||
onClick={() => {
|
||||
// 完成后先播放视频,不立即跳转页面
|
||||
saveLuxunStore()
|
||||
setShowEndingVideo(true)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<ExhibitOverlay
|
||||
visible={activeExhibitId !== null}
|
||||
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ''}
|
||||
onOpen={() => {
|
||||
if (activeExhibitId === 1) {
|
||||
triggerPuzzleAnimation(11)
|
||||
}
|
||||
if (activeExhibitId === 2) {
|
||||
triggerPuzzleAnimation(12)
|
||||
}
|
||||
if (activeExhibitId === 3) {
|
||||
triggerPuzzleAnimation(13)
|
||||
}
|
||||
}}
|
||||
description={
|
||||
activeExhibitId === 1
|
||||
? '瞿秋白同志曾说,“鲁迅是莱谟斯,是野兽的奶汁所喂养大的,是封建宗法社会的逆子,是绅士阶级的贰臣,而同时也是一些浪漫谛克的革命家的诤友!”'
|
||||
: activeExhibitId === 2
|
||||
? '鲁迅先生曾经抄录清朝诗人何瓦琴的对联赠给瞿秋白,“人生得一知己足矣,斯世当以同怀视之。”'
|
||||
: undefined
|
||||
}
|
||||
onClose={() => {
|
||||
if (activeExhibitId === 2) {
|
||||
setActiveExhibitId(null)
|
||||
setQuizVisible(true)
|
||||
return
|
||||
}
|
||||
if (activeExhibitId === 3) {
|
||||
// 对话关闭时再标记已读
|
||||
setActiveExhibitId(null)
|
||||
return
|
||||
}
|
||||
if (activeExhibitId !== null) {
|
||||
markExhibitVisited(place, activeExhibitId)
|
||||
}
|
||||
setActiveExhibitId(null)
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 学习引导结束后的对话 */}
|
||||
<GuideSteps
|
||||
visible={introGuideVisible}
|
||||
onVisibleChange={setIntroGuideVisible}
|
||||
currentStep={introGuideStep}
|
||||
onStepChange={setIntroGuideStep}
|
||||
showMask={false}
|
||||
highlightSelectors={[]}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_26.mp3')}>
|
||||
你说的是这间小小的客房吗,这里为什么会被称为“红色庇护所”呢?
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_27.mp3')}>
|
||||
你可别小看这间仅6平方米的客房,在白色恐怖笼罩的1933年至1936年,这里是很多共产党人的"安全港湾"。1933年,瞿秋白夫妇第三次到鲁迅家避难,就秘密住进了这里。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide">
|
||||
当时反动派到处搜捕共产党人,鲁迅冒着生命危险掩护他们,两人常彻夜长谈。瞿秋白的夫人杨之华回忆道:“秋白和鲁迅在一起,往往感觉夜太短。深刻的友谊的交谈,从政治到文艺,从实际到理论,从希腊到莫斯科,轻松,愉快,活泼。”
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
|
||||
{/* 光标2的题目 */}
|
||||
<SingleChoiceQuizPanel
|
||||
visible={quizVisible}
|
||||
title="【单选】上海鲁迅故居三楼客房被称为“红色庇护所”,以下哪位共产党人曾在此避难并与鲁迅探讨革命议题?"
|
||||
options={[
|
||||
{ value: 'A', label: 'A.陈独秀' },
|
||||
{ value: 'B', label: 'B.瞿秋白' },
|
||||
{ value: 'C', label: 'C.李大钊' },
|
||||
{ value: 'D', label: 'D.周恩来' },
|
||||
]}
|
||||
correctAnswer="B"
|
||||
errorMessage={quizError}
|
||||
onSubmit={(value, isCorrect) => {
|
||||
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的成功提示 */}
|
||||
<SuccessAlert
|
||||
visible={successAlertVisible}
|
||||
content="1933年,瞿秋白夫妇第三次到鲁迅家避难,就住进了这间仅6平方米的客房,与鲁迅常常彻夜长谈革命与文学。"
|
||||
onContinue={() => {
|
||||
setSuccessAlertVisible(false)
|
||||
markExhibitVisited(place, 2)
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 光标3的引导对话 */}
|
||||
<GuideSteps
|
||||
visible={guide3Visible}
|
||||
onVisibleChange={(visible) => {
|
||||
setGuide3Visible(visible)
|
||||
if (!visible) {
|
||||
markExhibitVisited(place, 3)
|
||||
}
|
||||
}}
|
||||
currentStep={guide3Step}
|
||||
onStepChange={setGuide3Step}
|
||||
showMask={false}
|
||||
highlightSelectors={[]}
|
||||
zIndex={10000}
|
||||
>
|
||||
<GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/luxun/mp3_luxun_28.mp3')}>
|
||||
除了瞿秋白,还有其他共产党人来过这里吗
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_29.mp3')}>
|
||||
当然!1936年4月,中共中央特派员冯雪峰到上海开展工作,也先住进了这间客房。冯雪峰把红军长征胜利、遵义会议召开的消息告诉鲁迅,还带来了毛泽东同志提出的抗日民族统一战线主张。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide">
|
||||
鲁迅听后格外振奋,激动地说“我做一个小兵还是胜任的,用笔!”,这句话也成了他晚年投身抗日救亡运动的誓言。
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
|
||||
{/* 结尾视频播放 */}
|
||||
{showEndingVideo && (
|
||||
<Video
|
||||
ref={videoRef}
|
||||
src={getPublicPath('video/luxun/luxun_06.mp4')}
|
||||
className="fixed inset-0 z-20000"
|
||||
controls
|
||||
autoPlay
|
||||
playsInline
|
||||
showSkipButton
|
||||
anchors={videoAnchors}
|
||||
onEnded={() => {
|
||||
setEndingGuideVisible(true)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 视频结束后的结束语对话 */}
|
||||
<GuideSteps
|
||||
visible={endingGuideVisible}
|
||||
onVisibleChange={(visible) => {
|
||||
setShowEndingVideo(false)
|
||||
setEndingGuideVisible(visible)
|
||||
if (!visible && moduleName) {
|
||||
// 对话结束后返回鲁迅首页
|
||||
setCourseTimeProgress(7)
|
||||
navigate(`/${moduleName}/${starName}/home`)
|
||||
}
|
||||
}}
|
||||
showMask={false}
|
||||
zIndex={20010}
|
||||
>
|
||||
<GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/luxun/mp3_luxun_30.mp3')}>
|
||||
我们已经了解了鲁迅居住在上海大陆新村9号时的重要事件。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem speaker="guide">
|
||||
接下来,请你接过先生手中的“笔”,走出上海,跨越时空,追寻他从绍兴三味书屋到上海的创作足迹——解锁每个地标背后的故事,填充文字里的时代线索,在互动中,读懂先生笔墨间的温度与力量。
|
||||
</GuideStepsItem>
|
||||
</GuideSteps>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LuxunPlace5
|
||||
Reference in new issue
Block a user