2026-03-29 20:31:13 +08:00
|
|
|
|
<template>
|
2026-03-21 10:13:35 +08:00
|
|
|
|
<div class="agent-view scanlines">
|
|
|
|
|
|
<div class="bg-grid"></div>
|
|
|
|
|
|
<div class="bg-glow"></div>
|
|
|
|
|
|
<div class="bg-particles">
|
|
|
|
|
|
<span v-for="p in bgParticles" :key="p.id" class="bg-particle" :style="p.style"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="view-header">
|
|
|
|
|
|
<div class="header-title">
|
|
|
|
|
|
<span class="title-bracket">[</span>
|
2026-03-25 11:27:16 +08:00
|
|
|
|
<span class="title-text">AGENT COMMAND CENTER</span>
|
2026-03-21 10:13:35 +08:00
|
|
|
|
<span class="title-bracket">]</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="header-actions">
|
|
|
|
|
|
<button class="btn-icon" @click="refreshStats" :class="{ spinning: loading }" title="刷新状态">
|
|
|
|
|
|
<RefreshCw :size="14" />
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<div class="status-bar">
|
|
|
|
|
|
<span class="status-dot" :class="connectionStatus"></span>
|
|
|
|
|
|
<span class="status-label">{{ connectionLabel }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-03-25 11:27:16 +08:00
|
|
|
|
<div
|
|
|
|
|
|
class="nodes-canvas"
|
|
|
|
|
|
ref="canvasRef"
|
|
|
|
|
|
:class="{ panning: isPanning }"
|
|
|
|
|
|
@mousedown="startPan"
|
|
|
|
|
|
@wheel.prevent="handleWheel"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="canvas-aura"></div>
|
|
|
|
|
|
<div class="canvas-scan"></div>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
|
|
|
|
|
|
<div class="hud-panels">
|
|
|
|
|
|
<div class="hud-panel route-telemetry" data-testid="route-telemetry">
|
|
|
|
|
|
<div class="route-main">{{ activeMainRouteLabel }}</div>
|
|
|
|
|
|
<div class="route-child">{{ activeChildRouteLabel }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-03-25 11:27:16 +08:00
|
|
|
|
<div class="nodes-viewport" :style="viewportStyle">
|
|
|
|
|
|
<div class="nodes-stage" :style="stageStyle">
|
|
|
|
|
|
<svg class="conn-svg" ref="svgRef">
|
|
|
|
|
|
<defs>
|
|
|
|
|
|
<filter id="lineGlow">
|
|
|
|
|
|
<feGaussianBlur stdDeviation="3" result="blur"/>
|
|
|
|
|
|
<feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
|
|
|
|
|
|
</filter>
|
|
|
|
|
|
</defs>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
|
2026-03-25 11:27:16 +08:00
|
|
|
|
<path
|
2026-03-25 15:45:10 +08:00
|
|
|
|
v-for="agent in mainAgents"
|
|
|
|
|
|
:key="`bus-${agent.id}`"
|
|
|
|
|
|
:d="getBusLinePath(agent.id)"
|
2026-03-25 11:27:16 +08:00
|
|
|
|
class="conn-path"
|
2026-03-25 15:45:10 +08:00
|
|
|
|
:class="{ energized: activeMainId === agent.id }"
|
|
|
|
|
|
:data-testid="`bus-link-${agent.id}`"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<path
|
|
|
|
|
|
v-for="agent in activeMainAgents"
|
|
|
|
|
|
:key="`bus-current-${agent.id}`"
|
|
|
|
|
|
:d="getBusLinePath(agent.id)"
|
|
|
|
|
|
class="conn-current"
|
|
|
|
|
|
:data-testid="`bus-current-${agent.id}`"
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
<path
|
|
|
|
|
|
v-for="child in childAgents"
|
|
|
|
|
|
:key="`sub-${child.id}`"
|
|
|
|
|
|
:d="getSubLinePath(child.id)"
|
|
|
|
|
|
class="conn-path conn-path-sub"
|
|
|
|
|
|
:class="{ energized: activeChildId === child.id }"
|
|
|
|
|
|
:data-testid="`sub-link-${child.id}`"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<path
|
|
|
|
|
|
v-for="child in activeChildAgents"
|
|
|
|
|
|
:key="`sub-current-${child.id}`"
|
|
|
|
|
|
:d="getSubLinePath(child.id)"
|
|
|
|
|
|
class="conn-current conn-current-sub"
|
|
|
|
|
|
:data-testid="`sub-current-${child.id}`"
|
2026-03-25 11:27:16 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
|
ref="masterCardRef"
|
|
|
|
|
|
class="node-card node-master"
|
|
|
|
|
|
:class="{ selected: selectedAgentId === 'master' }"
|
|
|
|
|
|
:style="masterNodeStyle"
|
|
|
|
|
|
@click="selectAgent('master')"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="node-inner">
|
|
|
|
|
|
<div class="node-corner tl"></div>
|
|
|
|
|
|
<div class="node-corner tr"></div>
|
|
|
|
|
|
<div class="node-corner bl"></div>
|
|
|
|
|
|
<div class="node-corner br"></div>
|
|
|
|
|
|
<div class="node-status" :class="getStatusClass('master')">
|
|
|
|
|
|
<span class="status-ring"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="node-label">MASTER CORE</div>
|
|
|
|
|
|
<div class="node-name">{{ getAgentName('master') }}</div>
|
|
|
|
|
|
<div class="node-role">{{ getAgentRole('master') }}</div>
|
|
|
|
|
|
<div class="node-desc">{{ getAgentDesc('master') }}</div>
|
|
|
|
|
|
<div class="node-footer">
|
|
|
|
|
|
<span class="node-stat">
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<span class="stat-label">璋冪敤</span>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
<span class="stat-val">{{ agentData.master?.callCount || 0 }}</span>
|
2026-03-25 11:27:16 +08:00
|
|
|
|
</span>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
<span v-if="agentData.master?.currentTask" class="node-task-tag">{{ agentData.master.currentTask }}</span>
|
2026-03-24 21:42:01 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-03-21 10:13:35 +08:00
|
|
|
|
</div>
|
2026-03-24 21:42:01 +08:00
|
|
|
|
|
2026-03-25 11:27:16 +08:00
|
|
|
|
<div
|
2026-03-25 15:45:10 +08:00
|
|
|
|
v-for="agent in mainAgents"
|
|
|
|
|
|
:key="agent.id"
|
|
|
|
|
|
:ref="el => setNodeRef(agent.id, el as HTMLElement)"
|
2026-03-25 11:27:16 +08:00
|
|
|
|
class="node-card node-sub"
|
2026-03-25 15:45:10 +08:00
|
|
|
|
:class="{ selected: selectedAgentId === agent.id, disabled: !localAgents[agent.id]?.enabled }"
|
|
|
|
|
|
:style="getMainNodeStyle(agent.id)"
|
|
|
|
|
|
:data-testid="`agent-chip-${agent.id}`"
|
|
|
|
|
|
@click="selectAgent(agent.id)"
|
2026-03-25 11:27:16 +08:00
|
|
|
|
>
|
|
|
|
|
|
<div class="node-inner">
|
|
|
|
|
|
<div class="node-corner tl"></div>
|
|
|
|
|
|
<div class="node-corner tr"></div>
|
|
|
|
|
|
<div class="node-corner bl"></div>
|
|
|
|
|
|
<div class="node-corner br"></div>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
<div class="node-status" :class="getStatusClass(agent.id)">
|
2026-03-25 11:27:16 +08:00
|
|
|
|
<span class="status-ring"></span>
|
2026-03-24 21:42:01 +08:00
|
|
|
|
</div>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
<div class="node-label">{{ getAgentName(agent.id) }}</div>
|
|
|
|
|
|
<div class="node-role">{{ getAgentRole(agent.id) }}</div>
|
|
|
|
|
|
<div class="node-desc">{{ getAgentDesc(agent.id) }}</div>
|
2026-03-25 11:27:16 +08:00
|
|
|
|
<div class="node-footer">
|
|
|
|
|
|
<span class="node-stat">
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<span class="stat-label">璋冪敤</span>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
<span class="stat-val">{{ agentData[agent.id]?.callCount || 0 }}</span>
|
2026-03-25 11:27:16 +08:00
|
|
|
|
</span>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
<span v-if="agentData[agent.id]?.currentTask" class="node-task-tag">{{ agentData[agent.id]?.currentTask }}</span>
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<span v-else class="node-idle">待命中</span>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="rel-label">{{ relationLabels[`master-${agent.id}`] }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="child in childAgents"
|
|
|
|
|
|
:key="child.id"
|
|
|
|
|
|
:ref="el => setNodeRef(child.id, el as HTMLElement)"
|
|
|
|
|
|
class="node-card node-sub node-child"
|
|
|
|
|
|
:class="{ selected: selectedAgentId === child.id, disabled: !localAgents[child.id]?.enabled }"
|
|
|
|
|
|
:style="getChildNodeStyle(child.id)"
|
|
|
|
|
|
:data-testid="`agent-chip-${child.id}`"
|
|
|
|
|
|
@click="selectAgent(child.id)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="node-inner">
|
|
|
|
|
|
<div class="node-corner tl"></div>
|
|
|
|
|
|
<div class="node-corner tr"></div>
|
|
|
|
|
|
<div class="node-corner bl"></div>
|
|
|
|
|
|
<div class="node-corner br"></div>
|
|
|
|
|
|
<div class="node-status" :class="getStatusClass(child.id)">
|
|
|
|
|
|
<span class="status-ring"></span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="node-label">{{ child.name }}</div>
|
|
|
|
|
|
<div class="node-role">{{ child.role }}</div>
|
|
|
|
|
|
<div class="node-desc">{{ child.description }}</div>
|
|
|
|
|
|
<div class="node-footer">
|
|
|
|
|
|
<span class="node-stat">
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<span class="stat-label">璋冪敤</span>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
<span class="stat-val">{{ agentData[child.id]?.callCount || 0 }}</span>
|
2026-03-25 11:27:16 +08:00
|
|
|
|
</span>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
<span v-if="agentData[child.id]?.currentTask" class="node-task-tag">{{ agentData[child.id]?.currentTask }}</span>
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<span v-else class="node-idle">待命中</span>
|
2026-03-24 21:42:01 +08:00
|
|
|
|
</div>
|
2026-03-25 15:45:10 +08:00
|
|
|
|
<div class="rel-label">{{ child.toolScopeLabel }}</div>
|
2026-03-25 11:27:16 +08:00
|
|
|
|
</div>
|
2026-03-21 10:13:35 +08:00
|
|
|
|
</div>
|
2026-03-25 11:27:16 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="canvas-controls">
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<button class="control-chip zoom-chip" @click="zoomOut" title="缂╁皬瑙嗗浘">
|
|
|
|
|
|
<span class="chip-symbol">-</span>
|
2026-03-25 11:27:16 +08:00
|
|
|
|
</button>
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<button class="control-chip zoom-readout" @click="resetView" title="閲嶇疆瑙嗗浘">
|
2026-03-25 11:27:16 +08:00
|
|
|
|
<span class="chip-value">{{ zoomPercent }}</span>
|
|
|
|
|
|
</button>
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<button class="control-chip zoom-chip" @click="zoomIn" title="鏀惧ぇ瑙嗗浘">
|
2026-03-25 11:27:16 +08:00
|
|
|
|
<span class="chip-symbol">+</span>
|
|
|
|
|
|
</button>
|
2026-03-21 10:13:35 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<Transition :css="false" @enter="animateIn" @leave="animateOut">
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<div v-if="drawerOpen" class="config-drawer" data-testid="agent-config-drawer">
|
2026-03-21 10:13:35 +08:00
|
|
|
|
<div class="drawer-header">
|
|
|
|
|
|
<span class="drawer-title">// AGENT CONFIGURATION</span>
|
|
|
|
|
|
<button class="btn-close" @click="drawerOpen = false"><X :size="16" /></button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="drawer-body" v-if="editAgent">
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
|
<label class="form-label">// AGENT NAME</label>
|
|
|
|
|
|
<input v-model="editAgent.name" type="text" class="form-input" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
|
<label class="form-label">// ROLE</label>
|
|
|
|
|
|
<input v-model="editAgent.role" type="text" class="form-input" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
|
<label class="form-label">// DESCRIPTION</label>
|
|
|
|
|
|
<textarea v-model="editAgent.description" class="form-textarea" rows="2"></textarea>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-group flex-1">
|
|
|
|
|
|
<label class="form-label">// SYSTEM PROMPT</label>
|
|
|
|
|
|
<textarea v-model="editAgent.systemPrompt" class="form-textarea code-textarea" rows="10"></textarea>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
|
<label class="form-label">// STATUS</label>
|
|
|
|
|
|
<div class="toggle-row">
|
|
|
|
|
|
<span class="toggle-label" :class="{ dim: editAgent.enabled }">DISABLED</span>
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<button class="toggle-btn" :class="{ active: editAgent.enabled }" @click="editAgent = { ...editAgent, enabled: !editAgent.enabled }">
|
2026-03-21 10:13:35 +08:00
|
|
|
|
<span class="toggle-knob"></span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<span class="toggle-label" :class="{ dim: !editAgent.enabled }">ENABLED</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<div class="form-group linked-skills-group" data-testid="linked-skills-section">
|
|
|
|
|
|
<label class="form-label">// LINKED SKILLS</label>
|
|
|
|
|
|
<div v-if="selectedNodePackages.length > 0" class="linked-skill-packages">
|
|
|
|
|
|
<span
|
|
|
|
|
|
v-for="pkg in selectedNodePackages"
|
|
|
|
|
|
:key="pkg.id"
|
|
|
|
|
|
class="linked-skill-package"
|
|
|
|
|
|
:data-testid="`linked-skills-package-${pkg.id}`"
|
|
|
|
|
|
>
|
|
|
|
|
|
<strong>{{ pkg.title }}</strong>
|
|
|
|
|
|
<span>{{ pkg.stateLabel }}</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-if="skillsLoading" class="linked-skills-state" data-testid="linked-skills-loading">鍔犺浇鎶€鑳戒腑...</div>
|
|
|
|
|
|
<div v-else-if="skillsError" class="linked-skills-state linked-skills-error" data-testid="linked-skills-error">{{ skillsError }}</div>
|
|
|
|
|
|
<div v-else-if="saveError" class="linked-skills-state linked-skills-error" data-testid="linked-skills-save-error">{{ saveError }}</div>
|
|
|
|
|
|
<div v-else-if="selectedNodeSkills.length === 0" class="linked-skills-state" data-testid="linked-skills-empty">
|
|
|
|
|
|
暂无可关联技能,请先到左侧能力中心创建或维护相关 Skill。
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-else class="linked-skill-list">
|
|
|
|
|
|
<label
|
|
|
|
|
|
v-for="skill in selectedNodeSkills"
|
|
|
|
|
|
:key="skill.id"
|
|
|
|
|
|
class="linked-skill-item"
|
|
|
|
|
|
:data-testid="`linked-skill-item-${skill.id}`"
|
|
|
|
|
|
>
|
|
|
|
|
|
<input
|
|
|
|
|
|
:checked="editAgent.selectedSkillIds.includes(skill.id)"
|
|
|
|
|
|
type="checkbox"
|
|
|
|
|
|
class="linked-skill-checkbox"
|
|
|
|
|
|
:data-testid="`linked-skill-checkbox-${skill.id}`"
|
|
|
|
|
|
@change="toggleSkillSelection(skill.id, ($event.target as HTMLInputElement).checked)"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div class="linked-skill-copy">
|
|
|
|
|
|
<div class="linked-skill-head">
|
|
|
|
|
|
<span class="linked-skill-name">{{ skill.name }}</span>
|
|
|
|
|
|
<span class="linked-skill-agent-type">{{ skill.agent_type }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="linked-skill-desc">{{ skill.description || '鏆傛棤鎻忚堪' }}</div>
|
|
|
|
|
|
<div v-if="skill.tools.length > 0" class="linked-skill-tools">
|
|
|
|
|
|
<span v-for="tool in skill.tools" :key="tool" class="linked-skill-tool">{{ tool }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-03-21 10:13:35 +08:00
|
|
|
|
<div class="drawer-actions">
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<button class="btn-secondary" data-testid="linked-skills-reset" @click="resetConfig">閲嶇疆</button>
|
|
|
|
|
|
<button class="btn-primary" data-testid="linked-skills-save" @click="saveConfig" :disabled="saving">
|
2026-03-21 10:13:35 +08:00
|
|
|
|
<span v-if="saving" class="btn-loader"></span>
|
2026-03-29 20:31:13 +08:00
|
|
|
|
{{ saving ? '淇濆瓨涓?..' : '淇濆瓨閰嶇疆' }}
|
2026-03-21 10:13:35 +08:00
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Transition>
|
|
|
|
|
|
|
2026-03-25 11:27:16 +08:00
|
|
|
|
<Transition :css="false" @enter="animateIn" @leave="animateOut">
|
|
|
|
|
|
<div v-if="addModalOpen" class="modal-overlay" @click.self="addModalOpen = false">
|
|
|
|
|
|
<div class="modal-card">
|
|
|
|
|
|
<div class="modal-header">
|
|
|
|
|
|
<span class="modal-title">// ADD NEW AGENT</span>
|
|
|
|
|
|
<button class="btn-close" @click="addModalOpen = false"><X :size="16" /></button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="modal-body">
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
|
<label class="form-label">// AGENT NAME</label>
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<input v-model="newAgent.name" type="text" class="form-input" placeholder="渚嬪: CODER" />
|
2026-03-25 11:27:16 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-group">
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<label class="form-label">// ROLE KEY (鑻辨枃鍞竴鏍囪瘑)</label>
|
|
|
|
|
|
<input v-model="newAgent.roleKey" type="text" class="form-input" placeholder="渚嬪: coder" />
|
2026-03-25 11:27:16 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
|
<label class="form-label">// ROLE</label>
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<input v-model="newAgent.role" type="text" class="form-input" placeholder="例如: 中文角色名" />
|
2026-03-25 11:27:16 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
|
|
<label class="form-label">// DESCRIPTION</label>
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<textarea v-model="newAgent.description" class="form-textarea" rows="2" placeholder="鎻忚堪姝?Agent 鐨勮亴璐?.."></textarea>
|
2026-03-25 11:27:16 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-group flex-1">
|
|
|
|
|
|
<label class="form-label">// SYSTEM PROMPT</label>
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<textarea v-model="newAgent.systemPrompt" class="form-textarea code-textarea" rows="6" placeholder="杈撳叆绯荤粺鎻愮ず璇?.."></textarea>
|
2026-03-25 11:27:16 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="modal-footer">
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<button class="btn-secondary" @click="addModalOpen = false">鍙栨秷</button>
|
2026-03-25 11:27:16 +08:00
|
|
|
|
<button class="btn-primary" @click="addAgent" :disabled="!newAgent.name || !newAgent.roleKey">创建智能体</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Transition>
|
|
|
|
|
|
|
2026-03-21 10:13:35 +08:00
|
|
|
|
<Transition :css="false" @enter="fadeIn" @leave="fadeOut">
|
|
|
|
|
|
<div v-if="drawerOpen" class="drawer-backdrop" @click="drawerOpen = false"></div>
|
|
|
|
|
|
</Transition>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2026-03-29 20:31:13 +08:00
|
|
|
|
import { RefreshCw, X } from 'lucide-vue-next'
|
|
|
|
|
|
import { useAgentsPage } from './composables/useAgentsPage'
|
|
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
|
bgParticles,
|
|
|
|
|
|
canvasRef,
|
|
|
|
|
|
svgRef,
|
|
|
|
|
|
masterCardRef,
|
|
|
|
|
|
isPanning,
|
|
|
|
|
|
connectionStatus,
|
|
|
|
|
|
connectionLabel,
|
|
|
|
|
|
loading,
|
|
|
|
|
|
drawerOpen,
|
|
|
|
|
|
addModalOpen,
|
|
|
|
|
|
editAgent,
|
|
|
|
|
|
newAgent,
|
|
|
|
|
|
skillsLoading,
|
|
|
|
|
|
skillsError,
|
|
|
|
|
|
saveError,
|
|
|
|
|
|
saving,
|
|
|
|
|
|
mainAgents,
|
|
|
|
|
|
childAgents,
|
|
|
|
|
|
relationLabels,
|
|
|
|
|
|
activeMainId,
|
|
|
|
|
|
activeChildId,
|
|
|
|
|
|
activeMainAgents,
|
|
|
|
|
|
activeChildAgents,
|
|
|
|
|
|
activeMainRouteLabel,
|
|
|
|
|
|
activeChildRouteLabel,
|
|
|
|
|
|
selectedAgentId,
|
|
|
|
|
|
selectedNodePackages,
|
|
|
|
|
|
selectedNodeSkills,
|
|
|
|
|
|
agentData,
|
|
|
|
|
|
localAgents,
|
|
|
|
|
|
viewportStyle,
|
|
|
|
|
|
stageStyle,
|
|
|
|
|
|
masterNodeStyle,
|
|
|
|
|
|
zoomPercent,
|
|
|
|
|
|
refreshStats,
|
|
|
|
|
|
startPan,
|
|
|
|
|
|
handleWheel,
|
|
|
|
|
|
getBusLinePath,
|
|
|
|
|
|
getSubLinePath,
|
|
|
|
|
|
selectAgent,
|
|
|
|
|
|
setNodeRef,
|
|
|
|
|
|
getStatusClass,
|
|
|
|
|
|
getAgentName,
|
|
|
|
|
|
getAgentRole,
|
|
|
|
|
|
getAgentDesc,
|
|
|
|
|
|
getMainNodeStyle,
|
|
|
|
|
|
getChildNodeStyle,
|
|
|
|
|
|
zoomOut,
|
|
|
|
|
|
zoomIn,
|
|
|
|
|
|
resetView,
|
|
|
|
|
|
toggleSkillSelection,
|
|
|
|
|
|
resetConfig,
|
|
|
|
|
|
saveConfig,
|
|
|
|
|
|
addAgent,
|
|
|
|
|
|
animateIn,
|
|
|
|
|
|
animateOut,
|
|
|
|
|
|
fadeIn,
|
|
|
|
|
|
fadeOut,
|
|
|
|
|
|
} = useAgentsPage()
|
2026-03-21 10:13:35 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
2026-03-29 20:31:13 +08:00
|
|
|
|
<style scoped src="./agentsPage.css"></style>
|
|
|
|
|
|
|