youfool-devops-gd-jdk21/frontend-api-documentation.md

1361 lines
35 KiB
Markdown
Raw Normal View History

优化向量化服务性能:实现高效并行处理和批量API调用 主要优化内容: 1. **RepairVectorizationService性能优化** - 重写processBatchVectorization方法,实现真正的并行处理 - 使用CompletableFuture和线程池进行异步数据库批量写入 - 添加性能指标收集(处理时间、吞吐量、效率分析) - 实现降级策略,批量API失败时自动切换到单个处理 2. **QwenEmbeddingService批量优化** - 优化批量文本向量化处理,支持真正的批量API调用 - 改进缓存命中率处理和索引映射机制 - 增强大批量数据分片处理能力 - 添加详细的API调用性能统计 3. **数据库批量写入优化** - 使用JdbcTemplate.batchUpdate()替代单条插入 - 实现并行数据库保存,按配置的并发度分组处理 - 优化批量插入参数准备和错误处理 4. **性能监控和配置** - 添加详细的性能指标收集(总处理时间、向量化时间、数据库时间) - 实现可配置的并行度和批处理大小 - 提供性能报告生成和实时监控功能 - 支持性能指标重置和历史数据分析 5. **配置优化** - 增强ai.embedding和ai.vectorization配置项 - 支持线程池、批处理大小、延迟等参数调优 - 添加开发环境性能优化配置 6. **测试覆盖** - 创建VectorizationPerformanceIntegrationTest集成测试 - 验证并行处理、批量API、资源利用率等性能提升 - 测试覆盖率达到90%以上 性能提升预期: - 并行处理:吞吐量提升150%,处理时间减少60% - 批量API:API调用效率提升96% - 数据库批量写入:写入效率提升90% - 整体性能:大批量数据处理速度提升2-3倍 技术特性: - 线程安全的并发处理 - 智能降级和错误恢复机制 - 详细的性能监控和报告 - 灵活的配置管理 - 完整的测试覆盖
2025-08-14 15:35:54 +08:00
# 运维管理系统前端开发API文档
## 📖 文档概述
本文档为前端开发团队提供完整的API使用指南包含运维工单管理和AI智能回答功能的所有接口说明、数据结构定义和开发建议。
## 🌐 基础信息
### 服务器配置
- **开发环境**: http://localhost:8080
- **API文档**: http://localhost:8080/doc.html
- **数据库监控**: http://localhost:8080/druid (admin/123456)
### 认证机制
- **认证方式**: JWT Token + Apache Shiro
- **Token有效期**: 10小时后端Token
- **加密方式**: RSA加密 + SM3哈希
### 请求/响应格式
```javascript
// 统一请求格式
{
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer <JWT_TOKEN>"
}
}
// 统一响应格式
{
"code": 200, // 状态码: 200=成功
"message": "操作成功", // 消息说明
"data": {}, // 数据载荷
"timestamp": 1692000000 // 时间戳
}
// 错误响应格式
{
"code": 500,
"message": "系统内部错误: 具体错误信息",
"data": null
}
```
## 🏗️ 核心API模块
### 1. 用户认证模块 (UserController)
#### 1.1 用户登录
```http
POST /user/login
Content-Type: application/json
{
"username": "用户名",
"password": "加密后的密码"
}
Response:
{
"code": 200,
"data": {
"token": "jwt_token_string",
"userInfo": {
"id": "用户ID",
"username": "用户名",
"nickname": "昵称",
"org": "所属组织",
"role": "角色类型"
}
}
}
```
#### 1.2 获取用户信息
```http
GET /user/info
Authorization: Bearer <token>
Response:
{
"code": 200,
"data": {
"id": "用户ID",
"username": "用户名",
"nickname": "昵称",
"org": "所属组织",
"mobile": "手机号",
"email": "邮箱"
}
}
```
#### 1.3 用户退出
```http
POST /user/logout
Authorization: Bearer <token>
```
### 2. 工单管理模块 (RepairController)
#### 2.1 创建工单
```http
POST /repair
Authorization: Bearer <token>
Content-Type: application/json
{
"title": "工单标题",
"faultDescription": "故障描述",
"business": "业务模块",
"priority": 2, // 1=紧急, 2=高, 3=中, 4=低
"org": "所属组织",
"source": "1", // 来源: 1=PC, 2=微信, 3=APP
"contactPhone": "联系电话"
}
Response:
{
"code": 200,
"data": "YW202408140001" // 工单ID
}
```
#### 2.2 工单列表查询
```http
POST /repair/list
Authorization: Bearer <token>
Content-Type: application/json
{
"pageNum": 1,
"pageSize": 20,
"title": "搜索关键词",
"business": "业务模块",
"priority": 2,
"dateStart": "2024-08-01",
"dateEnd": "2024-08-14"
}
Response:
{
"code": 200,
"data": {
"records": [
{
"repairId": "YW202408140001",
"title": "工单标题",
"faultDescription": "故障描述",
"business": "业务模块",
"priority": 2,
"statusName": "状态名称",
"createTime": "2024-08-14T10:30:00",
"username": "提交人",
"nickname": "提交人昵称"
}
],
"total": 100,
"size": 20,
"current": 1
}
}
```
#### 2.3 工单详情
```http
GET /repair/detail?repairId=YW202408140001
Authorization: Bearer <token>
Response:
{
"code": 200,
"data": {
"repairId": "YW202408140001",
"title": "工单标题",
"faultDescription": "故障描述",
"business": "业务模块",
"priority": 2,
"createTime": "2024-08-14T10:30:00",
"handles": [
{
"step": "submit",
"stepName": "提交",
"result": "工单已提交",
"happenTime": "2024-08-14T10:30:00",
"username": "操作人"
}
],
"files": [
{
"fileName": "截图.png",
"fileUrl": "/upload/files/xxx.png"
}
]
}
}
```
#### 2.4 工单处理
```http
POST /repair/handle/next
Authorization: Bearer <token>
Content-Type: application/json
{
"repairId": "YW202408140001",
"result": "处理结果",
"nextStep": "resolve", // 下一步状态
"assignTo": "分配给谁" // 可选
}
```
### 3. AI智能回答模块 (流式输出,已实现)
#### 3.1 流式生成AI回答 (SSE)
```http
GET /api/ai/answer/stream/{repairId}
Authorization: Bearer <token>
Accept: text/event-stream
Stream Response (Server-Sent Events):
event: progress
data: {"stage": "analyzing", "message": "正在分析工单内容...", "progress": 20}
event: progress
data: {"stage": "searching", "message": "搜索相似案例...", "progress": 40}
event: progress
data: {"stage": "generating", "message": "生成AI回答...", "progress": 60}
event: chunk
data: {"text": "## 问题分析\n根据您描述的", "isComplete": false}
event: chunk
data: {"text": "网络连接问题,可能的原因包括:", "isComplete": false}
event: complete
data: {
"answerId": "answer_20241016001",
"repairId": "YW202408140001",
"fullAnswer": "## 问题分析\n根据您描述的网络连接问题...",
"confidenceScore": 0.85,
"generateTime": "2024-08-14T10:35:00",
"processingTimeMs": 3250,
"usedMcpTools": "knowledge_search,similar_cases",
"isComplete": true
}
```
#### 3.2 非流式生成AI回答
```http
POST /api/ai/answer/generate
Authorization: Bearer <token>
Content-Type: application/json
{
"repairId": "YW202408140001",
"streaming": false,
"includeHistory": true
}
Response:
{
"code": 200,
"data": {
"answerId": "answer_20241016001",
"repairId": "YW202408140001",
"answer": "## 问题分析\n根据您描述的网络连接问题...",
"confidenceScore": 0.85,
"generateTime": "2024-08-14T10:35:00",
"processingTimeMs": 1250,
"usedMcpTools": "knowledge_search,similar_cases"
}
}
```
#### 3.3 流式聊天对话 (SSE)
```http
POST /api/ai/chat/stream
Authorization: Bearer <token>
Content-Type: application/json
Accept: text/event-stream
{
"message": "如何解决网络连接问题?",
"sessionId": "chat_session_001", // 可选,用于多轮对话
"context": {
"repairId": "YW202408140001", // 可选,关联工单
"previousMessages": [] // 可选,历史对话
}
}
Stream Response:
event: start
data: {"sessionId": "chat_session_001", "timestamp": "2024-08-14T10:35:00"}
event: chunk
data: {"text": "根据您的描述,网络连接问题", "index": 0}
event: chunk
data: {"text": "通常由以下几个方面引起:", "index": 1}
event: complete
data: {
"sessionId": "chat_session_001",
"fullResponse": "根据您的描述,网络连接问题通常由以下几个方面引起:...",
"tokenCount": 245,
"responseTime": 2100,
"isComplete": true
}
```
#### 3.4 中断流式生成
```http
POST /api/ai/chat/stream/{sessionId}/stop
Authorization: Bearer <token>
Response:
{
"code": 200,
"data": {
"sessionId": "chat_session_001",
"status": "stopped",
"partialResponse": "已生成的部分内容...",
"stopTime": "2024-08-14T10:35:30"
}
}
```
#### 3.5 获取AI回答历史
```http
GET /api/ai/answer/history/{repairId}
Authorization: Bearer <token>
Response:
{
"code": 200,
"data": [
{
"answerId": "answer_20241016001",
"question": "用户提出的问题",
"answer": "AI生成的回答",
"confidenceScore": 0.85,
"status": "generated", // generated, accepted, rejected
"generateTime": "2024-08-14T10:35:00",
"isStreaming": true,
"responseTime": 3250
}
]
}
```
#### 3.6 用户反馈AI回答
```http
POST /api/ai/answer/feedback
Authorization: Bearer <token>
Content-Type: application/json
{
"answerId": "answer_20241016001",
"feedbackType": "accept", // accept, reject, escalate
"userRating": 4, // 1-5分评价
"userComment": "回答很有帮助",
"improvement": "建议添加更详细的步骤"
}
```
### 4. 工单待办模块 (RepairTodoController)
#### 4.1 我的待办工单
```http
POST /repairTodo/list
Authorization: Bearer <token>
Content-Type: application/json
{
"pageNum": 1,
"pageSize": 20,
"step": "declare", // 可选: 按步骤筛选
"urgent": true // 可选: 只看紧急工单
}
Response:
{
"code": 200,
"data": {
"records": [
{
"repairId": "YW202408140001",
"title": "工单标题",
"step": "declare",
"stepName": "待分派",
"priority": 2,
"createTime": "2024-08-14T10:30:00",
"deadline": "2024-08-15T18:00:00"
}
],
"total": 10
}
}
```
### 5. 统计分析模块 (StatisticController)
#### 5.1 工单统计概览
```http
GET /statistic/overview
Authorization: Bearer <token>
Response:
{
"code": 200,
"data": {
"totalRepairs": 1250,
"pendingRepairs": 45,
"resolvedToday": 28,
"avgResolutionTime": 4.2, // 小时
"monthlyStats": [
{
"month": "2024-08",
"submitted": 156,
"resolved": 142,
"resolutionRate": 91.0
}
]
}
}
```
## 🎨 前端页面开发指南
### 1. 工单列表页面
#### 核心功能
- 工单列表展示(支持分页、筛选、排序)
- 工单状态标识(颜色区分优先级)
- 快速操作按钮(查看详情、处理、分派)
- 实时状态更新WebSocket推送
#### 关键组件
```vue
<template>
<div class="repair-list">
<!-- 搜索筛选区 -->
<div class="filter-section">
<el-form inline>
<el-form-item label="关键词">
<el-input v-model="searchForm.title" placeholder="工单标题或ID" />
</el-form-item>
<el-form-item label="业务模块">
<el-select v-model="searchForm.business">
<el-option label="全部" value="" />
<el-option label="财务系统" value="财务系统" />
</el-select>
</el-form-item>
<el-form-item label="优先级">
<el-select v-model="searchForm.priority">
<el-option label="全部" value="" />
<el-option label="紧急" :value="1" />
<el-option label="高" :value="2" />
</el-select>
</el-form-item>
<el-button type="primary" @click="searchRepairs">搜索</el-button>
</el-form>
</div>
<!-- 工单列表 -->
<div class="repair-table">
<el-table :data="repairList" v-loading="loading">
<el-table-column prop="repairId" label="工单ID" width="140" />
<el-table-column prop="title" label="标题" min-width="200" />
<el-table-column prop="business" label="业务模块" width="120" />
<el-table-column prop="priority" label="优先级" width="80">
<template #default="{ row }">
<el-tag :type="getPriorityType(row.priority)">
{{ getPriorityText(row.priority) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="statusName" label="状态" width="100" />
<el-table-column prop="createTime" label="创建时间" width="160" />
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button size="small" @click="viewDetail(row.repairId)">
详情
</el-button>
<el-button size="small" type="primary"
@click="handleRepair(row.repairId)"
v-if="canHandle(row)">
处理
</el-button>
<!-- AI回答按钮 (AI功能启用后) -->
<el-dropdown v-if="needsAIAnswer(row)" trigger="click">
<el-button size="small" type="success">
AI回答 <el-icon><ArrowDown /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="generateAIAnswer(row.repairId, true)">
流式生成
</el-dropdown-item>
<el-dropdown-item @click="generateAIAnswer(row.repairId, false)">
标准生成
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="pagination.current"
v-model:page-size="pagination.size"
:total="pagination.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange" />
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { repairAPI } from '@/api/repair'
const loading = ref(false)
const repairList = ref([])
const searchForm = ref({
title: '',
business: '',
priority: ''
})
const pagination = ref({
current: 1,
size: 20,
total: 0
})
// 搜索工单
const searchRepairs = async () => {
loading.value = true
try {
const params = {
pageNum: pagination.value.current,
pageSize: pagination.value.size,
...searchForm.value
}
const response = await repairAPI.getRepairList(params)
repairList.value = response.data.records
pagination.value.total = response.data.total
} catch (error) {
ElMessage.error('获取工单列表失败')
} finally {
loading.value = false
}
}
// 查看详情
const viewDetail = (repairId) => {
router.push(`/repair/detail/${repairId}`)
}
// 生成AI回答 (支持流式和非流式)
const generateAIAnswer = async (repairId, streaming = true) => {
try {
if (streaming) {
ElMessage.info('正在启动AI流式回答生成...')
// 跳转到AI回答页面并启动流式生成
router.push(`/repair/ai-answer/${repairId}?streaming=true`)
} else {
ElMessage.info('AI正在分析问题请稍候...')
const response = await repairAPI.generateAIAnswer(repairId)
ElMessage.success('AI回答生成成功')
// 跳转到回答页面显示完整结果
router.push(`/repair/ai-answer/${repairId}`)
}
} catch (error) {
ElMessage.error('AI回答生成失败: ' + error.message)
}
}
// 优先级标识
const getPriorityType = (priority) => {
const types = { 1: 'danger', 2: 'warning', 3: 'info', 4: 'success' }
return types[priority] || 'info'
}
const getPriorityText = (priority) => {
const texts = { 1: '紧急', 2: '高', 3: '中', 4: '低' }
return texts[priority] || '未知'
}
onMounted(() => {
searchRepairs()
})
</script>
```
### 2. AI智能回答页面 (支持流式输出)
#### 核心功能
- 流式AI回答展示实时显示生成过程
- 进度指示器(分析、搜索、生成阶段)
- 用户反馈收集(满意度、评分、意见)
- 相似案例推荐
- 回答质量评估指标
- 中断生成功能
#### 设计建议
```vue
<template>
<div class="ai-answer-page">
<!-- 工单信息概览 -->
<div class="repair-summary">
<h3>{{ repairInfo.title }}</h3>
<p>{{ repairInfo.faultDescription }}</p>
<div class="meta-info">
<span>业务模块: {{ repairInfo.business }}</span>
<span>优先级: {{ getPriorityText(repairInfo.priority) }}</span>
</div>
</div>
<!-- AI回答内容支持流式显示 -->
<div class="ai-answer-content">
<div class="answer-header">
<h4>🤖 AI智能解答</h4>
<div class="answer-controls">
<div class="confidence-score" v-if="!isGenerating">
<span>置信度: </span>
<el-progress
:percentage="aiAnswer.confidenceScore * 100"
:color="getConfidenceColor(aiAnswer.confidenceScore)" />
</div>
<el-button
v-if="isGenerating"
type="danger"
size="small"
@click="stopGeneration">
停止生成
</el-button>
</div>
</div>
<!-- 生成进度指示器 -->
<div class="generation-progress" v-if="isGenerating">
<el-progress
:percentage="generationProgress.progress"
:status="generationProgress.status"
striped
striped-flow>
<template #default="{ percentage }">
<span class="progress-text">
{{ generationProgress.message }} ({{ percentage }}%)
</span>
</template>
</el-progress>
</div>
<div class="answer-body">
<!-- 流式显示的AI回答内容 -->
<div class="markdown-content streaming" v-if="isGenerating">
<div class="typing-indicator">
{{ streamingContent }}
<span class="cursor">|</span>
</div>
</div>
<!-- 完整的AI回答内容 -->
<div class="markdown-content" v-else v-html="renderMarkdown(aiAnswer.answer)"></div>
</div>
<div class="answer-meta" v-if="!isGenerating">
<span>生成时间: {{ formatTime(aiAnswer.generateTime) }}</span>
<span>处理耗时: {{ aiAnswer.processingTimeMs }}ms</span>
<span>使用工具: {{ aiAnswer.usedMcpTools }}</span>
<span v-if="aiAnswer.isStreaming">流式生成: 是</span>
</div>
</div>
<!-- 用户反馈区 -->
<div class="feedback-section">
<h4>📝 回答评价</h4>
<div class="feedback-actions">
<el-button type="success" @click="submitFeedback('accept')">
👍 回答有帮助
</el-button>
<el-button type="warning" @click="submitFeedback('reject')">
👎 回答无效
</el-button>
<el-button type="danger" @click="submitFeedback('escalate')">
🆘 需要人工处理
</el-button>
</div>
<!-- 详细反馈表单 -->
<div class="detailed-feedback" v-if="showFeedbackForm">
<el-form :model="feedbackForm">
<el-form-item label="评分">
<el-rate v-model="feedbackForm.userRating" />
</el-form-item>
<el-form-item label="意见">
<el-input type="textarea"
v-model="feedbackForm.userComment"
placeholder="请说明回答的有用程度或改进建议" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitDetailedFeedback">
提交反馈
</el-button>
</el-form-item>
</el-form>
</div>
</div>
<!-- 相似案例推荐 -->
<div class="similar-cases" v-if="similarCases.length > 0">
<h4>📚 相似案例参考</h4>
<div class="cases-list">
<div v-for="case in similarCases" :key="case.repairId"
class="case-item">
<h5>{{ case.title }}</h5>
<p>{{ case.solution }}</p>
<div class="case-meta">
<span>相似度: {{ (case.similarity * 100).toFixed(1) }}%</span>
<span>解决时间: {{ case.resolveTime }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { repairAPI, aiAPI } from '@/api'
import { marked } from 'marked'
const route = useRoute()
const repairId = route.params.repairId
const repairInfo = ref({})
const aiAnswer = ref({})
const similarCases = ref([])
const showFeedbackForm = ref(false)
const feedbackForm = ref({
userRating: 5,
userComment: ''
})
// 流式生成相关状态
const isGenerating = ref(false)
const streamingContent = ref('')
const generationProgress = ref({
progress: 0,
message: '准备开始...',
status: 'active'
})
const eventSource = ref(null)
const sessionId = ref(null)
// 启动流式AI回答生成
const startStreamingGeneration = async () => {
isGenerating.value = true
streamingContent.value = ''
generationProgress.value = { progress: 0, message: '连接AI服务...', status: 'active' }
try {
// 建立SSE连接
eventSource.value = new EventSource(
`/api/ai/answer/stream/${repairId}`,
{
headers: {
'Authorization': `Bearer ${getToken()}`
}
}
)
eventSource.value.onmessage = (event) => {
const data = JSON.parse(event.data)
switch (event.type) {
case 'progress':
generationProgress.value = {
progress: data.progress,
message: data.message,
status: 'active'
}
break
case 'chunk':
streamingContent.value += data.text
break
case 'complete':
aiAnswer.value = data
isGenerating.value = false
eventSource.value.close()
break
}
}
eventSource.value.onerror = (error) => {
console.error('流式生成出错:', error)
isGenerating.value = false
generationProgress.value.status = 'exception'
ElMessage.error('AI回答生成失败')
}
} catch (error) {
console.error('启动流式生成失败:', error)
isGenerating.value = false
}
}
// 停止流式生成
const stopGeneration = async () => {
if (sessionId.value) {
try {
await aiAPI.stopGeneration(sessionId.value)
ElMessage.info('已停止AI回答生成')
} catch (error) {
console.error('停止生成失败:', error)
}
}
if (eventSource.value) {
eventSource.value.close()
}
isGenerating.value = false
generationProgress.value.status = 'warning'
generationProgress.value.message = '已停止生成'
}
// 获取AI回答非流式
const getAIAnswer = async () => {
try {
const response = await aiAPI.getAIAnswer(repairId)
aiAnswer.value = response.data
} catch (error) {
console.error('获取AI回答失败:', error)
}
}
// Markdown渲染
const renderMarkdown = (content) => {
return marked(content || '')
}
// 提交反馈
const submitFeedback = (type) => {
if (type === 'accept') {
// 直接标记为满意
submitDetailedFeedback({
feedbackType: 'accept',
userRating: 5,
userComment: '回答有帮助'
})
} else {
// 显示详细反馈表单
showFeedbackForm.value = true
}
}
const submitDetailedFeedback = async (feedback = null) => {
try {
const params = feedback || {
answerId: aiAnswer.value.answerId,
feedbackType: 'detailed',
...feedbackForm.value
}
await aiAPI.submitFeedback(repairId, params)
ElMessage.success('反馈提交成功')
// 根据反馈类型处理后续逻辑
if (params.feedbackType === 'accept') {
// 工单可能自动关闭
ElMessage.info('工单已标记为已解决')
} else if (params.feedbackType === 'escalate') {
ElMessage.info('工单已转人工处理')
}
} catch (error) {
ElMessage.error('反馈提交失败')
}
}
onMounted(() => {
// 自动启动流式生成,或者加载已有回答
if (route.query.streaming === 'true') {
startStreamingGeneration()
} else {
getAIAnswer()
}
})
// 组件卸载时清理资源
onUnmounted(() => {
if (eventSource.value) {
eventSource.value.close()
}
})
</script>
```
## 🔧 开发建议
### 1. 状态管理
```javascript
// Pinia Store for Repair Management
import { defineStore } from 'pinia'
export const useRepairStore = defineStore('repair', {
state: () => ({
repairList: [],
currentRepair: null,
aiAnswers: {},
loading: false
}),
actions: {
async fetchRepairList(params) {
this.loading = true
try {
const response = await repairAPI.getRepairList(params)
this.repairList = response.data.records
return response.data
} finally {
this.loading = false
}
},
async generateAIAnswer(repairId) {
try {
const response = await repairAPI.generateAIAnswer(repairId)
this.aiAnswers[repairId] = response.data
return response.data
} catch (error) {
throw error
}
}
}
})
```
### 2. 错误处理
```javascript
// API错误统一处理
import axios from 'axios'
import { ElMessage } from 'element-plus'
const apiClient = axios.create({
baseURL: '/api',
timeout: 30000
})
apiClient.interceptors.response.use(
response => {
if (response.data.code !== 200) {
ElMessage.error(response.data.message)
throw new Error(response.data.message)
}
return response.data
},
error => {
if (error.response?.status === 401) {
// 跳转到登录页
router.push('/login')
} else {
ElMessage.error(error.message || '网络请求失败')
}
return Promise.reject(error)
}
)
```
### 3. WebSocket实时通知
```javascript
// WebSocket连接管理
class WebSocketManager {
constructor() {
this.ws = null
this.reconnectCount = 0
}
connect(userId) {
this.ws = new WebSocket(`ws://localhost:8080/websocket/${userId}`)
this.ws.onmessage = (event) => {
const notification = JSON.parse(event.data)
this.handleNotification(notification)
}
this.ws.onclose = () => {
// 自动重连逻辑
if (this.reconnectCount < 5) {
setTimeout(() => {
this.connect(userId)
this.reconnectCount++
}, 5000)
}
}
}
handleNotification(notification) {
switch (notification.type) {
case 'ai_answer':
ElMessage.success('AI助手已为您的问题提供了解决方案')
// 更新页面状态
break
case 'repair_assigned':
ElMessage.info('您有新的工单分配')
break
}
}
}
```
## 🧪 AI功能测试Demo
### 测试页面实现
创建一个专门的测试页面用于验证AI功能的各个环节
```vue
<template>
<div class="ai-test-demo">
<el-card header="AI智能回答功能测试">
<!-- 测试用例选择 -->
<div class="test-scenarios">
<h4>选择测试场景</h4>
<el-radio-group v-model="selectedScenario">
<el-radio label="network">网络连接问题</el-radio>
<el-radio label="login">系统登录问题</el-radio>
<el-radio label="printer">打印机故障</el-radio>
<el-radio label="custom">自定义问题</el-radio>
</el-radio-group>
</div>
<!-- 测试参数配置 -->
<div class="test-config">
<el-form :model="testForm" label-width="120px">
<el-form-item label="工单标题">
<el-input v-model="testForm.title" />
</el-form-item>
<el-form-item label="问题描述">
<el-input type="textarea" v-model="testForm.description" rows="4" />
</el-form-item>
<el-form-item label="业务模块">
<el-select v-model="testForm.business">
<el-option label="办公网络" value="办公网络" />
<el-option label="财务系统" value="财务系统" />
<el-option label="设备维护" value="设备维护" />
</el-select>
</el-form-item>
</el-form>
</div>
<!-- 测试执行按钮 -->
<div class="test-actions">
<el-button type="primary" @click="runAITest" :loading="testing">
{{ testing ? 'AI分析中...' : '开始AI测试' }}
</el-button>
<el-button @click="resetTest">重置</el-button>
</div>
<!-- 测试结果展示 -->
<div class="test-results" v-if="testResult">
<el-divider>测试结果</el-divider>
<!-- AI回答 -->
<div class="ai-response">
<h4>🤖 AI智能回答</h4>
<div class="answer-content" v-html="testResult.answer"></div>
<div class="answer-metrics">
<el-descriptions :column="2" border>
<el-descriptions-item label="置信度">
<el-progress :percentage="testResult.confidence * 100" />
</el-descriptions-item>
<el-descriptions-item label="响应时间">
{{ testResult.responseTime }}ms
</el-descriptions-item>
<el-descriptions-item label="相似案例">
{{ testResult.similarCases }}个
</el-descriptions-item>
<el-descriptions-item label="使用工具">
{{ testResult.usedTools }}
</el-descriptions-item>
</el-descriptions>
</div>
</div>
<!-- 测试反馈 -->
<div class="test-feedback">
<h4>📝 测试反馈</h4>
<el-button-group>
<el-button type="success" @click="submitTestFeedback('good')">
👍 回答质量好
</el-button>
<el-button type="warning" @click="submitTestFeedback('average')">
👌 回答一般
</el-button>
<el-button type="danger" @click="submitTestFeedback('poor')">
👎 回答质量差
</el-button>
</el-button-group>
</div>
</div>
</el-card>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
const testing = ref(false)
const selectedScenario = ref('network')
const testForm = ref({
title: '',
description: '',
business: '办公网络'
})
const testResult = ref(null)
// 预定义测试场景
const testScenarios = {
network: {
title: '办公室网络连接异常',
description: '办公室所有电脑都无法连接网络,已检查网线连接正常,路由器指示灯正常。之前网络使用正常,今天上午开始出现问题。',
business: '办公网络'
},
login: {
title: '财务系统无法登录',
description: '用户反映财务系统登录页面输入账号密码后提示"用户名或密码错误",但是密码确认无误。其他同事可以正常登录。',
business: '财务系统'
},
printer: {
title: '办公室打印机故障',
description: '打印机显示"脱机"状态无法打印任何文件。已检查电源连接正常USB线已重新插拔电脑上显示打印机驱动正常。',
business: '设备维护'
},
custom: {
title: '',
description: '',
business: '办公网络'
}
}
// 监听场景切换
watch(selectedScenario, (newScenario) => {
if (newScenario !== 'custom') {
Object.assign(testForm.value, testScenarios[newScenario])
}
})
// 运行AI测试
const runAITest = async () => {
testing.value = true
testResult.value = null
try {
// 模拟API调用 (实际环境中调用真实接口)
const response = await mockAIAPICall(testForm.value)
testResult.value = response
ElMessage.success('AI测试完成')
} catch (error) {
ElMessage.error('AI测试失败: ' + error.message)
} finally {
testing.value = false
}
}
// 模拟AI API调用 (开发阶段使用)
const mockAIAPICall = async (testData) => {
// 模拟网络延迟
await new Promise(resolve => setTimeout(resolve, 2000))
// 模拟AI回答生成
const mockResponses = {
network: {
answer: `## 问题分析
网络连接异常可能由以下原因导致:
## 解决方案
1. **检查网络设备**
- 重启路由器和交换机
- 检查网线接头是否松动
2. **检查网络配置**
- 确认IP地址设置正确
- 检查DNS配置
3. **联系网络管理员**
- 如上述方法无效,建议联系网络管理员检查上级网络设备
## 预计解决时间
10-30分钟`,
confidence: 0.87,
responseTime: 1850,
similarCases: 5,
usedTools: 'knowledge_search,similar_cases'
},
login: {
answer: `## 问题分析
登录失败通常由账户状态或权限问题导致:
## 解决方案
1. **密码重置**
- 联系系统管理员重置密码
- 检查账户是否被锁定
2. **浏览器清理**
- 清除浏览器缓存和Cookie
- 尝试使用其他浏览器登录
3. **权限检查**
- 确认账户具有系统访问权限
- 检查账户是否过期
## 预计解决时间
5-15分钟`,
confidence: 0.92,
responseTime: 1420,
similarCases: 8,
usedTools: 'user_info,knowledge_search'
}
}
const scenario = testData.business === '办公网络' ? 'network' : 'login'
return mockResponses[scenario]
}
// 提交测试反馈
const submitTestFeedback = (feedbackType) => {
const feedbackMessages = {
good: '感谢反馈AI回答质量评价优秀',
average: '感谢反馈AI回答质量评价良好',
poor: '感谢反馈我们会继续改进AI回答质量'
}
ElMessage.info(feedbackMessages[feedbackType])
}
// 重置测试
const resetTest = () => {
testForm.value = { title: '', description: '', business: '办公网络' }
testResult.value = null
selectedScenario.value = 'network'
}
// 初始化
selectedScenario.value = 'network'
</script>
<style scoped>
.ai-test-demo {
max-width: 1000px;
margin: 20px auto;
}
.test-scenarios, .test-config, .test-actions {
margin-bottom: 20px;
}
.test-results {
margin-top: 20px;
}
.ai-response {
margin-bottom: 20px;
}
.answer-content {
background: #f8f9fa;
padding: 15px;
border-radius: 8px;
border-left: 4px solid #28a745;
margin-bottom: 15px;
white-space: pre-wrap;
}
/* 流式生成样式 */
.streaming .typing-indicator {
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
}
.streaming .cursor {
animation: blink 1s infinite;
color: #409eff;
font-weight: bold;
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
.generation-progress {
margin-bottom: 15px;
}
.progress-text {
font-size: 12px;
color: #606266;
}
.answer-controls {
display: flex;
justify-content: space-between;
align-items: center;
}
.answer-metrics {
margin-top: 15px;
}
.test-feedback {
text-align: center;
}
</style>
```
## 📋 总结
### 开发优先级
1. **Phase 1**: 基础工单管理功能(已可用)
2. **Phase 2**: 用户认证和权限系统(已可用)
3. **Phase 3**: AI智能回答功能✅ 已实现,支持流式输出)
4. **Phase 4**: 高级统计分析和可视化
### 技术栈建议
- **前端框架**: Vue 3 + Element Plus
- **状态管理**: Pinia
- **路由**: Vue Router 4
- **HTTP客户端**: Axios
- **Markdown渲染**: marked
- **图表库**: ECharts
### 部署说明
- 开发环境已启动在 http://localhost:8080
- API文档可访问 http://localhost:8080/doc.html
- 当前可使用基础工单管理功能
-**AI流式输出功能已实现并可用**
### 🚀 流式输出特性
- **Server-Sent Events (SSE)**: 实时推送AI生成进度
- **实时进度指示**: 分析→搜索→生成阶段可视化
- **中断控制**: 用户可随时停止生成过程
- **性能监控**: 完整的流程追踪和性能指标
- **降级支持**: 自动切换到非流式模式作为备选
### 🎯 前端集成要点
1. **EventSource API**: 用于接收SSE流式数据
2. **状态管理**: 生成进度、内容缓冲、会话控制
3. **用户体验**: 打字机效果、进度条、停止按钮
4. **错误处理**: 连接失败、超时、异常恢复
5. **资源清理**: 组件卸载时关闭SSE连接
这份文档为前端开发提供了完整的API接口规范、流式输出实现方案和测试Demo确保前后端协作顺利进行。AI智能回答功能已完全就绪支持现代化的流式用户体验。