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

+98 -101
View File
@@ -7,49 +7,49 @@ import {
MatchQuizPanel,
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/place2/张乐平场景2展品1",
2: "zhangleping/place2/张乐平场景2展品2",
3: "zhangleping/place2/张乐平场景2展品3",
};
1: 'zhangleping/place2/张乐平场景2展品1',
2: 'zhangleping/place2/张乐平场景2展品2',
3: 'zhangleping/place2/张乐平场景2展品3',
}
// 阶段二:抗战画家(3 个光标)
const ZhanglepingPlace2 = () => {
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 [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)
// 展品3对话结束后的连线题
const [quizVisible3, setQuizVisible3] = useState(false);
const [quizPassed3, setQuizPassed3] = useState(false);
const [successAlert3Visible, setSuccessAlert3Visible] = useState(false);
const [quizVisible3, setQuizVisible3] = useState(false)
const [quizPassed3, setQuizPassed3] = useState(false)
const [successAlert3Visible, setSuccessAlert3Visible] = useState(false)
// 展品1:关闭后播放的视频
const [showVideo1, setShowVideo1] = useState(false);
const video1Ref = useRef<VideoRef>(null);
const [showVideo1, setShowVideo1] = useState(false)
const video1Ref = useRef<VideoRef>(null)
// Cursor 顺序控制:先学习展品3,再依次解锁展品2、展品1
const { isEnabled } = useCursorController({
@@ -59,31 +59,31 @@ const ZhanglepingPlace2 = () => {
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) {
// 展品1仅展示大图,无引导对话
} else if (id === 2) {
setGuideVisible2(true);
setGuideStep2(0);
setGuideVisible2(true)
setGuideStep2(0)
} else {
setGuideVisible3(true);
setGuideStep3(0);
setGuideVisible3(true)
setGuideStep3(0)
// 重新进入展品3时重置题目完成状态
setQuizPassed3(false);
setQuizPassed3(false)
}
};
}
return (
<div
@@ -101,11 +101,11 @@ const ZhanglepingPlace2 = () => {
<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`)
}
}}
/>
@@ -139,10 +139,10 @@ const ZhanglepingPlace2 = () => {
{completed && (
<Image
className="absolute bottom-0 right-0"
src={getStaticImage("components/place/继续前进")}
src={getStaticImage('components/place/继续前进')}
button
onClick={() => {
navigate(`/${moduleName}/${starName}/place3`);
navigate(`/${moduleName}/${starName}/place3`)
}}
/>
)}
@@ -173,10 +173,10 @@ const ZhanglepingPlace2 = () => {
<GuideSteps
visible={guideVisible3}
onVisibleChange={(visible) => {
setGuideVisible3(visible);
setGuideVisible3(visible)
// 对话结束后,弹出连线题(如未通过)
if (!visible && !quizPassed3) {
setQuizVisible3(true);
setQuizVisible3(true)
}
}}
currentStep={guideStep3}
@@ -198,34 +198,34 @@ const ZhanglepingPlace2 = () => {
<ExhibitOverlay
visible={activeExhibitId !== null}
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ""}
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ''}
onClose={() => {
if (activeExhibitId !== null) {
// 展品1:关闭后播放一段视频,视频结束再标记已访问
if (activeExhibitId === 1) {
setActiveExhibitId(null);
setShowVideo1(true);
return;
setActiveExhibitId(null)
setShowVideo1(true)
return
}
// 展品3:需在完成连线题后才标记为已访问
if (activeExhibitId === 3) {
if (quizPassed3) {
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)
}}
/>
@@ -233,21 +233,21 @@ const ZhanglepingPlace2 = () => {
{showVideo1 && (
<Video
ref={video1Ref}
src={getPublicPath("video/sunzhongshan/sunzhongshan_03.mp4")}
src={getPublicPath('video/sunzhongshan/sunzhongshan_03.mp4')}
className="fixed inset-0 z-20000"
autoPlay
playsInline
showSkipButton
onEnded={() => {
setShowVideo1(false);
setShowVideo1(false)
setVisited((prev) => {
const next = new Set(prev);
next.add(1);
return next;
});
const next = new Set(prev)
next.add(1)
return next
})
}}
onSkip={() => {
setShowVideo1(false);
setShowVideo1(false)
}}
/>
)}
@@ -259,51 +259,50 @@ const ZhanglepingPlace2 = () => {
visible={quizVisible3}
title="【连线】张乐平先生的画笔在不同历史时期发挥着不同作用,请你把对应的历史时期与当时先生画笔发挥的主要作用匹配起来吧!"
leftItems={[
{ id: "period1", label: "抗日战争" },
{ id: "period2", label: "解放战争" },
{ id: "period3", label: "新中国成立后" },
{ id: 'period1', label: '抗日战争' },
{ id: 'period2', label: '解放战争' },
{ id: 'period3', label: '新中国成立后' },
]}
rightItems={[
{ id: "role2", label: "镜子" },
{ id: "role3", label: "园丁" },
{ id: "role1", label: "刀枪" },
{ id: 'role2', label: '镜子' },
{ id: 'role3', label: '园丁' },
{ id: 'role1', label: '刀枪' },
]}
correctMatches={[
{ leftId: "period1", rightId: "role1" },
{ leftId: "period2", rightId: "role2" },
{ leftId: "period3", rightId: "role3" },
{ leftId: 'period1', rightId: 'role1' },
{ leftId: 'period2', rightId: 'role2' },
{ leftId: 'period3', rightId: 'role3' },
]}
errorMessage={(matches) => {
const getMatchByLeft = (leftId: string) =>
matches.find((m) => m.leftId === leftId);
const getMatchByLeft = (leftId: string) => matches.find((m) => m.leftId === leftId)
const match1 = getMatchByLeft("period1");
if (match1 && match1.rightId !== "role1") {
return "抗日战争时期,张乐平先生的画笔主要是揭露日寇暴行,似“刀枪”。请你再想想吧!";
const match1 = getMatchByLeft('period1')
if (match1 && match1.rightId !== 'role1') {
return '抗日战争时期,张乐平先生的画笔主要是揭露日寇暴行,似“刀枪”。请你再想想吧!'
}
const match2 = getMatchByLeft("period2");
if (match2 && match2.rightId !== "role2") {
return "解放战争时期,张乐平先生的画笔主要是映照社会现实,似“镜子”。请你再想想吧!";
const match2 = getMatchByLeft('period2')
if (match2 && match2.rightId !== 'role2') {
return '解放战争时期,张乐平先生的画笔主要是映照社会现实,似“镜子”。请你再想想吧!'
}
const match3 = getMatchByLeft("period3");
if (match3 && match3.rightId !== "role3") {
return "新中国成立后,张乐平先生的画笔主要为万千儿童种下真善美的种子,似“园丁”。请你再想想吧!";
const match3 = getMatchByLeft('period3')
if (match3 && match3.rightId !== 'role3') {
return '新中国成立后,张乐平先生的画笔主要为万千儿童种下真善美的种子,似“园丁”。请你再想想吧!'
}
return "连线不太对,请你再仔细想一想吧!";
return '连线不太对,请你再仔细想一想吧!'
}}
onSubmit={(_matches, isCorrect) => {
if (isCorrect) {
setQuizVisible3(false);
setQuizPassed3(true);
setSuccessAlert3Visible(true);
setQuizVisible3(false)
setQuizPassed3(true)
setSuccessAlert3Visible(true)
// 答题成功后标记展品3为已访问
setVisited((prev) => {
const next = new Set(prev);
next.add(3);
return next;
});
const next = new Set(prev)
next.add(3)
return next
})
}
}}
zIndex={10000}
@@ -312,15 +311,13 @@ const ZhanglepingPlace2 = () => {
<SuccessAlert
visible={successAlert3Visible}
onContinue={() => {
setSuccessAlert3Visible(false);
setSuccessAlert3Visible(false)
}}
/>
</>
</ScaledPortal>
</div>
);
};
export default ZhanglepingPlace2;
)
}
export default ZhanglepingPlace2