@@ -177,6 +177,37 @@ function MainShell() {
177177 setFocusNoteId ( noteId ) ;
178178 setPage ( "notes" ) ;
179179 } ;
180+
181+ // 批 3 T12(规格 §6.1「⌘K 命令入口用来替代现在手写的 `focus*` 参数跳转」):把这 10 个 `focus*`
182+ // 字段的**跨页跳转入口**收敛成具名函数 —— ⌘K 命令与页内回调从此走**同一实现**(此前同一段
183+ // 「setFocus…+setPage」在 2–4 处各写一遍)。⚠️ 边界(计划 Step 5 明写):**只收敛入口** ——
184+ // 状态机、字段类型、各页消费逻辑一个字节未动(删字段 / 改路由参数是批 5 的视图层重构)。
185+ // 入口映射:⌘K 侧能独立发起的是页面命令(9 个)· 建体系向导 · 检索结果(带 ID 的笔记深链);
186+ // 其余带 ID 的深链(会话/体系/复习组/工作台/对话)仍由**页内入口**发起 —— ID 只有页内有。
187+ const goSessions = ( sessionId : number ) => {
188+ setFocusSessionId ( sessionId ) ;
189+ setPage ( "sessions" ) ;
190+ } ;
191+ // REQ-260:带词高亮打开(引用卡片与 ⌘K 检索结果的**共同实现**)——与上面的普通打开是两条路:
192+ // 普通打开必须清带词态(审查 H1),带词打开双设 focusNoteSearch(key 递增让同笔记可重触发)
193+ const openNoteHighlight = ( noteId : number , search : string ) => {
194+ setFocusNoteId ( noteId ) ;
195+ setFocusNoteSearch ( { noteId, search, key : Date . now ( ) } ) ;
196+ setPage ( "notes" ) ;
197+ } ;
198+ const goSystem = ( systemId : number ) => { setFocusSystemId ( systemId ) ; setPage ( "knowledge" ) ; } ;
199+ const goGroup = ( groupId : number ) => { setFocusGroupId ( groupId ) ; setPage ( "notes" ) ; } ;
200+ // 组预选允许 null(NotesPage 的「复习全部」路径——收敛前那个内联箭头也是这么推出来的)
201+ const goReviewGroup = ( groupId : number | null ) => { setFocusReviewGroupId ( groupId ) ; setPage ( "review" ) ; } ;
202+ const goChatSession = ( chatId : number ) => { setFocusChatId ( chatId ) ; setPage ( "chat" ) ; } ;
203+ const goChatTask = ( taskId : number ) => { setFocusChatTaskId ( taskId ) ; setPage ( "chat" ) ; } ;
204+ const goRefineWorkbench = ( sessionId : number , taskId : number ) => {
205+ setFocusSessionId ( sessionId ) ;
206+ setFocusRefineTaskId ( taskId ) ;
207+ setPage ( "sessions" ) ;
208+ } ;
209+ // 10 个 focus* 字段里**唯一无载荷**的入口(建体系向导不需要 ID)⇒ 它能由 ⌘K 独立发起
210+ const openSystemWizard = ( ) => { setCreateSystemSignal ( ( s ) => s + 1 ) ; setPage ( "knowledge" ) ; } ;
180211 // v0.13.7:跨页直达目标体系(组行徽标/结算简报 → 体系页自动选中)
181212 const [ focusSystemId , setFocusSystemId ] = useState < number | null > ( null ) ;
182213 // TD-2026-09-05-A:外部请求打开建体系向导(笔记页空体系引导 → 体系页向导)
@@ -361,12 +392,7 @@ function MainShell() {
361392 < main style = { { flex : 1 , minHeight : 0 , display : "flex" } } >
362393 < PageSlot show = { page === "classroom" } mounted = { mountedPages . has ( "classroom" ) } >
363394 { /* 2026-08 A4:融合完成直达会话(onOpenSessions 跳转 + focusSessionId 定位) */ }
364- < ClassroomPage
365- onOpenSessions = { ( id ) => {
366- setFocusSessionId ( id ) ;
367- setPage ( "sessions" ) ;
368- } }
369- />
395+ < ClassroomPage onOpenSessions = { goSessions } />
370396 </ PageSlot >
371397 < PageSlot show = { page === "sessions" } mounted = { mountedPages . has ( "sessions" ) } >
372398 { /* v0.7.1:active 驱动列表刷新(display:none 挂载不刷新根治)+ 查看笔记跨页直达 */ }
@@ -375,10 +401,8 @@ function MainShell() {
375401 // v0.16.1:工作台深链 / 精修启动 → AI 对话页(focus 消费后即清空)
376402 focusRefineTaskId = { focusRefineTaskId }
377403 onFocusRefineTaskConsumed = { ( ) => setFocusRefineTaskId ( null ) }
378- onRefineTaskStarted = { ( _sessionId , taskId ) => {
379- setFocusChatTaskId ( taskId ) ;
380- setPage ( "chat" ) ;
381- } }
404+ // 精修启动 → AI 对话页(T12:入口收敛为 goChatTask;sessionId 仍被忽略——与收敛前逐字一致)
405+ onRefineTaskStarted = { ( _sessionId , taskId ) => goChatTask ( taskId ) }
382406 active = { page === "sessions" }
383407 onOpenNote = { ( id ) => openNotePlain ( id ) }
384408 />
@@ -389,23 +413,11 @@ function MainShell() {
389413 focusNoteId = { focusNoteId }
390414 focusNoteSearch = { focusNoteSearch }
391415 focusGroupId = { focusGroupId }
392- // v0.20.10(批 5):ⓘ「复习本组」深链 → 复习页组预选
393- onOpenReview = { ( groupId ) => {
394- setFocusReviewGroupId ( groupId ) ;
395- setPage ( "review" ) ;
396- } }
397- onOpenSystem = { ( id ) => {
398- setFocusSystemId ( id ) ;
399- setPage ( "knowledge" ) ;
400- } }
401- onCreateSystem = { ( ) => {
402- setCreateSystemSignal ( ( s ) => s + 1 ) ;
403- setPage ( "knowledge" ) ;
404- } }
405- onOpenSessions = { ( id ) => {
406- setFocusSessionId ( id ) ;
407- setPage ( "sessions" ) ;
408- } }
416+ // v0.20.10(批 5):ⓘ「复习本组」深链 → 复习页组预选(T12:入口收敛为 goReviewGroup)
417+ onOpenReview = { goReviewGroup }
418+ onOpenSystem = { goSystem }
419+ onCreateSystem = { openSystemWizard }
420+ onOpenSessions = { goSessions }
409421 />
410422 </ PageSlot >
411423 { /* v0.20.5:行动域页(保活挂载 + active 门控切回重载——TD-004 模式) */ }
@@ -428,24 +440,17 @@ function MainShell() {
428440 AI 任务本页无感知;SessionsPage/ActionPage 同款 active 语义) */ }
429441 < ChatPage
430442 active = { page === "chat" }
431- onOpenSessions = { ( id ) => { setFocusSessionId ( id ) ; setPage ( "sessions" ) ; } }
443+ onOpenSessions = { goSessions }
432444 onOpenNote = { ( id ) => { setFocusNoteId ( id ) ; setPage ( "notes" ) ; } }
433- onOpenNoteHighlight = { ( noteId , search ) => {
434- setFocusNoteId ( noteId ) ;
435- setFocusNoteSearch ( { noteId, search, key : Date . now ( ) } ) ;
436- setPage ( "notes" ) ;
437- } } onOpenSettings = { ( ) => setPage ( "settings" ) }
445+ onOpenNoteHighlight = { openNoteHighlight }
446+ onOpenSettings = { ( ) => setPage ( "settings" ) }
438447 // v0.16.1:任务进入对话页(会话页精修启动自动跳转);任务视图 → 工作台深链
439448 focusTaskId = { focusChatTaskId }
440449 onFocusTaskConsumed = { ( ) => setFocusChatTaskId ( null ) }
441450 // REQ-274:对话面板「在对话页继续」直达会话(消费后清空)
442451 focusChatId = { focusChatId }
443452 onFocusChatConsumed = { ( ) => setFocusChatId ( null ) }
444- onOpenRefineWorkbench = { ( sessionId , taskId ) => {
445- setFocusSessionId ( sessionId ) ;
446- setFocusRefineTaskId ( taskId ) ;
447- setPage ( "sessions" ) ;
448- } }
453+ onOpenRefineWorkbench = { goRefineWorkbench }
449454 />
450455 </ PageSlot >
451456 < PageSlot show = { page === "knowledge" } mounted = { mountedPages . has ( "knowledge" ) } >
@@ -455,7 +460,7 @@ function MainShell() {
455460 focusSystemId = { focusSystemId }
456461 createSystemSignal = { createSystemSignal }
457462 onOpenNote = { ( id ) => { setFocusNoteId ( id ) ; setPage ( "notes" ) ; } }
458- onOpenGroup = { ( id ) => { setFocusGroupId ( id ) ; setPage ( "notes" ) ; } }
463+ onOpenGroup = { goGroup }
459464 />
460465 </ PageSlot >
461466 < PageSlot show = { page === "goals" } mounted = { mountedPages . has ( "goals" ) } >
@@ -504,10 +509,12 @@ function MainShell() {
504509 { aiToast . text }
505510 </ div >
506511 ) }
507- { /* 批 3 T11:⌘K 命令面板(规格 §6.1)。它是**壳级覆盖层**,与 toast 一样挂在导航壳最外层、
512+ { /* 批 3 T11/T12 :⌘K 命令面板(规格 §6.1)。它是**壳级覆盖层**,与 toast 一样挂在导航壳最外层、
508513 不是任何页面的子节点(切页不重挂、也不参与页面布局)。
509- `onPick` 只收口两种动作 —— 页面级 `setPage`(key 仍经 `isPageKey` 运行期校验,
510- 回调实参不被信任)与打开对话面板;`focus*` 深链状态机原样不动(收敛是 T12)。
514+ `onPick` 收口三类动作(回调实参不被信任):页面级 `setPage`(key 仍经 `isPageKey` 运行期校验)·
515+ 打开对话面板 · **T12 新增的两类** —— 检索结果(`kind:"hit"`:带载荷的深链入口,落到
516+ `focusNoteId` + `focusNoteSearch`,与引用卡片共用 `openNoteHighlight`)与无载荷的 `focus*`
517+ 入口(`kind:"create-system"`)。`focus*` 状态机本身原样不动(收敛的只是入口,见 T12 报告)。
511518 Esc / 点遮罩 / 焦点都在组件内部(自足实现,见 `shell/CommandPalette.tsx` 文件头)。 */ }
512519 < CommandPalette
513520 open = { paletteOpen }
@@ -517,6 +524,14 @@ function MainShell() {
517524 setDockOpen ( true ) ;
518525 return ;
519526 }
527+ if ( pick . kind === "hit" ) {
528+ openNoteHighlight ( pick . jump . noteId , pick . jump . search ) ;
529+ return ;
530+ }
531+ if ( pick . kind === "create-system" ) {
532+ openSystemWizard ( ) ;
533+ return ;
534+ }
520535 if ( isPageKey ( pick . key ) ) setPage ( pick . key ) ;
521536 } }
522537 />
@@ -529,15 +544,11 @@ function MainShell() {
529544 < AiConversationDock
530545 open = { dockOpen }
531546 onClose = { ( ) => setDockOpen ( false ) }
532- onOpenChat = { ( chatId ) => { setFocusChatId ( chatId ) ; setPage ( "chat" ) ; } }
533- onOpenTaskInChat = { ( taskId ) => { setFocusChatTaskId ( taskId ) ; setPage ( "chat" ) ; } }
534- onOpenSessions = { ( id ) => { setFocusSessionId ( id ) ; setPage ( "sessions" ) ; } }
535- onOpenNote = { ( id ) => openNotePlain ( id ) }
536- onOpenRefineWorkbench = { ( sessionId , taskId ) => {
537- setFocusSessionId ( sessionId ) ;
538- setFocusRefineTaskId ( taskId ) ;
539- setPage ( "sessions" ) ;
540- } }
547+ onOpenChat = { goChatSession }
548+ onOpenTaskInChat = { goChatTask }
549+ onOpenSessions = { goSessions }
550+ onOpenNote = { openNotePlain }
551+ onOpenRefineWorkbench = { goRefineWorkbench }
541552 />
542553 </ Suspense >
543554 ) }
0 commit comments