feat(review): 审稿选章可用——列章端点 + 选章下拉全章可见 + 默认最近章

- 后端新增 GET /projects/{id}/chapters(列真实存在的章 + has_draft/accepted/reviewed_at),TDD 10 测
- gen:api 重生成 TS 客户端(ChapterListItem)
- 选章下拉去掉 hidden(手机/窄屏也可切章);选项以真实章为准 + 大纲结构,
  无草稿章置灰(仅当前章例外),覆盖『写过但不在大纲』的章
- 无 ?chapter 时默认落到最近一个有草稿的章,而非硬编码第 1 章
This commit is contained in:
Yaojia Wang
2026-07-12 17:52:40 +02:00
parent 5f28491ad6
commit 9aa0cddeaf
12 changed files with 652 additions and 18 deletions

View File

@@ -93,6 +93,29 @@ export interface paths {
patch?: never;
trace?: never;
};
"/projects/{project_id}/chapters": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* List Chapters
* @description 列出该项目「真实存在的章」+ 可审/已审标记(审稿页选章下拉枚举)。
*
* 来源 `chapters`(草稿/accepted+ `chapter_reviews`,按章号去重升序。只读、不触 LLM。
* 项目不存在 → 404同其它端点owner 走 project_repo stub 校验)。
*/
get: operations["list_chapters_projects__project_id__chapters_get"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/projects/{project_id}/chapters/{chapter_no}/injection": {
parameters: {
query?: never;
@@ -1123,6 +1146,33 @@ export interface components {
*/
count: number;
};
/**
* ChapterListItem
* @description GET /projects/:id/chapters 单项:一个真实存在的章 + 可审/已审标记snake_case
*
* 数据来源为 `chapters`(草稿/accepted 版本)与 `chapter_reviews`,按章号去重升序。
* `has_draft`=有非空草稿正文(可审);`accepted`=已有 accepted 版本;
* `reviewed_at`=最近一次审稿时间(无则 null
*/
ChapterListItem: {
/** Chapter No */
chapter_no: number;
/**
* Has Draft
* @description 是否有非空草稿正文(可审)
*/
has_draft: boolean;
/**
* Accepted
* @description 是否已验收(存在 accepted 版本)
*/
accepted: boolean;
/**
* Reviewed At
* @description 最近一次审稿时间;未审为 null
*/
reviewed_at?: string | null;
};
/**
* CharacterCardView
* @description 单张角色卡(贴 ww_agents.CharacterCard预览 + 入库请求共用形)。
@@ -2857,6 +2907,46 @@ export interface operations {
};
};
};
list_chapters_projects__project_id__chapters_get: {
parameters: {
query?: never;
header?: never;
path: {
project_id: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ChapterListItem"][];
};
};
/** @description 资源不存在 */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ErrorEnvelope"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
get_injection_projects__project_id__chapters__chapter_no__injection_get: {
parameters: {
query?: never;

View File

@@ -1,5 +1,6 @@
import { serverApiBase } from "./config";
import type {
ChapterListItem,
CharacterListResponse,
DraftView,
ForeshadowBoardResponse,
@@ -150,6 +151,18 @@ export async function fetchOutline(
}
}
// 列章GET .../chapters裸数组审稿选章枚举真实存在的章 + 可审/已审标记。
// 任何错误降级为空列表(进页不阻塞,回退到大纲/当前章导航)。
export async function fetchChapters(
projectId: string,
): Promise<ChapterListItem[]> {
try {
return await getJson<ChapterListItem[]>(`/projects/${projectId}/chapters`);
} catch {
return [];
}
}
// 提示词/模板库列表GET /templates全局只读裸数组
// 任何错误(含后端未上线)降级为空列表,模板页照常渲染(进页不阻塞)。
export async function fetchTemplates(): Promise<TemplateResponse[]> {

View File

@@ -33,6 +33,8 @@ export type ReviewHistoryResponse =
export type ConflictDecision = components["schemas"]["ConflictDecision"];
export type AcceptRequest = components["schemas"]["AcceptRequest"];
export type AcceptResponse = components["schemas"]["AcceptResponse"];
// 列章GET .../chapters裸数组审稿选章枚举真实存在的章 + 可审/已审标记。
export type ChapterListItem = components["schemas"]["ChapterListItem"];
// Scope B 多章工作流链(发起 / 续跑;进度走 GET /jobs/{id} 轮询)。
export type ChainRunRequest = components["schemas"]["ChainRunRequest"];