- 侧栏与命令面板没有「待处理」;/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
130 lines
4.6 KiB
TypeScript
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>
|
|
);
|
|
}
|