feat:init
This commit is contained in:
1 parent
53d0eeac6b
commit
ae0c050010
494 files changed
+17701
-2318
No files matched your search
@@ -0,0 +1,147 @@
|
||||
import { useState } from "react";
|
||||
import { SingleChoice } from "@/components";
|
||||
import { getBackgroundImage } from "@/lib/utils";
|
||||
import type { SingleChoiceQuizPanelProps } from "./types";
|
||||
|
||||
/**
|
||||
* 单选题面板组件
|
||||
*
|
||||
* 内部管理选择状态,点击选项后自动提交并验证答案
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <SingleChoiceQuizPanel
|
||||
* visible={true}
|
||||
* title="这是一道单选题"
|
||||
* options={[
|
||||
* { value: "A", label: "选项A" },
|
||||
* { value: "B", label: "选项B" },
|
||||
* ]}
|
||||
* correctAnswer="B"
|
||||
* errorMessage="再想一想,注意题干中的时间和提示信息哦~"
|
||||
* onSubmit={(value, isCorrect) => {
|
||||
* console.log("用户选择:", value, "是否正确:", isCorrect);
|
||||
* }}
|
||||
* onError={(error) => {
|
||||
* console.log("错误信息:", error);
|
||||
* }}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
const SingleChoiceQuizPanel = ({
|
||||
visible,
|
||||
zIndex = 10000,
|
||||
title,
|
||||
options,
|
||||
correctAnswer,
|
||||
errorMessage,
|
||||
onSubmit,
|
||||
onError,
|
||||
disabled = false,
|
||||
}: SingleChoiceQuizPanelProps) => {
|
||||
const [selectedValue, setSelectedValue] = useState<string>("");
|
||||
const [error, setError] = useState<string>("");
|
||||
|
||||
if (!visible) return null;
|
||||
|
||||
// 处理选项点击
|
||||
const handleOptionClick = (value: string) => {
|
||||
if (disabled) return;
|
||||
|
||||
setSelectedValue(value);
|
||||
setError("");
|
||||
|
||||
// 验证答案
|
||||
const isCorrect =
|
||||
correctAnswer !== undefined ? value === correctAnswer : undefined;
|
||||
|
||||
// 如果提供了正确答案,进行验证
|
||||
if (correctAnswer !== undefined) {
|
||||
if (isCorrect) {
|
||||
// 答题成功:清空状态,执行 onSubmit(外部控制关闭窗口)
|
||||
setSelectedValue("");
|
||||
setError("");
|
||||
onSubmit?.(value, true);
|
||||
} else {
|
||||
// 答题失败:清空状态,执行 onError,允许重新选择
|
||||
setSelectedValue("");
|
||||
const errorMsg = errorMessage || "很抱歉,你选错了!请你再思考一下吧!";
|
||||
setError(errorMsg);
|
||||
onError?.(errorMsg);
|
||||
}
|
||||
} else {
|
||||
// 没有提供正确答案,直接提交
|
||||
setSelectedValue("");
|
||||
setError("");
|
||||
onSubmit?.(value, true);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 flex items-center justify-center bg-black/40"
|
||||
style={{ zIndex }}
|
||||
>
|
||||
<div className="relative w-[1728px] h-[972px] flex flex-col items-center justify-center">
|
||||
{/* 题干卡片 */}
|
||||
<div className="w-[1600px] min-h-[260px] rounded-[32px] bg-black px-20 py-14 shadow-[0_20px_60px_rgba(240,190,117,0.8)] border-4 border-[#d4c5a9]">
|
||||
<div className="text-[34px] leading-relaxed text-white">{title}</div>
|
||||
</div>
|
||||
|
||||
{/* 选项区域 */}
|
||||
<div className="mt-16 w-[1500px]">
|
||||
<SingleChoice
|
||||
options={options}
|
||||
value={selectedValue}
|
||||
disabled={disabled}
|
||||
renderOption={(option, isSelected) => (
|
||||
<div
|
||||
key={option.value}
|
||||
className="mb-6 cursor-pointer"
|
||||
onClick={() => handleOptionClick(option.value)}
|
||||
>
|
||||
<div
|
||||
className="w-[1431px] h-[156px] flex items-center px-16 text-[28px] leading-snug text-[#fdf5e6] bg-cover bg-center bg-no-repeat transition-all duration-150"
|
||||
style={{
|
||||
backgroundImage: getBackgroundImage(
|
||||
isSelected
|
||||
? "components/quiz/选中"
|
||||
: "components/quiz/未选择"
|
||||
),
|
||||
filter: isSelected ? undefined : "brightness(0.96)",
|
||||
opacity: disabled ? 0.6 : 1,
|
||||
cursor: disabled ? "not-allowed" : "pointer",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (isSelected || disabled) return;
|
||||
(e.currentTarget as HTMLDivElement).style.backgroundImage =
|
||||
getBackgroundImage("components/quiz/选中");
|
||||
(e.currentTarget as HTMLDivElement).style.filter = "";
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (isSelected || disabled) return;
|
||||
(e.currentTarget as HTMLDivElement).style.backgroundImage =
|
||||
getBackgroundImage("components/quiz/未选择");
|
||||
(e.currentTarget as HTMLDivElement).style.filter =
|
||||
"brightness(0.96)";
|
||||
}}
|
||||
>
|
||||
{option.label}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* 答案反馈 */}
|
||||
{error && (
|
||||
<div className="mt-6 text-center text-[26px] text-[#ff4d4f]">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SingleChoiceQuizPanel;
|
||||
Reference in new issue
Block a user