import { ExhibitOverlay, GuideSteps, GuideStepsItem, Image, MatchQuizPanel, MultipleChoiceQuizPanel, SingleChoiceQuizPanel, Title, } from '@/components' import Cursor from '@/components/cursor' import { ErrorAlert, SuccessAlert } from '@/components/layout' import { useCursorController } from '@/hooks/useCursorController' import { getBackgroundImage, getPublicPath, getStaticImage } from '@/lib/utils' import { useEffect, useMemo, useRef, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { useNieerStore, saveNieerStore } from '@/store/nieerStore' import { usePuzzleAnimation } from '@/contexts/PuzzleAnimationContext' const NieerPlace5 = () => { const navigate = useNavigate() const { moduleName } = useParams<{ moduleName: string }>() // 获取碎片动画触发方法 const { triggerPuzzleAnimation } = usePuzzleAnimation() const starName = 'nieer' const place = 'place5' const { markExhibitVisited, getVisitedExhibits } = useNieerStore() const setLastVisitedPlace = useNieerStore((s) => s.setLastVisitedPlace) const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | 3 | null>(null) // 光标1对话(图1) const [guide1Visible, setGuide1Visible] = useState(false) const [guide1Step, setGuide1Step] = useState(0) // 光标2对话(图2) const [guide2Visible, setGuide2Visible] = useState(false) const [guide2Step, setGuide2Step] = useState(0) // 光标3对话(图5) const [guide3Visible, setGuide3Visible] = useState(false) const [guide3Step, setGuide3Step] = useState(0) // 光标2题目1(图3:填空) const [quiz2_1Visible, setQuiz2_1Visible] = useState(false) const quiz2_1WrongCountRef = useRef(0) const [quiz2_1HintVisible, setQuiz2_1HintVisible] = useState(false) const [success2_1Visible, setSuccess2_1Visible] = useState(false) // 光标2题目2(图4:多选) const [quiz2_2Visible, setQuiz2_2Visible] = useState(false) const [success2_2Visible, setSuccess2_2Visible] = useState(false) // 光标3题目1(图6:配对) const [quiz3_1Visible, setQuiz3_1Visible] = useState(false) const [success3_1Visible, setSuccess3_1Visible] = useState(false) // 光标3题目2(图7:判断) const [quiz3_2Visible, setQuiz3_2Visible] = useState(false) const [success3_2Visible, setSuccess3_2Visible] = useState(false) const visitedExhibits = getVisitedExhibits(place) const visited = useMemo(() => new Set(visitedExhibits), [visitedExhibits]) const total = 3 const progressCount = visited.size const completed = progressCount >= total const subtitle = completed ? '已完成' : `${progressCount}/${total}` const { isEnabled } = useCursorController({ initialEnabled: [1], dependencies: { 2: [1], 3: [2], }, visited: visitedExhibits, }) useEffect(() => { if (!quiz2_1Visible) { quiz2_1WrongCountRef.current = 0 setQuiz2_1HintVisible(false) } }, [quiz2_1Visible]) if (!moduleName) return null const exhibitSrcMap: Record<1 | 2 | 3, string> = { 1: 'nieer/place5/场景5展品1', 2: 'nieer/place5/场景5展品3', 3: 'nieer/place5/场景5展品2', } const handleOpenExhibit = (id: 1 | 2 | 3) => { setActiveExhibitId(id) // 光标1显示guide2的内容(选定国歌时间线),光标2显示guide1的内容(宪法修正案) if (id === 1) { setGuide2Step(0) setGuide2Visible(true) } if (id === 2) { setGuide1Step(0) setGuide1Visible(true) } if (id === 3) { setGuide3Step(0) setGuide3Visible(true) } } return (
<Image className="absolute right-5 top-5" src={getStaticImage('components/离开')} button onClick={() => navigate(`/${moduleName}/${starName}/place4`)} /> <Cursor className="absolute left-165 bottom-122" onClick={() => handleOpenExhibit(1)} read={visited.has(1)} disabled={!isEnabled(1)} /> <Cursor className="absolute left-280 bottom-120" onClick={() => handleOpenExhibit(2)} read={visited.has(2)} disabled={!isEnabled(2)} /> <Cursor className="absolute right-46 bottom-120" onClick={() => handleOpenExhibit(3)} read={visited.has(3)} disabled={!isEnabled(3)} /> {completed && ( <Image className="absolute bottom-0 right-0" src={getStaticImage('components/place/继续前进')} button onClick={() => { setLastVisitedPlace('place6') saveNieerStore() navigate(`/${moduleName}/${starName}/place6`) }} /> )} <ExhibitOverlay visible={activeExhibitId !== null} src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ''} onOpen={() => { if (activeExhibitId === 1) { triggerPuzzleAnimation(9) } if (activeExhibitId === 2) { triggerPuzzleAnimation(10) } if (activeExhibitId === 3) { triggerPuzzleAnimation(11) } }} onClose={() => { const closingId = activeExhibitId setActiveExhibitId(null) setGuide1Visible(false) setGuide2Visible(false) setGuide3Visible(false) if (closingId == 1) { markExhibitVisited(place, 1) } // 展品2关闭后触发光标2的两道题 if (closingId === 2) { saveNieerStore() setQuiz2_1Visible(true) } if (closingId === 3) { setQuiz3_1Visible(true) } }} /> {/* 光标1对话(图1) - 选定国歌时间线 */} <GuideSteps visible={guide2Visible} currentStep={guide2Step} onStepChange={setGuide2Step} onVisibleChange={setGuide2Visible} showMask={false} highlightSelectors={[]} zIndex={10001} > <GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/nieer/mp3_nieer_20.mp3')}> 小沪,从抗日战歌到正式被确立为国歌,中间经历了多久呀?《义勇军进行曲》第一次作为国歌奏响是在什么时候呢? </GuideStepsItem> <GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/nieer/mp3_nieer_21_1.mp3')}> 时间跨度还真不短呢!1949年9月27日,中国人民政治协商会议第一届全体会议决定,在国歌未正式制定前,以《义勇军进行曲》作为代国歌。 </GuideStepsItem> <GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/nieer/mp3_nieer_21_2.mp3')}> 同年10月1日开国大典上,它第一次在天安门广场作为国歌庄严奏响,见证了新中国的诞生。直到1982年12月4日,第五届全国人民代表大会第五次会议才正式将它定为中华人民共和国国歌,完成了从代国歌到正式国歌的跨越。 </GuideStepsItem> </GuideSteps> {/* 光标2对话(图2) - 宪法修正案 */} <GuideSteps visible={guide1Visible} currentStep={guide1Step} onStepChange={setGuide1Step} onVisibleChange={setGuide1Visible} showMask={false} highlightSelectors={[]} zIndex={10001} > <GuideStepsItem speaker="student" audioSrc={getPublicPath('audio/nieer/mp3_nieer_22.mp3')}> 那2004年的宪法修正案又对国歌做了什么重要规定呢?为什么要把它写入宪法呀? </GuideStepsItem> <GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/nieer/mp3_nieer_23_1.mp3')}> 2004年3月14日,第十届全国人民代表大会二次会议通过宪法修正案,明确规定“中华人民共和国国歌是《义勇军进行曲》”,这让国歌的地位有了根本大法的保障。 </GuideStepsItem> <GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/nieer/mp3_nieer_23_2.mp3')}> 把它写入宪法,是因为这首歌不仅记录了民族救亡的历史,更凝聚了中华民族的精神气节。从抗战时期的冲锋号到新时代的强国音,它早已成为国家尊严的象征,写入宪法能更好地培育全民的爱国意识和国家观念。 </GuideStepsItem> </GuideSteps> {/* 光标2题目1(图3:选择题) - 错两次弹窗提示 */} <SingleChoiceQuizPanel visible={quiz2_1Visible} zIndex={10001} title="【单选】2004年3月14日,第十届全国人民代表大会二次会议通过宪法修正案,明确规定“中华人民共和国国歌是《____》”。" options={[ { value: 'A', label: 'A.义勇军进行曲' }, { value: 'B', label: 'B.卖报歌' }, { value: 'C', label: 'C.开矿歌' }, ]} correctAnswer="A" errorMessage="回答错误,请你再仔细想想吧。" onSubmit={(_value, isCorrect) => { if (isCorrect) { setQuiz2_1Visible(false) setSuccess2_1Visible(true) } }} onError={() => { quiz2_1WrongCountRef.current += 1 if (quiz2_1WrongCountRef.current >= 2) { setQuiz2_1HintVisible(true) } }} /> <ErrorAlert visible={quiz2_1HintVisible} text="提示:中华人民共和国国歌是田汉作词、聂耳作曲的《义勇军进行曲》。" zIndex={10002} onClose={() => setQuiz2_1HintVisible(false)} /> <SuccessAlert visible={success2_1Visible} onClose={() => { setSuccess2_1Visible(false) setQuiz2_2Visible(true) }} /> {/* 光标2题目2(图4:多选) */} <MultipleChoiceQuizPanel visible={quiz2_2Visible} zIndex={10001} title="【多选】2004年,《义勇军进行曲》被正式写入《中华人民共和国宪法》。下列关于国歌入宪意义的表述,正确的有:" options={[ { value: 'A', label: 'A.让国歌的地位获得了根本大法的坚实保障' }, { value: 'B', label: 'B.记录了民族救亡的历史,凝聚了中华民族的精神气节' }, { value: 'C', label: 'C.确立了国歌作为国家尊严象征的法律地位,更好地培育全民爱国意识和国家观念', }, ]} correctAnswer={['A', 'B', 'C']} errorMessage="你的选择还不够全面哦~请你再想想吧!" minSelections={1} maxSelections={3} submitText="提交" onSubmit={(_values, isCorrect) => { if (isCorrect) { setQuiz2_2Visible(false) setSuccess2_2Visible(true) } }} /> <SuccessAlert visible={success2_2Visible} onClose={() => { setSuccess2_2Visible(false) markExhibitVisited(place, 2) }} /> {/* 光标3对话(图5) - 关闭展品3后依次出现两道题 */} <GuideSteps visible={guide3Visible} currentStep={guide3Step} onStepChange={setGuide3Step} onVisibleChange={setGuide3Visible} showMask={false} highlightSelectors={[]} zIndex={10001} > <GuideStepsItem speaker="guide" audioSrc={getPublicPath('audio/nieer/mp3_nieer_24.mp3')}> 根据宪法,2017年9月1日第十二届全国人民代表大会常务委员会第二十九次会议通过《中华人民共和国国歌法》,通过国家立法对国歌的奏唱场合、奏唱礼仪和宣传教育进行规范。 </GuideStepsItem> </GuideSteps> {/* 光标3题目1(图6:配对) */} <MatchQuizPanel visible={quiz3_1Visible} zIndex={10001} title="【连线】请将左侧《义勇军进行曲》的关键事件与右侧时间进行匹配:" leftItems={[ { id: 'e1982', label: '第五届全国人民代表大会第五次会议正式将《义勇军进行曲》定为中华人民共和国国歌。', }, { id: 'e2017', label: '第十二届全国人民代表大会常务委员会第二十九次会议通过《中华人民共和国国歌法》。', }, { id: 'e1949', label: '中国人民政治协商会议第一届全体会议决定,在国歌未正式制定前,以《义勇军进行曲》作为代国歌。', }, { id: 'e2004', label: '第十届全国人民代表大会二次会议通过宪法修正案,明确规定“中华人民共和国国歌是《义勇军进行曲》”。', }, ]} rightItems={[ { id: 't1949', label: '1949年9月27日' }, { id: 't1982', label: '1982年12月4日' }, { id: 't2004', label: '2004年3月14日' }, { id: 't2017', label: '2017年9月1日' }, ]} correctMatches={[ { leftId: 'e1949', rightId: 't1949' }, { leftId: 'e1982', rightId: 't1982' }, { leftId: 'e2004', rightId: 't2004' }, { leftId: 'e2017', rightId: 't2017' }, ]} errorMessage={(matches) => { const expectedMap = new Map([ ['e1949', 't1949'], ['e1982', 't1982'], ['e2004', 't2004'], ['e2017', 't2017'], ]) const firstWrongLeft = matches.find( (m) => expectedMap.get(m.leftId) !== m.rightId )?.leftId if (!firstWrongLeft) return '请你再想想吧!' if (firstWrongLeft === 'e1949') { return '1949年9月27日,中国人民政治协商会议第一届全体会议决定,在国歌未正式制定前,以《义勇军进行曲》作为代国歌。请你再想想吧!' } if (firstWrongLeft === 'e1982') { return '1982年12月4日,第五届全国人民代表大会第五次会议正式将《义勇军进行曲》定为中华人民共和国国歌。请你再想想吧!' } if (firstWrongLeft === 'e2004') { return '2004年3月14日,第十届全国人民代表大会二次会议通过宪法修正案,明确规定“中华人民共和国国歌是《义勇军进行曲》”。请你再想想吧!' } return '2017年9月1日第十二届全国人民代表大会常务委员会第二十九次会议通过《中华人民共和国国歌法》。请你再想想吧!' }} onSubmit={(_matches, isCorrect) => { if (isCorrect) { setQuiz3_1Visible(false) setSuccess3_1Visible(true) } }} /> <SuccessAlert visible={success3_1Visible} title="恭喜你,匹配正确!" onClose={() => { setSuccess3_1Visible(false) setQuiz3_2Visible(true) }} /> {/* 光标3题目2(图7:判断) */} <SingleChoiceQuizPanel visible={quiz3_2Visible} zIndex={10001} title="【判断】《中华人民共和国国歌法》规定中华人民共和国国歌是《义勇军进行曲》。中华人民共和国国歌是中华人民共和国的象征和标志。一切公民和组织都应当尊重国歌,维护国歌的尊严。" options={[ { value: 'A', label: 'A.正确' }, { value: 'B', label: 'B.错误' }, ]} correctAnswer="A" errorMessage="请你再想想吧!" onSubmit={(_value, isCorrect) => { if (isCorrect) { setQuiz3_2Visible(false) setSuccess3_2Visible(true) } }} /> <SuccessAlert title="恭喜你,判断正确!" visible={success3_2Visible} onClose={() => { setSuccess3_2Visible(false) markExhibitVisited(place, 3) }} /> </div> ) } export default NieerPlace5