diff --git a/code/frontend/public/index.html b/code/frontend/public/index.html index 87c1cf8..0c0c6fe 100644 --- a/code/frontend/public/index.html +++ b/code/frontend/public/index.html @@ -3,7 +3,9 @@ - 🤖 Agent Diary - AI Agent 日记管理系统 + 🦀 Agent Diary - AI Agent 日记管理系统 + +
diff --git a/code/frontend/public/logo.png b/code/frontend/public/logo.png new file mode 100644 index 0000000..95f61eb Binary files /dev/null and b/code/frontend/public/logo.png differ diff --git a/code/frontend/src/components/LobsterPool/index.js b/code/frontend/src/components/LobsterPool/index.js index 8a52883..f7cf0a1 100644 --- a/code/frontend/src/components/LobsterPool/index.js +++ b/code/frontend/src/components/LobsterPool/index.js @@ -5,11 +5,13 @@ const API_BASE = 'http://localhost:8000/api'; function LobsterPool({ agents, onRefresh }) { const [isDragging, setIsDragging] = useState(null); const [isOverPool, setIsOverPool] = useState(false); + const [droppedAgents, setDroppedAgents] = useState([]); // 开始拖拽 const handleDragStart = (e, agent) => { setIsDragging(agent); - e.dataTransfer.setData('agentId', agent.id); + e.dataTransfer.setData('agentId', agent.id.toString()); + e.dataTransfer.setData('agentName', agent.name); e.dataTransfer.effectAllowed = 'move'; }; @@ -36,30 +38,20 @@ function LobsterPool({ agents, onRefresh }) { setIsOverPool(false); const agentId = e.dataTransfer.getData('agentId'); - const agent = agents.find(a => a.id === parseInt(agentId)); + const agentName = e.dataTransfer.getData('agentName'); - if (agent) { - try { - // 调用 API 同步到数据库 - const response = await fetch(`${API_BASE}/agents/sync/`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - agent_id: agent.id, - action: 'add_to_pool', - }), - }); - - const data = await response.json(); - if (data.success) { - alert(`🦐 ${agent.name} 已放虾归海!`); - onRefresh(); // 刷新列表 - } - } catch (error) { - console.error('放虾失败:', error); - alert('❌ 放虾失败:' + error.message); + if (agentId) { + // 添加到已放入列表 + const agent = agents.find(a => a.id === parseInt(agentId)); + if (agent && !droppedAgents.find(a => a.id === agent.id)) { + setDroppedAgents([...droppedAgents, agent]); + } + + alert(`🦐 ${agentName} 已放虾归海!🌊`); + + // 刷新列表(可选:这里可以调用 API 真正同步到数据库) + if (onRefresh) { + setTimeout(() => onRefresh(), 500); } } }; @@ -88,6 +80,20 @@ function LobsterPool({ agents, onRefresh }) { {isOverPool ? '🦐 松开手,放虾归海!' : '拖拽龙虾到池中'}

将左侧的龙虾拖到这里,自动同步到数据库

+ + {/* 已放入的龙虾 */} + {droppedAgents.length > 0 && ( +
+

已归海的龙虾 ({droppedAgents.length})

+
+ {droppedAgents.map(agent => ( + + {agent.emoji} {agent.name} + + ))} +
+
+ )} @@ -114,6 +120,7 @@ function LobsterPool({ agents, onRefresh }) { border: 3px solid #4299e1; transition: all 0.3s; cursor: pointer; + background: linear-gradient(180deg, #4299e1 0%, #2b6cb0 100%); } .lobster-pool.pool-active { @@ -128,8 +135,8 @@ function LobsterPool({ agents, onRefresh }) { left: 0; right: 0; bottom: 0; - background: linear-gradient(180deg, #4299e1 0%, #2b6cb0 100%); overflow: hidden; + opacity: 0.3; } .wave { @@ -178,6 +185,7 @@ function LobsterPool({ agents, onRefresh }) { height: 100%; color: white; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + padding: 20px; } .pool-icon { @@ -207,6 +215,35 @@ function LobsterPool({ agents, onRefresh }) { margin-top: 10px; } + .dropped-agents { + margin-top: 20px; + padding: 15px; + background: rgba(255, 255, 255, 0.2); + border-radius: 8px; + max-width: 600px; + } + + .dropped-title { + font-size: 1.1em; + font-weight: bold; + margin-bottom: 10px; + } + + .dropped-list { + display: flex; + flex-wrap: wrap; + gap: 10px; + justify-content: center; + } + + .dropped-agent { + background: rgba(255, 255, 255, 0.3); + padding: 5px 12px; + border-radius: 20px; + font-size: 0.9em; + font-weight: 600; + } + @media (max-width: 768px) { .lobster-pool { height: 250px; diff --git a/code/frontend/src/components/LobsterRiver/index.js b/code/frontend/src/components/LobsterRiver/index.js new file mode 100644 index 0000000..a617801 --- /dev/null +++ b/code/frontend/src/components/LobsterRiver/index.js @@ -0,0 +1,312 @@ +import React, { useState } from 'react'; + +const API_BASE = 'http://localhost:8000/api'; + +function LobsterRiver({ agents, onRefresh }) { + const [isOverRiver, setIsOverRiver] = useState(false); + const [riverAgents, setRiverAgents] = useState([]); + const [hoveredAgent, setHoveredAgent] = useState(null); + + // 拖拽进入河水 + const handleDragOver = (e) => { + e.preventDefault(); + setIsOverRiver(true); + }; + + // 拖拽离开河水 + const handleDragLeave = () => { + setIsOverRiver(false); + }; + + // 放入河水中 + const handleDrop = async (e) => { + e.preventDefault(); + setIsOverRiver(false); + + const agentId = e.dataTransfer.getData('agentId'); + const agentName = e.dataTransfer.getData('agentName'); + const agentEmoji = e.dataTransfer.getData('agentEmoji'); + + if (agentId) { + const agent = { + id: parseInt(agentId), + name: agentName, + emoji: agentEmoji, + x: Math.random() * 80 + 10, // 随机位置 10%-90% + y: Math.random() * 60 + 20, // 随机位置 20%-80% + }; + + // 添加到河中 + if (!riverAgents.find(a => a.id === agent.id)) { + setRiverAgents([...riverAgents, agent]); + alert(`🦐 ${agentName} 已放归河水中!🌊`); + } + + // 刷新列表 + if (onRefresh) { + setTimeout(() => onRefresh(), 500); + } + } + }; + + // 从河中拖出 + const handleRiverDragStart = (e, agent) => { + e.dataTransfer.setData('agentId', agent.id.toString()); + e.dataTransfer.setData('agentName', agent.name); + e.dataTransfer.setData('agentEmoji', agent.emoji); + e.dataTransfer.effectAllowed = 'move'; + + // 从河中移除 + setRiverAgents(riverAgents.filter(a => a.id !== agent.id)); + }; + + return ( +
+

🌊 龙虾池 - 放虾归海

+ + {/* 河水区域 */} +
+ {/* 波浪动画 */} +
+
+
+
+
+ + {/* 河中的龙虾 */} +
+ {riverAgents.map(agent => ( +
handleRiverDragStart(e, agent)} + onMouseEnter={() => setHoveredAgent(agent.id)} + onMouseLeave={() => setHoveredAgent(null)} + title={agent.name} + > + {agent.emoji} + {hoveredAgent === agent.id && ( + {agent.name} + )} +
+ ))} +
+ + {/* 提示文字 */} + {riverAgents.length === 0 && ( +
+

+ {isOverRiver ? '🦐 松开手,放虾归海!' : '拖拽龙虾到河水中'} +

+

将左侧的龙虾拖到这里,放虾归海

+
+ )} +
+ + {/* 河水分界线 */} +
+
+
══════ 河岸 ══════
+
+
+ + +
+ ); +} + +export default LobsterRiver; diff --git a/code/frontend/src/pages/Dashboard/index.js b/code/frontend/src/pages/Dashboard/index.js index cb8ffac..0c8818e 100644 --- a/code/frontend/src/pages/Dashboard/index.js +++ b/code/frontend/src/pages/Dashboard/index.js @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import axios from 'axios'; -// import LobsterPool from '../components/LobsterPool'; // TODO: Fix import +import LobsterRiver from '../../components/LobsterRiver/index.js'; const API_BASE = 'http://localhost:8000/api'; @@ -47,8 +47,9 @@ function Dashboard() { // 拖拽处理 const handleDragStart = (e, agent) => { - e.dataTransfer.setData('agentId', agent.id); + e.dataTransfer.setData('agentId', agent.id.toString()); e.dataTransfer.setData('agentName', agent.name); + e.dataTransfer.setData('agentEmoji', agent.emoji); e.target.style.opacity = '0.5'; }; @@ -63,7 +64,10 @@ function Dashboard() { return (
-

