forked from 77media/video-flow
19 KiB
19 KiB
Dashboard页面功能与接口调用全面分析
📋 概述
基于资深全栈开发视角,对Dashboard页面的功能架构、接口调用、数据流程和技术实现进行全面分析。
🏗️ 架构概览
1. 页面结构
Dashboard页面 (app/dashboard/page.tsx)
├── 页面容器组件
├── NetworkTimeline组件 (核心功能组件)
├── 数据获取逻辑
├── 实时刷新机制
└── 错误处理机制
2. 核心组件
- 主页面:
app/dashboard/page.tsx- 页面入口和数据管理 - 时间线组件:
components/dashboard/network-timeline.tsx- 核心功能实现 - API层:
api/video_flow.ts- 接口调用封装
🔌 接口调用分析
1. 主要接口
1.1 获取项目任务列表 (核心接口)
// 接口定义
export const getProjectTaskList = async (data: {
project_id: string;
}): Promise<ApiResponse<TaskItem[]>>
// 接口地址
POST https://77.smartvideo.py.qikongjian.com/task/get_project_task_list
// 请求参数
{
"project_id": "d203016d-6f7e-4d1c-b66b-1b7d33632800"
}
// 响应结构
{
"code": 0,
"message": "操作成功",
"data": [
{
"plan_id": "string",
"task_id": "string",
"start_time": "2025-08-24T17:37:31",
"end_time": "2025-08-24T17:37:31",
"task_name": "string",
"task_status": "SUCCESS|FAILED|COMPLETED|IN_PROGRESS|INIT",
"task_result": "string|object",
"task_params": "string",
"task_message": "string",
"created_at": "2025-08-23T02:40:58",
"updated_at": "2025-08-24T17:37:31",
"error_message": "string|null",
"error_traceback": "string|null",
"parent_task_id": "string|null",
"sub_tasks": [...]
}
],
"successful": true
}
1.2 其他相关接口
// 项目详情
detailScriptEpisodeNew(data: { project_id: string })
// 项目标题
getScriptTitle(data: { project_id: string })
// 运行状态数据
getRunningStreamData(data: { project_id: string })
2. 接口调用策略
2.1 数据获取流程
// 主页面数据获取逻辑
const fetchDashboardData = async () => {
try {
setIsLoading(true);
const response = await getProjectTaskList({ project_id: projectId });
if (response.code === 0) {
setDashboardData(response.data);
setLastUpdate(new Date());
} else {
// 降级到Mock数据
setDashboardData(mockTaskData);
}
} catch (error) {
console.error('获取任务数据失败:', error);
setDashboardData(mockTaskData);
} finally {
setIsLoading(false);
}
};
2.2 智能刷新机制
// 智能轮询逻辑
useEffect(() => {
if (!isPolling || !dashboardData) return;
// 检查是否有活跃任务
const hasRunningTasks = dashboardData.some((task: any) =>
task.task_status === 'IN_PROGRESS' ||
task.task_status === 'INIT' ||
(task.sub_tasks && task.sub_tasks.some((subTask: any) =>
subTask.task_status === 'IN_PROGRESS' ||
subTask.task_status === 'INIT'
))
);
if (hasRunningTasks) {
const interval = setInterval(fetchDashboardData, 5000); // 5秒轮询
return () => clearInterval(interval);
}
}, [isPolling, dashboardData]);
📊 数据处理分析
1. 数据结构转换
1.1 任务执行对象定义
interface TaskExecution {
id: string; // 任务ID
name: string; // 任务名称
displayName: string; // 显示名称
status: string; // 任务状态
statusCode: number; // 状态码
type: string; // 任务类型
dataSize: number; // 数据大小
executionTime: number; // 执行时间
startTime: number; // 开始时间
endTime: number; // 结束时间
progress: number; // 进度百分比
level: number; // 层级:0=主任务,1=子任务
parentId?: string; // 父任务ID
isExpanded?: boolean; // 是否展开子任务
subTasks?: TaskExecution[]; // 子任务列表
phases: { // 执行阶段
initialization?: number;
dataLoading?: number;
aiProcessing?: number;
resultGeneration?: number;
dataTransfer?: number;
completion?: number;
};
taskResult?: any; // 任务结果
}
1.2 数据转换逻辑
// 主任务处理
const mainTask: TaskExecution = {
id: task.task_id,
name: task.task_name,
displayName: getTaskDisplayName(task.task_name),
status: task.task_status,
statusCode: getTaskStatusCode(task.task_status),
type: getTaskType(task.task_name),
// ... 其他字段映射
};
// 子任务处理
if (task.sub_tasks && Array.isArray(task.sub_tasks)) {
const realSubTasks = task.sub_tasks.map((subTask: any) => ({
id: subTask.task_id,
name: subTask.task_name,
status: subTask.task_status,
level: 1,
parentId: task.task_id,
// ... 其他字段映射
}));
mainTask.subTasks = realSubTasks;
}
2. 数据映射函数
2.1 任务类型映射
function getTaskType(taskName: string): string {
const typeMap: Record<string, string> = {
'generate_character': 'AI',
'generate_character_image': 'AI',
'generate_sketch': 'AI',
'generate_shot_sketch': 'AI',
'generate_video': 'Video',
'generate_videos': 'Video',
'generate_music': 'Audio',
'final_composition': 'Comp',
'refine_orginal_script': 'Script',
'generate_production_bible': 'Doc',
'generate_production_bible_json': 'Data'
};
return typeMap[taskName] || 'Task';
}
2.2 状态映射
function getTaskStatusCode(status: string): number {
const statusCodeMap: Record<string, number> = {
'SUCCESS': 200,
'COMPLETED': 200,
'FINISHED': 200,
'IN_PROGRESS': 202,
'RUNNING': 202,
'PROCESSING': 202,
'INIT': 100,
'PENDING': 100,
'QUEUED': 100,
'FAILED': 500,
'FAILURE': 500,
'ERROR': 500,
'CANCELLED': 499,
'TIMEOUT': 408
};
return statusCodeMap[status] || 500;
}
🎨 功能特性分析
1. 核心功能
1.1 任务监控面板
- 实时状态显示: 显示所有任务的执行状态
- 层级结构: 支持主任务和子任务的层级显示
- 进度跟踪: 实时显示任务执行进度
- 时间信息: 显示开始时间、结束时间、执行时长
1.2 交互功能
- 展开/收起: 主任务可展开查看子任务
- 任务详情: 点击任务查看详细信息
- 搜索过滤: 支持按名称、状态、类型搜索
- 类型过滤: 动态下拉选择过滤任务类型
1.3 可视化展示
- 网络时间线: 可视化任务执行时间线
- 状态图标: 不同状态使用不同颜色和图标
- 进度条: 直观显示任务完成进度
- 错误提示: 悬停显示详细错误信息
2. 高级功能
2.1 智能刷新
// 基于任务状态的智能轮询
const hasRunningTasks = dashboardData.some((task: any) =>
task.task_status === 'IN_PROGRESS' ||
task.task_status === 'INIT'
);
if (hasRunningTasks) {
// 启动5秒轮询
const interval = setInterval(fetchDashboardData, 5000);
}
2.2 错误处理
// 多层级错误处理
try {
const response = await getProjectTaskList({ project_id });
// 处理成功响应
} catch (error) {
console.error('API调用失败:', error);
// 降级到Mock数据
setDashboardData(mockTaskData);
}
2.3 性能优化
// 数据计算优化
const mainTaskExecutions = useMemo(() => {
// 主任务计算,不依赖展开状态
}, [tasks]);
const taskExecutions = useMemo(() => {
// 轻量级展开状态处理
}, [mainTaskExecutions, expandedTasks]);
// 函数缓存
const toggleTaskExpansion = React.useCallback((taskId: string) => {
// 展开切换逻辑
}, []);
📈 统计信息
1. 任务统计
const taskStats = useMemo(() => {
const stats = { total: 0, completed: 0, inProgress: 0, failed: 0, pending: 0 };
tasks.forEach((task: any) => {
stats.total++;
const status = task.task_status;
if (['COMPLETED', 'SUCCESS'].includes(status)) {
stats.completed++;
} else if (['IN_PROGRESS', 'RUNNING', 'PROCESSING'].includes(status)) {
stats.inProgress++;
} else if (['FAILED', 'FAILURE', 'ERROR'].includes(status)) {
stats.failed++;
} else {
stats.pending++;
}
});
return stats;
}, [tasks]);
2. 进度计算
// 基于子任务的进度计算
function getTaskProgress(task: any): number {
if (task.sub_tasks && Array.isArray(task.sub_tasks) && task.sub_tasks.length > 0) {
const completedSubTasks = task.sub_tasks.filter((sub: any) =>
['SUCCESS', 'COMPLETED', 'FINISHED'].includes(sub.task_status)
).length;
return Math.round((completedSubTasks / task.sub_tasks.length) * 100);
}
// 其他进度计算逻辑...
}
🔧 技术实现
1. 状态管理
// React状态管理
const [dashboardData, setDashboardData] = useState<any[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [isPolling, setIsPolling] = useState(false);
const [lastUpdate, setLastUpdate] = useState<Date | null>(null);
const [selectedTask, setSelectedTask] = useState<string | null>(null);
const [expandedTasks, setExpandedTasks] = useState<Set<string>>(new Set());
2. 动画系统
// Framer Motion动画
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
animate={{ rotate: expandedTasks.has(task.id) ? 90 : 0 }}
transition={{ duration: 0.2, ease: "easeOut" }}
>
3. 样式系统
// Tailwind CSS + 条件样式
className={cn(
"flex items-center px-4 py-2 text-sm border-b border-gray-800/30",
"cursor-pointer hover:bg-gray-800/50 transition-all duration-200",
selectedTask === task.id && "bg-blue-600/20",
task.level === 1 && "ml-4 bg-gray-900/30"
)}
📊 数据流程图
用户访问Dashboard
↓
获取project_id (URL参数)
↓
调用getProjectTaskList接口
↓
数据转换和处理
↓
渲染NetworkTimeline组件
↓
用户交互 (展开/搜索/过滤)
↓
智能刷新检测
↓
条件性轮询更新
🎯 核心价值
1. 用户价值
- 实时监控: 实时了解任务执行状态
- 层次清晰: 主任务和子任务层级分明
- 操作便捷: 直观的交互和搜索功能
- 信息完整: 详细的任务信息和错误提示
2. 技术价值
- 性能优化: 智能轮询和数据缓存
- 用户体验: 流畅的动画和交互
- 可维护性: 清晰的组件结构和数据流
- 扩展性: 支持新的任务类型和状态
3. 业务价值
- 提升效率: 快速定位和解决问题
- 降低成本: 减少人工监控成本
- 增强体验: 专业的监控界面
- 数据驱动: 基于真实数据的决策支持
🚀 总结
Dashboard页面是一个功能完整、技术先进的任务监控系统,具备:
- 完整的数据流程: 从API调用到UI展示的完整链路
- 智能的交互设计: 基于用户需求的功能设计
- 优秀的性能表现: 通过多种优化策略确保流畅体验
- 强大的扩展能力: 支持未来功能扩展和数据结构变化
该系统充分体现了现代前端开发的最佳实践,是一个高质量的企业级应用。
🔍 深度技术分析
1. 接口设计模式
1.1 RESTful API设计
// 统一的API响应格式
interface ApiResponse<T> {
code: number; // 状态码:0=成功,非0=失败
message: string; // 响应消息
data: T; // 响应数据
successful: boolean; // 成功标识
}
// 错误处理策略
const handleApiError = (error: any) => {
if (error.code === 'NETWORK_ERROR') {
return '网络连接失败,请检查网络连接';
} else if (error.response?.status === 404) {
return 'API接口不存在';
} else if (error.response?.status === 500) {
return '服务器内部错误';
}
return error.message || '未知错误';
};
1.2 数据缓存策略
// 智能数据比较
const hasDataChanged = (newData: any, oldData: any) => {
if (!oldData || !newData) return true;
try {
return JSON.stringify(newData) !== JSON.stringify(oldData);
} catch {
return true; // 比较失败时认为数据已变化
}
};
// 后台静默刷新
const refreshDataSilently = async () => {
const response = await getProjectTaskList({ project_id: projectId });
if (hasDataChanged(response.data, dashboardData)) {
setDashboardData(response.data);
console.log('数据已更新');
} else {
console.log('数据无变化');
}
};
2. 组件架构设计
2.1 组件职责分离
// 页面组件 (app/dashboard/page.tsx)
// 职责:数据获取、状态管理、错误处理
export default function DashboardPage() {
// 数据管理逻辑
// 轮询逻辑
// 错误处理逻辑
}
// 展示组件 (components/dashboard/network-timeline.tsx)
// 职责:UI渲染、用户交互、数据展示
export function NetworkTimeline({ tasks, onRefresh, ... }) {
// UI渲染逻辑
// 交互处理逻辑
// 数据过滤和搜索逻辑
}
2.2 Hook设计模式
// 自定义Hook示例
const useTaskPolling = (projectId: string, interval: number) => {
const [data, setData] = useState(null);
const [isPolling, setIsPolling] = useState(false);
useEffect(() => {
if (!isPolling) return;
const timer = setInterval(async () => {
const response = await getProjectTaskList({ project_id: projectId });
setData(response.data);
}, interval);
return () => clearInterval(timer);
}, [projectId, interval, isPolling]);
return { data, isPolling, setIsPolling };
};
3. 性能优化策略
3.1 渲染优化
// 虚拟化长列表 (如果任务数量很大)
import { FixedSizeList as List } from 'react-window';
const TaskList = ({ tasks }) => (
<List
height={600}
itemCount={tasks.length}
itemSize={60}
itemData={tasks}
>
{TaskItem}
</List>
);
// 防抖搜索
const debouncedSearch = useMemo(
() => debounce((term: string) => {
setFilteredTasks(tasks.filter(task =>
task.name.toLowerCase().includes(term.toLowerCase())
));
}, 300),
[tasks]
);
3.2 内存管理
// 清理定时器和事件监听
useEffect(() => {
const interval = setInterval(fetchData, 5000);
const handleVisibilityChange = () => {
if (document.hidden) {
clearInterval(interval);
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
clearInterval(interval);
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, []);
4. 错误边界和容错机制
4.1 React错误边界
class TaskErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.error('任务组件错误:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return <div>任务加载失败,请刷新页面</div>;
}
return this.props.children;
}
}
4.2 API容错机制
// 重试机制
const fetchWithRetry = async (url: string, options: any, retries = 3) => {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
if (response.ok) return response;
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
};
// 降级策略
const fetchDataWithFallback = async () => {
try {
return await getProjectTaskList({ project_id });
} catch (error) {
console.warn('API调用失败,使用Mock数据');
return { code: 0, data: mockTaskData };
}
};
5. 测试策略
5.1 单元测试
// 数据转换函数测试
describe('getTaskType', () => {
it('should return correct task type', () => {
expect(getTaskType('generate_character')).toBe('AI');
expect(getTaskType('generate_video')).toBe('Video');
expect(getTaskType('unknown_task')).toBe('Task');
});
});
// 组件测试
describe('NetworkTimeline', () => {
it('should render task list correctly', () => {
const mockTasks = [{ task_id: '1', task_name: 'test' }];
render(<NetworkTimeline tasks={mockTasks} />);
expect(screen.getByText('test')).toBeInTheDocument();
});
});
5.2 集成测试
// API集成测试
describe('Dashboard API Integration', () => {
it('should fetch and display task data', async () => {
const mockResponse = { code: 0, data: mockTasks };
jest.spyOn(api, 'getProjectTaskList').mockResolvedValue(mockResponse);
render(<DashboardPage />);
await waitFor(() => {
expect(screen.getByText('任务列表')).toBeInTheDocument();
});
});
});
6. 监控和日志
6.1 性能监控
// 性能指标收集
const usePerformanceMonitor = () => {
useEffect(() => {
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.entryType === 'measure') {
console.log(`${entry.name}: ${entry.duration}ms`);
}
});
});
observer.observe({ entryTypes: ['measure'] });
return () => observer.disconnect();
}, []);
};
// 渲染时间测量
const measureRenderTime = (componentName: string) => {
performance.mark(`${componentName}-start`);
useEffect(() => {
performance.mark(`${componentName}-end`);
performance.measure(
`${componentName}-render`,
`${componentName}-start`,
`${componentName}-end`
);
});
};
6.2 错误日志
// 错误上报
const reportError = (error: Error, context: string) => {
const errorInfo = {
message: error.message,
stack: error.stack,
context,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
url: window.location.href
};
// 发送到错误监控服务
fetch('/api/errors', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(errorInfo)
});
};
🎯 最佳实践总结
1. 代码质量
- TypeScript: 完整的类型定义和类型安全
- ESLint/Prettier: 代码规范和格式化
- 组件化: 高内聚低耦合的组件设计
- Hook复用: 自定义Hook提取公共逻辑
2. 用户体验
- 加载状态: 清晰的加载和错误状态提示
- 响应式设计: 适配不同屏幕尺寸
- 无障碍访问: 键盘导航和屏幕阅读器支持
- 性能优化: 快速响应和流畅动画
3. 可维护性
- 模块化: 清晰的文件结构和模块划分
- 文档化: 完整的注释和文档
- 测试覆盖: 单元测试和集成测试
- 版本控制: 规范的Git提交和分支管理
这个Dashboard系统展现了现代React应用开发的最佳实践,是一个技术先进、用户友好、可维护性强的企业级应用。