diff --git a/src/components/practice/InputArea.tsx b/src/components/practice/InputArea.tsx index 80d3012..d65d8dc 100644 --- a/src/components/practice/InputArea.tsx +++ b/src/components/practice/InputArea.tsx @@ -41,13 +41,27 @@ export function InputArea({ if (inputLocked) return const newInput = [...userInput] - // 只取第一个字符 - newInput[index] = value.slice(0, 1) - onInputChange(newInput) - // 自动跳转到下一个输入框 - if (value && index < userInput.length - 1) { - inputRefs.current[index + 1]?.focus() + // 处理多字符输入(连续输入或粘贴) + if (value.length > 1) { + const chars = value.split('') + for (let i = 0; i < chars.length && index + i < userInput.length; i++) { + newInput[index + i] = chars[i] + } + onInputChange(newInput) + + // 聚焦到最后填充的位置的下一个 + const nextIndex = Math.min(index + chars.length, userInput.length - 1) + inputRefs.current[nextIndex]?.focus() + } else { + // 单字符输入 + newInput[index] = value + onInputChange(newInput) + + // 自动跳转到下一个输入框 + if (value && index < userInput.length - 1) { + inputRefs.current[index + 1]?.focus() + } } } @@ -80,7 +94,7 @@ export function InputArea({ } return ( -
+
{userInput.map((char, index) => { const status = charStatuses[index] || 'pending' diff --git a/src/components/practice/PracticeMatrix.tsx b/src/components/practice/PracticeMatrix.tsx index 5295f56..3d25b4d 100644 --- a/src/components/practice/PracticeMatrix.tsx +++ b/src/components/practice/PracticeMatrix.tsx @@ -1,6 +1,8 @@ import { knowledgeAreas, processGroups } from '@/data' import { getProcessesByKaAndPg } from '@/utils/practice' import { ProcessCell } from './ProcessCell' +import { useLongPress } from '@/hooks/useLongPress' +import clsx from 'clsx' interface PracticeMatrixProps { answeredCells: Map @@ -12,6 +14,77 @@ interface PracticeMatrixProps { getCellTabIndex: (cellId: string) => number } +interface KnowledgeAreaCellProps { + ka: any + isAnswered: boolean + isFocused: boolean + showAnswer?: string | null + onLongPress: (cellId: string) => void + onLongPressEnd: () => void + onClick: (cellId: string) => void + tabIndex: number +} + +function KnowledgeAreaCell({ + ka, + isAnswered, + isFocused, + showAnswer, + onLongPress, + onLongPressEnd, + onClick, + tabIndex, +}: KnowledgeAreaCellProps) { + const cellId = `ka-${ka.id}` + const longPressHandlers = useLongPress(cellId, { + onLongPress, + onLongPressEnd, + }) + + return ( + onClick(cellId)} + tabIndex={tabIndex} + role="button" + aria-label={`知识领域:${ka.name}`} + {...longPressHandlers} + > + {isAnswered ? ( +
+ + {ka.order} + + + {ka.name} + +
+ ) : ( +
+ )} + + {/* 长按显示答案 */} + {showAnswer && ( +
+ + {showAnswer} + +
+ )} + + ) +} + export function PracticeMatrix({ answeredCells, currentCellId, @@ -48,26 +121,24 @@ export function PracticeMatrix({ {/* 表体:知识领域 × 过程 */} {sortedKAs.map((ka) => { + const kaCellId = `ka-${ka.id}` return ( {/* 知识领域名称 */} - -
- - {ka.order} - - - {ka.name} - -
- + {/* 每个过程组的单元格 */} {sortedPGs.map((pg) => { diff --git a/src/pages/ProcessPracticePage.tsx b/src/pages/ProcessPracticePage.tsx index 238ef50..aae801b 100644 --- a/src/pages/ProcessPracticePage.tsx +++ b/src/pages/ProcessPracticePage.tsx @@ -57,17 +57,21 @@ export default function ProcessPracticePage() { setCharStatuses(new Array(cell.answer.length).fill('pending')) setLastErrorTimestamp(null) - // 滚动到可见区域并聚焦 + // 滚动到可见区域 requestAnimationFrame(() => { const element = document.querySelector( `[data-cell-id="${cell.id}"]` ) as HTMLElement element?.scrollIntoView({ behavior: 'smooth', block: 'center' }) - // 聚焦格子,使键盘长按生效 - setTimeout(() => { - element?.focus() - }, 100) }) + + // 延迟聚焦到第一个输入框,确保 DOM 已更新 + setTimeout(() => { + const firstInput = document.querySelector( + '.practice-input-area input' + ) as HTMLInputElement + firstInput?.focus() + }, 150) }, [] ) @@ -314,7 +318,7 @@ export default function ProcessPracticePage() {
{/* 底部固定区域 */} -
+
{/* 输入区域 */}