first commit
This commit is contained in:
158
src/components/NumberKeyboard.tsx
Normal file
158
src/components/NumberKeyboard.tsx
Normal file
@@ -0,0 +1,158 @@
|
||||
import React from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import { Delete, RotateCcw, Check } from 'lucide-react'
|
||||
|
||||
interface NumberKeyboardProps {
|
||||
onNumberClick: (number: string) => void
|
||||
onDeleteClick: () => void
|
||||
onClearClick: () => void
|
||||
onConfirmClick: () => void
|
||||
disabled?: boolean
|
||||
canConfirm?: boolean
|
||||
studentIdLength?: number
|
||||
}
|
||||
|
||||
const NumberKeyboard: React.FC<NumberKeyboardProps> = ({
|
||||
onNumberClick,
|
||||
onDeleteClick,
|
||||
onClearClick,
|
||||
onConfirmClick,
|
||||
disabled = false,
|
||||
canConfirm = false,
|
||||
studentIdLength = 0
|
||||
}) => {
|
||||
// 数字键盘布局
|
||||
const keyboardLayout = [
|
||||
['1', '2', '3'],
|
||||
['4', '5', '6'],
|
||||
['7', '8', '9'],
|
||||
['clear', '0', 'delete']
|
||||
]
|
||||
|
||||
// 按钮点击动画变体
|
||||
const buttonVariants = {
|
||||
initial: { scale: 1 },
|
||||
tap: { scale: 0.95 },
|
||||
hover: { scale: 1.05 }
|
||||
}
|
||||
|
||||
// 渲染按钮内容
|
||||
const renderButtonContent = (key: string) => {
|
||||
switch (key) {
|
||||
case 'delete':
|
||||
return <Delete className="w-8 h-8" />
|
||||
case 'clear':
|
||||
return <RotateCcw className="w-8 h-8" />
|
||||
default:
|
||||
return <span className="text-3xl font-bold">{key}</span>
|
||||
}
|
||||
}
|
||||
|
||||
// 检查数字键是否应该被禁用
|
||||
const isNumberKeyDisabled = (key: string) => {
|
||||
// 如果是数字键且学号已达到12位,则禁用
|
||||
return /^[0-9]$/.test(key) && studentIdLength >= 12
|
||||
}
|
||||
|
||||
// 获取按钮样式
|
||||
const getButtonStyle = (key: string) => {
|
||||
const baseStyle = "w-[140px] h-[140px] rounded-2xl font-bold transition-all duration-200 flex items-center justify-center shadow-lg"
|
||||
|
||||
if (disabled) {
|
||||
return `${baseStyle} bg-gray-500/20 text-gray-400 cursor-not-allowed`
|
||||
}
|
||||
|
||||
// 检查数字键是否被禁用
|
||||
if (isNumberKeyDisabled(key)) {
|
||||
return `${baseStyle} bg-gray-500/20 text-gray-400 cursor-not-allowed`
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case 'delete':
|
||||
return `${baseStyle} bg-red-500/20 hover:bg-red-500/30 text-red-400 hover:text-red-300 border border-red-500/30`
|
||||
case 'clear':
|
||||
return `${baseStyle} bg-yellow-500/20 hover:bg-yellow-500/30 text-yellow-400 hover:text-yellow-300 border border-yellow-500/30`
|
||||
default:
|
||||
return `${baseStyle} bg-blue-500/20 hover:bg-blue-500/30 text-white border border-blue-500/30 hover:border-blue-400`
|
||||
}
|
||||
}
|
||||
|
||||
// 处理按钮点击
|
||||
const handleButtonClick = (key: string) => {
|
||||
if (disabled) return
|
||||
|
||||
// 如果是数字键且被禁用,则不处理点击
|
||||
if (isNumberKeyDisabled(key)) return
|
||||
|
||||
switch (key) {
|
||||
case 'delete':
|
||||
onDeleteClick()
|
||||
break
|
||||
case 'clear':
|
||||
onClearClick()
|
||||
break
|
||||
default:
|
||||
onNumberClick(key)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
{/* 数字键盘网格 */}
|
||||
<div className="grid grid-cols-3 gap-[10px]">
|
||||
{keyboardLayout.map((row, rowIndex) =>
|
||||
row.map((key, keyIndex) => (
|
||||
<motion.button
|
||||
key={`${rowIndex}-${keyIndex}`}
|
||||
variants={buttonVariants}
|
||||
initial="initial"
|
||||
whileHover={disabled || isNumberKeyDisabled(key) ? "initial" : "hover"}
|
||||
whileTap={disabled || isNumberKeyDisabled(key) ? "initial" : "tap"}
|
||||
onClick={() => handleButtonClick(key)}
|
||||
className={getButtonStyle(key)}
|
||||
disabled={disabled || isNumberKeyDisabled(key)}
|
||||
>
|
||||
{renderButtonContent(key)}
|
||||
</motion.button>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 确认按钮 */}
|
||||
<motion.button
|
||||
variants={buttonVariants}
|
||||
initial="initial"
|
||||
whileHover={(!disabled && canConfirm) ? "hover" : "initial"}
|
||||
whileTap={(!disabled && canConfirm) ? "tap" : "initial"}
|
||||
onClick={onConfirmClick}
|
||||
disabled={disabled || !canConfirm}
|
||||
className={`w-full max-w-[450px] h-[80px] rounded-2xl font-bold text-xl transition-all duration-200 flex items-center justify-center space-x-3 shadow-lg ${
|
||||
disabled || !canConfirm
|
||||
? 'bg-gray-500/20 text-gray-400 cursor-not-allowed border border-gray-500/30'
|
||||
: 'bg-gradient-to-r from-green-500 to-emerald-500 hover:from-green-600 hover:to-emerald-600 text-white shadow-green-500/25 hover:shadow-green-500/40'
|
||||
}`}
|
||||
>
|
||||
<Check className="w-6 h-6" />
|
||||
<span>开始抽奖</span>
|
||||
</motion.button>
|
||||
|
||||
{/* 键盘说明 */}
|
||||
<div className="text-center text-white/50 text-sm space-y-1">
|
||||
<p>点击数字输入学号</p>
|
||||
<div className="flex items-center justify-center space-x-4">
|
||||
<div className="flex items-center space-x-1">
|
||||
<RotateCcw className="w-4 h-4" />
|
||||
<span>清空</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-1">
|
||||
<Delete className="w-4 h-4" />
|
||||
<span>删除</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(NumberKeyboard)
|
||||
Reference in New Issue
Block a user