diff --git a/src/data/knowledge-areas.json b/src/data/knowledge-areas.json index efa95d9..1ecccf8 100644 --- a/src/data/knowledge-areas.json +++ b/src/data/knowledge-areas.json @@ -52,7 +52,29 @@ "order": 2, "color": "#8B5CF6", "description": "确保项目包含且只包含成功完成项目所需的全部工作", - "processCount": 6 + "processCount": 6, + "tailoringFactors": [ + { + "title": "知识和需求管理", + "description": "项目经理应建立哪些指南?为了在未来项目中重复使用需求,组织是否拥有正式或非正式的知识和需求管理体系?" + }, + { + "title": "确认和控制", + "description": "组织是否有正式或非正式的与确认和控制相关政策、程序和指南?" + }, + { + "title": "开发方法", + "description": "组织是否采用敏捷方法管理项目?开发方法属于迭代型还是增量型?是否采用预测型方法?混合型方法是否有效?" + }, + { + "title": "需求的稳定性", + "description": "项目中是否存在需求不稳定的领域?是否有必要采用精益、敏捷或其他适应型技术来处理不稳定的需求,直至需求稳定且定义明确?" + }, + { + "title": "治理", + "description": "组织是否拥有正式或非正式的审计和治理政策、程序和指南?" + } + ] }, { "id": "KA03", diff --git a/src/pages/ProcessPracticePage.tsx b/src/pages/ProcessPracticePage.tsx index fd37fd2..a25e3a2 100644 --- a/src/pages/ProcessPracticePage.tsx +++ b/src/pages/ProcessPracticePage.tsx @@ -90,6 +90,23 @@ export default function ProcessPracticePage() { } }, [answeredCells, currentCellId]) + // 恢复焦点到第一个空输入框 + const restoreFocus = useCallback(() => { + setTimeout(() => { + const inputs = document.querySelectorAll('.practice-input-area input') + const firstEmptyInput = Array.from(inputs).find( + (input) => !(input as HTMLInputElement).value + ) as HTMLInputElement + + if (firstEmptyInput) { + firstEmptyInput.focus() + } else { + // 如果所有输入框都有值,聚焦到第一个 + (inputs[0] as HTMLInputElement)?.focus() + } + }, 100) + }, []) + // 切换到指定格子 const switchToCell = useCallback( (cell: CellInfo) => { @@ -251,16 +268,9 @@ export default function ProcessPracticePage() { setShowAnswerForCell(null) setInputLocked(false) announceToScreenReader('答案已隐藏') - - // 恢复焦点到第一个输入框 - setTimeout(() => { - const firstInput = document.querySelector( - '.practice-input-area input' - ) as HTMLInputElement - firstInput?.focus() - }, 100) + restoreFocus() } - }, [showAnswerForCell]) + }, [showAnswerForCell, restoreFocus]) // 自动过期检查 useEffect(() => { @@ -270,14 +280,7 @@ export default function ProcessPracticePage() { if (remainingTime <= 0) { setShowAnswerForCell(null) setInputLocked(false) - - // 恢复焦点 - setTimeout(() => { - const firstInput = document.querySelector( - '.practice-input-area input' - ) as HTMLInputElement - firstInput?.focus() - }, 100) + restoreFocus() return } @@ -285,18 +288,11 @@ export default function ProcessPracticePage() { setShowAnswerForCell(null) setInputLocked(false) announceToScreenReader('答案已自动隐藏') - - // 恢复焦点 - setTimeout(() => { - const firstInput = document.querySelector( - '.practice-input-area input' - ) as HTMLInputElement - firstInput?.focus() - }, 100) + restoreFocus() }, remainingTime) return () => clearTimeout(timer) - }, [showAnswerForCell]) + }, [showAnswerForCell, restoreFocus]) // 点击格子切换(允许回顾已答对的格子) const handleCellClick = useCallback(