Files
draw/src/components/NumberKeyboard.tsx
2025-09-18 23:34:55 +08:00

158 lines
4.9 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 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)