Files
shanghai-residences/src/pages/zhangleping/internalization.tsx
T
zhongyidianandClaude Opus 4.8 73f6df92ce chore: 更新素材和组件优化
- 更新展品图片(鲁迅/毛泽东/孙中山/黄炎培/聂耳/张乐平故居)
- 新增点击查看图标、报纸素材
- 优化视频组件、拼图组件、展品组件
- 更新陈云音频资源
- 新增输入验证文档和工具函数
- 组件布局和动画优化

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:50:40 +08:00

507 lines
19 KiB
TypeScript

import { useEffect, useMemo, useRef, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import {
Image,
Video,
type VideoAnchor,
type VideoRef,
LetterToZhangleping,
Narration,
EndingOverlay,
} from '@/components'
import { SuccessAlert } from '@/components/layout'
import { MultipleChoiceQuizPanel, SingleChoiceQuizPanel } from '@/components/layout/quiz'
import { getBackgroundImage, getPublicPath, getStaticImage } from '@/lib/utils'
import { GuideSteps, GuideStepsItem } from '@/components'
import { usePuzzleAnimation } from '@/contexts/PuzzleAnimationContext'
import { setCourseTimeProgress } from '@/lib/utils/api-common'
const starName = 'zhangleping'
type QuizOption = {
value: string
label: string
isCorrect?: boolean
explanation?: string
}
type QuizAnchor = {
id: string
time: number
type: 'single' | 'multiple'
title: string
options: QuizOption[]
correctAnswer: string | string[]
}
const QUIZ_ANCHORS: QuizAnchor[] = [
{
id: 'quiz-1',
time: 60 * 1 + 49,
type: 'single',
title: '【单选】张乐平的漫画能够比直白的道理说教更吸引人、更易传递美好品质的核心原因是:',
options: [
{
value: 'A',
label: 'A. 绘画技巧高超,色彩搭配丰富',
explanation: '张乐平的漫画魅力不在于复杂的技巧和色彩,而在于内容的真实性哦!请你再想想吧!',
},
{
value: 'B',
label: 'B. 源于生活实际,以贴近现实的“小切片”传递情感与品质',
explanation:
'艺术源于生活,张乐平的漫画捕捉生活中的真实场景与人物,没有口号式宣传,做到了潜移默化、寓教于乐。',
},
{
value: 'C',
label: 'C. 故事情节离奇,充满奇幻色彩',
explanation: '张乐平的漫画聚焦普通民众的生活与苦难,并非离奇的奇幻故事。请你再想想吧!',
},
],
correctAnswer: 'B',
},
{
id: 'quiz-2',
time: 60 * 3 + 23,
type: 'multiple',
title: '【多选】张乐平“化繁为简、以简为上”的艺术风格主要体现在以下哪些方面?',
options: [
{
value: 'A',
label: 'A. 抓住人物表情、动作等细节刻画人物,不事无巨细描摹服装',
},
{
value: 'B',
label: 'B. 场景刻画化繁为简,聚焦核心道具与场景,寥寥数笔呈现完整画面',
},
{
value: 'C',
label: 'C. 刻意简化故事逻辑,降低读者理解难度',
explanation:
'张乐平的漫画是“形式简”而非“逻辑简”,核心是通过简洁形式传递深刻内涵。请你再想想吧!',
},
],
correctAnswer: ['A', 'B'],
},
{
id: 'quiz-3',
time: 60 * 5 + 2,
type: 'single',
title:
'【判断】张乐平创作的“无字漫画”完全依靠人物的动态表情和场景刻画完成叙事,没有任何说明性文字和对话框。',
options: [
{
value: 'A',
label: 'A. 正确',
explanation: '无字漫画的特点是无说明性文字、无对话框,仅靠画面完成叙事。',
},
{
value: 'B',
label: 'B. 错误',
explanation:
'请回顾汪教授对“无字漫画”的解读,张乐平从1935年塑造三毛起就坚持这种创作形式哦!请你再想想吧!',
},
],
correctAnswer: 'A',
},
{
id: 'quiz-4',
time: 60 * 5 + 2,
type: 'multiple',
title: '【多选】以下哪些属于张乐平先生的创作理念与艺术追求?',
options: [
{
value: 'A',
label: 'A. 艺术源于生活,注重观察日常细节',
},
{
value: 'B',
label: 'B. 化繁为简,追求“以少胜多”的艺术境界',
},
{
value: 'C',
label: 'C. 用作品传递善良、正义与真善美',
},
{
value: 'D',
label: 'D. 仅专注于个人艺术表达,不关心社会现实',
explanation:
'张乐平始终以画笔担当社会责任,关注社会现实与民众疾苦,并非只专注个人表达。请你再想想吧!',
},
],
correctAnswer: ['A', 'B', 'C'],
},
]
const ZhanglepingInternalization = () => {
const navigate = useNavigate()
const { moduleName } = useParams<{ moduleName: string }>()
const { triggerPuzzleAnimation } = usePuzzleAnimation()
const [narrationVisible, setNarrationVisible] = useState(true)
const [visible, setVisible] = useState(false) // 对话引导面板是否可见
const [showVideo, setShowVideo] = useState(false) // 内化主视频是否展示
const [showLetter, setShowLetter] = useState(false)
const [showStudyGuide, setShowStudyGuide] = useState(false)
const [postGuideVisible, setPostGuideVisible] = useState(false)
const videoRef = useRef<VideoRef>(null)
const [showQuiz, setShowQuiz] = useState(false)
const [quizSuccessVisible, setQuizSuccessVisible] = useState(false)
// 视频锚点题目状态
const [activeSuccess, setActiveSuccess] = useState<string | null>(null)
const [successContent, setSuccessContent] = useState<string>('')
const [resumeCallback, setResumeCallback] = useState<(() => void) | null>(null)
// 旁白关闭后显示题目(答对后再显示对话引导)
useEffect(() => {
if (!narrationVisible) {
setShowQuiz(true)
}
}, [narrationVisible])
const handleVideoCanPlay = () => {
if (showVideo && videoRef.current) {
videoRef.current.play().catch(() => {})
}
}
const anchors: VideoAnchor[] = useMemo(() => {
return QUIZ_ANCHORS.map((item) => {
if (item.type === 'single') {
const correct = item.correctAnswer as string
return {
id: item.id,
time: item.time,
once: true,
afterResume: 'remove',
render: ({ resume }) => (
<>
<SingleChoiceQuizPanel
visible={activeSuccess !== item.id}
zIndex={10000}
title={item.title}
options={item.options.map((opt) => ({
value: opt.value,
label: opt.label,
}))}
correctAnswer={correct}
onWrongSelect={(value: string) => {
const opt = item.options.find((o) => o.value === value)
return opt?.explanation || '再思考一下,选择正确答案。'
}}
onSubmit={(value: string, isCorrect: boolean) => {
if (isCorrect) {
const opt = item.options.find((o) => o.value === value)
setActiveSuccess(item.id)
if (item.id === 'quiz-3') {
triggerPuzzleAnimation(15)
}
setSuccessContent(opt?.explanation || '恭喜你,选择正确!')
setResumeCallback(() => resume)
}
}}
/>
<SuccessAlert
visible={activeSuccess === item.id}
title={item.id === 'quiz-3' ? '恭喜你,判断正确!' : '恭喜你,选择正确!'}
content={successContent}
onContinue={() => {
setActiveSuccess(null)
setSuccessContent('')
const cb = resumeCallback
setResumeCallback(null)
cb?.()
}}
/>
</>
),
}
}
// 多选题
const correctAnswers = item.correctAnswer as string[]
return {
id: item.id,
time: item.time,
once: true,
afterResume: 'remove',
render: ({ resume }) => (
<>
<MultipleChoiceQuizPanel
visible={activeSuccess !== item.id}
zIndex={10000}
title={item.title}
options={item.options.map((opt) => ({
value: opt.value,
label: opt.label,
}))}
correctAnswer={correctAnswers}
errorMessage={(selectedValues: string[]) => {
const picked = new Set(selectedValues)
if (item.id === 'quiz-1') {
if (picked.has('A')) {
const optA = item.options.find((o) => o.value === 'A')
return (
optA?.explanation ||
'张乐平的漫画魅力不在于复杂的技巧和色彩,而在于内容的真实性哦!请你再想想吧!'
)
}
if (picked.has('C')) {
const optC = item.options.find((o) => o.value === 'C')
return (
optC?.explanation ||
'张乐平的漫画聚焦普通民众的生活与苦难,并非离奇的奇幻故事。请你再想想吧!'
)
}
return '你的选择还不够全面哦~请你再想想吧!'
}
if (item.id === 'quiz-2') {
if (picked.has('C')) {
const optC = item.options.find((o) => o.value === 'C')
return (
optC?.explanation ||
'张乐平的漫画是“形式简”而非“逻辑简”,核心是通过简洁形式传递深刻内涵。请你再想想吧!'
)
}
return '你的选择还不够全面哦~请你再想想吧!'
}
if (item.id === 'quiz-4') {
if (picked.has('D')) {
const optD = item.options.find((o) => o.value === 'D')
return (
optD?.explanation ||
'张乐平始终以画笔担当社会责任,关注社会现实与民众疾苦,并非只专注个人表达。请你再想想吧!'
)
}
return '你的选择还不够全面哦~请你再想想吧!'
}
return '你的选择还不够全面哦~请你再想想吧!'
}}
onSubmit={(values: string[], isCorrect: boolean) => {
if (isCorrect) {
setActiveSuccess(item.id)
if (item.id === 'quiz-1') {
setSuccessContent(
'艺术源于生活,张乐平的漫画捕捉生活中的真实场景与人物,没有口号式宣传,做到了潜移默化、寓教于乐。'
)
} else if (item.id === 'quiz-2') {
setSuccessContent(
'先生善于捕捉核心细节展现人物特质,化繁为简的场景刻画让漫画更具感染力,这正是“以少胜多”艺术境界的体现。'
)
} else if (item.id === 'quiz-4') {
triggerPuzzleAnimation(16)
setSuccessContent(
'张乐平先生坚持艺术扎根生活,以简洁笔墨刻画时代,用作品传递温暖与正义,这些都是他的核心创作理念。'
)
} else {
setSuccessContent('')
}
setResumeCallback(() => resume)
}
}}
/>
<SuccessAlert
visible={activeSuccess === item.id}
content={successContent}
onContinue={() => {
setActiveSuccess(null)
setSuccessContent('')
const cb = resumeCallback
setResumeCallback(null)
cb?.()
}}
/>
</>
),
}
})
}, [activeSuccess, resumeCallback, successContent, triggerPuzzleAnimation])
if (!moduleName) return null
return (
<div
className="relative h-full w-full bg-black"
style={{
backgroundImage: getBackgroundImage('components/internalization/bg'),
}}
>
{/* 离开按钮 */}
<Image
className="absolute right-8 top-8 z-10"
src={getStaticImage('components/离开')}
button
onClick={() => navigate(`/${moduleName}/${starName}/home`)}
/>
{/* 过度语 */}
<Narration
visible={narrationVisible}
audioChannelId="zhangleping-internalization-narration"
audioSrc={getPublicPath('audio/zhangleping/mp3_zhangleping_31.mp3')}
animationSpeed={200}
onClose={() => {
setNarrationVisible(false)
}}
text="从弄堂里的三毛记忆到画室中的笔墨传承,张乐平先生以一支画笔为刃,划破黑暗现实的迷雾;以一颗赤诚之心,守护万千儿童的童真。他笔下的三毛,从流浪儿到新中国少年,是一个民族的成长缩影;他坚持的艺术,源于生活、归于真诚,是跨越时空的精神纽带。今天,我们站在张乐平故居的画桌前,不仅要回望先生以笔为业、以爱为怀的一生,更要让这份艺术精神内化于心、外化于行,成为新时代青年学子践行初心、传递美好的力量。"
/>
{/* 题目弹窗(旁白结束后出现) */}
<MultipleChoiceQuizPanel
visible={showQuiz && !quizSuccessVisible}
zIndex={10000}
title="【多选】张乐平笔下的三毛形象能够跨越时代、深入人心,核心是因为承载了哪些精神品质?"
options={[
{ value: 'A', label: 'A. 善良悲悯,对弱者充满同情' },
{ value: 'B', label: 'B. 勇敢坚韧,在困境中顽强生存' },
{ value: 'C', label: 'C. 对正义的坚守,对美好生活的向往' },
]}
correctAnswer={['A', 'B', 'C']}
errorMessage="你的选择还不够全面哦~请你再想想吧!"
onSubmit={(values, isCorrect) => {
if (isCorrect) {
setQuizSuccessVisible(true)
}
}}
/>
<SuccessAlert
visible={quizSuccessVisible}
title="恭喜你,选择正确!"
onContinue={() => {
setQuizSuccessVisible(false)
setShowQuiz(false)
setVisible(true)
}}
/>
{/* 视频前引导 */}
<GuideSteps
visible={visible}
onVisibleChange={(v) => {
setVisible(v)
if (!v) {
setShowVideo(true)
handleVideoCanPlay()
}
}}
showMask={false}
>
<GuideStepsItem
speaker="student"
audioSrc={getPublicPath('audio/zhangleping/mp3_zhangleping_32_1.mp3')}
>
小沪,刚刚完成“三毛寻忆”的时空任务太有收获了!从童年学艺的老画桌到新中国的画架,我跟着三毛的记忆碎片,真切感受到张乐平先生用画笔记录时代、守护童心的坚守。
</GuideStepsItem>
<GuideStepsItem
speaker="student"
audioSrc={getPublicPath('audio/zhangleping/mp3_zhangleping_32_2.mp3')}
>
尤其是先生笔下三毛的形象从流浪儿到少先队员的转变,还有不同年代里“画笔如刀枪、如镜子、如园丁”的力量,都让我特别触动。但我还想从美术这一艺术创作角度出发更多了解张乐平先生,你能给我讲讲吗?
</GuideStepsItem>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath('audio/zhangleping/mp3_zhangleping_33_1.mp3')}
>
你的感悟特别深刻!关于你想了解的美术创作,今天我们有幸邀请到了上海大学美术学院设计系副主任、副教授汪宁,汪教授对张乐平漫画艺术开展过专门研究,对先生的创作理念与时代价值有着深入的理解。
</GuideStepsItem>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath('audio/zhangleping/mp3_zhangleping_33_2.mp3')}
>
接下来,就让我们跟随汪教授一起,探寻张乐平艺术作品和艺术精神的当代意义吧!
</GuideStepsItem>
</GuideSteps>
{/* 内化主视频 */}
{showVideo && (
<Video
ref={videoRef}
src={getPublicPath('video/zhangleping/zhangleping_neihua.mp4')}
className="h-full w-full"
anchors={anchors}
playsInline
controls
controlsOnReplay
skipKey="zhangleping_internalization_video"
showReadonlyProgress
onSkip={() => {
setShowVideo(false)
setPostGuideVisible(true)
}}
onCanPlay={handleVideoCanPlay}
onEnded={() => {
setShowVideo(false)
// 学习视频结束后,先展示对话,再进入写信
setPostGuideVisible(true)
}}
/>
)}
{/* 学习视频结束后的对话引导 */}
<GuideSteps
visible={postGuideVisible}
onVisibleChange={(v) => {
setPostGuideVisible(v)
if (!v) {
setShowLetter(true)
}
}}
showMask={false}
zIndex={60}
>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath('audio/zhangleping/mp3_zhangleping_34_1.mp3')}
>
张乐平先生的精神,不是挂在墙上的口号,而是“源于生活”的真诚、“化繁为简”的智慧、“向善向美”的坚守。这份精神,藏在三毛的三根头发里,藏在先生的笔墨春秋中,更藏在我们每一个人的日常行动里。
</GuideStepsItem>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath('audio/zhangleping/mp3_zhangleping_34_2.mp3')}
>
现在,就让我们站在这座承载着温暖与力量的故居中,把对先生的崇敬、对精神的体悟,浓缩进你想对先生说的话中吧!
</GuideStepsItem>
</GuideSteps>
{/* 写信组件 */}
<LetterToZhangleping
visible={showLetter}
onClose={() => {
setShowLetter(false)
}}
onSubmit={() => {}}
onAnimationEnd={() => {
setShowLetter(false)
setShowStudyGuide(true)
}}
showVideo={true}
/>
{/* 内化结束 */}
<EndingOverlay
visible={showStudyGuide}
audioSrc={getPublicPath('audio/zhangleping/mp3_zhangleping_35.mp3')}
text="恭喜你圆满完成张乐平故居的学习之旅,请带着研学感悟,前往荣德生旧居继续探访吧~"
animationSpeed={200}
onContinue={() => {
setShowStudyGuide(false)
setCourseTimeProgress(18)
navigate('/learning-map', { state: { completedResidence: 'zhangleping' } })
}}
/>
</div>
)
}
export default ZhanglepingInternalization