Skip to content

Commit 6b8f365

Browse files
committed
feat(kb): 空体系引导跳建体系向导链路(TD-2026-09-05-A)
1 parent b5d0ec9 commit 6b8f365

5 files changed

Lines changed: 46 additions & 7 deletions

File tree

‎app/src/App.tsx‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ function App() {
8080
};
8181
// v0.13.7:跨页直达目标体系(组行徽标/结算简报 → 体系页自动选中)
8282
const [focusSystemId, setFocusSystemId] = useState<number | null>(null);
83+
// TD-2026-09-05-A:外部请求打开建体系向导(笔记页空体系引导 → 体系页向导)
84+
const [createSystemSignal, setCreateSystemSignal] = useState(0);
8385
// v0.14 C2:图谱组节点 → 笔记页过滤该组(同 focusNoteId 模式)
8486
const [focusGroupId, setFocusGroupId] = useState<number | null>(null);
8587
// v0.16.1:工作台深链(对话页任务视图 → 会话页自动展开精修工作台)与
@@ -343,6 +345,10 @@ function App() {
343345
setFocusSystemId(id);
344346
setPage("knowledge");
345347
}}
348+
onCreateSystem={() => {
349+
setCreateSystemSignal((s) => s + 1);
350+
setPage("knowledge");
351+
}}
346352
onOpenSessions={(id) => {
347353
setFocusSessionId(id);
348354
setPage("sessions");
@@ -377,6 +383,7 @@ function App() {
377383
v0.13.7:focusSystemId 跨页直达(组行徽标/结算简报 → 自动选中体系) */}
378384
<KnowledgePage
379385
focusSystemId={focusSystemId}
386+
createSystemSignal={createSystemSignal}
380387
onOpenNote={(id) => { setFocusNoteId(id); setPage("notes"); }}
381388
onOpenGroup={(id) => { setFocusGroupId(id); setPage("notes"); }}
382389
/>

‎app/src/components/NoteLinkToSystem.test.tsx‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,19 @@ describe("NoteLinkToSystem v0.13.7 基础(REQ-286 列表选中语义)", () =
8888
});
8989
});
9090

91-
it("无体系时提示先创建体系(不显示确认按钮)", async () => {
91+
it("无体系时提示先创建体系(不显示确认按钮);引导按钮跳体系向导(TD-2026-09-05-A)", async () => {
9292
invokeMock.mockImplementation(async (cmd: string) => {
9393
if (cmd === "list_knowledge_systems") return [];
9494
if (cmd === "list_links_by_target") return [];
9595
throw new Error(`unexpected: ${cmd}`);
9696
});
97-
render(<NoteLinkToSystem noteId={7} onChanged={vi.fn()} />);
97+
const onGoto = vi.fn();
98+
render(<NoteLinkToSystem noteId={7} onChanged={vi.fn()} onGotoKnowledgeSystem={onGoto} />);
9899
fireEvent.click(await screen.findByTestId("note-link-open"));
99100
expect(await screen.findByTestId("note-link-empty")).toBeTruthy();
100101
expect(screen.queryByTestId("note-link-confirm")).toBeNull();
102+
fireEvent.click(screen.getByTestId("note-link-goto-system"));
103+
expect(onGoto).toHaveBeenCalledTimes(1);
101104
});
102105
});
103106

‎app/src/components/NoteLinkToSystem.tsx‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ interface Props {
3232
noteId: number;
3333
/** 挂接/取消后刷新回调(NotesPage 重载引用列表) */
3434
onChanged: () => void;
35+
/** TD-2026-09-05-A:空体系时引导跳体系页并打开建体系向导(App 级通道) */
36+
onGotoKnowledgeSystem?: () => void;
3537
}
3638

3739
/** 问题节点树 → 缩进行(父链循环守卫防脏数据死循环;深度上限 30) */
@@ -69,7 +71,7 @@ function flattenNodeRows(nodes: KnowledgeNode[]): LinkRow[] {
6971
return rows;
7072
}
7173

