Files
writer-work-flow/apps/web/lib/foreshadow/chapterForeshadow.ts
Yaojia Wang b810a3fa3c feat(foreshadow): 写作台本章伏笔主动提醒(前端)
- 新增 chapterForeshadow 纯分类:按当前章分 可回收/待回收/已逾期(启用闲置的 isWindowApproaching)
- useChapterForeshadow hook(复用 GET /foreshadow,切章仅重分类不重拉)
- 右栏「本章参考」+ ContextDrawer 伏笔页新增「本章伏笔」实时清单,
  分色展示 + 跳看板链接 + 空态;标注『按已验收进度』
2026-07-12 17:53:00 +02:00

52 lines
2.4 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.

// 「本章伏笔」主动提醒的纯分类逻辑(写作台右栏 / 速查抽屉共用)。
// 输入全量伏笔 + 当前章号,用 board 的 isWindowApproaching + status 分三类。
// 纯函数、不可变(返回全新对象,不改动入参);便于 node 环境单测。
import type { ForeshadowView } from "@/lib/api/types";
import { isWindowApproaching, LANE_LABELS, type ForeshadowStatus } from "./board";
// 本章伏笔三分类:
// - recyclable 可回收:本章落在 [from,to] 窗口内OPEN/PARTIAL由 isWindowApproaching 判定)。
// - pending 待回收OPEN/PARTIAL 但尚未进入回收窗口(窗口在后 / 未设窗口)。
// - overdue 已逾期status==OVERDUE后端验收后扫描得出略滞后于当前草稿
// CLOSED已回收与未知 status 不进任何一类——本章无需再提醒。
export interface ChapterForeshadowGroups {
recyclable: ForeshadowView[];
pending: ForeshadowView[];
overdue: ForeshadowView[];
}
// 按当前章号把伏笔分三类。纯函数:用 reduce + 展开返回新对象,不可变。
// 种子每次新建(不复用共享常量),空输入也返回独立的新对象。
export function classifyChapterForeshadow(
items: readonly ForeshadowView[] | undefined,
currentChapter: number,
): ChapterForeshadowGroups {
return (items ?? []).reduce<ChapterForeshadowGroups>(
(groups, item) => {
if (item.status === "OVERDUE") {
return { ...groups, overdue: [...groups.overdue, item] };
}
if (isWindowApproaching(item, currentChapter)) {
return { ...groups, recyclable: [...groups.recyclable, item] };
}
if (item.status === "OPEN" || item.status === "PARTIAL") {
return { ...groups, pending: [...groups.pending, item] };
}
return groups; // CLOSED / 未知 status本章不提醒
},
{ recyclable: [], pending: [], overdue: [] },
);
}
// 三类合计条数(是否有可提醒项,便于空态判断)。
export function chapterForeshadowTotal(groups: ChapterForeshadowGroups): number {
return groups.recyclable.length + groups.pending.length + groups.overdue.length;
}
// 单条伏笔的作者向状态文案(复用看板 LANE_LABELS未知 status 回退原值)。
export function foreshadowStatusLabel(status: string): string {
return LANE_LABELS[status as ForeshadowStatus] ?? status;
}