feat(server,contracts,web): dashboard library counts and engine runs triggeredBy/multi-status filters

- GET /dashboard: automation.library {entities, movies, series, seasons,
  episodes, assets} and automation.slotSatisfiedRate; home media overview
  shows the counts instead of placeholders.
- GET /engine/runs: `status` accepts comma-separated values; new
  `triggeredBy` filter (comma-separated) evaluated server-side by scanning
  batches and paging with the last inspected row's cursor (scan cap 2000).
- Task stream: source filter and the "active" tab (running,pending) are now
  one paginated server query.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 16:49:11 +08:00
1 parent 615917bb45
commit 363f85b1a1
13 files changed
+165 -250

No files matched your search

+6 -7
View File
@@ -280,19 +280,18 @@ function NeedsMe({ n }: { n: Dashboard["needsAttention"] }) {
);
}
// ─── 媒体概览:版本目标满足率 + 今日产出(作品/季/资产计数待 /dashboard 提供) ───
// ─── 媒体概览:作品/季/资产计数 + 版本目标满足率 + 今日产出 ───
function MediaOverview({ a }: { a: Dashboard["automation"] }) {
const c = a.slotCounts;
const total = Object.values(c).reduce((x, y) => x + y, 0);
const rate = total ? Math.round((c.satisfied / total) * 100) : null;
const lib = (a as { library?: { entities?: number; seasons?: number; assets?: number } }).library;
const num = (v: number | undefined) => (v === undefined ? "—" : v);
const rate = a.slotSatisfiedRate === null ? null : Math.round(a.slotSatisfiedRate * 100);
const lib = a.library;
return (
<Section title="媒体概览" icon={LibraryIcon} to={consolePath("library")}>
<div className="grid grid-cols-3 gap-2">
<StatTile plain label="作品" value={num(lib?.entities)} />
<StatTile plain label="季" value={num(lib?.seasons)} />
<StatTile plain label="资产" value={num(lib?.assets)} />
<StatTile plain label="作品" value={lib.entities} hint={`电影 ${lib.movies} · 剧集 ${lib.series}`} />
<StatTile plain label="季" value={lib.seasons} hint={`${lib.episodes} 集`} />
<StatTile plain label="资产" value={lib.assets} hint="已入库视频" />
</div>
<div className="mt-3">
<div className="flex items-baseline justify-between text-sm">