Files
xiaoxia-saas/apps/web/src/pages/workspace/ProjectTasks.tsx
T
CI Test 206957eb10 feat: V21 design system alignment for workspace pages and business components
- Add V21 styles to WorkspaceDetail page (page-head, cards, buttons)
- Create ProjectTasks.css and update ProjectTasks.tsx with V21 UI
- Create business.css with shared V21 styles (buttons, cards, tables, tags)
- Update InviteMemberModal with V21 modal styles
- Update MemberList with V21 table and tag styles
- Update PermissionMatrix with V21 card and table styles
- Update QuotaDisplay with V21 card and progress styles
- Update App.tsx and App.css with V21 design system
2026-06-26 21:37:28 +08:00

132 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 项目任务中心 - V21 UI
*/
import React from 'react';
import { Alert, Button, Card, Empty, List, Progress, Space, Tag, Typography } from 'antd';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useParams } from 'react-router-dom';
import { getProjectTasks, retryProjectTask } from '@/api/tasks';
import '@/components/business/business.css';
import './ProjectTasks.css';
const statusMap: Record<string, { label: string; color: string }> = {
pending: { label: '排队中', color: 'default' },
processing: { label: '处理中', color: 'processing' },
running: { label: '运行中', color: 'processing' },
completed: { label: '已完成', color: 'success' },
failed: { label: '失败', color: 'error' },
cancelled: { label: '已取消', color: 'default' },
};
const taskTypeLabels: Record<string, string> = {
ingest: '素材导入',
generation: '视频生成',
};
const ProjectTasks: React.FC = () => {
const { id } = useParams<{ id: string }>();
const projectId = id || '';
const queryClient = useQueryClient();
const tasksQuery = useQuery({
queryKey: ['project-tasks', projectId],
queryFn: () => getProjectTasks(projectId),
enabled: !!projectId,
refetchInterval: 5000,
});
const retryMutation = useMutation({
mutationFn: ({ taskType, sourceId }: { taskType: string; sourceId: string }) =>
retryProjectTask(taskType, sourceId),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['project-tasks', projectId] }),
});
return (
<div className="xx-project-tasks">
<div className="xx-page-head">
<div>
<h2>任务中心</h2>
<p>查看和管理项目中的所有任务</p>
</div>
<Button className="xx-ghost-btn" onClick={() => tasksQuery.refetch()}>
刷新
</Button>
</div>
<div className="xx-card">
{tasksQuery.isError && (
<Alert style={{ marginBottom: 16 }} type="error" showIcon message="任务列表加载失败" />
)}
{tasksQuery.data?.some((task) => task.retryable) && (
<Alert
style={{ marginBottom: 16 }}
type="warning"
showIcon
message="部分任务可重试"
description="失败任务可通过"重试"重新排队;系统会保留原始失败原因方便排查。"
/>
)}
<List
loading={tasksQuery.isLoading}
dataSource={tasksQuery.data || []}
locale={{
emptyText: (
<div className="xx-empty-state">
<div className="xx-empty-state-icon">📋</div>
<p>暂无任务,上传素材或发起生成后会出现在这里</p>
</div>
),
}}
renderItem={(task) => {
const status = statusMap[task.status] || { label: task.status, color: 'default' };
return (
<List.Item className="xx-task-item">
<List.Item.Meta
title={
<Space wrap className="xx-task-title">
<span className="xx-task-type">{taskTypeLabels[task.task_type] || task.task_type}</span>
<Tag color={status.color} className="xx-tag">{status.label}</Tag>
<Tag className="xx-tag xx-tag-indigo">{task.current_step}</Tag>
{task.retryable && (
<Button
size="small"
className="xx-ghost-btn"
loading={retryMutation.isPending}
onClick={() =>
retryMutation.mutate({ taskType: task.task_type, sourceId: task.source_id })
}
>
重试
</Button>
)}
</Space>
}
description={
<Space direction="vertical" style={{ width: '100%' }} className="xx-task-desc">
<Progress
percent={Math.round(task.progress || 0)}
size="small"
status={task.status === 'failed' ? 'exception' : undefined}
strokeColor={task.status === 'failed' ? '#ef4444' : '#4f46e5'}
/>
{task.user_message ? (
<Typography.Text type="danger">{task.user_message}</Typography.Text>
) : null}
<Typography.Text type="secondary" copyable style={{ fontSize: 12 }}>
任务 ID{task.source_id}
</Typography.Text>
</Space>
}
/>
</List.Item>
);
}}
/>
</div>
</div>
);
};
export const Component = ProjectTasks;
export default ProjectTasks;