feat: 更新 Web 前端页面

- 更新 Agents、Chat、Settings 等页面
- 新增 ModelAPIs 页面
- 更新各个模块的 composables
- 更新 vite 配置和依赖版本

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 21:29:01 +08:00
parent 71e8cc59d5
commit ecb6be6463
24 changed files with 1031 additions and 757 deletions

View File

@@ -30,6 +30,8 @@ const {
stats,
isAllSelected,
isIndeterminate,
isAllSelectedEdit,
isIndeterminateEdit,
fetchAgents,
fetchSkills,
fetchModels,
@@ -46,6 +48,8 @@ const {
handleSkillsModeClickEdit,
toggleSelectAll,
clearSkills,
toggleSelectAllEdit,
clearSkillsEdit,
toggleSkillsMode,
selectSkillsMode,
toggleSubSkillsDropdown,
@@ -62,9 +66,21 @@ const {
<div class="p-6 min-h-screen">
<!-- 顶部导航 -->
<div class="flex justify-between items-center mb-6">
<div class="flex items-center gap-2">
<i class="fa-solid fa-robot text-orange-500"></i>
<span class="font-medium">Agents</span>
<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<i class="fa-solid fa-robot text-orange-500 text-xl"></i>
<span class="text-xl font-semibold text-white">Agents</span>
</div>
<div class="flex items-center gap-3 text-sm">
<span class="text-gray-400">Total:</span>
<span class="text-white font-medium">{{ stats.total }}</span>
<span class="w-1 h-1 rounded-full bg-gray-500"></span>
<span class="text-gray-400">Active:</span>
<span class="text-green-400 font-medium">{{ stats.active }}</span>
<span class="w-1 h-1 rounded-full bg-gray-500"></span>
<span class="text-gray-400">Inactive:</span>
<span class="text-gray-400 font-medium">{{ stats.inactive }}</span>
</div>
</div>
<button @click="openCreateModal" class="btn-primary">
<i class="fa-solid fa-plus"></i>
@@ -75,7 +91,7 @@ const {
<!-- 搜索和筛选 -->
<div class="flex gap-4 mb-6">
<div class="flex-1 relative">
<i class="fa-solid fa-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
<i class="fa-solid fa-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-500"></i>
<input
v-model="searchQuery"
type="text"
@@ -92,7 +108,14 @@ const {
<!-- Agents 列表 -->
<div class="bg-dark-700 rounded-xl overflow-hidden">
<table v-if="filteredAgents.length > 0" class="w-full">
<!-- 加载状态 -->
<div v-if="isLoading" class="flex items-center justify-center py-20">
<div class="flex flex-col items-center gap-3">
<i class="fa-solid fa-circle-notch fa-spin text-3xl text-orange-500"></i>
<span class="text-gray-400">Loading agents...</span>
</div>
</div>
<table v-else-if="filteredAgents.length > 0" class="w-full">
<thead class="bg-dark-600">
<tr>
<th class="text-left px-4 py-3 text-sm font-medium text-gray-400">Agent Name</th>
@@ -126,8 +149,8 @@ const {
<span class="bg-dark-500 px-2 py-1 rounded text-sm text-gray-300">{{ agent.model }}</span>
</td>
<td class="px-4 py-3 text-center">
<span class="inline-flex items-center gap-1.5 px-2 py-1 rounded-full text-xs" :class="agent.status === 'active' ? 'bg-green-500/20 text-green-400' : 'bg-gray-500/20 text-gray-400'">
<span class="w-1.5 h-1.5 rounded-full" :class="agent.status === 'active' ? 'bg-green-500' : 'bg-gray-400'"></span>
<span class="inline-flex items-center gap-1.5 px-2 py-1 rounded-full text-xs transition-all duration-200" :class="agent.status === 'active' ? 'bg-green-500/20 text-green-400' : 'bg-gray-500/20 text-gray-400'">
<span class="w-1.5 h-1.5 rounded-full animate-pulse" :class="agent.status === 'active' ? 'bg-green-500' : 'bg-gray-400'"></span>
<span class="capitalize">{{ agent.status }}</span>
</span>
</td>
@@ -139,18 +162,18 @@ const {
class="btn-icon"
:title="agent.status === 'active' ? 'Deactivate' : 'Activate'"
>
<Pause v-if="agent.status === 'active'" class="w-4 h-4 text-gray-400 hover:text-yellow-400" />
<Play v-else class="w-4 h-4 text-gray-400 hover:text-green-400" />
<Pause v-if="agent.status === 'active'" class="w-4 h-4 text-gray-500 hover:text-yellow-400 transition-colors" />
<Play v-else class="w-4 h-4 text-gray-500 hover:text-green-400 transition-colors" />
</button>
<button @click="openEdit(agent)" class="btn-icon" title="Edit">
<Edit class="w-4 h-4 text-gray-400 hover:text-white" />
<Edit class="w-4 h-4 text-gray-500 hover:text-white transition-colors" />
</button>
<button
@click="deleteAgent(agent.id)"
@click.stop="deleteAgent(agent.id)"
class="btn-icon"
title="Delete"
>
<Trash2 class="w-4 h-4 text-gray-400 hover:text-red-400" />
<Trash2 class="w-4 h-4 text-gray-500 hover:text-red-400 transition-colors" />
</button>
</div>
</td>
@@ -159,19 +182,19 @@ const {
</table>
<!-- 空状态 -->
<div v-if="filteredAgents.length === 0" class="empty-box">
<div v-if="filteredAgents.length === 0 && !isLoading" class="empty-box">
<div class="empty-icon">
<i class="fa-solid fa-robot"></i>
</div>
<p class="empty-text">No agents found</p>
<p class="empty-tip">Click "New Agent" to create one</p>
<p class="empty-text">{{ searchQuery || filterStatus !== 'all' ? 'No matching agents found' : 'No agents found' }}</p>
<p class="empty-tip">{{ searchQuery || filterStatus !== 'all' ? 'Try adjusting your search or filter' : 'Click "New Agent" to create one' }}</p>
</div>
</div>
</div>
<!-- 创建智能体弹窗 -->
<Teleport to="body">
<div v-if="showCreateModal" class="fixed inset-0 bg-black/60 flex items-center justify-center z-50">
<div v-if="showCreateModal" class="fixed inset-0 bg-black/60 flex items-center justify-center z-50" @click.self="showCreateModal = false">
<div class="bg-dark-700 rounded-2xl w-full max-w-lg border border-dark-500 shadow-2xl">
<div class="flex items-center justify-between p-5 border-b border-dark-500">
<h3 class="text-lg font-semibold">Create New Agent</h3>
@@ -409,7 +432,7 @@ const {
<!-- 编辑智能体弹窗 -->
<Teleport to="body">
<div v-if="showEditModal" class="fixed inset-0 bg-black/60 flex items-center justify-center z-50">
<div v-if="showEditModal" class="fixed inset-0 bg-black/60 flex items-center justify-center z-50" @click.self="showEditModal = false">
<div class="bg-dark-700 rounded-2xl w-full max-w-lg border border-dark-500 shadow-2xl">
<div class="flex items-center justify-between p-5 border-b border-dark-500">
<h3 class="text-lg font-semibold">Edit Agent</h3>
@@ -548,10 +571,10 @@ const {
</div>
<div class="action-bar">
<label class="checkbox-label cursor-pointer">
<input type="checkbox" :checked="isAllSelected" :indeterminate="isIndeterminate" @change="toggleSelectAll" class="checkbox">
<input type="checkbox" :checked="isAllSelectedEdit" :indeterminate="isIndeterminateEdit" @change="toggleSelectAllEdit" class="checkbox">
<span class="checkbox-text">Select All</span>
</label>
<button v-if="editingAgent.selectedSkills.length > 0" type="button" @click="clearSkills" class="clear-btn">Clear</button>
<button v-if="editingAgent.selectedSkills.length > 0" type="button" @click="clearSkillsEdit" class="clear-btn">Clear</button>
</div>
<div class="options-list">
<template v-if="filteredSkills.length > 0">