- 在 DragQuizPanel 组件中添加空白分隔符功能,增强用户交互性。 - 更新多个场景中的图像资源,确保视觉内容的准确性和一致性。 - 调整引导对话文本,提升信息传达的清晰度。 - 引入新的拖拽题逻辑,优化用户填写体验。
149 lines
5.8 KiB
TypeScript
149 lines
5.8 KiB
TypeScript
import { useEffect, useRef } from "react";
|
||
import { DragFill } from "@/components";
|
||
import { cn } from "@/lib/utils";
|
||
import type { DragQuizPanelProps } from "./types";
|
||
|
||
/** 拖拽题面板:使用 DragFill 组件 */
|
||
const DragQuizPanel = ({
|
||
visible,
|
||
zIndex = 10000,
|
||
title,
|
||
questionPrefix,
|
||
questionSuffix,
|
||
options,
|
||
blanks,
|
||
blankSeparators,
|
||
value,
|
||
error,
|
||
onChange,
|
||
}: DragQuizPanelProps) => {
|
||
// 跟踪之前的 visible 状态
|
||
const prevVisibleRef = useRef(visible);
|
||
|
||
// 当窗口关闭时,清除拖拽状态
|
||
useEffect(() => {
|
||
// 如果从可见变为不可见,清除拖拽状态
|
||
if (prevVisibleRef.current && !visible && value.length > 0) {
|
||
onChange([]);
|
||
}
|
||
prevVisibleRef.current = visible;
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||
}, [visible]);
|
||
|
||
if (!visible) return null;
|
||
|
||
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 pt-12 pb-14">
|
||
{/* 题干卡片 */}
|
||
<div className="w-[1700px] rounded-[32px] bg-black/90 px-20 py-12 shadow-[0_20px_60px_rgba(240,190,117,0.8)] border-4 border-[#d4c5a9]">
|
||
<div className="text-[32px] leading-relaxed text-white">
|
||
{title && <div className="mb-4">{title}</div>}
|
||
|
||
<div>
|
||
{questionPrefix && <span>{questionPrefix}</span>}
|
||
{blanks.map((blank, index) => {
|
||
const filledResult = value.find((r) => r.blankId === blank.id);
|
||
const filledValue = filledResult?.optionValue || null;
|
||
return (
|
||
<span key={blank.id}>
|
||
<span
|
||
data-blank-id={blank.id}
|
||
className={cn(
|
||
"inline-flex items-center justify-center min-w-[140px] h-[56px] px-6 mx-3",
|
||
"rounded-xl border-2 transition-all duration-300 shadow-[0_4px_16px_rgba(0,0,0,0.2)]",
|
||
filledValue
|
||
? "border-[#f0be75] bg-gradient-to-br from-[#3a3020] to-[#2a2520] backdrop-blur-sm"
|
||
: "border-[#d4c5a9]/60 bg-white/10 backdrop-blur-sm hover:border-[#d4c5a9]"
|
||
)}
|
||
>
|
||
{filledValue ? (
|
||
<span className="text-[#f0be75] font-semibold flex items-center gap-3">
|
||
<span className="text-[28px]">{filledValue}</span>
|
||
<button
|
||
type="button"
|
||
className="w-7 h-7 flex items-center justify-center rounded-full bg-[#8b4513]/80 hover:bg-[#a0522d] text-white text-sm transition-all hover:scale-110 shadow-lg"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
onChange(
|
||
value.filter((r) => r.blankId !== blank.id)
|
||
);
|
||
}}
|
||
>
|
||
×
|
||
</button>
|
||
</span>
|
||
) : (
|
||
<span className="text-white/40 text-[24px] font-light">
|
||
____
|
||
</span>
|
||
)}
|
||
</span>
|
||
{index < blanks.length - 1 && (
|
||
<span className="text-white/80 mx-1">
|
||
{blankSeparators && blankSeparators[index]
|
||
? blankSeparators[index]
|
||
: "、"}
|
||
</span>
|
||
)}
|
||
</span>
|
||
);
|
||
})}
|
||
{questionSuffix && <span>{questionSuffix}</span>}
|
||
{/* 答案反馈 */}
|
||
{error && (
|
||
<div className="mt-5 text-center text-[26px] text-[#fcbe53]">
|
||
{error}
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 使用 DragFill 组件 */}
|
||
<div className="w-[1500px] mt-16">
|
||
<DragFill
|
||
options={options}
|
||
blanks={blanks}
|
||
value={value}
|
||
onChange={onChange}
|
||
hideLabels
|
||
showSubmitButton={false}
|
||
layout="vertical"
|
||
className="w-full"
|
||
renderOption={(option, isUsed) => (
|
||
<div
|
||
className={cn(
|
||
"relative h-[110px] px-10 flex items-center justify-center",
|
||
"rounded-[32px] transition-all duration-300",
|
||
"text-[32px] font-bold border-3 shadow-[0_8px_32px_rgba(0,0,0,0.3)]",
|
||
isUsed
|
||
? "border-[#8b7355] bg-[#3d3329] text-[#a89378] cursor-not-allowed opacity-50"
|
||
: "border-[#d4c5a9] bg-gradient-to-br from-[#4a3f35] to-[#3a2f25] text-[#f5e6d3] cursor-move hover:border-[#f0be75] hover:shadow-[0_12px_40px_rgba(240,190,117,0.7)] hover:scale-[1.02]"
|
||
)}
|
||
>
|
||
{!isUsed && (
|
||
<div className="absolute inset-0 rounded-[32px] bg-gradient-to-br from-[#d4c5a9]/20 to-transparent pointer-events-none" />
|
||
)}
|
||
<span className="relative z-10 drop-shadow-[0_2px_4px_rgba(0,0,0,0.3)]">
|
||
{option.label}
|
||
</span>
|
||
</div>
|
||
)}
|
||
renderBlank={(_blank) => {
|
||
// 返回一个隐藏元素,实际的空白区域在题干中
|
||
// 但需要通过 data-blank-id 让 DragFill 能找到它
|
||
return <div className="hidden" />;
|
||
}}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default DragQuizPanel;
|