Files
shanghai-residences/src/components/layout/quiz/DragQuizPanel.tsx
T
zhongyidian cf64e7ec50 feat: 更新拖拽题功能和图像资源,提升学习体验
- 在 DragQuizPanel 组件中添加空白分隔符功能,增强用户交互性。
- 更新多个场景中的图像资源,确保视觉内容的准确性和一致性。
- 调整引导对话文本,提升信息传达的清晰度。
- 引入新的拖拽题逻辑,优化用户填写体验。
2026-01-18 16:45:06 +08:00

149 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;