- 在 chenyunStore 中引入 lastVisitedPlace 和 setLastVisitedPlace 方法,支持记录用户上次访问的场景。 - 在各个场景组件中使用 useEffect 设置 lastVisitedPlace,确保用户在返回时能继续上次访问的地点。 - 更新相关组件,确保在导航时能够正确使用 lastVisitedPlace,提升用户交互体验。 - 在 puzzleStore 中添加保存用户定义的功能,增强数据持久性。
268 lines
9.2 KiB
TypeScript
268 lines
9.2 KiB
TypeScript
import { useState, useEffect } from 'react'
|
||
import {
|
||
ExhibitOverlay,
|
||
Title,
|
||
Image,
|
||
Cursor,
|
||
Video,
|
||
GuideSteps,
|
||
GuideStepsItem,
|
||
MultipleChoiceQuizPanel,
|
||
} from '@/components'
|
||
import { getBackgroundImage, getStaticImage, getPublicPath } from '@/lib/utils'
|
||
import { useNavigate, useParams } from 'react-router-dom'
|
||
import { useChenyunStore, saveChenyunStore } from '@/store/chenyunStore'
|
||
import { usePuzzleAnimation } from '@/contexts/PuzzleAnimationContext'
|
||
import { useCursorController } from '@/hooks/useCursorController'
|
||
import SuccessAlert from '@/components/layout/alert/success-alert'
|
||
import ScaledPortal from '@/components/layout/ScaledPortal'
|
||
|
||
// starName 固定为 chenyun
|
||
const starName = 'chenyun'
|
||
|
||
// 展品 ID 与资源路径映射
|
||
const exhibitSrcMap: Record<1 | 2 | 3, string> = {
|
||
1: 'chenyun/place5/场景5展品1',
|
||
2: 'chenyun/place5/场景5展品2',
|
||
3: 'chenyun/place5/场景5展品3',
|
||
}
|
||
// 展品描述映射(目前未使用,后续如需在展品弹窗中显示可恢复)
|
||
// const exhibitDescriptionMap: Record<1 | 2 | 3, string> = {
|
||
// 1: "",
|
||
// 2: "延安时期因为国民党的封锁,陕甘宁边区经济困难。陈云转战陕甘宁边区主持财经工作,他遇到了很多经济难题。1944年新春伊始,陈云开始担任西北财经办事处副主任,工作转到财经方面,这是陈云以主要精力从事领导经济工作的开始。当时,陕甘宁边区在国民党严密封锁下,财经状况严峻,边区物价猛涨,老百姓日常生活必需的布匹和粮食十分缺乏。国民党顽固派封锁边区,企图“不让一粒粮、一尺布进入边区”,同时千方百计阻止边区食盐出口。",
|
||
// 3: "",
|
||
// };
|
||
const ChenyunPlace5 = () => {
|
||
const navigate = useNavigate()
|
||
const { moduleName } = useParams<{
|
||
moduleName: string
|
||
}>()
|
||
|
||
// 获取碎片动画触发方法
|
||
const { triggerPuzzleAnimation } = usePuzzleAnimation()
|
||
|
||
const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | 3 | null>(null)
|
||
|
||
// 使用持久化的访问状态
|
||
const place = 'place5'
|
||
const { markExhibitVisited, getVisitedExhibits, setLastVisitedPlace } = useChenyunStore()
|
||
|
||
useEffect(() => {
|
||
setLastVisitedPlace(place)
|
||
}, [setLastVisitedPlace])
|
||
|
||
// 从 store 获取已访问的展品,转换为 Set 用于兼容现有代码
|
||
const visitedExhibits = getVisitedExhibits(place)
|
||
const visited = new Set(visitedExhibits)
|
||
const { isEnabled } = useCursorController({
|
||
initialEnabled: [1, 2],
|
||
dependencies: { 3: [1, 2] },
|
||
visited,
|
||
})
|
||
const [videoVisible3, setVideoVisible3] = useState(false)
|
||
const [quiz3Visible, setQuiz3Visible] = useState(false)
|
||
const [successAlert3Visible, setSuccessAlert3Visible] = useState(false)
|
||
|
||
// 展品1引导对话
|
||
const [guideVisible, setGuideVisible] = useState(false)
|
||
const [guideStep, setGuideStep] = useState(0)
|
||
|
||
const handleOpenExhibit = (index: 1 | 2 | 3) => {
|
||
if (index === 3) {
|
||
// 展品3:播放视频,不打开展品
|
||
setVideoVisible3(true)
|
||
return
|
||
}
|
||
if (index === 2) {
|
||
setGuideVisible(true)
|
||
setGuideStep(0)
|
||
}
|
||
setActiveExhibitId(index)
|
||
}
|
||
|
||
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(`chenyun/place5/场景5`),
|
||
}}
|
||
>
|
||
{/* 标题 */}
|
||
<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}/place4`)
|
||
}
|
||
}}
|
||
/>
|
||
|
||
{/* 展品1 */}
|
||
<Cursor
|
||
className="absolute left-30 top-70"
|
||
onClick={() => handleOpenExhibit(1)}
|
||
read={visited.has(1)}
|
||
disabled={!isEnabled(1)}
|
||
/>
|
||
{/* 展品2 */}
|
||
<Cursor
|
||
className="absolute left-107 top-72"
|
||
onClick={() => handleOpenExhibit(2)}
|
||
read={visited.has(2)}
|
||
disabled={!isEnabled(2)}
|
||
/>
|
||
|
||
{/* 展品3 */}
|
||
<Cursor
|
||
className="absolute right-170 top-84"
|
||
onClick={() => handleOpenExhibit(3)}
|
||
read={visited.has(3)}
|
||
disabled={!isEnabled(3)}
|
||
/>
|
||
|
||
{/* 继续前进 - 仅在完成所有展品后显示 */}
|
||
{completed && (
|
||
<Image
|
||
className="absolute bottom-5 right-20"
|
||
src={getStaticImage('chenyun/place5/继续前进4')}
|
||
button
|
||
onClick={() => {
|
||
saveChenyunStore()
|
||
navigate(`/${moduleName}/${starName}/place6`)
|
||
}}
|
||
/>
|
||
)}
|
||
|
||
{/* 展品1的引导对话 */}
|
||
<GuideSteps
|
||
visible={guideVisible}
|
||
onVisibleChange={setGuideVisible}
|
||
currentStep={guideStep}
|
||
onStepChange={(step) => setGuideStep(step)}
|
||
showMask={false}
|
||
highlightSelectors={[]}
|
||
zIndex={10000}
|
||
>
|
||
<GuideStepsItem
|
||
speaker="student"
|
||
audioSrc={getPublicPath('audio/chenyun/mp3_chenyun_15.mp3')}
|
||
>
|
||
小沪,延安时期因为国民党的封锁,陕甘宁边区经济困难。陈云转战陕甘宁边区主持财经工作,他一定遇到了很多经济难题吧。
|
||
</GuideStepsItem>
|
||
<GuideStepsItem
|
||
speaker="guide"
|
||
audioSrc={getPublicPath('audio/chenyun/mp3_chenyun_16.mp3')}
|
||
>
|
||
1944年新春伊始,陈云开始担任西北财经办事处副主任,工作转到财经方面,这是陈云以主要精力从事领导经济工作的开始。当时,陕甘宁边区在国民党严密封锁下,财经状况严峻,边区物价猛涨,老百姓日常生活必需的布匹和粮食十分缺乏。
|
||
</GuideStepsItem>
|
||
<GuideStepsItem speaker="guide">
|
||
国民党顽固派封锁边区,企图“不让一粒粮、一尺布进入边区”,同时千方百计阻止边区食盐出口。
|
||
</GuideStepsItem>
|
||
</GuideSteps>
|
||
|
||
{/* 展品3视频播放(全屏) */}
|
||
{videoVisible3 && (
|
||
<Video
|
||
src={getPublicPath('video/chenyun/chenyun_07.mp4')}
|
||
className="w-full h-full"
|
||
autoPlay
|
||
playsInline
|
||
showSkipButton
|
||
onEnded={() => {
|
||
setVideoVisible3(false)
|
||
setQuiz3Visible(true)
|
||
}}
|
||
/>
|
||
)}
|
||
|
||
{/* 展品3视频后的题目 + 成功提示(使用 ScaledPortal) */}
|
||
<ScaledPortal enabled={quiz3Visible || successAlert3Visible} zIndex={10050}>
|
||
<>
|
||
<MultipleChoiceQuizPanel
|
||
visible={quiz3Visible}
|
||
title="【多选】陈云主持陕甘宁边区财经工作期间,提出的解决当时经济困难的应对之策包括:"
|
||
options={[
|
||
{ value: 'A', label: 'A.实行贸易统一' },
|
||
{
|
||
value: 'B',
|
||
label: 'B.事先准确估计情况,预测市场商情,以争取主动',
|
||
},
|
||
{
|
||
value: 'C',
|
||
label: 'C.不断总结封锁状态下对外贸易的经验,摸索实现等价交换的途径',
|
||
},
|
||
{
|
||
value: 'D',
|
||
label: 'D.贸易公司对边区内部贸易也要采取市场上做生意的办法',
|
||
},
|
||
{ value: 'E', label: 'E.做贸易工作的干部要精通业务' },
|
||
]}
|
||
correctAnswer={['A', 'B', 'C', 'D', 'E']}
|
||
minSelections={1}
|
||
maxSelections={5}
|
||
errorMessage="你的选择还不够全面哦~请你再想想吧!"
|
||
onSubmit={(_values, isCorrect) => {
|
||
if (isCorrect) {
|
||
setQuiz3Visible(false)
|
||
setSuccessAlert3Visible(true)
|
||
}
|
||
}}
|
||
zIndex={10000}
|
||
/>
|
||
|
||
<SuccessAlert
|
||
visible={successAlert3Visible}
|
||
onContinue={() => {
|
||
setSuccessAlert3Visible(false)
|
||
markExhibitVisited(place, 3)
|
||
triggerPuzzleAnimation(8)
|
||
}}
|
||
/>
|
||
</>
|
||
</ScaledPortal>
|
||
|
||
{/* 遮罩层 */}
|
||
<ExhibitOverlay
|
||
visible={activeExhibitId !== null}
|
||
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ''}
|
||
// description={
|
||
// activeExhibitId ? exhibitDescriptionMap[activeExhibitId] : undefined
|
||
// }
|
||
autoPlayDescription={activeExhibitId === 2}
|
||
onOpen={() => {
|
||
if (activeExhibitId === 2) {
|
||
triggerPuzzleAnimation(7)
|
||
}
|
||
}}
|
||
onClose={() => {
|
||
if (activeExhibitId !== null) {
|
||
markExhibitVisited(place, activeExhibitId)
|
||
}
|
||
setActiveExhibitId(null)
|
||
}}
|
||
/>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default ChenyunPlace5
|