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 舰队监控中心
+
+

+
🦀 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;