'use client' import type { FC } from 'react' import { useState } from 'react' import { RiAddLine, RiCalendarScheduleLine, RiDeleteBinLine, RiRefreshLine, } from '@remixicon/react' import Modal from '@/app/components/base/modal' import Button from '@/app/components/base/button' import { ScheduleStatus } from '@/models/document-schedule' import type { Schedule } from '@/models/document-schedule' import { useCancelSchedule, useDocumentSchedules, useScheduleListKey, } from '@/service/knowledge/use-document-schedule' import { useToastContext } from '@/app/components/base/toast' import { useQueryClient } from '@tanstack/react-query' import Loading from '@/app/components/base/loading' import Confirm from '@/app/components/base/confirm' type ScheduleListProps = { isOpen: boolean onClose: () => void datasetId: string documentId: string documentName: string onCreateNew?: () => void } const ScheduleList: FC = ({ isOpen, onClose, datasetId, documentId, documentName, onCreateNew, }) => { const { notify } = useToastContext() const queryClient = useQueryClient() const [includeCompleted, setIncludeCompleted] = useState(false) const [cancelScheduleId, setCancelScheduleId] = useState(null) const { data, isLoading, refetch } = useDocumentSchedules( datasetId, documentId, includeCompleted, ) const { mutateAsync: cancelSchedule, isPending: isCancelling } = useCancelSchedule() const handleCancelSchedule = async () => { if (!cancelScheduleId) return try { await cancelSchedule({ datasetId, documentId, scheduleId: cancelScheduleId, }) notify({ type: 'success', message: '定时任务取消成功', }) // Invalidate schedules query queryClient.invalidateQueries({ queryKey: useScheduleListKey(datasetId, documentId), }) setCancelScheduleId(null) } catch (error: any) { notify({ type: 'error', message: error.message || '定时任务取消失败', }) } } const getStatusBadge = (status: ScheduleStatus) => { const statusConfig = { [ScheduleStatus.PENDING]: { bg: 'bg-util-colors-blue-blue-100', text: 'text-util-colors-blue-blue-600', label: '待执行', }, [ScheduleStatus.EXECUTING]: { bg: 'bg-util-colors-purple-purple-100', text: 'text-util-colors-purple-purple-600', label: '执行中', }, [ScheduleStatus.COMPLETED]: { bg: 'bg-util-colors-teal-teal-100', text: 'text-util-colors-teal-teal-600', label: '已完成', }, [ScheduleStatus.CANCELLED]: { bg: 'bg-util-colors-gray-gray-100', text: 'text-util-colors-gray-gray-600', label: '已取消', }, [ScheduleStatus.FAILED]: { bg: 'bg-util-colors-red-red-100', text: 'text-util-colors-red-red-600', label: '失败', }, } const config = statusConfig[status] return ( {config.label} ) } const getActionBadge = (action: string) => { const actionConfig: Record = { enable: { color: 'text-text-accent', label: '启用' }, disable: { color: 'text-text-warning', label: '禁用' }, archive: { color: 'text-text-tertiary', label: '归档' }, } const config = actionConfig[action] || actionConfig.enable return ( {config.label} ) } const schedules = data?.schedules || [] const hasSchedules = schedules.length > 0 return ( <> 定时任务列表 } className="!w-[720px] !max-w-[90vw]" >
{/* Document Name */}
文档: {documentName}
{/* Toolbar */}
{onCreateNew && ( )}
{/* Schedule List */}
{isLoading ? (
) : !hasSchedules ? (
暂无定时任务
{onCreateNew && ( )}
) : (
{schedules.map((schedule: Schedule) => (
{/* Action and Status */}
{getActionBadge(schedule.action)} {getStatusBadge(schedule.status)}
{/* Scheduled Time */}
计划执行时间:{' '} {new Date(schedule.scheduled_at).toLocaleString('zh-CN')}
{/* Metadata */} {schedule.metadata?.reason && (
原因: {schedule.metadata.reason}
)} {schedule.metadata?.notes && (
备注: {schedule.metadata.notes}
)} {/* Error Message */} {schedule.error_message && (
错误: {schedule.error_message}
)} {/* Created/Completed/Cancelled Time */}
{schedule.status === ScheduleStatus.COMPLETED && schedule.completed_at && ( 完成时间: {new Date(schedule.completed_at).toLocaleString('zh-CN')} )} {schedule.status === ScheduleStatus.CANCELLED && schedule.cancelled_at && ( 取消时间: {new Date(schedule.cancelled_at).toLocaleString('zh-CN')} )} {schedule.status === ScheduleStatus.PENDING && ( 创建时间: {new Date(schedule.created_at).toLocaleString('zh-CN')} )}
{/* Actions */} {schedule.status === ScheduleStatus.PENDING && ( )}
))}
)}
{/* Summary */} {hasSchedules && (
共 {data?.total || 0} 个定时任务
)}
{/* Footer */}
{/* Cancel Confirmation */} {cancelScheduleId && ( setCancelScheduleId(null)} onConfirm={handleCancelSchedule} onCancel={() => setCancelScheduleId(null)} title="取消定时任务" content="确定要取消这个定时任务吗?" confirmText="确定" isLoading={isCancelling} /> )} ) } export default ScheduleList