feat(organize): 整理记录默认按作品分组,行内显示整理方式标签与分类

学 MP 历史记录页:整理方式改为中性小标签(移动 / 复制 / 硬链接 / 原地入库),标题下显示分类(二级分类,没有时退回作品类型)。
列表缺省按作品分组:一季多集收成一组并缺省折叠,组头显示海报、作品、季集范围(S01E01–E10)、分类、条数与非成功状态;只有一条的作品和未识别记录不画组头。切换后本浏览器记住,URL ?group=entity|none 优先。
DataTable 分组追加可选项 meta / defaultCollapsed / flat(不改既有调用的表现)。

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-06 12:10:02 +08:00
1 parent 67f05895d3
commit e41a5d1f16
4 files changed
+274 -18

No files matched your search

+14 -2
View File
@@ -25,6 +25,12 @@ export type DataGroupBy<T> = {
/** 组顺序,缺省按首次出现 */
order?: (a: string, b: string) => number;
storageKey?: string;
/** 组头右侧的计数位,缺省为行数 */
meta?: (key: string, rows: T[]) => ReactNode;
/** 组缺省折叠(点开的组才记住);缺省展开 */
defaultCollapsed?: boolean;
/** 返回 true 的组不画组头、直接平铺行(如只有一行的组) */
flat?: (key: string, rows: T[]) => boolean;
};
const HIDE: Record<NonNullable<DataColumn<unknown>["hideBelow"]>, string> = {
@@ -189,7 +195,9 @@ export function DataTable<T>({
</thead>
{groups ? (
groups.map((g) => {
const open = !collapsed.has(g.key);
if (groupBy?.flat?.(g.key, g.rows)) return <tbody key={`g:${g.key}`}>{g.rows.map(renderRow)}</tbody>;
// defaultCollapsed 时集合里存的是点开的组
const open = groupBy?.defaultCollapsed ? collapsed.has(g.key) : !collapsed.has(g.key);
return (
<Fragment key={`g:${g.key}`}>
<tbody>
@@ -211,7 +219,11 @@ export function DataTable<T>({
<span className="min-w-0 truncate font-medium text-foreground">
{groupBy?.label ? groupBy.label(g.key, g.rows) : g.key}
</span>
<span className="tabular-nums">{g.rows.length}</span>
{groupBy?.meta ? (
groupBy.meta(g.key, g.rows)
) : (
<span className="tabular-nums">{g.rows.length}</span>
)}
</button>
</th>
</tr>