forked from 77media/video-flow
397 lines
11 KiB
Markdown
397 lines
11 KiB
Markdown
# 任务重试功能集成方案
|
||
|
||
## 📋 概述
|
||
|
||
本文档详细说明了如何将任务重试接口 `POST https://77.smartvideo.py.qikongjian.com/task/retry_task` 集成到Dashboard页面中,提供完整的用户体验和错误处理机制。
|
||
|
||
## 🏗️ 架构设计
|
||
|
||
### 1. API层设计
|
||
|
||
#### 1.1 接口定义
|
||
```typescript
|
||
// api/video_flow.ts
|
||
export const retryTask = async (request: {
|
||
/** 任务ID */
|
||
task_id: string;
|
||
}): Promise<ApiResponse<{
|
||
/** 任务ID */
|
||
task_id: string;
|
||
/** 重试状态 */
|
||
status: string;
|
||
/** 状态描述 */
|
||
message: string;
|
||
/** 是否成功启动重试 */
|
||
success: boolean;
|
||
}>>
|
||
```
|
||
|
||
#### 1.2 请求示例
|
||
```json
|
||
{
|
||
"task_id": "11ac5e0d-963d-4eb2-98e8-1eccf636f4f2"
|
||
}
|
||
```
|
||
|
||
#### 1.3 响应示例
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "success",
|
||
"data": {
|
||
"task_id": "11ac5e0d-963d-4eb2-98e8-1eccf636f4f2",
|
||
"status": "retrying",
|
||
"message": "任务重试已启动",
|
||
"success": true
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. Dashboard页面集成
|
||
|
||
#### 2.1 导入重试API
|
||
```typescript
|
||
import { getProjectTaskList, retryTask } from '@/api/video_flow';
|
||
```
|
||
|
||
#### 2.2 onRetryTask优化实现(避免页面刷新)
|
||
```typescript
|
||
onRetryTask={async (taskId: string) => {
|
||
console.log('重试任务:', taskId);
|
||
try {
|
||
// 1. 乐观更新:立即更新任务状态为重试中
|
||
setDashboardData(prevData => {
|
||
if (!Array.isArray(prevData)) return prevData;
|
||
|
||
return prevData.map(task => {
|
||
if (task.task_id === taskId) {
|
||
return { ...task, task_status: 'RETRYING' };
|
||
}
|
||
// 检查子任务
|
||
if (task.sub_tasks && Array.isArray(task.sub_tasks)) {
|
||
const updatedSubTasks = task.sub_tasks.map(subTask =>
|
||
subTask.task_id === taskId
|
||
? { ...subTask, task_status: 'RETRYING' }
|
||
: subTask
|
||
);
|
||
return { ...task, sub_tasks: updatedSubTasks };
|
||
}
|
||
return task;
|
||
});
|
||
});
|
||
|
||
// 2. 调用重试任务API
|
||
const retryResponse = await retryTask({ task_id: taskId });
|
||
|
||
if (retryResponse.code === 0 && retryResponse.data?.success) {
|
||
console.log('任务重试成功:', retryResponse.data);
|
||
// 3. 使用静默刷新,避免页面重载
|
||
setTimeout(() => {
|
||
refreshDataSilently();
|
||
}, 2000);
|
||
} else {
|
||
console.error('任务重试失败:', retryResponse.message);
|
||
setTimeout(() => {
|
||
refreshDataSilently();
|
||
}, 1000);
|
||
}
|
||
} catch (error) {
|
||
console.error('重试任务时发生错误:', error);
|
||
setTimeout(() => {
|
||
refreshDataSilently();
|
||
}, 1000);
|
||
}
|
||
}}
|
||
```
|
||
|
||
### 3. NetworkTimeline组件增强
|
||
|
||
#### 3.1 状态管理
|
||
```typescript
|
||
const [retryingTasks, setRetryingTasks] = useState<Set<string>>(new Set());
|
||
```
|
||
|
||
#### 3.2 优化的重试处理函数
|
||
```typescript
|
||
const handleRetryTask = async (taskId: string) => {
|
||
if (onRetryTask) {
|
||
try {
|
||
// 添加到重试中的任务集合
|
||
setRetryingTasks(prev => new Set(prev).add(taskId));
|
||
|
||
// 调用父组件的重试逻辑(包含乐观更新)
|
||
await onRetryTask(taskId);
|
||
|
||
console.log(`任务 ${taskId} 重试请求已发送`);
|
||
|
||
} catch (error) {
|
||
console.error('重试任务失败:', error);
|
||
// 重试失败时立即移除重试状态
|
||
setRetryingTasks(prev => {
|
||
const newSet = new Set(prev);
|
||
newSet.delete(taskId);
|
||
return newSet;
|
||
});
|
||
}
|
||
// 注意:成功情况下不立即移除重试状态
|
||
// 重试状态会在数据刷新后自然消失
|
||
}
|
||
};
|
||
|
||
// 自动清理重试状态
|
||
useEffect(() => {
|
||
if (retryingTasks.size === 0) return;
|
||
|
||
const currentRetryingTaskIds = Array.from(retryingTasks);
|
||
const tasksToRemove: string[] = [];
|
||
|
||
currentRetryingTaskIds.forEach(taskId => {
|
||
const isStillRetrying = tasks.some(task => {
|
||
if (task.task_id === taskId && task.task_status === 'RETRYING') {
|
||
return true;
|
||
}
|
||
if (task.sub_tasks && Array.isArray(task.sub_tasks)) {
|
||
return task.sub_tasks.some(subTask =>
|
||
subTask.task_id === taskId && subTask.task_status === 'RETRYING'
|
||
);
|
||
}
|
||
return false;
|
||
});
|
||
|
||
if (!isStillRetrying) {
|
||
tasksToRemove.push(taskId);
|
||
}
|
||
});
|
||
|
||
if (tasksToRemove.length > 0) {
|
||
setRetryingTasks(prev => {
|
||
const newSet = new Set(prev);
|
||
tasksToRemove.forEach(taskId => newSet.delete(taskId));
|
||
return newSet;
|
||
});
|
||
}
|
||
}, [tasks, retryingTasks]);
|
||
```
|
||
|
||
#### 3.3 UI增强
|
||
```typescript
|
||
{/* 重试按钮 - 列表视图 */}
|
||
<button
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
handleRetryTask(task.id);
|
||
}}
|
||
disabled={retryingTasks.has(task.id)}
|
||
className={cn(
|
||
"p-1 hover:bg-gray-700 rounded transition-colors",
|
||
retryingTasks.has(task.id)
|
||
? "text-yellow-400 cursor-not-allowed"
|
||
: "text-blue-400 hover:text-blue-300"
|
||
)}
|
||
title={retryingTasks.has(task.id) ? "重试中..." : "重试任务"}
|
||
>
|
||
<RefreshCw className={cn(
|
||
"w-4 h-4",
|
||
retryingTasks.has(task.id) && "animate-spin"
|
||
)} />
|
||
</button>
|
||
|
||
{/* 重试按钮 - 时间线视图 */}
|
||
<button
|
||
onClick={() => handleRetryTask(task.id)}
|
||
disabled={retryingTasks.has(task.id)}
|
||
className={cn(
|
||
"mt-2 flex items-center gap-1 px-2 py-1 text-white text-[10px] rounded transition-colors",
|
||
retryingTasks.has(task.id)
|
||
? "bg-yellow-600 cursor-not-allowed"
|
||
: "bg-blue-600 hover:bg-blue-700"
|
||
)}
|
||
>
|
||
<RefreshCw className={cn(
|
||
"w-3 h-3",
|
||
retryingTasks.has(task.id) && "animate-spin"
|
||
)} />
|
||
{retryingTasks.has(task.id) ? "重试中..." : "重试任务"}
|
||
</button>
|
||
```
|
||
|
||
## 🚀 核心优化要点
|
||
|
||
### 1. 避免页面刷新问题
|
||
**问题**: 原始实现使用 `fetchInitialData()` 导致整个页面重新加载,用户体验差
|
||
**解决方案**:
|
||
- 使用乐观更新立即反馈用户操作
|
||
- 采用 `refreshDataSilently()` 进行静默数据刷新
|
||
- 保持现有的智能轮询机制不受干扰
|
||
|
||
### 2. 乐观更新策略
|
||
```typescript
|
||
// 立即更新UI状态,给用户即时反馈
|
||
setDashboardData(prevData => {
|
||
return prevData.map(task => {
|
||
if (task.task_id === taskId) {
|
||
return { ...task, task_status: 'RETRYING' };
|
||
}
|
||
return task;
|
||
});
|
||
});
|
||
```
|
||
|
||
### 3. 智能状态管理
|
||
- **双重状态跟踪**: 组件内部 `retryingTasks` + 数据状态 `RETRYING`
|
||
- **自动状态清理**: 当任务不再是RETRYING状态时自动清理UI状态
|
||
- **防重复操作**: 重试过程中禁用按钮,防止重复点击
|
||
|
||
### 4. 渐进式数据更新
|
||
- **即时反馈**: 点击重试立即显示重试状态
|
||
- **API调用**: 后台调用重试接口
|
||
- **静默刷新**: 延迟获取真实状态,不影响用户体验
|
||
- **状态同步**: 自动清理过期的UI状态
|
||
|
||
## 🎯 功能特性
|
||
|
||
### 1. 智能重试机制
|
||
- **状态检测**: 只有失败状态的任务才显示重试按钮
|
||
- **防重复点击**: 重试过程中按钮变为禁用状态
|
||
- **视觉反馈**: 重试时显示旋转动画和"重试中..."文本
|
||
|
||
### 2. 错误处理
|
||
- **API错误处理**: 捕获并记录重试API调用失败
|
||
- **网络错误处理**: 处理网络连接问题
|
||
- **状态恢复**: 无论成功失败都会刷新数据获取最新状态
|
||
|
||
### 3. 用户体验优化
|
||
- **即时反馈**: 点击重试按钮立即显示加载状态
|
||
- **状态同步**: 重试后自动刷新任务列表
|
||
- **延迟恢复**: 给用户足够的视觉反馈时间
|
||
|
||
## 🔧 技术实现细节
|
||
|
||
### 1. 状态枚举扩展
|
||
```typescript
|
||
// app/model/enums.ts
|
||
export enum TaskStatusEnum {
|
||
PENDING = "pending",
|
||
PROCESSING = "processing",
|
||
COMPLETED = "completed",
|
||
FAILED = "failed",
|
||
RETRYING = "retrying", // 新增
|
||
CANCELLED = "cancelled", // 新增
|
||
}
|
||
```
|
||
|
||
### 2. 状态码映射
|
||
```typescript
|
||
function getTaskStatusCode(status: string): number {
|
||
const statusMap: Record<string, number> = {
|
||
'RETRYING': 202, // 重试状态映射为进行中
|
||
// ... 其他状态
|
||
};
|
||
return statusMap[status] || 200;
|
||
}
|
||
```
|
||
|
||
### 3. 状态文本映射
|
||
```typescript
|
||
function getTaskStatusText(status: string): string {
|
||
const statusTextMap: Record<string, string> = {
|
||
'RETRYING': '重试中', // 新增重试状态文本
|
||
// ... 其他状态
|
||
};
|
||
return statusTextMap[status] || status;
|
||
}
|
||
```
|
||
|
||
## 🚀 使用流程
|
||
|
||
### 1. 用户操作流程
|
||
1. 用户在Dashboard页面查看任务列表
|
||
2. 发现失败的任务(红色状态显示)
|
||
3. 点击任务旁边的重试按钮(蓝色刷新图标)
|
||
4. 按钮变为黄色并显示旋转动画
|
||
5. 系统调用重试API
|
||
6. 1秒后自动刷新任务列表
|
||
7. 2秒后重试按钮恢复正常状态
|
||
|
||
### 2. 系统处理流程
|
||
1. 前端调用 `retryTask` API
|
||
2. 后端接收重试请求并启动任务重试
|
||
3. 返回重试状态给前端
|
||
4. 前端更新UI状态并刷新数据
|
||
5. 后端异步处理任务重试
|
||
6. 下次数据刷新时获取最新任务状态
|
||
|
||
## 📊 监控和日志
|
||
|
||
### 1. 前端日志
|
||
```typescript
|
||
console.log('重试任务:', taskId);
|
||
console.log('任务重试成功:', retryResponse.data);
|
||
console.error('重试任务失败:', retryResponse.message);
|
||
console.error('重试任务时发生错误:', error);
|
||
```
|
||
|
||
### 2. 状态追踪
|
||
- 重试按钮状态变化
|
||
- API调用成功/失败
|
||
- 数据刷新时机
|
||
- 用户交互行为
|
||
|
||
## 🎨 UI/UX设计原则
|
||
|
||
### 1. 一致性
|
||
- 重试按钮在列表视图和时间线视图中保持一致的交互逻辑
|
||
- 状态颜色和图标使用统一的设计语言
|
||
|
||
### 2. 反馈性
|
||
- 立即的视觉反馈(按钮状态变化)
|
||
- 清晰的状态提示(重试中、重试任务)
|
||
- 动画效果增强用户感知
|
||
|
||
### 3. 容错性
|
||
- 防止重复点击
|
||
- 优雅的错误处理
|
||
- 自动状态恢复
|
||
|
||
## 🔍 测试建议
|
||
|
||
### 1. 功能测试
|
||
- 测试重试按钮的显示条件(只在失败任务上显示)
|
||
- 测试重试过程中的UI状态变化
|
||
- 测试重试成功后的数据刷新
|
||
|
||
### 2. 异常测试
|
||
- 测试网络错误时的处理
|
||
- 测试API返回错误时的处理
|
||
- 测试重复点击的防护机制
|
||
|
||
### 3. 性能测试
|
||
- 测试大量任务时的重试性能
|
||
- 测试并发重试的处理
|
||
- 测试内存泄漏问题
|
||
|
||
## 📈 未来扩展
|
||
|
||
### 1. 批量重试
|
||
- 支持选择多个失败任务进行批量重试
|
||
- 批量重试的进度显示
|
||
|
||
### 2. 重试策略
|
||
- 支持自动重试机制
|
||
- 可配置的重试次数和间隔
|
||
|
||
### 3. 重试历史
|
||
- 记录任务的重试历史
|
||
- 显示重试次数和时间
|
||
|
||
## 🎯 总结
|
||
|
||
通过以上设计和实现,任务重试功能已经完全集成到Dashboard页面中,提供了:
|
||
|
||
1. **完整的API集成**: 从接口定义到错误处理的完整链路
|
||
2. **优秀的用户体验**: 直观的UI反馈和流畅的交互
|
||
3. **健壮的错误处理**: 多层次的异常捕获和恢复机制
|
||
4. **可扩展的架构**: 支持未来功能扩展和优化
|
||
|
||
该实现充分体现了现代前端开发的最佳实践,是一个高质量的企业级功能实现。
|