417 lines
15 KiB
TypeScript
417 lines
15 KiB
TypeScript
import { useState, useRef } from 'react'
|
|
import {
|
|
ExhibitOverlay,
|
|
Title,
|
|
Image,
|
|
Cursor,
|
|
GuideSteps,
|
|
GuideStepsItem,
|
|
Video,
|
|
type VideoRef,
|
|
type DragFillResult,
|
|
} from '@/components'
|
|
import { useCursorController } from '@/hooks/useCursorController'
|
|
import { getBackgroundImage, getPublicPath, getStaticImage } from '@/lib/utils'
|
|
import { useNavigate, useParams } from 'react-router-dom'
|
|
import { SuccessAlert, DragQuizPanel } from '@/components/layout'
|
|
import { usePuzzleAnimation } from '@/contexts/PuzzleAnimationContext'
|
|
import { useSunzhongshanStore, saveSunzhongshanStore } from '@/store/sunzhongshanStore'
|
|
|
|
const starName = 'sunzhongshan'
|
|
|
|
const exhibitSrcMap: Record<1 | 2 | 3 | 4, string> = {
|
|
1: 'sunzhongshan/place3/李大钊给胡适的信',
|
|
2: 'sunzhongshan/place3/中国国民党第一次全国代表大会宣言',
|
|
3: 'sunzhongshan/place3/星期评论',
|
|
4: 'sunzhongshan/place3/社会主义的精义',
|
|
}
|
|
|
|
const SunzhongshanPlace3 = () => {
|
|
const navigate = useNavigate()
|
|
const { moduleName } = useParams<{
|
|
moduleName: string
|
|
}>()
|
|
|
|
// 获取碎片动画触发方法
|
|
const { triggerPuzzleAnimation } = usePuzzleAnimation()
|
|
|
|
const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | 3 | 4 | null>(null)
|
|
|
|
// 使用持久化的访问状态
|
|
const place = 'place3'
|
|
const { markExhibitVisited, getVisitedExhibits } = useSunzhongshanStore()
|
|
|
|
// 从 store 获取已访问的展品,转换为 Set 用于兼容现有代码
|
|
const visitedExhibits = getVisitedExhibits(place)
|
|
const visited = new Set(visitedExhibits)
|
|
|
|
// Cursor 顺序控制:1 -> 2 -> 3 -> 4
|
|
const { isEnabled } = useCursorController({
|
|
initialEnabled: [4],
|
|
dependencies: {
|
|
1: [3],
|
|
2: [1],
|
|
3: [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 [showVideo2, setShowVideo2] = useState(false)
|
|
const video2Ref = useRef<VideoRef>(null)
|
|
// 光标2的拖拽题状态
|
|
const [dragQuiz2Visible, setDragQuiz2Visible] = useState(false)
|
|
const [dragQuiz2Value, setDragQuiz2Value] = useState<DragFillResult[]>([])
|
|
const [dragQuiz2Error, setDragQuiz2Error] = useState('')
|
|
const [successAlert2Visible, setSuccessAlert2Visible] = useState(false)
|
|
// 光标3的对话状态
|
|
const [guide3Visible, setGuide3Visible] = useState(false)
|
|
const [guide3Step, setGuide3Step] = useState(0)
|
|
// 光标4的对话状态
|
|
const [guide4Visible, setGuide4Visible] = useState(false)
|
|
const [guide4Step, setGuide4Step] = useState(0)
|
|
|
|
const handleOpenExhibit = (index: 1 | 2 | 3 | 4) => {
|
|
setActiveExhibitId(index)
|
|
// 根据不同的展品显示对应的对话,并重置进度
|
|
if (index === 1) {
|
|
setGuide1Step(0)
|
|
setGuide1Visible(true)
|
|
} else if (index === 2) {
|
|
setGuide2Step(0)
|
|
setGuide2Visible(true)
|
|
} else if (index === 3) {
|
|
setGuide3Step(0)
|
|
setGuide3Visible(true)
|
|
} else if (index === 4) {
|
|
setGuide4Step(0)
|
|
setGuide4Visible(true)
|
|
}
|
|
}
|
|
|
|
const progressCount = visited.size
|
|
const total = 4
|
|
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(`sunzhongshan/place3/背景`),
|
|
}}
|
|
>
|
|
<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}/place2`)
|
|
}
|
|
}}
|
|
/>
|
|
|
|
<Cursor
|
|
className="absolute left-198 top-118"
|
|
onClick={() => handleOpenExhibit(1)}
|
|
read={visited.has(1)}
|
|
disabled={!isEnabled(1)}
|
|
/>
|
|
<Cursor
|
|
className="absolute left-210 top-140"
|
|
onClick={() => handleOpenExhibit(2)}
|
|
read={visited.has(2)}
|
|
disabled={!isEnabled(2)}
|
|
/>
|
|
|
|
<Cursor
|
|
className="absolute right-182 bottom-95"
|
|
onClick={() => handleOpenExhibit(3)}
|
|
read={visited.has(3)}
|
|
disabled={!isEnabled(3)}
|
|
/>
|
|
<Cursor
|
|
className="absolute right-158 bottom-95"
|
|
onClick={() => handleOpenExhibit(4)}
|
|
read={visited.has(4)}
|
|
disabled={!isEnabled(4)}
|
|
/>
|
|
|
|
{completed && (
|
|
<Image
|
|
className="absolute bottom-0 right-110"
|
|
src={getStaticImage('components/place/r-前进')}
|
|
button
|
|
onClick={() => {
|
|
const { setLastVisitedPlace } = useSunzhongshanStore.getState()
|
|
setLastVisitedPlace('place4')
|
|
saveSunzhongshanStore()
|
|
navigate(`/${moduleName}/${starName}/place4`)
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
<ExhibitOverlay
|
|
visible={activeExhibitId !== null}
|
|
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ''}
|
|
onOpen={() => {
|
|
if (activeExhibitId === 4) {
|
|
triggerPuzzleAnimation(8)
|
|
}
|
|
if (activeExhibitId === 1) {
|
|
triggerPuzzleAnimation(9)
|
|
}
|
|
if (activeExhibitId === 2) {
|
|
triggerPuzzleAnimation(10)
|
|
}
|
|
}}
|
|
onClose={() => {
|
|
const currentId = activeExhibitId
|
|
// 关闭展品框时,重置所有对话的进度并隐藏对话,确保遮罩层正确清理
|
|
setGuide1Step(0)
|
|
setGuide1Visible(false)
|
|
setGuide2Step(0)
|
|
setGuide2Visible(false)
|
|
setGuide3Step(0)
|
|
setGuide3Visible(false)
|
|
setGuide4Step(0)
|
|
setGuide4Visible(false)
|
|
|
|
if (currentId === 2) {
|
|
// 光标2:关闭窗口后播放视频
|
|
setActiveExhibitId(null)
|
|
setShowVideo2(true)
|
|
return
|
|
}
|
|
|
|
if (currentId !== null) {
|
|
markExhibitVisited(place, currentId)
|
|
}
|
|
setActiveExhibitId(null)
|
|
}}
|
|
/>
|
|
|
|
{/* 光标1的对话 */}
|
|
<GuideSteps
|
|
visible={guide1Visible}
|
|
currentStep={guide1Step}
|
|
onStepChange={setGuide1Step}
|
|
onVisibleChange={(nextVisible) => {
|
|
setGuide1Visible(nextVisible)
|
|
}}
|
|
showMask={false}
|
|
highlightSelectors={[]}
|
|
zIndex={10000}
|
|
>
|
|
<GuideStepsItem
|
|
speaker="student"
|
|
audioSrc={getPublicPath('audio/sunzhongshan/mp3_sunzhongshan_36.mp3')}
|
|
>
|
|
这张是李大钊先生的手迹啊,和孙中山先生有什么关系呢?
|
|
</GuideStepsItem>
|
|
<GuideStepsItem
|
|
speaker="guide"
|
|
audioSrc={getPublicPath('audio/sunzhongshan/mp3_sunzhongshan_37.mp3')}
|
|
>
|
|
这封信的收件人是胡适。信里提到,孙中山先生经历了陈炯明叛变事件回到上海后,态度变得很冷静,不再坚持之前的护法主张,反而提出“收军权于中央”“结合民主的联合战线,与反动派决裂”等。
|
|
</GuideStepsItem>
|
|
<GuideStepsItem
|
|
speaker="student"
|
|
audioSrc={getPublicPath('audio/sunzhongshan/mp3_sunzhongshan_38.mp3')}
|
|
>
|
|
孙先生与李大钊先生进行了深入的交谈。他在寻找新的合作力量吗?
|
|
</GuideStepsItem>
|
|
<GuideStepsItem
|
|
speaker="guide"
|
|
audioSrc={getPublicPath('audio/sunzhongshan/mp3_sunzhongshan_39.mp3')}
|
|
>
|
|
这个力量就是新生的中国共产党。孙中山先生向共产党人释放了巨大的诚意。除了与李大钊的频繁接触,他还在上海会见了共产国际代表马林,明确表示愿意和苏俄合作;邀请鲍罗庭来中国担任国民党组织教练员;
|
|
</GuideStepsItem>
|
|
<GuideStepsItem speaker="guide">
|
|
与陈独秀多次沟通,在共产国际与中共的建议和帮助下改组国民党,为国民党一大的召开做准备。
|
|
</GuideStepsItem>
|
|
</GuideSteps>
|
|
|
|
{/* 光标2的对话 */}
|
|
<GuideSteps
|
|
visible={guide2Visible}
|
|
currentStep={guide2Step}
|
|
onStepChange={setGuide2Step}
|
|
onVisibleChange={(nextVisible) => {
|
|
setGuide2Visible(nextVisible)
|
|
}}
|
|
showMask={false}
|
|
highlightSelectors={[]}
|
|
zIndex={10000}
|
|
>
|
|
<GuideStepsItem
|
|
speaker="student"
|
|
audioSrc={getPublicPath('audio/sunzhongshan/mp3_sunzhongshan_40.mp3')}
|
|
>
|
|
我记得在毛泽东旧居陈列馆中学到,国共第一次合作正式形成的标志就是国民党一大,这就是当时的大会宣言吗?
|
|
</GuideStepsItem>
|
|
<GuideStepsItem
|
|
speaker="guide"
|
|
audioSrc={getPublicPath('audio/sunzhongshan/mp3_sunzhongshan_41.mp3')}
|
|
>
|
|
完全正确!1924年1月20日,中国国民党第一次全国代表大会在广东高师礼堂开幕,孙中山先生以国民党总理的身份担任大会主席,主持开幕式。此次大会共有165名代表出席,其中共产党员代表超过20人,包括李大钊、毛泽东等中共早期领导人。
|
|
</GuideStepsItem>
|
|
<GuideStepsItem speaker="guide">
|
|
会议上,孙先生重新解释了三民主义,事实上确立了联俄、联共、扶助农工的三大政策。第一次国共合作正式形成后,轰轰烈烈的国民革命也就此展开。
|
|
</GuideStepsItem>
|
|
</GuideSteps>
|
|
|
|
{/* 光标2的视频 */}
|
|
{showVideo2 && (
|
|
<Video
|
|
ref={video2Ref}
|
|
src={getPublicPath('video/sunzhongshan/sunzhongshan_08.mp4')}
|
|
className="fixed inset-0 z-[20000]"
|
|
autoPlay
|
|
playsInline
|
|
showSkipButton
|
|
onEnded={() => {
|
|
setShowVideo2(false)
|
|
setDragQuiz2Visible(true)
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
{/* 光标2的拖拽题 */}
|
|
<DragQuizPanel
|
|
visible={dragQuiz2Visible}
|
|
zIndex={10000}
|
|
title=""
|
|
questionPrefix="【拖拽】中国国民党第一次全国代表大会事实上确立了:"
|
|
questionSuffix="三大政策。"
|
|
options={[
|
|
{ value: '联俄', label: '联俄' },
|
|
{ value: '联共', label: '联共' },
|
|
{ value: '扶助农工', label: '扶助农工' },
|
|
{ value: '反俄', label: '反俄' },
|
|
]}
|
|
blanks={[
|
|
{ id: 'blank1', label: '____' },
|
|
{ id: 'blank2', label: '____' },
|
|
{ id: 'blank3', label: '____' },
|
|
]}
|
|
value={dragQuiz2Value}
|
|
error={dragQuiz2Error}
|
|
onChange={(value) => {
|
|
setDragQuiz2Value(value)
|
|
setDragQuiz2Error('')
|
|
if (value.length < 3) return
|
|
// 检查答案:需要三个空白都填满,且答案正确
|
|
const correctAnswers = ['联俄', '联共', '扶助农工']
|
|
const filledAnswers = value.map((v) => v.optionValue)
|
|
const answerSet = new Set(correctAnswers)
|
|
const filledSet = new Set(filledAnswers)
|
|
const isCorrect =
|
|
answerSet.size === filledSet.size &&
|
|
[...answerSet].every((answer) => filledSet.has(answer))
|
|
if (isCorrect) {
|
|
setDragQuiz2Visible(false)
|
|
setSuccessAlert2Visible(true)
|
|
} else {
|
|
setDragQuiz2Error(
|
|
'中国国民党第一次全国代表大会上,孙中山重新解释了三民主义,事实上确立了联俄、联共、扶助农工的三大政策。三大政策是孙中山的重要政治主张,使他倡导的民族民主革命从屡受挫折转向成功进而走上了正确道路。'
|
|
)
|
|
}
|
|
}}
|
|
/>
|
|
|
|
{/* 光标2的成功提示 */}
|
|
<SuccessAlert
|
|
visible={successAlert2Visible}
|
|
onContinue={() => {
|
|
setSuccessAlert2Visible(false)
|
|
// 修改cursor状态
|
|
markExhibitVisited(place, 2)
|
|
}}
|
|
onClose={() => {
|
|
setSuccessAlert2Visible(false)
|
|
// 修改cursor状态
|
|
markExhibitVisited(place, 2)
|
|
}}
|
|
/>
|
|
|
|
{/* 光标3的对话 */}
|
|
<GuideSteps
|
|
visible={guide3Visible}
|
|
currentStep={guide3Step}
|
|
onStepChange={setGuide3Step}
|
|
onVisibleChange={(nextVisible) => {
|
|
setGuide3Visible(nextVisible)
|
|
}}
|
|
showMask={false}
|
|
highlightSelectors={[]}
|
|
zIndex={10000}
|
|
>
|
|
<GuideStepsItem
|
|
speaker="student"
|
|
audioSrc={getPublicPath('audio/sunzhongshan/mp3_sunzhongshan_34.mp3')}
|
|
>
|
|
这时候,工农群众的力量还没有正式登上历史舞台呢。
|
|
</GuideStepsItem>
|
|
<GuideStepsItem
|
|
speaker="guide"
|
|
audioSrc={getPublicPath('audio/sunzhongshan/mp3_sunzhongshan_35.mp3')}
|
|
>
|
|
旁边这本《星期评论》创刊于五四运动后。孙中山先生在五四运动中看到了群众的力量和工人、学生们的热情。更觉顺应时代潮流,传播新文化、介绍马克思主义、鼓励工人运动的重要性。
|
|
</GuideStepsItem>
|
|
<GuideStepsItem speaker="guide">
|
|
这份进步刊物成为一扇窗,让国人,也让孙先生自己看到了民族、民主革命的新转机。
|
|
</GuideStepsItem>
|
|
</GuideSteps>
|
|
|
|
{/* 光标4的对话 */}
|
|
<GuideSteps
|
|
visible={guide4Visible}
|
|
currentStep={guide4Step}
|
|
onStepChange={setGuide4Step}
|
|
onVisibleChange={(nextVisible) => {
|
|
setGuide4Visible(nextVisible)
|
|
}}
|
|
showMask={false}
|
|
highlightSelectors={[]}
|
|
zIndex={10000}
|
|
>
|
|
<GuideStepsItem
|
|
speaker="student"
|
|
audioSrc={getPublicPath('audio/sunzhongshan/mp3_sunzhongshan_32.mp3')}
|
|
>
|
|
这本书看起来很特别,《社会主义的精义》是孙中山先生写的吗?他也关注社会主义学说呀?
|
|
</GuideStepsItem>
|
|
<GuideStepsItem
|
|
speaker="guide"
|
|
audioSrc={getPublicPath('audio/sunzhongshan/mp3_sunzhongshan_33.mp3')}
|
|
>
|
|
不仅关注,而且还很早。1912年10月14日-16日,孙中山先生连续三日在上海三马路(今汉口路)中华大戏院发表关于社会主义学说的演讲,吸引了众多听众。这就是演说后经由他本人修订出版的小册子。
|
|
</GuideStepsItem>
|
|
<GuideStepsItem speaker="guide">
|
|
后来俄国十月革命胜利,上海《民国日报》最先在中国报道了这个消息。
|
|
</GuideStepsItem>
|
|
</GuideSteps>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default SunzhongshanPlace3
|