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

+79 -86
View File
@@ -6,53 +6,53 @@ import {
Title,
Overlay,
StudyGuideModal,
} from "@/components";
import { useNavigate, useParams } from "react-router-dom";
import { getBackgroundImage, getPublicPath, getStaticImage } from "@/lib/utils";
import { useState } from "react";
import Cursor from "@/components/cursor";
import { usePuzzleAnimation } from "@/contexts/PuzzleAnimationContext";
import { useChenyunStore } from "@/store/chenyunStore";
import { useCursorController } from "@/hooks/useCursorController";
} from '@/components'
import { useNavigate, useParams } from 'react-router-dom'
import { getBackgroundImage, getPublicPath, getStaticImage } from '@/lib/utils'
import { useState } from 'react'
import Cursor from '@/components/cursor'
import { usePuzzleAnimation } from '@/contexts/PuzzleAnimationContext'
import { useChenyunStore, saveChenyunStore } from '@/store/chenyunStore'
import { useCursorController } from '@/hooks/useCursorController'
// starName 固定为 chenyun
const starName = "chenyun";
const starName = 'chenyun'
// 展品 ID 与资源路径映射,ID 用来做唯一标识
const exhibitSrcMap: Record<1 | 2, string> = {
1: "chenyun/place1/场景1展品1",
2: "chenyun/place1/场景1展品2",
1: 'chenyun/place1/场景1展品1',
2: 'chenyun/place1/场景1展品2',
// 3: "chenyun/place1/场景1展品3",
// 4: "chenyun/place1/场景1展品4",
};
}
const ChenyunPlace1 = () => {
const navigate = useNavigate();
const navigate = useNavigate()
const { moduleName } = useParams<{
moduleName: string;
}>();
moduleName: string
}>()
// 获取碎片动画触发方法
const { triggerPuzzleAnimation } = usePuzzleAnimation();
const { triggerPuzzleAnimation } = usePuzzleAnimation()
// 学习引导弹窗
const [showGuideModal, setShowGuideModal] = useState(true);
const [showGuideModal, setShowGuideModal] = useState(true)
// 对话结束后的学习引导弹窗
const [showAfterDialogGuide, setShowAfterDialogGuide] = useState(false);
const [afterDialogGuideShown, setAfterDialogGuideShown] = useState(false);
const [showAfterDialogGuide, setShowAfterDialogGuide] = useState(false)
const [afterDialogGuideShown, setAfterDialogGuideShown] = useState(false)
// 学习说明对话框显示状态
const [showIntroDialog, setShowIntroDialog] = useState(false);
const [showIntroDialog, setShowIntroDialog] = useState(false)
// 引导对话显示状态
const [visible, setVisible] = useState(false);
const [visible, setVisible] = useState(false)
// 当前激活的展品 ID(只存 ID,不直接存路径,便于作为唯一标识)
const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | null>(null);
const [activeExhibitId, setActiveExhibitId] = useState<1 | 2 | null>(null)
// 使用持久化的访问状态
const place = "place1";
const { markExhibitVisited, getVisitedExhibits } = useChenyunStore();
const place = 'place1'
const { markExhibitVisited, getVisitedExhibits } = useChenyunStore()
// 从 store 获取已访问的展品,转换为 Set 用于兼容现有代码
const visitedExhibits = getVisitedExhibits(place);
const visited = new Set(visitedExhibits);
const visitedExhibits = getVisitedExhibits(place)
const visited = new Set(visitedExhibits)
// Cursor 控制器:使用依赖映射实现自动解锁
// cursor 1 初始启用,cursor 2 依赖展品1(当展品1被访问后自动解锁)
@@ -62,27 +62,27 @@ const ChenyunPlace1 = () => {
2: [1], // cursor 2 依赖展品 1,当展品1被访问后自动解锁
},
visited, // 传入数组,而不是 Set
});
})
const handleOpenExhibit = (index: 1 | 2) => {
setActiveExhibitId(index);
setActiveExhibitId(index)
// ExhibitOverlay 打开时会自动通过 onOpen 通知 ResidenceLayout 执行动画
};
}
const handleStartLearning = () => {
setShowIntroDialog(false);
setVisible(true);
};
setShowIntroDialog(false)
setVisible(true)
}
const progressCount = visited.size;
const total = 2;
const completed = progressCount >= total;
const progressCount = visited.size
const total = 2
const completed = progressCount >= total
const subtitle = completed
? "探索陈云纪念馆老宅堂屋(已完成)"
: `探索陈云纪念馆老宅堂屋(${progressCount}/${total})`;
? '探索陈云纪念馆老宅堂屋(已完成)'
: `探索陈云纪念馆老宅堂屋(${progressCount}/${total})`
const subtitleClassName = completed
? "text-[#fff998] [text-shadow:_0_8px_8px_rgba(0,0,0,0.35),_0_0_16px_rgba(0,0,0,0.25)]"
: undefined;
? 'text-[#fff998] [text-shadow:_0_8px_8px_rgba(0,0,0,0.35),_0_0_16px_rgba(0,0,0,0.25)]'
: undefined
return (
<div
@@ -101,11 +101,11 @@ const ChenyunPlace1 = () => {
<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`)
}
}}
/>
@@ -141,10 +141,11 @@ const ChenyunPlace1 = () => {
{completed && (
<Image
className="absolute bottom-0 right-0"
src={getStaticImage("chenyun/place1/继续前进")}
src={getStaticImage('chenyun/place1/继续前进')}
button
onClick={() => {
navigate(`/${moduleName}/${starName}/place2`);
saveChenyunStore()
navigate(`/${moduleName}/${starName}/place2`)
}}
/>
)}
@@ -152,20 +153,20 @@ const ChenyunPlace1 = () => {
{/* 遮罩层 */}
<ExhibitOverlay
visible={activeExhibitId !== null}
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ""}
src={activeExhibitId ? exhibitSrcMap[activeExhibitId] : ''}
onOpen={() => {
// 示例:展品1对应碎片1,展品2对应碎片2
// 根据实际需求调用 triggerPuzzleAnimation
if (activeExhibitId === 1) {
triggerPuzzleAnimation(1);
triggerPuzzleAnimation(1)
}
}}
onClose={() => {
if (activeExhibitId !== null) {
markExhibitVisited(place, activeExhibitId);
markExhibitVisited(place, activeExhibitId)
// cursor 状态会根据 visited 自动更新,无需手动调用 enable
}
setActiveExhibitId(null);
setActiveExhibitId(null)
}}
/>
@@ -173,12 +174,12 @@ const ChenyunPlace1 = () => {
<StudyGuideModal
visible={showGuideModal}
onContinue={() => {
setShowGuideModal(false);
setVisible(true);
setShowGuideModal(false)
setVisible(true)
}}
audioSrc={getPublicPath("audio/chenyun/mp3_chenyun_01.mp3")}
audioSrc={getPublicPath('audio/chenyun/mp3_chenyun_01.mp3')}
>
同学你好,欢迎来到“走进故居·对话”学习模块!{"\n"}
同学你好,欢迎来到“走进故居·对话”学习模块!{'\n'}
此刻你正站在陈云同志的故居堂屋里,接下来请跟着时光的脚步,
一起翻开他人生的7帧珍贵篇章:水乡少年·艰辛成长、商务启航·投身革命、
苏区淬炼·崭露头角、延安担当·经济破局、恢复时期·经济奠基、建设时期·务实兴邦、
@@ -201,23 +202,23 @@ const ChenyunPlace1 = () => {
<GuideSteps
visible={visible}
onVisibleChange={(nextVisible) => {
setVisible(nextVisible);
setVisible(nextVisible)
if (!nextVisible && !afterDialogGuideShown) {
setAfterDialogGuideShown(true);
setShowAfterDialogGuide(true);
setAfterDialogGuideShown(true)
setShowAfterDialogGuide(true)
}
}}
showMask={false}
>
<GuideStepsItem
speaker="student"
audioSrc={getPublicPath("audio/chenyun/mp3_chenyun_03.mp3")}
audioSrc={getPublicPath('audio/chenyun/mp3_chenyun_03.mp3')}
>
小沪!这就是陈云小时候生活的房子吗?看起来和普通农家差不多,他童年过得艰苦吗?
</GuideStepsItem>
<GuideStepsItem
speaker="guide"
audioSrc={getPublicPath("audio/chenyun/mp3_chenyun_04.mp3")}
audioSrc={getPublicPath('audio/chenyun/mp3_chenyun_04.mp3')}
>
这座房子就是陈云故居,位于上海市青浦区练塘镇下塘街95号,是一座坐南朝北、面向河畔的两层楼江南民居。
</GuideStepsItem>
@@ -234,24 +235,20 @@ const ChenyunPlace1 = () => {
visible={showAfterDialogGuide}
onContinue={() => setShowAfterDialogGuide(false)}
ailgn="left"
audioSrc={getPublicPath("audio/chenyun/mp3_chenyun_02.mp3")}
audioSrc={getPublicPath('audio/chenyun/mp3_chenyun_02.mp3')}
>
1.场景中出现动态光点的展品表示未浏览,可通过点击光点来了解展品背后的故事,通过滚轮可以放大展品,浏览展品后蓝色动态光点会变为已浏览状态。
{"\n"}
{'\n'}
2.在学习过程中会掉落拼图碎片,拼图碎片会自动收入拼图盒中,拼图盒可以点击查看当前拼图收集情况,点击单个拼图可以回到获得拼图的场景再次学习。
{"\n"}
{'\n'}
3.所有动态光点的展品全部学习后才能进入下一个场景学习。
</StudyGuideModal>
</div>
);
};
)
}
// 学习说明内容
const LearningIntroduction = ({
handleStartLearning,
}: {
handleStartLearning: () => void;
}) => {
const LearningIntroduction = ({ handleStartLearning }: { handleStartLearning: () => void }) => {
return (
<div className="fixed inset-0 z-50 flex items-center justify-center">
<div className="relative w-full h-full bg-gradient-to-b from-[#f5f1e8] via-[#ede8dc] to-[#e8e0d1] shadow-[0_20px_60px_rgba(0,0,0,0.4)] border-4 border-[#d4c5a9] overflow-hidden">
@@ -282,22 +279,20 @@ const LearningIntroduction = ({
<div className="mb-8 bg-[rgba(255,255,255,0.6)] rounded-2xl p-6 border-2 border-[#d4c5a9] flex-shrink-0">
<div className="flex flex-wrap items-center justify-center gap-4 text-2xl">
{[
"水乡少年 艰辛成长",
"商务启航 投身革命",
"苏区淬炼 崭露头角",
"延安担当经济破局",
"恢复时期经济奠基",
"建设时期 务实兴邦",
"改革浪潮 擘画实业",
'水乡少年 艰辛成长',
'商务启航 投身革命',
'苏区淬炼 崭露头角',
'延安担当经济破局',
'恢复时期经济奠基',
'建设时期 务实兴邦',
'改革浪潮 擘画实业',
].map((stage, index, array) => (
<div key={index} className="flex items-center">
<span className="px-4 py-2 bg-[rgba(139,115,85,0.15)] rounded-lg text-[#5c4a37] font-semibold">
{stage}
</span>
{index < array.length - 1 && (
<span className="mx-2 text-[#8b7355] font-bold text-3xl">
→
</span>
<span className="mx-2 text-[#8b7355] font-bold text-3xl">→</span>
)}
</div>
))}
@@ -308,10 +303,10 @@ const LearningIntroduction = ({
<div className="mb-8 space-y-4 flex-1 overflow-hidden">
<div className="h-full overflow-hidden">
{[
"走进故居-对话学习模块会包含多个场景,场景中有蓝色动态光点的展品,表示未浏览,可通过点击光点来学习展品背后的故事,学习展品后蓝色动态光点会变为绿色静态光点,表示已浏览。",
"场景中的展品有可能会包含一个或多个拼图,游览过程中如获得拼图,会自动掉落拼图并收入拼图盒中,拼图盒可以点开查看当前拼图收集情况,点击单个拼图可以回到获得拼图的场景再次学习。",
"所有有蓝色动态光点的展品全部学习后才能进入下一个场景进行学习。",
"每个阶段学习过后,会有学习回顾环节,以导图的形式总结了阶段的学习内容。",
'走进故居-对话学习模块会包含多个场景,场景中有蓝色动态光点的展品,表示未浏览,可通过点击光点来学习展品背后的故事,学习展品后蓝色动态光点会变为绿色静态光点,表示已浏览。',
'场景中的展品有可能会包含一个或多个拼图,游览过程中如获得拼图,会自动掉落拼图并收入拼图盒中,拼图盒可以点开查看当前拼图收集情况,点击单个拼图可以回到获得拼图的场景再次学习。',
'所有有蓝色动态光点的展品全部学习后才能进入下一个场景进行学习。',
'每个阶段学习过后,会有学习回顾环节,以导图的形式总结了阶段的学习内容。',
].map((feature, index) => (
<div
key={index}
@@ -320,9 +315,7 @@ const LearningIntroduction = ({
<span className="flex-shrink-0 w-12 h-12 bg-gradient-to-br from-[#8b7355] to-[#6b5d47] text-white text-3xl font-bold rounded-full flex items-center justify-center shadow-md">
{index + 1}
</span>
<p className="text-2xl text-[#5c4a37] leading-relaxed flex-1 pt-1">
{feature}
</p>
<p className="text-2xl text-[#5c4a37] leading-relaxed flex-1 pt-1">{feature}</p>
</div>
))}
</div>
@@ -341,7 +334,7 @@ const LearningIntroduction = ({
</div>
</div>
</div>
);
};
)
}
export default ChenyunPlace1;
export default ChenyunPlace1