- 删除 .claude/settings.local.json 配置文件,清理不必要的代码。 - 更新多个组件以引入音频资源,增强用户互动体验。 - 调整引导对话文本,确保信息准确性和一致性。 - 更新图像资源,提升视觉内容的准确性和一致性。
140 lines
4.0 KiB
TypeScript
140 lines
4.0 KiB
TypeScript
import { getStaticImage, getBackgroundImage } from "@/lib/utils";
|
|
import type { MouseEvent } from "react";
|
|
import { useEffect } from "react";
|
|
import { useAudioManager } from "@/hooks/useAudioManager";
|
|
|
|
export interface SuccessAlertProps {
|
|
/** 标题 */
|
|
title?: string;
|
|
/** 内容文本 */
|
|
content?: string;
|
|
/** 是否可见 */
|
|
visible?: boolean;
|
|
/** 成功提示音频地址(可选) */
|
|
audioSrc?: string;
|
|
/** 弹窗出现时是否自动播放音频(默认 true) */
|
|
autoPlayAudio?: boolean;
|
|
/** 音频分组 id,相同 channel 内互斥,不同 channel 可同时播放;不传则全局互斥 */
|
|
audioChannelId?: string;
|
|
/** 点击遮罩层回调 */
|
|
onMaskClick?: () => void;
|
|
/** 继续按钮回调 */
|
|
onContinue?: () => void;
|
|
/** 关闭回调 */
|
|
onClose?: () => void;
|
|
}
|
|
|
|
/**
|
|
* SuccessAlert 组件 - 成功提示弹窗
|
|
* 使用 components/正确版 作为背景
|
|
*/
|
|
const SuccessAlert = ({
|
|
title = "恭喜你, 选择正确!",
|
|
content,
|
|
visible = true,
|
|
audioSrc,
|
|
autoPlayAudio = true,
|
|
audioChannelId,
|
|
onMaskClick,
|
|
onContinue,
|
|
onClose,
|
|
}: SuccessAlertProps) => {
|
|
const { currentSrc, play, stop } = useAudioManager(
|
|
audioChannelId
|
|
? { mode: "channel", channelId: audioChannelId }
|
|
: { mode: "global" }
|
|
);
|
|
|
|
// 弹窗显示时自动播放音频
|
|
useEffect(() => {
|
|
if (!visible) return;
|
|
if (!autoPlayAudio) return;
|
|
if (!audioSrc) return;
|
|
play(audioSrc);
|
|
}, [visible, autoPlayAudio, audioSrc, play]);
|
|
|
|
// 弹窗关闭时停止音频(仅当当前播放的是该弹窗的 audioSrc)
|
|
useEffect(() => {
|
|
if (visible) return;
|
|
if (audioSrc && currentSrc === audioSrc) {
|
|
stop();
|
|
}
|
|
}, [visible, audioSrc, currentSrc, stop]);
|
|
|
|
if (!visible) return null;
|
|
|
|
const handleContinue = (e: MouseEvent) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
// 点击继续时停止音频
|
|
if (audioSrc && currentSrc === audioSrc) {
|
|
stop();
|
|
}
|
|
// 只调用 onContinue,它会处理关闭逻辑
|
|
if (onContinue) {
|
|
onContinue();
|
|
} else if (onClose) {
|
|
onClose();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-[10000] flex items-center justify-center">
|
|
{/* 蒙版背景 */}
|
|
<div
|
|
className="absolute inset-0 bg-cover bg-center bg-no-repeat"
|
|
style={{
|
|
backgroundImage: getBackgroundImage("components/蒙版遮罩"),
|
|
}}
|
|
onClick={onMaskClick || onClose}
|
|
/>
|
|
|
|
{/* 内容 */}
|
|
<div
|
|
className="relative w-full h-full z-10 flex flex-col items-center justify-center pointer-events-none"
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
{/* 文本内容 */}
|
|
<div className="relative z-10 w-full h-[619px] flex flex-col items-center justify-center gap-8 pt-20 pointer-events-none">
|
|
{/* 背景图片 - 使用 components/正确版 */}
|
|
<img
|
|
className="absolute inset-0 top-0 -z-10"
|
|
src={getStaticImage("components/正确版")}
|
|
alt="正确版"
|
|
/>
|
|
{/* 标题 */}
|
|
{title && (
|
|
<div className="text-[#ffbe57] text-6xl font-bold text-center">
|
|
{title}
|
|
</div>
|
|
)}
|
|
|
|
{/* 内容文本 */}
|
|
{content && (
|
|
<div className="text-white text-4xl font-medium max-w-[1600px] leading-relaxed px-20">
|
|
{content}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* 继续按钮 */}
|
|
<div className="mt-8 relative z-20 pointer-events-auto">
|
|
<div
|
|
className="w-[414px] h-[109px] bg-cover bg-center bg-no-repeat cursor-pointer hover:scale-105 hover:brightness-110 transition-all duration-300"
|
|
style={{
|
|
backgroundImage: `
|
|
${getBackgroundImage("components/继续前进")},
|
|
${getBackgroundImage("components/按钮")}
|
|
`,
|
|
}}
|
|
onClick={handleContinue}
|
|
onMouseDown={(e) => e.stopPropagation()}
|
|
></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default SuccessAlert;
|