Files
shanghai-residences/src/pages/huangyanpei/reflection/scene2/ChoiceDialog1.tsx
T

249 lines
8.6 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, ErrorAlert } from "@/components/layout";
export interface ChoiceDialog1Props {
/** 是否可见 */
visible?: boolean;
/** 关闭回调 */
onClose?: () => void;
/** 选择回调 */
onSelect?: (choice: "读书" | "没出息" | "女子不能上学") => void;
}
/**
* 第一个选择弹窗:人物和三个选择
* - 使用蒙版遮罩作为背景
* - 显示人物10_004和三个选择选项
*/
const ChoiceDialog1 = ({
visible = true,
onClose,
onSelect,
}: ChoiceDialog1Props) => {
const maskSrc = getStaticImage("components/蒙版遮罩");
const backSrc = getStaticImage("components/关闭");
const characterSrc = getStaticImage("huangyanpei/reflection/scene2/10_004");
const choice1Src = getStaticImage("huangyanpei/reflection/scene2/10_005");
const choice2Src = getStaticImage("huangyanpei/reflection/scene2/10_006");
const choice3Src = getStaticImage("huangyanpei/reflection/scene2/10_007");
const [mounted, setMounted] = useState(false);
const [showGuide, setShowGuide] = useState(false);
const [showSuccessAlert, setShowSuccessAlert] = useState(false);
const [showErrorAlert, setShowErrorAlert] = useState(false);
// SSR 兼容
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (visible) {
setShowGuide(true);
setShowSuccessAlert(false);
setShowErrorAlert(false);
} else {
setShowGuide(false);
}
}, [visible]);
const handleClose = useCallback(
(e: React.MouseEvent<HTMLImageElement>) => {
e.stopPropagation();
onClose?.();
},
[onClose]
);
const handleChoiceClick = useCallback(
(choice: "读书" | "没出息" | "女子不能上学") => {
if (choice === "读书") {
setShowGuide(false);
setShowSuccessAlert(true);
onSelect?.(choice);
} else {
setShowErrorAlert(true);
}
},
[onSelect]
);
// 样式
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-1"
style={overlayStyle}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.3, ease: "easeInOut" }}
>
<div
className={cn(
"fixed 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-between px-20">
{/* 人物 - 左侧 */}
<div className="flex-shrink-0">
<img src={characterSrc} alt="人物" />
</div>
{/* 三个选择选项 - 右侧水平排列 */}
<div className="flex items-center justify-center gap-16 flex-1">
{/* 选择A:读书 */}
<div
className="flex flex-col items-center cursor-pointer transition-transform duration-200 hover:scale-105 active:scale-95"
onClick={() => handleChoiceClick("读书")}
>
{/* 标签A */}
<div className="text-7xl font-bold text-[#ffa500] mb-3 [text-shadow:_3px_3px_0_#fff,_-3px_-3px_0_#fff,_3px_-3px_0_#fff,_-3px_3px_0_#fff]">
A
</div>
{/* 图标 */}
<img src={choice1Src} alt="读书" className="mb-3" />
{/* 文字说明 */}
<div className="text-black text-4xl text-center leading-relaxed font-bold">
读书只为
<br />
升官发财
</div>
</div>
{/* 选择B:没出息 */}
<div
className="flex flex-col items-center cursor-pointer transition-transform duration-200 hover:scale-105 active:scale-95"
onClick={() => handleChoiceClick("没出息")}
>
{/* 标签B */}
<div className="text-7xl font-bold text-[#ffa500] mb-3 [text-shadow:_3px_3px_0_#fff,_-3px_-3px_0_#fff,_3px_-3px_0_#fff,_-3px_3px_0_#fff]">
B
</div>
{/* 图标 */}
<img src={choice2Src} alt="没出息" className="mb-3" />
{/* 文字说明 */}
<div className="text-black text-4xl text-center leading-relaxed font-bold">
手工劳作
<br />
没出息
</div>
</div>
{/* 选择C:女子不能上学 */}
<div
className="flex flex-col items-center cursor-pointer transition-transform duration-200 hover:scale-105 active:scale-95"
onClick={() => handleChoiceClick("女子不能上学")}
>
{/* 标签C */}
<div className="text-7xl font-bold text-[#ffa500] mb-3 [text-shadow:_3px_3px_0_#fff,_-3px_-3px_0_#fff,_3px_-3px_0_#fff,_-3px_3px_0_#fff]">
C
</div>
{/* 图标 */}
<img src={choice3Src} alt="女子不能上学" className="mb-3" />
{/* 文字说明 */}
<div className="text-black text-4xl text-center leading-relaxed font-bold">
女子
<br />
不能上学
</div>
</div>
</div>
</div>
<SuccessAlert
visible={showSuccessAlert}
title="任务1 正确反馈"
content="答对啦!黄先生说“教育要为国家培养实干人才”,浦东中学就是要教大家学真本事,不是只为当官。"
onContinue={() => {
setShowSuccessAlert(false);
onClose?.();
}}
onClose={() => {
setShowSuccessAlert(false);
onClose?.();
}}
/>
<ErrorAlert
visible={showErrorAlert}
text="不对哦~黄先生虽然反对歧视女子、轻视手工,但创办浦东中学的核心是打破“读书只为当官”的旧思想,再选一次吧!"
onClose={() => setShowErrorAlert(false)}
/>
<SuccessAlert
visible={showSuccessAlert}
content="答对啦!黄先生说“教育要为国家培养实干人才”,浦东中学就是要教大家学真本事,不是只为当官。"
onContinue={() => {
setShowSuccessAlert(false);
onClose?.();
}}
onClose={() => {
setShowSuccessAlert(false);
onClose?.();
}}
/>
<ErrorAlert
visible={showErrorAlert}
text="不对哦~黄先生虽然反对歧视女子、轻视手工,但创办浦东中学的核心是打破“读书只为当官”的旧思想,再选一次吧!"
onClose={() => setShowErrorAlert(false)}
/>
</div>
</motion.div>
)}
</AnimatePresence>
);
return content;
};
export default ChoiceDialog1;