feat: 更新 ESLint 和 Prettier 配置,增强代码质量管理
- 在 .gitignore 中添加 public/audio/* 以忽略音频文件。 - 更新 bun.lock,添加 eslint-config-prettier 和 eslint-plugin-prettier 依赖,确保 ESLint 与 Prettier 的兼容性。 - 修改 eslint.config.ts,整合 Prettier 规则,优化代码风格一致性。 - 在 package.json 中添加 lint:fix 和 format 脚本,简化代码格式化和修复流程。 - 更新 tailwind.config.ts 和其他组件文件,统一代码风格,提升可读性。
This commit is contained in:
1 parent
5d00adc1a5
commit
76c67b492e
216 files changed
+12454
-13976
No files matched your search
@@ -7,57 +7,57 @@ import {
|
||||
SingleChoiceQuizPanel,
|
||||
Video,
|
||||
type VideoRef,
|
||||
} from "@/components";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { getBackgroundImage, getStaticImage, getPublicPath } from "@/lib/utils";
|
||||
import { useRef, useState } from "react";
|
||||
import Cursor from "@/components/cursor";
|
||||
import { useCursorController } from "@/hooks/useCursorController";
|
||||
import SuccessAlert from "@/components/layout/alert/success-alert";
|
||||
import ScaledPortal from "@/components/layout/ScaledPortal";
|
||||
} from '@/components'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { getBackgroundImage, getStaticImage, getPublicPath } from '@/lib/utils'
|
||||
import { useRef, useState } from 'react'
|
||||
import Cursor from '@/components/cursor'
|
||||
import { useCursorController } from '@/hooks/useCursorController'
|
||||
import SuccessAlert from '@/components/layout/alert/success-alert'
|
||||
import ScaledPortal from '@/components/layout/ScaledPortal'
|
||||
|
||||
// starName 固定为 zhangleping
|
||||
const starName = "zhangleping";
|
||||
const starName = 'zhangleping'
|
||||
|
||||
// 展品 ID 与资源路径映射
|
||||
const exhibitSrcMap: Record<1 | 2 | 3, string> = {
|
||||
1: "zhangleping/place3/张乐平场景3展品1",
|
||||
2: "zhangleping/place3/张乐平场景3展品2",
|
||||
3: "zhangleping/place3/张乐平场景3展品3",
|
||||
};
|
||||
1: 'zhangleping/place3/张乐平场景3展品1',
|
||||
2: 'zhangleping/place3/张乐平场景3展品2',
|
||||
3: 'zhangleping/place3/张乐平场景3展品3',
|
||||
}
|
||||
|
||||
// 阶段三:三毛之父(3 个光标)
|
||||
const ZhanglepingPlace3 = () => {
|
||||
const navigate = useNavigate();
|
||||
const navigate = useNavigate()
|
||||
const { moduleName } = useParams<{
|
||||
moduleName: string;
|
||||
}>();
|
||||
moduleName: string
|
||||
}>()
|
||||
|
||||
const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | 3 | null>(null);
|
||||
const [visited, setVisited] = useState<Set<1 | 2 | 3>>(() => new Set());
|
||||
const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | 3 | null>(null)
|
||||
const [visited, setVisited] = useState<Set<1 | 2 | 3>>(() => new Set())
|
||||
|
||||
const [guideVisible1, setGuideVisible1] = useState(false);
|
||||
const [guideStep1, setGuideStep1] = useState(0);
|
||||
const [guideVisible1, setGuideVisible1] = useState(false)
|
||||
const [guideStep1, setGuideStep1] = useState(0)
|
||||
|
||||
const [guideVisible2, setGuideVisible2] = useState(false);
|
||||
const [guideStep2, setGuideStep2] = useState(0);
|
||||
const [guideVisible2, setGuideVisible2] = useState(false)
|
||||
const [guideStep2, setGuideStep2] = useState(0)
|
||||
|
||||
const [guideVisible3, setGuideVisible3] = useState(false);
|
||||
const [guideStep3, setGuideStep3] = useState(0);
|
||||
const [guideVisible3, setGuideVisible3] = useState(false)
|
||||
const [guideStep3, setGuideStep3] = useState(0)
|
||||
|
||||
// 展品2:关闭后播放的视频 + 单选题
|
||||
const [showVideo2, setShowVideo2] = useState(false);
|
||||
const video2Ref = useRef<VideoRef>(null);
|
||||
const [quiz2Visible, setQuiz2Visible] = useState(false);
|
||||
const [successAlert2Visible, setSuccessAlert2Visible] = useState(false);
|
||||
const [successAlert2Content, setSuccessAlert2Content] = useState("");
|
||||
const [showVideo2, setShowVideo2] = useState(false)
|
||||
const video2Ref = useRef<VideoRef>(null)
|
||||
const [quiz2Visible, setQuiz2Visible] = useState(false)
|
||||
const [successAlert2Visible, setSuccessAlert2Visible] = useState(false)
|
||||
const [successAlert2Content, setSuccessAlert2Content] = useState('')
|
||||
|
||||
// 展品3对话结束后的两道单选题
|
||||
const [quiz3Visible, setQuiz3Visible] = useState(false);
|
||||
const [quiz3Step, setQuiz3Step] = useState<1 | 2>(1);
|
||||
const [quiz3Finished, setQuiz3Finished] = useState(false);
|
||||
const [successAlert3Visible, setSuccessAlert3Visible] = useState(false);
|
||||
const [successAlert3Content, setSuccessAlert3Content] = useState("");
|
||||
const [quiz3Visible, setQuiz3Visible] = useState(false)
|
||||
const [quiz3Step, setQuiz3Step] = useState<1 | 2>(1)
|
||||
const [quiz3Finished, setQuiz3Finished] = useState(false)
|
||||
const [successAlert3Visible, setSuccessAlert3Visible] = useState(false)
|
||||
const [successAlert3Content, setSuccessAlert3Content] = useState('')
|
||||
|
||||
const { isEnabled } = useCursorController({
|
||||
initialEnabled: [3],
|
||||
@@ -66,30 +66,30 @@ const ZhanglepingPlace3 = () => {
|
||||
1: [2],
|
||||
},
|
||||
visited,
|
||||
});
|
||||
})
|
||||
|
||||
if (!moduleName) return null;
|
||||
if (!moduleName) return null
|
||||
|
||||
const total = 3;
|
||||
const progressCount = visited.size;
|
||||
const completed = progressCount >= total;
|
||||
const total = 3
|
||||
const progressCount = visited.size
|
||||
const completed = progressCount >= total
|
||||
const subtitle = completed
|
||||
? "搜索该阶段相关资料(已完成)"
|
||||
: `搜索该阶段相关资料(${progressCount}/${total})`;
|
||||
? '搜索该阶段相关资料(已完成)'
|
||||
: `搜索该阶段相关资料(${progressCount}/${total})`
|
||||
|
||||
const handleOpenExhibit = (id: 1 | 2 | 3) => {
|
||||
setActiveExhibitId(id);
|
||||
setActiveExhibitId(id)
|
||||
if (id === 1) {
|
||||
setGuideVisible1(true);
|
||||
setGuideStep1(0);
|
||||
setGuideVisible1(true)
|
||||
setGuideStep1(0)
|
||||
} else if (id === 2) {
|
||||
setGuideVisible2(true);
|
||||
setGuideStep2(0);
|
||||
setGuideVisible2(true)
|
||||
setGuideStep2(0)
|
||||
} else {
|
||||
setGuideVisible3(true);
|
||||
setGuideStep3(0);
|
||||
setGuideVisible3(true)
|
||||
setGuideStep3(0)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -107,11 +107,11 @@ const ZhanglepingPlace3 = () => {
|
||||
|
||||
<Image
|
||||
className="absolute right-5 top-5"
|
||||
src={getStaticImage("components/离开")}
|
||||
src={getStaticImage('components/离开')}
|
||||
button
|
||||
onClick={() => {
|
||||
if (moduleName && starName) {
|
||||
navigate(`/${moduleName}/${starName}/home`);
|
||||
navigate(`/${moduleName}/${starName}/home`)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -144,10 +144,10 @@ const ZhanglepingPlace3 = () => {
|
||||
{completed && (
|
||||
<Image
|
||||
className="absolute bottom-0 right-0"
|
||||
src={getStaticImage("components/place/继续前进")}
|
||||
src={getStaticImage('components/place/继续前进')}
|
||||
button
|
||||
onClick={() => {
|
||||
navigate(`/${moduleName}/${starName}/place4`);
|
||||
navigate(`/${moduleName}/${starName}/place4`)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -201,11 +201,11 @@ const ZhanglepingPlace3 = () => {
|
||||
<GuideSteps
|
||||
visible={guideVisible3}
|
||||
onVisibleChange={(visible) => {
|
||||
setGuideVisible3(visible);
|
||||
setGuideVisible3(visible)
|
||||
// 对话结束后依次进入两道题目(仅在未完成时触发)
|
||||
if (!visible) {
|
||||
setQuiz3Step(1);
|
||||
setQuiz3Visible(true);
|
||||
setQuiz3Step(1)
|
||||
setQuiz3Visible(true)
|
||||
}
|
||||
}}
|
||||
currentStep={guideStep3}
|
||||
@@ -224,34 +224,34 @@ const ZhanglepingPlace3 = () => {
|
||||
|
||||
<ExhibitOverlay
|
||||
visible={activeExhibitId !== null}
|
||||
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ""}
|
||||
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ''}
|
||||
onClose={() => {
|
||||
if (activeExhibitId !== null) {
|
||||
// 展品2:关闭后先播放一段视频,视频结束再进入题目
|
||||
if (activeExhibitId === 2) {
|
||||
setActiveExhibitId(null);
|
||||
setShowVideo2(true);
|
||||
return;
|
||||
setActiveExhibitId(null)
|
||||
setShowVideo2(true)
|
||||
return
|
||||
}
|
||||
|
||||
// 展品3:需完成两道题目后才标记为已访问
|
||||
if (activeExhibitId === 3) {
|
||||
if (quiz3Finished) {
|
||||
setVisited((prev) => {
|
||||
const next = new Set(prev);
|
||||
next.add(3);
|
||||
return next;
|
||||
});
|
||||
const next = new Set(prev)
|
||||
next.add(3)
|
||||
return next
|
||||
})
|
||||
}
|
||||
} else {
|
||||
setVisited((prev) => {
|
||||
const next = new Set(prev);
|
||||
next.add(activeExhibitId);
|
||||
return next;
|
||||
});
|
||||
const next = new Set(prev)
|
||||
next.add(activeExhibitId)
|
||||
return next
|
||||
})
|
||||
}
|
||||
}
|
||||
setActiveExhibitId(null);
|
||||
setActiveExhibitId(null)
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -259,54 +259,51 @@ const ZhanglepingPlace3 = () => {
|
||||
{showVideo2 && (
|
||||
<Video
|
||||
ref={video2Ref}
|
||||
src={getPublicPath("video/sunzhongshan/sunzhongshan_03.mp4")}
|
||||
src={getPublicPath('video/sunzhongshan/sunzhongshan_03.mp4')}
|
||||
className="fixed inset-0 z-20000"
|
||||
autoPlay
|
||||
playsInline
|
||||
showSkipButton
|
||||
onEnded={() => {
|
||||
setShowVideo2(false);
|
||||
setQuiz2Visible(true);
|
||||
setShowVideo2(false)
|
||||
setQuiz2Visible(true)
|
||||
}}
|
||||
onSkip={() => {
|
||||
setShowVideo2(false);
|
||||
setQuiz2Visible(true);
|
||||
setShowVideo2(false)
|
||||
setQuiz2Visible(true)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 展品2关闭后的视频 + 单选题(如图1) */}
|
||||
<ScaledPortal
|
||||
enabled={quiz2Visible || successAlert2Visible}
|
||||
zIndex={10040}
|
||||
>
|
||||
<ScaledPortal enabled={quiz2Visible || successAlert2Visible} zIndex={10040}>
|
||||
<>
|
||||
<SingleChoiceQuizPanel
|
||||
visible={quiz2Visible}
|
||||
zIndex={10000}
|
||||
title="【单选】张乐平先生根据自己抗战前线的经历见闻创作的作品是:"
|
||||
options={[
|
||||
{ value: "A", label: "A.三毛流浪记" },
|
||||
{ value: "B", label: "B.三毛日记" },
|
||||
{ value: "C", label: "C.三毛从军记" },
|
||||
{ value: 'A', label: 'A.三毛流浪记' },
|
||||
{ value: 'B', label: 'B.三毛日记' },
|
||||
{ value: 'C', label: 'C.三毛从军记' },
|
||||
]}
|
||||
correctAnswer="C"
|
||||
onWrongSelect={(value) => {
|
||||
if (value === "A") {
|
||||
return "《三毛流浪记》以旧上海为背景,聚焦三毛在城市底层的流浪生活,主要反映旧社会儿童的苦难遭遇与人性冷暖。请你再想想吧!";
|
||||
if (value === 'A') {
|
||||
return '《三毛流浪记》以旧上海为背景,聚焦三毛在城市底层的流浪生活,主要反映旧社会儿童的苦难遭遇与人性冷暖。请你再想想吧!'
|
||||
}
|
||||
if (value === "B") {
|
||||
return "《三毛日记》以日记体形式记录三毛的日常琐事与童真视角,内容偏向儿童生活的趣味表达。请你再想想吧!";
|
||||
if (value === 'B') {
|
||||
return '《三毛日记》以日记体形式记录三毛的日常琐事与童真视角,内容偏向儿童生活的趣味表达。请你再想想吧!'
|
||||
}
|
||||
return "请你再想想吧!";
|
||||
return '请你再想想吧!'
|
||||
}}
|
||||
onSubmit={(_value, isCorrect) => {
|
||||
if (!isCorrect) return;
|
||||
setQuiz2Visible(false);
|
||||
if (!isCorrect) return
|
||||
setQuiz2Visible(false)
|
||||
setSuccessAlert2Content(
|
||||
"《三毛从军记》是张乐平根据自己奔赴抗战前线的亲身经历与见闻创作的作品,通过三毛从军的荒诞经历,讽刺了当时的社会乱象,也传递出抗战背景下的民生百态。"
|
||||
);
|
||||
setSuccessAlert2Visible(true);
|
||||
'《三毛从军记》是张乐平根据自己奔赴抗战前线的亲身经历与见闻创作的作品,通过三毛从军的荒诞经历,讽刺了当时的社会乱象,也传递出抗战背景下的民生百态。'
|
||||
)
|
||||
setSuccessAlert2Visible(true)
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -314,23 +311,20 @@ const ZhanglepingPlace3 = () => {
|
||||
visible={successAlert2Visible}
|
||||
content={successAlert2Content}
|
||||
onContinue={() => {
|
||||
setSuccessAlert2Visible(false);
|
||||
setSuccessAlert2Visible(false)
|
||||
// 答题成功后标记展品2为已访问
|
||||
setVisited((prev) => {
|
||||
const next = new Set(prev);
|
||||
next.add(2);
|
||||
return next;
|
||||
});
|
||||
const next = new Set(prev)
|
||||
next.add(2)
|
||||
return next
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
</ScaledPortal>
|
||||
|
||||
{/* 展品3对话结束后的两道单选题 + 每题答对后的提示(使用 ScaledPortal) */}
|
||||
<ScaledPortal
|
||||
enabled={quiz3Visible || successAlert3Visible}
|
||||
zIndex={10050}
|
||||
>
|
||||
<ScaledPortal enabled={quiz3Visible || successAlert3Visible} zIndex={10050}>
|
||||
<>
|
||||
{/* 题目1:三毛形象首次亮相年份与地点 */}
|
||||
<SingleChoiceQuizPanel
|
||||
@@ -338,27 +332,25 @@ const ZhanglepingPlace3 = () => {
|
||||
zIndex={10000}
|
||||
title="【单选】1935年,张乐平先生创作的三毛形象初次亮相于:"
|
||||
options={[
|
||||
{ value: "A", label: "A.上海" },
|
||||
{ value: "B", label: "B.延安" },
|
||||
{ value: "C", label: "C.浙江" },
|
||||
{ value: 'A', label: 'A.上海' },
|
||||
{ value: 'B', label: 'B.延安' },
|
||||
{ value: 'C', label: 'C.浙江' },
|
||||
]}
|
||||
correctAnswer="A"
|
||||
onWrongSelect={(value) => {
|
||||
if (value === "B") {
|
||||
return "延安是当时的革命根据地,但张乐平先生的主要创作活动和延安没有关联。请你再想想吧!";
|
||||
if (value === 'B') {
|
||||
return '延安是当时的革命根据地,但张乐平先生的主要创作活动和延安没有关联。请你再想想吧!'
|
||||
}
|
||||
if (value === "C") {
|
||||
return "浙江是张乐平先生的故乡,不是三毛初次亮相的地方。请你再想想吧!";
|
||||
if (value === 'C') {
|
||||
return '浙江是张乐平先生的故乡,不是三毛初次亮相的地方。请你再想想吧!'
|
||||
}
|
||||
return "请再仔细阅读题干中的时间和地点信息~";
|
||||
return '请再仔细阅读题干中的时间和地点信息~'
|
||||
}}
|
||||
onSubmit={(_value, isCorrect) => {
|
||||
if (!isCorrect) return;
|
||||
setQuiz3Visible(false);
|
||||
setSuccessAlert3Content(
|
||||
"张乐平先生创作的三毛初次亮相于1935年上海的《晨报》副刊。"
|
||||
);
|
||||
setSuccessAlert3Visible(true);
|
||||
if (!isCorrect) return
|
||||
setQuiz3Visible(false)
|
||||
setSuccessAlert3Content('张乐平先生创作的三毛初次亮相于1935年上海的《晨报》副刊。')
|
||||
setSuccessAlert3Visible(true)
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -368,21 +360,21 @@ const ZhanglepingPlace3 = () => {
|
||||
zIndex={10000}
|
||||
title="【判断】张乐平先生创作的三毛开创了中国无文字儿童连环漫画之先河。"
|
||||
options={[
|
||||
{ value: "A", label: "A.正确" },
|
||||
{ value: "B", label: "B.错误" },
|
||||
{ value: 'A', label: 'A.正确' },
|
||||
{ value: 'B', label: 'B.错误' },
|
||||
]}
|
||||
correctAnswer="A"
|
||||
onWrongSelect={(value) => {
|
||||
if (value === "B") {
|
||||
return "再想一想三毛在中国儿童漫画史上的地位吧~";
|
||||
if (value === 'B') {
|
||||
return '再想一想三毛在中国儿童漫画史上的地位吧~'
|
||||
}
|
||||
return "请再仔细对照题干信息选择~";
|
||||
return '请再仔细对照题干信息选择~'
|
||||
}}
|
||||
onSubmit={(_value, isCorrect) => {
|
||||
if (!isCorrect) return;
|
||||
setQuiz3Visible(false);
|
||||
setSuccessAlert3Content("");
|
||||
setSuccessAlert3Visible(true);
|
||||
if (!isCorrect) return
|
||||
setQuiz3Visible(false)
|
||||
setSuccessAlert3Content('')
|
||||
setSuccessAlert3Visible(true)
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -391,32 +383,30 @@ const ZhanglepingPlace3 = () => {
|
||||
visible={successAlert3Visible}
|
||||
content={successAlert3Content}
|
||||
onContinue={() => {
|
||||
setSuccessAlert3Visible(false);
|
||||
setSuccessAlert3Visible(false)
|
||||
// 进入下一题或标记完成
|
||||
setQuiz3Step((prev) => {
|
||||
const next = (prev + 1) as 1 | 2 | 3;
|
||||
const next = (prev + 1) as 1 | 2 | 3
|
||||
if (next === 2) {
|
||||
setQuiz3Visible(true);
|
||||
return 2;
|
||||
setQuiz3Visible(true)
|
||||
return 2
|
||||
}
|
||||
// 两题全部完成
|
||||
setQuiz3Finished(true);
|
||||
setQuiz3Finished(true)
|
||||
// 标记展品3为已访问
|
||||
setVisited((prevVisited) => {
|
||||
const nextVisited = new Set(prevVisited);
|
||||
nextVisited.add(3);
|
||||
return nextVisited;
|
||||
});
|
||||
return prev;
|
||||
});
|
||||
const nextVisited = new Set(prevVisited)
|
||||
nextVisited.add(3)
|
||||
return nextVisited
|
||||
})
|
||||
return prev
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
</ScaledPortal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ZhanglepingPlace3;
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default ZhanglepingPlace3
|
||||
Reference in new issue
Block a user