更新依赖项及历史人物相关内容资源

- 更新 package.json 和 package-lock.json 中的依赖项
- 新增/更新陈云、黄炎培、鲁迅、孙中山的音频文件
- 新增场景和组件的图片资源
- 清理未使用的音频和图片文件
- 优化多个组件和页面的实现逻辑
This commit is contained in:
zhongyidian committed 2026-04-20 13:27:18 +08:00
1 parent b1d55b9464
commit e0fa47d21a
629 files changed
+24390 -2991

No files matched your search

+473
View File
@@ -0,0 +1,473 @@
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'
const NieerPlace5 = () => {
const navigate = useNavigate()
const { moduleName } = useParams<{ moduleName: string }>()
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展品2',
3: 'nieer/place5/场景5展品3',
}
const handleOpenExhibit = (id: 1 | 2 | 3) => {
setActiveExhibitId(id)
if (id === 1) {
setGuide1Step(0)
setGuide1Visible(true)
}
if (id === 2) {
setGuide2Step(0)
setGuide2Visible(true)
}
if (id === 3) {
setGuide3Step(0)
setGuide3Visible(true)
}
}
return (
<div
className="w-full h-full bg-cover bg-center bg-no-repeat"
style={{
backgroundImage: getBackgroundImage(`${starName}/${place}/场景5`),
}}
>
<Title
title="强我中华的进行曲"
subtitle={subtitle}
className="absolute top-10 left-1/2 -translate-x-1/2"
/>
<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] : ''}
onClose={() => {
const closingId = activeExhibitId
setActiveExhibitId(null)
setGuide1Visible(false)
setGuide2Visible(false)
setGuide3Visible(false)
// 光标1:只需要对话,关窗即完成
if (closingId === 1) {
markExhibitVisited(place, 1)
saveNieerStore()
}
}}
/>
{/* 光标1对话(图1) */}
<GuideSteps
visible={guide1Visible}
currentStep={guide1Step}
onStepChange={setGuide1Step}
onVisibleChange={setGuide1Visible}
showMask={false}
highlightSelectors={[]}
zIndex={10001}
>
<GuideStepsItem
speaker="student"
audioSrc={getPublicPath('audio/nieer/mp3_nieer_place5_01.mp3')}
>
那2004年的宪法修正案又对国歌做了什么重要规定呢?为什么要把它写入宪法呀?
</GuideStepsItem>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath('audio/nieer/mp3_nieer_place5_02.mp3')}
>
2004年3月14日,第十届全国人民代表大会二次会议通过宪法修正案,明确规定“中华人民共和国国歌是《义勇军进行曲》”,这让国歌的地位有了根本大法的保障。
</GuideStepsItem>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath('audio/nieer/mp3_nieer_place5_03.mp3')}
>
把它写入宪法,是因为这首歌不仅记录了民族救亡的历史,更凝聚了中华民族的精神气节。从抗战时期的冲锋号到新时代的强国音,它早已成为国家尊严的象征,写入宪法能更好地培育全民的爱国意识和国家观念。
</GuideStepsItem>
</GuideSteps>
{/* 光标2对话(图2) - 对话结束后依次出现两道题 */}
<GuideSteps
visible={guide2Visible}
currentStep={guide2Step}
onStepChange={setGuide2Step}
onVisibleChange={(nextVisible) => {
setGuide2Visible(nextVisible)
if (!nextVisible) {
setQuiz2_1Visible(true)
}
}}
showMask={false}
highlightSelectors={[]}
zIndex={10001}
>
<GuideStepsItem
speaker="student"
audioSrc={getPublicPath('audio/nieer/mp3_nieer_place5_03.mp3')}
>
小沪,从抗日战歌到正式被确立为国歌,中间经历了多久呀?《义勇军进行曲》第一次作为国歌奏响是在什么时候呢?
</GuideStepsItem>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath('audio/nieer/mp3_nieer_place5_04.mp3')}
>
时间跨度还真不短呢!1949年9月27日,中国人民政治协商会议第一届全体会议决定,在国歌未正式制定前,以《义勇军进行曲》作为代国歌。
</GuideStepsItem>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath('audio/nieer/mp3_nieer_place5_05.mp3')}
>
同年10月1日开国大典上,它第一次在天安门广场作为国歌庄严奏响,见证了新中国的诞生。直到1982年12月4日,第五届全国人民代表大会第五次会议才正式将它定为中华人民共和国国歌,完成了从代国歌到正式国歌的跨越。
</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}
title="恭喜你, 选择正确!"
onContinue={() => {
setSuccess2_1Visible(false)
setQuiz2_2Visible(true)
}}
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}
onContinue={() => {
setSuccess2_2Visible(false)
markExhibitVisited(place, 2)
saveNieerStore()
}}
onClose={() => {
setSuccess2_2Visible(false)
markExhibitVisited(place, 2)
saveNieerStore()
}}
/>
{/* 光标3对话(图5) - 对话结束后依次出现两道题 */}
<GuideSteps
visible={guide3Visible}
currentStep={guide3Step}
onStepChange={setGuide3Step}
onVisibleChange={(nextVisible) => {
setGuide3Visible(nextVisible)
if (!nextVisible) {
setQuiz3_1Visible(true)
}
}}
showMask={false}
highlightSelectors={[]}
zIndex={10001}
>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath('audio/nieer/mp3_nieer_place5_05.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="恭喜你, 匹配正确!"
onContinue={() => {
setSuccess3_1Visible(false)
setQuiz3_2Visible(true)
}}
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
visible={success3_2Visible}
onContinue={() => {
setSuccess3_2Visible(false)
markExhibitVisited(place, 3)
saveNieerStore()
}}
onClose={() => {
setSuccess3_2Visible(false)
markExhibitVisited(place, 3)
saveNieerStore()
}}
/>
</div>
)
}
export default NieerPlace5