- 在多个场景中添加音频资源,增强学习互动性。 - 更新引导对话文本,确保信息准确性和一致性。 - 调整组件结构,清理不必要的代码,提升可维护性。 - 引入结束窗口,鼓励用户深入了解历史背景。
208 lines
6.7 KiB
TypeScript
208 lines
6.7 KiB
TypeScript
import { useState, useEffect, useMemo, useCallback } from "react";
|
|
import { AnimatePresence, motion } from "framer-motion";
|
|
import { cn, getStaticImage } from "@/lib/utils";
|
|
import { Image, StudyGuideModal } from "@/components";
|
|
import { SuccessAlert } from "@/components/layout";
|
|
|
|
export interface ChoiceDialog2Props {
|
|
/** 是否可见 */
|
|
visible?: boolean;
|
|
/** 关闭回调 */
|
|
onClose?: () => void;
|
|
/** 选择回调 */
|
|
onSelect?: (choice: "铁工科" | "商科") => void;
|
|
}
|
|
|
|
/**
|
|
* 第二个选择弹窗:背景图选择
|
|
* - 使用蒙版遮罩作为背景
|
|
* - 显示两个选择:10_008(箭头指向右边)和旋转后的背景图
|
|
*/
|
|
const ChoiceDialog2 = ({
|
|
visible = true,
|
|
onClose,
|
|
onSelect,
|
|
}: ChoiceDialog2Props) => {
|
|
const maskSrc = getStaticImage("components/蒙版遮罩");
|
|
const backSrc = getStaticImage("components/关闭");
|
|
const choiceSrc = getStaticImage("huangyanpei/reflection/scene2/10_008");
|
|
|
|
const [mounted, setMounted] = useState(false);
|
|
const [showGuide, setShowGuide] = useState(false);
|
|
const [showSuccessAlert, setShowSuccessAlert] = useState(false);
|
|
const [selectedChoice, setSelectedChoice] = useState<
|
|
"铁工科" | "商科" | null
|
|
>(null);
|
|
|
|
// SSR 兼容
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (visible) {
|
|
setShowGuide(true);
|
|
setShowSuccessAlert(false);
|
|
setSelectedChoice(null);
|
|
} else {
|
|
setShowGuide(false);
|
|
}
|
|
}, [visible]);
|
|
|
|
const handleClose = useCallback(
|
|
(e: React.MouseEvent<HTMLImageElement>) => {
|
|
e.stopPropagation();
|
|
onClose?.();
|
|
},
|
|
[onClose]
|
|
);
|
|
|
|
const handleChoiceClick = useCallback((choice: "铁工科" | "商科") => {
|
|
setSelectedChoice(choice);
|
|
setShowSuccessAlert(true);
|
|
}, []);
|
|
|
|
const handleSuccessAlertContinue = useCallback(() => {
|
|
setShowSuccessAlert(false);
|
|
if (selectedChoice) {
|
|
onSelect?.(selectedChoice);
|
|
}
|
|
onClose?.();
|
|
}, [selectedChoice, onSelect, onClose]);
|
|
|
|
// 样式
|
|
const overlayStyle = useMemo<React.CSSProperties>(
|
|
() => ({
|
|
position: "fixed",
|
|
inset: 0,
|
|
zIndex: 9999,
|
|
pointerEvents: "none",
|
|
}),
|
|
[]
|
|
);
|
|
|
|
if (!mounted) return null;
|
|
|
|
const content = (
|
|
<AnimatePresence>
|
|
{visible && (
|
|
<motion.div
|
|
key="choice-dialog-2"
|
|
style={overlayStyle}
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
transition={{ duration: 0.3, ease: "easeInOut" }}
|
|
>
|
|
<div
|
|
className={cn(
|
|
"absolute inset-0 flex flex-col items-center justify-center",
|
|
"bg-black/70"
|
|
)}
|
|
style={{ pointerEvents: "auto" }}
|
|
>
|
|
{/* 背景蒙版 */}
|
|
{maskSrc && (
|
|
<Image
|
|
src={maskSrc}
|
|
className="absolute inset-0 w-full h-full object-cover select-none pointer-events-none"
|
|
aria-hidden
|
|
/>
|
|
)}
|
|
|
|
<StudyGuideModal
|
|
visible={showGuide}
|
|
onContinue={() => setShowGuide(false)}
|
|
verticalAlign="center"
|
|
>
|
|
在浦东中学,你可以选未来的方向啦!不管选哪个,黄先生都会支持,因为“三百六十行,行行出状元”!
|
|
</StudyGuideModal>
|
|
|
|
{/* 返回按钮 */}
|
|
{onClose && (
|
|
<Image
|
|
src={backSrc}
|
|
onClick={handleClose}
|
|
alt="返回"
|
|
className="absolute top-5 right-5 z-20"
|
|
button
|
|
/>
|
|
)}
|
|
|
|
{/* 内容区域 */}
|
|
<div className="relative z-10 w-full h-full flex items-center justify-center">
|
|
<div className="flex flex-col items-center gap-12">
|
|
{/* 选择A:铁工科(箭头指向左边) */}
|
|
<div
|
|
className="flex items-center gap-6 cursor-pointer transition-transform duration-200 hover:scale-105 active:scale-95"
|
|
onClick={() => handleChoiceClick("铁工科")}
|
|
>
|
|
{/* 标签A */}
|
|
<div className="text-7xl font-bold text-[#ffa500] [text-shadow:_3px_3px_0_#fff,_-3px_-3px_0_#fff,_3px_-3px_0_#fff,_-3px_3px_0_#fff]">
|
|
A
|
|
</div>
|
|
{/* 箭头按钮 - 需要旋转180度使其指向左边 */}
|
|
<div
|
|
className="relative"
|
|
style={{ transform: "rotate(180deg)" }}
|
|
>
|
|
<img
|
|
src={choiceSrc}
|
|
alt="铁工科"
|
|
className="max-w-[800px] object-contain"
|
|
/>
|
|
{/* 文字覆盖层 */}
|
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
<div
|
|
className="text-white text-7xl font-bold"
|
|
style={{ transform: "rotate(180deg)" }}
|
|
>
|
|
铁工科
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 选择B:商科(箭头指向右边) */}
|
|
<div
|
|
className="flex items-center gap-6 cursor-pointer transition-transform duration-200 hover:scale-105 active:scale-95"
|
|
onClick={() => handleChoiceClick("商科")}
|
|
>
|
|
{/* 标签B */}
|
|
<div className="text-7xl font-bold text-[#ffa500] [text-shadow:_3px_3px_0_#fff,_-3px_-3px_0_#fff,_3px_-3px_0_#fff,_-3px_3px_0_#fff]">
|
|
B
|
|
</div>
|
|
{/* 箭头按钮 */}
|
|
<div className="relative">
|
|
<img
|
|
src={choiceSrc}
|
|
alt="商科"
|
|
className="max-w-[800px] object-contain"
|
|
/>
|
|
{/* 文字覆盖层 */}
|
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
<div className="text-white text-7xl font-bold">商科</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<SuccessAlert
|
|
visible={showSuccessAlert}
|
|
title="选得好!"
|
|
content="不管是做工匠还是做买卖,学好本事就能报效国家,这个选择会影响你在中华职业学校的专业哦!"
|
|
onContinue={handleSuccessAlertContinue}
|
|
onClose={handleSuccessAlertContinue}
|
|
/>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
);
|
|
|
|
return content;
|
|
};
|
|
|
|
export default ChoiceDialog2;
|