feat(web): organize records page parity with MP history (HIS-1)
Poster, source -> target, size, downloader; type/time filters; status counts; group by work; row menu; batch select, delete and reorganize; delete confirm dialog with dry-run summary; detail delete and download info. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
51e82f1cd9
commit
03c651085f
8 files changed
+898
-110
No files matched your search
@@ -16,6 +16,7 @@ import {
|
||||
useIdentify,
|
||||
useOrganizeFiles,
|
||||
useRecordSources,
|
||||
useRecordSourcesMany,
|
||||
} from "~/api/files.ts";
|
||||
import { useRecord } from "~/api/records.ts";
|
||||
import { useSettings } from "~/api/settings.ts";
|
||||
@@ -64,7 +65,9 @@ export type OrganizeSource =
|
||||
/** 做种中且 H&R 未满足:只能复制 */
|
||||
hnrBlocked?: boolean;
|
||||
}
|
||||
| { kind: "record"; recordId: string };
|
||||
| { kind: "record"; recordId: string }
|
||||
/** HIS-1 批量重新整理:几条记录的源文件一起进向导;preset = 这几条同属一个作品时预选 */
|
||||
| { kind: "records"; recordIds: string[]; preset?: WizardEntity | null };
|
||||
|
||||
const STEPS = ["文件与作品", "选项", "预览并执行"] as const;
|
||||
|
||||
@@ -90,6 +93,7 @@ function useResolvedSource(source: OrganizeSource, roots: FileRoot[] | undefined
|
||||
});
|
||||
const recSrc = useRecordSources(isRec ? source.recordId : null);
|
||||
const rec = useRecord(isRec ? source.recordId : undefined);
|
||||
const many = useRecordSourcesMany(source.kind === "records" ? source.recordIds : []);
|
||||
return useMemo((): Resolved => {
|
||||
const base = { unresolved: [], preset: null, pending: false, error: null };
|
||||
if (source.kind === "files")
|
||||
@@ -114,6 +118,28 @@ function useResolvedSource(source: OrganizeSource, roots: FileRoot[] | undefined
|
||||
label: `下载任务 · ${source.name}`,
|
||||
};
|
||||
}
|
||||
if (source.kind === "records") {
|
||||
const label = `重新整理 ${source.recordIds.length} 条记录`;
|
||||
if (many.isPending) return { ...base, items: [], hnrPaths: [], label, pending: true };
|
||||
if (many.error) return { ...base, items: [], hnrPaths: [], label, error: many.error };
|
||||
const seen = new Set<string>();
|
||||
const items = (many.data ?? [])
|
||||
.flatMap((r) => r.items)
|
||||
.filter((it) => {
|
||||
const k = `${it.root}\u0000${it.path}`;
|
||||
if (seen.has(k)) return false;
|
||||
seen.add(k);
|
||||
return true;
|
||||
});
|
||||
return {
|
||||
...base,
|
||||
items,
|
||||
hnrPaths: [],
|
||||
unresolved: [...new Set((many.data ?? []).flatMap((r) => r.unresolved))],
|
||||
preset: source.preset ?? null,
|
||||
label,
|
||||
};
|
||||
}
|
||||
if (recSrc.isPending) return { ...base, items: [], hnrPaths: [], label: "整理记录", pending: true };
|
||||
if (recSrc.error) return { ...base, items: [], hnrPaths: [], label: "整理记录", error: recSrc.error };
|
||||
const m = rec.data?.media;
|
||||
@@ -128,7 +154,19 @@ function useResolvedSource(source: OrganizeSource, roots: FileRoot[] | undefined
|
||||
: null,
|
||||
label: `重新整理 · ${m ? entityLabel(m) : "整理记录"}`,
|
||||
};
|
||||
}, [source, roots, maps.isLoading, maps.data, recSrc.isPending, recSrc.error, recSrc.data, rec.data]);
|
||||
}, [
|
||||
source,
|
||||
roots,
|
||||
maps.isLoading,
|
||||
maps.data,
|
||||
recSrc.isPending,
|
||||
recSrc.error,
|
||||
recSrc.data,
|
||||
rec.data,
|
||||
many.isPending,
|
||||
many.error,
|
||||
many.data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user