chore: 添加 .gitignore 规则,包含前端、pnpm、Node.js 和 AI 工具

This commit is contained in:
2026-03-20 09:14:58 +08:00
parent bf294f9f50
commit 176a727f6e
50 changed files with 6436 additions and 0 deletions

228
src/pages/ConsolePage.jsx Normal file
View File

@@ -0,0 +1,228 @@
import { useState, useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { FiPlus, FiClock, FiList, FiUsers } from 'react-icons/fi';
import { FaPuzzlePiece } from 'react-icons/fa';
import Layout from '../components/Layout.jsx';
import { conversations, getChatScenes } from '../data/conversations.js';
import { skills } from '../data/skills.js';
import ChatPage from './console/ChatPage.jsx';
import SkillsPage from './console/SkillsPage.jsx';
import SkillDetailPage from './console/SkillDetailPage.jsx';
import LogsPage from './console/LogsPage.jsx';
import TasksPage from './console/TasksPage.jsx';
import TaskDetailPage from './console/TaskDetailPage.jsx';
import AccountPage from './console/AccountPage.jsx';
import ProjectsPage from './console/ProjectsPage.jsx';
import MemberConfigPage from './console/MemberConfigPage.jsx';
import AddMemberPage from './console/AddMemberPage.jsx';
function ConsolePage() {
const location = useLocation();
const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(() => {
return localStorage.getItem('console_currentPage') || 'chat';
});
const [currentScene, setCurrentScene] = useState(() => {
return localStorage.getItem('console_currentScene') || 'welcome';
});
const [currentSkillId, setCurrentSkillId] = useState(null);
const [currentTaskId, setCurrentTaskId] = useState(null);
useEffect(() => {
if (location.state?.fromHome) {
setCurrentPage('chat');
setCurrentScene('welcome');
navigate('.', { replace: true, state: {} });
}
}, [location.state, navigate, setCurrentPage, setCurrentScene]);
useEffect(() => {
localStorage.setItem('console_currentPage', currentPage);
}, [currentPage]);
useEffect(() => {
localStorage.setItem('console_currentScene', currentScene);
}, [currentScene]);
const switchPage = (pageId, data = {}) => {
setCurrentPage(pageId);
if (data.skillId !== undefined) {
setCurrentSkillId(data.skillId);
}
};
const handleSkillClick = (skillId) => {
switchPage('skillDetail', { skillId });
};
const handleBack = () => {
switchPage('skills');
};
const switchChatScene = (scene) => {
setCurrentScene(scene);
if (currentPage !== 'chat') {
setCurrentPage('chat');
}
};
const createNewChat = () => {
setCurrentScene('welcome');
setCurrentPage('chat');
};
const activeScene = currentPage === 'chat' ? currentScene : null;
const renderPage = () => {
switch (currentPage) {
case 'chat':
return <ChatPage scene={currentScene} />;
case 'skills':
return <SkillsPage onSkillClick={handleSkillClick} />;
case 'skillDetail':
return <SkillDetailPage skillId={currentSkillId} onBack={handleBack} />;
case 'logs':
return <LogsPage />;
case 'scheduledTasks':
return <TasksPage
onViewDetail={(taskId) => {
setCurrentTaskId(taskId);
switchPage('taskDetail');
}}
/>;
case 'taskDetail':
return <TaskDetailPage
taskId={currentTaskId}
onBack={() => switchPage('scheduledTasks')}
/>;
case 'account':
return <AccountPage />;
case 'projects':
return <ProjectsPage onAddMember={() => switchPage('addMember')} />;
case 'memberConfig':
return <MemberConfigPage onBack={() => switchPage('projects')} />;
case 'addMember':
return <AddMemberPage onBack={() => switchPage('projects')} />;
default:
return <div>Page not found</div>;
}
};
const getPageTitle = () => {
const pageTitles = {
chat: '智能助手',
skills: '技能市场',
skillDetail: '技能详情',
logs: '日志查询',
scheduledTasks: '定时任务',
taskDetail: '任务详情',
account: '账号管理',
projects: '项目管理',
memberConfig: '成员配置',
addMember: '增加成员'
};
let title = pageTitles[currentPage] || '';
if (currentPage === 'chat') {
const conv = conversations.find(c => c.scene === currentScene);
title = conv?.title || '智能助手';
}
if (currentPage === 'skillDetail' && currentSkillId) {
const skill = skills.find(s => s.id === currentSkillId);
title = skill?.name || '技能详情';
}
return title;
};
const sidebar = (
<>
<div className="chat-sidebar-header">
<div className="sidebar-brand">
<div className="sidebar-logo-icon">
<span></span>
<span></span>
</div>
<div className="sidebar-brand-text">
<div className="sidebar-logo">GrandClaw</div>
<div className="sidebar-subtitle">企业级AI平台</div>
</div>
</div>
<div className="sidebar-divider"></div>
<button className="btn btn-primary" style={{ width: '100%' }} onClick={createNewChat}>
<span style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '6px' }}>
<FiPlus /> 新建对话
</span>
</button>
</div>
<div className="chat-sidebar-content">
{conversations.map(conv => (
<div
key={conv.id}
className={`conversation-item ${conv.scene === activeScene ? 'active' : ''}`}
onClick={() => switchChatScene(conv.scene)}
>
<div className="conversation-title">{conv.title}</div>
<div className="conversation-time">{conv.time}</div>
</div>
))}
</div>
<div className="chat-sidebar-project">
<label className="chat-sidebar-project-label">当前项目</label>
<select className="form-control chat-sidebar-project-select">
<option>企业 AI 智算平台</option>
<option>知识库管理系统</option>
<option>数据分析平台</option>
</select>
</div>
<div className="chat-sidebar-nav">
<div
className={`chat-nav-item ${currentPage === 'skills' ? 'active' : ''}`}
onClick={() => switchPage('skills')}
>
<span className="chat-nav-icon"><FaPuzzlePiece /></span>
<span className="chat-nav-text">技能市场</span>
</div>
<div
className={`chat-nav-item ${currentPage === 'scheduledTasks' ? 'active' : ''}`}
onClick={() => switchPage('scheduledTasks')}
>
<span className="chat-nav-icon"><FiClock /></span>
<span className="chat-nav-text">定时任务</span>
</div>
<div
className={`chat-nav-item ${currentPage === 'logs' ? 'active' : ''}`}
onClick={() => switchPage('logs')}
>
<span className="chat-nav-icon"><FiList /></span>
<span className="chat-nav-text">日志查询</span>
</div>
<div
className={`chat-nav-item ${currentPage === 'projects' ? 'active' : ''}`}
onClick={() => switchPage('projects')}
>
<span className="chat-nav-icon"><FiUsers /></span>
<span className="chat-nav-text">项目管理</span>
</div>
</div>
<div className="chat-sidebar-user" onClick={() => switchPage('account')}>
<div className="user-avatar"></div>
<div className="chat-sidebar-user-info">
<div className="chat-sidebar-user-name">张三</div>
<div className="chat-sidebar-user-role">AI 产品部</div>
</div>
</div>
</>
);
return (
<Layout
sidebar={sidebar}
headerTitle={getPageTitle()}
sidebarClassName="chat-sidebar"
contentClassName={currentPage === 'chat' ? 'page-content-full' : ''}
>
{renderPage()}
</Layout>
);
}
export default ConsolePage;