fix: 远程命令直连SSH(去轮询) + 去掉无用命令分类
This commit is contained in:
1 parent
ed3bf59c3b
commit
b8b1a3d5f6
4 files changed
+70
-68
No files matched your search
@@ -55,13 +55,10 @@ export function AgentMonitor() {
|
||||
// 远程命令
|
||||
const [cmdOpen, setCmdOpen] = useState(false);
|
||||
const [cmdHost, setCmdHost] = useState('');
|
||||
const [cmdType, setCmdType] = useState('command');
|
||||
const [cmdCommand, setCmdCommand] = useState('');
|
||||
const [cmdTimeout, setCmdTimeout] = useState('30');
|
||||
const [cmdTimeout, setCmdTimeout] = useState(30);
|
||||
const [cmdSubmitting, setCmdSubmitting] = useState(false);
|
||||
const [cmdResult, setCmdResult] = useState<any>(null);
|
||||
const [cmdPolling, setCmdPolling] = useState(false);
|
||||
const pollTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
|
||||
const loadLatest = useCallback(async (silent = false) => {
|
||||
if (!silent) setRefreshing(true);
|
||||
@@ -95,14 +92,13 @@ export function AgentMonitor() {
|
||||
// 打开远程命令弹窗
|
||||
const openCommandDialog = (hostname: string) => {
|
||||
setCmdHost(hostname);
|
||||
setCmdType('command');
|
||||
setCmdCommand('');
|
||||
setCmdTimeout('30');
|
||||
setCmdTimeout(30);
|
||||
setCmdResult(null);
|
||||
setCmdOpen(true);
|
||||
};
|
||||
|
||||
// 提交远程命令并轮询结果
|
||||
// 提交远程命令(直连 SSH 即时返回)
|
||||
const submitCommand = async () => {
|
||||
if (!cmdCommand.trim()) {
|
||||
toast.error('请输入要执行的命令');
|
||||
@@ -111,62 +107,26 @@ export function AgentMonitor() {
|
||||
setCmdSubmitting(true);
|
||||
setCmdResult(null);
|
||||
try {
|
||||
const res: any = await agentApi.createTask({
|
||||
const res: any = await agentApi.execCommand({
|
||||
hostname: cmdHost,
|
||||
type: cmdType,
|
||||
command: cmdCommand.trim(),
|
||||
timeout: Number(cmdTimeout) || 30,
|
||||
});
|
||||
const taskId = res?.id ?? res?.task_id;
|
||||
toast.success('任务已下发');
|
||||
setCmdSubmitting(false);
|
||||
|
||||
// 轮询任务结果
|
||||
if (taskId != null) {
|
||||
setCmdPolling(true);
|
||||
let attempts = 0;
|
||||
pollTimerRef.current = setInterval(async () => {
|
||||
attempts++;
|
||||
try {
|
||||
const tasks: any = await agentApi.listTasks({ hostname: cmdHost });
|
||||
const list = asList(tasks);
|
||||
const t = list.find((x: any) => String(x.id) === String(taskId));
|
||||
if (t && t.status && t.status !== 'pending' && t.status !== 'running') {
|
||||
setCmdResult(t);
|
||||
setCmdPolling(false);
|
||||
if (pollTimerRef.current) {
|
||||
clearInterval(pollTimerRef.current);
|
||||
pollTimerRef.current = null;
|
||||
}
|
||||
loadLatest(true);
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
if (attempts > 15) {
|
||||
// 30s 超时
|
||||
setCmdPolling(false);
|
||||
setCmdResult({ status: 'timeout', result: '等待结果超时,请稍后在任务列表查看' });
|
||||
if (pollTimerRef.current) {
|
||||
clearInterval(pollTimerRef.current);
|
||||
pollTimerRef.current = null;
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
setCmdResult({
|
||||
status: res?.code === 200 ? 'completed' : 'failed',
|
||||
result: res?.data?.output || res?.message || '无输出',
|
||||
error: res?.data?.error,
|
||||
});
|
||||
} catch (err: any) {
|
||||
toast.error(err?.message || '任务下发失败');
|
||||
setCmdResult({ status: 'failed', result: err?.message || '执行失败' });
|
||||
} finally {
|
||||
setCmdSubmitting(false);
|
||||
loadLatest(true);
|
||||
}
|
||||
};
|
||||
|
||||
const closeCommandDialog = () => {
|
||||
setCmdOpen(false);
|
||||
if (pollTimerRef.current) {
|
||||
clearInterval(pollTimerRef.current);
|
||||
pollTimerRef.current = null;
|
||||
}
|
||||
setCmdPolling(false);
|
||||
};
|
||||
|
||||
const onlineCount = hosts.filter((h) => isOnline(h.last_report || h.last_reported_at || h.updated_at)).length;
|
||||
@@ -358,18 +318,6 @@ export function AgentMonitor() {
|
||||
className="h-9 bg-slate-800 border-slate-700 text-slate-200"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label className="text-slate-300 text-xs">类型</Label>
|
||||
<Select value={cmdType} onValueChange={setCmdType}>
|
||||
<SelectTrigger className="h-9 bg-slate-800 border-slate-700 text-slate-200">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="bg-slate-800 border-slate-700 text-slate-200">
|
||||
<SelectItem value="command">Shell 命令</SelectItem>
|
||||
<SelectItem value="script">多行脚本</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
@@ -423,13 +371,11 @@ export function AgentMonitor() {
|
||||
</Button>
|
||||
<Button
|
||||
onClick={submitCommand}
|
||||
disabled={cmdSubmitting || cmdPolling || !cmdCommand.trim()}
|
||||
disabled={cmdSubmitting || !cmdCommand.trim()}
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white"
|
||||
>
|
||||
{cmdSubmitting ? (
|
||||
<><Loader2 className="h-4 w-4 mr-1.5 animate-spin" />下发中</>
|
||||
) : cmdPolling ? (
|
||||
<><Loader2 className="h-4 w-4 mr-1.5 animate-spin" />等待结果</>
|
||||
<><Loader2 className="h-4 w-4 mr-1.5 animate-spin" />执行中</>
|
||||
) : (
|
||||
<><Terminal className="h-4 w-4 mr-1.5" />执行</>
|
||||
)}
|
||||
|
||||
Reference in new issue
Block a user