copy: second-round copy review across console, settings, agent and server messages

- Trim descriptions, empty states, confirm buttons and toasts to facts
- Unify terms per glossary: 待处理/待识别/整理记录/运行记录/凭证/子会话/Agent 上游
- Subscription-login termsNote states facts only (borrowed client identity, ToS/ban risk)
- Shorter, concrete goal templates for built-in Agent checks
- Human-readable nouns instead of table names in instance CRUD errors
- Audit labels for pi_upstream / schedule / automation_grant actions
- Glossary: add 上游、订阅登录、凭证、定时任务、巡检、运行记录、子会话、停止、持续授权

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 13:29:42 +08:00
1 parent c67f6a9682
commit 31a54186c7
58 files changed
+200 -188

No files matched your search

+4 -7
View File
@@ -18,14 +18,11 @@ export default function AgentPage() {
return (
<>
<PageHeader
title="Agent 会话"
description="交代目标,Agent 在授权范围内边执行边汇报;只要方案时,它只调查不执行。"
/>
<PageHeader title="Agent 会话" description="交代目标,Agent 在授权范围内执行并汇报。只要方案时只调查,不执行。" />
{mock ? (
<div className="mb-4 flex flex-wrap items-center gap-3 rounded-xl border border-warning/40 bg-warning/10 px-4 py-3 text-caption text-warning">
<FlaskConical className="h-4 w-4 shrink-0" />
<span className="min-w-0 flex-1">演示模式:会话是本地假数据,不连后端,不会产生任何动作。</span>
<span className="min-w-0 flex-1">演示模式:会话是本地假数据,不连接后端,不执行任何操作。</span>
<Button variant="outline" size="sm" onClick={() => window.location.assign("/console/agent?mock=0")}>
退出演示
</Button>
@@ -54,8 +51,8 @@ export default function AgentPage() {
<div className="flex gap-3 rounded-xl border border-border/70 p-4 text-caption text-muted-foreground">
<ShieldCheck aria-hidden className="mt-0.5 size-4 shrink-0" />
<div className="space-y-1">
<p>每一次工具调用都经服务端授权校验:不在白名单或没有授权覆盖的调用会被拒绝,并在对话里醒目标出。</p>
<p>运行结束后,汇报分两栏:模型的自述只作参考,"系统核实的结果"取自下载计划、下载任务与整理记录。</p>
<p>每次工具调用都经服务端授权校验,不在白名单或没有授权的调用会被拒绝并在对话里标出。</p>
<p>汇报分两栏:模型自述仅供参考,"系统核实的结果"取自下载计划、下载任务和整理记录。</p>
</div>
</div>
</div>
+9
View File
@@ -37,6 +37,12 @@ const ACTION_LABEL: Record<string, string> = {
"secret.delete": "删除凭证",
"site_account.credentials_set": "录入站点凭证",
"engine.run_cancel": "取消引擎运行",
"pi_upstream.oauth_start": "开始订阅登录",
"pi_upstream.oauth_login": "完成订阅登录",
"pi_upstream.oauth_logout": "退出订阅登录",
"schedule.run_now": "立即执行定时任务",
"schedule.skip": "跳过定时任务",
"acquisition_plan.manual_submit": "手动提交下载计划",
};
const VERB: Record<string, string> = { create: "新建", update: "修改", delete: "删除", test: "测试", verify: "校验" };
const NOUN: Record<string, string> = {
@@ -44,6 +50,9 @@ const NOUN: Record<string, string> = {
downloader_instance: "下载器",
media_server_instance: "媒体服务器",
path_mapping: "路径映射",
pi_upstream: "Agent 上游",
schedule: "定时任务",
automation_grant: "持续授权",
};
function actionLabel(a: string): string {
if (ACTION_LABEL[a]) return ACTION_LABEL[a];
+1 -1
View File
@@ -143,7 +143,7 @@ export default function DownloadsPage() {
footer={
open ? (
<Button asChild variant="outline" size="sm">
<Link to={consolePath("downloads", open.id)}>在独立页面打开</Link>
<Link to={consolePath("downloads", open.id)}>打开详情页</Link>
</Button>
) : null
}
+14 -20
View File
@@ -155,10 +155,10 @@ function AutomationBanner({ a }: { a: Dashboard["automation"] }) {
</div>
<p className="mt-0.5 text-caption text-muted-foreground">
{paused
? "自动收录、下载、整理都已停下;查询与手动操作仍可用。"
? "自动收录、下载、整理已停止,手动操作仍可用。"
: readOnly
? "恢复后的只读对账:只核对不写入,确认无误后再关掉。"
: `${a.activeSubscriptions} 个订阅在追踪,按规则自动收录、下载与入库。`}
? "只核对,不写入。确认无误后关闭。"
: `${a.activeSubscriptions} 个订阅在追踪,自动收录、下载和整理。`}
</p>
</div>
</div>
@@ -170,7 +170,7 @@ function AutomationBanner({ a }: { a: Dashboard["automation"] }) {
checked={readOnly}
disabled={update.isPending}
onCheckedChange={(v) =>
setAutomation({ readOnlyReconcile: v }, v ? "已进入只读对账模式" : "已退出只读对账模式").catch(() => {})
setAutomation({ readOnlyReconcile: v }, v ? "已开启只读对账" : "已关闭只读对账").catch(() => {})
}
aria-label="只读对账模式"
/>
@@ -193,8 +193,8 @@ function AutomationBanner({ a }: { a: Dashboard["automation"] }) {
</Button>
}
title="暂停全部自动化?"
description="自动收录、下载、整理会停下,已提交的下载任务不受影响。随时可以恢复。"
confirmLabel="暂停"
description="自动收录、下载、整理会停止,已提交的下载任务不受影响。可随时恢复。"
confirmLabel="暂停自动化"
onConfirm={() => setAutomation({ enabled: false }, "自动化已暂停")}
/>
)}
@@ -278,9 +278,9 @@ function CurrentWork({ w }: { w: Dashboard["currentWork"] }) {
function NeedsAttention({ n }: { n: Dashboard["needsAttention"] }) {
return (
<Section title="需要我处理" icon={AlertTriangle} to={consolePath("inbox")}>
<Section title="待处理" icon={AlertTriangle} to={consolePath("inbox")}>
{n.total === 0 ? (
<EmptyState plain icon={CircleCheck} title="没有待你决定的事" className="py-6" />
<EmptyState plain icon={CircleCheck} title="没有待处理事项" className="py-6" />
) : (
<>
<p className="mb-2 text-title-sm font-semibold text-warning tabular-nums">
@@ -308,8 +308,8 @@ function CacheSection({ c }: { c: Dashboard["cache"] }) {
<EmptyState
plain
icon={HardDrive}
title="尚未登记下载器"
description="添加下载器实例后显示缓存卷水位。"
title="还没有下载器"
description="添加下载器后显示缓存水位。"
className="py-6"
/>
) : (
@@ -401,13 +401,7 @@ function SourcesSection({ s }: { s: Dashboard["sources"] }) {
return (
<Section title="来源健康" icon={Radio} to={consolePath("sources")}>
{rows.length === 0 ? (
<EmptyState
plain
icon={Radio}
title="还没有来源"
description="在站点工作台登记站点,在来源健康新建 Feed。"
className="py-6"
/>
<EmptyState plain icon={Radio} title="还没有来源" description="登记站点或新建 Feed 后显示。" className="py-6" />
) : (
<ul className="divide-y divide-border/60">
{rows.slice(0, 8).map((r) => {
@@ -438,7 +432,7 @@ function RecentOutput({ items }: { items: Dashboard["recentOutput"] }) {
return (
<Section title="最近产出" icon={ListTodo} to={consolePath("organize")}>
{items.length === 0 ? (
<EmptyState plain icon={ListTodo} title="还没有入库记录" className="py-6" />
<EmptyState plain icon={ListTodo} title="还没有整理记录" className="py-6" />
) : (
<ul className="divide-y divide-border/60">
{items.slice(0, 6).map((r) => {
@@ -478,7 +472,7 @@ export default function Home() {
<>
<PageHeader
title="首页"
description="系统是否在推进目标、完成了什么、还有什么缺口、是否需要你。"
description="目标进度、今日产出、缺口和待处理事项。"
actions={
<div className="flex items-center gap-2">
<LiveIndicator />
@@ -499,7 +493,7 @@ export default function Home() {
))}
</div>
) : q.isError ? (
<ErrorState title="首页数据加载失败" error={q.error} onRetry={() => q.refetch()} />
<ErrorState title="首页加载失败" error={q.error} onRetry={() => q.refetch()} />
) : (
<>
<AutomationBanner a={q.data.automation} />
+1 -1
View File
@@ -280,7 +280,7 @@ export default function IdentityPage() {
<Button asChild variant="outline" size="sm">
<Link to={INBOX_IDENTITY}>
<Inbox />
待确认身份
确认身份
</Link>
</Button>
}
+2 -2
View File
@@ -110,7 +110,7 @@ export default function SchedulesPage() {
) : board.isError ? (
<ErrorState error={board.error} onRetry={() => board.refetch()} />
) : items.length === 0 ? (
<EmptyState icon={CalendarClock} title="还没有登记的定时任务" description="worker 启动后会自动登记。" />
<EmptyState icon={CalendarClock} title="还没有定时任务" description="worker 启动后自动登记。" />
) : (
<div className="grid items-start gap-4 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-5">
{GROUP_ORDER.map((g) => {
@@ -123,7 +123,7 @@ export default function SchedulesPage() {
</h2>
{jobs.length === 0 ? (
<p className="rounded-xl border border-dashed border-border/70 px-4 py-6 text-center text-meta text-muted-foreground">
{g === "agent" ? "暂无巡检,点「新建巡检」添加。" : "暂无任务。"}
{g === "agent" ? "还没有巡检。" : "还没有定时任务。"}
</p>
) : (
jobs.map((j) => (
+1 -1
View File
@@ -43,7 +43,7 @@ export default function SettingsPage() {
return (
<>
<PageHeader title="设置" description="全局参数、接入的实例与凭证。凭证只写入,保存后不回显。" />
<PageHeader title="设置" description="全局参数、实例与凭证。凭证保存后不回显。" />
<div className="grid gap-6 lg:grid-cols-[13.5rem_minmax(0,1fr)] lg:gap-8">
{/* 窄屏:顶部下拉 */}
<div className="lg:hidden">
@@ -40,7 +40,7 @@ const PROMOS = [
];
const RESOLUTION: { value: ResolutionStatus; label: string }[] = [
{ value: "resolved", label: "已识别" },
{ value: "unresolved", label: "未识别" },
{ value: "unresolved", label: "待识别" },
{ value: "ambiguous", label: "有歧义" },
{ value: "unidentifiable", label: "无法识别" },
];
@@ -358,11 +358,7 @@ export default function SiteWorkbenchPage() {
</TabsContent>
<TabsContent value="origin">
<EmptyState
icon={Globe}
title="原站视图尚未提供"
description={<>计划在 M2 提供。资源详情里有站点 ID 和来源时间,可据此到原站查看。</>}
/>
<EmptyState icon={Globe} title="原站视图暂未提供" description={<>资源详情里有站点 ID,可据此到原站查看。</>} />
</TabsContent>
<TabsContent value="snapshots">
+1 -1
View File
@@ -146,7 +146,7 @@ export default function SitesPage() {
<EmptyState
icon={Globe}
title="还没有登记站点"
description="登记站点并填写账号凭证后,可在这里浏览和搜索资源。"
description="登记站点并填写账号后,在这里浏览和搜索资源。"
action={
<Button size="sm" onClick={() => setRegistering(true)}>
<Plus />
+1 -1
View File
@@ -84,7 +84,7 @@ export default function SourcesPage() {
<>
<PageHeader
title="来源健康"
description="单个站点的快照、Feed 与账号在站点工作台。"
description="单个站点的快照、Feed 和账号在站点工作台管理。"
actions={
<Button size="sm" onClick={() => setCreating(true)}>
<Plus />
+1 -1
View File
@@ -7,7 +7,7 @@ export default function NotFound() {
<div className="grid min-h-screen place-items-center bg-background px-4">
<EmptyState
title="页面不存在"
description="检查地址是否正确,或回到首页。"
description="检查地址,或回到首页。"
action={
<Link to="/console" className={buttonVariants({ variant: "outline" })}>
回到首页