Files
aiagent/frontend/src/components/MainLayout.vue
renjianbo 68fbadae76 feat: add 8 builtin tools, AgentSchedules management page, Celery Beat integration
- Add 3 schedule tools (create/list/delete) and 5 utility tools (crypto, random, email, URL, regex)
- Add frontend AgentSchedules.vue page with full CRUD, cron presets, manual trigger
- Integrate Celery Beat for automatic schedule execution
- Update startup scripts with Celery Beat launch
- Fix schedule list API to show all schedules for admin users
- Add celrybeat-schedule.* to .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-02 19:14:25 +08:00

223 lines
6.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="main-layout">
<el-container>
<el-header>
<div class="header-content">
<h1>低代码智能体平台</h1>
<div class="header-actions">
<span v-if="userStore.user">欢迎{{ userStore.user.username }}</span>
<el-button @click="handleLogout">退出</el-button>
</div>
</div>
</el-header>
<el-main>
<!-- 导航菜单 -->
<el-menu
:default-active="activeMenu"
class="nav-menu"
mode="horizontal"
:ellipsis="false"
@select="handleMenuSelect"
>
<el-menu-item index="console" @click="router.push('/console')">
<el-icon><Grid /></el-icon>
<span>主控台</span>
</el-menu-item>
<el-menu-item index="workflows">
<el-icon><Document /></el-icon>
<span>工作流管理</span>
</el-menu-item>
<el-menu-item index="agents">
<el-icon><User /></el-icon>
<span>Agent管理</span>
</el-menu-item>
<el-menu-item index="agent-chat" @click="router.push('/agent-chat')">
<el-icon><ChatLineSquare /></el-icon>
<span>Agent对话</span>
</el-menu-item>
<el-menu-item index="agent-schedules" @click="router.push('/agent-schedules')">
<el-icon><Clock /></el-icon>
<span>定时任务</span>
</el-menu-item>
<el-menu-item index="executions">
<el-icon><List /></el-icon>
<span>执行历史</span>
</el-menu-item>
<el-menu-item index="data-sources" @click="router.push('/data-sources')">
<el-icon><Connection /></el-icon>
<span>数据源管理</span>
</el-menu-item>
<el-menu-item index="tools" @click="router.push('/tools')">
<el-icon><Tools /></el-icon>
<span>工具市场</span>
</el-menu-item>
<el-menu-item index="model-configs" @click="router.push('/model-configs')">
<el-icon><Setting /></el-icon>
<span>模型配置管理</span>
</el-menu-item>
<el-menu-item index="node-templates" @click="router.push('/node-templates')">
<el-icon><Document /></el-icon>
<span>节点模板</span>
</el-menu-item>
<el-menu-item index="template-market" @click="router.push('/template-market')">
<el-icon><Star /></el-icon>
<span>模板市场</span>
</el-menu-item>
<el-menu-item
v-if="userStore.user?.role === 'admin'"
index="permissions"
@click="router.push('/permissions')"
>
<el-icon><Lock /></el-icon>
<span>权限管理</span>
</el-menu-item>
<el-menu-item index="monitoring" @click="router.push('/monitoring')">
<el-icon><Monitor /></el-icon>
<span>系统监控</span>
</el-menu-item>
<el-menu-item index="agent-monitoring" @click="router.push('/agent-monitoring')">
<el-icon><DataAnalysis /></el-icon>
<span>Agent监控</span>
</el-menu-item>
<el-menu-item index="alert-rules" @click="router.push('/alert-rules')">
<el-icon><Bell /></el-icon>
<span>告警规则</span>
</el-menu-item>
</el-menu>
<!-- 页面内容 -->
<div class="page-content">
<slot />
</div>
</el-main>
</el-container>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { Document, User, List, Connection, Setting, Star, Lock, Monitor, Bell, Grid, DataAnalysis, Tools, Clock } from '@element-plus/icons-vue'
const router = useRouter()
const route = useRoute()
const userStore = useUserStore()
// 当前激活的菜单
const activeMenu = computed(() => {
if (route.path === '/console') return 'console'
if (route.path === '/execution-board') return 'console'
if (route.path === '/' || route.path === '/workflow' || route.path.startsWith('/workflow/')) return 'workflows'
if (route.path === '/agents' || route.path.startsWith('/agents/')) return 'agents'
if (route.path === '/executions' || route.path.startsWith('/executions/')) return 'executions'
if (route.path === '/data-sources') return 'data-sources'
if (route.path === '/tools') return 'tools'
if (route.path === '/model-configs') return 'model-configs'
if (route.path === '/node-templates') return 'node-templates'
if (route.path === '/permissions') return 'permissions'
if (route.path === '/template-market') return 'template-market'
if (route.path === '/monitoring') return 'monitoring'
if (route.path === '/agent-monitoring') return 'agent-monitoring'
if (route.path === '/alert-rules') return 'alert-rules'
if (route.path === '/agent-chat' || route.path.startsWith('/agent-chat/')) return 'agent-chat'
if (route.path === '/agent-schedules') return 'agent-schedules'
return 'workflows'
})
// 菜单选择
const handleMenuSelect = (key: string) => {
if (key === 'console') {
router.push('/console')
} else if (key === 'workflows') {
router.push('/')
} else if (key === 'agents') {
router.push('/agents')
} else if (key === 'executions') {
router.push('/executions')
} else if (key === 'data-sources') {
router.push('/data-sources')
} else if (key === 'tools') {
router.push('/tools')
} else if (key === 'model-configs') {
router.push('/model-configs')
} else if (key === 'node-templates') {
router.push('/node-templates')
} else if (key === 'template-market') {
router.push('/template-market')
} else if (key === 'permissions') {
router.push('/permissions')
} else if (key === 'monitoring') {
router.push('/monitoring')
} else if (key === 'agent-monitoring') {
router.push('/agent-monitoring')
} else if (key === 'alert-rules') {
router.push('/alert-rules')
} else if (key === 'agent-schedules') {
router.push('/agent-schedules')
}
}
// 退出登录
const handleLogout = () => {
userStore.logout()
router.push('/login')
}
</script>
<style scoped>
.main-layout {
width: 100%;
height: 100vh;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
height: 100%;
padding: 0 20px;
background: #409eff;
color: white;
}
.header-content h1 {
margin: 0;
font-size: 20px;
font-weight: 500;
}
.header-actions {
display: flex;
align-items: center;
gap: 15px;
}
.nav-menu {
margin-bottom: 20px;
border-bottom: 1px solid #e4e7ed;
}
:deep(.el-menu--horizontal) {
border-bottom: 1px solid #e4e7ed;
}
:deep(.el-menu-item) {
height: 50px;
line-height: 50px;
}
:deep(.el-main) {
display: flex;
flex-direction: column;
padding: 20px;
}
.page-content {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
</style>