first commit

This commit is contained in:
2025-09-18 23:34:55 +08:00
commit 1f669143cc
84 changed files with 96383 additions and 0 deletions

View 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)