Files
makelore/src/pages/CloudAgents/CloudRecovery.tsx

52 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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: '创建子智能体',
wechatBindVerification: '微信连接验证', channelAccountWechatBindVerification: '微信连接验证',
createChannelAccount: '添加微信账号', routeChannelAccount: '切换目标智能体', enableChannelAccount: '启用渠道',
pauseChannelAccount: '暂停渠道', disconnectChannelAccount: '断开微信账号', channelAccountWechatBindStart: '微信扫码连接',
channelAccountWechatUnbind: '解除微信登录',
};
export function CloudRecovery({ pending, onResolved }: { pending: CloudPendingOperation[]; onResolved: () => void }) {
const [busy, setBusy] = useState('');
const [error, setError] = useState('');
const [notice, setNotice] = useState('');
const [result, setResult] = useState<{ operation: string; value: unknown } | null>(null);
const resolve = async (item: CloudPendingOperation, discard = false) => {
setBusy(item.id); setError(''); setNotice('');
try {
const response = await cloudAgentsApi.resolvePending(item.id, discard);
if (response.requires_input) {
setResult(null);
setNotice('这次微信验证还需要验证码。请进入「渠道 → 微信」,选择对应账号后继续连接验证。');
} else 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 && !notice) 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>}
{notice && <p role="status" className="text-muted-foreground">{notice}</p>}
</aside>;
}