Files
UHD_Media_Tool/apps/web/app/components/status/attention-cards.tsx
T
rootandClaude Opus 5.5 fa76d7563c feat(控制台): 去掉待处理中心,问题回到发生处
- 侧栏与命令面板没有「待处理」;/console/inbox?kind= 按问题类型跳到整理记录「需要处理」、下载面板、运行状态或订阅
- 整理记录加「需要处理」筛选,行内写原因与推荐动作(指定作品 / 重新整理 / 让智能体识别 / 替换·保留两者·跳过 / 忽略),
  详情页同样可处理;处理按钮从原待处理页抽成 components/decisions/decision-actions.tsx 复用
- 铃铛只放等你批准的智能体操作与系统健康;首页「要我处理」与运行状态「需要关注」放汇总计数,运行状态加智能体用量
- 设置 → 智能体:预算卡改为「用量与限制」(只剩单次工具调用与时长,附花费统计),自动调查卡加「整理识别不到作品时叫智能体识别」
- 集数待确认的原因显示在作品页集数映射(可确认建议规则 / 智能体建议)与订阅详情;未识别资源在媒体库「未识别」里直接选候选或指定
- 下载、站点、任务里指向待处理的链接改到对应页面

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
2026-10-06 16:47:25 +08:00

130 lines
4.6 KiB
TypeScript

import type { AgentSpendBucket, AgentSpendKind } from "@umt/contracts";
import { BellRing, Bot } from "lucide-react";
import { Link } from "react-router";
import { useAgentSpend, useAttention } from "~/api/attention.ts";
import { ErrorState, LoadingState } from "~/components/console/empty-state.tsx";
import { settingsPath } from "~/components/console/nav.ts";
import { AttentionList, attentionRows } from "~/components/dashboard/attention-summary.tsx";
import { formatRelative } from "~/lib/labels.ts";
import { humanizeReason } from "~/lib/reasons.ts";
// 运行状态页(2026-10-06):「需要关注」汇总(整理需要处理、等你批准、系统健康,系统健康逐条列出、恢复后自动消失)
// 与智能体用量(今天 / 最近 7 天按会话类型;不设上限,只展示)。
function Slab({
id,
title,
icon: Icon,
children,
}: {
id?: string;
title: string;
icon: typeof Bot;
children: React.ReactNode;
}) {
return (
<section id={id} className="pg-slab min-w-0 scroll-mt-20 rounded-xl p-5">
<div className="mb-3 flex items-center gap-2">
<Icon className="h-4 w-4 text-muted-foreground" />
<h2 className="text-body font-semibold text-foreground">{title}</h2>
</div>
{children}
</section>
);
}
export function AttentionCard() {
const q = useAttention();
const rows = attentionRows(q.data);
const health = q.data?.health.items ?? [];
return (
<Slab id="attention" title="需要关注" icon={BellRing}>
{q.isPending ? (
<LoadingState rows={2} />
) : q.isError ? (
<ErrorState plain error={q.error} onRetry={() => q.refetch()} />
) : rows.length === 0 ? (
<p className="text-caption text-muted-foreground">
没有需要处理的整理记录,也没有等你批准的操作;站点、下载器和下载目录都正常。
</p>
) : (
<>
<AttentionList rows={rows} />
{health.length ? (
<ul className="mt-3 space-y-2 border-t border-border/60 pt-3">
{health.map((d) => (
<li key={d.id} className="min-w-0 text-caption">
<p className="font-medium break-words text-foreground">{d.title}</p>
{d.summary ? (
<p className="break-words text-meta text-muted-foreground">{humanizeReason(d.summary)}</p>
) : null}
<p className="text-meta text-muted-foreground">{formatRelative(d.createdAt)}起,恢复后自动消失</p>
</li>
))}
</ul>
) : null}
</>
)}
</Slab>
);
}
const KIND_LABEL: Record<AgentSpendKind, string> = {
chat: "对话",
patrol: "巡检",
investigate: "后台调查",
organize_identify: "整理识别",
subagent: "子会话",
};
const usd = (n: number) => `$${n < 0.01 && n > 0 ? n.toFixed(4) : n.toFixed(2)}`;
function SpendBlock({ label, b }: { label: string; b: AgentSpendBucket }) {
return (
<div className="min-w-0">
<p className="text-meta text-muted-foreground">{label}</p>
<p className="text-title-sm font-semibold text-foreground tabular-nums">
{usd(b.costUsd)}
<span className="ml-1.5 text-caption font-normal text-muted-foreground">{b.runs} 次</span>
</p>
{b.byKind.length ? (
<ul className="mt-1 space-y-0.5 text-meta text-muted-foreground tabular-nums">
{b.byKind.map((k) => (
<li key={k.kind}>
{KIND_LABEL[k.kind]} {k.runs} 次 · {usd(k.costUsd)}
</li>
))}
</ul>
) : null}
</div>
);
}
/** 智能体用量(设置页「用量与限制」也用) */
export function AgentSpendSummary() {
const q = useAgentSpend();
if (q.isPending) return <LoadingState rows={2} />;
if (q.isError) return <ErrorState plain error={q.error} onRetry={() => q.refetch()} />;
if (!q.data.last7d.runs) return <p className="text-caption text-muted-foreground">最近 7 天智能体没有运行。</p>;
return (
<div className="grid gap-4 sm:grid-cols-2">
<SpendBlock label="今天" b={q.data.today} />
<SpendBlock label="最近 7 天" b={q.data.last7d} />
</div>
);
}
export function AgentSpendCard() {
return (
<Slab title="智能体用量" icon={Bot}>
<AgentSpendSummary />
<p className="mt-3 text-meta text-muted-foreground">
不设次数和花费上限,只限制单次的工具调用次数与时长。
<Link to={settingsPath("agent", "budget")} className="ml-1 underline-offset-4 hover:underline">
调整
</Link>
</p>
</Slab>
);
}