- 更新展品图片(鲁迅/毛泽东/孙中山/黄炎培/聂耳/张乐平故居) - 新增点击查看图标、报纸素材 - 优化视频组件、拼图组件、展品组件 - 更新陈云音频资源 - 新增输入验证文档和工具函数 - 组件布局和动画优化 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
268 lines
8.5 KiB
TypeScript
268 lines
8.5 KiB
TypeScript
import { useState, useRef } from 'react'
|
|
import { Title, Image, Cursor, StudyGuideModal, Video } from '@/components'
|
|
import { MultipleChoiceQuizPanel } from '@/components/layout/quiz'
|
|
import { SuccessAlert, ErrorAlert } from '@/components/layout'
|
|
import { getBackgroundImage, getStaticImage, getPublicPath } from '@/lib/utils'
|
|
import { useNavigate, useParams } from 'react-router-dom'
|
|
import ViseAssemblyDialog from './scene3/ViseAssemblyDialog'
|
|
import type { VideoRef } from '@/components/video'
|
|
import { QuizDialog } from './components'
|
|
import { useHuangyanpeiStore } from '@/store/huangyanpeiStore'
|
|
import { setCourseTimeProgress } from '@/lib/utils/api-common'
|
|
import { useCursorController } from '@/hooks/useCursorController'
|
|
import { saveHuangyanpeiStore } from '@/store/huangyanpeiStore'
|
|
import { usePuzzleAnimation } from '@/contexts/PuzzleAnimationContext'
|
|
|
|
const starName = 'huangyanpei'
|
|
|
|
const HuangyanpeiReflectionScene3 = () => {
|
|
const navigate = useNavigate()
|
|
const { moduleName } = useParams<{
|
|
moduleName: string
|
|
}>()
|
|
|
|
const { triggerPuzzleAnimation } = usePuzzleAnimation()
|
|
|
|
//喇叭考题弹窗
|
|
const [showQuizDialog, setShowQuizDialog] = useState(false)
|
|
|
|
const [showGuide1, setShowGuide1] = useState(true)
|
|
const [showDialog, setShowDialog] = useState(false)
|
|
const [showQuiz, setShowQuiz] = useState(false)
|
|
const [showSuccessAlert, setShowSuccessAlert] = useState(false)
|
|
const [showErrorAlert, setShowErrorAlert] = useState(false)
|
|
const [showErrorAlertForQuiz, setShowErrorAlertForQuiz] = useState(false)
|
|
const [showCompleteGuide, setShowCompleteGuide] = useState(false)
|
|
const [showVideo, setShowVideo] = useState(false)
|
|
const videoRef = useRef<VideoRef>(null)
|
|
|
|
// 使用持久化的reflection cursor状态
|
|
const scene = 'scene3'
|
|
const { markReflectionCursorVisited, getVisitedReflectionCursors } = useHuangyanpeiStore()
|
|
|
|
// 从 store 获取已完成的cursor,转换为 Set 用于兼容现有代码
|
|
const visitedCursors = getVisitedReflectionCursors(scene)
|
|
const visited = new Set(visitedCursors)
|
|
|
|
const { isEnabled } = useCursorController({
|
|
initialEnabled: [2],
|
|
dependencies: { 1: [2], 3: [1, 2] },
|
|
visited: visitedCursors,
|
|
})
|
|
|
|
if (!moduleName) {
|
|
return null
|
|
}
|
|
|
|
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(`huangyanpei/reflection/scene3/11_001`),
|
|
}}
|
|
>
|
|
<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={() => {
|
|
navigate(`/${moduleName}/${starName}/reflection2`)
|
|
}}
|
|
/>
|
|
|
|
<Image
|
|
className="absolute left-5 top-5"
|
|
src={getStaticImage('huangyanpei/reflection/components/喇叭1')}
|
|
// button
|
|
// onClick={() => {
|
|
// if (isEnabled(3)) {
|
|
// setShowQuizDialog(true)
|
|
// } else {
|
|
// setShowErrorAlertForQuiz(true)
|
|
// }
|
|
// }}
|
|
// aria-disabled={!isEnabled(3)}
|
|
/>
|
|
|
|
{/* 第一段引导 */}
|
|
<StudyGuideModal
|
|
visible={showGuide1}
|
|
onContinue={() => {
|
|
setShowGuide1(false)
|
|
}}
|
|
audioSrc={getPublicPath('audio/huangyanpei/mp3_huangyanpei_25.mp3')}
|
|
firstLineIndent="2em"
|
|
>
|
|
终于到中华职业学校啦!这里是中国近代职教的摇篮,“免学费、包分配”,还能学真手艺,快来练就一技之长。
|
|
{'\n'}
|
|
你选了学技术,那就来挑战制作中华职校的“明星产品”——台钳吧!当年这台钳还拿过巴拿马万国博览会金奖呢!
|
|
</StudyGuideModal>
|
|
|
|
{/* 互动展品光标:组装台钳互动 */}
|
|
<Cursor
|
|
className="absolute right-100 bottom-55"
|
|
onClick={() => {
|
|
setShowDialog(true)
|
|
}}
|
|
read={visited.has(1)}
|
|
disabled={!isEnabled(1)}
|
|
/>
|
|
|
|
{/* 答题光标 */}
|
|
<Cursor
|
|
className="absolute left-145 top-68"
|
|
onClick={() => {
|
|
setShowQuiz(true)
|
|
}}
|
|
read={visited.has(2)}
|
|
disabled={!isEnabled(2)}
|
|
/>
|
|
|
|
{/* 喇叭光标 */}
|
|
<Cursor
|
|
className="absolute left-31 top-9"
|
|
onClick={() => {
|
|
if (isEnabled(3)) {
|
|
setShowQuizDialog(true)
|
|
} else {
|
|
setShowErrorAlertForQuiz(true)
|
|
}
|
|
}}
|
|
read={visited.has(3)}
|
|
disabled={!isEnabled(3)}
|
|
/>
|
|
|
|
{/* 组装台钳互动弹窗 */}
|
|
<ViseAssemblyDialog
|
|
visible={showDialog}
|
|
onClose={() => setShowDialog(false)}
|
|
onComplete={() => {
|
|
setShowDialog(false)
|
|
setShowCompleteGuide(true)
|
|
markReflectionCursorVisited(scene, 1)
|
|
}}
|
|
/>
|
|
|
|
{/* 多选题答题框 */}
|
|
<MultipleChoiceQuizPanel
|
|
visible={showQuiz}
|
|
title="【多选】制作台钳需要哪些工具?"
|
|
options={[
|
|
{ value: 'A', label: 'A. 锯子' },
|
|
{ value: 'B', label: 'B. 毛笔' },
|
|
{ value: 'C', label: 'C. 锉刀' },
|
|
{ value: 'D', label: 'D. 铁锤' },
|
|
]}
|
|
correctAnswer={['A', 'C', 'D']}
|
|
errorMessage={(selectedValues) => {
|
|
// 如果选择了B,显示包含"毛笔是写字的哦"的提示
|
|
if (selectedValues.includes('B')) {
|
|
return '毛笔是写字的哦!台钳是铁制品,得用锯子、锉刀、铁锤这些工具,再选一次吧!'
|
|
}
|
|
// 其他情况(单选A或C或D,或者AC、CD、AD等组合)
|
|
return '台钳是铁制品,得用锯子、锉刀、铁锤这些工具,再选一次吧!'
|
|
}}
|
|
minSelections={1}
|
|
onSubmit={(values, isCorrect) => {
|
|
if (isCorrect) {
|
|
setShowQuiz(false)
|
|
setShowSuccessAlert(true)
|
|
}
|
|
}}
|
|
zIndex={10001}
|
|
/>
|
|
|
|
{/* 成功提示弹窗 */}
|
|
<SuccessAlert
|
|
visible={showSuccessAlert}
|
|
title="满分!"
|
|
content="黄先生说“手脑并用”,懂了理论,也要动手实践。"
|
|
onClose={() => {
|
|
setShowSuccessAlert(false)
|
|
markReflectionCursorVisited(scene, 2)
|
|
}}
|
|
/>
|
|
|
|
{/* 错误提示:请先去学习制作台钳 */}
|
|
<ErrorAlert
|
|
visible={showErrorAlert}
|
|
text="请先去学习台钳制作知识吧!"
|
|
onClose={() => setShowErrorAlert(false)}
|
|
/>
|
|
|
|
{/* 错误提示:请先完成前两个任务 */}
|
|
<ErrorAlert
|
|
visible={showErrorAlertForQuiz}
|
|
text="请先完成前两个任务吧!"
|
|
onClose={() => setShowErrorAlertForQuiz(false)}
|
|
/>
|
|
|
|
{/* 组装台钳完成提示 */}
|
|
<StudyGuideModal
|
|
visible={showCompleteGuide}
|
|
onContinue={() => setShowCompleteGuide(false)}
|
|
verticalAlign="center"
|
|
>
|
|
太厉害啦!你的台钳制作成功,和当年拿金奖的同款哦。
|
|
</StudyGuideModal>
|
|
|
|
{completed && (
|
|
<Image
|
|
className="absolute bottom-0 right-4"
|
|
src={getStaticImage('components/place/继续前进')}
|
|
button
|
|
onClick={() => {
|
|
setShowVideo(true)
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
{showVideo && (
|
|
<Video
|
|
ref={videoRef}
|
|
src={getPublicPath('video/huangyanpei/huangyanpei_09.mp4')}
|
|
className="h-full w-full"
|
|
autoPlay
|
|
playsInline
|
|
showSkipButton
|
|
skipKey="huangyanpei_reflection_scene3_video"
|
|
showReadonlyProgress
|
|
onEnded={() => {
|
|
setShowVideo(false)
|
|
saveHuangyanpeiStore()
|
|
setCourseTimeProgress(11)
|
|
navigate(`/${moduleName}/${starName}/home`)
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
<QuizDialog
|
|
visible={showQuizDialog}
|
|
onClose={() => setShowQuizDialog(false)}
|
|
onComplete={() => {
|
|
setShowQuizDialog(false)
|
|
markReflectionCursorVisited(scene, 3)
|
|
triggerPuzzleAnimation(15)
|
|
}}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default HuangyanpeiReflectionScene3
|