feat: add puzzle residence configuration and reflection progress logic

- Introduced `puzzleResidences.ts` to define puzzle residence configurations including properties like display name, position, and puzzle availability.
- Added `reflectionProgress.ts` to manage badge unlocking logic based on place completion, including functions to determine unlocked badges and video sources for scenes.
This commit is contained in:
zhongyidian committed 2026-04-27 11:49:30 +08:00
1 parent e0fa47d21a
commit f5f36f75b5
153 files changed
+3846 -2352

No files matched your search

+238 -233
View File
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react'
import { useEffect, useMemo, useRef, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import {
Image,
@@ -13,13 +13,131 @@ 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'
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) // 内化主视频是否展示
@@ -50,126 +168,59 @@ const ZhanglepingInternalization = () => {
}
}
type QuizOption = {
value: string
label: string
isCorrect?: boolean
explanation?: string
}
const anchors: VideoAnchor[] = useMemo(() => {
return QUIZ_ANCHORS.map((item) => {
if (item.type === 'single') {
const correct = item.correctAnswer as string
type QuizAnchor = {
id: string
time: number
type: 'single' | 'multiple'
title: string
options: QuizOption[]
correctAnswer: string | 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)
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 QUIZ_ANCHORS: QuizAnchor[] = [
{
id: 'quiz-1',
time: 60 * 1 + 49, // 1:49
type: 'multiple',
title: '【多选】张乐平的漫画能够比直白的道理说教更吸引人、更易传递美好品质的核心原因是:',
options: [
{
value: 'A',
label: 'A. 绘画技巧高超,色彩搭配丰富',
explanation:
'张乐平的漫画魅力不在于复杂的技巧和色彩,而在于内容的真实性哦!请你再想想吧!',
},
{
value: 'B',
label: 'B. 源于生活实际,以贴近现实的“小切片”传递情感与品质',
explanation:
'艺术源于生活,张乐平的漫画捕捉生活中的真实场景与人物,没有口号式宣传,做到了潜移默化、寓教于乐。',
},
{
value: 'C',
label: 'C. 故事情节离奇,充满奇幻色彩',
explanation: '张乐平的漫画聚焦普通民众的生活与苦难,并非离奇的奇幻故事。请你再想想吧!',
},
],
correctAnswer: ['A', 'B', 'C'],
},
{
id: 'quiz-2',
time: 60 * 3 + 22, // 3:22
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 + 1, // 5:01
type: 'single',
title:
'【判断】张乐平创作的“无字漫画”完全依靠人物的动态表情和场景刻画完成叙事,没有任何说明性文字和对话框。',
options: [
{
value: 'A',
label: 'A. 正确',
explanation: '无字漫画的特点是无说明性文字、无对话框,仅靠画面完成叙事。',
},
{
value: 'B',
label: 'B. 错误',
explanation:
'请回顾汪教授对“无字漫画”的解读,张乐平从1935年塑造三毛起就坚持这种创作形式哦!请你再想想吧!',
},
],
correctAnswer: 'A',
},
{
id: 'quiz-4',
time: 60 * 5 + 1, // 5:01,同一时间出现(对应图3、4)
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 anchors: VideoAnchor[] = QUIZ_ANCHORS.map((item) => {
if (item.type === 'single') {
const correct = item.correctAnswer as string
// 多选题
const correctAnswers = item.correctAnswer as string[]
return {
id: item.id,
@@ -178,7 +229,7 @@ const ZhanglepingInternalization = () => {
afterResume: 'remove',
render: ({ resume }) => (
<>
<SingleChoiceQuizPanel
<MultipleChoiceQuizPanel
visible={activeSuccess !== item.id}
zIndex={10000}
title={item.title}
@@ -186,23 +237,77 @@ const ZhanglepingInternalization = () => {
value: opt.value,
label: opt.label,
}))}
correctAnswer={correct}
onWrongSelect={(value: string) => {
const opt = item.options.find((o) => o.value === value)
return opt?.explanation || '再思考一下,选择正确答案。'
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={(value: string, isCorrect: boolean) => {
onSubmit={(values: string[], isCorrect: boolean) => {
if (isCorrect) {
const opt = item.options.find((o) => o.value === value)
setActiveSuccess(item.id)
setSuccessContent(opt?.explanation || '恭喜你,选择正确!')
if (item.id === 'quiz-1') {
setSuccessContent(
'艺术源于生活,张乐平的漫画捕捉生活中的真实场景与人物,没有口号式宣传,做到了潜移默化、寓教于乐。'
)
} else if (item.id === 'quiz-2') {
setSuccessContent(
'先生善于捕捉核心细节展现人物特质,化繁为简的场景刻画让漫画更具感染力,这正是“以少胜多”艺术境界的体现。'
)
} else if (item.id === 'quiz-4') {
triggerPuzzleAnimation(15)
setSuccessContent(
'张乐平先生坚持艺术扎根生活,以简洁笔墨刻画时代,用作品传递温暖与正义,这些都是他的核心创作理念。'
)
} else {
setSuccessContent('')
}
setResumeCallback(() => resume)
}
}}
/>
<SuccessAlert
visible={activeSuccess === item.id}
title={item.id === 'quiz-3' ? '恭喜你,判断正确!' : '恭喜你,选择正确!'}
content={successContent}
onContinue={() => {
setActiveSuccess(null)
@@ -215,109 +320,8 @@ const ZhanglepingInternalization = () => {
</>
),
}
}
// 多选题
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') {
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
@@ -345,7 +349,7 @@ const ZhanglepingInternalization = () => {
onClose={() => {
setNarrationVisible(false)
}}
text="从弄堂里的三毛记忆到画室中的笔墨传承,张乐平先生以一支画笔为刃,划破黑暗现实的迷雾;以一颗赤诚之心,守护万千儿童的童真。他笔下的三毛,从流浪儿到新中国少年,是一个民族的成长缩影;他坚持的艺术,源于生活、归于真诚,是跨越时空的精神纽带。今天,我们站在张乐平故居的画桌前,不仅要回望先生以笔为业、以爱为怀的一生,更要让这份艺术精神内化于心、外化于行,成为新时代中职学子践行初心、传递美好的力量。"
text="从弄堂里的三毛记忆到画室中的笔墨传承,张乐平先生以一支画笔为刃,划破黑暗现实的迷雾;以一颗赤诚之心,守护万千儿童的童真。他笔下的三毛,从流浪儿到新中国少年,是一个民族的成长缩影;他坚持的艺术,源于生活、归于真诚,是跨越时空的精神纽带。今天,我们站在张乐平故居的画桌前,不仅要回望先生以笔为业、以爱为怀的一生,更要让这份艺术精神内化于心、外化于行,成为新时代青年学子践行初心、传递美好的力量。"
/>
{/* 题目弹窗(旁白结束后出现) */}
@@ -436,6 +440,7 @@ const ZhanglepingInternalization = () => {
onVisibleChange={(v) => {
setPostGuideVisible(v)
if (!v) {
triggerPuzzleAnimation(16)
setShowLetter(true)
}
}}
@@ -475,7 +480,7 @@ const ZhanglepingInternalization = () => {
animationSpeed={200}
onContinue={() => {
setShowStudyGuide(false)
navigate(`/${moduleName}/${starName}/home`)
navigate('/menu')
}}
/>
</div>