667 lines
14 KiB
Markdown
667 lines
14 KiB
Markdown
|
|
# 前端项目架构设计文档 (DESIGN)
|
|||
|
|
|
|||
|
|
## 任务名称
|
|||
|
|
frontend-vue3
|
|||
|
|
|
|||
|
|
## 整体架构图
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
subgraph "前端应用 (Vue3)"
|
|||
|
|
A[App.vue] --> B[Vue Router]
|
|||
|
|
B --> C1[Models 模型管理]
|
|||
|
|
B --> C2[KnowledgeBase 知识库]
|
|||
|
|
B --> C3[Conversations 对话列表]
|
|||
|
|
B --> C4[Chat 聊天页]
|
|||
|
|
B --> C5[Agent 执行页]
|
|||
|
|
|
|||
|
|
C1 --> D1[API: models.js]
|
|||
|
|
C2 --> D2[API: kb.js]
|
|||
|
|
C3 --> D3[API: conversations.js]
|
|||
|
|
C4 --> D3
|
|||
|
|
C5 --> D4[API: agent.js]
|
|||
|
|
|
|||
|
|
D1 --> E[Axios Client]
|
|||
|
|
D2 --> E
|
|||
|
|
D3 --> E
|
|||
|
|
D4 --> E
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
E -->|HTTP Request| F[FastAPI Backend<br/>:8000/api/v1]
|
|||
|
|
|
|||
|
|
subgraph "公共层"
|
|||
|
|
G[Error Handler<br/>错误拦截器]
|
|||
|
|
H[Loading State<br/>加载状态]
|
|||
|
|
I[Message Tips<br/>消息提示]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
E --> G
|
|||
|
|
E --> H
|
|||
|
|
E --> I
|
|||
|
|
|
|||
|
|
style A fill:#e1f5fe
|
|||
|
|
style E fill:#fff3e0
|
|||
|
|
style F fill:#f3e5f5
|
|||
|
|
style G fill:#ffebee
|
|||
|
|
style H fill:#e8f5e9
|
|||
|
|
style I fill:#fff9c4
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 系统分层设计
|
|||
|
|
|
|||
|
|
### 1. 展示层 (Views)
|
|||
|
|
**职责**: 页面渲染、用户交互、状态展示
|
|||
|
|
|
|||
|
|
**核心页面**:
|
|||
|
|
- `Models.vue`: 模型管理页
|
|||
|
|
- `KnowledgeBase.vue`: 知识库管理页
|
|||
|
|
- `Conversations.vue`: 对话列表页
|
|||
|
|
- `Chat.vue`: 聊天界面
|
|||
|
|
- `Agent.vue`: Agent 执行页
|
|||
|
|
|
|||
|
|
**页面设计规范**:
|
|||
|
|
- 使用 Composition API (`<script setup>`)
|
|||
|
|
- 表单使用 Element Plus Form 组件
|
|||
|
|
- 数据表格使用 ElTable
|
|||
|
|
- 弹窗使用 ElDialog
|
|||
|
|
|
|||
|
|
### 2. 服务层 (API)
|
|||
|
|
**职责**: 封装 HTTP 请求、数据转换、错误处理
|
|||
|
|
|
|||
|
|
**API 模块**:
|
|||
|
|
```javascript
|
|||
|
|
// src/api/client.js - Axios 实例
|
|||
|
|
axios.create({
|
|||
|
|
baseURL: import.meta.env.VITE_API_BASE_URL,
|
|||
|
|
timeout: 30000,
|
|||
|
|
headers: { 'Content-Type': 'application/json' }
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// src/api/models.js - 模型管理
|
|||
|
|
export const modelAPI = {
|
|||
|
|
list(type?: string), // GET /models
|
|||
|
|
create(data), // POST /models
|
|||
|
|
getById(id), // GET /models/:id
|
|||
|
|
update(id, data), // PATCH /models/:id
|
|||
|
|
delete(id) // DELETE /models/:id
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// src/api/kb.js - 知识库
|
|||
|
|
export const kbAPI = {
|
|||
|
|
list(), // GET /kb
|
|||
|
|
create(data), // POST /kb
|
|||
|
|
getById(id), // GET /kb/:id
|
|||
|
|
delete(id), // DELETE /kb/:id
|
|||
|
|
ingest(id, data), // POST /kb/:id/ingest
|
|||
|
|
query(id, data), // POST /kb/:id/query
|
|||
|
|
getStatus(id) // GET /kb/:id/status
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// src/api/conversations.js - 对话
|
|||
|
|
export const conversationAPI = {
|
|||
|
|
create(data), // POST /conversations
|
|||
|
|
getById(id), // GET /conversations/:id
|
|||
|
|
delete(id), // DELETE /conversations/:id
|
|||
|
|
getMessages(id, params), // GET /conversations/:id/messages
|
|||
|
|
chat(id, data) // POST /conversations/:id/chat
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// src/api/agent.js - Agent
|
|||
|
|
export const agentAPI = {
|
|||
|
|
execute(data), // POST /agent/execute
|
|||
|
|
getLogs(agentId, params) // GET /agent/logs/:agent_id
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 路由层 (Router)
|
|||
|
|
**职责**: 页面导航、路由守卫、参数传递
|
|||
|
|
|
|||
|
|
**路由配置**:
|
|||
|
|
```javascript
|
|||
|
|
// src/router/index.js
|
|||
|
|
const routes = [
|
|||
|
|
{
|
|||
|
|
path: '/',
|
|||
|
|
redirect: '/models'
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
path: '/models',
|
|||
|
|
name: 'Models',
|
|||
|
|
component: () => import('@/views/Models.vue')
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
path: '/knowledge-base',
|
|||
|
|
name: 'KnowledgeBase',
|
|||
|
|
component: () => import('@/views/KnowledgeBase.vue')
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
path: '/conversations',
|
|||
|
|
name: 'Conversations',
|
|||
|
|
component: () => import('@/views/Conversations.vue')
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
path: '/conversations/:id/chat',
|
|||
|
|
name: 'Chat',
|
|||
|
|
component: () => import('@/views/Chat.vue'),
|
|||
|
|
props: true
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
path: '/agent',
|
|||
|
|
name: 'Agent',
|
|||
|
|
component: () => import('@/views/Agent.vue')
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 工具层 (Utils)
|
|||
|
|
**职责**: 通用函数、常量定义、辅助工具
|
|||
|
|
|
|||
|
|
**工具模块**:
|
|||
|
|
```javascript
|
|||
|
|
// src/utils/request.js - 请求拦截器
|
|||
|
|
// src/utils/message.js - 消息提示封装
|
|||
|
|
// src/utils/validator.js - 表单验证规则
|
|||
|
|
// src/utils/constants.js - 常量定义
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 核心组件设计
|
|||
|
|
|
|||
|
|
### Component 1: Models.vue (模型管理)
|
|||
|
|
|
|||
|
|
**功能模块**:
|
|||
|
|
1. 模型列表展示(表格)
|
|||
|
|
2. 类型筛选(LLM / Embedding)
|
|||
|
|
3. 创建模型弹窗
|
|||
|
|
4. 编辑/删除操作
|
|||
|
|
5. 设置默认模型
|
|||
|
|
|
|||
|
|
**数据流**:
|
|||
|
|
```mermaid
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant U as User
|
|||
|
|
participant V as Models.vue
|
|||
|
|
participant API as modelAPI
|
|||
|
|
participant B as Backend
|
|||
|
|
|
|||
|
|
U->>V: 访问页面
|
|||
|
|
V->>API: modelAPI.list()
|
|||
|
|
API->>B: GET /models
|
|||
|
|
B-->>API: 模型列表
|
|||
|
|
API-->>V: 渲染表格
|
|||
|
|
|
|||
|
|
U->>V: 点击"创建模型"
|
|||
|
|
V->>V: 打开表单弹窗
|
|||
|
|
U->>V: 填写表单并提交
|
|||
|
|
V->>API: modelAPI.create(data)
|
|||
|
|
API->>B: POST /models
|
|||
|
|
B-->>API: 创建成功
|
|||
|
|
API-->>V: 更新列表
|
|||
|
|
V->>U: 提示成功
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**核心状态**:
|
|||
|
|
```javascript
|
|||
|
|
const modelList = ref([])
|
|||
|
|
const loading = ref(false)
|
|||
|
|
const dialogVisible = ref(false)
|
|||
|
|
const formData = ref({
|
|||
|
|
name: '',
|
|||
|
|
type: 'llm',
|
|||
|
|
config: {},
|
|||
|
|
is_default: false
|
|||
|
|
})
|
|||
|
|
const typeFilter = ref('')
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Component 2: KnowledgeBase.vue (知识库管理)
|
|||
|
|
|
|||
|
|
**功能模块**:
|
|||
|
|
1. 知识库列表
|
|||
|
|
2. 创建知识库
|
|||
|
|
3. 文档摄取(多文档输入)
|
|||
|
|
4. 向量查询
|
|||
|
|
5. 状态查看(文档数、索引状态)
|
|||
|
|
6. 删除知识库
|
|||
|
|
|
|||
|
|
**文档摄取界面**:
|
|||
|
|
- 支持动态添加多个文档
|
|||
|
|
- 每个文档包含:title, content, source, metadata
|
|||
|
|
- 选择 embedding 模型
|
|||
|
|
- 提交后显示成功(不追踪状态)
|
|||
|
|
|
|||
|
|
**查询界面**:
|
|||
|
|
- 输入查询文本
|
|||
|
|
- 选择 k 值(返回数量)
|
|||
|
|
- 展示结果列表(content + score)
|
|||
|
|
|
|||
|
|
**核心状态**:
|
|||
|
|
```javascript
|
|||
|
|
const kbList = ref([])
|
|||
|
|
const currentKb = ref(null)
|
|||
|
|
const ingestDialogVisible = ref(false)
|
|||
|
|
const queryDialogVisible = ref(false)
|
|||
|
|
const documents = ref([{ title: '', content: '', source: '', metadata: {} }])
|
|||
|
|
const queryForm = ref({ query: '', k: 3 })
|
|||
|
|
const queryResults = ref([])
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Component 3: Conversations.vue (对话列表)
|
|||
|
|
|
|||
|
|
**功能模块**:
|
|||
|
|
1. 会话列表展示
|
|||
|
|
2. 创建新会话(user_id + title)
|
|||
|
|
3. 跳转到聊天页
|
|||
|
|
4. 删除会话
|
|||
|
|
|
|||
|
|
**核心状态**:
|
|||
|
|
```javascript
|
|||
|
|
const conversationList = ref([])
|
|||
|
|
const createDialogVisible = ref(false)
|
|||
|
|
const newConversation = ref({ user_id: 1, title: '' })
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Component 4: Chat.vue (聊天界面)
|
|||
|
|
|
|||
|
|
**功能模块**:
|
|||
|
|
1. 消息历史展示(分页加载)
|
|||
|
|
2. 发送消息
|
|||
|
|
3. RAG 开关
|
|||
|
|
4. 选择知识库和 LLM
|
|||
|
|
5. 显示来源(sources)
|
|||
|
|
|
|||
|
|
**分页加载策略**:
|
|||
|
|
- 初始加载: limit=50, offset=0
|
|||
|
|
- "加载更多"按钮: offset += 50
|
|||
|
|
- 消息逆序展示(最新在下)
|
|||
|
|
|
|||
|
|
**消息展示**:
|
|||
|
|
```vue
|
|||
|
|
<div class="message-list">
|
|||
|
|
<div v-for="msg in messages" :key="msg.id" :class="msg.role">
|
|||
|
|
<div class="content">{{ msg.content }}</div>
|
|||
|
|
<div v-if="msg.msg_metadata?.sources" class="sources">
|
|||
|
|
来源: {{ msg.msg_metadata.sources }}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**核心状态**:
|
|||
|
|
```javascript
|
|||
|
|
const conversationId = ref(route.params.id)
|
|||
|
|
const messages = ref([])
|
|||
|
|
const inputText = ref('')
|
|||
|
|
const useRag = ref(true)
|
|||
|
|
const selectedKbId = ref(null)
|
|||
|
|
const selectedLlm = ref(null)
|
|||
|
|
const pagination = ref({ limit: 50, offset: 0, hasMore: true })
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Component 5: Agent.vue (Agent 执行)
|
|||
|
|
|
|||
|
|
**功能模块**:
|
|||
|
|
1. 任务输入
|
|||
|
|
2. 选择知识库(可选)
|
|||
|
|
3. 选择 LLM
|
|||
|
|
4. 执行结果展示
|
|||
|
|
5. 工具调用日志(自动展示)
|
|||
|
|
|
|||
|
|
**执行流程**:
|
|||
|
|
```mermaid
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant U as User
|
|||
|
|
participant V as Agent.vue
|
|||
|
|
participant API as agentAPI
|
|||
|
|
participant B as Backend
|
|||
|
|
|
|||
|
|
U->>V: 输入任务并提交
|
|||
|
|
V->>API: agentAPI.execute(data)
|
|||
|
|
API->>B: POST /agent/execute
|
|||
|
|
B-->>API: { agent_id, output, success }
|
|||
|
|
API-->>V: 展示结果
|
|||
|
|
|
|||
|
|
V->>API: agentAPI.getLogs(agent_id)
|
|||
|
|
API->>B: GET /agent/logs/:agent_id
|
|||
|
|
B-->>API: { tool_calls: [...] }
|
|||
|
|
API-->>V: 展示日志表格
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**核心状态**:
|
|||
|
|
```javascript
|
|||
|
|
const taskInput = ref('')
|
|||
|
|
const selectedKbId = ref(null)
|
|||
|
|
const selectedLlm = ref(null)
|
|||
|
|
const executionResult = ref(null)
|
|||
|
|
const toolCallLogs = ref([])
|
|||
|
|
const executing = ref(false)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 接口契约定义
|
|||
|
|
|
|||
|
|
### Request 数据结构
|
|||
|
|
|
|||
|
|
**创建模型**:
|
|||
|
|
```typescript
|
|||
|
|
interface CreateModelRequest {
|
|||
|
|
name: string
|
|||
|
|
type: 'llm' | 'embedding'
|
|||
|
|
config: Record<string, any>
|
|||
|
|
is_default?: boolean
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**文档摄取**:
|
|||
|
|
```typescript
|
|||
|
|
interface IngestRequest {
|
|||
|
|
documents: Array<{
|
|||
|
|
content: string
|
|||
|
|
title?: string
|
|||
|
|
source?: string
|
|||
|
|
metadata?: Record<string, any>
|
|||
|
|
}>
|
|||
|
|
embedding_name: string
|
|||
|
|
background?: boolean // 固定为 true
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**发送消息**:
|
|||
|
|
```typescript
|
|||
|
|
interface ChatRequest {
|
|||
|
|
user_input: string
|
|||
|
|
kb_id?: number
|
|||
|
|
llm_name?: string
|
|||
|
|
use_rag?: boolean
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**执行 Agent**:
|
|||
|
|
```typescript
|
|||
|
|
interface AgentExecuteRequest {
|
|||
|
|
task: string
|
|||
|
|
kb_id?: number
|
|||
|
|
llm_name?: string
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Response 数据结构
|
|||
|
|
|
|||
|
|
**模型列表**:
|
|||
|
|
```typescript
|
|||
|
|
interface ModelResponse {
|
|||
|
|
id: number
|
|||
|
|
name: string
|
|||
|
|
type: 'llm' | 'embedding'
|
|||
|
|
config: Record<string, any>
|
|||
|
|
is_default: boolean
|
|||
|
|
status: string
|
|||
|
|
created_at: string
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**查询结果**:
|
|||
|
|
```typescript
|
|||
|
|
interface QueryResponse {
|
|||
|
|
results: Array<{
|
|||
|
|
content: string
|
|||
|
|
metadata: Record<string, any>
|
|||
|
|
score: number
|
|||
|
|
}>
|
|||
|
|
result_count: number
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**消息响应**:
|
|||
|
|
```typescript
|
|||
|
|
interface MessageResponse {
|
|||
|
|
message_id: number
|
|||
|
|
conversation_id: number
|
|||
|
|
role: 'user' | 'assistant'
|
|||
|
|
content: string
|
|||
|
|
metadata?: {
|
|||
|
|
sources?: Array<{ title: string, source: string }>
|
|||
|
|
model?: string
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Agent 日志**:
|
|||
|
|
```typescript
|
|||
|
|
interface ToolCallLog {
|
|||
|
|
id: number
|
|||
|
|
agent_id: string
|
|||
|
|
tool_name: string
|
|||
|
|
call_input: Record<string, any>
|
|||
|
|
call_output: Record<string, any>
|
|||
|
|
created_at: string
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 异常处理策略
|
|||
|
|
|
|||
|
|
### HTTP 错误拦截
|
|||
|
|
|
|||
|
|
**Axios Response Interceptor**:
|
|||
|
|
```javascript
|
|||
|
|
// src/api/client.js
|
|||
|
|
axios.interceptors.response.use(
|
|||
|
|
response => response.data,
|
|||
|
|
error => {
|
|||
|
|
const { response } = error
|
|||
|
|
|
|||
|
|
if (!response) {
|
|||
|
|
ElMessage.error('网络连接失败,请检查网络')
|
|||
|
|
return Promise.reject(error)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const { status, data } = response
|
|||
|
|
const message = data?.detail || '请求失败'
|
|||
|
|
|
|||
|
|
switch (status) {
|
|||
|
|
case 400:
|
|||
|
|
ElMessage.error(`请求错误: ${message}`)
|
|||
|
|
break
|
|||
|
|
case 404:
|
|||
|
|
ElMessage.error(`资源不存在: ${message}`)
|
|||
|
|
break
|
|||
|
|
case 500:
|
|||
|
|
ElMessage.error(`服务器错误: ${message}`)
|
|||
|
|
break
|
|||
|
|
default:
|
|||
|
|
ElMessage.error(`错误 ${status}: ${message}`)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return Promise.reject(error)
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 表单验证规则
|
|||
|
|
|
|||
|
|
**Element Plus Rules**:
|
|||
|
|
```javascript
|
|||
|
|
// src/utils/validator.js
|
|||
|
|
export const modelRules = {
|
|||
|
|
name: [
|
|||
|
|
{ required: true, message: '请输入模型名称', trigger: 'blur' },
|
|||
|
|
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
|||
|
|
],
|
|||
|
|
type: [
|
|||
|
|
{ required: true, message: '请选择模型类型', trigger: 'change' }
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const kbRules = {
|
|||
|
|
name: [
|
|||
|
|
{ required: true, message: '请输入知识库名称', trigger: 'blur' }
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const chatRules = {
|
|||
|
|
user_input: [
|
|||
|
|
{ required: true, message: '请输入消息内容', trigger: 'blur' }
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 加载状态管理
|
|||
|
|
|
|||
|
|
**统一 Loading 处理**:
|
|||
|
|
```javascript
|
|||
|
|
// 组件内使用
|
|||
|
|
const loading = ref(false)
|
|||
|
|
|
|||
|
|
const fetchData = async () => {
|
|||
|
|
loading.value = true
|
|||
|
|
try {
|
|||
|
|
const data = await modelAPI.list()
|
|||
|
|
// 处理数据
|
|||
|
|
} catch (error) {
|
|||
|
|
// 错误已被拦截器处理
|
|||
|
|
} finally {
|
|||
|
|
loading.value = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 数据流向图
|
|||
|
|
|
|||
|
|
### 对话流程数据流
|
|||
|
|
```mermaid
|
|||
|
|
flowchart LR
|
|||
|
|
A[用户输入消息] --> B{是否启用RAG?}
|
|||
|
|
B -->|是| C[选择知识库]
|
|||
|
|
B -->|否| D[直接发送]
|
|||
|
|
C --> E[构造请求]
|
|||
|
|
D --> E
|
|||
|
|
E --> F[POST /conversations/:id/chat]
|
|||
|
|
F --> G{请求成功?}
|
|||
|
|
G -->|是| H[追加消息到列表]
|
|||
|
|
G -->|否| I[显示错误]
|
|||
|
|
H --> J[滚动到底部]
|
|||
|
|
I --> K[用户重试]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Agent 执行数据流
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TB
|
|||
|
|
A[输入任务] --> B[选择配置]
|
|||
|
|
B --> C[POST /agent/execute]
|
|||
|
|
C --> D{执行成功?}
|
|||
|
|
D -->|是| E[显示输出]
|
|||
|
|
D -->|否| F[显示错误]
|
|||
|
|
E --> G[GET /agent/logs/:agent_id]
|
|||
|
|
G --> H[展示工具调用日志]
|
|||
|
|
H --> I[用户查看详情]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 布局设计
|
|||
|
|
|
|||
|
|
### 主布局结构
|
|||
|
|
```vue
|
|||
|
|
<!-- App.vue -->
|
|||
|
|
<el-container>
|
|||
|
|
<el-aside width="200px">
|
|||
|
|
<el-menu router>
|
|||
|
|
<el-menu-item index="/models">模型管理</el-menu-item>
|
|||
|
|
<el-menu-item index="/knowledge-base">知识库</el-menu-item>
|
|||
|
|
<el-menu-item index="/conversations">对话</el-menu-item>
|
|||
|
|
<el-menu-item index="/agent">Agent</el-menu-item>
|
|||
|
|
</el-menu>
|
|||
|
|
</el-aside>
|
|||
|
|
<el-main>
|
|||
|
|
<router-view />
|
|||
|
|
</el-main>
|
|||
|
|
</el-container>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 聊天页布局
|
|||
|
|
```vue
|
|||
|
|
<!-- Chat.vue -->
|
|||
|
|
<el-container direction="vertical">
|
|||
|
|
<el-header>
|
|||
|
|
<div class="chat-config">
|
|||
|
|
<el-switch v-model="useRag" label="启用RAG" />
|
|||
|
|
<el-select v-model="selectedKbId" v-if="useRag">...</el-select>
|
|||
|
|
<el-select v-model="selectedLlm">...</el-select>
|
|||
|
|
</div>
|
|||
|
|
</el-header>
|
|||
|
|
|
|||
|
|
<el-main class="message-area">
|
|||
|
|
<el-button @click="loadMore" v-if="hasMore">加载更多</el-button>
|
|||
|
|
<div v-for="msg in messages" :key="msg.id">...</div>
|
|||
|
|
</el-main>
|
|||
|
|
|
|||
|
|
<el-footer>
|
|||
|
|
<el-input v-model="inputText" @keyup.enter="sendMessage" />
|
|||
|
|
<el-button @click="sendMessage">发送</el-button>
|
|||
|
|
</el-footer>
|
|||
|
|
</el-container>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 环境配置
|
|||
|
|
|
|||
|
|
### 开发环境
|
|||
|
|
```bash
|
|||
|
|
# .env.development
|
|||
|
|
VITE_API_BASE_URL=http://localhost:8000/api/v1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 生产环境
|
|||
|
|
```bash
|
|||
|
|
# .env.production
|
|||
|
|
VITE_API_BASE_URL=https://your-production-domain.com/api/v1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Vite 配置
|
|||
|
|
```javascript
|
|||
|
|
// vite.config.js
|
|||
|
|
export default defineConfig({
|
|||
|
|
plugins: [vue()],
|
|||
|
|
server: {
|
|||
|
|
port: 5173,
|
|||
|
|
proxy: {
|
|||
|
|
'/api': {
|
|||
|
|
target: 'http://localhost:8000',
|
|||
|
|
changeOrigin: true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
resolve: {
|
|||
|
|
alias: {
|
|||
|
|
'@': fileURLToPath(new URL('./src', import.meta.url))
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 依赖管理
|
|||
|
|
|
|||
|
|
### 核心依赖
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"dependencies": {
|
|||
|
|
"vue": "^3.4.0",
|
|||
|
|
"vue-router": "^4.2.5",
|
|||
|
|
"axios": "^1.6.2",
|
|||
|
|
"element-plus": "^2.5.0",
|
|||
|
|
"@element-plus/icons-vue": "^2.3.1"
|
|||
|
|
},
|
|||
|
|
"devDependencies": {
|
|||
|
|
"@vitejs/plugin-vue": "^5.0.0",
|
|||
|
|
"vite": "^5.0.0"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 设计原则总结
|
|||
|
|
|
|||
|
|
1. **单一职责**: 每个组件只负责一个功能模块
|
|||
|
|
2. **API 封装**: 所有 HTTP 请求集中在 `src/api/`
|
|||
|
|
3. **错误优先**: 统一拦截器 + 详细提示
|
|||
|
|
4. **用户体验**: Loading 状态 + 操作反馈
|
|||
|
|
5. **可维护性**: 清晰的目录结构 + 模块化设计
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**架构设计完成,进入任务拆分阶段。**
|