feat(agents): 完善恢复费用与云资源交互
This commit is contained in:
1 parent
f8f39f39de
commit
303f26294e
24 files changed
+1170
-127
No files matched your search
@@ -0,0 +1,42 @@
|
||||
import { useState } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { cloudAgentsApi } from '@/lib/cloud-agents-api';
|
||||
import type { CloudPendingOperation } from '../../../shared/cloud-agents';
|
||||
|
||||
const labels: Record<string, string> = {
|
||||
createAgent: '创建智能体', submit: '发送消息', preview: '预览草稿', resume: '继续任务', publish: '发布版本',
|
||||
createApplication: '创建应用', createKey: '创建密钥', createKnowledge: '创建知识库', processKnowledge: '处理文档',
|
||||
createSchedule: '创建自动任务', runSchedule: '立即运行任务',
|
||||
importKnowledgeAttachment: '导入附件到知识库', createChild: '创建子智能体',
|
||||
};
|
||||
|
||||
export function CloudRecovery({ pending, onResolved }: { pending: CloudPendingOperation[]; onResolved: () => void }) {
|
||||
const [busy, setBusy] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
const [result, setResult] = useState<{ operation: string; value: unknown } | null>(null);
|
||||
const resolve = async (item: CloudPendingOperation, discard = false) => {
|
||||
setBusy(item.id); setError('');
|
||||
try {
|
||||
const response = await cloudAgentsApi.resolvePending(item.id, discard);
|
||||
if (!discard) setResult({ operation: item.operation, value: response.result });
|
||||
onResolved();
|
||||
} catch (e) { setError(e instanceof Error ? e.message : '暂时无法确认结果'); }
|
||||
finally { setBusy(''); }
|
||||
};
|
||||
if (!pending.length && !result && !error) return null;
|
||||
return <aside aria-label="未确认的云端操作" className="mx-auto mb-6 max-w-6xl space-y-3 rounded-xl border border-amber-200 bg-amber-50/30 p-4 text-sm">
|
||||
{pending.length > 0 && <><h2 className="font-medium">有 {pending.length} 个操作的结果尚未确认</h2>
|
||||
<p className="text-muted-foreground">重试会确认原操作,不会新建一份任务。移除提醒只清除本机记录,云端已接受的任务仍会继续。</p></>}
|
||||
{pending.map(item => <div key={item.id} className="flex flex-wrap items-center justify-between gap-3">
|
||||
<div><p>{labels[item.operation] ?? '云端操作'} · {new Date(item.created_at).toLocaleString()}</p>
|
||||
{typeof item.input.query === 'string' && <p className="mt-1 line-clamp-2 text-muted-foreground">{item.input.query}</p>}</div>
|
||||
<div className="flex gap-2"><Button size="sm" disabled={Boolean(busy)} onClick={() => void resolve(item)}>{busy === item.id ? '正在确认…' : '重试并确认结果'}</Button>
|
||||
<Button size="sm" variant="ghost" disabled={Boolean(busy)} onClick={() => void resolve(item, true)}>移除提醒</Button></div>
|
||||
</div>)}
|
||||
{result && <div className="space-y-2"><p>{labels[result.operation] ?? '操作'}的结果已确认。{result.operation === 'createKey' && '请保存下面的密钥,关闭后不再显示。'}</p>
|
||||
<details open={result.operation === 'createKey'}><summary className="cursor-pointer">查看结果</summary>
|
||||
<pre className="max-h-48 overflow-auto whitespace-pre-wrap break-all p-2 text-xs">{JSON.stringify(result.value, null, 2)}</pre></details>
|
||||
<Button variant="ghost" size="sm" onClick={() => setResult(null)}>关闭结果</Button></div>}
|
||||
{error && <p role="alert" className="text-destructive">{error}</p>}
|
||||
</aside>;
|
||||
}
|
||||
Reference in new issue
Block a user