Files
writer-work-flow/apps/web/lib/workbench/chapter.ts
Yaojia Wang 29265fa0fd feat(web): 审稿改稿闭环——一键采纳/AI改写/正文高亮定位编辑/伏笔确认/草稿自动保存/章节目录
- 冲突「采纳改法」:有补丁瞬时改入终稿并选中;无补丁但可定位则采纳时调 AI(refiner)重写该段套入;定位不到提示手改
- 正文改为行内高亮叠层编辑器(与页面同底色、随内容增高、无滚动条),点冲突卡/锚点整页滚到并选中+闪烁
- 仅对可在正文定位的冲突显示「跳转」/锚点;locate 支持从 where 引号抽原文,杜绝定位失败刷屏
- 伏笔建议卡:新埋一键登记(预填表单)/ 疑似回收一键标记 CLOSED(复用现有端点)
- 审稿页草稿自动保存(防抖 PUT /draft),与「验收本章」解耦,刷新不丢
- 写作路由带章号 ?chapter=N + 验收成功面板/大纲页「写下一章」入口;写作目录从大纲列出全部章节

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:28:29 +02:00

39 lines
1.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 工作台当前章号常量(纯模块,**非** "use client")。
// 必须放在非客户端模块Server Componentwrite/page.tsx要在服务端用它拼 GET draft 的 URL
// 若从客户端组件Workbench.tsx"use client"导入Next 会把它替换成客户端引用代理,
// 服务端使用时变成抛错的函数 → draft URL 变成 `/chapters/function(){…}/draft`422
export const WORKBENCH_CHAPTER_NO = 1;
// 从写作路由的 `?chapter=N` 解析章号:取正整数,非法/缺省/<1 → 默认第 1 章。
// 纯函数(可单测),供 write/page.tsxServer Component解析 searchParams。
export function parseChapterParam(raw: string | string[] | undefined): number {
const value = Array.isArray(raw) ? raw[0] : raw;
if (value === undefined) return WORKBENCH_CHAPTER_NO;
const n = Number.parseInt(value, 10);
return Number.isInteger(n) && n >= 1 ? n : WORKBENCH_CHAPTER_NO;
}
// 目录条目:章号 + 可选短标题(大纲无 title用首个节拍当摘要
export interface ChapterEntry {
no: number;
title?: string;
}
// 合并大纲章节与「当前章」成目录:按章号去重 + 升序;当前章即使超出大纲也必含
// (否则在写大纲外的新章时会从目录里消失,作者迷路)。纯函数(可单测)。
export function buildChapterEntries(
chapters: readonly ChapterEntry[],
currentChapterNo: number,
): ChapterEntry[] {
const byNo = new Map<number, ChapterEntry>();
for (const c of chapters) {
if (Number.isInteger(c.no) && c.no >= 1 && !byNo.has(c.no)) {
byNo.set(c.no, { no: c.no, title: c.title });
}
}
if (!byNo.has(currentChapterNo)) {
byNo.set(currentChapterNo, { no: currentChapterNo });
}
return [...byNo.values()].sort((a, b) => a.no - b.no);
}