mirror of
https://github.com/YFGaia/dify-plus.git
synced 2026-06-04 10:14:00 +08:00
fix: 批量工作流刷新效果修改
This commit is contained in:
@@ -180,12 +180,19 @@ const TextGeneration: FC<IMainProps> = ({
|
||||
const batchJobsLimit = 5 // 每页5个任务
|
||||
const [totalBatchJobs, setTotalBatchJobs] = useState(0)
|
||||
const [isLoadingBatchJobs, setIsLoadingBatchJobs] = useState(false)
|
||||
const lastRefreshTimeRef = useRef(0) // 记录上次刷新时间,避免频繁刷新
|
||||
|
||||
// 从后端获取批量工作流列表
|
||||
const loadBatchWorkflows = useCallback(async () => {
|
||||
const loadBatchWorkflows = useCallback(async (force = false) => {
|
||||
if (!appId || currentTab !== 'batch')
|
||||
return
|
||||
|
||||
// 防止过于频繁的刷新(至少间隔 1 秒)
|
||||
const now = Date.now()
|
||||
if (!force && now - lastRefreshTimeRef.current < 1000)
|
||||
return
|
||||
|
||||
lastRefreshTimeRef.current = now
|
||||
setIsLoadingBatchJobs(true)
|
||||
try {
|
||||
const result = await fetchBatchWorkflowListApi(installedAppInfo?.id, currentPage, batchJobsLimit)
|
||||
@@ -218,25 +225,9 @@ const TextGeneration: FC<IMainProps> = ({
|
||||
loadBatchWorkflows()
|
||||
}, [loadBatchWorkflows])
|
||||
|
||||
// 自动刷新批量工作流列表(每3秒)
|
||||
useEffect(() => {
|
||||
if (currentTab !== 'batch' || batchJobs.length === 0)
|
||||
return
|
||||
// 注意:不再需要自动刷新逻辑,因为每个批量任务现在自己管理进度刷新
|
||||
// 每个 BatchProgress 组件会独立轮询自己的进度(每 3 秒)
|
||||
|
||||
// 检查是否有进行中的任务
|
||||
const hasActiveJobs = batchJobs.some(job =>
|
||||
job.status === 'pending' || job.status === 'processing',
|
||||
)
|
||||
|
||||
if (!hasActiveJobs)
|
||||
return
|
||||
|
||||
const refreshInterval = setInterval(() => {
|
||||
loadBatchWorkflows()
|
||||
}, 3000) // 每3秒刷新一次
|
||||
|
||||
return () => clearInterval(refreshInterval)
|
||||
}, [currentTab, batchJobs, loadBatchWorkflows])
|
||||
|
||||
// 计算分页数据 - 现在数据已经是从后端分页获取的,不需要再切片
|
||||
const paginatedBatchJobs = batchJobs
|
||||
@@ -472,6 +463,28 @@ const TextGeneration: FC<IMainProps> = ({
|
||||
loadBatchWorkflows()
|
||||
console.log('批量任务重试成功,已刷新列表')
|
||||
}
|
||||
|
||||
// 处理单个任务进度更新(只更新列表中的对应项,不刷新整个列表)
|
||||
const handleJobUpdate = useCallback((jobId: string, updatedData: { status: string, processedRows: number, error?: string }) => {
|
||||
setBatchJobs(prevJobs => {
|
||||
// 检查是否真的有变化
|
||||
const job = prevJobs.find(j => j.id === jobId)
|
||||
if (!job)
|
||||
return prevJobs
|
||||
|
||||
// 如果没有变化,不更新
|
||||
if (job.status === updatedData.status && job.processedRows === updatedData.processedRows && job.error === updatedData.error)
|
||||
return prevJobs
|
||||
|
||||
// 有变化才更新
|
||||
return prevJobs.map(job =>
|
||||
job.id === jobId
|
||||
? { ...job, ...updatedData }
|
||||
: job
|
||||
)
|
||||
})
|
||||
}, [])
|
||||
|
||||
// Extend: Stop Batch import
|
||||
|
||||
const handleCompleted = (completionRes: string, taskId?: number, isSuccess?: boolean) => {
|
||||
@@ -662,6 +675,7 @@ const TextGeneration: FC<IMainProps> = ({
|
||||
jobData={job}
|
||||
onDownload={() => handleBatchDownload(job.id)}
|
||||
onRetrySuccess={handleRetrySuccess}
|
||||
onJobUpdate={(updatedData) => handleJobUpdate(job.id, updatedData)}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
RiRefreshLine,
|
||||
RiStopLine,
|
||||
} from '@remixicon/react'
|
||||
import { resumeBatchApi, retryFailedTasksApi, stopBatchApi } from '@/service/web-extend' // extend: 批量运行工单
|
||||
import { fetchProgressApi, resumeBatchApi, retryFailedTasksApi, stopBatchApi } from '@/service/web-extend' // extend: 批量运行工单
|
||||
import type { BatchStatus } from '@/utils/batch-progress-manager' // extend: 批量运行工单
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
|
||||
@@ -32,6 +32,7 @@ export type BatchProgressProps = {
|
||||
}
|
||||
onDownload: () => void
|
||||
onRetrySuccess?: () => void
|
||||
onJobUpdate?: (jobData: { status: string, processedRows: number, error?: string }) => void // 新增:任务更新回调
|
||||
}
|
||||
|
||||
const BatchProgress: FC<BatchProgressProps> = ({
|
||||
@@ -41,10 +42,62 @@ const BatchProgress: FC<BatchProgressProps> = ({
|
||||
jobData,
|
||||
onDownload,
|
||||
onRetrySuccess,
|
||||
onJobUpdate,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
// 本地进度状态,用于独立刷新
|
||||
const [localProgress, setLocalProgress] = useState({
|
||||
status: jobData.status,
|
||||
processedRows: jobData.processedRows,
|
||||
totalRows: jobData.totalRows,
|
||||
error: jobData.error,
|
||||
})
|
||||
|
||||
// 自动刷新单个任务的进度(每 3 秒)
|
||||
useEffect(() => {
|
||||
// 只在任务进行中时刷新
|
||||
if (localProgress.status !== 'pending' && localProgress.status !== 'processing')
|
||||
return
|
||||
|
||||
const refreshInterval = setInterval(async () => {
|
||||
try {
|
||||
const progress = await fetchProgressApi(batchId)
|
||||
if (progress) {
|
||||
const newStatus = progress.status as string
|
||||
const newProcessedRows = progress.processed_rows as number
|
||||
const newError = progress.error as string | undefined
|
||||
|
||||
// 只有当数据有变化时才更新
|
||||
if (
|
||||
newStatus !== localProgress.status
|
||||
|| newProcessedRows !== localProgress.processedRows
|
||||
|| newError !== localProgress.error
|
||||
) {
|
||||
const updatedProgress = {
|
||||
status: newStatus,
|
||||
processedRows: newProcessedRows,
|
||||
totalRows: progress.total_rows as number,
|
||||
error: newError,
|
||||
}
|
||||
setLocalProgress(updatedProgress)
|
||||
// 通知父组件数据已更新(用于列表级别的状态同步)
|
||||
onJobUpdate?.({
|
||||
status: newStatus,
|
||||
processedRows: newProcessedRows,
|
||||
error: newError,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Failed to fetch progress:', error)
|
||||
}
|
||||
}, 3000)
|
||||
|
||||
return () => clearInterval(refreshInterval)
|
||||
}, [batchId, localProgress.status, localProgress.processedRows, localProgress.error, onJobUpdate])
|
||||
|
||||
// 停止批量处理
|
||||
const handleStop = async () => {
|
||||
@@ -160,8 +213,8 @@ const BatchProgress: FC<BatchProgressProps> = ({
|
||||
})
|
||||
|
||||
// 计算进度
|
||||
const progress = jobData.totalRows > 0 ? (jobData.processedRows / jobData.totalRows) * 100 : 0
|
||||
const status = jobData.status as BatchStatus
|
||||
const progress = localProgress.totalRows > 0 ? (localProgress.processedRows / localProgress.totalRows) * 100 : 0
|
||||
const status = localProgress.status as BatchStatus
|
||||
const failed_count = 0 // 从列表API没有这个字段,如果需要可以后续添加
|
||||
|
||||
const getBorderColor = (status: BatchStatus) => {
|
||||
@@ -232,18 +285,18 @@ const BatchProgress: FC<BatchProgressProps> = ({
|
||||
</div>
|
||||
|
||||
{/* 详细进度信息 */}
|
||||
{jobData.totalRows > 0 && (
|
||||
{localProgress.totalRows > 0 && (
|
||||
<div className="mt-2 text-xs text-gray-500">
|
||||
{t('batchWorkflow.processed', {
|
||||
processed: jobData.processedRows || 0,
|
||||
total: jobData.totalRows || 0,
|
||||
processed: localProgress.processedRows || 0,
|
||||
total: localProgress.totalRows || 0,
|
||||
ns: 'extend',
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 错误信息显示 */}
|
||||
{jobData.error && status === 'failed' && (
|
||||
{localProgress.error && status === 'failed' && (
|
||||
<div className="mt-3 rounded-lg border border-red-200 bg-red-50 p-3">
|
||||
<div className="flex items-start space-x-2">
|
||||
<RiErrorWarningLine className="h-4 w-4 text-red-500 mt-0.5 flex-shrink-0" />
|
||||
@@ -252,7 +305,7 @@ const BatchProgress: FC<BatchProgressProps> = ({
|
||||
{t('batchWorkflow.errorOccurred', { ns: 'extend'} )}
|
||||
</div>
|
||||
<div className="text-xs text-red-700 break-words">
|
||||
{jobData.error}
|
||||
{localProgress.error}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user