72-
export default function NoteLinkToSystem({ noteId, onChanged }: Props) {
74+
export default function NoteLinkToSystem({ noteId, onChanged, onGotoKnowledgeSystem }: Props) {
7375
const [open, setOpen] = useState(false);
7476
const [systems, setSystems] = useState<KnowledgeSystem[]>([]);
7577
const [nodes, setNodes] = useState<KnowledgeNode[]>([]);
@@ -252,7 +254,19 @@ export default function NoteLinkToSystem({ noteId, onChanged }: Props) {
252254
}}
253255
>
254256
{domainSystems.length === 0 ? (
255-
<div data-testid="note-link-empty" style={{ fontSize: 12, color: "#9ca3af" }}>暂无体系——请先到「🧠 体系」页创建。</div>
257+
<div data-testid="note-link-empty" style={{ fontSize: 12, color: "#9ca3af", display: "flex", flexDirection: "column", gap: 6, alignItems: "flex-start" }}>
258+
<span>暂无体系——笔记无法挂接。</span>
259+
{/* TD-2026-09-05-A:引导按钮(跳体系页并打开建体系向导) */}
260+
{onGotoKnowledgeSystem && (
261+
<button
262+
data-testid="note-link-goto-system"
263+
onClick={onGotoKnowledgeSystem}
264+
style={{ fontSize: 12, padding: "4px 10px", borderRadius: 6, border: "1px solid #0f766e", background: "#f0fdfa", color: "#0f766e", cursor: "pointer" }}
265+
>
266+
➕ 去体系页创建(向导)
267+
</button>
268+
)}
269+
</div>
256270
) : (
257271
<>
258272
<select

‎app/src/pages/KnowledgePage.tsx‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@ interface Props {
5151
onOpenNote?: (noteId: number) => void;
5252
/** 图谱双击组节点 → 笔记页过滤该组 */
5353
onOpenGroup?: (groupId: number) => void;
54+
/** TD-2026-09-05-A:外部请求打开建体系向导(递增信号——挂起页常驻时仍触发) */
55+
createSystemSignal?: number;
5456
}
5557

56-
export default function KnowledgePage({ focusSystemId, onOpenNote, onOpenGroup }: Props) {
58+
export default function KnowledgePage({ focusSystemId, onOpenNote, onOpenGroup, createSystemSignal }: Props) {
5759
// v0.15:左列可拖拽/记忆/窄窗折叠(默认 260=历史值);详情面板宽度由父层持有
5860
const leftCol = useColumnLayout("knowledge-left", { default: 260, min: 200, max: 360, autoFoldBelow: 860 });
5961
const detailCol = useColumnLayout("knowledge-detail", { default: 320, min: 260, max: 420 });
@@ -131,6 +133,12 @@ export default function KnowledgePage({ focusSystemId, onOpenNote, onOpenGroup }
131133
// 保留挂载下后台仅数次轻查询 + hook 内防抖合并风暴)
132134
useDbRefresh(["knowledge"], reloadAll);
133135

136+
// TD-2026-09-05-A:外部(笔记页空体系引导)请求打开建体系向导——递增信号
137+
// 语义:挂起页(display:none 常驻)重复请求仍逐次触发
138+
useEffect(() => {
139+
if (createSystemSignal && createSystemSignal > 0) setWizardOpen(true);
140+
}, [createSystemSignal]);
141+
134142
// v0.13.7:跨页直达目标体系(与 NotesPage focusNoteId 同模式——仅 focusSystemId
135143
// 变化时跟随;空态无体系时该值无意义,由既有选中/创建逻辑接管)
136144
useEffect(() => {

‎app/src/pages/NotesPage.tsx‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@ interface Props {
5050
onOpenSessions?: (sessionId: number) => void;
5151
/** 打开体系页并选中体系(v0.13.7 触点① 组行徽标) */
5252
onOpenSystem?: (systemId: number) => void;
53+
/** TD-2026-09-05-A:空体系引导——跳体系页并打开建体系向导 */
54+
onCreateSystem?: () => void;
5355
}
5456

5557
/** 中部视图:notes=笔记列表(组过滤/搜索/标签);inbox=收件箱碎片列表 */
5658
type MiddleView = "notes" | "inbox";
5759

58-
export default function NotesPage({ focusNoteId, focusNoteSearch, focusGroupId, onOpenSessions, onOpenSystem }: Props) {
60+
export default function NotesPage({ focusNoteId, focusNoteSearch, focusGroupId, onOpenSessions, onOpenSystem, onCreateSystem }: Props) {
5961
const [notes, setNotes] = useState<Note[]>([]);
6062
const [keyword, setKeyword] = useState("");
6163
const [tagFilter, setTagFilter] = useState<string | null>(null);
@@ -531,7 +533,12 @@ export default function NotesPage({ focusNoteId, focusNoteSearch, focusGroupId,
531533
onChanged={() => void handleNoteChanged()}
532534
/>
533535
{/* v0.13.7 触点②:标题栏「挂到体系」入口;key=note.id 切笔记重置内部态 */}
534-
<NoteLinkToSystem key={`link-${selected.id}`} noteId={selected.id} onChanged={() => void handleNoteChanged()} />
536+
<NoteLinkToSystem
537+
key={`link-${selected.id}`}
538+
noteId={selected.id}
539+
onChanged={() => void handleNoteChanged()}
540+
onGotoKnowledgeSystem={onCreateSystem}
541+
/>
535542
{/* v0.17.0:编辑态 AI 能力统一入口(阅读态点击直接进入编辑态) */}
536543
<button
537544
data-testid="note-ai-entry"

0 commit comments

Comments
 (0)