feat(ux): B0 注入透明读端点 + F1 写作页右栏真面板

兑现「看到的=写章用的」信任牌(不变量 #6),替换写作页右栏过时假占位
(「M1 暂未接 / M2 开放」)。

后端:
- GET /projects/{id}/chapters/{no}/injection → InjectionResponse(selected
  实体 + 入选理由 + recent_n);调既有 assemble() 回放确定性 SelectionTrace,
  无 LLM / 无 commit / 无 DDL;项目不存在→404,无大纲→selected:[]。
- 新 schemas/injection.py;tests/test_injection.py(3 测)。

前端:
- gen:api 纳入端点;纯逻辑 lib/workbench/injection.ts(理由/类型→中文徽标
  + 4 vitest)+ useInjection 读 hook。
- ChapterAssistant 改 client 组件:列出选中实体 + 理由徽标 + 空/载/错三态,
  四审段指向审稿页;Workbench 传 projectId/chapterNo。

门禁:后端 ruff/format/mypy 159/alembic 无漂移/pytest 454;
前端 lint/typecheck/vitest 167/build。

B0 可控版(PUT override pin/排除/recent_n + selection 加参 + draft 同读
override + 持久化)+ F1 可控控件待后续。
This commit is contained in:
Yaojia Wang
2026-06-20 10:57:03 +02:00
parent 7e63534366
commit 8058cfb11a
12 changed files with 513 additions and 10 deletions

View File

@@ -0,0 +1,50 @@
"use client";
import { useEffect, useState } from "react";
import { api } from "@/lib/api/client";
import type { InjectionResponse } from "./injection";
export interface UseInjection {
data: InjectionResponse | null;
loading: boolean;
error: string | null;
}
// 本章注入透明B0 读端点):挂载时拉一次确定性 SelectionTrace。
// 只读、无 LLM、无 commit——展示「选了谁/为什么」。失败给可读文案不抛。
export function useInjection(
projectId: string,
chapterNo: number,
): UseInjection {
const [data, setData] = useState<InjectionResponse | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
let cancelled = false;
setLoading(true);
setError(null);
void (async () => {
const { data: body, error: err } = await api.GET(
"/projects/{project_id}/chapters/{chapter_no}/injection",
{ params: { path: { project_id: projectId, chapter_no: chapterNo } } },
);
if (cancelled) return;
if (err || !body) {
setError("注入信息暂不可用");
setData(null);
} else {
setData(body);
}
setLoading(false);
})();
return () => {
cancelled = true;
};
}, [projectId, chapterNo]);
return { data, loading, error };
}