Files
shanghai-residences/src/pages/chenyun/place/place8.tsx
T
2026-04-30 09:17:31 +08:00

318 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState } from 'react'
import {
ExhibitOverlay,
Title,
Image,
Cursor,
GuideSteps,
GuideStepsItem,
MultipleChoiceQuizPanel,
SingleChoiceQuizPanel,
} from '@/components'
import { getBackgroundImage, getPublicPath, getStaticImage } 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, string> = {
1: 'chenyun/place8/场景8展品1',
2: 'chenyun/place8/场景8展品2',
}
const ChenyunPlace8 = () => {
const navigate = useNavigate()
const { moduleName } = useParams<{
moduleName: string
}>()
// 获取碎片动画触发方法
const { triggerPuzzleAnimation } = usePuzzleAnimation()
const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | null>(null)
// 使用持久化的访问状态
const place = 'place8'
const { markExhibitVisited, getVisitedExhibits, setLastVisitedPlace } = useChenyunStore()
// 从 store 获取已访问的展品,转换为 Set 用于兼容现有代码
const visitedExhibits = getVisitedExhibits(place)
const visited = new Set(visitedExhibits)
const { isEnabled } = useCursorController({
initialEnabled: [1],
dependencies: { 2: [1] },
visited,
})
// 展品2的对话引导
const [guideVisible, setGuideVisible] = useState(false)
const [guideStep, setGuideStep] = useState(0)
const [guideVisible2, setGuideVisible2] = useState(false)
const [guideStep2, setGuideStep2] = useState(0)
const [quizVisible, setQuizVisible] = useState(false)
const [successAlertVisible, setSuccessAlertVisible] = useState(false)
const [quizPassed, setQuizPassed] = useState(false)
// 关闭对话后出现的“统购统销”单选题
const [closeQuizVisible, setCloseQuizVisible] = useState(false)
const [closeSuccessAlertVisible, setCloseSuccessAlertVisible] = useState(false)
const [closeQuizPassed, setCloseQuizPassed] = useState(false)
const handleOpenExhibit = (index: 1 | 2) => {
setActiveExhibitId(index)
if (index === 1) {
setGuideVisible2(true)
setGuideStep2(0)
setQuizPassed(false)
}
// 如果是展品2,显示对话引导
if (index === 2) {
setGuideVisible(true)
setGuideStep(0)
}
}
// 监听对话引导步骤变化
const handleGuideStepChange = (step: number) => {
setGuideStep(step)
}
// 监听对话引导完成
const handleGuideVisibleChange = (visible: boolean) => {
setGuideVisible(visible)
}
const progressCount = visited.size
const total = 2
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/place8/场景8`),
}}
>
{/* 标题 */}
<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}/place7`)
}
}}
/>
{/* 展品1 */}
<Cursor
className="absolute right-175 top-75"
onClick={() => handleOpenExhibit(1)}
read={visited.has(1)}
disabled={!isEnabled(1)}
/>
{/* 展品2 */}
<Cursor
className="absolute right-100 bottom-55"
onClick={() => handleOpenExhibit(2)}
read={visited.has(2)}
disabled={!isEnabled(2)}
/>
{/* 继续前进 - 仅在完成所有展品后显示 */}
{completed && (
<Image
className="absolute bottom-0 right-150"
src={getStaticImage('chenyun/place8/继续前进6')}
button
onClick={() => {
setLastVisitedPlace('place9')
saveChenyunStore()
navigate(`/${moduleName}/${starName}/place9`)
}}
/>
)}
{/* 遮罩层 */}
<ExhibitOverlay
visible={activeExhibitId !== null}
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ''}
onOpen={() => {
if (activeExhibitId === 1) {
triggerPuzzleAnimation(11)
}
}}
// description={
// activeExhibitId === 1
// ? `打赢“银元之战”“两白一黑”战役的过程彰显了中国共产党治理经济的卓越能力!这里有一份“一五”计划报告的手稿,陈云在“一五”计划的编制中做出了重大贡献。
// 一九五四年,陈云的主要工作之一,就是主持编制第一个五年计划纲要。这次编制工作是在前四次基础上进行的,陈云提出计划编制工作中要注意几个问题:首先是工业投资金额,其次是市场供应和人民生活,第三是农业发展速度,这三个问题对编制计划有指导意义。第一个五年计划纲要草案的重点是优先发展重工业,特别是156项重点工程。当时陈云重点抓重工业建设和粮食保障,通过“统购统销”稳定粮价,为重点工程项目筑牢根基,亲手铺就了我国工业化的起步之路。`
// : undefined
// }
onClose={() => {
if (activeExhibitId !== null) {
markExhibitVisited(place, activeExhibitId)
}
setActiveExhibitId(null)
}}
/>
{/* 展品2的对话引导 - 在展品遮罩层上方显示 */}
<GuideSteps
visible={guideVisible}
onVisibleChange={handleGuideVisibleChange}
currentStep={guideStep}
onStepChange={handleGuideStepChange}
showMask={false}
highlightSelectors={[]}
zIndex={10001}
>
<GuideStepsItem
speaker="student"
audioSrc={getPublicPath('audio/chenyun/mp3_chenyun_25.mp3')}
>
您讲的“统购统销”是不是和这里我们看到的粮票有直接关系啊?
</GuideStepsItem>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath('audio/chenyun/mp3_chenyun_26.mp3')}
>
不错,随着大规模经济建设的展开,全国粮、棉、油等主要农产品严重紧缺,供求矛盾尖锐。陈云经过调查研究,反复比较,权衡利弊得失,终于下决心采用在农村征购,在城市配售的解决粮食问题的办法,也就是后来所说的“统购统销”。
</GuideStepsItem>
<GuideStepsItem speaker="guide">
陈云说:“只有采用这种办法,才能保证我国人民生活日益增长的需要,才能制止投机活动,保证市场物价的稳定,才能使发展国民经济第一个五年计划得以顺利地进行。”
</GuideStepsItem>
</GuideSteps>
{/* 打赢“银元之战”“两白一黑”战役的过程真的是彰显了中国共产党治理经济的卓越能力!这里有一份“一五”计划报告的手稿,陈云在“一五”计划的编制中做出了什么贡献吗? */}
<GuideSteps
visible={guideVisible2}
onVisibleChange={(visible) => {
setGuideVisible2(visible)
// 关闭对话后,如果还未完成该题,则弹出题目
if (!visible && !closeQuizPassed) {
setCloseQuizVisible(true)
}
}}
currentStep={guideStep2}
onStepChange={(step) => {
// 在第 3 句(guideStep2 === 2)结束后,进入下一句前先弹题
if (step === 3 && !quizPassed) {
setGuideStep2(2)
setQuizVisible(true)
return
}
setGuideStep2(step)
}}
showMask={false}
highlightSelectors={[]}
zIndex={10001}
>
<GuideStepsItem
speaker="student"
audioSrc={getPublicPath('audio/chenyun/mp3_chenyun_23.mp3')}
>
打赢“银元之战”“两白一黑”战役的过程真的是彰显了中国共产党治理经济的卓越能力!这里有一份“一五”计划报告的手稿,陈云在“一五”计划的编制中做出了什么贡献吗?
</GuideStepsItem>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath('audio/chenyun/mp3_chenyun_24.mp3')}
>
一九五四年,陈云的主要工作之一,就是主持编制第一个五年计划纲要。
</GuideStepsItem>
<GuideStepsItem speaker="guide">
这次编制工作是在前四次基础上进行的,陈云提出计划编制工作中要注意几个问题:首先是工业投资金额,其次是市场供应和人民生活,第三是农业发展速度,这三个问题对编制计划有指导意义。
</GuideStepsItem>
<GuideStepsItem speaker="guide">
第一个五年计划纲要草案的重点是优先发展重工业,特别是156项重点工程。当时陈云重点抓重工业建设和粮食保障,通过“统购统销”稳定粮价,为重点工程项目筑牢根基,亲手铺就了我国工业化的起步之路。
</GuideStepsItem>
</GuideSteps>
{/* “这三个问题…”结束后的题目 + 成功提示(使用 ScaledPortal) */}
<ScaledPortal enabled={quizVisible || successAlertVisible} zIndex={10050}>
<>
<MultipleChoiceQuizPanel
visible={quizVisible}
title="【多选】陈云主持编制第一个五年计划纲要时提出计划编制工作中要注意的问题包括:"
options={[
{ value: 'A', label: 'A.工业投资金额' },
{ value: 'B', label: 'B.市场供应和人民生活' },
{ value: 'C', label: 'C.农业发展速度' },
]}
correctAnswer={['A', 'B', 'C']}
minSelections={1}
maxSelections={3}
errorMessage="你的选择还不够全面哦~请你再想想吧!"
onSubmit={(_values, isCorrect) => {
if (isCorrect) {
setQuizVisible(false)
setSuccessAlertVisible(true)
}
}}
zIndex={10000}
/>
<SuccessAlert
visible={successAlertVisible}
onContinue={() => {
setSuccessAlertVisible(false)
setQuizPassed(true)
setGuideVisible2(true)
setGuideStep2(3)
}}
/>
</>
</ScaledPortal>
{/* 关闭对话后出现的题目(单选) + 成功提示(使用 ScaledPortal) */}
<ScaledPortal enabled={closeQuizVisible || closeSuccessAlertVisible} zIndex={10050}>
<>
<SingleChoiceQuizPanel
visible={closeQuizVisible}
title="【单选】第一个五年计划纲要草案的重点是优先发展重工业,特别是156项重点工程。当时陈云重点抓重工业建设和粮食保障,通过“____”稳定粮价。"
options={[
{ value: 'A', label: 'A.优先分配' },
{ value: 'B', label: 'B.统购统销' },
{ value: 'C', label: 'C.依靠进口' },
]}
correctAnswer="B"
errorMessage="请你再想想吧!"
onWrongSelect={() => '这不是当时陈云稳定粮价的方法。请你再想想吧!'}
onSubmit={(_value, isCorrect) => {
if (!isCorrect) return
setCloseQuizVisible(false)
setCloseSuccessAlertVisible(true)
}}
zIndex={10000}
/>
<SuccessAlert
visible={closeSuccessAlertVisible}
onContinue={() => {
setCloseSuccessAlertVisible(false)
// setCloseQuizPassed(true);
}}
/>
</>
</ScaledPortal>
</div>
)
}
export default ChenyunPlace8