celery 容灾升级

This commit is contained in:
2026-07-22 14:48:29 +08:00
parent 3f1c4063b0
commit 69e7dec807
67 changed files with 6161 additions and 1958 deletions
@@ -38,6 +38,7 @@ import type {
} from '../types';
import { formatDate } from '../utils/formatDate';
import GenerationTaskResourceGrid from '../components/generation/GenerationTaskResourceGrid';
import { getGenerationStageLabel, getGenerationStatusColor, resolveGenerationUiState } from '../utils/generationTaskStatus';
const { RangePicker } = DatePicker;
@@ -72,29 +73,6 @@ const EMPTY_RESOURCE_STATE: PreviewResourceState = {
references: {},
};
const STATUS_MAP: Record<string, { color: string; text: string; icon: React.ReactNode }> = {
pending: { color: 'default', text: '待处理', icon: <ClockCircleOutlined /> },
generating: { color: 'warning', text: '生成中', icon: <LoadingOutlined spin /> },
completed: { color: 'success', text: '已完成', icon: <CheckCircleOutlined /> },
failed: { color: 'error', text: '失败', icon: <CloseCircleOutlined /> },
download_failed: { color: 'error', text: '下载失败', icon: <CloseCircleOutlined /> },
deleted: { color: 'default', text: '已删除', icon: <CloseCircleOutlined /> },
};
const PIPELINE_STAGE_MAP: Record<string, string> = {
timeout: '任务超时',
queued: '已入队',
preparing: '准备中',
creating_provider_task: '创建任务中',
waiting_remote: '等待生成',
result_ready: '结果就绪',
downloading: '下载中',
done: '完成',
download_failed: '下载失败',
polling: '轮询中',
failed: '失败',
};
const GEN_TYPE_MAP: Record<string, { text: string; color: string; icon: React.ReactNode }> = {
image: { text: '图片', color: 'purple', icon: <FileImageOutlined /> },
video: { text: '视频', color: 'geekblue', icon: <VideoCameraOutlined /> },
@@ -500,8 +478,8 @@ const AdminGenerationAiRecords: React.FC = () => {
const count = Math.max(1, Number(r.generationCount || 1));
if (count === 1) return <Tag>1</Tag>;
const children = r.childItems || [];
const completed = children.filter((item) => (item.displayStatus || item.status) === 'completed').length;
const failed = children.filter((item) => ['failed', 'download_failed'].includes(item.displayStatus || item.status)).length;
const completed = children.filter((item) => resolveGenerationUiState(item).isSuccess).length;
const failed = children.filter((item) => resolveGenerationUiState(item).isFailure).length;
const deleted = children.filter((item) => (item.displayStatus || item.status) === 'deleted').length;
return (
<Space size={4} wrap>
@@ -563,7 +541,7 @@ const AdminGenerationAiRecords: React.FC = () => {
{
title: '结果', key: 'result', width: 90,
render: (_: any, r: GenerationAITaskOut) => {
if (r.status !== 'completed') {
if (!resolveGenerationUiState(r).isSuccess) {
return <Typography.Text style={{ fontSize: 12, color: '#94a3b8' }}>-</Typography.Text>;
}
if (r.genType === 'video' && r.videoUrl) {
@@ -639,13 +617,14 @@ const AdminGenerationAiRecords: React.FC = () => {
{
title: '状态', dataIndex: 'status', width: 100,
render: (v: string) => {
const cfg = STATUS_MAP[v] || { color: 'default', text: v || '-', icon: null };
return <Tag color={cfg.color} icon={cfg.icon}>{cfg.text}</Tag>;
const state = resolveGenerationUiState({ status: v });
const icon = state.isActive ? <LoadingOutlined spin /> : (state.isSuccess ? <CheckCircleOutlined /> : (state.isFailure ? <CloseCircleOutlined /> : <ClockCircleOutlined />));
return <Tag color={state.color} icon={icon}>{state.label}</Tag>;
},
},
{
title: '阶段', dataIndex: 'pipelineStage', width: 120,
render: (v: string) => <Tag color="blue">{PIPELINE_STAGE_MAP[v] || v || '-'}</Tag>,
render: (v: string) => <Tag color={getGenerationStatusColor(v)}>{getGenerationStageLabel(v)}</Tag>,
},
{
title: '时间', key: 'time', width: 170,
@@ -667,10 +646,10 @@ const AdminGenerationAiRecords: React.FC = () => {
], [handleOpenPreview]);
const previewTypeConfig = preview ? (GEN_TYPE_MAP[preview.genType] || { text: preview.genType || '-', color: 'default', icon: null }) : null;
const previewStatusConfig = preview ? (STATUS_MAP[preview.status] || { color: 'default', text: preview.status || '-', icon: null }) : null;
const previewStatusConfig = preview ? resolveGenerationUiState(preview) : null;
const renderResultImage = () => {
if (!preview || preview.genType !== 'image' || preview.status !== 'completed') return null;
if (!preview || preview.genType !== 'image' || !resolveGenerationUiState(preview).isSuccess) return null;
if (!preview.imageUrl) {
return <MediaPlaceholder text="此图片任务暂无结果图片" minHeight={260} />;
@@ -810,7 +789,7 @@ const AdminGenerationAiRecords: React.FC = () => {
};
const renderResultVideo = () => {
if (!preview || preview.genType !== 'video' || preview.status !== 'completed') return null;
if (!preview || preview.genType !== 'video' || !resolveGenerationUiState(preview).isSuccess) return null;
if (!preview.videoUrl) {
return <MediaPlaceholder text="此视频任务暂无结果视频" minHeight={340} />;
@@ -1120,8 +1099,8 @@ const AdminGenerationAiRecords: React.FC = () => {
<div style={{ display: 'flex', flexDirection: 'column', gap: 16, marginTop: 12 }}>
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
{previewTypeConfig ? <Tag color={previewTypeConfig.color} icon={previewTypeConfig.icon}>{previewTypeConfig.text}</Tag> : null}
{previewStatusConfig ? <Tag color={previewStatusConfig.color} icon={previewStatusConfig.icon}>{previewStatusConfig.text}</Tag> : null}
{preview.pipelineStage ? <Tag color="blue">{PIPELINE_STAGE_MAP[preview.pipelineStage] || preview.pipelineStage}</Tag> : null}
{previewStatusConfig ? <Tag color={previewStatusConfig.color} icon={previewStatusConfig.isActive ? <LoadingOutlined spin /> : (previewStatusConfig.isSuccess ? <CheckCircleOutlined /> : (previewStatusConfig.isFailure ? <CloseCircleOutlined /> : <ClockCircleOutlined />))}>{previewStatusConfig.label}</Tag> : null}
{preview.pipelineStage ? <Tag color={getGenerationStatusColor(preview.pipelineStage)}>{getGenerationStageLabel(preview.pipelineStage)}</Tag> : null}
{/*{preview.generationMode ? <Tag>{preview.generationMode}</Tag> : null}*/}
</div>
@@ -1218,7 +1197,7 @@ const AdminGenerationAiRecords: React.FC = () => {
/>
</div>
{preview.status === 'failed' && preview.errorMessage ? (
{previewStatusConfig?.isFailure && preview.errorMessage ? (
<div style={{ padding: 12, borderRadius: 10, background: 'rgba(239,68,68,0.04)', border: '1px solid rgba(239,68,68,0.15)' }}>
<Typography.Text style={{ fontSize: 12, color: '#ef4444' }}>: {preview.errorMessage}</Typography.Text>
</div>