From 713c11b382629f4392099b381accc9a6092585b3 Mon Sep 17 00:00:00 2001 From: ittoview Date: Sun, 1 Mar 2026 16:57:16 +0000 Subject: [PATCH] =?UTF-8?q?fix(=E7=BB=83=E4=B9=A0):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=AD=94=E6=A1=88=E9=9A=90=E8=97=8F=E5=90=8E=E7=84=A6=E7=82=B9?= =?UTF-8?q?=E6=81=A2=E5=A4=8D=E9=80=BB=E8=BE=91=20feat(=E7=9F=A5=E8=AF=86?= =?UTF-8?q?=E9=A2=86=E5=9F=9F):=20=E6=B7=BB=E5=8A=A0=E6=95=8F=E6=8D=B7?= =?UTF-8?q?=E8=A3=81=E5=89=AA=E5=9B=A0=E7=B4=A0=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复答案隐藏后聚焦到第一个空输入框而非第一个输入框 - 添加 restoreFocus 辅助函数统一处理焦点恢复 - 更新知识领域裁剪因素数据 via [HAPI](https://hapi.run) Co-Authored-By: HAPI --- src/data/knowledge-areas.json | 24 +++++++++++++++- src/pages/ProcessPracticePage.tsx | 48 ++++++++++++++----------------- 2 files changed, 45 insertions(+), 27 deletions(-) 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(