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:
zhongyidian committed 2026-03-05 13:50:47 +08:00
1 parent 5d00adc1a5
commit 76c67b492e
216 files changed
+12454 -13976

No files matched your search

+129 -139
View File
@@ -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