feat: initialize ZCLAW project with core systems and Tauri desktop
- Created backend core systems: - Remote Execution System (远程执行系统) - Task Orchestration Engine (任务编排引擎) - Persistent Memory System (持续记忆系统) - Proactive Service System (主动服务系统) - Created Tauri desktop app: - Three-column layout based on AutoClaw design - React + TypeScript + Tailwind CSS - Zustand state management - Lucide React icons - Components: - Sidebar (Agent list, IM channels, scheduled tasks) - ChatArea (Chat interface with message bubbles) - RightPanel (Task progress, statistics, next actions) Next: Test Tauri dev server and integrate with OpenClaw backend
This commit is contained in:
112
desktop/src/components/ChatArea.tsx
Normal file
112
desktop/src/components/ChatArea.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import { useState } from 'react';
|
||||
import { useChatStore } from '../store/chatStore';
|
||||
import { Send, Paperclip, ChevronDown } from 'lucide-react';
|
||||
|
||||
export function ChatArea() {
|
||||
const { messages, currentAgent, addMessage } = useChatStore();
|
||||
const [input, setInput] = useState('');
|
||||
|
||||
const sendMessage = () => {
|
||||
if (!input.trim()) return;
|
||||
|
||||
const userMessage = {
|
||||
id: Date.now().toString(),
|
||||
role: 'user' as const,
|
||||
content: input,
|
||||
timestamp: new Date(),
|
||||
};
|
||||
|
||||
addMessage(userMessage);
|
||||
setInput('');
|
||||
|
||||
// TODO: 调用后端 API
|
||||
setTimeout(() => {
|
||||
const aiMessage = {
|
||||
id: (Date.now() + 1).toString(),
|
||||
role: 'assistant' as const,
|
||||
content: '收到你的消息了!正在处理中...',
|
||||
timestamp: new Date(),
|
||||
};
|
||||
addMessage(aiMessage);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* 顶部标题栏 */}
|
||||
<div className="h-14 border-b border-gray-100 flex items-center justify-between px-6 flex-shrink-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<h2 className="font-semibold text-gray-900">{currentAgent?.name || 'ZCLAW'}</h2>
|
||||
<span className="text-xs text-gray-400 flex items-center gap-1">
|
||||
<span className="w-1.5 h-1.5 bg-green-400 rounded-full"></span>
|
||||
在线
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 聊天内容区 */}
|
||||
<div className="flex-1 overflow-y-auto custom-scrollbar p-6 space-y-6">
|
||||
{messages.length === 0 && (
|
||||
<div className="text-center text-gray-400 py-20">
|
||||
<p className="text-lg mb-2">欢迎使用 ZCLAW 🦞</p>
|
||||
<p className="text-sm">发送消息开始对话</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{messages.map((message) => (
|
||||
<div
|
||||
key={message.id}
|
||||
className={lex gap-4 }
|
||||
>
|
||||
<div
|
||||
className={w-8 h-8 rounded-lg flex items-center justify-center flex-shrink-0 }
|
||||
>
|
||||
{message.role === 'user' ? '用' : '🦞'}
|
||||
</div>
|
||||
<div className={message.role === 'user' ? 'max-w-2xl' : 'flex-1 max-w-3xl'}>
|
||||
<div className={message.role === 'user' ? 'chat-bubble-user p-4 shadow-md' : 'chat-bubble-assistant p-4 shadow-sm'}>
|
||||
<p className="leading-relaxed text-gray-700">{message.content}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 底部输入区 */}
|
||||
<div className="border-t border-gray-100 p-4 bg-white">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="relative flex items-end gap-2 bg-gray-50 rounded-2xl border border-gray-200 p-2 focus-within:border-orange-300 focus-within:ring-2 focus-within:ring-orange-100 transition-all">
|
||||
<button className="p-2 text-gray-400 hover:text-gray-600 rounded-lg">
|
||||
<Paperclip className="w-5 h-5" />
|
||||
</button>
|
||||
<div className="flex-1 py-2">
|
||||
<input
|
||||
type="text"
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
|
||||
placeholder="发送给 ZCLAW"
|
||||
className="w-full bg-transparent border-none focus:outline-none text-gray-700 placeholder-gray-400"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 pr-2 pb-1">
|
||||
<button className="flex items-center gap-1 px-2 py-1 text-xs text-gray-500 hover:bg-gray-200 rounded-md transition-colors">
|
||||
<span>glm5</span>
|
||||
<ChevronDown className="w-3 h-3" />
|
||||
</button>
|
||||
<button
|
||||
onClick={sendMessage}
|
||||
className="w-8 h-8 bg-gray-900 text-white rounded-full flex items-center justify-center hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
<Send className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center mt-2 text-xs text-gray-400">
|
||||
Agent 在本地运行,内容由 AI 生成
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
106
desktop/src/components/RightPanel.tsx
Normal file
106
desktop/src/components/RightPanel.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import { FileText, User, Target, CheckSquare } from 'lucide-react';
|
||||
|
||||
export function RightPanel() {
|
||||
return (
|
||||
<aside className="w-80 bg-white border-l border-gray-200 flex flex-col flex-shrink-0">
|
||||
{/* 顶部工具栏 */}
|
||||
<div className="h-14 border-b border-gray-100 flex items-center justify-between px-4 flex-shrink-0">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-1 text-gray-600">
|
||||
<Target className="w-4 h-4" />
|
||||
<span className="font-medium">2268</span>
|
||||
</div>
|
||||
<button className="text-xs text-orange-600 hover:underline">去购买</button>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 text-gray-500">
|
||||
<button className="hover:text-gray-700 flex items-center gap-1 text-xs">
|
||||
<FileText className="w-4 h-4" />
|
||||
<span>文件</span>
|
||||
</button>
|
||||
<button className="hover:text-gray-700 flex items-center gap-1 text-xs">
|
||||
<User className="w-4 h-4" />
|
||||
<span>Agent</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 内容区 */}
|
||||
<div className="flex-1 overflow-y-auto custom-scrollbar p-4">
|
||||
{/* 任务进度 */}
|
||||
<div className="bg-gray-50 rounded-lg border border-gray-100 mb-6 overflow-hidden">
|
||||
<div className="p-3">
|
||||
<div className="flex justify-between text-xs mb-2">
|
||||
<span className="text-gray-600">任务进度</span>
|
||||
<span className="font-medium text-gray-900">65%</span>
|
||||
</div>
|
||||
<div className="w-full bg-gray-200 rounded-full h-2">
|
||||
<div className="bg-orange-500 h-2 rounded-full transition-all" style={{ width: '65%' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-t border-gray-100 divide-y divide-gray-100 text-xs">
|
||||
<div className="py-2 px-3 flex justify-between">
|
||||
<span className="text-gray-600">远程执行</span>
|
||||
<span className="text-green-600">✅ 完成</span>
|
||||
</div>
|
||||
<div className="py-2 px-3 flex justify-between">
|
||||
<span className="text-gray-600">任务编排</span>
|
||||
<span className="text-orange-600">🔄 进行中</span>
|
||||
</div>
|
||||
<div className="py-2 px-3 flex justify-between">
|
||||
<span className="text-gray-600">多 Agent 协作</span>
|
||||
<span className="text-gray-400">⏳ 待开始</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 今日统计 */}
|
||||
<div className="mb-6">
|
||||
<h3 className="font-bold text-gray-900 mb-3 text-sm">今日统计</h3>
|
||||
<div className="bg-gray-50 rounded-lg border border-gray-100 p-3">
|
||||
<div className="space-y-2 text-xs">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600">任务数</span>
|
||||
<span className="font-medium text-gray-900">8 个</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600">成功</span>
|
||||
<span className="font-medium text-green-600">6 个</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600">进行中</span>
|
||||
<span className="font-medium text-orange-600">2 个</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 下一步行动 */}
|
||||
<div>
|
||||
<h3 className="font-bold text-gray-900 mb-3 text-sm flex items-center gap-2">
|
||||
<span className="w-5 h-5 bg-orange-500 rounded-full flex items-center justify-center text-white text-xs">
|
||||
<Target className="w-3 h-3" />
|
||||
</span>
|
||||
下一步行动
|
||||
</h3>
|
||||
<div className="ml-7 space-y-2">
|
||||
<h4 className="text-xs font-semibold text-gray-900 mb-2">立即执行 (今天)</h4>
|
||||
<ul className="space-y-2">
|
||||
<li className="flex items-start gap-2 text-xs text-gray-600">
|
||||
<div className="w-3 h-3 border border-gray-300 rounded-sm mt-0.5 flex-shrink-0"></div>
|
||||
<span>初始化项目结构</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2 text-xs text-gray-600">
|
||||
<div className="w-3 h-3 border border-gray-300 rounded-sm mt-0.5 flex-shrink-0"></div>
|
||||
<span>创建核心系统代码</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2 text-xs text-gray-600">
|
||||
<div className="w-3 h-3 border border-gray-300 rounded-sm mt-0.5 flex-shrink-0"></div>
|
||||
<span>集成 OpenClaw SDK</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
70
desktop/src/components/Sidebar.tsx
Normal file
70
desktop/src/components/Sidebar.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import { useChatStore } from '../store/chatStore';
|
||||
import { Settings, Cat, Search, Globe, BarChart } from 'lucide-react';
|
||||
|
||||
export function Sidebar() {
|
||||
const { agents, currentAgent, setCurrentAgent } = useChatStore();
|
||||
const [activeTab, setActiveTab] = React.useState('agents');
|
||||
|
||||
return (
|
||||
<aside className="w-64 bg-gray-50 border-r border-gray-200 flex flex-col flex-shrink-0">
|
||||
{/* 顶部标签 */}
|
||||
<div className="flex border-b border-gray-200 bg-white">
|
||||
<button
|
||||
className={lex-1 py-3 px-4 text-xs font-medium }
|
||||
onClick={() => setActiveTab('agents')}
|
||||
>
|
||||
分身
|
||||
</button>
|
||||
<button
|
||||
className={lex-1 py-3 px-4 text-xs font-medium }
|
||||
onClick={() => setActiveTab('channels')}
|
||||
>
|
||||
IM 频道
|
||||
</button>
|
||||
<button
|
||||
className={lex-1 py-3 px-4 text-xs font-medium }
|
||||
onClick={() => setActiveTab('tasks')}
|
||||
>
|
||||
定时任务
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Agent 列表 */}
|
||||
<div className="flex-1 overflow-y-auto custom-scrollbar py-2">
|
||||
{agents.map((agent) => (
|
||||
<div
|
||||
key={agent.id}
|
||||
className={sidebar-item mx-2 px-3 py-3 rounded-lg cursor-pointer mb-1 }
|
||||
onClick={() => setCurrentAgent(agent)}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className={w-10 h-10 rounded-xl flex items-center justify-center text-white flex-shrink-0}>
|
||||
<span className="text-xl">{agent.icon}</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex justify-between items-center mb-0.5">
|
||||
<span className="font-semibold text-gray-900 truncate">{agent.name}</span>
|
||||
<span className="text-xs text-gray-400">{agent.time}</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 truncate leading-relaxed">{agent.lastMessage}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 底部用户 */}
|
||||
<div className="p-3 border-t border-gray-200 bg-gray-50">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 bg-gradient-to-br from-orange-400 to-red-500 rounded-full flex items-center justify-center text-white text-xs font-bold">
|
||||
🦞
|
||||
</div>
|
||||
<span className="font-medium text-gray-700">用户7141</span>
|
||||
<button className="ml-auto text-gray-400 hover:text-gray-600">
|
||||
<Settings className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user