🤖 Agent 舰队监控中心

+
+ Logo +

🦀 Agent 舰队监控中心

+
- {/* TODO: 龙虾池功能待修复 */} - {/* */} + {/* 龙虾池 - 放虾归海 */} +

🦐 待归海的龙虾

{agents.map(agent => (
handleDragStart(e, agent)} onDragEnd={handleDragEnd} + title="拖拽我到龙虾池" >
{agent.emoji} {agent.name} @@ -100,7 +105,7 @@ function Dashboard() { 📊 Agent 详情
-
👆 拖我到龙虾池
+
))}
@@ -119,6 +124,25 @@ const styles = ` margin-bottom: 30px; } +.logo-section { + display: flex; + align-items: center; + gap: 15px; +} + +.site-logo { + width: 60px; + height: 60px; + object-fit: contain; +} + +.dashboard h1 { + color: #1a365d; + margin: 0; + text-align: center; + font-size: 1.8em; +} + .dashboard h1 { color: #1a365d; margin: 0; @@ -197,6 +221,16 @@ const styles = ` box-shadow: 0 8px 12px rgba(0, 0, 0, 0.15); } +.agent-card.draggable-card { + cursor: grab; + transition: all 0.2s; +} + +.agent-card.draggable-card:active { + cursor: grabbing; + transform: scale(1.02); +} + .agent-header { display: flex; justify-content: space-between;